Skip to content

Instantly share code, notes, and snippets.

@vvuk
Created March 10, 2014 18:37
Show Gist options
  • Save vvuk/9471359 to your computer and use it in GitHub Desktop.
Save vvuk/9471359 to your computer and use it in GitHub Desktop.
commit 6746d57c33786267787be4cf19edbbc05e0b682f
Author: Vladimir Vukicevic <vladimir@pobox.com>
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