gfx/layers/opengl/CompositorOGL.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "CompositorOGL.h"
     7 #include <stddef.h>                     // for size_t
     8 #include <stdint.h>                     // for uint32_t, uint8_t
     9 #include <stdlib.h>                     // for free, malloc
    10 #include "GLContextProvider.h"          // for GLContextProvider
    11 #include "GLContext.h"                  // for GLContext
    12 #include "GLUploadHelpers.h"
    13 #include "Layers.h"                     // for WriteSnapshotToDumpFile
    14 #include "LayerScope.h"                 // for LayerScope
    15 #include "gfx2DGlue.h"                  // for ThebesFilter
    16 #include "gfx3DMatrix.h"                // for gfx3DMatrix
    17 #include "gfxCrashReporterUtils.h"      // for ScopedGfxFeatureReporter
    18 #include "gfxImageSurface.h"            // for gfxImageSurface
    19 #include "gfxMatrix.h"                  // for gfxMatrix
    20 #include "GraphicsFilter.h"             // for GraphicsFilter
    21 #include "gfxPlatform.h"                // for gfxPlatform
    22 #include "gfxPrefs.h"                   // for gfxPrefs
    23 #include "gfxRect.h"                    // for gfxRect
    24 #include "gfxUtils.h"                   // for NextPowerOfTwo, gfxUtils, etc
    25 #include "mozilla/ArrayUtils.h"         // for ArrayLength
    26 #include "mozilla/Preferences.h"        // for Preferences
    27 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
    28 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4, Matrix
    29 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite, etc
    30 #include "mozilla/layers/CompositingRenderTargetOGL.h"
    31 #include "mozilla/layers/Effects.h"     // for EffectChain, TexturedEffect, etc
    32 #include "mozilla/layers/TextureHost.h"  // for TextureSource, etc
    33 #include "mozilla/layers/TextureHostOGL.h"  // for TextureSourceOGL, etc
    34 #include "mozilla/mozalloc.h"           // for operator delete, etc
    35 #include "nsAString.h"
    36 #include "nsIConsoleService.h"          // for nsIConsoleService, etc
    37 #include "nsIWidget.h"                  // for nsIWidget
    38 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
    39 #include "nsMathUtils.h"                // for NS_roundf
    40 #include "nsRect.h"                     // for nsIntRect
    41 #include "nsServiceManagerUtils.h"      // for do_GetService
    42 #include "nsString.h"                   // for nsString, nsAutoCString, etc
    43 #include "DecomposeIntoNoRepeatTriangles.h"
    44 #include "ScopedGLHelpers.h"
    45 #include "GLReadTexImageHelper.h"
    46 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
    48 #if MOZ_ANDROID_OMTC
    49 #include "TexturePoolOGL.h"
    50 #endif
    52 #ifdef XP_MACOSX
    53 #include "nsCocoaFeatures.h"
    54 #endif
    56 #include "GeckoProfiler.h"
    58 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
    59 #include "libdisplay/GonkDisplay.h"     // for GonkDisplay
    60 #include <ui/Fence.h>
    61 #endif
    63 #define BUFFER_OFFSET(i) ((char *)nullptr + (i))
    65 namespace mozilla {
    67 using namespace std;
    68 using namespace gfx;
    70 namespace layers {
    72 using namespace mozilla::gl;
    74 static inline IntSize ns2gfxSize(const nsIntSize& s) {
    75   return IntSize(s.width, s.height);
    76 }
    78 static void
    79 BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
    80                    GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
    81 {
    82   MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
    83   aSourceMask->BindTexture(aTexUnit, gfx::Filter::LINEAR);
    84   aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
    85   aProgram->SetMaskLayerTransform(aTransform);
    86 }
    88 // Draw the given quads with the already selected shader. Texture coordinates
    89 // are supplied if the shader requires them.
    90 static void
    91 DrawQuads(GLContext *aGLContext,
    92           VBOArena &aVBOs,
    93           ShaderProgramOGL *aProg,
    94           GLenum aMode,
    95           RectTriangles &aRects)
    96 {
    97   NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
    98   GLuint vertAttribIndex =
    99     aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
   100   GLuint texCoordAttribIndex =
   101     aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
   102   bool texCoords = (texCoordAttribIndex != GLuint(-1));
   104   GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat);
   106   GLsizei total = bytes;
   107   if (texCoords) {
   108     total *= 2;
   109   }
   111   aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER,
   112                           aVBOs.Allocate(aGLContext));
   113   aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
   114                           total,
   115                           nullptr,
   116                           LOCAL_GL_STREAM_DRAW);
   118   aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
   119                              0,
   120                              bytes,
   121                              aRects.vertCoords().Elements());
   122   aGLContext->fEnableVertexAttribArray(vertAttribIndex);
   123   aGLContext->fVertexAttribPointer(vertAttribIndex,
   124                                    2, LOCAL_GL_FLOAT,
   125                                    LOCAL_GL_FALSE,
   126                                    0, BUFFER_OFFSET(0));
   128   if (texCoords) {
   129     aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
   130                                bytes,
   131                                bytes,
   132                                aRects.texCoords().Elements());
   133     aGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
   134     aGLContext->fVertexAttribPointer(texCoordAttribIndex,
   135                                      2, LOCAL_GL_FLOAT,
   136                                      LOCAL_GL_FALSE,
   137                                      0, BUFFER_OFFSET(bytes));
   138   } else {
   139     aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
   140   }
   142   aGLContext->fDrawArrays(aMode, 0, aRects.elements());
   144   aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
   145 }
   147 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
   148                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
   149   : mWidget(aWidget)
   150   , mWidgetSize(-1, -1)
   151   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   152   , mHasBGRA(0)
   153   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   154   , mFrameInProgress(false)
   155   , mDestroyed(false)
   156   , mHeight(0)
   157 {
   158   MOZ_COUNT_CTOR(CompositorOGL);
   159   SetBackend(LayersBackend::LAYERS_OPENGL);
   160 }
   162 CompositorOGL::~CompositorOGL()
   163 {
   164   MOZ_COUNT_DTOR(CompositorOGL);
   165   Destroy();
   166 }
   168 already_AddRefed<mozilla::gl::GLContext>
   169 CompositorOGL::CreateContext()
   170 {
   171   nsRefPtr<GLContext> context;
   173 #ifdef XP_WIN
   174   if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) {
   175     printf_stderr("Trying GL layers...\n");
   176     context = gl::GLContextProviderEGL::CreateForWindow(mWidget);
   177   }
   178 #endif
   180   if (!context)
   181     context = gl::GLContextProvider::CreateForWindow(mWidget);
   183   if (!context) {
   184     NS_WARNING("Failed to create CompositorOGL context");
   185   }
   187   return context.forget();
   188 }
   190 void
   191 CompositorOGL::Destroy()
   192 {
   193   if (gl() && gl()->MakeCurrent()) {
   194     mVBOs.Flush(gl());
   195   }
   197   if (mTexturePool) {
   198     mTexturePool->Clear();
   199     mTexturePool = nullptr;
   200   }
   202   if (!mDestroyed) {
   203     mDestroyed = true;
   204     CleanupResources();
   205   }
   206 }
   208 void
   209 CompositorOGL::CleanupResources()
   210 {
   211   if (!mGLContext)
   212     return;
   214   nsRefPtr<GLContext> ctx = mGLContext->GetSharedContext();
   215   if (!ctx) {
   216     ctx = mGLContext;
   217   }
   219   for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin();
   220        iter != mPrograms.end();
   221        iter++) {
   222     delete iter->second;
   223   }
   224   mPrograms.clear();
   226   if (!ctx->MakeCurrent()) {
   227     mQuadVBO = 0;
   228     mGLContext = nullptr;
   229     return;
   230   }
   232   ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
   234   if (mQuadVBO) {
   235     ctx->fDeleteBuffers(1, &mQuadVBO);
   236     mQuadVBO = 0;
   237   }
   239   mGLContext = nullptr;
   240 }
   242 bool
   243 CompositorOGL::Initialize()
   244 {
   245   ScopedGfxFeatureReporter reporter("GL Layers", true);
   247   // Do not allow double initialization
   248   NS_ABORT_IF_FALSE(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
   250   mGLContext = CreateContext();
   252 #ifdef MOZ_WIDGET_ANDROID
   253   if (!mGLContext)
   254     NS_RUNTIMEABORT("We need a context on Android");
   255 #endif
   257   if (!mGLContext)
   258     return false;
   260   MakeCurrent();
   262   mHasBGRA =
   263     mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
   264     mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
   266   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
   267                                  LOCAL_GL_ONE, LOCAL_GL_ONE);
   268   mGLContext->fEnable(LOCAL_GL_BLEND);
   270   // initialise a common shader to check that we can actually compile a shader
   271   RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0));
   272   ShaderConfigOGL config = GetShaderConfigFor(effect);
   273   if (!GetShaderProgramFor(config)) {
   274     return false;
   275   }
   277   if (mGLContext->WorkAroundDriverBugs()) {
   278     /**
   279     * We'll test the ability here to bind NPOT textures to a framebuffer, if
   280     * this fails we'll try ARB_texture_rectangle.
   281     */
   283     GLenum textureTargets[] = {
   284       LOCAL_GL_TEXTURE_2D,
   285       LOCAL_GL_NONE
   286     };
   288     if (!mGLContext->IsGLES()) {
   289       // No TEXTURE_RECTANGLE_ARB available on ES2
   290       textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
   291     }
   293     mFBOTextureTarget = LOCAL_GL_NONE;
   295     GLuint testFBO = 0;
   296     mGLContext->fGenFramebuffers(1, &testFBO);
   297     GLuint testTexture = 0;
   299     for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) {
   300       GLenum target = textureTargets[i];
   301       if (!target)
   302           continue;
   304       mGLContext->fGenTextures(1, &testTexture);
   305       mGLContext->fBindTexture(target, testTexture);
   306       mGLContext->fTexParameteri(target,
   307                                 LOCAL_GL_TEXTURE_MIN_FILTER,
   308                                 LOCAL_GL_NEAREST);
   309       mGLContext->fTexParameteri(target,
   310                                 LOCAL_GL_TEXTURE_MAG_FILTER,
   311                                 LOCAL_GL_NEAREST);
   312       mGLContext->fTexImage2D(target,
   313                               0,
   314                               LOCAL_GL_RGBA,
   315                               5, 3, /* sufficiently NPOT */
   316                               0,
   317                               LOCAL_GL_RGBA,
   318                               LOCAL_GL_UNSIGNED_BYTE,
   319                               nullptr);
   321       // unbind this texture, in preparation for binding it to the FBO
   322       mGLContext->fBindTexture(target, 0);
   324       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO);
   325       mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
   326                                         LOCAL_GL_COLOR_ATTACHMENT0,
   327                                         target,
   328                                         testTexture,
   329                                         0);
   331       if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
   332           LOCAL_GL_FRAMEBUFFER_COMPLETE)
   333       {
   334         mFBOTextureTarget = target;
   335         mGLContext->fDeleteTextures(1, &testTexture);
   336         break;
   337       }
   339       mGLContext->fDeleteTextures(1, &testTexture);
   340     }
   342     if (testFBO) {
   343       mGLContext->fDeleteFramebuffers(1, &testFBO);
   344     }
   346     if (mFBOTextureTarget == LOCAL_GL_NONE) {
   347       /* Unable to find a texture target that works with FBOs and NPOT textures */
   348       return false;
   349     }
   350   } else {
   351     // not trying to work around driver bugs, so TEXTURE_2D should just work
   352     mFBOTextureTarget = LOCAL_GL_TEXTURE_2D;
   353   }
   355   // back to default framebuffer, to avoid confusion
   356   mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
   358   if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
   359     /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
   360      * extension -- the EXT variant does not provide support for
   361      * texture rectangle access inside GLSL (sampler2DRect,
   362      * texture2DRect).
   363      */
   364     if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle))
   365       return false;
   366   }
   368   /* Create a simple quad VBO */
   370   mGLContext->fGenBuffers(1, &mQuadVBO);
   371   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
   373   GLfloat vertices[] = {
   374     /* First quad vertices */
   375     0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
   376     /* Then quad texcoords */
   377     0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
   378   };
   379   mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
   380   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
   382   nsCOMPtr<nsIConsoleService>
   383     console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   385   if (console) {
   386     nsString msg;
   387     msg +=
   388       NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: ");
   389     msg += NS_ConvertUTF8toUTF16(
   390       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
   391     msg += NS_LITERAL_STRING("\nVendor: ");
   392     msg += NS_ConvertUTF8toUTF16(
   393       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
   394     msg += NS_LITERAL_STRING("\nRenderer: ");
   395     msg += NS_ConvertUTF8toUTF16(
   396       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
   397     msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
   398     if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
   399       msg += NS_LITERAL_STRING("TEXTURE_2D");
   400     else
   401       msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
   402     console->LogStringMessage(msg.get());
   403   }
   405   reporter.SetSuccessful();
   406   return true;
   407 }
   409 // |aTextureTransform| is the texture transform that will be set on
   410 // aProg, possibly multiplied with another texture transform of our
   411 // own.
   412 // |aTexCoordRect| is the rectangle from the texture that we want to
   413 // draw using the given program.  The program already has a necessary
   414 // offset and scale, so the geometry that needs to be drawn is a unit
   415 // square from 0,0 to 1,1.
   416 //
   417 // |aTexture| is the texture we are drawing. Its actual size can be
   418 // larger than the rectangle given by |aTexCoordRect|.
   419 void
   420 CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
   421                                               const gfx3DMatrix& aTextureTransform,
   422                                               const Rect& aTexCoordRect,
   423                                               TextureSource *aTexture)
   424 {
   425   // Given what we know about these textures and coordinates, we can
   426   // compute fmod(t, 1.0f) to get the same texture coordinate out.  If
   427   // the texCoordRect dimension is < 0 or > width/height, then we have
   428   // wraparound that we need to deal with by drawing multiple quads,
   429   // because we can't rely on full non-power-of-two texture support
   430   // (which is required for the REPEAT wrap mode).
   432   RectTriangles rects;
   434   GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode();
   436   IntSize realTexSize = aTexture->GetSize();
   437   if (!CanUploadNonPowerOfTwo(mGLContext)) {
   438     realTexSize = IntSize(NextPowerOfTwo(realTexSize.width),
   439                           NextPowerOfTwo(realTexSize.height));
   440   }
   442   // We need to convert back to actual texels here to get proper behaviour with
   443   // our GL helper functions. Should fix this sometime.
   444   // I want to vomit.
   445   IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width),
   446                                  NS_roundf(aTexCoordRect.y * aTexture->GetSize().height),
   447                                  NS_roundf(aTexCoordRect.width * aTexture->GetSize().width),
   448                                  NS_roundf(aTexCoordRect.height * aTexture->GetSize().height));
   450   // This is fairly disgusting - if the texture should be flipped it will have a
   451   // negative height, in which case we un-invert the texture coords and pass the
   452   // flipped 'flag' to the functions below. We can't just use the inverted coords
   453   // because our GL funtions use an explicit flag.
   454   bool flipped = false;
   455   if (texCoordRect.height < 0) {
   456     flipped = true;
   457     texCoordRect.y = texCoordRect.YMost();
   458     texCoordRect.height = -texCoordRect.height;
   459   }
   461   if (wrapMode == LOCAL_GL_REPEAT) {
   462     rects.addRect(/* dest rectangle */
   463                   0.0f, 0.0f, 1.0f, 1.0f,
   464                   /* tex coords */
   465                   texCoordRect.x / GLfloat(realTexSize.width),
   466                   texCoordRect.y / GLfloat(realTexSize.height),
   467                   texCoordRect.XMost() / GLfloat(realTexSize.width),
   468                   texCoordRect.YMost() / GLfloat(realTexSize.height),
   469                   flipped);
   470   } else {
   471     nsIntRect tcRect(texCoordRect.x, texCoordRect.y,
   472                      texCoordRect.width, texCoordRect.height);
   473     DecomposeIntoNoRepeatTriangles(tcRect,
   474                                    nsIntSize(realTexSize.width, realTexSize.height),
   475                                    rects, flipped);
   476   }
   478   gfx3DMatrix textureTransform;
   479   if (rects.isSimpleQuad(textureTransform)) {
   480     Matrix4x4 transform;
   481     ToMatrix4x4(aTextureTransform * textureTransform, transform);
   482     aProg->SetTextureTransform(transform);
   483     BindAndDrawQuad(aProg);
   484   } else {
   485     Matrix4x4 transform;
   486     ToMatrix4x4(aTextureTransform, transform);
   487     aProg->SetTextureTransform(transform);
   488     DrawQuads(mGLContext, mVBOs, aProg, LOCAL_GL_TRIANGLES, rects);
   489   }
   490 }
   492 void
   493 CompositorOGL::PrepareViewport(const gfx::IntSize& aSize,
   494                                const Matrix& aWorldTransform)
   495 {
   496   // Set the viewport correctly.
   497   mGLContext->fViewport(0, 0, aSize.width, aSize.height);
   499   mHeight = aSize.height;
   501   // We flip the view matrix around so that everything is right-side up; we're
   502   // drawing directly into the window's back buffer, so this keeps things
   503   // looking correct.
   504   // XXX: We keep track of whether the window size changed, so we could skip
   505   // this update if it hadn't changed since the last call. We will need to
   506   // track changes to aTransformPolicy and aWorldTransform for this to work
   507   // though.
   509   // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
   510   // 2, 2) and flip the contents.
   511   Matrix viewMatrix;
   512   viewMatrix.Translate(-1.0, 1.0);
   513   viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
   514   viewMatrix.Scale(1.0f, -1.0f);
   515   if (!mTarget) {
   516     viewMatrix.Translate(mRenderOffset.x, mRenderOffset.y);
   517   }
   519   viewMatrix = aWorldTransform * viewMatrix;
   521   Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
   522   matrix3d._33 = 0.0f;
   524   mProjMatrix = matrix3d;
   525 }
   527 TemporaryRef<CompositingRenderTarget>
   528 CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit)
   529 {
   530   GLuint tex = 0;
   531   GLuint fbo = 0;
   532   CreateFBOWithTexture(aRect, false, 0, &fbo, &tex);
   533   RefPtr<CompositingRenderTargetOGL> surface
   534     = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
   535   surface->Initialize(aRect.Size(), mFBOTextureTarget, aInit);
   536   return surface.forget();
   537 }
   539 TemporaryRef<CompositingRenderTarget>
   540 CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect,
   541                                             const CompositingRenderTarget *aSource,
   542                                             const IntPoint &aSourcePoint)
   543 {
   544   GLuint tex = 0;
   545   GLuint fbo = 0;
   546   const CompositingRenderTargetOGL* sourceSurface
   547     = static_cast<const CompositingRenderTargetOGL*>(aSource);
   548   IntRect sourceRect(aSourcePoint, aRect.Size());
   549   if (aSource) {
   550     CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(),
   551                          &fbo, &tex);
   552   } else {
   553     CreateFBOWithTexture(sourceRect, true, 0,
   554                          &fbo, &tex);
   555   }
   557   RefPtr<CompositingRenderTargetOGL> surface
   558     = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
   559   surface->Initialize(aRect.Size(),
   560                       mFBOTextureTarget,
   561                       INIT_MODE_NONE);
   562   return surface.forget();
   563 }
   565 void
   566 CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface)
   567 {
   568   MOZ_ASSERT(aSurface);
   569   CompositingRenderTargetOGL* surface
   570     = static_cast<CompositingRenderTargetOGL*>(aSurface);
   571   if (mCurrentRenderTarget != surface) {
   572     surface->BindRenderTarget();
   573     mCurrentRenderTarget = surface;
   574   }
   575 }
   577 CompositingRenderTarget*
   578 CompositorOGL::GetCurrentRenderTarget() const
   579 {
   580   return mCurrentRenderTarget;
   581 }
   583 static GLenum
   584 GetFrameBufferInternalFormat(GLContext* gl,
   585                              GLuint aFrameBuffer,
   586                              nsIWidget* aWidget)
   587 {
   588   if (aFrameBuffer == 0) { // default framebuffer
   589     return aWidget->GetGLFrameBufferFormat();
   590   }
   591   return LOCAL_GL_RGBA;
   592 }
   594 /*
   595  * Returns a size that is larger than and closest to aSize where both
   596  * width and height are powers of two.
   597  * If the OpenGL setup is capable of using non-POT textures, then it
   598  * will just return aSize.
   599  */
   600 static IntSize
   601 CalculatePOTSize(const IntSize& aSize, GLContext* gl)
   602 {
   603   if (CanUploadNonPowerOfTwo(gl))
   604     return aSize;
   606   return IntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height));
   607 }
   609 void
   610 CompositorOGL::ClearRect(const gfx::Rect& aRect)
   611 {
   612   // Map aRect to OGL coordinates, origin:bottom-left
   613   GLint y = mHeight - (aRect.y + aRect.height);
   615   ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
   616   ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height);
   617   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   618   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
   619 }
   621 void
   622 CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
   623                           const Rect *aClipRectIn,
   624                           const gfx::Matrix& aTransform,
   625                           const Rect& aRenderBounds,
   626                           Rect *aClipRectOut,
   627                           Rect *aRenderBoundsOut)
   628 {
   629   PROFILER_LABEL("CompositorOGL", "BeginFrame");
   630   MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
   632   LayerScope::BeginFrame(mGLContext, PR_Now());
   634   mVBOs.Reset();
   636   mFrameInProgress = true;
   637   gfx::Rect rect;
   638   if (mUseExternalSurfaceSize) {
   639     rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
   640   } else {
   641     rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
   642     // If render bounds is not updated explicitly, try to infer it from widget
   643     if (rect.width == 0 || rect.height == 0) {
   644       // FIXME/bug XXXXXX this races with rotation changes on the main
   645       // thread, and undoes all the care we take with layers txns being
   646       // sent atomically with rotation changes
   647       nsIntRect intRect;
   648       mWidget->GetClientBounds(intRect);
   649       rect = gfx::Rect(0, 0, intRect.width, intRect.height);
   650     }
   651   }
   653   rect = aTransform.TransformBounds(rect);
   654   if (aRenderBoundsOut) {
   655     *aRenderBoundsOut = rect;
   656   }
   658   GLint width = rect.width;
   659   GLint height = rect.height;
   661   // We can't draw anything to something with no area
   662   // so just return
   663   if (width == 0 || height == 0)
   664     return;
   666   // If the widget size changed, we have to force a MakeCurrent
   667   // to make sure that GL sees the updated widget size.
   668   if (mWidgetSize.width != width ||
   669       mWidgetSize.height != height)
   670   {
   671     MakeCurrent(ForceMakeCurrent);
   673     mWidgetSize.width = width;
   674     mWidgetSize.height = height;
   675   } else {
   676     MakeCurrent();
   677   }
   679   mPixelsPerFrame = width * height;
   680   mPixelsFilled = 0;
   682 #if MOZ_ANDROID_OMTC
   683   TexturePoolOGL::Fill(gl());
   684 #endif
   686   mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this,
   687                             IntSize(width, height),
   688                             aTransform);
   689   mCurrentRenderTarget->BindRenderTarget();
   690 #ifdef DEBUG
   691   mWindowRenderTarget = mCurrentRenderTarget;
   692 #endif
   694   // Default blend function implements "OVER"
   695   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
   696                                  LOCAL_GL_ONE, LOCAL_GL_ONE);
   697   mGLContext->fEnable(LOCAL_GL_BLEND);
   699   mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
   701   if (aClipRectOut && !aClipRectIn) {
   702     aClipRectOut->SetRect(0, 0, width, height);
   703   }
   705   // If the Android compositor is being used, this clear will be done in
   706   // DrawWindowUnderlay. Make sure the bits used here match up with those used
   707   // in mobile/android/base/gfx/LayerRenderer.java
   708 #ifndef MOZ_ANDROID_OMTC
   709   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   710   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
   711 #endif
   712 }
   714 void
   715 CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
   716                                     GLuint aSourceFrameBuffer,
   717                                     GLuint *aFBO, GLuint *aTexture)
   718 {
   719   GLuint tex, fbo;
   721   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
   722   mGLContext->fGenTextures(1, &tex);
   723   mGLContext->fBindTexture(mFBOTextureTarget, tex);
   725   if (aCopyFromSource) {
   726     GLuint curFBO = mCurrentRenderTarget->GetFBO();
   727     if (curFBO != aSourceFrameBuffer) {
   728       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer);
   729     }
   731     // We're going to create an RGBA temporary fbo.  But to
   732     // CopyTexImage() from the current framebuffer, the framebuffer's
   733     // format has to be compatible with the new texture's.  So we
   734     // check the format of the framebuffer here and take a slow path
   735     // if it's incompatible.
   736     GLenum format =
   737       GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
   739     bool isFormatCompatibleWithRGBA
   740         = gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
   741                           : true;
   743     if (isFormatCompatibleWithRGBA) {
   744       mGLContext->fCopyTexImage2D(mFBOTextureTarget,
   745                                   0,
   746                                   LOCAL_GL_RGBA,
   747                                   aRect.x, FlipY(aRect.y + aRect.height),
   748                                   aRect.width, aRect.height,
   749                                   0);
   750     } else {
   751       // Curses, incompatible formats.  Take a slow path.
   753       // RGBA
   754       size_t bufferSize = aRect.width * aRect.height * 4;
   755       nsAutoArrayPtr<uint8_t> buf(new uint8_t[bufferSize]);
   757       mGLContext->fReadPixels(aRect.x, aRect.y,
   758                               aRect.width, aRect.height,
   759                               LOCAL_GL_RGBA,
   760                               LOCAL_GL_UNSIGNED_BYTE,
   761                               buf);
   762       mGLContext->fTexImage2D(mFBOTextureTarget,
   763                               0,
   764                               LOCAL_GL_RGBA,
   765                               aRect.width, aRect.height,
   766                               0,
   767                               LOCAL_GL_RGBA,
   768                               LOCAL_GL_UNSIGNED_BYTE,
   769                               buf);
   770     }
   771     GLenum error = mGLContext->GetAndClearError();
   772     if (error != LOCAL_GL_NO_ERROR) {
   773       nsAutoCString msg;
   774       msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d,  RGBA Compat %d",
   775                        error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA);
   776       NS_ERROR(msg.get());
   777     }
   778   } else {
   779     mGLContext->fTexImage2D(mFBOTextureTarget,
   780                             0,
   781                             LOCAL_GL_RGBA,
   782                             aRect.width, aRect.height,
   783                             0,
   784                             LOCAL_GL_RGBA,
   785                             LOCAL_GL_UNSIGNED_BYTE,
   786                             nullptr);
   787   }
   788   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
   789                              LOCAL_GL_LINEAR);
   790   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
   791                              LOCAL_GL_LINEAR);
   792   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S,
   793                              LOCAL_GL_CLAMP_TO_EDGE);
   794   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T,
   795                              LOCAL_GL_CLAMP_TO_EDGE);
   796   mGLContext->fBindTexture(mFBOTextureTarget, 0);
   798   mGLContext->fGenFramebuffers(1, &fbo);
   800   *aFBO = fbo;
   801   *aTexture = tex;
   802 }
   804 ShaderConfigOGL
   805 CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const
   806 {
   807   ShaderConfigOGL config;
   809   switch(aEffect->mType) {
   810   case EFFECT_SOLID_COLOR:
   811     config.SetRenderColor(true);
   812     break;
   813   case EFFECT_YCBCR:
   814     config.SetYCbCr(true);
   815     break;
   816   case EFFECT_COMPONENT_ALPHA:
   817   {
   818     config.SetComponentAlpha(true);
   819     EffectComponentAlpha* effectComponentAlpha =
   820       static_cast<EffectComponentAlpha*>(aEffect);
   821     gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat();
   822     config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 ||
   823                      format == gfx::SurfaceFormat::B8G8R8X8);
   824     break;
   825   }
   826   case EFFECT_RENDER_TARGET:
   827     config.SetTextureTarget(mFBOTextureTarget);
   828     break;
   829   default:
   830   {
   831     MOZ_ASSERT(aEffect->mType == EFFECT_RGB);
   832     TexturedEffect* texturedEffect =
   833         static_cast<TexturedEffect*>(aEffect);
   834     TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
   835     MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
   836                   source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8);
   837     MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
   838                   source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
   839                   source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
   840                   source->GetFormat() == gfx::SurfaceFormat::R5G6B5);
   841     config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
   842                                              source->GetFormat());
   843     break;
   844   }
   845   }
   846   config.SetMask2D(aMask == Mask2d);
   847   config.SetMask3D(aMask == Mask3d);
   848   return config;
   849 }
   851 ShaderProgramOGL*
   852 CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig)
   853 {
   854   std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig);
   855   if (iter != mPrograms.end())
   856     return iter->second;
   858   ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig);
   859   ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile);
   860   if (!shader->Initialize()) {
   861     delete shader;
   862     return nullptr;
   863   }
   865   mPrograms[aConfig] = shader;
   866   return shader;
   867 }
   869 void
   870 CompositorOGL::DrawLines(const std::vector<gfx::Point>& aLines, const gfx::Rect& aClipRect,
   871                          const gfx::Color& aColor,
   872                          gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform)
   873 {
   874   mGLContext->fLineWidth(2.0);
   876   EffectChain effects;
   877   effects.mPrimaryEffect = new EffectSolidColor(aColor);
   879   for (int32_t i = 0; i < (int32_t)aLines.size() - 1; i++) {
   880     const gfx::Point& p1 = aLines[i];
   881     const gfx::Point& p2 = aLines[i+1];
   882     DrawQuadInternal(Rect(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y),
   883                      aClipRect, effects, aOpacity, aTransform,
   884                      LOCAL_GL_LINE_STRIP);
   885   }
   886 }
   888 void
   889 CompositorOGL::DrawQuadInternal(const Rect& aRect,
   890                                 const Rect& aClipRect,
   891                                 const EffectChain &aEffectChain,
   892                                 Float aOpacity,
   893                                 const gfx::Matrix4x4 &aTransform,
   894                                 GLuint aDrawMode)
   895 {
   896   PROFILER_LABEL("CompositorOGL", "DrawQuad");
   897   MOZ_ASSERT(mFrameInProgress, "frame not started");
   899   Rect clipRect = aClipRect;
   900   if (!mTarget) {
   901     clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
   902   }
   903   IntRect intClipRect;
   904   clipRect.ToIntRect(&intClipRect);
   906   gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height),
   907                  intClipRect.width, intClipRect.height);
   909   LayerScope::SendEffectChain(mGLContext, aEffectChain,
   910                               aRect.width, aRect.height);
   912   MaskType maskType;
   913   EffectMask* effectMask;
   914   TextureSourceOGL* sourceMask = nullptr;
   915   gfx::Matrix4x4 maskQuadTransform;
   916   if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
   917     effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get());
   918     sourceMask = effectMask->mMaskTexture->AsSourceOGL();
   920     // NS_ASSERTION(textureMask->IsAlpha(),
   921     //              "OpenGL mask layers must be backed by alpha surfaces");
   923     // We're assuming that the gl backend won't cheat and use NPOT
   924     // textures when glContext says it can't (which seems to happen
   925     // on a mac when you force POT textures)
   926     IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext);
   928     const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform;
   929     NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
   930     Rect bounds = Rect(Point(), Size(maskSize));
   931     bounds = maskTransform.As2D().TransformBounds(bounds);
   933     maskQuadTransform._11 = 1.0f/bounds.width;
   934     maskQuadTransform._22 = 1.0f/bounds.height;
   935     maskQuadTransform._41 = float(-bounds.x)/bounds.width;
   936     maskQuadTransform._42 = float(-bounds.y)/bounds.height;
   938     maskType = effectMask->mIs3D
   939                  ? Mask3d
   940                  : Mask2d;
   941   } else {
   942     maskType = MaskNone;
   943   }
   945   mPixelsFilled += aRect.width * aRect.height;
   947   // Determine the color if this is a color shader and fold the opacity into
   948   // the color since color shaders don't have an opacity uniform.
   949   Color color;
   950   if (aEffectChain.mPrimaryEffect->mType == EFFECT_SOLID_COLOR) {
   951     EffectSolidColor* effectSolidColor =
   952       static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
   953     color = effectSolidColor->mColor;
   955     Float opacity = aOpacity * color.a;
   956     color.r *= opacity;
   957     color.g *= opacity;
   958     color.b *= opacity;
   959     color.a = opacity;
   961     // We can fold opacity into the color, so no need to consider it further.
   962     aOpacity = 1.f;
   963   }
   965   ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType);
   966   config.SetOpacity(aOpacity != 1.f);
   967   ShaderProgramOGL *program = GetShaderProgramFor(config);
   968   program->Activate();
   969   program->SetProjectionMatrix(mProjMatrix);
   970   program->SetLayerQuadRect(aRect);
   971   program->SetLayerTransform(aTransform);
   972   IntPoint offset = mCurrentRenderTarget->GetOrigin();
   973   program->SetRenderOffset(offset.x, offset.y);
   974   if (aOpacity != 1.f)
   975     program->SetLayerOpacity(aOpacity);
   976   if (config.mFeatures & ENABLE_TEXTURE_RECT) {
   977     TexturedEffect* texturedEffect =
   978         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
   979     TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
   980     // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
   981     program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
   982   }
   984   switch (aEffectChain.mPrimaryEffect->mType) {
   985     case EFFECT_SOLID_COLOR: {
   986       program->SetRenderColor(color);
   988       if (maskType != MaskNone) {
   989         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
   990       }
   992       BindAndDrawQuad(program, aDrawMode);
   993     }
   994     break;
   996   case EFFECT_RGB: {
   997       TexturedEffect* texturedEffect =
   998           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
   999       TextureSource *source = texturedEffect->mTexture;
  1001       if (!texturedEffect->mPremultiplied) {
  1002         mGLContext->fBlendFuncSeparate(LOCAL_GL_SRC_ALPHA, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
  1003                                        LOCAL_GL_ONE, LOCAL_GL_ONE);
  1006       gfx::Filter filter = texturedEffect->mFilter;
  1007       gfx3DMatrix textureTransform;
  1008       gfx::To3DMatrix(source->AsSourceOGL()->GetTextureTransform(), textureTransform);
  1010 #ifdef MOZ_WIDGET_ANDROID
  1011       gfxMatrix textureTransform2D;
  1012       if (filter != gfx::Filter::POINT &&
  1013           aTransform.Is2DIntegerTranslation() &&
  1014           textureTransform.Is2D(&textureTransform2D) &&
  1015           textureTransform2D.HasOnlyIntegerTranslation()) {
  1016         // On Android we encounter small resampling errors in what should be
  1017         // pixel-aligned compositing operations. This works around them. This
  1018         // code should not be needed!
  1019         filter = gfx::Filter::POINT;
  1021 #endif
  1022       source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter);
  1024       program->SetTextureUnit(0);
  1026       if (maskType != MaskNone) {
  1027         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
  1030       BindAndDrawQuadWithTextureRect(program, textureTransform,
  1031                                      texturedEffect->mTextureCoords, source);
  1033       if (!texturedEffect->mPremultiplied) {
  1034         mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
  1035                                        LOCAL_GL_ONE, LOCAL_GL_ONE);
  1038     break;
  1039   case EFFECT_YCBCR: {
  1040       EffectYCbCr* effectYCbCr =
  1041         static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
  1042       TextureSource* sourceYCbCr = effectYCbCr->mTexture;
  1043       const int Y = 0, Cb = 1, Cr = 2;
  1044       TextureSourceOGL* sourceY =  sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
  1045       TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
  1046       TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
  1048       if (!sourceY && !sourceCb && !sourceCr) {
  1049         NS_WARNING("Invalid layer texture.");
  1050         return;
  1053       sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mFilter);
  1054       sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mFilter);
  1055       sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mFilter);
  1057       program->SetYCbCrTextureUnits(Y, Cb, Cr);
  1059       if (maskType != MaskNone) {
  1060         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
  1062       BindAndDrawQuadWithTextureRect(program,
  1063                                      gfx3DMatrix(),
  1064                                      effectYCbCr->mTextureCoords,
  1065                                      sourceYCbCr->GetSubSource(Y));
  1067     break;
  1068   case EFFECT_RENDER_TARGET: {
  1069       EffectRenderTarget* effectRenderTarget =
  1070         static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
  1071       RefPtr<CompositingRenderTargetOGL> surface
  1072         = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get());
  1074       surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
  1076       // Drawing is always flipped, but when copying between surfaces we want to avoid
  1077       // this, so apply a flip here to cancel the other one out.
  1078       Matrix transform;
  1079       transform.Translate(0.0, 1.0);
  1080       transform.Scale(1.0f, -1.0f);
  1081       program->SetTextureTransform(Matrix4x4::From2D(transform));
  1082       program->SetTextureUnit(0);
  1084       if (maskType != MaskNone) {
  1085         sourceMask->BindTexture(LOCAL_GL_TEXTURE1, gfx::Filter::LINEAR);
  1086         program->SetMaskTextureUnit(1);
  1087         program->SetMaskLayerTransform(maskQuadTransform);
  1090       if (config.mFeatures & ENABLE_TEXTURE_RECT) {
  1091         // 2DRect case, get the multiplier right for a sampler2DRect
  1092         program->SetTexCoordMultiplier(aRect.width, aRect.height);
  1095       // Drawing is always flipped, but when copying between surfaces we want to avoid
  1096       // this. Pass true for the flip parameter to introduce a second flip
  1097       // that cancels the other one out.
  1098       BindAndDrawQuad(program);
  1100     break;
  1101   case EFFECT_COMPONENT_ALPHA: {
  1102       MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
  1103       EffectComponentAlpha* effectComponentAlpha =
  1104         static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
  1105       TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL();
  1106       TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL();
  1108       if (!sourceOnBlack->IsValid() ||
  1109           !sourceOnWhite->IsValid()) {
  1110         NS_WARNING("Invalid layer texture for component alpha");
  1111         return;
  1114       sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mFilter);
  1115       sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mFilter);
  1117       program->SetBlackTextureUnit(0);
  1118       program->SetWhiteTextureUnit(1);
  1119       program->SetTextureTransform(gfx::Matrix4x4());
  1121       if (maskType != MaskNone) {
  1122         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
  1124       // Pass 1.
  1125       gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
  1126                                LOCAL_GL_ONE, LOCAL_GL_ONE);
  1127       program->SetTexturePass2(false);
  1128       BindAndDrawQuadWithTextureRect(program,
  1129                                      gfx3DMatrix(),
  1130                                      effectComponentAlpha->mTextureCoords,
  1131                                      effectComponentAlpha->mOnBlack);
  1133       // Pass 2.
  1134       gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
  1135                                LOCAL_GL_ONE, LOCAL_GL_ONE);
  1137 #ifdef XP_MACOSX
  1138       if (gl()->WorkAroundDriverBugs() &&
  1139           gl()->Vendor() == GLVendor::NVIDIA &&
  1140           !nsCocoaFeatures::OnMavericksOrLater()) {
  1141         // Bug 987497: With some GPUs the nvidia driver on 10.8 and below
  1142         // won't pick up the TexturePass2 uniform change below if we don't do
  1143         // something to force it. Re-activating the shader seems to be one way
  1144         // of achieving that.
  1145         program->Activate();
  1147 #endif
  1149       program->SetTexturePass2(true);
  1150       BindAndDrawQuadWithTextureRect(program,
  1151                                      gfx3DMatrix(),
  1152                                      effectComponentAlpha->mTextureCoords,
  1153                                      effectComponentAlpha->mOnBlack);
  1155       mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
  1156                                      LOCAL_GL_ONE, LOCAL_GL_ONE);
  1158     break;
  1159   default:
  1160     MOZ_ASSERT(false, "Unhandled effect type");
  1161     break;
  1164   // in case rendering has used some other GL context
  1165   MakeCurrent();
  1168 void
  1169 CompositorOGL::EndFrame()
  1171   PROFILER_LABEL("CompositorOGL", "EndFrame");
  1172   MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
  1174 #ifdef MOZ_DUMP_PAINTING
  1175   if (gfxUtils::sDumpPainting) {
  1176     nsIntRect rect;
  1177     if (mUseExternalSurfaceSize) {
  1178       rect = nsIntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
  1179     } else {
  1180       mWidget->GetBounds(rect);
  1182     RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8);
  1183     CopyToTarget(target, mCurrentRenderTarget->GetTransform());
  1185     WriteSnapshotToDumpFile(this, target);
  1187 #endif
  1189   mFrameInProgress = false;
  1191   LayerScope::EndFrame(mGLContext);
  1193   if (mTarget) {
  1194     CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform());
  1195     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
  1196     mCurrentRenderTarget = nullptr;
  1197     return;
  1200   mCurrentRenderTarget = nullptr;
  1202   if (mTexturePool) {
  1203     mTexturePool->EndFrame();
  1206   mGLContext->SwapBuffers();
  1207   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
  1209   // Unbind all textures
  1210   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
  1211   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
  1212   if (!mGLContext->IsGLES()) {
  1213     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
  1216   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1);
  1217   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
  1218   if (!mGLContext->IsGLES()) {
  1219     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
  1222   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2);
  1223   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
  1224   if (!mGLContext->IsGLES()) {
  1225     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
  1229 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
  1230 void
  1231 CompositorOGL::SetFBAcquireFence(Layer* aLayer)
  1233   // OpenGL does not provide ReleaseFence for rendering.
  1234   // Instead use FBAcquireFence as layer buffer's ReleaseFence
  1235   // to prevent flickering and tearing.
  1236   // FBAcquireFence is FramebufferSurface's AcquireFence.
  1237   // AcquireFence will be signaled when a buffer's content is available.
  1238   // See Bug 974152.
  1240   if (!aLayer) {
  1241     return;
  1244   const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
  1245   if (visibleRegion.IsEmpty()) {
  1246       return;
  1249   // Set FBAcquireFence on ContainerLayer's childs
  1250   ContainerLayer* container = aLayer->AsContainerLayer();
  1251   if (container) {
  1252     for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
  1253       SetFBAcquireFence(child);
  1255     return;
  1258   // Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer.
  1259   TiledLayerComposer* composer = nullptr;
  1260   LayerComposite* shadow = aLayer->AsLayerComposite();
  1261   if (shadow) {
  1262     composer = shadow->GetTiledLayerComposer();
  1263     if (composer) {
  1264       composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
  1265       return;
  1269   // Set FBAcquireFence as layer buffer's ReleaseFence
  1270   LayerRenderState state = aLayer->GetRenderState();
  1271   if (!state.mTexture) {
  1272     return;
  1274   TextureHostOGL* texture = state.mTexture->AsHostOGL();
  1275   if (!texture) {
  1276     return;
  1278   texture->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
  1280 #else
  1281 void
  1282 CompositorOGL::SetFBAcquireFence(Layer* aLayer)
  1285 #endif
  1287 void
  1288 CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
  1290   // This lets us reftest and screenshot content rendered externally
  1291   if (mTarget) {
  1292     MakeCurrent();
  1293     CopyToTarget(mTarget, aTransform);
  1294     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
  1296   if (mTexturePool) {
  1297     mTexturePool->EndFrame();
  1301 void
  1302 CompositorOGL::AbortFrame()
  1304   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
  1305   mFrameInProgress = false;
  1306   mCurrentRenderTarget = nullptr;
  1308   if (mTexturePool) {
  1309     mTexturePool->EndFrame();
  1313 void
  1314 CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize)
  1316   mSurfaceSize.width = aSize.width;
  1317   mSurfaceSize.height = aSize.height;
  1320 void
  1321 CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform)
  1323   IntRect rect;
  1324   if (mUseExternalSurfaceSize) {
  1325     rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
  1326   } else {
  1327     rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height);
  1329   GLint width = rect.width;
  1330   GLint height = rect.height;
  1332   if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) {
  1333     NS_ERROR("Widget size too big - integer overflow!");
  1334     return;
  1337   mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
  1339   if (!mGLContext->IsGLES()) {
  1340     // GLES2 promises that binding to any custom FBO will attach
  1341     // to GL_COLOR_ATTACHMENT0 attachment point.
  1342     mGLContext->fReadBuffer(LOCAL_GL_BACK);
  1345   RefPtr<DataSourceSurface> source =
  1346         Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
  1348   DataSourceSurface::MappedSurface map;
  1349   source->Map(DataSourceSurface::MapType::WRITE, &map);
  1350   // XXX we should do this properly one day without using the gfxImageSurface
  1351   nsRefPtr<gfxImageSurface> surf =
  1352     new gfxImageSurface(map.mData,
  1353                         gfxIntSize(width, height),
  1354                         map.mStride,
  1355                         gfxImageFormat::ARGB32);
  1356   ReadPixelsIntoImageSurface(mGLContext, surf);
  1357   source->Unmap();
  1359   // Map from GL space to Cairo space and reverse the world transform.
  1360   Matrix glToCairoTransform = aTransform;
  1361   glToCairoTransform.Invert();
  1362   glToCairoTransform.Scale(1.0, -1.0);
  1363   glToCairoTransform.Translate(0.0, -height);
  1365   Matrix oldMatrix = aTarget->GetTransform();
  1366   aTarget->SetTransform(glToCairoTransform);
  1367   Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
  1368   aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
  1369   aTarget->SetTransform(oldMatrix);
  1370   aTarget->Flush();
  1373 void
  1374 CompositorOGL::Pause()
  1376 #ifdef MOZ_WIDGET_ANDROID
  1377   if (!gl() || gl()->IsDestroyed())
  1378     return;
  1380   // ReleaseSurface internally calls MakeCurrent.
  1381   gl()->ReleaseSurface();
  1382 #endif
  1385 bool
  1386 CompositorOGL::Resume()
  1388 #ifdef MOZ_WIDGET_ANDROID
  1389   if (!gl() || gl()->IsDestroyed())
  1390     return false;
  1392   // RenewSurface internally calls MakeCurrent.
  1393   return gl()->RenewSurface();
  1394 #endif
  1395   return true;
  1398 TemporaryRef<DataTextureSource>
  1399 CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
  1401   RefPtr<DataTextureSource> result =
  1402     new TextureImageTextureSourceOGL(mGLContext, aFlags);
  1403   return result;
  1406 bool
  1407 CompositorOGL::SupportsPartialTextureUpdate()
  1409   return CanUploadSubTextures(mGLContext);
  1412 int32_t
  1413 CompositorOGL::GetMaxTextureSize() const
  1415   MOZ_ASSERT(mGLContext);
  1416   GLint texSize = 0;
  1417   mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
  1418                             &texSize);
  1419   MOZ_ASSERT(texSize != 0);
  1420   return texSize;
  1423 void
  1424 CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
  1425   if (mDestroyed) {
  1426     NS_WARNING("Call on destroyed layer manager");
  1427     return;
  1429   mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
  1432 void
  1433 CompositorOGL::BindQuadVBO() {
  1434   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
  1437 void
  1438 CompositorOGL::QuadVBOVerticesAttrib(GLuint aAttribIndex) {
  1439   mGLContext->fVertexAttribPointer(aAttribIndex, 2,
  1440                                     LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
  1441                                     (GLvoid*) QuadVBOVertexOffset());
  1444 void
  1445 CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
  1446   mGLContext->fVertexAttribPointer(aAttribIndex, 2,
  1447                                     LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
  1448                                     (GLvoid*) QuadVBOTexCoordOffset());
  1451 void
  1452 CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
  1453                                GLuint aTexCoordAttribIndex,
  1454                                GLuint aDrawMode)
  1456   BindQuadVBO();
  1457   QuadVBOVerticesAttrib(aVertAttribIndex);
  1459   if (aTexCoordAttribIndex != GLuint(-1)) {
  1460     QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
  1461     mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex);
  1464   mGLContext->fEnableVertexAttribArray(aVertAttribIndex);
  1465   if (aDrawMode == LOCAL_GL_LINE_STRIP) {
  1466     mGLContext->fDrawArrays(aDrawMode, 1, 2);
  1467   } else {
  1468     mGLContext->fDrawArrays(aDrawMode, 0, 4);
  1472 void
  1473 CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
  1474                                GLuint aDrawMode)
  1476   NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
  1477   BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib),
  1478                   aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib),
  1479                   aDrawMode);
  1482 GLuint
  1483 CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
  1485   if (!mTexturePool) {
  1486 #ifdef MOZ_WIDGET_GONK
  1487     mTexturePool = new PerFrameTexturePoolOGL(gl());
  1488 #else
  1489     mTexturePool = new PerUnitTexturePoolOGL(gl());
  1490 #endif
  1492   return mTexturePool->GetTexture(aTarget, aUnit);
  1495 GLuint
  1496 PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit)
  1498   if (mTextureTarget == 0) {
  1499     mTextureTarget = aTarget;
  1501   MOZ_ASSERT(mTextureTarget == aTarget);
  1503   size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
  1504   // lazily grow the array of temporary textures
  1505   if (mTextures.Length() <= index) {
  1506     size_t prevLength = mTextures.Length();
  1507     mTextures.SetLength(index + 1);
  1508     for(unsigned int i = prevLength; i <= index; ++i) {
  1509       mTextures[i] = 0;
  1512   // lazily initialize the temporary textures
  1513   if (!mTextures[index]) {
  1514     if (!mGL->MakeCurrent()) {
  1515       return 0;
  1517     mGL->fGenTextures(1, &mTextures[index]);
  1518     mGL->fBindTexture(aTarget, mTextures[index]);
  1519     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
  1520     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
  1522   return mTextures[index];
  1525 void
  1526 PerUnitTexturePoolOGL::DestroyTextures()
  1528   if (mGL && mGL->MakeCurrent()) {
  1529     if (mTextures.Length() > 0) {
  1530       mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
  1533   mTextures.SetLength(0);
  1536 void
  1537 PerFrameTexturePoolOGL::DestroyTextures()
  1539   if (!mGL->MakeCurrent()) {
  1540     return;
  1543   if (mUnusedTextures.Length() > 0) {
  1544     mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]);
  1545     mUnusedTextures.Clear();
  1548   if (mCreatedTextures.Length() > 0) {
  1549     mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]);
  1550     mCreatedTextures.Clear();
  1554 GLuint
  1555 PerFrameTexturePoolOGL::GetTexture(GLenum aTarget, GLenum)
  1557   if (mTextureTarget == 0) {
  1558     mTextureTarget = aTarget;
  1561   // The pool should always use the same texture target because it is illegal
  1562   // to change the target of an already exisiting gl texture.
  1563   // If we need to use several targets, a pool with several sub-pools (one per
  1564   // target) will have to be implemented.
  1565   // At the moment this pool is only used with tiling on b2g so we always need
  1566   // the same target.
  1567   MOZ_ASSERT(mTextureTarget == aTarget);
  1569   GLuint texture = 0;
  1571   if (!mUnusedTextures.IsEmpty()) {
  1572     // Try to reuse one from the unused pile first
  1573     texture = mUnusedTextures[0];
  1574     mUnusedTextures.RemoveElementAt(0);
  1575   } else if (mGL->MakeCurrent()) {
  1576     // There isn't one to reuse, create one.
  1577     mGL->fGenTextures(1, &texture);
  1578     mGL->fBindTexture(aTarget, texture);
  1579     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
  1580     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
  1583   if (texture) {
  1584     mCreatedTextures.AppendElement(texture);
  1587   return texture;
  1590 void
  1591 PerFrameTexturePoolOGL::EndFrame()
  1593   if (!mGL->MakeCurrent()) {
  1594     // this means the context got destroyed underneith us somehow, and the driver
  1595     // already has destroyed the textures.
  1596     mCreatedTextures.Clear();
  1597     mUnusedTextures.Clear();
  1598     return;
  1601   // Some platforms have issues unlocking Gralloc buffers even when they're
  1602   // rebound.
  1603   if (gfxPrefs::OverzealousGrallocUnlocking()) {
  1604     mUnusedTextures.AppendElements(mCreatedTextures);
  1605     mCreatedTextures.Clear();
  1608   // Delete unused textures
  1609   for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
  1610     GLuint texture = mUnusedTextures[i];
  1611     mGL->fDeleteTextures(1, &texture);
  1613   mUnusedTextures.Clear();
  1615   // Move all created textures into the unused pile
  1616   mUnusedTextures.AppendElements(mCreatedTextures);
  1617   mCreatedTextures.Clear();
  1620 } /* layers */
  1621 } /* mozilla */

mercurial