Bug 1066280 - Add TexClient for ShSurf. - r=kamidphish,mattwoodrow
From a7c09c0f17e19fd2254cb1d7a8ddd07b327151ad Mon Sep 17 00:00:00 2001 --- gfx/2d/HelpersCairo.h | 2 + gfx/gl/GLContext.cpp | 3 +- gfx/gl/GLContext.h | 2 - gfx/gl/GLReadTexImageHelper.cpp | 21 +-- gfx/gl/GLReadTexImageHelper.h | 6 + gfx/gl/GLScreenBuffer.h | 6 +- gfx/gl/ScopedGLHelpers.cpp | 40 +++++ gfx/gl/ScopedGLHelpers.h | 26 ++- gfx/gl/SharedSurface.cpp | 94 +++++++++++ gfx/gl/SharedSurface.h | 19 +++ gfx/gl/SharedSurfaceIO.h | 4 + gfx/layers/CopyableCanvasLayer.cpp | 3 +- gfx/layers/client/CanvasClient.cpp | 276 +++++++++++++++++++++++++++++--- gfx/layers/client/CanvasClient.h | 34 ++++ gfx/layers/client/ClientCanvasLayer.cpp | 21 ++- gfx/layers/client/ClientCanvasLayer.h | 9 +- gfx/layers/client/TextureClient.cpp | 35 ++++ gfx/layers/client/TextureClient.h | 85 +++++++++- gfx/layers/composite/TextureHost.cpp | 131 ++++++++++++++- gfx/layers/composite/TextureHost.h | 64 ++++++++ gfx/layers/d3d10/CanvasLayerD3D10.cpp | 5 +- gfx/layers/ipc/LayersSurfaces.ipdlh | 5 + 22 files changed, 828 insertions(+), 63 deletions(-)
This commit is contained in:
@@ -9,10 +9,12 @@
|
||||
#include "CompositorChild.h" // for CompositorChild
|
||||
#include "GLContext.h" // for GLContext
|
||||
#include "GLScreenBuffer.h" // for GLScreenBuffer
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "SurfaceStream.h" // for SurfaceStream
|
||||
#include "SurfaceTypes.h" // for SurfaceStreamHandle
|
||||
#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
@@ -43,11 +45,18 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
|
||||
return new CanvasClient2D(aForwarder, aFlags);
|
||||
}
|
||||
#endif
|
||||
if (aType == CanvasClientGLContext) {
|
||||
|
||||
switch (aType) {
|
||||
case CanvasClientTypeShSurf:
|
||||
return new CanvasClientShSurf(aForwarder, aFlags);
|
||||
|
||||
case CanvasClientGLContext:
|
||||
aFlags |= TextureFlags::DEALLOCATE_CLIENT;
|
||||
return new CanvasClientSurfaceStream(aForwarder, aFlags);
|
||||
|
||||
default:
|
||||
return new CanvasClient2D(aForwarder, aFlags);
|
||||
}
|
||||
return new CanvasClient2D(aForwarder, aFlags);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -149,21 +158,16 @@ void
|
||||
CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
{
|
||||
aLayer->mGLContext->MakeCurrent();
|
||||
GLScreenBuffer* screen = aLayer->mGLContext->Screen();
|
||||
SurfaceStream* stream = nullptr;
|
||||
|
||||
if (aLayer->mStream) {
|
||||
stream = aLayer->mStream;
|
||||
SurfaceStream* stream = aLayer->mStream;
|
||||
MOZ_ASSERT(stream);
|
||||
|
||||
// Copy our current surface to the current producer surface in our stream, then
|
||||
// call SwapProducer to make a new buffer ready.
|
||||
stream->CopySurfaceToProducer(aLayer->mTextureSurface.get(),
|
||||
aLayer->mFactory.get());
|
||||
stream->SwapProducer(aLayer->mFactory.get(),
|
||||
gfx::IntSize(aSize.width, aSize.height));
|
||||
} else {
|
||||
stream = screen->Stream();
|
||||
}
|
||||
// Copy our current surface to the current producer surface in our stream, then
|
||||
// call SwapProducer to make a new buffer ready.
|
||||
stream->CopySurfaceToProducer(aLayer->mTextureSurface.get(),
|
||||
aLayer->mFactory.get());
|
||||
stream->SwapProducer(aLayer->mFactory.get(),
|
||||
gfx::IntSize(aSize.width, aSize.height));
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
SharedSurface* surf = stream->SwapConsumer();
|
||||
@@ -211,10 +215,12 @@ CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
} else {
|
||||
bool bufferCreated = false;
|
||||
if (!mBuffer) {
|
||||
StreamTextureClient* textureClient =
|
||||
new StreamTextureClient(mTextureInfo.mTextureFlags);
|
||||
textureClient->InitWith(stream);
|
||||
mBuffer = textureClient;
|
||||
// We need to dealloc in the client.
|
||||
TextureFlags flags = GetTextureFlags() |
|
||||
TextureFlags::DEALLOCATE_CLIENT;
|
||||
StreamTextureClient* texClient = new StreamTextureClient(flags);
|
||||
texClient->InitWith(stream);
|
||||
mBuffer = texClient;
|
||||
bufferCreated = true;
|
||||
}
|
||||
|
||||
@@ -232,5 +238,237 @@ CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
aLayer->Painted();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CanvasClientShSurf::CanvasClientShSurf(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags)
|
||||
: CanvasClient(aLayerForwarder, aFlags)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// Accelerated backends
|
||||
|
||||
static TemporaryRef<TextureClient>
|
||||
TexClientFromShSurf(SharedSurface* surf, TextureFlags baseFlags)
|
||||
{
|
||||
TextureFlags flags = baseFlags | TextureFlags::DEALLOCATE_CLIENT;
|
||||
|
||||
switch (surf->mType) {
|
||||
case SharedSurfaceType::Basic:
|
||||
return nullptr;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
case SharedSurfaceType::Gralloc:
|
||||
return GrallocTextureClientOGL::FromShSurf(surf, flags);
|
||||
#endif
|
||||
|
||||
default:
|
||||
return new ShSurfTexClient(flags, surf);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// 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
|
||||
{
|
||||
ISurfaceAllocator* const mAllocator;
|
||||
const bool mHasAlpha;
|
||||
const gfx::IntSize mSize;
|
||||
const gfx::BackendType mBackendType;
|
||||
const TextureFlags mBaseTexFlags;
|
||||
|
||||
public:
|
||||
TexClientFactory(ISurfaceAllocator* allocator, bool hasAlpha,
|
||||
const gfx::IntSize& size, gfx::BackendType backendType,
|
||||
TextureFlags baseTexFlags)
|
||||
: mAllocator(allocator)
|
||||
, mHasAlpha(hasAlpha)
|
||||
, mSize(size)
|
||||
, mBackendType(backendType)
|
||||
, mBaseTexFlags(baseTexFlags)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
TemporaryRef<BufferTextureClient> Create(gfx::SurfaceFormat format) {
|
||||
return TextureClient::CreateForRawBufferAccess(mAllocator, format,
|
||||
mSize, mBackendType,
|
||||
mBaseTexFlags);
|
||||
}
|
||||
|
||||
public:
|
||||
TemporaryRef<BufferTextureClient> CreateB8G8R8AX8() {
|
||||
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8
|
||||
: gfx::SurfaceFormat::B8G8R8X8;
|
||||
return Create(format);
|
||||
}
|
||||
|
||||
TemporaryRef<BufferTextureClient> CreateR8G8B8AX8() {
|
||||
// For now, assume that all RGBA formats are broken.
|
||||
RefPtr<BufferTextureClient> ret = CreateB8G8R8AX8();
|
||||
|
||||
if (ret) {
|
||||
ret->AddFlags(TextureFlags::RB_SWAPPED);
|
||||
}
|
||||
|
||||
return ret.forget();
|
||||
}
|
||||
};
|
||||
|
||||
static TemporaryRef<TextureClient>
|
||||
TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator,
|
||||
TextureFlags baseFlags, LayersBackend layersBackend)
|
||||
{
|
||||
auto backendType = gfx::BackendType::CAIRO;
|
||||
TexClientFactory factory(allocator, src->mHasAlpha, src->mSize, backendType,
|
||||
baseFlags);
|
||||
|
||||
RefPtr<BufferTextureClient> 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("Bad `read{Format,Type}`.");
|
||||
}
|
||||
|
||||
MOZ_ASSERT(texClient);
|
||||
if (!texClient)
|
||||
return nullptr;
|
||||
|
||||
// With a texClient, we can lock for writing.
|
||||
MOZ_ALWAYS_TRUE( texClient->Lock(OpenMode::OPEN_WRITE) );
|
||||
|
||||
uint8_t* lockedBytes = texClient->GetLockedData();
|
||||
|
||||
// ReadPixels from the current FB into lockedBits.
|
||||
auto width = src->mSize.width;
|
||||
auto height = src->mSize.height;
|
||||
|
||||
{
|
||||
ScopedPackAlignment autoAlign(gl, 4);
|
||||
|
||||
gl->raw_fReadPixels(0, 0, width, height, readFormat, readType, lockedBytes);
|
||||
}
|
||||
|
||||
// RB_SWAPPED doesn't work with D3D11. (bug 1051010)
|
||||
// RB_SWAPPED doesn't work with Basic. (bug ???????)
|
||||
bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_D3D11 ||
|
||||
layersBackend == LayersBackend::LAYERS_BASIC;
|
||||
if (texClient->HasFlags(TextureFlags::RB_SWAPPED) &&
|
||||
layersNeedsManualSwap)
|
||||
{
|
||||
size_t pixels = width * height;
|
||||
uint8_t* itr = lockedBytes;
|
||||
for (size_t i = 0; i < pixels; i++) {
|
||||
SwapRB_R8G8B8A8(itr);
|
||||
itr += 4;
|
||||
}
|
||||
|
||||
texClient->RemoveFlags(TextureFlags::RB_SWAPPED);
|
||||
}
|
||||
|
||||
texClient->Unlock();
|
||||
}
|
||||
|
||||
return texClient.forget();
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
void
|
||||
CanvasClientShSurf::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
{
|
||||
aLayer->mGLContext->MakeCurrent();
|
||||
GLScreenBuffer* screen = aLayer->mGLContext->Screen();
|
||||
|
||||
if (mFront) {
|
||||
mPrevFront = mFront;
|
||||
mFront = nullptr;
|
||||
}
|
||||
|
||||
mFront = screen->Front();
|
||||
|
||||
if (!mFront)
|
||||
return;
|
||||
|
||||
// Alright, now sort out the IPC goop.
|
||||
SharedSurface* surf = mFront->Surf();
|
||||
auto forwarder = GetForwarder();
|
||||
auto flags = GetTextureFlags() | TextureFlags::IMMUTABLE;
|
||||
|
||||
// Get a TexClient from our surf.
|
||||
RefPtr<TextureClient> newTex = TexClientFromShSurf(surf, flags);
|
||||
if (!newTex) {
|
||||
auto manager = aLayer->ClientManager();
|
||||
auto shadowForwarder = manager->AsShadowForwarder();
|
||||
auto layersBackend = shadowForwarder->GetCompositorBackendType();
|
||||
|
||||
newTex = TexClientFromReadback(surf, forwarder, flags, layersBackend);
|
||||
}
|
||||
MOZ_ASSERT(newTex);
|
||||
|
||||
// Add the new TexClient.
|
||||
MOZ_ALWAYS_TRUE( newTex->InitIPDLActor(forwarder) );
|
||||
MOZ_ASSERT(newTex->GetIPDLActor());
|
||||
|
||||
// Remove the old TexClient.
|
||||
if (mFrontTex) {
|
||||
// remove old buffer from CompositableHost
|
||||
RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker();
|
||||
// Hold TextureClient until transaction complete.
|
||||
tracker->SetTextureClient(mFrontTex);
|
||||
mFrontTex->SetRemoveFromCompositableTracker(tracker);
|
||||
// RemoveTextureFromCompositableAsync() expects CompositorChild's presence.
|
||||
GetForwarder()->RemoveTextureFromCompositableAsync(tracker, this, mFrontTex);
|
||||
|
||||
mFrontTex = nullptr;
|
||||
}
|
||||
|
||||
// Use the new TexClient.
|
||||
mFrontTex = newTex;
|
||||
|
||||
forwarder->UpdatedTexture(this, mFrontTex, nullptr);
|
||||
forwarder->UseTexture(this, mFrontTex);
|
||||
|
||||
aLayer->Painted();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user