Create a PaintWorker thread pool and dispatch tiles to it (
bug 1425056, r=bas)
This commit adds a paint worker thread pool to PaintThread, and dispatches
tiled paints to it. The thread pool is only created if tiling is enabled,
and its size is set by 'layers.omtp.paint-workers' and defaults to 1. If
-1 is specified, it will be sized to 'max((cpu_cores * 3) / 4, 1)'.
The one tricky part of dispatching tiled paints to a thread pool is the
AsyncEndLayerTransaction message that must execute once all paints are
finished. Previously, this runnable would be queued after all the paints
had been queued, ensuring it would be run after they had all completed.
With a thread pool, there is no guarantee. Instead this commit, uses
a flag on CompositorBridgeChild to signify whether all of the paints
have been queued ('mOutstandingAsyncEndLayerTransaction'), and after
every tiled paint it is examined to see if that paint was the last
paint, and if it is to run AsyncEndLayerTransaction. In addition,
if the async paints complete before we even mark the end of the
layer transaction, we queue it like normal.
The profiler markers are also complicated by using a thread pool.
I don't know of a great way to keep them working as they are per
thread, so for now I've removed them. I may have been the only
one using them anyway.
MozReview-Commit-ID: 5LIJ9GWSfCn
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -1,25 +1,32 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "PaintThread.h"
+#include <algorithm>
+
#include "base/task.h"
+#include "gfxPlatform.h"
#include "gfxPrefs.h"
#include "GeckoProfiler.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/ShadowLayers.h"
#include "mozilla/layers/SyncObject.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Preferences.h"
+#include "mozilla/SharedThreadPool.h"
#include "mozilla/SyncRunnable.h"
+#include "nsIPropertyBag2.h"
+#include "nsServiceManagerUtils.h"
+#include "nsSystemInfo.h"
// Uncomment the following line to dispatch sync runnables when
// painting so that rasterization happens synchronously from
// the perspective of the main thread
// #define OMTP_FORCE_SYNC
namespace mozilla {
namespace layers {
@@ -93,60 +100,57 @@ CapturedTiledPaintState::Clear::ClearBuf
mTarget->SetTransform(oldTransform);
}
StaticAutoPtr<PaintThread> PaintThread::sSingleton;
StaticRefPtr<nsIThread> PaintThread::sThread;
PlatformThreadId PaintThread::sThreadId;
-// RAII make sure we clean up and restore our draw targets
-// when we paint async.
-struct MOZ_STACK_CLASS AutoCapturedPaintSetup
-{
- AutoCapturedPaintSetup(CapturedPaintState* aState, CompositorBridgeChild* aBridge)
- : mState(aState)
- , mTarget(aState->mTargetDual)
- , mRestorePermitsSubpixelAA(mTarget->GetPermitSubpixelAA())
- , mOldTransform(mTarget->GetTransform())
- , mBridge(aBridge)
- {
- mTarget->SetTransform(aState->mCapture->GetTransform());
- mTarget->SetPermitSubpixelAA(aState->mCapture->GetPermitSubpixelAA());
- }
-
- ~AutoCapturedPaintSetup()
- {
- mTarget->SetTransform(mOldTransform);
- mTarget->SetPermitSubpixelAA(mRestorePermitsSubpixelAA);
- mBridge->NotifyFinishedAsyncPaint(mState);
- }
-
- RefPtr<CapturedPaintState> mState;
- RefPtr<DrawTarget> mTarget;
- bool mRestorePermitsSubpixelAA;
- Matrix mOldTransform;
- RefPtr<CompositorBridgeChild> mBridge;
-};
-
PaintThread::PaintThread()
- : mInAsyncPaintGroup(false)
{
}
void
PaintThread::Release()
{
}
void
PaintThread::AddRef()
{
}
+/* static */ int32_t
+PaintThread::CalculatePaintWorkerCount()
+{
+ int32_t cpuCores = 1;
+ nsCOMPtr<nsIPropertyBag2> systemInfo = do_GetService(NS_SYSTEMINFO_CONTRACTID);
+ if (systemInfo) {
+ nsresult rv = systemInfo->GetPropertyAsInt32(NS_LITERAL_STRING("cpucores"), &cpuCores);
+ if (NS_FAILED(rv)) {
+ cpuCores = 1;
+ }
+ }
+
+ int32_t workerCount = gfxPrefs::LayersOMTPPaintWorkers();
+
+ // If not manually specified, default to (cpuCores * 3) / 4
+ if (workerCount < 1) {
+ workerCount = std::max((cpuCores * 3) / 4, 1);
+ }
+
+ // Sanity check
+ if (workerCount > 32) {
+ workerCount = 32;
+ }
+
+ return workerCount;
+}
+
/* static */ void
PaintThread::Start()
{
PaintThread::sSingleton = new PaintThread();
if (!PaintThread::sSingleton->Init()) {
gfxCriticalNote << "Unable to start paint thread";
PaintThread::sSingleton = nullptr;
@@ -160,16 +164,21 @@ PaintThread::Init()
RefPtr<nsIThread> thread;
nsresult rv = NS_NewNamedThread("PaintThread", getter_AddRefs(thread));
if (NS_FAILED(rv)) {
return false;
}
sThread = thread;
+ if (gfxPlatform::UsesTiling()) {
+ int32_t paintWorkerCount = PaintThread::CalculatePaintWorkerCount();
+ mPaintWorkers = SharedThreadPool::Get(NS_LITERAL_CSTRING("PaintWorker"), paintWorkerCount);
+ }
+
nsCOMPtr<nsIRunnable> paintInitTask =
NewRunnableMethod("PaintThread::InitOnPaintThread",
this, &PaintThread::InitOnPaintThread);
SyncRunnable::DispatchToThread(sThread, paintInitTask);
return true;
}
void
@@ -215,22 +224,20 @@ PaintThread::Get()
}
/* static */ bool
PaintThread::IsOnPaintThread()
{
return sThreadId == PlatformThread::CurrentId();
}
-void
-PaintThread::BeginLayerTransaction()
+bool
+PaintThread::IsOnPaintWorkerThread()
{
- MOZ_ASSERT(NS_IsMainThread());
-
- MOZ_ASSERT(!mInAsyncPaintGroup);
+ return mPaintWorkers && mPaintWorkers->IsOnCurrentThread();
}
void
PaintThread::PrepareBuffer(CapturedBufferState* aState)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aState);
@@ -259,26 +266,25 @@ PaintThread::PrepareBuffer(CapturedBuffe
void
PaintThread::AsyncPrepareBuffer(CompositorBridgeChild* aBridge,
CapturedBufferState* aState)
{
MOZ_ASSERT(IsOnPaintThread());
MOZ_ASSERT(aState);
- if (!mInAsyncPaintGroup) {
- mInAsyncPaintGroup = true;
- PROFILER_TRACING("Paint", "Rasterize", TRACING_INTERVAL_START);
- }
-
if (!aState->PrepareBuffer()) {
gfxCriticalNote << "Failed to prepare buffers on the paint thread.";
}
- aBridge->NotifyFinishedAsyncPaint(aState);
+ if (aBridge->NotifyFinishedAsyncWorkerPaint(aState)) {
+ // We need to dispatch this task to ourselves so it runs after
+ // AsyncEndLayer
+ DispatchEndLayerTransaction(aBridge);
+ }
}
void
PaintThread::PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aState);
@@ -307,41 +313,48 @@ PaintThread::PaintContents(CapturedPaint
void
PaintThread::AsyncPaintContents(CompositorBridgeChild* aBridge,
CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback)
{
MOZ_ASSERT(IsOnPaintThread());
MOZ_ASSERT(aState);
- if (!mInAsyncPaintGroup) {
- mInAsyncPaintGroup = true;
- PROFILER_TRACING("Paint", "Rasterize", TRACING_INTERVAL_START);
- }
-
DrawTarget* target = aState->mTargetDual;
DrawTargetCapture* capture = aState->mCapture;
- AutoCapturedPaintSetup setup(aState, aBridge);
+ Matrix oldTransform = target->GetTransform();
+ bool oldPermitsSubpixelAA = target->GetPermitSubpixelAA();
+
+ target->SetTransform(capture->GetTransform());
+ target->SetPermitSubpixelAA(capture->GetPermitSubpixelAA());
+
+ if (aCallback(aState)) {
+ // Draw all the things into the actual dest target.
+ target->DrawCapturedDT(capture, Matrix());
- if (!aCallback(aState)) {
- return;
+ 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());
+ }
}
- // Draw all the things into the actual dest target.
- target->DrawCapturedDT(capture, Matrix());
- if (!mDrawTargetsToFlush.Contains(target)) {
- mDrawTargetsToFlush.AppendElement(target);
- }
+ target->SetTransform(oldTransform);
+ target->SetPermitSubpixelAA(oldPermitsSubpixelAA);
- 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());
+ if (aBridge->NotifyFinishedAsyncWorkerPaint(aState)) {
+ // We need to dispatch this task to ourselves so it runs after
+ // AsyncEndLayer
+ DispatchEndLayerTransaction(aBridge);
}
}
void
PaintThread::PaintTiledContents(CapturedTiledPaintState* aState)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aState);
@@ -350,39 +363,33 @@ PaintThread::PaintTiledContents(Captured
RefPtr<CapturedTiledPaintState> state(aState);
cbc->NotifyBeginAsyncPaint(state);
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PaintTiledContents",
[self, cbc, state]() -> void
{
- self->AsyncPaintTiledContents(cbc,
- state);
+ self->AsyncPaintTiledContents(cbc, state);
});
#ifndef OMTP_FORCE_SYNC
- sThread->Dispatch(task.forget());
+ mPaintWorkers->Dispatch(task.forget());
#else
- SyncRunnable::DispatchToThread(sThread, task);
+ SyncRunnable::DispatchToThread(mPaintWorkers, task);
#endif
}
void
PaintThread::AsyncPaintTiledContents(CompositorBridgeChild* aBridge,
CapturedTiledPaintState* aState)
{
- MOZ_ASSERT(IsOnPaintThread());
+ MOZ_ASSERT(IsOnPaintWorkerThread());
MOZ_ASSERT(aState);
- if (!mInAsyncPaintGroup) {
- mInAsyncPaintGroup = true;
- PROFILER_TRACING("Paint", "Rasterize", TRACING_INTERVAL_START);
- }
-
for (auto& copy : aState->mCopies) {
copy.CopyBuffer();
}
for (auto& clear : aState->mClears) {
clear.ClearBuffer();
}
@@ -395,17 +402,43 @@ 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->NotifyFinishedAsyncPaint(aState);
+ {
+ RefPtr<CompositorBridgeChild> cbc(aBridge);
+ RefPtr<CapturedTiledPaintState> state(aState);
+
+ RefPtr<PaintThread> self = this;
+ RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncPaintTiledContentsFinished",
+ [self, cbc, state]() -> void
+ {
+ self->AsyncPaintTiledContentsFinished(cbc, state);
+ });
+
+ #ifndef OMTP_FORCE_SYNC
+ sThread->Dispatch(task.forget());
+ #else
+ SyncRunnable::DispatchToThread(sThread, task);
+ #endif
+ }
+}
+
+void
+PaintThread::AsyncPaintTiledContentsFinished(CompositorBridgeChild* aBridge,
+ CapturedTiledPaintState* aState)
+{
+ MOZ_ASSERT(IsOnPaintThread());
+ if (aBridge->NotifyFinishedAsyncWorkerPaint(aState)) {
+ aBridge->NotifyFinishedAsyncEndLayerTransaction();
+ }
}
void
PaintThread::EndLayer()
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<PaintThread> self = this;
@@ -431,61 +464,68 @@ PaintThread::Dispatch(RefPtr<Runnable>&
SyncRunnable::DispatchToThread(sThread, aRunnable);
#endif
}
void
PaintThread::AsyncEndLayer()
{
MOZ_ASSERT(IsOnPaintThread());
+
// Textureclient forces a flush once we "end paint", so
// users of this texture expect all the drawing to be complete.
// Force a flush now.
for (size_t i = 0; i < mDrawTargetsToFlush.Length(); i++) {
mDrawTargetsToFlush[i]->Flush();
}
mDrawTargetsToFlush.Clear();
}
void
PaintThread::EndLayerTransaction(SyncObjectClient* aSyncObject)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
- RefPtr<SyncObjectClient> syncObject(aSyncObject);
-
- cbc->NotifyBeginAsyncEndLayerTransaction();
- RefPtr<PaintThread> self = this;
- RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncEndLayerTransaction",
- [self, cbc, syncObject]() -> void
- {
- self->AsyncEndLayerTransaction(cbc, syncObject);
- });
+ if (cbc->NotifyBeginAsyncEndLayerTransaction(aSyncObject)) {
+ RefPtr<PaintThread> self = this;
+ RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncEndLayerTransaction",
+ [self, cbc]() -> void
+ {
+ self->AsyncEndLayerTransaction(cbc);
+ });
-#ifndef OMTP_FORCE_SYNC
- sThread->Dispatch(task.forget());
-#else
- SyncRunnable::DispatchToThread(sThread, task);
-#endif
+ #ifndef OMTP_FORCE_SYNC
+ sThread->Dispatch(task.forget());
+ #else
+ SyncRunnable::DispatchToThread(sThread, task);
+ #endif
+ }
}
void
-PaintThread::AsyncEndLayerTransaction(CompositorBridgeChild* aBridge,
- SyncObjectClient* aSyncObject)
+PaintThread::AsyncEndLayerTransaction(CompositorBridgeChild* aBridge)
{
MOZ_ASSERT(IsOnPaintThread());
- MOZ_ASSERT(mInAsyncPaintGroup);
-
- if (aSyncObject) {
- aSyncObject->Synchronize();
- }
-
- mInAsyncPaintGroup = false;
- PROFILER_TRACING("Paint", "Rasterize", TRACING_INTERVAL_END);
aBridge->NotifyFinishedAsyncEndLayerTransaction();
}
+void
+PaintThread::DispatchEndLayerTransaction(CompositorBridgeChild* aBridge)
+{
+ MOZ_ASSERT(IsOnPaintThread());
+
+ RefPtr<CompositorBridgeChild> cbc = aBridge;
+ RefPtr<PaintThread> self = this;
+ RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncEndLayerTransaction",
+ [self, cbc]() -> void
+ {
+ self->AsyncEndLayerTransaction(cbc);
+ });
+
+ sThread->Dispatch(task.forget());
+}
+
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -10,16 +10,18 @@
#include "base/platform_thread.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/layers/TextureClient.h"
#include "RotatedBuffer.h"
#include "nsThreadUtils.h"
+class nsIThreadPool;
+
namespace mozilla {
namespace gfx {
class DrawTarget;
class DrawTargetCapture;
};
namespace layers {
@@ -256,22 +258,17 @@ class PaintThread final
public:
static void Start();
static void Shutdown();
static PaintThread* Get();
// Helper for asserts.
static bool IsOnPaintThread();
-
- // Must be called on the main thread. Signifies that a new layer transaction
- // is beginning. This must be called immediately after FlushAsyncPaints, and
- // before any new painting occurs, as there can't be any async paints queued
- // or running while this is executing.
- void BeginLayerTransaction();
+ bool IsOnPaintWorkerThread();
void PrepareBuffer(CapturedBufferState* aState);
void PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);
void PaintTiledContents(CapturedTiledPaintState* aState);
@@ -296,36 +293,41 @@ public:
// We're only temporarily using sync runnables so
// Override release/addref but don't do anything.
void Release();
void AddRef();
private:
PaintThread();
+ static int32_t CalculatePaintWorkerCount();
+
bool Init();
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 AsyncPaintTiledContentsFinished(CompositorBridgeChild* aBridge,
+ CapturedTiledPaintState* aState);
void AsyncEndLayer();
- void AsyncEndLayerTransaction(CompositorBridgeChild* aBridge,
- SyncObjectClient* aSyncObject);
+ void AsyncEndLayerTransaction(CompositorBridgeChild* aBridge);
+
+ void DispatchEndLayerTransaction(CompositorBridgeChild* aBridge);
static StaticAutoPtr<PaintThread> sSingleton;
static StaticRefPtr<nsIThread> sThread;
static PlatformThreadId sThreadId;
- bool mInAsyncPaintGroup;
+ RefPtr<nsIThreadPool> mPaintWorkers;
// This shouldn't be very many elements, so a list should be fine.
// Should only be accessed on the paint thread.
nsTArray<RefPtr<gfx::DrawTarget>> mDrawTargetsToFlush;
};
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -221,19 +221,16 @@ ClientLayerManager::CreateReadbackLayer(
return layer.forget();
}
bool
ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
{
// Wait for any previous async paints to complete before starting to paint again.
GetCompositorBridgeChild()->FlushAsyncPaints();
- if (PaintThread::Get()) {
- PaintThread::Get()->BeginLayerTransaction();
- }
MOZ_ASSERT(mForwarder, "ClientLayerManager::BeginTransaction without forwarder");
if (!mForwarder->IPCOpen()) {
gfxCriticalNote << "ClientLayerManager::BeginTransaction with IPC channel down. GPU process may have died.";
return false;
}
mInTransaction = true;
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -319,23 +319,17 @@ ClientLayerManager::CreatePaintedLayer()
{
return CreatePaintedLayerWithHint(NONE);
}
already_AddRefed<PaintedLayer>
ClientLayerManager::CreatePaintedLayerWithHint(PaintedLayerCreationHint aHint)
{
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
- // The non-tiling ContentClient requires CrossProcessSemaphore which
- // isn't implemented for OSX.
-#ifdef XP_MACOSX
- if (true) {
-#else
- if (gfxPrefs::LayersTilesEnabled()) {
-#endif
+ if (gfxPlatform::UsesTiling()) {
RefPtr<ClientTiledPaintedLayer> layer = new ClientTiledPaintedLayer(this, aHint);
CREATE_SHADOW(Painted);
return layer.forget();
} else {
RefPtr<ClientPaintedLayer> layer = new ClientPaintedLayer(this, aHint);
CREATE_SHADOW(Painted);
return layer.forget();
}
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -1187,30 +1187,38 @@ CompositorBridgeChild::FlushAsyncPaints(
mTotalFlushCount++;
double ratio = double(mSlowFlushCount) / double(mTotalFlushCount);
Telemetry::ScalarSet(Telemetry::ScalarID::GFX_OMTP_PAINT_WAIT_RATIO,
uint32_t(ratio * 100 * 100));
}
}
-void
-CompositorBridgeChild::NotifyBeginAsyncEndLayerTransaction()
+bool
+CompositorBridgeChild::NotifyBeginAsyncEndLayerTransaction(SyncObjectClient* aSyncObject)
{
MOZ_ASSERT(NS_IsMainThread());
MonitorAutoLock lock(mPaintLock);
MOZ_ASSERT(!mOutstandingAsyncEndTransaction);
mOutstandingAsyncEndTransaction = true;
+ mOutstandingAsyncSyncObject = aSyncObject;
+ return mOutstandingAsyncPaints == 0;
}
void
CompositorBridgeChild::NotifyFinishedAsyncEndLayerTransaction()
{
MOZ_ASSERT(PaintThread::IsOnPaintThread());
+
+ if (mOutstandingAsyncSyncObject) {
+ mOutstandingAsyncSyncObject->Synchronize();
+ mOutstandingAsyncSyncObject = nullptr;
+ }
+
MonitorAutoLock lock(mPaintLock);
// Since this should happen after ALL paints are done and
// at the end of a transaction, this should always be true.
MOZ_RELEASE_ASSERT(mOutstandingAsyncPaints == 0);
MOZ_ASSERT(mOutstandingAsyncEndTransaction);
mOutstandingAsyncEndTransaction = false;
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -245,38 +245,44 @@ public:
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.
template<typename CapturedState>
- void NotifyFinishedAsyncPaint(CapturedState& aState)
+ bool NotifyFinishedAsyncWorkerPaint(CapturedState& aState)
{
MOZ_ASSERT(PaintThread::IsOnPaintThread());
MonitorAutoLock lock(mPaintLock);
mOutstandingAsyncPaints--;
aState->ForEachTextureClient([] (auto aClient) {
aClient->DropPaintThreadRef();
});
aState->DropTextureClients();
+
+ // If the main thread has completed queuing work and this was the
+ // last paint, then it is time to end the layer transaction and sync
+ return mOutstandingAsyncEndTransaction && mOutstandingAsyncPaints == 0;
}
// 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();
+ // that all work has been submitted to the paint thread or paint worker
+ // threads, and returns whether all paints are completed. If this returns
+ // true, then an AsyncEndLayerTransaction must be queued, otherwise once
+ // NotifyFinishedAsyncWorkerPaint returns true, an AsyncEndLayerTransaction
+ // must be executed.
+ bool NotifyBeginAsyncEndLayerTransaction(SyncObjectClient* aSyncObject);
// 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.
+ // that the paint thread has finished all async paints and and may do the
+ // requested texture sync and resume sending messages.
void NotifyFinishedAsyncEndLayerTransaction();
// Must only be called from the main thread. Notifies the CompoistorBridge
// that a transaction is about to be sent, and if the paint thread is
// currently painting, to begin delaying IPC messages.
void PostponeMessagesIfAsyncPainting();
private:
@@ -401,16 +407,17 @@ private:
// Contains the number of outstanding asynchronous paints tied to a
// PLayerTransaction on this bridge. This is R/W on both the main and paint
// threads, and must be accessed within the paint lock.
size_t mOutstandingAsyncPaints;
// Whether we are waiting for an async paint end transaction
bool mOutstandingAsyncEndTransaction;
+ RefPtr<SyncObjectClient> mOutstandingAsyncSyncObject;
// True if this CompositorBridge is currently delaying its messages until the
// paint thread completes. This is R/W on both the main and paint threads, and
// must be accessed within the paint lock.
bool mIsDelayingForAsyncPaints;
uintptr_t mSlowFlushCount;
uintptr_t mTotalFlushCount;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2585,17 +2585,17 @@ 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() && gfxPrefs::TileEdgePaddingEnabled()) {
+ } else if (gfxPlatform::UsesTiling() && 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();
}
@@ -2657,16 +2657,28 @@ gfxPlatform::UsesOffMainThreadCompositin
#endif
firstTime = false;
}
return result;
}
+/* static */ bool
+gfxPlatform::UsesTiling()
+{
+ // The non-tiling ContentClient requires CrossProcessSemaphore which
+ // isn't implemented for OSX.
+#ifdef XP_MACOSX
+ return true;
+#else
+ return gfxPrefs::LayersTilesEnabled();
+#endif
+}
+
/***
* The preference "layout.frame_rate" has 3 meanings depending on the value:
*
* -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw vsync fails.
* 0 = ASAP mode - used during talos testing.
* X = Software vsync at a rate of X times per second.
*/
already_AddRefed<mozilla::gfx::VsyncSource>
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -594,16 +594,18 @@ public:
mozilla::layers::DiagnosticTypes GetLayerDiagnosticTypes();
mozilla::gl::SkiaGLGlue* GetSkiaGLGlue();
void PurgeSkiaGPUCache();
static void PurgeSkiaFontCache();
static bool UsesOffMainThreadCompositing();
+ static bool UsesTiling();
+
bool HasEnoughTotalSystemMemoryForSkiaGL();
/**
* Get the hardware vsync source for each platform.
* Should only exist and be valid on the parent process
*/
virtual mozilla::gfx::VsyncSource* GetHardwareVsync() {
MOZ_ASSERT(mVsyncSource != nullptr);
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -605,16 +605,17 @@ private:
DECL_GFX_PREF(Once, "layers.mlgpu.enable-clear-view", AdvancedLayersEnableClearView, bool, true);
DECL_GFX_PREF(Once, "layers.mlgpu.enable-cpu-occlusion", AdvancedLayersEnableCPUOcclusion, bool, true);
DECL_GFX_PREF(Once, "layers.mlgpu.enable-depth-buffer", AdvancedLayersEnableDepthBuffer, bool, false);
DECL_GFX_PREF(Live, "layers.mlgpu.enable-invalidation", AdvancedLayersUseInvalidation, bool, true);
DECL_GFX_PREF(Once, "layers.mlgpu.enable-on-windows7", AdvancedLayersEnableOnWindows7, bool, false);
DECL_GFX_PREF(Once, "layers.mlgpu.enable-container-resizing", AdvancedLayersEnableContainerResizing, bool, true);
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-disabled", LayersOffMainThreadCompositionForceDisabled, bool, false);
DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
+ DECL_GFX_PREF(Live, "layers.omtp.paint-workers", LayersOMTPPaintWorkers, int32_t, 1);
DECL_GFX_PREF(Live, "layers.omtp.release-capture-on-main-thread", LayersOMTPReleaseCaptureOnMainThread, bool, false);
DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0);
DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false);
DECL_GFX_PREF(Live, "layers.progressive-paint", ProgressivePaint, bool, false);
DECL_GFX_PREF(Live, "layers.shared-buffer-provider.enabled", PersistentBufferProviderSharedEnabled, bool, false);
DECL_GFX_PREF(Live, "layers.single-tile.enabled", LayersSingleTileEnabled, bool, true);
DECL_GFX_PREF(Live, "layers.force-synchronous-resize", LayersForceSynchronousResize, bool, true);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5878,8 +5878,9 @@ pref("toolkit.crashreporter.include_cont
pref("dom.noopener.newprocess.enabled", true);
#if defined(XP_WIN) || defined(XP_MACOSX)
pref("layers.omtp.enabled", true);
#else
pref("layers.omtp.enabled", false);
#endif
pref("layers.omtp.release-capture-on-main-thread", false);
+pref("layers.omtp.paint-workers", 1);
--- a/xpcom/base/moz.build
+++ b/xpcom/base/moz.build
@@ -72,16 +72,17 @@ EXPORTS += [
'nsISizeOf.h',
'nsISupportsBase.h',
'nsISupportsImpl.h',
'nsISupportsUtils.h',
'nsIWeakReferenceUtils.h',
'nsMemory.h',
'nsObjCExceptions.h',
'nsQueryObject.h',
+ 'nsSystemInfo.h',
'nsTraceRefcnt.h',
'nsTWeakRef.h',
'nsVersionComparator.h',
'nsWeakPtr.h',
'nsWeakReference.h',
]
if CONFIG['OS_ARCH'] == 'WINNT':