# HG changeset patch # User Morris Tseng Bug 709490 - part 7 interdiff. diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp index 32106b3..79e4806 100644 --- a/dom/canvas/OffscreenCanvas.cpp +++ b/dom/canvas/OffscreenCanvas.cpp @@ -18,35 +18,39 @@ #include "WebGL1Context.h" #include "WebGL2Context.h" namespace mozilla { namespace dom { OffscreenCanvasCloneData::OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, uint32_t aWidth, uint32_t aHeight, + layers::LayersBackend aCompositorBackend, bool aNeutered) : mRenderer(aRenderer) , mWidth(aWidth) , mHeight(aHeight) + , mCompositorBackendType(aCompositorBackend) , mNeutered(aNeutered) { } OffscreenCanvasCloneData::~OffscreenCanvasCloneData() { } OffscreenCanvas::OffscreenCanvas(uint32_t aWidth, uint32_t aHeight, + layers::LayersBackend aCompositorBackend, layers::AsyncCanvasRenderer* aRenderer) : mAttrDirty(false) , mNeutered(false) , mWidth(aWidth) , mHeight(aHeight) + , mCompositorBackendType(aCompositorBackend) , mCanvasClient(nullptr) , mCanvasRenderer(aRenderer) {} OffscreenCanvas::~OffscreenCanvas() { ClearResources(); } @@ -68,16 +72,19 @@ void OffscreenCanvas::ClearResources() { if (mCanvasClient) { mCanvasClient->Clear(); ImageBridgeChild::DispatchReleaseCanvasClient(mCanvasClient); mCanvasClient = nullptr; if (mCanvasRenderer) { + nsCOMPtr activeThread = mCanvasRenderer->GetActiveThread(); + MOZ_RELEASE_ASSERT(activeThread); + MOZ_RELEASE_ASSERT(activeThread == NS_GetCurrentThread()); mCanvasRenderer->SetCanvasClient(nullptr); mCanvasRenderer->mContext = nullptr; mCanvasRenderer->mGLContext = nullptr; mCanvasRenderer->ResetActiveThread(); } } } @@ -140,22 +147,16 @@ OffscreenCanvas::GetContext(JSContext* aCx, if (factory) screen->Morph(Move(factory)); } } return result; } -layers::LayersBackend -OffscreenCanvas::GetLayersBackend() const -{ - return mCanvasRenderer ? mCanvasRenderer->mBackend : LayersBackend::LAYERS_NONE; -} - already_AddRefed OffscreenCanvas::CreateContext(CanvasContextType aContextType) { nsRefPtr ret = CanvasRenderingContextHelper::CreateContext(aContextType); ret->SetOffscreenCanvas(this); return ret.forget(); @@ -176,36 +177,35 @@ OffscreenCanvas::CommitFrameToCompositor() } if (mCurrentContext) { static_cast(mCurrentContext.get())->PresentScreenBuffer(); } if (mCanvasRenderer && mCanvasRenderer->mGLContext) { mCanvasRenderer->NotifyElementAboutInvalidation(); - if (mCanvasRenderer->mBackend != layers::LayersBackend::LAYERS_BASIC) { - ImageBridgeChild::GetSingleton()-> - UpdateAsyncCanvasRenderer(mCanvasRenderer); - } + ImageBridgeChild::GetSingleton()-> + UpdateAsyncCanvasRenderer(mCanvasRenderer); } } OffscreenCanvasCloneData* OffscreenCanvas::ToCloneData() { - return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, - mHeight, mNeutered); + return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, mHeight, + mCompositorBackendType, mNeutered); } /* static */ already_AddRefed OffscreenCanvas::CreateFromCloneData(OffscreenCanvasCloneData* aData) { MOZ_ASSERT(aData); nsRefPtr wc = - new OffscreenCanvas(aData->mWidth, aData->mHeight, aData->mRenderer); + new OffscreenCanvas(aData->mWidth, aData->mHeight, + aData->mCompositorBackendType, aData->mRenderer); if (aData->mNeutered) { wc->SetNeutered(); } return wc.forget(); } /* static */ bool OffscreenCanvas::PrefEnabled(JSContext* aCx, JSObject* aObj) diff --git a/dom/canvas/OffscreenCanvas.h b/dom/canvas/OffscreenCanvas.h index 25baff0..cdad6bc 100644 --- a/dom/canvas/OffscreenCanvas.h +++ b/dom/canvas/OffscreenCanvas.h @@ -29,34 +29,37 @@ namespace dom { // This is helper class for transferring OffscreenCanvas to worker thread. // Because OffscreenCanvas is not thread-safe. So we cannot pass Offscreen- // Canvas to worker thread directly. Thus, we create this helper class and // store necessary data in it then pass it to worker thread. struct OffscreenCanvasCloneData final { OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, uint32_t aWidth, uint32_t aHeight, + layers::LayersBackend aCompositorBackend, bool aNeutered); ~OffscreenCanvasCloneData(); RefPtr mRenderer; uint32_t mWidth; uint32_t mHeight; + layers::LayersBackend mCompositorBackendType; bool mNeutered; }; class OffscreenCanvas final : public DOMEventTargetHelper , public CanvasRenderingContextHelper { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OffscreenCanvas, DOMEventTargetHelper) OffscreenCanvas(uint32_t aWidth, uint32_t aHeight, + layers::LayersBackend aCompositorBackend, layers::AsyncCanvasRenderer* aRenderer); OffscreenCanvas* GetParentObject() const; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; void ClearResources(); @@ -139,33 +142,38 @@ public: mNeutered = true; } bool IsNeutered() const { return mNeutered; } - layers::LayersBackend GetLayersBackend() const; + layers::LayersBackend GetCompositorBackendType() const + { + return mCompositorBackendType; + } private: ~OffscreenCanvas(); void CanvasAttrChanged() { mAttrDirty = true; UpdateContext(nullptr, JS::NullHandleValue); } bool mAttrDirty; bool mNeutered; uint32_t mWidth; uint32_t mHeight; + layers::LayersBackend mCompositorBackendType; + layers::CanvasClient* mCanvasClient; RefPtr mCanvasRenderer; }; } // namespace dom } // namespace mozilla #endif // MOZILLA_DOM_OFFSCREENCANVAS_H_ diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 62927a4..9178d15 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1208,23 +1208,19 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder, return canvasLayer.forget(); } layers::LayersBackend WebGLContext::GetCompositorBackendType() const { if (mCanvasElement) { - nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc()); - if (docWidget) { - layers::LayerManager* layerManager = docWidget->GetLayerManager(); - return layerManager->GetCompositorBackendType(); - } + return mCanvasElement->GetCompositorBackendType(); } else if (mOffscreenCanvas) { - return mOffscreenCanvas->GetLayersBackend(); + return mOffscreenCanvas->GetCompositorBackendType(); } return LayersBackend::LAYERS_NONE; } void WebGLContext::Commit() { diff --git a/dom/canvas/test/reftest/offscreencanvas-normal-ref.html b/dom/canvas/test/reftest/offscreencanvas-normal-ref.html new file mode 100644 index 0000000..af6f61c --- /dev/null +++ b/dom/canvas/test/reftest/offscreencanvas-normal-ref.html @@ -0,0 +1,16 @@ + + + +WebGL in OffscreenCanvas + + + + + + diff --git a/dom/canvas/test/reftest/offscreencanvas-normal.html b/dom/canvas/test/reftest/offscreencanvas-normal.html new file mode 100644 index 0000000..6b3b414 --- /dev/null +++ b/dom/canvas/test/reftest/offscreencanvas-normal.html @@ -0,0 +1,26 @@ + + + +WebGL in OffscreenCanvas + + + + + + diff --git a/dom/canvas/test/reftest/offscreencanvas.js b/dom/canvas/test/reftest/offscreencanvas.js index 7c4885a..2788e71 100644 --- a/dom/canvas/test/reftest/offscreencanvas.js +++ b/dom/canvas/test/reftest/offscreencanvas.js @@ -69,22 +69,28 @@ function drawWebGL(canvas) { var vertCoordBuff = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertCoordBuff); gl.bufferData(gl.ARRAY_BUFFER, vertCoordArr, gl.STATIC_DRAW); gl.useProgram(program); gl.enableVertexAttribArray(program.position); gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0); - // Start drawing - gl.viewport(0, 0, canvas.width, canvas.height); + return function() { + // Start drawing + gl.viewport(0, 0, canvas.width, canvas.height); - gl.clearColor(1.0, 0.0, 0.0, 1.0); - gl.clear(gl.COLOR_BUFFER_BIT); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - gl.commit(); + gl.clearColor(1.0, 0.0, 0.0, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + gl.commit(); + } } /* entry point */ onmessage = function entryFunction(evt) { - drawWebGL(evt.data.canvas); - postMessage({type: "finish"}); + var draw = drawWebGL(evt.data.canvas); + // Keep producing frame every 16 ms. + setInterval(function() { + draw(); + postMessage({type: "finish"}); + }, 16); }; diff --git a/dom/canvas/test/reftest/reftest.list b/dom/canvas/test/reftest/reftest.list index 01bc795..ea822a8 100644 --- a/dom/canvas/test/reftest/reftest.list +++ b/dom/canvas/test/reftest/reftest.list @@ -140,16 +140,17 @@ fuzzy(9,40000) skip-if(!(Android||B2G)) pref(webgl.prefer-16bpp,true) pref(webgl fuzzy(9,40000) skip-if(!(Android||B2G)) pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp&________&premult&alpha wrapper.html?colors-premult.png fuzzy(9,40000) skip-if(!(Android||B2G)) pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true) == webgl-color-test.html?16bpp&readback&premult&alpha wrapper.html?colors-premult.png # Force native GL (Windows): skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-color-test.html?native-gl wrapper.html?colors-no-alpha.png # OffscreenCanvas pref(gfx.offscreencanvas.enabled,true) == offscreencanvas-fallback.html offscreencanvas-fallback-ref.html +pref(gfx.offscreencanvas.enabled,true) == offscreencanvas-normal.html offscreencanvas-normal-ref.html # Non-WebGL Reftests! # Do we correctly handle multiple clip paths? != clip-multiple-paths.html clip-multiple-paths-badref.html # Bug 815648 diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 126cb7e..f95071f 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -669,17 +669,20 @@ HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv) } if (!mOffscreenCanvas) { nsIntSize sz = GetWidthHeight(); nsRefPtr renderer = GetAsyncCanvasRenderer(); renderer->SetWidth(sz.width); renderer->SetHeight(sz.height); - mOffscreenCanvas = new OffscreenCanvas(sz.width, sz.height, renderer); + mOffscreenCanvas = new OffscreenCanvas(sz.width, + sz.height, + GetCompositorBackendType(), + renderer); mContextObserver = new HTMLCanvasElementObserver(this); } else { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); } return mOffscreenCanvas; } @@ -958,17 +961,16 @@ HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, LayerUserData* userData = nullptr; layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData); CanvasLayer::Data data; data.mRenderer = GetAsyncCanvasRenderer(); data.mSize = GetWidthHeight(); layer->Initialize(data); - GetAsyncCanvasRenderer()->mBackend = aManager->GetBackendType(); layer->Updated(); return layer.forget(); } return nullptr; } bool @@ -1010,16 +1012,28 @@ HTMLCanvasElement::GetAsyncCanvasRenderer() if (!mAsyncCanvasRenderer) { mAsyncCanvasRenderer = new AsyncCanvasRenderer(); mAsyncCanvasRenderer->mHTMLCanvasElement = this; } return mAsyncCanvasRenderer; } +layers::LayersBackend +HTMLCanvasElement::GetCompositorBackendType() const +{ + nsIWidget* docWidget = nsContentUtils::WidgetForDocument(OwnerDoc()); + if (docWidget) { + layers::LayerManager* layerManager = docWidget->GetLayerManager(); + return layerManager->GetCompositorBackendType(); + } + + return LayersBackend::LAYERS_NONE; +} + void HTMLCanvasElement::OnVisibilityChange() { if (OwnerDoc()->Hidden()) { return; } if (mOffscreenCanvas) { @@ -1044,18 +1058,19 @@ HTMLCanvasElement::OnVisibilityChange() mRenderer = nullptr; } private: nsRefPtr mRenderer; }; nsRefPtr runnable = new Runnable(mAsyncCanvasRenderer); - if (mAsyncCanvasRenderer->GetActiveThread()) { - mAsyncCanvasRenderer->GetActiveThread()->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); + nsCOMPtr activeThread = mAsyncCanvasRenderer->GetActiveThread(); + if (activeThread) { + activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); } return; } if (mCurrentContext) { mCurrentContext->OnVisibilityChange(); } } @@ -1085,18 +1100,19 @@ HTMLCanvasElement::OnMemoryPressure() mRenderer = nullptr; } private: nsRefPtr mRenderer; }; nsRefPtr runnable = new Runnable(mAsyncCanvasRenderer); - if (mAsyncCanvasRenderer->GetActiveThread()) { - mAsyncCanvasRenderer->GetActiveThread()->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); + nsCOMPtr activeThread = mAsyncCanvasRenderer->GetActiveThread(); + if (activeThread) { + activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); } return; } if (mCurrentContext) { mCurrentContext->OnMemoryPressure(); } } diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index fb7eb2b..a7661b2 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -12,16 +12,17 @@ #include "nsIObserver.h" #include "nsGenericHTMLElement.h" #include "nsGkAtoms.h" #include "nsSize.h" #include "nsError.h" #include "mozilla/dom/CanvasRenderingContextHelper.h" #include "mozilla/gfx/Rect.h" +#include "mozilla/layers/LayersTypes.h" class nsICanvasRenderingContextInternal; class nsITimerCallback; namespace mozilla { class WebGLContext; @@ -259,16 +260,18 @@ public: // Call this whenever we need future changes to the canvas // to trigger fresh invalidation requests. This needs to be called // whenever we render the canvas contents to the screen, or whenever we // take a snapshot of the canvas that needs to be "live" (e.g. -moz-element). void MarkContextClean(); nsresult GetContext(const nsAString& aContextId, nsISupports** aContext); + layers::LayersBackend GetCompositorBackendType() const; + void OnVisibilityChange(); void OnMemoryPressure(); static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); protected: diff --git a/gfx/layers/AsyncCanvasRenderer.cpp b/gfx/layers/AsyncCanvasRenderer.cpp index 5abcd2d..ab7a56b 100644 --- a/gfx/layers/AsyncCanvasRenderer.cpp +++ b/gfx/layers/AsyncCanvasRenderer.cpp @@ -18,27 +18,25 @@ #include "nsIRunnable.h" #include "nsThreadUtils.h" #include "WorkerPrivate.h" namespace mozilla { namespace layers { AsyncCanvasRenderer::AsyncCanvasRenderer() - : mBackend(LayersBackend::LAYERS_NONE) - , mHTMLCanvasElement(nullptr) + : mHTMLCanvasElement(nullptr) , mContext(nullptr) , mGLContext(nullptr) , mIsAlphaPremultiplied(true) - , mIsSurfaceMutexLocked(false) , mWidth(0) , mHeight(0) , mCanvasClientAsyncID(0) , mCanvasClient(nullptr) - , mSurfaceMutex("AsyncCanvasRenderer::mSurface mutex") + , mMutex("AsyncCanvasRenderer::mMutex") { MOZ_COUNT_CTOR(AsyncCanvasRenderer); } AsyncCanvasRenderer::~AsyncCanvasRenderer() { MOZ_COUNT_DTOR(AsyncCanvasRenderer); } @@ -122,27 +120,37 @@ AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient) } else { mCanvasClientAsyncID = 0; } } void AsyncCanvasRenderer::SetActiveThread() { + MutexAutoLock lock(mMutex); mActiveThread = NS_GetCurrentThread(); mActiveWorkerPrivate = dom::workers::GetCurrentThreadWorkerPrivate(); } void AsyncCanvasRenderer::ResetActiveThread() { + MutexAutoLock lock(mMutex); mActiveThread = nullptr; mActiveWorkerPrivate = nullptr; } +already_AddRefed +AsyncCanvasRenderer::GetActiveThread() +{ + MutexAutoLock lock(mMutex); + nsCOMPtr result = mActiveThread; + return result.forget(); +} + void AsyncCanvasRenderer::UpdateTarget() { class UpdateTargetRunnable final : public dom::workers::MainThreadWorkerControlRunnable { public: UpdateTargetRunnable(dom::workers::WorkerPrivate* aWorkerPrivate, AsyncCanvasRenderer* aRenderer, @@ -195,100 +203,81 @@ AsyncCanvasRenderer::UpdateTarget() while (!done) { barrier.Wait(); } return; } MOZ_RELEASE_ASSERT(mActiveThread == NS_GetCurrentThread()); - MOZ_RELEASE_ASSERT(mIsSurfaceMutexLocked); gl::SharedSurface* frontbuffer = nullptr; gl::GLScreenBuffer* screen = mGLContext->Screen(); const auto& front = screen->Front(); if (front) { frontbuffer = front->Surf(); } if (!frontbuffer) { return; } EnsureSurface(frontbuffer->mSize, gfx::SurfaceFormat::B8G8R8A8); - RefPtr surface = GetSurface(); - if (NS_WARN_IF(!surface)) { + if (NS_WARN_IF(!mSurface)) { return; } // Readback handles Flush/MarkDirty. - mGLContext->Readback(frontbuffer, surface); + mGLContext->Readback(frontbuffer, mSurface); bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied; if (needsPremult) { - gfxUtils::PremultiplyDataSurface(surface, surface); + gfxUtils::PremultiplyDataSurface(mSurface, mSurface); } } void AsyncCanvasRenderer::EnsureSurface(gfx::IntSize aSize, gfx::SurfaceFormat aFormat) { - MOZ_RELEASE_ASSERT(mIsSurfaceMutexLocked); if (!mSurface || aSize != mSurface->GetSize() || aFormat != mSurface->GetFormat()) { // Create a surface aligned to 8 bytes since that's the highest // alignment WebGL can handle. uint32_t stride = gfx::GetAlignedStride<8>(aSize.width * BytesPerPixel(aFormat)); mSurface = gfx::Factory::CreateDataSourceSurfaceWithStride(aSize, aFormat, stride); } } -void -AsyncCanvasRenderer::LockSurfaceMutex() -{ - mSurfaceMutex.Lock(); - mIsSurfaceMutexLocked = true; -} - -void -AsyncCanvasRenderer::UnlockSurfaceMutex() -{ - mIsSurfaceMutexLocked = false; - mSurfaceMutex.Unlock(); -} - already_AddRefed -AsyncCanvasRenderer::GetSurface() +AsyncCanvasRenderer::GetAndUpdateSurface() { - MOZ_RELEASE_ASSERT(mIsSurfaceMutexLocked); + MutexAutoLock lock(mMutex); + UpdateTarget(); RefPtr result = mSurface; return result.forget(); } - nsresult AsyncCanvasRenderer::GetInputStream(const char *aMimeType, const char16_t *aEncoderOptions, nsIInputStream **aStream) { nsCString enccid("@mozilla.org/image/encoder;2?type="); enccid += aMimeType; nsCOMPtr encoder = do_CreateInstance(enccid.get()); if (!encoder) { return NS_ERROR_FAILURE; } nsAutoArrayPtr imageBuffer; int32_t format = 0; - GetSurfaceHelper helper(this); - UpdateTarget(); - RefPtr surface = GetSurface(); + RefPtr surface = GetAndUpdateSurface(); if (!surface) { return NS_ERROR_FAILURE; } // Handle y flip. RefPtr dt = gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO, gfx::IntSize(mWidth, mHeight), diff --git a/gfx/layers/AsyncCanvasRenderer.h b/gfx/layers/AsyncCanvasRenderer.h index 15098db..186ebf4c 100644 --- a/gfx/layers/AsyncCanvasRenderer.h +++ b/gfx/layers/AsyncCanvasRenderer.h @@ -80,25 +80,17 @@ public: { mIsAlphaPremultiplied = aIsAlphaPremultiplied; } // Active thread means the thread which spawns GLContext. void SetActiveThread(); void ResetActiveThread(); - // Readback current WebGL's content to mSurface. Note that the readback - // only happened in active thread which is GLContext creation thread. - // So that if this is called in other thread, we'll post a task to active - // thread and wait the result synchronously. - // Only called when mIsSurfaceMutexLocked is true. - void UpdateTarget(); - - // Only called when mIsSurfaceMutexLocked is true. - already_AddRefed GetSurface(); + already_AddRefed GetAndUpdateSurface(); // Readback current WebGL's content and convert it to InputStream. This // function called UpdateTarget implicitly and UpdateTarget handles the // threading issue. So this function can be called in any thread. nsresult GetInputStream(const char *aMimeType, const char16_t *aEncoderOptions, nsIInputStream **aStream); @@ -113,87 +105,65 @@ public: return mCanvasClientAsyncID; } CanvasClient* GetCanvasClient() const { return mCanvasClient; } - nsIThread* GetActiveThread() - { - return mActiveThread; - } - - // Indicate the backend type of layer which belong to this renderer - LayersBackend mBackend; + already_AddRefed GetActiveThread(); // The lifetime is controllered by HTMLCanvasElement. + // Only accessed in main thread. dom::HTMLCanvasElement* mHTMLCanvasElement; + // Only accessed in active thread. nsICanvasRenderingContextInternal* mContext; // We need to keep a reference to the context around here, otherwise the // canvas' surface texture destructor will deref and destroy it too early + // Only accessed in active thread. RefPtr mGLContext; - - // Helper class for locking mSurface in constructor and unlocking mSurface - // in destructor. - class GetSurfaceHelper final - { - public: - explicit GetSurfaceHelper(AsyncCanvasRenderer* aRenderer) - : mRenderer(aRenderer) - { - MOZ_RELEASE_ASSERT(mRenderer); - mRenderer->LockSurfaceMutex(); - } - - ~GetSurfaceHelper() - { - MOZ_RELEASE_ASSERT(mRenderer); - mRenderer->UnlockSurfaceMutex(); - } - - private: - AsyncCanvasRenderer* mRenderer; - }; - private: virtual ~AsyncCanvasRenderer(); - // Only called when mIsSurfaceMutexLocked is true. + // Readback current WebGL's content to mSurface. Note that the readback + // only happened in active thread which is GLContext creation thread. + // So that if this is called in other thread, we'll post a task to active + // thread and wait the result synchronously. + void UpdateTarget(); + void EnsureSurface(gfx::IntSize aSize, gfx::SurfaceFormat aFormat); - void LockSurfaceMutex(); - void UnlockSurfaceMutex(); - bool mIsAlphaPremultiplied; - bool mIsSurfaceMutexLocked; uint32_t mWidth; uint32_t mHeight; uint64_t mCanvasClientAsyncID; // The lifetime of this pointer is controlled by OffscreenCanvas + // Can be accessed in active thread and ImageBridge thread. + // But we never accessed it at the same time on both thread. So no + // need to protect this member. CanvasClient* mCanvasClient; // When backend is LAYER_BASIC, which means we need fallback to // BasicCanvasLayer. BasicCanvasLayer need a surface which contains // the result of OffscreenCanvas. So we store result in mSurface by // calling UpdateTarget(). RefPtr mSurface; - // When layers backend is LAYER_BASIC, worker thread will produce frame to - // mSurface. Main thread will acquire frame from mSurface in order to - // display frame to screen. To avoid race condition between these two - // threads, using mutex to protect mSurface. - Mutex mSurfaceMutex; + // Protect non thread-safe objects. + Mutex mMutex; + // Can be accessed in any thread, need protect by mutex. nsCOMPtr mActiveThread; + + // Can be accessed in any thread, need protext by mutex. dom::workers::WorkerPrivate* mActiveWorkerPrivate; }; } // namespace layers } // namespace mozilla #endif // MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index 6aff31c..cb3a141 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -79,18 +79,17 @@ CopyableCanvasLayer::IsDataValid(const Data& aData) { return mGLContext == aData.mGLContext; } void CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) { if (mAsyncRenderer) { - mAsyncRenderer->UpdateTarget(); - mSurface = mAsyncRenderer->GetSurface(); + mSurface = mAsyncRenderer->GetAndUpdateSurface(); } else if (mBufferProvider) { mSurface = mBufferProvider->GetSnapshot(); } if (!mGLContext && aDestTarget) { NS_ASSERTION(mSurface, "Must have surface to draw!"); if (mSurface) { aDestTarget->CopySurface(mSurface, diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index cf882506..f6f0788 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -21,21 +21,16 @@ using namespace mozilla::gl; namespace mozilla { namespace layers { void BasicCanvasLayer::Paint(DrawTarget* aDT, const Point& aDeviceOffset, Layer* aMaskLayer) { - UniquePtr helper; - if (mAsyncRenderer) { - helper = MakeUnique(mAsyncRenderer.get()); - } - if (IsHidden()) return; if (IsDirty()) { Painted(); FirePreTransactionCallback(); UpdateTarget();