зеркало из https://github.com/mozilla/gecko-dev.git
b=979489; Implement SimpleTiledContentClient and friends; r=jrmuizel
This commit is contained in:
Родитель
241dfbe366
Коммит
b7be770266
|
@ -665,7 +665,8 @@ let settingsToObserve = {
|
|||
prefName: 'dom.browser_frames.useAsyncPanZoom',
|
||||
defaultValue: false
|
||||
},
|
||||
'layers.enable-tiles': false,
|
||||
'layers.enable-tiles': true,
|
||||
'layers.simple-tiles': false,
|
||||
'layers.progressive-paint': false,
|
||||
'layers.draw-tile-borders': false,
|
||||
'layers.dump': false,
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 =
|
||||
static_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 (mAvailableTextureClients.size()) {
|
||||
textureClient = mAvailableTextureClients.top();
|
||||
mAvailableTextureClients.pop();
|
||||
RECYCLE_LOG("%s Skip allocate (%i left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mAvailableTextureClients.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) {
|
||||
mOutstandingTextureClients.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 (mAvailableTextureClients.size() < sMaxTextureClients) {
|
||||
mAvailableTextureClients.push(aClient);
|
||||
RECYCLE_LOG("%s recycled %p (have %d)\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), aClient, mAvailableTextureClients.size());
|
||||
} else {
|
||||
RECYCLE_LOG("%s did not recycle %p (have %d)\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), aClient, mAvailableTextureClients.size());
|
||||
}
|
||||
|
||||
// Kick off the pool shrinking timer if there are still more unused texture
|
||||
// clients than our desired minimum cache size.
|
||||
if (mAvailableTextureClients.size() > sMinCacheSize) {
|
||||
mTimer->InitWithFuncCallback(SimpleTextureClientPool::ShrinkCallback, this, sShrinkTimeout,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
mOutstandingTextureClients.remove(aClient);
|
||||
}
|
||||
|
||||
void
|
||||
SimpleTextureClientPool::ShrinkToMinimumSize()
|
||||
{
|
||||
RECYCLE_LOG("%s ShrinkToMinimumSize, removing %d clients", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mAvailableTextureClients.size() > sMinCacheSize ? mAvailableTextureClients.size() - sMinCacheSize : 0);
|
||||
|
||||
mTimer->Cancel();
|
||||
|
||||
while (mAvailableTextureClients.size() > sMinCacheSize) {
|
||||
mAvailableTextureClients.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SimpleTextureClientPool::Clear()
|
||||
{
|
||||
while (!mAvailableTextureClients.empty()) {
|
||||
mAvailableTextureClients.pop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/* -*- 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:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(SimpleTextureClientPool)
|
||||
|
||||
SimpleTextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
|
||||
ISurfaceAllocator *aAllocator);
|
||||
|
||||
~SimpleTextureClientPool()
|
||||
{
|
||||
for (auto it = mOutstandingTextureClients.begin(); it != mOutstandingTextureClients.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> > mAvailableTextureClients;
|
||||
std::list<RefPtr<TextureClient> > mOutstandingTextureClients;
|
||||
|
||||
nsRefPtr<nsITimer> mTimer;
|
||||
RefPtr<ISurfaceAllocator> mSurfaceAllocator;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* MOZILLA_GFX_SIMPLETEXTURECLIENTPOOL_H */
|
|
@ -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 "Units.h" // for ScreenIntRect, CSSPoint, etc
|
||||
#include "UnitTransforms.h" // for TransformTo
|
||||
#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();
|
||||
|
||||
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
|
||||
ApplyParentLayerToLayoutTransform(const gfx3DMatrix& aTransform, const ParentLayerRect& aParentLayerRect)
|
||||
{
|
||||
return TransformTo<LayoutDevicePixel>(aTransform, aParentLayerRect);
|
||||
}
|
||||
|
||||
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 layoutToParentLayer;
|
||||
gfx::To3DMatrix(effectiveTransform, layoutToParentLayer);
|
||||
layoutToParentLayer.ScalePost(metrics.GetParentResolution().scale,
|
||||
metrics.GetParentResolution().scale,
|
||||
1.f);
|
||||
|
||||
mPaintData.mTransformParentLayerToLayout = layoutToParentLayer.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 ParentLayerRect& criticalDisplayPort = metrics.mCriticalDisplayPort
|
||||
* metrics.mDevPixelsPerCSSPixel
|
||||
* metrics.GetParentResolution();
|
||||
LayoutDeviceRect transformedCriticalDisplayPort =
|
||||
ApplyParentLayerToLayoutTransform(mPaintData.mTransformParentLayerToLayout, 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 =
|
||||
ApplyParentLayerToLayoutTransform(mPaintData.mTransformParentLayerToLayout,
|
||||
ParentLayerRect(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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -278,6 +278,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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -275,7 +275,6 @@ class TextureHost
|
|||
void Finalize();
|
||||
|
||||
friend class AtomicRefCountedWithFinalize<TextureHost>;
|
||||
|
||||
public:
|
||||
TextureHost(TextureFlags aFlags);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -25,8 +25,12 @@ sync protocol PTexture {
|
|||
child:
|
||||
async __delete__();
|
||||
|
||||
async CompositorRecycle();
|
||||
|
||||
parent:
|
||||
|
||||
async ClientRecycle();
|
||||
|
||||
/**
|
||||
* Asynchronously tell the Compositor side to remove the texture.
|
||||
*/
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче