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

This commit is contained in:
Nicolas Silva 2015-09-24 17:35:15 +02:00
parent dbac937791
commit 9a89fcdfb3
5 changed files with 305 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;
}
}

120
gfx/2d/DrawingJob.cpp Normal file
View File

@ -0,0 +1,120 @@
/* -*- 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 "DrawingJob.h"
#include "JobScheduler.h"
#include "mozilla/gfx/2D.h"
namespace mozilla {
namespace gfx {
DrawingJobBuilder::DrawingJobBuilder()
{}
DrawingJobBuilder::~DrawingJobBuilder()
{
MOZ_ASSERT(!mDrawTarget);
}
void
DrawingJob::Clear()
{
mCommandBuffer = nullptr;
mCursor = 0;
}
void
DrawingJobBuilder::BeginDrawingJob(DrawTarget* aTarget, IntPoint aOffset,
SyncObject* aStart)
{
MOZ_ASSERT(mCommandOffsets.empty());
MOZ_ASSERT(aTarget);
mDrawTarget = aTarget;
mOffset = aOffset;
mStart = aStart;
}
DrawingJob*
DrawingJobBuilder::EndDrawingJob(CommandBuffer* aCmdBuffer,
SyncObject* aCompletion,
WorkerThread* aPinToWorker)
{
MOZ_ASSERT(mDrawTarget);
DrawingJob* task = new DrawingJob(mDrawTarget, mOffset, mStart, aCompletion, aPinToWorker);
task->mCommandBuffer = aCmdBuffer;
task->mCommandOffsets = Move(mCommandOffsets);
mDrawTarget = nullptr;
mOffset = IntPoint();
mStart = nullptr;
return task;
}
DrawingJob::DrawingJob(DrawTarget* aTarget, IntPoint aOffset,
SyncObject* aStart, SyncObject* aCompletion,
WorkerThread* aPinToWorker)
: Job(aStart, aCompletion, aPinToWorker)
, mCommandBuffer(nullptr)
, mCursor(0)
, mDrawTarget(aTarget)
, mOffset(aOffset)
{
mCommandOffsets.reserve(64);
}
JobStatus
DrawingJob::Run()
{
while (mCursor < mCommandOffsets.size()) {
DrawingCommand* cmd = mCommandBuffer->GetDrawingCommand(mCommandOffsets[mCursor]);
if (!cmd) {
return JobStatus::Error;
}
cmd->ExecuteOnDT(mDrawTarget);
++mCursor;
}
return JobStatus::Complete;
}
DrawingJob::~DrawingJob()
{
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

157
gfx/2d/DrawingJob.h Normal file
View File

@ -0,0 +1,157 @@
/* -*- 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/JobScheduler.h"
#include "mozilla/gfx/IterableArena.h"
#include "DrawCommand.h"
namespace mozilla {
namespace gfx {
class DrawingCommand;
class PrintCommand;
class SignalCommand;
class DrawingJob;
class WaitCommand;
class SyncObject;
class MultiThreadedJobQueue;
class DrawTarget;
class DrawingJobBuilder;
class CommandBufferBuilder;
/// Contains a sequence of immutable drawing commands that are typically used by
/// several DrawingJobs.
///
/// 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:
explicit 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 DrawingJob : public Job {
public:
~DrawingJob();
virtual JobStatus Run() override;
protected:
DrawingJob(DrawTarget* aTarget,
IntPoint aOffset,
SyncObject* aStart,
SyncObject* aCompletion,
WorkerThread* aPinToWorker = nullptr);
/// 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 DrawingJobBuilder;
};
/// Generates DrawingJob objects.
///
/// The builder is a separate object to ensure that commands are not added to a
/// submitted DrawingJob.
class DrawingJobBuilder {
public:
DrawingJobBuilder();
~DrawingJobBuilder();
/// Allocates a DrawingJob.
///
/// call this method before starting to add commands.
void BeginDrawingJob(DrawTarget* aTarget, IntPoint aOffset,
SyncObject* aStart = nullptr);
/// Build the DrawingJob, command after command.
/// This must be used between BeginDrawingJob and EndDrawingJob.
void AddCommand(ptrdiff_t offset)
{
mCommandOffsets.push_back(offset);
}
/// Finalizes and returns the drawing task.
///
/// 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.
DrawingJob* EndDrawingJob(CommandBuffer* aCmdBuffer,
SyncObject* aCompletion = nullptr,
WorkerThread* aPinToWorker = nullptr);
/// Returns true between BeginDrawingJob and EndDrawingJob, false otherwise.
bool HasDrawingJob() const { return !!mDrawTarget; }
protected:
std::vector<ptrdiff_t> mCommandOffsets;
RefPtr<DrawTarget> mDrawTarget;
IntPoint mOffset;
RefPtr<SyncObject> mStart;
};
} // namespace
} // namespace
#endif

View File

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