gfx/layers/opengl/CompositorOGL.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/layers/opengl/CompositorOGL.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1621 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "CompositorOGL.h"
    1.10 +#include <stddef.h>                     // for size_t
    1.11 +#include <stdint.h>                     // for uint32_t, uint8_t
    1.12 +#include <stdlib.h>                     // for free, malloc
    1.13 +#include "GLContextProvider.h"          // for GLContextProvider
    1.14 +#include "GLContext.h"                  // for GLContext
    1.15 +#include "GLUploadHelpers.h"
    1.16 +#include "Layers.h"                     // for WriteSnapshotToDumpFile
    1.17 +#include "LayerScope.h"                 // for LayerScope
    1.18 +#include "gfx2DGlue.h"                  // for ThebesFilter
    1.19 +#include "gfx3DMatrix.h"                // for gfx3DMatrix
    1.20 +#include "gfxCrashReporterUtils.h"      // for ScopedGfxFeatureReporter
    1.21 +#include "gfxImageSurface.h"            // for gfxImageSurface
    1.22 +#include "gfxMatrix.h"                  // for gfxMatrix
    1.23 +#include "GraphicsFilter.h"             // for GraphicsFilter
    1.24 +#include "gfxPlatform.h"                // for gfxPlatform
    1.25 +#include "gfxPrefs.h"                   // for gfxPrefs
    1.26 +#include "gfxRect.h"                    // for gfxRect
    1.27 +#include "gfxUtils.h"                   // for NextPowerOfTwo, gfxUtils, etc
    1.28 +#include "mozilla/ArrayUtils.h"         // for ArrayLength
    1.29 +#include "mozilla/Preferences.h"        // for Preferences
    1.30 +#include "mozilla/gfx/BasePoint.h"      // for BasePoint
    1.31 +#include "mozilla/gfx/Matrix.h"         // for Matrix4x4, Matrix
    1.32 +#include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite, etc
    1.33 +#include "mozilla/layers/CompositingRenderTargetOGL.h"
    1.34 +#include "mozilla/layers/Effects.h"     // for EffectChain, TexturedEffect, etc
    1.35 +#include "mozilla/layers/TextureHost.h"  // for TextureSource, etc
    1.36 +#include "mozilla/layers/TextureHostOGL.h"  // for TextureSourceOGL, etc
    1.37 +#include "mozilla/mozalloc.h"           // for operator delete, etc
    1.38 +#include "nsAString.h"
    1.39 +#include "nsIConsoleService.h"          // for nsIConsoleService, etc
    1.40 +#include "nsIWidget.h"                  // for nsIWidget
    1.41 +#include "nsLiteralString.h"            // for NS_LITERAL_STRING
    1.42 +#include "nsMathUtils.h"                // for NS_roundf
    1.43 +#include "nsRect.h"                     // for nsIntRect
    1.44 +#include "nsServiceManagerUtils.h"      // for do_GetService
    1.45 +#include "nsString.h"                   // for nsString, nsAutoCString, etc
    1.46 +#include "DecomposeIntoNoRepeatTriangles.h"
    1.47 +#include "ScopedGLHelpers.h"
    1.48 +#include "GLReadTexImageHelper.h"
    1.49 +#include "TiledLayerBuffer.h"           // for TiledLayerComposer
    1.50 +
    1.51 +#if MOZ_ANDROID_OMTC
    1.52 +#include "TexturePoolOGL.h"
    1.53 +#endif
    1.54 +
    1.55 +#ifdef XP_MACOSX
    1.56 +#include "nsCocoaFeatures.h"
    1.57 +#endif
    1.58 +
    1.59 +#include "GeckoProfiler.h"
    1.60 +
    1.61 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
    1.62 +#include "libdisplay/GonkDisplay.h"     // for GonkDisplay
    1.63 +#include <ui/Fence.h>
    1.64 +#endif
    1.65 +
    1.66 +#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
    1.67 +
    1.68 +namespace mozilla {
    1.69 +
    1.70 +using namespace std;
    1.71 +using namespace gfx;
    1.72 +
    1.73 +namespace layers {
    1.74 +
    1.75 +using namespace mozilla::gl;
    1.76 +
    1.77 +static inline IntSize ns2gfxSize(const nsIntSize& s) {
    1.78 +  return IntSize(s.width, s.height);
    1.79 +}
    1.80 +
    1.81 +static void
    1.82 +BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
    1.83 +                   GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
    1.84 +{
    1.85 +  MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
    1.86 +  aSourceMask->BindTexture(aTexUnit, gfx::Filter::LINEAR);
    1.87 +  aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
    1.88 +  aProgram->SetMaskLayerTransform(aTransform);
    1.89 +}
    1.90 +
    1.91 +// Draw the given quads with the already selected shader. Texture coordinates
    1.92 +// are supplied if the shader requires them.
    1.93 +static void
    1.94 +DrawQuads(GLContext *aGLContext,
    1.95 +          VBOArena &aVBOs,
    1.96 +          ShaderProgramOGL *aProg,
    1.97 +          GLenum aMode,
    1.98 +          RectTriangles &aRects)
    1.99 +{
   1.100 +  NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
   1.101 +  GLuint vertAttribIndex =
   1.102 +    aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
   1.103 +  GLuint texCoordAttribIndex =
   1.104 +    aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
   1.105 +  bool texCoords = (texCoordAttribIndex != GLuint(-1));
   1.106 +
   1.107 +  GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat);
   1.108 +
   1.109 +  GLsizei total = bytes;
   1.110 +  if (texCoords) {
   1.111 +    total *= 2;
   1.112 +  }
   1.113 +
   1.114 +  aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER,
   1.115 +                          aVBOs.Allocate(aGLContext));
   1.116 +  aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
   1.117 +                          total,
   1.118 +                          nullptr,
   1.119 +                          LOCAL_GL_STREAM_DRAW);
   1.120 +
   1.121 +  aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
   1.122 +                             0,
   1.123 +                             bytes,
   1.124 +                             aRects.vertCoords().Elements());
   1.125 +  aGLContext->fEnableVertexAttribArray(vertAttribIndex);
   1.126 +  aGLContext->fVertexAttribPointer(vertAttribIndex,
   1.127 +                                   2, LOCAL_GL_FLOAT,
   1.128 +                                   LOCAL_GL_FALSE,
   1.129 +                                   0, BUFFER_OFFSET(0));
   1.130 +
   1.131 +  if (texCoords) {
   1.132 +    aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
   1.133 +                               bytes,
   1.134 +                               bytes,
   1.135 +                               aRects.texCoords().Elements());
   1.136 +    aGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
   1.137 +    aGLContext->fVertexAttribPointer(texCoordAttribIndex,
   1.138 +                                     2, LOCAL_GL_FLOAT,
   1.139 +                                     LOCAL_GL_FALSE,
   1.140 +                                     0, BUFFER_OFFSET(bytes));
   1.141 +  } else {
   1.142 +    aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
   1.143 +  }
   1.144 +
   1.145 +  aGLContext->fDrawArrays(aMode, 0, aRects.elements());
   1.146 +
   1.147 +  aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
   1.148 +}
   1.149 +
   1.150 +CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
   1.151 +                             int aSurfaceHeight, bool aUseExternalSurfaceSize)
   1.152 +  : mWidget(aWidget)
   1.153 +  , mWidgetSize(-1, -1)
   1.154 +  , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   1.155 +  , mHasBGRA(0)
   1.156 +  , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   1.157 +  , mFrameInProgress(false)
   1.158 +  , mDestroyed(false)
   1.159 +  , mHeight(0)
   1.160 +{
   1.161 +  MOZ_COUNT_CTOR(CompositorOGL);
   1.162 +  SetBackend(LayersBackend::LAYERS_OPENGL);
   1.163 +}
   1.164 +
   1.165 +CompositorOGL::~CompositorOGL()
   1.166 +{
   1.167 +  MOZ_COUNT_DTOR(CompositorOGL);
   1.168 +  Destroy();
   1.169 +}
   1.170 +
   1.171 +already_AddRefed<mozilla::gl::GLContext>
   1.172 +CompositorOGL::CreateContext()
   1.173 +{
   1.174 +  nsRefPtr<GLContext> context;
   1.175 +
   1.176 +#ifdef XP_WIN
   1.177 +  if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) {
   1.178 +    printf_stderr("Trying GL layers...\n");
   1.179 +    context = gl::GLContextProviderEGL::CreateForWindow(mWidget);
   1.180 +  }
   1.181 +#endif
   1.182 +
   1.183 +  if (!context)
   1.184 +    context = gl::GLContextProvider::CreateForWindow(mWidget);
   1.185 +
   1.186 +  if (!context) {
   1.187 +    NS_WARNING("Failed to create CompositorOGL context");
   1.188 +  }
   1.189 +
   1.190 +  return context.forget();
   1.191 +}
   1.192 +
   1.193 +void
   1.194 +CompositorOGL::Destroy()
   1.195 +{
   1.196 +  if (gl() && gl()->MakeCurrent()) {
   1.197 +    mVBOs.Flush(gl());
   1.198 +  }
   1.199 +
   1.200 +  if (mTexturePool) {
   1.201 +    mTexturePool->Clear();
   1.202 +    mTexturePool = nullptr;
   1.203 +  }
   1.204 +
   1.205 +  if (!mDestroyed) {
   1.206 +    mDestroyed = true;
   1.207 +    CleanupResources();
   1.208 +  }
   1.209 +}
   1.210 +
   1.211 +void
   1.212 +CompositorOGL::CleanupResources()
   1.213 +{
   1.214 +  if (!mGLContext)
   1.215 +    return;
   1.216 +
   1.217 +  nsRefPtr<GLContext> ctx = mGLContext->GetSharedContext();
   1.218 +  if (!ctx) {
   1.219 +    ctx = mGLContext;
   1.220 +  }
   1.221 +
   1.222 +  for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin();
   1.223 +       iter != mPrograms.end();
   1.224 +       iter++) {
   1.225 +    delete iter->second;
   1.226 +  }
   1.227 +  mPrograms.clear();
   1.228 +
   1.229 +  if (!ctx->MakeCurrent()) {
   1.230 +    mQuadVBO = 0;
   1.231 +    mGLContext = nullptr;
   1.232 +    return;
   1.233 +  }
   1.234 +
   1.235 +  ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
   1.236 +
   1.237 +  if (mQuadVBO) {
   1.238 +    ctx->fDeleteBuffers(1, &mQuadVBO);
   1.239 +    mQuadVBO = 0;
   1.240 +  }
   1.241 +
   1.242 +  mGLContext = nullptr;
   1.243 +}
   1.244 +
   1.245 +bool
   1.246 +CompositorOGL::Initialize()
   1.247 +{
   1.248 +  ScopedGfxFeatureReporter reporter("GL Layers", true);
   1.249 +
   1.250 +  // Do not allow double initialization
   1.251 +  NS_ABORT_IF_FALSE(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
   1.252 +
   1.253 +  mGLContext = CreateContext();
   1.254 +
   1.255 +#ifdef MOZ_WIDGET_ANDROID
   1.256 +  if (!mGLContext)
   1.257 +    NS_RUNTIMEABORT("We need a context on Android");
   1.258 +#endif
   1.259 +
   1.260 +  if (!mGLContext)
   1.261 +    return false;
   1.262 +
   1.263 +  MakeCurrent();
   1.264 +
   1.265 +  mHasBGRA =
   1.266 +    mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
   1.267 +    mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
   1.268 +
   1.269 +  mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
   1.270 +                                 LOCAL_GL_ONE, LOCAL_GL_ONE);
   1.271 +  mGLContext->fEnable(LOCAL_GL_BLEND);
   1.272 +
   1.273 +  // initialise a common shader to check that we can actually compile a shader
   1.274 +  RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0));
   1.275 +  ShaderConfigOGL config = GetShaderConfigFor(effect);
   1.276 +  if (!GetShaderProgramFor(config)) {
   1.277 +    return false;
   1.278 +  }
   1.279 +
   1.280 +  if (mGLContext->WorkAroundDriverBugs()) {
   1.281 +    /**
   1.282 +    * We'll test the ability here to bind NPOT textures to a framebuffer, if
   1.283 +    * this fails we'll try ARB_texture_rectangle.
   1.284 +    */
   1.285 +
   1.286 +    GLenum textureTargets[] = {
   1.287 +      LOCAL_GL_TEXTURE_2D,
   1.288 +      LOCAL_GL_NONE
   1.289 +    };
   1.290 +
   1.291 +    if (!mGLContext->IsGLES()) {
   1.292 +      // No TEXTURE_RECTANGLE_ARB available on ES2
   1.293 +      textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
   1.294 +    }
   1.295 +
   1.296 +    mFBOTextureTarget = LOCAL_GL_NONE;
   1.297 +
   1.298 +    GLuint testFBO = 0;
   1.299 +    mGLContext->fGenFramebuffers(1, &testFBO);
   1.300 +    GLuint testTexture = 0;
   1.301 +
   1.302 +    for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) {
   1.303 +      GLenum target = textureTargets[i];
   1.304 +      if (!target)
   1.305 +          continue;
   1.306 +
   1.307 +      mGLContext->fGenTextures(1, &testTexture);
   1.308 +      mGLContext->fBindTexture(target, testTexture);
   1.309 +      mGLContext->fTexParameteri(target,
   1.310 +                                LOCAL_GL_TEXTURE_MIN_FILTER,
   1.311 +                                LOCAL_GL_NEAREST);
   1.312 +      mGLContext->fTexParameteri(target,
   1.313 +                                LOCAL_GL_TEXTURE_MAG_FILTER,
   1.314 +                                LOCAL_GL_NEAREST);
   1.315 +      mGLContext->fTexImage2D(target,
   1.316 +                              0,
   1.317 +                              LOCAL_GL_RGBA,
   1.318 +                              5, 3, /* sufficiently NPOT */
   1.319 +                              0,
   1.320 +                              LOCAL_GL_RGBA,
   1.321 +                              LOCAL_GL_UNSIGNED_BYTE,
   1.322 +                              nullptr);
   1.323 +
   1.324 +      // unbind this texture, in preparation for binding it to the FBO
   1.325 +      mGLContext->fBindTexture(target, 0);
   1.326 +
   1.327 +      mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO);
   1.328 +      mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
   1.329 +                                        LOCAL_GL_COLOR_ATTACHMENT0,
   1.330 +                                        target,
   1.331 +                                        testTexture,
   1.332 +                                        0);
   1.333 +
   1.334 +      if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
   1.335 +          LOCAL_GL_FRAMEBUFFER_COMPLETE)
   1.336 +      {
   1.337 +        mFBOTextureTarget = target;
   1.338 +        mGLContext->fDeleteTextures(1, &testTexture);
   1.339 +        break;
   1.340 +      }
   1.341 +
   1.342 +      mGLContext->fDeleteTextures(1, &testTexture);
   1.343 +    }
   1.344 +
   1.345 +    if (testFBO) {
   1.346 +      mGLContext->fDeleteFramebuffers(1, &testFBO);
   1.347 +    }
   1.348 +
   1.349 +    if (mFBOTextureTarget == LOCAL_GL_NONE) {
   1.350 +      /* Unable to find a texture target that works with FBOs and NPOT textures */
   1.351 +      return false;
   1.352 +    }
   1.353 +  } else {
   1.354 +    // not trying to work around driver bugs, so TEXTURE_2D should just work
   1.355 +    mFBOTextureTarget = LOCAL_GL_TEXTURE_2D;
   1.356 +  }
   1.357 +
   1.358 +  // back to default framebuffer, to avoid confusion
   1.359 +  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
   1.360 +
   1.361 +  if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
   1.362 +    /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
   1.363 +     * extension -- the EXT variant does not provide support for
   1.364 +     * texture rectangle access inside GLSL (sampler2DRect,
   1.365 +     * texture2DRect).
   1.366 +     */
   1.367 +    if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle))
   1.368 +      return false;
   1.369 +  }
   1.370 +
   1.371 +  /* Create a simple quad VBO */
   1.372 +
   1.373 +  mGLContext->fGenBuffers(1, &mQuadVBO);
   1.374 +  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
   1.375 +
   1.376 +  GLfloat vertices[] = {
   1.377 +    /* First quad vertices */
   1.378 +    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
   1.379 +    /* Then quad texcoords */
   1.380 +    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
   1.381 +  };
   1.382 +  mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
   1.383 +  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
   1.384 +
   1.385 +  nsCOMPtr<nsIConsoleService>
   1.386 +    console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   1.387 +
   1.388 +  if (console) {
   1.389 +    nsString msg;
   1.390 +    msg +=
   1.391 +      NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: ");
   1.392 +    msg += NS_ConvertUTF8toUTF16(
   1.393 +      nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
   1.394 +    msg += NS_LITERAL_STRING("\nVendor: ");
   1.395 +    msg += NS_ConvertUTF8toUTF16(
   1.396 +      nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
   1.397 +    msg += NS_LITERAL_STRING("\nRenderer: ");
   1.398 +    msg += NS_ConvertUTF8toUTF16(
   1.399 +      nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
   1.400 +    msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
   1.401 +    if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
   1.402 +      msg += NS_LITERAL_STRING("TEXTURE_2D");
   1.403 +    else
   1.404 +      msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
   1.405 +    console->LogStringMessage(msg.get());
   1.406 +  }
   1.407 +
   1.408 +  reporter.SetSuccessful();
   1.409 +  return true;
   1.410 +}
   1.411 +
   1.412 +// |aTextureTransform| is the texture transform that will be set on
   1.413 +// aProg, possibly multiplied with another texture transform of our
   1.414 +// own.
   1.415 +// |aTexCoordRect| is the rectangle from the texture that we want to
   1.416 +// draw using the given program.  The program already has a necessary
   1.417 +// offset and scale, so the geometry that needs to be drawn is a unit
   1.418 +// square from 0,0 to 1,1.
   1.419 +//
   1.420 +// |aTexture| is the texture we are drawing. Its actual size can be
   1.421 +// larger than the rectangle given by |aTexCoordRect|.
   1.422 +void
   1.423 +CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
   1.424 +                                              const gfx3DMatrix& aTextureTransform,
   1.425 +                                              const Rect& aTexCoordRect,
   1.426 +                                              TextureSource *aTexture)
   1.427 +{
   1.428 +  // Given what we know about these textures and coordinates, we can
   1.429 +  // compute fmod(t, 1.0f) to get the same texture coordinate out.  If
   1.430 +  // the texCoordRect dimension is < 0 or > width/height, then we have
   1.431 +  // wraparound that we need to deal with by drawing multiple quads,
   1.432 +  // because we can't rely on full non-power-of-two texture support
   1.433 +  // (which is required for the REPEAT wrap mode).
   1.434 +
   1.435 +  RectTriangles rects;
   1.436 +
   1.437 +  GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode();
   1.438 +
   1.439 +  IntSize realTexSize = aTexture->GetSize();
   1.440 +  if (!CanUploadNonPowerOfTwo(mGLContext)) {
   1.441 +    realTexSize = IntSize(NextPowerOfTwo(realTexSize.width),
   1.442 +                          NextPowerOfTwo(realTexSize.height));
   1.443 +  }
   1.444 +
   1.445 +  // We need to convert back to actual texels here to get proper behaviour with
   1.446 +  // our GL helper functions. Should fix this sometime.
   1.447 +  // I want to vomit.
   1.448 +  IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width),
   1.449 +                                 NS_roundf(aTexCoordRect.y * aTexture->GetSize().height),
   1.450 +                                 NS_roundf(aTexCoordRect.width * aTexture->GetSize().width),
   1.451 +                                 NS_roundf(aTexCoordRect.height * aTexture->GetSize().height));
   1.452 +
   1.453 +  // This is fairly disgusting - if the texture should be flipped it will have a
   1.454 +  // negative height, in which case we un-invert the texture coords and pass the
   1.455 +  // flipped 'flag' to the functions below. We can't just use the inverted coords
   1.456 +  // because our GL funtions use an explicit flag.
   1.457 +  bool flipped = false;
   1.458 +  if (texCoordRect.height < 0) {
   1.459 +    flipped = true;
   1.460 +    texCoordRect.y = texCoordRect.YMost();
   1.461 +    texCoordRect.height = -texCoordRect.height;
   1.462 +  }
   1.463 +
   1.464 +  if (wrapMode == LOCAL_GL_REPEAT) {
   1.465 +    rects.addRect(/* dest rectangle */
   1.466 +                  0.0f, 0.0f, 1.0f, 1.0f,
   1.467 +                  /* tex coords */
   1.468 +                  texCoordRect.x / GLfloat(realTexSize.width),
   1.469 +                  texCoordRect.y / GLfloat(realTexSize.height),
   1.470 +                  texCoordRect.XMost() / GLfloat(realTexSize.width),
   1.471 +                  texCoordRect.YMost() / GLfloat(realTexSize.height),
   1.472 +                  flipped);
   1.473 +  } else {
   1.474 +    nsIntRect tcRect(texCoordRect.x, texCoordRect.y,
   1.475 +                     texCoordRect.width, texCoordRect.height);
   1.476 +    DecomposeIntoNoRepeatTriangles(tcRect,
   1.477 +                                   nsIntSize(realTexSize.width, realTexSize.height),
   1.478 +                                   rects, flipped);
   1.479 +  }
   1.480 +
   1.481 +  gfx3DMatrix textureTransform;
   1.482 +  if (rects.isSimpleQuad(textureTransform)) {
   1.483 +    Matrix4x4 transform;
   1.484 +    ToMatrix4x4(aTextureTransform * textureTransform, transform);
   1.485 +    aProg->SetTextureTransform(transform);
   1.486 +    BindAndDrawQuad(aProg);
   1.487 +  } else {
   1.488 +    Matrix4x4 transform;
   1.489 +    ToMatrix4x4(aTextureTransform, transform);
   1.490 +    aProg->SetTextureTransform(transform);
   1.491 +    DrawQuads(mGLContext, mVBOs, aProg, LOCAL_GL_TRIANGLES, rects);
   1.492 +  }
   1.493 +}
   1.494 +
   1.495 +void
   1.496 +CompositorOGL::PrepareViewport(const gfx::IntSize& aSize,
   1.497 +                               const Matrix& aWorldTransform)
   1.498 +{
   1.499 +  // Set the viewport correctly.
   1.500 +  mGLContext->fViewport(0, 0, aSize.width, aSize.height);
   1.501 +
   1.502 +  mHeight = aSize.height;
   1.503 +
   1.504 +  // We flip the view matrix around so that everything is right-side up; we're
   1.505 +  // drawing directly into the window's back buffer, so this keeps things
   1.506 +  // looking correct.
   1.507 +  // XXX: We keep track of whether the window size changed, so we could skip
   1.508 +  // this update if it hadn't changed since the last call. We will need to
   1.509 +  // track changes to aTransformPolicy and aWorldTransform for this to work
   1.510 +  // though.
   1.511 +
   1.512 +  // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
   1.513 +  // 2, 2) and flip the contents.
   1.514 +  Matrix viewMatrix;
   1.515 +  viewMatrix.Translate(-1.0, 1.0);
   1.516 +  viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
   1.517 +  viewMatrix.Scale(1.0f, -1.0f);
   1.518 +  if (!mTarget) {
   1.519 +    viewMatrix.Translate(mRenderOffset.x, mRenderOffset.y);
   1.520 +  }
   1.521 +
   1.522 +  viewMatrix = aWorldTransform * viewMatrix;
   1.523 +
   1.524 +  Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
   1.525 +  matrix3d._33 = 0.0f;
   1.526 +
   1.527 +  mProjMatrix = matrix3d;
   1.528 +}
   1.529 +
   1.530 +TemporaryRef<CompositingRenderTarget>
   1.531 +CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit)
   1.532 +{
   1.533 +  GLuint tex = 0;
   1.534 +  GLuint fbo = 0;
   1.535 +  CreateFBOWithTexture(aRect, false, 0, &fbo, &tex);
   1.536 +  RefPtr<CompositingRenderTargetOGL> surface
   1.537 +    = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
   1.538 +  surface->Initialize(aRect.Size(), mFBOTextureTarget, aInit);
   1.539 +  return surface.forget();
   1.540 +}
   1.541 +
   1.542 +TemporaryRef<CompositingRenderTarget>
   1.543 +CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect,
   1.544 +                                            const CompositingRenderTarget *aSource,
   1.545 +                                            const IntPoint &aSourcePoint)
   1.546 +{
   1.547 +  GLuint tex = 0;
   1.548 +  GLuint fbo = 0;
   1.549 +  const CompositingRenderTargetOGL* sourceSurface
   1.550 +    = static_cast<const CompositingRenderTargetOGL*>(aSource);
   1.551 +  IntRect sourceRect(aSourcePoint, aRect.Size());
   1.552 +  if (aSource) {
   1.553 +    CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(),
   1.554 +                         &fbo, &tex);
   1.555 +  } else {
   1.556 +    CreateFBOWithTexture(sourceRect, true, 0,
   1.557 +                         &fbo, &tex);
   1.558 +  }
   1.559 +
   1.560 +  RefPtr<CompositingRenderTargetOGL> surface
   1.561 +    = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
   1.562 +  surface->Initialize(aRect.Size(),
   1.563 +                      mFBOTextureTarget,
   1.564 +                      INIT_MODE_NONE);
   1.565 +  return surface.forget();
   1.566 +}
   1.567 +
   1.568 +void
   1.569 +CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface)
   1.570 +{
   1.571 +  MOZ_ASSERT(aSurface);
   1.572 +  CompositingRenderTargetOGL* surface
   1.573 +    = static_cast<CompositingRenderTargetOGL*>(aSurface);
   1.574 +  if (mCurrentRenderTarget != surface) {
   1.575 +    surface->BindRenderTarget();
   1.576 +    mCurrentRenderTarget = surface;
   1.577 +  }
   1.578 +}
   1.579 +
   1.580 +CompositingRenderTarget*
   1.581 +CompositorOGL::GetCurrentRenderTarget() const
   1.582 +{
   1.583 +  return mCurrentRenderTarget;
   1.584 +}
   1.585 +
   1.586 +static GLenum
   1.587 +GetFrameBufferInternalFormat(GLContext* gl,
   1.588 +                             GLuint aFrameBuffer,
   1.589 +                             nsIWidget* aWidget)
   1.590 +{
   1.591 +  if (aFrameBuffer == 0) { // default framebuffer
   1.592 +    return aWidget->GetGLFrameBufferFormat();
   1.593 +  }
   1.594 +  return LOCAL_GL_RGBA;
   1.595 +}
   1.596 +
   1.597 +/*
   1.598 + * Returns a size that is larger than and closest to aSize where both
   1.599 + * width and height are powers of two.
   1.600 + * If the OpenGL setup is capable of using non-POT textures, then it
   1.601 + * will just return aSize.
   1.602 + */
   1.603 +static IntSize
   1.604 +CalculatePOTSize(const IntSize& aSize, GLContext* gl)
   1.605 +{
   1.606 +  if (CanUploadNonPowerOfTwo(gl))
   1.607 +    return aSize;
   1.608 +
   1.609 +  return IntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height));
   1.610 +}
   1.611 +
   1.612 +void
   1.613 +CompositorOGL::ClearRect(const gfx::Rect& aRect)
   1.614 +{
   1.615 +  // Map aRect to OGL coordinates, origin:bottom-left
   1.616 +  GLint y = mHeight - (aRect.y + aRect.height);
   1.617 +
   1.618 +  ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
   1.619 +  ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height);
   1.620 +  mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   1.621 +  mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
   1.622 +}
   1.623 +
   1.624 +void
   1.625 +CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
   1.626 +                          const Rect *aClipRectIn,
   1.627 +                          const gfx::Matrix& aTransform,
   1.628 +                          const Rect& aRenderBounds,
   1.629 +                          Rect *aClipRectOut,
   1.630 +                          Rect *aRenderBoundsOut)
   1.631 +{
   1.632 +  PROFILER_LABEL("CompositorOGL", "BeginFrame");
   1.633 +  MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
   1.634 +
   1.635 +  LayerScope::BeginFrame(mGLContext, PR_Now());
   1.636 +
   1.637 +  mVBOs.Reset();
   1.638 +
   1.639 +  mFrameInProgress = true;
   1.640 +  gfx::Rect rect;
   1.641 +  if (mUseExternalSurfaceSize) {
   1.642 +    rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
   1.643 +  } else {
   1.644 +    rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
   1.645 +    // If render bounds is not updated explicitly, try to infer it from widget
   1.646 +    if (rect.width == 0 || rect.height == 0) {
   1.647 +      // FIXME/bug XXXXXX this races with rotation changes on the main
   1.648 +      // thread, and undoes all the care we take with layers txns being
   1.649 +      // sent atomically with rotation changes
   1.650 +      nsIntRect intRect;
   1.651 +      mWidget->GetClientBounds(intRect);
   1.652 +      rect = gfx::Rect(0, 0, intRect.width, intRect.height);
   1.653 +    }
   1.654 +  }
   1.655 +
   1.656 +  rect = aTransform.TransformBounds(rect);
   1.657 +  if (aRenderBoundsOut) {
   1.658 +    *aRenderBoundsOut = rect;
   1.659 +  }
   1.660 +
   1.661 +  GLint width = rect.width;
   1.662 +  GLint height = rect.height;
   1.663 +
   1.664 +  // We can't draw anything to something with no area
   1.665 +  // so just return
   1.666 +  if (width == 0 || height == 0)
   1.667 +    return;
   1.668 +
   1.669 +  // If the widget size changed, we have to force a MakeCurrent
   1.670 +  // to make sure that GL sees the updated widget size.
   1.671 +  if (mWidgetSize.width != width ||
   1.672 +      mWidgetSize.height != height)
   1.673 +  {
   1.674 +    MakeCurrent(ForceMakeCurrent);
   1.675 +
   1.676 +    mWidgetSize.width = width;
   1.677 +    mWidgetSize.height = height;
   1.678 +  } else {
   1.679 +    MakeCurrent();
   1.680 +  }
   1.681 +
   1.682 +  mPixelsPerFrame = width * height;
   1.683 +  mPixelsFilled = 0;
   1.684 +
   1.685 +#if MOZ_ANDROID_OMTC
   1.686 +  TexturePoolOGL::Fill(gl());
   1.687 +#endif
   1.688 +
   1.689 +  mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this,
   1.690 +                            IntSize(width, height),
   1.691 +                            aTransform);
   1.692 +  mCurrentRenderTarget->BindRenderTarget();
   1.693 +#ifdef DEBUG
   1.694 +  mWindowRenderTarget = mCurrentRenderTarget;
   1.695 +#endif
   1.696 +
   1.697 +  // Default blend function implements "OVER"
   1.698 +  mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
   1.699 +                                 LOCAL_GL_ONE, LOCAL_GL_ONE);
   1.700 +  mGLContext->fEnable(LOCAL_GL_BLEND);
   1.701 +
   1.702 +  mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
   1.703 +
   1.704 +  if (aClipRectOut && !aClipRectIn) {
   1.705 +    aClipRectOut->SetRect(0, 0, width, height);
   1.706 +  }
   1.707 +
   1.708 +  // If the Android compositor is being used, this clear will be done in
   1.709 +  // DrawWindowUnderlay. Make sure the bits used here match up with those used
   1.710 +  // in mobile/android/base/gfx/LayerRenderer.java
   1.711 +#ifndef MOZ_ANDROID_OMTC
   1.712 +  mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   1.713 +  mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
   1.714 +#endif
   1.715 +}
   1.716 +
   1.717 +void
   1.718 +CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
   1.719 +                                    GLuint aSourceFrameBuffer,
   1.720 +                                    GLuint *aFBO, GLuint *aTexture)
   1.721 +{
   1.722 +  GLuint tex, fbo;
   1.723 +
   1.724 +  mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
   1.725 +  mGLContext->fGenTextures(1, &tex);
   1.726 +  mGLContext->fBindTexture(mFBOTextureTarget, tex);
   1.727 +
   1.728 +  if (aCopyFromSource) {
   1.729 +    GLuint curFBO = mCurrentRenderTarget->GetFBO();
   1.730 +    if (curFBO != aSourceFrameBuffer) {
   1.731 +      mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer);
   1.732 +    }
   1.733 +
   1.734 +    // We're going to create an RGBA temporary fbo.  But to
   1.735 +    // CopyTexImage() from the current framebuffer, the framebuffer's
   1.736 +    // format has to be compatible with the new texture's.  So we
   1.737 +    // check the format of the framebuffer here and take a slow path
   1.738 +    // if it's incompatible.
   1.739 +    GLenum format =
   1.740 +      GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
   1.741 +
   1.742 +    bool isFormatCompatibleWithRGBA
   1.743 +        = gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
   1.744 +                          : true;
   1.745 +
   1.746 +    if (isFormatCompatibleWithRGBA) {
   1.747 +      mGLContext->fCopyTexImage2D(mFBOTextureTarget,
   1.748 +                                  0,
   1.749 +                                  LOCAL_GL_RGBA,
   1.750 +                                  aRect.x, FlipY(aRect.y + aRect.height),
   1.751 +                                  aRect.width, aRect.height,
   1.752 +                                  0);
   1.753 +    } else {
   1.754 +      // Curses, incompatible formats.  Take a slow path.
   1.755 +
   1.756 +      // RGBA
   1.757 +      size_t bufferSize = aRect.width * aRect.height * 4;
   1.758 +      nsAutoArrayPtr<uint8_t> buf(new uint8_t[bufferSize]);
   1.759 +
   1.760 +      mGLContext->fReadPixels(aRect.x, aRect.y,
   1.761 +                              aRect.width, aRect.height,
   1.762 +                              LOCAL_GL_RGBA,
   1.763 +                              LOCAL_GL_UNSIGNED_BYTE,
   1.764 +                              buf);
   1.765 +      mGLContext->fTexImage2D(mFBOTextureTarget,
   1.766 +                              0,
   1.767 +                              LOCAL_GL_RGBA,
   1.768 +                              aRect.width, aRect.height,
   1.769 +                              0,
   1.770 +                              LOCAL_GL_RGBA,
   1.771 +                              LOCAL_GL_UNSIGNED_BYTE,
   1.772 +                              buf);
   1.773 +    }
   1.774 +    GLenum error = mGLContext->GetAndClearError();
   1.775 +    if (error != LOCAL_GL_NO_ERROR) {
   1.776 +      nsAutoCString msg;
   1.777 +      msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d,  RGBA Compat %d",
   1.778 +                       error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA);
   1.779 +      NS_ERROR(msg.get());
   1.780 +    }
   1.781 +  } else {
   1.782 +    mGLContext->fTexImage2D(mFBOTextureTarget,
   1.783 +                            0,
   1.784 +                            LOCAL_GL_RGBA,
   1.785 +                            aRect.width, aRect.height,
   1.786 +                            0,
   1.787 +                            LOCAL_GL_RGBA,
   1.788 +                            LOCAL_GL_UNSIGNED_BYTE,
   1.789 +                            nullptr);
   1.790 +  }
   1.791 +  mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
   1.792 +                             LOCAL_GL_LINEAR);
   1.793 +  mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
   1.794 +                             LOCAL_GL_LINEAR);
   1.795 +  mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S,
   1.796 +                             LOCAL_GL_CLAMP_TO_EDGE);
   1.797 +  mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T,
   1.798 +                             LOCAL_GL_CLAMP_TO_EDGE);
   1.799 +  mGLContext->fBindTexture(mFBOTextureTarget, 0);
   1.800 +
   1.801 +  mGLContext->fGenFramebuffers(1, &fbo);
   1.802 +
   1.803 +  *aFBO = fbo;
   1.804 +  *aTexture = tex;
   1.805 +}
   1.806 +
   1.807 +ShaderConfigOGL
   1.808 +CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const
   1.809 +{
   1.810 +  ShaderConfigOGL config;
   1.811 +
   1.812 +  switch(aEffect->mType) {
   1.813 +  case EFFECT_SOLID_COLOR:
   1.814 +    config.SetRenderColor(true);
   1.815 +    break;
   1.816 +  case EFFECT_YCBCR:
   1.817 +    config.SetYCbCr(true);
   1.818 +    break;
   1.819 +  case EFFECT_COMPONENT_ALPHA:
   1.820 +  {
   1.821 +    config.SetComponentAlpha(true);
   1.822 +    EffectComponentAlpha* effectComponentAlpha =
   1.823 +      static_cast<EffectComponentAlpha*>(aEffect);
   1.824 +    gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat();
   1.825 +    config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 ||
   1.826 +                     format == gfx::SurfaceFormat::B8G8R8X8);
   1.827 +    break;
   1.828 +  }
   1.829 +  case EFFECT_RENDER_TARGET:
   1.830 +    config.SetTextureTarget(mFBOTextureTarget);
   1.831 +    break;
   1.832 +  default:
   1.833 +  {
   1.834 +    MOZ_ASSERT(aEffect->mType == EFFECT_RGB);
   1.835 +    TexturedEffect* texturedEffect =
   1.836 +        static_cast<TexturedEffect*>(aEffect);
   1.837 +    TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
   1.838 +    MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
   1.839 +                  source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8);
   1.840 +    MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
   1.841 +                  source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
   1.842 +                  source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
   1.843 +                  source->GetFormat() == gfx::SurfaceFormat::R5G6B5);
   1.844 +    config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
   1.845 +                                             source->GetFormat());
   1.846 +    break;
   1.847 +  }
   1.848 +  }
   1.849 +  config.SetMask2D(aMask == Mask2d);
   1.850 +  config.SetMask3D(aMask == Mask3d);
   1.851 +  return config;
   1.852 +}
   1.853 +
   1.854 +ShaderProgramOGL*
   1.855 +CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig)
   1.856 +{
   1.857 +  std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig);
   1.858 +  if (iter != mPrograms.end())
   1.859 +    return iter->second;
   1.860 +
   1.861 +  ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig);
   1.862 +  ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile);
   1.863 +  if (!shader->Initialize()) {
   1.864 +    delete shader;
   1.865 +    return nullptr;
   1.866 +  }
   1.867 +
   1.868 +  mPrograms[aConfig] = shader;
   1.869 +  return shader;
   1.870 +}
   1.871 +
   1.872 +void
   1.873 +CompositorOGL::DrawLines(const std::vector<gfx::Point>& aLines, const gfx::Rect& aClipRect,
   1.874 +                         const gfx::Color& aColor,
   1.875 +                         gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform)
   1.876 +{
   1.877 +  mGLContext->fLineWidth(2.0);
   1.878 +
   1.879 +  EffectChain effects;
   1.880 +  effects.mPrimaryEffect = new EffectSolidColor(aColor);
   1.881 +
   1.882 +  for (int32_t i = 0; i < (int32_t)aLines.size() - 1; i++) {
   1.883 +    const gfx::Point& p1 = aLines[i];
   1.884 +    const gfx::Point& p2 = aLines[i+1];
   1.885 +    DrawQuadInternal(Rect(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y),
   1.886 +                     aClipRect, effects, aOpacity, aTransform,
   1.887 +                     LOCAL_GL_LINE_STRIP);
   1.888 +  }
   1.889 +}
   1.890 +
   1.891 +void
   1.892 +CompositorOGL::DrawQuadInternal(const Rect& aRect,
   1.893 +                                const Rect& aClipRect,
   1.894 +                                const EffectChain &aEffectChain,
   1.895 +                                Float aOpacity,
   1.896 +                                const gfx::Matrix4x4 &aTransform,
   1.897 +                                GLuint aDrawMode)
   1.898 +{
   1.899 +  PROFILER_LABEL("CompositorOGL", "DrawQuad");
   1.900 +  MOZ_ASSERT(mFrameInProgress, "frame not started");
   1.901 +
   1.902 +  Rect clipRect = aClipRect;
   1.903 +  if (!mTarget) {
   1.904 +    clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
   1.905 +  }
   1.906 +  IntRect intClipRect;
   1.907 +  clipRect.ToIntRect(&intClipRect);
   1.908 +
   1.909 +  gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height),
   1.910 +                 intClipRect.width, intClipRect.height);
   1.911 +
   1.912 +  LayerScope::SendEffectChain(mGLContext, aEffectChain,
   1.913 +                              aRect.width, aRect.height);
   1.914 +
   1.915 +  MaskType maskType;
   1.916 +  EffectMask* effectMask;
   1.917 +  TextureSourceOGL* sourceMask = nullptr;
   1.918 +  gfx::Matrix4x4 maskQuadTransform;
   1.919 +  if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
   1.920 +    effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get());
   1.921 +    sourceMask = effectMask->mMaskTexture->AsSourceOGL();
   1.922 +
   1.923 +    // NS_ASSERTION(textureMask->IsAlpha(),
   1.924 +    //              "OpenGL mask layers must be backed by alpha surfaces");
   1.925 +
   1.926 +    // We're assuming that the gl backend won't cheat and use NPOT
   1.927 +    // textures when glContext says it can't (which seems to happen
   1.928 +    // on a mac when you force POT textures)
   1.929 +    IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext);
   1.930 +
   1.931 +    const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform;
   1.932 +    NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
   1.933 +    Rect bounds = Rect(Point(), Size(maskSize));
   1.934 +    bounds = maskTransform.As2D().TransformBounds(bounds);
   1.935 +
   1.936 +    maskQuadTransform._11 = 1.0f/bounds.width;
   1.937 +    maskQuadTransform._22 = 1.0f/bounds.height;
   1.938 +    maskQuadTransform._41 = float(-bounds.x)/bounds.width;
   1.939 +    maskQuadTransform._42 = float(-bounds.y)/bounds.height;
   1.940 +
   1.941 +    maskType = effectMask->mIs3D
   1.942 +                 ? Mask3d
   1.943 +                 : Mask2d;
   1.944 +  } else {
   1.945 +    maskType = MaskNone;
   1.946 +  }
   1.947 +
   1.948 +  mPixelsFilled += aRect.width * aRect.height;
   1.949 +
   1.950 +  // Determine the color if this is a color shader and fold the opacity into
   1.951 +  // the color since color shaders don't have an opacity uniform.
   1.952 +  Color color;
   1.953 +  if (aEffectChain.mPrimaryEffect->mType == EFFECT_SOLID_COLOR) {
   1.954 +    EffectSolidColor* effectSolidColor =
   1.955 +      static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
   1.956 +    color = effectSolidColor->mColor;
   1.957 +
   1.958 +    Float opacity = aOpacity * color.a;
   1.959 +    color.r *= opacity;
   1.960 +    color.g *= opacity;
   1.961 +    color.b *= opacity;
   1.962 +    color.a = opacity;
   1.963 +
   1.964 +    // We can fold opacity into the color, so no need to consider it further.
   1.965 +    aOpacity = 1.f;
   1.966 +  }
   1.967 +
   1.968 +  ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType);
   1.969 +  config.SetOpacity(aOpacity != 1.f);
   1.970 +  ShaderProgramOGL *program = GetShaderProgramFor(config);
   1.971 +  program->Activate();
   1.972 +  program->SetProjectionMatrix(mProjMatrix);
   1.973 +  program->SetLayerQuadRect(aRect);
   1.974 +  program->SetLayerTransform(aTransform);
   1.975 +  IntPoint offset = mCurrentRenderTarget->GetOrigin();
   1.976 +  program->SetRenderOffset(offset.x, offset.y);
   1.977 +  if (aOpacity != 1.f)
   1.978 +    program->SetLayerOpacity(aOpacity);
   1.979 +  if (config.mFeatures & ENABLE_TEXTURE_RECT) {
   1.980 +    TexturedEffect* texturedEffect =
   1.981 +        static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
   1.982 +    TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
   1.983 +    // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
   1.984 +    program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
   1.985 +  }
   1.986 +
   1.987 +  switch (aEffectChain.mPrimaryEffect->mType) {
   1.988 +    case EFFECT_SOLID_COLOR: {
   1.989 +      program->SetRenderColor(color);
   1.990 +
   1.991 +      if (maskType != MaskNone) {
   1.992 +        BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
   1.993 +      }
   1.994 +
   1.995 +      BindAndDrawQuad(program, aDrawMode);
   1.996 +    }
   1.997 +    break;
   1.998 +
   1.999 +  case EFFECT_RGB: {
  1.1000 +      TexturedEffect* texturedEffect =
  1.1001 +          static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
  1.1002 +      TextureSource *source = texturedEffect->mTexture;
  1.1003 +
  1.1004 +      if (!texturedEffect->mPremultiplied) {
  1.1005 +        mGLContext->fBlendFuncSeparate(LOCAL_GL_SRC_ALPHA, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
  1.1006 +                                       LOCAL_GL_ONE, LOCAL_GL_ONE);
  1.1007 +      }
  1.1008 +
  1.1009 +      gfx::Filter filter = texturedEffect->mFilter;
  1.1010 +      gfx3DMatrix textureTransform;
  1.1011 +      gfx::To3DMatrix(source->AsSourceOGL()->GetTextureTransform(), textureTransform);
  1.1012 +
  1.1013 +#ifdef MOZ_WIDGET_ANDROID
  1.1014 +      gfxMatrix textureTransform2D;
  1.1015 +      if (filter != gfx::Filter::POINT &&
  1.1016 +          aTransform.Is2DIntegerTranslation() &&
  1.1017 +          textureTransform.Is2D(&textureTransform2D) &&
  1.1018 +          textureTransform2D.HasOnlyIntegerTranslation()) {
  1.1019 +        // On Android we encounter small resampling errors in what should be
  1.1020 +        // pixel-aligned compositing operations. This works around them. This
  1.1021 +        // code should not be needed!
  1.1022 +        filter = gfx::Filter::POINT;
  1.1023 +      }
  1.1024 +#endif
  1.1025 +      source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter);
  1.1026 +
  1.1027 +      program->SetTextureUnit(0);
  1.1028 +
  1.1029 +      if (maskType != MaskNone) {
  1.1030 +        BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
  1.1031 +      }
  1.1032 +
  1.1033 +      BindAndDrawQuadWithTextureRect(program, textureTransform,
  1.1034 +                                     texturedEffect->mTextureCoords, source);
  1.1035 +
  1.1036 +      if (!texturedEffect->mPremultiplied) {
  1.1037 +        mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
  1.1038 +                                       LOCAL_GL_ONE, LOCAL_GL_ONE);
  1.1039 +      }
  1.1040 +    }
  1.1041 +    break;
  1.1042 +  case EFFECT_YCBCR: {
  1.1043 +      EffectYCbCr* effectYCbCr =
  1.1044 +        static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
  1.1045 +      TextureSource* sourceYCbCr = effectYCbCr->mTexture;
  1.1046 +      const int Y = 0, Cb = 1, Cr = 2;
  1.1047 +      TextureSourceOGL* sourceY =  sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
  1.1048 +      TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
  1.1049 +      TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
  1.1050 +
  1.1051 +      if (!sourceY && !sourceCb && !sourceCr) {
  1.1052 +        NS_WARNING("Invalid layer texture.");
  1.1053 +        return;
  1.1054 +      }
  1.1055 +
  1.1056 +      sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mFilter);
  1.1057 +      sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mFilter);
  1.1058 +      sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mFilter);
  1.1059 +
  1.1060 +      program->SetYCbCrTextureUnits(Y, Cb, Cr);
  1.1061 +
  1.1062 +      if (maskType != MaskNone) {
  1.1063 +        BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
  1.1064 +      }
  1.1065 +      BindAndDrawQuadWithTextureRect(program,
  1.1066 +                                     gfx3DMatrix(),
  1.1067 +                                     effectYCbCr->mTextureCoords,
  1.1068 +                                     sourceYCbCr->GetSubSource(Y));
  1.1069 +    }
  1.1070 +    break;
  1.1071 +  case EFFECT_RENDER_TARGET: {
  1.1072 +      EffectRenderTarget* effectRenderTarget =
  1.1073 +        static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
  1.1074 +      RefPtr<CompositingRenderTargetOGL> surface
  1.1075 +        = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get());
  1.1076 +
  1.1077 +      surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
  1.1078 +
  1.1079 +      // Drawing is always flipped, but when copying between surfaces we want to avoid
  1.1080 +      // this, so apply a flip here to cancel the other one out.
  1.1081 +      Matrix transform;
  1.1082 +      transform.Translate(0.0, 1.0);
  1.1083 +      transform.Scale(1.0f, -1.0f);
  1.1084 +      program->SetTextureTransform(Matrix4x4::From2D(transform));
  1.1085 +      program->SetTextureUnit(0);
  1.1086 +
  1.1087 +      if (maskType != MaskNone) {
  1.1088 +        sourceMask->BindTexture(LOCAL_GL_TEXTURE1, gfx::Filter::LINEAR);
  1.1089 +        program->SetMaskTextureUnit(1);
  1.1090 +        program->SetMaskLayerTransform(maskQuadTransform);
  1.1091 +      }
  1.1092 +
  1.1093 +      if (config.mFeatures & ENABLE_TEXTURE_RECT) {
  1.1094 +        // 2DRect case, get the multiplier right for a sampler2DRect
  1.1095 +        program->SetTexCoordMultiplier(aRect.width, aRect.height);
  1.1096 +      }
  1.1097 +
  1.1098 +      // Drawing is always flipped, but when copying between surfaces we want to avoid
  1.1099 +      // this. Pass true for the flip parameter to introduce a second flip
  1.1100 +      // that cancels the other one out.
  1.1101 +      BindAndDrawQuad(program);
  1.1102 +    }
  1.1103 +    break;
  1.1104 +  case EFFECT_COMPONENT_ALPHA: {
  1.1105 +      MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
  1.1106 +      EffectComponentAlpha* effectComponentAlpha =
  1.1107 +        static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
  1.1108 +      TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL();
  1.1109 +      TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL();
  1.1110 +
  1.1111 +      if (!sourceOnBlack->IsValid() ||
  1.1112 +          !sourceOnWhite->IsValid()) {
  1.1113 +        NS_WARNING("Invalid layer texture for component alpha");
  1.1114 +        return;
  1.1115 +      }
  1.1116 +
  1.1117 +      sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mFilter);
  1.1118 +      sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mFilter);
  1.1119 +
  1.1120 +      program->SetBlackTextureUnit(0);
  1.1121 +      program->SetWhiteTextureUnit(1);
  1.1122 +      program->SetTextureTransform(gfx::Matrix4x4());
  1.1123 +
  1.1124 +      if (maskType != MaskNone) {
  1.1125 +        BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
  1.1126 +      }
  1.1127 +      // Pass 1.
  1.1128 +      gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
  1.1129 +                               LOCAL_GL_ONE, LOCAL_GL_ONE);
  1.1130 +      program->SetTexturePass2(false);
  1.1131 +      BindAndDrawQuadWithTextureRect(program,
  1.1132 +                                     gfx3DMatrix(),
  1.1133 +                                     effectComponentAlpha->mTextureCoords,
  1.1134 +                                     effectComponentAlpha->mOnBlack);
  1.1135 +
  1.1136 +      // Pass 2.
  1.1137 +      gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
  1.1138 +                               LOCAL_GL_ONE, LOCAL_GL_ONE);
  1.1139 +
  1.1140 +#ifdef XP_MACOSX
  1.1141 +      if (gl()->WorkAroundDriverBugs() &&
  1.1142 +          gl()->Vendor() == GLVendor::NVIDIA &&
  1.1143 +          !nsCocoaFeatures::OnMavericksOrLater()) {
  1.1144 +        // Bug 987497: With some GPUs the nvidia driver on 10.8 and below
  1.1145 +        // won't pick up the TexturePass2 uniform change below if we don't do
  1.1146 +        // something to force it. Re-activating the shader seems to be one way
  1.1147 +        // of achieving that.
  1.1148 +        program->Activate();
  1.1149 +      }
  1.1150 +#endif
  1.1151 +
  1.1152 +      program->SetTexturePass2(true);
  1.1153 +      BindAndDrawQuadWithTextureRect(program,
  1.1154 +                                     gfx3DMatrix(),
  1.1155 +                                     effectComponentAlpha->mTextureCoords,
  1.1156 +                                     effectComponentAlpha->mOnBlack);
  1.1157 +
  1.1158 +      mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
  1.1159 +                                     LOCAL_GL_ONE, LOCAL_GL_ONE);
  1.1160 +    }
  1.1161 +    break;
  1.1162 +  default:
  1.1163 +    MOZ_ASSERT(false, "Unhandled effect type");
  1.1164 +    break;
  1.1165 +  }
  1.1166 +
  1.1167 +  // in case rendering has used some other GL context
  1.1168 +  MakeCurrent();
  1.1169 +}
  1.1170 +
  1.1171 +void
  1.1172 +CompositorOGL::EndFrame()
  1.1173 +{
  1.1174 +  PROFILER_LABEL("CompositorOGL", "EndFrame");
  1.1175 +  MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
  1.1176 +
  1.1177 +#ifdef MOZ_DUMP_PAINTING
  1.1178 +  if (gfxUtils::sDumpPainting) {
  1.1179 +    nsIntRect rect;
  1.1180 +    if (mUseExternalSurfaceSize) {
  1.1181 +      rect = nsIntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
  1.1182 +    } else {
  1.1183 +      mWidget->GetBounds(rect);
  1.1184 +    }
  1.1185 +    RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8);
  1.1186 +    CopyToTarget(target, mCurrentRenderTarget->GetTransform());
  1.1187 +
  1.1188 +    WriteSnapshotToDumpFile(this, target);
  1.1189 +  }
  1.1190 +#endif
  1.1191 +
  1.1192 +  mFrameInProgress = false;
  1.1193 +
  1.1194 +  LayerScope::EndFrame(mGLContext);
  1.1195 +
  1.1196 +  if (mTarget) {
  1.1197 +    CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform());
  1.1198 +    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
  1.1199 +    mCurrentRenderTarget = nullptr;
  1.1200 +    return;
  1.1201 +  }
  1.1202 +
  1.1203 +  mCurrentRenderTarget = nullptr;
  1.1204 +
  1.1205 +  if (mTexturePool) {
  1.1206 +    mTexturePool->EndFrame();
  1.1207 +  }
  1.1208 +
  1.1209 +  mGLContext->SwapBuffers();
  1.1210 +  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
  1.1211 +
  1.1212 +  // Unbind all textures
  1.1213 +  mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
  1.1214 +  mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
  1.1215 +  if (!mGLContext->IsGLES()) {
  1.1216 +    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
  1.1217 +  }
  1.1218 +
  1.1219 +  mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1);
  1.1220 +  mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
  1.1221 +  if (!mGLContext->IsGLES()) {
  1.1222 +    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
  1.1223 +  }
  1.1224 +
  1.1225 +  mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2);
  1.1226 +  mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
  1.1227 +  if (!mGLContext->IsGLES()) {
  1.1228 +    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
  1.1229 +  }
  1.1230 +}
  1.1231 +
  1.1232 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
  1.1233 +void
  1.1234 +CompositorOGL::SetFBAcquireFence(Layer* aLayer)
  1.1235 +{
  1.1236 +  // OpenGL does not provide ReleaseFence for rendering.
  1.1237 +  // Instead use FBAcquireFence as layer buffer's ReleaseFence
  1.1238 +  // to prevent flickering and tearing.
  1.1239 +  // FBAcquireFence is FramebufferSurface's AcquireFence.
  1.1240 +  // AcquireFence will be signaled when a buffer's content is available.
  1.1241 +  // See Bug 974152.
  1.1242 +
  1.1243 +  if (!aLayer) {
  1.1244 +    return;
  1.1245 +  }
  1.1246 +
  1.1247 +  const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
  1.1248 +  if (visibleRegion.IsEmpty()) {
  1.1249 +      return;
  1.1250 +  }
  1.1251 +
  1.1252 +  // Set FBAcquireFence on ContainerLayer's childs
  1.1253 +  ContainerLayer* container = aLayer->AsContainerLayer();
  1.1254 +  if (container) {
  1.1255 +    for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
  1.1256 +      SetFBAcquireFence(child);
  1.1257 +    }
  1.1258 +    return;
  1.1259 +  }
  1.1260 +
  1.1261 +  // Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer.
  1.1262 +  TiledLayerComposer* composer = nullptr;
  1.1263 +  LayerComposite* shadow = aLayer->AsLayerComposite();
  1.1264 +  if (shadow) {
  1.1265 +    composer = shadow->GetTiledLayerComposer();
  1.1266 +    if (composer) {
  1.1267 +      composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
  1.1268 +      return;
  1.1269 +    }
  1.1270 +  }
  1.1271 +
  1.1272 +  // Set FBAcquireFence as layer buffer's ReleaseFence
  1.1273 +  LayerRenderState state = aLayer->GetRenderState();
  1.1274 +  if (!state.mTexture) {
  1.1275 +    return;
  1.1276 +  }
  1.1277 +  TextureHostOGL* texture = state.mTexture->AsHostOGL();
  1.1278 +  if (!texture) {
  1.1279 +    return;
  1.1280 +  }
  1.1281 +  texture->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
  1.1282 +}
  1.1283 +#else
  1.1284 +void
  1.1285 +CompositorOGL::SetFBAcquireFence(Layer* aLayer)
  1.1286 +{
  1.1287 +}
  1.1288 +#endif
  1.1289 +
  1.1290 +void
  1.1291 +CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
  1.1292 +{
  1.1293 +  // This lets us reftest and screenshot content rendered externally
  1.1294 +  if (mTarget) {
  1.1295 +    MakeCurrent();
  1.1296 +    CopyToTarget(mTarget, aTransform);
  1.1297 +    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
  1.1298 +  }
  1.1299 +  if (mTexturePool) {
  1.1300 +    mTexturePool->EndFrame();
  1.1301 +  }
  1.1302 +}
  1.1303 +
  1.1304 +void
  1.1305 +CompositorOGL::AbortFrame()
  1.1306 +{
  1.1307 +  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
  1.1308 +  mFrameInProgress = false;
  1.1309 +  mCurrentRenderTarget = nullptr;
  1.1310 +
  1.1311 +  if (mTexturePool) {
  1.1312 +    mTexturePool->EndFrame();
  1.1313 +  }
  1.1314 +}
  1.1315 +
  1.1316 +void
  1.1317 +CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize)
  1.1318 +{
  1.1319 +  mSurfaceSize.width = aSize.width;
  1.1320 +  mSurfaceSize.height = aSize.height;
  1.1321 +}
  1.1322 +
  1.1323 +void
  1.1324 +CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform)
  1.1325 +{
  1.1326 +  IntRect rect;
  1.1327 +  if (mUseExternalSurfaceSize) {
  1.1328 +    rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
  1.1329 +  } else {
  1.1330 +    rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height);
  1.1331 +  }
  1.1332 +  GLint width = rect.width;
  1.1333 +  GLint height = rect.height;
  1.1334 +
  1.1335 +  if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) {
  1.1336 +    NS_ERROR("Widget size too big - integer overflow!");
  1.1337 +    return;
  1.1338 +  }
  1.1339 +
  1.1340 +  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
  1.1341 +
  1.1342 +  if (!mGLContext->IsGLES()) {
  1.1343 +    // GLES2 promises that binding to any custom FBO will attach
  1.1344 +    // to GL_COLOR_ATTACHMENT0 attachment point.
  1.1345 +    mGLContext->fReadBuffer(LOCAL_GL_BACK);
  1.1346 +  }
  1.1347 +
  1.1348 +  RefPtr<DataSourceSurface> source =
  1.1349 +        Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
  1.1350 +
  1.1351 +  DataSourceSurface::MappedSurface map;
  1.1352 +  source->Map(DataSourceSurface::MapType::WRITE, &map);
  1.1353 +  // XXX we should do this properly one day without using the gfxImageSurface
  1.1354 +  nsRefPtr<gfxImageSurface> surf =
  1.1355 +    new gfxImageSurface(map.mData,
  1.1356 +                        gfxIntSize(width, height),
  1.1357 +                        map.mStride,
  1.1358 +                        gfxImageFormat::ARGB32);
  1.1359 +  ReadPixelsIntoImageSurface(mGLContext, surf);
  1.1360 +  source->Unmap();
  1.1361 +
  1.1362 +  // Map from GL space to Cairo space and reverse the world transform.
  1.1363 +  Matrix glToCairoTransform = aTransform;
  1.1364 +  glToCairoTransform.Invert();
  1.1365 +  glToCairoTransform.Scale(1.0, -1.0);
  1.1366 +  glToCairoTransform.Translate(0.0, -height);
  1.1367 +
  1.1368 +  Matrix oldMatrix = aTarget->GetTransform();
  1.1369 +  aTarget->SetTransform(glToCairoTransform);
  1.1370 +  Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
  1.1371 +  aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
  1.1372 +  aTarget->SetTransform(oldMatrix);
  1.1373 +  aTarget->Flush();
  1.1374 +}
  1.1375 +
  1.1376 +void
  1.1377 +CompositorOGL::Pause()
  1.1378 +{
  1.1379 +#ifdef MOZ_WIDGET_ANDROID
  1.1380 +  if (!gl() || gl()->IsDestroyed())
  1.1381 +    return;
  1.1382 +
  1.1383 +  // ReleaseSurface internally calls MakeCurrent.
  1.1384 +  gl()->ReleaseSurface();
  1.1385 +#endif
  1.1386 +}
  1.1387 +
  1.1388 +bool
  1.1389 +CompositorOGL::Resume()
  1.1390 +{
  1.1391 +#ifdef MOZ_WIDGET_ANDROID
  1.1392 +  if (!gl() || gl()->IsDestroyed())
  1.1393 +    return false;
  1.1394 +
  1.1395 +  // RenewSurface internally calls MakeCurrent.
  1.1396 +  return gl()->RenewSurface();
  1.1397 +#endif
  1.1398 +  return true;
  1.1399 +}
  1.1400 +
  1.1401 +TemporaryRef<DataTextureSource>
  1.1402 +CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
  1.1403 +{
  1.1404 +  RefPtr<DataTextureSource> result =
  1.1405 +    new TextureImageTextureSourceOGL(mGLContext, aFlags);
  1.1406 +  return result;
  1.1407 +}
  1.1408 +
  1.1409 +bool
  1.1410 +CompositorOGL::SupportsPartialTextureUpdate()
  1.1411 +{
  1.1412 +  return CanUploadSubTextures(mGLContext);
  1.1413 +}
  1.1414 +
  1.1415 +int32_t
  1.1416 +CompositorOGL::GetMaxTextureSize() const
  1.1417 +{
  1.1418 +  MOZ_ASSERT(mGLContext);
  1.1419 +  GLint texSize = 0;
  1.1420 +  mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
  1.1421 +                            &texSize);
  1.1422 +  MOZ_ASSERT(texSize != 0);
  1.1423 +  return texSize;
  1.1424 +}
  1.1425 +
  1.1426 +void
  1.1427 +CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
  1.1428 +  if (mDestroyed) {
  1.1429 +    NS_WARNING("Call on destroyed layer manager");
  1.1430 +    return;
  1.1431 +  }
  1.1432 +  mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
  1.1433 +}
  1.1434 +
  1.1435 +void
  1.1436 +CompositorOGL::BindQuadVBO() {
  1.1437 +  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
  1.1438 +}
  1.1439 +
  1.1440 +void
  1.1441 +CompositorOGL::QuadVBOVerticesAttrib(GLuint aAttribIndex) {
  1.1442 +  mGLContext->fVertexAttribPointer(aAttribIndex, 2,
  1.1443 +                                    LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
  1.1444 +                                    (GLvoid*) QuadVBOVertexOffset());
  1.1445 +}
  1.1446 +
  1.1447 +void
  1.1448 +CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
  1.1449 +  mGLContext->fVertexAttribPointer(aAttribIndex, 2,
  1.1450 +                                    LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
  1.1451 +                                    (GLvoid*) QuadVBOTexCoordOffset());
  1.1452 +}
  1.1453 +
  1.1454 +void
  1.1455 +CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
  1.1456 +                               GLuint aTexCoordAttribIndex,
  1.1457 +                               GLuint aDrawMode)
  1.1458 +{
  1.1459 +  BindQuadVBO();
  1.1460 +  QuadVBOVerticesAttrib(aVertAttribIndex);
  1.1461 +
  1.1462 +  if (aTexCoordAttribIndex != GLuint(-1)) {
  1.1463 +    QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
  1.1464 +    mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex);
  1.1465 +  }
  1.1466 +
  1.1467 +  mGLContext->fEnableVertexAttribArray(aVertAttribIndex);
  1.1468 +  if (aDrawMode == LOCAL_GL_LINE_STRIP) {
  1.1469 +    mGLContext->fDrawArrays(aDrawMode, 1, 2);
  1.1470 +  } else {
  1.1471 +    mGLContext->fDrawArrays(aDrawMode, 0, 4);
  1.1472 +  }
  1.1473 +}
  1.1474 +
  1.1475 +void
  1.1476 +CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
  1.1477 +                               GLuint aDrawMode)
  1.1478 +{
  1.1479 +  NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
  1.1480 +  BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib),
  1.1481 +                  aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib),
  1.1482 +                  aDrawMode);
  1.1483 +}
  1.1484 +
  1.1485 +GLuint
  1.1486 +CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
  1.1487 +{
  1.1488 +  if (!mTexturePool) {
  1.1489 +#ifdef MOZ_WIDGET_GONK
  1.1490 +    mTexturePool = new PerFrameTexturePoolOGL(gl());
  1.1491 +#else
  1.1492 +    mTexturePool = new PerUnitTexturePoolOGL(gl());
  1.1493 +#endif
  1.1494 +  }
  1.1495 +  return mTexturePool->GetTexture(aTarget, aUnit);
  1.1496 +}
  1.1497 +
  1.1498 +GLuint
  1.1499 +PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit)
  1.1500 +{
  1.1501 +  if (mTextureTarget == 0) {
  1.1502 +    mTextureTarget = aTarget;
  1.1503 +  }
  1.1504 +  MOZ_ASSERT(mTextureTarget == aTarget);
  1.1505 +
  1.1506 +  size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
  1.1507 +  // lazily grow the array of temporary textures
  1.1508 +  if (mTextures.Length() <= index) {
  1.1509 +    size_t prevLength = mTextures.Length();
  1.1510 +    mTextures.SetLength(index + 1);
  1.1511 +    for(unsigned int i = prevLength; i <= index; ++i) {
  1.1512 +      mTextures[i] = 0;
  1.1513 +    }
  1.1514 +  }
  1.1515 +  // lazily initialize the temporary textures
  1.1516 +  if (!mTextures[index]) {
  1.1517 +    if (!mGL->MakeCurrent()) {
  1.1518 +      return 0;
  1.1519 +    }
  1.1520 +    mGL->fGenTextures(1, &mTextures[index]);
  1.1521 +    mGL->fBindTexture(aTarget, mTextures[index]);
  1.1522 +    mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
  1.1523 +    mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
  1.1524 +  }
  1.1525 +  return mTextures[index];
  1.1526 +}
  1.1527 +
  1.1528 +void
  1.1529 +PerUnitTexturePoolOGL::DestroyTextures()
  1.1530 +{
  1.1531 +  if (mGL && mGL->MakeCurrent()) {
  1.1532 +    if (mTextures.Length() > 0) {
  1.1533 +      mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
  1.1534 +    }
  1.1535 +  }
  1.1536 +  mTextures.SetLength(0);
  1.1537 +}
  1.1538 +
  1.1539 +void
  1.1540 +PerFrameTexturePoolOGL::DestroyTextures()
  1.1541 +{
  1.1542 +  if (!mGL->MakeCurrent()) {
  1.1543 +    return;
  1.1544 +  }
  1.1545 +
  1.1546 +  if (mUnusedTextures.Length() > 0) {
  1.1547 +    mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]);
  1.1548 +    mUnusedTextures.Clear();
  1.1549 +  }
  1.1550 +
  1.1551 +  if (mCreatedTextures.Length() > 0) {
  1.1552 +    mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]);
  1.1553 +    mCreatedTextures.Clear();
  1.1554 +  }
  1.1555 +}
  1.1556 +
  1.1557 +GLuint
  1.1558 +PerFrameTexturePoolOGL::GetTexture(GLenum aTarget, GLenum)
  1.1559 +{
  1.1560 +  if (mTextureTarget == 0) {
  1.1561 +    mTextureTarget = aTarget;
  1.1562 +  }
  1.1563 +
  1.1564 +  // The pool should always use the same texture target because it is illegal
  1.1565 +  // to change the target of an already exisiting gl texture.
  1.1566 +  // If we need to use several targets, a pool with several sub-pools (one per
  1.1567 +  // target) will have to be implemented.
  1.1568 +  // At the moment this pool is only used with tiling on b2g so we always need
  1.1569 +  // the same target.
  1.1570 +  MOZ_ASSERT(mTextureTarget == aTarget);
  1.1571 +
  1.1572 +  GLuint texture = 0;
  1.1573 +
  1.1574 +  if (!mUnusedTextures.IsEmpty()) {
  1.1575 +    // Try to reuse one from the unused pile first
  1.1576 +    texture = mUnusedTextures[0];
  1.1577 +    mUnusedTextures.RemoveElementAt(0);
  1.1578 +  } else if (mGL->MakeCurrent()) {
  1.1579 +    // There isn't one to reuse, create one.
  1.1580 +    mGL->fGenTextures(1, &texture);
  1.1581 +    mGL->fBindTexture(aTarget, texture);
  1.1582 +    mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
  1.1583 +    mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
  1.1584 +  }
  1.1585 +
  1.1586 +  if (texture) {
  1.1587 +    mCreatedTextures.AppendElement(texture);
  1.1588 +  }
  1.1589 +
  1.1590 +  return texture;
  1.1591 +}
  1.1592 +
  1.1593 +void
  1.1594 +PerFrameTexturePoolOGL::EndFrame()
  1.1595 +{
  1.1596 +  if (!mGL->MakeCurrent()) {
  1.1597 +    // this means the context got destroyed underneith us somehow, and the driver
  1.1598 +    // already has destroyed the textures.
  1.1599 +    mCreatedTextures.Clear();
  1.1600 +    mUnusedTextures.Clear();
  1.1601 +    return;
  1.1602 +  }
  1.1603 +
  1.1604 +  // Some platforms have issues unlocking Gralloc buffers even when they're
  1.1605 +  // rebound.
  1.1606 +  if (gfxPrefs::OverzealousGrallocUnlocking()) {
  1.1607 +    mUnusedTextures.AppendElements(mCreatedTextures);
  1.1608 +    mCreatedTextures.Clear();
  1.1609 +  }
  1.1610 +
  1.1611 +  // Delete unused textures
  1.1612 +  for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
  1.1613 +    GLuint texture = mUnusedTextures[i];
  1.1614 +    mGL->fDeleteTextures(1, &texture);
  1.1615 +  }
  1.1616 +  mUnusedTextures.Clear();
  1.1617 +
  1.1618 +  // Move all created textures into the unused pile
  1.1619 +  mUnusedTextures.AppendElements(mCreatedTextures);
  1.1620 +  mCreatedTextures.Clear();
  1.1621 +}
  1.1622 +
  1.1623 +} /* layers */
  1.1624 +} /* mozilla */

mercurial