mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-20 22:27:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
531
gfx/layers/client/CanvasClient.cpp
Normal file
531
gfx/layers/client/CanvasClient.cpp
Normal file
|
|
@ -0,0 +1,531 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "CanvasClient.h"
|
||||
|
||||
#include "ClientCanvasLayer.h" // for ClientCanvasLayer
|
||||
#include "GLContext.h" // for GLContext
|
||||
#include "GLScreenBuffer.h" // for GLScreenBuffer
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
|
||||
#include "mozilla/layers/TextureClientOGL.h"
|
||||
#include "nsDebug.h" // for printf_stderr, NS_ASSERTION
|
||||
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
|
||||
#include "TextureClientSharedSurface.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/* static */ already_AddRefed<CanvasClient>
|
||||
CanvasClient::CreateCanvasClient(CanvasClientType aType,
|
||||
CompositableForwarder* aForwarder,
|
||||
TextureFlags aFlags)
|
||||
{
|
||||
switch (aType) {
|
||||
case CanvasClientTypeShSurf:
|
||||
return MakeAndAddRef<CanvasClientSharedSurface>(aForwarder, aFlags);
|
||||
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::UpdateFromTexture(TextureClient* aTexture)
|
||||
{
|
||||
MOZ_ASSERT(aTexture);
|
||||
|
||||
if (!aTexture->IsSharedWithCompositor()) {
|
||||
if (!AddTextureClient(aTexture)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mBackBuffer = nullptr;
|
||||
mFrontBuffer = nullptr;
|
||||
mBufferProviderTexture = aTexture;
|
||||
|
||||
AutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
|
||||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = aTexture;
|
||||
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), aTexture->GetSize());
|
||||
t->mFrameID = mFrameID;
|
||||
|
||||
GetForwarder()->UseTextures(this, textures);
|
||||
aTexture->SyncWithObject(GetForwarder()->GetSyncObject());
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
{
|
||||
mBufferProviderTexture = nullptr;
|
||||
|
||||
AutoRemoveTexture autoRemove(this);
|
||||
if (mBackBuffer && (mBackBuffer->IsReadLocked() || mBackBuffer->GetSize() != aSize)) {
|
||||
autoRemove.mTexture = mBackBuffer;
|
||||
mBackBuffer = nullptr;
|
||||
}
|
||||
|
||||
bool bufferCreated = false;
|
||||
if (!mBackBuffer) {
|
||||
bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
|
||||
gfxContentType 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;
|
||||
}
|
||||
|
||||
mBackBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, aLayer);
|
||||
if (!mBackBuffer) {
|
||||
NS_WARNING("Failed to allocate the TextureClient");
|
||||
return;
|
||||
}
|
||||
mBackBuffer->EnableReadLock();
|
||||
MOZ_ASSERT(mBackBuffer->CanExposeDrawTarget());
|
||||
|
||||
bufferCreated = true;
|
||||
}
|
||||
|
||||
bool updated = false;
|
||||
{
|
||||
TextureClientAutoLock autoLock(mBackBuffer, OpenMode::OPEN_WRITE_ONLY);
|
||||
if (!autoLock.Succeeded()) {
|
||||
mBackBuffer = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> target = mBackBuffer->BorrowDrawTarget();
|
||||
if (target) {
|
||||
if (!aLayer->UpdateTarget(target)) {
|
||||
NS_WARNING("Failed to copy the canvas into a TextureClient.");
|
||||
return;
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferCreated && !AddTextureClient(mBackBuffer)) {
|
||||
mBackBuffer = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
AutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
|
||||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = mBackBuffer;
|
||||
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBackBuffer->GetSize());
|
||||
t->mFrameID = mFrameID;
|
||||
GetForwarder()->UseTextures(this, textures);
|
||||
mBackBuffer->SyncWithObject(GetForwarder()->GetSyncObject());
|
||||
}
|
||||
|
||||
mBackBuffer.swap(mFrontBuffer);
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
TextureFlags aFlags,
|
||||
ClientCanvasLayer* aLayer)
|
||||
{
|
||||
if (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.
|
||||
return TextureClient::CreateForRawBufferAccess(GetForwarder(),
|
||||
aFormat, aSize, BackendType::CAIRO,
|
||||
mTextureFlags | aFlags);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
return CreateTextureClientForDrawing(aFormat, aSize, BackendSelector::Canvas, aFlags);
|
||||
#else
|
||||
// XXX - We should use CreateTextureClientForDrawing, but we first need
|
||||
// to use double buffering.
|
||||
gfx::BackendType backend = gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
|
||||
return TextureClient::CreateForRawBufferAccess(GetForwarder(),
|
||||
aFormat, aSize, backend,
|
||||
mTextureFlags | aFlags);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CanvasClientSharedSurface::CanvasClientSharedSurface(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags)
|
||||
: CanvasClient(aLayerForwarder, aFlags)
|
||||
{ }
|
||||
|
||||
CanvasClientSharedSurface::~CanvasClientSharedSurface()
|
||||
{
|
||||
ClearSurfaces();
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// Readback
|
||||
|
||||
// For formats compatible with R8G8B8A8.
|
||||
static inline void SwapRB_R8G8B8A8(uint8_t* pixel) {
|
||||
// [RR, GG, BB, AA]
|
||||
Swap(pixel[0], pixel[2]);
|
||||
}
|
||||
|
||||
class TexClientFactory
|
||||
{
|
||||
CompositableForwarder* const mAllocator;
|
||||
const bool mHasAlpha;
|
||||
const gfx::IntSize mSize;
|
||||
const gfx::BackendType mBackendType;
|
||||
const TextureFlags mBaseTexFlags;
|
||||
const LayersBackend mLayersBackend;
|
||||
|
||||
public:
|
||||
TexClientFactory(CompositableForwarder* allocator, bool hasAlpha,
|
||||
const gfx::IntSize& size, gfx::BackendType backendType,
|
||||
TextureFlags baseTexFlags, LayersBackend layersBackend)
|
||||
: mAllocator(allocator)
|
||||
, mHasAlpha(hasAlpha)
|
||||
, mSize(size)
|
||||
, mBackendType(backendType)
|
||||
, mBaseTexFlags(baseTexFlags)
|
||||
, mLayersBackend(layersBackend)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
already_AddRefed<TextureClient> Create(gfx::SurfaceFormat format) {
|
||||
return TextureClient::CreateForRawBufferAccess(mAllocator, format,
|
||||
mSize, mBackendType,
|
||||
mBaseTexFlags);
|
||||
}
|
||||
|
||||
public:
|
||||
already_AddRefed<TextureClient> CreateB8G8R8AX8() {
|
||||
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8
|
||||
: gfx::SurfaceFormat::B8G8R8X8;
|
||||
return Create(format);
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient> CreateR8G8B8AX8() {
|
||||
RefPtr<TextureClient> ret;
|
||||
|
||||
bool areRGBAFormatsBroken = mLayersBackend == LayersBackend::LAYERS_BASIC;
|
||||
if (!areRGBAFormatsBroken) {
|
||||
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
|
||||
: gfx::SurfaceFormat::R8G8B8X8;
|
||||
ret = Create(format);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
ret = CreateB8G8R8AX8();
|
||||
if (ret) {
|
||||
ret->AddFlags(TextureFlags::RB_SWAPPED);
|
||||
}
|
||||
}
|
||||
|
||||
return ret.forget();
|
||||
}
|
||||
};
|
||||
|
||||
static already_AddRefed<TextureClient>
|
||||
TexClientFromReadback(SharedSurface* src, CompositableForwarder* allocator,
|
||||
TextureFlags baseFlags, LayersBackend layersBackend)
|
||||
{
|
||||
auto backendType = gfx::BackendType::CAIRO;
|
||||
TexClientFactory factory(allocator, src->mHasAlpha, src->mSize, backendType,
|
||||
baseFlags, layersBackend);
|
||||
|
||||
RefPtr<TextureClient> texClient;
|
||||
|
||||
{
|
||||
gl::ScopedReadbackFB autoReadback(src);
|
||||
|
||||
// We have a source FB, now we need a format.
|
||||
GLenum destFormat = LOCAL_GL_BGRA;
|
||||
GLenum destType = LOCAL_GL_UNSIGNED_BYTE;
|
||||
GLenum readFormat;
|
||||
GLenum readType;
|
||||
|
||||
// We actually don't care if they match, since we can handle
|
||||
// any read{Format,Type} we get.
|
||||
auto gl = src->mGL;
|
||||
GetActualReadFormats(gl, destFormat, destType, &readFormat, &readType);
|
||||
|
||||
MOZ_ASSERT(readFormat == LOCAL_GL_RGBA ||
|
||||
readFormat == LOCAL_GL_BGRA);
|
||||
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
|
||||
|
||||
// With a format and type, we can create texClient.
|
||||
if (readFormat == LOCAL_GL_BGRA &&
|
||||
readType == LOCAL_GL_UNSIGNED_BYTE)
|
||||
{
|
||||
// 0xAARRGGBB
|
||||
// In Lendian: [BB, GG, RR, AA]
|
||||
texClient = factory.CreateB8G8R8AX8();
|
||||
|
||||
} else if (readFormat == LOCAL_GL_RGBA &&
|
||||
readType == LOCAL_GL_UNSIGNED_BYTE)
|
||||
{
|
||||
// [RR, GG, BB, AA]
|
||||
texClient = factory.CreateR8G8B8AX8();
|
||||
} else {
|
||||
MOZ_CRASH("GFX: Bad `read{Format,Type}`.");
|
||||
}
|
||||
|
||||
MOZ_ASSERT(texClient);
|
||||
if (!texClient)
|
||||
return nullptr;
|
||||
|
||||
// With a texClient, we can lock for writing.
|
||||
TextureClientAutoLock autoLock(texClient, OpenMode::OPEN_WRITE);
|
||||
DebugOnly<bool> succeeded = autoLock.Succeeded();
|
||||
MOZ_ASSERT(succeeded, "texture should have locked");
|
||||
|
||||
MappedTextureData mapped;
|
||||
texClient->BorrowMappedData(mapped);
|
||||
|
||||
// ReadPixels from the current FB into mapped.data.
|
||||
auto width = src->mSize.width;
|
||||
auto height = src->mSize.height;
|
||||
|
||||
{
|
||||
ScopedPackState scopedPackState(gl);
|
||||
|
||||
MOZ_ASSERT(mapped.stride/4 == mapped.size.width);
|
||||
gl->raw_fReadPixels(0, 0, width, height, readFormat, readType, mapped.data);
|
||||
}
|
||||
|
||||
// RB_SWAPPED doesn't work with D3D11. (bug 1051010)
|
||||
// RB_SWAPPED doesn't work with Basic. (bug ???????)
|
||||
// RB_SWAPPED doesn't work with D3D9. (bug ???????)
|
||||
bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_BASIC ||
|
||||
layersBackend == LayersBackend::LAYERS_D3D9 ||
|
||||
layersBackend == LayersBackend::LAYERS_D3D11;
|
||||
if (texClient->HasFlags(TextureFlags::RB_SWAPPED) &&
|
||||
layersNeedsManualSwap)
|
||||
{
|
||||
size_t pixels = width * height;
|
||||
uint8_t* itr = mapped.data;
|
||||
for (size_t i = 0; i < pixels; i++) {
|
||||
SwapRB_R8G8B8A8(itr);
|
||||
itr += 4;
|
||||
}
|
||||
|
||||
texClient->RemoveFlags(TextureFlags::RB_SWAPPED);
|
||||
}
|
||||
}
|
||||
|
||||
return texClient.forget();
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
static already_AddRefed<SharedSurfaceTextureClient>
|
||||
CloneSurface(gl::SharedSurface* src, gl::SurfaceFactory* factory)
|
||||
{
|
||||
RefPtr<SharedSurfaceTextureClient> dest = factory->NewTexClient(src->mSize);
|
||||
if (!dest) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gl::SharedSurface* destSurf = dest->Surf();
|
||||
|
||||
destSurf->ProducerAcquire();
|
||||
SharedSurface::ProdCopy(src, dest->Surf(), factory);
|
||||
destSurf->ProducerRelease();
|
||||
|
||||
return dest.forget();
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
{
|
||||
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 (layer && layer->mGLFrontbuffer) {
|
||||
mShSurfClient = CloneSurface(layer->mGLFrontbuffer.get(), layer->mFactory.get());
|
||||
if (!mShSurfClient) {
|
||||
gfxCriticalError() << "Invalid canvas front buffer";
|
||||
return;
|
||||
}
|
||||
} else if (layer && layer->mIsMirror) {
|
||||
mShSurfClient = CloneSurface(gl->Screen()->Front()->Surf(), layer->mFactory.get());
|
||||
if (!mShSurfClient) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
mShSurfClient = gl->Screen()->Front();
|
||||
if (mShSurfClient && mShSurfClient->GetAllocator() &&
|
||||
mShSurfClient->GetAllocator() != GetForwarder()->GetTextureForwarder()) {
|
||||
mShSurfClient = CloneSurface(mShSurfClient->Surf(), gl->Screen()->Factory());
|
||||
}
|
||||
if (!mShSurfClient) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(mShSurfClient);
|
||||
|
||||
newFront = mShSurfClient;
|
||||
|
||||
SharedSurface* surf = mShSurfClient->Surf();
|
||||
|
||||
// Readback if needed.
|
||||
mReadbackClient = nullptr;
|
||||
|
||||
auto forwarder = GetForwarder();
|
||||
|
||||
bool needsReadback = (surf->mType == SharedSurfaceType::Basic);
|
||||
if (needsReadback) {
|
||||
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 layersBackend = shadowForwarder->GetCompositorBackendType();
|
||||
mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend);
|
||||
|
||||
newFront = mReadbackClient;
|
||||
} else {
|
||||
mReadbackClient = nullptr;
|
||||
}
|
||||
|
||||
if (asyncRenderer) {
|
||||
// If surface type is Basic, above codes will readback
|
||||
// the GLContext to mReadbackClient in order to send frame to
|
||||
// compositor. We copy from this TextureClient directly by
|
||||
// calling CopyFromTextureClient().
|
||||
// Therefore, if main-thread want the content of GLContext,
|
||||
// it doesn't have to readback from GLContext again.
|
||||
//
|
||||
// Otherwise, if surface type isn't Basic, we will read from
|
||||
// SharedSurface directly from main-thread. We still pass
|
||||
// mReadbackClient which is nullptr here to tell
|
||||
// AsyncCanvasRenderer reset some properties.
|
||||
asyncRenderer->CopyFromTextureClient(mReadbackClient);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(newFront);
|
||||
if (!newFront) {
|
||||
// May happen in a release build in case of memory pressure.
|
||||
gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. Size: " << aSize;
|
||||
return;
|
||||
}
|
||||
|
||||
mNewFront = newFront;
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientSharedSurface::Updated()
|
||||
{
|
||||
if (!mNewFront) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto forwarder = GetForwarder();
|
||||
|
||||
mFront = mNewFront;
|
||||
mNewFront = nullptr;
|
||||
|
||||
// Add the new TexClient.
|
||||
MOZ_ALWAYS_TRUE( AddTextureClient(mFront) );
|
||||
|
||||
AutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
|
||||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = mFront;
|
||||
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize());
|
||||
t->mFrameID = mFrameID;
|
||||
forwarder->UseTextures(this, textures);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientSharedSurface::OnDetach() {
|
||||
ClearSurfaces();
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientSharedSurface::ClearSurfaces()
|
||||
{
|
||||
if (mFront) {
|
||||
mFront->CancelWaitForRecycle();
|
||||
}
|
||||
mFront = nullptr;
|
||||
mNewFront = nullptr;
|
||||
mShSurfClient = nullptr;
|
||||
mReadbackClient = nullptr;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
216
gfx/layers/client/CanvasClient.h
Normal file
216
gfx/layers/client/CanvasClient.h
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_CANVASCLIENT_H
|
||||
#define MOZILLA_GFX_CANVASCLIENT_H
|
||||
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
|
||||
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
|
||||
#include "mozilla/layers/PersistentBufferProvider.h"
|
||||
|
||||
// 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
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class AsyncCanvasRenderer;
|
||||
class ClientCanvasLayer;
|
||||
class CompositableForwarder;
|
||||
class ShadowableLayer;
|
||||
class SharedSurfaceTextureClient;
|
||||
|
||||
/**
|
||||
* Compositable client for 2d and webgl canvas.
|
||||
*/
|
||||
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
|
||||
* host.
|
||||
*/
|
||||
enum CanvasClientType {
|
||||
CanvasClientSurface,
|
||||
CanvasClientGLContext,
|
||||
CanvasClientTypeShSurf,
|
||||
CanvasClientAsync, // webgl on workers
|
||||
};
|
||||
static already_AddRefed<CanvasClient> CreateCanvasClient(CanvasClientType aType,
|
||||
CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags);
|
||||
|
||||
CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags)
|
||||
: CompositableClient(aFwd, aFlags)
|
||||
, mFrameID(0)
|
||||
{
|
||||
mTextureFlags = aFlags;
|
||||
}
|
||||
|
||||
virtual ~CanvasClient() {}
|
||||
|
||||
virtual void Clear() {};
|
||||
|
||||
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) = 0;
|
||||
|
||||
virtual bool AddTextureClient(TextureClient* aTexture) override
|
||||
{
|
||||
++mFrameID;
|
||||
return CompositableClient::AddTextureClient(aTexture);
|
||||
}
|
||||
|
||||
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) {}
|
||||
|
||||
virtual void UpdateFromTexture(TextureClient* aTexture) {}
|
||||
|
||||
virtual void Updated() { }
|
||||
|
||||
protected:
|
||||
int32_t mFrameID;
|
||||
};
|
||||
|
||||
// Used for 2D canvases and WebGL canvas on non-GL systems where readback is requried.
|
||||
class CanvasClient2D : public CanvasClient
|
||||
{
|
||||
public:
|
||||
CanvasClient2D(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags)
|
||||
: CanvasClient(aLayerForwarder, aFlags)
|
||||
{
|
||||
}
|
||||
|
||||
TextureInfo GetTextureInfo() const override
|
||||
{
|
||||
return TextureInfo(CompositableType::IMAGE, mTextureFlags);
|
||||
}
|
||||
|
||||
virtual void Clear() override
|
||||
{
|
||||
mBackBuffer = mFrontBuffer = nullptr;
|
||||
}
|
||||
|
||||
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) override;
|
||||
|
||||
virtual void UpdateFromTexture(TextureClient* aBuffer) override;
|
||||
|
||||
virtual bool AddTextureClient(TextureClient* aTexture) override
|
||||
{
|
||||
return CanvasClient::AddTextureClient(aTexture);
|
||||
}
|
||||
|
||||
virtual void OnDetach() override
|
||||
{
|
||||
mBackBuffer = mFrontBuffer = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
already_AddRefed<TextureClient>
|
||||
CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
TextureFlags aFlags,
|
||||
ClientCanvasLayer* aLayer);
|
||||
|
||||
RefPtr<TextureClient> mBackBuffer;
|
||||
RefPtr<TextureClient> mFrontBuffer;
|
||||
// We store this texture separately to make sure it is not written into
|
||||
// in Update() if for some silly reason we end up alternating between
|
||||
// UpdateFromTexture and Update.
|
||||
// This code is begging for a cleanup. The situation described above should
|
||||
// not be made possible.
|
||||
RefPtr<TextureClient> mBufferProviderTexture;
|
||||
};
|
||||
|
||||
// Used for GL canvases where we don't need to do any readback, i.e., with a
|
||||
// GL backend.
|
||||
class CanvasClientSharedSurface : public CanvasClient
|
||||
{
|
||||
private:
|
||||
RefPtr<SharedSurfaceTextureClient> mShSurfClient;
|
||||
RefPtr<TextureClient> mReadbackClient;
|
||||
RefPtr<TextureClient> mFront;
|
||||
RefPtr<TextureClient> mNewFront;
|
||||
|
||||
void ClearSurfaces();
|
||||
|
||||
public:
|
||||
CanvasClientSharedSurface(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags);
|
||||
|
||||
~CanvasClientSharedSurface();
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const override {
|
||||
return TextureInfo(CompositableType::IMAGE);
|
||||
}
|
||||
|
||||
virtual void Clear() override {
|
||||
ClearSurfaces();
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
#endif
|
||||
261
gfx/layers/client/ClientCanvasLayer.cpp
Normal file
261
gfx/layers/client/ClientCanvasLayer.cpp
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
/* -*- 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 "ClientCanvasLayer.h"
|
||||
#include "GLContext.h" // for GLContext
|
||||
#include "GLScreenBuffer.h" // for GLScreenBuffer
|
||||
#include "GeckoProfiler.h" // for PROFILER_LABEL
|
||||
#include "SharedSurfaceEGL.h" // for SurfaceFactory_EGLImage
|
||||
#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
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
|
||||
#include "gfxPrefs.h" // for WebGLForceLayersReadback
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
ClientCanvasLayer::~ClientCanvasLayer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ClientCanvasLayer);
|
||||
if (mCanvasClient) {
|
||||
mCanvasClient->OnDetach();
|
||||
mCanvasClient = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientCanvasLayer::Initialize(const Data& aData)
|
||||
{
|
||||
CopyableCanvasLayer::Initialize(aData);
|
||||
|
||||
mCanvasClient = nullptr;
|
||||
|
||||
if (!mGLContext)
|
||||
return;
|
||||
|
||||
GLScreenBuffer* screen = mGLContext->Screen();
|
||||
|
||||
SurfaceCaps caps;
|
||||
if (mGLFrontbuffer) {
|
||||
// The screen caps are irrelevant if we're using a separate frontbuffer.
|
||||
caps = mGLFrontbuffer->mHasAlpha ? SurfaceCaps::ForRGBA()
|
||||
: SurfaceCaps::ForRGB();
|
||||
} else {
|
||||
MOZ_ASSERT(screen);
|
||||
caps = screen->mCaps;
|
||||
}
|
||||
MOZ_ASSERT(caps.alpha == aData.mHasAlpha);
|
||||
|
||||
auto forwarder = ClientManager()->AsShadowForwarder();
|
||||
|
||||
mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT;
|
||||
if (!aData.mIsGLAlphaPremult) {
|
||||
mFlags |= TextureFlags::NON_PREMULTIPLIED;
|
||||
}
|
||||
|
||||
UniquePtr<SurfaceFactory> factory = 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<SurfaceFactory_Basic>(mGLContext, caps, mFlags);
|
||||
}
|
||||
} else {
|
||||
if (factory)
|
||||
screen->Morph(Move(factory));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientCanvasLayer::RenderLayer()
|
||||
{
|
||||
PROFILER_LABEL("ClientCanvasLayer", "RenderLayer",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
RenderMaskLayers(this);
|
||||
|
||||
if (!mCanvasClient) {
|
||||
TextureFlags flags = TextureFlags::DEFAULT;
|
||||
if (mOriginPos == gl::OriginPos::BottomLeft) {
|
||||
flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
|
||||
}
|
||||
|
||||
if (!mIsAlphaPremultiplied) {
|
||||
flags |= TextureFlags::NON_PREMULTIPLIED;
|
||||
}
|
||||
|
||||
mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(),
|
||||
ClientManager()->AsShadowForwarder(),
|
||||
flags);
|
||||
if (!mCanvasClient) {
|
||||
return;
|
||||
}
|
||||
if (HasShadow()) {
|
||||
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();
|
||||
if (mBufferProvider && mBufferProvider->GetTextureClient()) {
|
||||
if (!mBufferProvider->SetForwarder(ClientManager()->AsShadowForwarder())) {
|
||||
gfxCriticalNote << "BufferProvider::SetForwarder failed";
|
||||
return;
|
||||
}
|
||||
mCanvasClient->UpdateFromTexture(mBufferProvider->GetTextureClient());
|
||||
} else {
|
||||
mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this);
|
||||
}
|
||||
|
||||
FireDidTransactionCallback();
|
||||
|
||||
ClientManager()->Hold(this);
|
||||
mCanvasClient->Updated();
|
||||
}
|
||||
|
||||
bool
|
||||
ClientCanvasLayer::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, mBounds.width, mBounds.height),
|
||||
IntPoint(0, 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
SharedSurface* frontbuffer = nullptr;
|
||||
if (mGLFrontbuffer) {
|
||||
frontbuffer = mGLFrontbuffer.get();
|
||||
} else {
|
||||
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 = (GetContentFlags() & CONTENT_OPAQUE)
|
||||
? 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);
|
||||
mGLContext->Readback(frontbuffer, data);
|
||||
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.
|
||||
mGLContext->Readback(frontbuffer, resultSurf);
|
||||
if (needsPremult) {
|
||||
gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
|
||||
}
|
||||
|
||||
aDestTarget->CopySurface(resultSurf,
|
||||
IntRect(0, 0, readSize.width, readSize.height),
|
||||
IntPoint(0, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CanvasClient::CanvasClientType
|
||||
ClientCanvasLayer::GetCanvasClientType()
|
||||
{
|
||||
if (mAsyncRenderer) {
|
||||
return CanvasClient::CanvasClientAsync;
|
||||
}
|
||||
|
||||
if (mGLContext) {
|
||||
return CanvasClient::CanvasClientTypeShSurf;
|
||||
}
|
||||
return CanvasClient::CanvasClientSurface;
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasLayer>
|
||||
ClientLayerManager::CreateCanvasLayer()
|
||||
{
|
||||
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
||||
RefPtr<ClientCanvasLayer> layer =
|
||||
new ClientCanvasLayer(this);
|
||||
CREATE_SHADOW(Canvas);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
116
gfx/layers/client/ClientCanvasLayer.h
Normal file
116
gfx/layers/client/ClientCanvasLayer.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef GFX_CLIENTCANVASLAYER_H
|
||||
#define GFX_CLIENTCANVASLAYER_H
|
||||
|
||||
#include "CanvasClient.h" // for CanvasClient, etc
|
||||
#include "ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "CopyableCanvasLayer.h" // for CopyableCanvasLayer
|
||||
#include "Layers.h" // for CanvasLayer, etc
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/layers/LayersMessages.h" // for CanvasLayerAttributes, etc
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
class SurfaceFactory;
|
||||
} // namespace gl
|
||||
|
||||
namespace layers {
|
||||
|
||||
class CompositableClient;
|
||||
class ShadowableLayer;
|
||||
|
||||
class ClientCanvasLayer : public CopyableCanvasLayer,
|
||||
public ClientLayer
|
||||
{
|
||||
typedef CanvasClient::CanvasClientType CanvasClientType;
|
||||
public:
|
||||
explicit ClientCanvasLayer(ClientLayerManager* aLayerManager) :
|
||||
CopyableCanvasLayer(aLayerManager, static_cast<ClientLayer*>(this))
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientCanvasLayer);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~ClientCanvasLayer();
|
||||
|
||||
public:
|
||||
virtual void SetVisibleRegion(const LayerIntRegion& aRegion) override
|
||||
{
|
||||
NS_ASSERTION(ClientManager()->InConstruction(),
|
||||
"Can only set properties in construction phase");
|
||||
CanvasLayer::SetVisibleRegion(aRegion);
|
||||
}
|
||||
|
||||
virtual void Initialize(const Data& aData) override;
|
||||
|
||||
virtual void RenderLayer() override;
|
||||
|
||||
virtual void ClearCachedResources() override
|
||||
{
|
||||
if (mCanvasClient) {
|
||||
mCanvasClient->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void HandleMemoryPressure() override
|
||||
{
|
||||
if (mCanvasClient) {
|
||||
mCanvasClient->HandleMemoryPressure();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override
|
||||
{
|
||||
aAttrs = CanvasLayerAttributes(mSamplingFilter, mBounds);
|
||||
}
|
||||
|
||||
virtual Layer* AsLayer() override { return this; }
|
||||
virtual ShadowableLayer* AsShadowableLayer() override { return this; }
|
||||
|
||||
virtual void Disconnect() override
|
||||
{
|
||||
mCanvasClient = nullptr;
|
||||
ClientLayer::Disconnect();
|
||||
}
|
||||
|
||||
virtual CompositableClient* GetCompositableClient() override
|
||||
{
|
||||
return mCanvasClient;
|
||||
}
|
||||
|
||||
const TextureFlags& Flags() const { return mFlags; }
|
||||
|
||||
protected:
|
||||
|
||||
bool UpdateTarget(gfx::DrawTarget* aDestTarget = nullptr);
|
||||
|
||||
ClientLayerManager* ClientManager()
|
||||
{
|
||||
return static_cast<ClientLayerManager*>(mManager);
|
||||
}
|
||||
|
||||
CanvasClientType GetCanvasClientType();
|
||||
|
||||
RefPtr<CanvasClient> mCanvasClient;
|
||||
|
||||
UniquePtr<gl::SurfaceFactory> mFactory;
|
||||
|
||||
TextureFlags mFlags;
|
||||
|
||||
friend class CanvasClient2D;
|
||||
friend class CanvasClientSharedSurface;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
79
gfx/layers/client/ClientColorLayer.cpp
Normal file
79
gfx/layers/client/ClientColorLayer.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/* -*- 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 "ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "Layers.h" // for ColorLayer, etc
|
||||
#include "mozilla/layers/LayersMessages.h" // for ColorLayerAttributes, etc
|
||||
#include "mozilla/mozalloc.h" // for operator new
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
class ClientColorLayer : public ColorLayer,
|
||||
public ClientLayer {
|
||||
public:
|
||||
explicit ClientColorLayer(ClientLayerManager* aLayerManager) :
|
||||
ColorLayer(aLayerManager, static_cast<ClientLayer*>(this))
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientColorLayer);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~ClientColorLayer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ClientColorLayer);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void SetVisibleRegion(const LayerIntRegion& aRegion)
|
||||
{
|
||||
NS_ASSERTION(ClientManager()->InConstruction(),
|
||||
"Can only set properties in construction phase");
|
||||
ColorLayer::SetVisibleRegion(aRegion);
|
||||
}
|
||||
|
||||
virtual void RenderLayer()
|
||||
{
|
||||
RenderMaskLayers(this);
|
||||
}
|
||||
|
||||
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
|
||||
{
|
||||
aAttrs = ColorLayerAttributes(GetColor(), GetBounds());
|
||||
}
|
||||
|
||||
virtual Layer* AsLayer() { return this; }
|
||||
virtual ShadowableLayer* AsShadowableLayer() { return this; }
|
||||
|
||||
virtual void Disconnect()
|
||||
{
|
||||
ClientLayer::Disconnect();
|
||||
}
|
||||
|
||||
protected:
|
||||
ClientLayerManager* ClientManager()
|
||||
{
|
||||
return static_cast<ClientLayerManager*>(mManager);
|
||||
}
|
||||
};
|
||||
|
||||
already_AddRefed<ColorLayer>
|
||||
ClientLayerManager::CreateColorLayer()
|
||||
{
|
||||
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
||||
RefPtr<ClientColorLayer> layer =
|
||||
new ClientColorLayer(this);
|
||||
CREATE_SHADOW(Color);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
36
gfx/layers/client/ClientContainerLayer.cpp
Normal file
36
gfx/layers/client/ClientContainerLayer.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- 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 "ClientContainerLayer.h"
|
||||
#include "ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "mozilla/mozalloc.h" // for operator new
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
already_AddRefed<ContainerLayer>
|
||||
ClientLayerManager::CreateContainerLayer()
|
||||
{
|
||||
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
||||
RefPtr<ClientContainerLayer> layer =
|
||||
new ClientContainerLayer(this);
|
||||
CREATE_SHADOW(Container);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<RefLayer>
|
||||
ClientLayerManager::CreateRefLayer()
|
||||
{
|
||||
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
||||
RefPtr<ClientRefLayer> layer =
|
||||
new ClientRefLayer(this);
|
||||
CREATE_SHADOW(Ref);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
189
gfx/layers/client/ClientContainerLayer.h
Normal file
189
gfx/layers/client/ClientContainerLayer.h
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef GFX_CLIENTCONTAINERLAYER_H
|
||||
#define GFX_CLIENTCONTAINERLAYER_H
|
||||
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include "ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "Layers.h" // for Layer, ContainerLayer, etc
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
#include "nsTArray.h" // for AutoTArray
|
||||
#include "ReadbackProcessor.h"
|
||||
#include "ClientPaintedLayer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ShadowableLayer;
|
||||
|
||||
class ClientContainerLayer : public ContainerLayer,
|
||||
public ClientLayer
|
||||
{
|
||||
public:
|
||||
explicit ClientContainerLayer(ClientLayerManager* aManager) :
|
||||
ContainerLayer(aManager, static_cast<ClientLayer*>(this))
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientContainerLayer);
|
||||
mSupportsComponentAlphaChildren = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~ClientContainerLayer()
|
||||
{
|
||||
while (mFirstChild) {
|
||||
ContainerLayer::RemoveChild(mFirstChild);
|
||||
}
|
||||
|
||||
MOZ_COUNT_DTOR(ClientContainerLayer);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void RenderLayer() override
|
||||
{
|
||||
RenderMaskLayers(this);
|
||||
|
||||
DefaultComputeSupportsComponentAlphaChildren();
|
||||
|
||||
AutoTArray<Layer*, 12> children;
|
||||
SortChildrenBy3DZOrder(children);
|
||||
|
||||
ReadbackProcessor readback;
|
||||
readback.BuildUpdates(this);
|
||||
|
||||
for (uint32_t i = 0; i < children.Length(); i++) {
|
||||
Layer* child = children.ElementAt(i);
|
||||
|
||||
ToClientLayer(child)->RenderLayerWithReadback(&readback);
|
||||
|
||||
if (!ClientManager()->GetRepeatTransaction() &&
|
||||
!child->GetInvalidRegion().IsEmpty()) {
|
||||
child->Mutated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetVisibleRegion(const LayerIntRegion& aRegion) override
|
||||
{
|
||||
NS_ASSERTION(ClientManager()->InConstruction(),
|
||||
"Can only set properties in construction phase");
|
||||
ContainerLayer::SetVisibleRegion(aRegion);
|
||||
}
|
||||
virtual bool InsertAfter(Layer* aChild, Layer* aAfter) override
|
||||
{
|
||||
if(!ClientManager()->InConstruction()) {
|
||||
NS_ERROR("Can only set properties in construction phase");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ContainerLayer::InsertAfter(aChild, aAfter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClientManager()->AsShadowForwarder()->InsertAfter(ClientManager()->Hold(this),
|
||||
ClientManager()->Hold(aChild),
|
||||
aAfter ? ClientManager()->Hold(aAfter) : nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool RemoveChild(Layer* aChild) override
|
||||
{
|
||||
if (!ClientManager()->InConstruction()) {
|
||||
NS_ERROR("Can only set properties in construction phase");
|
||||
return false;
|
||||
}
|
||||
// hold on to aChild before we remove it!
|
||||
ShadowableLayer *heldChild = ClientManager()->Hold(aChild);
|
||||
if (!ContainerLayer::RemoveChild(aChild)) {
|
||||
return false;
|
||||
}
|
||||
ClientManager()->AsShadowForwarder()->RemoveChild(ClientManager()->Hold(this), heldChild);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool RepositionChild(Layer* aChild, Layer* aAfter) override
|
||||
{
|
||||
if (!ClientManager()->InConstruction()) {
|
||||
NS_ERROR("Can only set properties in construction phase");
|
||||
return false;
|
||||
}
|
||||
if (!ContainerLayer::RepositionChild(aChild, aAfter)) {
|
||||
return false;
|
||||
}
|
||||
ClientManager()->AsShadowForwarder()->RepositionChild(ClientManager()->Hold(this),
|
||||
ClientManager()->Hold(aChild),
|
||||
aAfter ? ClientManager()->Hold(aAfter) : nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual Layer* AsLayer() override { return this; }
|
||||
virtual ShadowableLayer* AsShadowableLayer() override { return this; }
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) override
|
||||
{
|
||||
DefaultComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
||||
void ForceIntermediateSurface() { mUseIntermediateSurface = true; }
|
||||
|
||||
void SetSupportsComponentAlphaChildren(bool aSupports) { mSupportsComponentAlphaChildren = aSupports; }
|
||||
|
||||
virtual void Disconnect() override
|
||||
{
|
||||
ClientLayer::Disconnect();
|
||||
}
|
||||
|
||||
protected:
|
||||
ClientLayerManager* ClientManager()
|
||||
{
|
||||
return static_cast<ClientLayerManager*>(mManager);
|
||||
}
|
||||
};
|
||||
|
||||
class ClientRefLayer : public RefLayer,
|
||||
public ClientLayer {
|
||||
public:
|
||||
explicit ClientRefLayer(ClientLayerManager* aManager) :
|
||||
RefLayer(aManager, static_cast<ClientLayer*>(this))
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientRefLayer);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~ClientRefLayer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ClientRefLayer);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Layer* AsLayer() { return this; }
|
||||
virtual ShadowableLayer* AsShadowableLayer() { return this; }
|
||||
|
||||
virtual void Disconnect()
|
||||
{
|
||||
ClientLayer::Disconnect();
|
||||
}
|
||||
|
||||
virtual void RenderLayer() { }
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
DefaultComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
||||
private:
|
||||
ClientLayerManager* ClientManager()
|
||||
{
|
||||
return static_cast<ClientLayerManager*>(mManager);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
170
gfx/layers/client/ClientImageLayer.cpp
Normal file
170
gfx/layers/client/ClientImageLayer.cpp
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/* -*- 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 "ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "ImageContainer.h" // for AutoLockImage, etc
|
||||
#include "ImageLayers.h" // for ImageLayer
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/ImageClient.h" // for ImageClient, etc
|
||||
#include "mozilla/layers/LayersMessages.h" // for ImageLayerAttributes, etc
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
class ClientImageLayer : public ImageLayer,
|
||||
public ClientLayer {
|
||||
public:
|
||||
explicit ClientImageLayer(ClientLayerManager* aLayerManager)
|
||||
: ImageLayer(aLayerManager, static_cast<ClientLayer*>(this))
|
||||
, mImageClientTypeContainer(CompositableType::UNKNOWN)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientImageLayer);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~ClientImageLayer()
|
||||
{
|
||||
DestroyBackBuffer();
|
||||
MOZ_COUNT_DTOR(ClientImageLayer);
|
||||
}
|
||||
|
||||
virtual void SetContainer(ImageContainer* aContainer) override
|
||||
{
|
||||
ImageLayer::SetContainer(aContainer);
|
||||
mImageClientTypeContainer = CompositableType::UNKNOWN;
|
||||
}
|
||||
|
||||
virtual void SetVisibleRegion(const LayerIntRegion& aRegion) override
|
||||
{
|
||||
NS_ASSERTION(ClientManager()->InConstruction(),
|
||||
"Can only set properties in construction phase");
|
||||
ImageLayer::SetVisibleRegion(aRegion);
|
||||
}
|
||||
|
||||
virtual void RenderLayer() override;
|
||||
|
||||
virtual void ClearCachedResources() override
|
||||
{
|
||||
DestroyBackBuffer();
|
||||
}
|
||||
|
||||
virtual void HandleMemoryPressure() override
|
||||
{
|
||||
if (mImageClient) {
|
||||
mImageClient->HandleMemoryPressure();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override
|
||||
{
|
||||
aAttrs = ImageLayerAttributes(mSamplingFilter, mScaleToSize, mScaleMode);
|
||||
}
|
||||
|
||||
virtual Layer* AsLayer() override { return this; }
|
||||
virtual ShadowableLayer* AsShadowableLayer() override { return this; }
|
||||
|
||||
virtual void Disconnect() override
|
||||
{
|
||||
DestroyBackBuffer();
|
||||
ClientLayer::Disconnect();
|
||||
}
|
||||
|
||||
void DestroyBackBuffer()
|
||||
{
|
||||
if (mImageClient) {
|
||||
mImageClient->SetLayer(nullptr);
|
||||
mImageClient->OnDetach();
|
||||
mImageClient = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual CompositableClient* GetCompositableClient() override
|
||||
{
|
||||
return mImageClient;
|
||||
}
|
||||
|
||||
protected:
|
||||
ClientLayerManager* ClientManager()
|
||||
{
|
||||
return static_cast<ClientLayerManager*>(mManager);
|
||||
}
|
||||
|
||||
CompositableType GetImageClientType()
|
||||
{
|
||||
if (mImageClientTypeContainer != CompositableType::UNKNOWN) {
|
||||
return mImageClientTypeContainer;
|
||||
}
|
||||
|
||||
if (mContainer->IsAsync()) {
|
||||
mImageClientTypeContainer = CompositableType::IMAGE_BRIDGE;
|
||||
return mImageClientTypeContainer;
|
||||
}
|
||||
|
||||
AutoLockImage autoLock(mContainer);
|
||||
|
||||
mImageClientTypeContainer = autoLock.HasImage()
|
||||
? CompositableType::IMAGE : CompositableType::UNKNOWN;
|
||||
return mImageClientTypeContainer;
|
||||
}
|
||||
|
||||
RefPtr<ImageClient> mImageClient;
|
||||
CompositableType mImageClientTypeContainer;
|
||||
};
|
||||
|
||||
void
|
||||
ClientImageLayer::RenderLayer()
|
||||
{
|
||||
RenderMaskLayers(this);
|
||||
|
||||
if (!mContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mImageClient ||
|
||||
!mImageClient->UpdateImage(mContainer, GetContentFlags())) {
|
||||
CompositableType type = GetImageClientType();
|
||||
if (type == CompositableType::UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
TextureFlags flags = TextureFlags::DEFAULT;
|
||||
mImageClient = ImageClient::CreateImageClient(type,
|
||||
ClientManager()->AsShadowForwarder(),
|
||||
flags);
|
||||
if (!mImageClient) {
|
||||
return;
|
||||
}
|
||||
mImageClient->SetLayer(this);
|
||||
if (HasShadow() && !mContainer->IsAsync()) {
|
||||
mImageClient->Connect();
|
||||
ClientManager()->AsShadowForwarder()->Attach(mImageClient, this);
|
||||
}
|
||||
if (!mImageClient->UpdateImage(mContainer, GetContentFlags())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ClientManager()->Hold(this);
|
||||
}
|
||||
|
||||
already_AddRefed<ImageLayer>
|
||||
ClientLayerManager::CreateImageLayer()
|
||||
{
|
||||
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
||||
RefPtr<ClientImageLayer> layer =
|
||||
new ClientImageLayer(this);
|
||||
CREATE_SHADOW(Image);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
907
gfx/layers/client/ClientLayerManager.cpp
Normal file
907
gfx/layers/client/ClientLayerManager.cpp
Normal file
|
|
@ -0,0 +1,907 @@
|
|||
/* -*- 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 "ClientLayerManager.h"
|
||||
#include "GeckoProfiler.h" // for PROFILER_LABEL
|
||||
#include "gfxPrefs.h" // for gfxPrefs::LayersTile...
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/dom/ScreenOrientation.h" // for ScreenOrientation
|
||||
#include "mozilla/dom/TabChild.h" // for TabChild
|
||||
#include "mozilla/hal_sandbox/PHal.h" // for ScreenConfiguration
|
||||
#include "mozilla/layers/CompositableClient.h"
|
||||
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
|
||||
#include "mozilla/layers/ContentClient.h"
|
||||
#include "mozilla/layers/FrameUniformityData.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/LayersMessages.h" // for EditReply, etc
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/PLayerChild.h" // for PLayerChild
|
||||
#include "mozilla/layers/LayerTransactionChild.h"
|
||||
#include "mozilla/layers/ShadowLayerChild.h"
|
||||
#include "mozilla/layers/PersistentBufferProvider.h"
|
||||
#include "ClientReadbackLayer.h" // for ClientReadbackLayer
|
||||
#include "nsAString.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsIWidgetListener.h"
|
||||
#include "nsTArray.h" // for AutoTArray
|
||||
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
|
||||
#include "TiledLayerBuffer.h"
|
||||
#include "mozilla/dom/WindowBinding.h" // for Overfill Callback
|
||||
#include "FrameLayerBuilder.h" // for FrameLayerbuilder
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
#include "AndroidBridge.h"
|
||||
#include "LayerMetricsWrapper.h"
|
||||
#endif
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
void
|
||||
ClientLayerManager::MemoryPressureObserver::Destroy()
|
||||
{
|
||||
UnregisterMemoryPressureEvent();
|
||||
mClientLayerManager = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ClientLayerManager::MemoryPressureObserver::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aSomeData)
|
||||
{
|
||||
if (!mClientLayerManager || strcmp(aTopic, "memory-pressure")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mClientLayerManager->HandleMemoryPressure();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::MemoryPressureObserver::RegisterMemoryPressureEvent()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
MOZ_ASSERT(observerService);
|
||||
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this, "memory-pressure", false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::MemoryPressureObserver::UnregisterMemoryPressureEvent()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
if (observerService) {
|
||||
observerService->RemoveObserver(this, "memory-pressure");
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(ClientLayerManager::MemoryPressureObserver, nsIObserver)
|
||||
|
||||
ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
|
||||
: mPhase(PHASE_NONE)
|
||||
, mWidget(aWidget)
|
||||
, mLatestTransactionId(0)
|
||||
, mLastPaintTime(TimeDuration::Forever())
|
||||
, mTargetRotation(ROTATION_0)
|
||||
, mRepeatTransaction(false)
|
||||
, mIsRepeatTransaction(false)
|
||||
, mTransactionIncomplete(false)
|
||||
, mCompositorMightResample(false)
|
||||
, mNeedsComposite(false)
|
||||
, mPaintSequenceNumber(0)
|
||||
, mForwarder(new ShadowLayerForwarder(this))
|
||||
, mDeviceCounter(gfxPlatform::GetPlatform()->GetDeviceCounter())
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientLayerManager);
|
||||
mMemoryPressureObserver = new MemoryPressureObserver(this);
|
||||
}
|
||||
|
||||
|
||||
ClientLayerManager::~ClientLayerManager()
|
||||
{
|
||||
mMemoryPressureObserver->Destroy();
|
||||
ClearCachedResources();
|
||||
// Stop receiveing AsyncParentMessage at Forwarder.
|
||||
// After the call, the message is directly handled by LayerTransactionChild.
|
||||
// Basically this function should be called in ShadowLayerForwarder's
|
||||
// destructor. But when the destructor is triggered by
|
||||
// CompositorBridgeChild::Destroy(), the destructor can not handle it correctly.
|
||||
// See Bug 1000525.
|
||||
mForwarder->StopReceiveAsyncParentMessge();
|
||||
mRoot = nullptr;
|
||||
|
||||
MOZ_COUNT_DTOR(ClientLayerManager);
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::Destroy()
|
||||
{
|
||||
// It's important to call ClearCachedResource before Destroy because the
|
||||
// former will early-return if the later has already run.
|
||||
ClearCachedResources();
|
||||
LayerManager::Destroy();
|
||||
|
||||
if (mTransactionIdAllocator) {
|
||||
// Make sure to notify the refresh driver just in case it's waiting on a
|
||||
// pending transaction. Do this at the top of the event loop so we don't
|
||||
// cause a paint to occur during compositor shutdown.
|
||||
RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
|
||||
uint64_t id = mLatestTransactionId;
|
||||
|
||||
RefPtr<Runnable> task = NS_NewRunnableFunction([allocator, id] () -> void {
|
||||
allocator->NotifyTransactionCompleted(id);
|
||||
});
|
||||
NS_DispatchToMainThread(task.forget());
|
||||
}
|
||||
|
||||
// Forget the widget pointer in case we outlive our owning widget.
|
||||
mWidget = nullptr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ClientLayerManager::GetMaxTextureSize() const
|
||||
{
|
||||
return mForwarder->GetMaxTextureSize();
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::SetDefaultTargetConfiguration(BufferMode aDoubleBuffering,
|
||||
ScreenRotation aRotation)
|
||||
{
|
||||
mTargetRotation = aRotation;
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::SetRoot(Layer* aLayer)
|
||||
{
|
||||
if (mRoot != aLayer) {
|
||||
// Have to hold the old root and its children in order to
|
||||
// maintain the same view of the layer tree in this process as
|
||||
// the parent sees. Otherwise layers can be destroyed
|
||||
// mid-transaction and bad things can happen (v. bug 612573)
|
||||
if (mRoot) {
|
||||
Hold(mRoot);
|
||||
}
|
||||
mForwarder->SetRoot(Hold(aLayer));
|
||||
NS_ASSERTION(aLayer, "Root can't be null");
|
||||
NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
|
||||
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
||||
mRoot = aLayer;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::Mutated(Layer* aLayer)
|
||||
{
|
||||
LayerManager::Mutated(aLayer);
|
||||
|
||||
NS_ASSERTION(InConstruction() || InDrawing(), "wrong phase");
|
||||
mForwarder->Mutated(Hold(aLayer));
|
||||
}
|
||||
|
||||
already_AddRefed<ReadbackLayer>
|
||||
ClientLayerManager::CreateReadbackLayer()
|
||||
{
|
||||
RefPtr<ReadbackLayer> layer = new ClientReadbackLayer(this);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
|
||||
{
|
||||
MOZ_ASSERT(mForwarder, "ClientLayerManager::BeginTransaction without forwarder");
|
||||
if (!mForwarder->IPCOpen()) {
|
||||
gfxCriticalNote << "ClientLayerManager::BeginTransaction with IPC channel down. GPU process may have died.";
|
||||
return false;
|
||||
}
|
||||
|
||||
mInTransaction = true;
|
||||
mTransactionStart = TimeStamp::Now();
|
||||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
MOZ_LAYERS_LOG(("[----- BeginTransaction"));
|
||||
Log();
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
|
||||
mPhase = PHASE_CONSTRUCTION;
|
||||
|
||||
if (DependsOnStaleDevice()) {
|
||||
FrameLayerBuilder::InvalidateAllLayers(this);
|
||||
mDeviceCounter = gfxPlatform::GetPlatform()->GetDeviceCounter();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mKeepAlive.IsEmpty(), "uncommitted txn?");
|
||||
|
||||
// If the last transaction was incomplete (a failed DoEmptyTransaction),
|
||||
// don't signal a new transaction to ShadowLayerForwarder. Carry on adding
|
||||
// to the previous transaction.
|
||||
dom::ScreenOrientationInternal orientation;
|
||||
if (dom::TabChild* window = mWidget->GetOwningTabChild()) {
|
||||
orientation = window->GetOrientation();
|
||||
} else {
|
||||
hal::ScreenConfiguration currentConfig;
|
||||
hal::GetCurrentScreenConfiguration(¤tConfig);
|
||||
orientation = currentConfig.orientation();
|
||||
}
|
||||
LayoutDeviceIntRect targetBounds = mWidget->GetNaturalBounds();
|
||||
targetBounds.x = targetBounds.y = 0;
|
||||
mForwarder->BeginTransaction(targetBounds.ToUnknownRect(), mTargetRotation,
|
||||
orientation);
|
||||
|
||||
// If we're drawing on behalf of a context with async pan/zoom
|
||||
// enabled, then the entire buffer of painted layers might be
|
||||
// composited (including resampling) asynchronously before we get
|
||||
// a chance to repaint, so we have to ensure that it's all valid
|
||||
// and not rotated.
|
||||
//
|
||||
// Desktop does not support async zoom yet, so we ignore this for those
|
||||
// platforms.
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
|
||||
if (mWidget && mWidget->GetOwningTabChild()) {
|
||||
mCompositorMightResample = AsyncPanZoomEnabled();
|
||||
}
|
||||
#endif
|
||||
|
||||
// If we have a non-default target, we need to let our shadow manager draw
|
||||
// to it. This will happen at the end of the transaction.
|
||||
if (aTarget && XRE_IsParentProcess()) {
|
||||
mShadowTarget = aTarget;
|
||||
} else {
|
||||
NS_ASSERTION(!aTarget,
|
||||
"Content-process ClientLayerManager::BeginTransactionWithTarget not supported");
|
||||
}
|
||||
|
||||
// If this is a new paint, increment the paint sequence number.
|
||||
if (!mIsRepeatTransaction) {
|
||||
// Increment the paint sequence number even if test logging isn't
|
||||
// enabled in this process; it may be enabled in the parent process,
|
||||
// and the parent process expects unique sequence numbers.
|
||||
++mPaintSequenceNumber;
|
||||
if (gfxPrefs::APZTestLoggingEnabled()) {
|
||||
mApzTestData.StartNewPaint(mPaintSequenceNumber);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::BeginTransaction()
|
||||
{
|
||||
return BeginTransactionWithTarget(nullptr);
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
EndTransactionFlags)
|
||||
{
|
||||
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Rasterization);
|
||||
|
||||
PROFILER_LABEL("ClientLayerManager", "EndTransactionInternal",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
MOZ_LAYERS_LOG((" ----- (beginning paint)"));
|
||||
Log();
|
||||
#endif
|
||||
profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_START);
|
||||
|
||||
NS_ASSERTION(InConstruction(), "Should be in construction phase");
|
||||
mPhase = PHASE_DRAWING;
|
||||
|
||||
ClientLayer* root = ClientLayer::ToClientLayer(GetRoot());
|
||||
|
||||
mTransactionIncomplete = false;
|
||||
|
||||
// Apply pending tree updates before recomputing effective
|
||||
// properties.
|
||||
GetRoot()->ApplyPendingUpdatesToSubtree();
|
||||
|
||||
mPaintedLayerCallback = aCallback;
|
||||
mPaintedLayerCallbackData = aCallbackData;
|
||||
|
||||
GetRoot()->ComputeEffectiveTransforms(Matrix4x4());
|
||||
|
||||
// Skip the painting if the device is in device-reset status.
|
||||
if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
|
||||
if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
|
||||
TimeStamp start = TimeStamp::Now();
|
||||
root->RenderLayer();
|
||||
mLastPaintTime = TimeStamp::Now() - start;
|
||||
} else {
|
||||
root->RenderLayer();
|
||||
}
|
||||
} else {
|
||||
gfxCriticalNote << "LayerManager::EndTransaction skip RenderLayer().";
|
||||
}
|
||||
|
||||
if (!mRepeatTransaction && !GetRoot()->GetInvalidRegion().IsEmpty()) {
|
||||
GetRoot()->Mutated();
|
||||
}
|
||||
|
||||
if (!mIsRepeatTransaction) {
|
||||
mAnimationReadyTime = TimeStamp::Now();
|
||||
GetRoot()->StartPendingAnimations(mAnimationReadyTime);
|
||||
}
|
||||
|
||||
mPaintedLayerCallback = nullptr;
|
||||
mPaintedLayerCallbackData = nullptr;
|
||||
|
||||
// Go back to the construction phase if the transaction isn't complete.
|
||||
// Layout will update the layer tree and call EndTransaction().
|
||||
mPhase = mTransactionIncomplete ? PHASE_CONSTRUCTION : PHASE_NONE;
|
||||
|
||||
NS_ASSERTION(!aCallback || !mTransactionIncomplete,
|
||||
"If callback is not null, transaction must be complete");
|
||||
|
||||
if (gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
|
||||
FrameLayerBuilder::InvalidateAllLayers(this);
|
||||
}
|
||||
|
||||
return !mTransactionIncomplete;
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>& aConfigurations)
|
||||
{
|
||||
if (mForwarder) {
|
||||
mForwarder->StorePluginWidgetConfigurations(aConfigurations);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
EndTransactionFlags aFlags)
|
||||
{
|
||||
if (!mForwarder->IPCOpen()) {
|
||||
mInTransaction = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWidget) {
|
||||
mWidget->PrepareWindowEffects();
|
||||
}
|
||||
EndTransactionInternal(aCallback, aCallbackData, aFlags);
|
||||
ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE));
|
||||
|
||||
if (mRepeatTransaction) {
|
||||
mRepeatTransaction = false;
|
||||
mIsRepeatTransaction = true;
|
||||
if (BeginTransaction()) {
|
||||
ClientLayerManager::EndTransaction(aCallback, aCallbackData, aFlags);
|
||||
}
|
||||
mIsRepeatTransaction = false;
|
||||
} else {
|
||||
MakeSnapshotIfRequired();
|
||||
}
|
||||
|
||||
mInTransaction = false;
|
||||
mTransactionStart = TimeStamp();
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
|
||||
{
|
||||
mInTransaction = false;
|
||||
|
||||
if (!mRoot || !mForwarder->IPCOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EndTransactionInternal(nullptr, nullptr, aFlags)) {
|
||||
// Return without calling ForwardTransaction. This leaves the
|
||||
// ShadowLayerForwarder transaction open; the following
|
||||
// EndTransaction will complete it.
|
||||
return false;
|
||||
}
|
||||
if (mWidget) {
|
||||
mWidget->PrepareWindowEffects();
|
||||
}
|
||||
ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE));
|
||||
MakeSnapshotIfRequired();
|
||||
return true;
|
||||
}
|
||||
|
||||
CompositorBridgeChild *
|
||||
ClientLayerManager::GetRemoteRenderer()
|
||||
{
|
||||
if (!mWidget) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mWidget->GetRemoteRenderer();
|
||||
}
|
||||
|
||||
CompositorBridgeChild*
|
||||
ClientLayerManager::GetCompositorBridgeChild()
|
||||
{
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return CompositorBridgeChild::Get();
|
||||
}
|
||||
return GetRemoteRenderer();
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::Composite()
|
||||
{
|
||||
mForwarder->Composite();
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::DidComposite(uint64_t aTransactionId,
|
||||
const TimeStamp& aCompositeStart,
|
||||
const TimeStamp& aCompositeEnd)
|
||||
{
|
||||
MOZ_ASSERT(mWidget);
|
||||
|
||||
// |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
|
||||
// layers transaction.
|
||||
if (aTransactionId) {
|
||||
nsIWidgetListener *listener = mWidget->GetWidgetListener();
|
||||
if (listener) {
|
||||
listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
|
||||
}
|
||||
listener = mWidget->GetAttachedWidgetListener();
|
||||
if (listener) {
|
||||
listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
|
||||
}
|
||||
mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
|
||||
}
|
||||
|
||||
// These observers fire whether or not we were in a transaction.
|
||||
for (size_t i = 0; i < mDidCompositeObservers.Length(); i++) {
|
||||
mDidCompositeObservers[i]->DidComposite();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::GetCompositorSideAPZTestData(APZTestData* aData) const
|
||||
{
|
||||
if (mForwarder->HasShadowManager()) {
|
||||
if (!mForwarder->GetShadowManager()->SendGetAPZTestData(aData)) {
|
||||
NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
ClientLayerManager::RequestProperty(const nsAString& aProperty)
|
||||
{
|
||||
if (mForwarder->HasShadowManager()) {
|
||||
float value;
|
||||
if (!mForwarder->GetShadowManager()->SendRequestProperty(nsString(aProperty), &value)) {
|
||||
NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::StartNewRepaintRequest(SequenceNumber aSequenceNumber)
|
||||
{
|
||||
if (gfxPrefs::APZTestLoggingEnabled()) {
|
||||
mApzTestData.StartNewRepaintRequest(aSequenceNumber);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::GetFrameUniformity(FrameUniformityData* aOutData)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Frame Uniformity only supported in parent process");
|
||||
|
||||
if (HasShadowManager()) {
|
||||
CompositorBridgeChild* child = GetRemoteRenderer();
|
||||
child->SendGetFrameUniformity(aOutData);
|
||||
return;
|
||||
}
|
||||
|
||||
return LayerManager::GetFrameUniformity(aOutData);
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::RequestOverfill(mozilla::dom::OverfillCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(aCallback != nullptr);
|
||||
MOZ_ASSERT(HasShadowManager(), "Request Overfill only supported on b2g for now");
|
||||
|
||||
if (HasShadowManager()) {
|
||||
CompositorBridgeChild* child = GetRemoteRenderer();
|
||||
NS_ASSERTION(child, "Could not get CompositorBridgeChild");
|
||||
|
||||
child->AddOverfillObserver(this);
|
||||
child->SendRequestOverfill();
|
||||
mOverfillCallbacks.AppendElement(aCallback);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::RunOverfillCallback(const uint32_t aOverfill)
|
||||
{
|
||||
for (size_t i = 0; i < mOverfillCallbacks.Length(); i++) {
|
||||
ErrorResult error;
|
||||
mOverfillCallbacks[i]->Call(aOverfill, error);
|
||||
}
|
||||
|
||||
mOverfillCallbacks.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::MakeSnapshotIfRequired()
|
||||
{
|
||||
if (!mShadowTarget) {
|
||||
return;
|
||||
}
|
||||
if (mWidget) {
|
||||
if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
|
||||
// The compositor doesn't draw to a different sized surface
|
||||
// when there's a rotation. Instead we rotate the result
|
||||
// when drawing into dt
|
||||
LayoutDeviceIntRect outerBounds = mWidget->GetBounds();
|
||||
|
||||
IntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
|
||||
if (mTargetRotation) {
|
||||
bounds =
|
||||
RotateRect(bounds, outerBounds.ToUnknownRect(), mTargetRotation);
|
||||
}
|
||||
|
||||
SurfaceDescriptor inSnapshot;
|
||||
if (!bounds.IsEmpty() &&
|
||||
mForwarder->AllocSurfaceDescriptor(bounds.Size(),
|
||||
gfxContentType::COLOR_ALPHA,
|
||||
&inSnapshot)) {
|
||||
|
||||
// Make a copy of |inSnapshot| because the call to send it over IPC
|
||||
// will call forget() on the Shmem inside, and zero it out.
|
||||
SurfaceDescriptor outSnapshot = inSnapshot;
|
||||
|
||||
if (remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
|
||||
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(outSnapshot);
|
||||
DrawTarget* dt = mShadowTarget->GetDrawTarget();
|
||||
|
||||
Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
Rect srcRect(0, 0, bounds.width, bounds.height);
|
||||
|
||||
gfx::Matrix rotate =
|
||||
ComputeTransformForUnRotation(outerBounds.ToUnknownRect(),
|
||||
mTargetRotation);
|
||||
|
||||
gfx::Matrix oldMatrix = dt->GetTransform();
|
||||
dt->SetTransform(rotate * oldMatrix);
|
||||
dt->DrawSurface(surf, dstRect, srcRect,
|
||||
DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||
dt->SetTransform(oldMatrix);
|
||||
}
|
||||
mForwarder->DestroySurfaceDescriptor(&outSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
mShadowTarget = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::FlushRendering()
|
||||
{
|
||||
if (mWidget) {
|
||||
if (CompositorBridgeChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
|
||||
remoteRenderer->SendFlushRendering();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier)
|
||||
{
|
||||
mForwarder->IdentifyTextureHost(aNewIdentifier);
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::SendInvalidRegion(const nsIntRegion& aRegion)
|
||||
{
|
||||
if (mWidget) {
|
||||
if (CompositorBridgeChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
|
||||
remoteRenderer->SendNotifyRegionInvalidated(aRegion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ClientLayerManager::StartFrameTimeRecording(int32_t aBufferSize)
|
||||
{
|
||||
CompositorBridgeChild* renderer = GetRemoteRenderer();
|
||||
if (renderer) {
|
||||
uint32_t startIndex;
|
||||
renderer->SendStartFrameTimeRecording(aBufferSize, &startIndex);
|
||||
return startIndex;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::StopFrameTimeRecording(uint32_t aStartIndex,
|
||||
nsTArray<float>& aFrameIntervals)
|
||||
{
|
||||
CompositorBridgeChild* renderer = GetRemoteRenderer();
|
||||
if (renderer) {
|
||||
renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
|
||||
{
|
||||
TimeStamp start = TimeStamp::Now();
|
||||
|
||||
// Skip the synchronization for buffer since we also skip the painting during
|
||||
// device-reset status.
|
||||
if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
|
||||
if (mForwarder->GetSyncObject() &&
|
||||
mForwarder->GetSyncObject()->IsSyncObjectValid()) {
|
||||
mForwarder->GetSyncObject()->FinalizeFrame();
|
||||
}
|
||||
}
|
||||
|
||||
mPhase = PHASE_FORWARD;
|
||||
|
||||
mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
|
||||
TimeStamp transactionStart;
|
||||
if (!mTransactionIdAllocator->GetTransactionStart().IsNull()) {
|
||||
transactionStart = mTransactionIdAllocator->GetTransactionStart();
|
||||
} else {
|
||||
transactionStart = mTransactionStart;
|
||||
}
|
||||
|
||||
if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
|
||||
mForwarder->SendPaintTime(mLatestTransactionId, mLastPaintTime);
|
||||
}
|
||||
|
||||
// forward this transaction's changeset to our LayerManagerComposite
|
||||
bool sent;
|
||||
AutoTArray<EditReply, 10> replies;
|
||||
if (mForwarder->EndTransaction(&replies, mRegionToClear,
|
||||
mLatestTransactionId, aScheduleComposite, mPaintSequenceNumber,
|
||||
mIsRepeatTransaction, transactionStart, &sent)) {
|
||||
for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
|
||||
const EditReply& reply = replies[i];
|
||||
|
||||
switch (reply.type()) {
|
||||
case EditReply::TOpContentBufferSwap: {
|
||||
MOZ_LAYERS_LOG(("[LayersForwarder] DoubleBufferSwap"));
|
||||
|
||||
const OpContentBufferSwap& obs = reply.get_OpContentBufferSwap();
|
||||
|
||||
RefPtr<CompositableClient> compositable =
|
||||
CompositableClient::FromIPDLActor(obs.compositableChild());
|
||||
ContentClientRemote* contentClient =
|
||||
static_cast<ContentClientRemote*>(compositable.get());
|
||||
MOZ_ASSERT(contentClient);
|
||||
|
||||
contentClient->SwapBuffers(obs.frontUpdatedRegion());
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_RUNTIMEABORT("not reached");
|
||||
}
|
||||
}
|
||||
|
||||
if (sent) {
|
||||
mNeedsComposite = false;
|
||||
}
|
||||
} else if (HasShadowManager()) {
|
||||
NS_WARNING("failed to forward Layers transaction");
|
||||
}
|
||||
|
||||
if (!sent) {
|
||||
// Clear the transaction id so that it doesn't get returned
|
||||
// unless we forwarded to somewhere that doesn't actually
|
||||
// have a compositor.
|
||||
mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
|
||||
}
|
||||
|
||||
mPhase = PHASE_NONE;
|
||||
|
||||
// this may result in Layers being deleted, which results in
|
||||
// PLayer::Send__delete__() and DeallocShmem()
|
||||
mKeepAlive.Clear();
|
||||
|
||||
TabChild* window = mWidget ? mWidget->GetOwningTabChild() : nullptr;
|
||||
if (window) {
|
||||
TimeStamp end = TimeStamp::Now();
|
||||
window->DidRequestComposite(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
ShadowableLayer*
|
||||
ClientLayerManager::Hold(Layer* aLayer)
|
||||
{
|
||||
MOZ_ASSERT(HasShadowManager(),
|
||||
"top-level tree, no shadow tree to remote to");
|
||||
|
||||
ShadowableLayer* shadowable = ClientLayer::ToClientLayer(aLayer);
|
||||
MOZ_ASSERT(shadowable, "trying to remote an unshadowable layer");
|
||||
|
||||
mKeepAlive.AppendElement(aLayer);
|
||||
return shadowable;
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::IsCompositingCheap()
|
||||
{
|
||||
// Whether compositing is cheap depends on the parent backend.
|
||||
return mForwarder->mShadowManager &&
|
||||
LayerManager::IsCompositingCheap(mForwarder->GetCompositorBackendType());
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::AreComponentAlphaLayersEnabled()
|
||||
{
|
||||
return GetCompositorBackendType() != LayersBackend::LAYERS_BASIC &&
|
||||
AsShadowForwarder()->SupportsComponentAlpha() &&
|
||||
LayerManager::AreComponentAlphaLayersEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::SetIsFirstPaint()
|
||||
{
|
||||
mForwarder->SetIsFirstPaint();
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::ClearCachedResources(Layer* aSubtree)
|
||||
{
|
||||
if (mDestroyed) {
|
||||
// ClearCachedResource was already called by ClientLayerManager::Destroy
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(!HasShadowManager() || !aSubtree);
|
||||
mForwarder->ClearCachedResources();
|
||||
if (aSubtree) {
|
||||
ClearLayer(aSubtree);
|
||||
} else if (mRoot) {
|
||||
ClearLayer(mRoot);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::HandleMemoryPressure()
|
||||
{
|
||||
if (mRoot) {
|
||||
HandleMemoryPressureLayer(mRoot);
|
||||
}
|
||||
|
||||
if (GetCompositorBridgeChild()) {
|
||||
GetCompositorBridgeChild()->HandleMemoryPressure();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::ClearLayer(Layer* aLayer)
|
||||
{
|
||||
ClientLayer::ToClientLayer(aLayer)->ClearCachedResources();
|
||||
for (Layer* child = aLayer->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
ClearLayer(child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::HandleMemoryPressureLayer(Layer* aLayer)
|
||||
{
|
||||
ClientLayer::ToClientLayer(aLayer)->HandleMemoryPressure();
|
||||
for (Layer* child = aLayer->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
HandleMemoryPressureLayer(child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::GetBackendName(nsAString& aName)
|
||||
{
|
||||
switch (mForwarder->GetCompositorBackendType()) {
|
||||
case LayersBackend::LAYERS_NONE: aName.AssignLiteral("None"); return;
|
||||
case LayersBackend::LAYERS_BASIC: aName.AssignLiteral("Basic"); return;
|
||||
case LayersBackend::LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return;
|
||||
case LayersBackend::LAYERS_D3D9: aName.AssignLiteral("Direct3D 9"); return;
|
||||
case LayersBackend::LAYERS_D3D11: {
|
||||
#ifdef XP_WIN
|
||||
if (DeviceManagerDx::Get()->IsWARP()) {
|
||||
aName.AssignLiteral("Direct3D 11 WARP");
|
||||
} else {
|
||||
aName.AssignLiteral("Direct3D 11");
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
default: NS_RUNTIMEABORT("Invalid backend");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::AsyncPanZoomEnabled() const
|
||||
{
|
||||
return mWidget && mWidget->AsyncPanZoomEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::SetNextPaintSyncId(int32_t aSyncId)
|
||||
{
|
||||
mForwarder->SetPaintSyncId(aSyncId);
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::SetLayerObserverEpoch(uint64_t aLayerObserverEpoch)
|
||||
{
|
||||
mForwarder->SetLayerObserverEpoch(aLayerObserverEpoch);
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::AddDidCompositeObserver(DidCompositeObserver* aObserver)
|
||||
{
|
||||
if (!mDidCompositeObservers.Contains(aObserver)) {
|
||||
mDidCompositeObservers.AppendElement(aObserver);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::RemoveDidCompositeObserver(DidCompositeObserver* aObserver)
|
||||
{
|
||||
mDidCompositeObservers.RemoveElement(aObserver);
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::DependsOnStaleDevice() const
|
||||
{
|
||||
return gfxPlatform::GetPlatform()->GetDeviceCounter() != mDeviceCounter;
|
||||
}
|
||||
|
||||
|
||||
already_AddRefed<PersistentBufferProvider>
|
||||
ClientLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize,
|
||||
gfx::SurfaceFormat aFormat)
|
||||
{
|
||||
// Don't use a shared buffer provider if compositing is considered "not cheap"
|
||||
// because the canvas will most likely be flattened into a thebes layer instead
|
||||
// of being sent to the compositor, in which case rendering into shared memory
|
||||
// is wasteful.
|
||||
if (IsCompositingCheap() &&
|
||||
gfxPrefs::PersistentBufferProviderSharedEnabled()) {
|
||||
RefPtr<PersistentBufferProvider> provider
|
||||
= PersistentBufferProviderShared::Create(aSize, aFormat, AsShadowForwarder());
|
||||
if (provider) {
|
||||
return provider.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return LayerManager::CreatePersistentBufferProvider(aSize, aFormat);
|
||||
}
|
||||
|
||||
|
||||
ClientLayer::~ClientLayer()
|
||||
{
|
||||
if (HasShadow()) {
|
||||
PLayerChild::Send__delete__(GetShadow());
|
||||
}
|
||||
MOZ_COUNT_DTOR(ClientLayer);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
422
gfx/layers/client/ClientLayerManager.h
Normal file
422
gfx/layers/client/ClientLayerManager.h
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef GFX_CLIENTLAYERMANAGER_H
|
||||
#define GFX_CLIENTLAYERMANAGER_H
|
||||
|
||||
#include <stdint.h> // for int32_t
|
||||
#include "Layers.h"
|
||||
#include "gfxContext.h" // for gfxContext
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/LinkedList.h" // For LinkedList
|
||||
#include "mozilla/WidgetUtils.h" // for ScreenRotation
|
||||
#include "mozilla/gfx/Rect.h" // for Rect
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/LayersTypes.h" // for BufferMode, LayersBackend, etc
|
||||
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder, etc
|
||||
#include "mozilla/layers/APZTestData.h" // for APZTestData
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsIObserver.h" // for nsIObserver
|
||||
#include "nsISupportsImpl.h" // for Layer::Release, etc
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "nsTArray.h" // for nsTArray
|
||||
#include "nscore.h" // for nsAString
|
||||
#include "mozilla/layers/TransactionIdAllocator.h"
|
||||
#include "nsIWidget.h" // For plugin window configuration information structs
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ClientPaintedLayer;
|
||||
class CompositorBridgeChild;
|
||||
class ImageLayer;
|
||||
class PLayerChild;
|
||||
class FrameUniformityData;
|
||||
|
||||
class ClientLayerManager final : public LayerManager
|
||||
{
|
||||
typedef nsTArray<RefPtr<Layer> > LayerRefArray;
|
||||
|
||||
public:
|
||||
explicit ClientLayerManager(nsIWidget* aWidget);
|
||||
|
||||
virtual void Destroy() override;
|
||||
|
||||
protected:
|
||||
virtual ~ClientLayerManager();
|
||||
|
||||
public:
|
||||
virtual ShadowLayerForwarder* AsShadowForwarder() override
|
||||
{
|
||||
return mForwarder;
|
||||
}
|
||||
|
||||
virtual ClientLayerManager* AsClientLayerManager() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual int32_t GetMaxTextureSize() const override;
|
||||
|
||||
virtual void SetDefaultTargetConfiguration(BufferMode aDoubleBuffering, ScreenRotation aRotation);
|
||||
virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override;
|
||||
virtual bool BeginTransaction() override;
|
||||
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
|
||||
virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
EndTransactionFlags aFlags = END_DEFAULT) override;
|
||||
|
||||
virtual LayersBackend GetBackendType() override { return LayersBackend::LAYERS_CLIENT; }
|
||||
virtual LayersBackend GetCompositorBackendType() override
|
||||
{
|
||||
return AsShadowForwarder()->GetCompositorBackendType();
|
||||
}
|
||||
virtual void GetBackendName(nsAString& name) override;
|
||||
virtual const char* Name() const override { return "Client"; }
|
||||
|
||||
virtual void SetRoot(Layer* aLayer) override;
|
||||
|
||||
virtual void Mutated(Layer* aLayer) override;
|
||||
|
||||
virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() override;
|
||||
virtual already_AddRefed<PaintedLayer> CreatePaintedLayerWithHint(PaintedLayerCreationHint aHint) override;
|
||||
virtual already_AddRefed<ContainerLayer> CreateContainerLayer() override;
|
||||
virtual already_AddRefed<ImageLayer> CreateImageLayer() override;
|
||||
virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() override;
|
||||
virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer() override;
|
||||
virtual already_AddRefed<ColorLayer> CreateColorLayer() override;
|
||||
virtual already_AddRefed<RefLayer> CreateRefLayer() override;
|
||||
|
||||
void UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier);
|
||||
TextureFactoryIdentifier GetTextureFactoryIdentifier()
|
||||
{
|
||||
return AsShadowForwarder()->GetTextureFactoryIdentifier();
|
||||
}
|
||||
|
||||
virtual void FlushRendering() override;
|
||||
void SendInvalidRegion(const nsIntRegion& aRegion);
|
||||
|
||||
virtual uint32_t StartFrameTimeRecording(int32_t aBufferSize) override;
|
||||
|
||||
virtual void StopFrameTimeRecording(uint32_t aStartIndex,
|
||||
nsTArray<float>& aFrameIntervals) override;
|
||||
|
||||
virtual bool NeedsWidgetInvalidation() override { return false; }
|
||||
|
||||
ShadowableLayer* Hold(Layer* aLayer);
|
||||
|
||||
bool HasShadowManager() const { return mForwarder->HasShadowManager(); }
|
||||
|
||||
virtual bool IsCompositingCheap() override;
|
||||
virtual bool HasShadowManagerInternal() const override { return HasShadowManager(); }
|
||||
|
||||
virtual void SetIsFirstPaint() override;
|
||||
|
||||
/**
|
||||
* Pass through call to the forwarder for nsPresContext's
|
||||
* CollectPluginGeometryUpdates. Passes widget configuration information
|
||||
* to the compositor for transmission to the chrome process. This
|
||||
* configuration gets set when the window paints.
|
||||
*/
|
||||
void StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>&
|
||||
aConfigurations) override;
|
||||
|
||||
// Drop cached resources and ask our shadow manager to do the same,
|
||||
// if we have one.
|
||||
virtual void ClearCachedResources(Layer* aSubtree = nullptr) override;
|
||||
|
||||
void HandleMemoryPressure();
|
||||
|
||||
void SetRepeatTransaction() { mRepeatTransaction = true; }
|
||||
bool GetRepeatTransaction() { return mRepeatTransaction; }
|
||||
|
||||
bool IsRepeatTransaction() { return mIsRepeatTransaction; }
|
||||
|
||||
void SetTransactionIncomplete() { mTransactionIncomplete = true; }
|
||||
|
||||
bool HasShadowTarget() { return !!mShadowTarget; }
|
||||
|
||||
void SetShadowTarget(gfxContext* aTarget) { mShadowTarget = aTarget; }
|
||||
|
||||
bool CompositorMightResample() { return mCompositorMightResample; }
|
||||
|
||||
DrawPaintedLayerCallback GetPaintedLayerCallback() const
|
||||
{ return mPaintedLayerCallback; }
|
||||
|
||||
void* GetPaintedLayerCallbackData() const
|
||||
{ return mPaintedLayerCallbackData; }
|
||||
|
||||
CompositorBridgeChild* GetRemoteRenderer();
|
||||
|
||||
CompositorBridgeChild* GetCompositorBridgeChild();
|
||||
|
||||
// Disable component alpha layers with the software compositor.
|
||||
virtual bool ShouldAvoidComponentAlphaLayers() override { return !IsCompositingCheap(); }
|
||||
|
||||
bool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
|
||||
#ifdef DEBUG
|
||||
bool InDrawing() { return mPhase == PHASE_DRAWING; }
|
||||
bool InForward() { return mPhase == PHASE_FORWARD; }
|
||||
#endif
|
||||
bool InTransaction() { return mPhase != PHASE_NONE; }
|
||||
|
||||
void SetNeedsComposite(bool aNeedsComposite)
|
||||
{
|
||||
mNeedsComposite = aNeedsComposite;
|
||||
}
|
||||
bool NeedsComposite() const { return mNeedsComposite; }
|
||||
|
||||
virtual void Composite() override;
|
||||
virtual void GetFrameUniformity(FrameUniformityData* aFrameUniformityData) override;
|
||||
virtual bool RequestOverfill(mozilla::dom::OverfillCallback* aCallback) override;
|
||||
virtual void RunOverfillCallback(const uint32_t aOverfill) override;
|
||||
|
||||
void DidComposite(uint64_t aTransactionId,
|
||||
const mozilla::TimeStamp& aCompositeStart,
|
||||
const mozilla::TimeStamp& aCompositeEnd);
|
||||
|
||||
virtual bool AreComponentAlphaLayersEnabled() override;
|
||||
|
||||
// Log APZ test data for the current paint. We supply the paint sequence
|
||||
// number ourselves, and take care of calling APZTestData::StartNewPaint()
|
||||
// when a new paint is started.
|
||||
void LogTestDataForCurrentPaint(FrameMetrics::ViewID aScrollId,
|
||||
const std::string& aKey,
|
||||
const std::string& aValue)
|
||||
{
|
||||
mApzTestData.LogTestDataForPaint(mPaintSequenceNumber, aScrollId, aKey, aValue);
|
||||
}
|
||||
|
||||
// Log APZ test data for a repaint request. The sequence number must be
|
||||
// passed in from outside, and APZTestData::StartNewRepaintRequest() needs
|
||||
// to be called from the outside as well when a new repaint request is started.
|
||||
void StartNewRepaintRequest(SequenceNumber aSequenceNumber);
|
||||
|
||||
// TODO(botond): When we start using this and write a wrapper similar to
|
||||
// nsLayoutUtils::LogTestDataForPaint(), make sure that wrapper checks
|
||||
// gfxPrefs::APZTestLoggingEnabled().
|
||||
void LogTestDataForRepaintRequest(SequenceNumber aSequenceNumber,
|
||||
FrameMetrics::ViewID aScrollId,
|
||||
const std::string& aKey,
|
||||
const std::string& aValue)
|
||||
{
|
||||
mApzTestData.LogTestDataForRepaintRequest(aSequenceNumber, aScrollId, aKey, aValue);
|
||||
}
|
||||
|
||||
// Get the content-side APZ test data for reading. For writing, use the
|
||||
// LogTestData...() functions.
|
||||
const APZTestData& GetAPZTestData() const {
|
||||
return mApzTestData;
|
||||
}
|
||||
|
||||
// Get a copy of the compositor-side APZ test data for our layers ID.
|
||||
void GetCompositorSideAPZTestData(APZTestData* aData) const;
|
||||
|
||||
void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) { mTransactionIdAllocator = aAllocator; }
|
||||
|
||||
float RequestProperty(const nsAString& aProperty) override;
|
||||
|
||||
bool AsyncPanZoomEnabled() const override;
|
||||
|
||||
void SetNextPaintSyncId(int32_t aSyncId);
|
||||
|
||||
void SetLayerObserverEpoch(uint64_t aLayerObserverEpoch);
|
||||
|
||||
class DidCompositeObserver {
|
||||
public:
|
||||
virtual void DidComposite() = 0;
|
||||
};
|
||||
|
||||
void AddDidCompositeObserver(DidCompositeObserver* aObserver);
|
||||
void RemoveDidCompositeObserver(DidCompositeObserver* aObserver);
|
||||
|
||||
virtual already_AddRefed<PersistentBufferProvider>
|
||||
CreatePersistentBufferProvider(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat) override;
|
||||
|
||||
protected:
|
||||
enum TransactionPhase {
|
||||
PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
|
||||
};
|
||||
TransactionPhase mPhase;
|
||||
|
||||
private:
|
||||
// Listen memory-pressure event for ClientLayerManager
|
||||
class MemoryPressureObserver final : public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
explicit MemoryPressureObserver(ClientLayerManager* aClientLayerManager)
|
||||
: mClientLayerManager(aClientLayerManager)
|
||||
{
|
||||
RegisterMemoryPressureEvent();
|
||||
}
|
||||
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
virtual ~MemoryPressureObserver() {}
|
||||
void RegisterMemoryPressureEvent();
|
||||
void UnregisterMemoryPressureEvent();
|
||||
|
||||
ClientLayerManager* mClientLayerManager;
|
||||
};
|
||||
|
||||
/**
|
||||
* Forward transaction results to the parent context.
|
||||
*/
|
||||
void ForwardTransaction(bool aScheduleComposite);
|
||||
|
||||
/**
|
||||
* Take a snapshot of the parent context, and copy
|
||||
* it into mShadowTarget.
|
||||
*/
|
||||
void MakeSnapshotIfRequired();
|
||||
|
||||
void ClearLayer(Layer* aLayer);
|
||||
|
||||
void HandleMemoryPressureLayer(Layer* aLayer);
|
||||
|
||||
bool EndTransactionInternal(DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
EndTransactionFlags);
|
||||
|
||||
bool DependsOnStaleDevice() const;
|
||||
|
||||
LayerRefArray mKeepAlive;
|
||||
|
||||
nsIWidget* mWidget;
|
||||
|
||||
/* PaintedLayer callbacks; valid at the end of a transaciton,
|
||||
* while rendering */
|
||||
DrawPaintedLayerCallback mPaintedLayerCallback;
|
||||
void *mPaintedLayerCallbackData;
|
||||
|
||||
// When we're doing a transaction in order to draw to a non-default
|
||||
// target, the layers transaction is only performed in order to send
|
||||
// a PLayers:Update. We save the original non-default target to
|
||||
// mShadowTarget, and then perform the transaction using
|
||||
// mDummyTarget as the render target. After the transaction ends,
|
||||
// we send a message to our remote side to capture the actual pixels
|
||||
// being drawn to the default target, and then copy those pixels
|
||||
// back to mShadowTarget.
|
||||
RefPtr<gfxContext> mShadowTarget;
|
||||
|
||||
RefPtr<TransactionIdAllocator> mTransactionIdAllocator;
|
||||
uint64_t mLatestTransactionId;
|
||||
TimeDuration mLastPaintTime;
|
||||
|
||||
// Sometimes we draw to targets that don't natively support
|
||||
// landscape/portrait orientation. When we need to implement that
|
||||
// ourselves, |mTargetRotation| describes the induced transform we
|
||||
// need to apply when compositing content to our target.
|
||||
ScreenRotation mTargetRotation;
|
||||
|
||||
// Used to repeat the transaction right away (to avoid rebuilding
|
||||
// a display list) to support progressive drawing.
|
||||
bool mRepeatTransaction;
|
||||
bool mIsRepeatTransaction;
|
||||
bool mTransactionIncomplete;
|
||||
bool mCompositorMightResample;
|
||||
bool mNeedsComposite;
|
||||
|
||||
// An incrementing sequence number for paints.
|
||||
// Incremented in BeginTransaction(), but not for repeat transactions.
|
||||
uint32_t mPaintSequenceNumber;
|
||||
|
||||
APZTestData mApzTestData;
|
||||
|
||||
RefPtr<ShadowLayerForwarder> mForwarder;
|
||||
AutoTArray<dom::OverfillCallback*,0> mOverfillCallbacks;
|
||||
mozilla::TimeStamp mTransactionStart;
|
||||
|
||||
nsTArray<DidCompositeObserver*> mDidCompositeObservers;
|
||||
|
||||
RefPtr<MemoryPressureObserver> mMemoryPressureObserver;
|
||||
uint64_t mDeviceCounter;
|
||||
};
|
||||
|
||||
class ClientLayer : public ShadowableLayer
|
||||
{
|
||||
public:
|
||||
ClientLayer()
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientLayer);
|
||||
}
|
||||
|
||||
~ClientLayer();
|
||||
|
||||
void SetShadow(PLayerChild* aShadow)
|
||||
{
|
||||
MOZ_ASSERT(!mShadow, "can't have two shadows (yet)");
|
||||
mShadow = aShadow;
|
||||
}
|
||||
|
||||
virtual void Disconnect()
|
||||
{
|
||||
// This is an "emergency Disconnect()", called when the compositing
|
||||
// process has died. |mShadow| and our Shmem buffers are
|
||||
// automatically managed by IPDL, so we don't need to explicitly
|
||||
// free them here (it's hard to get that right on emergency
|
||||
// shutdown anyway).
|
||||
mShadow = nullptr;
|
||||
}
|
||||
|
||||
virtual void ClearCachedResources() { }
|
||||
|
||||
// Shrink memory usage.
|
||||
// Called when "memory-pressure" is observed.
|
||||
virtual void HandleMemoryPressure() { }
|
||||
|
||||
virtual void RenderLayer() = 0;
|
||||
virtual void RenderLayerWithReadback(ReadbackProcessor *aReadback) { RenderLayer(); }
|
||||
|
||||
virtual ClientPaintedLayer* AsThebes() { return nullptr; }
|
||||
|
||||
static inline ClientLayer *
|
||||
ToClientLayer(Layer* aLayer)
|
||||
{
|
||||
return static_cast<ClientLayer*>(aLayer->ImplData());
|
||||
}
|
||||
|
||||
template <typename LayerType>
|
||||
static inline void RenderMaskLayers(LayerType* aLayer) {
|
||||
if (aLayer->GetMaskLayer()) {
|
||||
ToClientLayer(aLayer->GetMaskLayer())->RenderLayer();
|
||||
}
|
||||
for (size_t i = 0; i < aLayer->GetAncestorMaskLayerCount(); i++) {
|
||||
ToClientLayer(aLayer->GetAncestorMaskLayerAt(i))->RenderLayer();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Create a shadow layer (PLayerChild) for aLayer, if we're forwarding
|
||||
// our layer tree to a parent process. Record the new layer creation
|
||||
// in the current open transaction as a side effect.
|
||||
template<typename CreatedMethod> void
|
||||
CreateShadowFor(ClientLayer* aLayer,
|
||||
ClientLayerManager* aMgr,
|
||||
CreatedMethod aMethod)
|
||||
{
|
||||
PLayerChild* shadow = aMgr->AsShadowForwarder()->ConstructShadowFor(aLayer);
|
||||
if (!shadow) {
|
||||
return;
|
||||
}
|
||||
|
||||
aLayer->SetShadow(shadow);
|
||||
(aMgr->AsShadowForwarder()->*aMethod)(aLayer);
|
||||
aMgr->Hold(aLayer->AsLayer());
|
||||
}
|
||||
|
||||
#define CREATE_SHADOW(_type) \
|
||||
CreateShadowFor(layer, this, \
|
||||
&ShadowLayerForwarder::Created ## _type ## Layer)
|
||||
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* GFX_CLIENTLAYERMANAGER_H */
|
||||
175
gfx/layers/client/ClientPaintedLayer.cpp
Normal file
175
gfx/layers/client/ClientPaintedLayer.cpp
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- 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 "ClientPaintedLayer.h"
|
||||
#include "ClientTiledPaintedLayer.h" // for ClientTiledPaintedLayer
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include "GeckoProfiler.h" // for PROFILER_LABEL
|
||||
#include "client/ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "gfxContext.h" // for gfxContext
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/gfx/2D.h" // for DrawTarget
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix
|
||||
#include "mozilla/gfx/Rect.h" // for Rect, IntRect
|
||||
#include "mozilla/gfx/Types.h" // for Float, etc
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "gfx2DGlue.h"
|
||||
#include "ReadbackProcessor.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
void
|
||||
ClientPaintedLayer::PaintThebes()
|
||||
{
|
||||
PROFILER_LABEL("ClientPaintedLayer", "PaintThebes",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
NS_ASSERTION(ClientManager()->InDrawing(),
|
||||
"Can only draw in drawing phase");
|
||||
|
||||
uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
|
||||
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
|
||||
if (ClientManager()->CompositorMightResample()) {
|
||||
flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
|
||||
}
|
||||
if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) {
|
||||
if (MayResample()) {
|
||||
flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
PaintState state =
|
||||
mContentClient->BeginPaintBuffer(this, flags);
|
||||
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
|
||||
|
||||
if (!state.mRegionToDraw.IsEmpty() && !ClientManager()->GetPaintedLayerCallback()) {
|
||||
ClientManager()->SetTransactionIncomplete();
|
||||
return;
|
||||
}
|
||||
|
||||
// The area that became invalid and is visible needs to be repainted
|
||||
// (this could be the whole visible area if our buffer switched
|
||||
// from RGB to RGBA, because we might need to repaint with
|
||||
// subpixel AA)
|
||||
state.mRegionToInvalidate.And(state.mRegionToInvalidate,
|
||||
GetLocalVisibleRegion().ToUnknownRegion());
|
||||
|
||||
bool didUpdate = false;
|
||||
RotatedContentBuffer::DrawIterator iter;
|
||||
while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
|
||||
if (!target || !target->IsValid()) {
|
||||
if (target) {
|
||||
mContentClient->ReturnDrawTargetToBuffer(target);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
SetAntialiasingFlags(this, target);
|
||||
|
||||
RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(target);
|
||||
MOZ_ASSERT(ctx); // already checked the target above
|
||||
|
||||
ClientManager()->GetPaintedLayerCallback()(this,
|
||||
ctx,
|
||||
iter.mDrawRegion,
|
||||
iter.mDrawRegion,
|
||||
state.mClip,
|
||||
state.mRegionToInvalidate,
|
||||
ClientManager()->GetPaintedLayerCallbackData());
|
||||
|
||||
ctx = nullptr;
|
||||
mContentClient->ReturnDrawTargetToBuffer(target);
|
||||
didUpdate = true;
|
||||
}
|
||||
|
||||
if (didUpdate) {
|
||||
Mutated();
|
||||
|
||||
mValidRegion.Or(mValidRegion, state.mRegionToDraw);
|
||||
|
||||
ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get());
|
||||
MOZ_ASSERT(contentClientRemote->GetIPDLActor());
|
||||
|
||||
// Hold(this) ensures this layer is kept alive through the current transaction
|
||||
// The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
|
||||
// so deleting this Hold for whatever reason will break things.
|
||||
ClientManager()->Hold(this);
|
||||
contentClientRemote->Updated(state.mRegionToDraw,
|
||||
mVisibleRegion.ToUnknownRegion(),
|
||||
state.mDidSelfCopy);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
|
||||
{
|
||||
RenderMaskLayers(this);
|
||||
|
||||
if (!mContentClient) {
|
||||
mContentClient = ContentClient::CreateContentClient(ClientManager()->AsShadowForwarder());
|
||||
if (!mContentClient) {
|
||||
return;
|
||||
}
|
||||
mContentClient->Connect();
|
||||
ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
|
||||
MOZ_ASSERT(mContentClient->GetForwarder());
|
||||
}
|
||||
|
||||
nsTArray<ReadbackProcessor::Update> readbackUpdates;
|
||||
nsIntRegion readbackRegion;
|
||||
if (aReadback && UsedForReadback()) {
|
||||
aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
|
||||
}
|
||||
|
||||
IntPoint origin(mVisibleRegion.GetBounds().x, mVisibleRegion.GetBounds().y);
|
||||
mContentClient->BeginPaint();
|
||||
PaintThebes();
|
||||
mContentClient->EndPaint(&readbackUpdates);
|
||||
}
|
||||
|
||||
already_AddRefed<PaintedLayer>
|
||||
ClientLayerManager::CreatePaintedLayer()
|
||||
{
|
||||
return CreatePaintedLayerWithHint(NONE);
|
||||
}
|
||||
|
||||
already_AddRefed<PaintedLayer>
|
||||
ClientLayerManager::CreatePaintedLayerWithHint(PaintedLayerCreationHint aHint)
|
||||
{
|
||||
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
||||
if (gfxPrefs::LayersTilesEnabled()) {
|
||||
RefPtr<ClientTiledPaintedLayer> layer = new ClientTiledPaintedLayer(this, aHint);
|
||||
CREATE_SHADOW(Painted);
|
||||
return layer.forget();
|
||||
} else {
|
||||
RefPtr<ClientPaintedLayer> layer = new ClientPaintedLayer(this, aHint);
|
||||
CREATE_SHADOW(Painted);
|
||||
return layer.forget();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientPaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
{
|
||||
PaintedLayer::PrintInfo(aStream, aPrefix);
|
||||
if (mContentClient) {
|
||||
aStream << "\n";
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
mContentClient->PrintInfo(aStream, pfx.get());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
127
gfx/layers/client/ClientPaintedLayer.h
Normal file
127
gfx/layers/client/ClientPaintedLayer.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef GFX_CLIENTPAINTEDLAYER_H
|
||||
#define GFX_CLIENTPAINTEDLAYER_H
|
||||
|
||||
#include "ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "Layers.h" // for PaintedLayer, etc
|
||||
#include "RotatedBuffer.h" // for RotatedContentBuffer, etc
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/layers/ContentClient.h" // for ContentClient
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
#include "mozilla/layers/PLayerTransaction.h" // for PaintedLayerAttributes
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class CompositableClient;
|
||||
class ShadowableLayer;
|
||||
class SpecificLayerAttributes;
|
||||
|
||||
class ClientPaintedLayer : public PaintedLayer,
|
||||
public ClientLayer {
|
||||
public:
|
||||
typedef RotatedContentBuffer::PaintState PaintState;
|
||||
typedef RotatedContentBuffer::ContentType ContentType;
|
||||
|
||||
explicit ClientPaintedLayer(ClientLayerManager* aLayerManager,
|
||||
LayerManager::PaintedLayerCreationHint aCreationHint = LayerManager::NONE) :
|
||||
PaintedLayer(aLayerManager, static_cast<ClientLayer*>(this), aCreationHint),
|
||||
mContentClient(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientPaintedLayer);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~ClientPaintedLayer()
|
||||
{
|
||||
if (mContentClient) {
|
||||
mContentClient->OnDetach();
|
||||
mContentClient = nullptr;
|
||||
}
|
||||
MOZ_COUNT_DTOR(ClientPaintedLayer);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void SetVisibleRegion(const LayerIntRegion& aRegion) override
|
||||
{
|
||||
NS_ASSERTION(ClientManager()->InConstruction(),
|
||||
"Can only set properties in construction phase");
|
||||
PaintedLayer::SetVisibleRegion(aRegion);
|
||||
}
|
||||
virtual void InvalidateRegion(const nsIntRegion& aRegion) override
|
||||
{
|
||||
NS_ASSERTION(ClientManager()->InConstruction(),
|
||||
"Can only set properties in construction phase");
|
||||
mInvalidRegion.Add(aRegion);
|
||||
mValidRegion.Sub(mValidRegion, mInvalidRegion.GetRegion());
|
||||
}
|
||||
|
||||
virtual void RenderLayer() override { RenderLayerWithReadback(nullptr); }
|
||||
|
||||
virtual void RenderLayerWithReadback(ReadbackProcessor *aReadback) override;
|
||||
|
||||
virtual void ClearCachedResources() override
|
||||
{
|
||||
if (mContentClient) {
|
||||
mContentClient->Clear();
|
||||
}
|
||||
mValidRegion.SetEmpty();
|
||||
DestroyBackBuffer();
|
||||
}
|
||||
|
||||
virtual void HandleMemoryPressure() override
|
||||
{
|
||||
if (mContentClient) {
|
||||
mContentClient->HandleMemoryPressure();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override
|
||||
{
|
||||
aAttrs = PaintedLayerAttributes(GetValidRegion());
|
||||
}
|
||||
|
||||
ClientLayerManager* ClientManager()
|
||||
{
|
||||
return static_cast<ClientLayerManager*>(mManager);
|
||||
}
|
||||
|
||||
virtual Layer* AsLayer() override { return this; }
|
||||
virtual ShadowableLayer* AsShadowableLayer() override { return this; }
|
||||
|
||||
virtual CompositableClient* GetCompositableClient() override
|
||||
{
|
||||
return mContentClient;
|
||||
}
|
||||
|
||||
virtual void Disconnect() override
|
||||
{
|
||||
mContentClient = nullptr;
|
||||
ClientLayer::Disconnect();
|
||||
}
|
||||
|
||||
protected:
|
||||
void PaintThebes();
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
|
||||
|
||||
void DestroyBackBuffer()
|
||||
{
|
||||
mContentClient = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ContentClient> mContentClient;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
34
gfx/layers/client/ClientReadbackLayer.h
Normal file
34
gfx/layers/client/ClientReadbackLayer.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef GFX_CLIENTREADBACKLAYER_H
|
||||
#define GFX_CLIENTREADBACKLAYER_H
|
||||
|
||||
#include "ClientLayerManager.h"
|
||||
#include "ReadbackLayer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ClientReadbackLayer :
|
||||
public ReadbackLayer,
|
||||
public ClientLayer
|
||||
{
|
||||
public:
|
||||
explicit ClientReadbackLayer(ClientLayerManager *aManager)
|
||||
: ReadbackLayer(aManager, nullptr)
|
||||
{
|
||||
mImplData = static_cast<ClientLayer*>(this);
|
||||
}
|
||||
|
||||
virtual ShadowableLayer* AsShadowableLayer() override { return this; }
|
||||
virtual Layer* AsLayer() override { return this; }
|
||||
virtual void RenderLayer() override {}
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* GFX_CLIENTREADBACKLAYER_H */
|
||||
615
gfx/layers/client/ClientTiledPaintedLayer.cpp
Normal file
615
gfx/layers/client/ClientTiledPaintedLayer.cpp
Normal file
|
|
@ -0,0 +1,615 @@
|
|||
/* 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 "ClientTiledPaintedLayer.h"
|
||||
#include "FrameMetrics.h" // for FrameMetrics
|
||||
#include "Units.h" // for ScreenIntRect, CSSPoint, etc
|
||||
#include "UnitTransforms.h" // for TransformTo
|
||||
#include "ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/gfx/Rect.h" // for Rect, RectTyped
|
||||
#include "mozilla/layers/CompositorBridgeChild.h"
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
#include "mozilla/layers/LayersMessages.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "LayersLogging.h"
|
||||
#include "mozilla/layers/SingleTiledContentClient.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using gfx::Rect;
|
||||
using gfx::IntRect;
|
||||
using gfx::IntSize;
|
||||
|
||||
ClientTiledPaintedLayer::ClientTiledPaintedLayer(ClientLayerManager* const aManager,
|
||||
ClientLayerManager::PaintedLayerCreationHint aCreationHint)
|
||||
: PaintedLayer(aManager, static_cast<ClientLayer*>(this), aCreationHint)
|
||||
, mContentClient()
|
||||
, mHaveSingleTiledContentClient(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientTiledPaintedLayer);
|
||||
mPaintData.mLastScrollOffset = ParentLayerPoint(0, 0);
|
||||
mPaintData.mFirstPaint = true;
|
||||
}
|
||||
|
||||
ClientTiledPaintedLayer::~ClientTiledPaintedLayer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ClientTiledPaintedLayer);
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledPaintedLayer::ClearCachedResources()
|
||||
{
|
||||
if (mContentClient) {
|
||||
mContentClient->ClearCachedResources();
|
||||
}
|
||||
mValidRegion.SetEmpty();
|
||||
mContentClient = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledPaintedLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
|
||||
{
|
||||
aAttrs = PaintedLayerAttributes(GetValidRegion());
|
||||
}
|
||||
|
||||
static Maybe<LayerRect>
|
||||
ApplyParentLayerToLayerTransform(const ParentLayerToLayerMatrix4x4& aTransform,
|
||||
const ParentLayerRect& aParentLayerRect,
|
||||
const LayerRect& aClip)
|
||||
{
|
||||
return UntransformBy(aTransform, aParentLayerRect, aClip);
|
||||
}
|
||||
|
||||
static LayerToParentLayerMatrix4x4
|
||||
GetTransformToAncestorsParentLayer(Layer* aStart, const LayerMetricsWrapper& aAncestor)
|
||||
{
|
||||
gfx::Matrix4x4 transform;
|
||||
const LayerMetricsWrapper& ancestorParent = aAncestor.GetParent();
|
||||
for (LayerMetricsWrapper iter(aStart, LayerMetricsWrapper::StartAt::BOTTOM);
|
||||
ancestorParent ? iter != ancestorParent : iter.IsValid();
|
||||
iter = iter.GetParent()) {
|
||||
transform = transform * iter.GetTransform();
|
||||
|
||||
if (gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
// When scrolling containers, layout adds a post-scale into the transform
|
||||
// of the displayport-ancestor (which we pick up in GetTransform() above)
|
||||
// to cancel out the pres shell resolution (for historical reasons). The
|
||||
// compositor in turn cancels out this post-scale (i.e., scales by the
|
||||
// pres shell resolution), and to get correct calculations, we need to do
|
||||
// so here, too.
|
||||
//
|
||||
// With containerless scrolling, the offending post-scale is on the
|
||||
// parent layer of the displayport-ancestor, which we don't reach in this
|
||||
// loop, so we don't need to worry about it.
|
||||
float presShellResolution = iter.GetPresShellResolution();
|
||||
transform.PostScale(presShellResolution, presShellResolution, 1.0f);
|
||||
}
|
||||
}
|
||||
return ViewAs<LayerToParentLayerMatrix4x4>(transform);
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledPaintedLayer::GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
|
||||
LayerMetricsWrapper* aOutDisplayPortAncestor,
|
||||
bool* aOutHasTransformAnimation)
|
||||
{
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
LayerMetricsWrapper displayPortAncestor;
|
||||
bool hasTransformAnimation = false;
|
||||
for (LayerMetricsWrapper ancestor(this, LayerMetricsWrapper::StartAt::BOTTOM); ancestor; ancestor = ancestor.GetParent()) {
|
||||
hasTransformAnimation |= ancestor.HasTransformAnimation();
|
||||
const FrameMetrics& metrics = ancestor.Metrics();
|
||||
if (!scrollAncestor && metrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID) {
|
||||
scrollAncestor = ancestor;
|
||||
}
|
||||
if (!metrics.GetDisplayPort().IsEmpty()) {
|
||||
displayPortAncestor = ancestor;
|
||||
// Any layer that has a displayport must be scrollable, so we can break
|
||||
// here.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (aOutScrollAncestor) {
|
||||
*aOutScrollAncestor = scrollAncestor;
|
||||
}
|
||||
if (aOutDisplayPortAncestor) {
|
||||
*aOutDisplayPortAncestor = displayPortAncestor;
|
||||
}
|
||||
if (aOutHasTransformAnimation) {
|
||||
*aOutHasTransformAnimation = hasTransformAnimation;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledPaintedLayer::BeginPaint()
|
||||
{
|
||||
mPaintData.ResetPaintData();
|
||||
|
||||
if (!GetBaseTransform().Is2D()) {
|
||||
// Give up if there is a complex CSS transform on the layer. We might
|
||||
// eventually support these but for now it's too complicated to handle
|
||||
// given that it's a pretty rare scenario.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the metrics of the nearest scrollable layer and the nearest layer
|
||||
// with a displayport.
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
LayerMetricsWrapper displayPortAncestor;
|
||||
bool hasTransformAnimation;
|
||||
GetAncestorLayers(&scrollAncestor, &displayPortAncestor, &hasTransformAnimation);
|
||||
|
||||
if (!displayPortAncestor || !scrollAncestor) {
|
||||
// No displayport or scroll ancestor, so we can't do progressive rendering.
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
// Both Android and b2g on phones are guaranteed to have a displayport set, so this
|
||||
// should never happen.
|
||||
NS_WARNING("Tiled PaintedLayer with no scrollable container ancestor");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Found scrollAncestor %p, displayPortAncestor %p, transform %d\n", this,
|
||||
scrollAncestor.GetLayer(), displayPortAncestor.GetLayer(), hasTransformAnimation);
|
||||
|
||||
const FrameMetrics& scrollMetrics = scrollAncestor.Metrics();
|
||||
const FrameMetrics& displayportMetrics = displayPortAncestor.Metrics();
|
||||
|
||||
// Calculate the transform required to convert ParentLayer space of our
|
||||
// display port ancestor to the Layer space of this layer.
|
||||
ParentLayerToLayerMatrix4x4 transformDisplayPortToLayer =
|
||||
GetTransformToAncestorsParentLayer(this, displayPortAncestor).Inverse();
|
||||
|
||||
LayerRect layerBounds = ViewAs<LayerPixel>(Rect(GetLayerBounds()));
|
||||
|
||||
// Compute the critical display port that applies to this layer in the
|
||||
// LayoutDevice space of this layer, but only if there is no OMT animation
|
||||
// on this layer. If there is an OMT animation then we need to draw the whole
|
||||
// visible region of this layer as determined by layout, because we don't know
|
||||
// what parts of it might move into view in the compositor.
|
||||
mPaintData.mHasTransformAnimation = hasTransformAnimation;
|
||||
if (!mPaintData.mHasTransformAnimation &&
|
||||
mContentClient->GetLowPrecisionTiledBuffer()) {
|
||||
ParentLayerRect criticalDisplayPort =
|
||||
(displayportMetrics.GetCriticalDisplayPort() * displayportMetrics.GetZoom())
|
||||
+ displayportMetrics.GetCompositionBounds().TopLeft();
|
||||
Maybe<LayerRect> criticalDisplayPortTransformed =
|
||||
ApplyParentLayerToLayerTransform(transformDisplayPortToLayer, criticalDisplayPort, layerBounds);
|
||||
if (criticalDisplayPortTransformed) {
|
||||
mPaintData.mCriticalDisplayPort = Some(RoundedToInt(*criticalDisplayPortTransformed));
|
||||
} else {
|
||||
mPaintData.mCriticalDisplayPort = Some(LayerIntRect(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
TILING_LOG("TILING %p: Critical displayport %s\n", this,
|
||||
mPaintData.mCriticalDisplayPort ?
|
||||
Stringify(*mPaintData.mCriticalDisplayPort).c_str() : "not set");
|
||||
|
||||
// Store the resolution from the displayport ancestor layer. Because this is Gecko-side,
|
||||
// before any async transforms have occurred, we can use the zoom for this.
|
||||
mPaintData.mResolution = displayportMetrics.GetZoom();
|
||||
TILING_LOG("TILING %p: Resolution %s\n", this, Stringify(mPaintData.mResolution).c_str());
|
||||
|
||||
// Store the applicable composition bounds in this layer's Layer units.
|
||||
mPaintData.mTransformToCompBounds =
|
||||
GetTransformToAncestorsParentLayer(this, scrollAncestor);
|
||||
ParentLayerToLayerMatrix4x4 transformToBounds = mPaintData.mTransformToCompBounds.Inverse();
|
||||
Maybe<LayerRect> compositionBoundsTransformed = ApplyParentLayerToLayerTransform(
|
||||
transformToBounds, scrollMetrics.GetCompositionBounds(), layerBounds);
|
||||
if (compositionBoundsTransformed) {
|
||||
mPaintData.mCompositionBounds = *compositionBoundsTransformed;
|
||||
} else {
|
||||
mPaintData.mCompositionBounds.SetEmpty();
|
||||
}
|
||||
TILING_LOG("TILING %p: Composition bounds %s\n", this, Stringify(mPaintData.mCompositionBounds).c_str());
|
||||
|
||||
// Calculate the scroll offset since the last transaction
|
||||
mPaintData.mScrollOffset = displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoom();
|
||||
TILING_LOG("TILING %p: Scroll offset %s\n", this, Stringify(mPaintData.mScrollOffset).c_str());
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTiledPaintedLayer::IsScrollingOnCompositor(const FrameMetrics& aParentMetrics)
|
||||
{
|
||||
CompositorBridgeChild* compositor = nullptr;
|
||||
if (Manager() && Manager()->AsClientLayerManager()) {
|
||||
compositor = Manager()->AsClientLayerManager()->GetCompositorBridgeChild();
|
||||
}
|
||||
|
||||
if (!compositor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FrameMetrics compositorMetrics;
|
||||
if (!compositor->LookupCompositorFrameMetrics(aParentMetrics.GetScrollId(),
|
||||
compositorMetrics)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1 is a tad high for a fuzzy equals epsilon however if our scroll delta
|
||||
// is so small then we have nothing to gain from using paint heuristics.
|
||||
float COORDINATE_EPSILON = 1.f;
|
||||
|
||||
return !FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().x,
|
||||
aParentMetrics.GetScrollOffset().x,
|
||||
COORDINATE_EPSILON) ||
|
||||
!FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().y,
|
||||
aParentMetrics.GetScrollOffset().y,
|
||||
COORDINATE_EPSILON);
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTiledPaintedLayer::UseProgressiveDraw() {
|
||||
if (!gfxPrefs::ProgressivePaint()) {
|
||||
// pref is disabled, so never do progressive
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mContentClient->GetTiledBuffer()->SupportsProgressiveUpdate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ClientManager()->HasShadowTarget()) {
|
||||
// This condition is true when we are in a reftest scenario. We don't want
|
||||
// to draw progressively here because it can cause intermittent reftest
|
||||
// failures because the harness won't wait for all the tiles to be drawn.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetIsFixedPosition() || GetParent()->GetIsFixedPosition()) {
|
||||
// This layer is fixed-position and so even if it does have a scrolling
|
||||
// ancestor it will likely be entirely on-screen all the time, so we
|
||||
// should draw it all at once
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mPaintData.mHasTransformAnimation) {
|
||||
// The compositor is going to animate this somehow, so we want it all
|
||||
// on the screen at once.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ClientManager()->AsyncPanZoomEnabled()) {
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
|
||||
MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is set
|
||||
if (!scrollAncestor) {
|
||||
return false;
|
||||
}
|
||||
const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
|
||||
if (!IsScrollingOnCompositor(parentMetrics)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{
|
||||
// If we have started drawing low-precision already, then we
|
||||
// shouldn't do anything there.
|
||||
if (mPaintData.mLowPrecisionPaintCount != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only draw progressively when there is something to paint and the
|
||||
// resolution is unchanged
|
||||
if (!aInvalidRegion.IsEmpty() &&
|
||||
UseProgressiveDraw() &&
|
||||
mContentClient->GetTiledBuffer()->GetFrameResolution() == mPaintData.mResolution) {
|
||||
// Store the old valid region, then clear it before painting.
|
||||
// We clip the old valid region to the visible region, as it only gets
|
||||
// used to decide stale content (currently valid and previously visible)
|
||||
nsIntRegion oldValidRegion = mContentClient->GetTiledBuffer()->GetValidRegion();
|
||||
oldValidRegion.And(oldValidRegion, aVisibleRegion);
|
||||
if (mPaintData.mCriticalDisplayPort) {
|
||||
oldValidRegion.And(oldValidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this, Stringify(oldValidRegion).c_str());
|
||||
|
||||
return mContentClient->GetTiledBuffer()->ProgressiveUpdate(mValidRegion, aInvalidRegion,
|
||||
oldValidRegion, &mPaintData, aCallback, aCallbackData);
|
||||
}
|
||||
|
||||
// Otherwise do a non-progressive paint. We must do this even when
|
||||
// the region to paint is empty as the valid region may have shrunk.
|
||||
|
||||
mValidRegion = aVisibleRegion;
|
||||
if (mPaintData.mCriticalDisplayPort) {
|
||||
mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this, Stringify(aInvalidRegion).c_str());
|
||||
TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this, Stringify(mValidRegion).c_str());
|
||||
|
||||
mContentClient->GetTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
|
||||
mContentClient->GetTiledBuffer()->PaintThebes(mValidRegion, aInvalidRegion, aInvalidRegion,
|
||||
aCallback, aCallbackData);
|
||||
mPaintData.mPaintFinished = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTiledPaintedLayer::RenderLowPrecision(nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{
|
||||
// Render the low precision buffer, if the visible region is larger than the
|
||||
// critical display port.
|
||||
if (!mPaintData.mCriticalDisplayPort ||
|
||||
!nsIntRegion(mPaintData.mCriticalDisplayPort->ToUnknownRect()).Contains(aVisibleRegion)) {
|
||||
nsIntRegion oldValidRegion = mContentClient->GetLowPrecisionTiledBuffer()->GetValidRegion();
|
||||
oldValidRegion.And(oldValidRegion, aVisibleRegion);
|
||||
|
||||
bool updatedBuffer = false;
|
||||
|
||||
// If the frame resolution or format have changed, invalidate the buffer
|
||||
if (mContentClient->GetLowPrecisionTiledBuffer()->GetFrameResolution() != mPaintData.mResolution ||
|
||||
mContentClient->GetLowPrecisionTiledBuffer()->HasFormatChanged()) {
|
||||
if (!mLowPrecisionValidRegion.IsEmpty()) {
|
||||
updatedBuffer = true;
|
||||
}
|
||||
oldValidRegion.SetEmpty();
|
||||
mLowPrecisionValidRegion.SetEmpty();
|
||||
mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
|
||||
mContentClient->GetLowPrecisionTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
|
||||
aInvalidRegion = aVisibleRegion;
|
||||
}
|
||||
|
||||
// Invalidate previously valid content that is no longer visible
|
||||
if (mPaintData.mLowPrecisionPaintCount == 1) {
|
||||
mLowPrecisionValidRegion.And(mLowPrecisionValidRegion, aVisibleRegion);
|
||||
}
|
||||
mPaintData.mLowPrecisionPaintCount++;
|
||||
|
||||
// Remove the valid high-precision region from the invalid low-precision
|
||||
// region. We don't want to spend time drawing things twice.
|
||||
aInvalidRegion.Sub(aInvalidRegion, mValidRegion);
|
||||
|
||||
TILING_LOG("TILING %p: Progressive paint: low-precision invalid region is %s\n", this, Stringify(aInvalidRegion).c_str());
|
||||
TILING_LOG("TILING %p: Progressive paint: low-precision old valid region is %s\n", this, Stringify(oldValidRegion).c_str());
|
||||
|
||||
if (!aInvalidRegion.IsEmpty()) {
|
||||
updatedBuffer = mContentClient->GetLowPrecisionTiledBuffer()->ProgressiveUpdate(
|
||||
mLowPrecisionValidRegion, aInvalidRegion, oldValidRegion,
|
||||
&mPaintData, aCallback, aCallbackData);
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Progressive paint: low-precision new valid region is %s\n", this, Stringify(mLowPrecisionValidRegion).c_str());
|
||||
return updatedBuffer;
|
||||
}
|
||||
if (!mLowPrecisionValidRegion.IsEmpty()) {
|
||||
TILING_LOG("TILING %p: Clearing low-precision buffer\n", this);
|
||||
// Clear the low precision tiled buffer.
|
||||
mLowPrecisionValidRegion.SetEmpty();
|
||||
mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
|
||||
// Return true here so we send a Painted callback after clearing the valid
|
||||
// region of the low precision buffer. This allows the shadow buffer's valid
|
||||
// region to be updated and the associated resources to be freed.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledPaintedLayer::EndPaint()
|
||||
{
|
||||
mPaintData.mLastScrollOffset = mPaintData.mScrollOffset;
|
||||
mPaintData.mPaintFinished = true;
|
||||
mPaintData.mFirstPaint = false;
|
||||
TILING_LOG("TILING %p: Paint finished\n", this);
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledPaintedLayer::RenderLayer()
|
||||
{
|
||||
LayerManager::DrawPaintedLayerCallback callback =
|
||||
ClientManager()->GetPaintedLayerCallback();
|
||||
void *data = ClientManager()->GetPaintedLayerCallbackData();
|
||||
|
||||
IntSize layerSize = mVisibleRegion.ToUnknownRegion().GetBounds().Size();
|
||||
IntSize tileSize = gfx::gfxVars::TileSize();
|
||||
bool isHalfTileWidthOrHeight = layerSize.width <= tileSize.width / 2 ||
|
||||
layerSize.height <= tileSize.height / 2;
|
||||
|
||||
// Use single tile when layer is not scrollable, is smaller than one
|
||||
// tile, or when more than half of the tiles' pixels in either
|
||||
// dimension would be wasted.
|
||||
bool wantSingleTiledContentClient =
|
||||
(mCreationHint == LayerManager::NONE ||
|
||||
layerSize <= tileSize ||
|
||||
isHalfTileWidthOrHeight) &&
|
||||
SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) &&
|
||||
gfxPrefs::LayersSingleTileEnabled();
|
||||
|
||||
if (mContentClient && mHaveSingleTiledContentClient && !wantSingleTiledContentClient) {
|
||||
mContentClient = nullptr;
|
||||
mValidRegion.SetEmpty();
|
||||
}
|
||||
|
||||
if (!mContentClient) {
|
||||
if (wantSingleTiledContentClient) {
|
||||
mContentClient = new SingleTiledContentClient(*this, ClientManager());
|
||||
mHaveSingleTiledContentClient = true;
|
||||
} else {
|
||||
mContentClient = new MultiTiledContentClient(*this, ClientManager());
|
||||
mHaveSingleTiledContentClient = false;
|
||||
}
|
||||
|
||||
mContentClient->Connect();
|
||||
ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
|
||||
MOZ_ASSERT(mContentClient->GetForwarder());
|
||||
}
|
||||
|
||||
if (mContentClient->GetTiledBuffer()->HasFormatChanged()) {
|
||||
mValidRegion = nsIntRegion();
|
||||
mContentClient->GetTiledBuffer()->ResetPaintedAndValidState();
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Initial visible region %s\n", this, Stringify(mVisibleRegion).c_str());
|
||||
TILING_LOG("TILING %p: Initial valid region %s\n", this, Stringify(mValidRegion).c_str());
|
||||
TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this, Stringify(mLowPrecisionValidRegion).c_str());
|
||||
|
||||
nsIntRegion neededRegion = mVisibleRegion.ToUnknownRegion();
|
||||
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
|
||||
// This is handled by PadDrawTargetOutFromRegion in TiledContentClient for mobile
|
||||
if (MayResample()) {
|
||||
// If we're resampling then bilinear filtering can read up to 1 pixel
|
||||
// outside of our texture coords. Make the visible region a single rect,
|
||||
// and pad it out by 1 pixel (restricted to tile boundaries) so that
|
||||
// we always have valid content or transparent pixels to sample from.
|
||||
IntRect bounds = neededRegion.GetBounds();
|
||||
IntRect wholeTiles = bounds;
|
||||
wholeTiles.InflateToMultiple(gfx::gfxVars::TileSize());
|
||||
IntRect padded = bounds;
|
||||
padded.Inflate(1);
|
||||
padded.IntersectRect(padded, wholeTiles);
|
||||
neededRegion = padded;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIntRegion invalidRegion;
|
||||
invalidRegion.Sub(neededRegion, mValidRegion);
|
||||
if (invalidRegion.IsEmpty()) {
|
||||
EndPaint();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
ClientManager()->SetTransactionIncomplete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ClientManager()->IsRepeatTransaction()) {
|
||||
// Only paint the mask layers on the first transaction.
|
||||
RenderMaskLayers(this);
|
||||
|
||||
// For more complex cases we need to calculate a bunch of metrics before we
|
||||
// can do the paint.
|
||||
BeginPaint();
|
||||
if (mPaintData.mPaintFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure that tiles that fall outside of the visible region or outside of the
|
||||
// critical displayport are discarded on the first update. Also make sure that we
|
||||
// only draw stuff inside the critical displayport on the first update.
|
||||
mValidRegion.And(mValidRegion, neededRegion);
|
||||
if (mPaintData.mCriticalDisplayPort) {
|
||||
mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: First-transaction valid region %s\n", this, Stringify(mValidRegion).c_str());
|
||||
TILING_LOG("TILING %p: First-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str());
|
||||
} else {
|
||||
if (mPaintData.mCriticalDisplayPort) {
|
||||
invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
}
|
||||
TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str());
|
||||
}
|
||||
|
||||
nsIntRegion lowPrecisionInvalidRegion;
|
||||
if (mContentClient->GetLowPrecisionTiledBuffer()) {
|
||||
// Calculate the invalid region for the low precision buffer. Make sure
|
||||
// to remove the valid high-precision area so we don't double-paint it.
|
||||
lowPrecisionInvalidRegion.Sub(neededRegion, mLowPrecisionValidRegion);
|
||||
lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, mValidRegion);
|
||||
}
|
||||
TILING_LOG("TILING %p: Low-precision invalid region %s\n", this, Stringify(lowPrecisionInvalidRegion).c_str());
|
||||
|
||||
bool updatedHighPrecision = RenderHighPrecision(invalidRegion,
|
||||
neededRegion,
|
||||
callback, data);
|
||||
if (updatedHighPrecision) {
|
||||
ClientManager()->Hold(this);
|
||||
mContentClient->UpdatedBuffer(TiledContentClient::TILED_BUFFER);
|
||||
|
||||
if (!mPaintData.mPaintFinished) {
|
||||
// There is still more high-res stuff to paint, so we're not
|
||||
// done yet. A subsequent transaction will take care of this.
|
||||
ClientManager()->SetRepeatTransaction();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is nothing to draw in low-precision, then we're done.
|
||||
if (lowPrecisionInvalidRegion.IsEmpty()) {
|
||||
EndPaint();
|
||||
return;
|
||||
}
|
||||
|
||||
if (updatedHighPrecision) {
|
||||
// If there are low precision updates, but we just did some high-precision
|
||||
// updates, then mark the paint as unfinished and request a repeat transaction.
|
||||
// This is so that we don't perform low-precision updates in the same transaction
|
||||
// as high-precision updates.
|
||||
TILING_LOG("TILING %p: Scheduling repeat transaction for low-precision painting\n", this);
|
||||
ClientManager()->SetRepeatTransaction();
|
||||
mPaintData.mLowPrecisionPaintCount = 1;
|
||||
mPaintData.mPaintFinished = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool updatedLowPrecision = RenderLowPrecision(lowPrecisionInvalidRegion,
|
||||
neededRegion,
|
||||
callback, data);
|
||||
if (updatedLowPrecision) {
|
||||
ClientManager()->Hold(this);
|
||||
mContentClient->UpdatedBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
|
||||
|
||||
if (!mPaintData.mPaintFinished) {
|
||||
// There is still more low-res stuff to paint, so we're not
|
||||
// done yet. A subsequent transaction will take care of this.
|
||||
ClientManager()->SetRepeatTransaction();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, we've done all the high- and low-precision
|
||||
// paints we wanted to do, so we can finish the paint and chill.
|
||||
EndPaint();
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTiledPaintedLayer::IsOptimizedFor(LayerManager::PaintedLayerCreationHint aHint)
|
||||
{
|
||||
// The only creation hint is whether the layer is scrollable or not, and this
|
||||
// is only respected on B2G and OSX, where it's used to determine whether to
|
||||
// use a tiled content client or not.
|
||||
// There are pretty nasty performance consequences for not using tiles on
|
||||
// large, scrollable layers, so we want the layer to be recreated in this
|
||||
// situation.
|
||||
return aHint == GetCreationHint();
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledPaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
{
|
||||
PaintedLayer::PrintInfo(aStream, aPrefix);
|
||||
if (mContentClient) {
|
||||
aStream << "\n";
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
mContentClient->PrintInfo(aStream, pfx.get());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
153
gfx/layers/client/ClientTiledPaintedLayer.h
Normal file
153
gfx/layers/client/ClientTiledPaintedLayer.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/* 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 GFX_CLIENTTILEDPAINTEDLAYER_H
|
||||
#define GFX_CLIENTTILEDPAINTEDLAYER_H
|
||||
|
||||
#include "ClientLayerManager.h" // for ClientLayer, etc
|
||||
#include "Layers.h" // for PaintedLayer, etc
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/layers/TiledContentClient.h"
|
||||
#include "nsDebug.h" // for NS_RUNTIMEABORT
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ShadowableLayer;
|
||||
class SpecificLayerAttributes;
|
||||
|
||||
/**
|
||||
* An implementation of PaintedLayer that ONLY supports remote
|
||||
* composition that is backed by tiles. This painted layer implementation
|
||||
* is better suited to mobile hardware to work around slow implementation
|
||||
* of glTexImage2D (for OGL compositors), and restrait memory bandwidth.
|
||||
*
|
||||
* Tiled PaintedLayers use a different protocol compared with other
|
||||
* layers. A copy of the tiled buffer is made and sent to the compositing
|
||||
* thread via the layers protocol. Tiles are uploaded by the buffers
|
||||
* asynchonously without using IPC, that means they are not safe for cross-
|
||||
* process use (bug 747811). Each tile has a TextureHost/Client pair but
|
||||
* they communicate directly rather than using the Texture protocol.
|
||||
*
|
||||
* There is no ContentClient for tiled layers. There is a ContentHost, however.
|
||||
*/
|
||||
class ClientTiledPaintedLayer : public PaintedLayer,
|
||||
public ClientLayer
|
||||
{
|
||||
typedef PaintedLayer Base;
|
||||
|
||||
public:
|
||||
explicit ClientTiledPaintedLayer(ClientLayerManager* const aManager,
|
||||
ClientLayerManager::PaintedLayerCreationHint aCreationHint = LayerManager::NONE);
|
||||
|
||||
protected:
|
||||
~ClientTiledPaintedLayer();
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
|
||||
|
||||
public:
|
||||
// Override name to distinguish it from ClientPaintedLayer in layer dumps
|
||||
virtual const char* Name() const override { return "TiledPaintedLayer"; }
|
||||
|
||||
// PaintedLayer
|
||||
virtual Layer* AsLayer() override { return this; }
|
||||
virtual void InvalidateRegion(const nsIntRegion& aRegion) override {
|
||||
mInvalidRegion.Add(aRegion);
|
||||
nsIntRegion invalidRegion = mInvalidRegion.GetRegion();
|
||||
mValidRegion.Sub(mValidRegion, invalidRegion);
|
||||
mLowPrecisionValidRegion.Sub(mLowPrecisionValidRegion, invalidRegion);
|
||||
}
|
||||
|
||||
// Shadow methods
|
||||
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override;
|
||||
virtual ShadowableLayer* AsShadowableLayer() override { return this; }
|
||||
|
||||
virtual void Disconnect() override
|
||||
{
|
||||
ClientLayer::Disconnect();
|
||||
}
|
||||
|
||||
virtual void RenderLayer() override;
|
||||
|
||||
virtual void ClearCachedResources() override;
|
||||
|
||||
virtual void HandleMemoryPressure() override
|
||||
{
|
||||
if (mContentClient) {
|
||||
mContentClient->HandleMemoryPressure();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to find the nearest ancestor layers which
|
||||
* scroll and have a displayport. The parameters are out-params
|
||||
* which hold the return values; the values passed in may be null.
|
||||
*/
|
||||
void GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
|
||||
LayerMetricsWrapper* aOutDisplayPortAncestor,
|
||||
bool* aOutHasTransformAnimation);
|
||||
|
||||
virtual bool IsOptimizedFor(LayerManager::PaintedLayerCreationHint aCreationHint) override;
|
||||
|
||||
private:
|
||||
ClientLayerManager* ClientManager()
|
||||
{
|
||||
return static_cast<ClientLayerManager*>(mManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the initial PaintThebes of a transaction, calculates all the data
|
||||
* needed for that paint and any repeated transactions.
|
||||
*/
|
||||
void BeginPaint();
|
||||
|
||||
/**
|
||||
* Check if the layer is being scrolled by APZ on the compositor.
|
||||
*/
|
||||
bool IsScrollingOnCompositor(const FrameMetrics& aParentMetrics);
|
||||
|
||||
/**
|
||||
* Check if we should use progressive draw on this layer. We will
|
||||
* disable progressive draw based on a preference or if the layer
|
||||
* is not being scrolled.
|
||||
*/
|
||||
bool UseProgressiveDraw();
|
||||
|
||||
/**
|
||||
* Helper function to do the high-precision paint.
|
||||
* This function returns true if it updated the paint buffer.
|
||||
*/
|
||||
bool RenderHighPrecision(nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
/**
|
||||
* Helper function to do the low-precision paint.
|
||||
* This function returns true if it updated the paint buffer.
|
||||
*/
|
||||
bool RenderLowPrecision(nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
/**
|
||||
* This causes the paint to be marked as finished, and updates any data
|
||||
* necessary to persist until the next paint.
|
||||
*/
|
||||
void EndPaint();
|
||||
|
||||
RefPtr<TiledContentClient> mContentClient;
|
||||
// Flag to indicate if mContentClient is a SingleTiledContentClient. This is
|
||||
// only valid when mContentClient is non-null.
|
||||
bool mHaveSingleTiledContentClient;
|
||||
nsIntRegion mLowPrecisionValidRegion;
|
||||
BasicTiledLayerPaintData mPaintData;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
119
gfx/layers/client/CompositableChild.cpp
Normal file
119
gfx/layers/client/CompositableChild.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "CompositableChild.h"
|
||||
#include "CompositableClient.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/* static */ PCompositableChild*
|
||||
CompositableChild::CreateActor()
|
||||
{
|
||||
CompositableChild* child = new CompositableChild();
|
||||
child->AddRef();
|
||||
return child;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CompositableChild::DestroyActor(PCompositableChild* aChild)
|
||||
{
|
||||
static_cast<CompositableChild*>(aChild)->Release();
|
||||
}
|
||||
|
||||
CompositableChild::CompositableChild()
|
||||
: mCompositableClient(nullptr),
|
||||
mAsyncID(0),
|
||||
mCanSend(true)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CompositableChild);
|
||||
}
|
||||
|
||||
CompositableChild::~CompositableChild()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CompositableChild);
|
||||
}
|
||||
|
||||
bool
|
||||
CompositableChild::IsConnected() const
|
||||
{
|
||||
return mCompositableClient && mCanSend;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableChild::Init(CompositableClient* aCompositable, uint64_t aAsyncID)
|
||||
{
|
||||
mCompositableClient = aCompositable;
|
||||
mAsyncID = aAsyncID;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableChild::RevokeCompositableClient()
|
||||
{
|
||||
mCompositableClient = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CompositableClient>
|
||||
CompositableChild::GetCompositableClient()
|
||||
{
|
||||
return mCompositableClient;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableChild::ActorDestroy(ActorDestroyReason)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mCanSend = false;
|
||||
|
||||
if (mCompositableClient) {
|
||||
mCompositableClient->mCompositableChild = nullptr;
|
||||
mCompositableClient = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ PCompositableChild*
|
||||
AsyncCompositableChild::CreateActor()
|
||||
{
|
||||
AsyncCompositableChild* child = new AsyncCompositableChild();
|
||||
child->AddRef();
|
||||
return child;
|
||||
}
|
||||
|
||||
AsyncCompositableChild::AsyncCompositableChild()
|
||||
: mLock("AsyncCompositableChild.mLock")
|
||||
{
|
||||
}
|
||||
|
||||
AsyncCompositableChild::~AsyncCompositableChild()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCompositableChild::ActorDestroy(ActorDestroyReason)
|
||||
{
|
||||
mCanSend = false;
|
||||
|
||||
// We do not revoke CompositableClient::mCompositableChild here, since that
|
||||
// could race with the main thread.
|
||||
RevokeCompositableClient();
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCompositableChild::RevokeCompositableClient()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mCompositableClient = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CompositableClient>
|
||||
AsyncCompositableChild::GetCompositableClient()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
return CompositableChild::GetCompositableClient();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
91
gfx/layers/client/CompositableChild.h
Normal file
91
gfx/layers/client/CompositableChild.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef mozilla_gfx_layers_client_CompositableChild_h
|
||||
#define mozilla_gfx_layers_client_CompositableChild_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "IPDLActor.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/layers/PCompositableChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class CompositableClient;
|
||||
class AsyncCompositableChild;
|
||||
|
||||
/**
|
||||
* IPDL actor used by CompositableClient to match with its corresponding
|
||||
* CompositableHost on the compositor side.
|
||||
*
|
||||
* CompositableChild is owned by a CompositableClient.
|
||||
*/
|
||||
class CompositableChild : public PCompositableChild
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositableChild)
|
||||
|
||||
static PCompositableChild* CreateActor();
|
||||
static void DestroyActor(PCompositableChild* aChild);
|
||||
|
||||
void Init(CompositableClient* aCompositable, uint64_t aAsyncID);
|
||||
virtual void RevokeCompositableClient();
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason) override;
|
||||
|
||||
virtual RefPtr<CompositableClient> GetCompositableClient();
|
||||
|
||||
virtual AsyncCompositableChild* AsAsyncCompositableChild() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint64_t GetAsyncID() const {
|
||||
return mAsyncID;
|
||||
}
|
||||
|
||||
// These should only be called on the IPDL thread.
|
||||
bool IsConnected() const;
|
||||
bool CanSend() const {
|
||||
return mCanSend;
|
||||
}
|
||||
|
||||
protected:
|
||||
CompositableChild();
|
||||
virtual ~CompositableChild();
|
||||
|
||||
protected:
|
||||
CompositableClient* mCompositableClient;
|
||||
uint64_t mAsyncID;
|
||||
bool mCanSend;
|
||||
};
|
||||
|
||||
// This CompositableChild can be used off the main thread.
|
||||
class AsyncCompositableChild final : public CompositableChild
|
||||
{
|
||||
public:
|
||||
static PCompositableChild* CreateActor();
|
||||
|
||||
void RevokeCompositableClient() override;
|
||||
RefPtr<CompositableClient> GetCompositableClient() override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason) override;
|
||||
|
||||
AsyncCompositableChild* AsAsyncCompositableChild() override {
|
||||
return this;
|
||||
}
|
||||
|
||||
protected:
|
||||
AsyncCompositableChild();
|
||||
~AsyncCompositableChild() override;
|
||||
|
||||
private:
|
||||
Mutex mLock;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_gfx_layers_client_CompositableChild_h
|
||||
274
gfx/layers/client/CompositableClient.cpp
Normal file
274
gfx/layers/client/CompositableClient.cpp
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "mozilla/layers/CompositableClient.h"
|
||||
#include <stdint.h> // for uint64_t, uint32_t
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "mozilla/layers/CompositableChild.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
|
||||
#include "mozilla/layers/TextureClientOGL.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "mozilla/layers/PCompositableChild.h"
|
||||
#include "mozilla/layers/TextureClientRecycleAllocator.h"
|
||||
#ifdef XP_WIN
|
||||
#include "gfxWindowsPlatform.h" // for gfxWindowsPlatform
|
||||
#include "mozilla/layers/TextureD3D11.h"
|
||||
#include "mozilla/layers/TextureD3D9.h"
|
||||
#endif
|
||||
#include "gfxUtils.h"
|
||||
#include "IPDLActor.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
void
|
||||
CompositableClient::InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
mForwarder->AssertInForwarderThread();
|
||||
|
||||
mCompositableChild = static_cast<CompositableChild*>(aActor);
|
||||
mCompositableChild->Init(this, aAsyncID);
|
||||
}
|
||||
|
||||
/* static */ RefPtr<CompositableClient>
|
||||
CompositableClient::FromIPDLActor(PCompositableChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
RefPtr<CompositableClient> client = static_cast<CompositableChild*>(aActor)->GetCompositableClient();
|
||||
if (!client) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
client->mForwarder->AssertInForwarderThread();
|
||||
return client;
|
||||
}
|
||||
|
||||
CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
|
||||
TextureFlags aTextureFlags)
|
||||
: mForwarder(aForwarder)
|
||||
, mTextureFlags(aTextureFlags)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CompositableClient);
|
||||
}
|
||||
|
||||
CompositableClient::~CompositableClient()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CompositableClient);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
LayersBackend
|
||||
CompositableClient::GetCompositorBackendType() const
|
||||
{
|
||||
return mForwarder->GetCompositorBackendType();
|
||||
}
|
||||
|
||||
PCompositableChild*
|
||||
CompositableClient::GetIPDLActor() const
|
||||
{
|
||||
return mCompositableChild;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositableClient::Connect(ImageContainer* aImageContainer)
|
||||
{
|
||||
MOZ_ASSERT(!mCompositableChild);
|
||||
if (!GetForwarder() || GetIPDLActor()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GetForwarder()->AssertInForwarderThread();
|
||||
GetForwarder()->Connect(this, aImageContainer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositableClient::IsConnected() const
|
||||
{
|
||||
// CanSend() is only reliable in the same thread as the IPDL channel.
|
||||
mForwarder->AssertInForwarderThread();
|
||||
return mCompositableChild && mCompositableChild->IsConnected();
|
||||
}
|
||||
|
||||
void
|
||||
CompositableClient::Destroy()
|
||||
{
|
||||
if (!mCompositableChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTextureClientRecycler) {
|
||||
mTextureClientRecycler->Destroy();
|
||||
}
|
||||
|
||||
// Take away our IPDL's actor reference back to us.
|
||||
mCompositableChild->RevokeCompositableClient();
|
||||
|
||||
// Schedule the IPDL actor to be destroyed on the forwarder's thread.
|
||||
mForwarder->Destroy(mCompositableChild);
|
||||
mCompositableChild = nullptr;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
CompositableClient::GetAsyncID() const
|
||||
{
|
||||
if (mCompositableChild) {
|
||||
return mCompositableChild->GetAsyncID();
|
||||
}
|
||||
return 0; // zero is always an invalid async ID
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
return TextureClient::CreateForRawBufferAccess(GetForwarder(),
|
||||
aFormat, aSize, aMoz2DBackend,
|
||||
aTextureFlags | mTextureFlags);
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
CompositableClient::CreateTextureClientForDrawing(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
return TextureClient::CreateForDrawing(GetForwarder(),
|
||||
aFormat, aSize, aSelector,
|
||||
aTextureFlags | mTextureFlags,
|
||||
aAllocFlags);
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
CompositableClient::CreateTextureClientFromSurface(gfx::SourceSurface* aSurface,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
return TextureClient::CreateFromSurface(GetForwarder(),
|
||||
aSurface,
|
||||
aSelector,
|
||||
aTextureFlags | mTextureFlags,
|
||||
aAllocFlags);
|
||||
}
|
||||
|
||||
bool
|
||||
CompositableClient::AddTextureClient(TextureClient* aClient)
|
||||
{
|
||||
if(!aClient) {
|
||||
return false;
|
||||
}
|
||||
aClient->SetAddedToCompositableClient();
|
||||
return aClient->InitIPDLActor(mForwarder);
|
||||
}
|
||||
|
||||
void
|
||||
CompositableClient::ClearCachedResources()
|
||||
{
|
||||
if (mTextureClientRecycler) {
|
||||
mTextureClientRecycler->ShrinkToMinimumSize();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositableClient::HandleMemoryPressure()
|
||||
{
|
||||
if (mTextureClientRecycler) {
|
||||
mTextureClientRecycler->ShrinkToMinimumSize();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositableClient::RemoveTexture(TextureClient* aTexture)
|
||||
{
|
||||
mForwarder->RemoveTextureFromCompositable(this, aTexture);
|
||||
}
|
||||
|
||||
TextureClientRecycleAllocator*
|
||||
CompositableClient::GetTextureClientRecycler()
|
||||
{
|
||||
if (mTextureClientRecycler) {
|
||||
return mTextureClientRecycler;
|
||||
}
|
||||
|
||||
if (!mForwarder) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(!mForwarder->GetTextureForwarder()->UsesImageBridge()) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTextureClientRecycler = new layers::TextureClientRecycleAllocator(mForwarder);
|
||||
return mTextureClientRecycler;
|
||||
}
|
||||
|
||||
// Handle a case that mForwarder is ImageBridge
|
||||
|
||||
if (InImageBridgeChildThread()) {
|
||||
mTextureClientRecycler = new layers::TextureClientRecycleAllocator(mForwarder);
|
||||
return mTextureClientRecycler;
|
||||
}
|
||||
|
||||
ReentrantMonitor barrier("CompositableClient::GetTextureClientRecycler");
|
||||
ReentrantMonitorAutoEnter mainThreadAutoMon(barrier);
|
||||
bool done = false;
|
||||
|
||||
RefPtr<Runnable> runnable =
|
||||
NS_NewRunnableFunction([&]() {
|
||||
if (!mTextureClientRecycler) {
|
||||
mTextureClientRecycler = new layers::TextureClientRecycleAllocator(mForwarder);
|
||||
}
|
||||
ReentrantMonitorAutoEnter childThreadAutoMon(barrier);
|
||||
done = true;
|
||||
barrier.NotifyAll();
|
||||
});
|
||||
|
||||
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(runnable.forget());
|
||||
|
||||
// should stop the thread until done.
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
|
||||
return mTextureClientRecycler;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableClient::DumpTextureClient(std::stringstream& aStream,
|
||||
TextureClient* aTexture,
|
||||
TextureDumpMode aCompress)
|
||||
{
|
||||
if (!aTexture) {
|
||||
return;
|
||||
}
|
||||
RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
|
||||
if (!dSurf) {
|
||||
return;
|
||||
}
|
||||
if (aCompress == TextureDumpMode::Compress) {
|
||||
aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
|
||||
} else {
|
||||
aStream << gfxUtils::GetAsDataURI(dSurf).get();
|
||||
}
|
||||
}
|
||||
|
||||
AutoRemoveTexture::~AutoRemoveTexture()
|
||||
{
|
||||
if (mCompositable && mTexture && mCompositable->IsConnected()) {
|
||||
mCompositable->RemoveTexture(mTexture);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
209
gfx/layers/client/CompositableClient.h
Normal file
209
gfx/layers/client/CompositableClient.h
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_BUFFERCLIENT_H
|
||||
#define MOZILLA_GFX_BUFFERCLIENT_H
|
||||
|
||||
#include <stdint.h> // for uint64_t
|
||||
#include <vector> // for vector
|
||||
#include <map> // for map
|
||||
#include "mozilla/Assertions.h" // for MOZ_CRASH
|
||||
#include "mozilla/RefPtr.h" // for already_AddRefed, RefCounted
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/LayersTypes.h" // for LayersBackend, TextureDumpMode
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class CompositableClient;
|
||||
class ImageBridgeChild;
|
||||
class ImageContainer;
|
||||
class CompositableForwarder;
|
||||
class CompositableChild;
|
||||
class PCompositableChild;
|
||||
class TextureClientRecycleAllocator;
|
||||
|
||||
/**
|
||||
* CompositableClient manages the texture-specific logic for composite layers,
|
||||
* independently of the layer. It is the content side of a CompositableClient/
|
||||
* CompositableHost pair.
|
||||
*
|
||||
* CompositableClient's purpose is to send texture data to the compositor side
|
||||
* along with any extra information about how the texture is to be composited.
|
||||
* Things like opacity or transformation belong to layer and not compositable.
|
||||
*
|
||||
* Since Compositables are independent of layers it is possible to create one,
|
||||
* connect it to the compositor side, and start sending images to it. This alone
|
||||
* is arguably not very useful, but it means that as long as a shadow layer can
|
||||
* do the proper magic to find a reference to the right CompositableHost on the
|
||||
* Compositor side, a Compositable client can be used outside of the main
|
||||
* shadow layer forwarder machinery that is used on the main thread.
|
||||
*
|
||||
* The first step is to create a Compositable client and call Connect().
|
||||
* Connect() creates the underlying IPDL actor (see CompositableChild) and the
|
||||
* corresponding CompositableHost on the other side.
|
||||
*
|
||||
* To do in-transaction texture transfer (the default), call
|
||||
* ShadowLayerForwarder::Attach(CompositableClient*, ShadowableLayer*). This
|
||||
* will let the LayerComposite on the compositor side know which CompositableHost
|
||||
* to use for compositing.
|
||||
*
|
||||
* To do async texture transfer (like async-video), the CompositableClient
|
||||
* should be created with a different CompositableForwarder (like
|
||||
* ImageBridgeChild) and attachment is done with
|
||||
* CompositableForwarder::AttachAsyncCompositable that takes an identifier
|
||||
* instead of a CompositableChild, since the CompositableClient is not managed
|
||||
* by this layer forwarder (the matching uses a global map on the compositor side,
|
||||
* see CompositableMap in ImageBridgeParent.cpp)
|
||||
*
|
||||
* Subclasses: Painted layers use ContentClients, ImageLayers use ImageClients,
|
||||
* Canvas layers use CanvasClients (but ImageHosts). We have a different subclass
|
||||
* where we have a different way of interfacing with the textures - in terms of
|
||||
* drawing into the compositable and/or passing its contents to the compostior.
|
||||
*/
|
||||
class CompositableClient
|
||||
{
|
||||
protected:
|
||||
virtual ~CompositableClient();
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositableClient)
|
||||
|
||||
explicit CompositableClient(CompositableForwarder* aForwarder, TextureFlags aFlags = TextureFlags::NO_FLAGS);
|
||||
|
||||
virtual void Dump(std::stringstream& aStream,
|
||||
const char* aPrefix="",
|
||||
bool aDumpHtml=false,
|
||||
TextureDumpMode aCompress=TextureDumpMode::Compress) {};
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const = 0;
|
||||
|
||||
LayersBackend GetCompositorBackendType() const;
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2dBackend = gfx::BackendType::NONE,
|
||||
TextureFlags aFlags = TextureFlags::DEFAULT);
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
CreateTextureClientForDrawing(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
CreateTextureClientFromSurface(gfx::SourceSurface* aSurface,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
|
||||
|
||||
/**
|
||||
* Establishes the connection with compositor side through IPDL
|
||||
*/
|
||||
virtual bool Connect(ImageContainer* aImageContainer = nullptr);
|
||||
|
||||
void Destroy();
|
||||
|
||||
bool IsConnected() const;
|
||||
|
||||
PCompositableChild* GetIPDLActor() const;
|
||||
|
||||
CompositableForwarder* GetForwarder() const
|
||||
{
|
||||
return mForwarder;
|
||||
}
|
||||
|
||||
/**
|
||||
* This identifier is what lets us attach async compositables with a shadow
|
||||
* layer. It is not used if the compositable is used with the regular shadow
|
||||
* layer forwarder.
|
||||
*
|
||||
* If this returns zero, it means the compositable is not async (it is used
|
||||
* on the main thread).
|
||||
*/
|
||||
uint64_t GetAsyncID() const;
|
||||
|
||||
/**
|
||||
* Tells the Compositor to create a TextureHost for this TextureClient.
|
||||
*/
|
||||
virtual bool AddTextureClient(TextureClient* aClient);
|
||||
|
||||
/**
|
||||
* A hook for the when the Compositable is detached from it's layer.
|
||||
*/
|
||||
virtual void OnDetach() {}
|
||||
|
||||
/**
|
||||
* Clear any resources that are not immediately necessary. This may be called
|
||||
* in low-memory conditions.
|
||||
*/
|
||||
virtual void ClearCachedResources();
|
||||
|
||||
/**
|
||||
* Shrink memory usage.
|
||||
* Called when "memory-pressure" is observed.
|
||||
*/
|
||||
virtual void HandleMemoryPressure();
|
||||
|
||||
/**
|
||||
* Should be called when deataching a TextureClient from a Compositable, because
|
||||
* some platforms need to do some extra book keeping when this happens (for
|
||||
* example to properly keep track of fences on Gonk).
|
||||
*
|
||||
* See AutoRemoveTexture to automatically invoke this at the end of a scope.
|
||||
*/
|
||||
virtual void RemoveTexture(TextureClient* aTexture);
|
||||
|
||||
static RefPtr<CompositableClient> FromIPDLActor(PCompositableChild* aActor);
|
||||
|
||||
void InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID = 0);
|
||||
|
||||
TextureFlags GetTextureFlags() const { return mTextureFlags; }
|
||||
|
||||
TextureClientRecycleAllocator* GetTextureClientRecycler();
|
||||
|
||||
bool HasTextureClientRecycler() { return !!mTextureClientRecycler; }
|
||||
|
||||
static void DumpTextureClient(std::stringstream& aStream,
|
||||
TextureClient* aTexture,
|
||||
TextureDumpMode aCompress);
|
||||
protected:
|
||||
RefPtr<CompositableChild> mCompositableChild;
|
||||
RefPtr<CompositableForwarder> mForwarder;
|
||||
// Some layers may want to enforce some flags to all their textures
|
||||
// (like disallowing tiling)
|
||||
TextureFlags mTextureFlags;
|
||||
RefPtr<TextureClientRecycleAllocator> mTextureClientRecycler;
|
||||
|
||||
friend class CompositableChild;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to call RemoveTexture at the end of a scope.
|
||||
*/
|
||||
struct AutoRemoveTexture
|
||||
{
|
||||
explicit AutoRemoveTexture(CompositableClient* aCompositable,
|
||||
TextureClient* aTexture = nullptr)
|
||||
: mTexture(aTexture)
|
||||
, mCompositable(aCompositable)
|
||||
{}
|
||||
|
||||
~AutoRemoveTexture();
|
||||
|
||||
RefPtr<TextureClient> mTexture;
|
||||
private:
|
||||
CompositableClient* mCompositable;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
668
gfx/layers/client/ContentClient.cpp
Normal file
668
gfx/layers/client/ContentClient.cpp
Normal file
|
|
@ -0,0 +1,668 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "mozilla/layers/ContentClient.h"
|
||||
#include "BasicLayers.h" // for BasicLayerManager
|
||||
#include "gfxContext.h" // for gfxContext, etc
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "gfxEnv.h" // for gfxEnv
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "gfxPoint.h" // for IntSize, gfxPoint
|
||||
#include "gfxUtils.h" // for gfxUtils
|
||||
#include "ipc/ShadowLayers.h" // for ShadowLayerForwarder
|
||||
#include "mozilla/ArrayUtils.h" // for ArrayLength
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/gfx/2D.h" // for DrawTarget, Factory
|
||||
#include "mozilla/gfx/BasePoint.h" // for BasePoint
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Rect.h" // for Rect
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
|
||||
#include "mozilla/layers/LayerManagerComposite.h"
|
||||
#include "mozilla/layers/LayersMessages.h" // for ThebesBufferData
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
|
||||
#include "nsISupportsImpl.h" // for gfxContext::Release, etc
|
||||
#include "nsIWidget.h" // for nsIWidget
|
||||
#include "nsLayoutUtils.h"
|
||||
#ifdef XP_WIN
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
#include "gfxPlatformGtk.h"
|
||||
#endif
|
||||
#include "ReadbackLayer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
namespace layers {
|
||||
|
||||
static TextureFlags TextureFlagsForRotatedContentBufferFlags(uint32_t aBufferFlags)
|
||||
{
|
||||
TextureFlags result = TextureFlags::NO_FLAGS;
|
||||
|
||||
if (aBufferFlags & RotatedContentBuffer::BUFFER_COMPONENT_ALPHA) {
|
||||
result |= TextureFlags::COMPONENT_ALPHA;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<ContentClient>
|
||||
ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
|
||||
{
|
||||
LayersBackend backend = aForwarder->GetCompositorBackendType();
|
||||
if (backend != LayersBackend::LAYERS_OPENGL &&
|
||||
backend != LayersBackend::LAYERS_D3D9 &&
|
||||
backend != LayersBackend::LAYERS_D3D11 &&
|
||||
backend != LayersBackend::LAYERS_BASIC) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool useDoubleBuffering = false;
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (backend == LayersBackend::LAYERS_D3D11) {
|
||||
useDoubleBuffering = gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend();
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
// We can't use double buffering when using image content with
|
||||
// Xrender support on Linux, as ContentHostDoubleBuffered is not
|
||||
// suited for direct uploads to the server.
|
||||
if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() ||
|
||||
!gfxVars::UseXRender())
|
||||
#endif
|
||||
{
|
||||
useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() &&
|
||||
backend != LayersBackend::LAYERS_D3D9) ||
|
||||
backend == LayersBackend::LAYERS_BASIC;
|
||||
}
|
||||
|
||||
if (useDoubleBuffering || gfxEnv::ForceDoubleBuffering()) {
|
||||
return MakeAndAddRef<ContentClientDoubleBuffered>(aForwarder);
|
||||
}
|
||||
return MakeAndAddRef<ContentClientSingleBuffered>(aForwarder);
|
||||
}
|
||||
|
||||
void
|
||||
ContentClient::EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ContentClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
{
|
||||
aStream << aPrefix;
|
||||
aStream << nsPrintfCString("ContentClient (0x%p)", this).get();
|
||||
|
||||
if (profiler_feature_active("displaylistdump")) {
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
|
||||
Dump(aStream, pfx.get(), false);
|
||||
}
|
||||
}
|
||||
|
||||
// We pass a null pointer for the ContentClient Forwarder argument, which means
|
||||
// this client will not have a ContentHost on the other side.
|
||||
ContentClientBasic::ContentClientBasic(gfx::BackendType aBackend)
|
||||
: ContentClient(nullptr)
|
||||
, RotatedContentBuffer(ContainsVisibleBounds)
|
||||
, mBackend(aBackend)
|
||||
{}
|
||||
|
||||
void
|
||||
ContentClientBasic::CreateBuffer(ContentType aType,
|
||||
const IntRect& aRect,
|
||||
uint32_t aFlags,
|
||||
RefPtr<gfx::DrawTarget>* aBlackDT,
|
||||
RefPtr<gfx::DrawTarget>* aWhiteDT)
|
||||
{
|
||||
MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
|
||||
if (aFlags & BUFFER_COMPONENT_ALPHA) {
|
||||
gfxDevCrash(LogReason::AlphaWithBasicClient) << "Asking basic content client for component alpha";
|
||||
}
|
||||
|
||||
IntSize size(aRect.width, aRect.height);
|
||||
#ifdef XP_WIN
|
||||
if (mBackend == BackendType::CAIRO &&
|
||||
(aType == gfxContentType::COLOR || aType == gfxContentType::COLOR_ALPHA)) {
|
||||
RefPtr<gfxASurface> surf =
|
||||
new gfxWindowsSurface(size, aType == gfxContentType::COLOR ? gfxImageFormat::X8R8G8B8_UINT32 :
|
||||
gfxImageFormat::A8R8G8B8_UINT32);
|
||||
*aBlackDT = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
|
||||
|
||||
if (*aBlackDT) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*aBlackDT = gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(
|
||||
mBackend, size,
|
||||
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType));
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientRemoteBuffer::DestroyBuffers()
|
||||
{
|
||||
if (!mTextureClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
mOldTextures.AppendElement(mTextureClient);
|
||||
mTextureClient = nullptr;
|
||||
if (mTextureClientOnWhite) {
|
||||
mOldTextures.AppendElement(mTextureClientOnWhite);
|
||||
mTextureClientOnWhite = nullptr;
|
||||
}
|
||||
|
||||
DestroyFrontBuffer();
|
||||
}
|
||||
|
||||
class RemoteBufferReadbackProcessor : public TextureReadbackSink
|
||||
{
|
||||
public:
|
||||
RemoteBufferReadbackProcessor(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates,
|
||||
const IntRect& aBufferRect, const nsIntPoint& aBufferRotation)
|
||||
: mReadbackUpdates(*aReadbackUpdates)
|
||||
, mBufferRect(aBufferRect)
|
||||
, mBufferRotation(aBufferRotation)
|
||||
{
|
||||
for (uint32_t i = 0; i < mReadbackUpdates.Length(); ++i) {
|
||||
mLayerRefs.push_back(mReadbackUpdates[i].mLayer);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void ProcessReadback(gfx::DataSourceSurface *aSourceSurface)
|
||||
{
|
||||
SourceRotatedBuffer rotBuffer(aSourceSurface, nullptr, mBufferRect, mBufferRotation);
|
||||
|
||||
for (uint32_t i = 0; i < mReadbackUpdates.Length(); ++i) {
|
||||
ReadbackProcessor::Update& update = mReadbackUpdates[i];
|
||||
nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset();
|
||||
|
||||
ReadbackSink* sink = update.mLayer->GetSink();
|
||||
|
||||
if (!sink) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!aSourceSurface) {
|
||||
sink->SetUnknown(update.mSequenceCounter);
|
||||
continue;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> dt =
|
||||
sink->BeginUpdate(update.mUpdateRect + offset, update.mSequenceCounter);
|
||||
if (!dt) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dt->SetTransform(Matrix::Translation(offset.x, offset.y));
|
||||
|
||||
rotBuffer.DrawBufferWithRotation(dt, RotatedBuffer::BUFFER_BLACK);
|
||||
|
||||
update.mLayer->GetSink()->EndUpdate(update.mUpdateRect + offset);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<ReadbackProcessor::Update> mReadbackUpdates;
|
||||
// This array is used to keep the layers alive until the callback.
|
||||
vector<RefPtr<Layer>> mLayerRefs;
|
||||
|
||||
IntRect mBufferRect;
|
||||
nsIntPoint mBufferRotation;
|
||||
};
|
||||
|
||||
void
|
||||
ContentClientRemoteBuffer::BeginPaint()
|
||||
{
|
||||
EnsureBackBufferIfFrontBuffer();
|
||||
|
||||
// XXX: So we might not have a TextureClient yet.. because it will
|
||||
// only be created by CreateBuffer.. which will deliver a locked surface!.
|
||||
if (mTextureClient) {
|
||||
SetBufferProvider(mTextureClient);
|
||||
}
|
||||
if (mTextureClientOnWhite) {
|
||||
SetBufferProviderOnWhite(mTextureClientOnWhite);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientRemoteBuffer::EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
|
||||
{
|
||||
MOZ_ASSERT(!mTextureClientOnWhite || !aReadbackUpdates || aReadbackUpdates->Length() == 0);
|
||||
|
||||
// XXX: We might still not have a texture client if PaintThebes
|
||||
// decided we didn't need one yet because the region to draw was empty.
|
||||
SetBufferProvider(nullptr);
|
||||
SetBufferProviderOnWhite(nullptr);
|
||||
for (unsigned i = 0; i< mOldTextures.Length(); ++i) {
|
||||
if (mOldTextures[i]->IsLocked()) {
|
||||
mOldTextures[i]->Unlock();
|
||||
}
|
||||
}
|
||||
mOldTextures.Clear();
|
||||
|
||||
if (mTextureClient && mTextureClient->IsLocked()) {
|
||||
if (aReadbackUpdates->Length() > 0) {
|
||||
RefPtr<TextureReadbackSink> readbackSink = new RemoteBufferReadbackProcessor(aReadbackUpdates, mBufferRect, mBufferRotation);
|
||||
|
||||
mTextureClient->SetReadbackSink(readbackSink);
|
||||
}
|
||||
|
||||
mTextureClient->Unlock();
|
||||
mTextureClient->SyncWithObject(mForwarder->GetSyncObject());
|
||||
}
|
||||
if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) {
|
||||
mTextureClientOnWhite->Unlock();
|
||||
mTextureClientOnWhite->SyncWithObject(mForwarder->GetSyncObject());
|
||||
}
|
||||
|
||||
ContentClientRemote::EndPaint(aReadbackUpdates);
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
|
||||
const IntRect& aRect,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
// If we hit this assertion, then it might be due to an empty transaction
|
||||
// followed by a real transaction. Our buffers should be created (but not
|
||||
// painted in the empty transaction) and then painted (but not created) in the
|
||||
// real transaction. That is kind of fragile, and this assert will catch
|
||||
// circumstances where we screw that up, e.g., by unnecessarily recreating our
|
||||
// buffers.
|
||||
MOZ_ASSERT(!mIsNewBuffer,
|
||||
"Bad! Did we create a buffer twice without painting?");
|
||||
|
||||
mIsNewBuffer = true;
|
||||
|
||||
DestroyBuffers();
|
||||
|
||||
mSurfaceFormat = aFormat;
|
||||
mSize = IntSize(aRect.width, aRect.height);
|
||||
mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
|
||||
|
||||
if (aFlags & BUFFER_COMPONENT_ALPHA) {
|
||||
mTextureFlags |= TextureFlags::COMPONENT_ALPHA;
|
||||
}
|
||||
|
||||
CreateBackBuffer(mBufferRect);
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientRemoteBuffer::CreateBackBuffer(const IntRect& aBufferRect)
|
||||
{
|
||||
// gfx::BackendType::NONE means fallback to the content backend
|
||||
TextureAllocationFlags textureAllocFlags
|
||||
= (mTextureFlags & TextureFlags::COMPONENT_ALPHA) ?
|
||||
TextureAllocationFlags::ALLOC_CLEAR_BUFFER_BLACK :
|
||||
TextureAllocationFlags::ALLOC_CLEAR_BUFFER;
|
||||
|
||||
mTextureClient = CreateTextureClientForDrawing(
|
||||
mSurfaceFormat, mSize, BackendSelector::Content,
|
||||
mTextureFlags | ExtraTextureFlags(),
|
||||
textureAllocFlags
|
||||
);
|
||||
if (!mTextureClient || !AddTextureClient(mTextureClient)) {
|
||||
AbortTextureClientCreation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTextureFlags & TextureFlags::COMPONENT_ALPHA) {
|
||||
mTextureClientOnWhite = mTextureClient->CreateSimilar(
|
||||
mForwarder->GetCompositorBackendType(),
|
||||
mTextureFlags | ExtraTextureFlags(),
|
||||
TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE
|
||||
);
|
||||
if (!mTextureClientOnWhite || !AddTextureClient(mTextureClientOnWhite)) {
|
||||
AbortTextureClientCreation();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientRemoteBuffer::CreateBuffer(ContentType aType,
|
||||
const IntRect& aRect,
|
||||
uint32_t aFlags,
|
||||
RefPtr<gfx::DrawTarget>* aBlackDT,
|
||||
RefPtr<gfx::DrawTarget>* aWhiteDT)
|
||||
{
|
||||
BuildTextureClients(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType), aRect, aFlags);
|
||||
if (!mTextureClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We just created the textures and we are about to get their draw targets
|
||||
// so we have to lock them here.
|
||||
DebugOnly<bool> locked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE);
|
||||
MOZ_ASSERT(locked, "Could not lock the TextureClient");
|
||||
|
||||
*aBlackDT = mTextureClient->BorrowDrawTarget();
|
||||
if (aFlags & BUFFER_COMPONENT_ALPHA) {
|
||||
locked = mTextureClientOnWhite->Lock(OpenMode::OPEN_READ_WRITE);
|
||||
MOZ_ASSERT(locked, "Could not lock the second TextureClient for component alpha");
|
||||
|
||||
*aWhiteDT = mTextureClientOnWhite->BorrowDrawTarget();
|
||||
}
|
||||
}
|
||||
|
||||
nsIntRegion
|
||||
ContentClientRemoteBuffer::GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
bool aDidSelfCopy)
|
||||
{
|
||||
nsIntRegion updatedRegion;
|
||||
if (mIsNewBuffer || aDidSelfCopy) {
|
||||
// A buffer reallocation clears both buffers. The front buffer has all the
|
||||
// content by now, but the back buffer is still clear. Here, in effect, we
|
||||
// are saying to copy all of the pixels of the front buffer to the back.
|
||||
// Also when we self-copied in the buffer, the buffer space
|
||||
// changes and some changed buffer content isn't reflected in the
|
||||
// draw or invalidate region (on purpose!). When this happens, we
|
||||
// need to read back the entire buffer too.
|
||||
updatedRegion = aVisibleRegion.GetBounds();
|
||||
mIsNewBuffer = false;
|
||||
} else {
|
||||
updatedRegion = aRegionToDraw;
|
||||
}
|
||||
|
||||
NS_ASSERTION(BufferRect().Contains(aRegionToDraw.GetBounds()),
|
||||
"Update outside of buffer rect!");
|
||||
MOZ_ASSERT(mTextureClient, "should have a back buffer by now");
|
||||
|
||||
return updatedRegion;
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
bool aDidSelfCopy)
|
||||
{
|
||||
nsIntRegion updatedRegion = GetUpdatedRegion(aRegionToDraw,
|
||||
aVisibleRegion,
|
||||
aDidSelfCopy);
|
||||
|
||||
MOZ_ASSERT(mTextureClient);
|
||||
if (mTextureClientOnWhite) {
|
||||
mForwarder->UseComponentAlphaTextures(this, mTextureClient,
|
||||
mTextureClientOnWhite);
|
||||
} else {
|
||||
AutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
|
||||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = mTextureClient;
|
||||
IntSize size = mTextureClient->GetSize();
|
||||
t->mPictureRect = nsIntRect(0, 0, size.width, size.height);
|
||||
GetForwarder()->UseTextures(this, textures);
|
||||
}
|
||||
mForwarder->UpdateTextureRegion(this,
|
||||
ThebesBufferData(BufferRect(),
|
||||
BufferRotation()),
|
||||
updatedRegion);
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientRemoteBuffer::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
|
||||
{
|
||||
mFrontAndBackBufferDiffer = true;
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientRemoteBuffer::Dump(std::stringstream& aStream,
|
||||
const char* aPrefix,
|
||||
bool aDumpHtml, TextureDumpMode aCompress)
|
||||
{
|
||||
// TODO We should combine the OnWhite/OnBlack here an just output a single image.
|
||||
if (!aDumpHtml) {
|
||||
aStream << "\n" << aPrefix << "Surface: ";
|
||||
}
|
||||
CompositableClient::DumpTextureClient(aStream, mTextureClient, aCompress);
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientDoubleBuffered::Dump(std::stringstream& aStream,
|
||||
const char* aPrefix,
|
||||
bool aDumpHtml, TextureDumpMode aCompress)
|
||||
{
|
||||
// TODO We should combine the OnWhite/OnBlack here an just output a single image.
|
||||
if (!aDumpHtml) {
|
||||
aStream << "\n" << aPrefix << "Surface: ";
|
||||
}
|
||||
CompositableClient::DumpTextureClient(aStream, mFrontClient, aCompress);
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientDoubleBuffered::DestroyFrontBuffer()
|
||||
{
|
||||
if (mFrontClient) {
|
||||
mOldTextures.AppendElement(mFrontClient);
|
||||
mFrontClient = nullptr;
|
||||
}
|
||||
|
||||
if (mFrontClientOnWhite) {
|
||||
mOldTextures.AppendElement(mFrontClientOnWhite);
|
||||
mFrontClientOnWhite = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientDoubleBuffered::Updated(const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
bool aDidSelfCopy)
|
||||
{
|
||||
ContentClientRemoteBuffer::Updated(aRegionToDraw, aVisibleRegion, aDidSelfCopy);
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientDoubleBuffered::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
|
||||
{
|
||||
mFrontUpdatedRegion = aFrontUpdatedRegion;
|
||||
|
||||
RefPtr<TextureClient> oldBack = mTextureClient;
|
||||
mTextureClient = mFrontClient;
|
||||
mFrontClient = oldBack;
|
||||
|
||||
oldBack = mTextureClientOnWhite;
|
||||
mTextureClientOnWhite = mFrontClientOnWhite;
|
||||
mFrontClientOnWhite = oldBack;
|
||||
|
||||
IntRect oldBufferRect = mBufferRect;
|
||||
mBufferRect = mFrontBufferRect;
|
||||
mFrontBufferRect = oldBufferRect;
|
||||
|
||||
nsIntPoint oldBufferRotation = mBufferRotation;
|
||||
mBufferRotation = mFrontBufferRotation;
|
||||
mFrontBufferRotation = oldBufferRotation;
|
||||
|
||||
MOZ_ASSERT(mFrontClient);
|
||||
|
||||
ContentClientRemoteBuffer::SwapBuffers(aFrontUpdatedRegion);
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientDoubleBuffered::BeginPaint()
|
||||
{
|
||||
ContentClientRemoteBuffer::BeginPaint();
|
||||
|
||||
mIsNewBuffer = false;
|
||||
|
||||
if (!mFrontAndBackBufferDiffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDidSelfCopy) {
|
||||
// We can't easily draw our front buffer into us, since we're going to be
|
||||
// copying stuff around anyway it's easiest if we just move our situation
|
||||
// to non-rotated while we're at it. If this situation occurs we'll have
|
||||
// hit a self-copy path in PaintThebes before as well anyway.
|
||||
mBufferRect.MoveTo(mFrontBufferRect.TopLeft());
|
||||
mBufferRotation = nsIntPoint();
|
||||
return;
|
||||
}
|
||||
mBufferRect = mFrontBufferRect;
|
||||
mBufferRotation = mFrontBufferRotation;
|
||||
}
|
||||
|
||||
// Sync front/back buffers content
|
||||
// After executing, the new back buffer has the same (interesting) pixels as
|
||||
// the new front buffer, and mValidRegion et al. are correct wrt the new
|
||||
// back buffer (i.e. as they were for the old back buffer)
|
||||
void
|
||||
ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
|
||||
{
|
||||
if (mTextureClient) {
|
||||
DebugOnly<bool> locked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE);
|
||||
MOZ_ASSERT(locked);
|
||||
}
|
||||
if (mTextureClientOnWhite) {
|
||||
DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OpenMode::OPEN_READ_WRITE);
|
||||
MOZ_ASSERT(locked);
|
||||
}
|
||||
|
||||
if (!mFrontAndBackBufferDiffer) {
|
||||
MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?");
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mFrontClient);
|
||||
if (!mFrontClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
|
||||
this,
|
||||
mFrontUpdatedRegion.GetBounds().x,
|
||||
mFrontUpdatedRegion.GetBounds().y,
|
||||
mFrontUpdatedRegion.GetBounds().width,
|
||||
mFrontUpdatedRegion.GetBounds().height));
|
||||
|
||||
mFrontAndBackBufferDiffer = false;
|
||||
|
||||
nsIntRegion updateRegion = mFrontUpdatedRegion;
|
||||
if (mDidSelfCopy) {
|
||||
mDidSelfCopy = false;
|
||||
updateRegion = mBufferRect;
|
||||
}
|
||||
|
||||
// No point in sync'ing what we are going to draw over anyway. And if there is
|
||||
// nothing to sync at all, there is nothing to do and we can go home early.
|
||||
updateRegion.Sub(updateRegion, aRegionToDraw);
|
||||
if (updateRegion.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to ensure that we lock these two buffers in the same
|
||||
// order as the compositor to prevent deadlocks.
|
||||
TextureClientAutoLock frontLock(mFrontClient, OpenMode::OPEN_READ_ONLY);
|
||||
if (!frontLock.Succeeded()) {
|
||||
return;
|
||||
}
|
||||
Maybe<TextureClientAutoLock> frontOnWhiteLock;
|
||||
if (mFrontClientOnWhite) {
|
||||
frontOnWhiteLock.emplace(mFrontClientOnWhite, OpenMode::OPEN_READ_ONLY);
|
||||
if (!frontOnWhiteLock->Succeeded()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Restrict the DrawTargets and frontBuffer to a scope to make
|
||||
// sure there is no more external references to the DrawTargets
|
||||
// when we Unlock the TextureClients.
|
||||
gfx::DrawTarget* dt = mFrontClient->BorrowDrawTarget();
|
||||
gfx::DrawTarget* dtw = mFrontClientOnWhite ? mFrontClientOnWhite->BorrowDrawTarget() : nullptr;
|
||||
if (dt && dt->IsValid()) {
|
||||
RefPtr<SourceSurface> surf = dt->Snapshot();
|
||||
RefPtr<SourceSurface> surfOnWhite = dtw ? dtw->Snapshot() : nullptr;
|
||||
SourceRotatedBuffer frontBuffer(surf,
|
||||
surfOnWhite,
|
||||
mFrontBufferRect,
|
||||
mFrontBufferRotation);
|
||||
UpdateDestinationFrom(frontBuffer, updateRegion);
|
||||
} else {
|
||||
// We know this can happen, but we want to track it somewhat, in case it leads
|
||||
// to other problems.
|
||||
gfxCriticalNote << "Invalid draw target(s) " << hexa(dt) << " and " << hexa(dtw);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientDoubleBuffered::EnsureBackBufferIfFrontBuffer()
|
||||
{
|
||||
if (!mTextureClient && mFrontClient) {
|
||||
CreateBackBuffer(mFrontBufferRect);
|
||||
|
||||
mBufferRect = mFrontBufferRect;
|
||||
mBufferRotation = mFrontBufferRotation;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
|
||||
const nsIntRegion& aUpdateRegion)
|
||||
{
|
||||
DrawIterator iter;
|
||||
while (DrawTarget* destDT =
|
||||
BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
|
||||
bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
|
||||
if (isClippingCheap) {
|
||||
gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
|
||||
}
|
||||
|
||||
aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
|
||||
if (isClippingCheap) {
|
||||
destDT->PopClip();
|
||||
}
|
||||
// Flush the destination before the sources become inaccessible (Unlock).
|
||||
destDT->Flush();
|
||||
ReturnDrawTargetToBuffer(destDT);
|
||||
}
|
||||
|
||||
if (aSource.HaveBufferOnWhite()) {
|
||||
MOZ_ASSERT(HaveBufferOnWhite());
|
||||
DrawIterator whiteIter;
|
||||
while (DrawTarget* destDT =
|
||||
BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
|
||||
bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
|
||||
if (isClippingCheap) {
|
||||
gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
|
||||
}
|
||||
|
||||
aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
|
||||
if (isClippingCheap) {
|
||||
destDT->PopClip();
|
||||
}
|
||||
// Flush the destination before the sources become inaccessible (Unlock).
|
||||
destDT->Flush();
|
||||
ReturnDrawTargetToBuffer(destDT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentClientSingleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
|
||||
{
|
||||
if (mTextureClient) {
|
||||
DebugOnly<bool> locked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE);
|
||||
MOZ_ASSERT(locked);
|
||||
}
|
||||
if (mTextureClientOnWhite) {
|
||||
DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OpenMode::OPEN_READ_WRITE);
|
||||
MOZ_ASSERT(locked);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
412
gfx/layers/client/ContentClient.h
Normal file
412
gfx/layers/client/ContentClient.h
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_CONTENTCLIENT_H
|
||||
#define MOZILLA_GFX_CONTENTCLIENT_H
|
||||
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include "RotatedBuffer.h" // for RotatedContentBuffer, etc
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "mozilla/Assertions.h" // for MOZ_CRASH
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/LayersTypes.h" // for TextureDumpMode
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "ReadbackProcessor.h" // For ReadbackProcessor::Update
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
#include "nsTArray.h" // for nsTArray
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class DrawTarget;
|
||||
} // namespace gfx
|
||||
|
||||
namespace layers {
|
||||
|
||||
class PaintedLayer;
|
||||
|
||||
/**
|
||||
* A compositable client for PaintedLayers. These are different to Image/Canvas
|
||||
* clients due to sending a valid region across IPC and because we do a lot more
|
||||
* optimisation work, encapsualted in RotatedContentBuffers.
|
||||
*
|
||||
* We use content clients for OMTC and non-OMTC, basic rendering so that
|
||||
* BasicPaintedLayer has only one interface to deal with. We support single and
|
||||
* double buffered flavours. For tiled layers, we do not use a ContentClient
|
||||
* although we do have a ContentHost, and we do use texture clients and texture
|
||||
* hosts.
|
||||
*
|
||||
* The interface presented by ContentClient is used by the BasicPaintedLayer
|
||||
* methods - PaintThebes, which is the same for MT and OMTC, and PaintBuffer
|
||||
* which is different (the OMTC one does a little more). The 'buffer' in the
|
||||
* names of a lot of these method is actually the TextureClient. But, 'buffer'
|
||||
* for the RotatedContentBuffer (as in SetBuffer) means a gfxSurface. See the
|
||||
* comments for SetBuffer and SetBufferProvider in RotatedContentBuffer. To keep
|
||||
* these mapped buffers alive, we store a pointer in mOldTextures if the
|
||||
* RotatedContentBuffer's surface is not the one from our texture client, once we
|
||||
* are done painting we unmap the surface/texture client and don't need to keep
|
||||
* it alive anymore, so we clear mOldTextures.
|
||||
*
|
||||
* The sequence for painting is: call BeginPaint on the content client;
|
||||
* call BeginPaintBuffer on the content client. That will initialise the buffer
|
||||
* for painting, by calling RotatedContentBuffer::BeginPaint (usually) which
|
||||
* will call back to ContentClient::FinalizeFrame to finalize update of the
|
||||
* buffers before drawing (i.e., it finalizes the previous frame). Then call
|
||||
* BorrowDrawTargetForPainting to get a DrawTarget to paint into. Then paint.
|
||||
* Then return that DrawTarget using ReturnDrawTarget.
|
||||
* Call EndPaint on the content client;
|
||||
*
|
||||
* SwapBuffers is called in response to the transaction reply from the compositor.
|
||||
*/
|
||||
class ContentClient : public CompositableClient
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates, configures, and returns a new content client. If necessary, a
|
||||
* message will be sent to the compositor to create a corresponding content
|
||||
* host.
|
||||
*/
|
||||
static already_AddRefed<ContentClient> CreateContentClient(CompositableForwarder* aFwd);
|
||||
|
||||
explicit ContentClient(CompositableForwarder* aForwarder)
|
||||
: CompositableClient(aForwarder)
|
||||
{}
|
||||
virtual ~ContentClient()
|
||||
{}
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
|
||||
|
||||
virtual void Clear() = 0;
|
||||
virtual RotatedContentBuffer::PaintState BeginPaintBuffer(PaintedLayer* aLayer,
|
||||
uint32_t aFlags) = 0;
|
||||
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(RotatedContentBuffer::PaintState& aPaintState,
|
||||
RotatedContentBuffer::DrawIterator* aIter = nullptr) = 0;
|
||||
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) = 0;
|
||||
|
||||
// Called as part of the layers transation reply. Conveys data about our
|
||||
// buffer(s) from the compositor. If appropriate we should swap references
|
||||
// to our buffers.
|
||||
virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) {}
|
||||
|
||||
// call before and after painting into this content client
|
||||
virtual void BeginPaint() {}
|
||||
virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr);
|
||||
};
|
||||
|
||||
/**
|
||||
* A ContentClient for use with OMTC.
|
||||
*/
|
||||
class ContentClientRemote : public ContentClient
|
||||
{
|
||||
public:
|
||||
explicit ContentClientRemote(CompositableForwarder* aForwarder)
|
||||
: ContentClient(aForwarder)
|
||||
{}
|
||||
|
||||
virtual void Updated(const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
bool aDidSelfCopy) = 0;
|
||||
};
|
||||
|
||||
// thin wrapper around RotatedContentBuffer, for on-mtc
|
||||
class ContentClientBasic final : public ContentClient
|
||||
, protected RotatedContentBuffer
|
||||
{
|
||||
public:
|
||||
explicit ContentClientBasic(gfx::BackendType aBackend);
|
||||
|
||||
typedef RotatedContentBuffer::PaintState PaintState;
|
||||
typedef RotatedContentBuffer::ContentType ContentType;
|
||||
|
||||
virtual void Clear() override { RotatedContentBuffer::Clear(); }
|
||||
virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
|
||||
uint32_t aFlags) override
|
||||
{
|
||||
return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
|
||||
}
|
||||
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
|
||||
RotatedContentBuffer::DrawIterator* aIter = nullptr) override
|
||||
{
|
||||
return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
|
||||
}
|
||||
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) override
|
||||
{
|
||||
BorrowDrawTarget::ReturnDrawTarget(aReturned);
|
||||
}
|
||||
|
||||
void DrawTo(PaintedLayer* aLayer,
|
||||
gfx::DrawTarget* aTarget,
|
||||
float aOpacity,
|
||||
gfx::CompositionOp aOp,
|
||||
gfx::SourceSurface* aMask,
|
||||
const gfx::Matrix* aMaskTransform)
|
||||
{
|
||||
RotatedContentBuffer::DrawTo(aLayer, aTarget, aOpacity, aOp,
|
||||
aMask, aMaskTransform);
|
||||
}
|
||||
|
||||
virtual void CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
|
||||
RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) override;
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const override
|
||||
{
|
||||
MOZ_CRASH("GFX: Should not be called on non-remote ContentClient");
|
||||
}
|
||||
|
||||
private:
|
||||
gfx::BackendType mBackend;
|
||||
};
|
||||
|
||||
/**
|
||||
* A ContentClientRemote backed by a RotatedContentBuffer.
|
||||
*
|
||||
* When using a ContentClientRemote, SurfaceDescriptors are created on
|
||||
* the rendering side and destroyed on the compositing side. They are only
|
||||
* passed from one side to the other when the TextureClient/Hosts are created.
|
||||
* *Ownership* of the SurfaceDescriptor moves from the rendering side to the
|
||||
* compositing side with the create message (send from CreateBuffer) which
|
||||
* tells the compositor that TextureClients have been created and that the
|
||||
* compositor should assign the corresponding TextureHosts to our corresponding
|
||||
* ContentHost.
|
||||
*
|
||||
* If the size or type of our buffer(s) change(s), then we simply destroy and
|
||||
* create them.
|
||||
*/
|
||||
// Version using new texture clients
|
||||
class ContentClientRemoteBuffer : public ContentClientRemote
|
||||
, protected RotatedContentBuffer
|
||||
{
|
||||
using RotatedContentBuffer::BufferRect;
|
||||
using RotatedContentBuffer::BufferRotation;
|
||||
public:
|
||||
explicit ContentClientRemoteBuffer(CompositableForwarder* aForwarder)
|
||||
: ContentClientRemote(aForwarder)
|
||||
, RotatedContentBuffer(ContainsVisibleBounds)
|
||||
, mIsNewBuffer(false)
|
||||
, mFrontAndBackBufferDiffer(false)
|
||||
, mSurfaceFormat(gfx::SurfaceFormat::B8G8R8A8)
|
||||
{}
|
||||
|
||||
typedef RotatedContentBuffer::PaintState PaintState;
|
||||
typedef RotatedContentBuffer::ContentType ContentType;
|
||||
|
||||
virtual void Clear() override
|
||||
{
|
||||
RotatedContentBuffer::Clear();
|
||||
mTextureClient = nullptr;
|
||||
mTextureClientOnWhite = nullptr;
|
||||
}
|
||||
|
||||
virtual void Dump(std::stringstream& aStream,
|
||||
const char* aPrefix="",
|
||||
bool aDumpHtml=false,
|
||||
TextureDumpMode aCompress=TextureDumpMode::Compress) override;
|
||||
|
||||
virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
|
||||
uint32_t aFlags) override
|
||||
{
|
||||
return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
|
||||
}
|
||||
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
|
||||
RotatedContentBuffer::DrawIterator* aIter = nullptr) override
|
||||
{
|
||||
return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
|
||||
}
|
||||
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) override
|
||||
{
|
||||
BorrowDrawTarget::ReturnDrawTarget(aReturned);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin/End Paint map a gfxASurface from the texture client
|
||||
* into the buffer of RotatedBuffer. The surface is only
|
||||
* valid when the texture client is locked, so is mapped out
|
||||
* of RotatedContentBuffer when we are done painting.
|
||||
* None of the underlying buffer attributes (rect, rotation)
|
||||
* are affected by mapping/unmapping.
|
||||
*/
|
||||
virtual void BeginPaint() override;
|
||||
virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) override;
|
||||
|
||||
virtual void Updated(const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
bool aDidSelfCopy) override;
|
||||
|
||||
virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
|
||||
|
||||
// Expose these protected methods from the superclass.
|
||||
virtual const gfx::IntRect& BufferRect() const
|
||||
{
|
||||
return RotatedContentBuffer::BufferRect();
|
||||
}
|
||||
virtual const nsIntPoint& BufferRotation() const
|
||||
{
|
||||
return RotatedContentBuffer::BufferRotation();
|
||||
}
|
||||
|
||||
virtual void CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
|
||||
RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) override;
|
||||
|
||||
virtual TextureFlags ExtraTextureFlags() const
|
||||
{
|
||||
return TextureFlags::NO_FLAGS;
|
||||
}
|
||||
|
||||
protected:
|
||||
void DestroyBuffers();
|
||||
|
||||
virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
bool aDidSelfCopy);
|
||||
|
||||
void BuildTextureClients(gfx::SurfaceFormat aFormat,
|
||||
const gfx::IntRect& aRect,
|
||||
uint32_t aFlags);
|
||||
|
||||
void CreateBackBuffer(const gfx::IntRect& aBufferRect);
|
||||
|
||||
// Ensure we have a valid back buffer if we have a valid front buffer (i.e.
|
||||
// if a backbuffer has been created.)
|
||||
virtual void EnsureBackBufferIfFrontBuffer() {}
|
||||
|
||||
// Create the front buffer for the ContentClient/Host pair if necessary
|
||||
// and notify the compositor that we have created the buffer(s).
|
||||
virtual void DestroyFrontBuffer() {}
|
||||
|
||||
virtual void AbortTextureClientCreation()
|
||||
{
|
||||
mTextureClient = nullptr;
|
||||
mTextureClientOnWhite = nullptr;
|
||||
mIsNewBuffer = false;
|
||||
}
|
||||
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
RefPtr<TextureClient> mTextureClientOnWhite;
|
||||
// keep a record of texture clients we have created and need to keep around
|
||||
// (for RotatedBuffer to access), then unlock and remove them when we are done
|
||||
// painting.
|
||||
nsTArray<RefPtr<TextureClient> > mOldTextures;
|
||||
|
||||
bool mIsNewBuffer;
|
||||
bool mFrontAndBackBufferDiffer;
|
||||
gfx::IntSize mSize;
|
||||
gfx::SurfaceFormat mSurfaceFormat;
|
||||
};
|
||||
|
||||
/**
|
||||
* A double buffered ContentClient. mTextureClient is the back buffer, which
|
||||
* we draw into. mFrontClient is the front buffer which we may read from, but
|
||||
* not write to, when the compositor does not have the 'soft' lock. We can write
|
||||
* into mTextureClient at any time.
|
||||
*
|
||||
* The ContentHost keeps a reference to both corresponding texture hosts, in
|
||||
* response to our UpdateTextureRegion message, the compositor swaps its
|
||||
* references. In response to the compositor's reply we swap our references
|
||||
* (in SwapBuffers).
|
||||
*/
|
||||
class ContentClientDoubleBuffered : public ContentClientRemoteBuffer
|
||||
{
|
||||
public:
|
||||
explicit ContentClientDoubleBuffered(CompositableForwarder* aFwd)
|
||||
: ContentClientRemoteBuffer(aFwd)
|
||||
{}
|
||||
|
||||
virtual ~ContentClientDoubleBuffered() {}
|
||||
|
||||
virtual void Clear() override
|
||||
{
|
||||
ContentClientRemoteBuffer::Clear();
|
||||
mFrontClient = nullptr;
|
||||
mFrontClientOnWhite = nullptr;
|
||||
}
|
||||
|
||||
virtual void Updated(const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
bool aDidSelfCopy) override;
|
||||
|
||||
virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
|
||||
|
||||
virtual void BeginPaint() override;
|
||||
|
||||
virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) override;
|
||||
|
||||
virtual void EnsureBackBufferIfFrontBuffer() override;
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const override
|
||||
{
|
||||
return TextureInfo(CompositableType::CONTENT_DOUBLE, mTextureFlags);
|
||||
}
|
||||
|
||||
virtual void Dump(std::stringstream& aStream,
|
||||
const char* aPrefix="",
|
||||
bool aDumpHtml=false,
|
||||
TextureDumpMode aCompress=TextureDumpMode::Compress) override;
|
||||
protected:
|
||||
virtual void DestroyFrontBuffer() override;
|
||||
|
||||
private:
|
||||
void UpdateDestinationFrom(const RotatedBuffer& aSource,
|
||||
const nsIntRegion& aUpdateRegion);
|
||||
|
||||
virtual void AbortTextureClientCreation() override
|
||||
{
|
||||
mTextureClient = nullptr;
|
||||
mTextureClientOnWhite = nullptr;
|
||||
mFrontClient = nullptr;
|
||||
mFrontClientOnWhite = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<TextureClient> mFrontClient;
|
||||
RefPtr<TextureClient> mFrontClientOnWhite;
|
||||
nsIntRegion mFrontUpdatedRegion;
|
||||
gfx::IntRect mFrontBufferRect;
|
||||
nsIntPoint mFrontBufferRotation;
|
||||
};
|
||||
|
||||
/**
|
||||
* A single buffered ContentClient. We have a single TextureClient/Host
|
||||
* which we update and then send a message to the compositor that we are
|
||||
* done updating. It is not safe for the compositor to use the corresponding
|
||||
* TextureHost's memory directly, it must upload it to video memory of some
|
||||
* kind. We are free to modify the TextureClient once we receive reply from
|
||||
* the compositor.
|
||||
*/
|
||||
class ContentClientSingleBuffered : public ContentClientRemoteBuffer
|
||||
{
|
||||
public:
|
||||
explicit ContentClientSingleBuffered(CompositableForwarder* aFwd)
|
||||
: ContentClientRemoteBuffer(aFwd)
|
||||
{
|
||||
}
|
||||
virtual ~ContentClientSingleBuffered() {}
|
||||
|
||||
virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) override;
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const override
|
||||
{
|
||||
return TextureInfo(CompositableType::CONTENT_SINGLE, mTextureFlags | ExtraTextureFlags());
|
||||
}
|
||||
|
||||
virtual TextureFlags ExtraTextureFlags() const override
|
||||
{
|
||||
return TextureFlags::IMMEDIATE_UPLOAD;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
72
gfx/layers/client/GPUVideoTextureClient.cpp
Normal file
72
gfx/layers/client/GPUVideoTextureClient.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "GPUVideoTextureClient.h"
|
||||
#include "mozilla/dom/VideoDecoderManagerChild.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
GPUVideoTextureData::GPUVideoTextureData(dom::VideoDecoderManagerChild* aManager,
|
||||
const SurfaceDescriptorGPUVideo& aSD,
|
||||
const gfx::IntSize& aSize)
|
||||
: mManager(aManager)
|
||||
, mSD(aSD)
|
||||
, mSize(aSize)
|
||||
{}
|
||||
|
||||
GPUVideoTextureData::~GPUVideoTextureData()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
GPUVideoTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
aOutDescriptor = mSD;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GPUVideoTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = mSize;
|
||||
// TODO: We should probably try do better for this.
|
||||
// layers::Image doesn't expose a format, so it's hard
|
||||
// to figure out in VideoDecoderParent.
|
||||
aInfo.format = SurfaceFormat::B8G8R8X8;
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
aInfo.supportsMoz2D = false;
|
||||
aInfo.canExposeMappedData = false;
|
||||
}
|
||||
|
||||
already_AddRefed<SourceSurface>
|
||||
GPUVideoTextureData::GetAsSourceSurface()
|
||||
{
|
||||
return mManager->Readback(mSD);
|
||||
}
|
||||
|
||||
void
|
||||
GPUVideoTextureData::Deallocate(LayersIPCChannel* aAllocator)
|
||||
{
|
||||
mManager->DeallocateSurfaceDescriptorGPUVideo(mSD);
|
||||
mSD = SurfaceDescriptorGPUVideo();
|
||||
}
|
||||
|
||||
void
|
||||
GPUVideoTextureData::Forget(LayersIPCChannel* aAllocator)
|
||||
{
|
||||
// We always need to manually deallocate on the client side.
|
||||
// Ideally we'd set up our TextureClient with the DEALLOCATE_CLIENT
|
||||
// flag, but that forces texture destruction to be synchronous.
|
||||
// Instead let's just deallocate from here as well.
|
||||
Deallocate(aAllocator);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
56
gfx/layers/client/GPUVideoTextureClient.h
Normal file
56
gfx/layers/client/GPUVideoTextureClient.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_GPUVIDEOTEXTURECLIENT_H
|
||||
#define MOZILLA_GFX_GPUVIDEOTEXTURECLIENT_H
|
||||
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class SourceSurface;
|
||||
}
|
||||
namespace dom {
|
||||
class VideoDecoderManagerChild;
|
||||
}
|
||||
namespace layers {
|
||||
|
||||
class GPUVideoTextureData : public TextureData
|
||||
{
|
||||
public:
|
||||
GPUVideoTextureData(dom::VideoDecoderManagerChild* aManager,
|
||||
const SurfaceDescriptorGPUVideo& aSD,
|
||||
const gfx::IntSize& aSize);
|
||||
~GPUVideoTextureData();
|
||||
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual bool Lock(OpenMode) override { return true; };
|
||||
|
||||
virtual void Unlock() override {};
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
virtual void Deallocate(LayersIPCChannel* aAllocator) override;
|
||||
|
||||
virtual void Forget(LayersIPCChannel* aAllocator) override;
|
||||
|
||||
already_AddRefed<gfx::SourceSurface> GetAsSourceSurface();
|
||||
|
||||
virtual GPUVideoTextureData* AsGPUVideoTextureData() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
protected:
|
||||
RefPtr<dom::VideoDecoderManagerChild> mManager;
|
||||
SurfaceDescriptorGPUVideo mSD;
|
||||
gfx::IntSize mSize;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_GFX_GPUVIDEOTEXTURECLIENT_H
|
||||
300
gfx/layers/client/ImageClient.cpp
Normal file
300
gfx/layers/client/ImageClient.cpp
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "ImageClient.h"
|
||||
|
||||
#include <stdint.h> // for uint32_t
|
||||
|
||||
#include "ClientLayerManager.h" // for ClientLayer
|
||||
#include "ImageContainer.h" // for Image, PlanarYCbCrImage, etc
|
||||
#include "ImageTypes.h" // for ImageFormat::PLANAR_YCBCR, etc
|
||||
#include "GLImages.h" // for SurfaceTextureImage::Data, etc
|
||||
#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat, etc
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
|
||||
#include "mozilla/layers/TextureClientOGL.h" // for SurfaceTextureClient
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for Image::Release, etc
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
/* static */ already_AddRefed<ImageClient>
|
||||
ImageClient::CreateImageClient(CompositableType aCompositableHostType,
|
||||
CompositableForwarder* aForwarder,
|
||||
TextureFlags aFlags)
|
||||
{
|
||||
RefPtr<ImageClient> result = nullptr;
|
||||
switch (aCompositableHostType) {
|
||||
case CompositableType::IMAGE:
|
||||
result = new ImageClientSingle(aForwarder, aFlags, CompositableType::IMAGE);
|
||||
break;
|
||||
case CompositableType::IMAGE_BRIDGE:
|
||||
result = new ImageClientBridge(aForwarder, aFlags);
|
||||
break;
|
||||
case CompositableType::UNKNOWN:
|
||||
result = nullptr;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("GFX: unhandled program type image");
|
||||
}
|
||||
|
||||
NS_ASSERTION(result, "Failed to create ImageClient");
|
||||
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void
|
||||
ImageClient::RemoveTexture(TextureClient* aTexture)
|
||||
{
|
||||
GetForwarder()->RemoveTextureFromCompositable(this, aTexture);
|
||||
}
|
||||
|
||||
ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags,
|
||||
CompositableType aType)
|
||||
: ImageClient(aFwd, aFlags, aType)
|
||||
{
|
||||
}
|
||||
|
||||
TextureInfo ImageClientSingle::GetTextureInfo() const
|
||||
{
|
||||
return TextureInfo(CompositableType::IMAGE);
|
||||
}
|
||||
|
||||
void
|
||||
ImageClientSingle::FlushAllImages()
|
||||
{
|
||||
MOZ_ASSERT(GetForwarder()->GetTextureForwarder()->UsesImageBridge());
|
||||
|
||||
for (auto& b : mBuffers) {
|
||||
RemoveTexture(b.mTextureClient);
|
||||
}
|
||||
mBuffers.Clear();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<TextureClient>
|
||||
ImageClient::CreateTextureClientForImage(Image* aImage, KnowsCompositor* aForwarder)
|
||||
{
|
||||
RefPtr<TextureClient> texture;
|
||||
if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage);
|
||||
const PlanarYCbCrData* data = ycbcr->GetData();
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
texture = TextureClient::CreateForYCbCr(aForwarder,
|
||||
data->mYSize, data->mCbCrSize, data->mStereoMode,
|
||||
data->mYUVColorSpace,
|
||||
TextureFlags::DEFAULT);
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
|
||||
if (!autoLock.Succeeded()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool status = UpdateYCbCrTextureClient(texture, *data);
|
||||
MOZ_ASSERT(status);
|
||||
if (!status) {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
|
||||
aImage->GetFormat() == ImageFormat::EGLIMAGE) {
|
||||
gfx::IntSize size = aImage->GetSize();
|
||||
|
||||
if (aImage->GetFormat() == ImageFormat::EGLIMAGE) {
|
||||
EGLImageImage* typedImage = aImage->AsEGLImageImage();
|
||||
texture = EGLImageTextureData::CreateTextureClient(
|
||||
typedImage, size, aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT);
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
} else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
|
||||
SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage();
|
||||
texture = AndroidSurfaceTextureData::CreateTextureClient(
|
||||
typedImage->GetSurfaceTexture(), size, typedImage->GetOriginPos(),
|
||||
aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT);
|
||||
#endif
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Bad ImageFormat.");
|
||||
}
|
||||
} else {
|
||||
RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface();
|
||||
MOZ_ASSERT(surface);
|
||||
texture = TextureClient::CreateForDrawing(aForwarder, surface->GetFormat(), aImage->GetSize(),
|
||||
BackendSelector::Content, TextureFlags::DEFAULT);
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(texture->CanExposeDrawTarget());
|
||||
|
||||
if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
// We must not keep a reference to the DrawTarget after it has been unlocked.
|
||||
DrawTarget* dt = texture->BorrowDrawTarget();
|
||||
if (!dt) {
|
||||
gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(surface.get());
|
||||
dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
|
||||
}
|
||||
|
||||
texture->Unlock();
|
||||
}
|
||||
return texture.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
|
||||
{
|
||||
AutoTArray<ImageContainer::OwningImage,4> images;
|
||||
uint32_t generationCounter;
|
||||
aContainer->GetCurrentImages(&images, &generationCounter);
|
||||
|
||||
if (mLastUpdateGenerationCounter == generationCounter) {
|
||||
return true;
|
||||
}
|
||||
mLastUpdateGenerationCounter = generationCounter;
|
||||
|
||||
for (int32_t i = images.Length() - 1; i >= 0; --i) {
|
||||
if (!images[i].mImage->IsValid()) {
|
||||
// Don't try to update to an invalid image.
|
||||
images.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
if (images.IsEmpty()) {
|
||||
// This can happen if a ClearAllImages raced with SetCurrentImages from
|
||||
// another thread and ClearImagesFromImageBridge ran after the
|
||||
// SetCurrentImages call but before UpdateImageClientNow.
|
||||
// This can also happen if all images in the list are invalid.
|
||||
// We return true because the caller would attempt to recreate the
|
||||
// ImageClient otherwise, and that isn't going to help.
|
||||
return true;
|
||||
}
|
||||
|
||||
nsTArray<Buffer> newBuffers;
|
||||
AutoTArray<CompositableForwarder::TimedTextureClient,4> textures;
|
||||
|
||||
for (auto& img : images) {
|
||||
Image* image = img.mImage;
|
||||
|
||||
RefPtr<TextureClient> texture = image->GetTextureClient(GetForwarder());
|
||||
const bool hasTextureClient = !!texture;
|
||||
|
||||
for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) {
|
||||
if (mBuffers[i].mImageSerial == image->GetSerial()) {
|
||||
if (hasTextureClient) {
|
||||
MOZ_ASSERT(image->GetTextureClient(GetForwarder()) == mBuffers[i].mTextureClient);
|
||||
} else {
|
||||
texture = mBuffers[i].mTextureClient;
|
||||
}
|
||||
// Remove this element from mBuffers so mBuffers only contains
|
||||
// images that aren't present in 'images'
|
||||
mBuffers.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!texture) {
|
||||
// Slow path, we should not be hitting it very often and if we do it means
|
||||
// we are using an Image class that is not backed by textureClient and we
|
||||
// should fix it.
|
||||
texture = CreateTextureClientForImage(image, GetForwarder());
|
||||
}
|
||||
if (!texture || !AddTextureClient(texture)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = texture;
|
||||
t->mTimeStamp = img.mTimeStamp;
|
||||
t->mPictureRect = image->GetPictureRect();
|
||||
t->mFrameID = img.mFrameID;
|
||||
t->mProducerID = img.mProducerID;
|
||||
|
||||
Buffer* newBuf = newBuffers.AppendElement();
|
||||
newBuf->mImageSerial = image->GetSerial();
|
||||
newBuf->mTextureClient = texture;
|
||||
|
||||
texture->SyncWithObject(GetForwarder()->GetSyncObject());
|
||||
}
|
||||
|
||||
GetForwarder()->UseTextures(this, textures);
|
||||
|
||||
for (auto& b : mBuffers) {
|
||||
RemoveTexture(b.mTextureClient);
|
||||
}
|
||||
mBuffers.SwapElements(newBuffers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ImageClientSingle::AddTextureClient(TextureClient* aTexture)
|
||||
{
|
||||
MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
|
||||
return CompositableClient::AddTextureClient(aTexture);
|
||||
}
|
||||
|
||||
void
|
||||
ImageClientSingle::OnDetach()
|
||||
{
|
||||
mBuffers.Clear();
|
||||
}
|
||||
|
||||
ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
|
||||
CompositableType aType)
|
||||
: CompositableClient(aFwd, aFlags)
|
||||
, mLayer(nullptr)
|
||||
, mType(aType)
|
||||
, mLastUpdateGenerationCounter(0)
|
||||
{}
|
||||
|
||||
ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags)
|
||||
: ImageClient(aFwd, aFlags, CompositableType::IMAGE_BRIDGE)
|
||||
, mAsyncContainerID(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
|
||||
{
|
||||
if (!GetForwarder() || !mLayer) {
|
||||
return false;
|
||||
}
|
||||
if (mAsyncContainerID == aContainer->GetAsyncContainerID()) {
|
||||
return true;
|
||||
}
|
||||
mAsyncContainerID = aContainer->GetAsyncContainerID();
|
||||
static_cast<ShadowLayerForwarder*>(GetForwarder())->AttachAsyncCompositable(mAsyncContainerID, mLayer);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
138
gfx/layers/client/ImageClient.h
Normal file
138
gfx/layers/client/ImageClient.h
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_IMAGECLIENT_H
|
||||
#define MOZILLA_GFX_IMAGECLIENT_H
|
||||
|
||||
#include <stdint.h> // for uint32_t, uint64_t
|
||||
#include <sys/types.h> // for int32_t
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
|
||||
#include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ClientLayer;
|
||||
class CompositableForwarder;
|
||||
class Image;
|
||||
class ImageContainer;
|
||||
class ShadowableLayer;
|
||||
class ImageClientSingle;
|
||||
|
||||
/**
|
||||
* Image clients are used by basic image layers on the content thread, they
|
||||
* always match with an ImageHost on the compositor thread. See
|
||||
* CompositableClient.h for information on connecting clients to hosts.
|
||||
*/
|
||||
class ImageClient : public CompositableClient
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates, configures, and returns a new image client. If necessary, a
|
||||
* message will be sent to the compositor to create a corresponding image
|
||||
* host.
|
||||
*/
|
||||
static already_AddRefed<ImageClient> CreateImageClient(CompositableType aImageHostType,
|
||||
CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags);
|
||||
|
||||
virtual ~ImageClient() {}
|
||||
|
||||
/**
|
||||
* Update this ImageClient from aContainer in aLayer
|
||||
* returns false if this is the wrong kind of ImageClient for aContainer.
|
||||
* Note that returning true does not necessarily imply success
|
||||
*/
|
||||
virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) = 0;
|
||||
|
||||
void SetLayer(ClientLayer* aLayer) { mLayer = aLayer; }
|
||||
ClientLayer* GetLayer() const { return mLayer; }
|
||||
|
||||
/**
|
||||
* asynchronously remove all the textures used by the image client.
|
||||
*
|
||||
*/
|
||||
virtual void FlushAllImages() {}
|
||||
|
||||
virtual void RemoveTexture(TextureClient* aTexture) override;
|
||||
|
||||
virtual ImageClientSingle* AsImageClientSingle() { return nullptr; }
|
||||
|
||||
static already_AddRefed<TextureClient> CreateTextureClientForImage(Image* aImage, KnowsCompositor* aForwarder);
|
||||
|
||||
protected:
|
||||
ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
|
||||
CompositableType aType);
|
||||
|
||||
ClientLayer* mLayer;
|
||||
CompositableType mType;
|
||||
uint32_t mLastUpdateGenerationCounter;
|
||||
};
|
||||
|
||||
/**
|
||||
* An image client which uses a single texture client.
|
||||
*/
|
||||
class ImageClientSingle : public ImageClient
|
||||
{
|
||||
public:
|
||||
ImageClientSingle(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags,
|
||||
CompositableType aType);
|
||||
|
||||
virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) override;
|
||||
|
||||
virtual void OnDetach() override;
|
||||
|
||||
virtual bool AddTextureClient(TextureClient* aTexture) override;
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const override;
|
||||
|
||||
virtual void FlushAllImages() override;
|
||||
|
||||
ImageClientSingle* AsImageClientSingle() override { return this; }
|
||||
|
||||
protected:
|
||||
struct Buffer {
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
int32_t mImageSerial;
|
||||
};
|
||||
nsTArray<Buffer> mBuffers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Image class to be used for async image uploads using the image bridge
|
||||
* protocol.
|
||||
* We store the ImageBridge id in the TextureClientIdentifier.
|
||||
*/
|
||||
class ImageClientBridge : public ImageClient
|
||||
{
|
||||
public:
|
||||
ImageClientBridge(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags);
|
||||
|
||||
virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) override;
|
||||
virtual bool Connect(ImageContainer* aImageContainer) override { return false; }
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const override
|
||||
{
|
||||
return TextureInfo(mType);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t mAsyncContainerID;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
263
gfx/layers/client/SingleTiledContentClient.cpp
Normal file
263
gfx/layers/client/SingleTiledContentClient.cpp
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "mozilla/layers/SingleTiledContentClient.h"
|
||||
|
||||
#include "ClientTiledPaintedLayer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
|
||||
SingleTiledContentClient::SingleTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer,
|
||||
ClientLayerManager* aManager)
|
||||
: TiledContentClient(aManager, "Single")
|
||||
{
|
||||
MOZ_COUNT_CTOR(SingleTiledContentClient);
|
||||
|
||||
mTiledBuffer = new ClientSingleTiledLayerBuffer(aPaintedLayer, *this, aManager);
|
||||
}
|
||||
|
||||
void
|
||||
SingleTiledContentClient::ClearCachedResources()
|
||||
{
|
||||
CompositableClient::ClearCachedResources();
|
||||
mTiledBuffer->DiscardBuffers();
|
||||
}
|
||||
|
||||
void
|
||||
SingleTiledContentClient::UpdatedBuffer(TiledBufferType aType)
|
||||
{
|
||||
mForwarder->UseTiledLayerBuffer(this, mTiledBuffer->GetSurfaceDescriptorTiles());
|
||||
mTiledBuffer->ClearPaintedRegion();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
SingleTiledContentClient::ClientSupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager)
|
||||
{
|
||||
int32_t maxTextureSize = aManager->GetMaxTextureSize();
|
||||
return aSize.width <= maxTextureSize && aSize.height <= maxTextureSize;
|
||||
}
|
||||
|
||||
ClientSingleTiledLayerBuffer::ClientSingleTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer,
|
||||
CompositableClient& aCompositableClient,
|
||||
ClientLayerManager* aManager)
|
||||
: ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient)
|
||||
, mWasLastPaintProgressive(false)
|
||||
, mFormat(gfx::SurfaceFormat::UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ClientSingleTiledLayerBuffer::ReleaseTiles()
|
||||
{
|
||||
if (!mTile.IsPlaceholderTile()) {
|
||||
mTile.DiscardBuffers();
|
||||
}
|
||||
mTile.SetTextureAllocator(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
ClientSingleTiledLayerBuffer::DiscardBuffers()
|
||||
{
|
||||
if (!mTile.IsPlaceholderTile()) {
|
||||
mTile.DiscardFrontBuffer();
|
||||
mTile.DiscardBackBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceDescriptorTiles
|
||||
ClientSingleTiledLayerBuffer::GetSurfaceDescriptorTiles()
|
||||
{
|
||||
InfallibleTArray<TileDescriptor> tiles;
|
||||
|
||||
TileDescriptor tileDesc = mTile.GetTileDescriptor();
|
||||
tiles.AppendElement(tileDesc);
|
||||
mTile.mUpdateRect = gfx::IntRect();
|
||||
|
||||
return SurfaceDescriptorTiles(mValidRegion,
|
||||
tiles,
|
||||
mTilingOrigin,
|
||||
mSize,
|
||||
0, 0, 1, 1,
|
||||
1.0,
|
||||
mFrameResolution.xScale,
|
||||
mFrameResolution.yScale,
|
||||
mWasLastPaintProgressive);
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
ClientSingleTiledLayerBuffer::GetTextureClient()
|
||||
{
|
||||
MOZ_ASSERT(mFormat != gfx::SurfaceFormat::UNKNOWN);
|
||||
return mCompositableClient.CreateTextureClientForDrawing(
|
||||
gfx::ImageFormatToSurfaceFormat(mFormat), mSize, BackendSelector::Content,
|
||||
TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD);
|
||||
}
|
||||
|
||||
void
|
||||
ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
const nsIntRegion& aDirtyRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
bool aIsProgressive)
|
||||
{
|
||||
mWasLastPaintProgressive = aIsProgressive;
|
||||
|
||||
// Compare layer valid region size to current backbuffer size, discard if not matching.
|
||||
gfx::IntSize size = aNewValidRegion.GetBounds().Size();
|
||||
gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft();
|
||||
nsIntRegion paintRegion = aPaintRegion;
|
||||
|
||||
RefPtr<TextureClient> discardedFrontBuffer = nullptr;
|
||||
RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr;
|
||||
nsIntRegion discardedValidRegion;
|
||||
|
||||
if (mSize != size ||
|
||||
mTilingOrigin != origin) {
|
||||
discardedFrontBuffer = mTile.mFrontBuffer;
|
||||
discardedFrontBufferOnWhite = mTile.mFrontBufferOnWhite;
|
||||
discardedValidRegion = mValidRegion;
|
||||
|
||||
TILING_LOG("TILING %p: Single-tile valid region changed. Discarding buffers.\n", &mPaintedLayer)
|
||||
;
|
||||
ResetPaintedAndValidState();
|
||||
mSize = size;
|
||||
mTilingOrigin = origin;
|
||||
paintRegion = aNewValidRegion;
|
||||
}
|
||||
|
||||
SurfaceMode mode;
|
||||
gfxContentType content = GetContentType(&mode);
|
||||
mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content);
|
||||
|
||||
if (mTile.IsPlaceholderTile()) {
|
||||
mTile.SetTextureAllocator(this);
|
||||
}
|
||||
|
||||
// The dirty region relative to the top-left of the tile.
|
||||
nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin);
|
||||
|
||||
nsIntRegion extraPainted;
|
||||
RefPtr<TextureClient> backBufferOnWhite;
|
||||
RefPtr<TextureClient> backBuffer =
|
||||
mTile.GetBackBuffer(mCompositableClient,
|
||||
tileDirtyRegion,
|
||||
content, mode,
|
||||
extraPainted,
|
||||
&backBufferOnWhite);
|
||||
|
||||
mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
|
||||
|
||||
extraPainted.MoveBy(mTilingOrigin);
|
||||
extraPainted.And(extraPainted, aNewValidRegion);
|
||||
mPaintedRegion.OrWith(paintRegion);
|
||||
mPaintedRegion.OrWith(extraPainted);
|
||||
|
||||
if (!backBuffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DrawTarget> dt = backBuffer->BorrowDrawTarget();
|
||||
RefPtr<gfx::DrawTarget> dtOnWhite;
|
||||
if (backBufferOnWhite) {
|
||||
dtOnWhite = backBufferOnWhite->BorrowDrawTarget();
|
||||
}
|
||||
|
||||
if (mode != SurfaceMode::SURFACE_OPAQUE) {
|
||||
for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const gfx::IntRect& rect = iter.Get();
|
||||
if (dtOnWhite) {
|
||||
dt->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height),
|
||||
gfx::ColorPattern(gfx::Color(0.0, 0.0, 0.0, 1.0)));
|
||||
dtOnWhite->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height),
|
||||
gfx::ColorPattern(gfx::Color(1.0, 1.0, 1.0, 1.0)));
|
||||
} else {
|
||||
dt->ClearRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the old frontbuffer was discarded then attempt to copy what we
|
||||
// can from it to the new backbuffer.
|
||||
if (discardedFrontBuffer) {
|
||||
nsIntRegion copyableRegion;
|
||||
copyableRegion.And(aNewValidRegion, discardedValidRegion);
|
||||
copyableRegion.SubOut(aDirtyRegion);
|
||||
|
||||
if (!copyableRegion.IsEmpty()) {
|
||||
TextureClientAutoLock frontLock(discardedFrontBuffer,
|
||||
OpenMode::OPEN_READ);
|
||||
if (frontLock.Succeeded()) {
|
||||
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
|
||||
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
|
||||
discardedFrontBuffer->CopyToTextureClient(backBuffer, &rect, &dest);
|
||||
}
|
||||
}
|
||||
|
||||
if (discardedFrontBufferOnWhite && backBufferOnWhite) {
|
||||
TextureClientAutoLock frontOnWhiteLock(discardedFrontBufferOnWhite,
|
||||
OpenMode::OPEN_READ);
|
||||
if (frontOnWhiteLock.Succeeded()) {
|
||||
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
|
||||
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
|
||||
|
||||
discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite,
|
||||
&rect, &dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
|
||||
|
||||
// We don't need to repaint valid content that was just copied.
|
||||
paintRegion.SubOut(copyableRegion);
|
||||
}
|
||||
}
|
||||
|
||||
if (dtOnWhite) {
|
||||
dt = gfx::Factory::CreateDualDrawTarget(dt, dtOnWhite);
|
||||
dtOnWhite = nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
|
||||
if (!ctx) {
|
||||
gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(dt);
|
||||
return;
|
||||
}
|
||||
ctx->SetMatrix(ctx->CurrentMatrix().Translate(-mTilingOrigin.x, -mTilingOrigin.y));
|
||||
|
||||
aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
|
||||
}
|
||||
|
||||
// Mark the area we just drew into the back buffer as invalid in the front buffer as they're
|
||||
// now out of sync.
|
||||
mTile.mInvalidFront.OrWith(tileDirtyRegion);
|
||||
|
||||
// The new buffer is now validated, remove the dirty region from it.
|
||||
mTile.mInvalidBack.SubOut(tileDirtyRegion);
|
||||
|
||||
dt = nullptr;
|
||||
|
||||
mTile.Flip();
|
||||
UnlockTile(mTile);
|
||||
|
||||
if (backBuffer->HasIntermediateBuffer()) {
|
||||
// If our new buffer has an internal buffer, we don't want to keep another
|
||||
// TextureClient around unnecessarily, so discard the back-buffer.
|
||||
mTile.DiscardBackBuffer();
|
||||
}
|
||||
|
||||
mValidRegion = aNewValidRegion;
|
||||
mLastPaintSurfaceMode = mode;
|
||||
mLastPaintContentType = content;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
135
gfx/layers/client/SingleTiledContentClient.h
Normal file
135
gfx/layers/client/SingleTiledContentClient.h
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_SINGLETILEDCONTENTCLIENT_H
|
||||
#define MOZILLA_GFX_SINGLETILEDCONTENTCLIENT_H
|
||||
|
||||
#include "TiledContentClient.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ClientTiledPaintedLayer;
|
||||
class ClientLayerManager;
|
||||
|
||||
/**
|
||||
* Provide an instance of TiledLayerBuffer backed by drawable TextureClients.
|
||||
* This buffer provides an implementation of ValidateTile using a
|
||||
* thebes callback and can support painting using a single paint buffer.
|
||||
* Whether a single paint buffer is used is controlled by
|
||||
* gfxPrefs::PerTileDrawing().
|
||||
*/
|
||||
class ClientSingleTiledLayerBuffer
|
||||
: public ClientTiledLayerBuffer
|
||||
, public TextureClientAllocator
|
||||
{
|
||||
virtual ~ClientSingleTiledLayerBuffer() {}
|
||||
public:
|
||||
ClientSingleTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer,
|
||||
CompositableClient& aCompositableClient,
|
||||
ClientLayerManager* aManager);
|
||||
|
||||
// TextureClientAllocator
|
||||
already_AddRefed<TextureClient> GetTextureClient() override;
|
||||
void ReturnTextureClientDeferred(TextureClient* aClient) override {}
|
||||
void ReportClientLost() override {}
|
||||
|
||||
// ClientTiledLayerBuffer
|
||||
void PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
const nsIntRegion& aDirtyRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
bool aIsProgressive = false) override;
|
||||
|
||||
bool SupportsProgressiveUpdate() override { return false; }
|
||||
bool ProgressiveUpdate(nsIntRegion& aValidRegion,
|
||||
nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aOldValidRegion,
|
||||
BasicTiledLayerPaintData* aPaintData,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData) override
|
||||
{
|
||||
MOZ_ASSERT(false, "ProgressiveUpdate not supported!");
|
||||
return false;
|
||||
}
|
||||
|
||||
void ResetPaintedAndValidState() override {
|
||||
mPaintedRegion.SetEmpty();
|
||||
mValidRegion.SetEmpty();
|
||||
mTile.DiscardBuffers();
|
||||
}
|
||||
|
||||
const nsIntRegion& GetValidRegion() override {
|
||||
return mValidRegion;
|
||||
}
|
||||
|
||||
bool IsLowPrecision() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReleaseTiles();
|
||||
|
||||
void DiscardBuffers();
|
||||
|
||||
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
|
||||
|
||||
void ClearPaintedRegion() {
|
||||
mPaintedRegion.SetEmpty();
|
||||
}
|
||||
|
||||
private:
|
||||
TileClient mTile;
|
||||
|
||||
nsIntRegion mPaintedRegion;
|
||||
nsIntRegion mValidRegion;
|
||||
bool mWasLastPaintProgressive;
|
||||
|
||||
/**
|
||||
* While we're adding tiles, this is used to keep track of the position of
|
||||
* the top-left of the top-left-most tile. When we come to wrap the tiles in
|
||||
* TiledDrawTarget we subtract the value of this member from each tile's
|
||||
* offset so that all the tiles have a positive offset, then add a
|
||||
* translation to the TiledDrawTarget to compensate. This is important so
|
||||
* that the mRect of the TiledDrawTarget is always at a positive x/y
|
||||
* position, otherwise its GetSize() methods will be broken.
|
||||
*/
|
||||
gfx::IntPoint mTilingOrigin;
|
||||
gfx::IntSize mSize;
|
||||
gfxImageFormat mFormat;
|
||||
};
|
||||
|
||||
class SingleTiledContentClient : public TiledContentClient
|
||||
{
|
||||
public:
|
||||
SingleTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer,
|
||||
ClientLayerManager* aManager);
|
||||
|
||||
protected:
|
||||
~SingleTiledContentClient()
|
||||
{
|
||||
MOZ_COUNT_DTOR(SingleTiledContentClient);
|
||||
|
||||
mTiledBuffer->ReleaseTiles();
|
||||
}
|
||||
|
||||
public:
|
||||
static bool ClientSupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager);
|
||||
|
||||
virtual void ClearCachedResources() override;
|
||||
|
||||
virtual void UpdatedBuffer(TiledBufferType aType) override;
|
||||
|
||||
virtual ClientTiledLayerBuffer* GetTiledBuffer() override { return mTiledBuffer; }
|
||||
virtual ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() override { return nullptr; }
|
||||
|
||||
private:
|
||||
RefPtr<ClientSingleTiledLayerBuffer> mTiledBuffer;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
1707
gfx/layers/client/TextureClient.cpp
Normal file
1707
gfx/layers/client/TextureClient.cpp
Normal file
File diff suppressed because it is too large
Load diff
826
gfx/layers/client/TextureClient.h
Normal file
826
gfx/layers/client/TextureClient.h
Normal file
|
|
@ -0,0 +1,826 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_TEXTURECLIENT_H
|
||||
#define MOZILLA_GFX_TEXTURECLIENT_H
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint32_t, uint8_t, uint64_t
|
||||
#include "GLTextureImage.h" // for TextureImage
|
||||
#include "ImageTypes.h" // for StereoMode
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/RefPtr.h" // for RefPtr, RefCounted
|
||||
#include "mozilla/gfx/2D.h" // for DrawTarget
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat
|
||||
#include "mozilla/ipc/Shmem.h" // for Shmem
|
||||
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
|
||||
#include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "mozilla/gfx/CriticalSection.h"
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsISupportsImpl.h" // for TextureImage::AddRef, etc
|
||||
#include "GfxTexturesReporter.h"
|
||||
#include "pratom.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class gfxImageSurface;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// When defined, we track which pool the tile came from and test for
|
||||
// any inconsistencies. This can be defined in release build as well.
|
||||
#ifdef DEBUG
|
||||
#define GFX_DEBUG_TRACK_CLIENTS_IN_POOL 1
|
||||
#endif
|
||||
|
||||
namespace layers {
|
||||
|
||||
class AsyncTransactionWaiter;
|
||||
class BufferTextureData;
|
||||
class CompositableForwarder;
|
||||
class KnowsCompositor;
|
||||
class LayersIPCChannel;
|
||||
class CompositableClient;
|
||||
struct PlanarYCbCrData;
|
||||
class Image;
|
||||
class PTextureChild;
|
||||
class TextureChild;
|
||||
class TextureData;
|
||||
class GPUVideoTextureData;
|
||||
struct RawTextureBuffer;
|
||||
class RawYCbCrTextureBuffer;
|
||||
class TextureClient;
|
||||
class ITextureClientRecycleAllocator;
|
||||
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
|
||||
class TextureClientPool;
|
||||
#endif
|
||||
class TextureForwarder;
|
||||
class KeepAlive;
|
||||
|
||||
/**
|
||||
* TextureClient is the abstraction that allows us to share data between the
|
||||
* content and the compositor side.
|
||||
*/
|
||||
|
||||
enum TextureAllocationFlags {
|
||||
ALLOC_DEFAULT = 0,
|
||||
ALLOC_CLEAR_BUFFER = 1 << 1, // Clear the buffer to whatever is best for the draw target
|
||||
ALLOC_CLEAR_BUFFER_WHITE = 1 << 2, // explicit all white
|
||||
ALLOC_CLEAR_BUFFER_BLACK = 1 << 3, // explicit all black
|
||||
ALLOC_DISALLOW_BUFFERTEXTURECLIENT = 1 << 4,
|
||||
|
||||
// Allocate the texture for out-of-band content updates. This is mostly for
|
||||
// TextureClientD3D11, which may otherwise choose D3D10 or non-KeyedMutex
|
||||
// surfaces when used on the main thread.
|
||||
ALLOC_FOR_OUT_OF_BAND_CONTENT = 1 << 5,
|
||||
|
||||
// Disable any cross-device synchronization. This is also for TextureClientD3D11,
|
||||
// and creates a texture without KeyedMutex.
|
||||
ALLOC_MANUAL_SYNCHRONIZATION = 1 << 6,
|
||||
|
||||
// The texture is going to be updated using UpdateFromSurface and needs to support
|
||||
// that call.
|
||||
ALLOC_UPDATE_FROM_SURFACE = 1 << 7,
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
typedef void* SyncHandle;
|
||||
#else
|
||||
typedef uintptr_t SyncHandle;
|
||||
#endif // XP_WIN
|
||||
|
||||
class SyncObject : public RefCounted<SyncObject>
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SyncObject)
|
||||
virtual ~SyncObject() { }
|
||||
|
||||
static already_AddRefed<SyncObject> CreateSyncObject(SyncHandle aHandle);
|
||||
|
||||
enum class SyncType {
|
||||
D3D11,
|
||||
};
|
||||
|
||||
virtual SyncType GetSyncType() = 0;
|
||||
virtual void FinalizeFrame() = 0;
|
||||
virtual bool IsSyncObjectValid() = 0;
|
||||
|
||||
protected:
|
||||
SyncObject() { }
|
||||
};
|
||||
|
||||
/**
|
||||
* This class may be used to asynchronously receive an update when the content
|
||||
* drawn to this texture client is available for reading in CPU memory. This
|
||||
* can only be used on texture clients that support draw target creation.
|
||||
*/
|
||||
class TextureReadbackSink
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureReadbackSink)
|
||||
public:
|
||||
/**
|
||||
* Callback function to implement in order to receive a DataSourceSurface
|
||||
* containing the data read back from the texture client. This will always
|
||||
* be called on the main thread, and this may not hold on to the
|
||||
* DataSourceSurface beyond the execution of this function.
|
||||
*/
|
||||
virtual void ProcessReadback(gfx::DataSourceSurface *aSourceSurface) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~TextureReadbackSink() {}
|
||||
};
|
||||
|
||||
enum class BackendSelector
|
||||
{
|
||||
Content,
|
||||
Canvas
|
||||
};
|
||||
|
||||
/// Temporary object providing direct access to a Texture's memory.
|
||||
///
|
||||
/// see TextureClient::CanExposeMappedData() and TextureClient::BorrowMappedData().
|
||||
struct MappedTextureData
|
||||
{
|
||||
uint8_t* data;
|
||||
gfx::IntSize size;
|
||||
int32_t stride;
|
||||
gfx::SurfaceFormat format;
|
||||
};
|
||||
|
||||
struct MappedYCbCrChannelData
|
||||
{
|
||||
uint8_t* data;
|
||||
gfx::IntSize size;
|
||||
int32_t stride;
|
||||
int32_t skip;
|
||||
|
||||
bool CopyInto(MappedYCbCrChannelData& aDst);
|
||||
};
|
||||
|
||||
struct MappedYCbCrTextureData {
|
||||
MappedYCbCrChannelData y;
|
||||
MappedYCbCrChannelData cb;
|
||||
MappedYCbCrChannelData cr;
|
||||
// Sad but because of how SharedPlanarYCbCrData is used we have to expose this for now.
|
||||
uint8_t* metadata;
|
||||
StereoMode stereoMode;
|
||||
|
||||
bool CopyInto(MappedYCbCrTextureData& aDst)
|
||||
{
|
||||
return y.CopyInto(aDst.y)
|
||||
&& cb.CopyInto(aDst.cb)
|
||||
&& cr.CopyInto(aDst.cr);
|
||||
}
|
||||
};
|
||||
|
||||
class ReadLockDescriptor;
|
||||
|
||||
// A class to help implement copy-on-write semantics for shared textures.
|
||||
//
|
||||
// A TextureClient/Host pair can opt into using a ReadLock by calling
|
||||
// TextureClient::EnableReadLock. This will equip the TextureClient with a
|
||||
// ReadLock object that will be automatically ReadLock()'ed by the texture itself
|
||||
// when it is written into (see TextureClient::Unlock).
|
||||
// A TextureReadLock's counter starts at 1 and is expected to be equal to 1 when the
|
||||
// lock is destroyed. See ShmemTextureReadLock for explanations about why we use
|
||||
// 1 instead of 0 as the initial state.
|
||||
// TextureReadLock is mostly internally managed by the TextureClient/Host pair,
|
||||
// and the compositable only has to forward it during updates. If an update message
|
||||
// contains a null_t lock, it means that the texture was not written into on the
|
||||
// content side, and there is no synchronization required on the compositor side
|
||||
// (or it means that the texture pair did not opt into using ReadLocks).
|
||||
// On the compositor side, the TextureHost can receive a ReadLock during a
|
||||
// transaction, and will both ReadUnlock() it and drop it as soon as the shared
|
||||
// data is available again for writing (the texture upload is done, or the compositor
|
||||
// not reading the texture anymore). The lock is dropped to make sure it is
|
||||
// ReadUnlock()'ed only once.
|
||||
class TextureReadLock {
|
||||
protected:
|
||||
virtual ~TextureReadLock() {}
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureReadLock)
|
||||
|
||||
virtual int32_t ReadLock() = 0;
|
||||
virtual int32_t ReadUnlock() = 0;
|
||||
virtual int32_t GetReadCount() = 0;
|
||||
virtual bool IsValid() const = 0;
|
||||
|
||||
static already_AddRefed<TextureReadLock>
|
||||
Create(LayersIPCChannel* aAllocator);
|
||||
|
||||
static already_AddRefed<TextureReadLock>
|
||||
Deserialize(const ReadLockDescriptor& aDescriptor, ISurfaceAllocator* aAllocator);
|
||||
|
||||
virtual bool Serialize(ReadLockDescriptor& aOutput) = 0;
|
||||
|
||||
enum LockType {
|
||||
TYPE_MEMORY,
|
||||
TYPE_SHMEM
|
||||
};
|
||||
virtual LockType GetType() = 0;
|
||||
|
||||
protected:
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
class D3D11TextureData;
|
||||
#endif
|
||||
|
||||
class TextureData {
|
||||
public:
|
||||
struct Info {
|
||||
gfx::IntSize size;
|
||||
gfx::SurfaceFormat format;
|
||||
bool hasIntermediateBuffer;
|
||||
bool hasSynchronization;
|
||||
bool supportsMoz2D;
|
||||
bool canExposeMappedData;
|
||||
|
||||
Info()
|
||||
: format(gfx::SurfaceFormat::UNKNOWN)
|
||||
, hasIntermediateBuffer(false)
|
||||
, hasSynchronization(false)
|
||||
, supportsMoz2D(false)
|
||||
, canExposeMappedData(false)
|
||||
{}
|
||||
};
|
||||
|
||||
TextureData() { MOZ_COUNT_CTOR(TextureData); }
|
||||
|
||||
virtual ~TextureData() { MOZ_COUNT_DTOR(TextureData); }
|
||||
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const = 0;
|
||||
|
||||
virtual bool Lock(OpenMode aMode) = 0;
|
||||
|
||||
virtual void Unlock() = 0;
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() { return nullptr; }
|
||||
|
||||
virtual bool BorrowMappedData(MappedTextureData&) { return false; }
|
||||
|
||||
virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; }
|
||||
|
||||
virtual void Deallocate(LayersIPCChannel* aAllocator) = 0;
|
||||
|
||||
/// Depending on the texture's flags either Deallocate or Forget is called.
|
||||
virtual void Forget(LayersIPCChannel* aAllocator) {}
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aDescriptor) = 0;
|
||||
|
||||
virtual TextureData*
|
||||
CreateSimilar(LayersIPCChannel* aAllocator,
|
||||
LayersBackend aLayersBackend,
|
||||
TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const { return nullptr; }
|
||||
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) { return false; };
|
||||
|
||||
virtual bool ReadBack(TextureReadbackSink* aReadbackSink) { return false; }
|
||||
|
||||
virtual void SyncWithObject(SyncObject* aFence) {};
|
||||
|
||||
virtual TextureFlags GetTextureFlags() const { return TextureFlags::NO_FLAGS; }
|
||||
|
||||
#ifdef XP_WIN
|
||||
virtual D3D11TextureData* AsD3D11TextureData() {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual BufferTextureData* AsBufferTextureData() { return nullptr; }
|
||||
|
||||
virtual GPUVideoTextureData* AsGPUVideoTextureData() { return nullptr; }
|
||||
};
|
||||
|
||||
/**
|
||||
* TextureClient is a thin abstraction over texture data that need to be shared
|
||||
* between the content process and the compositor process. It is the
|
||||
* content-side half of a TextureClient/TextureHost pair. A corresponding
|
||||
* TextureHost lives on the compositor-side.
|
||||
*
|
||||
* TextureClient's primary purpose is to present texture data in a way that is
|
||||
* understood by the IPC system. There are two ways to use it:
|
||||
* - Use it to serialize image data that is not IPC-friendly (most likely
|
||||
* involving a copy into shared memory)
|
||||
* - preallocate it and paint directly into it, which avoids copy but requires
|
||||
* the painting code to be aware of TextureClient (or at least the underlying
|
||||
* shared memory).
|
||||
*
|
||||
* There is always one and only one TextureClient per TextureHost, and the
|
||||
* TextureClient/Host pair only owns one buffer of image data through its
|
||||
* lifetime. This means that the lifetime of the underlying shared data
|
||||
* matches the lifetime of the TextureClient/Host pair. It also means
|
||||
* TextureClient/Host do not implement double buffering, which is the
|
||||
* responsibility of the compositable (which would use two Texture pairs).
|
||||
* In order to send several different buffers to the compositor side, use
|
||||
* several TextureClients.
|
||||
*/
|
||||
class TextureClient
|
||||
: public AtomicRefCountedWithFinalize<TextureClient>
|
||||
{
|
||||
public:
|
||||
explicit TextureClient(TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator);
|
||||
|
||||
virtual ~TextureClient();
|
||||
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateWithData(TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator);
|
||||
|
||||
// Creates and allocates a TextureClient usable with Moz2D.
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateForDrawing(KnowsCompositor* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags flags = ALLOC_DEFAULT);
|
||||
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateFromSurface(KnowsCompositor* aAllocator,
|
||||
gfx::SourceSurface* aSurface,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags);
|
||||
|
||||
// Creates and allocates a TextureClient supporting the YCbCr format.
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateForYCbCr(KnowsCompositor* aAllocator,
|
||||
gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode,
|
||||
YUVColorSpace aYUVColorSpace,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
// Creates and allocates a TextureClient (can be accessed through raw
|
||||
// pointers).
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateForRawBufferAccess(KnowsCompositor* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags flags = ALLOC_DEFAULT);
|
||||
|
||||
// Creates and allocates a TextureClient (can beaccessed through raw
|
||||
// pointers) with a certain buffer size. It's unfortunate that we need this.
|
||||
// providing format and sizes could let us do more optimization.
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateForYCbCrWithBufferSize(KnowsCompositor* aAllocator,
|
||||
size_t aSize,
|
||||
YUVColorSpace aYUVColorSpace,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
// Creates and allocates a TextureClient of the same type.
|
||||
already_AddRefed<TextureClient>
|
||||
CreateSimilar(LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE,
|
||||
TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const;
|
||||
|
||||
/**
|
||||
* Locks the shared data, allowing the caller to get access to it.
|
||||
*
|
||||
* Please always lock/unlock when accessing the shared data.
|
||||
* If Lock() returns false, you should not attempt to access the shared data.
|
||||
*/
|
||||
bool Lock(OpenMode aMode);
|
||||
|
||||
void Unlock();
|
||||
|
||||
bool IsLocked() const { return mIsLocked; }
|
||||
|
||||
gfx::IntSize GetSize() const { return mInfo.size; }
|
||||
|
||||
gfx::SurfaceFormat GetFormat() const { return mInfo.format; }
|
||||
|
||||
/**
|
||||
* Returns true if this texture has a synchronization mechanism (mutex, fence, etc.).
|
||||
* Textures that do not implement synchronization should be immutable or should
|
||||
* use immediate uploads (see TextureFlags in CompositorTypes.h)
|
||||
* Even if a texture does not implement synchronization, Lock and Unlock need
|
||||
* to be used appropriately since the latter are also there to map/numap data.
|
||||
*/
|
||||
bool HasSynchronization() const { return mInfo.hasSynchronization; }
|
||||
|
||||
/**
|
||||
* Indicates whether the TextureClient implementation is backed by an
|
||||
* in-memory buffer. The consequence of this is that locking the
|
||||
* TextureClient does not contend with locking the texture on the host side.
|
||||
*/
|
||||
bool HasIntermediateBuffer() const { return mInfo.hasIntermediateBuffer; }
|
||||
|
||||
bool CanExposeDrawTarget() const { return mInfo.supportsMoz2D; }
|
||||
|
||||
bool CanExposeMappedData() const { return mInfo.canExposeMappedData; }
|
||||
|
||||
/**
|
||||
* Returns a DrawTarget to draw into the TextureClient.
|
||||
* This function should never be called when not on the main thread!
|
||||
*
|
||||
* This must never be called on a TextureClient that is not sucessfully locked.
|
||||
* When called several times within one Lock/Unlock pair, this method should
|
||||
* return the same DrawTarget.
|
||||
* The DrawTarget is automatically flushed by the TextureClient when the latter
|
||||
* is unlocked, and the DrawTarget that will be returned within the next
|
||||
* lock/unlock pair may or may not be the same object.
|
||||
* Do not keep references to the DrawTarget outside of the lock/unlock pair.
|
||||
*
|
||||
* This is typically used as follows:
|
||||
*
|
||||
* if (!texture->Lock(OpenMode::OPEN_READ_WRITE)) {
|
||||
* return false;
|
||||
* }
|
||||
* {
|
||||
* // Restrict this code's scope to ensure all references to dt are gone
|
||||
* // when Unlock is called.
|
||||
* DrawTarget* dt = texture->BorrowDrawTarget();
|
||||
* // use the draw target ...
|
||||
* }
|
||||
* texture->Unlock();
|
||||
*
|
||||
*/
|
||||
gfx::DrawTarget* BorrowDrawTarget();
|
||||
|
||||
/**
|
||||
* Similar to BorrowDrawTarget but provides direct access to the texture's bits
|
||||
* instead of a DrawTarget.
|
||||
*/
|
||||
bool BorrowMappedData(MappedTextureData&);
|
||||
bool BorrowMappedYCbCrData(MappedYCbCrTextureData&);
|
||||
|
||||
/**
|
||||
* This function can be used to update the contents of the TextureClient
|
||||
* off the main thread.
|
||||
*/
|
||||
void UpdateFromSurface(gfx::SourceSurface* aSurface);
|
||||
|
||||
/**
|
||||
* This method is strictly for debugging. It causes locking and
|
||||
* needless copies.
|
||||
*/
|
||||
already_AddRefed<gfx::DataSourceSurface> GetAsSurface();
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
|
||||
|
||||
/**
|
||||
* Copies a rectangle from this texture client to a position in aTarget.
|
||||
* It is assumed that the necessary locks are in place; so this should at
|
||||
* least have a read lock and aTarget should at least have a write lock.
|
||||
*/
|
||||
bool CopyToTextureClient(TextureClient* aTarget,
|
||||
const gfx::IntRect* aRect,
|
||||
const gfx::IntPoint* aPoint);
|
||||
|
||||
/**
|
||||
* Allocate and deallocate a TextureChild actor.
|
||||
*
|
||||
* TextureChild is an implementation detail of TextureClient that is not
|
||||
* exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
|
||||
* are for use with the managing IPDL protocols only (so that they can
|
||||
* implement AllocPextureChild and DeallocPTextureChild).
|
||||
*/
|
||||
static PTextureChild* CreateIPDLActor();
|
||||
static bool DestroyIPDLActor(PTextureChild* actor);
|
||||
|
||||
/**
|
||||
* Get the TextureClient corresponding to the actor passed in parameter.
|
||||
*/
|
||||
static already_AddRefed<TextureClient> AsTextureClient(PTextureChild* actor);
|
||||
|
||||
/**
|
||||
* TextureFlags contain important information about various aspects
|
||||
* of the texture, like how its liferime is managed, and how it
|
||||
* should be displayed.
|
||||
* See TextureFlags in CompositorTypes.h.
|
||||
*/
|
||||
TextureFlags GetFlags() const { return mFlags; }
|
||||
|
||||
bool HasFlags(TextureFlags aFlags) const
|
||||
{
|
||||
return (mFlags & aFlags) == aFlags;
|
||||
}
|
||||
|
||||
void AddFlags(TextureFlags aFlags);
|
||||
|
||||
void RemoveFlags(TextureFlags aFlags);
|
||||
|
||||
// Must not be called when TextureClient is in use by CompositableClient.
|
||||
void RecycleTexture(TextureFlags aFlags);
|
||||
|
||||
/**
|
||||
* After being shared with the compositor side, an immutable texture is never
|
||||
* modified, it can only be read. It is safe to not Lock/Unlock immutable
|
||||
* textures.
|
||||
*/
|
||||
bool IsImmutable() const { return !!(mFlags & TextureFlags::IMMUTABLE); }
|
||||
|
||||
void MarkImmutable() { AddFlags(TextureFlags::IMMUTABLE); }
|
||||
|
||||
bool IsSharedWithCompositor() const;
|
||||
|
||||
/**
|
||||
* If this method returns false users of TextureClient are not allowed
|
||||
* to access the shared data.
|
||||
*/
|
||||
bool IsValid() const { return !!mData; }
|
||||
|
||||
/**
|
||||
* Called when TextureClient is added to CompositableClient.
|
||||
*/
|
||||
void SetAddedToCompositableClient();
|
||||
|
||||
/**
|
||||
* If this method retuns false, TextureClient is already added to CompositableClient,
|
||||
* since its creation or recycling.
|
||||
*/
|
||||
bool IsAddedToCompositableClient() const { return mAddedToCompositableClient; }
|
||||
|
||||
/**
|
||||
* Create and init the TextureChild/Parent IPDL actor pair
|
||||
* with a CompositableForwarder.
|
||||
*
|
||||
* Should be called only once per TextureClient.
|
||||
* The TextureClient must not be locked when calling this method.
|
||||
*/
|
||||
bool InitIPDLActor(CompositableForwarder* aForwarder);
|
||||
|
||||
/**
|
||||
* Create and init the TextureChild/Parent IPDL actor pair
|
||||
* with a TextureForwarder.
|
||||
*
|
||||
* Should be called only once per TextureClient.
|
||||
* The TextureClient must not be locked when calling this method.
|
||||
*/
|
||||
bool InitIPDLActor(KnowsCompositor* aForwarder);
|
||||
|
||||
/**
|
||||
* Return a pointer to the IPDLActor.
|
||||
*
|
||||
* This is to be used with IPDL messages only. Do not store the returned
|
||||
* pointer.
|
||||
*/
|
||||
PTextureChild* GetIPDLActor();
|
||||
|
||||
/**
|
||||
* Triggers the destruction of the shared data and the corresponding TextureHost.
|
||||
*
|
||||
* If the texture flags contain TextureFlags::DEALLOCATE_CLIENT, the destruction
|
||||
* will be synchronously coordinated with the compositor side, otherwise it
|
||||
* will be done asynchronously.
|
||||
* If sync is true, the destruction will be synchronous regardless of the
|
||||
* texture's flags (bad for performance, use with care).
|
||||
*/
|
||||
void Destroy(bool sync = false);
|
||||
|
||||
/**
|
||||
* Track how much of this texture is wasted.
|
||||
* For example we might allocate a 256x256 tile but only use 10x10.
|
||||
*/
|
||||
void SetWaste(int aWasteArea) {
|
||||
mWasteTracker.Update(aWasteArea, BytesPerPixel(GetFormat()));
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the readback sink that this texture is to use. This will
|
||||
* receive the data for this texture as soon as it becomes available after
|
||||
* texture unlock.
|
||||
*/
|
||||
virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) {
|
||||
mReadbackSink = aReadbackSink;
|
||||
}
|
||||
|
||||
void SyncWithObject(SyncObject* aFence) { mData->SyncWithObject(aFence); }
|
||||
|
||||
LayersIPCChannel* GetAllocator() { return mAllocator; }
|
||||
|
||||
ITextureClientRecycleAllocator* GetRecycleAllocator() { return mRecycleAllocator; }
|
||||
void SetRecycleAllocator(ITextureClientRecycleAllocator* aAllocator);
|
||||
|
||||
/// If you add new code that uses this method, you are probably doing something wrong.
|
||||
TextureData* GetInternalData() { return mData; }
|
||||
const TextureData* GetInternalData() const { return mData; }
|
||||
|
||||
uint64_t GetSerial() const { return mSerial; }
|
||||
|
||||
void CancelWaitForRecycle();
|
||||
|
||||
/**
|
||||
* Set last transaction id of CompositableForwarder.
|
||||
*
|
||||
* Called when TextureClient has TextureFlags::RECYCLE flag.
|
||||
* When CompositableForwarder forwards the TextureClient with
|
||||
* TextureFlags::RECYCLE, it holds TextureClient's ref until host side
|
||||
* releases it. The host side sends TextureClient release message.
|
||||
* The id is used to check if the message is for the last TextureClient
|
||||
* forwarding.
|
||||
*/
|
||||
void SetLastFwdTransactionId(uint64_t aTransactionId)
|
||||
{
|
||||
MOZ_ASSERT(mFwdTransactionId <= aTransactionId);
|
||||
mFwdTransactionId = aTransactionId;
|
||||
}
|
||||
|
||||
uint64_t GetLastFwdTransactionId() { return mFwdTransactionId; }
|
||||
|
||||
void EnableReadLock();
|
||||
|
||||
TextureReadLock* GetReadLock() { return mReadLock; }
|
||||
|
||||
bool IsReadLocked() const;
|
||||
|
||||
void SerializeReadLock(ReadLockDescriptor& aDescriptor);
|
||||
|
||||
private:
|
||||
static void TextureClientRecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
// Internal helpers for creating texture clients using the actual forwarder instead
|
||||
// of KnowsCompositor. TextureClientPool uses these to let it cache texture clients
|
||||
// per-process instead of per ShadowLayerForwarder, but everyone else should
|
||||
// use the public functions instead.
|
||||
friend class TextureClientPool;
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateForDrawing(TextureForwarder* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
LayersBackend aLayersBackend,
|
||||
int32_t aMaxTextureSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
|
||||
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateForRawBufferAccess(LayersIPCChannel* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
LayersBackend aLayersBackend,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags flags = ALLOC_DEFAULT);
|
||||
|
||||
/**
|
||||
* Called once, during the destruction of the Texture, on the thread in which
|
||||
* texture's reference count reaches 0 (could be any thread).
|
||||
*
|
||||
* Here goes the shut-down code that uses virtual methods.
|
||||
* Must only be called by Release().
|
||||
*/
|
||||
void Finalize() {}
|
||||
|
||||
friend class AtomicRefCountedWithFinalize<TextureClient>;
|
||||
protected:
|
||||
/**
|
||||
* Should only be called *once* per texture, in TextureClient::InitIPDLActor.
|
||||
* Some texture implementations rely on the fact that the descriptor will be
|
||||
* deserialized.
|
||||
* Calling ToSurfaceDescriptor again after it has already returned true,
|
||||
* or never constructing a TextureHost with aDescriptor may result in a memory
|
||||
* leak (see TextureClientD3D9 for example).
|
||||
*/
|
||||
bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor);
|
||||
|
||||
void LockActor() const;
|
||||
void UnlockActor() const;
|
||||
|
||||
TextureData::Info mInfo;
|
||||
|
||||
RefPtr<LayersIPCChannel> mAllocator;
|
||||
RefPtr<TextureChild> mActor;
|
||||
RefPtr<ITextureClientRecycleAllocator> mRecycleAllocator;
|
||||
RefPtr<TextureReadLock> mReadLock;
|
||||
|
||||
TextureData* mData;
|
||||
RefPtr<gfx::DrawTarget> mBorrowedDrawTarget;
|
||||
|
||||
TextureFlags mFlags;
|
||||
|
||||
gl::GfxTextureWasteTracker mWasteTracker;
|
||||
|
||||
OpenMode mOpenMode;
|
||||
#ifdef DEBUG
|
||||
uint32_t mExpectedDtRefs;
|
||||
#endif
|
||||
bool mIsLocked;
|
||||
// This member tracks that the texture was written into until the update
|
||||
// is sent to the compositor. We need this remember to lock mReadLock on
|
||||
// behalf of the compositor just before sending the notification.
|
||||
bool mUpdated;
|
||||
|
||||
// Used when TextureClient is recycled with TextureFlags::RECYCLE flag.
|
||||
bool mAddedToCompositableClient;
|
||||
|
||||
bool mWorkaroundAnnoyingSharedSurfaceLifetimeIssues;
|
||||
bool mWorkaroundAnnoyingSharedSurfaceOwnershipIssues;
|
||||
|
||||
RefPtr<TextureReadbackSink> mReadbackSink;
|
||||
|
||||
uint64_t mFwdTransactionId;
|
||||
|
||||
// Serial id of TextureClient. It is unique in current process.
|
||||
const uint64_t mSerial;
|
||||
// Used to assign serial ids of TextureClient.
|
||||
static mozilla::Atomic<uint64_t> sSerialCounter;
|
||||
|
||||
friend class TextureChild;
|
||||
friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*);
|
||||
friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&);
|
||||
|
||||
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
|
||||
public:
|
||||
// Pointer to the pool this tile came from.
|
||||
TextureClientPool* mPoolTracker;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Task that releases TextureClient pointer on a specified thread.
|
||||
*/
|
||||
class TextureClientReleaseTask : public Runnable
|
||||
{
|
||||
public:
|
||||
explicit TextureClientReleaseTask(TextureClient* aClient)
|
||||
: mTextureClient(aClient) {
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mTextureClient = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
};
|
||||
|
||||
// Automatically lock and unlock a texture. Since texture locking is fallible,
|
||||
// Succeeded() must be checked on the guard object before proceeding.
|
||||
class MOZ_RAII TextureClientAutoLock
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
|
||||
|
||||
public:
|
||||
TextureClientAutoLock(TextureClient* aTexture, OpenMode aMode
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mTexture(aTexture),
|
||||
mSucceeded(false)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
mSucceeded = mTexture->Lock(aMode);
|
||||
#ifdef DEBUG
|
||||
mChecked = false;
|
||||
#endif
|
||||
}
|
||||
~TextureClientAutoLock() {
|
||||
MOZ_ASSERT(mChecked);
|
||||
if (mSucceeded) {
|
||||
mTexture->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool Succeeded() {
|
||||
#ifdef DEBUG
|
||||
mChecked = true;
|
||||
#endif
|
||||
return mSucceeded;
|
||||
}
|
||||
|
||||
private:
|
||||
TextureClient* mTexture;
|
||||
#ifdef DEBUG
|
||||
bool mChecked;
|
||||
#endif
|
||||
bool mSucceeded;
|
||||
};
|
||||
|
||||
class KeepAlive
|
||||
{
|
||||
public:
|
||||
virtual ~KeepAlive() {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class TKeepAlive : public KeepAlive
|
||||
{
|
||||
public:
|
||||
explicit TKeepAlive(T* aData) : mData(aData) {}
|
||||
protected:
|
||||
RefPtr<T> mData;
|
||||
};
|
||||
|
||||
/// Convenience function to set the content of ycbcr texture.
|
||||
bool UpdateYCbCrTextureClient(TextureClient* aTexture, const PlanarYCbCrData& aData);
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
339
gfx/layers/client/TextureClientPool.cpp
Normal file
339
gfx/layers/client/TextureClientPool.cpp
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "TextureClientPool.h"
|
||||
#include "CompositableClient.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/TextureForwarder.h"
|
||||
#include "mozilla/layers/TiledContentClient.h"
|
||||
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
#define TCP_LOG(...)
|
||||
//#define TCP_LOG(...) printf_stderr(__VA_ARGS__);
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
// We want to shrink to our maximum size of N unused tiles
|
||||
// after a timeout to allow for short-term budget requirements
|
||||
static void
|
||||
ShrinkCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
static_cast<TextureClientPool*>(aClosure)->ShrinkToMaximumSize();
|
||||
}
|
||||
|
||||
// After a certain amount of inactivity, let's clear the pool so that
|
||||
// we don't hold onto tiles needlessly. In general, allocations are
|
||||
// cheap enough that re-allocating isn't an issue unless we're allocating
|
||||
// at an inopportune time (e.g. mid-animation).
|
||||
static void
|
||||
ClearCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
static_cast<TextureClientPool*>(aClosure)->Clear();
|
||||
}
|
||||
|
||||
TextureClientPool::TextureClientPool(LayersBackend aLayersBackend,
|
||||
int32_t aMaxTextureSize,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
TextureFlags aFlags,
|
||||
uint32_t aShrinkTimeoutMsec,
|
||||
uint32_t aClearTimeoutMsec,
|
||||
uint32_t aInitialPoolSize,
|
||||
uint32_t aPoolUnusedSize,
|
||||
TextureForwarder* aAllocator)
|
||||
: mBackend(aLayersBackend)
|
||||
, mMaxTextureSize(aMaxTextureSize)
|
||||
, mFormat(aFormat)
|
||||
, mSize(aSize)
|
||||
, mFlags(aFlags)
|
||||
, mShrinkTimeoutMsec(aShrinkTimeoutMsec)
|
||||
, mClearTimeoutMsec(aClearTimeoutMsec)
|
||||
, mInitialPoolSize(aInitialPoolSize)
|
||||
, mPoolUnusedSize(aPoolUnusedSize)
|
||||
, mOutstandingClients(0)
|
||||
, mSurfaceAllocator(aAllocator)
|
||||
, mDestroyed(false)
|
||||
{
|
||||
TCP_LOG("TexturePool %p created with maximum unused texture clients %u\n",
|
||||
this, mInitialPoolSize);
|
||||
mShrinkTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mClearTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (aFormat == gfx::SurfaceFormat::UNKNOWN) {
|
||||
gfxWarning() << "Creating texture pool for SurfaceFormat::UNKNOWN format";
|
||||
}
|
||||
}
|
||||
|
||||
TextureClientPool::~TextureClientPool()
|
||||
{
|
||||
mShrinkTimer->Cancel();
|
||||
mClearTimer->Cancel();
|
||||
}
|
||||
|
||||
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
|
||||
static bool TestClientPool(const char* what,
|
||||
TextureClient* aClient,
|
||||
TextureClientPool* aPool)
|
||||
{
|
||||
if (!aClient || !aPool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextureClientPool* actual = aClient->mPoolTracker;
|
||||
bool ok = (actual == aPool);
|
||||
if (ok) {
|
||||
ok = (aClient->GetFormat() == aPool->GetFormat());
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
if (actual) {
|
||||
gfxCriticalError() << "Pool error(" << what << "): "
|
||||
<< aPool << "-" << aPool->GetFormat() << ", "
|
||||
<< actual << "-" << actual->GetFormat() << ", "
|
||||
<< aClient->GetFormat();
|
||||
MOZ_CRASH("GFX: Crashing with actual");
|
||||
} else {
|
||||
gfxCriticalError() << "Pool error(" << what << "): "
|
||||
<< aPool << "-" << aPool->GetFormat() << ", nullptr, "
|
||||
<< aClient->GetFormat();
|
||||
MOZ_CRASH("GFX: Crashing without actual");
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClientPool::GetTextureClient()
|
||||
{
|
||||
// Try to fetch a client from the pool
|
||||
RefPtr<TextureClient> textureClient;
|
||||
|
||||
// We initially allocate mInitialPoolSize for our pool. If we run
|
||||
// out of TextureClients, we allocate additional TextureClients to try and keep around
|
||||
// mPoolUnusedSize
|
||||
if (!mTextureClients.size()) {
|
||||
AllocateTextureClient();
|
||||
}
|
||||
|
||||
if (!mTextureClients.size()) {
|
||||
// All our allocations failed, return nullptr
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mOutstandingClients++;
|
||||
textureClient = mTextureClients.top();
|
||||
mTextureClients.pop();
|
||||
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
|
||||
if (textureClient) {
|
||||
textureClient->mPoolTracker = this;
|
||||
}
|
||||
DebugOnly<bool> ok = TestClientPool("fetch", textureClient, this);
|
||||
MOZ_ASSERT(ok);
|
||||
#endif
|
||||
TCP_LOG("TexturePool %p giving %p from pool; size %u outstanding %u\n",
|
||||
this, textureClient.get(), mTextureClients.size(), mOutstandingClients);
|
||||
|
||||
return textureClient.forget();
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::AllocateTextureClient()
|
||||
{
|
||||
TCP_LOG("TexturePool %p allocating TextureClient, outstanding %u\n",
|
||||
this, mOutstandingClients);
|
||||
|
||||
RefPtr<TextureClient> newClient;
|
||||
if (gfxPrefs::ForceShmemTiles()) {
|
||||
// gfx::BackendType::NONE means use the content backend
|
||||
newClient =
|
||||
TextureClient::CreateForRawBufferAccess(mSurfaceAllocator,
|
||||
mFormat, mSize,
|
||||
gfx::BackendType::NONE,
|
||||
mBackend,
|
||||
mFlags, ALLOC_DEFAULT);
|
||||
} else {
|
||||
newClient =
|
||||
TextureClient::CreateForDrawing(mSurfaceAllocator,
|
||||
mFormat, mSize,
|
||||
mBackend,
|
||||
mMaxTextureSize,
|
||||
BackendSelector::Content,
|
||||
mFlags);
|
||||
}
|
||||
|
||||
if (newClient) {
|
||||
mTextureClients.push(newClient);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ResetTimers()
|
||||
{
|
||||
// Shrink down if we're beyond our maximum size
|
||||
if (mShrinkTimeoutMsec &&
|
||||
mTextureClients.size() + mTextureClientsDeferred.size() > mPoolUnusedSize) {
|
||||
TCP_LOG("TexturePool %p scheduling a shrink-to-max-size\n", this);
|
||||
mShrinkTimer->InitWithFuncCallback(ShrinkCallback, this, mShrinkTimeoutMsec,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
// Clear pool after a period of inactivity to reduce memory consumption
|
||||
if (mClearTimeoutMsec) {
|
||||
TCP_LOG("TexturePool %p scheduling a clear\n", this);
|
||||
mClearTimer->InitWithFuncCallback(ClearCallback, this, mClearTimeoutMsec,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ReturnTextureClient(TextureClient *aClient)
|
||||
{
|
||||
if (!aClient || mDestroyed) {
|
||||
return;
|
||||
}
|
||||
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
|
||||
DebugOnly<bool> ok = TestClientPool("return", aClient, this);
|
||||
MOZ_ASSERT(ok);
|
||||
#endif
|
||||
// Add the client to the pool:
|
||||
MOZ_ASSERT(mOutstandingClients > mTextureClientsDeferred.size());
|
||||
mOutstandingClients--;
|
||||
mTextureClients.push(aClient);
|
||||
TCP_LOG("TexturePool %p had client %p returned; size %u outstanding %u\n",
|
||||
this, aClient, mTextureClients.size(), mOutstandingClients);
|
||||
|
||||
ResetTimers();
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ReturnTextureClientDeferred(TextureClient* aClient)
|
||||
{
|
||||
if (!aClient || mDestroyed) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(aClient->GetReadLock());
|
||||
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
|
||||
DebugOnly<bool> ok = TestClientPool("defer", aClient, this);
|
||||
MOZ_ASSERT(ok);
|
||||
#endif
|
||||
mTextureClientsDeferred.push_back(aClient);
|
||||
TCP_LOG("TexturePool %p had client %p defer-returned, size %u outstanding %u\n",
|
||||
this, aClient, mTextureClientsDeferred.size(), mOutstandingClients);
|
||||
|
||||
ResetTimers();
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ShrinkToMaximumSize()
|
||||
{
|
||||
// We're over our desired maximum size, immediately shrink down to the
|
||||
// maximum.
|
||||
//
|
||||
// We cull from the deferred TextureClients first, as we can't reuse those
|
||||
// until they get returned.
|
||||
uint32_t totalUnusedTextureClients = mTextureClients.size() + mTextureClientsDeferred.size();
|
||||
|
||||
// If we have > mInitialPoolSize outstanding, then we want to keep around
|
||||
// mPoolUnusedSize at a maximum. If we have fewer than mInitialPoolSize
|
||||
// outstanding, then keep around the entire initial pool size.
|
||||
uint32_t targetUnusedClients;
|
||||
if (mOutstandingClients > mInitialPoolSize) {
|
||||
targetUnusedClients = mPoolUnusedSize;
|
||||
} else {
|
||||
targetUnusedClients = mInitialPoolSize;
|
||||
}
|
||||
|
||||
TCP_LOG("TexturePool %p shrinking to maximum unused size %u; current pool size %u; total outstanding %u\n",
|
||||
this, targetUnusedClients, totalUnusedTextureClients, mOutstandingClients);
|
||||
|
||||
while (totalUnusedTextureClients > targetUnusedClients) {
|
||||
if (mTextureClientsDeferred.size()) {
|
||||
mOutstandingClients--;
|
||||
TCP_LOG("TexturePool %p dropped deferred client %p; %u remaining\n",
|
||||
this, mTextureClientsDeferred.front().get(),
|
||||
mTextureClientsDeferred.size() - 1);
|
||||
mTextureClientsDeferred.pop_front();
|
||||
} else {
|
||||
TCP_LOG("TexturePool %p dropped non-deferred client %p; %u remaining\n",
|
||||
this, mTextureClients.top().get(), mTextureClients.size() - 1);
|
||||
mTextureClients.pop();
|
||||
}
|
||||
totalUnusedTextureClients--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ReturnDeferredClients()
|
||||
{
|
||||
if (mTextureClientsDeferred.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TCP_LOG("TexturePool %p returning %u deferred clients to pool\n",
|
||||
this, mTextureClientsDeferred.size());
|
||||
|
||||
ReturnUnlockedClients();
|
||||
ShrinkToMaximumSize();
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ReturnUnlockedClients()
|
||||
{
|
||||
for (auto it = mTextureClientsDeferred.begin(); it != mTextureClientsDeferred.end();) {
|
||||
MOZ_ASSERT((*it)->GetReadLock()->GetReadCount() >= 1);
|
||||
// Last count is held by the lock itself.
|
||||
if (!(*it)->IsReadLocked()) {
|
||||
mTextureClients.push(*it);
|
||||
it = mTextureClientsDeferred.erase(it);
|
||||
|
||||
MOZ_ASSERT(mOutstandingClients > 0);
|
||||
mOutstandingClients--;
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ReportClientLost()
|
||||
{
|
||||
MOZ_ASSERT(mOutstandingClients > mTextureClientsDeferred.size());
|
||||
mOutstandingClients--;
|
||||
TCP_LOG("TexturePool %p getting report client lost; down to %u outstanding\n",
|
||||
this, mOutstandingClients);
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::Clear()
|
||||
{
|
||||
TCP_LOG("TexturePool %p getting cleared\n", this);
|
||||
while (!mTextureClients.empty()) {
|
||||
TCP_LOG("TexturePool %p releasing client %p\n",
|
||||
this, mTextureClients.top().get());
|
||||
mTextureClients.pop();
|
||||
}
|
||||
while (!mTextureClientsDeferred.empty()) {
|
||||
MOZ_ASSERT(mOutstandingClients > 0);
|
||||
mOutstandingClients--;
|
||||
TCP_LOG("TexturePool %p releasing deferred client %p\n",
|
||||
this, mTextureClientsDeferred.front().get());
|
||||
mTextureClientsDeferred.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void TextureClientPool::Destroy()
|
||||
{
|
||||
Clear();
|
||||
mDestroyed = true;
|
||||
mInitialPoolSize = 0;
|
||||
mPoolUnusedSize = 0;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
180
gfx/layers/client/TextureClientPool.h
Normal file
180
gfx/layers/client/TextureClientPool.h
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_TEXTURECLIENTPOOL_H
|
||||
#define MOZILLA_GFX_TEXTURECLIENTPOOL_H
|
||||
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "TextureClient.h"
|
||||
#include "nsITimer.h"
|
||||
#include <stack>
|
||||
#include <list>
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ISurfaceAllocator;
|
||||
class TextureForwarder;
|
||||
class TextureReadLock;
|
||||
|
||||
class TextureClientAllocator
|
||||
{
|
||||
protected:
|
||||
virtual ~TextureClientAllocator() {}
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(TextureClientAllocator)
|
||||
|
||||
virtual already_AddRefed<TextureClient> GetTextureClient() = 0;
|
||||
|
||||
/**
|
||||
* Return a TextureClient that is not yet ready to be reused, but will be
|
||||
* imminently.
|
||||
*/
|
||||
virtual void ReturnTextureClientDeferred(TextureClient *aClient) = 0;
|
||||
|
||||
virtual void ReportClientLost() = 0;
|
||||
};
|
||||
|
||||
class TextureClientPool final : public TextureClientAllocator
|
||||
{
|
||||
~TextureClientPool();
|
||||
|
||||
public:
|
||||
TextureClientPool(LayersBackend aBackend,
|
||||
int32_t aMaxTextureSize,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
TextureFlags aFlags,
|
||||
uint32_t aShrinkTimeoutMsec,
|
||||
uint32_t aClearTimeoutMsec,
|
||||
uint32_t aInitialPoolSize,
|
||||
uint32_t aPoolUnusedSize,
|
||||
TextureForwarder* aAllocator);
|
||||
|
||||
/**
|
||||
* Gets an allocated TextureClient of size and format that are determined
|
||||
* by the initialisation parameters given to the pool. This will either be
|
||||
* a cached client that was returned to the pool, or a newly allocated
|
||||
* client if one isn't available.
|
||||
*
|
||||
* All clients retrieved by this method should be returned using the return
|
||||
* functions, or reported lost so that the pool can manage its size correctly.
|
||||
*/
|
||||
already_AddRefed<TextureClient> GetTextureClient() override;
|
||||
|
||||
/**
|
||||
* Return a TextureClient that is no longer being used and is ready for
|
||||
* immediate re-use or destruction.
|
||||
*/
|
||||
void ReturnTextureClient(TextureClient *aClient);
|
||||
|
||||
/**
|
||||
* Return a TextureClient that is not yet ready to be reused, but will be
|
||||
* imminently.
|
||||
*/
|
||||
void ReturnTextureClientDeferred(TextureClient *aClient) override;
|
||||
|
||||
/**
|
||||
* Return any clients to the pool that were previously returned in
|
||||
* ReturnTextureClientDeferred.
|
||||
*/
|
||||
void ReturnDeferredClients();
|
||||
|
||||
/**
|
||||
* Attempt to shrink the pool so that there are no more than
|
||||
* mInitialPoolSize outstanding.
|
||||
*/
|
||||
void ShrinkToMaximumSize();
|
||||
|
||||
/**
|
||||
* Report that a client retrieved via GetTextureClient() has become
|
||||
* unusable, so that it will no longer be tracked.
|
||||
*/
|
||||
virtual void ReportClientLost() override;
|
||||
|
||||
/**
|
||||
* Calling this will cause the pool to attempt to relinquish any unused
|
||||
* clients.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
LayersBackend GetBackend() const { return mBackend; }
|
||||
int32_t GetMaxTextureSize() const { return mMaxTextureSize; }
|
||||
gfx::SurfaceFormat GetFormat() { return mFormat; }
|
||||
TextureFlags GetFlags() const { return mFlags; }
|
||||
|
||||
/**
|
||||
* Clear the pool and put it in a state where it won't recycle any new texture.
|
||||
*/
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
void ReturnUnlockedClients();
|
||||
|
||||
/// Allocate a single TextureClient to be returned from the pool.
|
||||
void AllocateTextureClient();
|
||||
|
||||
/// Reset and/or initialise timers for shrinking/clearing the pool.
|
||||
void ResetTimers();
|
||||
|
||||
/// Backend passed to the TextureClient for buffer creation.
|
||||
LayersBackend mBackend;
|
||||
|
||||
// Max texture size passed to the TextureClient for buffer creation.
|
||||
int32_t mMaxTextureSize;
|
||||
|
||||
/// Format is passed to the TextureClient for buffer creation.
|
||||
gfx::SurfaceFormat mFormat;
|
||||
|
||||
/// The width and height of the tiles to be used.
|
||||
gfx::IntSize mSize;
|
||||
|
||||
/// Flags passed to the TextureClient for buffer creation.
|
||||
const TextureFlags mFlags;
|
||||
|
||||
/// How long to wait after a TextureClient is returned before trying
|
||||
/// to shrink the pool to its maximum size of mPoolUnusedSize.
|
||||
uint32_t mShrinkTimeoutMsec;
|
||||
|
||||
/// How long to wait after a TextureClient is returned before trying
|
||||
/// to clear the pool.
|
||||
uint32_t mClearTimeoutMsec;
|
||||
|
||||
// The initial number of unused texture clients to seed the pool with
|
||||
// on construction
|
||||
uint32_t mInitialPoolSize;
|
||||
|
||||
// How many unused texture clients to try and keep around if we go over
|
||||
// the initial allocation
|
||||
uint32_t mPoolUnusedSize;
|
||||
|
||||
/// This is a total number of clients in the wild and in the stack of
|
||||
/// deferred clients (see below). So, the total number of clients in
|
||||
/// existence is always mOutstandingClients + the size of mTextureClients.
|
||||
uint32_t mOutstandingClients;
|
||||
|
||||
// On b2g gonk, std::queue might be a better choice.
|
||||
// On ICS, fence wait happens implicitly before drawing.
|
||||
// Since JB, fence wait happens explicitly when fetching a client from the pool.
|
||||
std::stack<RefPtr<TextureClient> > mTextureClients;
|
||||
|
||||
std::list<RefPtr<TextureClient>> mTextureClientsDeferred;
|
||||
RefPtr<nsITimer> mShrinkTimer;
|
||||
RefPtr<nsITimer> mClearTimer;
|
||||
// This mSurfaceAllocator owns us, so no need to hold a ref to it
|
||||
TextureForwarder* mSurfaceAllocator;
|
||||
|
||||
// Keep track of whether this pool has been destroyed or not. If it has,
|
||||
// we won't accept returns of TextureClients anymore, and the refcounting
|
||||
// should take care of their destruction.
|
||||
bool mDestroyed;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_GFX_TEXTURECLIENTPOOL_H */
|
||||
279
gfx/layers/client/TextureClientRecycleAllocator.cpp
Normal file
279
gfx/layers/client/TextureClientRecycleAllocator.cpp
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "gfxPlatform.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/TextureForwarder.h"
|
||||
#include "TextureClientRecycleAllocator.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
// Used to keep TextureClient's reference count stable as not to disrupt recycling.
|
||||
class TextureClientHolder
|
||||
{
|
||||
~TextureClientHolder() {}
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureClientHolder)
|
||||
|
||||
explicit TextureClientHolder(TextureClient* aClient)
|
||||
: mTextureClient(aClient)
|
||||
, mWillRecycle(true)
|
||||
{}
|
||||
|
||||
TextureClient* GetTextureClient()
|
||||
{
|
||||
return mTextureClient;
|
||||
}
|
||||
|
||||
bool WillRecycle()
|
||||
{
|
||||
return mWillRecycle;
|
||||
}
|
||||
|
||||
void ClearWillRecycle()
|
||||
{
|
||||
mWillRecycle = false;
|
||||
}
|
||||
|
||||
void ClearTextureClient() { mTextureClient = nullptr; }
|
||||
protected:
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
bool mWillRecycle;
|
||||
};
|
||||
|
||||
class DefaultTextureClientAllocationHelper : public ITextureClientAllocationHelper
|
||||
{
|
||||
public:
|
||||
DefaultTextureClientAllocationHelper(TextureClientRecycleAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocationFlags)
|
||||
: ITextureClientAllocationHelper(aFormat,
|
||||
aSize,
|
||||
aSelector,
|
||||
aTextureFlags,
|
||||
aAllocationFlags)
|
||||
, mAllocator(aAllocator)
|
||||
{}
|
||||
|
||||
bool IsCompatible(TextureClient* aTextureClient) override
|
||||
{
|
||||
if (aTextureClient->GetFormat() != mFormat ||
|
||||
aTextureClient->GetSize() != mSize) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient> Allocate(KnowsCompositor* aAllocator) override
|
||||
{
|
||||
return mAllocator->Allocate(mFormat,
|
||||
mSize,
|
||||
mSelector,
|
||||
mTextureFlags,
|
||||
mAllocationFlags);
|
||||
}
|
||||
|
||||
protected:
|
||||
TextureClientRecycleAllocator* mAllocator;
|
||||
};
|
||||
|
||||
YCbCrTextureClientAllocationHelper::YCbCrTextureClientAllocationHelper(const PlanarYCbCrData& aData,
|
||||
TextureFlags aTextureFlags)
|
||||
: ITextureClientAllocationHelper(gfx::SurfaceFormat::YUV,
|
||||
aData.mYSize,
|
||||
BackendSelector::Content,
|
||||
aTextureFlags,
|
||||
ALLOC_DEFAULT)
|
||||
, mData(aData)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
YCbCrTextureClientAllocationHelper::IsCompatible(TextureClient* aTextureClient)
|
||||
{
|
||||
MOZ_ASSERT(aTextureClient->GetFormat() == gfx::SurfaceFormat::YUV);
|
||||
|
||||
BufferTextureData* bufferData = aTextureClient->GetInternalData()->AsBufferTextureData();
|
||||
if (!bufferData ||
|
||||
aTextureClient->GetSize() != mData.mYSize ||
|
||||
bufferData->GetCbCrSize().isNothing() ||
|
||||
bufferData->GetCbCrSize().ref() != mData.mCbCrSize ||
|
||||
bufferData->GetYUVColorSpace().isNothing() ||
|
||||
bufferData->GetYUVColorSpace().ref() != mData.mYUVColorSpace ||
|
||||
bufferData->GetStereoMode().isNothing() ||
|
||||
bufferData->GetStereoMode().ref() != mData.mStereoMode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
YCbCrTextureClientAllocationHelper::Allocate(KnowsCompositor* aAllocator)
|
||||
{
|
||||
return TextureClient::CreateForYCbCr(aAllocator,
|
||||
mData.mYSize, mData.mCbCrSize,
|
||||
mData.mStereoMode,
|
||||
mData.mYUVColorSpace,
|
||||
mTextureFlags);
|
||||
}
|
||||
|
||||
TextureClientRecycleAllocator::TextureClientRecycleAllocator(KnowsCompositor* aAllocator)
|
||||
: mSurfaceAllocator(aAllocator)
|
||||
, mMaxPooledSize(kMaxPooledSized)
|
||||
, mLock("TextureClientRecycleAllocatorImp.mLock")
|
||||
, mIsDestroyed(false)
|
||||
{
|
||||
}
|
||||
|
||||
TextureClientRecycleAllocator::~TextureClientRecycleAllocator()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
while (!mPooledClients.empty()) {
|
||||
mPooledClients.pop();
|
||||
}
|
||||
MOZ_ASSERT(mInUseClients.empty());
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientRecycleAllocator::SetMaxPoolSize(uint32_t aMax)
|
||||
{
|
||||
mMaxPooledSize = aMax;
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClientRecycleAllocator::CreateOrRecycle(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
MOZ_ASSERT(!(aTextureFlags & TextureFlags::RECYCLE));
|
||||
DefaultTextureClientAllocationHelper helper(this,
|
||||
aFormat,
|
||||
aSize,
|
||||
aSelector,
|
||||
aTextureFlags,
|
||||
aAllocFlags);
|
||||
return CreateOrRecycle(helper);
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClientRecycleAllocator::CreateOrRecycle(ITextureClientAllocationHelper& aHelper)
|
||||
{
|
||||
MOZ_ASSERT(aHelper.mTextureFlags & TextureFlags::RECYCLE);
|
||||
|
||||
RefPtr<TextureClientHolder> textureHolder;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (mIsDestroyed) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!mPooledClients.empty()) {
|
||||
textureHolder = mPooledClients.top();
|
||||
mPooledClients.pop();
|
||||
// If a pooled TextureClient is not compatible, release it.
|
||||
if (!aHelper.IsCompatible(textureHolder->GetTextureClient())) {
|
||||
// Release TextureClient.
|
||||
RefPtr<Runnable> task = new TextureClientReleaseTask(textureHolder->GetTextureClient());
|
||||
textureHolder->ClearTextureClient();
|
||||
textureHolder = nullptr;
|
||||
mSurfaceAllocator->GetTextureForwarder()->GetMessageLoop()->PostTask(task.forget());
|
||||
} else {
|
||||
textureHolder->GetTextureClient()->RecycleTexture(aHelper.mTextureFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!textureHolder) {
|
||||
// Allocate new TextureClient
|
||||
RefPtr<TextureClient> texture = aHelper.Allocate(mSurfaceAllocator);
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
textureHolder = new TextureClientHolder(texture);
|
||||
}
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
MOZ_ASSERT(mInUseClients.find(textureHolder->GetTextureClient()) == mInUseClients.end());
|
||||
// Register TextureClient
|
||||
mInUseClients[textureHolder->GetTextureClient()] = textureHolder;
|
||||
}
|
||||
RefPtr<TextureClient> client(textureHolder->GetTextureClient());
|
||||
|
||||
// Make sure the texture holds a reference to us, and ask it to call RecycleTextureClient when its
|
||||
// ref count drops to 1.
|
||||
client->SetRecycleAllocator(this);
|
||||
return client.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClientRecycleAllocator::Allocate(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
return TextureClient::CreateForDrawing(mSurfaceAllocator, aFormat, aSize,
|
||||
aSelector, aTextureFlags, aAllocFlags);
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientRecycleAllocator::ShrinkToMinimumSize()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
while (!mPooledClients.empty()) {
|
||||
mPooledClients.pop();
|
||||
}
|
||||
// We can not clear using TextureClients safely.
|
||||
// Just clear WillRecycle here.
|
||||
std::map<TextureClient*, RefPtr<TextureClientHolder> >::iterator it;
|
||||
for (it = mInUseClients.begin(); it != mInUseClients.end(); it++) {
|
||||
RefPtr<TextureClientHolder> holder = it->second;
|
||||
holder->ClearWillRecycle();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientRecycleAllocator::Destroy()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
while (!mPooledClients.empty()) {
|
||||
mPooledClients.pop();
|
||||
}
|
||||
mIsDestroyed = true;
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientRecycleAllocator::RecycleTextureClient(TextureClient* aClient)
|
||||
{
|
||||
// Clearing the recycle allocator drops a reference, so make sure we stay alive
|
||||
// for the duration of this function.
|
||||
RefPtr<TextureClientRecycleAllocator> kungFuDeathGrip(this);
|
||||
aClient->SetRecycleAllocator(nullptr);
|
||||
|
||||
RefPtr<TextureClientHolder> textureHolder;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (mInUseClients.find(aClient) != mInUseClients.end()) {
|
||||
textureHolder = mInUseClients[aClient]; // Keep reference count of TextureClientHolder within lock.
|
||||
if (textureHolder->WillRecycle() &&
|
||||
!mIsDestroyed && mPooledClients.size() < mMaxPooledSize) {
|
||||
mPooledClients.push(textureHolder);
|
||||
}
|
||||
mInUseClients.erase(aClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
140
gfx/layers/client/TextureClientRecycleAllocator.h
Normal file
140
gfx/layers/client/TextureClientRecycleAllocator.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_TEXTURECLIENT_RECYCLE_ALLOCATOR_H
|
||||
#define MOZILLA_GFX_TEXTURECLIENT_RECYCLE_ALLOCATOR_H
|
||||
|
||||
#include <map>
|
||||
#include <stack>
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/layers/TextureForwarder.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "TextureClient.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class TextureClientHolder;
|
||||
struct PlanarYCbCrData;
|
||||
|
||||
class ITextureClientRecycleAllocator
|
||||
{
|
||||
protected:
|
||||
virtual ~ITextureClientRecycleAllocator() {}
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ITextureClientRecycleAllocator)
|
||||
|
||||
protected:
|
||||
friend class TextureClient;
|
||||
virtual void RecycleTextureClient(TextureClient* aClient) = 0;
|
||||
};
|
||||
|
||||
class ITextureClientAllocationHelper
|
||||
{
|
||||
public:
|
||||
ITextureClientAllocationHelper(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocationFlags)
|
||||
: mFormat(aFormat)
|
||||
, mSize(aSize)
|
||||
, mSelector(aSelector)
|
||||
, mTextureFlags(aTextureFlags | TextureFlags::RECYCLE) // Set recycle flag
|
||||
, mAllocationFlags(aAllocationFlags)
|
||||
{}
|
||||
|
||||
virtual already_AddRefed<TextureClient> Allocate(KnowsCompositor* aAllocator) = 0;
|
||||
virtual bool IsCompatible(TextureClient* aTextureClient) = 0;
|
||||
|
||||
const gfx::SurfaceFormat mFormat;
|
||||
const gfx::IntSize mSize;
|
||||
const BackendSelector mSelector;
|
||||
const TextureFlags mTextureFlags;
|
||||
const TextureAllocationFlags mAllocationFlags;
|
||||
};
|
||||
|
||||
class YCbCrTextureClientAllocationHelper : public ITextureClientAllocationHelper
|
||||
{
|
||||
public:
|
||||
YCbCrTextureClientAllocationHelper(const PlanarYCbCrData& aData,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
bool IsCompatible(TextureClient* aTextureClient) override;
|
||||
|
||||
already_AddRefed<TextureClient> Allocate(KnowsCompositor* aAllocator) override;
|
||||
|
||||
protected:
|
||||
const PlanarYCbCrData& mData;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* TextureClientRecycleAllocator provides TextureClients allocation and
|
||||
* recycling capabilities. It expects allocations of same sizes and
|
||||
* attributres. If a recycled TextureClient is different from
|
||||
* requested one, the recycled one is dropped and new TextureClient is allocated.
|
||||
*
|
||||
* By default this uses TextureClient::CreateForDrawing to allocate new texture
|
||||
* clients.
|
||||
*/
|
||||
class TextureClientRecycleAllocator : public ITextureClientRecycleAllocator
|
||||
{
|
||||
protected:
|
||||
virtual ~TextureClientRecycleAllocator();
|
||||
|
||||
public:
|
||||
explicit TextureClientRecycleAllocator(KnowsCompositor* aAllocator);
|
||||
|
||||
void SetMaxPoolSize(uint32_t aMax);
|
||||
|
||||
// Creates and allocates a TextureClient.
|
||||
already_AddRefed<TextureClient>
|
||||
CreateOrRecycle(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags flags = ALLOC_DEFAULT);
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
CreateOrRecycle(ITextureClientAllocationHelper& aHelper);
|
||||
|
||||
void ShrinkToMinimumSize();
|
||||
|
||||
void Destroy();
|
||||
|
||||
protected:
|
||||
virtual already_AddRefed<TextureClient>
|
||||
Allocate(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags);
|
||||
|
||||
RefPtr<KnowsCompositor> mSurfaceAllocator;
|
||||
|
||||
friend class DefaultTextureClientAllocationHelper;
|
||||
void RecycleTextureClient(TextureClient* aClient) override;
|
||||
|
||||
static const uint32_t kMaxPooledSized = 2;
|
||||
uint32_t mMaxPooledSize;
|
||||
|
||||
std::map<TextureClient*, RefPtr<TextureClientHolder> > mInUseClients;
|
||||
|
||||
// On b2g gonk, std::queue might be a better choice.
|
||||
// On ICS, fence wait happens implicitly before drawing.
|
||||
// Since JB, fence wait happens explicitly when fetching a client from the pool.
|
||||
// stack is good from Graphics cache usage point of view.
|
||||
std::stack<RefPtr<TextureClientHolder> > mPooledClients;
|
||||
Mutex mLock;
|
||||
bool mIsDestroyed;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_GFX_TEXTURECLIENT_RECYCLE_ALLOCATOR_H */
|
||||
96
gfx/layers/client/TextureClientSharedSurface.cpp
Normal file
96
gfx/layers/client/TextureClientSharedSurface.cpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 "TextureClientSharedSurface.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Logging.h" // for gfxDebug
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "SharedSurface.h"
|
||||
|
||||
using namespace mozilla::gl;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
|
||||
SharedSurfaceTextureData::SharedSurfaceTextureData(UniquePtr<gl::SharedSurface> surf)
|
||||
: mSurf(Move(surf))
|
||||
{}
|
||||
|
||||
SharedSurfaceTextureData::~SharedSurfaceTextureData()
|
||||
{}
|
||||
|
||||
void
|
||||
SharedSurfaceTextureData::Deallocate(LayersIPCChannel*)
|
||||
{}
|
||||
|
||||
void
|
||||
SharedSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = mSurf->mSize;
|
||||
aInfo.format = gfx::SurfaceFormat::UNKNOWN;
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
aInfo.supportsMoz2D = false;
|
||||
aInfo.canExposeMappedData = false;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
return mSurf->ToSurfaceDescriptor(&aOutDescriptor);
|
||||
}
|
||||
|
||||
|
||||
SharedSurfaceTextureClient::SharedSurfaceTextureClient(SharedSurfaceTextureData* aData,
|
||||
TextureFlags aFlags,
|
||||
LayersIPCChannel* aAllocator)
|
||||
: TextureClient(aData, aFlags, aAllocator)
|
||||
{
|
||||
mWorkaroundAnnoyingSharedSurfaceLifetimeIssues = true;
|
||||
}
|
||||
|
||||
already_AddRefed<SharedSurfaceTextureClient>
|
||||
SharedSurfaceTextureClient::Create(UniquePtr<gl::SharedSurface> surf, gl::SurfaceFactory* factory,
|
||||
LayersIPCChannel* aAllocator, TextureFlags aFlags)
|
||||
{
|
||||
if (!surf) {
|
||||
return nullptr;
|
||||
}
|
||||
TextureFlags flags = aFlags | TextureFlags::RECYCLE | surf->GetTextureFlags();
|
||||
SharedSurfaceTextureData* data = new SharedSurfaceTextureData(Move(surf));
|
||||
return MakeAndAddRef<SharedSurfaceTextureClient>(data, flags, aAllocator);
|
||||
}
|
||||
|
||||
SharedSurfaceTextureClient::~SharedSurfaceTextureClient()
|
||||
{
|
||||
// XXX - Things break when using the proper destruction handshake with
|
||||
// SharedSurfaceTextureData because the TextureData outlives its gl
|
||||
// context. Having a strong reference to the gl context creates a cycle.
|
||||
// This needs to be fixed in a better way, though, because deleting
|
||||
// the TextureData here can race with the compositor and cause flashing.
|
||||
TextureData* data = mData;
|
||||
mData = nullptr;
|
||||
|
||||
Destroy();
|
||||
|
||||
if (data) {
|
||||
// Destroy mData right away without doing the proper deallocation handshake,
|
||||
// because SharedSurface depends on things that may not outlive the texture's
|
||||
// destructor so we can't wait until we know the compositor isn't using the
|
||||
// texture anymore.
|
||||
// It goes without saying that this is really bad and we should fix the bugs
|
||||
// that block doing the right thing such as bug 1224199 sooner rather than
|
||||
// later.
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
77
gfx/layers/client/TextureClientSharedSurface.h
Normal file
77
gfx/layers/client/TextureClientSharedSurface.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_TEXTURECLIENT_SHAREDSURFACE_H
|
||||
#define MOZILLA_GFX_TEXTURECLIENT_SHAREDSURFACE_H
|
||||
|
||||
#include <cstddef> // for size_t
|
||||
#include <stdint.h> // for uint32_t, uint8_t, uint64_t
|
||||
#include "GLContextTypes.h" // for GLContext (ptr only), etc
|
||||
#include "TextureClient.h"
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/RefPtr.h" // for RefPtr, RefCounted
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat
|
||||
#include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
class GLContext;
|
||||
class SharedSurface;
|
||||
class SurfaceFactory;
|
||||
} // namespace gl
|
||||
|
||||
namespace layers {
|
||||
|
||||
class SharedSurfaceTextureClient;
|
||||
|
||||
class SharedSurfaceTextureData : public TextureData
|
||||
{
|
||||
protected:
|
||||
const UniquePtr<gl::SharedSurface> mSurf;
|
||||
|
||||
friend class SharedSurfaceTextureClient;
|
||||
|
||||
explicit SharedSurfaceTextureData(UniquePtr<gl::SharedSurface> surf);
|
||||
public:
|
||||
|
||||
~SharedSurfaceTextureData();
|
||||
|
||||
virtual bool Lock(OpenMode) override { return false; }
|
||||
|
||||
virtual void Unlock() override {}
|
||||
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
virtual void Deallocate(LayersIPCChannel*) override;
|
||||
|
||||
gl::SharedSurface* Surf() const { return mSurf.get(); }
|
||||
};
|
||||
|
||||
class SharedSurfaceTextureClient : public TextureClient
|
||||
{
|
||||
public:
|
||||
SharedSurfaceTextureClient(SharedSurfaceTextureData* aData,
|
||||
TextureFlags aFlags,
|
||||
LayersIPCChannel* aAllocator);
|
||||
|
||||
~SharedSurfaceTextureClient();
|
||||
|
||||
static already_AddRefed<SharedSurfaceTextureClient>
|
||||
Create(UniquePtr<gl::SharedSurface> surf, gl::SurfaceFactory* factory,
|
||||
LayersIPCChannel* aAllocator, TextureFlags aFlags);
|
||||
|
||||
gl::SharedSurface* Surf() const {
|
||||
return static_cast<const SharedSurfaceTextureData*>(GetInternalData())->Surf();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_GFX_TEXTURECLIENT_SHAREDSURFACE_H
|
||||
1430
gfx/layers/client/TiledContentClient.cpp
Normal file
1430
gfx/layers/client/TiledContentClient.cpp
Normal file
File diff suppressed because it is too large
Load diff
545
gfx/layers/client/TiledContentClient.h
Normal file
545
gfx/layers/client/TiledContentClient.h
Normal file
|
|
@ -0,0 +1,545 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_TILEDCONTENTCLIENT_H
|
||||
#define MOZILLA_GFX_TILEDCONTENTCLIENT_H
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint16_t
|
||||
#include <algorithm> // for swap
|
||||
#include <limits>
|
||||
#include "Layers.h" // for LayerManager, etc
|
||||
#include "TiledLayerBuffer.h" // for TiledLayerBuffer
|
||||
#include "Units.h" // for CSSPoint
|
||||
#include "gfxTypes.h"
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/ipc/Shmem.h" // for Shmem
|
||||
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory
|
||||
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
|
||||
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
|
||||
#include "mozilla/layers/LayersMessages.h" // for TileDescriptor
|
||||
#include "mozilla/layers/LayersTypes.h" // for TextureDumpMode
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/TextureClientPool.h"
|
||||
#include "ClientLayerManager.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_DTOR
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ClientTiledPaintedLayer;
|
||||
class ClientLayerManager;
|
||||
|
||||
/**
|
||||
* Represent a single tile in tiled buffer. The buffer keeps tiles,
|
||||
* each tile keeps a reference to a texture client and a read-lock. This
|
||||
* read-lock is used to help implement a copy-on-write mechanism. The tile
|
||||
* should be locked before being sent to the compositor. The compositor should
|
||||
* unlock the read-lock as soon as it has finished with the buffer in the
|
||||
* TextureHost to prevent more textures being created than is necessary.
|
||||
* Ideal place to store per tile debug information.
|
||||
*/
|
||||
struct TileClient
|
||||
{
|
||||
// Placeholder
|
||||
TileClient();
|
||||
~TileClient();
|
||||
|
||||
TileClient(const TileClient& o);
|
||||
|
||||
TileClient& operator=(const TileClient& o);
|
||||
|
||||
bool operator== (const TileClient& o) const
|
||||
{
|
||||
return mFrontBuffer == o.mFrontBuffer;
|
||||
}
|
||||
|
||||
bool operator!= (const TileClient& o) const
|
||||
{
|
||||
return mFrontBuffer != o.mFrontBuffer;
|
||||
}
|
||||
|
||||
void SetTextureAllocator(TextureClientAllocator* aAllocator)
|
||||
{
|
||||
mAllocator = aAllocator;
|
||||
}
|
||||
|
||||
bool IsPlaceholderTile() const
|
||||
{
|
||||
return mBackBuffer == nullptr && mFrontBuffer == nullptr;
|
||||
}
|
||||
|
||||
void DiscardBuffers()
|
||||
{
|
||||
DiscardFrontBuffer();
|
||||
DiscardBackBuffer();
|
||||
}
|
||||
|
||||
nsExpirationState *GetExpirationState() { return &mExpirationState; }
|
||||
|
||||
TileDescriptor GetTileDescriptor();
|
||||
|
||||
/**
|
||||
* For debugging.
|
||||
*/
|
||||
void Dump(std::stringstream& aStream);
|
||||
|
||||
/**
|
||||
* Swaps the front and back buffers.
|
||||
*/
|
||||
void Flip();
|
||||
|
||||
void DumpTexture(std::stringstream& aStream, TextureDumpMode aCompress) {
|
||||
// TODO We should combine the OnWhite/OnBlack here an just output a single image.
|
||||
CompositableClient::DumpTextureClient(aStream, mFrontBuffer, aCompress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unlocked TextureClient that can be used for writing new
|
||||
* data to the tile. This may flip the front-buffer to the back-buffer if
|
||||
* the front-buffer is still locked by the host, or does not have an
|
||||
* internal buffer (and so will always be locked).
|
||||
*
|
||||
* If getting the back buffer required copying pixels from the front buffer
|
||||
* then the copied region is stored in aAddPaintedRegion so the host side
|
||||
* knows to upload it.
|
||||
*
|
||||
* If nullptr is returned, aTextureClientOnWhite is undefined.
|
||||
*/
|
||||
TextureClient* GetBackBuffer(CompositableClient&,
|
||||
const nsIntRegion& aDirtyRegion,
|
||||
gfxContentType aContent, SurfaceMode aMode,
|
||||
nsIntRegion& aAddPaintedRegion,
|
||||
RefPtr<TextureClient>* aTextureClientOnWhite);
|
||||
|
||||
void DiscardFrontBuffer();
|
||||
|
||||
void DiscardBackBuffer();
|
||||
|
||||
/* We wrap the back buffer in a class that disallows assignment
|
||||
* so that we can track when ever it changes so that we can update
|
||||
* the expiry tracker for expiring the back buffers */
|
||||
class PrivateProtector {
|
||||
public:
|
||||
void Set(TileClient * container, RefPtr<TextureClient>);
|
||||
void Set(TileClient * container, TextureClient*);
|
||||
// Implicitly convert to TextureClient* because we can't chain
|
||||
// implicit conversion that would happen on RefPtr<TextureClient>
|
||||
operator TextureClient*() const { return mBuffer; }
|
||||
RefPtr<TextureClient> operator ->() { return mBuffer; }
|
||||
private:
|
||||
PrivateProtector& operator=(const PrivateProtector &);
|
||||
RefPtr<TextureClient> mBuffer;
|
||||
} mBackBuffer;
|
||||
RefPtr<TextureClient> mBackBufferOnWhite;
|
||||
RefPtr<TextureClient> mFrontBuffer;
|
||||
RefPtr<TextureClient> mFrontBufferOnWhite;
|
||||
RefPtr<TextureClientAllocator> mAllocator;
|
||||
gfx::IntRect mUpdateRect;
|
||||
bool mWasPlaceholder;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
TimeStamp mLastUpdate;
|
||||
#endif
|
||||
nsIntRegion mInvalidFront;
|
||||
nsIntRegion mInvalidBack;
|
||||
nsExpirationState mExpirationState;
|
||||
private:
|
||||
// Copies dirty pixels from the front buffer into the back buffer,
|
||||
// and records the copied region in aAddPaintedRegion.
|
||||
void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion,
|
||||
nsIntRegion& aAddPaintedRegion);
|
||||
};
|
||||
|
||||
/**
|
||||
* This struct stores all the data necessary to perform a paint so that it
|
||||
* doesn't need to be recalculated on every repeated transaction.
|
||||
*/
|
||||
struct BasicTiledLayerPaintData {
|
||||
/*
|
||||
* The scroll offset of the content from the nearest ancestor layer that
|
||||
* represents scrollable content with a display port set.
|
||||
*/
|
||||
ParentLayerPoint mScrollOffset;
|
||||
|
||||
/*
|
||||
* The scroll offset of the content from the nearest ancestor layer that
|
||||
* represents scrollable content with a display port set, for the last
|
||||
* layer update transaction.
|
||||
*/
|
||||
ParentLayerPoint mLastScrollOffset;
|
||||
|
||||
/*
|
||||
* The transform matrix to go from this layer's Layer units to
|
||||
* the scroll ancestor's ParentLayer units. The "scroll ancestor" is
|
||||
* the closest ancestor layer which scrolls, and is used to obtain
|
||||
* the composition bounds that are relevant for this layer.
|
||||
*/
|
||||
LayerToParentLayerMatrix4x4 mTransformToCompBounds;
|
||||
|
||||
/*
|
||||
* The critical displayport of the content from the nearest ancestor layer
|
||||
* that represents scrollable content with a display port set. isNothing()
|
||||
* if a critical displayport is not set.
|
||||
*/
|
||||
Maybe<LayerIntRect> mCriticalDisplayPort;
|
||||
|
||||
/*
|
||||
* The render resolution of the document that the content this layer
|
||||
* represents is in.
|
||||
*/
|
||||
CSSToParentLayerScale2D mResolution;
|
||||
|
||||
/*
|
||||
* The composition bounds of the layer, in Layer coordinates. This is
|
||||
* used to make sure that tiled updates to regions that are visible to the
|
||||
* user are grouped coherently.
|
||||
*/
|
||||
LayerRect mCompositionBounds;
|
||||
|
||||
/*
|
||||
* Low precision updates are always executed a tile at a time in repeated
|
||||
* transactions. This counter is set to 1 on the first transaction of a low
|
||||
* precision update, and incremented for each subsequent transaction.
|
||||
*/
|
||||
uint16_t mLowPrecisionPaintCount;
|
||||
|
||||
/*
|
||||
* Whether this is the first time this layer is painting
|
||||
*/
|
||||
bool mFirstPaint : 1;
|
||||
|
||||
/*
|
||||
* Whether there is further work to complete this paint. This is used to
|
||||
* determine whether or not to repeat the transaction when painting
|
||||
* progressively.
|
||||
*/
|
||||
bool mPaintFinished : 1;
|
||||
|
||||
/*
|
||||
* Whether or not there is an async transform animation active
|
||||
*/
|
||||
bool mHasTransformAnimation : 1;
|
||||
|
||||
/*
|
||||
* Initializes/clears data to prepare for paint action.
|
||||
*/
|
||||
void ResetPaintData();
|
||||
};
|
||||
|
||||
class SharedFrameMetricsHelper
|
||||
{
|
||||
public:
|
||||
SharedFrameMetricsHelper();
|
||||
~SharedFrameMetricsHelper();
|
||||
|
||||
/**
|
||||
* This is called by the BasicTileLayer to determine if it is still interested
|
||||
* in the update of this display-port to continue. We can return true here
|
||||
* to abort the current update and continue with any subsequent ones. This
|
||||
* is useful for slow-to-render pages when the display-port starts lagging
|
||||
* behind enough that continuing to draw it is wasted effort.
|
||||
*/
|
||||
bool UpdateFromCompositorFrameMetrics(const LayerMetricsWrapper& aLayer,
|
||||
bool aHasPendingNewThebesContent,
|
||||
bool aLowPrecision,
|
||||
AsyncTransform& aViewTransform);
|
||||
|
||||
/**
|
||||
* Determines if the compositor's upcoming composition bounds has fallen
|
||||
* outside of the contents display port. If it has then the compositor
|
||||
* will start to checker board. Checker boarding is when the compositor
|
||||
* tries to composite a tile and it is not available. Historically
|
||||
* a tile with a checker board pattern was used. Now a blank tile is used.
|
||||
*/
|
||||
bool AboutToCheckerboard(const FrameMetrics& aContentMetrics,
|
||||
const FrameMetrics& aCompositorMetrics);
|
||||
private:
|
||||
bool mLastProgressiveUpdateWasLowPrecision;
|
||||
bool mProgressiveUpdateWasInDanger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide an instance of TiledLayerBuffer backed by drawable TextureClients.
|
||||
* This buffer provides an implementation of ValidateTile using a
|
||||
* thebes callback and can support painting using a single paint buffer.
|
||||
* Whether a single paint buffer is used is controlled by
|
||||
* gfxPrefs::PerTileDrawing().
|
||||
*/
|
||||
class ClientTiledLayerBuffer
|
||||
{
|
||||
public:
|
||||
ClientTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer,
|
||||
CompositableClient& aCompositableClient)
|
||||
: mPaintedLayer(aPaintedLayer)
|
||||
, mCompositableClient(aCompositableClient)
|
||||
, mLastPaintContentType(gfxContentType::COLOR)
|
||||
, mLastPaintSurfaceMode(SurfaceMode::SURFACE_OPAQUE)
|
||||
, mWasLastPaintProgressive(false)
|
||||
{}
|
||||
|
||||
virtual void PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
const nsIntRegion& aDirtyRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
bool aIsProgressive = false) = 0;
|
||||
|
||||
virtual bool SupportsProgressiveUpdate() = 0;
|
||||
virtual bool ProgressiveUpdate(nsIntRegion& aValidRegion,
|
||||
nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aOldValidRegion,
|
||||
BasicTiledLayerPaintData* aPaintData,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData) = 0;
|
||||
virtual void ResetPaintedAndValidState() = 0;
|
||||
|
||||
virtual const nsIntRegion& GetValidRegion() = 0;
|
||||
|
||||
virtual bool IsLowPrecision() const = 0;
|
||||
|
||||
virtual void Dump(std::stringstream& aStream,
|
||||
const char* aPrefix,
|
||||
bool aDumpHtml,
|
||||
TextureDumpMode aCompress) {}
|
||||
|
||||
const CSSToParentLayerScale2D& GetFrameResolution() { return mFrameResolution; }
|
||||
void SetFrameResolution(const CSSToParentLayerScale2D& aResolution) { mFrameResolution = aResolution; }
|
||||
|
||||
bool HasFormatChanged() const;
|
||||
|
||||
protected:
|
||||
void UnlockTile(TileClient& aTile);
|
||||
gfxContentType GetContentType(SurfaceMode* aMode = nullptr) const;
|
||||
|
||||
ClientTiledPaintedLayer& mPaintedLayer;
|
||||
CompositableClient& mCompositableClient;
|
||||
|
||||
gfxContentType mLastPaintContentType;
|
||||
SurfaceMode mLastPaintSurfaceMode;
|
||||
CSSToParentLayerScale2D mFrameResolution;
|
||||
|
||||
bool mWasLastPaintProgressive;
|
||||
};
|
||||
|
||||
class ClientMultiTiledLayerBuffer
|
||||
: public TiledLayerBuffer<ClientMultiTiledLayerBuffer, TileClient>
|
||||
, public ClientTiledLayerBuffer
|
||||
{
|
||||
friend class TiledLayerBuffer<ClientMultiTiledLayerBuffer, TileClient>;
|
||||
public:
|
||||
ClientMultiTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer,
|
||||
CompositableClient& aCompositableClient,
|
||||
ClientLayerManager* aManager,
|
||||
SharedFrameMetricsHelper* aHelper);
|
||||
|
||||
void PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
const nsIntRegion& aDirtyRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
bool aIsProgressive = false) override;
|
||||
|
||||
virtual bool SupportsProgressiveUpdate() override { return true; }
|
||||
/**
|
||||
* Performs a progressive update of a given tiled buffer.
|
||||
* See ComputeProgressiveUpdateRegion below for parameter documentation.
|
||||
*/
|
||||
bool ProgressiveUpdate(nsIntRegion& aValidRegion,
|
||||
nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aOldValidRegion,
|
||||
BasicTiledLayerPaintData* aPaintData,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData) override;
|
||||
|
||||
void ResetPaintedAndValidState() override {
|
||||
mPaintedRegion.SetEmpty();
|
||||
mValidRegion.SetEmpty();
|
||||
mTiles.mSize.width = 0;
|
||||
mTiles.mSize.height = 0;
|
||||
DiscardBuffers();
|
||||
mRetainedTiles.Clear();
|
||||
}
|
||||
|
||||
|
||||
const nsIntRegion& GetValidRegion() override {
|
||||
return TiledLayerBuffer::GetValidRegion();
|
||||
}
|
||||
|
||||
bool IsLowPrecision() const override {
|
||||
return TiledLayerBuffer::IsLowPrecision();
|
||||
}
|
||||
|
||||
void Dump(std::stringstream& aStream,
|
||||
const char* aPrefix,
|
||||
bool aDumpHtml,
|
||||
TextureDumpMode aCompress) override {
|
||||
TiledLayerBuffer::Dump(aStream, aPrefix, aDumpHtml, aCompress);
|
||||
}
|
||||
|
||||
void ReadLock();
|
||||
|
||||
void Release();
|
||||
|
||||
void DiscardBuffers();
|
||||
|
||||
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
|
||||
|
||||
void SetResolution(float aResolution) {
|
||||
if (mResolution == aResolution) {
|
||||
return;
|
||||
}
|
||||
|
||||
Update(nsIntRegion(), nsIntRegion(), nsIntRegion());
|
||||
mResolution = aResolution;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool ValidateTile(TileClient& aTile,
|
||||
const nsIntPoint& aTileRect,
|
||||
const nsIntRegion& dirtyRect);
|
||||
|
||||
void Update(const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
const nsIntRegion& aDirtyRegion);
|
||||
|
||||
TileClient GetPlaceholderTile() const { return TileClient(); }
|
||||
|
||||
private:
|
||||
RefPtr<ClientLayerManager> mManager;
|
||||
LayerManager::DrawPaintedLayerCallback mCallback;
|
||||
void* mCallbackData;
|
||||
|
||||
// The region that will be made valid during Update(). Once Update() is
|
||||
// completed then this is identical to mValidRegion.
|
||||
nsIntRegion mNewValidRegion;
|
||||
|
||||
SharedFrameMetricsHelper* mSharedFrameMetricsHelper;
|
||||
// When using Moz2D's CreateTiledDrawTarget we maintain a list of gfx::Tiles
|
||||
std::vector<gfx::Tile> mMoz2DTiles;
|
||||
/**
|
||||
* While we're adding tiles, this is used to keep track of the position of
|
||||
* the top-left of the top-left-most tile. When we come to wrap the tiles in
|
||||
* TiledDrawTarget we subtract the value of this member from each tile's
|
||||
* offset so that all the tiles have a positive offset, then add a
|
||||
* translation to the TiledDrawTarget to compensate. This is important so
|
||||
* that the mRect of the TiledDrawTarget is always at a positive x/y
|
||||
* position, otherwise its GetSize() methods will be broken.
|
||||
*/
|
||||
gfx::IntPoint mTilingOrigin;
|
||||
/**
|
||||
* Calculates the region to update in a single progressive update transaction.
|
||||
* This employs some heuristics to update the most 'sensible' region to
|
||||
* update at this point in time, and how large an update should be performed
|
||||
* at once to maintain visual coherency.
|
||||
*
|
||||
* aInvalidRegion is the current invalid region.
|
||||
* aOldValidRegion is the valid region of mTiledBuffer at the beginning of the
|
||||
* current transaction.
|
||||
* aRegionToPaint will be filled with the region to update. This may be empty,
|
||||
* which indicates that there is no more work to do.
|
||||
* aIsRepeated should be true if this function has already been called during
|
||||
* this transaction.
|
||||
*
|
||||
* Returns true if it should be called again, false otherwise. In the case
|
||||
* that aRegionToPaint is empty, this will return aIsRepeated for convenience.
|
||||
*/
|
||||
bool ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aOldValidRegion,
|
||||
nsIntRegion& aRegionToPaint,
|
||||
BasicTiledLayerPaintData* aPaintData,
|
||||
bool aIsRepeated);
|
||||
};
|
||||
|
||||
class TiledContentClient : public CompositableClient
|
||||
{
|
||||
public:
|
||||
TiledContentClient(ClientLayerManager* aManager,
|
||||
const char* aName = "")
|
||||
: CompositableClient(aManager->AsShadowForwarder())
|
||||
, mName(aName)
|
||||
{}
|
||||
|
||||
protected:
|
||||
~TiledContentClient()
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
|
||||
|
||||
virtual void Dump(std::stringstream& aStream,
|
||||
const char* aPrefix="",
|
||||
bool aDumpHtml=false,
|
||||
TextureDumpMode aCompress=TextureDumpMode::Compress) override;
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const override
|
||||
{
|
||||
return TextureInfo(CompositableType::CONTENT_TILED);
|
||||
}
|
||||
|
||||
|
||||
virtual ClientTiledLayerBuffer* GetTiledBuffer() = 0;
|
||||
virtual ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() = 0;
|
||||
|
||||
enum TiledBufferType {
|
||||
TILED_BUFFER,
|
||||
LOW_PRECISION_TILED_BUFFER
|
||||
};
|
||||
virtual void UpdatedBuffer(TiledBufferType aType) = 0;
|
||||
|
||||
private:
|
||||
const char* mName;
|
||||
};
|
||||
|
||||
/**
|
||||
* An implementation of TiledContentClient that supports
|
||||
* multiple tiles and a low precision buffer.
|
||||
*/
|
||||
class MultiTiledContentClient : public TiledContentClient
|
||||
{
|
||||
public:
|
||||
MultiTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer,
|
||||
ClientLayerManager* aManager);
|
||||
|
||||
protected:
|
||||
~MultiTiledContentClient()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MultiTiledContentClient);
|
||||
|
||||
mTiledBuffer.DiscardBuffers();
|
||||
mLowPrecisionTiledBuffer.DiscardBuffers();
|
||||
}
|
||||
|
||||
public:
|
||||
void ClearCachedResources() override;
|
||||
void UpdatedBuffer(TiledBufferType aType) override;
|
||||
|
||||
ClientTiledLayerBuffer* GetTiledBuffer() override { return &mTiledBuffer; }
|
||||
ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() override {
|
||||
if (mHasLowPrecision) {
|
||||
return &mLowPrecisionTiledBuffer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
SharedFrameMetricsHelper mSharedFrameMetricsHelper;
|
||||
ClientMultiTiledLayerBuffer mTiledBuffer;
|
||||
ClientMultiTiledLayerBuffer mLowPrecisionTiledBuffer;
|
||||
bool mHasLowPrecision;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue