summaryrefslogtreecommitdiffstats
path: root/gfx/layers/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/opengl')
-rw-r--r--gfx/layers/opengl/Composer2D.h73
-rw-r--r--gfx/layers/opengl/CompositingRenderTargetOGL.cpp120
-rw-r--r--gfx/layers/opengl/CompositingRenderTargetOGL.h195
-rw-r--r--gfx/layers/opengl/CompositorOGL.cpp1916
-rw-r--r--gfx/layers/opengl/CompositorOGL.h502
-rw-r--r--gfx/layers/opengl/EGLImageHelpers.cpp53
-rw-r--r--gfx/layers/opengl/EGLImageHelpers.h27
-rw-r--r--gfx/layers/opengl/GLBlitTextureImageHelper.cpp280
-rw-r--r--gfx/layers/opengl/GLBlitTextureImageHelper.h71
-rw-r--r--gfx/layers/opengl/GLManager.cpp70
-rw-r--r--gfx/layers/opengl/GLManager.h44
-rw-r--r--gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp140
-rw-r--r--gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h58
-rw-r--r--gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp172
-rw-r--r--gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h114
-rw-r--r--gfx/layers/opengl/OGLShaderProgram.cpp974
-rw-r--r--gfx/layers/opengl/OGLShaderProgram.h621
-rw-r--r--gfx/layers/opengl/TextureClientOGL.cpp136
-rw-r--r--gfx/layers/opengl/TextureClientOGL.h89
-rw-r--r--gfx/layers/opengl/TextureHostOGL.cpp771
-rw-r--r--gfx/layers/opengl/TextureHostOGL.h539
-rw-r--r--gfx/layers/opengl/TexturePoolOGL.cpp123
-rw-r--r--gfx/layers/opengl/TexturePoolOGL.h40
-rw-r--r--gfx/layers/opengl/X11TextureSourceOGL.cpp114
-rw-r--r--gfx/layers/opengl/X11TextureSourceOGL.h65
25 files changed, 7307 insertions, 0 deletions
diff --git a/gfx/layers/opengl/Composer2D.h b/gfx/layers/opengl/Composer2D.h
new file mode 100644
index 000000000..a7cdcea36
--- /dev/null
+++ b/gfx/layers/opengl/Composer2D.h
@@ -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
diff --git a/gfx/layers/opengl/CompositingRenderTargetOGL.cpp b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
new file mode 100644
index 000000000..c05b8edfd
--- /dev/null
+++ b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
@@ -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
diff --git a/gfx/layers/opengl/CompositingRenderTargetOGL.h b/gfx/layers/opengl/CompositingRenderTargetOGL.h
new file mode 100644
index 000000000..501701d6f
--- /dev/null
+++ b/gfx/layers/opengl/CompositingRenderTargetOGL.h
@@ -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 */
diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp
new file mode 100644
index 000000000..bbe1b4657
--- /dev/null
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -0,0 +1,1916 @@
+/* -*- 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 "CompositorOGL.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint8_t
+#include <stdlib.h> // for free, malloc
+#include "GLContextProvider.h" // for GLContextProvider
+#include "GLContext.h" // for GLContext
+#include "GLUploadHelpers.h"
+#include "Layers.h" // for WriteSnapshotToDumpFile
+#include "LayerScope.h" // for LayerScope
+#include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter
+#include "gfxEnv.h" // for gfxEnv
+#include "gfxPlatform.h" // for gfxPlatform
+#include "gfxPrefs.h" // for gfxPrefs
+#include "gfxRect.h" // for gfxRect
+#include "gfxUtils.h" // for gfxUtils, etc
+#include "mozilla/ArrayUtils.h" // for ArrayLength
+#include "mozilla/Preferences.h" // for Preferences
+#include "mozilla/gfx/BasePoint.h" // for BasePoint
+#include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix
+#include "mozilla/gfx/Triangle.h" // for Triangle
+#include "mozilla/gfx/gfxVars.h" // for gfxVars
+#include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc
+#include "mozilla/layers/CompositingRenderTargetOGL.h"
+#include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc
+#include "mozilla/layers/TextureHost.h" // for TextureSource, etc
+#include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc
+#include "mozilla/mozalloc.h" // for operator delete, etc
+#include "nsAppRunner.h"
+#include "nsAString.h"
+#include "nsIConsoleService.h" // for nsIConsoleService, etc
+#include "nsIWidget.h" // for nsIWidget
+#include "nsLiteralString.h" // for NS_LITERAL_STRING
+#include "nsMathUtils.h" // for NS_roundf
+#include "nsRect.h" // for mozilla::gfx::IntRect
+#include "nsServiceManagerUtils.h" // for do_GetService
+#include "nsString.h" // for nsString, nsAutoCString, etc
+#include "ScopedGLHelpers.h"
+#include "GLReadTexImageHelper.h"
+#include "GLBlitTextureImageHelper.h"
+#include "HeapCopyOfStackArray.h"
+
+#if MOZ_WIDGET_ANDROID
+#include "TexturePoolOGL.h"
+#endif
+
+#include "GeckoProfiler.h"
+
+namespace mozilla {
+
+using namespace std;
+using namespace gfx;
+
+namespace layers {
+
+using namespace mozilla::gl;
+
+static const GLuint kCoordinateAttributeIndex = 0;
+static const GLuint kTexCoordinateAttributeIndex = 1;
+
+static void
+BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
+ GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
+{
+ MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
+ aSourceMask->BindTexture(aTexUnit, gfx::SamplingFilter::LINEAR);
+ aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
+ aProgram->SetMaskLayerTransform(aTransform);
+}
+
+void
+CompositorOGL::BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop, GLenum aTexUnit)
+{
+ MOZ_ASSERT(aBackdrop);
+
+ mGLContext->fActiveTexture(aTexUnit);
+ mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aBackdrop);
+ mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+ mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+ aProgram->SetBackdropTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
+}
+
+CompositorOGL::CompositorOGL(CompositorBridgeParent* aParent,
+ widget::CompositorWidget* aWidget,
+ int aSurfaceWidth, int aSurfaceHeight,
+ bool aUseExternalSurfaceSize)
+ : Compositor(aWidget, aParent)
+ , mWidgetSize(-1, -1)
+ , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
+ , mHasBGRA(0)
+ , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
+ , mFrameInProgress(false)
+ , mDestroyed(false)
+ , mViewportSize(0, 0)
+ , mCurrentProgram(nullptr)
+{
+ MOZ_COUNT_CTOR(CompositorOGL);
+}
+
+CompositorOGL::~CompositorOGL()
+{
+ MOZ_COUNT_DTOR(CompositorOGL);
+ Destroy();
+}
+
+already_AddRefed<mozilla::gl::GLContext>
+CompositorOGL::CreateContext()
+{
+ RefPtr<GLContext> context;
+
+ // Used by mock widget to create an offscreen context
+ nsIWidget* widget = mWidget->RealWidget();
+ void* widgetOpenGLContext = widget ? widget->GetNativeData(NS_NATIVE_OPENGL_CONTEXT) : nullptr;
+ if (widgetOpenGLContext) {
+ GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext);
+ return already_AddRefed<GLContext>(alreadyRefed);
+ }
+
+#ifdef XP_WIN
+ if (gfxEnv::LayersPreferEGL()) {
+ printf_stderr("Trying GL layers...\n");
+ context = gl::GLContextProviderEGL::CreateForCompositorWidget(mWidget, false);
+ }
+#endif
+
+ // Allow to create offscreen GL context for main Layer Manager
+ if (!context && gfxEnv::LayersPreferOffscreen()) {
+ SurfaceCaps caps = SurfaceCaps::ForRGB();
+ caps.preserve = false;
+ caps.bpp16 = gfxVars::OffscreenFormat() == SurfaceFormat::R5G6B5_UINT16;
+
+ nsCString discardFailureId;
+ context = GLContextProvider::CreateOffscreen(mSurfaceSize,
+ caps, CreateContextFlags::REQUIRE_COMPAT_PROFILE,
+ &discardFailureId);
+ }
+
+ if (!context) {
+ context = gl::GLContextProvider::CreateForCompositorWidget(mWidget,
+ gfxVars::RequiresAcceleratedGLContextForCompositorOGL());
+ }
+
+ if (!context) {
+ NS_WARNING("Failed to create CompositorOGL context");
+ }
+
+ return context.forget();
+}
+
+void
+CompositorOGL::Destroy()
+{
+ Compositor::Destroy();
+
+ if (mTexturePool) {
+ mTexturePool->Clear();
+ mTexturePool = nullptr;
+ }
+
+ if (!mDestroyed) {
+ mDestroyed = true;
+ CleanupResources();
+ }
+}
+
+void
+CompositorOGL::CleanupResources()
+{
+ if (!mGLContext)
+ return;
+
+ RefPtr<GLContext> ctx = mGLContext->GetSharedContext();
+ if (!ctx) {
+ ctx = mGLContext;
+ }
+
+ if (!ctx->MakeCurrent()) {
+ // Leak resources!
+ mQuadVBO = 0;
+ mTriangleVBO = 0;
+ mGLContext = nullptr;
+ mPrograms.clear();
+ return;
+ }
+
+ for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin();
+ iter != mPrograms.end();
+ iter++) {
+ delete iter->second;
+ }
+ mPrograms.clear();
+
+ ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+
+ if (mQuadVBO) {
+ ctx->fDeleteBuffers(1, &mQuadVBO);
+ mQuadVBO = 0;
+ }
+
+ if (mTriangleVBO) {
+ ctx->fDeleteBuffers(1, &mTriangleVBO);
+ mTriangleVBO = 0;
+ }
+
+ mGLContext->MakeCurrent();
+
+ mBlitTextureImageHelper = nullptr;
+
+ mContextStateTracker.DestroyOGL(mGLContext);
+
+ // On the main thread the Widget will be destroyed soon and calling MakeCurrent
+ // after that could cause a crash (at least with GLX, see bug 1059793), unless
+ // context is marked as destroyed.
+ // There may be some textures still alive that will try to call MakeCurrent on
+ // the context so let's make sure it is marked destroyed now.
+ mGLContext->MarkDestroyed();
+
+ mGLContext = nullptr;
+}
+
+bool
+CompositorOGL::Initialize(nsCString* const out_failureReason)
+{
+ ScopedGfxFeatureReporter reporter("GL Layers");
+
+ // Do not allow double initialization
+ MOZ_ASSERT(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
+
+ mGLContext = CreateContext();
+
+#ifdef MOZ_WIDGET_ANDROID
+ if (!mGLContext){
+ *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_ANDROID_CONTEXT";
+ NS_RUNTIMEABORT("We need a context on Android");
+ }
+#endif
+
+ if (!mGLContext){
+ *out_failureReason = "FEATURE_FAILURE_OPENGL_CREATE_CONTEXT";
+ return false;
+ }
+
+ MakeCurrent();
+
+ mHasBGRA =
+ mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
+ mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
+
+ mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
+ LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
+ mGLContext->fEnable(LOCAL_GL_BLEND);
+
+ // initialise a common shader to check that we can actually compile a shader
+ RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0));
+ ShaderConfigOGL config = GetShaderConfigFor(effect);
+ if (!GetShaderProgramFor(config)) {
+ *out_failureReason = "FEATURE_FAILURE_OPENGL_COMPILE_SHADER";
+ return false;
+ }
+
+ if (mGLContext->WorkAroundDriverBugs()) {
+ /**
+ * We'll test the ability here to bind NPOT textures to a framebuffer, if
+ * this fails we'll try ARB_texture_rectangle.
+ */
+
+ GLenum textureTargets[] = {
+ LOCAL_GL_TEXTURE_2D,
+ LOCAL_GL_NONE
+ };
+
+ if (!mGLContext->IsGLES()) {
+ // No TEXTURE_RECTANGLE_ARB available on ES2
+ textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
+ }
+
+ mFBOTextureTarget = LOCAL_GL_NONE;
+
+ GLuint testFBO = 0;
+ mGLContext->fGenFramebuffers(1, &testFBO);
+ GLuint testTexture = 0;
+
+ for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) {
+ GLenum target = textureTargets[i];
+ if (!target)
+ continue;
+
+ mGLContext->fGenTextures(1, &testTexture);
+ mGLContext->fBindTexture(target, testTexture);
+ mGLContext->fTexParameteri(target,
+ LOCAL_GL_TEXTURE_MIN_FILTER,
+ LOCAL_GL_NEAREST);
+ mGLContext->fTexParameteri(target,
+ LOCAL_GL_TEXTURE_MAG_FILTER,
+ LOCAL_GL_NEAREST);
+ mGLContext->fTexImage2D(target,
+ 0,
+ LOCAL_GL_RGBA,
+ 5, 3, /* sufficiently NPOT */
+ 0,
+ LOCAL_GL_RGBA,
+ LOCAL_GL_UNSIGNED_BYTE,
+ nullptr);
+
+ // unbind this texture, in preparation for binding it to the FBO
+ mGLContext->fBindTexture(target, 0);
+
+ mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO);
+ mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
+ LOCAL_GL_COLOR_ATTACHMENT0,
+ target,
+ testTexture,
+ 0);
+
+ if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
+ LOCAL_GL_FRAMEBUFFER_COMPLETE)
+ {
+ mFBOTextureTarget = target;
+ mGLContext->fDeleteTextures(1, &testTexture);
+ break;
+ }
+
+ mGLContext->fDeleteTextures(1, &testTexture);
+ }
+
+ if (testFBO) {
+ mGLContext->fDeleteFramebuffers(1, &testFBO);
+ }
+
+ if (mFBOTextureTarget == LOCAL_GL_NONE) {
+ /* Unable to find a texture target that works with FBOs and NPOT textures */
+ *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_TEXTURE_TARGET";
+ return false;
+ }
+ } else {
+ // not trying to work around driver bugs, so TEXTURE_2D should just work
+ mFBOTextureTarget = LOCAL_GL_TEXTURE_2D;
+ }
+
+ // back to default framebuffer, to avoid confusion
+ mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+
+ if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
+ /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
+ * extension -- the EXT variant does not provide support for
+ * texture rectangle access inside GLSL (sampler2DRect,
+ * texture2DRect).
+ */
+ if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)){
+ *out_failureReason = "FEATURE_FAILURE_OPENGL_ARB_EXT";
+ return false;
+ }
+ }
+
+ // Create a VBO for triangle vertices.
+ mGLContext->fGenBuffers(1, &mTriangleVBO);
+
+ /* Create a simple quad VBO */
+ mGLContext->fGenBuffers(1, &mQuadVBO);
+
+ // 4 quads, with the number of the quad (vertexID) encoded in w.
+ GLfloat vertices[] = {
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f,
+
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+
+ 0.0f, 0.0f, 0.0f, 2.0f,
+ 1.0f, 0.0f, 0.0f, 2.0f,
+ 0.0f, 1.0f, 0.0f, 2.0f,
+ 1.0f, 0.0f, 0.0f, 2.0f,
+ 0.0f, 1.0f, 0.0f, 2.0f,
+ 1.0f, 1.0f, 0.0f, 2.0f,
+
+ 0.0f, 0.0f, 0.0f, 3.0f,
+ 1.0f, 0.0f, 0.0f, 3.0f,
+ 0.0f, 1.0f, 0.0f, 3.0f,
+ 1.0f, 0.0f, 0.0f, 3.0f,
+ 0.0f, 1.0f, 0.0f, 3.0f,
+ 1.0f, 1.0f, 0.0f, 3.0f,
+ };
+ HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices);
+
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
+ mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
+ verticesOnHeap.ByteLength(),
+ verticesOnHeap.Data(),
+ LOCAL_GL_STATIC_DRAW);
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+
+ nsCOMPtr<nsIConsoleService>
+ console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
+
+ if (console) {
+ nsString msg;
+ msg +=
+ NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: ");
+ msg += NS_ConvertUTF8toUTF16(
+ nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
+ msg += NS_LITERAL_STRING("\nVendor: ");
+ msg += NS_ConvertUTF8toUTF16(
+ nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
+ msg += NS_LITERAL_STRING("\nRenderer: ");
+ msg += NS_ConvertUTF8toUTF16(
+ nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
+ msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
+ if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
+ msg += NS_LITERAL_STRING("TEXTURE_2D");
+ else
+ msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
+ console->LogStringMessage(msg.get());
+ }
+
+ reporter.SetSuccessful();
+
+ return true;
+}
+
+/*
+ * Returns a size that is equal to, or larger than and closest to,
+ * aSize where both width and height are powers of two.
+ * If the OpenGL setup is capable of using non-POT textures,
+ * then it will just return aSize.
+ */
+static IntSize
+CalculatePOTSize(const IntSize& aSize, GLContext* gl)
+{
+ if (CanUploadNonPowerOfTwo(gl))
+ return aSize;
+
+ return IntSize(RoundUpPow2(aSize.width), RoundUpPow2(aSize.height));
+}
+
+gfx::Rect
+CompositorOGL::GetTextureCoordinates(gfx::Rect textureRect, TextureSource* aTexture)
+{
+ // If the OpenGL setup does not support non-power-of-two textures then the
+ // texture's width and height will have been increased to the next
+ // power-of-two (unless already a power of two). In that case we must scale
+ // the texture coordinates to account for that.
+ if (!CanUploadNonPowerOfTwo(mGLContext)) {
+ const IntSize& textureSize = aTexture->GetSize();
+ const IntSize potSize = CalculatePOTSize(textureSize, mGLContext);
+ if (potSize != textureSize) {
+ const float xScale = (float)textureSize.width / (float)potSize.width;
+ const float yScale = (float)textureSize.height / (float)potSize.height;
+ textureRect.Scale(xScale, yScale);
+ }
+ }
+
+ return textureRect;
+}
+
+void
+CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget)
+{
+ MOZ_ASSERT(aRenderTarget);
+ // Logical surface size.
+ const gfx::IntSize& size = aRenderTarget->mInitParams.mSize;
+ // Physical surface size.
+ const gfx::IntSize& phySize = aRenderTarget->mInitParams.mPhySize;
+
+ // Set the viewport correctly.
+ mGLContext->fViewport(0, 0, phySize.width, phySize.height);
+
+ mViewportSize = size;
+
+ if (!aRenderTarget->HasComplexProjection()) {
+ // We flip the view matrix around so that everything is right-side up; we're
+ // drawing directly into the window's back buffer, so this keeps things
+ // looking correct.
+ // XXX: We keep track of whether the window size changed, so we could skip
+ // this update if it hadn't changed since the last call.
+
+ // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
+ // 2, 2) and flip the contents.
+ Matrix viewMatrix;
+ if (mGLContext->IsOffscreen() && !gIsGtest) {
+ // In case of rendering via GL Offscreen context, disable Y-Flipping
+ viewMatrix.PreTranslate(-1.0, -1.0);
+ viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
+ } else {
+ viewMatrix.PreTranslate(-1.0, 1.0);
+ viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
+ viewMatrix.PreScale(1.0f, -1.0f);
+ }
+
+ MOZ_ASSERT(mCurrentRenderTarget, "No destination");
+ // If we're drawing directly to the window then we want to offset
+ // drawing by the render offset.
+ if (!mTarget && mCurrentRenderTarget->IsWindow()) {
+ viewMatrix.PreTranslate(mRenderOffset.x, mRenderOffset.y);
+ }
+
+ Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
+ matrix3d._33 = 0.0f;
+ mProjMatrix = matrix3d;
+ mGLContext->fDepthRange(0.0f, 1.0f);
+ } else {
+ // XXX take into account mRenderOffset
+ bool depthEnable;
+ float zNear, zFar;
+ aRenderTarget->GetProjection(mProjMatrix, depthEnable, zNear, zFar);
+ mGLContext->fDepthRange(zNear, zFar);
+ }
+}
+
+already_AddRefed<CompositingRenderTarget>
+CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit)
+{
+ MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
+
+ if (aRect.width * aRect.height == 0) {
+ return nullptr;
+ }
+
+ if (!gl()) {
+ // CompositingRenderTargetOGL does not work without a gl context.
+ return nullptr;
+ }
+
+ GLuint tex = 0;
+ GLuint fbo = 0;
+ IntRect rect = aRect;
+ IntSize FBOSize;
+ CreateFBOWithTexture(rect, false, 0, &fbo, &tex, &FBOSize);
+ RefPtr<CompositingRenderTargetOGL> surface
+ = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
+ surface->Initialize(aRect.Size(), FBOSize, mFBOTextureTarget, aInit);
+ return surface.forget();
+}
+
+already_AddRefed<CompositingRenderTarget>
+CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect,
+ const CompositingRenderTarget *aSource,
+ const IntPoint &aSourcePoint)
+{
+ MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
+
+ if (aRect.width * aRect.height == 0) {
+ return nullptr;
+ }
+
+ if (!gl()) {
+ return nullptr;
+ }
+
+ GLuint tex = 0;
+ GLuint fbo = 0;
+ const CompositingRenderTargetOGL* sourceSurface
+ = static_cast<const CompositingRenderTargetOGL*>(aSource);
+ IntRect sourceRect(aSourcePoint, aRect.Size());
+ if (aSource) {
+ CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(),
+ &fbo, &tex);
+ } else {
+ CreateFBOWithTexture(sourceRect, true, 0,
+ &fbo, &tex);
+ }
+
+ RefPtr<CompositingRenderTargetOGL> surface
+ = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
+ surface->Initialize(aRect.Size(),
+ sourceRect.Size(),
+ mFBOTextureTarget,
+ INIT_MODE_NONE);
+ return surface.forget();
+}
+
+void
+CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface)
+{
+ MOZ_ASSERT(aSurface);
+ CompositingRenderTargetOGL* surface
+ = static_cast<CompositingRenderTargetOGL*>(aSurface);
+ if (mCurrentRenderTarget != surface) {
+ mCurrentRenderTarget = surface;
+ if (mCurrentRenderTarget) {
+ mContextStateTracker.PopOGLSection(gl(), "Frame");
+ }
+ mContextStateTracker.PushOGLSection(gl(), "Frame");
+ surface->BindRenderTarget();
+ }
+
+ PrepareViewport(mCurrentRenderTarget);
+}
+
+CompositingRenderTarget*
+CompositorOGL::GetCurrentRenderTarget() const
+{
+ return mCurrentRenderTarget;
+}
+
+static GLenum
+GetFrameBufferInternalFormat(GLContext* gl,
+ GLuint aFrameBuffer,
+ mozilla::widget::CompositorWidget* aWidget)
+{
+ if (aFrameBuffer == 0) { // default framebuffer
+ return aWidget->GetGLFrameBufferFormat();
+ }
+ return LOCAL_GL_RGBA;
+}
+
+void
+CompositorOGL::ClearRect(const gfx::Rect& aRect)
+{
+ // Map aRect to OGL coordinates, origin:bottom-left
+ GLint y = mViewportSize.height - (aRect.y + aRect.height);
+
+ ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
+ ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height);
+ mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
+ mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
+}
+
+void
+CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
+ const IntRect *aClipRectIn,
+ const IntRect& aRenderBounds,
+ const nsIntRegion& aOpaqueRegion,
+ IntRect *aClipRectOut,
+ IntRect *aRenderBoundsOut)
+{
+ PROFILER_LABEL("CompositorOGL", "BeginFrame",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame");
+
+ gfx::IntRect rect;
+ if (mUseExternalSurfaceSize) {
+ rect = gfx::IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
+ } else {
+ rect = gfx::IntRect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
+ }
+
+ if (aRenderBoundsOut) {
+ *aRenderBoundsOut = rect;
+ }
+
+ GLint width = rect.width;
+ GLint height = rect.height;
+
+ // We can't draw anything to something with no area
+ // so just return
+ if (width == 0 || height == 0)
+ return;
+
+ // We're about to actually draw a frame.
+ mFrameInProgress = true;
+
+ // If the widget size changed, we have to force a MakeCurrent
+ // to make sure that GL sees the updated widget size.
+ if (mWidgetSize.width != width ||
+ mWidgetSize.height != height)
+ {
+ MakeCurrent(ForceMakeCurrent);
+
+ mWidgetSize.width = width;
+ mWidgetSize.height = height;
+ } else {
+ MakeCurrent();
+ }
+
+ mPixelsPerFrame = width * height;
+ mPixelsFilled = 0;
+
+#ifdef MOZ_WIDGET_ANDROID
+ TexturePoolOGL::Fill(gl());
+#endif
+
+ // Default blend function implements "OVER"
+ mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
+ LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
+ mGLContext->fEnable(LOCAL_GL_BLEND);
+
+ RefPtr<CompositingRenderTargetOGL> rt =
+ CompositingRenderTargetOGL::RenderTargetForWindow(this,
+ IntSize(width, height));
+ SetRenderTarget(rt);
+
+#ifdef DEBUG
+ mWindowRenderTarget = mCurrentRenderTarget;
+#endif
+
+ if (aClipRectOut && !aClipRectIn) {
+ aClipRectOut->SetRect(0, 0, width, height);
+ }
+
+ mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b, mClearColor.a);
+ mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
+}
+
+void
+CompositorOGL::CreateFBOWithTexture(const gfx::IntRect& aRect,
+ bool aCopyFromSource,
+ GLuint aSourceFrameBuffer,
+ GLuint *aFBO, GLuint *aTexture,
+ gfx::IntSize* aAllocSize)
+{
+ *aTexture = CreateTexture(aRect, aCopyFromSource, aSourceFrameBuffer,
+ aAllocSize);
+ mGLContext->fGenFramebuffers(1, aFBO);
+}
+
+GLuint
+CompositorOGL::CreateTexture(const IntRect& aRect, bool aCopyFromSource,
+ GLuint aSourceFrameBuffer, IntSize* aAllocSize)
+{
+ // we're about to create a framebuffer backed by textures to use as an intermediate
+ // surface. What to do if its size (as given by aRect) would exceed the
+ // maximum texture size supported by the GL? The present code chooses the compromise
+ // of just clamping the framebuffer's size to the max supported size.
+ // This gives us a lower resolution rendering of the intermediate surface (children layers).
+ // See bug 827170 for a discussion.
+ IntRect clampedRect = aRect;
+ int32_t maxTexSize = GetMaxTextureSize();
+ clampedRect.width = std::min(clampedRect.width, maxTexSize);
+ clampedRect.height = std::min(clampedRect.height, maxTexSize);
+
+ GLuint tex;
+
+ mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
+ mGLContext->fGenTextures(1, &tex);
+ mGLContext->fBindTexture(mFBOTextureTarget, tex);
+
+ if (aCopyFromSource) {
+ GLuint curFBO = mCurrentRenderTarget->GetFBO();
+ if (curFBO != aSourceFrameBuffer) {
+ mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer);
+ }
+
+ // We're going to create an RGBA temporary fbo. But to
+ // CopyTexImage() from the current framebuffer, the framebuffer's
+ // format has to be compatible with the new texture's. So we
+ // check the format of the framebuffer here and take a slow path
+ // if it's incompatible.
+ GLenum format =
+ GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
+
+ bool isFormatCompatibleWithRGBA
+ = gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
+ : true;
+
+ if (isFormatCompatibleWithRGBA) {
+ mGLContext->fCopyTexImage2D(mFBOTextureTarget,
+ 0,
+ LOCAL_GL_RGBA,
+ clampedRect.x, FlipY(clampedRect.y + clampedRect.height),
+ clampedRect.width, clampedRect.height,
+ 0);
+ } else {
+ // Curses, incompatible formats. Take a slow path.
+
+ // RGBA
+ size_t bufferSize = clampedRect.width * clampedRect.height * 4;
+ auto buf = MakeUnique<uint8_t[]>(bufferSize);
+
+ mGLContext->fReadPixels(clampedRect.x, clampedRect.y,
+ clampedRect.width, clampedRect.height,
+ LOCAL_GL_RGBA,
+ LOCAL_GL_UNSIGNED_BYTE,
+ buf.get());
+ mGLContext->fTexImage2D(mFBOTextureTarget,
+ 0,
+ LOCAL_GL_RGBA,
+ clampedRect.width, clampedRect.height,
+ 0,
+ LOCAL_GL_RGBA,
+ LOCAL_GL_UNSIGNED_BYTE,
+ buf.get());
+ }
+
+ GLenum error = mGLContext->fGetError();
+ if (error != LOCAL_GL_NO_ERROR) {
+ nsAutoCString msg;
+ msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d, RGBA Compat %d",
+ error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA);
+ NS_ERROR(msg.get());
+ }
+ } else {
+ mGLContext->fTexImage2D(mFBOTextureTarget,
+ 0,
+ LOCAL_GL_RGBA,
+ clampedRect.width, clampedRect.height,
+ 0,
+ LOCAL_GL_RGBA,
+ LOCAL_GL_UNSIGNED_BYTE,
+ nullptr);
+ }
+ mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
+ LOCAL_GL_LINEAR);
+ mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
+ LOCAL_GL_LINEAR);
+ mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S,
+ LOCAL_GL_CLAMP_TO_EDGE);
+ mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T,
+ LOCAL_GL_CLAMP_TO_EDGE);
+ mGLContext->fBindTexture(mFBOTextureTarget, 0);
+
+ if (aAllocSize) {
+ aAllocSize->width = clampedRect.width;
+ aAllocSize->height = clampedRect.height;
+ }
+
+ return tex;
+}
+
+ShaderConfigOGL
+CompositorOGL::GetShaderConfigFor(Effect *aEffect,
+ MaskType aMask,
+ gfx::CompositionOp aOp,
+ bool aColorMatrix,
+ bool aDEAAEnabled) const
+{
+ ShaderConfigOGL config;
+
+ switch(aEffect->mType) {
+ case EffectTypes::SOLID_COLOR:
+ config.SetRenderColor(true);
+ break;
+ case EffectTypes::YCBCR:
+ config.SetYCbCr(true);
+ break;
+ case EffectTypes::NV12:
+ config.SetNV12(true);
+ config.SetTextureTarget(LOCAL_GL_TEXTURE_RECTANGLE_ARB);
+ break;
+ case EffectTypes::COMPONENT_ALPHA:
+ {
+ config.SetComponentAlpha(true);
+ EffectComponentAlpha* effectComponentAlpha =
+ static_cast<EffectComponentAlpha*>(aEffect);
+ gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat();
+ config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 ||
+ format == gfx::SurfaceFormat::B8G8R8X8);
+ TextureSourceOGL* source = effectComponentAlpha->mOnWhite->AsSourceOGL();
+ config.SetTextureTarget(source->GetTextureTarget());
+ break;
+ }
+ case EffectTypes::RENDER_TARGET:
+ config.SetTextureTarget(mFBOTextureTarget);
+ break;
+ default:
+ {
+ MOZ_ASSERT(aEffect->mType == EffectTypes::RGB);
+ TexturedEffect* texturedEffect =
+ static_cast<TexturedEffect*>(aEffect);
+ TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
+ MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
+ source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
+ source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8);
+ MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
+ source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
+ source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16 ||
+ source->GetFormat() == gfx::SurfaceFormat::YUV422 );
+ config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
+ source->GetFormat());
+ if (!texturedEffect->mPremultiplied) {
+ config.SetNoPremultipliedAlpha();
+ }
+ break;
+ }
+ }
+ config.SetColorMatrix(aColorMatrix);
+ config.SetMask(aMask == MaskType::Mask);
+ config.SetDEAA(aDEAAEnabled);
+ config.SetCompositionOp(aOp);
+ return config;
+}
+
+ShaderProgramOGL*
+CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig)
+{
+ std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig);
+ if (iter != mPrograms.end())
+ return iter->second;
+
+ ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig);
+ ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile);
+ if (!shader->Initialize()) {
+ delete shader;
+ return nullptr;
+ }
+
+ mPrograms[aConfig] = shader;
+ return shader;
+}
+
+void
+CompositorOGL::ActivateProgram(ShaderProgramOGL* aProg)
+{
+ if (mCurrentProgram != aProg) {
+ gl()->fUseProgram(aProg->GetProgram());
+ mCurrentProgram = aProg;
+ }
+}
+
+void
+CompositorOGL::ResetProgram()
+{
+ mCurrentProgram = nullptr;
+}
+
+static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode, bool aIsPremultiplied = true)
+{
+ if (BlendOpIsMixBlendMode(aBlendMode)) {
+ // Mix-blend modes require an extra step (or more) that cannot be expressed
+ // in the fixed-function blending capabilities of opengl. We handle them
+ // separately in shaders, and the shaders assume we will use our default
+ // blend function for compositing (premultiplied OP_OVER).
+ return false;
+ }
+ if (aBlendMode == gfx::CompositionOp::OP_OVER && aIsPremultiplied) {
+ return false;
+ }
+
+ GLenum srcBlend;
+ GLenum dstBlend;
+ GLenum srcAlphaBlend = LOCAL_GL_ONE;
+ GLenum dstAlphaBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
+
+ switch (aBlendMode) {
+ case gfx::CompositionOp::OP_OVER:
+ MOZ_ASSERT(!aIsPremultiplied);
+ srcBlend = LOCAL_GL_SRC_ALPHA;
+ dstBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case gfx::CompositionOp::OP_SOURCE:
+ srcBlend = aIsPremultiplied ? LOCAL_GL_ONE : LOCAL_GL_SRC_ALPHA;
+ dstBlend = LOCAL_GL_ZERO;
+ srcAlphaBlend = LOCAL_GL_ONE;
+ dstAlphaBlend = LOCAL_GL_ZERO;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unsupported blend mode!");
+ return false;
+ }
+
+ aGL->fBlendFuncSeparate(srcBlend, dstBlend,
+ srcAlphaBlend, dstAlphaBlend);
+ return true;
+}
+
+gfx::Point3D
+CompositorOGL::GetLineCoefficients(const gfx::Point& aPoint1,
+ const gfx::Point& aPoint2)
+{
+ // Return standard coefficients for a line between aPoint1 and aPoint2
+ // for standard line equation:
+ //
+ // Ax + By + C = 0
+ //
+ // A = (p1.y – p2.y)
+ // B = (p2.x – p1.x)
+ // C = (p1.x * p2.y) – (p2.x * p1.y)
+
+ gfx::Point3D coeffecients;
+ coeffecients.x = aPoint1.y - aPoint2.y;
+ coeffecients.y = aPoint2.x - aPoint1.x;
+ coeffecients.z = aPoint1.x * aPoint2.y - aPoint2.x * aPoint1.y;
+
+ coeffecients *= 1.0f / sqrtf(coeffecients.x * coeffecients.x +
+ coeffecients.y * coeffecients.y);
+
+ // Offset outwards by 0.5 pixel as the edge is considered to be 1 pixel
+ // wide and included within the interior of the polygon
+ coeffecients.z += 0.5f;
+
+ return coeffecients;
+}
+
+void
+CompositorOGL::DrawQuad(const Rect& aRect,
+ const IntRect& aClipRect,
+ const EffectChain &aEffectChain,
+ Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect)
+{
+ PROFILER_LABEL("CompositorOGL", "DrawQuad",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ DrawGeometry(aRect, aClipRect, aEffectChain,
+ aOpacity, aTransform, aVisibleRect);
+}
+
+void
+CompositorOGL::DrawTriangle(const gfx::TexturedTriangle& aTriangle,
+ const gfx::IntRect& aClipRect,
+ const EffectChain& aEffectChain,
+ gfx::Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect)
+{
+ PROFILER_LABEL("CompositorOGL", "DrawTriangle",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ DrawGeometry(aTriangle, aClipRect, aEffectChain,
+ aOpacity, aTransform, aVisibleRect);
+}
+
+template<typename Geometry>
+void
+CompositorOGL::DrawGeometry(const Geometry& aGeometry,
+ const IntRect& aClipRect,
+ const EffectChain &aEffectChain,
+ Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect)
+{
+ MOZ_ASSERT(mFrameInProgress, "frame not started");
+ MOZ_ASSERT(mCurrentRenderTarget, "No destination");
+
+ MakeCurrent();
+
+ IntPoint offset = mCurrentRenderTarget->GetOrigin();
+ IntSize size = mCurrentRenderTarget->GetSize();
+
+ Rect renderBound(0, 0, size.width, size.height);
+ renderBound.IntersectRect(renderBound, Rect(aClipRect));
+ renderBound.MoveBy(offset);
+
+ Rect destRect = aTransform.TransformAndClipBounds(aGeometry, renderBound);
+
+ // XXX: This doesn't handle 3D transforms. It also doesn't handled rotated
+ // quads. Fix me.
+ mPixelsFilled += destRect.width * destRect.height;
+
+ // Do a simple culling if this rect is out of target buffer.
+ // Inflate a small size to avoid some numerical imprecision issue.
+ destRect.Inflate(1, 1);
+ destRect.MoveBy(-offset);
+ renderBound = Rect(0, 0, size.width, size.height);
+ if (!renderBound.Intersects(destRect)) {
+ return;
+ }
+
+ LayerScope::DrawBegin();
+
+ IntRect clipRect = aClipRect;
+ // aClipRect is in destination coordinate space (after all
+ // transforms and offsets have been applied) so if our
+ // drawing is going to be shifted by mRenderOffset then we need
+ // to shift the clip rect by the same amount.
+ if (!mTarget && mCurrentRenderTarget->IsWindow()) {
+ clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
+ }
+
+ ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
+ ScopedScissorRect autoScissorRect(mGLContext, clipRect.x, FlipY(clipRect.y + clipRect.height),
+ clipRect.width, clipRect.height);
+
+ MaskType maskType;
+ EffectMask* effectMask;
+ TextureSourceOGL* sourceMask = nullptr;
+ gfx::Matrix4x4 maskQuadTransform;
+ if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
+ effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
+ sourceMask = effectMask->mMaskTexture->AsSourceOGL();
+
+ // NS_ASSERTION(textureMask->IsAlpha(),
+ // "OpenGL mask layers must be backed by alpha surfaces");
+
+ // We're assuming that the gl backend won't cheat and use NPOT
+ // textures when glContext says it can't (which seems to happen
+ // on a mac when you force POT textures)
+ IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext);
+
+ const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform;
+ NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
+ Rect bounds = Rect(Point(), Size(maskSize));
+ bounds = maskTransform.As2D().TransformBounds(bounds);
+
+ maskQuadTransform._11 = 1.0f/bounds.width;
+ maskQuadTransform._22 = 1.0f/bounds.height;
+ maskQuadTransform._41 = float(-bounds.x)/bounds.width;
+ maskQuadTransform._42 = float(-bounds.y)/bounds.height;
+
+ maskType = MaskType::Mask;
+ } else {
+ maskType = MaskType::MaskNone;
+ }
+
+ // Determine the color if this is a color shader and fold the opacity into
+ // the color since color shaders don't have an opacity uniform.
+ Color color;
+ if (aEffectChain.mPrimaryEffect->mType == EffectTypes::SOLID_COLOR) {
+ EffectSolidColor* effectSolidColor =
+ static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
+ color = effectSolidColor->mColor;
+
+ Float opacity = aOpacity * color.a;
+ color.r *= opacity;
+ color.g *= opacity;
+ color.b *= opacity;
+ color.a = opacity;
+
+ // We can fold opacity into the color, so no need to consider it further.
+ aOpacity = 1.f;
+ }
+
+ bool createdMixBlendBackdropTexture = false;
+ GLuint mixBlendBackdrop = 0;
+ gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
+
+ if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
+ EffectBlendMode *blendEffect =
+ static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
+ blendMode = blendEffect->mBlendMode;
+ }
+
+ // Only apply DEAA to quads that have been transformed such that aliasing
+ // could be visible
+ bool bEnableAA = gfxPrefs::LayersDEAAEnabled() &&
+ !aTransform.Is2DIntegerTranslation();
+
+ bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
+ ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect,
+ maskType, blendMode, colorMatrix,
+ bEnableAA);
+
+ config.SetOpacity(aOpacity != 1.f);
+ ApplyPrimitiveConfig(config, aGeometry);
+
+ ShaderProgramOGL *program = GetShaderProgramFor(config);
+ ActivateProgram(program);
+ program->SetProjectionMatrix(mProjMatrix);
+ program->SetLayerTransform(aTransform);
+ LayerScope::SetLayerTransform(aTransform);
+
+ if (colorMatrix) {
+ EffectColorMatrix* effectColorMatrix =
+ static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
+ program->SetColorMatrix(effectColorMatrix->mColorMatrix);
+ }
+
+ if (BlendOpIsMixBlendMode(blendMode)) {
+ gfx::Matrix4x4 backdropTransform;
+
+ if (gl()->IsExtensionSupported(GLContext::NV_texture_barrier)) {
+ // The NV_texture_barrier extension lets us read directly from the
+ // backbuffer. Let's do that.
+ // We need to tell OpenGL about this, so that it can make sure everything
+ // on the GPU is happening in the right order.
+ gl()->fTextureBarrier();
+ mixBlendBackdrop = mCurrentRenderTarget->GetTextureHandle();
+ } else {
+ gfx::IntRect rect = ComputeBackdropCopyRect(aGeometry, aClipRect,
+ aTransform, &backdropTransform);
+ mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO());
+ createdMixBlendBackdropTexture = true;
+ }
+ program->SetBackdropTransform(backdropTransform);
+ }
+
+ program->SetRenderOffset(offset.x, offset.y);
+ LayerScope::SetRenderOffset(offset.x, offset.y);
+
+ if (aOpacity != 1.f)
+ program->SetLayerOpacity(aOpacity);
+
+ if (config.mFeatures & ENABLE_TEXTURE_RECT) {
+ TextureSourceOGL* source = nullptr;
+ if (aEffectChain.mPrimaryEffect->mType == EffectTypes::COMPONENT_ALPHA) {
+ EffectComponentAlpha* effectComponentAlpha =
+ static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
+ source = effectComponentAlpha->mOnWhite->AsSourceOGL();
+ } else {
+ TexturedEffect* texturedEffect =
+ static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
+ source = texturedEffect->mTexture->AsSourceOGL();
+ }
+ // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
+ program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
+ }
+
+ // XXX kip - These calculations could be performed once per layer rather than
+ // for every tile. This might belong in Compositor.cpp once DEAA
+ // is implemented for DirectX.
+ if (bEnableAA) {
+ // Calculate the transformed vertices of aVisibleRect in screen space
+ // pixels, mirroring the calculations in the vertex shader
+ Matrix4x4 flatTransform = aTransform;
+ flatTransform.PostTranslate(-offset.x, -offset.y, 0.0f);
+ flatTransform *= mProjMatrix;
+
+ Rect viewportClip = Rect(-1.0f, -1.0f, 2.0f, 2.0f);
+ size_t edgeCount = 0;
+ Point3D coefficients[4];
+
+ Point points[Matrix4x4::kTransformAndClipRectMaxVerts];
+ size_t pointCount = flatTransform.TransformAndClipRect(aVisibleRect, viewportClip, points);
+ for (size_t i = 0; i < pointCount; i++) {
+ points[i] = Point((points[i].x * 0.5f + 0.5f) * mViewportSize.width,
+ (points[i].y * 0.5f + 0.5f) * mViewportSize.height);
+ }
+ if (pointCount > 2) {
+ // Use shoelace formula on a triangle in the clipped quad to determine if
+ // winding order is reversed. Iterate through the triangles until one is
+ // found with a non-zero area.
+ float winding = 0.0f;
+ size_t wp = 0;
+ while (winding == 0.0f && wp < pointCount) {
+ int wp1 = (wp + 1) % pointCount;
+ int wp2 = (wp + 2) % pointCount;
+ winding = (points[wp1].x - points[wp].x) * (points[wp1].y + points[wp].y) +
+ (points[wp2].x - points[wp1].x) * (points[wp2].y + points[wp1].y) +
+ (points[wp].x - points[wp2].x) * (points[wp].y + points[wp2].y);
+ wp++;
+ }
+ bool frontFacing = winding >= 0.0f;
+
+ // Calculate the line coefficients used by the DEAA shader to determine the
+ // sub-pixel coverage of the edge pixels
+ for (size_t i=0; i<pointCount; i++) {
+ const Point& p1 = points[i];
+ const Point& p2 = points[(i + 1) % pointCount];
+ // Create a DEAA edge for any non-straight lines, to a maximum of 4
+ if (p1.x != p2.x && p1.y != p2.y && edgeCount < 4) {
+ if (frontFacing) {
+ coefficients[edgeCount++] = GetLineCoefficients(p2, p1);
+ } else {
+ coefficients[edgeCount++] = GetLineCoefficients(p1, p2);
+ }
+ }
+ }
+ }
+
+ // The coefficients that are not needed must not cull any fragments.
+ // We fill these unused coefficients with a clipping plane that has no
+ // effect.
+ for (size_t i = edgeCount; i < 4; i++) {
+ coefficients[i] = Point3D(0.0f, 1.0f, mViewportSize.height);
+ }
+
+ // Set uniforms required by DEAA shader
+ Matrix4x4 transformInverted = aTransform;
+ transformInverted.Invert();
+ program->SetLayerTransformInverse(transformInverted);
+ program->SetDEAAEdges(coefficients);
+ program->SetVisibleCenter(aVisibleRect.Center());
+ program->SetViewportSize(mViewportSize);
+ }
+
+ bool didSetBlendMode = false;
+
+ switch (aEffectChain.mPrimaryEffect->mType) {
+ case EffectTypes::SOLID_COLOR: {
+ program->SetRenderColor(color);
+
+ if (maskType != MaskType::MaskNone) {
+ BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
+ }
+ if (mixBlendBackdrop) {
+ BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE1);
+ }
+
+ didSetBlendMode = SetBlendMode(gl(), blendMode);
+
+ BindAndDrawGeometry(program, aGeometry);
+ }
+ break;
+
+ case EffectTypes::RGB: {
+ TexturedEffect* texturedEffect =
+ static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
+ TextureSource *source = texturedEffect->mTexture;
+
+ didSetBlendMode = SetBlendMode(gl(), blendMode, texturedEffect->mPremultiplied);
+
+ gfx::SamplingFilter samplingFilter = texturedEffect->mSamplingFilter;
+
+ source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, samplingFilter);
+
+ program->SetTextureUnit(0);
+
+ Matrix4x4 textureTransform = source->AsSourceOGL()->GetTextureTransform();
+ program->SetTextureTransform(textureTransform);
+
+ if (maskType != MaskType::MaskNone) {
+ BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
+ }
+ if (mixBlendBackdrop) {
+ BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
+ }
+
+ BindAndDrawGeometryWithTextureRect(program, aGeometry,
+ texturedEffect->mTextureCoords, source);
+ }
+ break;
+ case EffectTypes::YCBCR: {
+ EffectYCbCr* effectYCbCr =
+ static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
+ TextureSource* sourceYCbCr = effectYCbCr->mTexture;
+ const int Y = 0, Cb = 1, Cr = 2;
+ TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
+ TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
+ TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
+
+ if (!sourceY || !sourceCb || !sourceCr) {
+ NS_WARNING("Invalid layer texture.");
+ return;
+ }
+
+ sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mSamplingFilter);
+ sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mSamplingFilter);
+ sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mSamplingFilter);
+
+ program->SetYCbCrTextureUnits(Y, Cb, Cr);
+ program->SetTextureTransform(Matrix4x4());
+ program->SetYUVColorSpace(effectYCbCr->mYUVColorSpace);
+
+ if (maskType != MaskType::MaskNone) {
+ BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
+ }
+ if (mixBlendBackdrop) {
+ BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE4);
+ }
+ didSetBlendMode = SetBlendMode(gl(), blendMode);
+ BindAndDrawGeometryWithTextureRect(program,
+ aGeometry,
+ effectYCbCr->mTextureCoords,
+ sourceYCbCr->GetSubSource(Y));
+ }
+ break;
+ case EffectTypes::NV12: {
+ EffectNV12* effectNV12 =
+ static_cast<EffectNV12*>(aEffectChain.mPrimaryEffect.get());
+ TextureSource* sourceNV12 = effectNV12->mTexture;
+ const int Y = 0, CbCr = 1;
+ TextureSourceOGL* sourceY = sourceNV12->GetSubSource(Y)->AsSourceOGL();
+ TextureSourceOGL* sourceCbCr = sourceNV12->GetSubSource(CbCr)->AsSourceOGL();
+
+ if (!sourceY || !sourceCbCr) {
+ NS_WARNING("Invalid layer texture.");
+ return;
+ }
+
+ sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectNV12->mSamplingFilter);
+ sourceCbCr->BindTexture(LOCAL_GL_TEXTURE1, effectNV12->mSamplingFilter);
+
+ if (config.mFeatures & ENABLE_TEXTURE_RECT) {
+ // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
+ program->SetCbCrTexCoordMultiplier(sourceCbCr->GetSize().width, sourceCbCr->GetSize().height);
+ }
+
+ program->SetNV12TextureUnits(Y, CbCr);
+ program->SetTextureTransform(Matrix4x4());
+
+ if (maskType != MaskType::MaskNone) {
+ BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
+ }
+ if (mixBlendBackdrop) {
+ BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE3);
+ }
+ didSetBlendMode = SetBlendMode(gl(), blendMode);
+ BindAndDrawGeometryWithTextureRect(program,
+ aGeometry,
+ effectNV12->mTextureCoords,
+ sourceNV12->GetSubSource(Y));
+ }
+ break;
+ case EffectTypes::RENDER_TARGET: {
+ EffectRenderTarget* effectRenderTarget =
+ static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
+ RefPtr<CompositingRenderTargetOGL> surface
+ = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get());
+
+ surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
+
+ // Drawing is always flipped, but when copying between surfaces we want to avoid
+ // this, so apply a flip here to cancel the other one out.
+ Matrix transform;
+ transform.PreTranslate(0.0, 1.0);
+ transform.PreScale(1.0f, -1.0f);
+ program->SetTextureTransform(Matrix4x4::From2D(transform));
+ program->SetTextureUnit(0);
+
+ if (maskType != MaskType::MaskNone) {
+ BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
+ }
+ if (mixBlendBackdrop) {
+ BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
+ }
+
+ if (config.mFeatures & ENABLE_TEXTURE_RECT) {
+ // 2DRect case, get the multiplier right for a sampler2DRect
+ program->SetTexCoordMultiplier(surface->GetSize().width,
+ surface->GetSize().height);
+ }
+
+ // Drawing is always flipped, but when copying between surfaces we want to avoid
+ // this. Pass true for the flip parameter to introduce a second flip
+ // that cancels the other one out.
+ didSetBlendMode = SetBlendMode(gl(), blendMode);
+ BindAndDrawGeometry(program, aGeometry);
+ }
+ break;
+ case EffectTypes::COMPONENT_ALPHA: {
+ MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
+ MOZ_ASSERT(blendMode == gfx::CompositionOp::OP_OVER, "Can't support blend modes with component alpha!");
+ EffectComponentAlpha* effectComponentAlpha =
+ static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
+ TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL();
+ TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL();
+
+ if (!sourceOnBlack->IsValid() ||
+ !sourceOnWhite->IsValid()) {
+ NS_WARNING("Invalid layer texture for component alpha");
+ return;
+ }
+
+ sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mSamplingFilter);
+ sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mSamplingFilter);
+
+ program->SetBlackTextureUnit(0);
+ program->SetWhiteTextureUnit(1);
+ program->SetTextureTransform(Matrix4x4());
+
+ if (maskType != MaskType::MaskNone) {
+ BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
+ }
+ // Pass 1.
+ gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
+ LOCAL_GL_ONE, LOCAL_GL_ONE);
+ program->SetTexturePass2(false);
+ BindAndDrawGeometryWithTextureRect(program,
+ aGeometry,
+ effectComponentAlpha->mTextureCoords,
+ effectComponentAlpha->mOnBlack);
+
+ // Pass 2.
+ gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
+ LOCAL_GL_ONE, LOCAL_GL_ONE);
+ program->SetTexturePass2(true);
+ BindAndDrawGeometryWithTextureRect(program,
+ aGeometry,
+ effectComponentAlpha->mTextureCoords,
+ effectComponentAlpha->mOnBlack);
+
+ mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
+ LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
+ }
+ break;
+ default:
+ MOZ_ASSERT(false, "Unhandled effect type");
+ break;
+ }
+
+ if (didSetBlendMode) {
+ gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
+ LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
+ }
+ if (createdMixBlendBackdropTexture) {
+ gl()->fDeleteTextures(1, &mixBlendBackdrop);
+ }
+
+ // in case rendering has used some other GL context
+ MakeCurrent();
+
+ LayerScope::DrawEnd(mGLContext, aEffectChain,
+ aGeometry.width, aGeometry.height);
+}
+
+void
+CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram,
+ const gfx::Rect& aRect,
+ const gfx::Rect& aTextureRect)
+{
+ BindAndDrawQuad(aProgram, aRect, aTextureRect);
+}
+
+void
+CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram,
+ const gfx::TexturedTriangle& aTriangle,
+ const gfx::Rect& aTextureRect)
+{
+ NS_ASSERTION(aProgram->HasInitialized(), "Shader program not correctly initialized");
+
+ const gfx::TexturedTriangle& t = aTriangle;
+ const gfx::Triangle& tex = t.textureCoords;
+
+ GLfloat vertices[] = {
+ t.p1.x, t.p1.y, 0.0f, 1.0f, tex.p1.x, tex.p1.y,
+ t.p2.x, t.p2.y, 0.0f, 1.0f, tex.p2.x, tex.p2.y,
+ t.p3.x, t.p3.y, 0.0f, 1.0f, tex.p3.x, tex.p3.y
+ };
+
+ HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices);
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTriangleVBO);
+ mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
+ verticesOnHeap.ByteLength(),
+ verticesOnHeap.Data(),
+ LOCAL_GL_STREAM_DRAW);
+
+ const GLsizei stride = 6 * sizeof(GLfloat);
+ InitializeVAO(kCoordinateAttributeIndex, 4, stride, 0);
+ InitializeVAO(kTexCoordinateAttributeIndex, 2, stride, 4 * sizeof(GLfloat));
+
+ mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 3);
+
+ mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
+ mGLContext->fDisableVertexAttribArray(kTexCoordinateAttributeIndex);
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+}
+
+// |aRect| is the rectangle we want to draw to. We will draw it with
+// up to 4 draw commands if necessary to avoid wrapping.
+// |aTexCoordRect| is the rectangle from the texture that we want to
+// draw using the given program.
+// |aTexture| is the texture we are drawing. Its actual size can be
+// larger than the rectangle given by |texCoordRect|.
+void
+CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
+ const Rect& aRect,
+ const Rect& aTexCoordRect,
+ TextureSource *aTexture)
+{
+ Rect scaledTexCoordRect = GetTextureCoordinates(aTexCoordRect, aTexture);
+ Rect layerRects[4];
+ Rect textureRects[4];
+ size_t rects = DecomposeIntoNoRepeatRects(aRect,
+ scaledTexCoordRect,
+ &layerRects,
+ &textureRects);
+
+ BindAndDrawQuads(aProg, rects, layerRects, textureRects);
+}
+
+void
+CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
+ const gfx::TexturedTriangle& aTriangle,
+ const gfx::Rect& aTexCoordRect,
+ TextureSource *aTexture)
+{
+ BindAndDrawGeometry(aProg, aTriangle,
+ GetTextureCoordinates(aTexCoordRect, aTexture));
+}
+
+void
+CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg,
+ int aQuads,
+ const Rect* aLayerRects,
+ const Rect* aTextureRects)
+{
+ NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
+
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
+ InitializeVAO(kCoordinateAttributeIndex, 4, 0, 0);
+
+ aProg->SetLayerRects(aLayerRects);
+ if (aProg->GetTextureCount() > 0) {
+ aProg->SetTextureRects(aTextureRects);
+ }
+
+ // We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly
+ // process uniform arrays with GL_TRIANGLE_STRIP. Go figure.
+ mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads);
+ mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+ LayerScope::SetDrawRects(aQuads, aLayerRects, aTextureRects);
+}
+
+void
+CompositorOGL::InitializeVAO(const GLuint aAttrib, const GLint aComponents,
+ const GLsizei aStride, const size_t aOffset)
+{
+ mGLContext->fVertexAttribPointer(aAttrib, aComponents, LOCAL_GL_FLOAT,
+ LOCAL_GL_FALSE, aStride,
+ reinterpret_cast<GLvoid*>(aOffset));
+ mGLContext->fEnableVertexAttribArray(aAttrib);
+}
+
+void
+CompositorOGL::EndFrame()
+{
+ PROFILER_LABEL("CompositorOGL", "EndFrame",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
+
+#ifdef MOZ_DUMP_PAINTING
+ if (gfxEnv::DumpCompositorTextures()) {
+ LayoutDeviceIntSize size;
+ if (mUseExternalSurfaceSize) {
+ size = LayoutDeviceIntSize(mSurfaceSize.width, mSurfaceSize.height);
+ } else {
+ size = mWidget->GetClientSize();
+ }
+ RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8);
+ if (target) {
+ CopyToTarget(target, nsIntPoint(), Matrix());
+ WriteSnapshotToDumpFile(this, target);
+ }
+ }
+#endif
+
+ mContextStateTracker.PopOGLSection(gl(), "Frame");
+
+ mFrameInProgress = false;
+
+ if (mTarget) {
+ CopyToTarget(mTarget, mTargetBounds.TopLeft(), Matrix());
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+ mCurrentRenderTarget = nullptr;
+ Compositor::EndFrame();
+ return;
+ }
+
+ mCurrentRenderTarget = nullptr;
+
+ if (mTexturePool) {
+ mTexturePool->EndFrame();
+ }
+
+ mGLContext->SwapBuffers();
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+
+ // Unbind all textures
+ for (GLuint i = 0; i <= 4; i++) {
+ mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+ mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
+ if (!mGLContext->IsGLES()) {
+ mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
+ }
+ }
+
+ Compositor::EndFrame();
+}
+
+void
+CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
+{
+ MOZ_ASSERT(!mTarget);
+ if (mTexturePool) {
+ mTexturePool->EndFrame();
+ }
+}
+
+void
+CompositorOGL::SetDestinationSurfaceSize(const IntSize& aSize)
+{
+ mSurfaceSize.width = aSize.width;
+ mSurfaceSize.height = aSize.height;
+}
+
+void
+CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aTransform)
+{
+ MOZ_ASSERT(aTarget);
+ IntRect rect;
+ if (mUseExternalSurfaceSize) {
+ rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
+ } else {
+ rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height);
+ }
+ GLint width = rect.width;
+ GLint height = rect.height;
+
+ if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) {
+ NS_ERROR("Widget size too big - integer overflow!");
+ return;
+ }
+
+ mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+
+ if (!mGLContext->IsGLES()) {
+ // GLES2 promises that binding to any custom FBO will attach
+ // to GL_COLOR_ATTACHMENT0 attachment point.
+ mGLContext->fReadBuffer(LOCAL_GL_BACK);
+ }
+
+ RefPtr<DataSourceSurface> source =
+ Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
+ if (NS_WARN_IF(!source)) {
+ return;
+ }
+
+ ReadPixelsIntoDataSurface(mGLContext, source);
+
+ // Map from GL space to Cairo space and reverse the world transform.
+ Matrix glToCairoTransform = aTransform;
+ glToCairoTransform.Invert();
+ glToCairoTransform.PreScale(1.0, -1.0);
+ glToCairoTransform.PreTranslate(0.0, -height);
+
+ glToCairoTransform.PostTranslate(-aTopLeft.x, -aTopLeft.y);
+
+ Matrix oldMatrix = aTarget->GetTransform();
+ aTarget->SetTransform(glToCairoTransform);
+ Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
+ aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
+ aTarget->SetTransform(oldMatrix);
+ aTarget->Flush();
+}
+
+void
+CompositorOGL::Pause()
+{
+#ifdef MOZ_WIDGET_ANDROID
+ if (!gl() || gl()->IsDestroyed())
+ return;
+
+ // ReleaseSurface internally calls MakeCurrent.
+ gl()->ReleaseSurface();
+#endif
+}
+
+bool
+CompositorOGL::Resume()
+{
+#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
+ if (!gl() || gl()->IsDestroyed())
+ return false;
+
+ // RenewSurface internally calls MakeCurrent.
+ return gl()->RenewSurface(GetWidget()->RealWidget());
+#endif
+ return true;
+}
+
+already_AddRefed<DataTextureSource>
+CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
+{
+ return MakeAndAddRef<TextureImageTextureSourceOGL>(this, aFlags);
+}
+
+bool
+CompositorOGL::SupportsPartialTextureUpdate()
+{
+ return CanUploadSubTextures(mGLContext);
+}
+
+int32_t
+CompositorOGL::GetMaxTextureSize() const
+{
+ MOZ_ASSERT(mGLContext);
+ GLint texSize = 0;
+ mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
+ &texSize);
+ MOZ_ASSERT(texSize != 0);
+ return texSize;
+}
+
+void
+CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
+ if (mDestroyed) {
+ NS_WARNING("Call on destroyed layer manager");
+ return;
+ }
+ mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
+}
+
+GLBlitTextureImageHelper*
+CompositorOGL::BlitTextureImageHelper()
+{
+ if (!mBlitTextureImageHelper) {
+ mBlitTextureImageHelper = MakeUnique<GLBlitTextureImageHelper>(this);
+ }
+
+ return mBlitTextureImageHelper.get();
+}
+
+
+
+GLuint
+CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
+{
+ if (!mTexturePool) {
+ mTexturePool = new PerUnitTexturePoolOGL(gl());
+ }
+ return mTexturePool->GetTexture(aTarget, aUnit);
+}
+
+GLuint
+PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit)
+{
+ if (mTextureTarget == 0) {
+ mTextureTarget = aTarget;
+ }
+ MOZ_ASSERT(mTextureTarget == aTarget);
+
+ size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
+ // lazily grow the array of temporary textures
+ if (mTextures.Length() <= index) {
+ size_t prevLength = mTextures.Length();
+ mTextures.SetLength(index + 1);
+ for(unsigned int i = prevLength; i <= index; ++i) {
+ mTextures[i] = 0;
+ }
+ }
+ // lazily initialize the temporary textures
+ if (!mTextures[index]) {
+ if (!mGL->MakeCurrent()) {
+ return 0;
+ }
+ mGL->fGenTextures(1, &mTextures[index]);
+ mGL->fBindTexture(aTarget, mTextures[index]);
+ mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+ mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+ }
+ return mTextures[index];
+}
+
+void
+PerUnitTexturePoolOGL::DestroyTextures()
+{
+ if (mGL && mGL->MakeCurrent()) {
+ if (mTextures.Length() > 0) {
+ mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
+ }
+ }
+ mTextures.SetLength(0);
+}
+
+void
+PerFrameTexturePoolOGL::DestroyTextures()
+{
+ if (!mGL->MakeCurrent()) {
+ return;
+ }
+
+ if (mUnusedTextures.Length() > 0) {
+ mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]);
+ mUnusedTextures.Clear();
+ }
+
+ if (mCreatedTextures.Length() > 0) {
+ mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]);
+ mCreatedTextures.Clear();
+ }
+}
+
+GLuint
+PerFrameTexturePoolOGL::GetTexture(GLenum aTarget, GLenum)
+{
+ if (mTextureTarget == 0) {
+ mTextureTarget = aTarget;
+ }
+
+ // The pool should always use the same texture target because it is illegal
+ // to change the target of an already exisiting gl texture.
+ // If we need to use several targets, a pool with several sub-pools (one per
+ // target) will have to be implemented.
+ // At the moment this pool is only used with tiling on b2g so we always need
+ // the same target.
+ MOZ_ASSERT(mTextureTarget == aTarget);
+
+ GLuint texture = 0;
+
+ if (!mUnusedTextures.IsEmpty()) {
+ // Try to reuse one from the unused pile first
+ texture = mUnusedTextures[0];
+ mUnusedTextures.RemoveElementAt(0);
+ } else if (mGL->MakeCurrent()) {
+ // There isn't one to reuse, create one.
+ mGL->fGenTextures(1, &texture);
+ mGL->fBindTexture(aTarget, texture);
+ mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+ mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+ }
+
+ if (texture) {
+ mCreatedTextures.AppendElement(texture);
+ }
+
+ return texture;
+}
+
+void
+PerFrameTexturePoolOGL::EndFrame()
+{
+ if (!mGL->MakeCurrent()) {
+ // this means the context got destroyed underneith us somehow, and the driver
+ // already has destroyed the textures.
+ mCreatedTextures.Clear();
+ mUnusedTextures.Clear();
+ return;
+ }
+
+ // Some platforms have issues unlocking Gralloc buffers even when they're
+ // rebound.
+ if (gfxPrefs::OverzealousGrallocUnlocking()) {
+ mUnusedTextures.AppendElements(mCreatedTextures);
+ mCreatedTextures.Clear();
+ }
+
+ // Delete unused textures
+ for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
+ GLuint texture = mUnusedTextures[i];
+ mGL->fDeleteTextures(1, &texture);
+ }
+ mUnusedTextures.Clear();
+
+ // Move all created textures into the unused pile
+ mUnusedTextures.AppendElements(mCreatedTextures);
+ mCreatedTextures.Clear();
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h
new file mode 100644
index 000000000..da204b12e
--- /dev/null
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -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 */
diff --git a/gfx/layers/opengl/EGLImageHelpers.cpp b/gfx/layers/opengl/EGLImageHelpers.cpp
new file mode 100644
index 000000000..4a720302f
--- /dev/null
+++ b/gfx/layers/opengl/EGLImageHelpers.cpp
@@ -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
diff --git a/gfx/layers/opengl/EGLImageHelpers.h b/gfx/layers/opengl/EGLImageHelpers.h
new file mode 100644
index 000000000..3e03a499c
--- /dev/null
+++ b/gfx/layers/opengl/EGLImageHelpers.h
@@ -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_
diff --git a/gfx/layers/opengl/GLBlitTextureImageHelper.cpp b/gfx/layers/opengl/GLBlitTextureImageHelper.cpp
new file mode 100644
index 000000000..8c6ac1703
--- /dev/null
+++ b/gfx/layers/opengl/GLBlitTextureImageHelper.cpp
@@ -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
diff --git a/gfx/layers/opengl/GLBlitTextureImageHelper.h b/gfx/layers/opengl/GLBlitTextureImageHelper.h
new file mode 100644
index 000000000..91cb1bf85
--- /dev/null
+++ b/gfx/layers/opengl/GLBlitTextureImageHelper.h
@@ -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_
diff --git a/gfx/layers/opengl/GLManager.cpp b/gfx/layers/opengl/GLManager.cpp
new file mode 100644
index 000000000..e4c0b361f
--- /dev/null
+++ b/gfx/layers/opengl/GLManager.cpp
@@ -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
diff --git a/gfx/layers/opengl/GLManager.h b/gfx/layers/opengl/GLManager.h
new file mode 100644
index 000000000..7c872758e
--- /dev/null
+++ b/gfx/layers/opengl/GLManager.h
@@ -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
diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp
new file mode 100644
index 000000000..dd522e650
--- /dev/null
+++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp
@@ -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
diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h
new file mode 100644
index 000000000..21e445953
--- /dev/null
+++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h
@@ -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
diff --git a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
new file mode 100644
index 000000000..05f8cf38f
--- /dev/null
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -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
diff --git a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
new file mode 100644
index 000000000..55e2f5019
--- /dev/null
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
@@ -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
diff --git a/gfx/layers/opengl/OGLShaderProgram.cpp b/gfx/layers/opengl/OGLShaderProgram.cpp
new file mode 100644
index 000000000..c06dc52dd
--- /dev/null
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -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
diff --git a/gfx/layers/opengl/OGLShaderProgram.h b/gfx/layers/opengl/OGLShaderProgram.h
new file mode 100644
index 000000000..ff4fb825f
--- /dev/null
+++ b/gfx/layers/opengl/OGLShaderProgram.h
@@ -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 */
diff --git a/gfx/layers/opengl/TextureClientOGL.cpp b/gfx/layers/opengl/TextureClientOGL.cpp
new file mode 100644
index 000000000..78d4e6d9c
--- /dev/null
+++ b/gfx/layers/opengl/TextureClientOGL.cpp
@@ -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
diff --git a/gfx/layers/opengl/TextureClientOGL.h b/gfx/layers/opengl/TextureClientOGL.h
new file mode 100644
index 000000000..6555f138a
--- /dev/null
+++ b/gfx/layers/opengl/TextureClientOGL.h
@@ -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
diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp
new file mode 100644
index 000000000..854160bc6
--- /dev/null
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -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
diff --git a/gfx/layers/opengl/TextureHostOGL.h b/gfx/layers/opengl/TextureHostOGL.h
new file mode 100644
index 000000000..dd425e768
--- /dev/null
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -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 */
diff --git a/gfx/layers/opengl/TexturePoolOGL.cpp b/gfx/layers/opengl/TexturePoolOGL.cpp
new file mode 100644
index 000000000..8ee3b4cbb
--- /dev/null
+++ b/gfx/layers/opengl/TexturePoolOGL.cpp
@@ -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
diff --git a/gfx/layers/opengl/TexturePoolOGL.h b/gfx/layers/opengl/TexturePoolOGL.h
new file mode 100644
index 000000000..136364e8c
--- /dev/null
+++ b/gfx/layers/opengl/TexturePoolOGL.h
@@ -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
diff --git a/gfx/layers/opengl/X11TextureSourceOGL.cpp b/gfx/layers/opengl/X11TextureSourceOGL.cpp
new file mode 100644
index 000000000..dbed66b61
--- /dev/null
+++ b/gfx/layers/opengl/X11TextureSourceOGL.cpp
@@ -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
diff --git a/gfx/layers/opengl/X11TextureSourceOGL.h b/gfx/layers/opengl/X11TextureSourceOGL.h
new file mode 100644
index 000000000..505847403
--- /dev/null
+++ b/gfx/layers/opengl/X11TextureSourceOGL.h
@@ -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