/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * 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 MOZILLA_GFX_TEXTUREOGL_H #define MOZILLA_GFX_TEXTUREOGL_H #include "ImageLayerOGL.h" #include "GLContextTypes.h" #include "gfx2DGlue.h" #include "mozilla/layers/Effects.h" #include "gfxReusableSurfaceWrapper.h" #include "TiledLayerBuffer.h" // for TILEDLAYERBUFFER_TILE_SIZE #ifdef MOZ_WIDGET_GONK #include #endif namespace mozilla { namespace layers { /* * TextureHost implementations for the OpenGL backend. * * Note that it is important to becareful about the ownership model with * the OpenGL backend, due to some widget limitation on Linux: before * the nsBaseWidget associated with our OpenGL context has been completely * deleted, every resource belonging to the OpenGL context MUST have been * released. At the moment the teardown sequence happens in the middle of * the nsBaseWidget's destructor, meaning that at a given moment we must be * able to easily find and release all the GL resources. * The point is: be careful about the ownership model and limit the number * of objects sharing references to GL resources to make the tear down * sequence as simple as possible. */ /** * TextureSourceOGL provides the necessary API for CompositorOGL to composite * a TextureSource. */ class TextureSourceOGL { public: virtual bool IsValid() const = 0; virtual void BindTexture(GLenum aTextureUnit) = 0; virtual gfx::IntSize GetSize() const = 0; virtual gl::ShaderProgramType GetShaderProgram() const { MOZ_NOT_REACHED("unhandled shader type"); } // TODO: Noone's implementing this anymore, should see if we need this. virtual GLenum GetTextureTarget() const { return LOCAL_GL_TEXTURE_2D; } virtual GLenum GetWrapMode() const = 0;// { return LOCAL_GL_CLAMP_TO_EDGE; } // default virtual gfx3DMatrix GetTextureTransform() const { return gfx3DMatrix(); } }; inline gl::ShaderProgramType GetProgramTypeForTexture(const TextureHost *aTextureHost) { switch (aTextureHost->GetFormat()) { case gfx::FORMAT_B8G8R8A8: return gl::BGRALayerProgramType;; case gfx::FORMAT_B8G8R8X8: return gl::BGRXLayerProgramType;; case gfx::FORMAT_R8G8B8X8: return gl::RGBXLayerProgramType;; case gfx::FORMAT_R8G8B8A8: return gl::RGBALayerProgramType;; default: MOZ_NOT_REACHED("unhandled program type"); } } /** * TextureHost implementation using a TextureImage as the underlying texture. */ class TextureImageTextureHostOGL : public TextureHost , public TextureSourceOGL , public TileIterator { public: TextureImageTextureHostOGL(gl::TextureImage* aTexImage = nullptr) : mTexture(aTexImage) , mGL(nullptr) , mIterating(false) { MOZ_COUNT_CTOR(TextureImageTextureHostOGL); } ~TextureImageTextureHostOGL(); TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; } // This is a hack that is here to not break on-main-thread ThebesLayerBuffer // please do not use it anywhere else, use SetCompositor instead. void SetGLContext(gl::GLContext* aGL) { mGL = aGL; } // TextureHost void UpdateImpl(const SurfaceDescriptor& aImage, nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE; virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE; bool IsValid() const MOZ_OVERRIDE { return !!mTexture; } virtual bool Lock() MOZ_OVERRIDE; // textureSource void BindTexture(GLenum aTextureUnit) MOZ_OVERRIDE { mTexture->BindTexture(aTextureUnit); } gfx::IntSize GetSize() const MOZ_OVERRIDE; gl::ShaderProgramType GetShaderProgram() const MOZ_OVERRIDE { return GetProgramTypeForTexture(this); } GLenum GetWrapMode() const MOZ_OVERRIDE { return mTexture->GetWrapMode(); } gl::TextureImage* GetTextureImage() { return mTexture; } void SetTextureImage(gl::TextureImage* aImage) { mTexture = aImage; } // TileIterator TileIterator* AsTileIterator() MOZ_OVERRIDE { return this; } void BeginTileIteration() MOZ_OVERRIDE { mTexture->BeginTileIteration(); mIterating = true; } void EndTileIteration() MOZ_OVERRIDE { mIterating = false; } nsIntRect GetTileRect() MOZ_OVERRIDE { return mTexture->GetTileRect(); } size_t GetTileCount() MOZ_OVERRIDE { return mTexture->GetTileCount(); } bool NextTile() MOZ_OVERRIDE { return mTexture->NextTile(); } #ifdef MOZ_LAYERS_HAVE_LOG virtual const char* Name() { return "TextureImageTextureHostOGL"; } #endif protected: nsRefPtr mTexture; gl::GLContext* mGL; bool mIterating; }; /** * TextureHost implementation for YCbCr images in the OpenGL backend. * * This TextureHost is a little bit particular in that it implements * the TextureSource interface, as it is required that a TextureHost * provides access to a TextureSource, but does not implement the * TextureHostOGL interface. Instead it contains 3 channels (one per * plane) that implement the TextureSourceOGL interface, and * YCbCrTextureHostOGL's TextureSource implementation provide access * to these channels with the GetSubSource method. */ class YCbCrTextureHostOGL : public TextureHost { public: YCbCrTextureHostOGL() : mGL(nullptr) { MOZ_COUNT_CTOR(YCbCrTextureHostOGL); mYTexture = new Channel; mCbTexture = new Channel; mCrTexture = new Channel; mFormat = gfx::FORMAT_YUV; } ~YCbCrTextureHostOGL() { MOZ_COUNT_DTOR(YCbCrTextureHostOGL); } virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE; virtual void UpdateImpl(const SurfaceDescriptor& aImage, nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE; virtual bool Lock() MOZ_OVERRIDE; virtual bool IsValid() const MOZ_OVERRIDE { return mYTexture->IsValid() && mCbTexture->IsValid() && mCrTexture->IsValid(); } struct Channel : public TextureSourceOGL , public TextureSource { TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; } nsRefPtr mTexImage; void BindTexture(GLenum aUnit) MOZ_OVERRIDE { mTexImage->BindTexture(aUnit); } virtual bool IsValid() const MOZ_OVERRIDE { return !!mTexImage; } virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return gfx::IntSize(mTexImage->GetSize().width, mTexImage->GetSize().height); } virtual GLenum GetWrapMode() const MOZ_OVERRIDE { return mTexImage->GetWrapMode(); } }; // TextureSource implementation TextureSource* GetSubSource(int index) MOZ_OVERRIDE { switch (index) { case 0 : return mYTexture.get(); case 1 : return mCbTexture.get(); case 2 : return mCrTexture.get(); } return nullptr; } gfx::IntSize GetSize() const MOZ_OVERRIDE { if (!mYTexture->mTexImage) { NS_WARNING("YCbCrTextureHost::GetSize called but no data has been set yet"); return gfx::IntSize(0,0); } return mYTexture->GetSize(); } #ifdef MOZ_LAYERS_HAVE_LOG virtual const char* Name() { return "YCbCrTextureHostOGL"; } #endif private: RefPtr mYTexture; RefPtr mCbTexture; RefPtr mCrTexture; gl::GLContext* mGL; }; class SharedTextureHostOGL : public TextureHost , public TextureSourceOGL { public: typedef gfxASurface::gfxContentType ContentType; typedef mozilla::gl::GLContext GLContext; typedef mozilla::gl::TextureImage TextureImage; SharedTextureHostOGL() : mGL(nullptr) , mTextureHandle(0) , mWrapMode(LOCAL_GL_CLAMP_TO_EDGE) , mSharedHandle(0) , mShareType(GLContext::SameProcess) {} virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE; virtual ~SharedTextureHostOGL() { if (mSharedHandle || mTextureHandle) { DeleteTextures(); } } virtual GLuint GetTextureHandle() { return mTextureHandle; } virtual TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; } bool IsValid() const MOZ_OVERRIDE { return !!mSharedHandle; } // override from TextureHost, we support both buffered // and unbuffered operation. virtual void UpdateImpl(const SurfaceDescriptor& aImage, nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE; virtual void SwapTexturesImpl(const SurfaceDescriptor& aImage, nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE; virtual bool Lock() MOZ_OVERRIDE; virtual void Unlock() MOZ_OVERRIDE; virtual GLenum GetWrapMode() const MOZ_OVERRIDE { return mWrapMode; } virtual void SetWrapMode(GLenum aMode) { mWrapMode = aMode; } gl::ShaderProgramType GetShaderProgram() const MOZ_OVERRIDE { return mShaderProgram; } gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; } void BindTexture(GLenum activetex) MOZ_OVERRIDE { MOZ_ASSERT(mGL); // Lock already bound us! MOZ_ASSERT(activetex == LOCAL_GL_TEXTURE0); } void ReleaseTexture() {} GLuint GetTextureID() { return mTextureHandle; } ContentType GetContentType() { return (mFormat == gfx::FORMAT_B8G8R8A8) ? gfxASurface::CONTENT_COLOR_ALPHA : gfxASurface::CONTENT_COLOR; } virtual gfx3DMatrix GetTextureTransform() const MOZ_OVERRIDE { return mTextureTransform; } #ifdef MOZ_LAYERS_HAVE_LOG virtual const char* Name() { return "SharedTextureHostOGL"; } #endif protected: void DeleteTextures(); gfx::IntSize mSize; nsRefPtr mGL; GLuint mTextureHandle; GLenum mWrapMode; GLenum mTextureTarget; gl::SharedTextureHandle mSharedHandle; gl::ShaderProgramType mShaderProgram; gl::GLContext::SharedTextureShareType mShareType; gfx3DMatrix mTextureTransform; }; class SurfaceStreamHostOGL : public TextureHost , public TextureSourceOGL { public: typedef gfxASurface::gfxContentType ContentType; typedef mozilla::gl::GLContext GLContext; typedef mozilla::gl::TextureImage TextureImage; virtual ~SurfaceStreamHostOGL() { DeleteTextures(); *mBuffer = SurfaceDescriptor(); } virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE; virtual GLuint GetTextureHandle() { return mTextureHandle; } virtual TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; } bool IsValid() const MOZ_OVERRIDE { return true; } // override from TextureHost virtual void SwapTexturesImpl(const SurfaceDescriptor& aImage, nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE; virtual bool Lock() MOZ_OVERRIDE; virtual void Unlock() MOZ_OVERRIDE; virtual GLenum GetWrapMode() const MOZ_OVERRIDE { return mWrapMode; } virtual void SetWrapMode(GLenum aMode) { mWrapMode = aMode; } gl::ShaderProgramType GetShaderProgram() const MOZ_OVERRIDE { return mShaderProgram; } gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; } virtual GLenum GetTextureTarget() const MOZ_OVERRIDE { return LOCAL_GL_TEXTURE_2D; } void BindTexture(GLenum activetex) MOZ_OVERRIDE { MOZ_ASSERT(mGL); mGL->fActiveTexture(activetex); mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mTextureHandle); } void ReleaseTexture() { } GLuint GetTextureID() { return mTextureHandle; } ContentType GetContentType() { return (mFormat == gfx::FORMAT_B8G8R8A8) ? gfxASurface::CONTENT_COLOR_ALPHA : gfxASurface::CONTENT_COLOR; } #ifdef MOZ_LAYERS_HAVE_LOG virtual const char* Name() { return "SurfaceStreamHostOGL"; } #endif SurfaceStreamHostOGL() : mGL(nullptr) , mTextureHandle(0) , mUploadTexture(0) , mWrapMode(LOCAL_GL_CLAMP_TO_EDGE) {} protected: void DeleteTextures(); gfx::IntSize mSize; nsRefPtr mGL; GLuint mTextureHandle; GLuint mUploadTexture; GLenum mWrapMode; gl::ShaderProgramType mShaderProgram; }; class TiledTextureHostOGL : public TextureHost , public TextureSourceOGL { public: TiledTextureHostOGL() : mTextureHandle(0) , mGL(nullptr) {} ~TiledTextureHostOGL(); virtual void SetCompositor(Compositor* aCompositor); // have to pass the size in here (every time) because of DrawQuad API :-( virtual void Update(gfxReusableSurfaceWrapper* aReusableSurface, TextureFlags aFlags, const gfx::IntSize& aSize) MOZ_OVERRIDE; virtual bool Lock() MOZ_OVERRIDE; virtual void Unlock() MOZ_OVERRIDE {} virtual TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; } virtual bool IsValid() const MOZ_OVERRIDE { return true; } virtual GLenum GetWrapMode() const MOZ_OVERRIDE { return LOCAL_GL_CLAMP_TO_EDGE; } virtual void BindTexture(GLenum aTextureUnit) MOZ_OVERRIDE { mGL->fActiveTexture(aTextureUnit); mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mTextureHandle); } virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; } gl::ShaderProgramType GetShaderProgram() const MOZ_OVERRIDE { return GetProgramTypeForTexture(this); } virtual void SwapTexturesImpl(const SurfaceDescriptor& aImage, nsIntRegion* aRegion = nullptr) { MOZ_ASSERT(false, "Tiles should not use this path"); } #ifdef MOZ_LAYERS_HAVE_LOG virtual const char* Name() { return "TiledTextureHostOGL"; } #endif protected: void DeleteTextures(); virtual uint64_t GetIdentifier() const MOZ_OVERRIDE { return static_cast(mTextureHandle); } private: GLenum GetTileType() { // Deduce the type that was assigned in GetFormatAndTileForImageFormat return mGLFormat == LOCAL_GL_RGB ? LOCAL_GL_UNSIGNED_SHORT_5_6_5 : LOCAL_GL_UNSIGNED_BYTE; } gfx::IntSize mSize; GLuint mTextureHandle; GLenum mGLFormat; gl::GLContext* mGL; }; #ifdef MOZ_WIDGET_GONK // For direct texturing with gralloc buffers. The corresponding TextureClient is TextureClientShmem, // which automatically gets gralloc when it can, in which case the compositor sees that the // SurfaceDescriptor is gralloc, and decides to use a GrallocTextureHostOGL to do direct texturing, // saving the cost of a texture upload. class GrallocTextureHostOGL : public TextureHost , public TextureSourceOGL { public: GrallocTextureHostOGL() : mGL(nullptr) , mTextureTarget(0) , mGLTexture(0) , mEGLImage(0) { } ~GrallocTextureHostOGL(); virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE; virtual GLuint GetTextureHandle() { return mGLTexture; } virtual void UpdateImpl(const SurfaceDescriptor& aImage, nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE; virtual void SwapTexturesImpl(const SurfaceDescriptor& aImage, nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE; virtual bool Lock() MOZ_OVERRIDE; virtual void Unlock() MOZ_OVERRIDE; virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mGraphicBuffer.get() ? gfx::IntSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight()) : gfx::IntSize(0, 0); } gl::ShaderProgramType GetShaderProgram() const MOZ_OVERRIDE { if (mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL) { return gl::RGBAExternalLayerProgramType; } MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D); return mFormat == gfx::FORMAT_B8G8R8A8 || mFormat == gfx::FORMAT_B8G8R8X8 ? gl::BGRALayerProgramType : gl::RGBALayerProgramType; } GLenum GetWrapMode() const MOZ_OVERRIDE { return LOCAL_GL_CLAMP_TO_EDGE; } bool IsValid() const MOZ_OVERRIDE; #ifdef MOZ_LAYERS_HAVE_LOG virtual const char* Name() { return "GrallocTextureHostOGL"; } #endif void BindTexture(GLenum aTextureUnit) MOZ_OVERRIDE; virtual gfx::SurfaceFormat GetFormat() const; virtual TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; } // only overridden for hacky fix in gecko 23 for bug 862324 // see bug 865908 about fixing this. virtual void SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceAllocator* aAllocator) MOZ_OVERRIDE; // used only for hacky fix in gecko 23 for bug 862324 virtual void ForgetBuffer() { if (mBuffer) { // Intentionally don't destroy the actor held by mBuffer here. // The point is that this is only called from GrallocBufferActor::ActorDestroy // where we know that the actor is already being deleted. // See bug 862324 comment 39. delete mBuffer; mBuffer = nullptr; } mGraphicBuffer = nullptr; DeleteTextures(); } private: void DeleteTextures(); RefPtr mGL; android::sp mGraphicBuffer; GLenum mTextureTarget; GLuint mGLTexture; EGLImage mEGLImage; }; #endif } // namespace } // namespace #endif /* MOZILLA_GFX_TEXTUREOGL_H */