diff --git a/content/media/omx/OmxDecoder.cpp b/content/media/omx/OmxDecoder.cpp index 76eb73c9af89..2a5f195e137f 100644 --- a/content/media/omx/OmxDecoder.cpp +++ b/content/media/omx/OmxDecoder.cpp @@ -39,8 +39,8 @@ namespace layers { VideoGraphicBuffer::VideoGraphicBuffer(const android::wp aOmxDecoder, android::MediaBuffer *aBuffer, - SurfaceDescriptor *aDescriptor) - : GraphicBufferLocked(*aDescriptor), + SurfaceDescriptor& aDescriptor) + : GraphicBufferLocked(aDescriptor), mMediaBuffer(aBuffer), mOmxDecoder(aOmxDecoder) { @@ -591,11 +591,11 @@ bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs, // Change the descriptor's size to video's size. There are cases that // GraphicBuffer's size and actual video size is different. // See Bug 850566. - const mozilla::layers::SurfaceDescriptorGralloc& grallocDesc = descriptor->get_SurfaceDescriptorGralloc(); - mozilla::layers::SurfaceDescriptor newDescriptor = mozilla::layers::SurfaceDescriptorGralloc(grallocDesc.bufferParent(), - grallocDesc.bufferChild(), nsIntSize(mVideoWidth, mVideoHeight), grallocDesc.external()); + mozilla::layers::SurfaceDescriptorGralloc newDescriptor = descriptor->get_SurfaceDescriptorGralloc(); + newDescriptor.size() = nsIntSize(mVideoWidth, mVideoHeight); - aFrame->mGraphicBuffer = new mozilla::layers::VideoGraphicBuffer(this, mVideoBuffer, &newDescriptor); + mozilla::layers::SurfaceDescriptor descWrapper(newDescriptor); + aFrame->mGraphicBuffer = new mozilla::layers::VideoGraphicBuffer(this, mVideoBuffer, descWrapper); aFrame->mRotation = mVideoRotation; aFrame->mTimeUs = timeUs; aFrame->mKeyFrame = keyFrame; diff --git a/content/media/omx/OmxDecoder.h b/content/media/omx/OmxDecoder.h index fa2783737cfd..f2361e48a503 100644 --- a/content/media/omx/OmxDecoder.h +++ b/content/media/omx/OmxDecoder.h @@ -27,7 +27,7 @@ class VideoGraphicBuffer : public GraphicBufferLocked { public: VideoGraphicBuffer(const android::wp aOmxDecoder, android::MediaBuffer *aBuffer, - SurfaceDescriptor *aDescriptor); + SurfaceDescriptor& aDescriptor); ~VideoGraphicBuffer(); void Unlock(); }; diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index aa6247e6d32c..4aa07fb58ffd 100644 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -10,6 +10,10 @@ #include "GLContext.h" #include "SharedSurfaceGL.h" #include "SurfaceStream.h" +#ifdef MOZ_B2G +#include "SharedSurfaceGralloc.h" +#include "nsXULAppAPI.h" +#endif using namespace mozilla::gfx; @@ -27,7 +31,20 @@ GLScreenBuffer::Create(GLContext* gl, return nullptr; } - SurfaceFactory_GL* factory = new SurfaceFactory_Basic(gl, caps); + SurfaceFactory_GL* factory = nullptr; + +#ifdef MOZ_B2G + /* On B2G, we want a Gralloc factory, and we want one right at the start */ + if (!factory && + XRE_GetProcessType() != GeckoProcessType_Default) + { + factory = new SurfaceFactory_Gralloc(gl, caps); + } +#endif + + if (!factory) + factory = new SurfaceFactory_Basic(gl, caps); + SurfaceStream* stream = SurfaceStream::CreateForType( SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread, caps.preserve), diff --git a/gfx/gl/Makefile.in b/gfx/gl/Makefile.in index acc6c588eba9..e85264225e92 100644 --- a/gfx/gl/Makefile.in +++ b/gfx/gl/Makefile.in @@ -37,6 +37,11 @@ CPPSRCS = \ SurfaceStream.cpp \ $(NULL) +ifdef MOZ_B2G +CPPSRCS += SharedSurfaceGralloc.cpp +EXPORTS += SharedSurfaceGralloc.h +endif + GL_PROVIDER = Null ifeq ($(MOZ_WIDGET_TOOLKIT),windows) @@ -110,6 +115,8 @@ endif include $(topsrcdir)/config/rules.mk +include $(topsrcdir)/ipc/chromium/chromium-config.mk + DEFINES := $(filter-out -DUNICODE,$(DEFINES)) CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PIXMAN_CFLAGS) $(TK_CFLAGS) diff --git a/gfx/gl/SharedSurfaceGralloc.cpp b/gfx/gl/SharedSurfaceGralloc.cpp new file mode 100644 index 000000000000..a788d06eb571 --- /dev/null +++ b/gfx/gl/SharedSurfaceGralloc.cpp @@ -0,0 +1,165 @@ +/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ +/* 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/Preferences.h" + +#include "SharedSurfaceGralloc.h" + +#include "GLContext.h" +#include "SharedSurfaceGL.h" +#include "SurfaceFactory.h" +#include "GLLibraryEGL.h" +#include "mozilla/layers/ShadowLayers.h" + +#include "ui/GraphicBuffer.h" +#include "../layers/ipc/ShadowLayers.h" + +#define DEBUG_GRALLOC +#ifdef DEBUG_GRALLOC +#define DEBUG_PRINT(...) do { printf_stderr(__VA_ARGS__); } while (0) +#else +#define DEBUG_PRINT(...) do { } while (0) +#endif + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace gl; +using namespace layers; +using namespace android; + +static bool sForceReadPixelsToFence = false; + + +SurfaceFactory_Gralloc::SurfaceFactory_Gralloc(GLContext* prodGL, + const SurfaceCaps& caps, + layers::ISurfaceAllocator* allocator) + : SurfaceFactory_GL(prodGL, SharedSurfaceType::Gralloc, caps) +{ + if (!allocator) { + allocator = layers::ShadowLayerForwarder::GetActiveForwarder(); + } + + mAllocator = allocator; +} + +SharedSurface_Gralloc* +SharedSurface_Gralloc::Create(GLContext* prodGL, + const GLFormats& formats, + const gfxIntSize& size, + bool hasAlpha, + ISurfaceAllocator* allocator) +{ + static bool runOnce = true; + if (runOnce) { + sForceReadPixelsToFence = false; + mozilla::Preferences::AddBoolVarCache(&sForceReadPixelsToFence, + "gfx.gralloc.fence-with-readpixels"); + runOnce = false; + } + + GLLibraryEGL* egl = prodGL->GetLibraryEGL(); + MOZ_ASSERT(egl); + + DEBUG_PRINT("SharedSurface_Gralloc::Create -------\n"); + + if (!HasExtensions(egl, prodGL)) + return nullptr; + + SurfaceDescriptor baseDesc; + SurfaceDescriptorGralloc desc; + + gfxASurface::gfxContentType type = hasAlpha ? gfxASurface::CONTENT_COLOR_ALPHA + : gfxASurface::CONTENT_COLOR; + if (!allocator->AllocSurfaceDescriptorWithCaps(size, type, USING_GL_RENDERING_ONLY, &baseDesc)) + return false; + + if (baseDesc.type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) { + allocator->DestroySharedSurface(&baseDesc); + return false; + } + + desc = baseDesc.get_SurfaceDescriptorGralloc(); + + sp buffer = GrallocBufferActor::GetFrom(desc); + + EGLDisplay display = egl->Display(); + EGLClientBuffer clientBuffer = buffer->getNativeBuffer(); + EGLint attrs[] = { + LOCAL_EGL_NONE, LOCAL_EGL_NONE + }; + EGLImage image = egl->fCreateImage(display, + EGL_NO_CONTEXT, + LOCAL_EGL_NATIVE_BUFFER_ANDROID, + clientBuffer, attrs); + if (!image) { + allocator->DestroySharedSurface(&baseDesc); + return nullptr; + } + + prodGL->MakeCurrent(); + GLuint prodTex = 0; + prodGL->fGenTextures(1, &prodTex); + ScopedBindTexture autoTex(prodGL, prodTex); + prodGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, image); + + egl->fDestroyImage(display, image); + + SharedSurface_Gralloc *surf = new SharedSurface_Gralloc(prodGL, size, hasAlpha, egl, allocator, desc, prodTex); + + DEBUG_PRINT("SharedSurface_Gralloc::Create: success -- surface %p, GraphicBuffer %p.\n", surf, buffer.get()); + + return surf; +} + + +bool +SharedSurface_Gralloc::HasExtensions(GLLibraryEGL* egl, GLContext* gl) +{ + return egl->HasKHRImageBase() && + gl->IsExtensionSupported(GLContext::OES_EGL_image); +} + +SharedSurface_Gralloc::~SharedSurface_Gralloc() +{ + + DEBUG_PRINT("[SharedSurface_Gralloc %p] destroyed\n", this); + + mGL->MakeCurrent(); + mGL->fDeleteTextures(1, (GLuint*)&mProdTex); + + SurfaceDescriptor desc(mDesc); + mAllocator->DestroySharedSurface(&desc); +} + +void +SharedSurface_Gralloc::Fence() +{ + // We should be able to rely on genlock write locks/read locks. + // But they're broken on some configs, and even a glFinish doesn't + // work. glReadPixels seems to, though. + if (sForceReadPixelsToFence) { + mGL->MakeCurrent(); + // read a 1x1 pixel + unsigned char pixels[4]; + mGL->fReadPixels(0, 0, 1, 1, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, &pixels[0]); + } +} + +bool +SharedSurface_Gralloc::WaitSync() +{ + return true; +} + +void +SharedSurface_Gralloc::LockProdImpl() +{ +} + +void +SharedSurface_Gralloc::UnlockProdImpl() +{ +} + diff --git a/gfx/gl/SharedSurfaceGralloc.h b/gfx/gl/SharedSurfaceGralloc.h new file mode 100644 index 000000000000..22ef55ff8f24 --- /dev/null +++ b/gfx/gl/SharedSurfaceGralloc.h @@ -0,0 +1,111 @@ +/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ +/* 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 SHARED_SURFACE_GRALLOC_H_ +#define SHARED_SURFACE_GRALLOC_H_ + +#include "SharedSurfaceGL.h" +#include "mozilla/layers/LayersSurfaces.h" + +namespace mozilla { +namespace layers { +class ISurfaceAllocator; +class SurfaceDescriptorGralloc; +} + +namespace gl { +class GLContext; +class GLLibraryEGL; + +class SharedSurface_Gralloc + : public SharedSurface_GL +{ +public: + static SharedSurface_Gralloc* Create(GLContext* prodGL, + const GLFormats& formats, + const gfxIntSize& size, + bool hasAlpha, + layers::ISurfaceAllocator* allocator); + + static SharedSurface_Gralloc* Cast(SharedSurface* surf) { + MOZ_ASSERT(surf->Type() == SharedSurfaceType::Gralloc); + + return (SharedSurface_Gralloc*)surf; + } + +protected: + GLLibraryEGL* const mEGL; + layers::ISurfaceAllocator* const mAllocator; + // We keep the SurfaceDescriptor around, because we'll end up + // using it often and it's handy to do so. The actual + // GraphicBuffer is kept alive by the sp in + // GrallocBufferActor; the actor will stay alive until we + // explicitly destroy this descriptor (and thus deallocate the + // actor) it in the destructor of this class. This is okay to do + // on the client, but is very bad to do on the server (because on + // the client, the actor has no chance of going away unless the + // whole app died). + layers::SurfaceDescriptorGralloc mDesc; + const GLuint mProdTex; + + SharedSurface_Gralloc(GLContext* prodGL, + const gfxIntSize& size, + bool hasAlpha, + GLLibraryEGL* egl, + layers::ISurfaceAllocator* allocator, + layers::SurfaceDescriptorGralloc& desc, + GLuint prodTex) + : SharedSurface_GL(SharedSurfaceType::Gralloc, + AttachmentType::GLTexture, + prodGL, + size, + hasAlpha) + , mEGL(egl) + , mAllocator(allocator) + , mDesc(desc) + , mProdTex(prodTex) + {} + + static bool HasExtensions(GLLibraryEGL* egl, GLContext* gl); + +public: + virtual ~SharedSurface_Gralloc(); + + virtual void Fence(); + virtual bool WaitSync(); + + virtual void LockProdImpl(); + virtual void UnlockProdImpl(); + + virtual GLuint Texture() const { + return mProdTex; + } + + layers::SurfaceDescriptorGralloc& GetDescriptor() { + return mDesc; + } +}; + +class SurfaceFactory_Gralloc + : public SurfaceFactory_GL +{ +protected: + layers::ISurfaceAllocator* mAllocator; + +public: + SurfaceFactory_Gralloc(GLContext* prodGL, + const SurfaceCaps& caps, + layers::ISurfaceAllocator* allocator = nullptr); + + virtual SharedSurface* CreateShared(const gfxIntSize& size) { + bool hasAlpha = mReadCaps.alpha; + return SharedSurface_Gralloc::Create(mGL, mFormats, size, hasAlpha, mAllocator); + } +}; + +} /* namespace gl */ +} /* namespace mozilla */ + +#endif /* SHARED_SURFACE_GRALLOC_H_ */ diff --git a/gfx/layers/CompositorTypes.h b/gfx/layers/CompositorTypes.h index 07b2f95cb1ab..64a60600736e 100644 --- a/gfx/layers/CompositorTypes.h +++ b/gfx/layers/CompositorTypes.h @@ -36,6 +36,9 @@ const TextureFlags NewTile = 0x10; const TextureFlags HostRelease = 0x20; // The texture is part of a component-alpha pair const TextureFlags ComponentAlpha = 0x40; +// The shared resources are owned by client +const TextureFlags OwnByClient = 0x80; + /** * The kind of memory held by the texture client/host pair. This will diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index 13e06d5dd909..7166df2be83f 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -14,6 +14,9 @@ #include "SurfaceStream.h" #include "SharedSurfaceGL.h" #include "SharedSurfaceEGL.h" +#ifdef MOZ_B2G +#include "SharedSurfaceGralloc.h" +#endif #include "GeckoProfiler.h" #include "nsXULAppAPI.h" diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index f9dc486a52fe..9f232ce54e7a 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -11,6 +11,10 @@ #include "nsXULAppAPI.h" #include "GLContext.h" #include "SurfaceStream.h" +#include "SharedSurface.h" +#ifdef MOZ_B2G +#include "SharedSurfaceGralloc.h" +#endif using namespace mozilla::gl; @@ -95,9 +99,33 @@ CanvasClientWebGL::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) mTextureClient->EnsureAllocated(aSize, gfxASurface::CONTENT_COLOR); GLScreenBuffer* screen = aLayer->mGLContext->Screen(); - SurfaceStreamHandle handle = screen->Stream()->GetShareHandle(); + SurfaceStream* stream = screen->Stream(); - mTextureClient->SetDescriptor(SurfaceStreamDescriptor(handle, false)); + bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default); + if (isCrossProcess) { + // swap staging -> consumer so we can send it to the compositor + SharedSurface* surf = stream->SwapConsumer(); + if (!surf) { + printf_stderr("surf is null post-SwapConsumer!\n"); + return; + } + +#ifdef MOZ_B2G + if (surf->Type() != SharedSurfaceType::Gralloc) { + printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!"); + return; + } + + SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf); + mTextureClient->SetDescriptor(grallocSurf->GetDescriptor()); +#else + printf_stderr("isCrossProcess, but not MOZ_B2G! Someone needs to write some code!"); + MOZ_ASSERT(false); +#endif + } else { + SurfaceStreamHandle handle = stream->GetShareHandle(); + mTextureClient->SetDescriptor(SurfaceStreamDescriptor(handle, false)); + } aLayer->Painted(); } diff --git a/gfx/layers/client/ClientCanvasLayer.cpp b/gfx/layers/client/ClientCanvasLayer.cpp index f8b129491d17..24b18fe16a62 100644 --- a/gfx/layers/client/ClientCanvasLayer.cpp +++ b/gfx/layers/client/ClientCanvasLayer.cpp @@ -8,6 +8,9 @@ #include "SurfaceStream.h" #include "SharedSurfaceGL.h" #include "SharedSurfaceEGL.h" +#ifdef MOZ_B2G +#include "SharedSurfaceGralloc.h" +#endif using namespace mozilla::gl; @@ -37,7 +40,12 @@ ClientCanvasLayer::Initialize(const Data& aData) factory = SurfaceFactory_EGLImage::Create(mGLContext, screen->Caps()); } else { // [Basic/OGL Layers, OOPC] WebGL layer init. (Out Of Process Compositing) - // Fall back to readback. +#ifdef MOZ_B2G + factory = new SurfaceFactory_Gralloc(mGLContext, screen->Caps(), ClientManager()); +#else + // we could do readback here maybe + NS_NOTREACHED("isCrossProcess but not on B2G!"); +#endif } } else { // [Basic Layers, OMTC] WebGL layer init. @@ -70,6 +78,15 @@ ClientCanvasLayer::RenderLayer() if (mNeedsYFlip) { flags |= NeedsYFlip; } + + bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default); + //Append OwnByClient flag for streaming buffer under OOPC case + if (isCrossProcess && mGLContext) { + GLScreenBuffer* screen = mGLContext->Screen(); + if (screen && screen->Stream()) { + flags |= OwnByClient; + } + } mCanvasClient = CanvasClient::CreateCanvasClient(GetCompositableClientType(), ClientManager(), flags); if (!mCanvasClient) { diff --git a/gfx/layers/client/ClientCanvasLayer.h b/gfx/layers/client/ClientCanvasLayer.h index 488bddc23731..b0fe3273f543 100644 --- a/gfx/layers/client/ClientCanvasLayer.h +++ b/gfx/layers/client/ClientCanvasLayer.h @@ -73,7 +73,7 @@ protected: CompositableType GetCompositableClientType() { - if (mGLContext && XRE_GetProcessType() == GeckoProcessType_Default) { + if (mGLContext) { return BUFFER_IMAGE_BUFFERED; } return BUFFER_IMAGE_SINGLE; diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index a71029f68f00..e62067660425 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -77,10 +77,12 @@ TextureHost::TextureHost() TextureHost::~TextureHost() { if (mBuffer) { - if (mDeAllocator) { - mDeAllocator->DestroySharedSurface(mBuffer); - } else { - MOZ_ASSERT(mBuffer->type() == SurfaceDescriptor::Tnull_t); + if (!(mFlags & OwnByClient)) { + if (mDeAllocator) { + mDeAllocator->DestroySharedSurface(mBuffer); + } else { + MOZ_ASSERT(mBuffer->type() == SurfaceDescriptor::Tnull_t); + } } delete mBuffer; } diff --git a/gfx/layers/ipc/ISurfaceAllocator.h b/gfx/layers/ipc/ISurfaceAllocator.h index fa330b723080..9ac28db34dc4 100644 --- a/gfx/layers/ipc/ISurfaceAllocator.h +++ b/gfx/layers/ipc/ISurfaceAllocator.h @@ -44,7 +44,11 @@ enum BufferCapabilities { * The allocated buffer must be efficiently mappable as a * gfxImageSurface. */ - MAP_AS_IMAGE_SURFACE = 1 << 0 + MAP_AS_IMAGE_SURFACE = 1 << 0, + /** + * The allocated buffer will be used for GL rendering only + */ + USING_GL_RENDERING_ONLY = 1 << 1 }; class SurfaceDescriptor; @@ -114,8 +118,11 @@ protected: gfxASurface::gfxContentType aContent, uint32_t aCaps, SurfaceDescriptor* aBuffer); + + // method that does the actual allocation work virtual PGrallocBufferChild* AllocGrallocBuffer(const gfxIntSize& aSize, - gfxASurface::gfxContentType aContent, + uint32_t aFormat, + uint32_t aUsage, MaybeMagicGrallocBufferHandle* aHandle) { return nullptr; diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index c5d60c1dba40..32f8c8e26292 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -577,7 +577,7 @@ ImageBridgeChild::AllocSurfaceDescriptorGrallocNow(const gfxIntSize& aSize, GrallocBufferActor* gba = static_cast(gc); gba->InitFromHandle(handle.get_MagicGrallocBufferHandle()); - *aBuffer = SurfaceDescriptorGralloc(nullptr, gc, aSize, /* external */ false); + *aBuffer = SurfaceDescriptorGralloc(nullptr, gc, aSize, /* external */ false, /* swapRB */ false); return true; #else NS_RUNTIMEABORT("No gralloc buffers for you"); @@ -744,13 +744,14 @@ ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) PGrallocBufferChild* ImageBridgeChild::AllocGrallocBuffer(const gfxIntSize& aSize, - gfxASurface::gfxContentType aContent, + uint32_t aFormat, + uint32_t aUsage, MaybeMagicGrallocBufferHandle* aHandle) { #ifdef MOZ_WIDGET_GONK return SendPGrallocBufferConstructor(aSize, - aContent, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + aFormat, + aUsage, aHandle); #else NS_RUNTIMEABORT("not implemented"); diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index 723a9719f04c..058d38a31777 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -199,7 +199,7 @@ public: */ bool AllocSurfaceDescriptorGrallocNow(const gfxIntSize& aSize, - const uint32_t& aContent, + const uint32_t& aFormat, const uint32_t& aUsage, SurfaceDescriptor* aBuffer); @@ -337,8 +337,9 @@ protected: CompositableTransaction* mTxn; + // ISurfaceAllocator virtual PGrallocBufferChild* AllocGrallocBuffer(const gfxIntSize& aSize, - gfxASurface::gfxContentType aContent, + uint32_t aFormat, uint32_t aUsage, MaybeMagicGrallocBufferHandle* aHandle) MOZ_OVERRIDE; }; diff --git a/gfx/layers/ipc/LayerTransactionChild.cpp b/gfx/layers/ipc/LayerTransactionChild.cpp index f9d51fd2a1b1..9073477e4445 100644 --- a/gfx/layers/ipc/LayerTransactionChild.cpp +++ b/gfx/layers/ipc/LayerTransactionChild.cpp @@ -24,8 +24,9 @@ LayerTransactionChild::Destroy() PGrallocBufferChild* LayerTransactionChild::AllocPGrallocBuffer(const gfxIntSize&, - const gfxContentType&, - MaybeMagicGrallocBufferHandle*) + const uint32_t&, + const uint32_t&, + MaybeMagicGrallocBufferHandle*) { #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC return GrallocBufferActor::Create(); diff --git a/gfx/layers/ipc/LayerTransactionChild.h b/gfx/layers/ipc/LayerTransactionChild.h index edfa3890579f..ca01d9cb177d 100644 --- a/gfx/layers/ipc/LayerTransactionChild.h +++ b/gfx/layers/ipc/LayerTransactionChild.h @@ -30,7 +30,8 @@ public: protected: virtual PGrallocBufferChild* - AllocPGrallocBuffer(const gfxIntSize&, const gfxContentType&, + AllocPGrallocBuffer(const gfxIntSize&, + const uint32_t&, const uint32_t&, MaybeMagicGrallocBufferHandle*) MOZ_OVERRIDE; virtual bool DeallocPGrallocBuffer(PGrallocBufferChild* actor) MOZ_OVERRIDE; diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 6d9f0836ace7..4f7556089cb1 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -464,11 +464,12 @@ LayerTransactionParent::RecvClearCachedResources() PGrallocBufferParent* LayerTransactionParent::AllocPGrallocBuffer(const gfxIntSize& aSize, - const gfxContentType& aContent, + const uint32_t& aFormat, + const uint32_t& aUsage, MaybeMagicGrallocBufferHandle* aOutHandle) { #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC - return GrallocBufferActor::Create(aSize, aContent, aOutHandle); + return GrallocBufferActor::Create(aSize, aFormat, aUsage, aOutHandle); #else NS_RUNTIMEABORT("No gralloc buffers for you"); return nullptr; diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h index f63946214ed4..b1902d00add8 100644 --- a/gfx/layers/ipc/LayerTransactionParent.h +++ b/gfx/layers/ipc/LayerTransactionParent.h @@ -78,7 +78,8 @@ protected: virtual bool RecvClearCachedResources() MOZ_OVERRIDE; virtual PGrallocBufferParent* - AllocPGrallocBuffer(const gfxIntSize& aSize, const gfxContentType& aContent, + AllocPGrallocBuffer(const gfxIntSize& aSize, + const uint32_t& aFormat, const uint32_t& aUsage, MaybeMagicGrallocBufferHandle* aOutHandle) MOZ_OVERRIDE; virtual bool DeallocPGrallocBuffer(PGrallocBufferParent* actor) MOZ_OVERRIDE; diff --git a/gfx/layers/ipc/LayersSurfaces.ipdlh b/gfx/layers/ipc/LayersSurfaces.ipdlh index b0aa97cfa002..a574c7356677 100644 --- a/gfx/layers/ipc/LayersSurfaces.ipdlh +++ b/gfx/layers/ipc/LayersSurfaces.ipdlh @@ -62,6 +62,17 @@ struct SurfaceDescriptorGralloc { * prevent its consumer from mistakenly freeing the buffer. */ bool external; + + /** + * This gralloc buffer will be treated as if the RB bytes are swapped. + * This is useful for rendering using Cairo/Thebes, because there is no + * BGRX Android pixel format, and so we have to do byte swapping. + * + * For example, if the GraphicBuffer has an Android pixel format of + * PIXEL_FORMAT_RGBA_8888 and isRBSwapped is true, when it is sampled + * (for example, with GL), a BGRA shader should be used. + */ + bool isRBSwapped; }; struct SurfaceStreamDescriptor { diff --git a/gfx/layers/ipc/PLayerTransaction.ipdl b/gfx/layers/ipc/PLayerTransaction.ipdl index 566a80a6cef0..649b18cbc418 100644 --- a/gfx/layers/ipc/PLayerTransaction.ipdl +++ b/gfx/layers/ipc/PLayerTransaction.ipdl @@ -43,8 +43,30 @@ parent: * Only the parent side has privileges to allocate the buffer. * Allocation may fail (pmem is a scarce resource), and if so null_t * is returned. + * + * |format| is an Android PixelFormat (see PixelFormat.h) + * + * commonly used PixelFormats are: + * PIXEL_FORMAT_RGBA_8888 + * PIXEL_FORMAT_RGBX_8888 + * PIXEL_FORMAT_BGRA_8888 + * + * Note that SurfaceDescriptorGralloc has a "isRBSwapped" boolean + * that can treat the R/B bytes as swapped when they are rendered + * to the screen, to help with matching the native pixel format + * of other rendering engines. + * + * |usage| is a USAGE_* mask (see GraphicBuffer.h) + * + * commonly used USAGE flags are: + * USAGE_SW_READ_OFTEN | USAGE_SW_WRITE_OFTEN | USAGE_HW_TEXTURE + * - used for software rendering to a buffer which the compositor + * treats as a texture + * USAGE_HW_RENDER | USAGE_HW_TEXTURE + * - used for GL rendering to a buffer which the compositor + * treats as a texture */ - sync PGrallocBuffer(gfxIntSize size, gfxContentType content) + sync PGrallocBuffer(gfxIntSize size, uint32_t format, uint32_t usage) returns (MaybeMagicGrallocBufferHandle handle); async PLayer(); async PCompositable(TextureInfo aTextureInfo); diff --git a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp index e1a96fd6273f..9f94c267588b 100644 --- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp +++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp @@ -146,6 +146,31 @@ PixelFormatForImageFormat(gfxASurface::gfxImageFormat aFormat) return gfxASurface::ImageFormatARGB32; } +static size_t +BytesPerPixelForPixelFormat(android::PixelFormat aFormat) +{ + switch (aFormat) { + case PIXEL_FORMAT_RGBA_8888: + case PIXEL_FORMAT_RGBX_8888: + case PIXEL_FORMAT_BGRA_8888: + return 4; + case PIXEL_FORMAT_RGB_888: + return 3; + case PIXEL_FORMAT_RGB_565: + case PIXEL_FORMAT_RGBA_5551: + case PIXEL_FORMAT_RGBA_4444: + case PIXEL_FORMAT_LA_88: + return 2; + case PIXEL_FORMAT_L_8: + case PIXEL_FORMAT_A_8: + case PIXEL_FORMAT_RGB_332: + return 1; + default: + MOZ_NOT_REACHED("Unknown gralloc pixel format"); + } + return gfxASurface::ImageFormatARGB32; +} + static android::PixelFormat PixelFormatForContentType(gfxASurface::gfxContentType aContentType) { @@ -197,28 +222,32 @@ GrallocBufferActor::~GrallocBufferActor() /*static*/ PGrallocBufferParent* GrallocBufferActor::Create(const gfxIntSize& aSize, - const gfxContentType& aContent, + const uint32_t& aFormat, + const uint32_t& aUsage, MaybeMagicGrallocBufferHandle* aOutHandle) { PROFILER_LABEL("GrallocBufferActor", "Create"); GrallocBufferActor* actor = new GrallocBufferActor(); *aOutHandle = null_t(); - android::PixelFormat format = PixelFormatForContentType(aContent); - sp buffer( - new GraphicBuffer(aSize.width, aSize.height, format, - GraphicBuffer::USAGE_SW_READ_OFTEN | - GraphicBuffer::USAGE_SW_WRITE_OFTEN | - GraphicBuffer::USAGE_HW_TEXTURE)); + uint32_t format = aFormat; + uint32_t usage = aUsage; + + if (format == 0 || usage == 0) { + printf_stderr("GrallocBufferActor::Create -- format and usage must be non-zero"); + return actor; + } + + sp buffer(new GraphicBuffer(aSize.width, aSize.height, format, usage)); if (buffer->initCheck() != OK) return actor; - size_t bpp = gfxASurface::BytePerPixelFromFormat( - gfxPlatform::GetPlatform()->OptimalFormatForContent(aContent)); + size_t bpp = BytesPerPixelForPixelFormat(format); actor->mAllocBytes = aSize.width * aSize.height * bpp; sCurrentAlloc += actor->mAllocBytes; actor->mGraphicBuffer = buffer; *aOutHandle = MagicGrallocBufferHandle(buffer); + return actor; } @@ -261,24 +290,6 @@ LayerManagerComposite::PlatformSyncBeforeReplyUpdate() // Nothing to be done for gralloc. } -/*static*/ PGrallocBufferParent* -GrallocBufferActor::Create(const gfxIntSize& aSize, - const uint32_t& aFormat, - const uint32_t& aUsage, - MaybeMagicGrallocBufferHandle* aOutHandle) -{ - GrallocBufferActor* actor = new GrallocBufferActor(); - *aOutHandle = null_t(); - sp buffer( - new GraphicBuffer(aSize.width, aSize.height, aFormat, aUsage)); - if (buffer->initCheck() != OK) - return actor; - - actor->mGraphicBuffer = buffer; - *aOutHandle = MagicGrallocBufferHandle(buffer); - return actor; -} - bool ISurfaceAllocator::PlatformDestroySharedSurface(SurfaceDescriptor* aSurface) { @@ -322,10 +333,11 @@ GrallocBufferActor::InitFromHandle(const MagicGrallocBufferHandle& aHandle) PGrallocBufferChild* ShadowLayerForwarder::AllocGrallocBuffer(const gfxIntSize& aSize, - gfxASurface::gfxContentType aContent, + uint32_t aFormat, + uint32_t aUsage, MaybeMagicGrallocBufferHandle* aHandle) { - return mShadowManager->SendPGrallocBufferConstructor(aSize, aContent, aHandle); + return mShadowManager->SendPGrallocBufferConstructor(aSize, aFormat, aUsage, aHandle); } bool @@ -345,7 +357,31 @@ ISurfaceAllocator::PlatformAllocSurfaceDescriptor(const gfxIntSize& aSize, // Gralloc buffers are efficiently mappable as gfxImageSurface, so // no need to check |aCaps & MAP_AS_IMAGE_SURFACE|. MaybeMagicGrallocBufferHandle handle; - PGrallocBufferChild* gc = AllocGrallocBuffer(aSize, aContent, &handle); + PGrallocBufferChild* gc; + bool defaultRBSwap; + + if (aCaps & USING_GL_RENDERING_ONLY) { + gc = AllocGrallocBuffer(aSize, + PixelFormatForContentType(aContent), + GraphicBuffer::USAGE_HW_RENDER | + GraphicBuffer::USAGE_HW_TEXTURE, + &handle); + // If you're allocating for USING_GL_RENDERING_ONLY, then we don't flag + // this for RB swap. + defaultRBSwap = false; + } else { + gc = AllocGrallocBuffer(aSize, + PixelFormatForContentType(aContent), + GraphicBuffer::USAGE_SW_READ_OFTEN | + GraphicBuffer::USAGE_SW_WRITE_OFTEN | + GraphicBuffer::USAGE_HW_TEXTURE, + &handle); + // But if you're allocating for non-GL-only rendering, we flag for + // RB swap to preserve old behaviour and proper interaction with + // cairo. + defaultRBSwap = true; + } + if (!gc) { NS_ERROR("GrallocBufferConstructor failed by returned null"); return false; @@ -358,7 +394,9 @@ ISurfaceAllocator::PlatformAllocSurfaceDescriptor(const gfxIntSize& aSize, GrallocBufferActor* gba = static_cast(gc); gba->InitFromHandle(handle.get_MagicGrallocBufferHandle()); - *aBuffer = SurfaceDescriptorGralloc(nullptr, gc, aSize, /* external */ false); + *aBuffer = SurfaceDescriptorGralloc(nullptr, gc, aSize, + /* external */ false, + defaultRBSwap); return true; } diff --git a/gfx/layers/ipc/ShadowLayerUtilsGralloc.h b/gfx/layers/ipc/ShadowLayerUtilsGralloc.h index aca155a7aa3c..011e2f14804b 100644 --- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.h +++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.h @@ -71,10 +71,6 @@ class GrallocBufferActor : public PGrallocBufferChild public: virtual ~GrallocBufferActor(); - static PGrallocBufferParent* - Create(const gfxIntSize& aSize, const gfxContentType& aContent, - MaybeMagicGrallocBufferHandle* aOutHandle); - static PGrallocBufferParent* Create(const gfxIntSize& aSize, const uint32_t& aFormat, const uint32_t& aUsage, MaybeMagicGrallocBufferHandle* aOutHandle); diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index 23f2e9cffd2d..94e1fc4041b4 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -36,6 +36,9 @@ using namespace mozilla::dom; namespace mozilla { namespace layers { +// static +ShadowLayerForwarder* ShadowLayerForwarder::sActiveForwarder = nullptr; + typedef nsTArray BufferArray; typedef std::vector EditVector; typedef std::set ShadowableLayerSet; @@ -170,12 +173,18 @@ ShadowLayerForwarder::ShadowLayerForwarder() , mDrawColoredBorders(false) { mTxn = new Transaction(); + + MOZ_ASSERT(!sActiveForwarder); + sActiveForwarder = this; } ShadowLayerForwarder::~ShadowLayerForwarder() { NS_ABORT_IF_FALSE(mTxn->Finished(), "unfinished transaction?"); delete mTxn; + + MOZ_ASSERT(this == sActiveForwarder); + sActiveForwarder = nullptr; } void diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h index 277e41523c2b..53a562069cd0 100644 --- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -138,6 +138,14 @@ class ShadowLayerForwarder : public CompositableForwarder friend class TextureClientShmem; friend class ContentClientIncremental; +private: + static ShadowLayerForwarder* sActiveForwarder; + +public: + static ShadowLayerForwarder* GetActiveForwarder() { + return sActiveForwarder; + } + public: virtual ~ShadowLayerForwarder(); @@ -388,8 +396,10 @@ protected: PLayerTransactionChild* mShadowManager; #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC + // from ISurfaceAllocator virtual PGrallocBufferChild* AllocGrallocBuffer(const gfxIntSize& aSize, - gfxASurface::gfxContentType aContent, + uint32_t aFormat, + uint32_t aUsage, MaybeMagicGrallocBufferHandle* aHandle) MOZ_OVERRIDE; #endif diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index fb06c98502a3..508634bec0b1 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -639,13 +639,16 @@ TiledTextureHostOGL::Lock() #ifdef MOZ_WIDGET_GONK static gfx::SurfaceFormat -SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat) +SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat, + bool swapRB = false) { switch (aFormat) { + case android::PIXEL_FORMAT_BGRA_8888: + return swapRB ? FORMAT_R8G8B8A8 : FORMAT_B8G8R8A8; case android::PIXEL_FORMAT_RGBA_8888: - return FORMAT_B8G8R8A8; + return swapRB ? FORMAT_B8G8R8A8 : FORMAT_R8G8B8A8; case android::PIXEL_FORMAT_RGBX_8888: - return FORMAT_B8G8R8X8; + return swapRB ? FORMAT_B8G8R8X8 : FORMAT_R8G8B8X8; case android::PIXEL_FORMAT_RGB_565: return FORMAT_R5G6B5; case android::PIXEL_FORMAT_A_8: @@ -757,7 +760,8 @@ GrallocTextureHostOGL::SwapTexturesImpl(const SurfaceDescriptor& aImage, const SurfaceDescriptorGralloc& desc = aImage.get_SurfaceDescriptorGralloc(); mGraphicBuffer = GrallocBufferActor::GetFrom(desc); - mFormat = SurfaceFormatForAndroidPixelFormat(mGraphicBuffer->getPixelFormat()); + mFormat = SurfaceFormatForAndroidPixelFormat(mGraphicBuffer->getPixelFormat(), + desc.isRBSwapped()); mTextureTarget = TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat()); DeleteTextures(); diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index a34898b0a814..2ec2e082c4dc 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -3957,6 +3957,9 @@ pref("webgl.default-no-alpha", false); pref("webgl.force-layers-readback", false); pref("webgl.lose-context-on-heap-minimize", false); pref("webgl.can-lose-context-in-foreground", true); +#ifdef MOZ_B2G +pref("gfx.gralloc.fence-with-readpixels", false); +#endif // Stagefright prefs pref("stagefright.force-enabled", false);