Created
March 10, 2014 18:37
-
-
Save vvuk/9471359 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 6746d57c33786267787be4cf19edbbc05e0b682f | |
Author: Vladimir Vukicevic <[email protected]> | |
Date: Mon Mar 10 14:34:57 2014 -0400 | |
Implement SimpleTiledContentClient and friends | |
diff --git a/b2g/chrome/content/settings.js b/b2g/chrome/content/settings.js | |
index 73257c1..92a465b 100644 | |
--- a/b2g/chrome/content/settings.js | |
+++ b/b2g/chrome/content/settings.js | |
@@ -666,6 +666,7 @@ let settingsToObserve = { | |
defaultValue: false | |
}, | |
'layers.enable-tiles': false, | |
+ 'layers.simple-tiles': false, | |
'layers.progressive-paint': false, | |
'layers.draw-tile-borders': false, | |
'layers.dump': false, | |
diff --git a/gfx/layers/AtomicRefCountedWithFinalize.h b/gfx/layers/AtomicRefCountedWithFinalize.h | |
index 3bb00b1..5d9926b 100644 | |
--- a/gfx/layers/AtomicRefCountedWithFinalize.h | |
+++ b/gfx/layers/AtomicRefCountedWithFinalize.h | |
@@ -7,6 +7,7 @@ | |
#define MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_ | |
#include "mozilla/RefPtr.h" | |
+#include "mozilla/NullPtr.h" | |
namespace mozilla { | |
@@ -15,7 +16,8 @@ class AtomicRefCountedWithFinalize | |
{ | |
protected: | |
AtomicRefCountedWithFinalize() | |
- : mRefCount(0) | |
+ : mRecycleCallback(nullptr) | |
+ , mRefCount(0) | |
{} | |
~AtomicRefCountedWithFinalize() {} | |
@@ -28,17 +30,38 @@ class AtomicRefCountedWithFinalize | |
void Release() { | |
MOZ_ASSERT(mRefCount > 0); | |
- if (0 == --mRefCount) { | |
+ int currCount = --mRefCount; | |
+ if (0 == currCount) { | |
+ // Recycle listeners must call ClearRecycleCallback | |
+ // before releasing their strong reference. | |
+ MOZ_ASSERT(mRecycleCallback == nullptr); | |
#ifdef DEBUG | |
mRefCount = detail::DEAD; | |
#endif | |
T* derived = static_cast<T*>(this); | |
derived->Finalize(); | |
delete derived; | |
+ } else if (1 == currCount && mRecycleCallback) { | |
+ T* derived = static_cast<T*>(this); | |
+ mRecycleCallback(derived, mClosure); | |
} | |
} | |
+ typedef void (*RecycleCallback)(T* aObject, void* aClosure); | |
+ /** | |
+ * Set a callback responsible for recycling this object | |
+ * before it is finalized. | |
+ */ | |
+ void SetRecycleCallback(RecycleCallback aCallback, void* aClosure) | |
+ { | |
+ mRecycleCallback = aCallback; | |
+ mClosure = aClosure; | |
+ } | |
+ void ClearRecycleCallback() { SetRecycleCallback(nullptr, nullptr); } | |
+ | |
private: | |
+ RecycleCallback mRecycleCallback; | |
+ void *mClosure; | |
Atomic<int> mRefCount; | |
}; | |
diff --git a/gfx/layers/CompositorTypes.h b/gfx/layers/CompositorTypes.h | |
index cc61aba..943c2d8 100644 | |
--- a/gfx/layers/CompositorTypes.h | |
+++ b/gfx/layers/CompositorTypes.h | |
@@ -55,6 +55,8 @@ const TextureFlags TEXTURE_ON_WHITE = 1 << 13; | |
const TextureFlags TEXTURE_ON_BLACK = 1 << 14; | |
// A texture host that supports tiling | |
const TextureFlags TEXTURE_TILE = 1 << 15; | |
+// A texture should be recycled when no longer in used | |
+const TextureFlags TEXTURE_RECYCLE = 1 << 16; | |
// Texture contents should be initialized | |
// from the previous texture. | |
const TextureFlags TEXTURE_COPY_PREVIOUS = 1 << 24; | |
@@ -164,7 +166,9 @@ enum CompositableType | |
BUFFER_CONTENT_DIRECT, // thebes layer interface, double buffering | |
BUFFER_CONTENT_INC, // thebes layer interface, only sends incremental | |
// updates to a texture on the compositor side. | |
+ // somewhere in the middle | |
BUFFER_TILED, // tiled thebes layer | |
+ BUFFER_SIMPLE_TILED, | |
// the new compositable types | |
COMPOSITABLE_IMAGE, // image with single buffering | |
COMPOSITABLE_CONTENT_SINGLE, // thebes layer interface, single buffering | |
diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp | |
index c7b8342..ffa3435 100644 | |
--- a/gfx/layers/client/ClientLayerManager.cpp | |
+++ b/gfx/layers/client/ClientLayerManager.cpp | |
@@ -21,6 +21,7 @@ | |
#include "mozilla/layers/PLayerChild.h" // for PLayerChild | |
#include "mozilla/layers/LayerTransactionChild.h" | |
#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool | |
+#include "mozilla/layers/SimpleTextureClientPool.h" // for SimpleTextureClientPool | |
#include "nsAString.h" | |
#include "nsIWidget.h" // for nsIWidget | |
#include "nsTArray.h" // for AutoInfallibleTArray | |
@@ -474,6 +475,21 @@ ClientLayerManager::GetTexturePool(SurfaceFormat aFormat) | |
return texturePoolMember->mTexturePool; | |
} | |
+SimpleTextureClientPool* | |
+ClientLayerManager::GetSimpleTileTexturePool(SurfaceFormat aFormat) | |
+{ | |
+ int index = (int) aFormat; | |
+ mSimpleTilePools.EnsureLengthAtLeast(index+1); | |
+ | |
+ if (mSimpleTilePools[index].get() == nullptr) { | |
+ mSimpleTilePools[index] = new SimpleTextureClientPool(aFormat, IntSize(TILEDLAYERBUFFER_TILE_SIZE, | |
+ TILEDLAYERBUFFER_TILE_SIZE), | |
+ mForwarder); | |
+ } | |
+ | |
+ return mSimpleTilePools[index]; | |
+} | |
+ | |
void | |
ClientLayerManager::ClearCachedResources(Layer* aSubtree) | |
{ | |
diff --git a/gfx/layers/client/ClientLayerManager.h b/gfx/layers/client/ClientLayerManager.h | |
index 90ed3f5..56fce23 100644 | |
--- a/gfx/layers/client/ClientLayerManager.h | |
+++ b/gfx/layers/client/ClientLayerManager.h | |
@@ -34,6 +34,7 @@ class CompositorChild; | |
class ImageLayer; | |
class PLayerChild; | |
class TextureClientPool; | |
+class SimpleTextureClientPool; | |
class TextureClientPoolMember | |
: public LinkedListElement<TextureClientPoolMember> { | |
@@ -108,6 +109,7 @@ public: | |
virtual void SetIsFirstPaint() MOZ_OVERRIDE; | |
TextureClientPool *GetTexturePool(gfx::SurfaceFormat aFormat); | |
+ SimpleTextureClientPool *GetSimpleTileTexturePool(gfx::SurfaceFormat aFormat); | |
// Drop cached resources and ask our shadow manager to do the same, | |
// if we have one. | |
@@ -228,6 +230,9 @@ private: | |
RefPtr<ShadowLayerForwarder> mForwarder; | |
LinkedList<TextureClientPoolMember> mTexturePools; | |
+ | |
+ // indexed by gfx::SurfaceFormat | |
+ nsTArray<RefPtr<SimpleTextureClientPool> > mSimpleTilePools; | |
}; | |
class ClientLayer : public ShadowableLayer | |
diff --git a/gfx/layers/client/ClientThebesLayer.cpp b/gfx/layers/client/ClientThebesLayer.cpp | |
index b32b7a9..3faad85 100644 | |
--- a/gfx/layers/client/ClientThebesLayer.cpp | |
+++ b/gfx/layers/client/ClientThebesLayer.cpp | |
@@ -5,6 +5,7 @@ | |
#include "ClientThebesLayer.h" | |
#include "ClientTiledThebesLayer.h" // for ClientTiledThebesLayer | |
+#include "SimpleTiledContentClient.h" | |
#include <stdint.h> // for uint32_t | |
#include "GeckoProfiler.h" // for PROFILER_LABEL | |
#include "client/ClientLayerManager.h" // for ClientLayerManager, etc | |
@@ -176,10 +177,17 @@ ClientLayerManager::CreateThebesLayerWithHint(ThebesLayerCreationHint aHint) | |
(AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL || | |
AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D9 || | |
AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D11)) { | |
- nsRefPtr<ClientTiledThebesLayer> layer = | |
- new ClientTiledThebesLayer(this); | |
- CREATE_SHADOW(Thebes); | |
- return layer.forget(); | |
+ if (gfxPrefs::LayersUseSimpleTiles()) { | |
+ nsRefPtr<SimpleClientTiledThebesLayer> layer = | |
+ new SimpleClientTiledThebesLayer(this); | |
+ CREATE_SHADOW(Thebes); | |
+ return layer.forget(); | |
+ } else { | |
+ nsRefPtr<ClientTiledThebesLayer> layer = | |
+ new ClientTiledThebesLayer(this); | |
+ CREATE_SHADOW(Thebes); | |
+ return layer.forget(); | |
+ } | |
} else | |
{ | |
nsRefPtr<ClientThebesLayer> layer = | |
diff --git a/gfx/layers/client/SimpleTextureClientPool.cpp b/gfx/layers/client/SimpleTextureClientPool.cpp | |
new file mode 100644 | |
index 0000000..d8a88e6 | |
--- /dev/null | |
+++ b/gfx/layers/client/SimpleTextureClientPool.cpp | |
@@ -0,0 +1,137 @@ | |
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- | |
+* 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 "SimpleTextureClientPool.h" | |
+#include "CompositableClient.h" | |
+#include "mozilla/layers/ISurfaceAllocator.h" | |
+ | |
+#include "gfxPrefs.h" | |
+ | |
+#include "nsComponentManagerUtils.h" | |
+ | |
+#if 0 | |
+#define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) | |
+#else | |
+#define RECYCLE_LOG(...) do { } while (0) | |
+#endif | |
+ | |
+namespace mozilla { | |
+namespace layers { | |
+ | |
+using gfx::SurfaceFormat; | |
+ | |
+/* static */ void | |
+SimpleTextureClientPool::ShrinkCallback(nsITimer *aTimer, void *aClosure) | |
+{ | |
+ static_cast<SimpleTextureClientPool*>(aClosure)->ShrinkToMinimumSize(); | |
+} | |
+ | |
+/* static */ void | |
+SimpleTextureClientPool::RecycleCallback(TextureClient* aClient, void* aClosure) | |
+{ | |
+ SimpleTextureClientPool* pool = | |
+ reinterpret_cast<SimpleTextureClientPool*>(aClosure); | |
+ | |
+ aClient->ClearRecycleCallback(); | |
+ pool->ReturnTextureClient(aClient); | |
+} | |
+ | |
+/* static */ void | |
+SimpleTextureClientPool::WaitForCompositorRecycleCallback(TextureClient* aClient, void* aClosure) | |
+{ | |
+ // This will grab a reference that will be released once the compositor | |
+ // acknowledges the remote recycle. Once it is received the object | |
+ // will be fully recycled. | |
+ aClient->WaitForCompositorRecycle(); | |
+ aClient->SetRecycleCallback(SimpleTextureClientPool::RecycleCallback, aClosure); | |
+} | |
+ | |
+SimpleTextureClientPool::SimpleTextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize, | |
+ ISurfaceAllocator *aAllocator) | |
+ : mFormat(aFormat) | |
+ , mSize(aSize) | |
+ , mSurfaceAllocator(aAllocator) | |
+{ | |
+ mTimer = do_CreateInstance("@mozilla.org/timer;1"); | |
+} | |
+ | |
+TemporaryRef<TextureClient> | |
+SimpleTextureClientPool::GetTextureClient(bool aAutoRecycle) | |
+{ | |
+ // Try to fetch a client from the pool | |
+ RefPtr<TextureClient> textureClient; | |
+ if (mTextureClients.size()) { | |
+ textureClient = mTextureClients.top(); | |
+ mTextureClients.pop(); | |
+ RECYCLE_LOG("%s Skip allocate (%i left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mTextureClients.size(), textureClient.get()); | |
+ | |
+ } else { | |
+ // No unused clients in the pool, create one | |
+ if (gfxPrefs::ForceShmemTiles()) { | |
+ textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator, mFormat, TEXTURE_IMMEDIATE_UPLOAD | TEXTURE_RECYCLE); | |
+ } else { | |
+ textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator, mFormat, TEXTURE_FLAGS_DEFAULT | TEXTURE_RECYCLE); | |
+ } | |
+ if (!textureClient->AsTextureClientDrawTarget()->AllocateForSurface(mSize, ALLOC_DEFAULT)) { | |
+ NS_WARNING("TextureClient::AllocateForSurface failed!"); | |
+ } | |
+ RECYCLE_LOG("%s Must allocate (0 left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), textureClient.get()); | |
+ } | |
+ | |
+ if (aAutoRecycle) { | |
+ mAutoRecycle.push_back(textureClient); | |
+ textureClient->SetRecycleCallback(SimpleTextureClientPool::WaitForCompositorRecycleCallback, this); | |
+ } | |
+ | |
+ return textureClient; | |
+} | |
+ | |
+void | |
+SimpleTextureClientPool::ReturnTextureClient(TextureClient *aClient) | |
+{ | |
+ if (!aClient) { | |
+ return; | |
+ } | |
+ | |
+ // If we haven't hit our max cached client limit, add this one | |
+ if (mTextureClients.size() < sMaxTextureClients) { | |
+ mTextureClients.push(aClient); | |
+ RECYCLE_LOG("%s recycled %p (have %d)\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), aClient, mTextureClients.size()); | |
+ } else { | |
+ RECYCLE_LOG("%s did not recycle %p (have %d)\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), aClient, mTextureClients.size()); | |
+ } | |
+ | |
+ // Kick off the pool shrinking timer if there are still more unused texture | |
+ // clients than our desired minimum cache size. | |
+ if (mTextureClients.size() > sMinCacheSize) { | |
+ mTimer->InitWithFuncCallback(SimpleTextureClientPool::ShrinkCallback, this, sShrinkTimeout, | |
+ nsITimer::TYPE_ONE_SHOT); | |
+ } | |
+ | |
+ mAutoRecycle.remove(aClient); | |
+} | |
+ | |
+void | |
+SimpleTextureClientPool::ShrinkToMinimumSize() | |
+{ | |
+ RECYCLE_LOG("%s ShrinkToMinimumSize, removing %d clients", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mTextureClients.size() > sMinCacheSize ? mTextureClients.size() - sMinCacheSize : 0); | |
+ | |
+ mTimer->Cancel(); | |
+ | |
+ while (mTextureClients.size() > sMinCacheSize) { | |
+ mTextureClients.pop(); | |
+ } | |
+} | |
+ | |
+void | |
+SimpleTextureClientPool::Clear() | |
+{ | |
+ while (!mTextureClients.empty()) { | |
+ mTextureClients.pop(); | |
+ } | |
+} | |
+ | |
+} | |
+} | |
diff --git a/gfx/layers/client/SimpleTextureClientPool.h b/gfx/layers/client/SimpleTextureClientPool.h | |
new file mode 100644 | |
index 0000000..d8e71b1 | |
--- /dev/null | |
+++ b/gfx/layers/client/SimpleTextureClientPool.h | |
@@ -0,0 +1,89 @@ | |
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- | |
+* 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 MOZILLA_GFX_SIMPLETEXTURECLIENTPOOL_H | |
+#define MOZILLA_GFX_SIMPLETEXTURECLIENTPOOL_H | |
+ | |
+#include "mozilla/gfx/Types.h" | |
+#include "mozilla/gfx/Point.h" | |
+#include "mozilla/RefPtr.h" | |
+#include "TextureClient.h" | |
+#include "nsITimer.h" | |
+#include <stack> | |
+#include <list> | |
+ | |
+namespace mozilla { | |
+namespace layers { | |
+ | |
+class ISurfaceAllocator; | |
+ | |
+class SimpleTextureClientPool : public RefCounted<SimpleTextureClientPool> | |
+{ | |
+public: | |
+ SimpleTextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize, | |
+ ISurfaceAllocator *aAllocator); | |
+ | |
+ ~SimpleTextureClientPool() | |
+ { | |
+ for (auto it = mAutoRecycle.begin(); it != mAutoRecycle.end(); ++it) { | |
+ (*it)->ClearRecycleCallback(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * If a TextureClient is AutoRecycled, when the last reference is | |
+ * released this object will be automatically return to the pool as | |
+ * soon as the compositor informs us it is done with it. | |
+ */ | |
+ TemporaryRef<TextureClient> GetTextureClient(bool aAutoRecycle = false); | |
+ TemporaryRef<TextureClient> GetTextureClientWithAutoRecycle() { return GetTextureClient(true); } | |
+ | |
+ void ReturnTextureClient(TextureClient *aClient); | |
+ | |
+ void ShrinkToMinimumSize(); | |
+ | |
+ void Clear(); | |
+ | |
+private: | |
+ // The time in milliseconds before the pool will be shrunk to the minimum | |
+ // size after returning a client. | |
+ static const uint32_t sShrinkTimeout = 3000; | |
+ | |
+ // The minimum size of the pool (the number of tiles that will be kept after | |
+ // shrinking). | |
+ static const uint32_t sMinCacheSize = 16; | |
+ | |
+ // This is the number of cached texture clients we don't want to exceed, even | |
+ // temporarily (pre-shrink) | |
+ static const uint32_t sMaxTextureClients = 50; | |
+ | |
+ static void ShrinkCallback(nsITimer *aTimer, void *aClosure); | |
+ static void RecycleCallback(TextureClient* aClient, void* aClosure); | |
+ static void WaitForCompositorRecycleCallback(TextureClient* aClient, void* aClosure); | |
+ | |
+ gfx::SurfaceFormat mFormat; | |
+ gfx::IntSize mSize; | |
+ | |
+ // We use a std::stack and make sure to use it the following way: | |
+ // new (available to be used) elements are push()'d to the front | |
+ // requests are served from the front via pop() | |
+ // -- the thinking is that recently-used elements are most likely | |
+ // to be in any data cache, so we can get some wins there | |
+ // -- the converse though is that if there is some GPU locking going on | |
+ // the most recently used elements may also have the most contention; | |
+ // if we see that, then we should use push_back() to add new elements | |
+ // when we shrink this list, we use pop(), but should use pop_back() to | |
+ // nuke the oldest. | |
+ // We may need to switch to a std::deque | |
+ std::stack<RefPtr<TextureClient> > mTextureClients; | |
+ std::list<RefPtr<TextureClient> > mAutoRecycle; | |
+ | |
+ nsRefPtr<nsITimer> mTimer; | |
+ RefPtr<ISurfaceAllocator> mSurfaceAllocator; | |
+}; | |
+ | |
+} | |
+} | |
+#endif /* MOZILLA_GFX_SIMPLETEXTURECLIENTPOOL_H */ | |
diff --git a/gfx/layers/client/SimpleTiledContentClient.cpp b/gfx/layers/client/SimpleTiledContentClient.cpp | |
new file mode 100644 | |
index 0000000..db1b2fa | |
--- /dev/null | |
+++ b/gfx/layers/client/SimpleTiledContentClient.cpp | |
@@ -0,0 +1,472 @@ | |
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- | |
+ * 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 "mozilla/layers/SimpleTiledContentClient.h" | |
+ | |
+#include <math.h> // for ceil, ceilf, floor | |
+#include "ClientTiledThebesLayer.h" // for ClientTiledThebesLayer | |
+#include "GeckoProfiler.h" // for PROFILER_LABEL | |
+#include "ClientLayerManager.h" // for ClientLayerManager | |
+#include "CompositorChild.h" // for CompositorChild | |
+#include "gfxContext.h" // for gfxContext, etc | |
+#include "gfxPlatform.h" // for gfxPlatform | |
+#include "gfxRect.h" // for gfxRect | |
+#include "mozilla/Attributes.h" // for MOZ_THIS_IN_INITIALIZER_LIST | |
+#include "mozilla/MathAlgorithms.h" // for Abs | |
+#include "mozilla/gfx/Point.h" // for IntSize | |
+#include "mozilla/gfx/Rect.h" // for Rect | |
+#include "mozilla/layers/CompositableForwarder.h" | |
+#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder | |
+#include "SimpleTextureClientPool.h" | |
+#include "nsDebug.h" // for NS_ASSERTION | |
+#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc | |
+#include "nsSize.h" // for nsIntSize | |
+#include "gfxReusableSharedImageSurfaceWrapper.h" | |
+#include "nsMathUtils.h" // for NS_roundf | |
+#include "gfx2DGlue.h" | |
+ | |
+#define ALOG(...) __android_log_print(ANDROID_LOG_INFO, "SimpleTiles", __VA_ARGS__) | |
+ | |
+using namespace mozilla::gfx; | |
+ | |
+namespace mozilla { | |
+namespace layers { | |
+ | |
+void | |
+SimpleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, | |
+ const nsIntRegion& aPaintRegion, | |
+ LayerManager::DrawThebesLayerCallback aCallback, | |
+ void* aCallbackData) | |
+{ | |
+ mCallback = aCallback; | |
+ mCallbackData = aCallbackData; | |
+ | |
+#ifdef GFX_TILEDLAYER_PREF_WARNINGS | |
+ long start = PR_IntervalNow(); | |
+#endif | |
+ | |
+ // If this region is empty XMost() - 1 will give us a negative value. | |
+ NS_ASSERTION(!aPaintRegion.GetBounds().IsEmpty(), "Empty paint region\n"); | |
+ | |
+ PROFILER_LABEL("SimpleTiledLayerBuffer", "PaintThebesUpdate"); | |
+ | |
+ Update(aNewValidRegion, aPaintRegion); | |
+ | |
+#ifdef GFX_TILEDLAYER_PREF_WARNINGS | |
+ if (PR_IntervalNow() - start > 10) { | |
+ const nsIntRect bounds = aPaintRegion.GetBounds(); | |
+ printf_stderr("Time to tile [%i, %i, %i, %i] -> %i\n", bounds.x, bounds.y, bounds.width, bounds.height, PR_IntervalNow() - start); | |
+ } | |
+#endif | |
+ | |
+ mLastPaintOpaque = mThebesLayer->CanUseOpaqueSurface(); | |
+ mCallback = nullptr; | |
+ mCallbackData = nullptr; | |
+} | |
+ | |
+SimpleTiledLayerTile | |
+SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile, | |
+ const nsIntPoint& aTileOrigin, | |
+ const nsIntRegion& aDirtyRegion) | |
+{ | |
+ PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile"); | |
+ static gfx::IntSize kTileSize(TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE); | |
+ | |
+ gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType()); | |
+ | |
+ // if this is true, we're using a separate buffer to do our drawing first | |
+ bool doBufferedDrawing = true; | |
+ bool fullPaint = false; | |
+ | |
+ RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle(); | |
+ //RefPtr<TextureClient> textureClient = mManager->GetTexturePool(tileFormat)->GetTextureClient(); | |
+ //mManager->GetTexturePool(tileFormat)->AutoRecycle(textureClient); | |
+ | |
+ if (!textureClient) { | |
+ NS_WARNING("TextureClient allocation failed"); | |
+ return SimpleTiledLayerTile(); | |
+ } | |
+ | |
+ if (!textureClient->Lock(OPEN_WRITE)) { | |
+ NS_WARNING("TextureClient lock failed"); | |
+ return SimpleTiledLayerTile(); | |
+ } | |
+ | |
+ TextureClientSurface *textureClientSurf = textureClient->AsTextureClientSurface(); | |
+ if (!textureClientSurf) { | |
+ doBufferedDrawing = false; | |
+ } | |
+ | |
+ RefPtr<DrawTarget> drawTarget; | |
+ | |
+ nsRefPtr<gfxImageSurface> clientAsImageSurface; | |
+ unsigned char *bufferData = nullptr; | |
+ | |
+ // these are set/updated differently based on doBufferedDrawing | |
+ nsIntRect drawBounds; | |
+ nsIntRegion drawRegion; | |
+ nsIntRegion invalidateRegion; | |
+ | |
+ if (doBufferedDrawing) { | |
+ // try to obtain the TextureClient as an ImageSurface, so that we can | |
+ // access the pixels directly | |
+ nsRefPtr<gfxASurface> asurf = textureClientSurf->GetAsSurface(); | |
+ clientAsImageSurface = asurf ? asurf->GetAsImageSurface() : nullptr; | |
+ if (clientAsImageSurface) { | |
+ int32_t bufferStride = clientAsImageSurface->Stride(); | |
+ | |
+ if (!aTile.mCachedBuffer) { | |
+ aTile.mCachedBuffer = SharedBuffer::Create(clientAsImageSurface->GetDataSize()); | |
+ fullPaint = true; | |
+ } | |
+ bufferData = (unsigned char*) aTile.mCachedBuffer->Data(); | |
+ | |
+ drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData, | |
+ kTileSize, | |
+ bufferStride, | |
+ tileFormat); | |
+ | |
+ if (fullPaint) { | |
+ drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength()); | |
+ drawRegion = nsIntRegion(drawBounds); | |
+ } else { | |
+ drawBounds = aDirtyRegion.GetBounds(); | |
+ drawRegion = nsIntRegion(drawBounds); | |
+ if (GetContentType() == gfxContentType::COLOR_ALPHA) | |
+ drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y, | |
+ drawBounds.width, drawBounds.height)); | |
+ } | |
+ } else { | |
+ // failed to obtain the client as an ImageSurface | |
+ doBufferedDrawing = false; | |
+ } | |
+ } | |
+ | |
+ // this might get set above if we couldn't extract out a buffer | |
+ if (!doBufferedDrawing) { | |
+ drawTarget = textureClient->AsTextureClientDrawTarget()->GetAsDrawTarget(); | |
+ | |
+ fullPaint = true; | |
+ drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength()); | |
+ drawRegion = nsIntRegion(drawBounds); | |
+ | |
+ if (GetContentType() == gfxContentType::COLOR_ALPHA) | |
+ drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height)); | |
+ } | |
+ | |
+ // do the drawing | |
+ RefPtr<gfxContext> ctxt = new gfxContext(drawTarget); | |
+ | |
+ ctxt->Scale(mResolution, mResolution); | |
+ ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y)); | |
+ | |
+ mCallback(mThebesLayer, ctxt, | |
+ drawRegion, | |
+ fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED? | |
+ invalidateRegion, | |
+ mCallbackData); | |
+ | |
+ ctxt = nullptr; | |
+ drawTarget = nullptr; | |
+ | |
+ if (doBufferedDrawing) { | |
+ memcpy(clientAsImageSurface->Data(), bufferData, clientAsImageSurface->GetDataSize()); | |
+ clientAsImageSurface = nullptr; | |
+ bufferData = nullptr; | |
+ } | |
+ | |
+ textureClient->Unlock(); | |
+ | |
+ if (!mCompositableClient->AddTextureClient(textureClient)) { | |
+ NS_WARNING("Failed to add tile TextureClient [simple]"); | |
+ return SimpleTiledLayerTile(); | |
+ } | |
+ | |
+ // aTile.mCachedBuffer was set earlier | |
+ aTile.mTileBuffer = textureClient; | |
+ aTile.mManager = mManager; | |
+ aTile.mLastUpdate = TimeStamp::Now(); | |
+ | |
+ return aTile; | |
+} | |
+ | |
+SurfaceDescriptorTiles | |
+SimpleTiledLayerBuffer::GetSurfaceDescriptorTiles() | |
+{ | |
+ InfallibleTArray<TileDescriptor> tiles; | |
+ | |
+ for (size_t i = 0; i < mRetainedTiles.Length(); i++) { | |
+ tiles.AppendElement(mRetainedTiles[i].GetTileDescriptor()); | |
+ } | |
+ | |
+ return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion, | |
+ tiles, mRetainedWidth, mRetainedHeight, | |
+ mResolution); | |
+} | |
+ | |
+bool | |
+SimpleTiledLayerBuffer::HasFormatChanged() const | |
+{ | |
+ return mThebesLayer->CanUseOpaqueSurface() != mLastPaintOpaque; | |
+} | |
+ | |
+gfxContentType | |
+SimpleTiledLayerBuffer::GetContentType() const | |
+{ | |
+ if (mThebesLayer->CanUseOpaqueSurface()) | |
+ return gfxContentType::COLOR; | |
+ | |
+ return gfxContentType::COLOR_ALPHA; | |
+} | |
+ | |
+SimpleTiledContentClient::SimpleTiledContentClient(SimpleClientTiledThebesLayer* aThebesLayer, | |
+ ClientLayerManager* aManager) | |
+ : CompositableClient(aManager->AsShadowForwarder()) | |
+ , mTiledBuffer(aThebesLayer, MOZ_THIS_IN_INITIALIZER_LIST(), aManager) | |
+{ | |
+ MOZ_COUNT_CTOR(SimpleTiledContentClient); | |
+} | |
+ | |
+SimpleTiledContentClient::~SimpleTiledContentClient() | |
+{ | |
+ MOZ_COUNT_DTOR(SimpleTiledContentClient); | |
+ mTiledBuffer.Release(); | |
+} | |
+ | |
+void | |
+SimpleTiledContentClient::UseTiledLayerBuffer() | |
+{ | |
+ mForwarder->UseTiledLayerBuffer(this, mTiledBuffer.GetSurfaceDescriptorTiles()); | |
+ mTiledBuffer.ClearPaintedRegion(); | |
+} | |
+ | |
+SimpleClientTiledThebesLayer::SimpleClientTiledThebesLayer(ClientLayerManager* aManager) | |
+ : ThebesLayer(aManager, | |
+ static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST())) | |
+ , mContentClient() | |
+{ | |
+ MOZ_COUNT_CTOR(SimpleClientTiledThebesLayer); | |
+ | |
+ mPaintData.mLastScrollOffset = ScreenPoint(0, 0); | |
+ mPaintData.mFirstPaint = true; | |
+} | |
+ | |
+SimpleClientTiledThebesLayer::~SimpleClientTiledThebesLayer() | |
+{ | |
+ MOZ_COUNT_DTOR(SimpleClientTiledThebesLayer); | |
+} | |
+ | |
+void | |
+SimpleClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs) | |
+{ | |
+ aAttrs = ThebesLayerAttributes(GetValidRegion()); | |
+} | |
+ | |
+static LayoutDeviceRect | |
+ApplyScreenToLayoutTransform(const gfx3DMatrix& aTransform, const ScreenRect& aScreenRect) | |
+{ | |
+ gfxRect input(aScreenRect.x, aScreenRect.y, aScreenRect.width, aScreenRect.height); | |
+ gfxRect output = aTransform.TransformBounds(input); | |
+ return LayoutDeviceRect(output.x, output.y, output.width, output.height); | |
+} | |
+ | |
+void | |
+SimpleClientTiledThebesLayer::BeginPaint() | |
+{ | |
+ if (ClientManager()->IsRepeatTransaction()) { | |
+ return; | |
+ } | |
+ | |
+ mPaintData.mLowPrecisionPaintCount = 0; | |
+ mPaintData.mPaintFinished = false; | |
+ | |
+ // Get the metrics of the nearest scroll container. | |
+ ContainerLayer* scrollParent = nullptr; | |
+ for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) { | |
+ const FrameMetrics& metrics = parent->GetFrameMetrics(); | |
+ if (metrics.mScrollId != FrameMetrics::NULL_SCROLL_ID) { | |
+ scrollParent = parent; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (!scrollParent) { | |
+ // XXX I don't think this can happen, but if it does, warn and set the | |
+ // composition bounds to empty so that progressive updates are disabled. | |
+ NS_WARNING("Tiled Thebes layer with no scrollable container parent"); | |
+ mPaintData.mCompositionBounds.SetEmpty(); | |
+ return; | |
+ } | |
+ | |
+ const FrameMetrics& metrics = scrollParent->GetFrameMetrics(); | |
+ | |
+ // Calculate the transform required to convert screen space into transformed | |
+ // layout device space. | |
+ gfx::Matrix4x4 effectiveTransform = GetEffectiveTransform(); | |
+ for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) { | |
+ if (parent->UseIntermediateSurface()) { | |
+ effectiveTransform = effectiveTransform * parent->GetEffectiveTransform(); | |
+ } | |
+ } | |
+ gfx3DMatrix layoutToScreen; | |
+ gfx::To3DMatrix(effectiveTransform, layoutToScreen); | |
+ layoutToScreen.ScalePost(metrics.mCumulativeResolution.scale, | |
+ metrics.mCumulativeResolution.scale, | |
+ 1.f); | |
+ | |
+ mPaintData.mTransformScreenToLayout = layoutToScreen.Inverse(); | |
+ | |
+ // Compute the critical display port in layer space. | |
+ mPaintData.mLayoutCriticalDisplayPort.SetEmpty(); | |
+ if (!metrics.mCriticalDisplayPort.IsEmpty()) { | |
+ // Convert the display port to screen space first so that we can transform | |
+ // it into layout device space. | |
+ const ScreenRect& criticalDisplayPort = metrics.mCriticalDisplayPort * metrics.mZoom; | |
+ LayoutDeviceRect transformedCriticalDisplayPort = | |
+ ApplyScreenToLayoutTransform(mPaintData.mTransformScreenToLayout, criticalDisplayPort); | |
+ mPaintData.mLayoutCriticalDisplayPort = | |
+ LayoutDeviceIntRect::ToUntyped(RoundedOut(transformedCriticalDisplayPort)); | |
+ } | |
+ | |
+ // Calculate the frame resolution. Because this is Gecko-side, before any | |
+ // async transforms have occurred, we can use mZoom for this. | |
+ mPaintData.mResolution = metrics.mZoom; | |
+ | |
+ // Calculate the scroll offset since the last transaction, and the | |
+ // composition bounds. | |
+ mPaintData.mCompositionBounds.SetEmpty(); | |
+ mPaintData.mScrollOffset.MoveTo(0, 0); | |
+ Layer* primaryScrollable = ClientManager()->GetPrimaryScrollableLayer(); | |
+ if (primaryScrollable) { | |
+ const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics(); | |
+ mPaintData.mScrollOffset = metrics.mScrollOffset * metrics.mZoom; | |
+ mPaintData.mCompositionBounds = | |
+ ApplyScreenToLayoutTransform(mPaintData.mTransformScreenToLayout, | |
+ ScreenRect(metrics.mCompositionBounds)); | |
+ } | |
+} | |
+ | |
+void | |
+SimpleClientTiledThebesLayer::EndPaint(bool aFinish) | |
+{ | |
+ if (!aFinish && !mPaintData.mPaintFinished) { | |
+ return; | |
+ } | |
+ | |
+ mPaintData.mLastScrollOffset = mPaintData.mScrollOffset; | |
+ mPaintData.mPaintFinished = true; | |
+ mPaintData.mFirstPaint = false; | |
+} | |
+ | |
+void | |
+SimpleClientTiledThebesLayer::RenderLayer() | |
+{ | |
+ LayerManager::DrawThebesLayerCallback callback = | |
+ ClientManager()->GetThebesLayerCallback(); | |
+ void *data = ClientManager()->GetThebesLayerCallbackData(); | |
+ if (!callback) { | |
+ ClientManager()->SetTransactionIncomplete(); | |
+ return; | |
+ } | |
+ | |
+ // First time? Create a content client. | |
+ if (!mContentClient) { | |
+ mContentClient = new SimpleTiledContentClient(this, ClientManager()); | |
+ | |
+ mContentClient->Connect(); | |
+ ClientManager()->AsShadowForwarder()->Attach(mContentClient, this); | |
+ MOZ_ASSERT(mContentClient->GetForwarder()); | |
+ } | |
+ | |
+ // If the format changed, nothing is valid | |
+ if (mContentClient->mTiledBuffer.HasFormatChanged()) { | |
+ mValidRegion = nsIntRegion(); | |
+ } | |
+ | |
+ nsIntRegion invalidRegion = mVisibleRegion; | |
+ invalidRegion.Sub(invalidRegion, mValidRegion); | |
+ if (invalidRegion.IsEmpty()) { | |
+ EndPaint(true); | |
+ return; | |
+ } | |
+ | |
+ const FrameMetrics& parentMetrics = GetParent()->GetFrameMetrics(); | |
+ | |
+ nsIntRegion wantToPaintRegion = mVisibleRegion; | |
+ | |
+ // Only paint the mask layer on the first transaction. | |
+ if (GetMaskLayer() && !ClientManager()->IsRepeatTransaction()) { | |
+ ToClientLayer(GetMaskLayer())->RenderLayer(); | |
+ } | |
+ | |
+ // Fast path for no progressive updates, no low-precision updates and no | |
+ // critical display-port set, or no display-port set. | |
+ if (parentMetrics.mCriticalDisplayPort.IsEmpty() || | |
+ parentMetrics.mDisplayPort.IsEmpty()) | |
+ { | |
+ mValidRegion = wantToPaintRegion; | |
+ | |
+ NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer"); | |
+ | |
+ mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, | |
+ callback, data); | |
+ | |
+ ClientManager()->Hold(this); | |
+ | |
+ mContentClient->UseTiledLayerBuffer(); | |
+ | |
+ return; | |
+ } | |
+ | |
+ // Calculate everything we need to perform the paint. | |
+ BeginPaint(); | |
+ | |
+ if (mPaintData.mPaintFinished) { | |
+ return; | |
+ } | |
+ | |
+ // Make sure that tiles that fall outside of the visible region are | |
+ // discarded on the first update. | |
+ if (!ClientManager()->IsRepeatTransaction()) { | |
+ mValidRegion.And(mValidRegion, wantToPaintRegion); | |
+ if (!mPaintData.mLayoutCriticalDisplayPort.IsEmpty()) { | |
+ // Make sure that tiles that fall outside of the critical displayport are | |
+ // discarded on the first update. | |
+ mValidRegion.And(mValidRegion, mPaintData.mLayoutCriticalDisplayPort); | |
+ } | |
+ } | |
+ | |
+ nsIntRegion lowPrecisionInvalidRegion; | |
+ if (!mPaintData.mLayoutCriticalDisplayPort.IsEmpty()) { | |
+ // Clip the invalid region to the critical display-port | |
+ invalidRegion.And(invalidRegion, mPaintData.mLayoutCriticalDisplayPort); | |
+ if (invalidRegion.IsEmpty() && lowPrecisionInvalidRegion.IsEmpty()) { | |
+ EndPaint(true); | |
+ return; | |
+ } | |
+ } | |
+ | |
+ if (!invalidRegion.IsEmpty()) { | |
+ mValidRegion = wantToPaintRegion; | |
+ if (!mPaintData.mLayoutCriticalDisplayPort.IsEmpty()) { | |
+ mValidRegion.And(mValidRegion, mPaintData.mLayoutCriticalDisplayPort); | |
+ } | |
+ mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution); | |
+ mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, | |
+ callback, data); | |
+ | |
+ ClientManager()->Hold(this); | |
+ mContentClient->UseTiledLayerBuffer(); | |
+ | |
+ EndPaint(false); | |
+ return; | |
+ } | |
+ | |
+ EndPaint(false); | |
+} | |
+ | |
+ | |
+} | |
+} | |
diff --git a/gfx/layers/client/SimpleTiledContentClient.h b/gfx/layers/client/SimpleTiledContentClient.h | |
new file mode 100644 | |
index 0000000..9623599 | |
--- /dev/null | |
+++ b/gfx/layers/client/SimpleTiledContentClient.h | |
@@ -0,0 +1,193 @@ | |
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- | |
+ * 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 MOZILLA_GFX_SIMPLETILEDCONTENTCLIENT_H | |
+#define MOZILLA_GFX_SIMPLETILEDCONTENTCLIENT_H | |
+ | |
+// We include this header here so that we don't need to | |
+// duplicate BasicTiledLayerPaintData | |
+#include "TiledContentClient.h" | |
+ | |
+#include "SharedBuffer.h" | |
+ | |
+namespace mozilla { | |
+namespace layers { | |
+ | |
+class ClientTiledThebesLayer; | |
+ | |
+class SimpleTiledLayerTile; | |
+class SimpleTiledLayerBuffer; | |
+class SimpleClientTiledThebesLayer; | |
+class SimpleTiledLayerBuffer; | |
+ | |
+#define GFX_SIMP_TILEDLAYER_DEBUG_OVERLAY | |
+ | |
+struct SimpleTiledLayerTile | |
+{ | |
+ RefPtr<TextureClient> mTileBuffer; | |
+ RefPtr<ClientLayerManager> mManager; | |
+ nsRefPtr<SharedBuffer> mCachedBuffer; | |
+ TimeStamp mLastUpdate; | |
+ | |
+ SimpleTiledLayerTile() { } | |
+ | |
+ SimpleTiledLayerTile(ClientLayerManager *aManager, TextureClient *aBuffer) | |
+ : mTileBuffer(aBuffer) | |
+ , mManager(aManager) | |
+ { } | |
+ | |
+ bool operator== (const SimpleTiledLayerTile& o) const | |
+ { | |
+ return mTileBuffer == o.mTileBuffer; | |
+ } | |
+ | |
+ bool operator!= (const SimpleTiledLayerTile& o) const | |
+ { | |
+ return mTileBuffer != o.mTileBuffer; | |
+ } | |
+ | |
+ void SetLayerManager(ClientLayerManager *aManager) | |
+ { | |
+ mManager = aManager; | |
+ } | |
+ | |
+ bool IsPlaceholderTile() | |
+ { | |
+ return mTileBuffer == nullptr; | |
+ } | |
+ | |
+ TileDescriptor GetTileDescriptor() | |
+ { | |
+ if (mTileBuffer) | |
+ return TexturedTileDescriptor(nullptr, mTileBuffer->GetIPDLActor(), 0); | |
+ | |
+ NS_NOTREACHED("Unhandled SimpleTiledLayerTile type"); | |
+ return PlaceholderTileDescriptor(); | |
+ } | |
+ | |
+ void Release() | |
+ { | |
+ mTileBuffer = nullptr; | |
+ mCachedBuffer = nullptr; | |
+ } | |
+}; | |
+ | |
+class SimpleTiledLayerBuffer | |
+ : public TiledLayerBuffer<SimpleTiledLayerBuffer, SimpleTiledLayerTile> | |
+{ | |
+ friend class TiledLayerBuffer<SimpleTiledLayerBuffer, SimpleTiledLayerTile>; | |
+ | |
+public: | |
+ SimpleTiledLayerBuffer(SimpleClientTiledThebesLayer* aThebesLayer, | |
+ CompositableClient* aCompositableClient, | |
+ ClientLayerManager* aManager) | |
+ : mThebesLayer(aThebesLayer) | |
+ , mCompositableClient(aCompositableClient) | |
+ , mManager(aManager) | |
+ , mLastPaintOpaque(false) | |
+ {} | |
+ | |
+ SimpleTiledLayerBuffer() | |
+ : mLastPaintOpaque(false) | |
+ {} | |
+ | |
+ void PaintThebes(const nsIntRegion& aNewValidRegion, | |
+ const nsIntRegion& aPaintRegion, | |
+ LayerManager::DrawThebesLayerCallback aCallback, | |
+ void* aCallbackData); | |
+ | |
+ SurfaceDescriptorTiles GetSurfaceDescriptorTiles(); | |
+ | |
+ void Release() { | |
+ for (size_t i = 0; i < mRetainedTiles.Length(); i++) { | |
+ mRetainedTiles[i].Release(); | |
+ } | |
+ } | |
+ | |
+ const CSSToScreenScale& GetFrameResolution() const { return mFrameResolution; } | |
+ void SetFrameResolution(const CSSToScreenScale& aResolution) { mFrameResolution = aResolution; } | |
+ | |
+ bool HasFormatChanged() const; | |
+private: | |
+ SimpleClientTiledThebesLayer* mThebesLayer; | |
+ CompositableClient* mCompositableClient; | |
+ ClientLayerManager* mManager; | |
+ LayerManager::DrawThebesLayerCallback mCallback; | |
+ void* mCallbackData; | |
+ CSSToScreenScale mFrameResolution; | |
+ bool mLastPaintOpaque; | |
+ | |
+ gfxContentType GetContentType() const; | |
+ | |
+ SimpleTiledLayerTile ValidateTile(SimpleTiledLayerTile aTile, | |
+ const nsIntPoint& aTileOrigin, | |
+ const nsIntRegion& aDirtyRect); | |
+ | |
+ SimpleTiledLayerTile GetPlaceholderTile() const { return SimpleTiledLayerTile(); } | |
+ | |
+ void ReleaseTile(SimpleTiledLayerTile aTile) { aTile.Release(); } | |
+ | |
+ void SwapTiles(SimpleTiledLayerTile& aTileA, SimpleTiledLayerTile& aTileB) { std::swap(aTileA, aTileB); } | |
+}; | |
+ | |
+class SimpleTiledContentClient : public CompositableClient | |
+{ | |
+ friend class SimpleClientTiledThebesLayer; | |
+ | |
+public: | |
+ SimpleTiledContentClient(SimpleClientTiledThebesLayer* aThebesLayer, | |
+ ClientLayerManager* aManager); | |
+ | |
+ ~SimpleTiledContentClient(); | |
+ | |
+ virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE | |
+ { | |
+ return TextureInfo(BUFFER_SIMPLE_TILED); | |
+ } | |
+ | |
+ void UseTiledLayerBuffer(); | |
+ | |
+private: | |
+ SimpleTiledLayerBuffer mTiledBuffer; | |
+}; | |
+ | |
+class SimpleClientTiledThebesLayer : public ThebesLayer, | |
+ public ClientLayer | |
+{ | |
+ typedef ThebesLayer Base; | |
+ | |
+public: | |
+ SimpleClientTiledThebesLayer(ClientLayerManager* const aManager); | |
+ ~SimpleClientTiledThebesLayer(); | |
+ | |
+ // Thebes Layer | |
+ virtual Layer* AsLayer() { return this; } | |
+ virtual void InvalidateRegion(const nsIntRegion& aRegion) { | |
+ mInvalidRegion.Or(mInvalidRegion, aRegion); | |
+ mValidRegion.Sub(mValidRegion, aRegion); | |
+ } | |
+ | |
+ // Shadow methods | |
+ virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs); | |
+ virtual ShadowableLayer* AsShadowableLayer() { return this; } | |
+ | |
+ virtual void Disconnect() { ClientLayer::Disconnect(); } | |
+ | |
+ virtual void RenderLayer(); | |
+ | |
+protected: | |
+ ClientLayerManager* ClientManager() { return static_cast<ClientLayerManager*>(mManager); } | |
+ | |
+ void BeginPaint(); | |
+ void EndPaint(bool aFinish); | |
+ | |
+ RefPtr<SimpleTiledContentClient> mContentClient; | |
+ BasicTiledLayerPaintData mPaintData; | |
+}; | |
+ | |
+} // mozilla | |
+} // layers | |
+ | |
+#endif | |
diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp | |
index d18f6b3..04e736f 100644 | |
--- a/gfx/layers/client/TextureClient.cpp | |
+++ b/gfx/layers/client/TextureClient.cpp | |
@@ -52,6 +52,12 @@ | |
# include "gfxSharedImageSurface.h" | |
#endif | |
+#if 0 | |
+#define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) | |
+#else | |
+#define RECYCLE_LOG(...) do { } while (0) | |
+#endif | |
+ | |
using namespace mozilla::gl; | |
using namespace mozilla::gfx; | |
@@ -90,6 +96,20 @@ public: | |
bool Recv__delete__() MOZ_OVERRIDE; | |
+ bool RecvCompositorRecycle() | |
+ { | |
+ RECYCLE_LOG("Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get()); | |
+ mWaitForRecycle = nullptr; | |
+ return true; | |
+ } | |
+ | |
+ void WaitForCompositorRecycle() | |
+ { | |
+ mWaitForRecycle = mTextureClient; | |
+ RECYCLE_LOG("Wait for recycle %p\n", mWaitForRecycle.get()); | |
+ SendClientRecycle(); | |
+ } | |
+ | |
/** | |
* Only used during the deallocation phase iff we need synchronization between | |
* the client and host side for deallocation (that is, when the data is going | |
@@ -128,6 +148,7 @@ private: | |
} | |
RefPtr<CompositableForwarder> mForwarder; | |
+ RefPtr<TextureClient> mWaitForRecycle; | |
TextureClientData* mTextureData; | |
TextureClient* mTextureClient; | |
bool mIPCOpen; | |
@@ -138,6 +159,7 @@ private: | |
void | |
TextureChild::DeleteTextureData() | |
{ | |
+ mWaitForRecycle = nullptr; | |
if (mTextureData) { | |
mTextureData->DeallocateSharedData(GetAllocator()); | |
delete mTextureData; | |
@@ -158,6 +180,7 @@ TextureChild::ActorDestroy(ActorDestroyReason why) | |
if (mTextureClient) { | |
mTextureClient->mActor = nullptr; | |
} | |
+ mWaitForRecycle = nullptr; | |
} | |
// static | |
@@ -181,7 +204,13 @@ TextureClient::DestroyIPDLActor(PTextureChild* actor) | |
TextureClient* | |
TextureClient::AsTextureClient(PTextureChild* actor) | |
{ | |
- return actor? static_cast<TextureChild*>(actor)->mTextureClient : nullptr; | |
+ return actor ? static_cast<TextureChild*>(actor)->mTextureClient : nullptr; | |
+} | |
+ | |
+void | |
+TextureClient::WaitForCompositorRecycle() | |
+{ | |
+ mActor->WaitForCompositorRecycle(); | |
} | |
bool | |
diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h | |
index b9a9e28..6aeddb0 100644 | |
--- a/gfx/layers/client/TextureClient.h | |
+++ b/gfx/layers/client/TextureClient.h | |
@@ -279,6 +279,15 @@ public: | |
TextureFlags GetFlags() const { return mFlags; } | |
/** | |
+ * valid only for TEXTURE_RECYCLE TextureClient. | |
+ * When called this texture client will grab a strong reference and release | |
+ * it once the compositor notifies that it is done with the texture. | |
+ * NOTE: In this stage the texture client can no longer be used by the | |
+ * client in a transaction. | |
+ */ | |
+ void WaitForCompositorRecycle(); | |
+ | |
+ /** | |
* After being shared with the compositor side, an immutable texture is never | |
* modified, it can only be read. It is safe to not Lock/Unlock immutable | |
* textures. | |
diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp | |
index 37df0b6..70b9283 100644 | |
--- a/gfx/layers/composite/CompositableHost.cpp | |
+++ b/gfx/layers/composite/CompositableHost.cpp | |
@@ -160,6 +160,7 @@ CompositableHost::Create(const TextureInfo& aTextureInfo) | |
result = new ContentHostIncremental(aTextureInfo); | |
break; | |
case BUFFER_TILED: | |
+ case BUFFER_SIMPLE_TILED: | |
result = new TiledContentHost(aTextureInfo); | |
break; | |
case COMPOSITABLE_IMAGE: | |
diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp | |
index 107c728..c9476ce 100644 | |
--- a/gfx/layers/composite/TextureHost.cpp | |
+++ b/gfx/layers/composite/TextureHost.cpp | |
@@ -22,8 +22,15 @@ | |
#include "nsAutoPtr.h" // for nsRefPtr | |
#include "nsPrintfCString.h" // for nsPrintfCString | |
#include "mozilla/layers/PTextureParent.h" | |
+#include "mozilla/unused.h" | |
#include <limits> | |
+#if 0 | |
+#define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) | |
+#else | |
+#define RECYCLE_LOG(...) do { } while (0) | |
+#endif | |
+ | |
struct nsIntPoint; | |
namespace mozilla { | |
@@ -43,6 +50,9 @@ public: | |
bool Init(const SurfaceDescriptor& aSharedData, | |
const TextureFlags& aFlags); | |
+ void CompositorRecycle(); | |
+ virtual bool RecvClientRecycle() MOZ_OVERRIDE; | |
+ | |
virtual bool RecvRemoveTexture() MOZ_OVERRIDE; | |
virtual bool RecvRemoveTextureSync() MOZ_OVERRIDE; | |
@@ -52,6 +62,7 @@ public: | |
void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; | |
ISurfaceAllocator* mAllocator; | |
+ RefPtr<TextureHost> mWaitForClientRecycle; | |
RefPtr<TextureHost> mTextureHost; | |
}; | |
@@ -728,7 +739,37 @@ TextureParent::TextureParent(ISurfaceAllocator* aAllocator) | |
TextureParent::~TextureParent() | |
{ | |
MOZ_COUNT_DTOR(TextureParent); | |
- mTextureHost = nullptr; | |
+ if (mTextureHost) { | |
+ mTextureHost->ClearRecycleCallback(); | |
+ } | |
+} | |
+ | |
+static void RecycleCallback(TextureHost* textureHost, void* aClosure) { | |
+ TextureParent* tp = reinterpret_cast<TextureParent*>(aClosure); | |
+ tp->CompositorRecycle(); | |
+} | |
+ | |
+void | |
+TextureParent::CompositorRecycle() | |
+{ | |
+ mTextureHost->ClearRecycleCallback(); | |
+ mozilla::unused << SendCompositorRecycle(); | |
+ | |
+ // Don't forget to prepare for the next reycle | |
+ mWaitForClientRecycle = mTextureHost; | |
+} | |
+ | |
+bool | |
+TextureParent::RecvClientRecycle() | |
+{ | |
+ // This will allow the RecycleCallback to be called once the compositor | |
+ // releases any external references to TextureHost. | |
+ mTextureHost->SetRecycleCallback(RecycleCallback, this); | |
+ if (!mWaitForClientRecycle) { | |
+ RECYCLE_LOG("Not a recycable tile"); | |
+ } | |
+ mWaitForClientRecycle = nullptr; | |
+ return true; | |
} | |
bool | |
@@ -738,7 +779,14 @@ TextureParent::Init(const SurfaceDescriptor& aSharedData, | |
mTextureHost = TextureHost::Create(aSharedData, | |
mAllocator, | |
aFlags); | |
- mTextureHost->mActor = this; | |
+ if (mTextureHost) { | |
+ mTextureHost->mActor = this; | |
+ if (aFlags & TEXTURE_RECYCLE) { | |
+ mWaitForClientRecycle = mTextureHost; | |
+ RECYCLE_LOG("Setup recycling for tile %p\n", this); | |
+ } | |
+ } | |
+ | |
return !!mTextureHost; | |
} | |
@@ -773,6 +821,10 @@ TextureParent::ActorDestroy(ActorDestroyReason why) | |
NS_RUNTIMEABORT("FailedConstructor isn't possible in PTexture"); | |
} | |
+ if (mTextureHost->GetFlags() & TEXTURE_RECYCLE) { | |
+ RECYCLE_LOG("clear recycling for tile %p\n", this); | |
+ mTextureHost->ClearRecycleCallback(); | |
+ } | |
if (mTextureHost->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) { | |
mTextureHost->ForgetSharedData(); | |
} | |
diff --git a/gfx/layers/composite/TextureHost.h b/gfx/layers/composite/TextureHost.h | |
index 96d930d..590bb9b 100644 | |
--- a/gfx/layers/composite/TextureHost.h | |
+++ b/gfx/layers/composite/TextureHost.h | |
@@ -275,7 +275,6 @@ class TextureHost | |
void Finalize(); | |
friend class AtomicRefCountedWithFinalize<TextureHost>; | |
- | |
public: | |
TextureHost(TextureFlags aFlags); | |
diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp | |
index e0090bd..664cbf9 100644 | |
--- a/gfx/layers/composite/TiledContentHost.cpp | |
+++ b/gfx/layers/composite/TiledContentHost.cpp | |
@@ -34,6 +34,7 @@ TiledLayerBufferComposite::TiledLayerBufferComposite() | |
TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator, | |
const SurfaceDescriptorTiles& aDescriptor, | |
const nsIntRegion& aOldPaintedRegion) | |
+ : mFrameResolution(1.0) | |
{ | |
mUninitialized = false; | |
mHasDoubleBufferedTiles = false; | |
@@ -61,13 +62,13 @@ TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocat | |
sharedLock = gfxShmSharedReadLock::Open(aAllocator, ipcLock.get_Shmem()); | |
} else { | |
sharedLock = reinterpret_cast<gfxMemorySharedReadLock*>(ipcLock.get_uintptr_t()); | |
- // The corresponding AddRef is in TiledClient::GetTileDescriptor | |
- sharedLock->Release(); | |
- } | |
- MOZ_ASSERT(sharedLock); | |
- if (sharedLock) { | |
- mRetainedTiles.AppendElement(TileHost(sharedLock, texture)); | |
+ if (sharedLock) { | |
+ // The corresponding AddRef is in TiledClient::GetTileDescriptor | |
+ sharedLock->Release(); | |
+ } | |
} | |
+ | |
+ mRetainedTiles.AppendElement(TileHost(sharedLock, texture)); | |
break; | |
} | |
default: | |
diff --git a/gfx/layers/composite/TiledContentHost.h b/gfx/layers/composite/TiledContentHost.h | |
index 665dc79..8f66ce0 100644 | |
--- a/gfx/layers/composite/TiledContentHost.h | |
+++ b/gfx/layers/composite/TiledContentHost.h | |
@@ -88,9 +88,6 @@ public: | |
bool IsPlaceholderTile() const { return mTextureHost == nullptr; } | |
void ReadUnlock() { | |
- // Warn if we have a texture host, but no corresponding lock. | |
- NS_WARN_IF_FALSE(mTextureHost == nullptr || mSharedLock != nullptr, | |
- "ReadUnlock with no gfxSharedReadLock"); | |
if (mSharedLock) { | |
mSharedLock->ReadUnlock(); | |
} | |
@@ -263,8 +260,8 @@ private: | |
TiledLayerBufferComposite mLowPrecisionTiledBuffer; | |
TiledLayerBufferComposite mOldTiledBuffer; | |
TiledLayerBufferComposite mOldLowPrecisionTiledBuffer; | |
- bool mPendingUpload : 1; | |
- bool mPendingLowPrecisionUpload : 1; | |
+ bool mPendingUpload; | |
+ bool mPendingLowPrecisionUpload; | |
}; | |
} | |
diff --git a/gfx/layers/ipc/PTexture.ipdl b/gfx/layers/ipc/PTexture.ipdl | |
index 288ee07..af02eaf 100644 | |
--- a/gfx/layers/ipc/PTexture.ipdl | |
+++ b/gfx/layers/ipc/PTexture.ipdl | |
@@ -25,8 +25,12 @@ sync protocol PTexture { | |
child: | |
async __delete__(); | |
+ async CompositorRecycle(); | |
+ | |
parent: | |
+ async ClientRecycle(); | |
+ | |
/** | |
* Asynchronously tell the Compositor side to remove the texture. | |
*/ | |
diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build | |
index 0387ff8..0d508c4 100644 | |
--- a/gfx/layers/moz.build | |
+++ b/gfx/layers/moz.build | |
@@ -105,6 +105,8 @@ EXPORTS.mozilla.layers += [ | |
'client/CompositableClient.h', | |
'client/ContentClient.h', | |
'client/ImageClient.h', | |
+ 'client/SimpleTextureClientPool.h', | |
+ 'client/SimpleTiledContentClient.h', | |
'client/TextureClient.h', | |
'client/TextureClientPool.h', | |
'client/TiledContentClient.h', | |
@@ -234,6 +236,8 @@ UNIFIED_SOURCES += [ | |
'client/CompositableClient.cpp', | |
'client/ContentClient.cpp', | |
'client/ImageClient.cpp', | |
+ 'client/SimpleTextureClientPool.cpp', | |
+ 'client/SimpleTiledContentClient.cpp', | |
'client/TextureClient.cpp', | |
'client/TextureClientPool.cpp', | |
'client/TiledContentClient.cpp', | |
diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h | |
index 2d810b5..e2d7bbe 100644 | |
--- a/gfx/thebes/gfxPrefs.h | |
+++ b/gfx/thebes/gfxPrefs.h | |
@@ -156,6 +156,7 @@ private: | |
DECL_GFX_PREF(Live, "layers.draw-tile-borders", DrawTileBorders, bool, false); | |
DECL_GFX_PREF(Once, "layers.dump", LayersDump, bool, false); | |
DECL_GFX_PREF(Once, "layers.enable-tiles", LayersTilesEnabled, bool, false); | |
+ DECL_GFX_PREF(Once, "layers.simple-tiles", LayersUseSimpleTiles, bool, false); | |
DECL_GFX_PREF(Once, "layers.force-per-tile-drawing", PerTileDrawing, bool, false); | |
DECL_GFX_PREF(Once, "layers.overzealous-gralloc-unlocking", OverzealousGrallocUnlocking, bool, false); | |
DECL_GFX_PREF(Once, "layers.force-shmem-tiles", ForceShmemTiles, bool, false); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment