Bug 1048108 - Exclude RGBA configs when alpha:false. - r=kamidphish
authorJeff Gilbert <jgilbert@mozilla.com>
Wed, 24 Sep 2014 16:42:27 -0700
changeset 207105 8bba4620826b0887d16cd6d631220e2eaf4c7207
parent 207104 e6e63113336d5f447a0d9cbb75dc49727059f630
child 207106 432cdf1c88a97c8a64335269a0d4455253a4bba1
push id49593
push userjgilbert@mozilla.com
push dateWed, 24 Sep 2014 23:42:31 +0000
treeherdermozilla-inbound@8bba4620826b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskamidphish
bugs1048108
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1048108 - Exclude RGBA configs when alpha:false. - r=kamidphish
dom/canvas/test/webgl-mochitest.ini
dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
dom/canvas/test/webgl-mochitest/test-backbuffer-channels.html
dom/canvas/test/webgl-mochitest/test-hidden-alpha.html
gfx/gl/SharedSurfaceANGLE.cpp
gfx/gl/SharedSurfaceANGLE.h
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -1,13 +1,15 @@
 [DEFAULT]
 support-files =
   webgl-mochitest/driver-info.js
   webgl-mochitest/webgl-util.js
 
+[webgl-mochitest/test-backbuffer-channels.html]
+[webgl-mochitest/test-hidden-alpha.html]
 [webgl-mochitest/test_depth_readpixels.html]
 [webgl-mochitest/test_draw.html]
 [webgl-mochitest/test_fb_param.html]
 [webgl-mochitest/test_fb_param_crash.html]
 [webgl-mochitest/test_highp_fs.html]
 [webgl-mochitest/test_no_arr_points.html]
 [webgl-mochitest/test_noprog_draw.html]
 [webgl-mochitest/test_privileged_exts.html]
--- a/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
+++ b/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
@@ -4,17 +4,17 @@ import re
 
 assert len(sys.argv) == 2
 mochiPath = sys.argv[1]
 
 extDotPos = mochiPath.find('.html')
 assert extDotPos != -1, 'mochitest target must be an html doc.'
 
 testPath = mochiPath[:extDotPos] + '.solo.html'
-    
+
 def ReadLocalFile(include):
     incPath = os.path.dirname(mochiPath)
     filePath = os.path.join(incPath, include)
 
     data = None
     try:
         f = open(filePath, 'r')
         data = f.read()
@@ -26,61 +26,68 @@ def ReadLocalFile(include):
     except:
         pass
 
     return data
 
 kSimpleTestReplacement = '''\n
 <script>
 // SimpleTest.js replacement
+
+function debug(text) {
+  var elem = document.getElementById('mochi-to-testcase-output');
+  elem.innerHTML += '\\n<br/>\\n' + text;
+}
+
 function ok(val, text) {
-  var elem = document.getElementById('mochi-to-testcase-output');
   var status = val ? 'Test <font color=\\'green\\'>passed</font>: '
                    : 'Test <font color=\\'red\\'  >FAILED</font>: ';
-  elem.innerHTML += '\\n<br/>\\n' + status + text;
+  debug(status + text);
 }
 
 function todo(val, text) {
-  ok(!val, 'Todo: ' + text);
+  var status = val ? 'Test <font color=\\'orange\\'>UNEXPECTED PASS</font>: '
+                   : 'Test <font color=\\'blue\\'  >todo</font>: ';
+  debug(status + text);
 }
 </script>
 <div id='mochi-to-testcase-output'></div>
 \n'''
 
-fin = open(mochiPath, 'r')
-fout = open(testPath, 'w')
+fin = open(mochiPath, 'rb')
+fout = open(testPath, 'wb')
 includePattern = re.compile('<script\\s*src=[\'"](.*)\\.js[\'"]>\\s*</script>')
 cssPattern = re.compile('<link\\s*rel=[\'"]stylesheet[\'"]\\s*href=[\'"]([^=>]*)[\'"]>')
 for line in fin:
     skipLine = False
     for css in cssPattern.findall(line):
         skipLine = True
         print('Ignoring stylesheet: ' + css)
-    
+
     for inc in includePattern.findall(line):
         skipLine = True
         if inc == '/MochiKit/MochiKit':
             continue
 
         if inc == '/tests/SimpleTest/SimpleTest':
             print('Injecting SimpleTest replacement')
             fout.write(kSimpleTestReplacement);
             continue
-            
+
         incData = ReadLocalFile(inc + '.js')
         if not incData:
             print('Warning: Unknown JS file ignored: ' + inc + '.js')
             continue
 
         print('Injecting include: ' + inc + '.js')
         fout.write('\n<script>\n// Imported from: ' + inc + '.js\n');
         fout.write(incData);
         fout.write('\n</script>\n');
         continue
 
     if skipLine:
         continue
-    
+
     fout.write(line)
     continue
 
 fin.close()
 fout.close()
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test-backbuffer-channels.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<title>WebGL test: bug 958723</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script src="driver-info.js"></script>
+<script src="webgl-util.js"></script>
+<body>
+<script>
+
+function TestAttribs(attribs) {
+  debug('Testing attribs: ' + JSON.stringify(attribs));
+  var canvas = document.createElement('canvas');
+  var gl = canvas.getContext('experimental-webgl', attribs);
+  ok(gl, 'No tested attribs should result in failure to create a context');
+  if (!gl)
+    return;
+
+  var actual = gl.getContextAttributes();
+
+  ok(actual.alpha == attribs.alpha,
+     'Resulting `alpha` should match request.');
+  ok(actual.premultipliedAlpha == attribs.premultipliedAlpha,
+     'Resulting `premultipliedAlpha` should match request.');
+  ok(actual.preserveDrawingBuffer == attribs.preserveDrawingBuffer,
+     'Resulting `preserveDrawingBuffer` should match request.');
+
+  // "The depth, stencil and antialias attributes, when set to true, are
+  // requests, not requirements."
+  if (!attribs.antialias) {
+    ok(!actual.antialias, 'No `antialias` if not requested.');
+  }
+  if (!attribs.depth) {
+    ok(!actual.depth, 'No `depth` if not requested.');
+  }
+  if (!attribs.stencil) {
+    ok(!actual.stencil, 'No `stencil` if not requested.');
+  }
+
+  var hasAlpha = !!gl.getParameter(gl.ALPHA_BITS);
+  var hasDepth = !!gl.getParameter(gl.DEPTH_BITS);
+  var hasStencil = !!gl.getParameter(gl.STENCIL_BITS);
+  var hasAntialias = !!gl.getParameter(gl.SAMPLES);
+
+  ok(hasAlpha == actual.alpha, 'Bits should match `alpha` attrib.');
+  ok(hasAntialias == actual.antialias, 'Bits should match `antialias` attrib.');
+  ok(hasDepth == actual.depth, 'Bits should match `depth` attrib.');
+  ok(hasStencil == actual.stencil, 'Bits should match `stencil` attrib.');
+}
+
+function CloneAttribs(attribs) {
+  return {
+    alpha: attribs.alpha,
+    antialias: attribs.antialias,
+    depth: attribs.depth,
+    premultipliedAlpha: attribs.premultipliedAlpha,
+    preserveDrawingBuffer: attribs.preserveDrawingBuffer,
+    stencil: attribs.stencil,
+  };
+}
+
+function SplitForAttrib(list, attrib) {
+  var ret = [];
+
+  for (var i in list) {
+    var cur = list[i];
+    if (cur[attrib])
+      throw 'Attrib is already true.';
+
+    var clone = CloneAttribs(cur);
+    clone[attrib] = true;
+
+    ret.push(cur);
+    ret.push(clone);
+  }
+
+  return ret;
+}
+
+function GenAttribList() {
+  var base = {
+    alpha: false,
+    antialias: false,
+    depth: false,
+    premultipliedAlpha: false,
+    preserveDrawingBuffer: false,
+    stencil: false,
+  };
+  var list = [base];
+  list = SplitForAttrib(list, 'alpha');
+  list = SplitForAttrib(list, 'antialias');
+  list = SplitForAttrib(list, 'depth');
+  list = SplitForAttrib(list, 'premultipliedAlpha');
+  list = SplitForAttrib(list, 'preserveDrawingBuffer');
+  list = SplitForAttrib(list, 'stencil');
+
+  if (list.length != 1<<6)
+    throw 'Attribs list length wrong: ' + list.length;
+
+  return list;
+}
+
+var list = GenAttribList();
+for (var i in list) {
+  var attribs = list[i];
+  TestAttribs(attribs);
+}
+
+ok(true, 'Test complete.');
+
+</script>
+
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test-hidden-alpha.html
@@ -0,0 +1,153 @@
+<!DOCTYPE HTML>
+<title>WebGL test: Hidden alpha on no-alpha contexts</title>
+<script src='/tests/SimpleTest/SimpleTest.js'></script>
+<link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+<script src='driver-info.js'></script>
+<script src='webgl-util.js'></script>
+<body>
+<script id='vs' type='x-shader/x-vertex'>
+  attribute vec2 aPosCoord;
+
+  void main(void) {
+    gl_Position = vec4(aPosCoord, 0.0, 1.0);
+  }
+</script>
+
+<script id='fs' type='x-shader/x-fragment'>
+  precision mediump float;
+
+  void main(void) {
+    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+  }
+</script>
+<canvas id='canvas' style='border: none;' width='100' height='100'></canvas>
+<script>
+
+var posCoords_arr = new Float32Array(2 * 4);
+var posCoords_buff = null;
+function DrawQuad(gl, prog, x0, y0, x1, y1) {
+  gl.useProgram(prog);
+
+  if (!posCoords_buff) {
+    posCoords_buff = gl.createBuffer();
+  }
+  gl.bindBuffer(gl.ARRAY_BUFFER, posCoords_buff);
+  posCoords_arr[0] = x0;
+  posCoords_arr[1] = y0;
+
+  posCoords_arr[2] = x1;
+  posCoords_arr[3] = y0;
+
+  posCoords_arr[4] = x0;
+  posCoords_arr[5] = y1;
+
+  posCoords_arr[6] = x1;
+  posCoords_arr[7] = y1;
+  gl.bufferData(gl.ARRAY_BUFFER, posCoords_arr, gl.STREAM_DRAW);
+
+  gl.enableVertexAttribArray(prog.aPosCoord);
+  gl.vertexAttribPointer(prog.aPosCoord, 2, gl.FLOAT, false, 0, 0);
+
+  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+}
+
+function DrawSquare(gl, prog, size) {
+  DrawQuad(gl, prog, -size, -size, size, size);
+}
+
+function Reset(gl) {
+  gl.canvas.width += 1;
+  gl.canvas.width -= 1;
+}
+
+function ReadCenterPixel(gl) {
+  var w = gl.drawingbufferWidth;
+  var h = gl.drawingbufferHeight;
+  var ret = new Uint8Array(4);
+  gl.readPixels(w/2, h/2, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, ret);
+  return ret;
+}
+
+function Test(gl, prog) {
+  gl.enable(gl.BLEND);
+  gl.blendFunc(gl.ZERO, gl.DST_ALPHA);
+
+  var iColor = 64;
+  var fColor = iColor / 255.0;
+
+  //////////////////
+
+  debug('clear(R,G,B,0)');
+
+  Reset(gl);
+
+  gl.clearColor(fColor, fColor, fColor, 0.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  var dataURL_pre = gl.canvas.toDataURL();
+  //console.log('Before blending: ' + dataURL_pre);
+
+  DrawSquare(gl, prog, 0.7);
+
+  var pixel = ReadCenterPixel(gl);
+  ok(pixel[0] == iColor &&
+     pixel[1] == iColor &&
+     pixel[2] == iColor, 'Color should be the same.');
+  ok(pixel[3] == 255, 'No-alpha should always readback as 1.0 alpha.');
+
+  var dataURL_post = gl.canvas.toDataURL();
+  //console.log('After blending: ' + dataURL_post);
+  ok(dataURL_post == dataURL_pre,
+     'toDataURL should be unchanged after blending.');
+
+  //////////////////
+
+  debug('mask(R,G,B,0), clear(R,G,B,1)');
+
+  Reset(gl);
+
+  gl.colorMask(true, true, true, false);
+  gl.clearColor(fColor, fColor, fColor, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  gl.colorMask(true, true, true, true);
+
+  dataURL_pre = gl.canvas.toDataURL();
+  //console.log('Before blending: ' + dataURL_pre);
+
+  DrawSquare(gl, prog, 0.7);
+
+  var pixel = ReadCenterPixel(gl);
+  ok(pixel[0] == iColor &&
+     pixel[1] == iColor &&
+     pixel[2] == iColor, 'Color should be the same.');
+  ok(pixel[3] == 255, 'No-alpha should always readback as 1.0 alpha.');
+  ok(gl.getError() == 0, 'Should have no errors.');
+
+  dataURL_post = gl.canvas.toDataURL();
+  //console.log('After blending: ' + dataURL_post);
+  ok(dataURL_post == dataURL_pre,
+     'toDataURL should be unchanged after blending.');
+
+  ok(true, 'Test complete.');
+}
+
+(function(){
+  var canvas = document.getElementById('canvas');
+  var attribs = {
+    alpha: false,
+    antialias: false,
+    premultipliedAlpha: false,
+  };
+  var gl = canvas.getContext('experimental-webgl', attribs);
+  ok(gl, 'WebGL should work.');
+  ok(gl.getParameter(gl.ALPHA_BITS) == 0, 'Shouldn\'t have alpha bits.');
+
+  var prog = WebGLUtil.createProgramByIds(gl, 'vs', 'fs');
+  ok(prog, 'Program should link.');
+  prog.aPosCoord = gl.getAttribLocation(prog, 'aPosCoord');
+
+  setTimeout(function(){ Test(gl, prog); }, 500);
+})();
+
+</script>
+</body>
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -6,16 +6,83 @@
 #include "SharedSurfaceANGLE.h"
 
 #include "GLContextEGL.h"
 #include "GLLibraryEGL.h"
 
 namespace mozilla {
 namespace gl {
 
+// Returns `EGL_NO_SURFACE` (`0`) on error.
+static EGLSurface
+CreatePBufferSurface(GLLibraryEGL* egl,
+                     EGLDisplay display,
+                     EGLConfig config,
+                     const gfx::IntSize& size)
+{
+    auto width = size.width;
+    auto height = size.height;
+
+    EGLint attribs[] = {
+        LOCAL_EGL_WIDTH, width,
+        LOCAL_EGL_HEIGHT, height,
+        LOCAL_EGL_NONE
+    };
+
+    DebugOnly<EGLint> preCallErr = egl->fGetError();
+    MOZ_ASSERT(preCallErr == LOCAL_EGL_SUCCESS);
+    EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs);
+    EGLint err = egl->fGetError();
+    if (err != LOCAL_EGL_SUCCESS)
+        return 0;
+
+    return surface;
+}
+
+/*static*/ UniquePtr<SharedSurface_ANGLEShareHandle>
+SharedSurface_ANGLEShareHandle::Create(GLContext* gl,
+                                       EGLContext context, EGLConfig config,
+                                       const gfx::IntSize& size, bool hasAlpha)
+{
+    GLLibraryEGL* egl = &sEGLLibrary;
+    MOZ_ASSERT(egl);
+    MOZ_ASSERT(egl->IsExtensionSupported(
+               GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle));
+
+    if (!context || !config)
+        return nullptr;
+
+    EGLDisplay display = egl->Display();
+    EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size);
+    if (!pbuffer)
+        return nullptr;
+
+    // Declare everything before 'goto's.
+    HANDLE shareHandle = nullptr;
+    bool ok = egl->fQuerySurfacePointerANGLE(display,
+                                             pbuffer,
+                                             LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
+                                             &shareHandle);
+    if (!ok) {
+        egl->fDestroySurface(egl->Display(), pbuffer);
+        return nullptr;
+    }
+
+    GLuint fence = 0;
+    if (gl->IsExtensionSupported(GLContext::NV_fence)) {
+        gl->MakeCurrent();
+        gl->fGenFences(1, &fence);
+    }
+
+    typedef SharedSurface_ANGLEShareHandle ptrT;
+    UniquePtr<ptrT> ret( new ptrT(gl, egl, size, hasAlpha, context,
+                                  pbuffer, shareHandle, fence) );
+    return Move(ret);
+}
+
 EGLDisplay
 SharedSurface_ANGLEShareHandle::Display()
 {
     return mEGL->Display();
 }
 
 SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(GLContext* gl,
                                                                GLLibraryEGL* egl,
@@ -109,16 +176,19 @@ SharedSurface_ANGLEShareHandle::PollSync
     if (mFence) {
         mGL->MakeCurrent();
         return mGL->fTestFence(mFence);
     }
 
     return PollSync();
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// Factory
+
 static void
 FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs,
                           int redBits, int greenBits,
                           int blueBits, int alphaBits,
                           int depthBits, int stencilBits)
 {
     aAttrs.Clear();
 
@@ -164,157 +234,126 @@ FillPBufferAttribs_BySizes(nsTArray<EGLi
             blue = 5;
         }
     } else {
         red = green = blue = 8;
         if (hasAlpha)
             alpha = 8;
     }
 
-    FillPBufferAttribs_ByBits(attribs,
-                              red, green, blue, alpha,
-                              depthBits, stencilBits);
+    FillPBufferAttribs_ByBits(attribs, red, green, blue, alpha, depthBits,
+                              stencilBits);
+}
+
+static bool
+DoesAttribBitsMatchCapBool(GLLibraryEGL* egl, EGLConfig config, EGLint attrib,
+                           bool capBool)
+{
+    EGLint bits = 0;
+    egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits);
+    MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
+
+    bool hasBits = !!bits;
+
+    return hasBits == capBool;
 }
 
 static EGLConfig
-ChooseConfig(GLContext* gl,
-             GLLibraryEGL* egl,
-             const SurfaceCaps& caps)
+ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps)
 {
     MOZ_ASSERT(egl);
     MOZ_ASSERT(caps.color);
 
     // We might want 24-bit depth, but we're only (fairly) sure to get 16-bit.
     int depthBits = caps.depth ? 16 : 0;
     int stencilBits = caps.stencil ? 8 : 0;
 
     // Ok, now we have everything.
     nsTArray<EGLint> attribs(32);
-    FillPBufferAttribs_BySizes(attribs,
-                               caps.bpp16, caps.alpha,
-                               depthBits, stencilBits);
+    FillPBufferAttribs_BySizes(attribs, caps.bpp16, caps.alpha, depthBits,
+                               stencilBits);
 
     // Time to try to get this config:
     EGLConfig configs[64];
     int numConfigs = sizeof(configs)/sizeof(EGLConfig);
     int foundConfigs = 0;
 
-    if (!egl->fChooseConfig(egl->Display(),
-                            attribs.Elements(),
-                            configs, numConfigs,
-                            &foundConfigs) ||
+    if (!egl->fChooseConfig(egl->Display(), attribs.Elements(), configs,
+                            numConfigs, &foundConfigs) ||
         !foundConfigs)
     {
         NS_WARNING("No configs found for the requested formats.");
         return EGL_NO_CONFIG;
     }
 
-    // TODO: Pick a config progamatically instead of hoping that
-    // the first config will be minimally matching our request.
-    EGLConfig config = configs[0];
+    // The requests passed to ChooseConfig are treated as minimums. If you ask
+    // for 0 bits of alpha, we might still get 8 bits.
+    EGLConfig config = EGL_NO_CONFIG;
+    for (int i = 0; i < foundConfigs; i++) {
+        EGLConfig cur = configs[0];
+        if (DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
+                                       caps.alpha) &&
+            DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
+                                       caps.depth) &&
+            DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE,
+                                       caps.stencil))
+        {
+            config = cur;
+            break;
+        }
+    }
+
+    if (config == EGL_NO_CONFIG) {
+        NS_WARNING("No acceptable EGLConfig found.");
+        return EGL_NO_CONFIG;
+    }
 
     if (gl->DebugMode()) {
         egl->DumpEGLConfig(config);
     }
 
     return config;
 }
 
-// Returns `EGL_NO_SURFACE` (`0`) on error.
-static EGLSurface
-CreatePBufferSurface(GLLibraryEGL* egl,
-                     EGLDisplay display,
-                     EGLConfig config,
-                     const gfx::IntSize& size)
-{
-    auto width = size.width;
-    auto height = size.height;
-
-    EGLint attribs[] = {
-        LOCAL_EGL_WIDTH, width,
-        LOCAL_EGL_HEIGHT, height,
-        LOCAL_EGL_NONE
-    };
-
-    DebugOnly<EGLint> preCallErr = egl->fGetError();
-    MOZ_ASSERT(preCallErr == LOCAL_EGL_SUCCESS);
-    EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs);
-    EGLint err = egl->fGetError();
-    if (err != LOCAL_EGL_SUCCESS)
-        return 0;
-
-    return surface;
-}
-
-/*static*/ UniquePtr<SharedSurface_ANGLEShareHandle>
-SharedSurface_ANGLEShareHandle::Create(GLContext* gl,
-                                       EGLContext context, EGLConfig config,
-                                       const gfx::IntSize& size, bool hasAlpha)
-{
-    GLLibraryEGL* egl = &sEGLLibrary;
-    MOZ_ASSERT(egl);
-    MOZ_ASSERT(egl->IsExtensionSupported(
-               GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle));
-
-    if (!context || !config)
-        return nullptr;
-
-    EGLDisplay display = egl->Display();
-    EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size);
-    if (!pbuffer)
-        return nullptr;
-
-    // Declare everything before 'goto's.
-    HANDLE shareHandle = nullptr;
-    bool ok = egl->fQuerySurfacePointerANGLE(display,
-                                             pbuffer,
-                                             LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
-                                             &shareHandle);
-    if (!ok) {
-        egl->fDestroySurface(egl->Display(), pbuffer);
-        return nullptr;
-    }
-
-    GLuint fence = 0;
-    if (gl->IsExtensionSupported(GLContext::NV_fence)) {
-        gl->MakeCurrent();
-        gl->fGenFences(1, &fence);
-    }
-
-    typedef SharedSurface_ANGLEShareHandle ptrT;
-    UniquePtr<ptrT> ret( new ptrT(gl, egl, size, hasAlpha, context,
-                                  pbuffer, shareHandle, fence) );
-    return Move(ret);
-}
-
 /*static*/ UniquePtr<SurfaceFactory_ANGLEShareHandle>
 SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
                                         const SurfaceCaps& caps)
 {
     GLLibraryEGL* egl = &sEGLLibrary;
     if (!egl)
         return nullptr;
 
     auto ext = GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle;
     if (!egl->IsExtensionSupported(ext))
-    {
         return nullptr;
-    }
 
+    bool success;
     typedef SurfaceFactory_ANGLEShareHandle ptrT;
-    UniquePtr<ptrT> ret( new ptrT(gl, egl, caps) );
+    UniquePtr<ptrT> ret( new ptrT(gl, egl, caps, &success) );
+
+    if (!success)
+        return nullptr;
+
     return Move(ret);
 }
 
 SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl,
                                                                  GLLibraryEGL* egl,
-                                                                 const SurfaceCaps& caps)
+                                                                 const SurfaceCaps& caps,
+                                                                 bool* const out_success)
     : SurfaceFactory(gl, SharedSurfaceType::EGLSurfaceANGLE, caps)
     , mProdGL(gl)
     , mEGL(egl)
 {
-    mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps);
+    MOZ_ASSERT(out_success);
+    *out_success = false;
+
     mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext();
+    mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps);
+    if (mConfig == EGL_NO_CONFIG)
+        return;
+
     MOZ_ASSERT(mConfig && mContext);
+    *out_success = true;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/gl/SharedSurfaceANGLE.h
+++ b/gfx/gl/SharedSurfaceANGLE.h
@@ -83,17 +83,18 @@ protected:
 
 public:
     static UniquePtr<SurfaceFactory_ANGLEShareHandle> Create(GLContext* gl,
                                                              const SurfaceCaps& caps);
 
 protected:
     SurfaceFactory_ANGLEShareHandle(GLContext* gl,
                                     GLLibraryEGL* egl,
-                                    const SurfaceCaps& caps);
+                                    const SurfaceCaps& caps,
+                                    bool* const out_success);
 
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) MOZ_OVERRIDE {
         bool hasAlpha = mReadCaps.alpha;
         return SharedSurface_ANGLEShareHandle::Create(mProdGL,
                                                       mContext, mConfig,
                                                       size, hasAlpha);
     }
 };