import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,73 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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_layers_Composer2D_h
#define mozilla_layers_Composer2D_h
#include "gfxTypes.h"
#include "nsISupportsImpl.h"
/**
* Many platforms have dedicated hardware for simple composition.
* This hardware is usually faster or more power efficient than the
* GPU. However, in exchange for this better performance, generality
* has to be sacrificed: no 3d transforms, no intermediate surfaces,
* no special shader effects, loss of other goodies depending on the
* platform.
*
* Composer2D is a very simple interface to this class of hardware
* that allows an implementation to "try rendering" with the fast
* path. If the given layer tree requires more generality than the
* hardware provides, the implementation should bail and have the
* layer manager fall back on full GPU composition.
*/
class nsIWidget;
namespace mozilla {
namespace layers {
class Layer;
class Composer2D {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Composer2D)
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~Composer2D() {}
public:
/**
* Return true if |aRoot| met the implementation's criteria for fast
* composition and the render was successful. Return false to fall
* back on the GPU.
*
* Currently, when TryRender() returns true, the entire framebuffer
* must have been rendered.
*/
virtual bool TryRenderWithHwc(Layer* aRoot,
nsIWidget* aWidget,
bool aGeometryChanged,
bool aHasImageHostOverlays) = 0;
/**
* Return true if Composer2D does composition. Return false if Composer2D
* failed the composition.
*/
virtual bool Render(nsIWidget* aWidget) = 0;
/**
* Return true if Composer2D has a fast composition hardware.
* Return false if Composer2D does not have a fast composition hardware.
*/
virtual bool HasHwc() = 0;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_Composer2D_h

View file

@ -0,0 +1,120 @@
/* -*- 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/. */
#include "CompositingRenderTargetOGL.h"
#include "GLContext.h"
#include "GLReadTexImageHelper.h"
#include "ScopedGLHelpers.h"
#include "mozilla/gfx/2D.h"
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
using namespace mozilla::gl;
CompositingRenderTargetOGL::~CompositingRenderTargetOGL()
{
if (mGL && mGL->MakeCurrent()) {
mGL->fDeleteTextures(1, &mTextureHandle);
mGL->fDeleteFramebuffers(1, &mFBO);
}
}
void
CompositingRenderTargetOGL::BindTexture(GLenum aTextureUnit, GLenum aTextureTarget)
{
MOZ_ASSERT(mInitParams.mStatus == InitParams::INITIALIZED);
MOZ_ASSERT(mTextureHandle != 0);
mGL->fActiveTexture(aTextureUnit);
mGL->fBindTexture(aTextureTarget, mTextureHandle);
}
void
CompositingRenderTargetOGL::BindRenderTarget()
{
bool needsClear = false;
if (mInitParams.mStatus != InitParams::INITIALIZED) {
InitializeImpl();
if (mInitParams.mInit == INIT_MODE_CLEAR) {
needsClear = true;
mClearOnBind = false;
}
} else {
MOZ_ASSERT(mInitParams.mStatus == InitParams::INITIALIZED);
GLuint fbo = mFBO == 0 ? mGL->GetDefaultFramebuffer() : mFBO;
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fbo);
GLenum result = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
// The main framebuffer (0) of non-offscreen contexts
// might be backed by a EGLSurface that needs to be renewed.
if (mFBO == 0 && !mGL->IsOffscreen()) {
mGL->RenewSurface(mCompositor->GetWidget()->RealWidget());
result = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
}
if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
nsAutoCString msg;
msg.AppendPrintf("Framebuffer not complete -- CheckFramebufferStatus returned 0x%x, "
"GLContext=%p, IsOffscreen()=%d, mFBO=%d, aFBOTextureTarget=0x%x, "
"aRect.width=%d, aRect.height=%d",
result, mGL, mGL->IsOffscreen(), mFBO, mInitParams.mFBOTextureTarget,
mInitParams.mSize.width, mInitParams.mSize.height);
NS_WARNING(msg.get());
}
}
needsClear = mClearOnBind;
}
if (needsClear) {
ScopedGLState scopedScissorTestState(mGL, LOCAL_GL_SCISSOR_TEST, true);
ScopedScissorRect autoScissorRect(mGL, 0, 0, mInitParams.mSize.width,
mInitParams.mSize.height);
mGL->fClearColor(0.0, 0.0, 0.0, 0.0);
mGL->fClearDepth(0.0);
mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
}
}
#ifdef MOZ_DUMP_PAINTING
already_AddRefed<DataSourceSurface>
CompositingRenderTargetOGL::Dump(Compositor* aCompositor)
{
MOZ_ASSERT(mInitParams.mStatus == InitParams::INITIALIZED);
CompositorOGL* compositorOGL = aCompositor->AsCompositorOGL();
return ReadBackSurface(mGL, mTextureHandle, true, compositorOGL->GetFBOFormat());
}
#endif
void
CompositingRenderTargetOGL::InitializeImpl()
{
MOZ_ASSERT(mInitParams.mStatus == InitParams::READY);
//TODO: call mGL->GetBackbufferFB(), use that
GLuint fbo = mFBO == 0 ? mGL->GetDefaultFramebuffer() : mFBO;
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fbo);
mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_COLOR_ATTACHMENT0,
mInitParams.mFBOTextureTarget,
mTextureHandle,
0);
// Making this call to fCheckFramebufferStatus prevents a crash on
// PowerVR. See bug 695246.
GLenum result = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
nsAutoCString msg;
msg.AppendPrintf("Framebuffer not complete -- error 0x%x, aFBOTextureTarget 0x%x, mFBO %d, mTextureHandle %d, aRect.width %d, aRect.height %d",
result, mInitParams.mFBOTextureTarget, mFBO, mTextureHandle, mInitParams.mSize.width, mInitParams.mSize.height);
NS_ERROR(msg.get());
}
mInitParams.mStatus = InitParams::INITIALIZED;
}
} // namespace layers
} // namespace mozilla

View file

@ -0,0 +1,195 @@
/* -*- 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_COMPOSITINGRENDERTARGETOGL_H
#define MOZILLA_GFX_COMPOSITINGRENDERTARGETOGL_H
#include "GLContextTypes.h" // for GLContext
#include "GLDefs.h" // for GLenum, LOCAL_GL_FRAMEBUFFER, etc
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/Attributes.h" // for override
#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
#include "mozilla/gfx/Point.h" // for IntSize, IntSizeTyped
#include "mozilla/gfx/Types.h" // for SurfaceFormat, etc
#include "mozilla/layers/Compositor.h" // for SurfaceInitMode, etc
#include "mozilla/layers/TextureHost.h" // for CompositingRenderTarget
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
#include "mozilla/mozalloc.h" // for operator new
#include "nsAString.h"
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsDebug.h" // for NS_ERROR, NS_WARNING
#include "nsString.h" // for nsAutoCString
namespace mozilla {
namespace gl {
class BindableTexture;
} // namespace gl
namespace gfx {
class DataSourceSurface;
} // namespace gfx
namespace layers {
class TextureSource;
class CompositingRenderTargetOGL : public CompositingRenderTarget
{
typedef mozilla::gl::GLContext GLContext;
friend class CompositorOGL;
// For lazy initialisation of the GL stuff
struct InitParams
{
InitParams() : mStatus(NO_PARAMS) {}
InitParams(const gfx::IntSize& aSize,
const gfx::IntSize& aPhySize,
GLenum aFBOTextureTarget,
SurfaceInitMode aInit)
: mStatus(READY)
, mSize(aSize)
, mPhySize(aPhySize)
, mFBOTextureTarget(aFBOTextureTarget)
, mInit(aInit)
{}
enum {
NO_PARAMS,
READY,
INITIALIZED
} mStatus;
/*
* Users of render target would draw in logical size, but it is
* actually drawn to a surface in physical size. GL surfaces have
* a limitation on their size, a smaller surface would be
* allocated for the render target if the caller requests in a
* size too big.
*/
gfx::IntSize mSize; // Logical size, the expected by callers.
gfx::IntSize mPhySize; // Physical size, the real size of the surface.
GLenum mFBOTextureTarget;
SurfaceInitMode mInit;
};
public:
CompositingRenderTargetOGL(CompositorOGL* aCompositor, const gfx::IntPoint& aOrigin,
GLuint aTexure, GLuint aFBO)
: CompositingRenderTarget(aOrigin)
, mInitParams()
, mCompositor(aCompositor)
, mGL(aCompositor->gl())
, mTextureHandle(aTexure)
, mFBO(aFBO)
{
MOZ_ASSERT(mGL);
}
~CompositingRenderTargetOGL();
virtual const char* Name() const override { return "CompositingRenderTargetOGL"; }
/**
* Create a render target around the default FBO, for rendering straight to
* the window.
*/
static already_AddRefed<CompositingRenderTargetOGL>
RenderTargetForWindow(CompositorOGL* aCompositor,
const gfx::IntSize& aSize)
{
RefPtr<CompositingRenderTargetOGL> result
= new CompositingRenderTargetOGL(aCompositor, gfx::IntPoint(), 0, 0);
result->mInitParams = InitParams(aSize, aSize, 0, INIT_MODE_NONE);
result->mInitParams.mStatus = InitParams::INITIALIZED;
return result.forget();
}
/**
* Some initialisation work on the backing FBO and texture.
* We do this lazily so that when we first set this render target on the
* compositor we do not have to re-bind the FBO after unbinding it, or
* alternatively leave the FBO bound after creation.
*/
void Initialize(const gfx::IntSize& aSize,
const gfx::IntSize& aPhySize,
GLenum aFBOTextureTarget,
SurfaceInitMode aInit)
{
MOZ_ASSERT(mInitParams.mStatus == InitParams::NO_PARAMS, "Initialized twice?");
// postpone initialization until we actually want to use this render target
mInitParams = InitParams(aSize, aPhySize, aFBOTextureTarget, aInit);
}
void BindTexture(GLenum aTextureUnit, GLenum aTextureTarget);
/**
* Call when we want to draw into our FBO
*/
void BindRenderTarget();
bool IsWindow() { return GetFBO() == 0; }
GLuint GetFBO() const
{
MOZ_ASSERT(mInitParams.mStatus == InitParams::INITIALIZED);
return mFBO;
}
GLuint GetTextureHandle() const
{
MOZ_ASSERT(mInitParams.mStatus == InitParams::INITIALIZED);
return mTextureHandle;
}
// TextureSourceOGL
TextureSourceOGL* AsSourceOGL() override
{
// XXX - Bug 900770
MOZ_ASSERT(false, "CompositingRenderTargetOGL should not be used as a TextureSource");
return nullptr;
}
gfx::IntSize GetSize() const override
{
return mInitParams.mSize;
}
gfx::SurfaceFormat GetFormat() const override
{
// XXX - Should it be implemented ? is the above assert true ?
MOZ_ASSERT(false, "Not implemented");
return gfx::SurfaceFormat::UNKNOWN;
}
#ifdef MOZ_DUMP_PAINTING
virtual already_AddRefed<gfx::DataSourceSurface> Dump(Compositor* aCompositor) override;
#endif
const gfx::IntSize& GetInitSize() const {
return mInitParams.mSize;
}
private:
/**
* Actually do the initialisation. Note that we leave our FBO bound, and so
* calling this method is only suitable when about to use this render target.
*/
void InitializeImpl();
InitParams mInitParams;
/**
* There is temporary a cycle between the compositor and the render target,
* each having a strong ref to the other. The compositor's reference to
* the target is always cleared at the end of a frame.
*/
RefPtr<CompositorOGL> mCompositor;
GLContext* mGL;
GLuint mTextureHandle;
GLuint mFBO;
};
} // namespace layers
} // namespace mozilla
#endif /* MOZILLA_GFX_SURFACEOGL_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,502 @@
/* -*- 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 "ContextStateTracker.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 override, final
#include "mozilla/RefPtr.h" // for already_AddRefed, RefPtr
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/MatrixFwd.h" // for Matrix4x4
#include "mozilla/gfx/Point.h" // for IntSize, Point
#include "mozilla/gfx/Rect.h" // for Rect, IntRect
#include "mozilla/gfx/Triangle.h" // for Triangle
#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::MaskType::NumMaskTypes, etc
#include "mozilla/layers/LayersTypes.h"
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsTArray.h" // for AutoTArray, nsTArray, etc
#include "nsThreadUtils.h" // for nsRunnable
#include "nsXULAppAPI.h" // for XRE_GetProcessType
#include "nscore.h" // for NS_IMETHOD
class nsIWidget;
namespace mozilla {
namespace layers {
class CompositingRenderTarget;
class CompositingRenderTargetOGL;
class DataTextureSource;
class GLManagerCompositor;
class TextureSource;
struct Effect;
struct EffectChain;
class GLBlitTextureImageHelper;
/**
* 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:
explicit PerUnitTexturePoolOGL(gl::GLContext* aGL)
: mTextureTarget(0) // zero is never a valid texture target
, mGL(aGL)
{}
virtual ~PerUnitTexturePoolOGL()
{
DestroyTextures();
}
virtual void Clear() override
{
DestroyTextures();
}
virtual GLuint GetTexture(GLenum aTarget, GLenum aUnit) override;
virtual void EndFrame() override {}
protected:
void DestroyTextures();
GLenum mTextureTarget;
nsTArray<GLuint> mTextures;
RefPtr<gl::GLContext> 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:
explicit PerFrameTexturePoolOGL(gl::GLContext* aGL)
: mTextureTarget(0) // zero is never a valid texture target
, mGL(aGL)
{}
virtual ~PerFrameTexturePoolOGL()
{
DestroyTextures();
}
virtual void Clear() override
{
DestroyTextures();
}
virtual GLuint GetTexture(GLenum aTarget, GLenum aUnit) override;
virtual void EndFrame() override;
protected:
void DestroyTextures();
GLenum mTextureTarget;
RefPtr<gl::GLContext> mGL;
nsTArray<GLuint> mCreatedTextures;
nsTArray<GLuint> mUnusedTextures;
};
// If you want to make this class not final, first remove calls to virtual
// methods (Destroy) that are made in the destructor.
class CompositorOGL final : public Compositor
{
typedef mozilla::gl::GLContext GLContext;
friend class GLManagerCompositor;
friend class CompositingRenderTargetOGL;
std::map<ShaderConfigOGL, ShaderProgramOGL*> mPrograms;
public:
explicit CompositorOGL(CompositorBridgeParent* aParent,
widget::CompositorWidget* aWidget,
int aSurfaceWidth = -1, int aSurfaceHeight = -1,
bool aUseExternalSurfaceSize = false);
protected:
virtual ~CompositorOGL();
public:
virtual CompositorOGL* AsCompositorOGL() override { return this; }
virtual already_AddRefed<DataTextureSource>
CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) override;
virtual bool Initialize(nsCString* const out_failureReason) override;
virtual void Destroy() override;
virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override
{
TextureFactoryIdentifier result =
TextureFactoryIdentifier(LayersBackend::LAYERS_OPENGL,
XRE_GetProcessType(),
GetMaxTextureSize(),
mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
SupportsPartialTextureUpdate());
return result;
}
virtual already_AddRefed<CompositingRenderTarget>
CreateRenderTarget(const gfx::IntRect &aRect, SurfaceInitMode aInit) override;
virtual already_AddRefed<CompositingRenderTarget>
CreateRenderTargetFromSource(const gfx::IntRect &aRect,
const CompositingRenderTarget *aSource,
const gfx::IntPoint &aSourcePoint) override;
virtual void SetRenderTarget(CompositingRenderTarget *aSurface) override;
virtual CompositingRenderTarget* GetCurrentRenderTarget() const override;
virtual void DrawQuad(const gfx::Rect& aRect,
const gfx::IntRect& aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect) override;
virtual void DrawTriangle(const gfx::TexturedTriangle& aTriangle,
const gfx::IntRect& aClipRect,
const EffectChain& aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect) override;
virtual void EndFrame() override;
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override;
virtual bool SupportsPartialTextureUpdate() override;
virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override
{
if (!mGLContext)
return false;
int32_t maxSize = GetMaxTextureSize();
return aSize <= gfx::IntSize(maxSize, maxSize);
}
virtual int32_t GetMaxTextureSize() const 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) override;
virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) override {
mRenderOffset = aOffset;
}
virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) override;
#ifdef MOZ_DUMP_PAINTING
virtual const char* Name() const override { return "OGL"; }
#endif // MOZ_DUMP_PAINTING
virtual LayersBackend GetBackendType() const override {
return LayersBackend::LAYERS_OPENGL;
}
virtual void Pause() override;
virtual bool Resume() override;
virtual bool HasImageHostOverlays() override
{
return false;
}
virtual void AddImageHostOverlay(ImageHostOverlay* aOverlay) override
{
}
virtual void RemoveImageHostOverlay(ImageHostOverlay* aOverlay) override
{
}
GLContext* gl() const { return mGLContext; }
/**
* Clear the program state. This must be called
* before operating on the GLContext directly. */
void ResetProgram();
gfx::SurfaceFormat GetFBOFormat() const {
return gfx::SurfaceFormat::R8G8B8A8;
}
GLBlitTextureImageHelper* BlitTextureImageHelper();
/**
* 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;
}
void SetProjMatrix(const gfx::Matrix4x4& aProjMatrix) {
mProjMatrix = aProjMatrix;
}
const gfx::IntSize GetDestinationSurfaceSize() const {
return gfx::IntSize (mSurfaceSize.width, mSurfaceSize.height);
}
const ScreenPoint& GetScreenRenderOffset() const {
return mRenderOffset;
}
private:
template<typename Geometry>
void DrawGeometry(const Geometry& aGeometry,
const gfx::IntRect& aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect);
void PrepareViewport(CompositingRenderTargetOGL *aRenderTarget);
/** Widget associated with this compositor */
LayoutDeviceIntSize mWidgetSize;
RefPtr<GLContext> mGLContext;
UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
gfx::Matrix4x4 mProjMatrix;
/** The size of the surface we are rendering to */
gfx::IntSize mSurfaceSize;
ScreenPoint mRenderOffset;
already_AddRefed<mozilla::gl::GLContext> CreateContext();
/** Texture target to use for FBOs */
GLenum mFBOTextureTarget;
/** Currently bound render target */
RefPtr<CompositingRenderTargetOGL> mCurrentRenderTarget;
#ifdef DEBUG
CompositingRenderTargetOGL* mWindowRenderTarget;
#endif
/**
* VBO that has some basics in it for a textured quad, including vertex
* coords and texcoords.
*/
GLuint mQuadVBO;
/**
* VBO that stores dynamic triangle geometry.
*/
GLuint mTriangleVBO;
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) 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::IntRect *aClipRectIn,
const gfx::IntRect& aRenderBounds,
const nsIntRegion& aOpaqueRegion,
gfx::IntRect *aClipRectOut = nullptr,
gfx::IntRect *aRenderBoundsOut = nullptr) override;
ShaderConfigOGL GetShaderConfigFor(Effect *aEffect,
MaskType aMask = MaskType::MaskNone,
gfx::CompositionOp aOp = gfx::CompositionOp::OP_OVER,
bool aColorMatrix = false,
bool aDEAAEnabled = false) const;
ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL &aConfig);
void ApplyPrimitiveConfig(ShaderConfigOGL& aConfig,
const gfx::Rect&)
{
aConfig.SetDynamicGeometry(false);
}
void ApplyPrimitiveConfig(ShaderConfigOGL& aConfig,
const gfx::TexturedTriangle&)
{
aConfig.SetDynamicGeometry(true);
}
/**
* 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,
gfx::IntSize* aAllocSize = nullptr);
GLuint CreateTexture(const gfx::IntRect& aRect, bool aCopyFromSource,
GLuint aSourceFrameBuffer,
gfx::IntSize* aAllocSize = nullptr);
gfx::Point3D GetLineCoefficients(const gfx::Point& aPoint1,
const gfx::Point& aPoint2);
void ActivateProgram(ShaderProgramOGL *aProg);
void CleanupResources();
void BindAndDrawQuads(ShaderProgramOGL *aProg,
int aQuads,
const gfx::Rect* aLayerRect,
const gfx::Rect* aTextureRect);
void BindAndDrawQuad(ShaderProgramOGL *aProg,
const gfx::Rect& aLayerRect,
const gfx::Rect& aTextureRect =
gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f))
{
gfx::Rect layerRects[4];
gfx::Rect textureRects[4];
layerRects[0] = aLayerRect;
textureRects[0] = aTextureRect;
BindAndDrawQuads(aProg, 1, layerRects, textureRects);
}
void BindAndDrawGeometry(ShaderProgramOGL* aProgram,
const gfx::Rect& aRect,
const gfx::Rect& aTextureRect =
gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f));
void BindAndDrawGeometry(ShaderProgramOGL* aProgram,
const gfx::TexturedTriangle& aTriangle,
const gfx::Rect& aTextureRect =
gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f));
void BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
const gfx::Rect& aRect,
const gfx::Rect& aTexCoordRect,
TextureSource *aTexture);
void BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
const gfx::TexturedTriangle& aTriangle,
const gfx::Rect& aTexCoordRect,
TextureSource *aTexture);
void InitializeVAO(const GLuint aAttribIndex, const GLint aComponents,
const GLsizei aStride, const size_t aOffset);
gfx::Rect GetTextureCoordinates(gfx::Rect textureRect,
TextureSource* aTexture);
/**
* Bind the texture behind the current render target as the backdrop for a
* mix-blend shader.
*/
void BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop, GLenum aTexUnit);
/**
* 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 nsIntPoint& aTopLeft, 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 mViewportSize.height - y; }
RefPtr<CompositorTexturePoolOGL> mTexturePool;
ContextStateTrackerOGL mContextStateTracker;
bool mDestroyed;
/**
* Size of the OpenGL context's primary framebuffer in pixels. Used by
* FlipY for the y-flipping calculation and by the DEAA shader.
*/
gfx::IntSize mViewportSize;
ShaderProgramOGL *mCurrentProgram;
};
} // namespace layers
} // namespace mozilla
#endif /* MOZILLA_GFX_COMPOSITOROGL_H */

View file

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* 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/. */
#include "EGLImageHelpers.h"
#include "GLContext.h"
#include "GLLibraryEGL.h"
namespace mozilla
{
namespace layers {
using namespace gl;
EGLImage
EGLImageCreateFromNativeBuffer(GLContext* aGL, void* aBuffer, const gfx::IntSize& aCropSize)
{
EGLint attrs[] = {
LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE,
LOCAL_EGL_NONE, LOCAL_EGL_NONE,
};
EGLint cropAttrs[] = {
LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE,
LOCAL_EGL_IMAGE_CROP_LEFT_ANDROID, 0,
LOCAL_EGL_IMAGE_CROP_TOP_ANDROID, 0,
LOCAL_EGL_IMAGE_CROP_RIGHT_ANDROID, aCropSize.width,
LOCAL_EGL_IMAGE_CROP_BOTTOM_ANDROID, aCropSize.height,
LOCAL_EGL_NONE, LOCAL_EGL_NONE,
};
bool hasCropRect = (aCropSize.width != 0 && aCropSize.height != 0);
EGLint* usedAttrs = attrs;
if (hasCropRect && sEGLLibrary.IsExtensionSupported(GLLibraryEGL::EGL_ANDROID_image_crop)) {
usedAttrs = cropAttrs;
}
return sEGLLibrary.fCreateImage(sEGLLibrary.Display(),
EGL_NO_CONTEXT,
LOCAL_EGL_NATIVE_BUFFER_ANDROID,
aBuffer, usedAttrs);
}
void
EGLImageDestroy(GLContext* aGL, EGLImage aImage)
{
sEGLLibrary.fDestroyImage(sEGLLibrary.Display(), aImage);
}
} // namespace layers
} // namespace mozilla

View file

@ -0,0 +1,27 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* 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 EGLIMAGEHELPERS_H_
#define EGLIMAGEHELPERS_H_
#include "mozilla/gfx/Point.h"
typedef void* EGLImage;
namespace mozilla {
namespace gl {
class GLContext;
}
namespace layers {
EGLImage EGLImageCreateFromNativeBuffer(gl::GLContext* aGL, void* aBuffer, const gfx::IntSize& aCropSize);
void EGLImageDestroy(gl::GLContext* aGL, EGLImage aImage);
} // namespace layers
} // namespace mozilla
#endif // EGLIMAGEHELPERS_H_

View file

@ -0,0 +1,280 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* 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/. */
#include "GLBlitTextureImageHelper.h"
#include "GLUploadHelpers.h"
#include "DecomposeIntoNoRepeatTriangles.h"
#include "GLContext.h"
#include "GLTextureImage.h"
#include "ScopedGLHelpers.h"
#include "nsRect.h"
#include "gfx2DGlue.h"
#include "gfxUtils.h"
#include "CompositorOGL.h"
#include "mozilla/gfx/Point.h"
using namespace mozilla::gl;
namespace mozilla {
namespace layers {
GLBlitTextureImageHelper::GLBlitTextureImageHelper(CompositorOGL* aCompositor)
: mCompositor(aCompositor)
, mBlitProgram(0)
, mBlitFramebuffer(0)
{
}
GLBlitTextureImageHelper::~GLBlitTextureImageHelper()
{
GLContext *gl = mCompositor->gl();
// Likely used by OGL Layers.
gl->fDeleteProgram(mBlitProgram);
gl->fDeleteFramebuffers(1, &mBlitFramebuffer);
}
void
GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const gfx::IntRect& aSrcRect,
TextureImage *aDst, const gfx::IntRect& aDstRect)
{
GLContext *gl = mCompositor->gl();
if (!aSrc || !aDst || aSrcRect.IsEmpty() || aDstRect.IsEmpty())
return;
int savedFb = 0;
gl->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb);
ScopedGLState scopedScissorTestState(gl, LOCAL_GL_SCISSOR_TEST, false);
ScopedGLState scopedBlendState(gl, LOCAL_GL_BLEND, false);
// 2.0 means scale up by two
float blitScaleX = float(aDstRect.width) / float(aSrcRect.width);
float blitScaleY = float(aDstRect.height) / float(aSrcRect.height);
// We start iterating over all destination tiles
aDst->BeginBigImageIteration();
do {
// calculate portion of the tile that is going to be painted to
gfx::IntRect dstSubRect;
gfx::IntRect dstTextureRect = aDst->GetTileRect();
dstSubRect.IntersectRect(aDstRect, dstTextureRect);
// this tile is not part of the destination rectangle aDstRect
if (dstSubRect.IsEmpty())
continue;
// (*) transform the rect of this tile into the rectangle defined by aSrcRect...
gfx::IntRect dstInSrcRect(dstSubRect);
dstInSrcRect.MoveBy(-aDstRect.TopLeft());
// ...which might be of different size, hence scale accordingly
dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY);
dstInSrcRect.MoveBy(aSrcRect.TopLeft());
SetBlitFramebufferForDestTexture(aDst->GetTextureID());
UseBlitProgram();
aSrc->BeginBigImageIteration();
// now iterate over all tiles in the source Image...
do {
// calculate portion of the source tile that is in the source rect
gfx::IntRect srcSubRect;
gfx::IntRect srcTextureRect = aSrc->GetTileRect();
srcSubRect.IntersectRect(aSrcRect, srcTextureRect);
// this tile is not part of the source rect
if (srcSubRect.IsEmpty()) {
continue;
}
// calculate intersection of source rect with destination rect
srcSubRect.IntersectRect(srcSubRect, dstInSrcRect);
// this tile does not overlap the current destination tile
if (srcSubRect.IsEmpty()) {
continue;
}
// We now have the intersection of
// the current source tile
// and the desired source rectangle
// and the destination tile
// and the desired destination rectange
// in destination space.
// We need to transform this back into destination space, inverting the transform from (*)
gfx::IntRect srcSubInDstRect(srcSubRect);
srcSubInDstRect.MoveBy(-aSrcRect.TopLeft());
srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY);
srcSubInDstRect.MoveBy(aDstRect.TopLeft());
// we transform these rectangles to be relative to the current src and dst tiles, respectively
gfx::IntSize srcSize = srcTextureRect.Size();
gfx::IntSize dstSize = dstTextureRect.Size();
srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y);
srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y);
float dx0 = 2.0f * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0f;
float dy0 = 2.0f * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0f;
float dx1 = 2.0f * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0f;
float dy1 = 2.0f * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0f;
ScopedViewportRect autoViewportRect(gl, 0, 0, dstSize.width, dstSize.height);
RectTriangles rects;
gfx::IntSize realTexSize = srcSize;
if (!CanUploadNonPowerOfTwo(gl)) {
realTexSize = gfx::IntSize(RoundUpPow2(srcSize.width),
RoundUpPow2(srcSize.height));
}
if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) {
rects.addRect(/* dest rectangle */
dx0, dy0, dx1, dy1,
/* tex coords */
srcSubRect.x / float(realTexSize.width),
srcSubRect.y / float(realTexSize.height),
srcSubRect.XMost() / float(realTexSize.width),
srcSubRect.YMost() / float(realTexSize.height));
} else {
DecomposeIntoNoRepeatTriangles(srcSubRect, realTexSize, rects);
// now put the coords into the d[xy]0 .. d[xy]1 coordinate space
// from the 0..1 that it comes out of decompose
InfallibleTArray<RectTriangles::coord>& coords = rects.vertCoords();
for (unsigned int i = 0; i < coords.Length(); ++i) {
coords[i].x = (coords[i].x * (dx1 - dx0)) + dx0;
coords[i].y = (coords[i].y * (dy1 - dy0)) + dy0;
}
}
ScopedBindTextureUnit autoTexUnit(gl, LOCAL_GL_TEXTURE0);
ScopedBindTexture autoTex(gl, aSrc->GetTextureID());
ScopedVertexAttribPointer autoAttrib0(gl, 0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0, rects.vertCoords().Elements());
ScopedVertexAttribPointer autoAttrib1(gl, 1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0, rects.texCoords().Elements());
gl->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
} while (aSrc->NextTile());
} while (aDst->NextTile());
// unbind the previous texture from the framebuffer
SetBlitFramebufferForDestTexture(0);
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb);
}
void
GLBlitTextureImageHelper::SetBlitFramebufferForDestTexture(GLuint aTexture)
{
GLContext *gl = mCompositor->gl();
if (!mBlitFramebuffer) {
gl->fGenFramebuffers(1, &mBlitFramebuffer);
}
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBlitFramebuffer);
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_TEXTURE_2D,
aTexture,
0);
GLenum result = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
if (aTexture && (result != LOCAL_GL_FRAMEBUFFER_COMPLETE)) {
nsAutoCString msg;
msg.AppendLiteral("Framebuffer not complete -- error 0x");
msg.AppendInt(result, 16);
// Note: if you are hitting this, it is likely that
// your texture is not texture complete -- that is, you
// allocated a texture name, but didn't actually define its
// size via a call to TexImage2D.
NS_RUNTIMEABORT(msg.get());
}
}
void
GLBlitTextureImageHelper::UseBlitProgram()
{
// XXX: GLBlitTextureImageHelper doesn't use ShaderProgramOGL
// so we need to Reset the program
mCompositor->ResetProgram();
GLContext *gl = mCompositor->gl();
if (mBlitProgram) {
gl->fUseProgram(mBlitProgram);
return;
}
mBlitProgram = gl->fCreateProgram();
GLuint shaders[2];
shaders[0] = gl->fCreateShader(LOCAL_GL_VERTEX_SHADER);
shaders[1] = gl->fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
const char *blitVSSrc =
"attribute vec2 aVertex;"
"attribute vec2 aTexCoord;"
"varying vec2 vTexCoord;"
"void main() {"
" vTexCoord = aTexCoord;"
" gl_Position = vec4(aVertex, 0.0, 1.0);"
"}";
const char *blitFSSrc = "#ifdef GL_ES\nprecision mediump float;\n#endif\n"
"uniform sampler2D uSrcTexture;"
"varying vec2 vTexCoord;"
"void main() {"
" gl_FragColor = texture2D(uSrcTexture, vTexCoord);"
"}";
gl->fShaderSource(shaders[0], 1, (const GLchar**) &blitVSSrc, nullptr);
gl->fShaderSource(shaders[1], 1, (const GLchar**) &blitFSSrc, nullptr);
for (int i = 0; i < 2; ++i) {
GLint success, len = 0;
gl->fCompileShader(shaders[i]);
gl->fGetShaderiv(shaders[i], LOCAL_GL_COMPILE_STATUS, &success);
NS_ASSERTION(success, "Shader compilation failed!");
if (!success) {
nsAutoCString log;
gl->fGetShaderiv(shaders[i], LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
log.SetCapacity(len);
gl->fGetShaderInfoLog(shaders[i], len, (GLint*) &len, (char*) log.BeginWriting());
log.SetLength(len);
printf_stderr("Shader %d compilation failed:\n%s\n", i, log.get());
return;
}
gl->fAttachShader(mBlitProgram, shaders[i]);
gl->fDeleteShader(shaders[i]);
}
gl->fBindAttribLocation(mBlitProgram, 0, "aVertex");
gl->fBindAttribLocation(mBlitProgram, 1, "aTexCoord");
gl->fLinkProgram(mBlitProgram);
GLint success, len = 0;
gl->fGetProgramiv(mBlitProgram, LOCAL_GL_LINK_STATUS, &success);
NS_ASSERTION(success, "Shader linking failed!");
if (!success) {
nsAutoCString log;
gl->fGetProgramiv(mBlitProgram, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
log.SetCapacity(len);
gl->fGetProgramInfoLog(mBlitProgram, len, (GLint*) &len, (char*) log.BeginWriting());
log.SetLength(len);
printf_stderr("Program linking failed:\n%s\n", log.get());
return;
}
gl->fUseProgram(mBlitProgram);
gl->fUniform1i(gl->fGetUniformLocation(mBlitProgram, "uSrcTexture"), 0);
}
} // namespace layers
} // namespace mozilla

View file

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* 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 GLBLITTEXTUREIMAGEHELPER_H_
#define GLBLITTEXTUREIMAGEHELPER_H_
#include "mozilla/Attributes.h"
#include "GLContextTypes.h"
#include "GLConsts.h"
#include "mozilla/gfx/Rect.h"
namespace mozilla {
namespace gl {
class GLContext;
class TextureImage;
} // namespace gl
namespace layers {
class CompositorOGL;
class GLBlitTextureImageHelper final
{
// The GLContext is the sole owner of the GLBlitTextureImageHelper.
CompositorOGL* mCompositor;
// lazy-initialized things
GLuint mBlitProgram, mBlitFramebuffer;
void UseBlitProgram();
void SetBlitFramebufferForDestTexture(GLuint aTexture);
public:
explicit GLBlitTextureImageHelper(CompositorOGL *gl);
~GLBlitTextureImageHelper();
/**
* Copy a rectangle from one TextureImage into another. The
* source and destination are given in integer coordinates, and
* will be converted to texture coordinates.
*
* For the source texture, the wrap modes DO apply -- it's valid
* to use REPEAT or PAD and expect appropriate behaviour if the source
* rectangle extends beyond its bounds.
*
* For the destination texture, the wrap modes DO NOT apply -- the
* destination will be clipped by the bounds of the texture.
*
* Note: calling this function will cause the following OpenGL state
* to be changed:
*
* - current program
* - framebuffer binding
* - viewport
* - blend state (will be enabled at end)
* - scissor state (will be enabled at end)
* - vertex attrib 0 and 1 (pointer and enable state [enable state will be disabled at exit])
* - array buffer binding (will be 0)
* - active texture (will be 0)
* - texture 0 binding
*/
void BlitTextureImage(gl::TextureImage *aSrc, const gfx::IntRect& aSrcRect,
gl::TextureImage *aDst, const gfx::IntRect& aDstRect);
};
} // namespace layers
} // namespace mozilla
#endif // GLBLITTEXTUREIMAGEHELPER_H_

View file

@ -0,0 +1,70 @@
/* -*- 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/. */
#include "GLManager.h"
#include "CompositorOGL.h" // for CompositorOGL
#include "GLContext.h" // for GLContext
#include "mozilla/Attributes.h" // for override
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/mozalloc.h" // for operator new, etc
using namespace mozilla::gl;
namespace mozilla {
namespace layers {
class GLManagerCompositor : public GLManager
{
public:
explicit GLManagerCompositor(CompositorOGL* aCompositor)
: mImpl(aCompositor)
{}
virtual GLContext* gl() const override
{
return mImpl->gl();
}
virtual void ActivateProgram(ShaderProgramOGL *aProg) override
{
mImpl->ActivateProgram(aProg);
}
virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) override
{
ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(aTarget, aFormat);
return mImpl->GetShaderProgramFor(config);
}
virtual const gfx::Matrix4x4& GetProjMatrix() const override
{
return mImpl->GetProjMatrix();
}
virtual void BindAndDrawQuad(ShaderProgramOGL *aProg,
const gfx::Rect& aLayerRect,
const gfx::Rect& aTextureRect) override
{
mImpl->BindAndDrawQuad(aProg, aLayerRect, aTextureRect);
}
private:
RefPtr<CompositorOGL> mImpl;
};
/* static */ GLManager*
GLManager::CreateGLManager(LayerManagerComposite* aManager)
{
if (aManager && aManager->GetCompositor()->GetBackendType() == LayersBackend::LAYERS_OPENGL) {
return new GLManagerCompositor(aManager->GetCompositor()->AsCompositorOGL());
}
return nullptr;
}
} // namespace layers
} // namespace mozilla

View file

@ -0,0 +1,44 @@
/* -*- 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_GLMANAGER_H
#define MOZILLA_GFX_GLMANAGER_H
#include "mozilla/gfx/Types.h" // for SurfaceFormat
#include "OGLShaderProgram.h"
namespace mozilla {
namespace gl {
class GLContext;
} // namespace gl
namespace layers {
class LayerManagerComposite;
/**
* Minimal interface to allow widgets to draw using OpenGL. Abstracts
* CompositorOGL. Call CreateGLManager with a LayerManagerComposite
* backed by a CompositorOGL.
*/
class GLManager
{
public:
static GLManager* CreateGLManager(LayerManagerComposite* aManager);
virtual ~GLManager() {}
virtual gl::GLContext* gl() const = 0;
virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) = 0;
virtual void ActivateProgram(ShaderProgramOGL* aPrg) = 0;
virtual const gfx::Matrix4x4& GetProjMatrix() const = 0;
virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aLayerRect,
const gfx::Rect& aTextureRect) = 0;
};
} // namespace layers
} // namespace mozilla
#endif

View file

@ -0,0 +1,140 @@
/* -*- 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/. */
#include "MacIOSurfaceTextureClientOGL.h"
#include "mozilla/gfx/MacIOSurface.h"
#include "MacIOSurfaceHelpers.h"
#include "gfxPlatform.h"
namespace mozilla {
namespace layers {
using namespace gfx;
MacIOSurfaceTextureData::MacIOSurfaceTextureData(MacIOSurface* aSurface,
BackendType aBackend)
: mSurface(aSurface)
, mBackend(aBackend)
{
MOZ_ASSERT(mSurface);
}
MacIOSurfaceTextureData::~MacIOSurfaceTextureData()
{}
// static
MacIOSurfaceTextureData*
MacIOSurfaceTextureData::Create(MacIOSurface* aSurface, BackendType aBackend)
{
MOZ_ASSERT(aSurface);
if (!aSurface) {
return nullptr;
}
return new MacIOSurfaceTextureData(aSurface, aBackend);
}
MacIOSurfaceTextureData*
MacIOSurfaceTextureData::Create(const IntSize& aSize,
SurfaceFormat aFormat,
BackendType aBackend)
{
if (aFormat != SurfaceFormat::B8G8R8A8 &&
aFormat != SurfaceFormat::B8G8R8X8) {
return nullptr;
}
RefPtr<MacIOSurface> surf = MacIOSurface::CreateIOSurface(aSize.width, aSize.height,
1.0,
aFormat == SurfaceFormat::B8G8R8A8);
if (!surf) {
return nullptr;
}
return Create(surf, aBackend);
}
bool
MacIOSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
{
aOutDescriptor = SurfaceDescriptorMacIOSurface(mSurface->GetIOSurfaceID(),
mSurface->GetContentsScaleFactor(),
!mSurface->HasAlpha());
return true;
}
void
MacIOSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const
{
aInfo.size = gfx::IntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight());
aInfo.format = mSurface->HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
aInfo.hasIntermediateBuffer = false;
aInfo.hasSynchronization = false;
aInfo.supportsMoz2D = true;
aInfo.canExposeMappedData = false;
}
bool
MacIOSurfaceTextureData::Lock(OpenMode)
{
mSurface->Lock(false);
return true;
}
void
MacIOSurfaceTextureData::Unlock()
{
mSurface->Unlock(false);
}
already_AddRefed<DataSourceSurface>
MacIOSurfaceTextureData::GetAsSurface()
{
RefPtr<SourceSurface> surf = CreateSourceSurfaceFromMacIOSurface(mSurface);
return surf->GetDataSurface();
}
already_AddRefed<DrawTarget>
MacIOSurfaceTextureData::BorrowDrawTarget()
{
MOZ_ASSERT(mBackend != BackendType::NONE);
if (mBackend == BackendType::NONE) {
// shouldn't happen, but degrade gracefully
return nullptr;
}
return Factory::CreateDrawTargetForData(
mBackend,
(unsigned char*)mSurface->GetBaseAddress(),
IntSize(mSurface->GetWidth(), mSurface->GetHeight()),
mSurface->GetBytesPerRow(),
mSurface->HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8,
true);
}
void
MacIOSurfaceTextureData::Deallocate(LayersIPCChannel*)
{
mSurface = nullptr;
}
void
MacIOSurfaceTextureData::Forget(LayersIPCChannel*)
{
mSurface = nullptr;
}
bool
MacIOSurfaceTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
{
RefPtr<DrawTarget> dt = BorrowDrawTarget();
if (!dt) {
return false;
}
dt->CopySurface(aSurface, IntRect(IntPoint(), aSurface->GetSize()), IntPoint());
return true;
}
} // namespace layers
} // namespace mozilla

View file

@ -0,0 +1,58 @@
/* -*- 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_MACIOSURFACETEXTURECLIENTOGL_H
#define MOZILLA_GFX_MACIOSURFACETEXTURECLIENTOGL_H
#include "mozilla/layers/TextureClientOGL.h"
class MacIOSurface;
namespace mozilla {
namespace layers {
class MacIOSurfaceTextureData : public TextureData
{
public:
static MacIOSurfaceTextureData* Create(MacIOSurface* aSurface,
gfx::BackendType aBackend);
static MacIOSurfaceTextureData*
Create(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
gfx::BackendType aBackend);
~MacIOSurfaceTextureData();
virtual void FillInfo(TextureData::Info& aInfo) const override;
virtual bool Lock(OpenMode) override;
virtual void Unlock() override;
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
virtual void Deallocate(LayersIPCChannel*) override;
virtual void Forget(LayersIPCChannel*) override;
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
// For debugging purposes only.
already_AddRefed<gfx::DataSourceSurface> GetAsSurface();
protected:
MacIOSurfaceTextureData(MacIOSurface* aSurface,
gfx::BackendType aBackend);
RefPtr<MacIOSurface> mSurface;
gfx::BackendType mBackend;
};
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_GFX_MACIOSURFACETEXTURECLIENTOGL_H

View file

@ -0,0 +1,172 @@
/* -*- 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/. */
#include "MacIOSurfaceTextureHostOGL.h"
#include "mozilla/gfx/MacIOSurface.h"
#include "GLContextCGL.h"
namespace mozilla {
namespace layers {
MacIOSurfaceTextureHostOGL::MacIOSurfaceTextureHostOGL(TextureFlags aFlags,
const SurfaceDescriptorMacIOSurface& aDescriptor)
: TextureHost(aFlags)
{
MOZ_COUNT_CTOR(MacIOSurfaceTextureHostOGL);
mSurface = MacIOSurface::LookupSurface(aDescriptor.surfaceId(),
aDescriptor.scaleFactor(),
!aDescriptor.isOpaque());
}
MacIOSurfaceTextureHostOGL::~MacIOSurfaceTextureHostOGL()
{
MOZ_COUNT_DTOR(MacIOSurfaceTextureHostOGL);
}
GLTextureSource*
MacIOSurfaceTextureHostOGL::CreateTextureSourceForPlane(size_t aPlane)
{
GLuint textureHandle;
gl::GLContext* gl = mCompositor->gl();
gl->fGenTextures(1, &textureHandle);
gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textureHandle);
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
mSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(gl)->GetCGLContext(), aPlane);
return new GLTextureSource(mCompositor, textureHandle, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
gfx::IntSize(mSurface->GetDevicePixelWidth(aPlane),
mSurface->GetDevicePixelHeight(aPlane)),
// XXX: This isn't really correct (but isn't used), we should be using the
// format of the individual plane, not of the whole buffer.
mSurface->GetFormat());
}
bool
MacIOSurfaceTextureHostOGL::Lock()
{
if (!gl() || !gl()->MakeCurrent() || !mSurface) {
return false;
}
if (!mTextureSource) {
mTextureSource = CreateTextureSourceForPlane(0);
RefPtr<TextureSource> prev = mTextureSource;
for (size_t i = 1; i < mSurface->GetPlaneCount(); i++) {
RefPtr<TextureSource> next = CreateTextureSourceForPlane(i);
prev->SetNextSibling(next);
prev = next;
}
}
return true;
}
void
MacIOSurfaceTextureHostOGL::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = AssertGLCompositor(aCompositor);
if (!glCompositor) {
mTextureSource = nullptr;
mCompositor = nullptr;
return;
}
if (mCompositor != glCompositor) {
// Cannot share GL texture identifiers across compositors.
mTextureSource = nullptr;
}
mCompositor = glCompositor;
}
gfx::SurfaceFormat
MacIOSurfaceTextureHostOGL::GetFormat() const {
return mSurface->GetFormat();
}
gfx::SurfaceFormat
MacIOSurfaceTextureHostOGL::GetReadFormat() const {
return mSurface->GetReadFormat();
}
gfx::IntSize
MacIOSurfaceTextureHostOGL::GetSize() const {
if (!mSurface) {
return gfx::IntSize();
}
return gfx::IntSize(mSurface->GetDevicePixelWidth(),
mSurface->GetDevicePixelHeight());
}
gl::GLContext*
MacIOSurfaceTextureHostOGL::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
MacIOSurfaceTextureSourceOGL::MacIOSurfaceTextureSourceOGL(
CompositorOGL* aCompositor,
MacIOSurface* aSurface)
: mCompositor(aCompositor)
, mSurface(aSurface)
{
MOZ_ASSERT(aCompositor);
MOZ_COUNT_CTOR(MacIOSurfaceTextureSourceOGL);
}
MacIOSurfaceTextureSourceOGL::~MacIOSurfaceTextureSourceOGL()
{
MOZ_COUNT_DTOR(MacIOSurfaceTextureSourceOGL);
}
gfx::IntSize
MacIOSurfaceTextureSourceOGL::GetSize() const
{
return gfx::IntSize(mSurface->GetDevicePixelWidth(),
mSurface->GetDevicePixelHeight());
}
gfx::SurfaceFormat
MacIOSurfaceTextureSourceOGL::GetFormat() const
{
return mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8
: gfx::SurfaceFormat::R8G8B8X8;
}
void
MacIOSurfaceTextureSourceOGL::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
gl::GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
NS_WARNING("Trying to bind a texture without a working GLContext");
return;
}
GLuint tex = mCompositor->GetTemporaryTexture(GetTextureTarget(), aTextureUnit);
gl->fActiveTexture(aTextureUnit);
gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, tex);
mSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(gl)->GetCGLContext());
ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
}
void
MacIOSurfaceTextureSourceOGL::SetCompositor(Compositor* aCompositor)
{
mCompositor = AssertGLCompositor(aCompositor);
if (mCompositor && mNextSibling) {
mNextSibling->SetCompositor(aCompositor);
}
}
gl::GLContext*
MacIOSurfaceTextureSourceOGL::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
} // namespace layers
} // namespace mozilla

View file

@ -0,0 +1,114 @@
/* -*- 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_MACIOSURFACETEXTUREHOSTOGL_H
#define MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_H
#include "mozilla/layers/CompositorOGL.h"
#include "mozilla/layers/TextureHostOGL.h"
class MacIOSurface;
namespace mozilla {
namespace layers {
/**
* A texture source meant for use with MacIOSurfaceTextureHostOGL.
*
* It does not own any GL texture, and attaches its shared handle to one of
* the compositor's temporary textures when binding.
*/
class MacIOSurfaceTextureSourceOGL : public TextureSource
, public TextureSourceOGL
{
public:
MacIOSurfaceTextureSourceOGL(CompositorOGL* aCompositor,
MacIOSurface* aSurface);
virtual ~MacIOSurfaceTextureSourceOGL();
virtual const char* Name() const override { return "MacIOSurfaceTextureSourceOGL"; }
virtual TextureSourceOGL* AsSourceOGL() override { return this; }
virtual void BindTexture(GLenum activetex,
gfx::SamplingFilter aSamplingFilter) override;
virtual bool IsValid() const override { return !!gl(); }
virtual gfx::IntSize GetSize() const override;
virtual gfx::SurfaceFormat GetFormat() const override;
virtual GLenum GetTextureTarget() const override { return LOCAL_GL_TEXTURE_RECTANGLE_ARB; }
virtual GLenum GetWrapMode() const override { return LOCAL_GL_CLAMP_TO_EDGE; }
// MacIOSurfaceTextureSourceOGL doesn't own any gl texture
virtual void DeallocateDeviceData() override {}
virtual void SetCompositor(Compositor* aCompositor) override;
gl::GLContext* gl() const;
protected:
RefPtr<CompositorOGL> mCompositor;
RefPtr<MacIOSurface> mSurface;
};
/**
* A TextureHost for shared MacIOSurface
*
* Most of the logic actually happens in MacIOSurfaceTextureSourceOGL.
*/
class MacIOSurfaceTextureHostOGL : public TextureHost
{
public:
MacIOSurfaceTextureHostOGL(TextureFlags aFlags,
const SurfaceDescriptorMacIOSurface& aDescriptor);
virtual ~MacIOSurfaceTextureHostOGL();
// MacIOSurfaceTextureSourceOGL doesn't own any GL texture
virtual void DeallocateDeviceData() override {}
virtual void SetCompositor(Compositor* aCompositor) override;
virtual Compositor* GetCompositor() override { return mCompositor; }
virtual bool Lock() override;
virtual gfx::SurfaceFormat GetFormat() const override;
virtual gfx::SurfaceFormat GetReadFormat() const override;
virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
{
aTexture = mTextureSource;
return !!aTexture;
}
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
{
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}
gl::GLContext* gl() const;
virtual gfx::IntSize GetSize() const override;
#ifdef MOZ_LAYERS_HAVE_LOG
virtual const char* Name() override { return "MacIOSurfaceTextureHostOGL"; }
#endif
protected:
GLTextureSource* CreateTextureSourceForPlane(size_t aPlane);
RefPtr<CompositorOGL> mCompositor;
RefPtr<GLTextureSource> mTextureSource;
RefPtr<MacIOSurface> mSurface;
};
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_H

View file

@ -0,0 +1,974 @@
/* 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/. */
#include "OGLShaderProgram.h"
#include <stdint.h> // for uint32_t
#include <sstream> // for ostringstream
#include "gfxEnv.h"
#include "gfxRect.h" // for gfxRect
#include "gfxUtils.h"
#include "mozilla/DebugOnly.h" // for DebugOnly
#include "mozilla/layers/Compositor.h" // for BlendOpIsMixBlendMode
#include "nsAString.h"
#include "nsString.h" // for nsAutoCString
#include "Layers.h"
#include "GLContext.h"
namespace mozilla {
namespace layers {
using namespace std;
#define GAUSSIAN_KERNEL_HALF_WIDTH 11
#define GAUSSIAN_KERNEL_STEP 0.2
void
AddUniforms(ProgramProfileOGL& aProfile)
{
// This needs to be kept in sync with the KnownUniformName enum
static const char *sKnownUniformNames[] = {
"uLayerTransform",
"uLayerTransformInverse",
"uMaskTransform",
"uBackdropTransform",
"uLayerRects",
"uMatrixProj",
"uTextureTransform",
"uTextureRects",
"uRenderTargetOffset",
"uLayerOpacity",
"uTexture",
"uYTexture",
"uCbTexture",
"uCrTexture",
"uBlackTexture",
"uWhiteTexture",
"uMaskTexture",
"uBackdropTexture",
"uRenderColor",
"uTexCoordMultiplier",
"uCbCrTexCoordMultiplier",
"uTexturePass2",
"uColorMatrix",
"uColorMatrixVector",
"uBlurRadius",
"uBlurOffset",
"uBlurAlpha",
"uBlurGaussianKernel",
"uSSEdges",
"uViewportSize",
"uVisibleCenter",
"uYuvColorMatrix",
nullptr
};
for (int i = 0; sKnownUniformNames[i] != nullptr; ++i) {
aProfile.mUniforms[i].mNameString = sKnownUniformNames[i];
aProfile.mUniforms[i].mName = (KnownUniform::KnownUniformName) i;
}
}
void
ShaderConfigOGL::SetRenderColor(bool aEnabled)
{
SetFeature(ENABLE_RENDER_COLOR, aEnabled);
}
void
ShaderConfigOGL::SetTextureTarget(GLenum aTarget)
{
SetFeature(ENABLE_TEXTURE_EXTERNAL | ENABLE_TEXTURE_RECT, false);
switch (aTarget) {
case LOCAL_GL_TEXTURE_EXTERNAL:
SetFeature(ENABLE_TEXTURE_EXTERNAL, true);
break;
case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
SetFeature(ENABLE_TEXTURE_RECT, true);
break;
}
}
void
ShaderConfigOGL::SetRBSwap(bool aEnabled)
{
SetFeature(ENABLE_TEXTURE_RB_SWAP, aEnabled);
}
void
ShaderConfigOGL::SetNoAlpha(bool aEnabled)
{
SetFeature(ENABLE_TEXTURE_NO_ALPHA, aEnabled);
}
void
ShaderConfigOGL::SetOpacity(bool aEnabled)
{
SetFeature(ENABLE_OPACITY, aEnabled);
}
void
ShaderConfigOGL::SetYCbCr(bool aEnabled)
{
SetFeature(ENABLE_TEXTURE_YCBCR, aEnabled);
MOZ_ASSERT(!(mFeatures & ENABLE_TEXTURE_NV12));
}
void
ShaderConfigOGL::SetNV12(bool aEnabled)
{
SetFeature(ENABLE_TEXTURE_NV12, aEnabled);
MOZ_ASSERT(!(mFeatures & ENABLE_TEXTURE_YCBCR));
}
void
ShaderConfigOGL::SetComponentAlpha(bool aEnabled)
{
SetFeature(ENABLE_TEXTURE_COMPONENT_ALPHA, aEnabled);
}
void
ShaderConfigOGL::SetColorMatrix(bool aEnabled)
{
SetFeature(ENABLE_COLOR_MATRIX, aEnabled);
}
void
ShaderConfigOGL::SetBlur(bool aEnabled)
{
SetFeature(ENABLE_BLUR, aEnabled);
}
void
ShaderConfigOGL::SetMask(bool aEnabled)
{
SetFeature(ENABLE_MASK, aEnabled);
}
void
ShaderConfigOGL::SetNoPremultipliedAlpha()
{
SetFeature(ENABLE_NO_PREMUL_ALPHA, true);
}
void
ShaderConfigOGL::SetDEAA(bool aEnabled)
{
SetFeature(ENABLE_DEAA, aEnabled);
}
void
ShaderConfigOGL::SetCompositionOp(gfx::CompositionOp aOp)
{
mCompositionOp = aOp;
}
void
ShaderConfigOGL::SetDynamicGeometry(bool aEnabled)
{
SetFeature(ENABLE_DYNAMIC_GEOMETRY, aEnabled);
}
/* static */ ProgramProfileOGL
ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
{
ProgramProfileOGL result;
ostringstream fs, vs;
AddUniforms(result);
gfx::CompositionOp blendOp = aConfig.mCompositionOp;
vs << "#ifdef GL_ES" << endl;
vs << "#define EDGE_PRECISION mediump" << endl;
vs << "#else" << endl;
vs << "#define EDGE_PRECISION" << endl;
vs << "#endif" << endl;
vs << "uniform mat4 uMatrixProj;" << endl;
vs << "uniform vec4 uLayerRects[4];" << endl;
vs << "uniform mat4 uLayerTransform;" << endl;
if (aConfig.mFeatures & ENABLE_DEAA) {
vs << "uniform mat4 uLayerTransformInverse;" << endl;
vs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
vs << "uniform vec2 uVisibleCenter;" << endl;
vs << "uniform vec2 uViewportSize;" << endl;
}
vs << "uniform vec2 uRenderTargetOffset;" << endl;
vs << "attribute vec4 aCoord;" << endl;
result.mAttributes.AppendElement(Pair<nsCString, GLuint> {"aCoord", 0});
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
vs << "uniform mat4 uTextureTransform;" << endl;
vs << "uniform vec4 uTextureRects[4];" << endl;
vs << "varying vec2 vTexCoord;" << endl;
if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
vs << "attribute vec2 aTexCoord;" << endl;
result.mAttributes.AppendElement(Pair<nsCString, GLuint> {"aTexCoord", 1});
}
}
if (BlendOpIsMixBlendMode(blendOp)) {
vs << "uniform mat4 uBackdropTransform;" << endl;
vs << "varying vec2 vBackdropCoord;" << endl;
}
if (aConfig.mFeatures & ENABLE_MASK) {
vs << "uniform mat4 uMaskTransform;" << endl;
vs << "varying vec3 vMaskCoord;" << endl;
}
vs << "void main() {" << endl;
if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
vs << " vec4 finalPosition = vec4(aCoord.xy, 0.0, 1.0);" << endl;
} else {
vs << " int vertexID = int(aCoord.w);" << endl;
vs << " vec4 layerRect = uLayerRects[vertexID];" << endl;
vs << " vec4 finalPosition = vec4(aCoord.xy * layerRect.zw + layerRect.xy, 0.0, 1.0);" << endl;
}
vs << " finalPosition = uLayerTransform * finalPosition;" << endl;
if (aConfig.mFeatures & ENABLE_DEAA) {
// XXX kip - The DEAA shader could be made simpler if we switch to
// using dynamic vertex buffers instead of sending everything
// in through uniforms. This would enable passing information
// about how to dilate each vertex explicitly and eliminate the
// need to extrapolate this with the sub-pixel coverage
// calculation in the vertex shader.
// Calculate the screen space position of this vertex, in screen pixels
vs << " vec4 ssPos = finalPosition;" << endl;
vs << " ssPos.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
vs << " ssPos = uMatrixProj * ssPos;" << endl;
vs << " ssPos.xy = ((ssPos.xy/ssPos.w)*0.5+0.5)*uViewportSize;" << endl;
if (aConfig.mFeatures & ENABLE_MASK ||
!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
vs << " vec4 coordAdjusted;" << endl;
vs << " coordAdjusted.xy = aCoord.xy;" << endl;
}
// It is necessary to dilate edges away from uVisibleCenter to ensure that
// fragments with less than 50% sub-pixel coverage will be shaded.
// This offset is applied when the sub-pixel coverage of the vertex is
// less than 100%. Expanding by 0.5 pixels in screen space is sufficient
// to include these pixels.
vs << " if (dot(uSSEdges[0], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
vs << " dot(uSSEdges[1], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
vs << " dot(uSSEdges[2], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
vs << " dot(uSSEdges[3], vec3(ssPos.xy, 1.0)) < 1.5) {" << endl;
// If the shader reaches this branch, then this vertex is on the edge of
// the layer's visible rect and should be dilated away from the center of
// the visible rect. We don't want to hit this for inner facing
// edges between tiles, as the pixels may be covered twice without clipping
// against uSSEdges. If all edges were dilated, it would result in
// artifacts visible within semi-transparent layers with multiple tiles.
vs << " vec4 visibleCenter = uLayerTransform * vec4(uVisibleCenter, 0.0, 1.0);" << endl;
vs << " vec2 dilateDir = finalPosition.xy / finalPosition.w - visibleCenter.xy / visibleCenter.w;" << endl;
vs << " vec2 offset = sign(dilateDir) * 0.5;" << endl;
vs << " finalPosition.xy += offset * finalPosition.w;" << endl;
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
// We must adjust the texture coordinates to compensate for the dilation
vs << " coordAdjusted = uLayerTransformInverse * finalPosition;" << endl;
vs << " coordAdjusted /= coordAdjusted.w;" << endl;
if (!(aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY)) {
vs << " coordAdjusted.xy -= layerRect.xy;" << endl;
vs << " coordAdjusted.xy /= layerRect.zw;" << endl;
}
}
vs << " }" << endl;
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
vs << " vTexCoord = (uTextureTransform * vec4(aTexCoord, 0.0, 1.0)).xy;" << endl;
} else {
vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
vs << " vec2 texCoord = coordAdjusted.xy * textureRect.zw + textureRect.xy;" << endl;
vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
}
}
} else if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
vs << " vTexCoord = (uTextureTransform * vec4(aTexCoord, 0.0, 1.0)).xy;" << endl;
} else {
vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
vs << " vec2 texCoord = aCoord.xy * textureRect.zw + textureRect.xy;" << endl;
vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
}
}
if (aConfig.mFeatures & ENABLE_MASK) {
vs << " vMaskCoord.xy = (uMaskTransform * (finalPosition / finalPosition.w)).xy;" << endl;
// correct for perspective correct interpolation, see comment in D3D11 shader
vs << " vMaskCoord.z = 1.0;" << endl;
vs << " vMaskCoord *= finalPosition.w;" << endl;
}
vs << " finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
vs << " finalPosition = uMatrixProj * finalPosition;" << endl;
if (BlendOpIsMixBlendMode(blendOp)) {
// Translate from clip space (-1, 1) to (0..1), apply the backdrop
// transform, then invert the y-axis.
vs << " vBackdropCoord.x = (finalPosition.x + 1.0) / 2.0;" << endl;
vs << " vBackdropCoord.y = 1.0 - (finalPosition.y + 1.0) / 2.0;" << endl;
vs << " vBackdropCoord = (uBackdropTransform * vec4(vBackdropCoord.xy, 0.0, 1.0)).xy;" << endl;
vs << " vBackdropCoord.y = 1.0 - vBackdropCoord.y;" << endl;
}
vs << " gl_Position = finalPosition;" << endl;
vs << "}" << endl;
if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
fs << "#extension GL_ARB_texture_rectangle : require" << endl;
}
if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
fs << "#extension GL_OES_EGL_image_external : require" << endl;
}
fs << "#ifdef GL_ES" << endl;
fs << "precision mediump float;" << endl;
fs << "#define COLOR_PRECISION lowp" << endl;
fs << "#define EDGE_PRECISION mediump" << endl;
fs << "#else" << endl;
fs << "#define COLOR_PRECISION" << endl;
fs << "#define EDGE_PRECISION" << endl;
fs << "#endif" << endl;
if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
fs << "uniform COLOR_PRECISION vec4 uRenderColor;" << endl;
} else {
// for tiling, texcoord can be greater than the lowfp range
fs << "varying vec2 vTexCoord;" << endl;
if (aConfig.mFeatures & ENABLE_BLUR) {
fs << "uniform bool uBlurAlpha;" << endl;
fs << "uniform vec2 uBlurRadius;" << endl;
fs << "uniform vec2 uBlurOffset;" << endl;
fs << "uniform float uBlurGaussianKernel[" << GAUSSIAN_KERNEL_HALF_WIDTH << "];" << endl;
}
if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) {
fs << "uniform mat4 uColorMatrix;" << endl;
fs << "uniform vec4 uColorMatrixVector;" << endl;
}
if (aConfig.mFeatures & ENABLE_OPACITY) {
fs << "uniform COLOR_PRECISION float uLayerOpacity;" << endl;
}
}
if (BlendOpIsMixBlendMode(blendOp)) {
fs << "varying vec2 vBackdropCoord;" << endl;
}
const char *sampler2D = "sampler2D";
const char *texture2D = "texture2D";
if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
fs << "uniform vec2 uTexCoordMultiplier;" << endl;
if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR ||
aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
fs << "uniform vec2 uCbCrTexCoordMultiplier;" << endl;
}
sampler2D = "sampler2DRect";
texture2D = "texture2DRect";
}
if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
sampler2D = "samplerExternalOES";
}
if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
fs << "uniform sampler2D uYTexture;" << endl;
fs << "uniform sampler2D uCbTexture;" << endl;
fs << "uniform sampler2D uCrTexture;" << endl;
fs << "uniform mat3 uYuvColorMatrix;" << endl;
} else if (aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
fs << "uniform " << sampler2D << " uYTexture;" << endl;
fs << "uniform " << sampler2D << " uCbTexture;" << endl;
} else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
fs << "uniform " << sampler2D << " uBlackTexture;" << endl;
fs << "uniform " << sampler2D << " uWhiteTexture;" << endl;
fs << "uniform bool uTexturePass2;" << endl;
} else {
fs << "uniform " << sampler2D << " uTexture;" << endl;
}
if (BlendOpIsMixBlendMode(blendOp)) {
// Component alpha should be flattened away inside blend containers.
MOZ_ASSERT(!(aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA));
fs << "uniform sampler2D uBackdropTexture;" << endl;
}
if (aConfig.mFeatures & ENABLE_MASK) {
fs << "varying vec3 vMaskCoord;" << endl;
fs << "uniform sampler2D uMaskTexture;" << endl;
}
if (aConfig.mFeatures & ENABLE_DEAA) {
fs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
}
if (BlendOpIsMixBlendMode(blendOp)) {
BuildMixBlender(aConfig, fs);
}
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
fs << "vec4 sample(vec2 coord) {" << endl;
fs << " vec4 color;" << endl;
if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR ||
aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
fs << " COLOR_PRECISION float y = texture2D(uYTexture, coord * uTexCoordMultiplier).r;" << endl;
fs << " COLOR_PRECISION float cb = texture2D(uCbTexture, coord * uCbCrTexCoordMultiplier).r;" << endl;
fs << " COLOR_PRECISION float cr = texture2D(uCrTexture, coord * uCbCrTexCoordMultiplier).r;" << endl;
} else {
fs << " COLOR_PRECISION float y = texture2D(uYTexture, coord).r;" << endl;
fs << " COLOR_PRECISION float cb = texture2D(uCbTexture, coord).r;" << endl;
fs << " COLOR_PRECISION float cr = texture2D(uCrTexture, coord).r;" << endl;
}
} else {
if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
fs << " COLOR_PRECISION float y = " << texture2D << "(uYTexture, coord * uTexCoordMultiplier).r;" << endl;
fs << " COLOR_PRECISION float cb = " << texture2D << "(uCbTexture, coord * uCbCrTexCoordMultiplier).r;" << endl;
fs << " COLOR_PRECISION float cr = " << texture2D << "(uCbTexture, coord * uCbCrTexCoordMultiplier).a;" << endl;
} else {
fs << " COLOR_PRECISION float y = " << texture2D << "(uYTexture, coord).r;" << endl;
fs << " COLOR_PRECISION float cb = " << texture2D << "(uCbTexture, coord).r;" << endl;
fs << " COLOR_PRECISION float cr = " << texture2D << "(uCbTexture, coord).a;" << endl;
}
}
fs << " y = y - 0.06275;" << endl;
fs << " cb = cb - 0.50196;" << endl;
fs << " cr = cr - 0.50196;" << endl;
fs << " vec3 yuv = vec3(y, cb, cr);" << endl;
fs << " color.rgb = uYuvColorMatrix * yuv;" << endl;
fs << " color.a = 1.0;" << endl;
} else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
fs << " COLOR_PRECISION vec3 onBlack = " << texture2D << "(uBlackTexture, coord * uTexCoordMultiplier).rgb;" << endl;
fs << " COLOR_PRECISION vec3 onWhite = " << texture2D << "(uWhiteTexture, coord * uTexCoordMultiplier).rgb;" << endl;
} else {
fs << " COLOR_PRECISION vec3 onBlack = " << texture2D << "(uBlackTexture, coord).rgb;" << endl;
fs << " COLOR_PRECISION vec3 onWhite = " << texture2D << "(uWhiteTexture, coord).rgb;" << endl;
}
fs << " COLOR_PRECISION vec4 alphas = (1.0 - onWhite + onBlack).rgbg;" << endl;
fs << " if (uTexturePass2)" << endl;
fs << " color = vec4(onBlack, alphas.a);" << endl;
fs << " else" << endl;
fs << " color = alphas;" << endl;
} else {
if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
fs << " color = " << texture2D << "(uTexture, coord * uTexCoordMultiplier);" << endl;
} else {
fs << " color = " << texture2D << "(uTexture, coord);" << endl;
}
}
if (aConfig.mFeatures & ENABLE_TEXTURE_RB_SWAP) {
fs << " color = color.bgra;" << endl;
}
if (aConfig.mFeatures & ENABLE_TEXTURE_NO_ALPHA) {
fs << " color = vec4(color.rgb, 1.0);" << endl;
}
fs << " return color;" << endl;
fs << "}" << endl;
if (aConfig.mFeatures & ENABLE_BLUR) {
fs << "vec4 sampleAtRadius(vec2 coord, float radius) {" << endl;
fs << " coord += uBlurOffset;" << endl;
fs << " coord += radius * uBlurRadius;" << endl;
fs << " if (coord.x < 0. || coord.y < 0. || coord.x > 1. || coord.y > 1.)" << endl;
fs << " return vec4(0, 0, 0, 0);" << endl;
fs << " return sample(coord);" << endl;
fs << "}" << endl;
fs << "vec4 blur(vec4 color, vec2 coord) {" << endl;
fs << " vec4 total = color * uBlurGaussianKernel[0];" << endl;
fs << " for (int i = 1; i < " << GAUSSIAN_KERNEL_HALF_WIDTH << "; ++i) {" << endl;
fs << " float r = float(i) * " << GAUSSIAN_KERNEL_STEP << ";" << endl;
fs << " float k = uBlurGaussianKernel[i];" << endl;
fs << " total += sampleAtRadius(coord, r) * k;" << endl;
fs << " total += sampleAtRadius(coord, -r) * k;" << endl;
fs << " }" << endl;
fs << " if (uBlurAlpha) {" << endl;
fs << " color *= total.a;" << endl;
fs << " } else {" << endl;
fs << " color = total;" << endl;
fs << " }" << endl;
fs << " return color;" << endl;
fs << "}" << endl;
}
}
fs << "void main() {" << endl;
if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
fs << " vec4 color = uRenderColor;" << endl;
} else {
fs << " vec4 color = sample(vTexCoord);" << endl;
if (aConfig.mFeatures & ENABLE_BLUR) {
fs << " color = blur(color, vTexCoord);" << endl;
}
if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) {
fs << " color = uColorMatrix * vec4(color.rgb / color.a, color.a) + uColorMatrixVector;" << endl;
fs << " color.rgb *= color.a;" << endl;
}
if (aConfig.mFeatures & ENABLE_OPACITY) {
fs << " color *= uLayerOpacity;" << endl;
}
}
if (aConfig.mFeatures & ENABLE_DEAA) {
// Calculate the sub-pixel coverage of the pixel and modulate its opacity
// by that amount to perform DEAA.
fs << " vec3 ssPos = vec3(gl_FragCoord.xy, 1.0);" << endl;
fs << " float deaaCoverage = clamp(dot(uSSEdges[0], ssPos), 0.0, 1.0);" << endl;
fs << " deaaCoverage *= clamp(dot(uSSEdges[1], ssPos), 0.0, 1.0);" << endl;
fs << " deaaCoverage *= clamp(dot(uSSEdges[2], ssPos), 0.0, 1.0);" << endl;
fs << " deaaCoverage *= clamp(dot(uSSEdges[3], ssPos), 0.0, 1.0);" << endl;
fs << " color *= deaaCoverage;" << endl;
}
if (BlendOpIsMixBlendMode(blendOp)) {
fs << " vec4 backdrop = texture2D(uBackdropTexture, vBackdropCoord);" << endl;
fs << " color = mixAndBlend(backdrop, color);" << endl;
}
if (aConfig.mFeatures & ENABLE_MASK) {
fs << " vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl;
fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, maskCoords).r;" << endl;
fs << " color *= mask;" << endl;
} else {
fs << " COLOR_PRECISION float mask = 1.0;" << endl;
fs << " color *= mask;" << endl;
}
fs << " gl_FragColor = color;" << endl;
fs << "}" << endl;
result.mVertexShaderString = vs.str();
result.mFragmentShaderString = fs.str();
if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
result.mTextureCount = 0;
} else {
if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
result.mTextureCount = 3;
} else if (aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
result.mTextureCount = 2;
} else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
result.mTextureCount = 2;
} else {
result.mTextureCount = 1;
}
}
if (aConfig.mFeatures & ENABLE_MASK) {
result.mTextureCount = 1;
}
if (BlendOpIsMixBlendMode(blendOp)) {
result.mTextureCount += 1;
}
return result;
}
void
ProgramProfileOGL::BuildMixBlender(const ShaderConfigOGL& aConfig, std::ostringstream& fs)
{
// From the "Compositing and Blending Level 1" spec.
// Generate helper functions first.
switch (aConfig.mCompositionOp) {
case gfx::CompositionOp::OP_OVERLAY:
case gfx::CompositionOp::OP_HARD_LIGHT:
// Note: we substitute (2*src-1) into the screen formula below.
fs << "float hardlight(float dest, float src) {" << endl;
fs << " if (src <= 0.5) {" << endl;
fs << " return dest * (2.0 * src);" << endl;
fs << " } else {" << endl;
fs << " return 2.0*dest + 2.0*src - 1.0 - 2.0*dest*src;" << endl;
fs << " }" << endl;
fs << "}" << endl;
break;
case gfx::CompositionOp::OP_COLOR_DODGE:
fs << "float dodge(float dest, float src) {" << endl;
fs << " if (dest == 0.0) {" << endl;
fs << " return 0.0;" << endl;
fs << " } else if (src == 1.0) {" << endl;
fs << " return 1.0;" << endl;
fs << " } else {" << endl;
fs << " return min(1.0, dest / (1.0 - src));" << endl;
fs << " }" << endl;
fs << "}" << endl;
break;
case gfx::CompositionOp::OP_COLOR_BURN:
fs << "float burn(float dest, float src) {" << endl;
fs << " if (dest == 1.0) {" << endl;
fs << " return 1.0;" << endl;
fs << " } else if (src == 0.0) {" << endl;
fs << " return 0.0;" << endl;
fs << " } else {" << endl;
fs << " return 1.0 - min(1.0, (1.0 - dest) / src);" << endl;
fs << " }" << endl;
fs << "}" << endl;
break;
case gfx::CompositionOp::OP_SOFT_LIGHT:
fs << "float darken(float dest) {" << endl;
fs << " if (dest <= 0.25) {" << endl;
fs << " return ((16.0 * dest - 12.0) * dest + 4.0) * dest;" << endl;
fs << " } else {" << endl;
fs << " return sqrt(dest);" << endl;
fs << " }" << endl;
fs << "}" << endl;
fs << "float softlight(float dest, float src) {" << endl;
fs << " if (src <= 0.5) {" << endl;
fs << " return dest - (1.0 - 2.0 * src) * dest * (1.0 - dest);" << endl;
fs << " } else {" << endl;
fs << " return dest + (2.0 * src - 1.0) * (darken(dest) - dest);" << endl;
fs << " }" << endl;
fs << "}" << endl;
break;
case gfx::CompositionOp::OP_HUE:
case gfx::CompositionOp::OP_SATURATION:
case gfx::CompositionOp::OP_COLOR:
case gfx::CompositionOp::OP_LUMINOSITY:
fs << "float Lum(vec3 c) {" << endl;
fs << " return dot(vec3(0.3, 0.59, 0.11), c);" << endl;
fs << "}" << endl;
fs << "vec3 ClipColor(vec3 c) {" << endl;
fs << " float L = Lum(c);" << endl;
fs << " float n = min(min(c.r, c.g), c.b);" << endl;
fs << " float x = max(max(c.r, c.g), c.b);" << endl;
fs << " if (n < 0.0) {" << endl;
fs << " c = L + (((c - L) * L) / (L - n));" << endl;
fs << " }" << endl;
fs << " if (x > 1.0) {" << endl;
fs << " c = L + (((c - L) * (1.0 - L)) / (x - L));" << endl;
fs << " }" << endl;
fs << " return c;" << endl;
fs << "}" << endl;
fs << "vec3 SetLum(vec3 c, float L) {" << endl;
fs << " float d = L - Lum(c);" << endl;
fs << " return ClipColor(vec3(" << endl;
fs << " c.r + d," << endl;
fs << " c.g + d," << endl;
fs << " c.b + d));" << endl;
fs << "}" << endl;
fs << "float Sat(vec3 c) {" << endl;
fs << " return max(max(c.r, c.g), c.b) - min(min(c.r, c.g), c.b);" << endl;
fs << "}" << endl;
// To use this helper, re-arrange rgb such that r=min, g=mid, and b=max.
fs << "vec3 SetSatInner(vec3 c, float s) {" << endl;
fs << " if (c.b > c.r) {" << endl;
fs << " c.g = (((c.g - c.r) * s) / (c.b - c.r));" << endl;
fs << " c.b = s;" << endl;
fs << " } else {" << endl;
fs << " c.gb = vec2(0.0, 0.0);" << endl;
fs << " }" << endl;
fs << " return vec3(0.0, c.gb);" << endl;
fs << "}" << endl;
fs << "vec3 SetSat(vec3 c, float s) {" << endl;
fs << " if (c.r <= c.g) {" << endl;
fs << " if (c.g <= c.b) {" << endl;
fs << " c.rgb = SetSatInner(c.rgb, s);" << endl;
fs << " } else if (c.r <= c.b) {" << endl;
fs << " c.rbg = SetSatInner(c.rbg, s);" << endl;
fs << " } else {" << endl;
fs << " c.brg = SetSatInner(c.brg, s);" << endl;
fs << " }" << endl;
fs << " } else if (c.r <= c.b) {" << endl;
fs << " c.grb = SetSatInner(c.grb, s);" << endl;
fs << " } else if (c.g <= c.b) {" << endl;
fs << " c.gbr = SetSatInner(c.gbr, s);" << endl;
fs << " } else {" << endl;
fs << " c.bgr = SetSatInner(c.bgr, s);" << endl;
fs << " }" << endl;
fs << " return c;" << endl;
fs << "}" << endl;
break;
default:
break;
}
// Generate the main blending helper.
fs << "vec3 blend(vec3 dest, vec3 src) {" << endl;
switch (aConfig.mCompositionOp) {
case gfx::CompositionOp::OP_MULTIPLY:
fs << " return dest * src;" << endl;
break;
case gfx::CompositionOp::OP_SCREEN:
fs << " return dest + src - (dest * src);" << endl;
break;
case gfx::CompositionOp::OP_OVERLAY:
fs << " return vec3(" << endl;
fs << " hardlight(src.r, dest.r)," << endl;
fs << " hardlight(src.g, dest.g)," << endl;
fs << " hardlight(src.b, dest.b));" << endl;
break;
case gfx::CompositionOp::OP_DARKEN:
fs << " return min(dest, src);" << endl;
break;
case gfx::CompositionOp::OP_LIGHTEN:
fs << " return max(dest, src);" << endl;
break;
case gfx::CompositionOp::OP_COLOR_DODGE:
fs << " return vec3(" << endl;
fs << " dodge(dest.r, src.r)," << endl;
fs << " dodge(dest.g, src.g)," << endl;
fs << " dodge(dest.b, src.b));" << endl;
break;
case gfx::CompositionOp::OP_COLOR_BURN:
fs << " return vec3(" << endl;
fs << " burn(dest.r, src.r)," << endl;
fs << " burn(dest.g, src.g)," << endl;
fs << " burn(dest.b, src.b));" << endl;
break;
case gfx::CompositionOp::OP_HARD_LIGHT:
fs << " return vec3(" << endl;
fs << " hardlight(dest.r, src.r)," << endl;
fs << " hardlight(dest.g, src.g)," << endl;
fs << " hardlight(dest.b, src.b));" << endl;
break;
case gfx::CompositionOp::OP_SOFT_LIGHT:
fs << " return vec3(" << endl;
fs << " softlight(dest.r, src.r)," << endl;
fs << " softlight(dest.g, src.g)," << endl;
fs << " softlight(dest.b, src.b));" << endl;
break;
case gfx::CompositionOp::OP_DIFFERENCE:
fs << " return abs(dest - src);" << endl;
break;
case gfx::CompositionOp::OP_EXCLUSION:
fs << " return dest + src - 2.0*dest*src;" << endl;
break;
case gfx::CompositionOp::OP_HUE:
fs << " return SetLum(SetSat(src, Sat(dest)), Lum(dest));" << endl;
break;
case gfx::CompositionOp::OP_SATURATION:
fs << " return SetLum(SetSat(dest, Sat(src)), Lum(dest));" << endl;
break;
case gfx::CompositionOp::OP_COLOR:
fs << " return SetLum(src, Lum(dest));" << endl;
break;
case gfx::CompositionOp::OP_LUMINOSITY:
fs << " return SetLum(dest, Lum(src));" << endl;
break;
default:
MOZ_ASSERT_UNREACHABLE("unknown blend mode");
}
fs << "}" << endl;
// Generate the mix-blend function the fragment shader will call.
fs << "vec4 mixAndBlend(vec4 backdrop, vec4 color) {" << endl;
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
// Infinity into the blend function and return incorrect results.
fs << " if (backdrop.a == 0.0) {" << endl;
fs << " return color;" << endl;
fs << " }" << endl;
fs << " if (color.a == 0.0) {" << endl;
fs << " return vec4(0.0, 0.0, 0.0, 0.0);" << endl;
fs << " }" << endl;
// The spec assumes there is no premultiplied alpha. The backdrop is always
// premultiplied, so undo the premultiply. If the source is premultiplied we
// must fix that as well.
fs << " backdrop.rgb /= backdrop.a;" << endl;
if (!(aConfig.mFeatures & ENABLE_NO_PREMUL_ALPHA)) {
fs << " color.rgb /= color.a;" << endl;
}
fs << " vec3 blended = blend(backdrop.rgb, color.rgb);" << endl;
fs << " color.rgb = (1.0 - backdrop.a) * color.rgb + backdrop.a * blended.rgb;" << endl;
fs << " color.rgb *= color.a;" << endl;
fs << " return color;" << endl;
fs << "}" << endl;
}
ShaderProgramOGL::ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile)
: mGL(aGL)
, mProgram(0)
, mProfile(aProfile)
, mProgramState(STATE_NEW)
{
}
ShaderProgramOGL::~ShaderProgramOGL()
{
if (mProgram <= 0) {
return;
}
RefPtr<GLContext> ctx = mGL->GetSharedContext();
if (!ctx) {
ctx = mGL;
}
ctx->MakeCurrent();
ctx->fDeleteProgram(mProgram);
}
bool
ShaderProgramOGL::Initialize()
{
NS_ASSERTION(mProgramState == STATE_NEW, "Shader program has already been initialised");
ostringstream vs, fs;
for (uint32_t i = 0; i < mProfile.mDefines.Length(); ++i) {
vs << mProfile.mDefines[i] << endl;
fs << mProfile.mDefines[i] << endl;
}
vs << mProfile.mVertexShaderString << endl;
fs << mProfile.mFragmentShaderString << endl;
if (!CreateProgram(vs.str().c_str(), fs.str().c_str())) {
mProgramState = STATE_ERROR;
return false;
}
mProgramState = STATE_OK;
for (uint32_t i = 0; i < KnownUniform::KnownUniformCount; ++i) {
mProfile.mUniforms[i].mLocation =
mGL->fGetUniformLocation(mProgram, mProfile.mUniforms[i].mNameString);
}
return true;
}
GLint
ShaderProgramOGL::CreateShader(GLenum aShaderType, const char *aShaderSource)
{
GLint success, len = 0;
GLint sh = mGL->fCreateShader(aShaderType);
mGL->fShaderSource(sh, 1, (const GLchar**)&aShaderSource, nullptr);
mGL->fCompileShader(sh);
mGL->fGetShaderiv(sh, LOCAL_GL_COMPILE_STATUS, &success);
mGL->fGetShaderiv(sh, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
/* Even if compiling is successful, there may still be warnings. Print them
* in a debug build. The > 10 is to catch silly compilers that might put
* some whitespace in the log but otherwise leave it empty.
*/
if (!success
#ifdef DEBUG
|| (len > 10 && gfxEnv::DebugShaders())
#endif
)
{
nsAutoCString log;
log.SetCapacity(len);
mGL->fGetShaderInfoLog(sh, len, (GLint*) &len, (char*) log.BeginWriting());
log.SetLength(len);
if (!success) {
printf_stderr("=== SHADER COMPILATION FAILED ===\n");
} else {
printf_stderr("=== SHADER COMPILATION WARNINGS ===\n");
}
printf_stderr("=== Source:\n%s\n", aShaderSource);
printf_stderr("=== Log:\n%s\n", log.get());
printf_stderr("============\n");
if (!success) {
mGL->fDeleteShader(sh);
return 0;
}
}
return sh;
}
bool
ShaderProgramOGL::CreateProgram(const char *aVertexShaderString,
const char *aFragmentShaderString)
{
GLuint vertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString);
GLuint fragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString);
if (!vertexShader || !fragmentShader)
return false;
GLint result = mGL->fCreateProgram();
mGL->fAttachShader(result, vertexShader);
mGL->fAttachShader(result, fragmentShader);
for (Pair<nsCString, GLuint>& attribute : mProfile.mAttributes) {
mGL->fBindAttribLocation(result, attribute.second(),
attribute.first().get());
}
mGL->fLinkProgram(result);
GLint success, len;
mGL->fGetProgramiv(result, LOCAL_GL_LINK_STATUS, &success);
mGL->fGetProgramiv(result, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
/* Even if linking is successful, there may still be warnings. Print them
* in a debug build. The > 10 is to catch silly compilers that might put
* some whitespace in the log but otherwise leave it empty.
*/
if (!success
#ifdef DEBUG
|| (len > 10 && gfxEnv::DebugShaders())
#endif
)
{
nsAutoCString log;
log.SetCapacity(len);
mGL->fGetProgramInfoLog(result, len, (GLint*) &len, (char*) log.BeginWriting());
log.SetLength(len);
if (!success) {
printf_stderr("=== PROGRAM LINKING FAILED ===\n");
} else {
printf_stderr("=== PROGRAM LINKING WARNINGS ===\n");
}
printf_stderr("=== Log:\n%s\n", log.get());
printf_stderr("============\n");
}
// We can mark the shaders for deletion; they're attached to the program
// and will remain attached.
mGL->fDeleteShader(vertexShader);
mGL->fDeleteShader(fragmentShader);
if (!success) {
mGL->fDeleteProgram(result);
return false;
}
mProgram = result;
return true;
}
GLuint
ShaderProgramOGL::GetProgram()
{
if (mProgramState == STATE_NEW) {
if (!Initialize()) {
NS_WARNING("Shader could not be initialised");
}
}
MOZ_ASSERT(HasInitialized(), "Attempting to get a program that's not been initialized!");
return mProgram;
}
void
ShaderProgramOGL::SetBlurRadius(float aRX, float aRY)
{
float f[] = {aRX, aRY};
SetUniform(KnownUniform::BlurRadius, 2, f);
float gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH];
float sum = 0.0f;
for (int i = 0; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) {
float x = i * GAUSSIAN_KERNEL_STEP;
float sigma = 1.0f;
gaussianKernel[i] = exp(-x * x / (2 * sigma * sigma)) / sqrt(2 * M_PI * sigma * sigma);
sum += gaussianKernel[i] * (i == 0 ? 1 : 2);
}
for (int i = 0; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) {
gaussianKernel[i] /= sum;
}
SetArrayUniform(KnownUniform::BlurGaussianKernel, GAUSSIAN_KERNEL_HALF_WIDTH, gaussianKernel);
}
void
ShaderProgramOGL::SetYUVColorSpace(YUVColorSpace aYUVColorSpace)
{
float* yuvToRgb = gfxUtils::Get3x3YuvColorMatrix(aYUVColorSpace);
SetMatrix3fvUniform(KnownUniform::YuvColorMatrix, yuvToRgb);
}
} // namespace layers
} // namespace mozilla

View file

@ -0,0 +1,621 @@
/* -*- 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 GFX_OGLSHADERPROGRAM_H
#define GFX_OGLSHADERPROGRAM_H
#include "GLContext.h" // for fast inlines of glUniform*
#include "gfxTypes.h"
#include "ImageTypes.h"
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/Pair.h" // for Pair
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/gfx/Types.h"
#include "nsDebug.h" // for NS_ASSERTION
#include "nsPoint.h" // for nsIntPoint
#include "nsTArray.h" // for nsTArray
#include "mozilla/layers/CompositorTypes.h"
#include <string>
namespace mozilla {
namespace layers {
class Layer;
enum ShaderFeatures {
ENABLE_RENDER_COLOR=0x01,
ENABLE_TEXTURE_RECT=0x02,
ENABLE_TEXTURE_EXTERNAL=0x04,
ENABLE_TEXTURE_YCBCR=0x08,
ENABLE_TEXTURE_NV12=0x10,
ENABLE_TEXTURE_COMPONENT_ALPHA=0x20,
ENABLE_TEXTURE_NO_ALPHA=0x40,
ENABLE_TEXTURE_RB_SWAP=0x80,
ENABLE_OPACITY=0x100,
ENABLE_BLUR=0x200,
ENABLE_COLOR_MATRIX=0x400,
ENABLE_MASK=0x800,
ENABLE_NO_PREMUL_ALPHA=0x1000,
ENABLE_DEAA=0x2000,
ENABLE_DYNAMIC_GEOMETRY=0x4000
};
class KnownUniform {
public:
// this needs to be kept in sync with strings in 'AddUniforms'
enum KnownUniformName {
NotAKnownUniform = -1,
LayerTransform = 0,
LayerTransformInverse,
MaskTransform,
BackdropTransform,
LayerRects,
MatrixProj,
TextureTransform,
TextureRects,
RenderTargetOffset,
LayerOpacity,
Texture,
YTexture,
CbTexture,
CrTexture,
BlackTexture,
WhiteTexture,
MaskTexture,
BackdropTexture,
RenderColor,
TexCoordMultiplier,
CbCrTexCoordMultiplier,
TexturePass2,
ColorMatrix,
ColorMatrixVector,
BlurRadius,
BlurOffset,
BlurAlpha,
BlurGaussianKernel,
SSEdges,
ViewportSize,
VisibleCenter,
YuvColorMatrix,
KnownUniformCount
};
KnownUniform()
{
mName = NotAKnownUniform;
mNameString = nullptr;
mLocation = -1;
memset(&mValue, 0, sizeof(mValue));
}
bool UpdateUniform(int32_t i1) {
if (mLocation == -1) return false;
if (mValue.i1 != i1) {
mValue.i1 = i1;
return true;
}
return false;
}
bool UpdateUniform(float f1) {
if (mLocation == -1) return false;
if (mValue.f1 != f1) {
mValue.f1 = f1;
return true;
}
return false;
}
bool UpdateUniform(float f1, float f2) {
if (mLocation == -1) return false;
if (mValue.f16v[0] != f1 ||
mValue.f16v[1] != f2)
{
mValue.f16v[0] = f1;
mValue.f16v[1] = f2;
return true;
}
return false;
}
bool UpdateUniform(float f1, float f2, float f3, float f4) {
if (mLocation == -1) return false;
if (mValue.f16v[0] != f1 ||
mValue.f16v[1] != f2 ||
mValue.f16v[2] != f3 ||
mValue.f16v[3] != f4)
{
mValue.f16v[0] = f1;
mValue.f16v[1] = f2;
mValue.f16v[2] = f3;
mValue.f16v[3] = f4;
return true;
}
return false;
}
bool UpdateUniform(int cnt, const float *fp) {
if (mLocation == -1) return false;
switch (cnt) {
case 1:
case 2:
case 3:
case 4:
case 9:
case 16:
if (memcmp(mValue.f16v, fp, sizeof(float) * cnt) != 0) {
memcpy(mValue.f16v, fp, sizeof(float) * cnt);
return true;
}
return false;
}
NS_NOTREACHED("cnt must be 1 2 3 4 9 or 16");
return false;
}
bool UpdateArrayUniform(int cnt, const float *fp) {
if (mLocation == -1) return false;
if (cnt > 16) {
return false;
}
if (memcmp(mValue.f16v, fp, sizeof(float) * cnt) != 0) {
memcpy(mValue.f16v, fp, sizeof(float) * cnt);
return true;
}
return false;
}
bool UpdateArrayUniform(int cnt, const gfx::Point3D* points) {
if (mLocation == -1) return false;
if (cnt > 4) {
return false;
}
float fp[12];
float *d = fp;
for(int i=0; i < cnt; i++) {
// Note: Do not want to make assumptions about .x, .y, .z member packing.
// If gfx::Point3D is updated to make this guarantee, SIMD optimizations
// may be possible
*d++ = points[i].x;
*d++ = points[i].y;
*d++ = points[i].z;
}
if (memcmp(mValue.f16v, fp, sizeof(float) * cnt * 3) != 0) {
memcpy(mValue.f16v, fp, sizeof(float) * cnt * 3);
return true;
}
return false;
}
KnownUniformName mName;
const char *mNameString;
int32_t mLocation;
union {
int i1;
float f1;
float f16v[16];
} mValue;
};
class ShaderConfigOGL
{
public:
ShaderConfigOGL() :
mFeatures(0),
mCompositionOp(gfx::CompositionOp::OP_OVER)
{}
void SetRenderColor(bool aEnabled);
void SetTextureTarget(GLenum aTarget);
void SetRBSwap(bool aEnabled);
void SetNoAlpha(bool aEnabled);
void SetOpacity(bool aEnabled);
void SetYCbCr(bool aEnabled);
void SetNV12(bool aEnabled);
void SetComponentAlpha(bool aEnabled);
void SetColorMatrix(bool aEnabled);
void SetBlur(bool aEnabled);
void SetMask(bool aEnabled);
void SetDEAA(bool aEnabled);
void SetCompositionOp(gfx::CompositionOp aOp);
void SetNoPremultipliedAlpha();
void SetDynamicGeometry(bool aEnabled);
bool operator< (const ShaderConfigOGL& other) const {
return mFeatures < other.mFeatures ||
(mFeatures == other.mFeatures &&
(int)mCompositionOp < (int)other.mCompositionOp);
}
public:
void SetFeature(int aBitmask, bool aState) {
if (aState)
mFeatures |= aBitmask;
else
mFeatures &= (~aBitmask);
}
int mFeatures;
gfx::CompositionOp mCompositionOp;
};
static inline ShaderConfigOGL
ShaderConfigFromTargetAndFormat(GLenum aTarget,
gfx::SurfaceFormat aFormat)
{
ShaderConfigOGL config;
config.SetTextureTarget(aTarget);
config.SetRBSwap(aFormat == gfx::SurfaceFormat::B8G8R8A8 ||
aFormat == gfx::SurfaceFormat::B8G8R8X8);
config.SetNoAlpha(aFormat == gfx::SurfaceFormat::B8G8R8X8 ||
aFormat == gfx::SurfaceFormat::R8G8B8X8 ||
aFormat == gfx::SurfaceFormat::R5G6B5_UINT16);
return config;
}
/**
* This struct represents the shaders that make up a program and the uniform
* and attribute parmeters that those shaders take.
* It is used by ShaderProgramOGL.
* Use the factory method GetProfileFor to create instances.
*/
struct ProgramProfileOGL
{
/**
* Factory method; creates an instance of this class for the given
* ShaderConfigOGL
*/
static ProgramProfileOGL GetProfileFor(ShaderConfigOGL aConfig);
// the source code for the program's shaders
std::string mVertexShaderString;
std::string mFragmentShaderString;
// the vertex attributes
nsTArray<Pair<nsCString, GLuint>> mAttributes;
KnownUniform mUniforms[KnownUniform::KnownUniformCount];
nsTArray<const char *> mDefines;
size_t mTextureCount;
ProgramProfileOGL() :
mTextureCount(0)
{}
private:
static void BuildMixBlender(const ShaderConfigOGL& aConfig, std::ostringstream& fs);
};
#if defined(DEBUG)
#define CHECK_CURRENT_PROGRAM 1
#define ASSERT_THIS_PROGRAM \
do { \
GLuint currentProgram; \
mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram); \
MOZ_ASSERT(currentProgram == mProgram, \
"SetUniform with wrong program active!"); \
} while (0)
#else
#define ASSERT_THIS_PROGRAM \
do { } while (0)
#endif
/**
* Represents an OGL shader program. The details of a program are represented
* by a ProgramProfileOGL
*/
class ShaderProgramOGL
{
public:
typedef mozilla::gl::GLContext GLContext;
ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile);
~ShaderProgramOGL();
bool HasInitialized() {
NS_ASSERTION(mProgramState != STATE_OK || mProgram > 0, "Inconsistent program state");
return mProgramState == STATE_OK;
}
GLuint GetProgram();
bool Initialize();
GLint CreateShader(GLenum aShaderType, const char *aShaderSource);
/**
* Creates a program and stores its id.
*/
bool CreateProgram(const char *aVertexShaderString,
const char *aFragmentShaderString);
/**
* The following set of methods set a uniform argument to the shader program.
* Not all uniforms may be set for all programs, and such uses will throw
* an assertion.
*/
void SetLayerTransform(const gfx::Matrix4x4& aMatrix) {
SetMatrixUniform(KnownUniform::LayerTransform, aMatrix);
}
void SetLayerTransformInverse(const gfx::Matrix4x4& aMatrix) {
SetMatrixUniform(KnownUniform::LayerTransformInverse, aMatrix);
}
void SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) {
SetMatrixUniform(KnownUniform::MaskTransform, aMatrix);
}
void SetBackdropTransform(const gfx::Matrix4x4& aMatrix) {
SetMatrixUniform(KnownUniform::BackdropTransform, aMatrix);
}
void SetDEAAEdges(const gfx::Point3D* aEdges) {
SetArrayUniform(KnownUniform::SSEdges, 4, aEdges);
}
void SetViewportSize(const gfx::IntSize& aSize) {
float vals[2] = { (float)aSize.width, (float)aSize.height };
SetUniform(KnownUniform::ViewportSize, 2, vals);
}
void SetVisibleCenter(const gfx::Point& aVisibleCenter) {
float vals[2] = { aVisibleCenter.x, aVisibleCenter.y };
SetUniform(KnownUniform::VisibleCenter, 2, vals);
}
void SetLayerRects(const gfx::Rect* aRects) {
float vals[16] = { aRects[0].x, aRects[0].y, aRects[0].width, aRects[0].height,
aRects[1].x, aRects[1].y, aRects[1].width, aRects[1].height,
aRects[2].x, aRects[2].y, aRects[2].width, aRects[2].height,
aRects[3].x, aRects[3].y, aRects[3].width, aRects[3].height };
SetUniform(KnownUniform::LayerRects, 16, vals);
}
void SetProjectionMatrix(const gfx::Matrix4x4& aMatrix) {
SetMatrixUniform(KnownUniform::MatrixProj, aMatrix);
}
// sets this program's texture transform, if it uses one
void SetTextureTransform(const gfx::Matrix4x4& aMatrix) {
SetMatrixUniform(KnownUniform::TextureTransform, aMatrix);
}
void SetTextureRects(const gfx::Rect* aRects) {
float vals[16] = { aRects[0].x, aRects[0].y, aRects[0].width, aRects[0].height,
aRects[1].x, aRects[1].y, aRects[1].width, aRects[1].height,
aRects[2].x, aRects[2].y, aRects[2].width, aRects[2].height,
aRects[3].x, aRects[3].y, aRects[3].width, aRects[3].height };
SetUniform(KnownUniform::TextureRects, 16, vals);
}
void SetRenderOffset(const nsIntPoint& aOffset) {
float vals[4] = { float(aOffset.x), float(aOffset.y) };
SetUniform(KnownUniform::RenderTargetOffset, 2, vals);
}
void SetRenderOffset(float aX, float aY) {
float vals[2] = { aX, aY };
SetUniform(KnownUniform::RenderTargetOffset, 2, vals);
}
void SetLayerOpacity(float aOpacity) {
SetUniform(KnownUniform::LayerOpacity, aOpacity);
}
void SetTextureUnit(GLint aUnit) {
SetUniform(KnownUniform::Texture, aUnit);
}
void SetYTextureUnit(GLint aUnit) {
SetUniform(KnownUniform::YTexture, aUnit);
}
void SetCbTextureUnit(GLint aUnit) {
SetUniform(KnownUniform::CbTexture, aUnit);
}
void SetCrTextureUnit(GLint aUnit) {
SetUniform(KnownUniform::CrTexture, aUnit);
}
void SetYCbCrTextureUnits(GLint aYUnit, GLint aCbUnit, GLint aCrUnit) {
SetUniform(KnownUniform::YTexture, aYUnit);
SetUniform(KnownUniform::CbTexture, aCbUnit);
SetUniform(KnownUniform::CrTexture, aCrUnit);
}
void SetNV12TextureUnits(GLint aYUnit, GLint aCbCrUnit) {
SetUniform(KnownUniform::YTexture, aYUnit);
SetUniform(KnownUniform::CbTexture, aCbCrUnit);
}
void SetBlackTextureUnit(GLint aUnit) {
SetUniform(KnownUniform::BlackTexture, aUnit);
}
void SetWhiteTextureUnit(GLint aUnit) {
SetUniform(KnownUniform::WhiteTexture, aUnit);
}
void SetMaskTextureUnit(GLint aUnit) {
SetUniform(KnownUniform::MaskTexture, aUnit);
}
void SetBackdropTextureUnit(GLint aUnit) {
SetUniform(KnownUniform::BackdropTexture, aUnit);
}
void SetRenderColor(const gfx::Color& aColor) {
SetUniform(KnownUniform::RenderColor, aColor);
}
void SetColorMatrix(const gfx::Matrix5x4& aColorMatrix)
{
SetMatrixUniform(KnownUniform::ColorMatrix, &aColorMatrix._11);
SetUniform(KnownUniform::ColorMatrixVector, 4, &aColorMatrix._51);
}
void SetTexCoordMultiplier(float aWidth, float aHeight) {
float f[] = {aWidth, aHeight};
SetUniform(KnownUniform::TexCoordMultiplier, 2, f);
}
void SetCbCrTexCoordMultiplier(float aWidth, float aHeight) {
float f[] = {aWidth, aHeight};
SetUniform(KnownUniform::CbCrTexCoordMultiplier, 2, f);
}
void SetYUVColorSpace(YUVColorSpace aYUVColorSpace);
// Set whether we want the component alpha shader to return the color
// vector (pass 1, false) or the alpha vector (pass2, true). With support
// for multiple render targets we wouldn't need two passes here.
void SetTexturePass2(bool aFlag) {
SetUniform(KnownUniform::TexturePass2, aFlag ? 1 : 0);
}
void SetBlurRadius(float aRX, float aRY);
void SetBlurAlpha(float aAlpha) {
SetUniform(KnownUniform::BlurAlpha, aAlpha);
}
void SetBlurOffset(float aOffsetX, float aOffsetY) {
float f[] = {aOffsetX, aOffsetY};
SetUniform(KnownUniform::BlurOffset, 2, f);
}
size_t GetTextureCount() const {
return mProfile.mTextureCount;
}
protected:
RefPtr<GLContext> mGL;
// the OpenGL id of the program
GLuint mProgram;
ProgramProfileOGL mProfile;
enum {
STATE_NEW,
STATE_OK,
STATE_ERROR
} mProgramState;
#ifdef CHECK_CURRENT_PROGRAM
static int sCurrentProgramKey;
#endif
void SetUniform(KnownUniform::KnownUniformName aKnownUniform, float aFloatValue)
{
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
if (ku.UpdateUniform(aFloatValue)) {
mGL->fUniform1f(ku.mLocation, aFloatValue);
}
}
void SetUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Color& aColor) {
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
if (ku.UpdateUniform(aColor.r, aColor.g, aColor.b, aColor.a)) {
mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v);
}
}
void SetUniform(KnownUniform::KnownUniformName aKnownUniform, int aLength, const float *aFloatValues)
{
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
if (ku.UpdateUniform(aLength, aFloatValues)) {
switch (aLength) {
case 1: mGL->fUniform1fv(ku.mLocation, 1, ku.mValue.f16v); break;
case 2: mGL->fUniform2fv(ku.mLocation, 1, ku.mValue.f16v); break;
case 3: mGL->fUniform3fv(ku.mLocation, 1, ku.mValue.f16v); break;
case 4: mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); break;
case 16: mGL->fUniform4fv(ku.mLocation, 4, ku.mValue.f16v); break;
default:
NS_NOTREACHED("Bogus aLength param");
}
}
}
void SetArrayUniform(KnownUniform::KnownUniformName aKnownUniform, int aLength, float *aFloatValues)
{
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
if (ku.UpdateArrayUniform(aLength, aFloatValues)) {
mGL->fUniform1fv(ku.mLocation, aLength, ku.mValue.f16v);
}
}
void SetArrayUniform(KnownUniform::KnownUniformName aKnownUniform, int aLength, const gfx::Point3D *aPointValues)
{
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
if (ku.UpdateArrayUniform(aLength, aPointValues)) {
mGL->fUniform3fv(ku.mLocation, aLength, ku.mValue.f16v);
}
}
void SetUniform(KnownUniform::KnownUniformName aKnownUniform, GLint aIntValue) {
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
if (ku.UpdateUniform(aIntValue)) {
mGL->fUniform1i(ku.mLocation, aIntValue);
}
}
void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const float *aFloatValues) {
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
if (ku.UpdateUniform(16, aFloatValues)) {
mGL->fUniformMatrix4fv(ku.mLocation, 1, false, ku.mValue.f16v);
}
}
void SetMatrix3fvUniform(KnownUniform::KnownUniformName aKnownUniform, const float *aFloatValues) {
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
if (ku.UpdateUniform(9, aFloatValues)) {
mGL->fUniformMatrix3fv(ku.mLocation, 1, false, ku.mValue.f16v);
}
}
void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Matrix4x4& aMatrix) {
SetMatrixUniform(aKnownUniform, &aMatrix._11);
}
};
} // namespace layers
} // namespace mozilla
#endif /* GFX_OGLSHADERPROGRAM_H */

View file

@ -0,0 +1,136 @@
/* -*- 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/. */
#include "GLContext.h" // for GLContext, etc
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/layers/TextureClientOGL.h"
#include "mozilla/gfx/Point.h" // for IntSize
#include "GLLibraryEGL.h"
using namespace mozilla::gl;
namespace mozilla {
namespace layers {
class CompositableForwarder;
////////////////////////////////////////////////////////////////////////
// EGLImage
EGLImageTextureData::EGLImageTextureData(EGLImageImage* aImage, gfx::IntSize aSize)
: mImage(aImage)
, mSize(aSize)
{
MOZ_ASSERT(aImage);
}
already_AddRefed<TextureClient>
EGLImageTextureData::CreateTextureClient(EGLImageImage* aImage, gfx::IntSize aSize,
LayersIPCChannel* aAllocator, TextureFlags aFlags)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Can't pass an `EGLImage` between processes.");
if (!aImage || !XRE_IsParentProcess()) {
return nullptr;
}
// XXX - This is quite sad and slow.
aFlags |= TextureFlags::DEALLOCATE_CLIENT;
if (aImage->GetOriginPos() == gl::OriginPos::BottomLeft) {
aFlags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
}
return TextureClient::CreateWithData(
new EGLImageTextureData(aImage, aSize),
aFlags, aAllocator
);
}
void
EGLImageTextureData::FillInfo(TextureData::Info& aInfo) const
{
aInfo.size = mSize;
aInfo.format = gfx::SurfaceFormat::UNKNOWN;
aInfo.hasIntermediateBuffer = false;
aInfo.hasSynchronization = false;
aInfo.supportsMoz2D = false;
aInfo.canExposeMappedData = false;
}
bool
EGLImageTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
{
const bool hasAlpha = true;
aOutDescriptor =
EGLImageDescriptor((uintptr_t)mImage->GetImage(),
(uintptr_t)mImage->GetSync(),
mImage->GetSize(), hasAlpha);
return true;
}
////////////////////////////////////////////////////////////////////////
// AndroidSurface
#ifdef MOZ_WIDGET_ANDROID
already_AddRefed<TextureClient>
AndroidSurfaceTextureData::CreateTextureClient(AndroidSurfaceTexture* aSurfTex,
gfx::IntSize aSize,
gl::OriginPos aOriginPos,
LayersIPCChannel* aAllocator,
TextureFlags aFlags)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Can't pass an android surfaces between processes.");
if (!aSurfTex || !XRE_IsParentProcess()) {
return nullptr;
}
if (aOriginPos == gl::OriginPos::BottomLeft) {
aFlags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
}
return TextureClient::CreateWithData(
new AndroidSurfaceTextureData(aSurfTex, aSize),
aFlags, aAllocator
);
}
AndroidSurfaceTextureData::AndroidSurfaceTextureData(AndroidSurfaceTexture* aSurfTex,
gfx::IntSize aSize)
: mSurfTex(aSurfTex)
, mSize(aSize)
{}
AndroidSurfaceTextureData::~AndroidSurfaceTextureData()
{}
void
AndroidSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const
{
aInfo.size = mSize;
aInfo.format = gfx::SurfaceFormat::UNKNOWN;
aInfo.hasIntermediateBuffer = false;
aInfo.hasSynchronization = false;
aInfo.supportsMoz2D = false;
aInfo.canExposeMappedData = false;
}
bool
AndroidSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
{
aOutDescriptor = SurfaceTextureDescriptor((uintptr_t)mSurfTex.get(),
mSize);
return true;
}
#endif // MOZ_WIDGET_ANDROID
} // namespace layers
} // namespace mozilla

View file

@ -0,0 +1,89 @@
/* -*- 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_TEXTURECLIENTOGL_H
#define MOZILLA_GFX_TEXTURECLIENTOGL_H
#include "GLContextTypes.h" // for SharedTextureHandle, etc
#include "GLImages.h"
#include "gfxTypes.h"
#include "mozilla/Attributes.h" // for override
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
#include "AndroidSurfaceTexture.h"
namespace mozilla {
namespace layers {
class EGLImageTextureData : public TextureData
{
public:
static already_AddRefed<TextureClient>
CreateTextureClient(EGLImageImage* aImage, gfx::IntSize aSize,
LayersIPCChannel* aAllocator, TextureFlags aFlags);
virtual void FillInfo(TextureData::Info& aInfo) const override;
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
virtual void Deallocate(LayersIPCChannel*) override { mImage = nullptr; }
virtual void Forget(LayersIPCChannel*) override { mImage = nullptr; }
// Unused functions.
virtual bool Lock(OpenMode) override { return true; }
virtual void Unlock() override {}
protected:
EGLImageTextureData(EGLImageImage* aImage, gfx::IntSize aSize);
RefPtr<EGLImageImage> mImage;
const gfx::IntSize mSize;
};
#ifdef MOZ_WIDGET_ANDROID
class AndroidSurfaceTextureData : public TextureData
{
public:
static already_AddRefed<TextureClient>
CreateTextureClient(gl::AndroidSurfaceTexture* aSurfTex,
gfx::IntSize aSize,
gl::OriginPos aOriginPos,
LayersIPCChannel* aAllocator,
TextureFlags aFlags);
~AndroidSurfaceTextureData();
virtual void FillInfo(TextureData::Info& aInfo) const override;
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
// Useless functions.
virtual bool Lock(OpenMode) override { return true; }
virtual void Unlock() override {}
// Our data is always owned externally.
virtual void Deallocate(LayersIPCChannel*) override {}
protected:
AndroidSurfaceTextureData(gl::AndroidSurfaceTexture* aSurfTex, gfx::IntSize aSize);
const RefPtr<gl::AndroidSurfaceTexture> mSurfTex;
const gfx::IntSize mSize;
};
#endif // MOZ_WIDGET_ANDROID
} // namespace layers
} // namespace mozilla
#endif

View file

@ -0,0 +1,771 @@
/* -*- 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/. */
#include "TextureHostOGL.h"
#include "EGLUtils.h"
#include "GLContext.h" // for GLContext, etc
#include "GLLibraryEGL.h" // for GLLibraryEGL
#include "GLUploadHelpers.h"
#include "GLReadTexImageHelper.h"
#include "gfx2DGlue.h" // for ContentForFormat, etc
#include "mozilla/gfx/2D.h" // for DataSourceSurface
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Logging.h" // for gfxCriticalError
#include "mozilla/layers/ISurfaceAllocator.h"
#include "nsRegion.h" // for nsIntRegion
#include "AndroidSurfaceTexture.h"
#include "GfxTexturesReporter.h" // for GfxTexturesReporter
#include "GLBlitTextureImageHelper.h"
#include "GeckoProfiler.h"
#ifdef XP_MACOSX
#include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
#endif
#ifdef GL_PROVIDER_GLX
#include "mozilla/layers/X11TextureHost.h"
#endif
using namespace mozilla::gl;
using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
class Compositor;
already_AddRefed<TextureHost>
CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
ISurfaceAllocator* aDeallocator,
TextureFlags aFlags)
{
RefPtr<TextureHost> result;
switch (aDesc.type()) {
case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
result = CreateBackendIndependentTextureHost(aDesc,
aDeallocator, aFlags);
break;
}
#ifdef MOZ_WIDGET_ANDROID
case SurfaceDescriptor::TSurfaceTextureDescriptor: {
const SurfaceTextureDescriptor& desc = aDesc.get_SurfaceTextureDescriptor();
result = new SurfaceTextureHost(aFlags,
(AndroidSurfaceTexture*)desc.surfTex(),
desc.size());
break;
}
#endif
case SurfaceDescriptor::TEGLImageDescriptor: {
const EGLImageDescriptor& desc = aDesc.get_EGLImageDescriptor();
result = new EGLImageTextureHost(aFlags,
(EGLImage)desc.image(),
(EGLSync)desc.fence(),
desc.size(),
desc.hasAlpha());
break;
}
#ifdef XP_MACOSX
case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
const SurfaceDescriptorMacIOSurface& desc =
aDesc.get_SurfaceDescriptorMacIOSurface();
result = new MacIOSurfaceTextureHostOGL(aFlags, desc);
break;
}
#endif
#ifdef GL_PROVIDER_GLX
case SurfaceDescriptor::TSurfaceDescriptorX11: {
const auto& desc = aDesc.get_SurfaceDescriptorX11();
result = new X11TextureHost(aFlags, desc);
break;
}
#endif
case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: {
const auto& desc = aDesc.get_SurfaceDescriptorSharedGLTexture();
result = new GLTextureHost(aFlags, desc.texture(),
desc.target(),
(GLsync)desc.fence(),
desc.size(),
desc.hasAlpha());
break;
}
default: return nullptr;
}
return result.forget();
}
static gl::TextureImage::Flags
FlagsToGLFlags(TextureFlags aFlags)
{
uint32_t result = TextureImage::NoFlags;
if (aFlags & TextureFlags::USE_NEAREST_FILTER)
result |= TextureImage::UseNearestFilter;
if (aFlags & TextureFlags::ORIGIN_BOTTOM_LEFT)
result |= TextureImage::OriginBottomLeft;
if (aFlags & TextureFlags::DISALLOW_BIGIMAGE)
result |= TextureImage::DisallowBigImage;
return static_cast<gl::TextureImage::Flags>(result);
}
bool
TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
nsIntRegion* aDestRegion,
gfx::IntPoint* aSrcOffset)
{
GLContext *gl = mCompositor->gl();
MOZ_ASSERT(gl);
if (!gl || !gl->MakeCurrent()) {
NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext");
return false;
}
if (!aSurface) {
gfxCriticalError() << "Invalid surface for OGL update";
return false;
}
MOZ_ASSERT(aSurface);
IntSize size = aSurface->GetSize();
if (!mTexImage ||
(mTexImage->GetSize() != size && !aSrcOffset) ||
mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) {
if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) {
GLint maxTextureSize;
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize);
if (size.width > maxTextureSize || size.height > maxTextureSize) {
NS_WARNING("Texture exceeds maximum texture size, refusing upload");
return false;
}
// Explicitly use CreateBasicTextureImage instead of CreateTextureImage,
// because CreateTextureImage might still choose to create a tiled
// texture image.
mTexImage = CreateBasicTextureImage(gl, size,
gfx::ContentForFormat(aSurface->GetFormat()),
LOCAL_GL_CLAMP_TO_EDGE,
FlagsToGLFlags(mFlags));
} else {
// XXX - clarify which size we want to use. IncrementalContentHost will
// require the size of the destination surface to be different from
// the size of aSurface.
// See bug 893300 (tracks the implementation of ContentHost for new textures).
mTexImage = CreateTextureImage(gl,
size,
gfx::ContentForFormat(aSurface->GetFormat()),
LOCAL_GL_CLAMP_TO_EDGE,
FlagsToGLFlags(mFlags),
SurfaceFormatToImageFormat(aSurface->GetFormat()));
}
ClearCachedFilter();
if (aDestRegion &&
!aSrcOffset &&
!aDestRegion->IsEqual(gfx::IntRect(0, 0, size.width, size.height))) {
// UpdateFromDataSource will ignore our specified aDestRegion since the texture
// hasn't been allocated with glTexImage2D yet. Call Resize() to force the
// allocation (full size, but no upload), and then we'll only upload the pixels
// we care about below.
mTexImage->Resize(size);
}
}
mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);
return true;
}
void
TextureImageTextureSourceOGL::EnsureBuffer(const IntSize& aSize,
gfxContentType aContentType)
{
if (!mTexImage ||
mTexImage->GetSize() != aSize ||
mTexImage->GetContentType() != aContentType) {
mTexImage = CreateTextureImage(mCompositor->gl(),
aSize,
aContentType,
LOCAL_GL_CLAMP_TO_EDGE,
FlagsToGLFlags(mFlags));
}
mTexImage->Resize(aSize);
}
void
TextureImageTextureSourceOGL::CopyTo(const gfx::IntRect& aSourceRect,
DataTextureSource *aDest,
const gfx::IntRect& aDestRect)
{
MOZ_ASSERT(aDest->AsSourceOGL(), "Incompatible destination type!");
TextureImageTextureSourceOGL *dest =
aDest->AsSourceOGL()->AsTextureImageTextureSource();
MOZ_ASSERT(dest, "Incompatible destination type!");
mCompositor->BlitTextureImageHelper()->BlitTextureImage(mTexImage, aSourceRect,
dest->mTexImage, aDestRect);
dest->mTexImage->MarkValid();
}
CompositorOGL* AssertGLCompositor(Compositor* aCompositor)
{
CompositorOGL* compositor = aCompositor ? aCompositor->AsCompositorOGL()
: nullptr;
MOZ_ASSERT(!!compositor);
return compositor;
}
void
TextureImageTextureSourceOGL::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = AssertGLCompositor(aCompositor);
if (!glCompositor) {
DeallocateDeviceData();
return;
}
if (mCompositor != glCompositor) {
DeallocateDeviceData();
mCompositor = glCompositor;
}
}
gfx::IntSize
TextureImageTextureSourceOGL::GetSize() const
{
if (mTexImage) {
if (mIterating) {
return mTexImage->GetTileRect().Size();
}
return mTexImage->GetSize();
}
NS_WARNING("Trying to query the size of an empty TextureSource.");
return gfx::IntSize(0, 0);
}
gfx::SurfaceFormat
TextureImageTextureSourceOGL::GetFormat() const
{
if (mTexImage) {
return mTexImage->GetTextureFormat();
}
NS_WARNING("Trying to query the format of an empty TextureSource.");
return gfx::SurfaceFormat::UNKNOWN;
}
gfx::IntRect TextureImageTextureSourceOGL::GetTileRect()
{
return mTexImage->GetTileRect();
}
void
TextureImageTextureSourceOGL::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
MOZ_ASSERT(mTexImage,
"Trying to bind a TextureSource that does not have an underlying GL texture.");
mTexImage->BindTexture(aTextureUnit);
SetSamplingFilter(mCompositor->gl(), aSamplingFilter);
}
////////////////////////////////////////////////////////////////////////
// GLTextureSource
GLTextureSource::GLTextureSource(CompositorOGL* aCompositor,
GLuint aTextureHandle,
GLenum aTarget,
gfx::IntSize aSize,
gfx::SurfaceFormat aFormat,
bool aExternallyOwned)
: mCompositor(aCompositor)
, mTextureHandle(aTextureHandle)
, mTextureTarget(aTarget)
, mSize(aSize)
, mFormat(aFormat)
, mExternallyOwned(aExternallyOwned)
{
MOZ_COUNT_CTOR(GLTextureSource);
}
GLTextureSource::~GLTextureSource()
{
MOZ_COUNT_DTOR(GLTextureSource);
if (!mExternallyOwned) {
DeleteTextureHandle();
}
}
void
GLTextureSource::DeallocateDeviceData()
{
if (!mExternallyOwned) {
DeleteTextureHandle();
}
}
void
GLTextureSource::DeleteTextureHandle()
{
GLContext* gl = this->gl();
if (mTextureHandle != 0 && gl && gl->MakeCurrent()) {
gl->fDeleteTextures(1, &mTextureHandle);
}
mTextureHandle = 0;
}
void
GLTextureSource::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
MOZ_ASSERT(mTextureHandle != 0);
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
return;
}
gl->fActiveTexture(aTextureUnit);
gl->fBindTexture(mTextureTarget, mTextureHandle);
ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
}
void
GLTextureSource::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = AssertGLCompositor(aCompositor);
if (!glCompositor) {
return;
}
if (mCompositor && mCompositor != glCompositor) {
gfxCriticalError() << "GLTextureSource does not support changing compositors";
}
mCompositor = glCompositor;
if (mNextSibling) {
mNextSibling->SetCompositor(aCompositor);
}
}
bool
GLTextureSource::IsValid() const
{
return !!gl() && mTextureHandle != 0;
}
gl::GLContext*
GLTextureSource::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// SurfaceTextureHost
#ifdef MOZ_WIDGET_ANDROID
SurfaceTextureSource::SurfaceTextureSource(CompositorOGL* aCompositor,
AndroidSurfaceTexture* aSurfTex,
gfx::SurfaceFormat aFormat,
GLenum aTarget,
GLenum aWrapMode,
gfx::IntSize aSize)
: mCompositor(aCompositor)
, mSurfTex(aSurfTex)
, mFormat(aFormat)
, mTextureTarget(aTarget)
, mWrapMode(aWrapMode)
, mSize(aSize)
{
}
void
SurfaceTextureSource::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
MOZ_ASSERT(mSurfTex);
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
NS_WARNING("Trying to bind a texture without a GLContext");
return;
}
gl->fActiveTexture(aTextureUnit);
// SurfaceTexture spams us if there are any existing GL errors, so
// we'll clear them here in order to avoid that.
gl->FlushErrors();
mSurfTex->UpdateTexImage();
ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
}
void
SurfaceTextureSource::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = AssertGLCompositor(aCompositor);
if (!glCompositor) {
DeallocateDeviceData();
return;
}
if (mCompositor != glCompositor) {
DeallocateDeviceData();
}
mCompositor = glCompositor;
}
bool
SurfaceTextureSource::IsValid() const
{
return !!gl();
}
gl::GLContext*
SurfaceTextureSource::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
gfx::Matrix4x4
SurfaceTextureSource::GetTextureTransform()
{
MOZ_ASSERT(mSurfTex);
gfx::Matrix4x4 ret;
mSurfTex->GetTransformMatrix(ret);
return ret;
}
void
SurfaceTextureSource::DeallocateDeviceData()
{
mSurfTex = nullptr;
}
////////////////////////////////////////////////////////////////////////
SurfaceTextureHost::SurfaceTextureHost(TextureFlags aFlags,
AndroidSurfaceTexture* aSurfTex,
gfx::IntSize aSize)
: TextureHost(aFlags)
, mSurfTex(aSurfTex)
, mSize(aSize)
, mCompositor(nullptr)
{
}
SurfaceTextureHost::~SurfaceTextureHost()
{
}
gl::GLContext*
SurfaceTextureHost::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
bool
SurfaceTextureHost::Lock()
{
MOZ_ASSERT(mSurfTex);
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
return false;
}
if (!mTextureSource) {
gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8;
GLenum target = LOCAL_GL_TEXTURE_EXTERNAL;
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
mTextureSource = new SurfaceTextureSource(mCompositor,
mSurfTex,
format,
target,
wrapMode,
mSize);
}
return NS_SUCCEEDED(mSurfTex->Attach(gl));
}
void
SurfaceTextureHost::Unlock()
{
MOZ_ASSERT(mSurfTex);
mSurfTex->Detach();
}
void
SurfaceTextureHost::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = AssertGLCompositor(aCompositor);
if (!glCompositor) {
DeallocateDeviceData();
return;
}
mCompositor = glCompositor;
if (mTextureSource) {
mTextureSource->SetCompositor(glCompositor);
}
}
gfx::SurfaceFormat
SurfaceTextureHost::GetFormat() const
{
return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN;
}
void
SurfaceTextureHost::DeallocateDeviceData()
{
if (mTextureSource) {
mTextureSource->DeallocateDeviceData();
}
mSurfTex = nullptr;
}
#endif // MOZ_WIDGET_ANDROID
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// EGLImage
EGLImageTextureSource::EGLImageTextureSource(CompositorOGL* aCompositor,
EGLImage aImage,
gfx::SurfaceFormat aFormat,
GLenum aTarget,
GLenum aWrapMode,
gfx::IntSize aSize)
: mCompositor(aCompositor)
, mImage(aImage)
, mFormat(aFormat)
, mTextureTarget(aTarget)
, mWrapMode(aWrapMode)
, mSize(aSize)
{
MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D ||
mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL);
}
void
EGLImageTextureSource::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
NS_WARNING("Trying to bind a texture without a GLContext");
return;
}
MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl),
"EGLImage not supported or disabled in runtime");
GLuint tex = mCompositor->GetTemporaryTexture(mTextureTarget, aTextureUnit);
gl->fActiveTexture(aTextureUnit);
gl->fBindTexture(mTextureTarget, tex);
gl->fEGLImageTargetTexture2D(mTextureTarget, mImage);
ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
}
void
EGLImageTextureSource::SetCompositor(Compositor* aCompositor)
{
mCompositor = AssertGLCompositor(aCompositor);
}
bool
EGLImageTextureSource::IsValid() const
{
return !!gl();
}
gl::GLContext*
EGLImageTextureSource::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
gfx::Matrix4x4
EGLImageTextureSource::GetTextureTransform()
{
gfx::Matrix4x4 ret;
return ret;
}
////////////////////////////////////////////////////////////////////////
EGLImageTextureHost::EGLImageTextureHost(TextureFlags aFlags,
EGLImage aImage,
EGLSync aSync,
gfx::IntSize aSize,
bool hasAlpha)
: TextureHost(aFlags)
, mImage(aImage)
, mSync(aSync)
, mSize(aSize)
, mHasAlpha(hasAlpha)
, mCompositor(nullptr)
{}
EGLImageTextureHost::~EGLImageTextureHost()
{}
gl::GLContext*
EGLImageTextureHost::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
bool
EGLImageTextureHost::Lock()
{
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
return false;
}
EGLint status = LOCAL_EGL_CONDITION_SATISFIED;
if (mSync) {
MOZ_ASSERT(sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync));
status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER);
}
if (status != LOCAL_EGL_CONDITION_SATISFIED) {
MOZ_ASSERT(status != 0,
"ClientWaitSync generated an error. Has mSync already been destroyed?");
return false;
}
if (!mTextureSource) {
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
: gfx::SurfaceFormat::R8G8B8X8;
GLenum target = gl->GetPreferredEGLImageTextureTarget();
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
mTextureSource = new EGLImageTextureSource(mCompositor,
mImage,
format,
target,
wrapMode,
mSize);
}
return true;
}
void
EGLImageTextureHost::Unlock()
{
}
void
EGLImageTextureHost::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = AssertGLCompositor(aCompositor);
if (!glCompositor) {
mCompositor = nullptr;
mTextureSource = nullptr;
return;
}
mCompositor = glCompositor;
if (mTextureSource) {
mTextureSource->SetCompositor(glCompositor);
}
}
gfx::SurfaceFormat
EGLImageTextureHost::GetFormat() const
{
MOZ_ASSERT(mTextureSource);
return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN;
}
//
GLTextureHost::GLTextureHost(TextureFlags aFlags,
GLuint aTextureHandle,
GLenum aTarget,
GLsync aSync,
gfx::IntSize aSize,
bool aHasAlpha)
: TextureHost(aFlags)
, mTexture(aTextureHandle)
, mTarget(aTarget)
, mSync(aSync)
, mSize(aSize)
, mHasAlpha(aHasAlpha)
, mCompositor(nullptr)
{}
GLTextureHost::~GLTextureHost()
{}
gl::GLContext*
GLTextureHost::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
bool
GLTextureHost::Lock()
{
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
return false;
}
if (mSync) {
if (!gl->MakeCurrent()) {
return false;
}
gl->fWaitSync(mSync, 0, LOCAL_GL_TIMEOUT_IGNORED);
gl->fDeleteSync(mSync);
mSync = 0;
}
if (!mTextureSource) {
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
: gfx::SurfaceFormat::R8G8B8X8;
mTextureSource = new GLTextureSource(mCompositor,
mTexture,
mTarget,
mSize,
format,
false /* owned by the client */);
}
return true;
}
void
GLTextureHost::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = AssertGLCompositor(aCompositor);
if (!glCompositor) {
mCompositor = nullptr;
mTextureSource = nullptr;
return;
}
mCompositor = glCompositor;
if (mTextureSource) {
mTextureSource->SetCompositor(glCompositor);
}
}
gfx::SurfaceFormat
GLTextureHost::GetFormat() const
{
MOZ_ASSERT(mTextureSource);
return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN;
}
} // namespace layers
} // namespace mozilla

View file

@ -0,0 +1,539 @@
/* -*- 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 <stddef.h> // for size_t
#include <stdint.h> // for uint64_t
#include "CompositableHost.h"
#include "GLContextTypes.h" // for GLContext
#include "GLDefs.h" // for GLenum, LOCAL_GL_CLAMP_TO_EDGE, etc
#include "GLTextureImage.h" // for TextureImage
#include "gfxTypes.h"
#include "mozilla/GfxMessageUtils.h" // for gfxContentType
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/Attributes.h" // for override
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/gfx/Point.h" // for IntSize, IntPoint
#include "mozilla/gfx/Types.h" // for SurfaceFormat, etc
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
#include "mozilla/layers/CompositorTypes.h" // for TextureFlags
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/TextureHost.h" // for TextureHost, etc
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsDebug.h" // for NS_WARNING
#include "nsISupportsImpl.h" // for TextureImage::Release, etc
#include "nsRegionFwd.h" // for nsIntRegion
#include "OGLShaderProgram.h" // for ShaderProgramType, etc
namespace mozilla {
namespace gfx {
class DataSourceSurface;
} // namespace gfx
namespace gl {
class AndroidSurfaceTexture;
} // namespace gl
namespace layers {
class Compositor;
class CompositorOGL;
class TextureImageTextureSourceOGL;
class GLTextureSource;
inline void ApplySamplingFilterToBoundTexture(gl::GLContext* aGL,
gfx::SamplingFilter aSamplingFilter,
GLuint aTarget = LOCAL_GL_TEXTURE_2D)
{
GLenum filter =
(aSamplingFilter == gfx::SamplingFilter::POINT ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR);
aGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MIN_FILTER, filter);
aGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, filter);
}
/*
* TextureHost implementations for the OpenGL backend.
*
* Note that it is important to be careful 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:
TextureSourceOGL()
: mHasCachedSamplingFilter(false)
{}
virtual bool IsValid() const = 0;
virtual void BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter) = 0;
virtual gfx::IntSize GetSize() const = 0;
virtual GLenum GetTextureTarget() const { return LOCAL_GL_TEXTURE_2D; }
virtual gfx::SurfaceFormat GetFormat() const = 0;
virtual GLenum GetWrapMode() const = 0;
virtual gfx::Matrix4x4 GetTextureTransform() { return gfx::Matrix4x4(); }
virtual TextureImageTextureSourceOGL* AsTextureImageTextureSource() { return nullptr; }
virtual GLTextureSource* AsGLTextureSource() { return nullptr; }
void SetSamplingFilter(gl::GLContext* aGL, gfx::SamplingFilter aSamplingFilter)
{
if (mHasCachedSamplingFilter &&
mCachedSamplingFilter == aSamplingFilter) {
return;
}
mHasCachedSamplingFilter = true;
mCachedSamplingFilter = aSamplingFilter;
ApplySamplingFilterToBoundTexture(aGL, aSamplingFilter, GetTextureTarget());
}
void ClearCachedFilter() { mHasCachedSamplingFilter = false; }
private:
gfx::SamplingFilter mCachedSamplingFilter;
bool mHasCachedSamplingFilter;
};
/**
* A TextureSource backed by a TextureImage.
*
* Depending on the underlying TextureImage, may support texture tiling, so
* make sure to check AsBigImageIterator() and use the texture accordingly.
*
* This TextureSource can be used without a TextureHost and manage it's own
* GL texture(s).
*/
class TextureImageTextureSourceOGL final : public DataTextureSource
, public TextureSourceOGL
, public BigImageIterator
{
public:
explicit TextureImageTextureSourceOGL(CompositorOGL *aCompositor,
TextureFlags aFlags = TextureFlags::DEFAULT)
: mCompositor(aCompositor)
, mFlags(aFlags)
, mIterating(false)
{}
virtual const char* Name() const override { return "TextureImageTextureSourceOGL"; }
// DataTextureSource
virtual bool Update(gfx::DataSourceSurface* aSurface,
nsIntRegion* aDestRegion = nullptr,
gfx::IntPoint* aSrcOffset = nullptr) override;
void EnsureBuffer(const gfx::IntSize& aSize,
gfxContentType aContentType);
void CopyTo(const gfx::IntRect& aSourceRect,
DataTextureSource* aDest,
const gfx::IntRect& aDestRect);
virtual TextureImageTextureSourceOGL* AsTextureImageTextureSource() override { return this; }
// TextureSource
virtual void DeallocateDeviceData() override
{
mTexImage = nullptr;
SetUpdateSerial(0);
}
virtual TextureSourceOGL* AsSourceOGL() override { return this; }
virtual void BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter) override;
virtual gfx::IntSize GetSize() const override;
virtual gfx::SurfaceFormat GetFormat() const override;
virtual bool IsValid() const override { return !!mTexImage; }
virtual void SetCompositor(Compositor* aCompositor) override;
virtual GLenum GetWrapMode() const override
{
return mTexImage->GetWrapMode();
}
// BigImageIterator
virtual BigImageIterator* AsBigImageIterator() override { return this; }
virtual void BeginBigImageIteration() override
{
mTexImage->BeginBigImageIteration();
mIterating = true;
}
virtual void EndBigImageIteration() override
{
mIterating = false;
}
virtual gfx::IntRect GetTileRect() override;
virtual size_t GetTileCount() override
{
return mTexImage->GetTileCount();
}
virtual bool NextTile() override
{
return mTexImage->NextTile();
}
protected:
RefPtr<gl::TextureImage> mTexImage;
RefPtr<CompositorOGL> mCompositor;
TextureFlags mFlags;
bool mIterating;
};
/**
* A texture source for GL textures.
*
* It does not own any GL texture, and attaches its shared handle to one of
* the compositor's temporary textures when binding.
*
* The shared texture handle is owned by the TextureHost.
*/
class GLTextureSource : public TextureSource
, public TextureSourceOGL
{
public:
GLTextureSource(CompositorOGL* aCompositor,
GLuint aTextureHandle,
GLenum aTarget,
gfx::IntSize aSize,
gfx::SurfaceFormat aFormat,
bool aExternallyOwned = false);
~GLTextureSource();
virtual const char* Name() const override { return "GLTextureSource"; }
virtual GLTextureSource* AsGLTextureSource() override { return this; }
virtual TextureSourceOGL* AsSourceOGL() override { return this; }
virtual void BindTexture(GLenum activetex,
gfx::SamplingFilter aSamplingFilter) override;
virtual bool IsValid() const override;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
virtual GLenum GetTextureTarget() const override { return mTextureTarget; }
virtual GLenum GetWrapMode() const override { return LOCAL_GL_CLAMP_TO_EDGE; }
virtual void DeallocateDeviceData() override;
virtual void SetCompositor(Compositor* aCompositor) override;
void SetSize(gfx::IntSize aSize) { mSize = aSize; }
void SetFormat(gfx::SurfaceFormat aFormat) { mFormat = aFormat; }
GLuint GetTextureHandle() const { return mTextureHandle; }
gl::GLContext* gl() const;
protected:
void DeleteTextureHandle();
RefPtr<CompositorOGL> mCompositor;
GLuint mTextureHandle;
GLenum mTextureTarget;
gfx::IntSize mSize;
gfx::SurfaceFormat mFormat;
// If the texture is externally owned, the gl handle will not be deleted
// in the destructor.
bool mExternallyOwned;
};
class GLTextureHost : public TextureHost
{
public:
GLTextureHost(TextureFlags aFlags,
GLuint aTextureHandle,
GLenum aTarget,
GLsync aSync,
gfx::IntSize aSize,
bool aHasAlpha);
virtual ~GLTextureHost();
// We don't own anything.
virtual void DeallocateDeviceData() override {}
virtual void SetCompositor(Compositor* aCompositor) override;
virtual Compositor* GetCompositor() override { return mCompositor; }
virtual bool Lock() override;
virtual void Unlock() override {}
virtual gfx::SurfaceFormat GetFormat() const override;
virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
{
aTexture = mTextureSource;
return !!aTexture;
}
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
{
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}
gl::GLContext* gl() const;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual const char* Name() override { return "GLTextureHost"; }
protected:
const GLuint mTexture;
const GLenum mTarget;
GLsync mSync;
const gfx::IntSize mSize;
const bool mHasAlpha;
RefPtr<CompositorOGL> mCompositor;
RefPtr<GLTextureSource> mTextureSource;
};
////////////////////////////////////////////////////////////////////////
// SurfaceTexture
#ifdef MOZ_WIDGET_ANDROID
class SurfaceTextureSource : public TextureSource
, public TextureSourceOGL
{
public:
SurfaceTextureSource(CompositorOGL* aCompositor,
mozilla::gl::AndroidSurfaceTexture* aSurfTex,
gfx::SurfaceFormat aFormat,
GLenum aTarget,
GLenum aWrapMode,
gfx::IntSize aSize);
virtual const char* Name() const override { return "SurfaceTextureSource"; }
virtual TextureSourceOGL* AsSourceOGL() override { return this; }
virtual void BindTexture(GLenum activetex,
gfx::SamplingFilter aSamplingFilter) override;
virtual bool IsValid() const override;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
virtual gfx::Matrix4x4 GetTextureTransform() override;
virtual GLenum GetTextureTarget() const override { return mTextureTarget; }
virtual GLenum GetWrapMode() const override { return mWrapMode; }
virtual void DeallocateDeviceData() override;
virtual void SetCompositor(Compositor* aCompositor) override;
gl::GLContext* gl() const;
protected:
RefPtr<CompositorOGL> mCompositor;
RefPtr<gl::AndroidSurfaceTexture> mSurfTex;
const gfx::SurfaceFormat mFormat;
const GLenum mTextureTarget;
const GLenum mWrapMode;
const gfx::IntSize mSize;
};
class SurfaceTextureHost : public TextureHost
{
public:
SurfaceTextureHost(TextureFlags aFlags,
mozilla::gl::AndroidSurfaceTexture* aSurfTex,
gfx::IntSize aSize);
virtual ~SurfaceTextureHost();
virtual void DeallocateDeviceData() override;
virtual void SetCompositor(Compositor* aCompositor) override;
virtual Compositor* GetCompositor() override { return mCompositor; }
virtual bool Lock() override;
virtual void Unlock() override;
virtual gfx::SurfaceFormat GetFormat() const override;
virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
{
aTexture = mTextureSource;
return !!aTexture;
}
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
{
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}
gl::GLContext* gl() const;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual const char* Name() override { return "SurfaceTextureHost"; }
protected:
RefPtr<gl::AndroidSurfaceTexture> mSurfTex;
const gfx::IntSize mSize;
RefPtr<CompositorOGL> mCompositor;
RefPtr<SurfaceTextureSource> mTextureSource;
};
#endif // MOZ_WIDGET_ANDROID
////////////////////////////////////////////////////////////////////////
// EGLImage
class EGLImageTextureSource : public TextureSource
, public TextureSourceOGL
{
public:
EGLImageTextureSource(CompositorOGL* aCompositor,
EGLImage aImage,
gfx::SurfaceFormat aFormat,
GLenum aTarget,
GLenum aWrapMode,
gfx::IntSize aSize);
virtual const char* Name() const override { return "EGLImageTextureSource"; }
virtual TextureSourceOGL* AsSourceOGL() override { return this; }
virtual void BindTexture(GLenum activetex,
gfx::SamplingFilter aSamplingFilter) override;
virtual bool IsValid() const override;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
virtual gfx::Matrix4x4 GetTextureTransform() override;
virtual GLenum GetTextureTarget() const override { return mTextureTarget; }
virtual GLenum GetWrapMode() const override { return mWrapMode; }
// We don't own anything.
virtual void DeallocateDeviceData() override {}
virtual void SetCompositor(Compositor* aCompositor) override;
gl::GLContext* gl() const;
protected:
RefPtr<CompositorOGL> mCompositor;
const EGLImage mImage;
const gfx::SurfaceFormat mFormat;
const GLenum mTextureTarget;
const GLenum mWrapMode;
const gfx::IntSize mSize;
};
class EGLImageTextureHost : public TextureHost
{
public:
EGLImageTextureHost(TextureFlags aFlags,
EGLImage aImage,
EGLSync aSync,
gfx::IntSize aSize,
bool hasAlpha);
virtual ~EGLImageTextureHost();
// We don't own anything.
virtual void DeallocateDeviceData() override {}
virtual void SetCompositor(Compositor* aCompositor) override;
virtual Compositor* GetCompositor() override { return mCompositor; }
virtual bool Lock() override;
virtual void Unlock() override;
virtual gfx::SurfaceFormat GetFormat() const override;
virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
{
aTexture = mTextureSource;
return !!aTexture;
}
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
{
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}
gl::GLContext* gl() const;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual const char* Name() override { return "EGLImageTextureHost"; }
protected:
const EGLImage mImage;
const EGLSync mSync;
const gfx::IntSize mSize;
const bool mHasAlpha;
RefPtr<CompositorOGL> mCompositor;
RefPtr<EGLImageTextureSource> mTextureSource;
};
CompositorOGL* AssertGLCompositor(Compositor* aCompositor);
} // namespace layers
} // namespace mozilla
#endif /* MOZILLA_GFX_TEXTUREOGL_H */

View file

@ -0,0 +1,123 @@
/* 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/. */
#include "TexturePoolOGL.h"
#include <stdlib.h> // for malloc
#include "GLContext.h" // for GLContext
#include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsDebug.h" // for NS_ASSERTION, NS_ERROR, etc
#include "nsDeque.h" // for nsDeque
#define TEXTURE_POOL_SIZE 10
namespace mozilla {
namespace gl {
static GLContext* sActiveContext = nullptr;
static Monitor* sMonitor = nullptr;
static nsDeque* sTextures = nullptr;
GLuint TexturePoolOGL::AcquireTexture()
{
NS_ASSERTION(sMonitor, "not initialized");
MonitorAutoLock lock(*sMonitor);
if (!sActiveContext) {
// Wait for a context
sMonitor->Wait();
if (!sActiveContext)
return 0;
}
GLuint texture = 0;
if (sActiveContext->IsOwningThreadCurrent()) {
sActiveContext->MakeCurrent();
sActiveContext->fGenTextures(1, &texture);
} else {
while (sTextures->GetSize() == 0) {
NS_WARNING("Waiting for texture");
sMonitor->Wait();
}
GLuint* popped = (GLuint*) sTextures->Pop();
if (!popped) {
NS_ERROR("Failed to pop texture pool item");
return 0;
}
texture = *popped;
delete popped;
NS_ASSERTION(texture, "Failed to retrieve texture from pool");
}
return texture;
}
static void Clear()
{
if (!sActiveContext)
return;
sActiveContext->MakeCurrent();
GLuint* item;
while (sTextures->GetSize()) {
item = (GLuint*)sTextures->Pop();
sActiveContext->fDeleteTextures(1, item);
delete item;
}
}
void TexturePoolOGL::Fill(GLContext* aContext)
{
NS_ASSERTION(aContext, "NULL GLContext");
NS_ASSERTION(sMonitor, "not initialized");
MonitorAutoLock lock(*sMonitor);
if (sActiveContext != aContext) {
Clear();
sActiveContext = aContext;
}
if (sTextures->GetSize() == TEXTURE_POOL_SIZE)
return;
sActiveContext->MakeCurrent();
GLuint* texture = nullptr;
while (sTextures->GetSize() < TEXTURE_POOL_SIZE) {
texture = (GLuint*)malloc(sizeof(GLuint));
sActiveContext->fGenTextures(1, texture);
sTextures->Push((void*) texture);
}
sMonitor->NotifyAll();
}
GLContext* TexturePoolOGL::GetGLContext()
{
return sActiveContext;
}
void TexturePoolOGL::Init()
{
sMonitor = new Monitor("TexturePoolOGL.sMonitor");
sTextures = new nsDeque();
}
void TexturePoolOGL::Shutdown()
{
delete sMonitor;
delete sTextures;
}
} // namespace gl
} // namespace mozilla

View file

@ -0,0 +1,40 @@
/* 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 GFX_TEXTUREPOOLOGL_H
#define GFX_TEXTUREPOOLOGL_H
#include "GLContextTypes.h" // for GLContext, GLuint
namespace mozilla {
namespace gl {
// A texture pool for for the on-screen GLContext. The main purpose of this class
// is to provide the ability to easily allocate an on-screen texture from the
// content thread. The unfortunate nature of the SurfaceTexture API (see AndroidSurfaceTexture)
// necessitates this.
class TexturePoolOGL
{
public:
// Get a new texture from the pool. Will block
// and wait for one to be created if necessary
static GLuint AcquireTexture();
// Called by the active LayerManagerOGL to fill
// the pool
static void Fill(GLContext* aContext);
static GLContext* GetGLContext();
// Initializes the pool, but does not fill it. Called by gfxPlatform init.
static void Init();
// Clears all internal data structures in preparation for shutdown
static void Shutdown();
};
} // namespace gl
} // namespace mozilla
#endif // GFX_TEXTUREPOOLOGL_H

View file

@ -0,0 +1,114 @@
/* -*- 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/. */
#ifdef GL_PROVIDER_GLX
#include "X11TextureSourceOGL.h"
#include "gfxXlibSurface.h"
#include "gfx2DGlue.h"
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
X11TextureSourceOGL::X11TextureSourceOGL(CompositorOGL* aCompositor, gfxXlibSurface* aSurface)
: mCompositor(aCompositor)
, mSurface(aSurface)
, mTexture(0)
, mUpdated(false)
{
}
X11TextureSourceOGL::~X11TextureSourceOGL()
{
DeallocateDeviceData();
}
void
X11TextureSourceOGL::DeallocateDeviceData()
{
if (mTexture) {
if (gl() && gl()->MakeCurrent()) {
gl::sGLXLibrary.ReleaseTexImage(mSurface->XDisplay(), mSurface->GetGLXPixmap());
gl()->fDeleteTextures(1, &mTexture);
mTexture = 0;
}
}
}
void
X11TextureSourceOGL::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
gl()->fActiveTexture(aTextureUnit);
if (!mTexture) {
gl()->fGenTextures(1, &mTexture);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
gl::sGLXLibrary.BindTexImage(mSurface->XDisplay(), mSurface->GetGLXPixmap());
} else {
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
if (mUpdated) {
gl::sGLXLibrary.UpdateTexImage(mSurface->XDisplay(), mSurface->GetGLXPixmap());
mUpdated = false;
}
}
ApplySamplingFilterToBoundTexture(gl(), aSamplingFilter, LOCAL_GL_TEXTURE_2D);
}
IntSize
X11TextureSourceOGL::GetSize() const
{
return mSurface->GetSize();
}
SurfaceFormat
X11TextureSourceOGL::GetFormat() const {
gfxContentType type = mSurface->GetContentType();
return X11TextureSourceOGL::ContentTypeToSurfaceFormat(type);
}
void
X11TextureSourceOGL::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = AssertGLCompositor(aCompositor);
if (mCompositor == glCompositor) {
return;
}
DeallocateDeviceData();
if (glCompositor) {
mCompositor = glCompositor;
}
}
gl::GLContext*
X11TextureSourceOGL::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
SurfaceFormat
X11TextureSourceOGL::ContentTypeToSurfaceFormat(gfxContentType aType)
{
// X11 uses a switched format and the OGL compositor
// doesn't support ALPHA / A8.
switch (aType) {
case gfxContentType::COLOR:
return SurfaceFormat::R8G8B8X8;
case gfxContentType::COLOR_ALPHA:
return SurfaceFormat::R8G8B8A8;
default:
return SurfaceFormat::UNKNOWN;
}
}
}
}
#endif

View file

@ -0,0 +1,65 @@
/* -*- 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_X11TEXTURESOURCEOGL__H
#define MOZILLA_GFX_X11TEXTURESOURCEOGL__H
#ifdef GL_PROVIDER_GLX
#include "mozilla/layers/CompositorOGL.h"
#include "mozilla/layers/TextureHostOGL.h"
#include "mozilla/layers/X11TextureHost.h"
#include "mozilla/gfx/2D.h"
namespace mozilla {
namespace layers {
// TextureSource for Xlib-backed surfaces.
class X11TextureSourceOGL
: public TextureSourceOGL
, public X11TextureSource
{
public:
X11TextureSourceOGL(CompositorOGL* aCompositor, gfxXlibSurface* aSurface);
~X11TextureSourceOGL();
virtual X11TextureSourceOGL* AsSourceOGL() override { return this; }
virtual bool IsValid() const override { return !!gl(); } ;
virtual void BindTexture(GLenum aTextureUnit, gfx::SamplingFilter aSamplingFilter) override;
virtual gfx::IntSize GetSize() const override;
virtual GLenum GetTextureTarget() const override { return LOCAL_GL_TEXTURE_2D; }
virtual gfx::SurfaceFormat GetFormat() const override;
virtual GLenum GetWrapMode() const override { return LOCAL_GL_CLAMP_TO_EDGE; }
virtual void DeallocateDeviceData() override;
virtual void SetCompositor(Compositor* aCompositor) override;
virtual void Updated() override { mUpdated = true; }
gl::GLContext* gl() const;
static gfx::SurfaceFormat ContentTypeToSurfaceFormat(gfxContentType aType);
protected:
RefPtr<CompositorOGL> mCompositor;
RefPtr<gfxXlibSurface> mSurface;
RefPtr<gfx::SourceSurface> mSourceSurface;
GLuint mTexture;
bool mUpdated;
};
} // namespace layers
} // namespace mozilla
#endif
#endif // MOZILLA_GFX_X11TEXTURESOURCEOGL__H