Bug 709490 - Part 1: Let ImageBridge transfer CanvasClient async, r=nical

This commit is contained in:
Morris Tseng 2015-09-29 11:51:23 +01:00
parent aeafeb1d45
commit d9a54c0ad1
20 changed files with 631 additions and 99 deletions

View File

@ -21,6 +21,7 @@
#include "mozilla/dom/MouseEvent.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
@ -251,6 +252,10 @@ HTMLCanvasElement::~HTMLCanvasElement()
if (mRequestedFrameRefreshObserver) {
mRequestedFrameRefreshObserver->DetachFromRefreshDriver();
}
if (mAsyncCanvasRenderer) {
mAsyncCanvasRenderer->mHTMLCanvasElement = nullptr;
}
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement,
@ -1236,5 +1241,38 @@ HTMLCanvasElement::GetSurfaceSnapshot(bool* aPremultAlpha)
return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha);
}
AsyncCanvasRenderer*
HTMLCanvasElement::GetAsyncCanvasRenderer()
{
if (!mAsyncCanvasRenderer) {
mAsyncCanvasRenderer = new AsyncCanvasRenderer();
mAsyncCanvasRenderer->mHTMLCanvasElement = this;
}
return mAsyncCanvasRenderer;
}
/* static */ void
HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer)
{
HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
if (!element) {
return;
}
gfx::IntSize asyncCanvasSize = aRenderer->GetSize();
ErrorResult rv;
element->SetUnsignedIntAttr(nsGkAtoms::width, asyncCanvasSize.width, rv);
if (rv.Failed()) {
NS_WARNING("Failed to set width attribute to a canvas element asynchronously.");
}
element->SetUnsignedIntAttr(nsGkAtoms::height, asyncCanvasSize.height, rv);
if (rv.Failed()) {
NS_WARNING("Failed to set height attribute to a canvas element asynchronously.");
}
}
} // namespace dom
} // namespace mozilla

View File

@ -22,6 +22,7 @@ class nsITimerCallback;
namespace mozilla {
namespace layers {
class AsyncCanvasRenderer;
class CanvasLayer;
class Image;
class LayerManager;
@ -91,6 +92,7 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
DEFAULT_CANVAS_HEIGHT = 150
};
typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer;
typedef layers::CanvasLayer CanvasLayer;
typedef layers::LayerManager LayerManager;
@ -282,6 +284,8 @@ public:
nsresult GetContext(const nsAString& aContextId, nsISupports** aContext);
static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer);
protected:
virtual ~HTMLCanvasElement();
@ -307,6 +311,8 @@ protected:
nsISupports** aResult);
void CallPrintCallback();
AsyncCanvasRenderer* GetAsyncCanvasRenderer();
CanvasContextType mCurrentContextType;
nsRefPtr<HTMLCanvasElement> mOriginalCanvas;
nsRefPtr<PrintCallback> mPrintCallback;
@ -314,6 +320,7 @@ protected:
nsRefPtr<HTMLCanvasPrintState> mPrintState;
nsTArray<WeakPtr<FrameCaptureListener>> mRequestedFrameListeners;
nsRefPtr<RequestedFrameRefreshObserver> mRequestedFrameRefreshObserver;
nsRefPtr<AsyncCanvasRenderer> mAsyncCanvasRenderer;
public:
// Record whether this canvas should be write-only or not.

View File

@ -10,18 +10,32 @@
#include "GLContext.h"
#include "GLBlitHelper.h"
#include "GLReadTexImageHelper.h"
#include "SharedSurfaceEGL.h"
#include "SharedSurfaceGL.h"
#include "ScopedGLHelpers.h"
#include "gfx2DGlue.h"
#include "../layers/ipc/ShadowLayers.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#ifdef XP_WIN
#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle
#include "gfxWindowsPlatform.h"
#endif
#ifdef MOZ_WIDGET_GONK
#include "SharedSurfaceGralloc.h"
#include "nsXULAppAPI.h"
#endif
#ifdef XP_MACOSX
#include "SharedSurfaceIO.h"
#endif
#include "ScopedGLHelpers.h"
#include "gfx2DGlue.h"
#include "../layers/ipc/ShadowLayers.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#ifdef GL_PROVIDER_GLX
#include "GLXLibrary.h"
#include "SharedSurfaceGLX.h"
#endif
namespace mozilla {
namespace gl {
@ -51,6 +65,53 @@ GLScreenBuffer::Create(GLContext* gl,
return Move(ret);
}
/* static */ UniquePtr<SurfaceFactory>
GLScreenBuffer::CreateFactory(GLContext* gl,
const SurfaceCaps& caps,
const RefPtr<layers::CompositableForwarder>& forwarder,
const layers::TextureFlags& flags)
{
UniquePtr<SurfaceFactory> factory = nullptr;
if (!gfxPrefs::WebGLForceLayersReadback()) {
switch (forwarder->GetCompositorBackendType()) {
case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
#if defined(XP_MACOSX)
factory = SurfaceFactory_IOSurface::Create(gl, caps, forwarder, flags);
#elif defined(MOZ_WIDGET_GONK)
factory = MakeUnique<SurfaceFactory_Gralloc>(gl, caps, forwarder, flags);
#elif defined(GL_PROVIDER_GLX)
if (sGLXLibrary.UseSurfaceSharing())
factory = SurfaceFactory_GLXDrawable::Create(gl, caps, forwarder, flags);
#else
if (gl->GetContextType() == GLContextType::EGL) {
if (XRE_IsParentProcess()) {
factory = SurfaceFactory_EGLImage::Create(gl, caps, forwarder, flags);
}
}
#endif
break;
}
case mozilla::layers::LayersBackend::LAYERS_D3D11: {
#ifdef XP_WIN
// Enable surface sharing only if ANGLE and compositing devices
// are both WARP or both not WARP
if (gl->IsANGLE() &&
(gl->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) &&
gfxWindowsPlatform::GetPlatform()->CompositorD3D11TextureSharingWorks())
{
factory = SurfaceFactory_ANGLEShareHandle::Create(gl, caps, forwarder, flags);
}
#endif
break;
}
default:
break;
}
}
return factory;
}
GLScreenBuffer::GLScreenBuffer(GLContext* gl,
const SurfaceCaps& caps,
UniquePtr<SurfaceFactory> factory)

View File

@ -25,6 +25,7 @@
namespace mozilla {
namespace layers {
class CompositableForwarder;
class SharedSurfaceTextureClient;
} // namespace layers
@ -133,6 +134,12 @@ public:
const gfx::IntSize& size,
const SurfaceCaps& caps);
static UniquePtr<SurfaceFactory>
CreateFactory(GLContext* gl,
const SurfaceCaps& caps,
const RefPtr<layers::CompositableForwarder>& forwarder,
const layers::TextureFlags& flags);
protected:
GLContext* const mGL; // Owns us.
public:

View File

@ -311,6 +311,7 @@ SurfaceFactory::SurfaceFactory(SharedSurfaceType type, GLContext* gl,
, mAllocator(allocator)
, mFlags(flags)
, mFormats(gl->ChooseGLFormats(caps))
, mMutex("SurfaceFactor::mMutex")
{
ChooseBufferBits(mCaps, &mDrawCaps, &mReadCaps);
}
@ -368,6 +369,7 @@ SurfaceFactory::StartRecycling(layers::SharedSurfaceTextureClient* tc)
void
SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc)
{
MutexAutoLock autoLock(mMutex);
// Must clear before releasing ref.
tc->ClearRecycleCallback();
@ -379,11 +381,8 @@ SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc)
/*static*/ void
SurfaceFactory::RecycleCallback(layers::TextureClient* rawTC, void* rawFactory)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<layers::SharedSurfaceTextureClient> tc;
tc = static_cast<layers::SharedSurfaceTextureClient*>(rawTC);
SurfaceFactory* factory = static_cast<SurfaceFactory*>(rawFactory);
if (tc->mSurf->mCanRecycle) {
@ -399,6 +398,7 @@ bool
SurfaceFactory::Recycle(layers::SharedSurfaceTextureClient* texClient)
{
MOZ_ASSERT(texClient);
MutexAutoLock autoLock(mMutex);
if (mRecycleFreePool.size() >= 2) {
return false;

View File

@ -24,6 +24,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/Mutex.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "ScopedGLHelpers.h"
@ -298,6 +299,7 @@ public:
const RefPtr<layers::ISurfaceAllocator> mAllocator;
const layers::TextureFlags mFlags;
const GLFormats mFormats;
Mutex mMutex;
protected:
SurfaceCaps mDrawCaps;
SurfaceCaps mReadCaps;

View File

@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "AsyncCanvasRenderer.h"
#include "gfxUtils.h"
#include "GLContext.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/layers/CanvasClient.h"
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace layers {
AsyncCanvasRenderer::AsyncCanvasRenderer()
: mWidth(0)
, mHeight(0)
, mCanvasClientAsyncID(0)
, mCanvasClient(nullptr)
{
MOZ_COUNT_CTOR(AsyncCanvasRenderer);
}
AsyncCanvasRenderer::~AsyncCanvasRenderer()
{
MOZ_COUNT_DTOR(AsyncCanvasRenderer);
}
void
AsyncCanvasRenderer::NotifyElementAboutAttributesChanged()
{
class Runnable final : public nsRunnable
{
public:
Runnable(AsyncCanvasRenderer* aRenderer)
: mRenderer(aRenderer)
{}
NS_IMETHOD Run()
{
if (mRenderer) {
dom::HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(mRenderer);
}
return NS_OK;
}
void Revoke()
{
mRenderer = nullptr;
}
private:
nsRefPtr<AsyncCanvasRenderer> mRenderer;
};
nsRefPtr<nsRunnable> runnable = new Runnable(this);
nsresult rv = NS_DispatchToMainThread(runnable);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch a runnable to the main-thread.");
}
}
void
AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient)
{
mCanvasClient = aClient;
if (aClient) {
mCanvasClientAsyncID = aClient->GetAsyncID();
} else {
mCanvasClientAsyncID = 0;
}
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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_LAYERS_ASYNCCANVASRENDERER_H_
#define MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/RefPtr.h" // for nsAutoPtr, nsRefPtr, etc
class nsICanvasRenderingContextInternal;
namespace mozilla {
namespace gl {
class GLContext;
}
namespace dom {
class HTMLCanvasElement;
}
namespace layers {
class CanvasClient;
/**
* Since HTMLCanvasElement and OffscreenCanvas are not thread-safe, we create
* AsyncCanvasRenderer which is thread-safe wrapper object for communicating
* among main, worker and ImageBridgeChild threads.
*
* Each HTMLCanvasElement object is responsible for creating
* AsyncCanvasRenderer object. Once Canvas is transfered to worker,
* OffscreenCanvas will keep reference pointer of this object.
* This object will pass to ImageBridgeChild for submitting frames to
* Compositor.
*/
class AsyncCanvasRenderer final
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncCanvasRenderer)
public:
AsyncCanvasRenderer();
void NotifyElementAboutAttributesChanged();
void SetCanvasClient(CanvasClient* aClient);
void SetWidth(uint32_t aWidth)
{
mWidth = aWidth;
}
void SetHeight(uint32_t aHeight)
{
mHeight = aHeight;
}
gfx::IntSize GetSize() const
{
return gfx::IntSize(mWidth, mHeight);
}
uint64_t GetCanvasClientAsyncID() const
{
return mCanvasClientAsyncID;
}
CanvasClient* GetCanvasClient() const
{
return mCanvasClient;
}
// The lifetime is controllered by HTMLCanvasElement.
dom::HTMLCanvasElement* mHTMLCanvasElement;
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
RefPtr<gl::GLContext> mGLContext;
private:
virtual ~AsyncCanvasRenderer();
uint32_t mWidth;
uint32_t mHeight;
uint64_t mCanvasClientAsyncID;
// The lifetime of this pointer is controlled by OffscreenCanvas
CanvasClient* mCanvasClient;
};
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_

View File

@ -80,6 +80,10 @@ CopyableCanvasLayer::IsDataValid(const Data& aData)
void
CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
{
if (!mBufferProvider && !mGLContext) {
return;
}
if (mBufferProvider) {
mSurface = mBufferProvider->GetSnapshot();
}
@ -99,8 +103,6 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
return;
}
MOZ_ASSERT(mGLContext);
SharedSurface* frontbuffer = nullptr;
if (mGLFrontbuffer) {
frontbuffer = mGLFrontbuffer.get();

View File

@ -25,6 +25,7 @@
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite
@ -2104,6 +2105,25 @@ ColorLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
layer->set_color(mColor.ToABGR());
}
CanvasLayer::CanvasLayer(LayerManager* aManager, void* aImplData)
: Layer(aManager, aImplData)
, mPreTransCallback(nullptr)
, mPreTransCallbackData(nullptr)
, mPostTransCallback(nullptr)
, mPostTransCallbackData(nullptr)
, mFilter(GraphicsFilter::FILTER_GOOD)
, mDirty(false)
{}
CanvasLayer::~CanvasLayer()
{}
void
CanvasLayer::SetAsyncRenderer(AsyncCanvasRenderer *aAsyncRenderer)
{
mAsyncRenderer = aAsyncRenderer;
}
void
CanvasLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{

View File

@ -74,6 +74,7 @@ namespace layers {
class Animation;
class AnimationData;
class AsyncCanvasRenderer;
class AsyncPanZoomController;
class ClientLayerManager;
class Layer;
@ -2392,16 +2393,16 @@ public:
ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
}
bool GetIsAsyncRenderer() const
{
return !!mAsyncRenderer;
}
void SetAsyncRenderer(AsyncCanvasRenderer *aAsyncRenderer);
protected:
CanvasLayer(LayerManager* aManager, void* aImplData)
: Layer(aManager, aImplData)
, mPreTransCallback(nullptr)
, mPreTransCallbackData(nullptr)
, mPostTransCallback(nullptr)
, mPostTransCallbackData(nullptr)
, mFilter(GraphicsFilter::FILTER_GOOD)
, mDirty(false)
{}
CanvasLayer(LayerManager* aManager, void* aImplData);
virtual ~CanvasLayer();
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
@ -2423,6 +2424,7 @@ protected:
DidTransactionCallback mPostTransCallback;
void* mPostTransCallbackData;
GraphicsFilter mFilter;
nsRefPtr<AsyncCanvasRenderer> mAsyncRenderer;
private:
/**

View File

@ -13,6 +13,7 @@
#include "gfxPlatform.h" // for gfxPlatform
#include "GLReadTexImageHelper.h"
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorChild.h" // for CompositorChild
#include "mozilla/layers/GrallocTextureClient.h"
@ -38,14 +39,32 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
switch (aType) {
case CanvasClientTypeShSurf:
return MakeAndAddRef<CanvasClientSharedSurface>(aForwarder, aFlags);
break;
case CanvasClientAsync:
return MakeAndAddRef<CanvasClientBridge>(aForwarder, aFlags);
default:
return MakeAndAddRef<CanvasClient2D>(aForwarder, aFlags);
break;
}
}
void
CanvasClientBridge::UpdateAsync(AsyncCanvasRenderer* aRenderer)
{
if (!GetForwarder() || !mLayer || !aRenderer ||
!aRenderer->GetCanvasClient()) {
return;
}
uint64_t asyncID = aRenderer->GetCanvasClientAsyncID();
if (asyncID == 0 || mAsyncID == asyncID) {
return;
}
static_cast<ShadowLayerForwarder*>(GetForwarder())
->AttachAsyncCompositable(asyncID, mLayer);
mAsyncID = asyncID;
}
void
CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
{
@ -321,13 +340,38 @@ CloneSurface(gl::SharedSurface* src, gl::SurfaceFactory* factory)
void
CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
{
auto gl = aLayer->mGLContext;
Renderer renderer;
renderer.construct<ClientCanvasLayer*>(aLayer);
UpdateRenderer(aSize, renderer);
}
void
CanvasClientSharedSurface::UpdateAsync(AsyncCanvasRenderer* aRenderer)
{
Renderer renderer;
renderer.construct<AsyncCanvasRenderer*>(aRenderer);
UpdateRenderer(aRenderer->GetSize(), renderer);
}
void
CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer)
{
GLContext* gl = nullptr;
ClientCanvasLayer* layer = nullptr;
AsyncCanvasRenderer* asyncRenderer = nullptr;
if (aRenderer.constructed<ClientCanvasLayer*>()) {
layer = aRenderer.ref<ClientCanvasLayer*>();
gl = layer->mGLContext;
} else {
asyncRenderer = aRenderer.ref<AsyncCanvasRenderer*>();
gl = asyncRenderer->mGLContext;
}
gl->MakeCurrent();
RefPtr<TextureClient> newFront;
if (aLayer->mGLFrontbuffer) {
mShSurfClient = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get());
if (layer && layer->mGLFrontbuffer) {
mShSurfClient = CloneSurface(layer->mGLFrontbuffer.get(), layer->mFactory.get());
if (!mShSurfClient) {
gfxCriticalError() << "Invalid canvas front buffer";
return;
@ -351,11 +395,18 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
bool needsReadback = (surf->mType == SharedSurfaceType::Basic);
if (needsReadback) {
TextureFlags flags = aLayer->Flags() |
TextureFlags::IMMUTABLE;
TextureFlags flags = TextureFlags::IMMUTABLE;
CompositableForwarder* shadowForwarder = nullptr;
if (layer) {
flags |= layer->Flags();
shadowForwarder = layer->ClientManager()->AsShadowForwarder();
} else {
MOZ_ASSERT(asyncRenderer);
flags |= mTextureFlags;
shadowForwarder = GetForwarder();
}
auto manager = aLayer->ClientManager();
auto shadowForwarder = manager->AsShadowForwarder();
auto layersBackend = shadowForwarder->GetCompositorBackendType();
mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend);
@ -371,6 +422,14 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
return;
}
mNewFront = newFront;
}
void
CanvasClientSharedSurface::Updated()
{
auto forwarder = GetForwarder();
#ifndef MOZ_WIDGET_GONK
if (mFront) {
if (mFront->GetFlags() & TextureFlags::RECYCLE) {
@ -385,12 +444,13 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
// - Call RemoveTexture() after newFront's UseTextures() call.
// It could improve performance of Host side's EGL handling on gonk
AutoRemoveTexture autoRemove(this);
if (mFront && mFront != newFront) {
if (mFront && mFront != mNewFront) {
autoRemove.mTexture = mFront;
}
#endif
mFront = newFront;
mFront = mNewFront;
mNewFront = nullptr;
// Add the new TexClient.
MOZ_ALWAYS_TRUE( AddTextureClient(mFront) );
@ -406,6 +466,7 @@ void
CanvasClientSharedSurface::ClearSurfaces()
{
mFront = nullptr;
mNewFront = nullptr;
mShSurfClient = nullptr;
mReadbackClient = nullptr;
}

View File

@ -13,6 +13,11 @@
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
// Fix X11 header brain damage that conflicts with MaybeOneOf::None
#undef None
#include "mozilla/MaybeOneOf.h"
#include "mozilla/mozalloc.h" // for operator delete
#include "mozilla/gfx/Point.h" // for IntSize
@ -21,8 +26,10 @@
namespace mozilla {
namespace layers {
class AsyncCanvasRenderer;
class ClientCanvasLayer;
class CompositableForwarder;
class ShadowableLayer;
class SharedSurfaceTextureClient;
/**
@ -31,6 +38,8 @@ class SharedSurfaceTextureClient;
class CanvasClient : public CompositableClient
{
public:
typedef MaybeOneOf<ClientCanvasLayer*, AsyncCanvasRenderer*> Renderer;
/**
* Creates, configures, and returns a new canvas client. If necessary, a
* message will be sent to the compositor to create a corresponding image
@ -40,6 +49,7 @@ public:
CanvasClientSurface,
CanvasClientGLContext,
CanvasClientTypeShSurf,
CanvasClientAsync, // webgl on workers
};
static already_AddRefed<CanvasClient> CreateCanvasClient(CanvasClientType aType,
CompositableForwarder* aFwd,
@ -57,6 +67,8 @@ public:
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) = 0;
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) {}
virtual void Updated() { }
};
@ -111,6 +123,7 @@ private:
RefPtr<SharedSurfaceTextureClient> mShSurfClient;
RefPtr<TextureClient> mReadbackClient;
RefPtr<TextureClient> mFront;
RefPtr<TextureClient> mNewFront;
void ClearSurfaces();
@ -130,12 +143,54 @@ public:
virtual void Update(gfx::IntSize aSize,
ClientCanvasLayer* aLayer) override;
void UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer);
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
virtual void Updated() override;
virtual void OnDetach() override {
ClearSurfaces();
}
};
/**
* Used for OMT<canvas> uploads using the image bridge protocol.
* Actual CanvasClient is on the ImageBridgeChild thread, so we
* only forward its AsyncID here
*/
class CanvasClientBridge final : public CanvasClient
{
public:
CanvasClientBridge(CompositableForwarder* aLayerForwarder,
TextureFlags aFlags)
: CanvasClient(aLayerForwarder, aFlags)
, mAsyncID(0)
, mLayer(nullptr)
{
}
TextureInfo GetTextureInfo() const override
{
return TextureInfo(CompositableType::IMAGE);
}
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) override
{
}
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
void SetLayer(ShadowableLayer* aLayer)
{
mLayer = aLayer;
}
protected:
uint64_t mAsyncID;
ShadowableLayer* mLayer;
};
} // namespace layers
} // namespace mozilla

View File

@ -11,6 +11,7 @@
#include "SharedSurfaceGL.h" // for SurfaceFactory_GLTexture, etc
#include "ClientLayerManager.h" // for ClientLayerManager, etc
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsCOMPtr.h" // for already_AddRefed
@ -19,24 +20,6 @@
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
#include "gfxPrefs.h" // for WebGLForceLayersReadback
#ifdef XP_WIN
#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle
#include "gfxWindowsPlatform.h"
#endif
#ifdef MOZ_WIDGET_GONK
#include "SharedSurfaceGralloc.h"
#endif
#ifdef XP_MACOSX
#include "SharedSurfaceIO.h"
#endif
#ifdef GL_PROVIDER_GLX
#include "GLXLibrary.h"
#include "SharedSurfaceGLX.h"
#endif
using namespace mozilla::gfx;
using namespace mozilla::gl;
@ -82,46 +65,7 @@ ClientCanvasLayer::Initialize(const Data& aData)
mFlags |= TextureFlags::NON_PREMULTIPLIED;
}
UniquePtr<SurfaceFactory> factory;
if (!gfxPrefs::WebGLForceLayersReadback()) {
switch (forwarder->GetCompositorBackendType()) {
case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
#if defined(XP_MACOSX)
factory = SurfaceFactory_IOSurface::Create(mGLContext, caps, forwarder, mFlags);
#elif defined(MOZ_WIDGET_GONK)
factory = MakeUnique<SurfaceFactory_Gralloc>(mGLContext, caps, forwarder, mFlags);
#elif defined(GL_PROVIDER_GLX)
if (sGLXLibrary.UseSurfaceSharing())
factory = SurfaceFactory_GLXDrawable::Create(mGLContext, caps, forwarder, mFlags);
#else
if (mGLContext->GetContextType() == GLContextType::EGL) {
if (XRE_IsParentProcess()) {
factory = SurfaceFactory_EGLImage::Create(mGLContext, caps, forwarder,
mFlags);
}
}
#endif
break;
}
case mozilla::layers::LayersBackend::LAYERS_D3D11: {
#ifdef XP_WIN
// Enable surface sharing only if ANGLE and compositing devices
// are both WARP or both not WARP
if (mGLContext->IsANGLE() &&
(mGLContext->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) &&
gfxWindowsPlatform::GetPlatform()->CompositorD3D11TextureSharingWorks())
{
factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps, forwarder,
mFlags);
}
#endif
break;
}
default:
break;
}
}
UniquePtr<SurfaceFactory> factory = GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
if (mGLFrontbuffer) {
// We're using a source other than the one in the default screen.
@ -145,11 +89,6 @@ ClientCanvasLayer::RenderLayer()
RenderMaskLayers(this);
if (!IsDirty()) {
return;
}
Painted();
if (!mCanvasClient) {
TextureFlags flags = TextureFlags::IMMEDIATE_UPLOAD;
if (mOriginPos == gl::OriginPos::BottomLeft) {
@ -172,11 +111,24 @@ ClientCanvasLayer::RenderLayer()
return;
}
if (HasShadow()) {
mCanvasClient->Connect();
ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this);
if (mAsyncRenderer) {
static_cast<CanvasClientBridge*>(mCanvasClient.get())->SetLayer(this);
} else {
mCanvasClient->Connect();
ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this);
}
}
}
if (mCanvasClient && mAsyncRenderer) {
mCanvasClient->UpdateAsync(mAsyncRenderer);
}
if (!IsDirty()) {
return;
}
Painted();
FirePreTransactionCallback();
mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this);
@ -189,6 +141,10 @@ ClientCanvasLayer::RenderLayer()
CanvasClient::CanvasClientType
ClientCanvasLayer::GetCanvasClientType()
{
if (mAsyncRenderer) {
return CanvasClient::CanvasClientAsync;
}
if (mGLContext) {
return CanvasClient::CanvasClientTypeShSurf;
}

View File

@ -97,7 +97,6 @@ protected:
TextureFlags mFlags;
friend class DeprecatedCanvasClient2D;
friend class CanvasClient2D;
friend class CanvasClientSharedSurface;
};

View File

@ -169,6 +169,7 @@ TextureChild::ActorDestroy(ActorDestroyReason why)
{
if (mTextureClient) {
mTextureClient->mActor = nullptr;
mTextureClient->mAllocator = nullptr;
}
mWaitForRecycle = nullptr;
mKeep = nullptr;

View File

@ -21,6 +21,7 @@
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
@ -231,6 +232,19 @@ static void CreateImageClientSync(RefPtr<ImageClient>* result,
barrier->NotifyAll();
}
// dispatched function
static void CreateCanvasClientSync(ReentrantMonitor* aBarrier,
CanvasClient::CanvasClientType aType,
TextureFlags aFlags,
RefPtr<CanvasClient>* const outResult,
bool* aDone)
{
ReentrantMonitorAutoEnter autoMon(*aBarrier);
*outResult = sImageBridgeChildSingleton->CreateCanvasClientNow(aType, aFlags);
*aDone = true;
aBarrier->NotifyAll();
}
static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * parent)
{
MessageLoop *parentMsgLoop = parent->GetMessageLoop();
@ -269,9 +283,14 @@ ImageBridgeChild::Connect(CompositableClient* aCompositable,
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(!mShuttingDown);
uint64_t id = 0;
PImageContainerChild* imageContainerChild = nullptr;
if (aImageContainer)
imageContainerChild = aImageContainer->GetPImageContainerChild();
PCompositableChild* child =
SendPCompositableConstructor(aCompositable->GetTextureInfo(),
aImageContainer->GetPImageContainerChild(), &id);
imageContainerChild, &id);
MOZ_ASSERT(child);
aCompositable->InitIPDLActor(child, id);
}
@ -374,6 +393,35 @@ void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient,
NewRunnableFunction(&ReleaseImageClientNow, aClient, aChild));
}
static void ReleaseCanvasClientNow(CanvasClient* aClient)
{
MOZ_ASSERT(InImageBridgeChildThread());
aClient->Release();
}
// static
void ImageBridgeChild::DispatchReleaseCanvasClient(CanvasClient* aClient)
{
if (!aClient) {
return;
}
if (!IsCreated()) {
// CompositableClient::Release should normally happen in the ImageBridgeChild
// thread because it usually generate some IPDL messages.
// However, if we take this branch it means that the ImageBridgeChild
// has already shut down, along with the CompositableChild, which means no
// message will be sent and it is safe to run this code from any thread.
MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
aClient->Release();
return;
}
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(&ReleaseCanvasClientNow, aClient));
}
static void ReleaseTextureClientNow(TextureClient* aClient)
{
MOZ_ASSERT(InImageBridgeChildThread());
@ -412,7 +460,7 @@ static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContaine
sImageBridgeChildSingleton->EndTransaction();
}
//static
// static
void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient,
ImageContainer* aContainer)
{
@ -432,6 +480,51 @@ void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient,
nsRefPtr<ImageContainer> >(&UpdateImageClientNow, aClient, aContainer));
}
static void UpdateAsyncCanvasRendererSync(AsyncCanvasRenderer* aWrapper,
ReentrantMonitor* aBarrier,
bool* const outDone)
{
ImageBridgeChild::UpdateAsyncCanvasRendererNow(aWrapper);
ReentrantMonitorAutoEnter autoMon(*aBarrier);
*outDone = true;
aBarrier->NotifyAll();
}
// static
void ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper)
{
aWrapper->GetCanvasClient()->UpdateAsync(aWrapper);
if (InImageBridgeChildThread()) {
UpdateAsyncCanvasRendererNow(aWrapper);
return;
}
ReentrantMonitor barrier("UpdateAsyncCanvasRenderer Lock");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(&UpdateAsyncCanvasRendererSync, aWrapper, &barrier, &done));
// should stop the thread until the CanvasClient has been created on
// the other thread
while (!done) {
barrier.Wait();
}
}
// static
void ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper)
{
MOZ_ASSERT(aWrapper);
sImageBridgeChildSingleton->BeginTransaction();
aWrapper->GetCanvasClient()->Updated();
sImageBridgeChildSingleton->EndTransaction();
}
static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer,
AsyncTransactionWaiter* aWaiter)
{
@ -449,7 +542,7 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer,
aWaiter->DecrementWaitCount();
}
//static
// static
void ImageBridgeChild::FlushAllImages(ImageClient* aClient,
ImageContainer* aContainer)
{
@ -705,6 +798,42 @@ ImageBridgeChild::CreateImageClientNow(CompositableType aType,
return client.forget();
}
already_AddRefed<CanvasClient>
ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType,
TextureFlags aFlag)
{
if (InImageBridgeChildThread()) {
return CreateCanvasClientNow(aType, aFlag);
}
ReentrantMonitor barrier("CreateCanvasClient Lock");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
RefPtr<CanvasClient> result = nullptr;
GetMessageLoop()->PostTask(FROM_HERE,
NewRunnableFunction(&CreateCanvasClientSync,
&barrier, aType, aFlag, &result, &done));
// should stop the thread until the CanvasClient has been created on the
// other thread
while (!done) {
barrier.Wait();
}
return result.forget();
}
already_AddRefed<CanvasClient>
ImageBridgeChild::CreateCanvasClientNow(CanvasClient::CanvasClientType aType,
TextureFlags aFlag)
{
RefPtr<CanvasClient> client
= CanvasClient::CreateCanvasClient(aType, this, aFlag);
MOZ_ASSERT(client, "failed to create CanvasClient");
if (client) {
client->Connect();
}
return client.forget();
}
bool
ImageBridgeChild::AllocUnsafeShmem(size_t aSize,
ipc::SharedMemory::SharedMemoryType aType,

View File

@ -12,6 +12,7 @@
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder
#include "mozilla/layers/CanvasClient.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/PImageBridgeChild.h"
@ -32,6 +33,7 @@ class Shmem;
namespace layers {
class AsyncCanvasRenderer;
class AsyncTransactionTracker;
class ImageClient;
class ImageContainer;
@ -210,12 +212,20 @@ public:
ImageContainer* aImageContainer);
already_AddRefed<ImageClient> CreateImageClientNow(CompositableType aType,
ImageContainer* aImageContainer);
already_AddRefed<CanvasClient> CreateCanvasClient(CanvasClient::CanvasClientType aType,
TextureFlags aFlag);
already_AddRefed<CanvasClient> CreateCanvasClientNow(CanvasClient::CanvasClientType aType,
TextureFlags aFlag);
static void DispatchReleaseImageClient(ImageClient* aClient,
PImageContainerChild* aChild = nullptr);
static void DispatchReleaseCanvasClient(CanvasClient* aClient);
static void DispatchReleaseTextureClient(TextureClient* aClient);
static void DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer);
static void UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aClient);
static void UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aClient);
/**
* Flush all Images sent to CompositableHost.
*/

View File

@ -58,7 +58,7 @@ parent:
sync Stop();
sync PCompositable(TextureInfo aInfo,
PImageContainer aImageContainer) returns (uint64_t id);
nullable PImageContainer aImageContainer) returns (uint64_t id);
async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags);
async PMediaSystemResourceManager();
async PImageContainer();

View File

@ -107,6 +107,7 @@ EXPORTS.mozilla.layers += [
'apz/util/ChromeProcessController.h',
'apz/util/DoubleTapToZoom.h',
'apz/util/InputAPZContext.h',
'AsyncCanvasRenderer.h',
'AtomicRefCountedWithFinalize.h',
'AxisPhysicsModel.h',
'AxisPhysicsMSDModel.h',
@ -252,6 +253,7 @@ UNIFIED_SOURCES += [
'apz/util/ChromeProcessController.cpp',
'apz/util/DoubleTapToZoom.cpp',
'apz/util/InputAPZContext.cpp',
'AsyncCanvasRenderer.cpp',
'AxisPhysicsModel.cpp',
'AxisPhysicsMSDModel.cpp',
'basic/BasicCanvasLayer.cpp',