diff --git a/gfx/2d/DrawCommand.h b/gfx/2d/DrawCommand.h index 228d627c0888..bad569c8b0c0 100644 --- a/gfx/2d/DrawCommand.h +++ b/gfx/2d/DrawCommand.h @@ -39,7 +39,7 @@ class DrawingCommand public: virtual ~DrawingCommand() {} - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix& aTransform) = 0; + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aTransform = nullptr) = 0; protected: explicit DrawingCommand(CommandType aType) @@ -130,7 +130,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->DrawSurface(mSurface, mDest, mSource, mSurfOptions, mOptions); } @@ -154,7 +154,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->DrawFilter(mFilter, mSourceRect, mDestPoint, mOptions); } @@ -175,7 +175,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->ClearRect(mRect); } @@ -197,11 +197,13 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix& aTransform) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aTransform) { - MOZ_ASSERT(!aTransform.HasNonIntegerTranslation()); + MOZ_ASSERT(!aTransform || !aTransform->HasNonIntegerTranslation()); Point dest(Float(mDestination.x), Float(mDestination.y)); - dest = aTransform * dest; + if (aTransform) { + dest = (*aTransform) * dest; + } aDT->CopySurface(mSurface, mSourceRect, IntPoint(uint32_t(dest.x), uint32_t(dest.y))); } @@ -224,7 +226,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->FillRect(mRect, mPattern, mOptions); } @@ -250,7 +252,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->StrokeRect(mRect, mPattern, mStrokeOptions, mOptions); } @@ -279,7 +281,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->StrokeLine(mStart, mEnd, mPattern, mStrokeOptions, mOptions); } @@ -305,7 +307,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->Fill(mPath, mPattern, mOptions); } @@ -331,7 +333,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->Stroke(mPath, mPattern, mStrokeOptions, mOptions); } @@ -361,7 +363,7 @@ public: memcpy(&mGlyphs.front(), aBuffer.mGlyphs, sizeof(Glyph) * aBuffer.mNumGlyphs); } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { GlyphBuffer buf; buf.mNumGlyphs = mGlyphs.size(); @@ -390,7 +392,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->Mask(mSource, mMask, mOptions); } @@ -416,7 +418,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->MaskSurface(mSource, mMask, mOffset, mOptions); } @@ -437,7 +439,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->PushClip(mPath); } @@ -455,7 +457,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->PushClipRect(mRect); } @@ -472,7 +474,7 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) { aDT->PopClip(); } @@ -487,11 +489,13 @@ public: { } - virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix& aMatrix) + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aMatrix) { - Matrix transform = mTransform; - transform *= aMatrix; - aDT->SetTransform(transform); + if (aMatrix) { + aDT->SetTransform(mTransform * (*aMatrix)); + } else { + aDT->SetTransform(mTransform); + } } private: diff --git a/gfx/2d/DrawTargetCapture.cpp b/gfx/2d/DrawTargetCapture.cpp index 84d08d7d28cc..f3dd4d0923e5 100644 --- a/gfx/2d/DrawTargetCapture.cpp +++ b/gfx/2d/DrawTargetCapture.cpp @@ -188,7 +188,7 @@ DrawTargetCaptureImpl::ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransf uint8_t* current = start; while (current < start + mDrawCommandStorage.size()) { - reinterpret_cast(current + sizeof(uint32_t))->ExecuteOnDT(aDT, aTransform); + reinterpret_cast(current + sizeof(uint32_t))->ExecuteOnDT(aDT, &aTransform); current += *(uint32_t*)current; } } diff --git a/gfx/2d/DrawingTask.cpp b/gfx/2d/DrawingTask.cpp new file mode 100644 index 000000000000..de7d571df9e2 --- /dev/null +++ b/gfx/2d/DrawingTask.cpp @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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 "DrawingTask.h" +#include "TaskScheduler.h" +#include "mozilla/gfx/2D.h" + +namespace mozilla { +namespace gfx { + +DrawingTaskBuilder::DrawingTaskBuilder() +: mTask(nullptr) +{} + +DrawingTaskBuilder::~DrawingTaskBuilder() +{ + if (mTask) { + delete mTask; + } +} + +void +DrawingTask::Clear() +{ + mCommandBuffer = nullptr; + mCursor = 0; +} + +void +DrawingTaskBuilder::BeginDrawingTask(MultiThreadedTaskQueue* aTaskQueue, + DrawTarget* aTarget, IntPoint aOffset, + SyncObject* aStart) +{ + MOZ_ASSERT(!mTask); + MOZ_ASSERT(aTaskQueue); + mTask = new DrawingTask(aTaskQueue, aTarget, aOffset, aStart); +} + +DrawingTask* +DrawingTaskBuilder::EndDrawingTask(CommandBuffer* aCmdBuffer, SyncObject* aCompletion) +{ + MOZ_ASSERT(mTask); + mTask->mCompletionSync = aCompletion; + mTask->mCommandBuffer = aCmdBuffer; + DrawingTask* task = mTask; + mTask = nullptr; + return task; +} + +DrawingTask::DrawingTask(MultiThreadedTaskQueue* aTaskQueue, + DrawTarget* aTarget, IntPoint aOffset, + SyncObject* aStart) +: Task(aTaskQueue, aStart, nullptr) +, mCommandBuffer(nullptr) +, mCursor(0) +, mDrawTarget(aTarget) +, mOffset(aOffset) +{ + mCommandOffsets.reserve(64); +} + +TaskStatus +DrawingTask::Run() +{ + while (mCursor < mCommandOffsets.size()) { + + DrawingCommand* cmd = mCommandBuffer->GetDrawingCommand(mCommandOffsets[mCursor]); + + if (!cmd) { + return TaskStatus::Error; + } + + cmd->ExecuteOnDT(mDrawTarget); + + ++mCursor; + } + + return TaskStatus::Complete; +} + +DrawingTask::~DrawingTask() +{ + Clear(); +} + +DrawingCommand* +CommandBuffer::GetDrawingCommand(ptrdiff_t aId) +{ + return static_cast(mStorage.GetStorage(aId)); +} + +CommandBuffer::~CommandBuffer() +{ + mStorage.ForEach([](void* item){ + static_cast(item)->~DrawingCommand(); + }); + mStorage.Clear(); +} + +void +CommandBufferBuilder::BeginCommandBuffer(size_t aBufferSize) +{ + MOZ_ASSERT(!mCommands); + mCommands = new CommandBuffer(aBufferSize); +} + +already_AddRefed +CommandBufferBuilder::EndCommandBuffer() +{ + return mCommands.forget(); +} + +} // namespace +} // namespace diff --git a/gfx/2d/DrawingTask.h b/gfx/2d/DrawingTask.h new file mode 100644 index 000000000000..3c972b0c21f5 --- /dev/null +++ b/gfx/2d/DrawingTask.h @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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/. */ + +#ifndef MOZILLA_GFX_COMMANDBUFFER_H_ +#define MOZILLA_GFX_COMMANDBUFFER_H_ + +#include + +#include "mozilla/RefPtr.h" +#include "mozilla/Assertions.h" +#include "mozilla/gfx/Matrix.h" +#include "mozilla/gfx/TaskScheduler.h" +#include "mozilla/gfx/IterableArena.h" +#include "DrawCommand.h" + +namespace mozilla { +namespace gfx { + +class DrawingCommand; +class PrintCommand; +class SignalCommand; +class DrawingTask; +class WaitCommand; + +class SyncObject; +class MultiThreadedTaskQueue; + +class DrawTarget; + +class DrawingTaskBuilder; +class CommandBufferBuilder; + +/// Contains a sequence of immutable drawing commands that are typically used by +/// several DrawingTasks. +/// +/// CommandBuffer objects are built using CommandBufferBuilder. +class CommandBuffer : public external::AtomicRefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_TYPENAME(CommandBuffer) + + ~CommandBuffer(); + + DrawingCommand* GetDrawingCommand(ptrdiff_t aId); + +protected: + CommandBuffer(size_t aSize = 256) + : mStorage(IterableArena::GROWABLE, aSize) + {} + + IterableArena mStorage; + friend class CommandBufferBuilder; +}; + +/// Generates CommandBuffer objects. +/// +/// The builder is a separate object to ensure that commands are not added to a +/// submitted CommandBuffer. +class CommandBufferBuilder +{ +public: + void BeginCommandBuffer(size_t aBufferSize = 256); + + already_AddRefed EndCommandBuffer(); + + /// Build the CommandBuffer, command after command. + /// This must be used between BeginCommandBuffer and EndCommandBuffer. + template + ptrdiff_t AddCommand(Args&&... aArgs) + { + static_assert(IsBaseOf::value, + "T must derive from DrawingCommand"); + return mCommands->mStorage.Alloc(Forward(aArgs)...); + } + + bool HasCommands() const { return !!mCommands; } + +protected: + RefPtr mCommands; +}; + +/// Stores multiple commands to be executed sequencially. +class DrawingTask : public Task { +public: + DrawingTask(MultiThreadedTaskQueue* aTaskQueue, + DrawTarget* aTarget, + IntPoint aOffset, + SyncObject* aStart); + + ~DrawingTask(); + + virtual TaskStatus Run() override; + +protected: + /// Runs the tasks's destructors and resets the buffer. + void Clear(); + + std::vector mCommandOffsets; + RefPtr mCommandBuffer; + uint32_t mCursor; + + RefPtr mDrawTarget; + IntPoint mOffset; + + friend class DrawingTaskBuilder; +}; + +/// Generates DrawingTask objects. +/// +/// The builder is a separate object to ensure that commands are not added to a +/// submitted DrawingTask. +class DrawingTaskBuilder { +public: + DrawingTaskBuilder(); + + ~DrawingTaskBuilder(); + + /// Allocates a DrawingTask. + /// + /// call this method before starting to add commands. + void BeginDrawingTask(MultiThreadedTaskQueue* aTaskQueue, + DrawTarget* aTarget, IntPoint aOffset, + SyncObject* aStart = nullptr); + + /// Build the DrawingTask, command after command. + /// This must be used between BeginDrawingTask and EndDrawingTask. + void AddCommand(ptrdiff_t offset) + { + MOZ_ASSERT(mTask); + mTask->mCommandOffsets.push_back(offset); + } + + /// Finalizes and returns the command buffer. + /// + /// If aCompletion is not null, the sync object will be signaled after the + /// task buffer is destroyed (and after the destructor of the tasks have run). + /// In most cases this means after the completion of all tasks in the task buffer, + /// but also when the task buffer is destroyed due to an error. + DrawingTask* EndDrawingTask(CommandBuffer* aCmdBuffer, SyncObject* aCompletion = nullptr); + + /// Returns true between BeginDrawingTask and EndDrawingTask, false otherwise. + bool HasDrawingTask() const { return !!mTask; } + +protected: + DrawingTask* mTask; +}; + +} // namespace +} // namespace + +#endif diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index f742f6f3283c..4c46c6e336be 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -127,6 +127,7 @@ UNIFIED_SOURCES += [ 'DataSourceSurface.cpp', 'DataSurfaceHelpers.cpp', 'DrawEventRecorder.cpp', + 'DrawingTask.cpp', 'DrawTarget.cpp', 'DrawTargetCairo.cpp', 'DrawTargetCapture.cpp',