Files
tubestation/gfx/layers/ShareableCanvasRenderer.cpp
Morris Tseng cb1ff9368d Bug 1379920 - Introduce CanvasRenderer and its derived classes. r=nical,jrmuizel
This patch move common canvas interfaces out of layer. So I create a
base class CanvasRenderer which move interfaces from CanvasLayer.
CopyableCanvasRenderer from CopyableCanvasLayer, ClientCanvasRenderer
from ClientCanvasLayer and WebRenderCanvasRenderer from
WebRenderCanvasLayer. And finally, WebRenderCanvasRendererSync for the
non layers free mode and WebRenderCanvasRendererAsync for the layers
free mode.

Summary all changes in this patch.
* Move class CanvasLayer::Data to CanvasRenderer.h and rename it to
CanvasInitializeData. Because this class not only use by layer but also
* Move BasicCanvasLayer::UpdateSurface to
CopyableCanvasRenderer::ReadbackSurface.
* CanvasClient::Update now accepts ShareableCanvasRenderer as parameter.
not CanvasLayer.
use by layers-free mode. Move it out of layer's class makes more sense.
* Add InitializeCanvasRenderer in the canvas related classes to
initialize CanvasRenderer without involved layer.
* All canvas layer has function "CreateCanvasRendererInternal" that
initialize corresponding CanvasRenderer.

* Description of all CanvasRenderer classes:
** CanvasRenderer: Based classes.
** CopyableCanvasRenderer: Can readback canvas content to a
SourceSurface. Use by BasicCanvasLayer.
** ShareableCanvasRenderer: Provide IPC capabilities that allow sending
canvas content over IPC. This is pure virtual class because the IPC handling is
different in different LayerManager.
** ClientCanvasRenderer: Implement IPC handling for ClientLayerManager.
Use by ClientCanvasLayer.
** WebRenderCanvasRenderer: Implement IPC handling for
WebRenderLayerManager.
** WebRenderCanvasRendererSync: Use by WebRenderCanvasLayer.
** WebRenderCanvasRendererAsync: Use by layers-free mode in WebRender.

class diagram shows below:

                      +--------------+
                      |CanvasRenderer|
                      +-------+------+
                              ^
                              |
                  +----------------------+
                  |CopyableCanvasRenderer|
                  +----------------------+
                              ^
                              |
                  +-----------+-----------+
                  |ShareableCanvasRenderer|
                  +-----+-----------------+
                        ^      ^
          +-------------+      +-------+
          |                            |
+--------------------+       +---------+-------------+
|ClientCanvasRenderer|       |WebRenderCanvasRenderer|
+--------------------+       +--------+--+-----------+
                                      ^  ^
              +-----------------------+  +----+
              |                               |
+-------------+-------------+   +-------------+--------------+
|WebRenderCanvasRendererSync|   |WebRenderCanvasRendererAsync|
+---------------------------+   +----------------------------+

MozReview-Commit-ID: 5hqQ19W169r
2017-08-03 13:55:14 +08:00

244 lines
6.2 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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 "ShareableCanvasRenderer.h"
#include "GLContext.h" // for GLContext
#include "GLScreenBuffer.h" // for GLScreenBuffer
#include "SharedSurfaceGL.h" // for SurfaceFactory_GLTexture, etc
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
namespace mozilla {
namespace layers {
ShareableCanvasRenderer::ShareableCanvasRenderer()
: mCanvasClient(nullptr)
, mFactory(nullptr)
, mFlags(TextureFlags::NO_FLAGS)
{
MOZ_COUNT_CTOR(ShareableCanvasRenderer);
}
ShareableCanvasRenderer::~ShareableCanvasRenderer()
{
MOZ_COUNT_DTOR(ShareableCanvasRenderer);
Destroy();
}
void
ShareableCanvasRenderer::Initialize(const CanvasInitializeData& aData)
{
CopyableCanvasRenderer::Initialize(aData);
mCanvasClient = nullptr;
if (!mGLContext)
return;
gl::GLScreenBuffer* screen = mGLContext->Screen();
gl::SurfaceCaps caps;
if (mGLFrontbuffer) {
// The screen caps are irrelevant if we're using a separate frontbuffer.
caps = mGLFrontbuffer->mHasAlpha ? gl::SurfaceCaps::ForRGBA()
: gl::SurfaceCaps::ForRGB();
} else {
MOZ_ASSERT(screen);
caps = screen->mCaps;
}
MOZ_ASSERT(caps.alpha == aData.mHasAlpha);
auto forwarder = GetForwarder();
mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT;
if (!aData.mIsGLAlphaPremult) {
mFlags |= TextureFlags::NON_PREMULTIPLIED;
}
UniquePtr<gl::SurfaceFactory> factory =
gl::GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
if (mGLFrontbuffer || aData.mIsMirror) {
// We're using a source other than the one in the default screen.
// (SkiaGL)
mFactory = Move(factory);
if (!mFactory) {
// Absolutely must have a factory here, so create a basic one
mFactory = MakeUnique<gl::SurfaceFactory_Basic>(mGLContext, caps, mFlags);
}
} else {
if (factory)
screen->Morph(Move(factory));
}
}
void
ShareableCanvasRenderer::ClearCachedResources()
{
CopyableCanvasRenderer::ClearCachedResources();
if (mCanvasClient) {
mCanvasClient->Clear();
}
}
void
ShareableCanvasRenderer::Destroy()
{
CopyableCanvasRenderer::Destroy();
if (mCanvasClient) {
mCanvasClient->OnDetach();
mCanvasClient = nullptr;
}
}
bool
ShareableCanvasRenderer::UpdateTarget(DrawTarget* aDestTarget)
{
MOZ_ASSERT(aDestTarget);
if (!aDestTarget) {
return false;
}
RefPtr<SourceSurface> surface;
if (!mGLContext) {
AutoReturnSnapshot autoReturn;
if (mAsyncRenderer) {
surface = mAsyncRenderer->GetSurface();
} else if (mBufferProvider) {
surface = mBufferProvider->BorrowSnapshot();
autoReturn.mSnapshot = &surface;
autoReturn.mBufferProvider = mBufferProvider;
}
MOZ_ASSERT(surface);
if (!surface) {
return false;
}
aDestTarget->CopySurface(surface,
IntRect(0, 0, mSize.width, mSize.height),
IntPoint(0, 0));
return true;
}
gl::SharedSurface* frontbuffer = nullptr;
if (mGLFrontbuffer) {
frontbuffer = mGLFrontbuffer.get();
} else {
gl::GLScreenBuffer* screen = mGLContext->Screen();
const auto& front = screen->Front();
if (front) {
frontbuffer = front->Surf();
}
}
if (!frontbuffer) {
NS_WARNING("Null frame received.");
return false;
}
IntSize readSize(frontbuffer->mSize);
SurfaceFormat format =
mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
// Try to read back directly into aDestTarget's output buffer
uint8_t* destData;
IntSize destSize;
int32_t destStride;
SurfaceFormat destFormat;
if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
if (destSize == readSize && destFormat == format) {
RefPtr<DataSourceSurface> data =
Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
if (!mGLContext->Readback(frontbuffer, data)) {
aDestTarget->ReleaseBits(destData);
return false;
}
if (needsPremult) {
gfxUtils::PremultiplyDataSurface(data, data);
}
aDestTarget->ReleaseBits(destData);
return true;
}
aDestTarget->ReleaseBits(destData);
}
RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
// There will already be a warning from inside of GetTempSurface, but
// it doesn't hurt to complain:
if (NS_WARN_IF(!resultSurf)) {
return false;
}
// Readback handles Flush/MarkDirty.
if (!mGLContext->Readback(frontbuffer, resultSurf)) {
return false;
}
if (needsPremult) {
gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
}
aDestTarget->CopySurface(resultSurf,
IntRect(0, 0, readSize.width, readSize.height),
IntPoint(0, 0));
return true;
}
CanvasClient::CanvasClientType
ShareableCanvasRenderer::GetCanvasClientType()
{
if (mAsyncRenderer) {
return CanvasClient::CanvasClientAsync;
}
if (mGLContext) {
return CanvasClient::CanvasClientTypeShSurf;
}
return CanvasClient::CanvasClientSurface;
}
void
ShareableCanvasRenderer::UpdateCompositableClient()
{
if (!CreateCompositable()) {
return;
}
if (mCanvasClient && mAsyncRenderer) {
mCanvasClient->UpdateAsync(mAsyncRenderer);
}
if (!IsDirty()) {
return;
}
ResetDirty();
FirePreTransactionCallback();
if (mBufferProvider && mBufferProvider->GetTextureClient()) {
if (!mBufferProvider->SetForwarder(GetForwarder()->AsLayerForwarder())) {
gfxCriticalNote << "BufferProvider::SetForwarder failed";
return;
}
mCanvasClient->UpdateFromTexture(mBufferProvider->GetTextureClient());
} else {
mCanvasClient->Update(gfx::IntSize(mSize.width, mSize.height), this);
}
FireDidTransactionCallback();
mCanvasClient->Updated();
}
} // namespace layers
} // namespace mozilla