From bd7ba17b6a1495bdb94021065ff8e42563f0be96 Mon Sep 17 00:00:00 2001 From: jdashg Date: Tue, 7 Oct 2014 21:01:51 -0700 Subject: [PATCH] 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(-) --- 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(-) diff --git a/gfx/2d/HelpersCairo.h b/gfx/2d/HelpersCairo.h index a0f52b398848..ab9940e0e78e 100644 --- a/gfx/2d/HelpersCairo.h +++ b/gfx/2d/HelpersCairo.h @@ -141,6 +141,7 @@ GfxFormatToCairoFormat(SurfaceFormat format) return CAIRO_FORMAT_RGB16_565; default: gfxWarning() << "Unknown image format"; + MOZ_ASSERT(false, "Unknown image format"); return CAIRO_FORMAT_ARGB32; } } @@ -159,6 +160,7 @@ GfxFormatToCairoContent(SurfaceFormat format) return CAIRO_CONTENT_ALPHA; default: gfxWarning() << "Unknown image format"; + MOZ_ASSERT(false, "Unknown image format"); return CAIRO_CONTENT_COLOR_ALPHA; } } diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 09f553ef855d..f671d87471ba 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -2005,8 +2005,9 @@ SharedSurface* GLContext::RequestFrame() { MOZ_ASSERT(mScreen); + MOZ_CRASH("Not anymore!"); - return mScreen->Stream()->SwapConsumer(); + return nullptr; } diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 246398d09f15..bc41796dd42c 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -1576,7 +1576,6 @@ public: AFTER_GL_CALL; } -private: void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(pixels); BEFORE_GL_CALL; @@ -1585,7 +1584,6 @@ private: mHeavyGLCallsSinceLastFlush = true; } -public: void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { BeforeGLReadCall(); diff --git a/gfx/gl/GLReadTexImageHelper.cpp b/gfx/gl/GLReadTexImageHelper.cpp index bbb99b5511da..e153b0ba00ef 100644 --- a/gfx/gl/GLReadTexImageHelper.cpp +++ b/gfx/gl/GLReadTexImageHelper.cpp @@ -155,16 +155,19 @@ GLReadTexImageHelper::DidGLErrorOccur(const char* str) return false; } -static bool +bool GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType, - GLenum& readFormat, GLenum& readType) + GLenum* out_readFormat, GLenum* out_readType) { + MOZ_ASSERT(out_readFormat); + MOZ_ASSERT(out_readType); + if (destFormat == LOCAL_GL_RGBA && destType == LOCAL_GL_UNSIGNED_BYTE) { - readFormat = destFormat; - readType = destType; + *out_readFormat = destFormat; + *out_readType = destType; return true; } @@ -197,12 +200,12 @@ GetActualReadFormats(GLContext* gl, } if (fallback) { - readFormat = LOCAL_GL_RGBA; - readType = LOCAL_GL_UNSIGNED_BYTE; + *out_readFormat = LOCAL_GL_RGBA; + *out_readType = LOCAL_GL_UNSIGNED_BYTE; return false; } else { - readFormat = destFormat; - readType = destType; + *out_readFormat = destFormat; + *out_readType = destType; return true; } } @@ -395,7 +398,7 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) GLenum readType = destType; bool needsTempSurf = !GetActualReadFormats(gl, destFormat, destType, - readFormat, readType); + &readFormat, &readType); RefPtr tempSurf; DataSourceSurface* readSurf = dest; diff --git a/gfx/gl/GLReadTexImageHelper.h b/gfx/gl/GLReadTexImageHelper.h index cc835ebd4cb7..a1662a74b900 100644 --- a/gfx/gl/GLReadTexImageHelper.h +++ b/gfx/gl/GLReadTexImageHelper.h @@ -22,6 +22,12 @@ class DataSourceSurface; namespace gl { +// Returns true if the `dest{Format,Type}` are the same as the +// `read{Format,Type}`. +bool GetActualReadFormats(GLContext* gl, + GLenum destFormat, GLenum destType, + GLenum* out_readFormat, GLenum* out_readType); + void ReadPixelsIntoDataSurface(GLContext* aGL, gfx::DataSourceSurface* aSurface); diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index 679ea74e9b16..38ecfee6243f 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -28,6 +28,8 @@ namespace gl { class GLContext; class SharedSurface; +class ShSurfHandle; +class SurfaceFactory; class SurfaceStream; class DrawBuffer @@ -173,8 +175,8 @@ public: return mFactory.get(); } - SharedSurface* Front() const { - return mFront->Surf(); + ShSurfHandle* Front() const { + return mFront; } SharedSurface* SharedSurf() const { diff --git a/gfx/gl/ScopedGLHelpers.cpp b/gfx/gl/ScopedGLHelpers.cpp index 9d00912224b6..227d8d08111d 100644 --- a/gfx/gl/ScopedGLHelpers.cpp +++ b/gfx/gl/ScopedGLHelpers.cpp @@ -11,6 +11,14 @@ namespace mozilla { namespace gl { +#ifdef DEBUG +bool +IsContextCurrent(GLContext* gl) +{ + return gl->IsCurrent(); +} +#endif + /* ScopedGLState - Wraps glEnable/glDisable. **********************************/ // Use |newState = true| to enable, |false| to disable. @@ -483,5 +491,37 @@ ScopedGLDrawState::~ScopedGLDrawState() mGL->fUseProgram(boundProgram); } + +//////////////////////////////////////////////////////////////////////// +// ScopedPackAlignment + +ScopedPackAlignment::ScopedPackAlignment(GLContext* gl, GLint scopedVal) + : ScopedGLWrapper(gl) +{ + MOZ_ASSERT(scopedVal == 1 || + scopedVal == 2 || + scopedVal == 4 || + scopedVal == 8); + + gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mOldVal); + + if (scopedVal != mOldVal) { + gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, scopedVal); + } else { + // Don't try to re-set it during unwrap. + mOldVal = 0; + } +} + +void +ScopedPackAlignment::UnwrapImpl() { + // Check that we're not falling out of scope after the current context changed. + MOZ_ASSERT(mGL->IsCurrent()); + + if (mOldVal) { + mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mOldVal); + } +} + } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/ScopedGLHelpers.h b/gfx/gl/ScopedGLHelpers.h index 8929e1cf60c9..0da3303b62e5 100644 --- a/gfx/gl/ScopedGLHelpers.h +++ b/gfx/gl/ScopedGLHelpers.h @@ -6,13 +6,18 @@ #ifndef SCOPEDGLHELPERS_H_ #define SCOPEDGLHELPERS_H_ +#include "GLDefs.h" #include "mozilla/UniquePtr.h" -#include "GLContext.h" - namespace mozilla { namespace gl { +class GLContext; + +#ifdef DEBUG +bool IsContextCurrent(GLContext* gl); +#endif + //RAII via CRTP! template struct ScopedGLWrapper @@ -29,7 +34,7 @@ protected: { MOZ_ASSERT(&ScopedGLWrapper::Unwrap == &Derived::Unwrap); MOZ_ASSERT(&Derived::UnwrapImpl); - MOZ_ASSERT(mGL->IsCurrent()); + MOZ_ASSERT(IsContextCurrent(mGL)); } virtual ~ScopedGLWrapper() { @@ -338,6 +343,21 @@ struct ScopedGLDrawState { GLContext* const mGL; GLuint packAlign; }; + +struct ScopedPackAlignment + : public ScopedGLWrapper +{ + friend struct ScopedGLWrapper; + +protected: + GLint mOldVal; + +public: + ScopedPackAlignment(GLContext* aGL, GLint scopedVal); + +protected: + void UnwrapImpl(); +}; } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/SharedSurface.cpp b/gfx/gl/SharedSurface.cpp index 1ca52bc7b13d..b09a5cda3c6c 100644 --- a/gfx/gl/SharedSurface.cpp +++ b/gfx/gl/SharedSurface.cpp @@ -353,5 +353,99 @@ SurfaceFactory::Recycle(UniquePtr surf) } } +//////////////////////////////////////////////////////////////////////////////// +// ScopedReadbackFB + +ScopedReadbackFB::ScopedReadbackFB(SharedSurface* src) + : mGL(src->mGL) + , mAutoFB(mGL) + , mTempFB(0) + , mTempTex(0) + , mSurfToUnlock(nullptr) + , mSurfToLock(nullptr) +{ + switch (src->mAttachType) { + case AttachmentType::GLRenderbuffer: + { + mGL->fGenFramebuffers(1, &mTempFB); + mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB); + + GLuint rb = src->ProdRenderbuffer(); + mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_RENDERBUFFER, rb); + break; + } + case AttachmentType::GLTexture: + { + mGL->fGenFramebuffers(1, &mTempFB); + mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB); + + GLuint tex = src->ProdTexture(); + GLenum texImageTarget = src->ProdTextureTarget(); + mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + texImageTarget, tex, 0); + break; + } + case AttachmentType::Screen: + { + SharedSurface* origLocked = mGL->GetLockedSurface(); + if (origLocked != src) { + if (origLocked) { + mSurfToLock = origLocked; + mSurfToLock->UnlockProd(); + } + + mSurfToUnlock = src; + mSurfToUnlock->LockProd(); + } + + // TODO: This should just be BindFB, but we don't have + // the patch for this yet. (bug 1045955) + MOZ_ASSERT(mGL->Screen()); + mGL->Screen()->BindReadFB_Internal(0); + break; + } + default: + MOZ_CRASH("Unhandled `mAttachType`."); + } + + if (src->NeedsIndirectReads()) { + mGL->fGenTextures(1, &mTempTex); + + { + ScopedBindTexture autoTex(mGL, mTempTex); + + GLenum format = src->mHasAlpha ? LOCAL_GL_RGBA + : LOCAL_GL_RGB; + auto width = src->mSize.width; + auto height = src->mSize.height; + mGL->fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, 0, 0, width, + height, 0); + } + + mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_TEXTURE_2D, mTempTex, 0); + } +} + +ScopedReadbackFB::~ScopedReadbackFB() +{ + if (mTempFB) { + mGL->fDeleteFramebuffers(1, &mTempFB); + } + if (mTempTex) { + mGL->fDeleteTextures(1, &mTempTex); + } + if (mSurfToUnlock) { + mSurfToUnlock->UnlockProd(); + } + if (mSurfToLock) { + mSurfToLock->LockProd(); + } +} + } /* namespace gfx */ } /* namespace mozilla */ diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h index e46b476ae651..44fba8d3b96c 100644 --- a/gfx/gl/SharedSurface.h +++ b/gfx/gl/SharedSurface.h @@ -25,6 +25,7 @@ #include "mozilla/gfx/Point.h" #include "mozilla/UniquePtr.h" #include "mozilla/WeakPtr.h" +#include "ScopedGLHelpers.h" #include "SurfaceTypes.h" class nsIThread; @@ -127,6 +128,10 @@ public: { return false; } + + virtual bool NeedsIndirectReads() const { + return false; + } }; template @@ -234,6 +239,20 @@ public: } }; +class ScopedReadbackFB +{ + GLContext* const mGL; + ScopedBindFramebuffer mAutoFB; + GLuint mTempFB; + GLuint mTempTex; + SharedSurface* mSurfToUnlock; + SharedSurface* mSurfToLock; + +public: + ScopedReadbackFB(SharedSurface* src); + ~ScopedReadbackFB(); +}; + } // namespace gl } // namespace mozilla diff --git a/gfx/gl/SharedSurfaceIO.h b/gfx/gl/SharedSurfaceIO.h index 8dff33a397d9..e7488f2b4d67 100644 --- a/gfx/gl/SharedSurfaceIO.h +++ b/gfx/gl/SharedSurfaceIO.h @@ -56,6 +56,10 @@ public: return mIOSurf; } + virtual bool NeedsIndirectReads() const MOZ_OVERRIDE { + return true; + } + private: SharedSurface_IOSurface(const RefPtr& ioSurf, GLContext* gl, const gfx::IntSize& size, diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index 19e2ea770d57..795d2a186cbd 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -101,7 +101,8 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) if (mStream) { sharedSurf = mStream->SwapConsumer(); } else { - sharedSurf = mGLContext->RequestFrame(); + auto screen = mGLContext->Screen(); + sharedSurf = screen->Front()->Surf(); } if (!sharedSurf) { diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 87f56be0e55b..e0352a9136bb 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -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 +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 Create(gfx::SurfaceFormat format) { + return TextureClient::CreateForRawBufferAccess(mAllocator, format, + mSize, mBackendType, + mBaseTexFlags); + } + +public: + TemporaryRef CreateB8G8R8AX8() { + gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8 + : gfx::SurfaceFormat::B8G8R8X8; + return Create(format); + } + + TemporaryRef CreateR8G8B8AX8() { + // For now, assume that all RGBA formats are broken. + RefPtr ret = CreateB8G8R8AX8(); + + if (ret) { + ret->AddFlags(TextureFlags::RB_SWAPPED); + } + + return ret.forget(); + } +}; + +static TemporaryRef +TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator, + TextureFlags baseFlags, LayersBackend layersBackend) +{ + auto backendType = gfx::BackendType::CAIRO; + TexClientFactory factory(allocator, src->mHasAlpha, src->mSize, backendType, + baseFlags); + + RefPtr 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 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 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(); +} + } } diff --git a/gfx/layers/client/CanvasClient.h b/gfx/layers/client/CanvasClient.h index df130567b174..a0ff6defec2c 100644 --- a/gfx/layers/client/CanvasClient.h +++ b/gfx/layers/client/CanvasClient.h @@ -21,6 +21,7 @@ namespace mozilla { namespace gl { class SharedSurface; +class ShSurfHandle; } } @@ -44,6 +45,7 @@ public: enum CanvasClientType { CanvasClientSurface, CanvasClientGLContext, + CanvasClientTypeShSurf, }; static TemporaryRef CreateCanvasClient(CanvasClientType aType, CompositableForwarder* aFwd, @@ -138,6 +140,38 @@ private: RefPtr mBuffer; }; +// Used for GL canvases where we don't need to do any readback, i.e., with a +// GL backend. +class CanvasClientShSurf : public CanvasClient +{ +private: + RefPtr mFront; + RefPtr mPrevFront; + + RefPtr mFrontTex; + +public: + CanvasClientShSurf(CompositableForwarder* aLayerForwarder, + TextureFlags aFlags); + + virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE { + return TextureInfo(CompositableType::IMAGE); + } + + virtual void Clear() MOZ_OVERRIDE { + mFront = nullptr; + mPrevFront = nullptr; + mFrontTex = nullptr; + } + + virtual void Update(gfx::IntSize aSize, + ClientCanvasLayer* aLayer) MOZ_OVERRIDE; + + virtual void OnDetach() MOZ_OVERRIDE { + CanvasClientShSurf::Clear(); + } +}; + } } diff --git a/gfx/layers/client/ClientCanvasLayer.cpp b/gfx/layers/client/ClientCanvasLayer.cpp index c874f6f2980f..2bb7407efa2c 100644 --- a/gfx/layers/client/ClientCanvasLayer.cpp +++ b/gfx/layers/client/ClientCanvasLayer.cpp @@ -70,9 +70,6 @@ ClientCanvasLayer::Initialize(const Data& aData) } MOZ_ASSERT(caps.alpha == aData.mHasAlpha); - SurfaceStreamType streamType = - SurfaceStream::ChooseGLStreamType(SurfaceStream::OffMainThread, - screen->PreserveBuffer()); UniquePtr factory; if (!gfxPrefs::WebGLForceLayersReadback()) { @@ -139,7 +136,7 @@ ClientCanvasLayer::Initialize(const Data& aData) MOZ_ASSERT(producer, "Failed to create initial canvas surface with basic factory"); } } else if (factory) { - screen->Morph(Move(factory), streamType); + screen->Morph(Move(factory)); } } } @@ -167,10 +164,6 @@ ClientCanvasLayer::RenderLayer() if (!mGLContext) { // We don't support locking for buffer surfaces currently flags |= TextureFlags::IMMEDIATE_UPLOAD; - } else { - // GLContext's SurfaceStream handles ownership itself, - // and doesn't require layers to do any deallocation. - flags |= TextureFlags::DEALLOCATE_CLIENT; } if (!mIsAlphaPremultiplied) { @@ -199,6 +192,18 @@ ClientCanvasLayer::RenderLayer() mCanvasClient->OnTransaction(); } +CanvasClient::CanvasClientType +ClientCanvasLayer::GetCanvasClientType() +{ + if (mGLContext) { + if (mGLContext->Screen()) { + return CanvasClient::CanvasClientTypeShSurf; + } + return CanvasClient::CanvasClientGLContext; + } + return CanvasClient::CanvasClientSurface; +} + already_AddRefed ClientLayerManager::CreateCanvasLayer() { diff --git a/gfx/layers/client/ClientCanvasLayer.h b/gfx/layers/client/ClientCanvasLayer.h index b9de0fce0da7..0e8470937b97 100644 --- a/gfx/layers/client/ClientCanvasLayer.h +++ b/gfx/layers/client/ClientCanvasLayer.h @@ -91,13 +91,7 @@ protected: return static_cast(mManager); } - CanvasClientType GetCanvasClientType() - { - if (mGLContext) { - return CanvasClient::CanvasClientGLContext; - } - return CanvasClient::CanvasClientSurface; - } + CanvasClientType GetCanvasClientType(); RefPtr mCanvasClient; @@ -108,6 +102,7 @@ protected: friend class CanvasClient2D; friend class DeprecatedCanvasClientSurfaceStream; friend class CanvasClientSurfaceStream; + friend class CanvasClientShSurf; }; } } diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 851b10145dc4..cc2e078218be 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -19,6 +19,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/layers/TextureClientOGL.h" #include "mozilla/layers/PTextureChild.h" +#include "SharedSurface.h" #include "SurfaceStream.h" #include "GLContext.h" @@ -792,6 +793,17 @@ BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize, return true; } +uint8_t* +BufferTextureClient::GetLockedData() const +{ + MOZ_ASSERT(IsLocked()); + + ImageDataSerializer serializer(GetBuffer(), GetBufferSize()); + MOZ_ASSERT(serializer.IsValid()); + + return serializer.GetData(); +} + //////////////////////////////////////////////////////////////////////// // StreamTextureClient StreamTextureClient::StreamTextureClient(TextureFlags aFlags) @@ -848,6 +860,29 @@ StreamTextureClient::IsAllocated() const return mStream != 0; } +//////////////////////////////////////////////////////////////////////// +// ShSurfTexClient + +ShSurfTexClient::ShSurfTexClient(TextureFlags aFlags, gl::SharedSurface* surf) + : TextureClient(aFlags) + , mIsLocked(false) + , mSurf(surf) + , mGL(mSurf->mGL) +{ + mSurf->Fence(); +} + +ShSurfTexClient::~ShSurfTexClient() +{ + // the data is owned externally. +} + +bool +ShSurfTexClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) +{ + aOutDescriptor = ShSurfDescriptor((uintptr_t)mSurf); + return true; +} } } diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index 7d2a36a466ec..00cc59841fff 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -34,6 +34,7 @@ class gfxImageSurface; namespace mozilla { namespace gl { class GLContext; +class SharedSurface; class SurfaceStream; } @@ -296,6 +297,23 @@ public: */ TextureFlags GetFlags() const { return mFlags; } + bool HasFlags(TextureFlags aFlags) const + { + return (mFlags & aFlags) == aFlags; + } + + void AddFlags(TextureFlags aFlags) + { + MOZ_ASSERT(!IsSharedWithCompositor()); + mFlags |= aFlags; + } + + void RemoveFlags(TextureFlags aFlags) + { + MOZ_ASSERT(!IsSharedWithCompositor()); + mFlags &= ~aFlags; + } + /** * valid only for TextureFlags::RECYCLE TextureClient. * When called this texture client will grab a strong reference and release @@ -431,12 +449,6 @@ protected: */ virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0; - void AddFlags(TextureFlags aFlags) - { - MOZ_ASSERT(!IsSharedWithCompositor()); - mFlags |= aFlags; - } - ISurfaceAllocator* GetAllocator() { return mAllocator; @@ -504,6 +516,8 @@ public: virtual bool IsLocked() const MOZ_OVERRIDE { return mLocked; } + uint8_t* GetLockedData() const; + virtual bool CanExposeDrawTarget() const MOZ_OVERRIDE { return true; } virtual gfx::DrawTarget* BorrowDrawTarget() MOZ_OVERRIDE; @@ -665,6 +679,65 @@ protected: RefPtr mGL; // Just for reference holding. }; +/** + * A TextureClient implementation to share SharedSurfaces. + */ +class ShSurfTexClient : public TextureClient +{ +public: + explicit ShSurfTexClient(TextureFlags aFlags, gl::SharedSurface* surf); + +protected: + ~ShSurfTexClient(); + +public: + // Boilerplate start + virtual bool IsAllocated() const MOZ_OVERRIDE { return true; } + + virtual bool Lock(OpenMode) MOZ_OVERRIDE { + MOZ_ASSERT(!mIsLocked); + mIsLocked = true; + return true; + } + + virtual void Unlock() MOZ_OVERRIDE { + MOZ_ASSERT(mIsLocked); + mIsLocked = false; + } + + virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; } + + virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; } + + virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE { + return gfx::SurfaceFormat::UNKNOWN; + } + + virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return gfx::IntSize(); } + + // This TextureClient should not be used in a context where we use CreateSimilar + // (ex. component alpha) because the underlying texture data is always created by + // an external producer. + virtual TemporaryRef + CreateSimilar(TextureFlags, TextureAllocationFlags) const MOZ_OVERRIDE { + return nullptr; + } + + virtual bool AllocateForSurface(gfx::IntSize, + TextureAllocationFlags) MOZ_OVERRIDE { + MOZ_CRASH("Should never hit this."); + return false; + } + // Boilerplate end + + virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE; + +protected: + bool mIsLocked; + gl::SharedSurface* const mSurf; + RefPtr mGL; // Just for reference holding. +}; + struct TextureClientAutoUnlock { TextureClient* mTexture; diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index 3fb9e63ff8e5..2125c92b88d7 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -203,6 +203,9 @@ TextureHost::Create(const SurfaceDescriptor& aDesc, case SurfaceDescriptor::TSurfaceStreamDescriptor: return new StreamTextureHost(aFlags, aDesc.get_SurfaceStreamDescriptor()); + case SurfaceDescriptor::TShSurfDescriptor: + return new ShSurfTexHost(aFlags, aDesc.get_ShSurfDescriptor()); + case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: if (Compositor::GetBackend() == LayersBackend::LAYERS_OPENGL) { return CreateTextureHostOGL(aDesc, aDeallocator, aFlags); @@ -997,8 +1000,134 @@ StreamTextureHost::GetSize() const MOZ_ASSERT(mTextureSource); return mTextureSource->GetSize(); } +//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// +static RefPtr +ShSurfToTexSource(gl::SharedSurface* abstractSurf, Compositor* compositor) +{ + MOZ_ASSERT(abstractSurf); + MOZ_ASSERT(abstractSurf->mType != gl::SharedSurfaceType::Basic); + MOZ_ASSERT(abstractSurf->mType != gl::SharedSurfaceType::Gralloc); + + if (!compositor) { + return nullptr; + } + + gfx::SurfaceFormat format = abstractSurf->mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 + : gfx::SurfaceFormat::R8G8B8X8; + + RefPtr texSource; + switch (abstractSurf->mType) { +#ifdef XP_WIN + case gl::SharedSurfaceType::EGLSurfaceANGLE: { + auto surf = gl::SharedSurface_ANGLEShareHandle::Cast(abstractSurf); + HANDLE shareHandle = surf->GetShareHandle(); + + MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_D3D11); + CompositorD3D11* compositorD3D11 = static_cast(compositor); + ID3D11Device* d3d = compositorD3D11->GetDevice(); + + nsRefPtr tex; + HRESULT hr = d3d->OpenSharedResource(shareHandle, + __uuidof(ID3D11Texture2D), + getter_AddRefs(tex)); + if (FAILED(hr)) { + NS_WARNING("Failed to open shared resource."); + break; + } + texSource = new DataTextureSourceD3D11(format, compositorD3D11, tex); + break; + } +#endif + case gl::SharedSurfaceType::GLTextureShare: { + auto surf = gl::SharedSurface_GLTexture::Cast(abstractSurf); + + MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_OPENGL); + CompositorOGL* compositorOGL = static_cast(compositor); + gl::GLContext* gl = compositorOGL->gl(); + + GLenum target = surf->ConsTextureTarget(); + GLuint tex = surf->ConsTexture(gl); + texSource = new GLTextureSource(compositorOGL, tex, format, target, + surf->mSize); + break; + } + case gl::SharedSurfaceType::EGLImageShare: { + auto surf = gl::SharedSurface_EGLImage::Cast(abstractSurf); + + MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_OPENGL); + CompositorOGL* compositorOGL = static_cast(compositor); + gl::GLContext* gl = compositorOGL->gl(); + MOZ_ASSERT(gl->IsCurrent()); + + GLenum target = 0; + GLuint tex = 0; + surf->AcquireConsumerTexture(gl, &tex, &target); + + texSource = new GLTextureSource(compositorOGL, tex, format, target, + surf->mSize); + break; + } +#ifdef XP_MACOSX + case gl::SharedSurfaceType::IOSurface: { + auto surf = gl::SharedSurface_IOSurface::Cast(abstractSurf); + MacIOSurface* ioSurf = surf->GetIOSurface(); + + MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_OPENGL); + CompositorOGL* compositorOGL = static_cast(compositor); + + texSource = new MacIOSurfaceTextureSourceOGL(compositorOGL, ioSurf); + break; + } +#endif + default: + break; + } + + MOZ_ASSERT(texSource.get(), "TextureSource creation failed."); + return texSource; +} + +//////////////////////////////////////////////////////////////////////////////// +// ShSurfTexHost + +ShSurfTexHost::ShSurfTexHost(TextureFlags aFlags, const ShSurfDescriptor& aDesc) + : TextureHost(aFlags) + , mIsLocked(false) + , mSurf((gl::SharedSurface*)aDesc.surf()) + , mCompositor(nullptr) +{ + MOZ_ASSERT(mSurf); +} + +gfx::SurfaceFormat +ShSurfTexHost::GetFormat() const +{ + MOZ_ASSERT(mTexSource); + return mTexSource->GetFormat(); +} + +gfx::IntSize +ShSurfTexHost::GetSize() const +{ + MOZ_ASSERT(mTexSource); + return mTexSource->GetSize(); +} + +void +ShSurfTexHost::EnsureTexSource() +{ + MOZ_ASSERT(mIsLocked); + + if (mTexSource) + return; + + mSurf->WaitSync(); + mTexSource = ShSurfToTexSource(mSurf, mCompositor); + MOZ_ASSERT(mTexSource); +} + +//////////////////////////////////////////////////////////////////////////////// } // namespace } // namespace diff --git a/gfx/layers/composite/TextureHost.h b/gfx/layers/composite/TextureHost.h index ceae69abdab5..714e408da8c7 100644 --- a/gfx/layers/composite/TextureHost.h +++ b/gfx/layers/composite/TextureHost.h @@ -35,6 +35,7 @@ struct nsIntRect; namespace mozilla { namespace gl { +class SharedSurface; class SurfaceStream; } namespace ipc { @@ -49,6 +50,7 @@ class CompositableBackendSpecificData; class CompositableParentManager; class SurfaceDescriptor; class SurfaceStreamDescriptor; +class ShSurfDescriptor; class ISurfaceAllocator; class TextureHostOGL; class TextureSourceOGL; @@ -615,6 +617,68 @@ protected: RefPtr mDataTextureSource; }; +/** + * A TextureHost for SharedSurfaces + */ +class ShSurfTexHost : public TextureHost +{ +public: + ShSurfTexHost(TextureFlags aFlags, const ShSurfDescriptor& aDesc); + + virtual ~ShSurfTexHost() {}; + + virtual void DeallocateDeviceData() MOZ_OVERRIDE {}; + + virtual TemporaryRef GetAsSurface() MOZ_OVERRIDE { + return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING) + } + + virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE { + MOZ_ASSERT(!mIsLocked); + + if (aCompositor == mCompositor) + return; + + mTexSource = nullptr; + mCompositor = aCompositor; + } + +public: + virtual bool Lock() MOZ_OVERRIDE { + MOZ_ASSERT(!mIsLocked); + mIsLocked = true; + EnsureTexSource(); + return true; + } + + virtual void Unlock() MOZ_OVERRIDE { + MOZ_ASSERT(mIsLocked); + mIsLocked = false; + } + + virtual NewTextureSource* GetTextureSources() MOZ_OVERRIDE { + MOZ_ASSERT(mIsLocked); + MOZ_ASSERT(mTexSource); + return mTexSource; + } + + virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE; + + virtual gfx::IntSize GetSize() const MOZ_OVERRIDE; + +#ifdef MOZ_LAYERS_HAVE_LOG + virtual const char* Name() { return "ShSurfTexHost"; } +#endif + +protected: + void EnsureTexSource(); + + bool mIsLocked; + gl::SharedSurface* const mSurf; + Compositor* mCompositor; + RefPtr mTexSource; +}; + class MOZ_STACK_CLASS AutoLockTextureHost { public: diff --git a/gfx/layers/d3d10/CanvasLayerD3D10.cpp b/gfx/layers/d3d10/CanvasLayerD3D10.cpp index 65930ae1d243..01eabf55a966 100644 --- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp +++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp @@ -47,9 +47,6 @@ CanvasLayerD3D10::Initialize(const Data& aData) mNeedsYFlip = true; GLScreenBuffer* screen = mGLContext->Screen(); - SurfaceStreamType streamType = - SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread, - screen->PreserveBuffer()); UniquePtr factory = nullptr; if (!gfxPrefs::WebGLForceLayersReadback()) { @@ -60,7 +57,7 @@ CanvasLayerD3D10::Initialize(const Data& aData) } if (factory) { - screen->Morph(Move(factory), streamType); + screen->Morph(Move(factory)); } } else if (aData.mDrawTarget) { mDrawTarget = aData.mDrawTarget; diff --git a/gfx/layers/ipc/LayersSurfaces.ipdlh b/gfx/layers/ipc/LayersSurfaces.ipdlh index f78e153aeef1..e80cdf39f245 100644 --- a/gfx/layers/ipc/LayersSurfaces.ipdlh +++ b/gfx/layers/ipc/LayersSurfaces.ipdlh @@ -81,6 +81,10 @@ struct SurfaceStreamDescriptor { bool yflip; }; +struct ShSurfDescriptor { + uintptr_t surf; +}; + /** * Used for shmem-backed YCbCr and (flavors of) RGBA textures */ @@ -109,6 +113,7 @@ union SurfaceDescriptor { SurfaceStreamDescriptor; SurfaceDescriptorMacIOSurface; NewSurfaceDescriptorGralloc; + ShSurfDescriptor; null_t; };