From 16e8c5d42601e0eec873d2305ed6e100db52fdd4 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Thu, 26 Jul 2018 16:33:07 -0500 Subject: [PATCH] Bug 1478815 part 9 - Add ability to create a DrawTargetCapture that can flush to its destination draw target. r=bas This commit adds the ability to create a different kind of DrawTargetCapture which has a limit on the size of which its CaptureCommandList can grow before it is synchronously flushed to its destination DrawTarget. Special care is taken to not do a sync flush until we would need to resize the backing store of the CaptureCommandList. This allows us to not waste memory we've already allocated. The async painting content clients are updated to use it, and get a default value from a new preference. MozReview-Commit-ID: CJL7ffvaRzR --HG-- extra : rebase_source : f646862dcef7a480b21dfb7ddb1fa165338ba506 extra : source : b865a866fe5a3257615cb54b7e5e790cc9331988 --- gfx/2d/2D.h | 12 ++++++++++++ gfx/2d/CaptureCommandList.cpp | 8 ++++++++ gfx/2d/CaptureCommandList.h | 11 +++++++++++ gfx/2d/DrawTargetCapture.cpp | 17 ++++++++++++++++- gfx/2d/DrawTargetCapture.h | 18 ++++++++++++++++++ gfx/2d/Factory.cpp | 6 ++++++ gfx/layers/RotatedBuffer.cpp | 5 +---- gfx/layers/client/TiledContentClient.cpp | 5 +---- gfx/thebes/gfxPrefs.h | 1 + 9 files changed, 74 insertions(+), 9 deletions(-) diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index d1b958b0fa02..2a6c795c782e 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -1632,6 +1632,18 @@ public: static already_AddRefed CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat); + /** + * Create a DrawTarget that captures the drawing commands to eventually be replayed + * onto the DrawTarget provided. An optional byte size can be provided as a limit + * for the CaptureCommandList. When the limit is reached, the CaptureCommandList + * will be replayed to the target and then cleared. + * + * @param aSize Size of the area this DT will capture. + * @param aFlushBytes The byte limit at which to flush the CaptureCommandList + */ + static already_AddRefed + CreateCaptureDrawTargetForTarget(gfx::DrawTarget* aTarget, size_t aFlushBytes = 0); + /** * Create a DrawTarget that captures the drawing commands and can be replayed * onto a compatible DrawTarget afterwards. diff --git a/gfx/2d/CaptureCommandList.cpp b/gfx/2d/CaptureCommandList.cpp index d0a06f708c37..108d255fa26d 100644 --- a/gfx/2d/CaptureCommandList.cpp +++ b/gfx/2d/CaptureCommandList.cpp @@ -11,11 +11,19 @@ namespace mozilla { namespace gfx { CaptureCommandList::~CaptureCommandList() +{ + Clear(); +} + +void +CaptureCommandList::Clear() { for (iterator iter(*this); !iter.Done(); iter.Next()) { DrawingCommand* cmd = iter.Get(); cmd->~DrawingCommand(); } + mLastCommand = nullptr; + mStorage.clear(); } } // namespace gfx diff --git a/gfx/2d/CaptureCommandList.h b/gfx/2d/CaptureCommandList.h index bb2f6924f89d..58a02c4642d5 100644 --- a/gfx/2d/CaptureCommandList.h +++ b/gfx/2d/CaptureCommandList.h @@ -64,6 +64,17 @@ public: return Append(); } + template + bool BufferWillAlloc() const { + return mStorage.size() + sizeof(uint32_t) + sizeof(T) > mStorage.capacity(); + } + + size_t BufferCapacity() const { + return mStorage.capacity(); + } + + void Clear(); + class iterator { public: diff --git a/gfx/2d/DrawTargetCapture.cpp b/gfx/2d/DrawTargetCapture.cpp index 3e36cd514872..e380f15ef8c9 100644 --- a/gfx/2d/DrawTargetCapture.cpp +++ b/gfx/2d/DrawTargetCapture.cpp @@ -23,13 +23,27 @@ DrawTargetCaptureImpl::~DrawTargetCaptureImpl() } } +DrawTargetCaptureImpl::DrawTargetCaptureImpl(gfx::DrawTarget* aTarget, size_t aFlushBytes) + : mSnapshot(nullptr), + mStride(0), + mSurfaceAllocationSize(0), + mFlushBytes(aFlushBytes) +{ + mSize = aTarget->GetSize(); + mFormat = aTarget->GetFormat(); + SetPermitSubpixelAA(aTarget->GetPermitSubpixelAA()); + + mRefDT = aTarget; +} + DrawTargetCaptureImpl::DrawTargetCaptureImpl(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) : mSize(aSize), mSnapshot(nullptr), mStride(0), - mSurfaceAllocationSize(0) + mSurfaceAllocationSize(0), + mFlushBytes(0) { RefPtr screenRefDT = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); @@ -75,6 +89,7 @@ DrawTargetCaptureImpl::Init(const IntSize& aSize, DrawTarget* aRefDT) void DrawTargetCaptureImpl::InitForData(int32_t aStride, size_t aSurfaceAllocationSize) { + MOZ_ASSERT(!mFlushBytes); mStride = aStride; mSurfaceAllocationSize = aSurfaceAllocationSize; } diff --git a/gfx/2d/DrawTargetCapture.h b/gfx/2d/DrawTargetCapture.h index 58943cb358b7..fe5ceff62566 100644 --- a/gfx/2d/DrawTargetCapture.h +++ b/gfx/2d/DrawTargetCapture.h @@ -24,6 +24,7 @@ class DrawTargetCaptureImpl : public DrawTargetCapture friend class SourceSurfaceCapture; public: + DrawTargetCaptureImpl(gfx::DrawTarget* aTarget, size_t aFlushBytes); DrawTargetCaptureImpl(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat); bool Init(const IntSize& aSize, DrawTarget* aRefDT); @@ -158,6 +159,12 @@ protected: void MarkChanged(); private: + void FlushCommandBuffer() + { + ReplayToDrawTarget(mRefDT, Matrix()); + mCommands.Clear(); + } + // This storage system was used to minimize the amount of heap allocations // that are required while recording. It should be noted there's no // guarantees on the alignments of DrawingCommands allocated in this array. @@ -166,6 +173,11 @@ private: if (T::AffectsSnapshot) { MarkChanged(); } + if (mFlushBytes && + mCommands.BufferWillAlloc() && + mCommands.BufferCapacity() > mFlushBytes) { + FlushCommandBuffer(); + } return mCommands.Append(); } template @@ -173,6 +185,11 @@ private: if (T::AffectsSnapshot) { MarkChanged(); } + if (mFlushBytes && + mCommands.BufferWillAlloc() && + mCommands.BufferCapacity() > mFlushBytes) { + FlushCommandBuffer(); + } return mCommands.ReuseOrAppend(); } @@ -194,6 +211,7 @@ private: std::vector mPushedLayers; CaptureCommandList mCommands; + size_t mFlushBytes; }; } // namespace gfx diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index a5604e9bab0b..fbc9270ad1f1 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -452,6 +452,12 @@ Factory::CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT return MakeAndAddRef(aRecorder, aDT, aSize); } +already_AddRefed +Factory::CreateCaptureDrawTargetForTarget(gfx::DrawTarget* aTarget, size_t aFlushBytes) +{ + return MakeAndAddRef(aTarget, aFlushBytes); +} + already_AddRefed Factory::CreateCaptureDrawTarget(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) { diff --git a/gfx/layers/RotatedBuffer.cpp b/gfx/layers/RotatedBuffer.cpp index 3c0201c79aee..cb9e894d062f 100644 --- a/gfx/layers/RotatedBuffer.cpp +++ b/gfx/layers/RotatedBuffer.cpp @@ -83,10 +83,7 @@ RotatedBuffer::BeginCapture() MOZ_ASSERT(!mCapture); MOZ_ASSERT(target); - mCapture = - Factory::CreateCaptureDrawTarget(target->GetBackendType(), - target->GetSize(), - target->GetFormat()); + mCapture = Factory::CreateCaptureDrawTargetForTarget(target, gfxPrefs::LayersOMTPCaptureLimit()); } RefPtr diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 5c48396d2153..8b94a3eed134 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -711,10 +711,7 @@ TileClient::AcquireBackBuffer(CompositableClient& aCompositable, // Construct a capture draw target if necessary RefPtr capture; if (aFlags & TilePaintFlags::Async) { - capture = - Factory::CreateCaptureDrawTarget(target->GetBackendType(), - target->GetSize(), - target->GetFormat()); + capture = Factory::CreateCaptureDrawTargetForTarget(target, gfxPrefs::LayersOMTPCaptureLimit()); target = capture; } diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 025a6a6fcbc4..8913bf773a39 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -634,6 +634,7 @@ private: 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(Once, "layers.omtp.capture-limit", LayersOMTPCaptureLimit, uint32_t, 25 * 1024 * 1024); DECL_GFX_PREF(Live, "layers.omtp.dump-capture", LayersOMTPDumpCapture, bool, false); DECL_GFX_PREF(Once, "layers.omtp.paint-workers", LayersOMTPPaintWorkers, int32_t, 1); DECL_GFX_PREF(Live, "layers.omtp.release-capture-on-main-thread", LayersOMTPReleaseCaptureOnMainThread, bool, false);