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);