tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

OGLShaderProgram.cpp (41503B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "OGLShaderProgram.h"
      8 
      9 #include <stdint.h>  // for uint32_t
     10 
     11 #include <sstream>  // for std::ostringstream
     12 
     13 #include "GLContext.h"
     14 #include "gfxEnv.h"
     15 #include "gfxRect.h"  // for gfxRect
     16 #include "gfxUtils.h"
     17 #include "mozilla/DebugOnly.h"  // for DebugOnly
     18 #include "mozilla/gfx/Logging.h"
     19 #include "mozilla/layers/Compositor.h"  // for BlendOpIsMixBlendMode
     20 #include "nsAString.h"
     21 #include "nsString.h"  // for nsAutoCString
     22 
     23 namespace mozilla {
     24 namespace layers {
     25 
     26 using std::endl;
     27 
     28 #define GAUSSIAN_KERNEL_HALF_WIDTH 11
     29 #define GAUSSIAN_KERNEL_STEP 0.2
     30 
     31 static void AddUniforms(ProgramProfileOGL& aProfile) {
     32  // This needs to be kept in sync with the KnownUniformName enum
     33  static const char* sKnownUniformNames[] = {"uLayerTransform",
     34                                             "uLayerTransformInverse",
     35                                             "uMaskTransform",
     36                                             "uBackdropTransform",
     37                                             "uLayerRects",
     38                                             "uMatrixProj",
     39                                             "uTextureTransform",
     40                                             "uTextureRects",
     41                                             "uRenderTargetOffset",
     42                                             "uLayerOpacity",
     43                                             "uTexture",
     44                                             "uYTexture",
     45                                             "uCbTexture",
     46                                             "uCrTexture",
     47                                             "uRenderColor",
     48                                             "uTexCoordMultiplier",
     49                                             "uCbCrTexCoordMultiplier",
     50                                             "uSSEdges",
     51                                             "uViewportSize",
     52                                             "uVisibleCenter",
     53                                             "uYuvColorMatrix",
     54                                             "uYuvOffsetVector",
     55                                             "uRoundedClipRect",
     56                                             "uRoundedClipRadii",
     57                                             nullptr};
     58 
     59  for (int i = 0; sKnownUniformNames[i] != nullptr; ++i) {
     60    aProfile.mUniforms[i].mNameString = sKnownUniformNames[i];
     61    aProfile.mUniforms[i].mName = (KnownUniform::KnownUniformName)i;
     62  }
     63 }
     64 
     65 void ShaderConfigOGL::SetRenderColor(bool aEnabled) {
     66  SetFeature(ENABLE_RENDER_COLOR, aEnabled);
     67 }
     68 
     69 void ShaderConfigOGL::SetTextureTarget(GLenum aTarget) {
     70  SetFeature(ENABLE_TEXTURE_EXTERNAL | ENABLE_TEXTURE_RECT, false);
     71  switch (aTarget) {
     72    case LOCAL_GL_TEXTURE_EXTERNAL:
     73      SetFeature(ENABLE_TEXTURE_EXTERNAL, true);
     74      break;
     75    case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
     76      SetFeature(ENABLE_TEXTURE_RECT, true);
     77      break;
     78  }
     79 }
     80 
     81 void ShaderConfigOGL::SetMaskTextureTarget(GLenum aTarget) {
     82  if (aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
     83    SetFeature(ENABLE_MASK_TEXTURE_RECT, true);
     84  } else {
     85    MOZ_ASSERT(aTarget == LOCAL_GL_TEXTURE_2D);
     86    SetFeature(ENABLE_MASK_TEXTURE_RECT, false);
     87  }
     88 }
     89 
     90 void ShaderConfigOGL::SetRBSwap(bool aEnabled) {
     91  SetFeature(ENABLE_TEXTURE_RB_SWAP, aEnabled);
     92 }
     93 
     94 void ShaderConfigOGL::SetNoAlpha(bool aEnabled) {
     95  SetFeature(ENABLE_TEXTURE_NO_ALPHA, aEnabled);
     96 }
     97 
     98 void ShaderConfigOGL::SetOpacity(bool aEnabled) {
     99  SetFeature(ENABLE_OPACITY, aEnabled);
    100 }
    101 
    102 void ShaderConfigOGL::SetYCbCr(bool aEnabled) {
    103  SetFeature(ENABLE_TEXTURE_YCBCR, aEnabled);
    104  MOZ_ASSERT(!(mFeatures & ENABLE_TEXTURE_NV12));
    105 }
    106 
    107 void ShaderConfigOGL::SetColorMultiplier(uint32_t aMultiplier) {
    108  MOZ_ASSERT(mFeatures & ENABLE_TEXTURE_YCBCR,
    109             "Multiplier only supported with YCbCr!");
    110  mMultiplier = aMultiplier;
    111 }
    112 
    113 void ShaderConfigOGL::SetRoundedClip(bool aEnabled) {
    114  SetFeature(ENABLE_ROUNDED_CLIP, aEnabled);
    115 }
    116 
    117 void ShaderConfigOGL::SetNV12(bool aEnabled) {
    118  SetFeature(ENABLE_TEXTURE_NV12, aEnabled);
    119  MOZ_ASSERT(!(mFeatures & ENABLE_TEXTURE_YCBCR));
    120 #ifdef MOZ_WIDGET_GTK
    121  SetFeature(ENABLE_TEXTURE_NV12_GA_SWITCH, aEnabled);
    122 #endif
    123 }
    124 
    125 void ShaderConfigOGL::SetComponentAlpha(bool aEnabled) {
    126  SetFeature(ENABLE_TEXTURE_COMPONENT_ALPHA, aEnabled);
    127 }
    128 
    129 void ShaderConfigOGL::SetColorMatrix(bool aEnabled) {
    130  SetFeature(ENABLE_COLOR_MATRIX, aEnabled);
    131 }
    132 
    133 void ShaderConfigOGL::SetBlur(bool aEnabled) {
    134  SetFeature(ENABLE_BLUR, aEnabled);
    135 }
    136 
    137 void ShaderConfigOGL::SetMask(bool aEnabled) {
    138  SetFeature(ENABLE_MASK, aEnabled);
    139 }
    140 
    141 void ShaderConfigOGL::SetNoPremultipliedAlpha() {
    142  SetFeature(ENABLE_NO_PREMUL_ALPHA, true);
    143 }
    144 
    145 void ShaderConfigOGL::SetDEAA(bool aEnabled) {
    146  SetFeature(ENABLE_DEAA, aEnabled);
    147 }
    148 
    149 void ShaderConfigOGL::SetCompositionOp(gfx::CompositionOp aOp) {
    150  mCompositionOp = aOp;
    151 }
    152 
    153 void ShaderConfigOGL::SetDynamicGeometry(bool aEnabled) {
    154  SetFeature(ENABLE_DYNAMIC_GEOMETRY, aEnabled);
    155 }
    156 
    157 /* static */
    158 ProgramProfileOGL ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig) {
    159  ProgramProfileOGL result;
    160  std::ostringstream fs, vs;
    161 
    162  AddUniforms(result);
    163 
    164  gfx::CompositionOp blendOp = aConfig.mCompositionOp;
    165 
    166  vs << "#ifdef GL_ES" << endl;
    167  vs << "#define EDGE_PRECISION mediump" << endl;
    168  vs << "#else" << endl;
    169  vs << "#define EDGE_PRECISION" << endl;
    170  vs << "#endif" << endl;
    171  vs << "uniform mat4 uMatrixProj;" << endl;
    172  vs << "uniform vec4 uLayerRects[4];" << endl;
    173  vs << "uniform mat4 uLayerTransform;" << endl;
    174  if (aConfig.mFeatures & ENABLE_DEAA) {
    175    vs << "uniform mat4 uLayerTransformInverse;" << endl;
    176    vs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
    177    vs << "uniform vec2 uVisibleCenter;" << endl;
    178    vs << "uniform vec2 uViewportSize;" << endl;
    179  }
    180  vs << "uniform vec2 uRenderTargetOffset;" << endl;
    181  if (aConfig.mFeatures & ENABLE_ROUNDED_CLIP) {
    182    vs << "uniform vec4 uRoundedClipRect;" << endl;
    183    vs << "varying vec2 vRoundedClipSize;" << endl;
    184    vs << "varying vec2 vRoundedClipPos;" << endl;
    185  }
    186 
    187  if (!(aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY)) {
    188    vs << "attribute vec4 aCoord;" << endl;
    189  } else {
    190    vs << "attribute vec2 aCoord;" << endl;
    191  }
    192 
    193  result.mAttributes.AppendElement(std::pair<nsCString, GLuint>{"aCoord", 0});
    194 
    195  if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
    196    vs << "uniform mat4 uTextureTransform;" << endl;
    197    vs << "uniform vec4 uTextureRects[4];" << endl;
    198    vs << "varying vec2 vTexCoord;" << endl;
    199 
    200    if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
    201      vs << "attribute vec2 aTexCoord;" << endl;
    202      result.mAttributes.AppendElement(
    203          std::pair<nsCString, GLuint>{"aTexCoord", 1});
    204    }
    205  }
    206 
    207  if (BlendOpIsMixBlendMode(blendOp)) {
    208    vs << "uniform mat4 uBackdropTransform;" << endl;
    209    vs << "varying vec2 vBackdropCoord;" << endl;
    210  }
    211 
    212  if (aConfig.mFeatures & ENABLE_MASK) {
    213    vs << "uniform mat4 uMaskTransform;" << endl;
    214    vs << "varying vec3 vMaskCoord;" << endl;
    215  }
    216 
    217  vs << "void main() {" << endl;
    218 
    219  if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
    220    vs << "  vec4 finalPosition = vec4(aCoord.xy, 0.0, 1.0);" << endl;
    221  } else {
    222    vs << "  int vertexID = int(aCoord.w);" << endl;
    223    vs << "  vec4 layerRect = uLayerRects[vertexID];" << endl;
    224    vs << "  vec4 finalPosition = vec4(aCoord.xy * layerRect.zw + "
    225          "layerRect.xy, 0.0, 1.0);"
    226       << endl;
    227  }
    228 
    229  vs << "  finalPosition = uLayerTransform * finalPosition;" << endl;
    230 
    231  if (aConfig.mFeatures & ENABLE_ROUNDED_CLIP) {
    232    vs << "  vec2 halfSize = 0.5 * uRoundedClipRect.zw;" << endl;
    233    vs << "  vRoundedClipPos = uRoundedClipRect.xy + halfSize - "
    234          "finalPosition.xy;"
    235       << endl;
    236    vs << "  vRoundedClipSize = halfSize;" << endl;
    237  }
    238 
    239  if (aConfig.mFeatures & ENABLE_DEAA) {
    240    // XXX kip - The DEAA shader could be made simpler if we switch to
    241    //           using dynamic vertex buffers instead of sending everything
    242    //           in through uniforms.  This would enable passing information
    243    //           about how to dilate each vertex explicitly and eliminate the
    244    //           need to extrapolate this with the sub-pixel coverage
    245    //           calculation in the vertex shader.
    246 
    247    // Calculate the screen space position of this vertex, in screen pixels
    248    vs << "  vec4 ssPos = finalPosition;" << endl;
    249    vs << "  ssPos.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
    250    vs << "  ssPos = uMatrixProj * ssPos;" << endl;
    251    vs << "  ssPos.xy = ((ssPos.xy/ssPos.w)*0.5+0.5)*uViewportSize;" << endl;
    252 
    253    if (aConfig.mFeatures & ENABLE_MASK ||
    254        !(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
    255      vs << "  vec4 coordAdjusted;" << endl;
    256      vs << "  coordAdjusted.xy = aCoord.xy;" << endl;
    257    }
    258 
    259    // It is necessary to dilate edges away from uVisibleCenter to ensure that
    260    // fragments with less than 50% sub-pixel coverage will be shaded.
    261    // This offset is applied when the sub-pixel coverage of the vertex is
    262    // less than 100%.  Expanding by 0.5 pixels in screen space is sufficient
    263    // to include these pixels.
    264    vs << "  if (dot(uSSEdges[0], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
    265    vs << "      dot(uSSEdges[1], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
    266    vs << "      dot(uSSEdges[2], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
    267    vs << "      dot(uSSEdges[3], vec3(ssPos.xy, 1.0)) < 1.5) {" << endl;
    268    // If the shader reaches this branch, then this vertex is on the edge of
    269    // the layer's visible rect and should be dilated away from the center of
    270    // the visible rect.  We don't want to hit this for inner facing
    271    // edges between tiles, as the pixels may be covered twice without clipping
    272    // against uSSEdges.  If all edges were dilated, it would result in
    273    // artifacts visible within semi-transparent layers with multiple tiles.
    274    vs << "    vec4 visibleCenter = uLayerTransform * vec4(uVisibleCenter, "
    275          "0.0, 1.0);"
    276       << endl;
    277    vs << "    vec2 dilateDir = finalPosition.xy / finalPosition.w - "
    278          "visibleCenter.xy / visibleCenter.w;"
    279       << endl;
    280    vs << "    vec2 offset = sign(dilateDir) * 0.5;" << endl;
    281    vs << "    finalPosition.xy += offset * finalPosition.w;" << endl;
    282    if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
    283      // We must adjust the texture coordinates to compensate for the dilation
    284      vs << "    coordAdjusted = uLayerTransformInverse * finalPosition;"
    285         << endl;
    286      vs << "    coordAdjusted /= coordAdjusted.w;" << endl;
    287 
    288      if (!(aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY)) {
    289        vs << "    coordAdjusted.xy -= layerRect.xy;" << endl;
    290        vs << "    coordAdjusted.xy /= layerRect.zw;" << endl;
    291      }
    292    }
    293    vs << "  }" << endl;
    294 
    295    if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
    296      if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
    297        vs << "  vTexCoord = (uTextureTransform * vec4(aTexCoord, 0.0, "
    298              "1.0)).xy;"
    299           << endl;
    300      } else {
    301        vs << "  vec4 textureRect = uTextureRects[vertexID];" << endl;
    302        vs << "  vec2 texCoord = coordAdjusted.xy * textureRect.zw + "
    303              "textureRect.xy;"
    304           << endl;
    305        vs << "  vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;"
    306           << endl;
    307      }
    308    }
    309  } else if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
    310    if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
    311      vs << "  vTexCoord = (uTextureTransform * vec4(aTexCoord, 0.0, 1.0)).xy;"
    312         << endl;
    313    } else {
    314      vs << "  vec4 textureRect = uTextureRects[vertexID];" << endl;
    315      vs << "  vec2 texCoord = aCoord.xy * textureRect.zw + textureRect.xy;"
    316         << endl;
    317      vs << "  vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;"
    318         << endl;
    319    }
    320  }
    321 
    322  if (aConfig.mFeatures & ENABLE_MASK) {
    323    vs << "  vMaskCoord.xy = (uMaskTransform * (finalPosition / "
    324          "finalPosition.w)).xy;"
    325       << endl;
    326    // correct for perspective correct interpolation, see comment in D3D11
    327    // shader
    328    vs << "  vMaskCoord.z = 1.0;" << endl;
    329    vs << "  vMaskCoord *= finalPosition.w;" << endl;
    330  }
    331  vs << "  finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
    332  vs << "  finalPosition = uMatrixProj * finalPosition;" << endl;
    333  if (BlendOpIsMixBlendMode(blendOp)) {
    334    // Translate from clip space (-1, 1) to (0..1), apply the backdrop
    335    // transform, then invert the y-axis.
    336    vs << "  vBackdropCoord.x = (finalPosition.x + 1.0) / 2.0;" << endl;
    337    vs << "  vBackdropCoord.y = 1.0 - (finalPosition.y + 1.0) / 2.0;" << endl;
    338    vs << "  vBackdropCoord = (uBackdropTransform * vec4(vBackdropCoord.xy, "
    339          "0.0, 1.0)).xy;"
    340       << endl;
    341    vs << "  vBackdropCoord.y = 1.0 - vBackdropCoord.y;" << endl;
    342  }
    343  vs << "  gl_Position = finalPosition;" << endl;
    344  vs << "}" << endl;
    345 
    346  if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
    347    fs << "#extension GL_ARB_texture_rectangle : require" << endl;
    348  }
    349  if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
    350    fs << "#extension GL_OES_EGL_image_external : require" << endl;
    351  }
    352  fs << "#ifdef GL_ES" << endl;
    353  fs << "precision mediump float;" << endl;
    354  fs << "#define COLOR_PRECISION lowp" << endl;
    355  fs << "#define EDGE_PRECISION mediump" << endl;
    356  fs << "#else" << endl;
    357  fs << "#define COLOR_PRECISION" << endl;
    358  fs << "#define EDGE_PRECISION" << endl;
    359  fs << "#endif" << endl;
    360  if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
    361    fs << "uniform COLOR_PRECISION vec4 uRenderColor;" << endl;
    362  } else {
    363    // for tiling, texcoord can be greater than the lowfp range
    364    fs << "varying vec2 vTexCoord;" << endl;
    365    if (aConfig.mFeatures & ENABLE_BLUR) {
    366      fs << "uniform bool uBlurAlpha;" << endl;
    367      fs << "uniform vec2 uBlurRadius;" << endl;
    368      fs << "uniform vec2 uBlurOffset;" << endl;
    369      fs << "uniform float uBlurGaussianKernel[" << GAUSSIAN_KERNEL_HALF_WIDTH
    370         << "];" << endl;
    371    }
    372    if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) {
    373      fs << "uniform mat4 uColorMatrix;" << endl;
    374      fs << "uniform vec4 uColorMatrixVector;" << endl;
    375    }
    376    if (aConfig.mFeatures & ENABLE_OPACITY) {
    377      fs << "uniform COLOR_PRECISION float uLayerOpacity;" << endl;
    378    }
    379  }
    380  if (aConfig.mFeatures & ENABLE_ROUNDED_CLIP) {
    381    fs << "uniform vec4 uRoundedClipRadii;" << endl;
    382    fs << "varying vec2 vRoundedClipSize;" << endl;
    383    fs << "varying vec2 vRoundedClipPos;" << endl;
    384  }
    385  if (BlendOpIsMixBlendMode(blendOp)) {
    386    fs << "varying vec2 vBackdropCoord;" << endl;
    387  }
    388 
    389  const char* sampler2D = "sampler2D";
    390  const char* texture2D = "texture2D";
    391 
    392  if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
    393    fs << "uniform vec2 uTexCoordMultiplier;" << endl;
    394    if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR ||
    395        aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
    396      fs << "uniform vec2 uCbCrTexCoordMultiplier;" << endl;
    397    }
    398    sampler2D = "sampler2DRect";
    399    texture2D = "texture2DRect";
    400  }
    401 
    402  const char* maskSampler2D = "sampler2D";
    403  const char* maskTexture2D = "texture2D";
    404 
    405  if (aConfig.mFeatures & ENABLE_MASK &&
    406      aConfig.mFeatures & ENABLE_MASK_TEXTURE_RECT) {
    407    fs << "uniform vec2 uMaskCoordMultiplier;" << endl;
    408    maskSampler2D = "sampler2DRect";
    409    maskTexture2D = "texture2DRect";
    410  }
    411 
    412  if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
    413    sampler2D = "samplerExternalOES";
    414  }
    415 
    416  if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
    417    fs << "uniform " << sampler2D << " uYTexture;" << endl;
    418    fs << "uniform " << sampler2D << " uCbTexture;" << endl;
    419    fs << "uniform " << sampler2D << " uCrTexture;" << endl;
    420    fs << "uniform mat3 uYuvColorMatrix;" << endl;
    421    fs << "uniform vec3 uYuvOffsetVector;" << endl;
    422  } else if (aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
    423    fs << "uniform " << sampler2D << " uYTexture;" << endl;
    424    fs << "uniform " << sampler2D << " uCbTexture;" << endl;
    425    fs << "uniform mat3 uYuvColorMatrix;" << endl;
    426    fs << "uniform vec3 uYuvOffsetVector;" << endl;
    427  } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
    428    fs << "uniform " << sampler2D << " uBlackTexture;" << endl;
    429    fs << "uniform " << sampler2D << " uWhiteTexture;" << endl;
    430    fs << "uniform bool uTexturePass2;" << endl;
    431  } else {
    432    fs << "uniform " << sampler2D << " uTexture;" << endl;
    433  }
    434 
    435  if (BlendOpIsMixBlendMode(blendOp)) {
    436    // Component alpha should be flattened away inside blend containers.
    437    MOZ_ASSERT(!(aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA));
    438 
    439    fs << "uniform sampler2D uBackdropTexture;" << endl;
    440  }
    441 
    442  if (aConfig.mFeatures & ENABLE_MASK) {
    443    fs << "varying vec3 vMaskCoord;" << endl;
    444    fs << "uniform " << maskSampler2D << " uMaskTexture;" << endl;
    445  }
    446 
    447  if (aConfig.mFeatures & ENABLE_DEAA) {
    448    fs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
    449  }
    450 
    451  if (BlendOpIsMixBlendMode(blendOp)) {
    452    BuildMixBlender(aConfig, fs);
    453  }
    454 
    455  if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
    456    fs << "vec4 sample(vec2 coord) {" << endl;
    457    fs << "  vec4 color;" << endl;
    458    if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR ||
    459        aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
    460      if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
    461        if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
    462          fs << "  COLOR_PRECISION float y = " << texture2D
    463             << "(uYTexture, coord * uTexCoordMultiplier).r;" << endl;
    464          fs << "  COLOR_PRECISION float cb = " << texture2D
    465             << "(uCbTexture, coord * uCbCrTexCoordMultiplier).r;" << endl;
    466          fs << "  COLOR_PRECISION float cr = " << texture2D
    467             << "(uCrTexture, coord * uCbCrTexCoordMultiplier).r;" << endl;
    468        } else {
    469          fs << "  COLOR_PRECISION float y = " << texture2D
    470             << "(uYTexture, coord).r;" << endl;
    471          fs << "  COLOR_PRECISION float cb = " << texture2D
    472             << "(uCbTexture, coord).r;" << endl;
    473          fs << "  COLOR_PRECISION float cr = " << texture2D
    474             << "(uCrTexture, coord).r;" << endl;
    475        }
    476      } else {
    477        if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
    478          fs << "  COLOR_PRECISION float y = " << texture2D
    479             << "(uYTexture, coord * uTexCoordMultiplier).r;" << endl;
    480          fs << "  COLOR_PRECISION float cb = " << texture2D
    481             << "(uCbTexture, coord * uCbCrTexCoordMultiplier).r;" << endl;
    482          if (aConfig.mFeatures & ENABLE_TEXTURE_NV12_GA_SWITCH) {
    483            fs << "  COLOR_PRECISION float cr = " << texture2D
    484               << "(uCbTexture, coord * uCbCrTexCoordMultiplier).g;" << endl;
    485          } else {
    486            fs << "  COLOR_PRECISION float cr = " << texture2D
    487               << "(uCbTexture, coord * uCbCrTexCoordMultiplier).a;" << endl;
    488          }
    489        } else {
    490          fs << "  COLOR_PRECISION float y = " << texture2D
    491             << "(uYTexture, coord).r;" << endl;
    492          fs << "  COLOR_PRECISION float cb = " << texture2D
    493             << "(uCbTexture, coord).r;" << endl;
    494          if (aConfig.mFeatures & ENABLE_TEXTURE_NV12_GA_SWITCH) {
    495            fs << "  COLOR_PRECISION float cr = " << texture2D
    496               << "(uCbTexture, coord).g;" << endl;
    497          } else {
    498            fs << "  COLOR_PRECISION float cr = " << texture2D
    499               << "(uCbTexture, coord).a;" << endl;
    500          }
    501        }
    502      }
    503      fs << "  vec3 yuv = vec3(y, cb, cr);" << endl;
    504      if (aConfig.mMultiplier != 1) {
    505        fs << "  yuv *= " << aConfig.mMultiplier << ".0;" << endl;
    506      }
    507      fs << "  yuv -= uYuvOffsetVector;" << endl;
    508      fs << "  color.rgb = uYuvColorMatrix * yuv;" << endl;
    509      fs << "  color.a = 1.0;" << endl;
    510    } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
    511      if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
    512        fs << "  COLOR_PRECISION vec3 onBlack = " << texture2D
    513           << "(uBlackTexture, coord * uTexCoordMultiplier).rgb;" << endl;
    514        fs << "  COLOR_PRECISION vec3 onWhite = " << texture2D
    515           << "(uWhiteTexture, coord * uTexCoordMultiplier).rgb;" << endl;
    516      } else {
    517        fs << "  COLOR_PRECISION vec3 onBlack = " << texture2D
    518           << "(uBlackTexture, coord).rgb;" << endl;
    519        fs << "  COLOR_PRECISION vec3 onWhite = " << texture2D
    520           << "(uWhiteTexture, coord).rgb;" << endl;
    521      }
    522      fs << "  COLOR_PRECISION vec4 alphas = (1.0 - onWhite + onBlack).rgbg;"
    523         << endl;
    524      fs << "  if (uTexturePass2)" << endl;
    525      fs << "    color = vec4(onBlack, alphas.a);" << endl;
    526      fs << "  else" << endl;
    527      fs << "    color = alphas;" << endl;
    528    } else {
    529      if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
    530        fs << "  color = " << texture2D
    531           << "(uTexture, coord * uTexCoordMultiplier);" << endl;
    532      } else {
    533        fs << "  color = " << texture2D << "(uTexture, coord);" << endl;
    534      }
    535    }
    536    if (aConfig.mFeatures & ENABLE_TEXTURE_RB_SWAP) {
    537      fs << "  color = color.bgra;" << endl;
    538    }
    539    if (aConfig.mFeatures & ENABLE_TEXTURE_NO_ALPHA) {
    540      fs << "  color = vec4(color.rgb, 1.0);" << endl;
    541    }
    542    fs << "  return color;" << endl;
    543    fs << "}" << endl;
    544    if (aConfig.mFeatures & ENABLE_BLUR) {
    545      fs << "vec4 sampleAtRadius(vec2 coord, float radius) {" << endl;
    546      fs << "  coord += uBlurOffset;" << endl;
    547      fs << "  coord += radius * uBlurRadius;" << endl;
    548      fs << "  if (coord.x < 0. || coord.y < 0. || coord.x > 1. || coord.y > "
    549            "1.)"
    550         << endl;
    551      fs << "    return vec4(0, 0, 0, 0);" << endl;
    552      fs << "  return sample(coord);" << endl;
    553      fs << "}" << endl;
    554      fs << "vec4 blur(vec4 color, vec2 coord) {" << endl;
    555      fs << "  vec4 total = color * uBlurGaussianKernel[0];" << endl;
    556      fs << "  for (int i = 1; i < " << GAUSSIAN_KERNEL_HALF_WIDTH << "; ++i) {"
    557         << endl;
    558      fs << "    float r = float(i) * " << GAUSSIAN_KERNEL_STEP << ";" << endl;
    559      fs << "    float k = uBlurGaussianKernel[i];" << endl;
    560      fs << "    total += sampleAtRadius(coord, r) * k;" << endl;
    561      fs << "    total += sampleAtRadius(coord, -r) * k;" << endl;
    562      fs << "  }" << endl;
    563      fs << "  if (uBlurAlpha) {" << endl;
    564      fs << "    color *= total.a;" << endl;
    565      fs << "  } else {" << endl;
    566      fs << "    color = total;" << endl;
    567      fs << "  }" << endl;
    568      fs << "  return color;" << endl;
    569      fs << "}" << endl;
    570    }
    571  }
    572  if (aConfig.mFeatures & ENABLE_ROUNDED_CLIP) {
    573    fs << "float sd_round_box(vec2 pos, vec2 half_box_size, vec4 radii) {"
    574       << endl;
    575    fs << "  radii.xy = (pos.x > 0.0) ? radii.xy : radii.zw;" << endl;
    576    fs << "  radii.x  = (pos.y > 0.0) ? radii.x  : radii.y;" << endl;
    577    fs << "  vec2 q = abs(pos) - half_box_size + radii.x;" << endl;
    578    fs << "  return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - radii.x;"
    579       << endl;
    580    fs << "}" << endl;
    581  }
    582  fs << "void main() {" << endl;
    583  if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
    584    fs << "  vec4 color = uRenderColor;" << endl;
    585  } else {
    586    fs << "  vec4 color = sample(vTexCoord);" << endl;
    587    if (aConfig.mFeatures & ENABLE_BLUR) {
    588      fs << "  color = blur(color, vTexCoord);" << endl;
    589    }
    590    if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) {
    591      fs << "  color = uColorMatrix * vec4(color.rgb / color.a, color.a) + "
    592            "uColorMatrixVector;"
    593         << endl;
    594      fs << "  color.rgb *= color.a;" << endl;
    595    }
    596    if (aConfig.mFeatures & ENABLE_OPACITY) {
    597      fs << "  color *= uLayerOpacity;" << endl;
    598    }
    599  }
    600  if (aConfig.mFeatures & ENABLE_DEAA) {
    601    // Calculate the sub-pixel coverage of the pixel and modulate its opacity
    602    // by that amount to perform DEAA.
    603    fs << "  vec3 ssPos = vec3(gl_FragCoord.xy, 1.0);" << endl;
    604    fs << "  float deaaCoverage = clamp(dot(uSSEdges[0], ssPos), 0.0, 1.0);"
    605       << endl;
    606    fs << "  deaaCoverage *= clamp(dot(uSSEdges[1], ssPos), 0.0, 1.0);" << endl;
    607    fs << "  deaaCoverage *= clamp(dot(uSSEdges[2], ssPos), 0.0, 1.0);" << endl;
    608    fs << "  deaaCoverage *= clamp(dot(uSSEdges[3], ssPos), 0.0, 1.0);" << endl;
    609    fs << "  color *= deaaCoverage;" << endl;
    610  }
    611  if (BlendOpIsMixBlendMode(blendOp)) {
    612    fs << "  vec4 backdrop = texture2D(uBackdropTexture, vBackdropCoord);"
    613       << endl;
    614    fs << "  color = mixAndBlend(backdrop, color);" << endl;
    615  }
    616  if (aConfig.mFeatures & ENABLE_MASK) {
    617    fs << "  vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl;
    618    if (aConfig.mFeatures & ENABLE_MASK_TEXTURE_RECT) {
    619      fs << "  COLOR_PRECISION float mask = " << maskTexture2D
    620         << "(uMaskTexture, maskCoords * uMaskCoordMultiplier).r;" << endl;
    621    } else {
    622      fs << "  COLOR_PRECISION float mask = " << maskTexture2D
    623         << "(uMaskTexture, maskCoords).r;" << endl;
    624    }
    625    fs << "  color *= mask;" << endl;
    626  } else {
    627    fs << "  COLOR_PRECISION float mask = 1.0;" << endl;
    628    fs << "  color *= mask;" << endl;
    629  }
    630  if (aConfig.mFeatures & ENABLE_ROUNDED_CLIP) {
    631    fs << "  float d = sd_round_box(vRoundedClipPos, vRoundedClipSize, "
    632          "uRoundedClipRadii);"
    633       << endl;
    634    // TODO(gw): Probably want some proper AA step here
    635    fs << "  color *= 1.0 - clamp(d, 0.0, 1.0);" << endl;
    636  }
    637  fs << "  gl_FragColor = color;" << endl;
    638  fs << "}" << endl;
    639 
    640  result.mVertexShaderString = vs.str();
    641  result.mFragmentShaderString = fs.str();
    642 
    643  if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
    644    result.mTextureCount = 0;
    645  } else {
    646    if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
    647      result.mTextureCount = 3;
    648    } else if (aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
    649      result.mTextureCount = 2;
    650    } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
    651      result.mTextureCount = 2;
    652    } else {
    653      result.mTextureCount = 1;
    654    }
    655  }
    656  if (aConfig.mFeatures & ENABLE_MASK) {
    657    result.mTextureCount = 1;
    658  }
    659  if (BlendOpIsMixBlendMode(blendOp)) {
    660    result.mTextureCount += 1;
    661  }
    662 
    663  return result;
    664 }
    665 
    666 void ProgramProfileOGL::BuildMixBlender(const ShaderConfigOGL& aConfig,
    667                                        std::ostringstream& fs) {
    668  // From the "Compositing and Blending Level 1" spec.
    669  // Generate helper functions first.
    670  switch (aConfig.mCompositionOp) {
    671    case gfx::CompositionOp::OP_OVERLAY:
    672    case gfx::CompositionOp::OP_HARD_LIGHT:
    673      // Note: we substitute (2*src-1) into the screen formula below.
    674      fs << "float hardlight(float dest, float src) {" << endl;
    675      fs << "  if (src <= 0.5) {" << endl;
    676      fs << "    return dest * (2.0 * src);" << endl;
    677      fs << "  } else {" << endl;
    678      fs << "    return 2.0*dest + 2.0*src - 1.0 - 2.0*dest*src;" << endl;
    679      fs << "  }" << endl;
    680      fs << "}" << endl;
    681      break;
    682    case gfx::CompositionOp::OP_COLOR_DODGE:
    683      fs << "float dodge(float dest, float src) {" << endl;
    684      fs << "  if (dest == 0.0) {" << endl;
    685      fs << "    return 0.0;" << endl;
    686      fs << "  } else if (src == 1.0) {" << endl;
    687      fs << "    return 1.0;" << endl;
    688      fs << "  } else {" << endl;
    689      fs << "    return min(1.0, dest / (1.0 - src));" << endl;
    690      fs << "  }" << endl;
    691      fs << "}" << endl;
    692      break;
    693    case gfx::CompositionOp::OP_COLOR_BURN:
    694      fs << "float burn(float dest, float src) {" << endl;
    695      fs << "  if (dest == 1.0) {" << endl;
    696      fs << "    return 1.0;" << endl;
    697      fs << "  } else if (src == 0.0) {" << endl;
    698      fs << "    return 0.0;" << endl;
    699      fs << "  } else {" << endl;
    700      fs << "    return 1.0 - min(1.0, (1.0 - dest) / src);" << endl;
    701      fs << "  }" << endl;
    702      fs << "}" << endl;
    703      break;
    704    case gfx::CompositionOp::OP_SOFT_LIGHT:
    705      fs << "float darken(float dest) {" << endl;
    706      fs << "  if (dest <= 0.25) {" << endl;
    707      fs << "    return ((16.0 * dest - 12.0) * dest + 4.0) * dest;" << endl;
    708      fs << "  } else {" << endl;
    709      fs << "    return sqrt(dest);" << endl;
    710      fs << "  }" << endl;
    711      fs << "}" << endl;
    712      fs << "float softlight(float dest, float src) {" << endl;
    713      fs << "  if (src <= 0.5) {" << endl;
    714      fs << "    return dest - (1.0 - 2.0 * src) * dest * (1.0 - dest);"
    715         << endl;
    716      fs << "  } else {" << endl;
    717      fs << "    return dest + (2.0 * src - 1.0) * (darken(dest) - dest);"
    718         << endl;
    719      fs << "  }" << endl;
    720      fs << "}" << endl;
    721      break;
    722    case gfx::CompositionOp::OP_HUE:
    723    case gfx::CompositionOp::OP_SATURATION:
    724    case gfx::CompositionOp::OP_COLOR:
    725    case gfx::CompositionOp::OP_LUMINOSITY:
    726      fs << "float Lum(vec3 c) {" << endl;
    727      fs << "  return dot(vec3(0.3, 0.59, 0.11), c);" << endl;
    728      fs << "}" << endl;
    729      fs << "vec3 ClipColor(vec3 c) {" << endl;
    730      fs << "  float L = Lum(c);" << endl;
    731      fs << "  float n = min(min(c.r, c.g), c.b);" << endl;
    732      fs << "  float x = max(max(c.r, c.g), c.b);" << endl;
    733      fs << "  if (n < 0.0) {" << endl;
    734      fs << "    c = L + (((c - L) * L) / (L - n));" << endl;
    735      fs << "  }" << endl;
    736      fs << "  if (x > 1.0) {" << endl;
    737      fs << "    c = L + (((c - L) * (1.0 - L)) / (x - L));" << endl;
    738      fs << "  }" << endl;
    739      fs << "  return c;" << endl;
    740      fs << "}" << endl;
    741      fs << "vec3 SetLum(vec3 c, float L) {" << endl;
    742      fs << "  float d = L - Lum(c);" << endl;
    743      fs << "  return ClipColor(vec3(" << endl;
    744      fs << "    c.r + d," << endl;
    745      fs << "    c.g + d," << endl;
    746      fs << "    c.b + d));" << endl;
    747      fs << "}" << endl;
    748      fs << "float Sat(vec3 c) {" << endl;
    749      fs << "  return max(max(c.r, c.g), c.b) - min(min(c.r, c.g), c.b);"
    750         << endl;
    751      fs << "}" << endl;
    752 
    753      // To use this helper, re-arrange rgb such that r=min, g=mid, and b=max.
    754      fs << "vec3 SetSatInner(vec3 c, float s) {" << endl;
    755      fs << "  if (c.b > c.r) {" << endl;
    756      fs << "    c.g = (((c.g - c.r) * s) / (c.b - c.r));" << endl;
    757      fs << "    c.b = s;" << endl;
    758      fs << "  } else {" << endl;
    759      fs << "    c.gb = vec2(0.0, 0.0);" << endl;
    760      fs << "  }" << endl;
    761      fs << "  return vec3(0.0, c.gb);" << endl;
    762      fs << "}" << endl;
    763 
    764      fs << "vec3 SetSat(vec3 c, float s) {" << endl;
    765      fs << "  if (c.r <= c.g) {" << endl;
    766      fs << "    if (c.g <= c.b) {" << endl;
    767      fs << "      c.rgb = SetSatInner(c.rgb, s);" << endl;
    768      fs << "    } else if (c.r <= c.b) {" << endl;
    769      fs << "      c.rbg = SetSatInner(c.rbg, s);" << endl;
    770      fs << "    } else {" << endl;
    771      fs << "      c.brg = SetSatInner(c.brg, s);" << endl;
    772      fs << "    }" << endl;
    773      fs << "  } else if (c.r <= c.b) {" << endl;
    774      fs << "    c.grb = SetSatInner(c.grb, s);" << endl;
    775      fs << "  } else if (c.g <= c.b) {" << endl;
    776      fs << "    c.gbr = SetSatInner(c.gbr, s);" << endl;
    777      fs << "  } else {" << endl;
    778      fs << "    c.bgr = SetSatInner(c.bgr, s);" << endl;
    779      fs << "  }" << endl;
    780      fs << "  return c;" << endl;
    781      fs << "}" << endl;
    782      break;
    783    default:
    784      break;
    785  }
    786 
    787  // Generate the main blending helper.
    788  fs << "vec3 blend(vec3 dest, vec3 src) {" << endl;
    789  switch (aConfig.mCompositionOp) {
    790    case gfx::CompositionOp::OP_MULTIPLY:
    791      fs << "  return dest * src;" << endl;
    792      break;
    793    case gfx::CompositionOp::OP_SCREEN:
    794      fs << "  return dest + src - (dest * src);" << endl;
    795      break;
    796    case gfx::CompositionOp::OP_OVERLAY:
    797      fs << "  return vec3(" << endl;
    798      fs << "    hardlight(src.r, dest.r)," << endl;
    799      fs << "    hardlight(src.g, dest.g)," << endl;
    800      fs << "    hardlight(src.b, dest.b));" << endl;
    801      break;
    802    case gfx::CompositionOp::OP_DARKEN:
    803      fs << "  return min(dest, src);" << endl;
    804      break;
    805    case gfx::CompositionOp::OP_LIGHTEN:
    806      fs << "  return max(dest, src);" << endl;
    807      break;
    808    case gfx::CompositionOp::OP_COLOR_DODGE:
    809      fs << "  return vec3(" << endl;
    810      fs << "    dodge(dest.r, src.r)," << endl;
    811      fs << "    dodge(dest.g, src.g)," << endl;
    812      fs << "    dodge(dest.b, src.b));" << endl;
    813      break;
    814    case gfx::CompositionOp::OP_COLOR_BURN:
    815      fs << "  return vec3(" << endl;
    816      fs << "    burn(dest.r, src.r)," << endl;
    817      fs << "    burn(dest.g, src.g)," << endl;
    818      fs << "    burn(dest.b, src.b));" << endl;
    819      break;
    820    case gfx::CompositionOp::OP_HARD_LIGHT:
    821      fs << "  return vec3(" << endl;
    822      fs << "    hardlight(dest.r, src.r)," << endl;
    823      fs << "    hardlight(dest.g, src.g)," << endl;
    824      fs << "    hardlight(dest.b, src.b));" << endl;
    825      break;
    826    case gfx::CompositionOp::OP_SOFT_LIGHT:
    827      fs << "  return vec3(" << endl;
    828      fs << "    softlight(dest.r, src.r)," << endl;
    829      fs << "    softlight(dest.g, src.g)," << endl;
    830      fs << "    softlight(dest.b, src.b));" << endl;
    831      break;
    832    case gfx::CompositionOp::OP_DIFFERENCE:
    833      fs << "  return abs(dest - src);" << endl;
    834      break;
    835    case gfx::CompositionOp::OP_EXCLUSION:
    836      fs << "  return dest + src - 2.0*dest*src;" << endl;
    837      break;
    838    case gfx::CompositionOp::OP_HUE:
    839      fs << "  return SetLum(SetSat(src, Sat(dest)), Lum(dest));" << endl;
    840      break;
    841    case gfx::CompositionOp::OP_SATURATION:
    842      fs << "  return SetLum(SetSat(dest, Sat(src)), Lum(dest));" << endl;
    843      break;
    844    case gfx::CompositionOp::OP_COLOR:
    845      fs << "  return SetLum(src, Lum(dest));" << endl;
    846      break;
    847    case gfx::CompositionOp::OP_LUMINOSITY:
    848      fs << "  return SetLum(dest, Lum(src));" << endl;
    849      break;
    850    default:
    851      MOZ_ASSERT_UNREACHABLE("unknown blend mode");
    852  }
    853  fs << "}" << endl;
    854 
    855  // Generate the mix-blend function the fragment shader will call.
    856  fs << "vec4 mixAndBlend(vec4 backdrop, vec4 color) {" << endl;
    857 
    858  // Shortcut when the backdrop or source alpha is 0, otherwise we may leak
    859  // Infinity into the blend function and return incorrect results.
    860  fs << "  if (backdrop.a == 0.0) {" << endl;
    861  fs << "    return color;" << endl;
    862  fs << "  }" << endl;
    863  fs << "  if (color.a == 0.0) {" << endl;
    864  fs << "    return vec4(0.0, 0.0, 0.0, 0.0);" << endl;
    865  fs << "  }" << endl;
    866 
    867  // The spec assumes there is no premultiplied alpha. The backdrop is always
    868  // premultiplied, so undo the premultiply. If the source is premultiplied we
    869  // must fix that as well.
    870  fs << "  backdrop.rgb /= backdrop.a;" << endl;
    871  if (!(aConfig.mFeatures & ENABLE_NO_PREMUL_ALPHA)) {
    872    fs << "  color.rgb /= color.a;" << endl;
    873  }
    874  fs << "  vec3 blended = blend(backdrop.rgb, color.rgb);" << endl;
    875  fs << "  color.rgb = (1.0 - backdrop.a) * color.rgb + backdrop.a * "
    876        "blended.rgb;"
    877     << endl;
    878  fs << "  color.rgb *= color.a;" << endl;
    879  fs << "  return color;" << endl;
    880  fs << "}" << endl;
    881 }
    882 
    883 ShaderProgramOGL::ShaderProgramOGL(GLContext* aGL,
    884                                   const ProgramProfileOGL& aProfile)
    885    : mGL(aGL), mProgram(0), mProfile(aProfile), mProgramState(STATE_NEW) {}
    886 
    887 ShaderProgramOGL::~ShaderProgramOGL() {
    888  if (mProgram <= 0) {
    889    return;
    890  }
    891 
    892  RefPtr<GLContext> ctx = mGL->GetSharedContext();
    893  if (!ctx) {
    894    ctx = mGL;
    895  }
    896  ctx->MakeCurrent();
    897  ctx->fDeleteProgram(mProgram);
    898 }
    899 
    900 bool ShaderProgramOGL::Initialize() {
    901  NS_ASSERTION(mProgramState == STATE_NEW,
    902               "Shader program has already been initialised");
    903 
    904  std::ostringstream vs, fs;
    905  for (uint32_t i = 0; i < mProfile.mDefines.Length(); ++i) {
    906    vs << mProfile.mDefines[i] << endl;
    907    fs << mProfile.mDefines[i] << endl;
    908  }
    909  vs << mProfile.mVertexShaderString << endl;
    910  fs << mProfile.mFragmentShaderString << endl;
    911 
    912  if (!CreateProgram(vs.str().c_str(), fs.str().c_str())) {
    913    mProgramState = STATE_ERROR;
    914    return false;
    915  }
    916 
    917  mProgramState = STATE_OK;
    918 
    919  for (uint32_t i = 0; i < KnownUniform::KnownUniformCount; ++i) {
    920    mProfile.mUniforms[i].mLocation =
    921        mGL->fGetUniformLocation(mProgram, mProfile.mUniforms[i].mNameString);
    922  }
    923 
    924  return true;
    925 }
    926 
    927 GLint ShaderProgramOGL::CreateShader(GLenum aShaderType,
    928                                     const char* aShaderSource) {
    929  GLint success, len = 0;
    930 
    931  GLint sh = mGL->fCreateShader(aShaderType);
    932  mGL->fShaderSource(sh, 1, (const GLchar**)&aShaderSource, nullptr);
    933  mGL->fCompileShader(sh);
    934  mGL->fGetShaderiv(sh, LOCAL_GL_COMPILE_STATUS, &success);
    935  mGL->fGetShaderiv(sh, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&len);
    936  /* Even if compiling is successful, there may still be warnings.  Print them
    937   * in a debug build.  The > 10 is to catch silly compilers that might put
    938   * some whitespace in the log but otherwise leave it empty.
    939   */
    940  if (!success
    941 #ifdef DEBUG
    942      || (len > 10 && gfxEnv::MOZ_DEBUG_SHADERS())
    943 #endif
    944  ) {
    945    nsAutoCString log;
    946    log.SetLength(len);
    947    mGL->fGetShaderInfoLog(sh, len, (GLint*)&len, (char*)log.BeginWriting());
    948    log.Truncate(len);
    949 
    950    if (!success) {
    951      printf_stderr("=== SHADER COMPILATION FAILED ===\n");
    952    } else {
    953      printf_stderr("=== SHADER COMPILATION WARNINGS ===\n");
    954    }
    955 
    956    printf_stderr("=== Source:\n%s\n", aShaderSource);
    957    printf_stderr("=== Log:\n%s\n", log.get());
    958    printf_stderr("============\n");
    959 
    960    if (!success) {
    961      mGL->fDeleteShader(sh);
    962      return 0;
    963    }
    964  }
    965 
    966  return sh;
    967 }
    968 
    969 bool ShaderProgramOGL::CreateProgram(const char* aVertexShaderString,
    970                                     const char* aFragmentShaderString) {
    971  GLuint vertexShader =
    972      CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString);
    973  GLuint fragmentShader =
    974      CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString);
    975 
    976  if (!vertexShader || !fragmentShader) return false;
    977 
    978  GLint result = mGL->fCreateProgram();
    979  mGL->fAttachShader(result, vertexShader);
    980  mGL->fAttachShader(result, fragmentShader);
    981 
    982  for (std::pair<nsCString, GLuint>& attribute : mProfile.mAttributes) {
    983    mGL->fBindAttribLocation(result, attribute.second, attribute.first.get());
    984  }
    985 
    986  mGL->fLinkProgram(result);
    987 
    988  GLint success, len;
    989  mGL->fGetProgramiv(result, LOCAL_GL_LINK_STATUS, &success);
    990  mGL->fGetProgramiv(result, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&len);
    991  /* Even if linking is successful, there may still be warnings.  Print them
    992   * in a debug build.  The > 10 is to catch silly compilers that might put
    993   * some whitespace in the log but otherwise leave it empty.
    994   */
    995  if (!success
    996 #ifdef DEBUG
    997      || (len > 10 && gfxEnv::MOZ_DEBUG_SHADERS())
    998 #endif
    999  ) {
   1000    nsAutoCString log;
   1001    log.SetLength(len);
   1002    mGL->fGetProgramInfoLog(result, len, (GLint*)&len,
   1003                            (char*)log.BeginWriting());
   1004 
   1005    if (!success) {
   1006      printf_stderr("=== PROGRAM LINKING FAILED ===\n");
   1007    } else {
   1008      printf_stderr("=== PROGRAM LINKING WARNINGS ===\n");
   1009    }
   1010    printf_stderr("=== Log:\n%s\n", log.get());
   1011    printf_stderr("============\n");
   1012  }
   1013 
   1014  // We can mark the shaders for deletion; they're attached to the program
   1015  // and will remain attached.
   1016  mGL->fDeleteShader(vertexShader);
   1017  mGL->fDeleteShader(fragmentShader);
   1018 
   1019  if (!success) {
   1020    mGL->fDeleteProgram(result);
   1021    return false;
   1022  }
   1023 
   1024  mProgram = result;
   1025  return true;
   1026 }
   1027 
   1028 GLuint ShaderProgramOGL::GetProgram() {
   1029  if (mProgramState == STATE_NEW) {
   1030    if (!Initialize()) {
   1031      NS_WARNING("Shader could not be initialised");
   1032    }
   1033  }
   1034  MOZ_ASSERT(HasInitialized(),
   1035             "Attempting to get a program that's not been initialized!");
   1036  return mProgram;
   1037 }
   1038 
   1039 void ShaderProgramOGL::SetYUVColorSpace(gfx::YUVColorSpace aYUVColorSpace) {
   1040  const float* yuvToRgb =
   1041      gfxUtils::YuvToRgbMatrix3x3ColumnMajor(aYUVColorSpace);
   1042  SetMatrix3fvUniform(KnownUniform::YuvColorMatrix, yuvToRgb);
   1043  if (aYUVColorSpace == gfx::YUVColorSpace::Identity) {
   1044    const float identity[] = {0.0, 0.0, 0.0};
   1045    SetVec3fvUniform(KnownUniform::YuvOffsetVector, identity);
   1046  } else {
   1047    const float offset[] = {0.06275, 0.50196, 0.50196};
   1048    SetVec3fvUniform(KnownUniform::YuvOffsetVector, offset);
   1049  }
   1050 }
   1051 
   1052 ShaderProgramOGLsHolder::ShaderProgramOGLsHolder(gl::GLContext* aGL)
   1053    : mGL(aGL) {}
   1054 
   1055 ShaderProgramOGLsHolder::~ShaderProgramOGLsHolder() { Clear(); }
   1056 
   1057 ShaderProgramOGL* ShaderProgramOGLsHolder::GetShaderProgramFor(
   1058    const ShaderConfigOGL& aConfig) {
   1059  auto iter = mPrograms.find(aConfig);
   1060  if (iter != mPrograms.end()) {
   1061    return iter->second.get();
   1062  }
   1063 
   1064  ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig);
   1065  auto shader = MakeUnique<ShaderProgramOGL>(mGL, profile);
   1066  if (!shader->Initialize()) {
   1067    gfxCriticalError() << "Shader compilation failure, cfg:"
   1068                       << " features: " << gfx::hexa(aConfig.mFeatures)
   1069                       << " multiplier: " << aConfig.mMultiplier
   1070                       << " op: " << aConfig.mCompositionOp;
   1071    return nullptr;
   1072  }
   1073 
   1074  mPrograms.emplace(aConfig, std::move(shader));
   1075  return mPrograms[aConfig].get();
   1076 }
   1077 
   1078 void ShaderProgramOGLsHolder::Clear() { mPrograms.clear(); }
   1079 
   1080 ShaderProgramOGL* ShaderProgramOGLsHolder::ActivateProgram(
   1081    const ShaderConfigOGL& aConfig) {
   1082  ShaderProgramOGL* program = GetShaderProgramFor(aConfig);
   1083  MOZ_DIAGNOSTIC_ASSERT(program);
   1084  if (!program) {
   1085    return nullptr;
   1086  }
   1087  if (mCurrentProgram != program) {
   1088    mGL->fUseProgram(program->GetProgram());
   1089    mCurrentProgram = program;
   1090  }
   1091  return program;
   1092 }
   1093 
   1094 void ShaderProgramOGLsHolder::ResetCurrentProgram() {
   1095  mCurrentProgram = nullptr;
   1096 }
   1097 
   1098 }  // namespace layers
   1099 }  // namespace mozilla