Bug 1387639 Sync Textures once all async OMTP paints are done. r=mattwoodrow

This commit is contained in:
Mason Chang 2017-08-10 21:41:31 -07:00
parent 517c688524
commit a7da7e14fb
7 changed files with 66 additions and 2 deletions

View File

@ -9,6 +9,8 @@
#include "base/task.h"
#include "gfxPrefs.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/SyncRunnable.h"
@ -207,6 +209,35 @@ PaintThread::EndAsyncPainting(CompositorBridgeChild* aBridge)
}
}
void
PaintThread::SynchronizePaintTextures(SyncObjectClient* aSyncObject)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSyncObject);
RefPtr<SyncObjectClient> syncObject(aSyncObject);
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::SyncTextureData",
[self, syncObject]() -> void
{
self->SyncTextureData(syncObject);
});
if (!gfxPrefs::LayersOMTPForceSync()) {
sThread->Dispatch(task.forget());
} else {
SyncRunnable::DispatchToThread(sThread, task);
}
}
void
PaintThread::SyncTextureData(SyncObjectClient* aSyncObject)
{
MOZ_ASSERT(IsOnPaintThread());
MOZ_ASSERT(aSyncObject);
aSyncObject->Synchronize();
}
void
PaintThread::PaintContents(CapturedPaintState* aState,

View File

@ -75,6 +75,14 @@ public:
// and the main thread is finished recording this layer.
void FinishedLayerBatch();
// Must be called on the main thread. Tells the paint thread
// to schedule a sync textures after all async paints are done.
// NOTE: The other paint thread functions are on a per PAINT
// or per paint layer basis. This MUST be called at the end
// of a layer transaction as multiple paints can occur
// with multiple layers. We only have to do this once per transaction.
void SynchronizePaintTextures(SyncObjectClient* aSyncObject);
// Sync Runnables need threads to be ref counted,
// But this thread lives through the whole process.
// We're only temporarily using sync runnables so
@ -93,6 +101,7 @@ private:
CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);
void EndAsyncPainting(CompositorBridgeChild* aBridge);
void SyncTextureData(SyncObjectClient* aSyncObject);
static StaticAutoPtr<PaintThread> sSingleton;
static StaticRefPtr<nsIThread> sThread;

View File

@ -100,6 +100,7 @@ ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
, mTransactionIncomplete(false)
, mCompositorMightResample(false)
, mNeedsComposite(false)
, mTextureSyncOnPaintThread(false)
, mPaintSequenceNumber(0)
, mDeviceResetSequenceNumber(0)
, mForwarder(new ShadowLayerForwarder(this))
@ -358,6 +359,7 @@ ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
ClientLayer* root = ClientLayer::ToClientLayer(GetRoot());
mTransactionIncomplete = false;
mTextureSyncOnPaintThread = false;
// Apply pending tree updates before recomputing effective
// properties.
@ -725,11 +727,17 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
TimeStamp start = TimeStamp::Now();
// Skip the synchronization for buffer since we also skip the painting during
// device-reset status.
// device-reset status. With OMTP, we have to wait for async paints
// before we synchronize and it's done on the paint thread.
if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
if (mForwarder->GetSyncObject() &&
mForwarder->GetSyncObject()->IsSyncObjectValid()) {
mForwarder->GetSyncObject()->Synchronize();
if (mTextureSyncOnPaintThread) {
// We have to wait for all async paints to finish to do this
PaintThread::Get()->SynchronizePaintTextures(mForwarder->GetSyncObject());
} else {
mForwarder->GetSyncObject()->Synchronize();
}
}
}

View File

@ -17,6 +17,7 @@
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/FocusTarget.h" // for FocusTarget
#include "mozilla/layers/LayersTypes.h" // for BufferMode, LayersBackend, etc
#include "mozilla/layers/PaintThread.h" // For PaintThread
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder, etc
#include "mozilla/layers/APZTestData.h" // for APZTestData
#include "nsCOMPtr.h" // for already_AddRefed
@ -158,6 +159,7 @@ public:
bool IsRepeatTransaction() { return mIsRepeatTransaction; }
void SetTransactionIncomplete() { mTransactionIncomplete = true; }
void SetNeedTextureSyncOnPaintThread() { mTextureSyncOnPaintThread = true; }
bool HasShadowTarget() { return !!mShadowTarget; }
@ -349,6 +351,7 @@ private:
bool mTransactionIncomplete;
bool mCompositorMightResample;
bool mNeedsComposite;
bool mTextureSyncOnPaintThread;
// An incrementing sequence number for paints.
// Incremented in BeginTransaction(), but not for repeat transactions.

View File

@ -268,6 +268,7 @@ ClientPaintedLayer::PaintOffMainThread()
if (didUpdate) {
UpdateContentClient(state);
ClientManager()->SetNeedTextureSyncOnPaintThread();
}
return true;
}

View File

@ -1623,6 +1623,7 @@ SyncObjectD3D11Host::Synchronize()
SyncObjectD3D11Client::SyncObjectD3D11Client(SyncHandle aSyncHandle, ID3D11Device* aDevice)
: mSyncHandle(aSyncHandle)
, mSyncLock("SyncObjectD3D11")
{
if (!aDevice) {
mDevice = DeviceManagerDx::Get()->GetContentDevice();
@ -1678,9 +1679,19 @@ SyncObjectD3D11Client::IsSyncObjectValid()
return true;
}
// We have only 1 sync object. As a thing that somehow works,
// we copy each of the textures that need to be synced with the compositor
// into our sync object and only use a lock for this sync object.
// This way, we don't have to sync every texture we send to the compositor.
// We only have to do this once per transaction.
void
SyncObjectD3D11Client::Synchronize()
{
// This can be called from the paint or main thread depending on OMTP.
// We need this lock in addition to the AutoTextureLock in case we have to
// init here.
MutexAutoLock syncLock(mSyncLock);
if (!mSyncedTextures.size()) {
return;
}

View File

@ -484,6 +484,7 @@ private:
RefPtr<ID3D11Texture2D> mSyncTexture;
RefPtr<IDXGIKeyedMutex> mKeyedMutex;
std::vector<ID3D11Texture2D*> mSyncedTextures;
Mutex mSyncLock;
};
inline uint32_t GetMaxTextureSizeForFeatureLevel(D3D_FEATURE_LEVEL aFeatureLevel)