-
Notifications
You must be signed in to change notification settings - Fork 669
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial conformance tests for WEBGL_shader_pixel_local_storage
Creates a set of tests that verify the non-normative WebGL behavior, as well as providing some scaffolding to verify the ANGLE extension is properly hooked up. If these all look good, we can start porting tests from the ANGLE extension next.
- Loading branch information
1 parent
539037f
commit 13531ea
Showing
3 changed files
with
344 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
334 changes: 334 additions & 0 deletions
334
sdk/tests/conformance2/extensions/webgl-shader-pixel-local-storage.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,334 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>WebGL WEBGL_shader_pixel_local_storage Conformance Tests</title> | ||
<link rel="stylesheet" href="../../resources/js-test-style.css"/> | ||
<script src="../../js/desktop-gl-constants.js"></script> | ||
<script src="../../js/js-test-pre.js"></script> | ||
<script src="../../js/webgl-test-utils.js"></script> | ||
<script src="../../js/tests/compositing-test.js"></script> | ||
<script src="../../js/tests/invalid-vertex-attrib-test.js"></script> | ||
</head> | ||
<body> | ||
<div id="description"></div> | ||
<canvas id="canvas" width="128" height="128"> </canvas> | ||
<div id="console"></div> | ||
<script> | ||
"use strict"; | ||
description("This test verifies the functionality of the WEBGL_shader_pixel_local_storage " + | ||
"extension, if it is available."); | ||
|
||
const wtu = WebGLTestUtils; | ||
const canvas = document.getElementById("canvas"); | ||
const gl = wtu.create3DContext(canvas, null, 2); | ||
let pls = null; | ||
let MAX_PIXEL_LOCAL_STORAGE_PLANES = null; | ||
let MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE = null; | ||
let MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES = null; | ||
let MAX_COLOR_ATTACHMENTS = null; | ||
let MAX_DRAW_BUFFERS = null; | ||
|
||
function arraysEqual(a, b) { | ||
if (typeof a !== typeof b) | ||
return false; | ||
if (a.length != b.length) | ||
return false; | ||
for (let i = 0; i < a.length; ++i) { | ||
if (a[i] !== b[i]) | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
function runTest() { | ||
if (!gl) { | ||
return function() { | ||
testFailed("WebGL2 context does not exist"); | ||
} | ||
} | ||
|
||
// Check the behavior surrounding WEBGL_shader_pixel_local_storage being enabled. | ||
checkExtensionNotSupportedWhenDisabled(); | ||
checkDependencyExtensionsEnabled(false); | ||
pls = gl.getExtension("WEBGL_shader_pixel_local_storage"); | ||
wtu.runExtensionSupportedTest(gl, "WEBGL_shader_pixel_local_storage", pls != null); | ||
if (!pls) | ||
return; | ||
checkDependencyExtensionsEnabled(true); | ||
|
||
// Query and verify PLS implementation dependent limits. | ||
MAX_PIXEL_LOCAL_STORAGE_PLANES = | ||
gl.getParameter(pls.MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL); | ||
MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE = | ||
gl.getParameter(pls.MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE_WEBGL); | ||
MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES = | ||
gl.getParameter(pls.MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_WEBGL); | ||
wtu.glErrorShouldBe(gl, gl.NONE, "Pixel local storage queries should be supported."); | ||
MAX_COLOR_ATTACHMENTS = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS); | ||
MAX_DRAW_BUFFERS = gl.getParameter(gl.MAX_DRAW_BUFFERS); | ||
checkImplementationDependentLimits(); | ||
|
||
checkInitialValues(); | ||
checkWebGLNonNormativeBehavior(); | ||
|
||
gl.disable(gl.DITHER); | ||
checkRendering(); | ||
} | ||
|
||
// Check that a context does not support WEBGL_shader_pixel_local_storage before it is enabled. | ||
function checkExtensionNotSupportedWhenDisabled() { | ||
shouldBeNull("gl.getParameter(0x96E0 /*MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL*/)"); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); | ||
shouldBeNull( | ||
"gl.getParameter(0x96E1 /*MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE_WEBGL*/)"); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); | ||
shouldBeNull( | ||
"gl.getParameter(0x96E2 /*MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_WEBGL*/)"); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); | ||
shouldBeNull( | ||
"gl.getParameter(0x96E3 /*PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL*/)"); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
} | ||
|
||
// Check that the dependency extensions of WEBGL_shader_pixel_local_storage are properly enabled or | ||
// disabled. | ||
function checkDependencyExtensionsEnabled(enabled) { | ||
if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "OES_draw_buffers_indexed") !== undefined) { | ||
gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 1); | ||
wtu.glErrorShouldBe(gl, enabled ? gl.NONE : gl.INVALID_ENUM, | ||
"OES_draw_buffers_indexed not enabled or disabled as expected"); | ||
gl.bindRenderbuffer(gl.RENDERBUFFER, null); | ||
} | ||
if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "EXT_color_buffer_float") !== undefined) { | ||
gl.bindRenderbuffer(gl.RENDERBUFFER, gl.createRenderbuffer()); | ||
gl.renderbufferStorage(gl.RENDERBUFFER, gl.R32F, 1, 1); | ||
wtu.glErrorShouldBe(gl, enabled ? gl.NONE : gl.INVALID_ENUM, | ||
"EXT_color_buffer_float not enabled or disabled as expected"); | ||
gl.bindRenderbuffer(gl.RENDERBUFFER, null); | ||
} | ||
if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "EXT_color_buffer_half_float") !== undefined) { | ||
gl.bindRenderbuffer(gl.RENDERBUFFER, gl.createRenderbuffer()); | ||
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RG16F, 1, 1); | ||
wtu.glErrorShouldBe(gl, enabled ? gl.NONE : gl.INVALID_ENUM, | ||
"EXT_color_buffer_half_float not enabled or disabled as expected"); | ||
gl.bindRenderbuffer(gl.RENDERBUFFER, null); | ||
} | ||
} | ||
|
||
// Verify conformant implementation-dependent PLS limits. | ||
function checkImplementationDependentLimits() { | ||
// Table 6.X: Impementation Dependent Pixel Local Storage Limits. | ||
shouldBeTrue("MAX_PIXEL_LOCAL_STORAGE_PLANES >= 4"); | ||
shouldBeTrue("MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE >= 0"); | ||
shouldBeTrue("MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >= 4"); | ||
|
||
// Logical deductions based on 6.X. | ||
shouldBeTrue(`MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >= | ||
MAX_PIXEL_LOCAL_STORAGE_PLANES`); | ||
shouldBeTrue(`MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >= | ||
MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE`); | ||
shouldBeTrue(`MAX_COLOR_ATTACHMENTS + MAX_PIXEL_LOCAL_STORAGE_PLANES >= | ||
MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES`); | ||
shouldBeTrue(`MAX_DRAW_BUFFERS + MAX_PIXEL_LOCAL_STORAGE_PLANES >= | ||
MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES`); | ||
} | ||
|
||
// Check that PLS state has the specified initialized values. | ||
function checkInitialValues() { | ||
shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0"); | ||
wtu.glErrorShouldBe( | ||
gl, gl.NONE, | ||
"It's valid to query GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL even when fbo 0 is bound."); | ||
|
||
// Table 6.Y: Pixel Local Storage State | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer()); | ||
shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0"); | ||
for (let i = 0; i < MAX_PIXEL_LOCAL_STORAGE_PLANES; ++i) | ||
{ | ||
expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
i, pls.PIXEL_LOCAL_FORMAT_WEBGL) == gl.NONE); | ||
expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
i, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) == null); | ||
expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
i, pls.PIXEL_LOCAL_TEXTURE_LEVEL_WEBGL) == 0); | ||
expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
i, pls.PIXEL_LOCAL_TEXTURE_LAYER_WEBGL) == 0); | ||
expectTrue(arraysEqual( | ||
pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
i, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL), | ||
new Float32Array([0, 0, 0, 0]))); | ||
expectTrue(arraysEqual( | ||
pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
i, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL), | ||
new Int32Array([0, 0, 0, 0]))); | ||
expectTrue(arraysEqual( | ||
pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
i, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL), | ||
new Uint32Array([0, 0, 0, 0]))); | ||
} | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, null); | ||
} | ||
|
||
// Check the non-normative behavior not found in the ANGLE_shader_pixel_local_storage specification. | ||
function checkWebGLNonNormativeBehavior() { | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer()); | ||
|
||
// If 'texture' has been deleted, generates an INVALID_OPERATION error. | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
const tex = gl.createTexture(); | ||
gl.bindTexture(gl.TEXTURE_2D, tex); | ||
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
gl.deleteTexture(tex); | ||
pls.framebufferTexturePixelLocalStorageWEBGL(0, tex, 0, 0); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); | ||
|
||
// If 'texture' was generated by a different WebGL2RenderingContext than this one, generates an | ||
// INVALID_OPERATION error. | ||
const gl2 = wtu.create3DContext(null, null, 2); | ||
const tex2 = gl2.createTexture(); | ||
gl2.bindTexture(gl2.TEXTURE_2D, tex2); | ||
gl2.texStorage2D(gl2.TEXTURE_2D, 1, gl2.RGBA8, 1, 1); | ||
pls.framebufferTexturePixelLocalStorageWEBGL(0, tex2, 0, 0); | ||
wtu.glErrorShouldBe(gl2, gl2.NONE); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); | ||
|
||
// If value has less than srcOffset + 4 elements, generates an INVALID_VALUE error. | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
pls.framebufferPixelLocalClearValuefvWEBGL(0, new Float32Array(3)); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValuefvWEBGL(1, [0, 0, 0]); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValueivWEBGL(2, new Int32Array(3)); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValueivWEBGL(3, [0, 0, 0]); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValueuivWEBGL(4, new Uint32Array(3)); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValueuivWEBGL(3, [0, 0, 0]); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValuefvWEBGL(2, new Float32Array(5), 2); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValuefvWEBGL(1, [0, 0, 0, 0, 0], 2); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValueivWEBGL(0, new Int32Array(5), 2); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValueivWEBGL(1, [0, 0, 0, 0, 0], 2); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValueuivWEBGL(2, new Uint32Array(5), 2); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
pls.framebufferPixelLocalClearValueuivWEBGL(3, [0, 0, 0, 0, 0], 2); | ||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); | ||
|
||
// Check that srcOffset works properly. | ||
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; | ||
pls.framebufferPixelLocalClearValuefvWEBGL(0, new Float32Array(arr), 1); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
0, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL), | ||
new Float32Array([1, 2, 3, 4]))`); | ||
pls.framebufferPixelLocalClearValuefvWEBGL(1, new Float32Array(arr), 2); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
1, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL), | ||
[2, 3, 4, 5])`); | ||
pls.framebufferPixelLocalClearValueivWEBGL(2, new Int32Array(arr), 3); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
2, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL), | ||
new Float32Array([3, 4, 5, 6]))`); | ||
pls.framebufferPixelLocalClearValueivWEBGL(3, new Float32Array(arr), 4); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
3, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL), | ||
[4, 5, 6, 7])`); | ||
pls.framebufferPixelLocalClearValueuivWEBGL(2, new Int32Array(arr), 5); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
2, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL), | ||
new Uint32Array([5, 6, 7, 8]))`); | ||
pls.framebufferPixelLocalClearValueuivWEBGL(1, new Float32Array(arr), 6); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( | ||
1, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL), | ||
[6, 7, 8, 9])`); | ||
|
||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, null); | ||
} | ||
|
||
// Check very simple rendering. | ||
function checkRendering() { | ||
const tex = gl.createTexture(); | ||
gl.bindTexture(gl.TEXTURE_2D, tex); | ||
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 10, 10); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
|
||
const fbo = gl.createFramebuffer(); | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); | ||
pls.framebufferTexturePixelLocalStorageWEBGL(0, tex, 0, 0); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
|
||
gl.viewport(0, 0, 10, 10); | ||
|
||
const vs = `#version 300 es | ||
void main() { | ||
gl_Position.x = (gl_VertexID & 1) == 0 ? -1. : 1.; | ||
gl_Position.y = (gl_VertexID & 2) == 0 ? -1. : 1.; | ||
gl_Position.zw = vec2(0, 1); | ||
}`; | ||
|
||
const fs = `#version 300 es | ||
#extension GL_ANGLE_shader_pixel_local_storage : require | ||
precision lowp float; | ||
uniform vec4 color; | ||
layout(binding=0, rgba8) uniform lowp pixelLocalANGLE pls; | ||
void main() { | ||
vec4 newColor = color + pixelLocalLoadANGLE(pls); | ||
pixelLocalStoreANGLE(pls, newColor); | ||
}`; | ||
|
||
const program = wtu.setupProgram(gl, [vs, fs]); | ||
if (!program) { | ||
testFailed("Failed to compile program."); | ||
return; | ||
} | ||
|
||
gl.useProgram(program); | ||
const colorUniLocation = gl.getUniformLocation(program, "color"); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
|
||
pls.beginPixelLocalStorageWEBGL([pls.LOAD_OP_ZERO_WEBGL]); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1"); | ||
|
||
gl.uniform4f(colorUniLocation, 1, 0, 0, 0); | ||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); | ||
|
||
pls.pixelLocalStorageBarrierWEBGL(); | ||
|
||
gl.uniform4f(colorUniLocation, 0, 0, 1, 0); | ||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); | ||
|
||
pls.endPixelLocalStorageWEBGL([pls.STORE_OP_STORE_WEBGL]); | ||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0"); | ||
|
||
const readFBO = gl.createFramebuffer(); | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, readFBO); | ||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); | ||
wtu.checkCanvasRect(gl, 0, 0, 10, 10, [255, 0, 255, 0]); | ||
|
||
wtu.glErrorShouldBe(gl, gl.NONE); | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, null); | ||
} | ||
|
||
runTest(); | ||
var successfullyParsed = true; | ||
</script> | ||
<script src="../../js/js-test-post.js"></script> | ||
</body> | ||
</html> |