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