Bug 1083101 - Implement gfx::DrawingTask. r=jrmuizel

This commit is contained in:
Nicolas Silva 2015-09-04 14:27:30 +02:00
parent aaddfb2ca8
commit bd562c4ed4
5 changed files with 297 additions and 23 deletions

View File

@ -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:

View File

@ -188,7 +188,7 @@ DrawTargetCaptureImpl::ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransf
uint8_t* current = start;
while (current < start + mDrawCommandStorage.size()) {
reinterpret_cast<DrawingCommand*>(current + sizeof(uint32_t))->ExecuteOnDT(aDT, aTransform);
reinterpret_cast<DrawingCommand*>(current + sizeof(uint32_t))->ExecuteOnDT(aDT, &aTransform);
current += *(uint32_t*)current;
}
}

116
gfx/2d/DrawingTask.cpp Normal file
View File

@ -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<DrawingCommand*>(mStorage.GetStorage(aId));
}
CommandBuffer::~CommandBuffer()
{
mStorage.ForEach([](void* item){
static_cast<DrawingCommand*>(item)->~DrawingCommand();
});
mStorage.Clear();
}
void
CommandBufferBuilder::BeginCommandBuffer(size_t aBufferSize)
{
MOZ_ASSERT(!mCommands);
mCommands = new CommandBuffer(aBufferSize);
}
already_AddRefed<CommandBuffer>
CommandBufferBuilder::EndCommandBuffer()
{
return mCommands.forget();
}
} // namespace
} // namespace

153
gfx/2d/DrawingTask.h Normal file
View File

@ -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 <stdint.h>
#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<CommandBuffer>
{
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<CommandBuffer> EndCommandBuffer();
/// Build the CommandBuffer, command after command.
/// This must be used between BeginCommandBuffer and EndCommandBuffer.
template<typename T, typename... Args>
ptrdiff_t AddCommand(Args&&... aArgs)
{
static_assert(IsBaseOf<DrawingCommand, T>::value,
"T must derive from DrawingCommand");
return mCommands->mStorage.Alloc<T>(Forward<Args>(aArgs)...);
}
bool HasCommands() const { return !!mCommands; }
protected:
RefPtr<CommandBuffer> 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<ptrdiff_t> mCommandOffsets;
RefPtr<CommandBuffer> mCommandBuffer;
uint32_t mCursor;
RefPtr<DrawTarget> 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

View File

@ -127,6 +127,7 @@ UNIFIED_SOURCES += [
'DataSourceSurface.cpp',
'DataSurfaceHelpers.cpp',
'DrawEventRecorder.cpp',
'DrawingTask.cpp',
'DrawTarget.cpp',
'DrawTargetCairo.cpp',
'DrawTargetCapture.cpp',