michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef MOZILLA_GFX_COMPOSITOROGL_H michael@0: #define MOZILLA_GFX_COMPOSITOROGL_H michael@0: michael@0: #include "gfx2DGlue.h" michael@0: #include "GLContextTypes.h" // for GLContext, etc michael@0: #include "GLDefs.h" // for GLuint, LOCAL_GL_TEXTURE_2D, etc michael@0: #include "OGLShaderProgram.h" // for ShaderProgramOGL, etc michael@0: #include "Units.h" // for ScreenPoint michael@0: #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc michael@0: #include "mozilla/Attributes.h" // for MOZ_OVERRIDE, MOZ_FINAL michael@0: #include "mozilla/RefPtr.h" // for TemporaryRef, RefPtr michael@0: #include "mozilla/gfx/2D.h" // for DrawTarget michael@0: #include "mozilla/gfx/BaseSize.h" // for BaseSize michael@0: #include "mozilla/gfx/Point.h" // for IntSize, Point michael@0: #include "mozilla/gfx/Rect.h" // for Rect, IntRect michael@0: #include "mozilla/gfx/Types.h" // for Float, SurfaceFormat, etc michael@0: #include "mozilla/layers/Compositor.h" // for SurfaceInitMode, Compositor, etc michael@0: #include "mozilla/layers/CompositorTypes.h" // for MaskType::NumMaskTypes, etc michael@0: #include "mozilla/layers/LayersTypes.h" michael@0: #include "nsAutoPtr.h" // for nsRefPtr, nsAutoPtr michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING michael@0: #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc michael@0: #include "nsSize.h" // for nsIntSize michael@0: #include "nsTArray.h" // for nsAutoTArray, nsTArray, etc michael@0: #include "nsThreadUtils.h" // for nsRunnable michael@0: #include "nsXULAppAPI.h" // for XRE_GetProcessType michael@0: #include "nscore.h" // for NS_IMETHOD michael@0: #include "VBOArena.h" // for gl::VBOArena michael@0: #ifdef MOZ_WIDGET_GONK michael@0: #include michael@0: #endif michael@0: michael@0: class gfx3DMatrix; michael@0: class nsIWidget; michael@0: michael@0: namespace mozilla { michael@0: class TimeStamp; michael@0: michael@0: namespace gfx { michael@0: class Matrix4x4; michael@0: } michael@0: michael@0: namespace layers { michael@0: michael@0: class CompositingRenderTarget; michael@0: class CompositingRenderTargetOGL; michael@0: class DataTextureSource; michael@0: class GLManagerCompositor; michael@0: class TextureSource; michael@0: struct Effect; michael@0: struct EffectChain; michael@0: michael@0: /** michael@0: * Interface for pools of temporary gl textures for the compositor. michael@0: * The textures are fully owned by the pool, so the latter is responsible michael@0: * calling fDeleteTextures accordingly. michael@0: * Users of GetTexture receive a texture that is only valid for the duration michael@0: * of the current frame. michael@0: * This is primarily intended for direct texturing APIs that need to attach michael@0: * shared objects (such as an EGLImage) to a gl texture. michael@0: */ michael@0: class CompositorTexturePoolOGL michael@0: { michael@0: protected: michael@0: virtual ~CompositorTexturePoolOGL() {} michael@0: michael@0: public: michael@0: NS_INLINE_DECL_REFCOUNTING(CompositorTexturePoolOGL) michael@0: michael@0: virtual void Clear() = 0; michael@0: michael@0: virtual GLuint GetTexture(GLenum aTarget, GLenum aEnum) = 0; michael@0: michael@0: virtual void EndFrame() = 0; michael@0: }; michael@0: michael@0: /** michael@0: * Agressively reuses textures. One gl texture per texture unit in total. michael@0: * So far this hasn't shown the best results on b2g. michael@0: */ michael@0: class PerUnitTexturePoolOGL : public CompositorTexturePoolOGL michael@0: { michael@0: public: michael@0: PerUnitTexturePoolOGL(gl::GLContext* aGL) michael@0: : mTextureTarget(0) // zero is never a valid texture target michael@0: , mGL(aGL) michael@0: {} michael@0: michael@0: virtual ~PerUnitTexturePoolOGL() michael@0: { michael@0: DestroyTextures(); michael@0: } michael@0: michael@0: virtual void Clear() MOZ_OVERRIDE michael@0: { michael@0: DestroyTextures(); michael@0: } michael@0: michael@0: virtual GLuint GetTexture(GLenum aTarget, GLenum aUnit) MOZ_OVERRIDE; michael@0: michael@0: virtual void EndFrame() MOZ_OVERRIDE {} michael@0: michael@0: protected: michael@0: void DestroyTextures(); michael@0: michael@0: GLenum mTextureTarget; michael@0: nsTArray mTextures; michael@0: RefPtr mGL; michael@0: }; michael@0: michael@0: /** michael@0: * Reuse gl textures from a pool of textures that haven't yet been michael@0: * used during the current frame. michael@0: * All the textures that are not used at the end of a frame are michael@0: * deleted. michael@0: * This strategy seems to work well with gralloc textures because destroying michael@0: * unused textures which are bound to gralloc buffers let drivers know that it michael@0: * can unlock the gralloc buffers. michael@0: */ michael@0: class PerFrameTexturePoolOGL : public CompositorTexturePoolOGL michael@0: { michael@0: public: michael@0: PerFrameTexturePoolOGL(gl::GLContext* aGL) michael@0: : mTextureTarget(0) // zero is never a valid texture target michael@0: , mGL(aGL) michael@0: {} michael@0: michael@0: virtual ~PerFrameTexturePoolOGL() michael@0: { michael@0: DestroyTextures(); michael@0: } michael@0: michael@0: virtual void Clear() MOZ_OVERRIDE michael@0: { michael@0: DestroyTextures(); michael@0: } michael@0: michael@0: virtual GLuint GetTexture(GLenum aTarget, GLenum aUnit) MOZ_OVERRIDE; michael@0: michael@0: virtual void EndFrame() MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: void DestroyTextures(); michael@0: michael@0: GLenum mTextureTarget; michael@0: RefPtr mGL; michael@0: nsTArray mCreatedTextures; michael@0: nsTArray mUnusedTextures; michael@0: }; michael@0: michael@0: class CompositorOGL : public Compositor michael@0: { michael@0: typedef mozilla::gl::GLContext GLContext; michael@0: michael@0: friend class GLManagerCompositor; michael@0: michael@0: std::map mPrograms; michael@0: public: michael@0: CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth = -1, int aSurfaceHeight = -1, michael@0: bool aUseExternalSurfaceSize = false); michael@0: michael@0: virtual ~CompositorOGL(); michael@0: michael@0: virtual TemporaryRef michael@0: CreateDataTextureSource(TextureFlags aFlags = 0) MOZ_OVERRIDE; michael@0: michael@0: virtual bool Initialize() MOZ_OVERRIDE; michael@0: michael@0: virtual void Destroy() MOZ_OVERRIDE; michael@0: michael@0: virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() MOZ_OVERRIDE michael@0: { michael@0: return TextureFactoryIdentifier(LayersBackend::LAYERS_OPENGL, michael@0: XRE_GetProcessType(), michael@0: GetMaxTextureSize(), michael@0: mFBOTextureTarget == LOCAL_GL_TEXTURE_2D, michael@0: SupportsPartialTextureUpdate()); michael@0: } michael@0: michael@0: virtual TemporaryRef michael@0: CreateRenderTarget(const gfx::IntRect &aRect, SurfaceInitMode aInit) MOZ_OVERRIDE; michael@0: michael@0: virtual TemporaryRef michael@0: CreateRenderTargetFromSource(const gfx::IntRect &aRect, michael@0: const CompositingRenderTarget *aSource, michael@0: const gfx::IntPoint &aSourcePoint) MOZ_OVERRIDE; michael@0: michael@0: virtual void SetRenderTarget(CompositingRenderTarget *aSurface) MOZ_OVERRIDE; michael@0: virtual CompositingRenderTarget* GetCurrentRenderTarget() const MOZ_OVERRIDE; michael@0: michael@0: virtual void DrawQuad(const gfx::Rect& aRect, michael@0: const gfx::Rect& aClipRect, michael@0: const EffectChain &aEffectChain, michael@0: gfx::Float aOpacity, michael@0: const gfx::Matrix4x4 &aTransform) MOZ_OVERRIDE michael@0: { michael@0: DrawQuadInternal(aRect, aClipRect, aEffectChain, michael@0: aOpacity, aTransform, LOCAL_GL_TRIANGLE_STRIP); michael@0: } michael@0: michael@0: virtual void DrawLines(const std::vector& aLines, michael@0: const gfx::Rect& aClipRect, michael@0: const gfx::Color& aColor, michael@0: gfx::Float aOpacity, michael@0: const gfx::Matrix4x4 &aTransform) MOZ_OVERRIDE; michael@0: michael@0: michael@0: virtual void EndFrame() MOZ_OVERRIDE; michael@0: virtual void SetFBAcquireFence(Layer* aLayer) MOZ_OVERRIDE; michael@0: virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE; michael@0: virtual void AbortFrame() MOZ_OVERRIDE; michael@0: michael@0: virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE; michael@0: michael@0: virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE michael@0: { michael@0: if (!mGLContext) michael@0: return false; michael@0: int32_t maxSize = GetMaxTextureSize(); michael@0: return aSize <= gfx::IntSize(maxSize, maxSize); michael@0: } michael@0: michael@0: virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Set the size of the EGL surface we're rendering to, if we're rendering to michael@0: * an EGL surface. michael@0: */ michael@0: virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) MOZ_OVERRIDE; michael@0: michael@0: virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE { michael@0: mRenderOffset = aOffset; michael@0: } michael@0: michael@0: virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) MOZ_OVERRIDE; michael@0: michael@0: virtual void SetTargetContext(gfx::DrawTarget* aTarget) MOZ_OVERRIDE michael@0: { michael@0: mTarget = aTarget; michael@0: } michael@0: michael@0: virtual void PrepareViewport(const gfx::IntSize& aSize, michael@0: const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE; michael@0: michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: virtual const char* Name() const MOZ_OVERRIDE { return "OGL"; } michael@0: #endif // MOZ_DUMP_PAINTING michael@0: michael@0: virtual LayersBackend GetBackendType() const MOZ_OVERRIDE { michael@0: return LayersBackend::LAYERS_OPENGL; michael@0: } michael@0: michael@0: virtual void Pause() MOZ_OVERRIDE; michael@0: virtual bool Resume() MOZ_OVERRIDE; michael@0: michael@0: virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; } michael@0: michael@0: GLContext* gl() const { return mGLContext; } michael@0: gfx::SurfaceFormat GetFBOFormat() const { michael@0: return gfx::SurfaceFormat::R8G8B8A8; michael@0: } michael@0: michael@0: /** michael@0: * The compositor provides with temporary textures for use with direct michael@0: * textruing like gralloc texture. michael@0: * Doing so lets us use gralloc the way it has been designed to be used michael@0: * (see https://wiki.mozilla.org/Platform/GFX/Gralloc) michael@0: */ michael@0: GLuint GetTemporaryTexture(GLenum aTarget, GLenum aUnit); michael@0: michael@0: const gfx::Matrix4x4& GetProjMatrix() const { michael@0: return mProjMatrix; michael@0: } michael@0: private: michael@0: virtual void DrawQuadInternal(const gfx::Rect& aRect, michael@0: const gfx::Rect& aClipRect, michael@0: const EffectChain &aEffectChain, michael@0: gfx::Float aOpacity, michael@0: const gfx::Matrix4x4 &aTransformi, michael@0: GLuint aDrawMode); michael@0: michael@0: virtual gfx::IntSize GetWidgetSize() const MOZ_OVERRIDE michael@0: { michael@0: return gfx::ToIntSize(mWidgetSize); michael@0: } michael@0: michael@0: /** michael@0: * Context target, nullptr when drawing directly to our swap chain. michael@0: */ michael@0: RefPtr mTarget; michael@0: michael@0: /** Widget associated with this compositor */ michael@0: nsIWidget *mWidget; michael@0: nsIntSize mWidgetSize; michael@0: nsRefPtr mGLContext; michael@0: gfx::Matrix4x4 mProjMatrix; michael@0: michael@0: /** The size of the surface we are rendering to */ michael@0: nsIntSize mSurfaceSize; michael@0: michael@0: ScreenPoint mRenderOffset; michael@0: michael@0: already_AddRefed CreateContext(); michael@0: michael@0: /** Texture target to use for FBOs */ michael@0: GLenum mFBOTextureTarget; michael@0: michael@0: /** Currently bound render target */ michael@0: RefPtr mCurrentRenderTarget; michael@0: #ifdef DEBUG michael@0: CompositingRenderTargetOGL* mWindowRenderTarget; michael@0: #endif michael@0: michael@0: /** michael@0: * VBO that has some basics in it for a textured quad, including vertex michael@0: * coords and texcoords. michael@0: */ michael@0: GLuint mQuadVBO; michael@0: michael@0: /** michael@0: * When we can't use mQuadVBO, we allocate VBOs from this arena instead. michael@0: */ michael@0: gl::VBOArena mVBOs; michael@0: michael@0: bool mHasBGRA; michael@0: michael@0: /** michael@0: * When rendering to some EGL surfaces (e.g. on Android), we rely on being told michael@0: * about size changes (via SetSurfaceSize) rather than pulling this information michael@0: * from the widget. michael@0: */ michael@0: bool mUseExternalSurfaceSize; michael@0: michael@0: /** michael@0: * Have we had DrawQuad calls since the last frame was rendered? michael@0: */ michael@0: bool mFrameInProgress; michael@0: michael@0: /* michael@0: * Clear aRect on current render target. michael@0: */ michael@0: virtual void ClearRect(const gfx::Rect& aRect) MOZ_OVERRIDE; michael@0: michael@0: /* Start a new frame. If aClipRectIn is null and aClipRectOut is non-null, michael@0: * sets *aClipRectOut to the screen dimensions. michael@0: */ michael@0: virtual void BeginFrame(const nsIntRegion& aInvalidRegion, michael@0: const gfx::Rect *aClipRectIn, michael@0: const gfx::Matrix& aTransform, michael@0: const gfx::Rect& aRenderBounds, michael@0: gfx::Rect *aClipRectOut = nullptr, michael@0: gfx::Rect *aRenderBoundsOut = nullptr) MOZ_OVERRIDE; michael@0: michael@0: ShaderConfigOGL GetShaderConfigFor(Effect *aEffect, MaskType aMask = MaskNone) const; michael@0: ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL &aConfig); michael@0: michael@0: /** michael@0: * Create a FBO backed by a texture. michael@0: * Note that the texture target type will be michael@0: * of the type returned by FBOTextureTarget; different michael@0: * shaders are required to sample from the different michael@0: * texture types. michael@0: */ michael@0: void CreateFBOWithTexture(const gfx::IntRect& aRect, bool aCopyFromSource, michael@0: GLuint aSourceFrameBuffer, michael@0: GLuint *aFBO, GLuint *aTexture); michael@0: michael@0: GLintptr QuadVBOVertexOffset() { return 0; } michael@0: GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; } michael@0: michael@0: void BindQuadVBO(); michael@0: void QuadVBOVerticesAttrib(GLuint aAttribIndex); michael@0: void QuadVBOTexCoordsAttrib(GLuint aAttribIndex); michael@0: void BindAndDrawQuad(GLuint aVertAttribIndex, michael@0: GLuint aTexCoordAttribIndex, michael@0: GLuint aDrawMode = LOCAL_GL_TRIANGLE_STRIP); michael@0: void BindAndDrawQuad(ShaderProgramOGL *aProg, michael@0: GLuint aDrawMode = LOCAL_GL_TRIANGLE_STRIP); michael@0: void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg, michael@0: const gfx3DMatrix& aTextureTransform, michael@0: const gfx::Rect& aTexCoordRect, michael@0: TextureSource *aTexture); michael@0: michael@0: void CleanupResources(); michael@0: michael@0: /** michael@0: * Copies the content of our backbuffer to the set transaction target. michael@0: * Does not restore the target FBO, so only call from EndFrame. michael@0: */ michael@0: void CopyToTarget(gfx::DrawTarget* aTarget, const gfx::Matrix& aWorldMatrix); michael@0: michael@0: /** michael@0: * Implements the flipping of the y-axis to convert from layers/compositor michael@0: * coordinates to OpenGL coordinates. michael@0: * michael@0: * Indeed, the only coordinate system that OpenGL knows has the y-axis michael@0: * pointing upwards, but the layers/compositor coordinate system has the michael@0: * y-axis pointing downwards, for good reason as Web pages are typically michael@0: * scrolled downwards. So, some flipping has to take place; FlippedY does it. michael@0: */ michael@0: GLint FlipY(GLint y) const { return mHeight - y; } michael@0: michael@0: RefPtr mTexturePool; michael@0: michael@0: bool mDestroyed; michael@0: michael@0: /** michael@0: * Height of the OpenGL context's primary framebuffer in pixels. Used by michael@0: * FlipY for the y-flipping calculation. michael@0: */ michael@0: GLint mHeight; michael@0: }; michael@0: michael@0: } michael@0: } michael@0: michael@0: #endif /* MOZILLA_GFX_COMPOSITOROGL_H */