From 747011926e8a60e4c61d98e07f0e71ecc463b594 Mon Sep 17 00:00:00 2001 From: CJKu Date: Thu, 28 May 2015 02:30:00 -0400 Subject: [PATCH] Bug 1168015 - Dump source image from graphic buffer directly on B2G. r=kamidphish, r=hshih --- gfx/layers/Effects.h | 17 +- gfx/layers/LayerScope.cpp | 208 ++++++++++++++++++---- gfx/layers/composite/ContentHost.cpp | 6 +- gfx/layers/composite/ImageHost.cpp | 6 +- gfx/layers/composite/TiledContentHost.cpp | 7 +- 5 files changed, 201 insertions(+), 43 deletions(-) diff --git a/gfx/layers/Effects.h b/gfx/layers/Effects.h index d5cae98a29e..04c7882a7f2 100644 --- a/gfx/layers/Effects.h +++ b/gfx/layers/Effects.h @@ -74,6 +74,7 @@ struct TexturedEffect : public Effect TextureSource* mTexture; bool mPremultiplied; gfx::Filter mFilter; + LayerRenderState mState; }; // Support an alpha mask. @@ -248,7 +249,8 @@ inline TemporaryRef CreateTexturedEffect(gfx::SurfaceFormat aFormat, TextureSource* aSource, const gfx::Filter& aFilter, - bool isAlphaPremultiplied) + bool isAlphaPremultiplied, + const LayerRenderState &state = LayerRenderState()) { MOZ_ASSERT(aSource); RefPtr result; @@ -268,6 +270,8 @@ CreateTexturedEffect(gfx::SurfaceFormat aFormat, break; } + result->mState = state; + return result.forget(); } @@ -281,7 +285,8 @@ inline TemporaryRef CreateTexturedEffect(TextureSource* aSource, TextureSource* aSourceOnWhite, const gfx::Filter& aFilter, - bool isAlphaPremultiplied) + bool isAlphaPremultiplied, + const LayerRenderState &state = LayerRenderState()) { MOZ_ASSERT(aSource); if (aSourceOnWhite) { @@ -294,7 +299,8 @@ CreateTexturedEffect(TextureSource* aSource, return CreateTexturedEffect(aSource->GetFormat(), aSource, aFilter, - isAlphaPremultiplied); + isAlphaPremultiplied, + state); } /** @@ -304,9 +310,10 @@ CreateTexturedEffect(TextureSource* aSource, */ inline TemporaryRef CreateTexturedEffect(TextureSource *aTexture, - const gfx::Filter& aFilter) + const gfx::Filter& aFilter, + const LayerRenderState &state = LayerRenderState()) { - return CreateTexturedEffect(aTexture, nullptr, aFilter, true); + return CreateTexturedEffect(aTexture, nullptr, aFilter, true, state); } diff --git a/gfx/layers/LayerScope.cpp b/gfx/layers/LayerScope.cpp index 40f2d8ead92..4df84cf7d37 100644 --- a/gfx/layers/LayerScope.cpp +++ b/gfx/layers/LayerScope.cpp @@ -270,6 +270,87 @@ protected: int64_t mFrameStamp; }; +#ifdef MOZ_WIDGET_GONK +// B2G optimization. +class DebugGLGraphicBuffer final: public DebugGLData { +public: + DebugGLGraphicBuffer(void *layerRef, + GLenum target, + GLuint name, + const LayerRenderState &aState) + : DebugGLData(Packet::TEXTURE), + mLayerRef(reinterpret_cast(layerRef)), + mTarget(target), + mName(name), + mState(aState) + { + } + + virtual bool Write() override { + return WriteToStream(mPacket); + } + + bool TryPack() { + android::sp buffer = mState.mSurface; + MOZ_ASSERT(buffer.get()); + + mPacket.set_type(mDataType); + TexturePacket* tp = mPacket.mutable_texture(); + tp->set_layerref(mLayerRef); + tp->set_name(mName); + tp->set_target(mTarget); + + int format = buffer->getPixelFormat(); + if (HAL_PIXEL_FORMAT_RGBA_8888 != format && + HAL_PIXEL_FORMAT_RGBX_8888 != format) { + return false; + } + + uint8_t* grallocData; + if (BAD_VALUE == buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_NEVER, + reinterpret_cast(&grallocData))) { + return false; + } + + int32_t stride = buffer->getStride() * 4; + int32_t height = buffer->getHeight(); + int32_t width = buffer->getWidth(); + int32_t sourceSize = stride * height; + bool ret = false; + + if (sourceSize > 0) { + auto compressedData = MakeUnique(LZ4::maxCompressedSize(sourceSize)); + int compressedSize = LZ4::compress((char*)grallocData, + sourceSize, + compressedData.get()); + + if (compressedSize > 0) { + uint32_t format = mState.FormatRBSwapped() ? + LOCAL_GL_BGRA : LOCAL_GL_RGBA; + tp->set_dataformat(format); + tp->set_dataformat((1 << 16 | tp->dataformat())); + tp->set_width(width); + tp->set_height(height); + tp->set_stride(stride); + tp->set_data(compressedData.get(), compressedSize); + ret = true; + } + } + + buffer->unlock(); + return ret; + } + +private: + uint64_t mLayerRef; + GLenum mTarget; + GLuint mName; + const LayerRenderState &mState; + Packet mPacket; +}; +#endif + class DebugGLTextureData final: public DebugGLData { public: DebugGLTextureData(GLContext* cx, @@ -608,7 +689,6 @@ public: static void ClearTextureIdList(); - static bool IsTextureIdContainsInList(GLuint aTextureId); // Sender private functions private: @@ -619,14 +699,23 @@ private: static void SendTextureSource(GLContext* aGLContext, void* aLayerRef, TextureSourceOGL* aSource, + GLuint aTexID, bool aFlipY); +#ifdef MOZ_WIDGET_GONK + static bool SendGraphicBuffer(void* aLayerRef, + TextureSourceOGL* aSource, + GLuint aTexID, + const TexturedEffect* aEffect); +#endif static void SendTexturedEffect(GLContext* aGLContext, void* aLayerRef, const TexturedEffect* aEffect); static void SendYCbCrEffect(GLContext* aGLContext, void* aLayerRef, const EffectYCbCr* aEffect); - + static GLuint GetTextureID(GLContext* aGLContext, + TextureSourceOGL* aSource); + static bool IsTextureIdContainsInList(GLuint aTextureId); // Data fields private: static bool sLayersTreeSendable; @@ -714,10 +803,31 @@ SenderHelper::SendColor(void* aLayerRef, new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight)); } +GLuint +SenderHelper::GetTextureID(GLContext* aGLContext, + TextureSourceOGL* aSource) { + GLenum textureTarget = aSource->GetTextureTarget(); + aSource->BindTexture(LOCAL_GL_TEXTURE0, gfx::Filter::LINEAR); + + GLuint texID = 0; + // This is horrid hack. It assumes that aGLContext matches the context + // aSource has bound to. + if (textureTarget == LOCAL_GL_TEXTURE_2D) { + aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &texID); + } else if (textureTarget == LOCAL_GL_TEXTURE_EXTERNAL) { + aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &texID); + } else if (textureTarget == LOCAL_GL_TEXTURE_RECTANGLE) { + aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &texID); + } + + return texID; +} + void SenderHelper::SendTextureSource(GLContext* aGLContext, void* aLayerRef, TextureSourceOGL* aSource, + GLuint aTexID, bool aFlipY) { MOZ_ASSERT(aGLContext); @@ -730,46 +840,68 @@ SenderHelper::SendTextureSource(GLContext* aGLContext, aSource->GetFormat()); int shaderConfig = config.mFeatures; - aSource->BindTexture(LOCAL_GL_TEXTURE0, gfx::Filter::LINEAR); + gfx::IntSize size = aSource->GetSize(); - GLuint textureId = 0; - // This is horrid hack. It assumes that aGLContext matches the context - // aSource has bound to. - if (textureTarget == LOCAL_GL_TEXTURE_2D) { - aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &textureId); - } else if (textureTarget == LOCAL_GL_TEXTURE_EXTERNAL) { - aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &textureId); - } else if (textureTarget == LOCAL_GL_TEXTURE_RECTANGLE) { - aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &textureId); - } - - if (!IsTextureIdContainsInList(textureId)) { - gfx::IntSize size = aSource->GetSize(); - - // By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding - // texture correctly. textureId is used for tracking in DebugGLTextureData. - RefPtr img = - aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget, + // By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding + // texture correctly. texID is used for tracking in DebugGLTextureData. + RefPtr img = + aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget, size, shaderConfig, aFlipY); - sTextureIdList.push_back(textureId); - WebSocketHelper::GetSocketManager()->AppendDebugData( - new DebugGLTextureData(aGLContext, aLayerRef, textureTarget, - textureId, img)); - } + WebSocketHelper::GetSocketManager()->AppendDebugData( + new DebugGLTextureData(aGLContext, aLayerRef, textureTarget, + aTexID, img)); + + sTextureIdList.push_back(aTexID); } +#ifdef MOZ_WIDGET_GONK +bool +SenderHelper::SendGraphicBuffer(void* aLayerRef, + TextureSourceOGL* aSource, + GLuint aTexID, + const TexturedEffect* aEffect) { + if (!aEffect->mState.mSurface.get()) { + return false; + } + + GLenum target = aSource->GetTextureTarget(); + mozilla::UniquePtr package = + MakeUnique(aLayerRef, target, aTexID, aEffect->mState); + + if (!package->TryPack()) { + return false; + } + + // Transfer ownership to SocketManager. + WebSocketHelper::GetSocketManager()->AppendDebugData(package.release()); + sTextureIdList.push_back(aTexID); + return true; +} +#endif + void SenderHelper::SendTexturedEffect(GLContext* aGLContext, void* aLayerRef, const TexturedEffect* aEffect) { TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL(); - if (!source) + if (!source) { return; + } - bool flipY = false; - SendTextureSource(aGLContext, aLayerRef, source, flipY); + GLuint texID = GetTextureID(aGLContext, source); + if (IsTextureIdContainsInList(texID)) { + return; + } + +#ifdef MOZ_WIDGET_GONK + if (SendGraphicBuffer(aLayerRef, source, texID, aEffect)) { + return; + } +#endif + // Render to texture and read pixels back. + SendTextureSource(aGLContext, aLayerRef, source, texID, false); } void @@ -786,10 +918,20 @@ SenderHelper::SendYCbCrEffect(GLContext* aGLContext, TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(); TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL(); - bool flipY = false; - SendTextureSource(aGLContext, aLayerRef, sourceY, flipY); - SendTextureSource(aGLContext, aLayerRef, sourceCb, flipY); - SendTextureSource(aGLContext, aLayerRef, sourceCr, flipY); + GLuint texID = GetTextureID(aGLContext, sourceY); + if (!IsTextureIdContainsInList(texID)) { + SendTextureSource(aGLContext, aLayerRef, sourceY, texID, false); + } + + texID = GetTextureID(aGLContext, sourceCb); + if (!IsTextureIdContainsInList(texID)) { + SendTextureSource(aGLContext, aLayerRef, sourceCb, texID, false); + } + + texID = GetTextureID(aGLContext, sourceCr); + if (!IsTextureIdContainsInList(texID)) { + SendTextureSource(aGLContext, aLayerRef, sourceCr, texID, false); + } } void diff --git a/gfx/layers/composite/ContentHost.cpp b/gfx/layers/composite/ContentHost.cpp index 9fe1cf60c3e..b27214753f0 100644 --- a/gfx/layers/composite/ContentHost.cpp +++ b/gfx/layers/composite/ContentHost.cpp @@ -63,7 +63,8 @@ ContentHostTexture::Composite(EffectChain& aEffectChain, RefPtr effect = CreateTexturedEffect(mTextureSource.get(), mTextureSourceOnWhite.get(), - aFilter, true); + aFilter, true, + GetRenderState()); if (!effect) { return; } @@ -460,7 +461,8 @@ ContentHostTexture::GenEffect(const gfx::Filter& aFilter) } return CreateTexturedEffect(mTextureSource.get(), mTextureSourceOnWhite.get(), - aFilter, true); + aFilter, true, + GetRenderState()); } TemporaryRef diff --git a/gfx/layers/composite/ImageHost.cpp b/gfx/layers/composite/ImageHost.cpp index 5142122e464..9c0ebe34d69 100644 --- a/gfx/layers/composite/ImageHost.cpp +++ b/gfx/layers/composite/ImageHost.cpp @@ -106,7 +106,8 @@ ImageHost::Composite(EffectChain& aEffectChain, RefPtr effect = CreateTexturedEffect(mFrontBuffer->GetFormat(), mTextureSource.get(), aFilter, - isAlphaPremultiplied); + isAlphaPremultiplied, + GetRenderState()); if (!effect) { return; } @@ -298,7 +299,8 @@ ImageHost::GenEffect(const gfx::Filter& aFilter) return CreateTexturedEffect(mFrontBuffer->GetFormat(), mTextureSource, aFilter, - isAlphaPremultiplied); + isAlphaPremultiplied, + GetRenderState()); } #ifdef MOZ_WIDGET_GONK diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp index bf28b7d029e..5dfdc47a1ec 100644 --- a/gfx/layers/composite/TiledContentHost.cpp +++ b/gfx/layers/composite/TiledContentHost.cpp @@ -468,7 +468,12 @@ TiledContentHost::RenderTile(TileHost& aTile, return; } - RefPtr effect = CreateTexturedEffect(aTile.mTextureSource, aTile.mTextureSourceOnWhite, aFilter, true); + RefPtr effect = + CreateTexturedEffect(aTile.mTextureSource, + aTile.mTextureSourceOnWhite, + aFilter, + true, + aTile.mTextureHost->GetRenderState()); if (!effect) { return; }