diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index 86efafefb5e..af7b3f42319 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -232,6 +232,7 @@ CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth, , mSurfaceSize(aSurfaceWidth, aSurfaceHeight) , mHasBGRA(0) , mUseExternalSurfaceSize(aUseExternalSurfaceSize) + , mTextures({0, 0, 0}) , mFrameInProgress(false) , mDestroyed(false) { @@ -279,9 +280,29 @@ CompositorOGL::AddPrograms(ShaderProgramType aType) } } +GLuint +CompositorOGL::GetTemporaryTexture(GLenum aTextureUnit) +{ + if (!mTextures[aTextureUnit - LOCAL_GL_TEXTURE0]) { + gl()->MakeCurrent(); + gl()->fGenTextures(1, &mTextures[aTextureUnit - LOCAL_GL_TEXTURE0]); + } + return mTextures[aTextureUnit - LOCAL_GL_TEXTURE0]; +} + void CompositorOGL::Destroy() { + if (gl()) { + gl()->MakeCurrent(); + gl()->fDeleteTextures(3, mTextures); + mTextures[0] = 0; + mTextures[1] = 0; + mTextures[2] = 0; + } else { + MOZ_ASSERT(!mTextures[0] && !mTextures[1] && !mTextures[2]); + } + if (!mDestroyed) { mDestroyed = true; CleanupResources(); diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h index 666445efbd4..66374e2f529 100644 --- a/gfx/layers/opengl/CompositorOGL.h +++ b/gfx/layers/opengl/CompositorOGL.h @@ -134,6 +134,13 @@ public: gl::RGBARectLayerProgramType : gl::RGBALayerProgramType; } + /** + * The compositor provides with temporary textures for use with direct + * textruing like gralloc texture. + * Doing so lets us use gralloc the way it has been designed to be used + * (see https://wiki.mozilla.org/Platform/GFX/Gralloc) + */ + GLuint GetTemporaryTexture(GLenum aUnit); private: /** * Context target, nullptr when drawing directly to our swap chain. @@ -319,6 +326,9 @@ private: bool mDestroyed; nsAutoPtr mFPS; + // Textures used for direct texturing of buffers like gralloc. + // The index of the texture in this array must correspond to the texture unit. + GLuint mTextures[3]; static bool sDrawFPS; static bool sFrameCounter; }; diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index cbc1fa4fbfc..7d4d6f7f54b 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -700,28 +700,29 @@ TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat) } } +GrallocTextureHostOGL::GrallocTextureHostOGL() +: mCompositor(nullptr) +, mTextureTarget(0) +, mEGLImage(0) +{ +} + void GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor) { CompositorOGL* glCompositor = static_cast(aCompositor); - if (mGL && !glCompositor) { + if (mCompositor && !glCompositor) { DeleteTextures(); } - mGL = glCompositor ? glCompositor->gl() : nullptr; + mCompositor = glCompositor; } void GrallocTextureHostOGL::DeleteTextures() { - if (mGLTexture || mEGLImage) { - mGL->MakeCurrent(); - if (mGLTexture) { - mGL->fDeleteTextures(1, &mGLTexture); - mGLTexture = 0; - } - if (mEGLImage) { - mGL->DestroyEGLImage(mEGLImage); - mEGLImage = 0; - } + if (mEGLImage) { + gl()->MakeCurrent(); + gl()->DestroyEGLImage(mEGLImage); + mEGLImage = 0; } } @@ -767,20 +768,43 @@ GrallocTextureHostOGL::SwapTexturesImpl(const SurfaceDescriptor& aImage, RegisterTextureHostAtGrallocBufferActor(this, aImage); } +gl::GLContext* +GrallocTextureHostOGL::gl() const +{ + return mCompositor ? mCompositor->gl() : nullptr; +} + void GrallocTextureHostOGL::BindTexture(GLenum aTextureUnit) { - MOZ_ASSERT(mGLTexture); + /* + * The job of this function is to ensure that the texture is tied to the + * android::GraphicBuffer, so that texturing will source the GraphicBuffer. + * + * To this effect we create an EGLImage wrapping this GraphicBuffer, + * using CreateEGLImageForNativeBuffer, and then we tie this EGLImage to our + * texture using fEGLImageTargetTexture2D. + * + * We try to avoid re-creating the EGLImage everytime, by keeping it around + * as the mEGLImage member of this class. + */ + MOZ_ASSERT(gl()); + gl()->MakeCurrent(); - mGL->MakeCurrent(); - mGL->fActiveTexture(aTextureUnit); - mGL->fBindTexture(mTextureTarget, mGLTexture); - mGL->fActiveTexture(LOCAL_GL_TEXTURE0); + GLuint tex = mCompositor->GetTemporaryTexture(aTextureUnit); + + gl()->fActiveTexture(aTextureUnit); + gl()->fBindTexture(mTextureTarget, tex); + if (!mEGLImage) { + mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer()); + } + gl()->fEGLImageTargetTexture2D(mTextureTarget, mEGLImage); + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); } bool GrallocTextureHostOGL::IsValid() const { - return !!mGL && !!mGraphicBuffer.get(); + return !!gl() && !!mGraphicBuffer.get(); } GrallocTextureHostOGL::~GrallocTextureHostOGL() @@ -798,65 +822,14 @@ GrallocTextureHostOGL::~GrallocTextureHostOGL() bool GrallocTextureHostOGL::Lock() { - if (!IsValid()) { - return false; - } - /* - * The job of this function is to ensure that the texture is tied to the - * android::GraphicBuffer, so that texturing will source the GraphicBuffer. - * - * To this effect we create an EGLImage wrapping this GraphicBuffer, - * using CreateEGLImageForNativeBuffer, and then we tie this EGLImage to our - * texture using fEGLImageTargetTexture2D. - * - * We try to avoid re-creating the EGLImage everytime, by keeping it around - * as the mEGLImage member of this class. - */ - MOZ_ASSERT(mGraphicBuffer.get()); - - mGL->MakeCurrent(); - - if (!mGLTexture) { - mGL->fGenTextures(1, &mGLTexture); - } - mGL->fActiveTexture(LOCAL_GL_TEXTURE0); - mGL->fBindTexture(mTextureTarget, mGLTexture); - if (!mEGLImage) { - mEGLImage = mGL->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer()); - } - mGL->fEGLImageTargetTexture2D(mTextureTarget, mEGLImage); - return true; + // Lock/Unlock is done internally when binding the gralloc buffer to a gl texture + return IsValid(); } void GrallocTextureHostOGL::Unlock() { - /* - * The job of this function is to ensure that we release any read lock placed on - * our android::GraphicBuffer by any drawing code that sourced it via this TextureHost. - * - * Indeed, as soon as we draw with a texture that's tied to a android::GraphicBuffer, - * the GL may place read locks on it. We must ensure that we release them early enough, - * i.e. before the next time that we will try to acquire a write lock on the same buffer, - * because read and write locks on gralloc buffers are mutually exclusive. - */ - if (mGL->Renderer() == GLContext::RendererAdrenoTM205) { - /* XXX This is working around a driver bug exhibited on at least the - * Geeksphone Peak, where retargeting to a different EGL image is very - * slow. See Bug 869696. - */ - if (mGLTexture) { - mGL->MakeCurrent(); - mGL->fDeleteTextures(1, &mGLTexture); - mGLTexture = 0; - } - return; - } - - mGL->MakeCurrent(); - mGL->fActiveTexture(LOCAL_GL_TEXTURE0); - mGL->fBindTexture(mTextureTarget, mGLTexture); - mGL->fEGLImageTargetTexture2D(mTextureTarget, mGL->GetNullEGLImage()); + // Lock/Unlock is done internally when binding the gralloc buffer to a gl texture } gfx::SurfaceFormat @@ -877,7 +850,7 @@ GrallocTextureHostOGL::SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceAllocator* RegisterTextureHostAtGrallocBufferActor(this, *mBuffer); } -#endif +#endif // MOZ_WIDGET_GONK already_AddRefed TextureImageTextureHostOGL::GetAsSurface() { @@ -932,10 +905,20 @@ TiledTextureHostOGL::GetAsSurface() { #ifdef MOZ_WIDGET_GONK already_AddRefed GrallocTextureHostOGL::GetAsSurface() { - nsRefPtr surf = IsValid() && mGLTexture ? - mGL->GetTexImage(mGLTexture, - false, - GetShaderProgram()) + gl()->MakeCurrent(); + + GLuint tex = mCompositor->GetTemporaryTexture(LOCAL_GL_TEXTURE0); + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); + gl()->fBindTexture(mTextureTarget, tex); + if (!mEGLImage) { + mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer()); + } + gl()->fEGLImageTargetTexture2D(mTextureTarget, mEGLImage); + + nsRefPtr surf = IsValid() ? + gl()->GetTexImage(tex, + false, + GetShaderProgram()) : nullptr; return surf.forget(); } diff --git a/gfx/layers/opengl/TextureHostOGL.h b/gfx/layers/opengl/TextureHostOGL.h index 049f408238b..bcebfa0a68a 100644 --- a/gfx/layers/opengl/TextureHostOGL.h +++ b/gfx/layers/opengl/TextureHostOGL.h @@ -21,6 +21,7 @@ namespace mozilla { namespace layers { class TextureImageTextureHostOGL; +class CompositorOGL; /* * TextureHost implementations for the OpenGL backend. @@ -568,23 +569,12 @@ class GrallocTextureHostOGL , public TextureSourceOGL { public: - GrallocTextureHostOGL() - : mGL(nullptr) - , mTextureTarget(0) - , mGLTexture(0) - , mEGLImage(0) - { - } + GrallocTextureHostOGL(); ~GrallocTextureHostOGL(); virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE; - virtual GLuint GetTextureHandle() - { - return mGLTexture; - } - virtual void UpdateImpl(const SurfaceDescriptor& aImage, nsIntRegion* aRegion = nullptr, nsIntPoint* aOffset = nullptr) MOZ_OVERRIDE; @@ -652,12 +642,13 @@ public: } private: + gl::GLContext* gl() const; + void DeleteTextures(); - RefPtr mGL; + RefPtr mCompositor; android::sp mGraphicBuffer; GLenum mTextureTarget; - GLuint mGLTexture; EGLImage mEGLImage; }; #endif