--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -2281,17 +2281,18 @@ DrawTargetCairo::GetUserSpaceClip()
return Rect(clipX1, clipY1, clipX2 - clipX1, clipY2 - clipY1); // Narrowing of doubles to floats
}
cairo_t*
BorrowedCairoContext::BorrowCairoContextFromDrawTarget(DrawTarget* aDT)
{
if (aDT->GetBackendType() != BackendType::CAIRO ||
aDT->IsDualDrawTarget() ||
- aDT->IsTiledDrawTarget()) {
+ aDT->IsTiledDrawTarget() ||
+ aDT->IsCaptureDT()) {
return nullptr;
}
DrawTargetCairo* cairoDT = static_cast<DrawTargetCairo*>(aDT);
cairoDT->WillChange();
// save the state to make it easier for callers to avoid mucking with things
cairo_save(cairoDT->mContext);
--- a/gfx/2d/FilterNodeD2D1.cpp
+++ b/gfx/2d/FilterNodeD2D1.cpp
@@ -145,17 +145,17 @@ D2D1_CHANNEL_SELECTOR D2DChannelSelector
}
MOZ_CRASH("GFX: Unknown enum value D2DChannelSelector!");
return D2D1_CHANNEL_SELECTOR_R;
}
already_AddRefed<ID2D1Image> GetImageForSourceSurface(DrawTarget *aDT, SourceSurface *aSurface)
{
- if (aDT->IsTiledDrawTarget() || aDT->IsDualDrawTarget()) {
+ if (aDT->IsTiledDrawTarget() || aDT->IsDualDrawTarget() || aDT->IsCaptureDT()) {
gfxDevCrash(LogReason::FilterNodeD2D1Target) << "Incompatible draw target type! " << (int)aDT->IsTiledDrawTarget() << " " << (int)aDT->IsDualDrawTarget();
return nullptr;
}
switch (aDT->GetBackendType()) {
case BackendType::DIRECT2D1_1:
return static_cast<DrawTargetD2D1*>(aDT)->GetImageForSurface(aSurface, ExtendMode::CLAMP);
default:
gfxDevCrash(LogReason::FilterNodeD2D1Backend) << "Unknown draw target type! " << (int)aDT->GetBackendType();
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -336,16 +336,74 @@ PaintThread::AsyncPaintContents(Composit
// This should ensure the capture drawtarget, which may hold on to UnscaledFont objects,
// gets destroyed on the main thread (See bug 1404742). This assumes (unflushed) target
// DrawTargets do not themselves hold on to UnscaledFonts.
NS_ReleaseOnMainThreadSystemGroup("CapturePaintState::DrawTargetCapture", aState->mCapture.forget());
}
}
void
+PaintThread::PaintTiledContents(CapturedTiledPaintState* aState)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(aState);
+
+ RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
+ RefPtr<CapturedTiledPaintState> state(aState);
+
+ cbc->NotifyBeginAsyncTiledPaint(state);
+
+ RefPtr<PaintThread> self = this;
+ RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PaintTiledContents",
+ [self, cbc, state]() -> void
+ {
+ self->AsyncPaintTiledContents(cbc,
+ state);
+ });
+
+#ifndef OMTP_FORCE_SYNC
+ sThread->Dispatch(task.forget());
+#else
+ SyncRunnable::DispatchToThread(sThread, task);
+#endif
+}
+
+void
+PaintThread::AsyncPaintTiledContents(CompositorBridgeChild* aBridge,
+ CapturedTiledPaintState* aState)
+{
+ MOZ_ASSERT(IsOnPaintThread());
+ MOZ_ASSERT(aState);
+
+ if (!mInAsyncPaintGroup) {
+ mInAsyncPaintGroup = true;
+ PROFILER_TRACING("Paint", "Rasterize", TRACING_INTERVAL_START);
+ }
+
+ DrawTarget* target = aState->mTargetTiled;
+ DrawTargetCapture* capture = aState->mCapture;
+
+ // Draw all the things into the actual dest target.
+ target->DrawCapturedDT(capture, Matrix());
+
+ if (!mDrawTargetsToFlush.Contains(target)) {
+ mDrawTargetsToFlush.AppendElement(target);
+ }
+
+ if (gfxPrefs::LayersOMTPReleaseCaptureOnMainThread()) {
+ // This should ensure the capture drawtarget, which may hold on to UnscaledFont objects,
+ // gets destroyed on the main thread (See bug 1404742). This assumes (unflushed) target
+ // DrawTargets do not themselves hold on to UnscaledFonts.
+ NS_ReleaseOnMainThreadSystemGroup("CapturePaintState::DrawTargetCapture", aState->mCapture.forget());
+ }
+
+ aBridge->NotifyFinishedAsyncTiledPaint(aState);
+}
+
+void
PaintThread::EndLayer()
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncEndLayer",
[self]() -> void
{
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -107,16 +107,35 @@ public:
Maybe<Copy> mBufferInitialize;
protected:
~CapturedBufferState() {}
};
typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState* aPaintState);
+// Holds the key operations needed to update a tiled content client on the
+// paint thread.
+class CapturedTiledPaintState {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CapturedPaintState)
+public:
+ CapturedTiledPaintState(gfx::DrawTarget* aTargetTiled,
+ gfx::DrawTargetCapture* aCapture)
+ : mTargetTiled(aTargetTiled)
+ , mCapture(aCapture)
+ {}
+
+ RefPtr<gfx::DrawTarget> mTargetTiled;
+ RefPtr<gfx::DrawTargetCapture> mCapture;
+ std::vector<RefPtr<TextureClient>> mClients;
+
+protected:
+ virtual ~CapturedTiledPaintState() {}
+};
+
class CompositorBridgeChild;
class PaintThread final
{
friend void DestroyPaintThread(UniquePtr<PaintThread>&& aPaintThread);
public:
static void Start();
@@ -132,16 +151,18 @@ public:
// or running while this is executing.
void BeginLayerTransaction();
void PrepareBuffer(CapturedBufferState* aState);
void PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);
+ void PaintTiledContents(CapturedTiledPaintState* aState);
+
// Must be called on the main thread. Signifies that the current
// batch of CapturedPaintStates* for PaintContents have been recorded
// and the main thread is finished recording this layer.
void EndLayer();
// This allows external users to run code on the paint thread.
void Dispatch(RefPtr<Runnable>& aRunnable);
@@ -167,16 +188,18 @@ private:
void ShutdownOnPaintThread();
void InitOnPaintThread();
void AsyncPrepareBuffer(CompositorBridgeChild* aBridge,
CapturedBufferState* aState);
void AsyncPaintContents(CompositorBridgeChild* aBridge,
CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);
+ void AsyncPaintTiledContents(CompositorBridgeChild* aBridge,
+ CapturedTiledPaintState* aState);
void AsyncEndLayer();
void AsyncEndLayerTransaction(CompositorBridgeChild* aBridge,
SyncObjectClient* aSyncObject);
static StaticAutoPtr<PaintThread> sSingleton;
static StaticRefPtr<nsIThread> sThread;
static PlatformThreadId sThreadId;
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -14,16 +14,17 @@
#include "gfxRect.h" // for gfxRect
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/Rect.h" // for Rect, RectTyped
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
#include "mozilla/layers/LayersMessages.h"
+#include "mozilla/layers/PaintThread.h"
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "LayersLogging.h"
#include "mozilla/layers/SingleTiledContentClient.h"
namespace mozilla {
namespace layers {
@@ -339,19 +340,23 @@ ClientTiledPaintedLayer::RenderHighPreci
if (mPaintData.mCriticalDisplayPort) {
validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
}
SetValidRegion(validRegion);
TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this, Stringify(aInvalidRegion).c_str());
TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this, Stringify(GetValidRegion()).c_str());
+ TilePaintFlags flags = PaintThread::Get()
+ ? TilePaintFlags::Async
+ : TilePaintFlags::None;
+
mContentClient->GetTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
mContentClient->GetTiledBuffer()->PaintThebes(GetValidRegion(), aInvalidRegion, aInvalidRegion,
- aCallback, aCallbackData);
+ aCallback, aCallbackData, flags);
mPaintData.mPaintFinished = true;
return true;
}
bool
ClientTiledPaintedLayer::RenderLowPrecision(const nsIntRegion& aInvalidRegion,
const nsIntRegion& aVisibleRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -100,19 +100,19 @@ ClientSingleTiledLayerBuffer::GetTexture
}
void
ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData,
- bool aIsProgressive)
+ TilePaintFlags aFlags)
{
- mWasLastPaintProgressive = aIsProgressive;
+ mWasLastPaintProgressive = !!(aFlags & TilePaintFlags::Progressive);
// Compare layer valid region size to current backbuffer size, discard if not matching.
gfx::IntSize size = aNewValidRegion.GetBounds().Size();
gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft();
nsIntRegion paintRegion = aPaintRegion;
RefPtr<TextureClient> discardedFrontBuffer = nullptr;
RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr;
@@ -145,16 +145,17 @@ ClientSingleTiledLayerBuffer::PaintThebe
nsIntRegion extraPainted;
RefPtr<TextureClient> backBufferOnWhite;
RefPtr<TextureClient> backBuffer =
mTile.GetBackBuffer(mCompositableClient,
tileDirtyRegion,
content, mode,
extraPainted,
+ TilePaintFlags::None,
&backBufferOnWhite);
// Mark the area we need to paint in the back buffer as invalid in the
// front buffer as they will become out of sync.
mTile.mInvalidFront.OrWith(tileDirtyRegion);
// Add backbuffer's invalid region to the dirty region to be painted.
// This will be empty if we were able to copy from the front in to the back.
--- a/gfx/layers/client/SingleTiledContentClient.h
+++ b/gfx/layers/client/SingleTiledContentClient.h
@@ -38,17 +38,17 @@ public:
void ReportClientLost() override {}
// ClientTiledLayerBuffer
void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData,
- bool aIsProgressive = false) override;
+ TilePaintFlags aFlags = TilePaintFlags::None) override;
bool SupportsProgressiveUpdate() override { return false; }
bool ProgressiveUpdate(const nsIntRegion& aValidRegion,
const nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion,
nsIntRegion& aOutDrawnRegion,
BasicTiledLayerPaintData* aPaintData,
LayerManager::DrawPaintedLayerCallback aCallback,
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -17,16 +17,17 @@
#include "mozilla/MathAlgorithms.h" // for Abs
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/gfx/Tools.h" // for BytesPerPixel
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
#include "mozilla/layers/LayerMetricsWrapper.h"
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
+#include "mozilla/layers/PaintThread.h" // for PaintThread
#include "TextureClientPool.h"
#include "nsDebug.h" // for NS_ASSERTION
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
#include "nsExpirationTracker.h" // for nsExpirationTracker
#include "nsMathUtils.h" // for NS_lroundf
#include "LayersLogging.h"
#include "UnitTransforms.h" // for TransformTo
#include "mozilla/UniquePtr.h"
@@ -471,36 +472,42 @@ TileClient::Flip()
nsIntRegion invalidFront = mInvalidFront;
mInvalidFront = mInvalidBack;
mInvalidBack = invalidFront;
}
static bool
CopyFrontToBack(TextureClient* aFront,
TextureClient* aBack,
- const gfx::IntRect& aRectToCopy)
+ const gfx::IntRect& aRectToCopy,
+ TilePaintFlags aFlags)
{
+ bool asyncPaint = !!(aFlags & TilePaintFlags::Async);
+ OpenMode lockMode = asyncPaint ? OpenMode::OPEN_READ_ASYNC_WRITE
+ : OpenMode::OPEN_READ_WRITE;
+
TextureClientAutoLock frontLock(aFront, OpenMode::OPEN_READ);
if (!frontLock.Succeeded()) {
return false;
}
- if (!aBack->Lock(OpenMode::OPEN_READ_WRITE)) {
+ if (!aBack->Lock(lockMode)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock the tile's back buffer";
return false;
}
gfx::IntPoint rectToCopyTopLeft = aRectToCopy.TopLeft();
aFront->CopyToTextureClient(aBack, &aRectToCopy, &rectToCopyTopLeft);
return true;
}
void
TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
- nsIntRegion& aAddPaintedRegion)
+ nsIntRegion& aAddPaintedRegion,
+ TilePaintFlags aFlags)
{
if (mBackBuffer && mFrontBuffer) {
gfx::IntSize tileSize = mFrontBuffer->GetSize();
const IntRect tileRect = IntRect(0, 0, tileSize.width, tileSize.height);
if (aDirtyRegion.Contains(tileRect)) {
// The dirty region means that we no longer need the front buffer, so
// discard it.
@@ -518,20 +525,20 @@ TileClient::ValidateBackBufferFromFront(
return;
}
// Copy the bounding rect of regionToCopy. As tiles are quite small, it
// is unlikely that we'd save much by copying each individual rect of the
// region, but we can reevaluate this if it becomes an issue.
const IntRect rectToCopy = regionToCopy.GetBounds();
gfx::IntRect gfxRectToCopy(rectToCopy.x, rectToCopy.y, rectToCopy.Width(), rectToCopy.Height());
- if (CopyFrontToBack(mFrontBuffer, mBackBuffer, gfxRectToCopy)) {
+ if (CopyFrontToBack(mFrontBuffer, mBackBuffer, gfxRectToCopy, aFlags)) {
if (mBackBufferOnWhite) {
MOZ_ASSERT(mFrontBufferOnWhite);
- if (CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, gfxRectToCopy)) {
+ if (CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, gfxRectToCopy, aFlags)) {
mInvalidBack.SetEmpty();
}
}
}
}
}
}
@@ -621,16 +628,17 @@ CreateBackBufferTexture(TextureClient* a
}
TextureClient*
TileClient::GetBackBuffer(CompositableClient& aCompositable,
const nsIntRegion& aDirtyRegion,
gfxContentType aContent,
SurfaceMode aMode,
nsIntRegion& aAddPaintedRegion,
+ TilePaintFlags aFlags,
RefPtr<TextureClient>* aBackBufferOnWhite)
{
if (!mAllocator) {
gfxCriticalError() << "[TileClient] Missing TextureClientAllocator.";
return nullptr;
}
if (aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA) {
// It can happen that a component-alpha layer stops being on component alpha
@@ -676,30 +684,33 @@ TileClient::GetBackBuffer(CompositableCl
if (!mBackBufferOnWhite) {
DiscardBackBuffer();
DiscardFrontBuffer();
return nullptr;
}
mInvalidBack = IntRect(IntPoint(), mBackBufferOnWhite->GetSize());
}
- ValidateBackBufferFromFront(aDirtyRegion, aAddPaintedRegion);
+ ValidateBackBufferFromFront(aDirtyRegion, aAddPaintedRegion, aFlags);
}
+ OpenMode lockMode = aFlags & TilePaintFlags::Async ? OpenMode::OPEN_READ_ASYNC_WRITE
+ : OpenMode::OPEN_READ_WRITE;
+
if (!mBackBuffer->IsLocked()) {
- if (!mBackBuffer->Lock(OpenMode::OPEN_READ_WRITE)) {
+ if (!mBackBuffer->Lock(lockMode)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (B)";
DiscardBackBuffer();
DiscardFrontBuffer();
return nullptr;
}
}
if (mBackBufferOnWhite && !mBackBufferOnWhite->IsLocked()) {
- if (!mBackBufferOnWhite->Lock(OpenMode::OPEN_READ_WRITE)) {
+ if (!mBackBufferOnWhite->Lock(lockMode)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (W)";
DiscardBackBuffer();
DiscardFrontBuffer();
return nullptr;
}
}
*aBackBufferOnWhite = mBackBufferOnWhite;
@@ -761,24 +772,24 @@ ClientMultiTiledLayerBuffer::GetSurfaceD
}
void
ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData,
- bool aIsProgressive)
+ TilePaintFlags aFlags)
{
TILING_LOG("TILING %p: PaintThebes painting region %s\n", &mPaintedLayer, Stringify(aPaintRegion).c_str());
TILING_LOG("TILING %p: PaintThebes new valid region %s\n", &mPaintedLayer, Stringify(aNewValidRegion).c_str());
mCallback = aCallback;
mCallbackData = aCallbackData;
- mWasLastPaintProgressive = aIsProgressive;
+ mWasLastPaintProgressive = !!(aFlags & TilePaintFlags::Progressive);
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
long start = PR_IntervalNow();
#endif
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (PR_IntervalNow() - start > 30) {
const IntRect bounds = aPaintRegion.GetBounds();
@@ -793,17 +804,17 @@ ClientMultiTiledLayerBuffer::PaintThebes
}
}
start = PR_IntervalNow();
#endif
AUTO_PROFILER_LABEL("ClientMultiTiledLayerBuffer::PaintThebes", GRAPHICS);
mNewValidRegion = aNewValidRegion;
- Update(aNewValidRegion, aPaintRegion, aDirtyRegion);
+ Update(aNewValidRegion, aPaintRegion, aDirtyRegion, aFlags);
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (PR_IntervalNow() - start > 10) {
const IntRect bounds = aPaintRegion.GetBounds();
printf_stderr("Time to tile %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
}
#endif
@@ -909,17 +920,18 @@ ClientTiledLayerBuffer::UnlockTile(TileC
}
if (aTile.mBackBufferOnWhite && aTile.mBackBufferOnWhite->IsLocked()) {
aTile.mBackBufferOnWhite->Unlock();
}
}
void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
const nsIntRegion& aPaintRegion,
- const nsIntRegion& aDirtyRegion)
+ const nsIntRegion& aDirtyRegion,
+ TilePaintFlags aFlags)
{
const IntSize scaledTileSize = GetScaledTileSize();
const gfx::IntRect newBounds = newValidRegion.GetBounds();
const TilesPlacement oldTiles = mTiles;
const TilesPlacement newTiles(floor_div(newBounds.x, scaledTileSize.width),
floor_div(newBounds.y, scaledTileSize.height),
floor_div(GetTileStart(newBounds.x, scaledTileSize.width)
@@ -960,48 +972,79 @@ void ClientMultiTiledLayerBuffer::Update
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
tileDrawRegion.AndWith(paintRegion);
if (tileDrawRegion.IsEmpty()) {
continue;
}
TileClient& tile = mRetainedTiles[i];
- if (!ValidateTile(tile, GetTileOffset(tilePosition), tileDrawRegion)) {
+ if (!ValidateTile(tile, GetTileOffset(tilePosition), tileDrawRegion, aFlags)) {
gfxCriticalError() << "ValidateTile failed";
}
// Validating the tile may have required more to be painted.
paintRegion.OrWith(tileDrawRegion);
dirtyRegion.OrWith(tileDrawRegion);
}
- if (!mMoz2DTiles.empty()) {
+ if (!mPaintTiles.empty()) {
+ // Create a tiled draw target
gfx::TileSet tileset;
- for (size_t i = 0; i < mMoz2DTiles.size(); ++i) {
- mMoz2DTiles[i].mTileOrigin -= mTilingOrigin;
+ for (size_t i = 0; i < mPaintTiles.size(); ++i) {
+ mPaintTiles[i].mTileOrigin -= mTilingOrigin;
}
- tileset.mTiles = &mMoz2DTiles[0];
- tileset.mTileCount = mMoz2DTiles.size();
+ tileset.mTiles = &mPaintTiles[0];
+ tileset.mTileCount = mPaintTiles.size();
RefPtr<DrawTarget> drawTarget = gfx::Factory::CreateTiledDrawTarget(tileset);
if (!drawTarget || !drawTarget->IsValid()) {
gfxDevCrash(LogReason::InvalidContext) << "Invalid tiled draw target";
return;
}
drawTarget->SetTransform(Matrix());
- RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(drawTarget);
- MOZ_ASSERT(ctx); // already checked the draw target above
- ctx->SetMatrix(
- ctx->CurrentMatrix().PreScale(mResolution, mResolution).PreTranslate(-mTilingOrigin));
+ if (aFlags & TilePaintFlags::Async) {
+ // Create a capture draw target
+ RefPtr<DrawTargetCapture> captureDT =
+ Factory::CreateCaptureDrawTarget(drawTarget->GetBackendType(),
+ drawTarget->GetSize(),
+ drawTarget->GetFormat());
+
+ // Draw into the capture target
+ RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(captureDT);
+ MOZ_ASSERT(ctx); // already checked the draw target above
+ ctx->SetMatrix(
+ ctx->CurrentMatrix().PreScale(mResolution, mResolution).PreTranslate(-mTilingOrigin));
+
+ mCallback(&mPaintedLayer, ctx, paintRegion, dirtyRegion,
+ DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
+ ctx = nullptr;
- mCallback(&mPaintedLayer, ctx, paintRegion, dirtyRegion,
- DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
- mMoz2DTiles.clear();
- // Reset:
+ // Replay on the paint thread
+ RefPtr<CapturedTiledPaintState> capturedState =
+ new CapturedTiledPaintState(drawTarget,
+ captureDT);
+ capturedState->mClients = std::move(mPaintTilesTextureClients);
+
+ PaintThread::Get()->PaintTiledContents(capturedState);
+ mManager->SetQueuedAsyncPaints();
+ } else {
+ // Draw into the tiled draw target
+ RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(drawTarget);
+ MOZ_ASSERT(ctx); // already checked the draw target above
+ ctx->SetMatrix(
+ ctx->CurrentMatrix().PreScale(mResolution, mResolution).PreTranslate(-mTilingOrigin));
+
+ mCallback(&mPaintedLayer, ctx, paintRegion, dirtyRegion,
+ DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
+ }
+
+ // Reset
+ mPaintTiles.clear();
+ mPaintTilesTextureClients.clear();
mTilingOrigin = IntPoint(std::numeric_limits<int32_t>::max(),
std::numeric_limits<int32_t>::max());
}
bool edgePaddingEnabled = gfxPrefs::TileEdgePaddingEnabled();
for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
TileClient& tile = mRetainedTiles[i];
@@ -1041,17 +1084,18 @@ void ClientMultiTiledLayerBuffer::Update
mTiles = newTiles;
mValidRegion = newValidRegion;
mPaintedRegion.OrWith(paintRegion);
}
bool
ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
const nsIntPoint& aTileOrigin,
- nsIntRegion& aDirtyRegion)
+ nsIntRegion& aDirtyRegion,
+ TilePaintFlags aFlags)
{
AUTO_PROFILER_LABEL("ClientMultiTiledLayerBuffer::ValidateTile", GRAPHICS);
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (aDirtyRegion.IsComplex()) {
printf_stderr("Complex region\n");
}
#endif
@@ -1072,16 +1116,17 @@ ClientMultiTiledLayerBuffer::ValidateTil
nsIntRegion extraPainted;
RefPtr<TextureClient> backBufferOnWhite;
RefPtr<TextureClient> backBuffer =
aTile.GetBackBuffer(mCompositableClient,
offsetScaledDirtyRegion,
content, mode,
extraPainted,
+ aFlags,
&backBufferOnWhite);
// Mark the area we need to paint in the back buffer as invalid in the
// front buffer as they will become out of sync.
aTile.mInvalidFront.OrWith(offsetScaledDirtyRegion);
// Add backbuffer's invalid region to the dirty region to be painted.
// This will be empty if we were able to copy from the front in to the back.
@@ -1097,34 +1142,41 @@ ClientMultiTiledLayerBuffer::ValidateTil
extraPainted.MoveBy(aTileOrigin);
extraPainted.And(extraPainted, mNewValidRegion);
mPaintedRegion.Or(mPaintedRegion, extraPainted);
if (!backBuffer) {
return false;
}
- gfx::Tile moz2DTile;
+ gfx::Tile paintTile;
RefPtr<DrawTarget> dt = backBuffer->BorrowDrawTarget();
RefPtr<DrawTarget> dtOnWhite;
if (backBufferOnWhite) {
dtOnWhite = backBufferOnWhite->BorrowDrawTarget();
- moz2DTile.mDrawTarget = Factory::CreateDualDrawTarget(dt, dtOnWhite);
+ paintTile.mDrawTarget = Factory::CreateDualDrawTarget(dt, dtOnWhite);
} else {
- moz2DTile.mDrawTarget = dt;
+ paintTile.mDrawTarget = dt;
}
- moz2DTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
+ paintTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
if (!dt || (backBufferOnWhite && !dtOnWhite)) {
aTile.DiscardBuffers();
return false;
}
- mMoz2DTiles.push_back(moz2DTile);
- mTilingOrigin.x = std::min(mTilingOrigin.x, moz2DTile.mTileOrigin.x);
- mTilingOrigin.y = std::min(mTilingOrigin.y, moz2DTile.mTileOrigin.y);
+ mPaintTiles.push_back(paintTile);
+ mTilingOrigin.x = std::min(mTilingOrigin.x, paintTile.mTileOrigin.x);
+ mTilingOrigin.y = std::min(mTilingOrigin.y, paintTile.mTileOrigin.y);
+
+ if (aFlags & TilePaintFlags::Async) {
+ mPaintTilesTextureClients.push_back(backBuffer);
+ if (backBufferOnWhite) {
+ mPaintTilesTextureClients.push_back(backBufferOnWhite);
+ }
+ }
for (auto iter = offsetScaledDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::Rect drawRect(iter.Get().x, iter.Get().y,
iter.Get().width, iter.Get().height);
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
dt->FillRect(drawRect, ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
dtOnWhite->FillRect(drawRect, ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
@@ -1389,17 +1441,17 @@ ClientMultiTiledLayerBuffer::Progressive
// aValidRegion may have been altered by InvalidateRegion, but we still
// want to display stale content until it gets progressively updated.
// Create a region that includes stale content.
nsIntRegion validOrStale;
validOrStale.Or(updatedValidRegion, aOldValidRegion);
// Paint the computed region and subtract it from the invalid region.
PaintThebes(validOrStale, regionToPaint, remainingInvalidRegion,
- aCallback, aCallbackData, true);
+ aCallback, aCallbackData, TilePaintFlags::Progressive);
remainingInvalidRegion.SubOut(regionToPaint);
} while (repeat);
TILING_LOG("TILING %p: Progressive update final valid region %s buffer changed %d\n", &mPaintedLayer, Stringify(updatedValidRegion).c_str(), isBufferChanged);
TILING_LOG("TILING %p: Progressive update final invalid region %s\n", &mPaintedLayer, Stringify(remainingInvalidRegion).c_str());
// Return false if nothing has been drawn, or give what has been drawn
// to the shadow layer to upload.
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -37,16 +37,23 @@
#include "mozilla/layers/ISurfaceAllocator.h"
namespace mozilla {
namespace layers {
class ClientTiledPaintedLayer;
class ClientLayerManager;
+enum class TilePaintFlags : uint8_t {
+ None = 0x0,
+ Async = 0x1,
+ Progressive = 0x2,
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TilePaintFlags)
+
/**
* Represent a single tile in tiled buffer. The buffer keeps tiles,
* each tile keeps a reference to a texture client and a read-lock. This
* read-lock is used to help implement a copy-on-write mechanism. The tile
* should be locked before being sent to the compositor. The compositor should
* unlock the read-lock as soon as it has finished with the buffer in the
* TextureHost to prevent more textures being created than is necessary.
* Ideal place to store per tile debug information.
@@ -117,16 +124,17 @@ struct TileClient
* knows to upload it.
*
* If nullptr is returned, aTextureClientOnWhite is undefined.
*/
TextureClient* GetBackBuffer(CompositableClient&,
const nsIntRegion& aDirtyRegion,
gfxContentType aContent, SurfaceMode aMode,
nsIntRegion& aAddPaintedRegion,
+ TilePaintFlags aFlags,
RefPtr<TextureClient>* aTextureClientOnWhite);
void DiscardFrontBuffer();
void DiscardBackBuffer();
/* We wrap the back buffer in a class that disallows assignment
* so that we can track when ever it changes so that we can update
@@ -154,17 +162,18 @@ struct TileClient
#endif
nsIntRegion mInvalidFront;
nsIntRegion mInvalidBack;
nsExpirationState mExpirationState;
private:
// Copies dirty pixels from the front buffer into the back buffer,
// and records the copied region in aAddPaintedRegion.
void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion,
- nsIntRegion& aAddPaintedRegion);
+ nsIntRegion& aAddPaintedRegion,
+ TilePaintFlags aFlags);
};
/**
* This struct stores all the data necessary to perform a paint so that it
* doesn't need to be recalculated on every repeated transaction.
*/
struct BasicTiledLayerPaintData {
/*
@@ -289,17 +298,17 @@ public:
, mWasLastPaintProgressive(false)
{}
virtual void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData,
- bool aIsProgressive = false) = 0;
+ TilePaintFlags aFlags) = 0;
virtual bool SupportsProgressiveUpdate() = 0;
virtual bool ProgressiveUpdate(const nsIntRegion& aValidRegion,
const nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion,
nsIntRegion& aOutDrawnRegion,
BasicTiledLayerPaintData* aPaintData,
LayerManager::DrawPaintedLayerCallback aCallback,
@@ -345,17 +354,17 @@ public:
ClientLayerManager* aManager,
SharedFrameMetricsHelper* aHelper);
void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData,
- bool aIsProgressive = false) override;
+ TilePaintFlags aFlags = TilePaintFlags::None) override;
virtual bool SupportsProgressiveUpdate() override { return true; }
/**
* Performs a progressive update of a given tiled buffer.
* See ComputeProgressiveUpdateRegion below for parameter documentation.
* aOutDrawnRegion is an outparameter that contains the region that was
* drawn, and which can now be added to the layer's valid region.
*/
@@ -400,43 +409,49 @@ public:
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
void SetResolution(float aResolution) {
if (mResolution == aResolution) {
return;
}
- Update(nsIntRegion(), nsIntRegion(), nsIntRegion());
+ Update(nsIntRegion(), nsIntRegion(), nsIntRegion(), TilePaintFlags::None);
mResolution = aResolution;
}
protected:
bool ValidateTile(TileClient& aTile,
const nsIntPoint& aTileRect,
- nsIntRegion& aDirtyRegion);
+ nsIntRegion& aDirtyRegion,
+ TilePaintFlags aFlags);
void Update(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
- const nsIntRegion& aDirtyRegion);
+ const nsIntRegion& aDirtyRegion,
+ TilePaintFlags aFlags);
TileClient GetPlaceholderTile() const { return TileClient(); }
private:
RefPtr<ClientLayerManager> mManager;
LayerManager::DrawPaintedLayerCallback mCallback;
void* mCallbackData;
// The region that will be made valid during Update(). Once Update() is
// completed then this is identical to mValidRegion.
nsIntRegion mNewValidRegion;
SharedFrameMetricsHelper* mSharedFrameMetricsHelper;
- // When using Moz2D's CreateTiledDrawTarget we maintain a list of gfx::Tiles
- std::vector<gfx::Tile> mMoz2DTiles;
+
+ // Parameters that are collected during Update for a paint before they
+ // are either executed or replayed on the paint thread.
+ std::vector<gfx::Tile> mPaintTiles;
+ std::vector<RefPtr<TextureClient>> mPaintTilesTextureClients;
+
/**
* While we're adding tiles, this is used to keep track of the position of
* the top-left of the top-left-most tile. When we come to wrap the tiles in
* TiledDrawTarget we subtract the value of this member from each tile's
* offset so that all the tiles have a positive offset, then add a
* translation to the TiledDrawTarget to compensate. This is important so
* that the mRect of the TiledDrawTarget is always at a positive x/y
* position, otherwise its GetSize() methods will be broken.
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -1271,16 +1271,50 @@ CompositorBridgeChild::NotifyFinishedAsy
aState->mTextureClient = nullptr;
if (aState->mTextureClientOnWhite) {
aState->mTextureClientOnWhite->DropPaintThreadRef();
aState->mTextureClientOnWhite = nullptr;
}
}
void
+CompositorBridgeChild::NotifyBeginAsyncTiledPaint(CapturedTiledPaintState* aState)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ MonitorAutoLock lock(mPaintLock);
+
+ // We must not be waiting for paints to complete yet. This would imply we
+ // started a new paint without waiting for a previous one, which could lead to
+ // incorrect rendering or IPDL deadlocks.
+ MOZ_ASSERT(!mIsDelayingForAsyncPaints);
+
+ mOutstandingAsyncPaints++;
+
+ // Mark texture clients that they are being used for async painting, and
+ // make sure we hold them alive on the main thread.
+ for (auto& client : aState->mClients) {
+ mTextureClientsForAsyncPaint.AppendElement(client);
+ }
+ aState->mClients.clear();
+}
+
+void
+CompositorBridgeChild::NotifyFinishedAsyncTiledPaint(CapturedTiledPaintState* aState)
+{
+ MOZ_ASSERT(PaintThread::IsOnPaintThread());
+
+ MonitorAutoLock lock(mPaintLock);
+
+ mOutstandingAsyncPaints--;
+
+ aState->mTargetTiled = nullptr;
+}
+
+void
CompositorBridgeChild::NotifyBeginAsyncEndLayerTransaction()
{
MOZ_ASSERT(NS_IsMainThread());
MonitorAutoLock lock(mPaintLock);
MOZ_ASSERT(!mOutstandingAsyncEndTransaction);
mOutstandingAsyncEndTransaction = true;
}
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -42,16 +42,17 @@ class APZCTreeManagerChild;
class ClientLayerManager;
class CompositorBridgeParent;
class CompositorManagerChild;
class CompositorOptions;
class TextureClient;
class TextureClientPool;
class CapturedBufferState;
class CapturedPaintState;
+class CapturedTiledPaintState;
struct FrameMetrics;
class CompositorBridgeChild final : public PCompositorBridgeChild,
public TextureForwarder
{
typedef InfallibleTArray<AsyncParentMessageData> AsyncParentMessageArray;
public:
@@ -236,16 +237,24 @@ public:
// that the paint thread is going to begin painting asynchronously.
void NotifyBeginAsyncPaint(CapturedPaintState* aState);
// Must only be called from the paint thread. Notifies the CompositorBridge
// that the paint thread has finished an asynchronous paint request.
void NotifyFinishedAsyncPaint(CapturedPaintState* aState);
// Must only be called from the main thread. Notifies the CompositorBridge
+ // that the paint thread is going to begin painting asynchronously.
+ void NotifyBeginAsyncTiledPaint(CapturedTiledPaintState* aState);
+
+ // Must only be called from the paint thread. Notifies the CompositorBridge
+ // that the paint thread has finished an asynchronous paint request.
+ void NotifyFinishedAsyncTiledPaint(CapturedTiledPaintState* aState);
+
+ // Must only be called from the main thread. Notifies the CompositorBridge
// that the paint thread is going to perform texture synchronization at the
// end of async painting, and should postpone messages if needed until
// finished.
void NotifyBeginAsyncEndLayerTransaction();
// Must only be called from the paint thread. Notifies the CompositorBridge
// that the paint thread has finished all async paints and texture syncs from
// a given transaction and may resume sending messages.
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2597,18 +2597,18 @@ gfxPlatform::InitOMTPConfig()
if (mContentBackend == BackendType::CAIRO) {
omtp.ForceDisable(FeatureStatus::Broken, "OMTP is not supported when using cairo",
NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF"));
}
if (InSafeMode()) {
omtp.ForceDisable(FeatureStatus::Blocked, "OMTP blocked by safe-mode",
NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
- } else if (gfxPrefs::LayersTilesEnabled()) {
- omtp.ForceDisable(FeatureStatus::Blocked, "OMTP does not yet support tiling",
+ } else if (gfxPrefs::TileEdgePaddingEnabled()) {
+ omtp.ForceDisable(FeatureStatus::Blocked, "OMTP does not yet support tiling with edge padding",
NS_LITERAL_CSTRING("FEATURE_FAILURE_OMTP_TILING"));
}
if (omtp.IsEnabled()) {
gfxVars::SetUseOMTP(true);
reporter.SetSuccessful();
}
}
--- a/gfx/thebes/gfxQuartzNativeDrawing.cpp
+++ b/gfx/thebes/gfxQuartzNativeDrawing.cpp
@@ -19,17 +19,17 @@ gfxQuartzNativeDrawing::gfxQuartzNativeD
}
CGContextRef
gfxQuartzNativeDrawing::BeginNativeDrawing()
{
NS_ASSERTION(!mCGContext, "BeginNativeDrawing called when drawing already in progress");
DrawTarget *dt = mDrawTarget;
- if (dt->IsDualDrawTarget() || dt->IsTiledDrawTarget() ||
+ if (dt->IsDualDrawTarget() || dt->IsTiledDrawTarget() || dt->IsCaptureDT() ||
dt->GetBackendType() != BackendType::SKIA || dt->IsRecording()) {
// We need a DrawTarget that we can get a CGContextRef from:
Matrix transform = dt->GetTransform();
mNativeRect = transform.TransformBounds(mNativeRect);
mNativeRect.RoundOut();
if (mNativeRect.IsEmpty()) {
return nullptr;