Refactor NotifyBeginAsyncPaint logic to not be repeated (
bug 1422392, r=dvander)
MozReview-Commit-ID: B8BZCxYErjv
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -46,59 +46,16 @@ CapturedBufferState::Unrotate::UnrotateB
bool
CapturedBufferState::PrepareBuffer()
{
return (!mBufferFinalize || mBufferFinalize->CopyBuffer()) &&
(!mBufferUnrotate || mBufferUnrotate->UnrotateBuffer()) &&
(!mBufferInitialize || mBufferInitialize->CopyBuffer());
}
-void
-CapturedBufferState::GetTextureClients(nsTArray<RefPtr<TextureClient>>& aTextureClients)
-{
- if (mBufferFinalize) {
- if (TextureClient* source = mBufferFinalize->mSource->GetClient()) {
- aTextureClients.AppendElement(source);
- }
- if (TextureClient* sourceOnWhite = mBufferFinalize->mSource->GetClientOnWhite()) {
- aTextureClients.AppendElement(sourceOnWhite);
- }
- if (TextureClient* destination = mBufferFinalize->mDestination->GetClient()) {
- aTextureClients.AppendElement(destination);
- }
- if (TextureClient* destinationOnWhite = mBufferFinalize->mDestination->GetClientOnWhite()) {
- aTextureClients.AppendElement(destinationOnWhite);
- }
- }
-
- if (mBufferUnrotate) {
- if (TextureClient* client = mBufferUnrotate->mBuffer->GetClient()) {
- aTextureClients.AppendElement(client);
- }
- if (TextureClient* clientOnWhite = mBufferUnrotate->mBuffer->GetClientOnWhite()) {
- aTextureClients.AppendElement(clientOnWhite);
- }
- }
-
- if (mBufferInitialize) {
- if (TextureClient* source = mBufferInitialize->mSource->GetClient()) {
- aTextureClients.AppendElement(source);
- }
- if (TextureClient* sourceOnWhite = mBufferInitialize->mSource->GetClientOnWhite()) {
- aTextureClients.AppendElement(sourceOnWhite);
- }
- if (TextureClient* destination = mBufferInitialize->mDestination->GetClient()) {
- aTextureClients.AppendElement(destination);
- }
- if (TextureClient* destinationOnWhite = mBufferInitialize->mDestination->GetClientOnWhite()) {
- aTextureClients.AppendElement(destinationOnWhite);
- }
- }
-}
-
bool
CapturedTiledPaintState::Copy::CopyBuffer()
{
RefPtr<gfx::SourceSurface> source = mSource->Snapshot();
// This operation requires the destination draw target to be untranslated,
// but the destination will have a transform from being part of a tiled draw
// target. However in this case, CopySurface ignores transforms so we don't
@@ -278,17 +235,17 @@ PaintThread::PrepareBuffer(CapturedBuffe
MOZ_ASSERT(aState);
// If painting asynchronously, we need to acquire the compositor bridge which
// owns the underlying MessageChannel. Otherwise we leave it null and use
// synchronous dispatch.
RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
RefPtr<CapturedBufferState> state(aState);
- cbc->NotifyBeginAsyncPrepareBuffer(state);
+ cbc->NotifyBeginAsyncPaint(state);
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PrepareBuffer",
[self, cbc, state]() -> void
{
self->AsyncPrepareBuffer(cbc,
state);
});
@@ -311,17 +268,17 @@ PaintThread::AsyncPrepareBuffer(Composit
mInAsyncPaintGroup = true;
PROFILER_TRACING("Paint", "Rasterize", TRACING_INTERVAL_START);
}
if (!aState->PrepareBuffer()) {
gfxCriticalNote << "Failed to prepare buffers on the paint thread.";
}
- aBridge->NotifyFinishedAsyncPrepareBuffer(aState);
+ aBridge->NotifyFinishedAsyncPaint(aState);
}
void
PaintThread::PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aState);
@@ -387,17 +344,17 @@ void
PaintThread::PaintTiledContents(CapturedTiledPaintState* aState)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aState);
RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
RefPtr<CapturedTiledPaintState> state(aState);
- cbc->NotifyBeginAsyncTiledPaint(state);
+ cbc->NotifyBeginAsyncPaint(state);
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PaintTiledContents",
[self, cbc, state]() -> void
{
self->AsyncPaintTiledContents(cbc,
state);
});
@@ -441,17 +398,17 @@ PaintThread::AsyncPaintTiledContents(Com
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);
+ aBridge->NotifyFinishedAsyncPaint(aState);
}
void
PaintThread::EndLayer()
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<PaintThread> self = this;
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -39,16 +39,31 @@ public:
, mTargetDual(aTargetDual)
, mTarget(aTarget)
, mTargetOnWhite(aTargetOnWhite)
, mTargetTransform(aTargetTransform)
, mSurfaceMode(aSurfaceMode)
, mContentType(aContentType)
{}
+ template<typename F>
+ void ForEachTextureClient(F aClosure) const
+ {
+ aClosure(mTextureClient);
+ if (mTextureClientOnWhite) {
+ aClosure(mTextureClientOnWhite);
+ }
+ }
+
+ void DropTextureClients()
+ {
+ mTextureClient = nullptr;
+ mTextureClientOnWhite = nullptr;
+ }
+
nsIntRegion mRegionToDraw;
RefPtr<TextureClient> mTextureClient;
RefPtr<TextureClient> mTextureClientOnWhite;
RefPtr<gfx::DrawTargetCapture> mCapture;
RefPtr<gfx::DrawTarget> mTargetDual;
RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTarget> mTargetOnWhite;
gfx::Matrix mTargetTransform;
@@ -95,17 +110,66 @@ public:
/**
* Prepares the rotated buffers for painting by copying a previous frame
* into the buffer and/or unrotating the pixels and returns whether the
* operations were successful. If this fails a new buffer should be created
* for the frame.
*/
bool PrepareBuffer();
- void GetTextureClients(nsTArray<RefPtr<TextureClient>>& aTextureClients);
+
+ template<typename F>
+ void ForEachTextureClient(F aClosure) const
+ {
+ if (mBufferFinalize) {
+ if (TextureClient* source = mBufferFinalize->mSource->GetClient()) {
+ aClosure(source);
+ }
+ if (TextureClient* sourceOnWhite = mBufferFinalize->mSource->GetClientOnWhite()) {
+ aClosure(sourceOnWhite);
+ }
+ if (TextureClient* destination = mBufferFinalize->mDestination->GetClient()) {
+ aClosure(destination);
+ }
+ if (TextureClient* destinationOnWhite = mBufferFinalize->mDestination->GetClientOnWhite()) {
+ aClosure(destinationOnWhite);
+ }
+ }
+
+ if (mBufferUnrotate) {
+ if (TextureClient* client = mBufferUnrotate->mBuffer->GetClient()) {
+ aClosure(client);
+ }
+ if (TextureClient* clientOnWhite = mBufferUnrotate->mBuffer->GetClientOnWhite()) {
+ aClosure(clientOnWhite);
+ }
+ }
+
+ if (mBufferInitialize) {
+ if (TextureClient* source = mBufferInitialize->mSource->GetClient()) {
+ aClosure(source);
+ }
+ if (TextureClient* sourceOnWhite = mBufferInitialize->mSource->GetClientOnWhite()) {
+ aClosure(sourceOnWhite);
+ }
+ if (TextureClient* destination = mBufferInitialize->mDestination->GetClient()) {
+ aClosure(destination);
+ }
+ if (TextureClient* destinationOnWhite = mBufferInitialize->mDestination->GetClientOnWhite()) {
+ aClosure(destinationOnWhite);
+ }
+ }
+ }
+
+ void DropTextureClients()
+ {
+ mBufferFinalize = Nothing();
+ mBufferUnrotate = Nothing();
+ mBufferInitialize = Nothing();
+ }
Maybe<Copy> mBufferFinalize;
Maybe<Unrotate> mBufferUnrotate;
Maybe<Copy> mBufferInitialize;
protected:
~CapturedBufferState() {}
};
@@ -153,16 +217,29 @@ public:
};
CapturedTiledPaintState(gfx::DrawTarget* aTargetTiled,
gfx::DrawTargetCapture* aCapture)
: mTargetTiled(aTargetTiled)
, mCapture(aCapture)
{}
+ template<typename F>
+ void ForEachTextureClient(F aClosure) const
+ {
+ for (auto client : mClients) {
+ aClosure(client);
+ }
+ }
+
+ void DropTextureClients()
+ {
+ mClients.clear();
+ }
+
RefPtr<gfx::DrawTarget> mTargetTiled;
RefPtr<gfx::DrawTargetCapture> mCapture;
std::vector<Copy> mCopies;
std::vector<Clear> mClears;
std::vector<RefPtr<TextureClient>> mClients;
protected:
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -1188,133 +1188,16 @@ CompositorBridgeChild::FlushAsyncPaints(
double ratio = double(mSlowFlushCount) / double(mTotalFlushCount);
Telemetry::ScalarSet(Telemetry::ScalarID::GFX_OMTP_PAINT_WAIT_RATIO,
uint32_t(ratio * 100 * 100));
}
}
void
-CompositorBridgeChild::NotifyBeginAsyncPrepareBuffer(CapturedBufferState* aState)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- MonitorAutoLock lock(mPaintLock);
-
- // We must not be waiting for paints (or buffer copying) 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.
- aState->GetTextureClients(mTextureClientsForAsyncPaint);
-}
-
-void
-CompositorBridgeChild::NotifyFinishedAsyncPrepareBuffer(CapturedBufferState* aState)
-{
- MOZ_ASSERT(PaintThread::IsOnPaintThread());
-
- MonitorAutoLock lock(mPaintLock);
- mOutstandingAsyncPaints--;
-}
-
-void
-CompositorBridgeChild::NotifyBeginAsyncPaint(CapturedPaintState* 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.
- aState->mTextureClient->AddPaintThreadRef();
- mTextureClientsForAsyncPaint.AppendElement(aState->mTextureClient);
- if (aState->mTextureClientOnWhite) {
- aState->mTextureClientOnWhite->AddPaintThreadRef();
- mTextureClientsForAsyncPaint.AppendElement(aState->mTextureClientOnWhite);
- }
-}
-
-void
-CompositorBridgeChild::NotifyFinishedAsyncPaint(CapturedPaintState* aState)
-{
- MOZ_ASSERT(PaintThread::IsOnPaintThread());
-
- MonitorAutoLock lock(mPaintLock);
-
- mOutstandingAsyncPaints--;
-
- // These textures should be held alive on the main thread. The ref we
- // captured should not be the final ref.
- MOZ_RELEASE_ASSERT(!aState->mTextureClient->HasOneRef());
-
- // It's now safe to drop the paint thread ref we're holding, since we've
- // flushed writes to the underlying TextureData. Note that we keep the
- // main thread ref around until FlushAsyncPaints is called, lazily ensuring
- // the Release occurs on the main thread (versus a message in the event
- // loop).
- //
- // Note that we zap our ref immediately after. Otherwise, the main thread
- // could wake up when we drop the lock, and we could still be holding a ref
- // on the paint thread. If this causes TextureClient to destroy then it will
- // be destroyed on the wrong thread.
- aState->mTextureClient->DropPaintThreadRef();
- 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
@@ -9,16 +9,17 @@
#include "base/basictypes.h" // for DISALLOW_EVIL_CONSTRUCTORS
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
#include "mozilla/Attributes.h" // for override
#include "mozilla/Monitor.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/layers/PCompositorBridgeChild.h"
#include "mozilla/layers/TextureForwarder.h" // for TextureForwarder
+#include "mozilla/layers/PaintThread.h" // for PaintThread
#include "mozilla/webrender/WebRenderTypes.h"
#include "nsClassHashtable.h" // for nsClassHashtable
#include "nsRefPtrHashtable.h"
#include "nsCOMPtr.h" // for nsCOMPtr
#include "nsHashKeys.h" // for nsUint64HashKey
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
#include "nsWeakReference.h"
@@ -40,19 +41,16 @@ using mozilla::dom::TabChild;
class IAPZCTreeManager;
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:
@@ -221,38 +219,54 @@ public:
wr::PipelineId GetNextPipelineId();
// Must only be called from the main thread. Ensures that any paints from
// previous frames have been flushed. The main thread blocks until the
// operation completes.
void FlushAsyncPaints();
// Must only be called from the main thread. Notifies the CompositorBridge
- // that the paint thread is going to begin preparing a buffer asynchronously.
- void NotifyBeginAsyncPrepareBuffer(CapturedBufferState* aState);
+ // that the paint thread is going to begin painting asynchronously.
+ template<typename CapturedState>
+ void NotifyBeginAsyncPaint(CapturedState& aState)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ MonitorAutoLock lock(mPaintLock);
- // Must only be called from the paint thread. Notifies the CompositorBridge
- // that the paint thread has finished an asynchronous buffer prepare.
- void NotifyFinishedAsyncPrepareBuffer(CapturedBufferState* aState);
+ // We must not be waiting for paints or buffer copying 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++;
- // Must only be called from the main thread. Notifies the CompositorBridge
- // that the paint thread is going to begin painting asynchronously.
- void NotifyBeginAsyncPaint(CapturedPaintState* aState);
+ // Mark texture clients that they are being used for async painting, and
+ // make sure we hold them alive on the main thread.
+ aState->ForEachTextureClient([this] (auto aClient) {
+ aClient->AddPaintThreadRef();
+ mTextureClientsForAsyncPaint.AppendElement(aClient);
+ });
+ }
// 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);
+ template<typename CapturedState>
+ void NotifyFinishedAsyncPaint(CapturedState& aState)
+ {
+ MOZ_ASSERT(PaintThread::IsOnPaintThread());
- // 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);
+ MonitorAutoLock lock(mPaintLock);
+ mOutstandingAsyncPaints--;
- // 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);
+ aState->ForEachTextureClient([this] (auto aClient) {
+ aClient->DropPaintThreadRef();
+ });
+ aState->DropTextureClients();
+ }
// 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