mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1048108 - Exclude RGBA configs when alpha:false. - r=kamidphish
This commit is contained in:
parent
1ec62ca2c2
commit
feb7643d1e
@ -3,6 +3,8 @@ support-files =
|
|||||||
webgl-mochitest/driver-info.js
|
webgl-mochitest/driver-info.js
|
||||||
webgl-mochitest/webgl-util.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_depth_readpixels.html]
|
||||||
[webgl-mochitest/test_draw.html]
|
[webgl-mochitest/test_draw.html]
|
||||||
[webgl-mochitest/test_fb_param.html]
|
[webgl-mochitest/test_fb_param.html]
|
||||||
|
@ -9,7 +9,7 @@ extDotPos = mochiPath.find('.html')
|
|||||||
assert extDotPos != -1, 'mochitest target must be an html doc.'
|
assert extDotPos != -1, 'mochitest target must be an html doc.'
|
||||||
|
|
||||||
testPath = mochiPath[:extDotPos] + '.solo.html'
|
testPath = mochiPath[:extDotPos] + '.solo.html'
|
||||||
|
|
||||||
def ReadLocalFile(include):
|
def ReadLocalFile(include):
|
||||||
incPath = os.path.dirname(mochiPath)
|
incPath = os.path.dirname(mochiPath)
|
||||||
filePath = os.path.join(incPath, include)
|
filePath = os.path.join(incPath, include)
|
||||||
@ -31,22 +31,29 @@ def ReadLocalFile(include):
|
|||||||
kSimpleTestReplacement = '''\n
|
kSimpleTestReplacement = '''\n
|
||||||
<script>
|
<script>
|
||||||
// SimpleTest.js replacement
|
// SimpleTest.js replacement
|
||||||
function ok(val, text) {
|
|
||||||
|
function debug(text) {
|
||||||
var elem = document.getElementById('mochi-to-testcase-output');
|
var elem = document.getElementById('mochi-to-testcase-output');
|
||||||
|
elem.innerHTML += '\\n<br/>\\n' + text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ok(val, text) {
|
||||||
var status = val ? 'Test <font color=\\'green\\'>passed</font>: '
|
var status = val ? 'Test <font color=\\'green\\'>passed</font>: '
|
||||||
: 'Test <font color=\\'red\\' >FAILED</font>: ';
|
: 'Test <font color=\\'red\\' >FAILED</font>: ';
|
||||||
elem.innerHTML += '\\n<br/>\\n' + status + text;
|
debug(status + text);
|
||||||
}
|
}
|
||||||
|
|
||||||
function todo(val, 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>
|
</script>
|
||||||
<div id='mochi-to-testcase-output'></div>
|
<div id='mochi-to-testcase-output'></div>
|
||||||
\n'''
|
\n'''
|
||||||
|
|
||||||
fin = open(mochiPath, 'r')
|
fin = open(mochiPath, 'rb')
|
||||||
fout = open(testPath, 'w')
|
fout = open(testPath, 'wb')
|
||||||
includePattern = re.compile('<script\\s*src=[\'"](.*)\\.js[\'"]>\\s*</script>')
|
includePattern = re.compile('<script\\s*src=[\'"](.*)\\.js[\'"]>\\s*</script>')
|
||||||
cssPattern = re.compile('<link\\s*rel=[\'"]stylesheet[\'"]\\s*href=[\'"]([^=>]*)[\'"]>')
|
cssPattern = re.compile('<link\\s*rel=[\'"]stylesheet[\'"]\\s*href=[\'"]([^=>]*)[\'"]>')
|
||||||
for line in fin:
|
for line in fin:
|
||||||
@ -54,7 +61,7 @@ for line in fin:
|
|||||||
for css in cssPattern.findall(line):
|
for css in cssPattern.findall(line):
|
||||||
skipLine = True
|
skipLine = True
|
||||||
print('Ignoring stylesheet: ' + css)
|
print('Ignoring stylesheet: ' + css)
|
||||||
|
|
||||||
for inc in includePattern.findall(line):
|
for inc in includePattern.findall(line):
|
||||||
skipLine = True
|
skipLine = True
|
||||||
if inc == '/MochiKit/MochiKit':
|
if inc == '/MochiKit/MochiKit':
|
||||||
@ -64,7 +71,7 @@ for line in fin:
|
|||||||
print('Injecting SimpleTest replacement')
|
print('Injecting SimpleTest replacement')
|
||||||
fout.write(kSimpleTestReplacement);
|
fout.write(kSimpleTestReplacement);
|
||||||
continue
|
continue
|
||||||
|
|
||||||
incData = ReadLocalFile(inc + '.js')
|
incData = ReadLocalFile(inc + '.js')
|
||||||
if not incData:
|
if not incData:
|
||||||
print('Warning: Unknown JS file ignored: ' + inc + '.js')
|
print('Warning: Unknown JS file ignored: ' + inc + '.js')
|
||||||
@ -78,7 +85,7 @@ for line in fin:
|
|||||||
|
|
||||||
if skipLine:
|
if skipLine:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
fout.write(line)
|
fout.write(line)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
111
dom/canvas/test/webgl-mochitest/test-backbuffer-channels.html
Normal file
111
dom/canvas/test/webgl-mochitest/test-backbuffer-channels.html
Normal file
@ -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>
|
||||||
|
|
153
dom/canvas/test/webgl-mochitest/test-hidden-alpha.html
Normal file
153
dom/canvas/test/webgl-mochitest/test-hidden-alpha.html
Normal file
@ -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>
|
@ -11,6 +11,73 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace gl {
|
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
|
EGLDisplay
|
||||||
SharedSurface_ANGLEShareHandle::Display()
|
SharedSurface_ANGLEShareHandle::Display()
|
||||||
{
|
{
|
||||||
@ -114,6 +181,9 @@ SharedSurface_ANGLEShareHandle::PollSync_ContentThread_Impl()
|
|||||||
return PollSync();
|
return PollSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Factory
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs,
|
FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs,
|
||||||
int redBits, int greenBits,
|
int redBits, int greenBits,
|
||||||
@ -169,15 +239,25 @@ FillPBufferAttribs_BySizes(nsTArray<EGLint>& attribs,
|
|||||||
alpha = 8;
|
alpha = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
FillPBufferAttribs_ByBits(attribs,
|
FillPBufferAttribs_ByBits(attribs, red, green, blue, alpha, depthBits,
|
||||||
red, green, blue, alpha,
|
stencilBits);
|
||||||
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
|
static EGLConfig
|
||||||
ChooseConfig(GLContext* gl,
|
ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps)
|
||||||
GLLibraryEGL* egl,
|
|
||||||
const SurfaceCaps& caps)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(egl);
|
MOZ_ASSERT(egl);
|
||||||
MOZ_ASSERT(caps.color);
|
MOZ_ASSERT(caps.color);
|
||||||
@ -188,28 +268,43 @@ ChooseConfig(GLContext* gl,
|
|||||||
|
|
||||||
// Ok, now we have everything.
|
// Ok, now we have everything.
|
||||||
nsTArray<EGLint> attribs(32);
|
nsTArray<EGLint> attribs(32);
|
||||||
FillPBufferAttribs_BySizes(attribs,
|
FillPBufferAttribs_BySizes(attribs, caps.bpp16, caps.alpha, depthBits,
|
||||||
caps.bpp16, caps.alpha,
|
stencilBits);
|
||||||
depthBits, stencilBits);
|
|
||||||
|
|
||||||
// Time to try to get this config:
|
// Time to try to get this config:
|
||||||
EGLConfig configs[64];
|
EGLConfig configs[64];
|
||||||
int numConfigs = sizeof(configs)/sizeof(EGLConfig);
|
int numConfigs = sizeof(configs)/sizeof(EGLConfig);
|
||||||
int foundConfigs = 0;
|
int foundConfigs = 0;
|
||||||
|
|
||||||
if (!egl->fChooseConfig(egl->Display(),
|
if (!egl->fChooseConfig(egl->Display(), attribs.Elements(), configs,
|
||||||
attribs.Elements(),
|
numConfigs, &foundConfigs) ||
|
||||||
configs, numConfigs,
|
|
||||||
&foundConfigs) ||
|
|
||||||
!foundConfigs)
|
!foundConfigs)
|
||||||
{
|
{
|
||||||
NS_WARNING("No configs found for the requested formats.");
|
NS_WARNING("No configs found for the requested formats.");
|
||||||
return EGL_NO_CONFIG;
|
return EGL_NO_CONFIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Pick a config progamatically instead of hoping that
|
// The requests passed to ChooseConfig are treated as minimums. If you ask
|
||||||
// the first config will be minimally matching our request.
|
// for 0 bits of alpha, we might still get 8 bits.
|
||||||
EGLConfig config = configs[0];
|
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()) {
|
if (gl->DebugMode()) {
|
||||||
egl->DumpEGLConfig(config);
|
egl->DumpEGLConfig(config);
|
||||||
@ -218,73 +313,6 @@ ChooseConfig(GLContext* gl,
|
|||||||
return 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>
|
/*static*/ UniquePtr<SurfaceFactory_ANGLEShareHandle>
|
||||||
SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
|
SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
|
||||||
const SurfaceCaps& caps)
|
const SurfaceCaps& caps)
|
||||||
@ -295,25 +323,36 @@ SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
|
|||||||
|
|
||||||
auto ext = GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle;
|
auto ext = GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle;
|
||||||
if (!egl->IsExtensionSupported(ext))
|
if (!egl->IsExtensionSupported(ext))
|
||||||
{
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
|
bool success;
|
||||||
typedef SurfaceFactory_ANGLEShareHandle ptrT;
|
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);
|
return Move(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl,
|
SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl,
|
||||||
GLLibraryEGL* egl,
|
GLLibraryEGL* egl,
|
||||||
const SurfaceCaps& caps)
|
const SurfaceCaps& caps,
|
||||||
|
bool* const out_success)
|
||||||
: SurfaceFactory(gl, SharedSurfaceType::EGLSurfaceANGLE, caps)
|
: SurfaceFactory(gl, SharedSurfaceType::EGLSurfaceANGLE, caps)
|
||||||
, mProdGL(gl)
|
, mProdGL(gl)
|
||||||
, mEGL(egl)
|
, mEGL(egl)
|
||||||
{
|
{
|
||||||
mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps);
|
MOZ_ASSERT(out_success);
|
||||||
|
*out_success = false;
|
||||||
|
|
||||||
mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext();
|
mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext();
|
||||||
|
mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps);
|
||||||
|
if (mConfig == EGL_NO_CONFIG)
|
||||||
|
return;
|
||||||
|
|
||||||
MOZ_ASSERT(mConfig && mContext);
|
MOZ_ASSERT(mConfig && mContext);
|
||||||
|
*out_success = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace gl */
|
} /* namespace gl */
|
||||||
|
@ -88,7 +88,8 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
SurfaceFactory_ANGLEShareHandle(GLContext* gl,
|
SurfaceFactory_ANGLEShareHandle(GLContext* gl,
|
||||||
GLLibraryEGL* egl,
|
GLLibraryEGL* egl,
|
||||||
const SurfaceCaps& caps);
|
const SurfaceCaps& caps,
|
||||||
|
bool* const out_success);
|
||||||
|
|
||||||
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) MOZ_OVERRIDE {
|
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) MOZ_OVERRIDE {
|
||||||
bool hasAlpha = mReadCaps.alpha;
|
bool hasAlpha = mReadCaps.alpha;
|
||||||
|
Loading…
Reference in New Issue
Block a user