From a459a00ba8036449ce6d0a9f78de60ab617396a7 Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Tue, 24 Apr 2012 22:48:33 -0400 Subject: [PATCH] Bug 745177 - Retain and re-use uploaded GL tiles. r=ajuma Rather than discarding uploaded tiles once they fall outside of the valid region, shuffle them off into a separate tile-store with all the metadata they need to render them, and render them in the areas that our current valid region doesn't cover in TiledThebesLayerOGL::RenderLayer. --- gfx/layers/Layers.h | 5 + gfx/layers/Makefile.in | 1 + gfx/layers/TiledLayerBuffer.h | 52 +++++- gfx/layers/ipc/ShadowLayerUtils.h | 4 +- gfx/layers/opengl/ReusableTileStoreOGL.cpp | 188 +++++++++++++++++++++ gfx/layers/opengl/ReusableTileStoreOGL.h | 96 +++++++++++ gfx/layers/opengl/TiledThebesLayerOGL.cpp | 92 ++++++++-- gfx/layers/opengl/TiledThebesLayerOGL.h | 25 ++- ipc/glue/IPCMessageUtils.h | 22 +++ layout/base/nsDisplayList.cpp | 4 + 10 files changed, 458 insertions(+), 31 deletions(-) create mode 100644 gfx/layers/opengl/ReusableTileStoreOGL.cpp create mode 100644 gfx/layers/opengl/ReusableTileStoreOGL.h diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 8f5558c5dfb..25bad3a7215 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -110,6 +110,7 @@ public: , mViewportScrollOffset(0, 0) , mScrollId(NULL_SCROLL_ID) , mCSSContentSize(0, 0) + , mResolution(1, 1) {} // Default copy ctor and operator= are fine @@ -151,6 +152,10 @@ public: // Consumers often want to know the size before scaling to pixels // so we record this size as well. gfx::Size mCSSContentSize; + + // This represents the resolution at which the associated layer + // will been rendered. + gfxSize mResolution; }; #define MOZ_LAYER_DECL_NAME(n, e) \ diff --git a/gfx/layers/Makefile.in b/gfx/layers/Makefile.in index a2a8331f910..9cafe5b56e3 100644 --- a/gfx/layers/Makefile.in +++ b/gfx/layers/Makefile.in @@ -86,6 +86,7 @@ CPPSRCS = \ LayerManagerOGL.cpp \ ThebesLayerOGL.cpp \ TiledThebesLayerOGL.cpp \ + ReusableTileStoreOGL.cpp \ LayerSorter.cpp \ ImageLayers.cpp \ $(NULL) diff --git a/gfx/layers/TiledLayerBuffer.h b/gfx/layers/TiledLayerBuffer.h index 8a5351d2538..c65955f17df 100644 --- a/gfx/layers/TiledLayerBuffer.h +++ b/gfx/layers/TiledLayerBuffer.h @@ -87,8 +87,20 @@ public: // (x*GetTileLength(), y*GetTileLength(), GetTileLength(), GetTileLength()) Tile GetTile(int x, int y) const; + // This operates the same as GetTile(aTileOrigin), but will also replace the + // specified tile with the placeholder tile. This does not call ReleaseTile + // on the removed tile. + bool RemoveTile(const nsIntPoint& aTileOrigin, Tile& aRemovedTile); + + // This operates the same as GetTile(x, y), but will also replace the + // specified tile with the placeholder tile. This does not call ReleaseTile + // on the removed tile. + bool RemoveTile(int x, int y, Tile& aRemovedTile); + uint16_t GetTileLength() const { return TILEDLAYERBUFFER_TILE_SIZE; } + unsigned int GetTileCount() const { return mRetainedTiles.Length(); } + const nsIntRegion& GetValidRegion() const { return mValidRegion; } const nsIntRegion& GetLastPaintRegion() const { return mLastPaintRegion; } void SetLastPaintRegion(const nsIntRegion& aLastPaintRegion) { @@ -161,6 +173,30 @@ TiledLayerBuffer::GetTile(int x, int y) const return mRetainedTiles.SafeElementAt(index, AsDerived().GetPlaceholderTile()); } +template bool +TiledLayerBuffer::RemoveTile(const nsIntPoint& aTileOrigin, + Tile& aRemovedTile) +{ + int firstTileX = mValidRegion.GetBounds().x / GetTileLength(); + int firstTileY = mValidRegion.GetBounds().y / GetTileLength(); + return RemoveTile(aTileOrigin.x / GetTileLength() - firstTileX, + aTileOrigin.y / GetTileLength() - firstTileY, + aRemovedTile); +} + +template bool +TiledLayerBuffer::RemoveTile(int x, int y, Tile& aRemovedTile) +{ + int index = x * mRetainedHeight + y; + const Tile& tileToRemove = mRetainedTiles.SafeElementAt(index, AsDerived().GetPlaceholderTile()); + if (!IsPlaceholder(tileToRemove)) { + aRemovedTile = tileToRemove; + mRetainedTiles[index] = AsDerived().GetPlaceholderTile(); + return true; + } + return false; +} + template void TiledLayerBuffer::Update(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion) @@ -209,14 +245,16 @@ TiledLayerBuffer::Update(const nsIntRegion& aNewValidRegion, int tileY = (y - oldBufferOrigin.y) / GetTileLength(); int index = tileX * oldRetainedHeight + tileY; - NS_ABORT_IF_FALSE(!IsPlaceholder(oldRetainedTiles. - SafeElementAt(index, AsDerived().GetPlaceholderTile())), - "Expected tile"); + // The tile may have been removed, skip over it in this case. + if (IsPlaceholder(oldRetainedTiles. + SafeElementAt(index, AsDerived().GetPlaceholderTile()))) { + newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile()); + } else { + Tile tileWithPartialValidContent = oldRetainedTiles[index]; + newRetainedTiles.AppendElement(tileWithPartialValidContent); + oldRetainedTiles[index] = AsDerived().GetPlaceholderTile(); + } - Tile tileWithPartialValidContent = oldRetainedTiles[index]; - newRetainedTiles.AppendElement(tileWithPartialValidContent); - - oldRetainedTiles[index] = AsDerived().GetPlaceholderTile(); } else { // This tile is either: // 1) Outside the new valid region and will simply be an empty diff --git a/gfx/layers/ipc/ShadowLayerUtils.h b/gfx/layers/ipc/ShadowLayerUtils.h index f6570453565..d329a78f3b2 100644 --- a/gfx/layers/ipc/ShadowLayerUtils.h +++ b/gfx/layers/ipc/ShadowLayerUtils.h @@ -73,6 +73,7 @@ struct ParamTraits WriteParam(aMsg, aParam.mViewportScrollOffset); WriteParam(aMsg, aParam.mDisplayPort); WriteParam(aMsg, aParam.mScrollId); + WriteParam(aMsg, aParam.mResolution); } static bool Read(const Message* aMsg, void** aIter, paramType* aResult) @@ -82,7 +83,8 @@ struct ParamTraits ReadParam(aMsg, aIter, &aResult->mContentSize) && ReadParam(aMsg, aIter, &aResult->mViewportScrollOffset) && ReadParam(aMsg, aIter, &aResult->mDisplayPort) && - ReadParam(aMsg, aIter, &aResult->mScrollId)); + ReadParam(aMsg, aIter, &aResult->mScrollId) && + ReadParam(aMsg, aIter, &aResult->mResolution)); } }; diff --git a/gfx/layers/opengl/ReusableTileStoreOGL.cpp b/gfx/layers/opengl/ReusableTileStoreOGL.cpp new file mode 100644 index 00000000000..0b928d15d57 --- /dev/null +++ b/gfx/layers/opengl/ReusableTileStoreOGL.cpp @@ -0,0 +1,188 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ReusableTileStoreOGL.h" + +namespace mozilla { +namespace layers { + +ReusableTileStoreOGL::~ReusableTileStoreOGL() +{ + if (mTiles.Length() == 0) + return; + + mContext->MakeCurrent(); + for (int i = 0; i < mTiles.Length(); i++) + mContext->fDeleteTextures(1, &mTiles[i]->mTexture.mTextureHandle); + mTiles.Clear(); +} + +void +ReusableTileStoreOGL::HarvestTiles(TiledLayerBufferOGL* aVideoMemoryTiledBuffer, + const nsIntRegion& aOldValidRegion, + const nsIntRegion& aNewValidRegion, + const gfxSize& aOldResolution, + const gfxSize& aNewResolution) +{ + gfxSize scaleFactor = gfxSize(aNewResolution.width / aOldResolution.width, + aNewResolution.height / aOldResolution.height); + +#ifdef GFX_TILEDLAYER_PREF_WARNINGS + printf_stderr("Seeing if there are any tiles we can reuse\n"); +#endif + + // Iterate over existing harvested tiles and release any that are contained + // within the new valid region. + mContext->MakeCurrent(); + for (int i = 0; i < mTiles.Length();) { + ReusableTiledTextureOGL* tile = mTiles[i]; + + bool release = false; + if (tile->mResolution == aNewResolution) { + if (aNewValidRegion.Contains(tile->mTileRegion)) + release = true; + } else { + nsIntRegion transformedTileRegion(tile->mTileRegion); + transformedTileRegion.ScaleRoundOut(tile->mResolution.width / aNewResolution.width, + tile->mResolution.height / aNewResolution.height); + if (aNewValidRegion.Contains(transformedTileRegion)) + release = true; + } + + if (release) { +#ifdef GFX_TILEDLAYER_PREF_WARNINGS + nsIntRect tileBounds = tile->mTileRegion.GetBounds(); + printf_stderr("Releasing obsolete reused tile at %d,%d, x%f\n", + tileBounds.x, tileBounds.y, tile->mResolution.width); +#endif + mContext->fDeleteTextures(1, &tile->mTexture.mTextureHandle); + mTiles.RemoveElementAt(i); + continue; + } + + i++; + } + + // Iterate over the tiles and decide which ones we're going to harvest. + // We harvest any tile that is entirely outside of the new valid region, or + // any tile that is partially outside of the valid region and whose + // resolution has changed. + // XXX Tile iteration needs to be abstracted, or have some utility functions + // to make it simpler. + uint16_t tileSize = aVideoMemoryTiledBuffer->GetTileLength(); + nsIntRect validBounds = aOldValidRegion.GetBounds(); + for (int x = validBounds.x; x < validBounds.XMost();) { + int w = tileSize - x % tileSize; + if (x + w > validBounds.x + validBounds.width) + w = validBounds.x + validBounds.width - x; + + for (int y = validBounds.y; y < validBounds.YMost();) { + int h = tileSize - y % tileSize; + if (y + h > validBounds.y + validBounds.height) + h = validBounds.y + validBounds.height - y; + + // If the new valid region doesn't contain this tile region, + // harvest the tile. + nsIntRegion tileRegion; + tileRegion.And(aOldValidRegion, nsIntRect(x, y, w, h)); + + nsIntRegion intersectingRegion; + bool retainTile = false; + if (aNewResolution != aOldResolution) { + // Reconcile resolution changes. + // If the resolution changes, we know the backing layer will have been + // invalidated, so retain tiles that are partially encompassed by the + // new valid area, instead of just tiles that don't intersect at all. + nsIntRegion transformedTileRegion(tileRegion); + transformedTileRegion.ScaleRoundOut(scaleFactor.width, scaleFactor.height); + if (!aNewValidRegion.Contains(transformedTileRegion)) + retainTile = true; + } else if (intersectingRegion.And(tileRegion, aNewValidRegion).IsEmpty()) { + retainTile = true; + } + + if (retainTile) { +#ifdef GFX_TILEDLAYER_PREF_WARNINGS + printf_stderr("Retaining tile at %d,%d, x%f for reuse\n", x, y, aOldResolution.width); +#endif + TiledTexture removedTile; + if (aVideoMemoryTiledBuffer->RemoveTile(nsIntPoint(x, y), removedTile)) { + ReusableTiledTextureOGL* reusedTile = + new ReusableTiledTextureOGL(removedTile, tileRegion, tileSize, + aOldResolution); + mTiles.AppendElement(reusedTile); + } +#ifdef GFX_TILEDLAYER_PREF_WARNINGS + else + printf_stderr("Failed to retain tile for reuse\n"); +#endif + } + + y += h; + } + + x += w; + } + + // Now prune our reused tile store of its oldest tiles if it gets too large. + while (mTiles.Length() > aVideoMemoryTiledBuffer->GetTileCount() * mSizeLimit) { +#ifdef GFX_TILEDLAYER_PREF_WARNINGS + nsIntRect tileBounds = mTiles[0]->mTileRegion.GetBounds(); + printf_stderr("Releasing old reused tile at %d,%d, x%f\n", + tileBounds.x, tileBounds.y, mTiles[0]->mResolution.width); +#endif + mContext->fDeleteTextures(1, &mTiles[0]->mTexture.mTextureHandle); + mTiles.RemoveElementAt(0); + } + +#ifdef GFX_TILEDLAYER_PREF_WARNINGS + printf_stderr("Retained %d tiles\n", mTiles.Length()); +#endif +} + +void +ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer, + const nsIntRegion& aValidRegion, + const gfxSize& aResolution, + const gfx3DMatrix& aTransform, + const nsIntPoint& aRenderOffset) +{ + // Render old tiles to fill in gaps we haven't had the time to render yet. + for (size_t i = 0; i < mTiles.Length(); i++) { + ReusableTiledTextureOGL* tile = mTiles[i]; + + // Work out the scaling factor in case of resolution differences. + gfxSize scaleFactor = gfxSize(aResolution.width / tile->mResolution.width, + aResolution.height / tile->mResolution.height); + + // Get the valid tile region, in the given coordinate space. + nsIntRegion transformedTileRegion(tile->mTileRegion); + if (aResolution != tile->mResolution) + transformedTileRegion.ScaleRoundOut(scaleFactor.width, scaleFactor.height); + + // Skip drawing tiles that will be completely drawn over. + if (aValidRegion.Contains(transformedTileRegion)) + continue; + + // Reconcile the resolution difference by adjusting the transform. + gfx3DMatrix transform = aTransform; + if (aResolution != tile->mResolution) + transform.Scale(scaleFactor.width, scaleFactor.height, 1); + + // XXX We should clip here to make sure we don't overlap with the valid + // region, otherwise we may end up with rendering artifacts on + // semi-transparent layers. + // Similarly, if we have multiple tiles covering the same area, we will + // end up with rendering artifacts if the aLayer isn't opaque. + nsIntRect tileRect = tile->mTileRegion.GetBounds(); + uint16_t tileStartX = tileRect.x % tile->mTileSize; + uint16_t tileStartY = tileRect.y % tile->mTileSize; + nsIntRect textureRect(tileStartX, tileStartY, tileRect.width, tileRect.height); + nsIntSize textureSize(tile->mTileSize, tile->mTileSize); + aLayer->RenderTile(tile->mTexture, transform, aRenderOffset, tileRect, textureRect, textureSize); + } +} + +} // mozilla +} // layers diff --git a/gfx/layers/opengl/ReusableTileStoreOGL.h b/gfx/layers/opengl/ReusableTileStoreOGL.h new file mode 100644 index 00000000000..eb94636e34a --- /dev/null +++ b/gfx/layers/opengl/ReusableTileStoreOGL.h @@ -0,0 +1,96 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_REUSABLETILESTOREOGL_H +#define GFX_REUSABLETILESTOREOGL_H + +#include "TiledThebesLayerOGL.h" +#include "nsTArray.h" +#include "nsAutoPtr.h" + +namespace mozilla { + +namespace gl { +class GLContext; +} + +namespace layers { + +// A storage class for the information required to render a single tile from +// a TiledLayerBufferOGL. +class ReusableTiledTextureOGL +{ +public: + ReusableTiledTextureOGL(TiledTexture aTexture, + const nsIntRegion& aTileRegion, + uint16_t aTileSize, + gfxSize aResolution) + : mTexture(aTexture) + , mTileRegion(aTileRegion) + , mTileSize(aTileSize) + , mResolution(aResolution) + {} + + ~ReusableTiledTextureOGL() {} + + TiledTexture mTexture; + const nsIntRegion mTileRegion; + uint16_t mTileSize; + gfxSize mResolution; +}; + +// This class will operate on a TiledLayerBufferOGL to harvest tiles that have +// rendered content that is about to become invalid. We do this so that in the +// situation that we need to render an area of a TiledThebesLayerOGL that hasn't +// been updated quickly enough, we can still display something (and hopefully +// it'll be the same as the valid rendered content). While this may end up +// showing invalid data, it should only be momentarily. +class ReusableTileStoreOGL +{ +public: + ReusableTileStoreOGL(gl::GLContext* aContext, float aSizeLimit) + : mContext(aContext) + , mSizeLimit(aSizeLimit) + {} + + ~ReusableTileStoreOGL(); + + // Harvests tiles from a TiledLayerBufferOGL that are about to become + // invalid. aOldValidRegion and aOldResolution should be the valid region + // and resolution of the data currently in aVideoMemoryTiledBuffer, and + // aNewValidRegion and aNewResolution should be the valid region and + // resolution of the data that is about to update aVideoMemoryTiledBuffer. + void HarvestTiles(TiledLayerBufferOGL* aVideoMemoryTiledBuffer, + const nsIntRegion& aOldValidRegion, + const nsIntRegion& aNewValidRegion, + const gfxSize& aOldResolution, + const gfxSize& aNewResolution); + + // Draws all harvested tiles that don't intersect with the given valid region. + // Differences in resolution will be reconciled via altering the given + // transformation. + void DrawTiles(TiledThebesLayerOGL* aLayer, + const nsIntRegion& aValidRegion, + const gfxSize& aResolution, + const gfx3DMatrix& aTransform, + const nsIntPoint& aRenderOffset); + +private: + // This GLContext should correspond to the one used in any TiledLayerBufferOGL + // that is passed into HarvestTiles and DrawTiles. + nsRefPtr mContext; + + // This determines the maximum number of tiles stored in this tile store, + // as a fraction of the amount of tiles stored in the TiledLayerBufferOGL + // given to HarvestTiles. + float mSizeLimit; + + // This stores harvested tiles, in the order in which they were harvested. + nsTArray< nsAutoPtr > mTiles; +}; + +} // layers +} // mozilla + +#endif // GFX_REUSABLETILESTOREOGL_H diff --git a/gfx/layers/opengl/TiledThebesLayerOGL.cpp b/gfx/layers/opengl/TiledThebesLayerOGL.cpp index 888a818f096..1cd93e3c611 100644 --- a/gfx/layers/opengl/TiledThebesLayerOGL.cpp +++ b/gfx/layers/opengl/TiledThebesLayerOGL.cpp @@ -4,6 +4,7 @@ #include "mozilla/layers/PLayersChild.h" #include "TiledThebesLayerOGL.h" +#include "ReusableTileStoreOGL.h" #include "BasicTiledThebesLayer.h" #include "gfxImageSurface.h" @@ -37,12 +38,15 @@ TiledLayerBufferOGL::ReleaseTile(TiledTexture aTile) void TiledLayerBufferOGL::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer, const nsIntRegion& aNewValidRegion, - const nsIntRegion& aInvalidateRegion) + const nsIntRegion& aInvalidateRegion, + const gfxSize& aResolution) { #ifdef GFX_TILEDLAYER_PREF_WARNINGS printf_stderr("Upload %i, %i, %i, %i\n", aInvalidateRegion.GetBounds().x, aInvalidateRegion.GetBounds().y, aInvalidateRegion.GetBounds().width, aInvalidateRegion.GetBounds().height); long start = PR_IntervalNow(); #endif + + mResolution = aResolution; mMainMemoryTiledBuffer = aMainMemoryTiledBuffer; mContext->MakeCurrent(); Update(aNewValidRegion, aInvalidateRegion); @@ -113,6 +117,15 @@ TiledThebesLayerOGL::TiledThebesLayerOGL(LayerManagerOGL *aManager) , mVideoMemoryTiledBuffer(aManager->gl()) { mImplData = static_cast(this); + // XXX Add a pref for reusable tile store size + mReusableTileStore = new ReusableTileStoreOGL(aManager->gl(), 1); +} + +TiledThebesLayerOGL::~TiledThebesLayerOGL() +{ + mMainMemoryTiledBuffer.ReadUnlock(); + if (mReusableTileStore) + delete mReusableTileStore; } void @@ -132,7 +145,29 @@ TiledThebesLayerOGL::ProcessUploadQueue() if (mRegionToUpload.IsEmpty()) return; - mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer, mMainMemoryTiledBuffer.GetValidRegion(), mRegionToUpload); + gfxSize resolution(1, 1); + if (mReusableTileStore) { + // Work out render resolution by multiplying the resolution of our ancestors. + // Only container layers can have frame metrics, so we start off with a + // resolution of 1, 1. + // XXX For large layer trees, it would be faster to do this once from the + // root node upwards and store the value on each layer. + for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) { + const FrameMetrics& metrics = parent->GetFrameMetrics(); + resolution.width *= metrics.mResolution.width; + resolution.height *= metrics.mResolution.height; + } + + mReusableTileStore->HarvestTiles(&mVideoMemoryTiledBuffer, + mVideoMemoryTiledBuffer.GetValidRegion(), + mMainMemoryTiledBuffer.GetValidRegion(), + mVideoMemoryTiledBuffer.GetResolution(), + resolution); + } + + mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer, + mMainMemoryTiledBuffer.GetValidRegion(), + mRegionToUpload, resolution); mValidRegion = mVideoMemoryTiledBuffer.GetValidRegion(); mMainMemoryTiledBuffer.ReadUnlock(); @@ -146,12 +181,46 @@ TiledThebesLayerOGL::ProcessUploadQueue() } +void +TiledThebesLayerOGL::RenderTile(TiledTexture aTile, + const gfx3DMatrix& aTransform, + const nsIntPoint& aOffset, + nsIntRect aScreenRect, + nsIntRect aTextureRect, + nsIntSize aTextureBounds) +{ + gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle); + ColorTextureLayerProgram *program; + if (aTile.mFormat == LOCAL_GL_RGB) { + program = mOGLManager->GetRGBXLayerProgram(); + } else { + program = mOGLManager->GetBGRALayerProgram(); + } + program->Activate(); + program->SetTextureUnit(0); + program->SetLayerOpacity(GetEffectiveOpacity()); + program->SetLayerTransform(aTransform); + program->SetRenderOffset(aOffset); + program->SetLayerQuadRect(aScreenRect); + + mOGLManager->BindAndDrawQuadWithTextureRect(program, + aTextureRect, + aTextureBounds); +} + void TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset) { gl()->MakeCurrent(); ProcessUploadQueue(); + // Render old tiles to fill in gaps we haven't had the time to render yet. + if (mReusableTileStore) + mReusableTileStore->DrawTiles(this, mVideoMemoryTiledBuffer.GetValidRegion(), + mVideoMemoryTiledBuffer.GetResolution(), + GetEffectiveTransform(), aOffset); + + // Render valid tiles. const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion(); const nsIntRect visibleRect = visibleRegion.GetBounds(); unsigned int rowCount = 0; @@ -173,22 +242,9 @@ TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOf GetTile(nsIntPoint(mVideoMemoryTiledBuffer.RoundDownToTileEdge(x), mVideoMemoryTiledBuffer.RoundDownToTileEdge(y))); if (tileTexture != mVideoMemoryTiledBuffer.GetPlaceholderTile()) { - - gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, tileTexture.mTextureHandle); - ColorTextureLayerProgram *program; - if (tileTexture.mFormat == LOCAL_GL_RGB) { - program = mOGLManager->GetRGBXLayerProgram(); - } else { - program = mOGLManager->GetBGRALayerProgram(); - } - program->Activate(); - program->SetTextureUnit(0); - program->SetLayerOpacity(GetEffectiveOpacity()); - program->SetLayerTransform(GetEffectiveTransform()); - program->SetRenderOffset(aOffset); - program->SetLayerQuadRect(nsIntRect(x,y,w,h)); // screen - mOGLManager->BindAndDrawQuadWithTextureRect(program, nsIntRect(tileStartX, tileStartY, w, h), nsIntSize(mVideoMemoryTiledBuffer.GetTileLength(), mVideoMemoryTiledBuffer.GetTileLength())); // texture bounds - + uint16_t tileSize = mVideoMemoryTiledBuffer.GetTileLength(); + RenderTile(tileTexture, GetEffectiveTransform(), aOffset, nsIntRect(x,y,w,h), + nsIntRect(tileStartX, tileStartY, w, h), nsIntSize(tileSize, tileSize)); } tileY++; y += h; diff --git a/gfx/layers/opengl/TiledThebesLayerOGL.h b/gfx/layers/opengl/TiledThebesLayerOGL.h index 9e5ba064a90..5511684a909 100644 --- a/gfx/layers/opengl/TiledThebesLayerOGL.h +++ b/gfx/layers/opengl/TiledThebesLayerOGL.h @@ -20,6 +20,8 @@ class GLContext; namespace layers { +class ReusableTileStoreOGL; + class TiledTexture { public: // Constructs a placeholder TiledTexture. See the comments above @@ -73,10 +75,13 @@ public: void Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer, const nsIntRegion& aNewValidRegion, - const nsIntRegion& aInvalidateRegion); + const nsIntRegion& aInvalidateRegion, + const gfxSize& aResolution); TiledTexture GetPlaceholderTile() const { return TiledTexture(); } + const gfxSize& GetResolution() { return mResolution; } + protected: TiledTexture ValidateTile(TiledTexture aTile, const nsIntPoint& aTileRect, @@ -91,6 +96,7 @@ protected: private: nsRefPtr mContext; const BasicTiledLayerBuffer* mMainMemoryTiledBuffer; + gfxSize mResolution; void GetFormatAndTileForImageFormat(gfxASurface::gfxImageFormat aFormat, GLenum& aOutFormat, @@ -103,10 +109,7 @@ class TiledThebesLayerOGL : public ShadowThebesLayer, { public: TiledThebesLayerOGL(LayerManagerOGL *aManager); - virtual ~TiledThebesLayerOGL() - { - mMainMemoryTiledBuffer.ReadUnlock(); - } + virtual ~TiledThebesLayerOGL(); // LayerOGL impl void Destroy() {} @@ -126,10 +129,22 @@ public: } void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer); void ProcessUploadQueue(); + + // Renders a single given tile. + // XXX This currently takes an nsIntRect, but should actually take an + // nsIntRegion and iterate over each rectangle in the region. + void RenderTile(TiledTexture aTile, + const gfx3DMatrix& aTransform, + const nsIntPoint& aOffset, + nsIntRect aScreenRect, + nsIntRect aTextureRect, + nsIntSize aTextureBounds); + private: nsIntRegion mRegionToUpload; BasicTiledLayerBuffer mMainMemoryTiledBuffer; TiledLayerBufferOGL mVideoMemoryTiledBuffer; + ReusableTileStoreOGL* mReusableTileStore; }; } // layers diff --git a/ipc/glue/IPCMessageUtils.h b/ipc/glue/IPCMessageUtils.h index 04c805c664b..c0cfb7104e3 100644 --- a/ipc/glue/IPCMessageUtils.h +++ b/ipc/glue/IPCMessageUtils.h @@ -53,6 +53,7 @@ #include "gfxColor.h" #include "gfxMatrix.h" #include "gfxPattern.h" +#include "gfxPoint.h" #include "nsRect.h" #include "nsRegion.h" #include "gfxASurface.h" @@ -458,6 +459,27 @@ struct ParamTraits } }; +template<> +struct ParamTraits +{ + typedef gfxSize paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.width); + WriteParam(aMsg, aParam.height); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + if (ReadParam(aMsg, aIter, &aResult->width) && + ReadParam(aMsg, aIter, &aResult->height)) + return true; + + return false; + } +}; + template<> struct ParamTraits { diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index d7084dac5ce..4ca121dea63 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -250,6 +250,10 @@ static void RecordFrameMetrics(nsIFrame* aForFrame, } metrics.mScrollId = aScrollId; + + nsIPresShell* presShell = presContext->GetPresShell(); + metrics.mResolution = gfxSize(presShell->GetXResolution(), presShell->GetYResolution()); + aRoot->SetFrameMetrics(metrics); }