Bug 801176 - part2-v5: Let Canvas 2d context works on Workers. r=roc

---
 dom/canvas/CanvasRenderingContext2D.cpp | 53 ++++++++++++-----------
 dom/canvas/OffscreenCanvas.cpp          | 46 +++++++++++---------
 dom/html/HTMLCanvasElement.cpp          |  1 +
 gfx/layers/AsyncCanvasRenderer.cpp      | 17 ++++++++
 gfx/layers/AsyncCanvasRenderer.h        | 16 +++++++
 gfx/layers/Effects.cpp                  |  6 +++
 gfx/layers/GLImages.cpp                 |  5 +--
 gfx/layers/client/CanvasClient.cpp      | 74 +++++++++++++++++++++++++--------
 gfx/layers/client/CanvasClient.h        | 10 ++++-
 9 files changed, 162 insertions(+), 66 deletions(-)
This commit is contained in:
vincentliu 2016-03-04 15:22:39 +08:00
Родитель 2a98ba1c2c
Коммит 906120d775
9 изменённых файлов: 162 добавлений и 66 удалений

Просмотреть файл

@ -975,7 +975,8 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
sNumLivingContexts++;
// The default is to use OpenGL mode
if (gfxPlatform::GetPlatform()->UseAcceleratedCanvas()) {
if (NS_IsMainThread() &&
gfxPlatform::GetPlatform()->UseAcceleratedCanvas()) {
mDrawObserver = new CanvasDrawObserver(this);
} else {
mRenderingMode = RenderingMode::SoftwareBackendMode;
@ -1418,32 +1419,36 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode)
nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
}
if (layerManager) {
if (mode == RenderingMode::OpenGLBackendMode &&
gfxPlatform::GetPlatform()->UseAcceleratedCanvas() &&
CheckSizeForSkiaGL(size)) {
DemoteOldestContextIfNecessary();
mBufferProvider = nullptr;
if (mode == RenderingMode::OpenGLBackendMode &&
gfxPlatform::GetPlatform()->UseAcceleratedCanvas() &&
CheckSizeForSkiaGL(size)) {
DemoteOldestContextIfNecessary();
mBufferProvider = nullptr;
#if USE_SKIA_GPU
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
if (glue && glue->GetGrContext() && glue->GetGLContext()) {
mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
if (mTarget) {
AddDemotableContext(this);
if (glue && glue->GetGrContext() && glue->GetGLContext()) {
mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
if (mTarget) {
AddDemotableContext(this);
if (NS_IsMainThread()) {
mBufferProvider = new PersistentBufferProviderBasic(mTarget);
mIsSkiaGL = true;
} else {
gfxCriticalNote << "Failed to create a SkiaGL DrawTarget, falling back to software\n";
mode = RenderingMode::SoftwareBackendMode;
}
mIsSkiaGL = true;
} else {
gfxCriticalNote << "Failed to create a SkiaGL DrawTarget, falling back to software\n";
mode = RenderingMode::SoftwareBackendMode;
}
#endif
}
#endif
}
if (!mBufferProvider) {
if (!mBufferProvider) {
if (layerManager) {
mBufferProvider = layerManager->CreatePersistentBufferProvider(size, format);
} else {
mBufferProvider = new PersistentBufferProviderBasic(size, format, gfxPlatform::GetPlatform()->GetPreferredCanvasBackend());
}
}
@ -5646,17 +5651,15 @@ void CanvasRenderingContext2D::RemoveDrawObserver()
PersistentBufferProvider*
CanvasRenderingContext2D::GetBufferProvider(LayerManager* aManager)
{
if (!mTarget) {
EnsureTarget();
}
if (mBufferProvider) {
return mBufferProvider;
}
if (!mTarget) {
} else {
return nullptr;
}
mBufferProvider = new PersistentBufferProviderBasic(mTarget);
return mBufferProvider;
}
already_AddRefed<Layer>

Просмотреть файл

@ -113,7 +113,6 @@ OffscreenCanvas::GetContext(JSContext* aCx,
return nullptr;
}
// We only support WebGL in workers for now
CanvasContextType contextType;
if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType)) {
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
@ -122,6 +121,7 @@ OffscreenCanvas::GetContext(JSContext* aCx,
if (!(contextType == CanvasContextType::WebGL1 ||
contextType == CanvasContextType::WebGL2 ||
contextType == CanvasContextType::Canvas2D ||
contextType == CanvasContextType::ImageBitmap))
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
@ -138,33 +138,39 @@ OffscreenCanvas::GetContext(JSContext* aCx,
return nullptr;
}
if (mCanvasRenderer) {
if (mCanvasRenderer && ImageBridgeChild::IsCreated()) {
mCanvasRenderer->mContext = mCurrentContext;
TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT;
if (contextType == CanvasContextType::WebGL1 ||
contextType == CanvasContextType::WebGL2) {
WebGLContext* webGL = static_cast<WebGLContext*>(mCurrentContext.get());
gl::GLContext* gl = webGL->GL();
mCanvasRenderer->mContext = mCurrentContext;
mCanvasRenderer->SetActiveThread();
mCanvasRenderer->mGLContext = gl;
mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha);
if (ImageBridgeChild::IsCreated()) {
TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT;
mCanvasClient = ImageBridgeChild::GetSingleton()->
CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take();
mCanvasRenderer->SetCanvasClient(mCanvasClient);
mCanvasClient = ImageBridgeChild::GetSingleton()->
CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take();
gl::GLScreenBuffer* screen = gl->Screen();
gl::SurfaceCaps caps = screen->mCaps;
auto forwarder = mCanvasClient->GetForwarder();
gl::GLScreenBuffer* screen = gl->Screen();
gl::SurfaceCaps caps = screen->mCaps;
auto forwarder = mCanvasClient->GetForwarder();
UniquePtr<gl::SurfaceFactory> factory =
gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags);
UniquePtr<gl::SurfaceFactory> factory =
gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags);
if (factory)
screen->Morph(Move(factory));
}
if (factory)
screen->Morph(Move(factory));
} else if (contextType == CanvasContextType::Canvas2D) {
CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext2D*>(mCurrentContext.get());
mCanvasRenderer->mGLContext = nullptr;
mCanvasRenderer->mBufferProvider = context2D->GetBufferProvider(nullptr);
mCanvasClient = ImageBridgeChild::GetSingleton()->
CreateCanvasClient(CanvasClient::CanvasClientSurface, flags).take();
}
mCanvasRenderer->SetCanvasClient(mCanvasClient);
}
return result;
@ -200,11 +206,11 @@ OffscreenCanvas::CommitFrameToCompositor()
mAttrDirty = false;
}
if (mCurrentContext) {
static_cast<WebGLContext*>(mCurrentContext.get())->PresentScreenBuffer();
}
if (mCurrentContext && mCanvasRenderer) {
if (mCanvasRenderer->mGLContext) {
static_cast<WebGLContext*>(mCurrentContext.get())->PresentScreenBuffer();
}
if (mCanvasRenderer && mCanvasRenderer->mGLContext) {
mCanvasRenderer->NotifyElementAboutInvalidation();
ImageBridgeChild::GetSingleton()->
UpdateAsyncCanvasRenderer(mCanvasRenderer);

Просмотреть файл

@ -785,6 +785,7 @@ HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv)
RefPtr<AsyncCanvasRenderer> renderer = GetAsyncCanvasRenderer();
renderer->SetWidth(sz.width);
renderer->SetHeight(sz.height);
renderer->SetOpaque(GetIsOpaque());
nsCOMPtr<nsIGlobalObject> global =
do_QueryInterface(OwnerDoc()->GetInnerWindow());

Просмотреть файл

@ -18,6 +18,7 @@
#include "mozilla/ReentrantMonitor.h"
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
#include "PersistentBufferProvider.h"
namespace mozilla {
namespace layers {
@ -234,6 +235,22 @@ AsyncCanvasRenderer::UpdateTarget()
return surface.forget();
}
void
AsyncCanvasRenderer::UpdateTarget(TextureClient* aTexture)
{
if (!mBufferProvider) {
return;
}
RefPtr<gfx::SourceSurface> surface = mBufferProvider->GetSnapshot();
if (surface) {
NS_ASSERTION(surface, "Must have surface to draw!");
aTexture->UpdateFromSurface(surface);
surface = nullptr;
}
}
already_AddRefed<gfx::DataSourceSurface>
AsyncCanvasRenderer::GetSurface()
{

Просмотреть файл

@ -21,6 +21,7 @@ namespace mozilla {
namespace gfx {
class DataSourceSurface;
class DrawTarget;
}
namespace gl {
@ -34,6 +35,7 @@ class HTMLCanvasElement;
namespace layers {
class CanvasClient;
class PersistentBufferProvider;
class TextureClient;
/**
@ -74,11 +76,23 @@ public:
mHeight = aHeight;
}
bool GetOpaque()
{
return mOpaque;
}
void SetOpaque(bool aOpaque)
{
mOpaque = aOpaque;
}
void SetIsAlphaPremultiplied(bool aIsAlphaPremultiplied)
{
mIsAlphaPremultiplied = aIsAlphaPremultiplied;
}
void UpdateTarget(TextureClient* aTexture);
// Active thread means the thread which spawns GLContext.
void SetActiveThread();
void ResetActiveThread();
@ -130,6 +144,7 @@ public:
// canvas' surface texture destructor will deref and destroy it too early
// Only accessed in active thread.
RefPtr<gl::GLContext> mGLContext;
PersistentBufferProvider* mBufferProvider;
private:
virtual ~AsyncCanvasRenderer();
@ -138,6 +153,7 @@ private:
already_AddRefed<gfx::DataSourceSurface> UpdateTarget();
bool mIsAlphaPremultiplied;
bool mOpaque;
uint32_t mWidth;
uint32_t mHeight;

Просмотреть файл

@ -9,6 +9,9 @@
#include "nsPrintfCString.h" // for nsPrintfCString
#include "nsString.h" // for nsAutoCString
namespace mozilla {
namespace layers {
using namespace mozilla::layers;
void
@ -76,3 +79,6 @@ EffectVRDistortion::PrintInfo(std::stringstream& aStream, const char* aPrefix)
aStream << nsPrintfCString("EffectVRDistortion (0x%p) [hmd=%p] [render-target=%p] [texture=%p]",
this, mHMD.get(), mRenderTarget.get(), mTexture).get();
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -8,12 +8,11 @@
#include "GLReadTexImageHelper.h"
#include "GLLibraryEGL.h"
using namespace mozilla;
using namespace mozilla::gl;
namespace mozilla {
namespace layers {
using namespace mozilla;
using namespace mozilla::gl;
static RefPtr<GLContext> sSnapshotContext;
EGLImageImage::EGLImageImage(EGLImage aImage, EGLSync aSync,

Просмотреть файл

@ -26,6 +26,7 @@
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
#include "TextureClientSharedSurface.h"
#include "VRManagerChild.h"
#include "gfxUtils.h"
using namespace mozilla::gfx;
using namespace mozilla::gl;
@ -69,38 +70,69 @@ CanvasClientBridge::UpdateAsync(AsyncCanvasRenderer* aRenderer)
void
CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
{
Renderer renderer;
renderer.construct<ClientCanvasLayer*>(aLayer);
UpdateRenderer(aSize, renderer);
}
void
CanvasClient2D::UpdateAsync(AsyncCanvasRenderer* aRenderer)
{
Renderer renderer;
renderer.construct<AsyncCanvasRenderer*>(aRenderer);
UpdateRenderer(aRenderer->GetSize(), renderer);
}
void
CanvasClient2D::UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer)
{
AutoRemoveTexture autoRemove(this);
ClientCanvasLayer* layer = nullptr;
AsyncCanvasRenderer* asyncRenderer = nullptr;
if (aRenderer.constructed<ClientCanvasLayer*>()) {
layer = aRenderer.ref<ClientCanvasLayer*>();
} else {
asyncRenderer = aRenderer.ref<AsyncCanvasRenderer*>();
}
if (mBuffer &&
(mBuffer->IsImmutable() || mBuffer->GetSize() != aSize)) {
autoRemove.mTexture = mBuffer;
mBuffer = nullptr;
}
bool bufferCreated = false;
mBufferCreated = false;
if (!mBuffer) {
bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
gfxContentType contentType = isOpaque
? gfxContentType::COLOR
: gfxContentType::COLOR_ALPHA;
gfx::SurfaceFormat surfaceFormat
= gfxPlatform::GetPlatform()->Optimal2DFormatForContent(contentType);
bool isOpaque;
gfxContentType contentType;
if (layer) {
isOpaque = (layer->GetContentFlags() & Layer::CONTENT_OPAQUE);
} else {
isOpaque = (asyncRenderer->GetOpaque() & Layer::CONTENT_OPAQUE);
}
contentType = isOpaque
? gfxContentType::COLOR
: gfxContentType::COLOR_ALPHA;
gfx::SurfaceFormat surfaceFormat =
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(contentType);
TextureFlags flags = TextureFlags::DEFAULT;
if (mTextureFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) {
flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
}
mBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, aLayer);
flags = TextureFlags::NO_FLAGS;
mBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, layer);
if (!mBuffer) {
NS_WARNING("Failed to allocate the TextureClient");
return;
}
MOZ_ASSERT(mBuffer->CanExposeDrawTarget());
bufferCreated = true;
mBufferCreated = true;
}
bool updated = false;
mUpdated = false;
{
TextureClientAutoLock autoLock(mBuffer, OpenMode::OPEN_WRITE_ONLY);
if (!autoLock.Succeeded()) {
@ -108,19 +140,27 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
return;
}
RefPtr<DrawTarget> target = mBuffer->BorrowDrawTarget();
if (target) {
aLayer->UpdateTarget(target);
updated = true;
if (layer) {
RefPtr<DrawTarget> target = mBuffer->BorrowDrawTarget();
if (target) {
layer->UpdateTarget(target);
}
} else {
asyncRenderer->UpdateTarget(mBuffer);
}
mUpdated = true;
}
}
if (bufferCreated && !AddTextureClient(mBuffer)) {
void
CanvasClient2D::Updated()
{
if (mBufferCreated && !AddTextureClient(mBuffer)) {
mBuffer = nullptr;
return;
}
if (updated) {
if (mUpdated) {
AutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
t->mTextureClient = mBuffer;
@ -138,7 +178,7 @@ CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
TextureFlags aFlags,
ClientCanvasLayer* aLayer)
{
if (aLayer->IsGLLayer()) {
if (aLayer && aLayer->IsGLLayer()) {
// We want a cairo backend here as we don't want to be copying into
// an accelerated backend and we like LockBits to work. This is currently
// the most effective way to make this work.

Просмотреть файл

@ -88,7 +88,9 @@ class CanvasClient2D : public CanvasClient
public:
CanvasClient2D(CompositableForwarder* aLayerForwarder,
TextureFlags aFlags)
: CanvasClient(aLayerForwarder, aFlags)
: CanvasClient(aLayerForwarder, aFlags),
mBufferCreated(false),
mUpdated(false)
{
}
@ -103,6 +105,8 @@ public:
}
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) override;
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
void UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer);
virtual bool AddTextureClient(TextureClient* aTexture) override
{
@ -110,6 +114,8 @@ public:
return CanvasClient::AddTextureClient(aTexture);
}
virtual void Updated() override;
virtual void OnDetach() override
{
mBuffer = nullptr;
@ -123,6 +129,8 @@ private:
ClientCanvasLayer* aLayer);
RefPtr<TextureClient> mBuffer;
bool mBufferCreated;
bool mUpdated;
};
// Used for GL canvases where we don't need to do any readback, i.e., with a