Bug 857895 - Run canvas rendering asynchronously on OSX. r=Bas,bholley

This commit is contained in:
Matt Woodrow 2013-04-09 16:51:44 +12:00
parent e8febe7166
commit 6719119889
7 changed files with 315 additions and 33 deletions

View File

@ -19,6 +19,8 @@
#include "nsSVGEffects.h" #include "nsSVGEffects.h"
#include "nsPresContext.h" #include "nsPresContext.h"
#include "nsIPresShell.h" #include "nsIPresShell.h"
#include "nsWidgetsCID.h"
#include "nsIAppShell.h"
#include "nsIInterfaceRequestorUtils.h" #include "nsIInterfaceRequestorUtils.h"
#include "nsIFrame.h" #include "nsIFrame.h"
@ -114,6 +116,7 @@
#include "nsDeviceContext.h" #include "nsDeviceContext.h"
#include "nsFontMetrics.h" #include "nsFontMetrics.h"
#include "Units.h" #include "Units.h"
#include "mozilla/Services.h"
#undef free // apparently defined by some windows header, clashing with a free() #undef free // apparently defined by some windows header, clashing with a free()
// method in SkTypes.h // method in SkTypes.h
@ -179,6 +182,64 @@ public:
NS_IMPL_ISUPPORTS(Canvas2dPixelsReporter, nsIMemoryReporter) NS_IMPL_ISUPPORTS(Canvas2dPixelsReporter, nsIMemoryReporter)
class CanvasShutdownObserver : public nsIObserver
{
virtual ~CanvasShutdownObserver() {}
public:
NS_DECL_ISUPPORTS
explicit CanvasShutdownObserver(CanvasRenderingContext2D* aCanvas)
: mCanvas(aCanvas)
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
observerService->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false);
}
void Shutdown() {
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
observerService->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
}
NS_IMETHOD Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData) override
{
mCanvas->ShutdownTaskQueue();
return NS_OK;
}
private:
CanvasRenderingContext2D* mCanvas;
};
NS_IMPL_ISUPPORTS(CanvasShutdownObserver, nsIObserver);
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
void
CanvasRenderingContext2D::RecordCommand()
{
static uint32_t kBatchSize = 5;
if (++mPendingCommands > kBatchSize) {
mPendingCommands = 0;
FlushDelayedTarget();
return;
}
if (mScheduledFlush) {
return;
}
mScheduledFlush = true;
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &CanvasRenderingContext2D::StableStateReached);
appShell->RunInStableState(r);
}
class CanvasRadialGradient : public CanvasGradient class CanvasRadialGradient : public CanvasGradient
{ {
public: public:
@ -393,6 +454,11 @@ public:
mCtx->CurrentState().filterAdditionalImages, mCtx->CurrentState().filterAdditionalImages,
mPostFilterBounds.TopLeft() - mOffset, mPostFilterBounds.TopLeft() - mOffset,
DrawOptions(1.0f, mCompositionOp)); DrawOptions(1.0f, mCompositionOp));
// DrawTargetCapture doesn't properly support filter nodes because they are
// mutable. Block until drawing is done to avoid races.
mCtx->FlushDelayedTarget();
mCtx->FinishDelayedRendering();
} }
DrawTarget* DT() DrawTarget* DT()
@ -817,6 +883,9 @@ public:
if (!context || !context->mTarget) if (!context || !context->mTarget)
return; return;
context->FlushDelayedTarget();
context->FinishDelayedRendering();
// Since SkiaGL default to store drawing command until flush // Since SkiaGL default to store drawing command until flush
// We will have to flush it before present. // We will have to flush it before present.
context->mTarget->Flush(); context->mTarget->Flush();
@ -938,6 +1007,8 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
, mZero(false), mOpaque(false) , mZero(false), mOpaque(false)
, mResetLayer(true) , mResetLayer(true)
, mIPC(false) , mIPC(false)
, mPendingCommands(0)
, mScheduledFlush(false)
, mDrawObserver(nullptr) , mDrawObserver(nullptr)
, mIsEntireFrameInvalid(false) , mIsEntireFrameInvalid(false)
, mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false) , mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
@ -945,6 +1016,14 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
{ {
sNumLivingContexts++; sNumLivingContexts++;
#ifdef XP_MACOSX
// Restrict async rendering to OSX for now until the failures on other
// platforms get resolved.
mTaskQueue = new MediaTaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("Canvas Rendering"),
4));
mShutdownObserver = new CanvasShutdownObserver(this);
#endif
// The default is to use OpenGL mode // The default is to use OpenGL mode
if (!gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas()) { if (!gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas()) {
mRenderingMode = RenderingMode::SoftwareBackendMode; mRenderingMode = RenderingMode::SoftwareBackendMode;
@ -957,6 +1036,9 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
CanvasRenderingContext2D::~CanvasRenderingContext2D() CanvasRenderingContext2D::~CanvasRenderingContext2D()
{ {
if (mTaskQueue) {
ShutdownTaskQueue();
}
RemoveDrawObserver(); RemoveDrawObserver();
RemovePostRefreshObserver(); RemovePostRefreshObserver();
Reset(); Reset();
@ -979,6 +1061,19 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D()
RemoveDemotableContext(this); RemoveDemotableContext(this);
} }
void
CanvasRenderingContext2D::ShutdownTaskQueue()
{
mShutdownObserver->Shutdown();
mShutdownObserver = nullptr;
FlushDelayedTarget();
FinishDelayedRendering();
mTaskQueue->BeginShutdown();
mTaskQueue = nullptr;
mDelayedTarget = nullptr;
}
JSObject* JSObject*
CanvasRenderingContext2D::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) CanvasRenderingContext2D::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
{ {
@ -1034,7 +1129,10 @@ CanvasRenderingContext2D::Reset()
gCanvasAzureMemoryUsed -= mWidth * mHeight * 4; gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
} }
FinishDelayedRendering();
mTarget = nullptr; mTarget = nullptr;
mDelayedTarget = nullptr;
mFinalTarget = nullptr;
// reset hit regions // reset hit regions
mHitRegionsOptions.ClearAndRetainStorage(); mHitRegionsOptions.ClearAndRetainStorage();
@ -1101,6 +1199,8 @@ CanvasRenderingContext2D::StyleColorToString(const nscolor& aColor, nsAString& a
nsresult nsresult
CanvasRenderingContext2D::Redraw() CanvasRenderingContext2D::Redraw()
{ {
RecordCommand();
if (mIsEntireFrameInvalid) { if (mIsEntireFrameInvalid) {
return NS_OK; return NS_OK;
} }
@ -1122,6 +1222,7 @@ CanvasRenderingContext2D::Redraw()
void void
CanvasRenderingContext2D::Redraw(const mgfx::Rect &r) CanvasRenderingContext2D::Redraw(const mgfx::Rect &r)
{ {
RecordCommand();
++mInvalidateCount; ++mInvalidateCount;
if (mIsEntireFrameInvalid) { if (mIsEntireFrameInvalid) {
@ -1144,6 +1245,18 @@ CanvasRenderingContext2D::Redraw(const mgfx::Rect &r)
mCanvasElement->InvalidateCanvasContent(&r); mCanvasElement->InvalidateCanvasContent(&r);
} }
TemporaryRef<SourceSurface>
CanvasRenderingContext2D::GetSurfaceSnapshot(bool* aPremultAlpha /* = nullptr */)
{
EnsureTarget();
if (aPremultAlpha) {
*aPremultAlpha = true;
}
FlushDelayedTarget();
FinishDelayedRendering();
return mFinalTarget->Snapshot();
}
void void
CanvasRenderingContext2D::DidRefresh() CanvasRenderingContext2D::DidRefresh()
{ {
@ -1161,6 +1274,7 @@ CanvasRenderingContext2D::RedrawUser(const gfxRect& r)
{ {
if (mIsEntireFrameInvalid) { if (mIsEntireFrameInvalid) {
++mInvalidateCount; ++mInvalidateCount;
RecordCommand();
return; return;
} }
@ -1186,7 +1300,7 @@ bool CanvasRenderingContext2D::SwitchRenderingMode(RenderingMode aRenderingMode)
} }
#endif #endif
RefPtr<SourceSurface> snapshot = mTarget->Snapshot(); RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot();
RefPtr<DrawTarget> oldTarget = mTarget; RefPtr<DrawTarget> oldTarget = mTarget;
mTarget = nullptr; mTarget = nullptr;
mResetLayer = true; mResetLayer = true;
@ -1360,7 +1474,7 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode)
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue(); SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
if (glue && glue->GetGrContext() && glue->GetGLContext()) { if (glue && glue->GetGrContext() && glue->GetGLContext()) {
mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format); mFinalTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
if (mTarget) { if (mTarget) {
AddDemotableContext(this); AddDemotableContext(this);
} else { } else {
@ -1369,19 +1483,31 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode)
} }
} }
#endif #endif
if (!mTarget) { if (!mFinalTarget) {
mTarget = layerManager->CreateDrawTarget(size, format); mFinalTarget = layerManager->CreateDrawTarget(size, format);
} }
} else { } else {
mTarget = layerManager->CreateDrawTarget(size, format); mFinalTarget = layerManager->CreateDrawTarget(size, format);
mode = RenderingMode::SoftwareBackendMode; mode = RenderingMode::SoftwareBackendMode;
} }
} else { } else {
mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format); mFinalTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
mode = RenderingMode::SoftwareBackendMode; mode = RenderingMode::SoftwareBackendMode;
} }
} }
// Restrict async canvas drawing to OSX for now since we get test failures
// on other platforms.
if (mFinalTarget) {
#ifdef XP_MACOSX
mTarget = mDelayedTarget = mFinalTarget->CreateCaptureDT(size);
#else
mTarget = mFinalTarget;
#endif
}
mPendingCommands = 0;
if (mTarget) { if (mTarget) {
static bool registered = false; static bool registered = false;
if (!registered) { if (!registered) {
@ -1415,7 +1541,7 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode)
Redraw(); Redraw();
} else { } else {
EnsureErrorTarget(); EnsureErrorTarget();
mTarget = sErrorTarget; mTarget = mFinalTarget = sErrorTarget;
} }
return mode; return mode;
@ -1435,6 +1561,51 @@ CanvasRenderingContext2D::GetHeight() const
} }
#endif #endif
class DrawCaptureTask : public nsRunnable
{
public:
DrawCaptureTask(DrawTargetCapture *aReplay, DrawTarget* aDest)
: mReplay(aReplay)
, mDest(aDest)
{
}
NS_IMETHOD Run()
{
mDest->DrawCapturedDT(mReplay, Matrix());
return NS_OK;
}
private:
RefPtr<DrawTargetCapture> mReplay;
RefPtr<DrawTarget> mDest;
};
void
CanvasRenderingContext2D::FlushDelayedTarget()
{
if (!mDelayedTarget) {
return;
}
mPendingCommands = 0;
nsCOMPtr<nsIRunnable> task = new DrawCaptureTask(mDelayedTarget, mFinalTarget);
mTaskQueue->Dispatch(task.forget());
mDelayedTarget = mFinalTarget->CreateCaptureDT(IntSize(mWidth, mHeight));
mDelayedTarget->SetTransform(mTarget->GetTransform());
mTarget = mDelayedTarget;
}
void
CanvasRenderingContext2D::FinishDelayedRendering()
{
if (mTaskQueue) {
mTaskQueue->AwaitIdle();
}
}
NS_IMETHODIMP NS_IMETHODIMP
CanvasRenderingContext2D::SetDimensions(int32_t width, int32_t height) CanvasRenderingContext2D::SetDimensions(int32_t width, int32_t height)
{ {
@ -1584,7 +1755,7 @@ CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
*aFormat = 0; *aFormat = 0;
EnsureTarget(); EnsureTarget();
RefPtr<SourceSurface> snapshot = mTarget->Snapshot(); RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot();
if (!snapshot) { if (!snapshot) {
return; return;
} }
@ -2003,7 +2174,7 @@ CanvasRenderingContext2D::CreatePattern(const HTMLImageOrCanvasOrVideoElement& e
// of animated images // of animated images
nsLayoutUtils::SurfaceFromElementResult res = nsLayoutUtils::SurfaceFromElementResult res =
nsLayoutUtils::SurfaceFromElement(htmlElement, nsLayoutUtils::SurfaceFromElement(htmlElement,
nsLayoutUtils::SFE_WANT_FIRST_FRAME, mTarget); nsLayoutUtils::SFE_WANT_FIRST_FRAME, mFinalTarget);
if (!res.mSourceSurface) { if (!res.mSourceSurface) {
error.Throw(NS_ERROR_NOT_AVAILABLE); error.Throw(NS_ERROR_NOT_AVAILABLE);
@ -4314,7 +4485,7 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
nsLayoutUtils::SurfaceFromElementResult res = nsLayoutUtils::SurfaceFromElementResult res =
CachedSurfaceFromElement(element); CachedSurfaceFromElement(element);
if (!res.mSourceSurface) if (!res.mSourceSurface)
res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget); res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mFinalTarget);
if (!res.mSourceSurface && !res.mDrawInfo.mImgContainer) { if (!res.mSourceSurface && !res.mDrawInfo.mImgContainer) {
// The spec says to silently do nothing in the following cases: // The spec says to silently do nothing in the following cases:
@ -4658,7 +4829,12 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget) && if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget) &&
GlobalAlpha() == 1.0f) GlobalAlpha() == 1.0f)
{ {
thebes = new gfxContext(mTarget); // Complete any async rendering and use synchronous rendering for DrawWindow
// until we're confident it works for all content.
FlushDelayedTarget();
FinishDelayedRendering();
thebes = new gfxContext(mFinalTarget);
thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21, thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
matrix._22, matrix._31, matrix._32)); matrix._22, matrix._31, matrix._32));
} else { } else {
@ -4915,7 +5091,7 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
IntRect srcReadRect = srcRect.Intersect(destRect); IntRect srcReadRect = srcRect.Intersect(destRect);
RefPtr<DataSourceSurface> readback; RefPtr<DataSourceSurface> readback;
if (!srcReadRect.IsEmpty() && !mZero) { if (!srcReadRect.IsEmpty() && !mZero) {
RefPtr<SourceSurface> snapshot = mTarget->Snapshot(); RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot();
if (snapshot) { if (snapshot) {
readback = snapshot->GetDataSurface(); readback = snapshot->GetDataSurface();
} }
@ -5301,7 +5477,7 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
return nullptr; return nullptr;
} }
mTarget->Flush(); FlushDelayedTarget();
if (!mResetLayer && aOldLayer) { if (!mResetLayer && aOldLayer) {
CanvasRenderingContext2DUserData* userData = CanvasRenderingContext2DUserData* userData =
@ -5350,6 +5526,8 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
userData = new CanvasRenderingContext2DUserData(this); userData = new CanvasRenderingContext2DUserData(this);
canvasLayer->SetDidTransactionCallback( canvasLayer->SetDidTransactionCallback(
CanvasRenderingContext2DUserData::DidTransactionCallback, userData); CanvasRenderingContext2DUserData::DidTransactionCallback, userData);
canvasLayer->SetPreTransactionCallback(
CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
canvasLayer->SetUserData(&g2DContextLayerUserData, userData); canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
CanvasLayer::Data data; CanvasLayer::Data data;
@ -5358,16 +5536,13 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
GLuint skiaGLTex = SkiaGLTex(); GLuint skiaGLTex = SkiaGLTex();
if (skiaGLTex) { if (skiaGLTex) {
canvasLayer->SetPreTransactionCallback(
CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue(); SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
MOZ_ASSERT(glue); MOZ_ASSERT(glue);
data.mGLContext = glue->GetGLContext(); data.mGLContext = glue->GetGLContext();
data.mFrontbufferGLTex = skiaGLTex; data.mFrontbufferGLTex = skiaGLTex;
} else { } else {
data.mDrawTarget = mTarget; data.mDrawTarget = mFinalTarget;
} }
canvasLayer->Initialize(data); canvasLayer->Initialize(data);

View File

@ -10,6 +10,7 @@
#include "nsIDOMCanvasRenderingContext2D.h" #include "nsIDOMCanvasRenderingContext2D.h"
#include "nsICanvasRenderingContextInternal.h" #include "nsICanvasRenderingContextInternal.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "mozilla/Monitor.h"
#include "nsColor.h" #include "nsColor.h"
#include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/HTMLVideoElement.h" #include "mozilla/dom/HTMLVideoElement.h"
@ -27,6 +28,7 @@
#include "mozilla/EnumeratedArray.h" #include "mozilla/EnumeratedArray.h"
#include "FilterSupport.h" #include "FilterSupport.h"
#include "nsSVGEffects.h" #include "nsSVGEffects.h"
#include "MediaTaskQueue.h"
class nsGlobalWindow; class nsGlobalWindow;
class nsXULElement; class nsXULElement;
@ -52,6 +54,7 @@ template<typename T> class Optional;
struct CanvasBidiProcessor; struct CanvasBidiProcessor;
class CanvasRenderingContext2DUserData; class CanvasRenderingContext2DUserData;
class CanvasDrawObserver; class CanvasDrawObserver;
class CanvasShutdownObserver;
/** /**
** CanvasRenderingContext2D ** CanvasRenderingContext2D
@ -442,14 +445,7 @@ public:
const char16_t* aEncoderOptions, const char16_t* aEncoderOptions,
nsIInputStream **aStream) override; nsIInputStream **aStream) override;
mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override;
{
EnsureTarget();
if (aPremultAlpha) {
*aPremultAlpha = true;
}
return mTarget->Snapshot();
}
NS_IMETHOD SetIsOpaque(bool isOpaque) override; NS_IMETHOD SetIsOpaque(bool isOpaque) override;
bool GetIsOpaque() override { return mOpaque; } bool GetIsOpaque() override { return mOpaque; }
@ -521,6 +517,7 @@ public:
} }
friend class CanvasRenderingContext2DUserData; friend class CanvasRenderingContext2DUserData;
friend class CanvasShutdownObserver;
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) override; virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) override;
@ -532,6 +529,21 @@ public:
// return true and fills in the bound rect if element has a hit region. // return true and fills in the bound rect if element has a hit region.
bool GetHitRegionRect(Element* aElement, nsRect& aRect) override; bool GetHitRegionRect(Element* aElement, nsRect& aRect) override;
/**
* Deferred rendering functions
*/
/**
* Called when the event loop reaches a stable
* state, and trigger us to flush any outstanding
* commands to the rendering thread.
*/
void StableStateReached()
{
mScheduledFlush = false;
FlushDelayedTarget();
}
protected: protected:
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY, nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
uint32_t aWidth, uint32_t aHeight, uint32_t aWidth, uint32_t aHeight,
@ -550,6 +562,8 @@ protected:
nsresult InitializeWithTarget(mozilla::gfx::DrawTarget *surface, nsresult InitializeWithTarget(mozilla::gfx::DrawTarget *surface,
int32_t width, int32_t height); int32_t width, int32_t height);
void ShutdownTaskQueue();
/** /**
* The number of living nsCanvasRenderingContexts. When this goes down to * The number of living nsCanvasRenderingContexts. When this goes down to
* 0, we free the premultiply and unpremultiply tables, if they exist. * 0, we free the premultiply and unpremultiply tables, if they exist.
@ -713,6 +727,54 @@ protected:
// sErrorTarget. // sErrorTarget.
mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget; mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
/**
* Deferred rendering implementation
*/
// If we are using deferred rendering, then this is the current
// deferred rendering target. It is the same pointer as mTarget.
mozilla::RefPtr<mozilla::gfx::DrawTargetCapture> mDelayedTarget;
// If we are using deferred rendering, then this is the actual destination
// buffer.
mozilla::RefPtr<mozilla::gfx::DrawTarget> mFinalTarget;
/**
* Add the current DelayedDrawTarget to the rendering queue,
* schedule a rendering job if required, and create a new
* DelayedDrawTarget.
*/
void FlushDelayedTarget();
/**
* Make sure all commands have been flushed to
* the rendering thread, and block until they
* are completed.
*/
void FinishDelayedRendering();
/**
* Called when a command is added to the current
* delayed draw target.
*
* Either flushes the current batch of commands to
* the rendering thread, or ensures that this happens
* the next time the event loop reaches a stable state.
*/
void RecordCommand();
// The number of commands currently waiting to be sent
// to the rendering thread.
uint32_t mPendingCommands;
// True if we have scheduled FlushDelayedTarget to be
// called in the next browser stable state.
bool mScheduledFlush;
nsRefPtr<MediaTaskQueue> mTaskQueue;
nsRefPtr<CanvasShutdownObserver> mShutdownObserver;
uint32_t SkiaGLTex() const; uint32_t SkiaGLTex() const;
// This observes our draw calls at the beginning of the canvas // This observes our draw calls at the beginning of the canvas

View File

@ -27,6 +27,7 @@ MediaTaskQueue::~MediaTaskQueue()
{ {
MonitorAutoLock mon(mQueueMonitor); MonitorAutoLock mon(mQueueMonitor);
MOZ_ASSERT(mIsShutdown); MOZ_ASSERT(mIsShutdown);
MOZ_DIAGNOSTIC_ASSERT(mTasks.empty());
MOZ_COUNT_DTOR(MediaTaskQueue); MOZ_COUNT_DTOR(MediaTaskQueue);
} }

View File

@ -155,7 +155,7 @@ struct DrawSurfaceOptions {
* matching DrawTarget. Not adhering to this condition will make a draw call * matching DrawTarget. Not adhering to this condition will make a draw call
* fail. * fail.
*/ */
class GradientStops : public RefCounted<GradientStops> class GradientStops : public external::AtomicRefCounted<GradientStops>
{ {
public: public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops) MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops)
@ -318,7 +318,7 @@ class DrawTargetCaptureImpl;
* which may be used as a source in a SurfacePattern or a DrawSurface call. * which may be used as a source in a SurfacePattern or a DrawSurface call.
* They cannot be drawn to directly. * They cannot be drawn to directly.
*/ */
class SourceSurface : public RefCounted<SourceSurface> class SourceSurface : public external::AtomicRefCounted<SourceSurface>
{ {
public: public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface) MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface)
@ -476,7 +476,7 @@ class FlattenedPath;
/** The path class is used to create (sets of) figures of any shape that can be /** The path class is used to create (sets of) figures of any shape that can be
* filled or stroked to a DrawTarget * filled or stroked to a DrawTarget
*/ */
class Path : public RefCounted<Path> class Path : public external::AtomicRefCounted<Path>
{ {
public: public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path) MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path)
@ -577,7 +577,7 @@ struct GlyphBuffer
* at a particular size. It is passed into text drawing calls to describe * at a particular size. It is passed into text drawing calls to describe
* the font used for the drawing call. * the font used for the drawing call.
*/ */
class ScaledFont : public RefCounted<ScaledFont> class ScaledFont : public external::AtomicRefCounted<ScaledFont>
{ {
public: public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont) MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
@ -622,7 +622,7 @@ protected:
* parameters. This is because different platforms have unique rendering * parameters. This is because different platforms have unique rendering
* parameters. * parameters.
*/ */
class GlyphRenderingOptions : public RefCounted<GlyphRenderingOptions> class GlyphRenderingOptions : public external::AtomicRefCounted<GlyphRenderingOptions>
{ {
public: public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptions) MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptions)
@ -641,7 +641,7 @@ class DrawTargetCapture;
* may be used either through a Snapshot or by flushing the target and directly * may be used either through a Snapshot or by flushing the target and directly
* accessing the backing store a DrawTarget was created with. * accessing the backing store a DrawTarget was created with.
*/ */
class DrawTarget : public RefCounted<DrawTarget> class DrawTarget : public external::AtomicRefCounted<DrawTarget>
{ {
public: public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget) MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget)

View File

@ -148,7 +148,7 @@ class DrawFilterCommand : public DrawingCommand
public: public:
DrawFilterCommand(FilterNode* aFilter, const Rect& aSourceRect, DrawFilterCommand(FilterNode* aFilter, const Rect& aSourceRect,
const Point& aDestPoint, const DrawOptions& aOptions) const Point& aDestPoint, const DrawOptions& aOptions)
: DrawingCommand(CommandType::DRAWSURFACE) : DrawingCommand(CommandType::DRAWFILTER)
, mFilter(aFilter), mSourceRect(aSourceRect) , mFilter(aFilter), mSourceRect(aSourceRect)
, mDestPoint(aDestPoint), mOptions(aOptions) , mDestPoint(aDestPoint), mOptions(aOptions)
{ {
@ -166,6 +166,36 @@ private:
DrawOptions mOptions; DrawOptions mOptions;
}; };
class DrawSurfaceWithShadowCommand : public DrawingCommand
{
public:
DrawSurfaceWithShadowCommand(SourceSurface* aSurface, const Point& aDest,
const Color& aColor, const Point& aOffset,
Float aSigma, CompositionOp aOperator)
: DrawingCommand(CommandType::DRAWSURFACEWITHSHADOW)
, mSurface(aSurface)
, mDest(aDest)
, mColor(aColor)
, mOffset(aOffset)
, mSigma(aSigma)
, mOperator(aOperator)
{
}
virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&)
{
aDT->DrawSurfaceWithShadow(mSurface, mDest, mColor, mOffset, mSigma, mOperator);
}
private:
RefPtr<SourceSurface> mSurface;
Point mDest;
Color mColor;
Point mOffset;
Float mSigma;
CompositionOp mOperator;
};
class ClearRectCommand : public DrawingCommand class ClearRectCommand : public DrawingCommand
{ {
public: public:

View File

@ -30,6 +30,7 @@ DrawTargetCaptureImpl::Init(const IntSize& aSize, DrawTarget* aRefDT)
} }
mRefDT = aRefDT; mRefDT = aRefDT;
mFormat = mRefDT->GetFormat();
mSize = aSize; mSize = aSize;
return true; return true;
@ -69,6 +70,18 @@ DrawTargetCaptureImpl::DrawFilter(FilterNode *aNode,
AppendCommand(DrawFilterCommand)(aNode, aSourceRect, aDestPoint, aOptions); AppendCommand(DrawFilterCommand)(aNode, aSourceRect, aDestPoint, aOptions);
} }
void
DrawTargetCaptureImpl::DrawSurfaceWithShadow(SourceSurface *aSurface,
const Point &aDest,
const Color &aColor,
const Point &aOffset,
Float aSigma,
CompositionOp aOperator)
{
aSurface->GuaranteePersistance();
AppendCommand(DrawSurfaceWithShadowCommand)(aSurface, aDest, aColor, aOffset, aSigma, aOperator);
}
void void
DrawTargetCaptureImpl::ClearRect(const Rect &aRect) DrawTargetCaptureImpl::ClearRect(const Rect &aRect)
{ {
@ -178,6 +191,7 @@ void
DrawTargetCaptureImpl::SetTransform(const Matrix& aTransform) DrawTargetCaptureImpl::SetTransform(const Matrix& aTransform)
{ {
AppendCommand(SetTransformCommand)(aTransform); AppendCommand(SetTransformCommand)(aTransform);
mTransform = aTransform;
} }
void void

View File

@ -45,7 +45,7 @@ public:
const Color &aColor, const Color &aColor,
const Point &aOffset, const Point &aOffset,
Float aSigma, Float aSigma,
CompositionOp aOperator) { /* Not implemented */ } CompositionOp aOperator);
virtual void ClearRect(const Rect &aRect); virtual void ClearRect(const Rect &aRect);
virtual void MaskSurface(const Pattern &aSource, virtual void MaskSurface(const Pattern &aSource,