зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
2a98ba1c2c
Коммит
906120d775
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче