diff options
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance2/rendering')
26 files changed, 5625 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt new file mode 100644 index 000000000..7aed37329 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt @@ -0,0 +1,25 @@ +attrib-type-match.html +blitframebuffer-filter-outofbounds.html +blitframebuffer-filter-srgb.html +blitframebuffer-multisampled-readbuffer.html +--min-version 2.0.1 blitframebuffer-outside-readbuffer.html +blitframebuffer-scissor-enabled.html +blitframebuffer-size-overflow.html +--min-version 2.0.1 blitframebuffer-srgb-and-linear-drawbuffers.html +--min-version 2.0.1 blitframebuffer-stencil-only.html +blitframebuffer-test.html +canvas-resizing-with-pbo-bound.html +clear-func-buffer-type-match.html +--min-version 2.0.1 clear-srgb-color-buffer.html +--min-version 2.0.1 clipping-wide-points.html +draw-buffers.html +element-index-uint.html +framebuffer-completeness-unaffected.html +framebuffer-unsupported.html +--min-version 2.0.1 fs-color-type-mismatch-color-buffer-type.html +instanced-arrays.html +--min-version 2.0.1 instanced-rendering-bug.html +out-of-bounds-index-buffers-after-copying.html +--min-version 2.0.1 rendering-sampling-feedback-loop.html +rgb-format-support.html +uniform-block-buffer-size.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/attrib-type-match.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/attrib-type-match.html new file mode 100644 index 000000000..5d810187f --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/attrib-type-match.html @@ -0,0 +1,582 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL Conformance Tests: Vertex Attribute Type Match</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> +</head> +<body> +<div id="description"></div> +<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas> +<div id="console"></div> +<!-- Shaders for testing instanced draws --> +<script id="outputVertexShader" type="x-shader/x-vertex">#version 300 es +in vec4 aPosition; +in ivec2 aOffsetI; +in uvec2 aOffsetU; +in vec4 aColor; +out vec4 vColor; +void main() { + vColor = aColor; + vec2 offset = vec2(float(aOffsetI.x) + float(aOffsetU.x), + float(aOffsetI.y) + float(aOffsetU.y)); + gl_Position = aPosition + vec4(offset, 0.0, 0.0); +} +</script> + +<script id="outputFragmentShader" type="x-shader/x-fragment">#version 300 es +precision mediump float; +in vec4 vColor; +out vec4 fragColor; +void main() { + fragColor = vColor; +} +</script> + +<script id='vshader_inactive_attrib' type='x-shader/x-vertex'>#version 300 es +in ivec4 p; +in ivec4 a; +void main() +{ + gl_Position = vec4(p); +} +</script> +<script id='vshader_active_attrib_int' type='x-shader/x-vertex'>#version 300 es +in ivec4 p; +in ivec4 a; +in uvec4 b; +void main() +{ + gl_Position = vec4(p) + vec4(a) + vec4(b); +} +</script> +<script id='vshader_active_attrib_float' type='x-shader/x-vertex'>#version 300 es +in vec4 p; +in vec4 a; +in vec4 c; +void main() +{ + gl_Position = vec4(p) + vec4(a) + vec4(c); +} +</script> +<script id='fshader' type='x-shader/x-fragment'>#version 300 es +precision mediump float; +layout(location=0) out vec4 oColor; +void main() +{ + oColor = vec4(1.0, 0.0, 0.0, 1.0); +} +</script> + + +<script> +"use strict"; +description("This test verifies an active vertex attribute's base type has to match the verexAttrib function type."); + +debug(""); + +var wtu = WebGLTestUtils; +var canvas = document.getElementById("canvas"); +var gl = wtu.create3DContext(canvas, null, 2); + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + testGenericAttribs(); + runTests(); +} + +function testGenericAttribs() { + debug(""); + debug("Test Generic Vertex Attributes for some corner cases"); + + var pIndex = 2; + var aIndex = 3; + var bIndex = 4; + var cIndex = 5; + var program0 = wtu.setupProgram(gl, ["vshader_inactive_attrib", "fshader"], + ['p', 'a'], [pIndex, aIndex]); + var program1 = wtu.setupProgram(gl, ["vshader_active_attrib_int", "fshader"], + ['p', 'a', 'b'], [pIndex, aIndex, bIndex]); + var program2 = wtu.setupProgram(gl, ["vshader_active_attrib_float", "fshader"], + ['p', 'a', 'c'], [pIndex, aIndex, cIndex]); + if (!program0 || !program1 || !program2) { + testFailed("Set up program failed"); + return; + } + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No GL error from set up"); + + wtu.setupUnitQuad(gl, 0); + + debug("Inactive input in vertex shader"); + gl.useProgram(program0); + gl.vertexAttribI4i(pIndex, 1, 0, 0, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds: type in shader mismatch default vertex type is valid for inactive attrib"); + + gl.vertexAttrib4f(aIndex, 0.0, 1.0, 0.0, 0.0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds: type in shader mismatch vertexAttrib type is valid for inactive attrib"); + + debug("active int/uint inputs in vertex shader"); + gl.useProgram(program1); + gl.vertexAttribI4i(pIndex, 1, 0, 0, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Type mismatch: type in shader mismatch the default type for a vertex attrib"); + gl.vertexAttribI4i(aIndex, 0, 1, 0, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Type mismatch: type in shader mismatch the default type for a vertex attrib"); + gl.vertexAttribI4ui(bIndex, 0, 0, 1, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds"); + + debug("active float input in vertex shader"); + gl.useProgram(program2); + gl.vertexAttrib4f(pIndex, 1.0, 0.0, 0.0, 0.0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Type mismatch: generic attrib is valid per context. 'a' is set to int type by previous test case"); + gl.vertexAttrib4f(aIndex, 0.0, 1.0, 0.0, 0.0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds: default type of generic attrib is float"); +} + +function setupAttribValues(offsetILoc, offsetULoc, colorLoc) { + gl.vertexAttribI4i(offsetILoc, -1, -2, 0, 0); + gl.vertexAttribI4ui(offsetULoc, 1, 2, 0, 0); + gl.vertexAttrib4f(colorLoc, 1.0, 0, 0, 1.0); +} + +function setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer) { + gl.bindBuffer(gl.ARRAY_BUFFER, offsetIBuffer); + gl.vertexAttribIPointer(offsetILoc, 2, gl.INT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, offsetUBuffer); + gl.vertexAttribIPointer(offsetULoc, 2, gl.UNSIGNED_INT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0); +} + +function runTests() { + debug(""); + debug("Test vertexAttrib with drawArrays and drawArraysInstanced"); + + var instanceCount = 4; + + var positionLoc = 0; + var offsetILoc = 2; + var offsetULoc = 3; + var colorLoc = 4; + var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], + ['aPosition', 'aOffsetI', 'aOffsetU','aColor'], + [positionLoc, offsetILoc, offsetULoc, colorLoc]); + if (!program) { + testFailed("Set up program failed"); + return; + } + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No GL error from set up"); + + wtu.setupUnitQuad(gl, 0); + + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); + + debug("int type function on uint type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttribI4i(offsetULoc, 1, 2, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("float type function on uint type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttrib4f(offsetULoc, 1.0, 2.0, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("uint type function on int type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttribI4ui(offsetILoc, 1, 2, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("float type function on int type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttrib4f(offsetILoc, 1.0, 2.0, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("int type function on float type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttribI4i(colorLoc, 1, 0, 0, 1); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("uint type function on float type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttribI4ui(colorLoc, 1, 0, 0, 1); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug(""); + debug("Test vertexAttrib with drawElements, drawRangeElements, and drawElementsInstanced"); + wtu.setupIndexedQuad(gl, 1, 0); + + debug("Correct setup"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawRangeElements succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]); + + debug("int type function on uint type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttribI4i(offsetULoc, 1, 2, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("float type function on uint type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttrib4f(offsetULoc, 1.0, 2.0, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("uint type function on int type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttribI4ui(offsetILoc, 1, 2, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("float type function on int type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttrib4f(offsetILoc, 1.0, 2.0, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("int type function on float type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttribI4i(colorLoc, 1, 0, 0, 1); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("uint type function on float type attrib"); + setupAttribValues(offsetILoc, offsetULoc, colorLoc); + gl.vertexAttribI4ui(colorLoc, 1, 0, 0, 1); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + + var offsetIBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetIBuffer); + var offsetI = new Int32Array([-1, -2, + -1, -2, + -1, -2, + -1, -2, + -1, -2, + -1, -2]); + gl.bufferData(gl.ARRAY_BUFFER, offsetI, gl.STATIC_DRAW); + + var offsetUBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetUBuffer); + var offsetU = new Uint32Array([1, 2, + 1, 2, + 1, 2, + 1, 2, + 1, 2, + 1, 2]); + gl.bufferData(gl.ARRAY_BUFFER, offsetU, gl.STATIC_DRAW); + + var offsetFBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer); + var offsetF = new Float32Array([1.0, 2.0, + 1.0, 2.0, + 1.0, 2.0, + 1.0, 2.0, + 1.0, 2.0, + 1.0, 2.0]); + gl.bufferData(gl.ARRAY_BUFFER, offsetF, gl.STATIC_DRAW); + + var colorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + var colors = new Float32Array([0.0, 1.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0]); + gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); + + var colorUBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer); + var colorsU = new Uint32Array([0, 1, 0, 1, + 0, 1, 0, 1, + 0, 1, 0, 1, + 0, 1, 0, 1, + 0, 1, 0, 1, + 0, 1, 0, 1]); + gl.bufferData(gl.ARRAY_BUFFER, colorsU, gl.STATIC_DRAW); + + gl.enableVertexAttribArray(offsetILoc); + gl.enableVertexAttribArray(offsetULoc); + gl.enableVertexAttribArray(colorLoc); + + debug(""); + debug("Test vertexAttrib{I}Pointer with drawArrays and drawArraysInstanced"); + wtu.setupUnitQuad(gl, 0); + + debug("Correct setup"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]); + + debug("vertexAttribIPointer with int type on uint type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetIBuffer); + gl.vertexAttribIPointer(offsetULoc, 2, gl.INT, false, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("vertexAttribPointer on uint type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer); + gl.vertexAttribPointer(offsetULoc, 2, gl.FLOAT, false, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("VertexAttribIPointer with uint type on int type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetUBuffer); + gl.vertexAttribIPointer(offsetILoc, 2, gl.UNSIGNED_INT, false, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("vertexAttribPointer on int type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer); + gl.vertexAttribPointer(offsetILoc, 2, gl.FLOAT, false, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("vertexAttribIPointer with uint type on float type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer); + gl.vertexAttribIPointer(colorLoc, 4, gl.UNSIGNED_INT, false, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("vertexAttribIPointer with int type on float type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer); + gl.vertexAttribIPointer(colorLoc, 4, gl.INT, false, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug(""); + debug("Test vertexAttrib{I}Pointer with drawElements, drawRangeElements, and drawElementsInstanced"); + wtu.setupIndexedQuad(gl, 1, 0); + + debug("Correct setup"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds"); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawRangeElements succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced succeeds"); + wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]); + + debug("vertexAttribIPointer with int type on uint type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetIBuffer); + gl.vertexAttribIPointer(offsetULoc, 2, gl.INT, false, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("vertexAttribPointer on uint type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer); + gl.vertexAttribPointer(offsetULoc, 2, gl.FLOAT, false, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("VertexAttribIPointer with uint type on int type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetUBuffer); + gl.vertexAttribIPointer(offsetILoc, 2, gl.UNSIGNED_INT, false, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("vertexAttribPointer on int type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer); + gl.vertexAttribPointer(offsetILoc, 2, gl.FLOAT, false, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("vertexAttribIPointer with uint type on float type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer); + gl.vertexAttribIPointer(colorLoc, 4, gl.UNSIGNED_INT, false, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + + debug("vertexAttribIPointer with int type on float type attrib"); + setupAttribPointers(offsetILoc, offsetULoc, colorLoc, + offsetIBuffer, offsetUBuffer, colorBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer); + gl.vertexAttribIPointer(colorLoc, 4, gl.INT, false, 0, 0); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch"); +} + +debug(""); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-outofbounds.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-outofbounds.html new file mode 100644 index 000000000..358465214 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-outofbounds.html @@ -0,0 +1,199 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL BlitFramebuffer Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/glsl-conformance-test.js"></script> +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script> + +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies the functionality of blitFramebuffer when src/dst region are out-of-bounds."); + +var gl = wtu.create3DContext("example", undefined, 2); + +function checkPixel(color, expectedColor) { + var tolerance = 3; + return (Math.abs(color[0] - expectedColor[0]) <= tolerance && + Math.abs(color[1] - expectedColor[1]) <= tolerance && + Math.abs(color[2] - expectedColor[2]) <= tolerance && + Math.abs(color[3] - expectedColor[3]) <= tolerance); +} + +function blitframebuffer_filter_outofbounds(readbufferFormat, drawbufferFormat, filter) { + debug(""); + debug("blitting pixels out-of-bounds, read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat) + ", filter is: " + wtu.glEnumToString(gl, filter)); + + // Initiate data to read framebuffer + var size = 8; + var uint_read = new Uint8Array(size * size * 4); + var color = 0x20; + for (var ii = 0; ii < size * size * 4; ii += 4) { + for (var jj = 0; jj < 3; ++jj) { + uint_read[ii + jj] = color; + } + uint_read[ii + 3] = 0xff; + } + + // Create read framebuffer and feed data to read buffer + // Read buffer may have srgb image + var tex_read = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex_read); + gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint_read); + + var fbo_read = gl.createFramebuffer(); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0); + + // Create draw framebuffer. Color in draw buffer is initialized to 0. + // Draw buffer may have srgb image + var tex_draw = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex_draw); + gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + + var fbo_draw = gl.createFramebuffer(); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_draw, 0); + + if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) { + // Blit read framebuffer to the image in draw framebuffer. + var test = [ + // [srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1] + [-2, -2, 4, 4, 1, 1, 4, 4], // only src region is out-of-bounds, dst region has different width/height as src region. + [-2, -2, 4, 4, 1, 1, 7, 7], // only src region is out-of-bounds, dst region has the same width/height as src region. + [0, 0, 6, 6, 7, 7, 10, 10], // only dst region is out-of-bounds, dst region has different width/height as src region after dst region is clipped to the bounds of draw buffer. + [0, 0, 6, 6, 4, 4, 10, 10], // only dst region is out-of-bounds, dst region has the same width/height as src region after dst region is clipped to the bounds of draw buffer. + [-2, -2, 4, 4, 7, 7, 10, 10], // both src and dst region are out-of-bounds, dst region has different width/height as src region after dst region is clipped to the bounds of draw buffer. + [-2, -2, 4, 4, 4, 4, 10, 10], // both src and dst region are out-of-bounds, dst region has the same width/height as src region after dst region is clipped to the bounds of draw buffer. + [-2, -2, 4, 4, 2, 2, 10, 10], // both src and dst region are out-of-bounds. There are some dst pixels (x and y are within [4, 8] , and x or y equals to 4) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying outside the real sampling area. + [-2, -2, 4, 4, 3, 3, 10, 10], // both src and dst region are out-of-bounds. There are some dst pixels (x and y are within [4, 7] , and x or y equals to 5) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying inside the real sampling area. + [-2, -2, 4, 4, 10, 10, 2, 2], // both src and dst region are out-of-bounds, and the dst coordinates are reversed. There are some dst pixels (x and y are within [2, 7] , and x or y equals to 7) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying outside the real sampling area. + [-2, -2, 4, 4, 10, 10, 3, 3], // both src and dst region are out-of-bounds, and the dst coordinates are reversed. There are some dst pixels (x and y are within [3, 7] , and x or y equals to 7) whose corresponding src pixels are partially inside and partially outside the read sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying inside the real sampling area. + ]; + + var realBlittedDstRegion = [ + [2, 2, 4, 4], + [3, 3, 7, 7], + [7, 7, 8, 8], + [4, 4, 8, 8], + [8, 8, 8, 8], + [6, 6, 8, 8], + [5, 5, 8, 8], + [5, 5, 8, 8], + [2, 2, 7, 7], + [3, 3, 8, 8], + ] + var readbufferHasSRGBImage = (readbufferFormat == gl.SRGB8_ALPHA8); + var drawbufferHasSRGBImage = (drawbufferFormat == gl.SRGB8_ALPHA8); + + for (var i = 0; i < test.length; ++i) { + debug(""); + debug("both the read framebuffer and draw framebuffer bounds are [0, 0, 8, 8]"); + debug("blitting from src region [" + test[i][0] + ", " + test[i][1] + ", " + test[i][2] + ", " + test[i][3] + "] to dst region [" + test[i][4] + ", " + test[i][5] + ", " + test[i][6] + ", " + test[i][7] + "]"); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); + gl.bindTexture(gl.TEXTURE_2D, tex_draw); + gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.blitFramebuffer(test[i][0], test[i][1], test[i][2], test[i][3], test[i][4], test[i][5], test[i][6], test[i][7], gl.COLOR_BUFFER_BIT, filter); + + // Read pixels and check the correctness. + var pixels = new Uint8Array(size * size * 4); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw); + gl.readPixels(0, 0, size, size, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + + for (var ii = 0; ii < size; ++ii) { + for (var jj = 0; jj < size; ++jj) { + var loc = ii * size + jj; + var color = [pixels[loc * 4], pixels[loc * 4 + 1], pixels[loc * 4 + 2], pixels[loc * 4 + 3]]; + + var expectedColor = [0, 0, 0, 0]; + if (ii >= realBlittedDstRegion[i][0] && ii < realBlittedDstRegion[i][2] && jj >= realBlittedDstRegion[i][1] && jj < realBlittedDstRegion[i][3]) { + expectedColor = [0x20, 0x20, 0x20, 0xff]; + + // We may need to covert the color space for pixels in blit region + if (readbufferHasSRGBImage ^ drawbufferHasSRGBImage) { + if (drawbufferHasSRGBImage) { + expectedColor = wtu.linearToSRGB(expectedColor); + } else { + expectedColor = wtu.sRGBToLinear(expectedColor); + } + } + } + + if (checkPixel(color, expectedColor) == true) { + testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!"); + } else { + testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")"); + } + } + } + } + } else { + testFailed("framebuffer not complete"); + } + + gl.bindTexture(gl.TEXTURE_2D, null); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.deleteFramebuffer(fbo_read); + gl.deleteFramebuffer(fbo_draw); + gl.deleteTexture(tex_read); + gl.deleteTexture(tex_draw); +}; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + var filters = [gl.LINEAR, gl.NEAREST]; + for (var ii = 0; ii < filters.length; ++ii) { + blitframebuffer_filter_outofbounds(gl.RGBA8, gl.RGBA8, filters[ii]); + blitframebuffer_filter_outofbounds(gl.RGBA8, gl.SRGB8_ALPHA8, filters[ii]); + blitframebuffer_filter_outofbounds(gl.SRGB8_ALPHA8, gl.RGBA8, filters[ii]); + blitframebuffer_filter_outofbounds(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii]); + } +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-srgb.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-srgb.html new file mode 100644 index 000000000..7cce19513 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-srgb.html @@ -0,0 +1,183 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL BlitFramebuffer Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/glsl-conformance-test.js"></script> +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies the functionality of blitFramebuffer with sRGB framebuffers."); + +var gl = wtu.create3DContext("example", undefined, 2); + +function checkPixel(color, expectedColor) { + var tolerance = 7; + return (Math.abs(color[0] - expectedColor[0]) <= tolerance && + Math.abs(color[1] - expectedColor[1]) <= tolerance && + Math.abs(color[2] - expectedColor[2]) <= tolerance && + Math.abs(color[3] - expectedColor[3]) <= tolerance); +} + +var tex_read = gl.createTexture(); +var tex_draw = gl.createTexture(); +var fbo_read = gl.createFramebuffer(); +var fbo_draw = gl.createFramebuffer(); +var size_read = 4; +var size_draw = 0; + +function blitframebuffer_helper(readbufferFormat, drawbufferFormat, filter, data) { + // Create read framebuffer and feed data to read buffer + gl.bindTexture(gl.TEXTURE_2D, tex_read); + gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size_read, size_read, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0); + + // Create draw framebuffer and feed 0 to draw buffer + gl.bindTexture(gl.TEXTURE_2D, tex_draw); + gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size_draw, size_draw, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_draw, 0); + + gl.blitFramebuffer(0, 0, size_read, size_read, 0, 0, size_draw, size_draw, gl.COLOR_BUFFER_BIT, filter); + + // Read pixels for comparision + var pixels = new Uint8Array(size_draw * size_draw * 4); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw); + gl.readPixels(0, 0, size_draw, size_draw, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + return pixels; +} + +function blitframebuffer_filter_srgb(readbufferFormat, drawbufferFormat, filter, minified) { + debug(""); + debug("Test srgb filtering for blitFramebuffer, the current filter is: " + wtu.glEnumToString(gl, filter)); + var min_mag = minified ? "minified to half the size." : "magnified to double the size."; + debug("read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat) + ", minify/magnify: " + min_mag); + + // Initiate data to read framebuffer + var src_buffer = new Uint8Array(size_read * size_read * 4); + var start = 0; + for (var ii = 0; ii < size_read * size_read * 4; ii += 4) { + for (var jj = 0; jj < 3; ++jj) { + src_buffer[ii + jj] = start; + } + src_buffer[ii + 3] = 0xff; + start += 0x10; + } + + // We may need to decode srgb to linear for reference data + var ref_buffer = new Uint8Array(size_read * size_read * 4); + for (var ii = 0; ii < size_read * size_read * 4; ii += 4) { + var color = [src_buffer[ii], src_buffer[ii + 1], src_buffer[ii + 2], src_buffer[ii + 3]]; + var ref_color; + if (readbufferFormat == gl.SRGB8_ALPHA8) { + ref_color = wtu.sRGBToLinear(color); + } else { + ref_color = color; + } + for (var jj = 0; jj < 4; ++jj) { + ref_buffer[ii + jj] = ref_color[jj]; + } + } + + // Blit framebuffer to filter srgb image, but the reference data is always retrieved by blitFramebuffer against linear image + size_draw = minified ? size_read / 2 : size_read * 2; + var pixels = blitframebuffer_helper(readbufferFormat, drawbufferFormat, filter, src_buffer); + var temp = blitframebuffer_helper(gl.RGBA, gl.RGBA, filter, ref_buffer); + + // We may need to encode linear to srgb for reference data + var ref_pixels = new Uint8Array(size_draw * size_draw * 4); + for (var ii = 0; ii < size_draw * size_draw * 4; ii += 4) { + var color = [temp[ii], temp[ii + 1], temp[ii + 2], temp[ii + 3]]; + var ref_color; + if (drawbufferFormat == gl.SRGB8_ALPHA8) { + ref_color = wtu.linearToSRGB(color); + } else { + ref_color = color; + } + for (var jj = 0; jj < 4; ++jj) { + ref_pixels[ii + jj] = ref_color[jj]; + } + } + + // Compare + for (var ii = 0; ii < size_draw; ++ii) { + for (var jj = 0; jj < size_draw; ++jj) { + var index = ii * size_draw * 4 + jj; + var color = [pixels[index], pixels[index + 1], pixels[index + 2], pixels[index + 3]]; + var expectedColor = [ref_pixels[index], ref_pixels[index + 1], ref_pixels[index + 2], ref_pixels[index + 3]]; + if (checkPixel(color, expectedColor) == true) { + testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!"); + } else { + testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")"); + } + } + } +} + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + var filters = [gl.LINEAR, gl.NEAREST]; + for (var ii = 0; ii < filters.length; ++ii) { + blitframebuffer_filter_srgb(gl.RGBA8, gl.SRGB8_ALPHA8, filters[ii], true); + blitframebuffer_filter_srgb(gl.RGBA8, gl.SRGB8_ALPHA8, filters[ii], false); + blitframebuffer_filter_srgb(gl.SRGB8_ALPHA8, gl.RGBA8, filters[ii], true); + blitframebuffer_filter_srgb(gl.SRGB8_ALPHA8, gl.RGBA8, filters[ii], false); + blitframebuffer_filter_srgb(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii], true); + blitframebuffer_filter_srgb(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii], false); + } +} + +gl.bindTexture(gl.TEXTURE_2D, null); +gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); +gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); +gl.deleteFramebuffer(fbo_read); +gl.deleteFramebuffer(fbo_draw); +gl.deleteTexture(tex_read); +gl.deleteTexture(tex_draw); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-multisampled-readbuffer.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-multisampled-readbuffer.html new file mode 100644 index 000000000..568442a01 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-multisampled-readbuffer.html @@ -0,0 +1,134 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL BlitFramebuffer Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/glsl-conformance-test.js"></script> +</head> +<body> +<canvas id="canvas" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies the functionality of blitFramebuffer with multisampled sRGB color buffer."); + +var gl = wtu.create3DContext("canvas", undefined, 2); + +var tex_blit = gl.createTexture(); +var fb0 = gl.createFramebuffer(); +var rb0 = gl.createRenderbuffer(); +var fbo_blit = gl.createFramebuffer(); +var size = 32; +var program; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + init(); + + var filters = [gl.LINEAR, gl.NEAREST]; + for (var ii = 0; ii < filters.length; ++ii) { + blitframebuffer_multisampled_readbuffer(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii]); + } +} + +function init() { + program = wtu.setupColorQuad(gl); + gl.viewport(0, 0, size, size); +} + +function blitframebuffer_helper(readbufferFormat, drawbufferFormat, filter) { + // Create draw framebuffer and feed 0 to draw buffer + gl.bindTexture(gl.TEXTURE_2D, tex_blit); + gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_blit); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_blit, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup draw framebuffer should succeed"); + + gl.blitFramebuffer(0, 0, size, size, 0, 0, size, size, gl.COLOR_BUFFER_BIT, filter); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitframebuffer should succeed"); +} + +function blitframebuffer_multisampled_readbuffer(readbufferFormat, drawbufferFormat, filter) { + debug(""); + debug("Test blitFramebuffer when the read buffer is a multisampled srgb image. The filter is: " + wtu.glEnumToString(gl, filter)); + debug("read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat)); + + // Draw to a multi-sampled srgb image, and blit to a srgb image. + gl.bindRenderbuffer(gl.RENDERBUFFER, rb0); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, readbufferFormat, size, size); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb0); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0); + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + var color = [252, 122, 15, 255]; + var expectedColor = wtu.linearToSRGB(color); + for (var i = 0; i < 4; ++i) { + color[i] = color[i] / 255; + } + // Draw a rectangle. Fill it with solid color. + // Note that the draw buffer is a multisampled srgb image. So during drawing, the color will be converted into srgb color space. + gl.useProgram(program); + wtu.drawFloatColorQuad(gl, color); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + blitframebuffer_helper(readbufferFormat, drawbufferFormat, filter); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Blit from a multi-sampled srgb image to a srgb image should succeed"); + + // Compare + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_blit); + wtu.checkCanvasRect(gl, 0, 0, size, size, expectedColor); +} + +gl.bindTexture(gl.TEXTURE_2D, null); +gl.bindRenderbuffer(gl.RENDERBUFFER, null); +gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); +gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); +gl.deleteRenderbuffer(rb0); +gl.deleteTexture(tex_blit); +gl.deleteFramebuffer(fb0); +gl.deleteFramebuffer(fbo_blit); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-outside-readbuffer.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-outside-readbuffer.html new file mode 100644 index 000000000..00c5f86f3 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-outside-readbuffer.html @@ -0,0 +1,289 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL BlitFramebuffer Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/glsl-conformance-test.js"></script> +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies the functionality of blitFramebuffer."); + +var gl = wtu.create3DContext("example", undefined, 2); + +function checkPixel(color, expectedColor) { + var tolerance = 3; + return (Math.abs(color[0] - expectedColor[0]) <= tolerance && + Math.abs(color[1] - expectedColor[1]) <= tolerance && + Math.abs(color[2] - expectedColor[2]) <= tolerance && + Math.abs(color[3] - expectedColor[3]) <= tolerance); +} + +function blitframebuffer_outside_readbuffer(readbufferFormat, drawbufferFormat) { + debug(""); + debug("blitting outside of read framebuffer, read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat)); + + // Initiate data to read framebuffer + var size_read = 3; + var uint_read = new Uint8Array(size_read * size_read * 4); + var start = 0x20; + for (var ii = 0; ii < size_read * size_read * 4; ii += 4) { + for (var jj = 0; jj < 3; ++jj) { + uint_read[ii + jj] = start; + } + uint_read[ii + 3] = 0xff; + start += 0x10; + } + + // Create read framebuffer and feed data to read buffer + // Read buffer may has srgb image + var tex_read = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex_read); + gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size_read, size_read, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint_read); + + var fbo_read = gl.createFramebuffer(); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0); + + // Initiate data to draw framebuffer + var size_draw = 7; + var uint_draw = new Uint8Array(size_draw * size_draw * 4); + for (var ii = 0; ii < size_draw * size_draw * 4; ii += 4) { + for (var jj = 0; jj < 3; ++jj) { + uint_draw[ii + jj] = 0x10; + } + uint_draw[ii + 3] = 0xff; + } + + // Create draw framebuffer and feed data to draw buffer + // Draw buffer may has srgb image + var tex_draw = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex_draw); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + + gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size_draw, size_draw, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint_draw); + + var fbo_draw = gl.createFramebuffer(); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_draw, 0); + + if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) { + var ref = [ + // The reference pixels of the 1st line: (0, 0) ~ (6, 0) + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + + // The reference pixels of the 2nd line: (0, 1) ~ (6, 1) + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + + // The reference pixels of the 3rd line: (0, 2) ~ (6, 2) + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x20, 0x20, 0x20, 0xff], [0x30, 0x30, 0x30, 0xff], + [0x40, 0x40, 0x40, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + + // The reference pixels of the 4th line: (0, 3) ~ (6, 3) + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x50, 0x50, 0x50, 0xff], [0x60, 0x60, 0x60, 0xff], + [0x70, 0x70, 0x70, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + + // The reference pixels of the 5th line: (0, 4) ~ (6, 4) + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x80, 0x80, 0x80, 0xff], [0x90, 0x90, 0x90, 0xff], + [0xa0, 0xa0, 0xa0, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + + // The reference pixels of the 6th line: (0, 5) ~ (6, 5) + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + + // The reference pixels of the 7th line: (0, 6) ~ (6, 6) + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], + ]; + + // The 1st round test: blit read framebuffer to the image in draw framebuffer + // All directions of the read region have pixels outside of the read buffer + // The src region and/or dst region may be reversed during blitting. + var test1 = [ + [-1, 4, 1, 6], // reverse neither src nor dst + [4, -1, 1, 6], // reverse src only + [-1, 4, 6, 1], // reverse dst only + [4, -1, 6, 1] // reverse both src and dst + ]; + + var readbufferHasSRGBImage = (readbufferFormat == gl.SRGB8_ALPHA8); + var drawbufferHasSRGBImage = (drawbufferFormat == gl.SRGB8_ALPHA8); + + for (var i = 0; i < 4; ++i) { + debug(""); + switch (i) { + case 0: debug("reverse neither src region nor dst region"); break; + case 1: debug("reverse src region only"); break; + case 2: debug("reverse dst region only"); break; + case 3: debug("reverse both src region and dst region"); break; + } + var srcStart = test1[i][0]; + var srcEnd = test1[i][1]; + var dstStart = test1[i][2]; + var dstEnd = test1[i][3]; + var realBlittedDstStart = 2; + var realBlittedDstEnd = 5; + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); + gl.blitFramebuffer(srcStart, srcStart, srcEnd, srcEnd, dstStart, dstStart, dstEnd, dstEnd, gl.COLOR_BUFFER_BIT, gl.LINEAR); + + // Read pixels and check the correctness. + var pixels = new Uint8Array(size_draw * size_draw * 4); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw); + gl.readPixels(0, 0, size_draw, size_draw, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + + for (var ii = 0; ii < size_draw; ++ii) { + for (var jj = 0; jj < size_draw; ++jj) { + var loc = ii * size_draw + jj; + var color = [pixels[loc * 4], pixels[loc * 4 + 1], pixels[loc * 4 + 2], pixels[loc * 4 + 3]]; + + // We may need to reverse the reference loc if necessary + var ref_loc = loc; + var reverse_src = (srcStart < srcEnd); + var reverse_dst = (dstStart < dstEnd); + var reversed = reverse_src ^ reverse_dst; + if (reversed) { + ref_loc = (size_draw - ii - 1) * size_draw + (size_draw - jj -1); + } + var expectedColor = ref[ref_loc]; + + // We may need to covert the color space for pixels in blit region + if ((readbufferHasSRGBImage ^ drawbufferHasSRGBImage) && + (ii >= realBlittedDstStart && ii < realBlittedDstEnd && jj >= realBlittedDstStart && jj < realBlittedDstEnd)) { + if (drawbufferHasSRGBImage) { + expectedColor = wtu.linearToSRGB(expectedColor); + } else { + expectedColor = wtu.sRGBToLinear(expectedColor); + } + } + if (checkPixel(color, expectedColor) == true) { + testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!"); + } else { + testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")"); + } + } + } + } + + // The 2nd round test: blit read framebuffer to the image in draw framebuffer + // Only one direction of the read region have pixels outside of the read buffer + var tests = [ + [-1, 0], // pixels are outside the left edge of the read buffer + [0, -1], // pixels are outside the bottom edge of the read buffer + [1, 0], // pixels are outside the right edge of the read buffer + [0, 1] // pixels are outside the top edge of the read buffer + ]; + for (var i = 0; i < 4; ++i) { + debug(""); + switch (i) { + case 0: debug("verify that pixels lying outside the left edge of the read buffer should remain untouched"); break; + case 1: debug("verify that pixels lying outside the bottom edge of the read buffer should remain untouched"); break; + case 2: debug("verify that pixels lying outside the right edge of the read buffer should remain untouched"); break; + case 3: debug("verify that pixels lying outside the top edge of the read buffer should remain untouched"); break; + } + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); + var srcX = tests[i][0]; + var srcY = tests[i][1]; + var offset = dstStart - srcStart; + gl.blitFramebuffer(srcX, srcY, srcX + size_read, srcY + size_read, + srcX + offset, srcY + offset, srcX + offset + size_read, srcY + offset + size_read, + gl.COLOR_BUFFER_BIT, gl.LINEAR); + + // Read pixels and check the correctness. + var pixels = new Uint8Array(size_draw * size_draw * 4); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw); + gl.readPixels(0, 0, size_draw, size_draw, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + for (var ii = srcY + offset; ii < srcY + offset + size_read; ++ii) { + for (var jj = srcX + offset; jj < srcX + offset + size_read; ++jj) { + var loc = ii * size_draw + jj; + var color = [pixels[loc * 4], pixels[loc * 4 + 1], pixels[loc * 4 + 2], pixels[loc * 4 + 3]]; + var expectedColor = ref[loc]; + // We may need to covert the color space for pixels in blit region + if ((readbufferHasSRGBImage ^ drawbufferHasSRGBImage) && + (ii >= realBlittedDstStart && ii < realBlittedDstEnd && jj >= realBlittedDstStart && jj < realBlittedDstEnd)) { + if (drawbufferHasSRGBImage) { + expectedColor = wtu.linearToSRGB(expectedColor); + } else { + expectedColor = wtu.sRGBToLinear(expectedColor); + } + } + if (checkPixel(color, expectedColor) == true) { + testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!"); + } else { + testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")"); + } + } + } + } + } else { + testFailed("framebuffer not complete"); + } + + gl.bindTexture(gl.TEXTURE_2D, null); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.deleteFramebuffer(fbo_read); + gl.deleteFramebuffer(fbo_draw); + gl.deleteTexture(tex_read); + gl.deleteTexture(tex_draw); +}; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + blitframebuffer_outside_readbuffer(gl.RGBA8, gl.RGBA8); + blitframebuffer_outside_readbuffer(gl.RGBA8, gl.SRGB8_ALPHA8); + blitframebuffer_outside_readbuffer(gl.SRGB8_ALPHA8, gl.RGBA8); + blitframebuffer_outside_readbuffer(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-scissor-enabled.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-scissor-enabled.html new file mode 100644 index 000000000..d1077b9d4 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-scissor-enabled.html @@ -0,0 +1,182 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL BlitFramebuffer Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/glsl-conformance-test.js"></script> +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies the functionality of blitFramebuffer when scissor test is enabled."); + +var gl = wtu.create3DContext("example", undefined, 2); + +// Define the src region and dst region for blitFramebuffer +var blit_src = [0, 0, 4, 4]; +var blit_dst = [2, 2, 6, 6]; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + var bounds = [ + [0, 0, 4, 4], // Partially intersects with blitFramebuffer's dst region + [0, 0, 2, 2], // No intersection with blitFramebuffer's dst region + ]; + + // We can compute the real drawing area by intersecting the scissor bound with dst region of blitting. + var intersections = [ + [2, 2, 4, 4], + [0, 0, 0, 0], + ]; + + for (var ii = 0; ii < bounds.length; ++ii) { + blitframebuffer_scissor(gl.RGBA8, gl.RGBA8, bounds[ii], intersections[ii]); + blitframebuffer_scissor(gl.RGBA8, gl.SRGB8_ALPHA8, bounds[ii], intersections[ii]); + blitframebuffer_scissor(gl.SRGB8_ALPHA8, gl.RGBA8, bounds[ii], intersections[ii]); + blitframebuffer_scissor(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, bounds[ii], intersections[ii]); + } +} + +function checkPixel(color, expectedColor) { + var tolerance = 3; + return (Math.abs(color[0] - expectedColor[0]) <= tolerance && + Math.abs(color[1] - expectedColor[1]) <= tolerance && + Math.abs(color[2] - expectedColor[2]) <= tolerance && + Math.abs(color[3] - expectedColor[3]) <= tolerance); +} + +function blitframebuffer_scissor(readbufferFormat, drawbufferFormat, bound, intersection) { + debug(""); + debug("read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat)); + + + // Initiate data to read framebuffer + var size = 8; + var data = new Uint8Array(size * size * 4); + var color = [250, 100, 15, 255]; + for (var ii = 0; ii < size * size * 4; ii += 4) { + for (var jj = 0; jj < 4; ++jj) { + data[ii + jj] = color[jj]; + } + } + + // Feed data to read buffer. Feed 0 to draw buffer. + var tex_read = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex_read); + gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); + + var fbo_read = gl.createFramebuffer(); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0); + + var tex_draw = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex_draw); + gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + + var fbo_draw = gl.createFramebuffer(); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_draw, 0); + if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE || gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + + // Enable scissor test. Then blit framebuffer. + gl.enable(gl.SCISSOR_TEST); + gl.scissor(bound[0], bound[1], bound[2], bound[3]); + gl.blitFramebuffer(blit_src[0], blit_src[1], blit_src[2], blit_src[3], blit_dst[0], blit_dst[1], blit_dst[2], blit_dst[3], gl.COLOR_BUFFER_BIT, gl.LINEAR); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitframebuffer should succeed"); + + // Read pixels and Comparison + var pixels = new Uint8Array(size * size * 4); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw); + gl.readPixels(0, 0, size, size, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels should succeed"); + + var blitColor; + var expectedColor; + var clearColor = [0, 0, 0, 0]; + + if (readbufferFormat == drawbufferFormat) { + blitColor = color; + } else if (readbufferFormat == gl.SRGB8_ALPHA8) { + blitColor = wtu.sRGBToLinear(color); + } else { + blitColor = wtu.linearToSRGB(color); + } + + var failed = false; + for (var ii = 0; ii < size; ++ii) { + for (var jj = 0; jj < size; ++jj) { + if (ii >= intersection[0] && jj >= intersection[1] && ii < intersection[2] && jj < intersection[3]) { + expectedColor = blitColor; + } else { + expectedColor = clearColor; + } + var index = (ii * size + jj) * 4; + var pixelColor = [pixels[index], pixels[index + 1], pixels[index + 2], pixels[index + 3]]; + if (checkPixel(pixelColor, expectedColor) == false) { + failed = true; + debug("Pixels comparison failed. Pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + pixelColor + ")"); + } + } + } + if (failed == false) { + testPassed("All pixels comparision passed!"); + } + + // Deinit + gl.bindTexture(gl.TEXTURE_2D, null); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.deleteFramebuffer(fbo_read); + gl.deleteFramebuffer(fbo_draw); + gl.deleteTexture(tex_read); + gl.deleteTexture(tex_draw); +}; + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-size-overflow.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-size-overflow.html new file mode 100644 index 000000000..71e3ab7d9 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-size-overflow.html @@ -0,0 +1,98 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL BlitFramebuffer Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies blitFramebuffer won't cause a crash when the computed sizes might overflow."); + +var width = 8; +var height = 8; + +var gl = wtu.create3DContext("example", undefined, 2); +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + blit_region_test(); +} + +function blit_region_test() { + + debug(""); + debug("Begin to run blitFramebuffer. The computed width/height of src and/or dst region might overflow during blitting."); + var tex0 = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + var fb0 = gl.createFramebuffer(); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex0, 0); + + var tex1 = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex1); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + var fb1 = gl.createFramebuffer(); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb1); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex1, 0); + if ((gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) || + (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)) { + testFailed("Framebuffer incomplete."); + return; + } + + var max = 0x7fffffff; + gl.blitFramebuffer(0, 0, max, max, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST); + gl.blitFramebuffer(0, 0, width, height, 0, 0, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST); + gl.blitFramebuffer(0, 0, max, max, 0, 0, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST); + + gl.blitFramebuffer(-1, -1, max, max, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST); + gl.blitFramebuffer(0, 0, width, height, -1, -1, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST); + gl.blitFramebuffer(-1, -1, max, max, -1, -1, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST); + gl.blitFramebuffer(-max - 1, -max - 1, max, max, -max - 1, -max - 1, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST); + testPassed("Congratulations! blitFramebuffer doesn't cause the browser crash when the computed width/height of src and/or dst region might overflow."); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-srgb-and-linear-drawbuffers.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-srgb-and-linear-drawbuffers.html new file mode 100644 index 000000000..39803416f --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-srgb-and-linear-drawbuffers.html @@ -0,0 +1,229 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL BlitFramebuffer Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/glsl-conformance-test.js"></script> +</head> +<body> +<canvas id="canvas" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies the functionality of blitFramebuffer with multiple draw buffers (srgb image and linear image)."); + +var gl = wtu.create3DContext("canvas", undefined, 2); +var linearMask = 1; +var srgbMask = 2; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + var filters = [gl.LINEAR, gl.NEAREST]; + var drawbuffersFormats = [linearMask, srgbMask, linearMask | srgbMask]; + for (var ii = 0; ii < filters.length; ++ii) { + for (var jj = 0; jj < drawbuffersFormats.length; ++jj) { + blitframebuffer_srgb_and_linear_drawbuffers(gl.SRGB8_ALPHA8, drawbuffersFormats[jj], filters[ii]); + blitframebuffer_srgb_and_linear_drawbuffers(gl.RGBA8, drawbuffersFormats[jj], filters[ii]); + } + } +} + +function blitframebuffer_srgb_and_linear_drawbuffers(readbufferFormat, drawbuffersFormatMask, filter) { + debug(""); + debug("The filter is: " + wtu.glEnumToString(gl, filter)); + debug("Read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat)); + var drawbuffersFormat = "\0"; + if (drawbuffersFormatMask & linearMask) { + drawbuffersFormat += " linear "; + } + if (drawbuffersFormatMask & srgbMask) { + drawbuffersFormat += " srgb "; + } + debug("The test have multiple draw buffers, the images are: " + drawbuffersFormat); + + var tex_srgb0 = gl.createTexture(); + var tex_srgb1 = gl.createTexture(); + var tex_linear0 = gl.createTexture(); + var tex_linear1 = gl.createTexture(); + var tex_read = gl.createTexture(); + var fbo_read = gl.createFramebuffer(); + var fbo_draw = gl.createFramebuffer(); + + // Create read buffer and feed data to the read buffer + var size = 8; + var data = new Uint8Array(size * size * 4); + var color = [250, 100, 15, 255]; + for (var ii = 0; ii < size * size * 4; ii += 4) { + for (var jj = 0; jj < 4; ++jj) { + data[ii + jj] = color[jj]; + } + } + gl.bindTexture(gl.TEXTURE_2D, tex_read); + gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup read framebuffer should succeed"); + + // Create multiple textures. Attach them as fbo's draw buffers. + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); + + var drawbuffers = [gl.NONE, gl.NONE, gl.NONE, gl.NONE]; + if (drawbuffersFormatMask & srgbMask) { + gl.bindTexture(gl.TEXTURE_2D, tex_srgb0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_srgb0, 0); + gl.bindTexture(gl.TEXTURE_2D, tex_srgb1); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_2D, tex_srgb1, 0); + drawbuffers[0] = gl.COLOR_ATTACHMENT0; + drawbuffers[2] = gl.COLOR_ATTACHMENT2; + } + + if (drawbuffersFormatMask & linearMask) { + gl.bindTexture(gl.TEXTURE_2D, tex_linear0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex_linear0, 0); + gl.bindTexture(gl.TEXTURE_2D, tex_linear1); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT3, gl.TEXTURE_2D, tex_linear1, 0); + drawbuffers[1] = gl.COLOR_ATTACHMENT1; + drawbuffers[3] = gl.COLOR_ATTACHMENT3; + } + + gl.drawBuffers(drawbuffers); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup draw framebuffer should succeed"); + + if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE || + gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete when setup draw framebuffer."); + return; + } + + // Blit to multiple draw buffers with srgb images and linear images + var dstSize = size - 1; + gl.blitFramebuffer(0, 0, size, size, 0, 0, dstSize, dstSize, gl.COLOR_BUFFER_BIT, filter); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitframebuffer should succeed"); + + // Read pixels from srgb images and linear images + var srgbPixels0 = new Uint8Array(dstSize * dstSize * 4); + var srgbPixels1 = new Uint8Array(dstSize * dstSize * 4); + var linearPixels0 = new Uint8Array(dstSize * dstSize * 4); + var linearPixels1 = new Uint8Array(dstSize * dstSize * 4); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw); + if (drawbuffersFormatMask & srgbMask) { + gl.readBuffer(gl.COLOR_ATTACHMENT0); + gl.readPixels(0, 0, dstSize, dstSize, gl.RGBA, gl.UNSIGNED_BYTE, srgbPixels0); + gl.readBuffer(gl.COLOR_ATTACHMENT2); + gl.readPixels(0, 0, dstSize, dstSize, gl.RGBA, gl.UNSIGNED_BYTE, srgbPixels1); + } + + if (drawbuffersFormatMask & linearMask) { + gl.readBuffer(gl.COLOR_ATTACHMENT1); + gl.readPixels(0, 0, dstSize, dstSize, gl.RGBA, gl.UNSIGNED_BYTE, linearPixels0); + gl.readBuffer(gl.COLOR_ATTACHMENT3); + gl.readPixels(0, 0, dstSize, dstSize, gl.RGBA, gl.UNSIGNED_BYTE, linearPixels1); + } + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readpixels should succeed"); + + // Compare + var expectedSRGBColor = (readbufferFormat == gl.SRGB8_ALPHA8) ? color : wtu.linearToSRGB(color); + var expectedLinearColor = (readbufferFormat == gl.SRGB8_ALPHA8) ? wtu.sRGBToLinear(color) : color; + var failed = false; + for (var ii = 0; ii < dstSize; ++ii) { + for (var jj = 0; jj < dstSize; ++jj) { + var index = (ii * dstSize + jj) * 4; + if (drawbuffersFormatMask & srgbMask) { + var srgbColor0 = [srgbPixels0[index], srgbPixels0[index + 1], srgbPixels0[index + 2], srgbPixels0[index + 3]]; + if (checkPixel(srgbColor0, expectedSRGBColor) == false) { + failed = true; + debug("Pixels comparison failed for the 1st sRGB image. Pixel at [" + jj + ", " + ii + "] should be (" + expectedSRGBColor + "), but the actual color is (" + srgbColor0 + ")"); + } + var srgbColor1 = [srgbPixels1[index], srgbPixels1[index + 1], srgbPixels1[index + 2], srgbPixels1[index + 3]]; + if (checkPixel(srgbColor1, expectedSRGBColor) == false) { + failed = true; + debug("Pixels comparison failed for the 2nd sRGB image. Pixel at [" + jj + ", " + ii + "] should be (" + expectedSRGBColor + "), but the actual color is (" + srgbColor1 + ")"); + } + } + + if (drawbuffersFormatMask & linearMask) { + var linearColor0 = [linearPixels0[index], linearPixels0[index + 1], linearPixels0[index + 2], linearPixels0[index + 3]]; + if (checkPixel(linearColor0, expectedLinearColor) == false) { + failed = true; + debug("Pixel comparison failed for the 1st linear image. Pixel at [" + jj + ", " + ii + "] should be (" + color + "), but the actual color is (" + linearColor0 + ")"); + } + var linearColor1 = [linearPixels1[index], linearPixels1[index + 1], linearPixels1[index + 2], linearPixels1[index + 3]]; + if (checkPixel(linearColor1, expectedLinearColor) == false) { + failed = true; + debug("Pixel comparison failed for the 2nd linear image. Pixel at [" + jj + ", " + ii + "] should be (" + color + "), but the actual color is (" + linearColor1 + ")"); + } + } + } + } + if (failed == false) { + testPassed("All pixels comparision passed!"); + } + + // deinit + gl.bindTexture(gl.TEXTURE_2D, null); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.deleteTexture(tex_srgb0); + gl.deleteTexture(tex_linear0); + gl.deleteTexture(tex_srgb1); + gl.deleteTexture(tex_linear1); + gl.deleteTexture(tex_read); + gl.deleteFramebuffer(fbo_read); + gl.deleteFramebuffer(fbo_draw); +} + +function checkPixel(color, expectedColor) { + var tolerance = 3; + return (Math.abs(color[0] - expectedColor[0]) <= tolerance && + Math.abs(color[1] - expectedColor[1]) <= tolerance && + Math.abs(color[2] - expectedColor[2]) <= tolerance && + Math.abs(color[3] - expectedColor[3]) <= tolerance); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-stencil-only.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-stencil-only.html new file mode 100644 index 000000000..9817b6240 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-stencil-only.html @@ -0,0 +1,192 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL BlitFramebuffer Stencil-only Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/glsl-conformance-test.js"></script> + +<script id="vs" type="x-shader/x-vertex">#version 300 es +in vec4 position; +void main() { + gl_Position = position; +} +</script> +<script id="fs" type="x-shader/x-fragment">#version 300 es +out mediump vec4 colorOut; +uniform mediump vec3 color; +void main() { + colorOut = vec4(color, 1.0); +} +</script> + +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test covers some edge cases of blitFramebuffer with stencil."); + +var gl = wtu.create3DContext("example", undefined, 2); + +var program, colorLoc; + +function init_buffer(format) { + var buf = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, buf) + var tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 16, 16); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + var rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, format, 16, 16); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, + gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, rbo); + + gl.clearBufferfi(gl.DEPTH_STENCIL, 0, 1.0, 0); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after buffer init"); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + return { fbo: buf, color: tex, depthStencil: rbo }; +} + +var quadVB; + +function drawQuad(depth) { + if (!quadVB) { + quadVB = gl.createBuffer() + } + + var quadVerts = new Float32Array(3 * 6); + quadVerts[0] = -1.0; quadVerts[1] = 1.0; quadVerts[2] = depth; + quadVerts[3] = -1.0; quadVerts[4] = -1.0; quadVerts[5] = depth; + quadVerts[6] = 1.0; quadVerts[7] = -1.0; quadVerts[8] = depth; + quadVerts[9] = -1.0; quadVerts[10] = 1.0; quadVerts[11] = depth; + quadVerts[12] = 1.0; quadVerts[13] = -1.0; quadVerts[14] = depth; + quadVerts[15] = 1.0; quadVerts[16] = 1.0; quadVerts[17] = depth; + + gl.bindBuffer(gl.ARRAY_BUFFER, quadVB); + gl.bufferData(gl.ARRAY_BUFFER, quadVerts, gl.STATIC_DRAW); + gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, 0); + gl.enableVertexAttribArray(0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawQuad"); +} + +// Test based on dEQP-GLES3.functional.blit.depth_stencil.depth_24_stencil8_stencil_only +function test_stencil_only_blit(format) { + debug("testing format: " + wtu.glEnumToString(format)) + + var src = init_buffer(format); + var dest = init_buffer(format); + + gl.bindFramebuffer(gl.FRAMEBUFFER, src.fbo); + gl.viewport(0, 0, 16, 16); + + // Fill source with red, depth = 0.5, stencil = 7 + gl.enable(gl.DEPTH_TEST); + gl.enable(gl.STENCIL_TEST); + gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); + gl.stencilFunc(gl.ALWAYS, 7, 0xFF); + gl.uniform3f(colorLoc, 1.0, 0.0, 0.0); + drawQuad(0.5); + + // Fill dest with yellow, depth = 0.0, stencil = 1 + gl.bindFramebuffer(gl.FRAMEBUFFER, dest.fbo); + gl.stencilFunc(gl.ALWAYS, 1, 0xff); + gl.uniform3f(colorLoc, 1.0, 1.0, 0.0); + drawQuad(0.0); + + // Perform copy. + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, src.fbo); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, dest.fbo); + gl.blitFramebuffer(0, 0, 16, 16, 0, 0, 16, 16, gl.STENCIL_BUFFER_BIT, gl.NEAREST); + + // Render blue where depth < 0, decrement on depth failure. + gl.bindFramebuffer(gl.FRAMEBUFFER, dest.fbo); + gl.stencilOp(gl.KEEP, gl.DECR, gl.KEEP); + gl.stencilFunc(gl.ALWAYS, 0, 0xff); + + gl.uniform3f(colorLoc, 0.0, 0.0, 1.0); + drawQuad(0.0); + + // Render green where stencil == 6. + gl.disable(gl.DEPTH_TEST); + gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); + gl.stencilFunc(gl.EQUAL, 6, 0xff); + + gl.uniform3f(colorLoc, 0.0, 1.0, 0.0); + drawQuad(0.0); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after test"); + wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0, 255, 0, 255], + "stencil test should be green"); + + gl.deleteFramebuffer(src.fbo); + gl.deleteFramebuffer(dest.fbo); + gl.deleteTexture(src.color); + gl.deleteTexture(dest.color); + gl.deleteRenderbuffer(src.depthStencil); + gl.deleteRenderbuffer(dest.depthStencil); +} + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + program = wtu.setupProgram(gl, ["vs", "fs"], ["position"]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after program initialization"); + shouldBe('gl.getProgramParameter(program, gl.LINK_STATUS)', 'true'); + + colorLoc = gl.getUniformLocation(program, "color") + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "query uniform location"); + shouldBeNonNull('colorLoc') + + test_stencil_only_blit(gl.DEPTH24_STENCIL8); + test_stencil_only_blit(gl.DEPTH32F_STENCIL8); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-test.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-test.html new file mode 100644 index 000000000..0322abac3 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-test.html @@ -0,0 +1,342 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL BlitFramebuffer Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies the functionality of blitFramebuffer for some corner cases."); + +var width = 8; +var height = 8; + +var gl = wtu.create3DContext("example", undefined, 2); +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + blit_framebuffer_feedback_loop(); + blit_framebuffer_multisampling_srgb(); +} + + +function blit_framebuffer_feedback_loop() { + + debug(""); + debug("This test vefify that whether the src resource and dst resource have identical image."); + // Create read fbo and its color attachment. + var tex_2d = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex_2d); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.generateMipmap(gl.TEXTURE_2D); + + var fb0 = gl.createFramebuffer(); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_2d, 0); + if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + + // Create draw fbo and its color attachment. + var rb0 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb0); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, width, height); + + var fb1 = gl.createFramebuffer(); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0); + if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + + // Blit framebuffer, all conditions are OK. + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed."); + + // Blit framebuffer, the src buffer and the dst buffer should not be identical. + // Exactly the same read/draw fbo + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb0); + gl.blitFramebuffer(0, 0, 2, 2, 4, 4, 6, 6, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw buffer are identical."); + + // Exactly the same read/draw framebuffer: default framebuffer + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.blitFramebuffer(0, 0, 2, 2, 4, 4, 6, 6, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw buffer are identical."); + + // The same image with the same level bound to read/draw buffer. + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_2d, 0); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_2d, 0); + if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE || + gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + gl.blitFramebuffer(0, 0, 2, 2, 4, 4, 6, 6, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw color buffer are identical."); + + // The same image in read/draw buffer, but different levels are bound to read/draw buffer respectively. + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_2d, 1); + if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed if read/draw buffer has the same image with different levels."); + + // The same cube_map image in read/draw buffer, but different faces are bound to read/draw buffer respectively. + var tex_cube_map = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex_cube_map); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, tex_cube_map, 0); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_NEGATIVE_X, tex_cube_map, 0); + if ((gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) || + (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)) { + testFailed("Framebuffer incomplete."); + return; + } + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed if read/draw buffer has the same CUBE_MAP image with different faces."); + + // The same 3D/2D_ARRAY image in read/draw buffer, but different layers are bound to read/draw buffer respectively. + var tex_2d_array = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D_ARRAY, tex_2d_array); + var depth = 2; + gl.texImage3D(gl.TEXTURE_2D_ARRAY, 0, gl.RGBA8, width, height, depth, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + var level = 0, layer = 0; + gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex_2d_array, level, layer); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + layer = 1; + gl.framebufferTextureLayer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex_2d_array, level, layer); + if ((gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) || + (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)) { + testFailed("Framebuffer incomplete."); + return; + } + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed if read/draw buffer has the same 3D/2D_ARRAY image with different layers."); + + // The same image are bound as depth buffer in both read framebuffer and draw framebuffer + var rb1 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, width, height); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, tex_cube_map, 0); + gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb1); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_NEGATIVE_X, tex_cube_map, 0); + gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb1); + if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE || + gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + // But the mask doesn't have depth buffer bit. + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed."); + + // The mask has depth buffer bit. + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw framebuffer have identical depth buffer attachment."); + + // The same image are bound as stencil buffer in both read framebuffer and draw framebuffer + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, rb1); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, rb1); + if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE || + gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + // But the mask doesn't have stencil buffer bit. + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed."); + + // The mask has stencil buffer bit. + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw framebuffer have identical stencil buffer attachment."); + + // The same image are bound as color buffer in both read framebuffer and draw framebuffer + var rb2 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb2); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, width, height); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, tex_cube_map, 0); + gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null); + gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null); + gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb2); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_NEGATIVE_X, tex_cube_map, 0); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_CUBE_MAP_POSITIVE_X, tex_cube_map, 0); + gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb1); + if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE || + gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + // But the mask doesn't have color buffer bit. + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.DEPTH_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed."); + + // The mask has color buffer bit, but the same image is not specified as draw buffer. + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed."); + + // The mask has color buffer bit, the same image is specified as both read buffer and draw buffer. + gl.drawBuffers([gl.COLOR_ATTACHENT0, gl.COLOR_ATTACHMENT1]); + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw buffers have identical color buffer attachment."); + + gl.bindTexture(gl.TEXTURE_2D, null); + gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); + gl.bindTexture(gl.TEXTURE_2D_ARRAY, null); + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.deleteTexture(tex_2d); + gl.deleteTexture(tex_cube_map); + gl.deleteTexture(tex_2d_array); + gl.deleteRenderbuffer(rb0); + gl.deleteRenderbuffer(rb1); + gl.deleteRenderbuffer(rb2); + gl.deleteFramebuffer(fb0); + gl.deleteFramebuffer(fb1); +}; + +function blit_framebuffer_multisampling_srgb() { + + debug(""); + debug("This test vefify the functionality of blitframebuffer from or to a multisampled srgb image."); + + // Read buffer can have multisampled srgb image, but draw buffers can not. + var rb0 = gl.createRenderbuffer(); + var fb0 = gl.createFramebuffer(); + var rb1 = gl.createRenderbuffer(); + var fb1 = gl.createFramebuffer(); + var samples = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.SRGB8_ALPHA8, gl.SAMPLES); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb0); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[0], gl.SRGB8_ALPHA8, width, height); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0); + gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0); + + gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.SRGB8_ALPHA8, width, height); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb1); + if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE || + gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.LINEAR); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer from multisampled srgb image should succeed."); + + gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[0], gl.SRGB8_ALPHA8, width, height); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb1); + if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.LINEAR); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer to a multisampled srgb image should generate INVALID_OPERATION."); + + // BlitFramebuffer from a multisampled srgb image, the src region and the dst region must be exactly the same. + gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.SRGB8_ALPHA8, width, height); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb1); + if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + gl.blitFramebuffer(0, 0, 2, 2, 2, 2, 4, 4, gl.COLOR_BUFFER_BIT, gl.LINEAR); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer from a multisampled srgb image, the src region and the dst region must be exactly the same."); + + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 4, 4, gl.COLOR_BUFFER_BIT, gl.LINEAR); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer from a multisampled srgb image, the src region and the dst region must be exactly the same."); + + // BlitFramebuffer from a multisampled srgb image, the format/type must be exactly the same. So blit from a multisampled srgb image to a linear image is invalid. + var tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1); + gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.LINEAR); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer from a multisampled srgb image, the format/type must be exactly the same."); + + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + gl.bindTexture(gl.TEXTURE_2D, null); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.deleteRenderbuffer(rb0); + gl.deleteRenderbuffer(rb1); + gl.deleteTexture(tex); + gl.deleteFramebuffer(fb0); + gl.deleteFramebuffer(fb1); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/canvas-resizing-with-pbo-bound.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/canvas-resizing-with-pbo-bound.html new file mode 100644 index 000000000..e09a4473a --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/canvas-resizing-with-pbo-bound.html @@ -0,0 +1,130 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL 2 Resizing With PBO Bound Test</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<canvas id="canvas1" style="width: 256px; height: 256px;"> </canvas> +<canvas id="canvas2" style="width: 256px; height: 256px;"> </canvas> +<div id="console"></div> +<script> +"use strict"; + +description("Verifies that resizing the canvas (recreating the backing framebuffer) works correctly while a PBO is bound."); + +debug(""); +debug("Regression test for Chromium <a href='https://bugs.chromium.org/p/chromium/issues/detail?id=644572'>Issue 644572</a>"); +debug(""); + +var wtu = WebGLTestUtils; +var canvas; +var largeSize = 256; +var smallSize = 128; +var currentSize; +var gl; +var numFrames = 0; +var testNumber = 0; +var pbo; + +function nextTest() { + ++testNumber; + numFrames = 0; + currentSize = largeSize; + if (testNumber > 2) { + finishTest(); + return; + } + + canvas = document.getElementById("canvas" + testNumber); + canvas.width = currentSize; + canvas.height = currentSize; + var usePreserveDrawingBuffer = (testNumber == 1) ? true : false; + debug("Testing preserveDrawingBuffer = " + usePreserveDrawingBuffer); + gl = wtu.create3DContext(canvas, { preserveDrawingBuffer: usePreserveDrawingBuffer }, 2); + + if (!gl) { + testFailed("context does not exist"); + } else { + testPassed("context exists"); + + gl.clearColor(0, 1, 0, 1); + + pbo = gl.createBuffer(); + gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo); + + wtu.requestAnimFrame(render); + } +} + +function render() { + if (++numFrames < 4) { + if (currentSize == largeSize) { + canvas.height = smallSize; + currentSize = smallSize; + } else { + canvas.height = largeSize; + currentSize = largeSize; + } + } + + gl.viewport(0, 0, largeSize, currentSize); + gl.clear(gl.COLOR_BUFFER_BIT); + + // Check the four corners + var green = [ 0, 255, 0, 255 ]; + var inset = 3; + wtu.checkCanvasRect(gl, inset, inset, 1, 1, green, "lower left should be green", 1); + wtu.checkCanvasRect(gl, largeSize - inset, inset, 1, 1, green, "lower right should be green", 1); + wtu.checkCanvasRect(gl, inset, currentSize - inset, 1, 1, green, "upper left should be green", 1); + wtu.checkCanvasRect(gl, largeSize - inset, currentSize - inset, 1, 1, green, "upper right should be green", 1); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No GL error"); + if (gl.getParameter(gl.PIXEL_UNPACK_BUFFER_BINDING) != pbo) { + testFailed("Pixel unpack buffer binding was lost"); + } + + if (numFrames < 4) { + wtu.requestAnimFrame(render); + } else { + wtu.requestAnimFrame(nextTest); + } +} + +wtu.requestAnimFrame(nextTest); + +</script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-func-buffer-type-match.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-func-buffer-type-match.html new file mode 100644 index 000000000..ac16ea251 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-func-buffer-type-match.html @@ -0,0 +1,166 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Test clear and clearBuffer functions have to match fbo's buffer format</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<canvas id="canvas" width="20" height="20"> </canvas> +<script> +"use strict"; +description("This tests the WebGL2 specific constraint that clear or clearBuffer* functions have to be compatible with fbo's buffer format"); + +var setupRenderbuffer = function(attachment, format) { + var renderbuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderbuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, format, canvas.width, canvas.height); + return renderbuffer; +} + +var wtu = WebGLTestUtils; +var canvas = document.getElementById("canvas"); +var gl = wtu.create3DContext(canvas, undefined, 2); +if (!gl) { + testFailed("context does not exist"); +} else { + testPassed("context exists"); + + var fb = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + + debug(""); + debug("Signed integer buffer"); + + var colorbuffer = setupRenderbuffer(gl.COLOR_ATTACHMENT0, gl.RGBA8); + var colorbuffer1 = setupRenderbuffer(gl.COLOR_ATTACHMENT1, gl.RGBA32I); + gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + gl.clear(gl.COLOR_BUFFER_BIT); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clear and INT buffer"); + + gl.clearBufferfv(gl.COLOR, 1, new Float32Array(4)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferfv and INT buffer"); + + gl.clearBufferuiv(gl.COLOR, 1, new Uint32Array(4)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferuiv and INT buffer"); + + debug("Set up draw buffer so INT buffer is set to NONE"); + gl.drawBuffers([gl.COLOR_ATTACHMENT0]); + gl.clear(gl.COLOR_BUFFER_BIT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clear and INT buffer is NONE"); + + gl.clearBufferfv(gl.COLOR, 1, new Float32Array(4)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clearBufferfv and INT buffer is NONE"); + + gl.clearBufferuiv(gl.COLOR, 1, new Uint32Array(4)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferuiv and float buffer"); + + debug(""); + debug("Unsigned integer buffer"); + + colorbuffer = setupRenderbuffer(gl.COLOR_ATTACHMENT0, gl.RGBA32UI); + colorbuffer1 = setupRenderbuffer(gl.COLOR_ATTACHMENT1, gl.RGBA8); + gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + gl.clear(gl.COLOR_BUFFER_BIT); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clear and UINT buffer"); + + gl.clearBufferfv(gl.COLOR, 0, new Float32Array(4)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferfv and UINT buffer"); + + gl.clearBufferiv(gl.COLOR, 0, new Int32Array(4)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferiv and UINT buffer"); + + debug("Set up draw buffer so INT buffer is set to NONE"); + gl.drawBuffers([gl.NONE, gl.COLOR_ATTACHMENT1]); + gl.clear(gl.COLOR_BUFFER_BIT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clear and UINT buffer is NONE"); + + gl.clearBufferfv(gl.COLOR, 0, new Float32Array(4)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clearBufferfv and UINT buffer is NONE"); + + gl.clearBufferiv(gl.COLOR, 0, new Int32Array(4)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferiv and float buffer"); + + debug(""); + debug("Float buffer"); + + colorbuffer = setupRenderbuffer(gl.COLOR_ATTACHMENT0, gl.RGBA8); + var numAttachments = 1; + var ext = gl.getExtension("EXT_color_buffer_float"); + var bufferType = "float buffer"; + if (ext) { + debug("EXT_color_buffer_float is available: testing RGBA8 + RGBA32F"); + colorbuffer1 = setupRenderbuffer(gl.COLOR_ATTACHMENT1, gl.RGBA32F); + ++numAttachments; + gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]); + } else { + debug("EXT_color_buffer_float is unavailable: testing RGBA8"); + gl.drawBuffers([gl.COLOR_ATTACHMENT0]); + bufferType = "RGBA8 buffer"; + } + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + gl.clear(gl.COLOR_BUFFER_BIT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clear and " + bufferType); + + for (var ii = 0; ii < numAttachments; ++ii) { + gl.clearBufferfv(gl.COLOR, ii, new Float32Array(4)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clearBufferfv and " + bufferType); + + gl.clearBufferiv(gl.COLOR, ii, new Int32Array(4)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferiv and " + bufferType); + + gl.clearBufferuiv(gl.COLOR, ii, new Uint32Array(4)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferuiv and " + bufferType); + } + + gl.deleteFramebuffer(fb); + gl.deleteRenderbuffer(colorbuffer); + gl.deleteRenderbuffer(colorbuffer1); +} + +debug(""); +wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no error"); +var successfullyParsed = true; + +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-srgb-color-buffer.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-srgb-color-buffer.html new file mode 100644 index 000000000..b721a5d5f --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-srgb-color-buffer.html @@ -0,0 +1,109 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Clear sRGB Color Buffer</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/glsl-conformance-test.js"></script> +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies the functionality of clearing srgb color buffer."); + +var gl = wtu.create3DContext("example", undefined, 2); + +var tex = gl.createTexture(); +var fbo = gl.createFramebuffer(); +var size = 8; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + // Create a srgb color buffer + init(); + + clear_srgb_color_buffer(0); + clear_srgb_color_buffer(1); +} + +function init() { + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } else { + testPassed("framebuffer complete!"); + } +} + +function clear_srgb_color_buffer(iter) { + debug(""); + debug("Clear sRGB color buffer through glClear or glClearBufferfv"); + + var color = [0x33, 0x88, 0xbb, 0xff]; + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + if (iter == 0) { + gl.clearColor(color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255); + gl.clear(gl.COLOR_BUFFER_BIT); + } else { + var data = new Float32Array([color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255]); + gl.clearBufferfv(gl.COLOR, 0, data); + } + + var color_ref = wtu.linearToSRGB(color); + wtu.checkCanvasRect(gl, 0, 0, size, size, color_ref); +} + +gl.bindTexture(gl.TEXTURE_2D, null); +gl.bindFramebuffer(gl.FRAMEBUFFER, null); +gl.deleteTexture(tex); +gl.deleteFramebuffer(fbo); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clipping-wide-points.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clipping-wide-points.html new file mode 100644 index 000000000..8ca5305ec --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clipping-wide-points.html @@ -0,0 +1,47 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<title>Clipping wide points test</title> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas id="testbed" width="1" height="1"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +var contextVersion = 2; +</script> +<script src="../../js/tests/clipping-wide-points.js"></script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/draw-buffers.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/draw-buffers.html new file mode 100644 index 000000000..b09491b6b --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/draw-buffers.html @@ -0,0 +1,581 @@ +<!-- + +/* +** Copyright (c) 2013 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL Draw Buffers Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<canvas id="canvas" width="64" height="64"> </canvas> +<div id="console"></div> +<script id="vshaderESSL3" type="x-shader/x-vertex">#version 300 es +in vec4 a_position; +void main() { + gl_Position = a_position; +} +</script> +<script id="vshaderESSL1" type="x-shader/x-vertex"> +attribute vec4 a_position; +void main() { + gl_Position = a_position; +} +</script> +<script id="fshader" type="x-shader/x-fragment">#version 300 es +precision mediump float; +uniform vec4 u_colors[$(numDrawingBuffers)]; + +// Only one out variable - does not need explicit output layout (ESSL 3 section 4.3.8.2) +out vec4 my_FragData[$(numDrawingBuffers)]; +void main() { +$(assignUColorsToFragData) +} +</script> +<script id="fshaderRed" type="x-shader/x-fragment">#version 300 es +precision mediump float; + +out vec4 my_FragColor; +void main() { + my_FragColor = vec4(1, 0, 0, 1); +} +</script> +<script id="fshaderBlueESSL1" type="x-shader/x-fragment"> +precision mediump float; + +void main() { + gl_FragColor = vec4(0, 0, 1, 1); +} +</script> +<script id="fshaderBuiltInConstEnabled" type="x-shader/x-fragment">#version 300 es +precision mediump float; + +out vec4 my_FragColor; +void main() { + my_FragColor = (gl_MaxDrawBuffers == $(numDrawingBuffers)) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); +} +</script> +<script> +"use strict"; +description("This test verifies the functionality of Multiple Render Targets."); + +debug(""); + +var wtu = WebGLTestUtils; +var canvas = document.getElementById("canvas"); +var output = document.getElementById("console"); +var gl = wtu.create3DContext(canvas, null, 2); + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + if (testParameters()) { + runShadersTest(); + runAttachmentTest(); + runDrawTests(); + } + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); +} + +function createDrawBuffersProgram(scriptId, sub) { + var fsource = wtu.getScript(scriptId); + fsource = wtu.replaceParams(fsource, sub); + wtu.addShaderSource(output, "fragment shader", fsource); + return wtu.setupProgram(gl, ["vshaderESSL3", fsource], ["a_position"]); +} + +function runShadersTest() { + debug(""); + debug("test shaders"); + + var sub = {numDrawingBuffers: gl.getParameter(gl.MAX_DRAW_BUFFERS)}; + var program = createDrawBuffersProgram("fshaderBuiltInConstEnabled", sub); + wtu.setupUnitQuad(gl); + wtu.clearAndDrawUnitQuad(gl); + wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green"); + gl.deleteProgram(program); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); +} + +function makeArray(size, value) { + var array = [] + for (var ii = 0; ii < size; ++ii) { + array.push(value); + } + return array; +} + +function makeColorAttachmentArray(size) { + var array = [] + for (var ii = 0; ii < size; ++ii) { + array.push(gl.COLOR_ATTACHMENT0 + ii); + } + return array; +} + +function runAttachmentTest() { + debug(""); + debug("test attachment enabled"); + + var maxDrawingBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS); + var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS); + + var tex = gl.createTexture(); + var fb = gl.createFramebuffer(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments, gl.TEXTURE_2D, tex, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "should not be able to attach pass the max attachment point: gl.COLOR_ATTACHMENT0 + " + maxColorAttachments); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments - 1, gl.TEXTURE_2D, tex, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to attach to the max attachment point: gl.COLOR_ATTACHMENT0 + " + (maxColorAttachments - 1)); + gl.drawBuffers(makeArray(maxDrawingBuffers, gl.NONE)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with array NONE of size " + maxColorAttachments); + var bufs = makeColorAttachmentArray(maxDrawingBuffers); + gl.drawBuffers(bufs); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with array attachments of size " + maxColorAttachments); + bufs[0] = gl.NONE; + gl.drawBuffers(bufs); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with mixed array attachments of size " + maxColorAttachments); + if (maxDrawingBuffers > 1) { + bufs[0] = gl.COLOR_ATTACHMENT1; + bufs[1] = gl.COLOR_ATTACHMENT0; + gl.drawBuffers(bufs); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should not be able to call drawBuffers with out of order attachments of size " + maxColorAttachments); + var bufs = makeColorAttachmentArray(Math.floor(maxDrawingBuffers / 2)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with short array of attachments of size " + bufs.length); + } + + gl.deleteFramebuffer(fb); + gl.deleteTexture(tex); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); +} + +function makeColorByIndex(index) { + var low = (index - 1) % 15 + 1; + var high = (index - 1) / 15; + + var zeroOrOne = function(v) { + return v ? 1 : 0; + }; + + var oneOrTwo = function(v) { + return v ? 2 : 1; + } + + var makeComponent = function(b0, b1, b2) { + return Math.floor(255 * zeroOrOne(b0) / oneOrTwo(b1) / oneOrTwo(b2)); + }; + return [ + makeComponent(low & (1 << 0), high & (1 << 0), high & (1 << 4)), + makeComponent(low & (1 << 1), high & (1 << 1), high & (1 << 5)), + makeComponent(low & (1 << 2), high & (1 << 2), high & (1 << 6)), + makeComponent(low & (1 << 3), high & (1 << 3), high & (1 << 7)), + ]; +} + +function runDrawTests() { + debug(""); + debug("--------- draw tests -----------"); + var fb = gl.createFramebuffer(); + var fb2 = gl.createFramebuffer(); + var halfFB1 = gl.createFramebuffer(); + var halfFB2 = gl.createFramebuffer(); + var endsFB = gl.createFramebuffer(); + var middleFB = gl.createFramebuffer(); + + var maxDrawingBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS); + var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS); + var maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS); + var maxUsable = Math.min(maxDrawingBuffers, maxColorAttachments, maxUniformVectors); + var half = Math.floor(maxUsable / 2); + var bufs = makeColorAttachmentArray(maxUsable); + var nones = makeArray(maxUsable, gl.NONE); + + [fb, fb2, halfFB1, halfFB2, endsFB, middleFB].forEach(function(fbo) { + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.drawBuffers(bufs); + }); + + var checkProgram = wtu.setupTexturedQuad(gl); + var redProgram = wtu.setupProgram(gl, ["vshaderESSL3", "fshaderRed"], ["a_position"]); + var blueProgramESSL1 = wtu.setupProgram(gl, ["vshaderESSL1", "fshaderBlueESSL1"], ["a_position"]); + + var assignCode = []; + for (var i = 0; i < maxDrawingBuffers; ++i) { + assignCode.push(" my_FragData[" + i + "] = u_colors[" + i + "];"); + } + + var drawProgram = createDrawBuffersProgram("fshader", + {numDrawingBuffers: maxDrawingBuffers, assignUColorsToFragData: assignCode.join("\n")}); + var width = 64; + var height = 64; + var attachments = []; + // Makes 6 framebuffers. + // fb and fb2 have all the attachments. + // halfFB1 has the first half of the attachments + // halfFB2 has the second half of the attachments + // endsFB has the first and last attachments + // middleFB has all but the first and last attachments + for (var ii = 0; ii < maxUsable; ++ii) { + var tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0); + gl.bindFramebuffer(gl.FRAMEBUFFER, ii < half ? halfFB1 : halfFB2); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0); + gl.bindFramebuffer(gl.FRAMEBUFFER, (ii == 0 || ii == (maxUsable - 1)) ? endsFB : middleFB); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0); + var location = gl.getUniformLocation(drawProgram, "u_colors[" + ii + "]"); + var color = makeColorByIndex(ii + 1); + var floatColor = [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255]; + gl.uniform4fv(location, floatColor); + attachments.push({ + texture: tex, + location: location, + color: color + }); + } + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); + shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); + + var checkAttachmentsForColorFn = function(attachments, colorFn) { + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.useProgram(checkProgram); + attachments.forEach(function(attachment, index) { + gl.bindTexture(gl.TEXTURE_2D, attachment.texture); + wtu.clearAndDrawUnitQuad(gl); + var expectedColor = colorFn(attachment, index); + var tolerance = 0; + expectedColor.forEach(function(v) { + if (v != 0 && v != 255) { + tolerance = 8; + } + }); + wtu.checkCanvas(gl, expectedColor, "attachment " + index + " should be " + expectedColor.toString(), tolerance); + }); + debug(""); + }; + + var checkAttachmentsForColor = function(attachments, color) { + checkAttachmentsForColorFn(attachments, function(attachment, index) { + return color || attachment.color; + }); + }; + + var drawAndCheckAttachments = function(testFB, msg, testFn) { + debug("test clearing " + msg); + + gl.bindFramebuffer(gl.FRAMEBUFFER, testFB); + + attachments.forEach(function(attachment, index) { + debug("attachment: " + index + " = " + wtu.glEnumToString(gl, gl.getParameter(gl.DRAW_BUFFER0 + index)) + + ", " + wtu.glEnumToString(gl, gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + index, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE))); + }); + + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + debug("framebuffer not complete"); + debug(""); + return; + } + + // Clear all the attachments + gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); + gl.clearColor(0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + //checkAttachmentsForColorFn(attachments, function(attachment, index) { + // return [0, 0, 0, 0]; + //}); + //debug("--"); + + // Clear some attachments using testFB + gl.bindFramebuffer(gl.FRAMEBUFFER, testFB); + + gl.clearColor(0, 1, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + checkAttachmentsForColorFn(attachments, function(attachment, index) { + return testFn(attachment, index) ? [0, 255, 0, 255] : [0, 0, 0, 0]; + }); + + debug("test drawing to " + msg); + + // Draw to some attachments using testFB + gl.useProgram(drawProgram); + gl.bindFramebuffer(gl.FRAMEBUFFER, testFB); + wtu.drawUnitQuad(gl); + + checkAttachmentsForColorFn(attachments, function(attachment, index) { + return testFn(attachment, index) ? attachment.color : [0, 0, 0, 0]; + }); + }; + + gl.useProgram(drawProgram); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); + gl.drawBuffers(bufs); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.drawBuffers(bufs); + + wtu.drawUnitQuad(gl); + + debug("test that each texture got the correct color."); + + checkAttachmentsForColor(attachments); + + debug("test clearing clears all the textures"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.clearColor(0, 1, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + checkAttachmentsForColor(attachments, [0, 255, 0, 255]); + + debug("test that NONE draws nothing"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.drawBuffers(nones); + gl.useProgram(redProgram); + wtu.clearAndDrawUnitQuad(gl); + + checkAttachmentsForColor(attachments, [0, 255, 0, 255]); + + // GLES3 spec section 3.9.2 Shader Outputs + debug("test that gl_FragColor only writes to color number zero"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.drawBuffers(bufs); + gl.useProgram(blueProgramESSL1); + wtu.drawUnitQuad(gl); + + checkAttachmentsForColorFn(attachments, function(attachment, index) { + return (index == 0) ? [0, 0, 255, 255] : [0, 255, 0, 255]; + }); + + // If there is only a single output, the location defaults to zero if not specified. + // See GLSL ES Spec 3.00.4, Section 4.3.8.2, Output Layout Qualifiers. + debug("test that an OpenGL ES Shading Language 3.00 shader with a single output color defaults to color number zero"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.drawBuffers(bufs); + gl.useProgram(redProgram); + wtu.drawUnitQuad(gl); + + checkAttachmentsForColorFn(attachments, function(attachment, index) { + return (index == 0) ? [255, 0, 0, 255] : [0, 255, 0, 255]; + }); + + if (maxUsable > 1) { + // Prepare for following tests by clearing all attachments to red. + debug("prepare by clearing all attachments to red"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.drawBuffers(bufs); + gl.clearColor(1, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + checkAttachmentsForColor(attachments, [255, 0, 0, 255]); + + var bufs1 = makeColorAttachmentArray(maxUsable); + var bufs2 = makeColorAttachmentArray(maxUsable); + for (var ii = 0; ii < maxUsable; ++ii) { + if (ii < half) { + bufs1[ii] = gl.NONE; + } else { + bufs2[ii] = gl.NONE; + } + } + + debug("test setting first half to NONE and clearing"); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.drawBuffers(bufs1); + gl.clearColor(0, 1, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + checkAttachmentsForColorFn(attachments, function(attachment, index) { + return index < half ? [255, 0, 0, 255] : [0, 255, 0, 255]; + }); + + debug("test setting first half to NONE and drawing"); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.useProgram(drawProgram); + wtu.drawUnitQuad(gl); + + checkAttachmentsForColorFn(attachments, function(attachment, index) { + return index < half ? [255, 0, 0, 255] : attachment.color; + }); + + debug("test setting second half to NONE and clearing"); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.drawBuffers(bufs); + gl.clearColor(1, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawBuffers(bufs2); + gl.clearColor(0, 0, 1, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + checkAttachmentsForColorFn(attachments, function(attachment, index) { + return index < half ? [0, 0, 255, 255] : [255, 0, 0, 255]; + }); + + debug("test setting second half to NONE and drawing"); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.useProgram(drawProgram); + wtu.drawUnitQuad(gl); + + checkAttachmentsForColorFn(attachments, function(attachment, index) { + return index < half ? attachment.color : [255, 0, 0, 255]; + }); + + gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB1); + gl.drawBuffers(bufs); + drawAndCheckAttachments( + halfFB1, "framebuffer that only has first half of attachments", + function(attachment, index) { + return index < half; + }); + + gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB2); + gl.drawBuffers(bufs); + drawAndCheckAttachments( + halfFB2, "framebuffer that only has second half of attachments", + function(attachment, index) { + return index >= half; + }); + + if (maxUsable > 2) { + gl.bindFramebuffer(gl.FRAMEBUFFER, endsFB); + gl.drawBuffers(bufs); + drawAndCheckAttachments( + endsFB, "framebuffer that only has first and last attachments", + function(attachment, index) { + return index == 0 || index == (maxUsable - 1); + }); + + gl.bindFramebuffer(gl.FRAMEBUFFER, middleFB); + gl.drawBuffers(bufs); + drawAndCheckAttachments( + middleFB, + "framebuffer that has all but the first and last attachments", + function(attachment, index) { + return index != 0 && index != (maxUsable - 1); + }); + } + } + + debug("test switching between fbos keeps drawbuffer state"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); + gl.drawBuffers(nones); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.drawBuffers(bufs); + gl.clearColor(1, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + checkAttachmentsForColor(attachments, [255, 0, 0, 255]); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); + gl.useProgram(drawProgram); + wtu.drawUnitQuad(gl); + checkAttachmentsForColor(attachments, [255, 0, 0, 255]); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.useProgram(drawProgram); + wtu.drawUnitQuad(gl); + checkAttachmentsForColor(attachments); + + debug("test queries"); + debug("check framebuffer with all attachments on"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + for (var ii = 0; ii < maxUsable; ++ii) { + shouldBe("gl.getParameter(gl.DRAW_BUFFER0 + " + ii + ")", "gl.COLOR_ATTACHMENT0 + " + ii); + } + + debug("check framebuffer with all attachments off"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); + for (var ii = 0; ii < maxUsable; ++ii) { + shouldBe("gl.getParameter(gl.DRAW_BUFFER0 + " + ii + ")", "gl.NONE"); + } + + // WebGL generates FRAMEBUFFER_INCOMPLETE_DIMENSIONS when attached images have different sizes. + // This behavior differs from GLES 3. + debug("test attachment size mis-match"); + gl.bindTexture(gl.TEXTURE_2D, attachments[0].texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width * 2, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb2); + shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + + // TODO: Rendering when framebuffer attachments have mismatched size should be tested, maybe in a separate test. + + gl.deleteFramebuffer(fb); + gl.deleteFramebuffer(fb2); + gl.deleteFramebuffer(halfFB1); + gl.deleteFramebuffer(halfFB2); + attachments.forEach(function(attachment) { + gl.deleteTexture(attachment.texture); + }); + gl.deleteProgram(checkProgram); + gl.deleteProgram(redProgram); + gl.deleteProgram(drawProgram); +} + +function testParameters() { + debug(""); + debug("check that MAX_DRAW_BUFFERS and MAX_COLOR_ATTACHMENTS are valid"); + var maxDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS); + var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS); + debug("MAX_DRAW_BUFFERS = " + maxDrawBuffers); + debug("MAX_COLOR_ATTACHMENTS = " + maxColorAttachments); + if (maxDrawBuffers != maxColorAttachments) { + testFailed("MAX_DRAW_BUFFERS and MAX_COLOR_ATTACHMENTS should be the same"); + return false; + } + if (maxDrawBuffers < 4) { + testFailed("MAX_DRAW_BUFFERS should be at least 4"); + return false; + } + return true; +} + +debug(""); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/element-index-uint.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/element-index-uint.html new file mode 100644 index 000000000..f19529022 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/element-index-uint.html @@ -0,0 +1,426 @@ +<!-- + +/* +** Copyright (c) 2013 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL Uint element indices Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> + +<script id="vs" type="x-shader/x-vertex"> +attribute vec4 vPosition; +attribute vec4 vColor; +varying vec4 color; +void main() { + gl_Position = vPosition; + color = vColor; +} +</script> +<script id="fs" type="x-shader/x-fragment"> +precision mediump float; +varying vec4 color; +void main() { + gl_FragColor = color; +} +</script> + +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the Uint element indices."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = null; +var canvas = null; + +// Test both STATIC_DRAW and DYNAMIC_DRAW as a regression test +// for a bug in ANGLE which has since been fixed. +for (var ii = 0; ii < 2; ++ii) { + canvas = document.createElement("canvas"); + canvas.width = 50; + canvas.height = 50; + + gl = wtu.create3DContext(canvas, null, 2); + + if (!gl) { + testFailed("WebGL context does not exist"); + } else { + testPassed("WebGL context exists"); + + var drawType = (ii == 0) ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW; + debug("Testing " + ((ii == 0) ? "STATIC_DRAW" : "DYNAMIC_DRAW")); + + runDrawTests(drawType); + + // These tests are tweaked duplicates of the buffers/index-validation* tests + // using unsigned int indices to ensure that behavior remains consistent + runIndexValidationTests(drawType); + runCopiesIndicesTests(drawType); + runResizedBufferTests(drawType); + runVerifiesTooManyIndicesTests(drawType); + runCrashWithBufferSubDataTests(drawType); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); + } +} + +function runDrawTests(drawType) { + debug("Test that draws with unsigned integer indices produce the expected results"); + + canvas.width = 50; canvas.height = 50; + gl.viewport(0, 0, canvas.width, canvas.height); + + var program = wtu.setupNoTexCoordTextureProgram(gl); + + function setupDraw(s) { + // Create a vertex buffer that cannot be fully indexed via shorts + var quadArrayLen = 65537 * 3; + var quadArray = new Float32Array(quadArrayLen); + + // Leave all but the last 4 values zero-ed out + var idx = quadArrayLen - 12; + + // Initialized the last 4 values to a quad + quadArray[idx++] = 1.0 * s; + quadArray[idx++] = 1.0 * s; + quadArray[idx++] = 0.0; + + quadArray[idx++] = -1.0 * s; + quadArray[idx++] = 1.0 * s; + quadArray[idx++] = 0.0; + + quadArray[idx++] = -1.0 * s; + quadArray[idx++] = -1.0 * s; + quadArray[idx++] = 0.0; + + quadArray[idx++] = 1.0 * s; + quadArray[idx++] = -1.0 * s; + quadArray[idx++] = 0.0; + + var vertexObject = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject); + gl.bufferData(gl.ARRAY_BUFFER, quadArray, drawType); + + // Create an unsigned int index buffer that indexes the last 4 vertices + var baseIndex = (quadArrayLen / 3) - 4; + + var indexObject = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array([ + baseIndex + 0, + baseIndex + 1, + baseIndex + 2, + baseIndex + 2, + baseIndex + 3, + baseIndex + 0]), drawType); + + var opt_positionLocation = 0; + gl.enableVertexAttribArray(opt_positionLocation); + gl.vertexAttribPointer(opt_positionLocation, 3, gl.FLOAT, false, 0, 0); + }; + function readLocation(x, y) { + var pixels = new Uint8Array(1 * 1 * 4); + gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + return pixels; + }; + function testPixel(blackList, whiteList) { + function testList(list, expected) { + for (var n = 0; n < list.length; n++) { + var l = list[n]; + var x = -Math.floor(l * canvas.width / 2) + canvas.width / 2; + var y = -Math.floor(l * canvas.height / 2) + canvas.height / 2; + var source = readLocation(x, y); + if (Math.abs(source[0] - expected) > 2) { + return false; + } + } + return true; + } + return testList(blackList, 0) && testList(whiteList, 255); + }; + function verifyDraw(drawNumber, s) { + gl.clearColor(1.0, 1.0, 1.0, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0); + + var blackList = []; + var whiteList = []; + var points = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]; + for (var n = 0; n < points.length; n++) { + if (points[n] <= s) { + blackList.push(points[n]); + } else { + whiteList.push(points[n]); + } + } + if (testPixel(blackList, whiteList)) { + testPassed("Draw " + drawNumber + " passed pixel test"); + } else { + testFailed("Draw " + drawNumber + " failed pixel test"); + } + }; + + setupDraw(0.5); + verifyDraw(0, 0.5); +} + +function runIndexValidationTests(drawType) { + description("Tests that index validation verifies the correct number of indices"); + + function sizeInBytes(type) { + switch (type) { + case gl.BYTE: + case gl.UNSIGNED_BYTE: + return 1; + case gl.SHORT: + case gl.UNSIGNED_SHORT: + return 2; + case gl.INT: + case gl.UNSIGNED_INT: + case gl.FLOAT: + return 4; + default: + throw "unknown type"; + } + } + + var program = wtu.loadStandardProgram(gl); + + // 3 vertices => 1 triangle, interleaved data + var dataComplete = new Float32Array([0, 0, 0, 1, + 0, 0, 1, + 1, 0, 0, 1, + 0, 0, 1, + 1, 1, 1, 1, + 0, 0, 1]); + var dataIncomplete = new Float32Array([0, 0, 0, 1, + 0, 0, 1, + 1, 0, 0, 1, + 0, 0, 1, + 1, 1, 1, 1]); + var indices = new Uint32Array([0, 1, 2]); + + debug("Testing with valid indices"); + + var bufferComplete = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, bufferComplete); + gl.bufferData(gl.ARRAY_BUFFER, dataComplete, drawType); + var elements = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elements); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType); + gl.useProgram(program); + var vertexLoc = gl.getAttribLocation(program, "a_vertex"); + var normalLoc = gl.getAttribLocation(program, "a_normal"); + gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0); + gl.enableVertexAttribArray(vertexLoc); + gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT)); + gl.enableVertexAttribArray(normalLoc); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + + debug("Testing with out-of-range indices"); + + var bufferIncomplete = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, bufferIncomplete); + gl.bufferData(gl.ARRAY_BUFFER, dataIncomplete, drawType); + gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0); + gl.enableVertexAttribArray(vertexLoc); + gl.disableVertexAttribArray(normalLoc); + debug("Enable vertices, valid"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + debug("Enable normals, out-of-range"); + gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT)); + gl.enableVertexAttribArray(normalLoc); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); + + debug("Test with enabled attribute that does not belong to current program"); + + gl.disableVertexAttribArray(normalLoc); + var extraLoc = Math.max(vertexLoc, normalLoc) + 1; + gl.enableVertexAttribArray(extraLoc); + debug("Enable an extra attribute with null"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); + debug("Enable an extra attribute with insufficient data buffer"); + gl.vertexAttribPointer(extraLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); + debug("Pass large negative index to vertexAttribPointer"); + gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), -2000000000 * sizeInBytes(gl.FLOAT)); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)'); +} + +function runCopiesIndicesTests(drawType) { + debug("Test that client data is always copied during bufferData and bufferSubData calls"); + + var program = wtu.loadStandardProgram(gl); + + gl.useProgram(program); + var vertexObject = gl.createBuffer(); + gl.enableVertexAttribArray(0); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject); + // 4 vertices -> 2 triangles + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), drawType); + gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); + + var indexObject = gl.createBuffer(); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject); + var indices = new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType); + wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)"); + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)"); + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)"); + indices[0] = 2; + indices[5] = 1; + wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)"); + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)"); + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)"); +} + +function runResizedBufferTests(drawType) { + debug("Test that updating the size of a vertex buffer is properly noticed by the WebGL implementation."); + + var program = wtu.setupProgram(gl, ["vs", "fs"], ["vPosition", "vColor"]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after initialization"); + + var vertexObject = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array( + [-1,1,0, 1,1,0, -1,-1,0, + -1,-1,0, 1,1,0, 1,-1,0]), drawType); + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after vertex setup"); + + var texCoordObject = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, texCoordObject); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array( + [0,0, 1,0, 0,1, + 0,1, 1,0, 1,1]), drawType); + gl.enableVertexAttribArray(1); + gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after texture coord setup"); + + // Now resize these buffers because we want to change what we're drawing. + gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + -1,1,0, 1,1,0, -1,-1,0, 1,-1,0, + -1,1,0, 1,1,0, -1,-1,0, 1,-1,0]), drawType); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after vertex redefinition"); + gl.bindBuffer(gl.ARRAY_BUFFER, texCoordObject); + gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array([ + 255, 0, 0, 255, + 255, 0, 0, 255, + 255, 0, 0, 255, + 255, 0, 0, 255, + 0, 255, 0, 255, + 0, 255, 0, 255, + 0, 255, 0, 255, + 0, 255, 0, 255]), drawType); + gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, false, 0, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after texture coordinate / color redefinition"); + + var numQuads = 2; + var indices = new Uint32Array(numQuads * 6); + for (var ii = 0; ii < numQuads; ++ii) { + var offset = ii * 6; + var quad = (ii == (numQuads - 1)) ? 4 : 0; + indices[offset + 0] = quad + 0; + indices[offset + 1] = quad + 1; + indices[offset + 2] = quad + 2; + indices[offset + 3] = quad + 2; + indices[offset + 4] = quad + 1; + indices[offset + 5] = quad + 3; + } + var indexObject = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setting up indices"); + gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_INT, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawing"); +} + +function runVerifiesTooManyIndicesTests(drawType) { + description("Tests that index validation for drawElements does not examine too many indices"); + + var program = wtu.loadStandardProgram(gl); + + gl.useProgram(program); + var vertexObject = gl.createBuffer(); + gl.enableVertexAttribArray(0); + gl.disableVertexAttribArray(1); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject); + // 4 vertices -> 2 triangles + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), drawType); + gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); + + var indexObject = gl.createBuffer(); + + debug("Test out of range indices") + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]), drawType); + wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)"); + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)"); + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)"); +} + +function runCrashWithBufferSubDataTests(drawType) { + debug('Verifies that the index validation code which is within bufferSubData does not crash.') + + var elementBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 256, drawType); + var data = new Uint32Array(127); + gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 64, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "after attempting to update a buffer outside of the allocated bounds"); + testPassed("bufferSubData, when buffer object was initialized with null, did not crash"); +} + +debug(""); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-completeness-unaffected.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-completeness-unaffected.html new file mode 100644 index 000000000..f614607f8 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-completeness-unaffected.html @@ -0,0 +1,113 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Test drawBuffers, readBuffer, and fbo completeness</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<canvas id="canvas" width="20" height="20"> </canvas> +<script> +// In MacOSX, if drawBuffers() and readBuffer() both select an attachment with no image attached, +// fbo becomes incomplete. However, drawBuffers() and readBuffer() should not affect fbo completeness. + +"use strict"; +description("This tests drawBuffers, readBuffer, and fbo completeness"); + +var setupRenderbuffer = function(attachment) { + var renderbuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderbuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, canvas.width, canvas.height); + return renderbuffer; +} + +var wtu = WebGLTestUtils; +var canvas = document.getElementById("canvas"); +var gl = wtu.create3DContext(canvas, undefined, 2); +if (!gl) { + testFailed("context does not exist"); +} else { + testPassed("context exists"); + + var fb = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + + debug("fbo with two color images attached should be complete"); + var colorbuffer = setupRenderbuffer(gl.COLOR_ATTACHMENT0); + var colorbuffer1 = setupRenderbuffer(gl.COLOR_ATTACHMENT1); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + debug("drawBuffers selects ATTACHMENT1, fbo should be complete"); + gl.drawBuffers([gl.NONE, gl.COLOR_ATTACHMENT1]); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + debug("remove image attached to ATTACHMENT1, fbo should be complete"); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, null); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + // Setting of GL_READ_BUFFER and GL_DRAW_BUFFERs affects framebuffer completeness on Mac Intel. + // Chromium bug: crbug.com/630800 + // Apple Radar: 28236629 + //debug("set read buffer to ATTACHMENT1, fbo should be complete"); + //gl.readBuffer(gl.COLOR_ATTACHMENT1); + //shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + debug("drawBuffers selects ATTACHMENT0, fbo should be complete"); + gl.drawBuffers([gl.COLOR_ATTACHMENT0]); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + debug("drawBuffers selects ATTACHMENT1, fbo should be complete"); + gl.drawBuffers([gl.NONE, gl.COLOR_ATTACHMENT1]); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + debug("set read buffer to ATTACHMENT0, fbo should be complete"); + gl.readBuffer(gl.COLOR_ATTACHMENT0); + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + gl.deleteFramebuffer(fb); + gl.deleteRenderbuffer(colorbuffer); + gl.deleteRenderbuffer(colorbuffer1); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no error after setup and clear render buffer"); +} + +debug(""); +var successfullyParsed = true; + +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-unsupported.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-unsupported.html new file mode 100644 index 000000000..2188ab0fc --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-unsupported.html @@ -0,0 +1,155 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL FRAMEBUFFER_UNSUPPORTED Test</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<canvas id="canvas" width="2" height="2"> </canvas> + +<script> +"use strict"; +var wtu = WebGLTestUtils; +var gl; +var canvas = document.getElementById("canvas"); + +function checkFramebuffer(expected) { + var actual = gl.checkFramebufferStatus(gl.FRAMEBUFFER); + if (expected.indexOf(actual) < 0) { + var msg = "checkFramebufferStatus expects ["; + for (var index = 0; index < expected.length; ++index) { + msg += wtu.glEnumToString(gl, expected[index]); + if (index + 1 < expected.length) + msg += ", "; + } + msg += "], was " + wtu.glEnumToString(gl, actual); + testFailed(msg); + } else { + var msg = "checkFramebufferStatus got " + wtu.glEnumToString(gl, actual) + + " as expected"; + testPassed(msg); + } +} + +function testImageAttachedTwoPoints() { + debug(""); + debug("Checking an image is attached to more than one color attachment in a framebuffer."); + + var tex1 = gl.createTexture(); + var tex2 = gl.createTexture(); + var fb = gl.createFramebuffer(); + gl.bindTexture(gl.TEXTURE_2D, tex1); + gl.texImage2D(gl.TEXTURE_2D, + 0, // level + gl.RGBA, // internalFormat + 1, // width + 1, // height + 0, // border + gl.RGBA, // format + gl.UNSIGNED_BYTE, // type + new Uint8Array(4)); // data + gl.bindTexture(gl.TEXTURE_2D, tex2); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Texture creation should succeed."); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex1, 0); + checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex2, 0); + checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_2D, tex1, 0); + checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.deleteFramebuffer(fb); + fb = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + var texCube = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_CUBE_MAP, texCube); + for (var target = gl.TEXTURE_CUBE_MAP_POSITIVE_X; target < gl.TEXTURE_CUBE_MAP_POSITIVE_X + 6; target++) { + gl.texImage2D(target, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4)); + } + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, texCube, 0); + checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, texCube, 0); + checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_CUBE_MAP_POSITIVE_X, texCube, 0); + checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]); + + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.deleteFramebuffer(fb); + fb = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + var tex3d = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_3D, tex3d); + gl.texImage3D(gl.TEXTURE_3D, + 0, // level + gl.RGBA, // internalFormat + 2, // width + 2, // height + 2, // depth + 0, // border + gl.RGBA, // format + gl.UNSIGNED_BYTE, // type + new Uint8Array(4 * 2 * 2 * 2)); // data + gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex3d, 0, 0); + checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); + gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, tex3d, 0, 1); + checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); + gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, tex3d, 0, 0); + checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]); + + // Clean up + gl.deleteTexture(tex1); + gl.deleteTexture(tex2); + gl.deleteTexture(texCube); + gl.deleteTexture(tex3d); + gl.deleteFramebuffer(fb); +} + +description("This tests FRAMEBUFFER_UNSUPPORTED."); + +shouldBeNonNull("gl = wtu.create3DContext(undefined, undefined, 2)"); + +testImageAttachedTwoPoints(); + +debug(""); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/fs-color-type-mismatch-color-buffer-type.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/fs-color-type-mismatch-color-buffer-type.html new file mode 100644 index 000000000..19eb6ff82 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/fs-color-type-mismatch-color-buffer-type.html @@ -0,0 +1,190 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>The Color Types of Fragment Shader's Outputs Should Match The Data Types of Color Buffers</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script id="vshader" type="x-shader/x-vertex">#version 300 es +in highp vec4 aPosition; +void main() { + gl_Position = aPosition; +} +</script> + +<script id="fshader" type="x-shader/x-fragment">#version 300 es +precision mediump float; +out vec4 oColor; +void main() { + oColor = vec4(1.0, 0.0, 0.0, 0.0); +} +</script> + +<script id="fshaderMRT" type="x-shader/x-fragment">#version 300 es +precision mediump float; +out vec4 oColor[2]; +void main() { + oColor[0] = vec4(1.0, 0.0, 0.0, 0.0); +} +</script> + +<script id="fshaderRealMRT" type="x-shader/x-fragment">#version 300 es +precision mediump float; +out vec4 oColor[2]; +void main() { + oColor[0] = vec4(1.0, 0.0, 0.0, 0.0); + oColor[1] = vec4(0.0, 1.0, 0.0, 0.0); +} +</script> + +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies that the color types of fragment shader's outputs should match color buffers' types."); + +var gl = wtu.create3DContext("example", undefined, 2); + +var width = 8; +var height = 8; +var tex0; +var tex1; +var rb0; +var rb1; +var fbo = gl.createFramebuffer(); +var program0; +var program1; +var program2; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + init(); + + // COLOR_ATTACHMENT0 is fixed-point data, which can be converted to float. + // COLOR_ATTACHMENT1 is integer data. The fragment outputs are all float. + allocate_textures(); + check_type_match(); + allocate_renderbuffers(); + check_type_match(); +} + +function check_type_match() { + gl.useProgram(program0); + rendering([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR); + rendering([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.NO_ERROR); + + gl.useProgram(program1); + rendering([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR); + rendering([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION); + + gl.useProgram(program2); + rendering([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR); + rendering([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION); +} + +function init() { + program0 = wtu.setupProgram(gl, ['vshader', 'fshader'], ['aPosition'], [0]); + program1 = wtu.setupProgram(gl, ['vshader', 'fshaderMRT'], ['aPosition'], [0]); + program2 = wtu.setupProgram(gl, ['vshader', 'fshaderRealMRT'], ['aPosition'], [0]); + if (!program0 || !program1 || !program2) { + testFailed("Failed to set up program"); + return; + } + testPassed("Succeed to set up program"); + + wtu.setupUnitQuad(gl, 0, 1); + gl.viewport(0, 0, width, height); +} + +function allocate_textures() { + tex0 = gl.createTexture(); + tex1 = gl.createTexture(); + wtu.fillTexture(gl, tex0, width, height, [0xff, 0x0, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA); + wtu.fillTexture(gl, tex1, width, height, [0x0, 0xff, 0x0, 0xff], 0, gl.RGBA_INTEGER, gl.UNSIGNED_BYTE, gl.RGBA8UI); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex0, 0); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex1, 0); +} + +function allocate_renderbuffers() { + rb0 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb0); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, width, height); + rb1 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8UI, width, height); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1); +} + +function rendering(draw_buffers, error) { + gl.drawBuffers(draw_buffers); + + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, error, "If color buffers' type mismatch the type of fragment shader's outputs, geneate INVALID_OPERATION. Otherwise, it should be NO_ERROR"); +} + +gl.bindTexture(gl.TEXTURE_2D, null); +gl.bindRenderbuffer(gl.RENDERBUFFER, null); +gl.bindFramebuffer(gl.FRAMEBUFFER, null); +gl.useProgram(null); +gl.deleteTexture(tex0); +gl.deleteTexture(tex1); +gl.deleteRenderbuffer(rb0); +gl.deleteRenderbuffer(rb1); +gl.deleteFramebuffer(fbo); +gl.deleteProgram(program0); +gl.deleteProgram(program1); +gl.deleteProgram(program2); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-arrays.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-arrays.html new file mode 100644 index 000000000..dee7b387f --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-arrays.html @@ -0,0 +1,242 @@ +<!-- + +/* +** Copyright (c) 2013 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL Instanced Arrays 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> +</head> +<body> +<div id="description"></div> +<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas> +<div id="console"></div> +<!-- Shaders for testing instanced draws --> +<script id="outputVertexShader" type="x-shader/x-vertex"> +attribute vec4 aPosition; +attribute vec2 aOffset; +attribute vec4 aColor; +varying vec4 vColor; +void main() { + vColor = aColor; + gl_Position = aPosition + vec4(aOffset, 0.0, 0.0); +} +</script> + +<script id="outputFragmentShader" type="x-shader/x-fragment"> +precision mediump float; +varying vec4 vColor; +void main() { + gl_FragColor = vColor; +} +</script> + +<script> +"use strict"; +description("This test verifies the functionality of Instanced Arrays."); + +debug(""); + +var wtu = WebGLTestUtils; +var canvas = document.getElementById("canvas"); +var gl = wtu.create3DContext(canvas, null, 2); + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + runDivisorTest(); + runOutputTests(); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); +} + +function runDivisorTest() { + debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR"); + + shouldBe("gl.VERTEX_ATTRIB_ARRAY_DIVISOR", "0x88FE"); + + var max_vertex_attribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); + + for (var i = 0; i < max_vertex_attribs; ++i) { + var queried_value = gl.getVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_DIVISOR); + if(queried_value == 0){ + testPassed("Vertex attribute " + i + " must has a default divisor of 0"); + } + else{ + testFailed("Default divisor of vertex attribute " + i + " should be: 0, returned value was: " + queried_value); + } + } + + gl.vertexAttribDivisor(max_vertex_attribs, 2); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "vertexAttribDivisor index set greater than or equal to MAX_VERTEX_ATTRIBS should be an invalid value"); + + gl.vertexAttribDivisor(max_vertex_attribs-1, 2); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertexAttribDivisor index set less than MAX_VERTEX_ATTRIBS should succeed"); + + var queried_value = gl.getVertexAttrib(max_vertex_attribs-1, gl.VERTEX_ATTRIB_ARRAY_DIVISOR); + if(queried_value == 2){ + testPassed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR matches expecation"); + } + else{ + testFailed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR should be: 2, returned value was: " + queried_value); + } +} + +function runOutputTests() { + var e = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher + var instanceCount = 4; + + debug("Testing various draws for valid built-in function behavior"); + + canvas.width = 50; canvas.height = 50; + gl.viewport(0, 0, canvas.width, canvas.height); + gl.clearColor(0, 0, 0, 0); + + var positionLoc = 0; + var offsetLoc = 2; + var colorLoc = 3; + var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['aPosition', 'aOffset', 'aColor'], [positionLoc, offsetLoc, colorLoc]); + + var offsets = new Float32Array([ + -1.0, 1.0, + 1.0, 1.0, + -1.0, -1.0, + 1.0, -1.0, + ]); + var offsetBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); + gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW); + gl.enableVertexAttribArray(offsetLoc); + gl.vertexAttribPointer(offsetLoc, 2, gl.FLOAT, false, 0, 0); + gl.vertexAttribDivisor(offsetLoc, 1); + + var colors = new Float32Array([ + 1.0, 0.0, 0.0, 1.0, // Red + 0.0, 1.0, 0.0, 1.0, // Green + 0.0, 0.0, 1.0, 1.0, // Blue + 1.0, 1.0, 0.0, 1.0, // Yellow + ]); + var colorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); + gl.enableVertexAttribArray(colorLoc); + gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0); + gl.vertexAttribDivisor(colorLoc, 1); + + // Draw 1: Draw Non-indexed instances + debug("Testing drawArraysInstanced"); + gl.clear(gl.COLOR_BUFFER_BIT); + wtu.setupUnitQuad(gl, 0); + + // Test drawArraysInstanced error conditions + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]); + wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]); + wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]); + wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]); + + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, -1); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstanced cannot have a primcount less than 0"); + + gl.drawArraysInstanced(gl.TRIANGLES, 0, -1, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstanced cannot have a count less than 0"); + + gl.vertexAttribDivisor(positionLoc, 1); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawArraysInstanced"); + gl.vertexAttribDivisor(positionLoc, 0); + + gl.drawArraysInstanced(gl.POINTS, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced with POINTS should succeed"); + gl.drawArraysInstanced(gl.LINES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced with LINES should succeed"); + gl.drawArraysInstanced(gl.LINE_LIST, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced with LINE_LIST should return succeed"); + gl.drawArraysInstanced(gl.TRI_LIST, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced with TRI_LIST should succeed"); + + gl.drawArraysInstanced(desktopGL['QUAD_STRIP'], 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstanced with QUAD_STRIP should return INVALID_ENUM"); + gl.drawArraysInstanced(desktopGL['QUADS'], 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstanced with QUADS should return INVALID_ENUM"); + gl.drawArraysInstanced(desktopGL['POLYGON'], 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstanced with POLYGON should return INVALID_ENUM"); + + // Draw 2: Draw indexed instances + debug("Testing drawElementsInstanced"); + gl.clear(gl.COLOR_BUFFER_BIT); + wtu.setupIndexedQuad(gl, 1, 0); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]); + wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]); + wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]); + wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]); + + // Test drawElementsInstanced error conditions + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, -1); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstanced cannot have a primcount less than 0"); + + gl.drawElementsInstanced(gl.TRIANGLES, -1, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstanced cannot have a count less than 0"); + + gl.vertexAttribDivisor(positionLoc, 1); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawElementsInstanced"); + gl.vertexAttribDivisor(positionLoc, 0); + + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with UNSIGNED_BYTE should succeed"); + + gl.drawElementsInstanced(gl.POINTS, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with POINTS should succeed"); + gl.drawElementsInstanced(gl.LINES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with LINES should succeed"); + gl.drawElementsInstanced(gl.LINE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with LINE_LIST should return succeed"); + gl.drawElementsInstanced(gl.TRI_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with TRI_LIST should succeed"); + + gl.drawElementsInstanced(desktopGL['QUAD_STRIP'], 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstanced with QUAD_STRIP should return INVALID_ENUM"); + gl.drawElementsInstanced(desktopGL['QUADS'], 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstanced with QUADS should return INVALID_ENUM"); + gl.drawElementsInstanced(desktopGL['POLYGON'], 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstanced with POLYGON should return INVALID_ENUM"); +} + +debug(""); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-rendering-bug.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-rendering-bug.html new file mode 100644 index 000000000..14d576f8d --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-rendering-bug.html @@ -0,0 +1,275 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL Instanced Arrays 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> +</head> +<body> +<div id="description"></div> +<canvas id="canvas" style="width: 128px; height: 128px;"> </canvas> +<div id="console"></div> +<script id="outputVertexShader" type="x-shader/x-vertex">#version 300 es +in highp vec2 aPosition; +in highp float aOffset; +in highp float aColor; +out mediump float vColor; +void main() { + gl_Position = vec4(aPosition, 0.0, 1.0) + vec4(aOffset, 0.0, 0.0, 0.0); + vColor = aColor; +} +</script> + +<script id="outputFragmentShader" type="x-shader/x-fragment">#version 300 es +layout(location = 0) out mediump vec4 oColor; +in mediump float vColor; +void main() { + oColor = vec4(vColor, 0.0, 0.0, 1.0); +} +</script> + +<script> +"use strict"; +description("This test verifies a bug related with instanced rendering on Mac AMD."); +debug("http://crbug.com/645298"); + +debug(""); + +var wtu = WebGLTestUtils; +var canvas = document.getElementById("canvas"); +var gl = wtu.create3DContext(canvas, null, 2); + +// The second and fourth test cases fail - it seems if the divisor doesn't change, +// the next instanced draw call behaves incorrectly. +// Also note that if we don't perform a readPixels (in wtu.checkCanvasRect), the bug +// isn't triggered. +var testCases = [ + { instanceCount: 8, divisor: 4 }, + { instanceCount: 6, divisor: 4 }, + { instanceCount: 6, divisor: 3 }, + { instanceCount: 8, divisor: 3 }, +]; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + for (var ii = 0; ii < testCases.length; ++ii) { + runDrawArraysTest(testCases[ii].instanceCount, testCases[ii].divisor); + } + + for (var ii = 0; ii < testCases.length; ++ii) { + runDrawElementsTest(testCases[ii].instanceCount, testCases[ii].divisor); + } +} + +function runDrawArraysTest(instanceCount, divisor) { + debug(""); + debug("Testing drawArraysInstanced: instanceCount = " + instanceCount + ", divisor = " + divisor); + + gl.viewport(0, 0, canvas.width, canvas.height); + + var vao = gl.createVertexArray(); + gl.bindVertexArray(vao); + + var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"]); + var positionLoc = gl.getAttribLocation(program, "aPosition"); + var offsetLoc = gl.getAttribLocation(program, "aOffset"); + var colorLoc = gl.getAttribLocation(program, "aColor"); + if (!program || positionLoc < 0 || offsetLoc < 0 || colorLoc < 0) { + testFailed("Set up program failed"); + return; + } + testPassed("Set up program succeeded"); + + var scale = 1.0 / instanceCount; + + gl.enableVertexAttribArray(positionLoc); + gl.vertexAttribDivisor(positionLoc, 0); + var positions = new Float32Array([ + 1.0 * scale, 1.0, + -1.0 * scale, 1.0, + -1.0 * scale, -1.0, + 1.0 * scale, 1.0, + -1.0 * scale, -1.0, + 1.0 * scale, -1.0, + ]); + var positionBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); + gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); + + gl.enableVertexAttribArray(offsetLoc); + gl.vertexAttribDivisor(offsetLoc, 1); + var offsets = new Float32Array(instanceCount); + for (var ii = 0; ii < instanceCount; ++ii) { + offsets[ii] = scale * (1 - instanceCount + ii * 2); + } + var offsetBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); + gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW); + gl.vertexAttribPointer(offsetLoc, 1, gl.FLOAT, false, 0, 0); + + gl.enableVertexAttribArray(colorLoc); + gl.vertexAttribDivisor(colorLoc, divisor); + var colorCount = instanceCount / divisor; + if ((instanceCount % divisor) != 0) + colorCount++; + var colors = new Float32Array(colorCount); + for (var ii = 0; ii < colorCount; ++ii) { + colors[ii] = 1.0 / colorCount * (ii + 1); + } + var colorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); + gl.vertexAttribPointer(colorLoc, 1, gl.FLOAT, false, 0, 0); + + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced should succeed"); + + var colorIndex = -1; + for (var ii = 0; ii < instanceCount; ++ii) { + if ((ii % divisor) == 0) + colorIndex++; + var refColor = [ Math.floor(colors[colorIndex] * 255), 0, 0, 255 ]; + wtu.checkCanvasRect(gl, Math.floor(canvas.width / instanceCount * ii) + 1, 0, 1, canvas.height, refColor, + "instance " + ii + " should be " + refColor, 2); + } + + gl.deleteBuffer(positionBuffer); + gl.deleteBuffer(offsetBuffer); + gl.deleteBuffer(colorBuffer); + gl.deleteProgram(program); + gl.deleteVertexArray(vao); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + gl.useProgram(null); + gl.bindVertexArray(null); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clean up should succeed"); +} + +function runDrawElementsTest(instanceCount, divisor) { + debug(""); + debug("Testing drawElementsInstanced: instanceCount = " + instanceCount + ", divisor = " + divisor); + + gl.viewport(0, 0, canvas.width, canvas.height); + + var vao = gl.createVertexArray(); + gl.bindVertexArray(vao); + + var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"]); + var positionLoc = gl.getAttribLocation(program, "aPosition"); + var offsetLoc = gl.getAttribLocation(program, "aOffset"); + var colorLoc = gl.getAttribLocation(program, "aColor"); + if (!program || positionLoc < 0 || offsetLoc < 0 || colorLoc < 0) { + testFailed("Set up program failed"); + return; + } + testPassed("Set up program succeeded"); + + var scale = 1.0 / instanceCount; + + gl.enableVertexAttribArray(positionLoc); + gl.vertexAttribDivisor(positionLoc, 0); + var positions = new Float32Array([ + 1.0 * scale, 1.0, + -1.0 * scale, 1.0, + -1.0 * scale, -1.0, + 1.0 * scale, -1.0, + ]); + var positionBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); + gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); + + gl.enableVertexAttribArray(offsetLoc); + gl.vertexAttribDivisor(offsetLoc, 1); + var offsets = new Float32Array(instanceCount); + for (var ii = 0; ii < instanceCount; ++ii) { + offsets[ii] = scale * (1 - instanceCount + ii * 2); + } + var offsetBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); + gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW); + gl.vertexAttribPointer(offsetLoc, 1, gl.FLOAT, false, 0, 0); + + gl.enableVertexAttribArray(colorLoc); + gl.vertexAttribDivisor(colorLoc, divisor); + var colorCount = instanceCount / divisor; + if ((instanceCount % divisor) != 0) + colorCount++; + var colors = new Float32Array(colorCount); + for (var ii = 0; ii < colorCount; ++ii) { + colors[ii] = 1.0 / colorCount * (ii + 1); + } + var colorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); + gl.vertexAttribPointer(colorLoc, 1, gl.FLOAT, false, 0, 0); + + var indexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); + var indices = new Uint16Array([0, 1, 2, 0, 2, 3]); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); + + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced should succeed"); + + var colorIndex = -1; + for (var ii = 0; ii < instanceCount; ++ii) { + if ((ii % divisor) == 0) + colorIndex++; + var refColor = [ Math.floor(colors[colorIndex] * 255), 0, 0, 255 ]; + wtu.checkCanvasRect(gl, Math.floor(canvas.width / instanceCount * ii) + 1, 0, 1, canvas.height, refColor, + "instance " + ii + " should be " + refColor, 2); + } + + gl.deleteBuffer(positionBuffer); + gl.deleteBuffer(offsetBuffer); + gl.deleteBuffer(colorBuffer); + gl.deleteBuffer(indexBuffer); + gl.deleteProgram(program); + gl.deleteVertexArray(vao); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); + gl.useProgram(null); + gl.bindVertexArray(null); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clean up should succeed"); +} + +debug(""); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/out-of-bounds-index-buffers-after-copying.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/out-of-bounds-index-buffers-after-copying.html new file mode 100644 index 000000000..e01f71753 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/out-of-bounds-index-buffers-after-copying.html @@ -0,0 +1,207 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<title>WebGL Out-of-Bounds Index Buffer Caused by CopyBufferSubData Conformance Test</title> +</head> +<body> +<canvas id="canvas" width="8" height="8" style="width: 100px; height: 100px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script id="vsCheckOutOfBounds" type="x-shader/x-vertex"> + #define TEST_CASE_IN_BOUND 1 + #define TEST_CASE_OUT_OF_BOUND 2 + + precision mediump float; + attribute vec2 position; + attribute vec4 vecRandom; + varying vec4 v_color; + uniform int u_testCase; + + bool testFloatComponentAccurate(float component) { + return component == 0.2; + } + // Per the spec, each component can either contain existing contents + // of the buffer or 0. + bool testFloatComponent(float component) { + return (component == 0.2 || component == 0.0); + } + // The last component is additionally allowed to be 1.0. + bool testLastFloatComponent(float component) { + return testFloatComponent(component) || component == 1.0; + } + + bool testData(vec4 data) { + if (u_testCase == TEST_CASE_IN_BOUND) { + return (testFloatComponentAccurate(data.x) && + testFloatComponentAccurate(data.y) && + testFloatComponentAccurate(data.z) && + testFloatComponentAccurate(data.w)); + } else if (u_testCase == TEST_CASE_OUT_OF_BOUND) { + return (testFloatComponent(data.x) && + testFloatComponent(data.y) && + testFloatComponent(data.z) && + testLastFloatComponent(data.w)); + } + return false; + } + + void main() { + if (testData(vecRandom)) { + v_color = vec4(0.0, 1.0, 0.0, 1.0); // green -- We're good + } else { + v_color = vec4(1.0, 0.0, 0.0, 1.0); // red -- Unexpected value + } + gl_Position = vec4(position, 0.0, 1.0); + } +</script> +<script> +"use strict"; +description("This test verifies that out-of-bounds index buffers caused by CopyBufferSubData behave according to spec."); + +// Ensure that drawElements flags either no error or INVALID_OPERATION. In the case of INVALID_OPERATION, +// no canvas pixels can be touched. In the case of NO_ERROR, all written values must either be the +// zero vertex or a value in the vertex buffer. See vsCheckOutOfBounds shader. +function verifyOutOfBoundsIndex(gl) { + var error = gl.getError(); + if (error === gl.INVALID_OPERATION) { + testPassed("drawElements flagged INVALID_OPERATION, which is valid so long as all canvas pixels were not touched."); + wtu.checkCanvas(gl, [0, 0, 255, 255]); + } else if (error === gl.NO_ERROR) { + testPassed("drawElements flagged NO_ERROR, which is valid so long as all canvas pixels are green."); + wtu.checkCanvas(gl, [0, 255, 0, 255]); + } else { + testFailed("Invalid error flagged by drawElements. Should be INVALID_OPERATION or NO_ERROR"); + } +} + +// Create an element array buffer with a tri-strip that starts at startIndex and make +// it the active element array buffer. +function prepareElementArrayBuffer(gl, startIndex) { + var glElementArrayBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, glElementArrayBuffer); + var quadIndices = new Uint16Array(4); + for (var i = 0; i < quadIndices.length; i++) { + quadIndices[i] = startIndex + i; + } + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, quadIndices, gl.STATIC_DRAW); + return glElementArrayBuffer; +} + + +var wtu = WebGLTestUtils; +var canvas = document.getElementById("canvas"); +var gl = wtu.create3DContext(canvas, {antialias: false}, 2); + +var numberOfQuads = 200; + +// Create a vertex buffer with 200 properly formed tri-strip quads. These quads will cover the canvas texture +// such that every single pixel is touched by the fragment shader. +var quadBuffer = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer); +var quadPositions = new Float32Array(numberOfQuads * /*ComponentsPerQuad*/2 * /*VerticesPerQuad*/4); +for (var i = 0; i < quadPositions.length; i += /*ComponentsPerQuad*/2 * /*VerticesPerQuad*/4) { + quadPositions[i+0] = -1.0; // upper left + quadPositions[i+1] = 1.0; + quadPositions[i+2] = 1.0; // upper right + quadPositions[i+3] = 1.0; + quadPositions[i+4] = -1.0; // lower left + quadPositions[i+5] = -1.0; + quadPositions[i+6] = 1.0; // lower right + quadPositions[i+7] = -1.0; +} +gl.bufferData(gl.ARRAY_BUFFER, quadPositions, gl.STATIC_DRAW); +gl.enableVertexAttribArray(0); +gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0); + +// Create a small vertex buffer with determined-ahead-of-time "random" values (0.2). This buffer will be +// the one indexed off the end. +var vertexBuffer = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); +gl.bufferData(gl.ARRAY_BUFFER, + new Float32Array([0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2]), + gl.STATIC_DRAW); +gl.enableVertexAttribArray(1); +gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0); + +// Setup the verification program. +var program = wtu.setupProgram(gl, ["vsCheckOutOfBounds", wtu.simpleVertexColorFragmentShader], ["position", "vecRandom"]); +wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Shader and buffer setup should generate no errors"); +var loc = gl.getUniformLocation(program, "u_testCase"); +shouldBeNonNull(loc); + +debug(""); +debug("Test -- Vertex indices are in bounds."); +gl.uniform1i(loc, 1); // TEST_CASE_IN_BOUND == 1 +gl.clearColor(0.0, 0.0, 1.0, 1.0); // Start with blue to indicate no pixels touched. +gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); +var elementArrayBuffer = prepareElementArrayBuffer(gl, /*StartIndex*/0); +gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_SHORT, /*offset*/0); +wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Draw call should generate no errors"); +wtu.checkCanvas(gl, [0, 255, 0, 255]); + +debug(""); +debug("Test -- Index off the end of the vertex buffer near the beginning of the out of bounds area."); +gl.uniform1i(loc, 2); // TEST_CASE_OUT_OF_BOUND == 2 +gl.clearColor(0.0, 0.0, 1.0, 1.0); // Start with blue to indicate no pixels touched. +gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); +var outOfBoundsElementArrayBuffer = prepareElementArrayBuffer(gl, /*StartIndex*/4); +gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, outOfBoundsElementArrayBuffer); +gl.bindBuffer(gl.COPY_WRITE_BUFFER, elementArrayBuffer); +gl.copyBufferSubData(gl.ELEMENT_ARRAY_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 4 * Uint16Array.BYTES_PER_ELEMENT); +wtu.glErrorShouldBe(gl, gl.NO_ERROR, "copyBufferSubData should generate no errors"); +gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementArrayBuffer); +gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_SHORT, /*offset*/0); +verifyOutOfBoundsIndex(gl); + +debug(""); +debug("Test -- Index off the end of the vertex buffer near the end of the out of bounds area.") +gl.uniform1i(loc, 2); // TEST_CASE_OUT_OF_BOUND == 2 +gl.clearColor(0.0, 0.0, 1.0, 1.0); // Start with blue to indicate no pixels touched. +gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); +outOfBoundsElementArrayBuffer = prepareElementArrayBuffer(gl, /*StartIndex*/numberOfQuads - 4); +gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementArrayBuffer); +gl.bindBuffer(gl.COPY_READ_BUFFER, outOfBoundsElementArrayBuffer); +gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.ELEMENT_ARRAY_BUFFER, 0, 0, 4 * Uint16Array.BYTES_PER_ELEMENT); +wtu.glErrorShouldBe(gl, gl.NO_ERROR, "copyBufferSubData should generate no errors"); +gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_SHORT, /*offset*/0); +verifyOutOfBoundsIndex(gl); + +debug(""); +wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Running tests should generate no errors"); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rendering-sampling-feedback-loop.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rendering-sampling-feedback-loop.html new file mode 100644 index 000000000..9bbfe3a7b --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rendering-sampling-feedback-loop.html @@ -0,0 +1,148 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL Rendering and Sampling Feedback Loop Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas id="example" width="8" height="8"></canvas> +<div id="description"></div> +<div id="console"></div> + +<script id="vshader" type="x-shader/x-vertex">#version 300 es +in highp vec4 aPosition; +in vec2 aTexCoord; +out vec2 texCoord; +void main() { + gl_Position = aPosition; + texCoord = aTexCoord; +} +</script> + +<script id="fshader" type="x-shader/x-fragment">#version 300 es +precision mediump float; +uniform sampler2D tex; +in vec2 texCoord; +out vec4 oColor; +void main() { + oColor = texture(tex, texCoord); +} +</script> + +<script> +"use strict"; + +var wtu = WebGLTestUtils; +description("This test verifies the functionality of rendering to the same texture where it samples from."); + +var gl = wtu.create3DContext("example", undefined, 2); + +var width = 8; +var height = 8; +var tex0; +var tex1; +var fbo; +var program; +var positionLoc; +var texCoordLoc; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + init(); + + // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation + allocate_resource(); + + rendering_sampling_feedback_loop([gl.NONE, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION); + rendering_sampling_feedback_loop([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION); + rendering_sampling_feedback_loop([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR); +} + +function init() { + program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['aPosition', 'aTexCoord'], [0, 1]); + positionLoc = gl.getAttribLocation(program, "aPosition"); + texCoordLoc = gl.getAttribLocation(program, "aTexCoord"); + if (!program || positionLoc < 0 || texCoordLoc < 0) { + testFailed("Set up program failed"); + return; + } + testPassed("Set up program succeeded"); + + wtu.setupUnitQuad(gl, 0, 1); + gl.viewport(0, 0, width, height); +} + +function allocate_resource() { + tex0 = gl.createTexture(); + tex1 = gl.createTexture(); + fbo = gl.createFramebuffer(); + wtu.fillTexture(gl, tex0, width, height, [0xff, 0x0, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA); + wtu.fillTexture(gl, tex1, width, height, [0x0, 0xff, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA); + + gl.bindTexture(gl.TEXTURE_2D, tex1); + var texLoc = gl.getUniformLocation(program, "tex"); + gl.uniform1i(texLoc, 0); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex0, 0); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex1, 0); +} + +function rendering_sampling_feedback_loop(draw_buffers, error) { + gl.drawBuffers(draw_buffers); + + // Make sure framebuffer is complete before feedback loop detection + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("Framebuffer incomplete."); + return; + } + + wtu.clearAndDrawUnitQuad(gl); + wtu.glErrorShouldBe(gl, error, "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise, it should be NO_ERROR"); +} + +gl.bindTexture(gl.TEXTURE_2D, null); +gl.bindFramebuffer(gl.FRAMEBUFFER, null); +gl.deleteTexture(tex0); +gl.deleteTexture(tex1); +gl.deleteFramebuffer(fbo); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rgb-format-support.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rgb-format-support.html new file mode 100644 index 000000000..bb67edffb --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rgb-format-support.html @@ -0,0 +1,132 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +var wtu = WebGLTestUtils; +description("Verify RGB/RGB8 textures and renderbuffers support"); + +var gl = wtu.create3DContext(undefined, undefined, 2); + +function testRenderbuffer(width, height) { + var samples = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGB8, gl.SAMPLES); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from getInternalformatParameter()"); + + if (!samples || samples.length == 0) { + testFailed("getInternalformatParameter on RGB8 fails to return valid samples"); + return; + } + + for (var idx = 0; idx < samples.length + 2; ++idx) { + debug(""); + var renderbuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); + var sampleCount = 0; + switch (idx) { + case samples.length: + sampleCount = 0; + break; + case samples.length + 1: + sampleCount = -1; // non multisampled + break; + default: + sampleCount = samples[idx]; + } + + if (sampleCount < 0) { + debug("test non-multisampled RGB8 renderbuffer"); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB8, 2, 2); + } else { + debug("test RGB8 renderbuffer with " + sampleCount + " samples"); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGB8, width, height); + } + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from renderbufferStorage{Multisample}"); + + var fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderbuffer); + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("framebuffer with renderbuffer is incomplete"); + } else { + testPassed("framebuffer with renderbuffer is complete"); + } + + gl.clearColor(1, 0, 1, 1); + gl.clear(gl.COLOR_BIT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from clear()"); + } +} + +function testTexture(width, height) { + var formats = [ "RGB", "RGB8" ]; + for (var idx = 0; idx < formats.length; ++idx) { + debug(""); + debug("test texture format " + formats[idx]); + var internalformat = gl[formats[idx]]; + var tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, internalformat, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, null); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture setup"); + + var fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + testFailed("framebuffer with texture is incomplete"); + } else { + testPassed("framebuffer with texture is complete"); + } + + gl.clearColor(1, 0, 1, 1); + gl.clear(gl.COLOR_BIT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from clear()"); + } +} + +if (!gl) { + testFailed('canvas.getContext() failed'); +} else { + testRenderbuffer(2, 2); + testTexture(2, 2); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/uniform-block-buffer-size.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/uniform-block-buffer-size.html new file mode 100644 index 000000000..96b111ec4 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/uniform-block-buffer-size.html @@ -0,0 +1,249 @@ +<!-- + +/* +** Copyright (c) 2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL UniformBlock Buffer Size Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script id='vshader' type='x-shader/x-vertex'>#version 300 es +layout(location=0) in vec3 p; +void main() +{ + gl_Position = vec4(p.xyz, 1.0); +} +</script> +<script id='fshader' type='x-shader/x-fragment'>#version 300 es +precision mediump float; +layout(location=0) out vec4 oColor; + +uniform UBOData { + float UBORed; + float UBOGreen; + float UBOBlue; +}; + +void main() +{ + oColor = vec4(UBORed, UBOGreen, UBOBlue, 1.0); +} +</script> +</head> +<body> +<div id="description"></div> +<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies an active UniformBlock should be populated with a large enough buffer object"); + +debug(""); + +var wtu = WebGLTestUtils; +var canvas = document.getElementById("canvas"); +var gl = wtu.create3DContext(canvas, null, 2); + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + runDrawArraysTests(); + runDrawElementsTests(); +} + +function runDrawArraysTests() { + debug(""); + debug("Testing drawArrays and drawArraysInstanced"); + + var instanceCount = 4; + + var program = wtu.setupProgram(gl, ['vshader', 'fshader']); + if (!program) { + testFailed("Could not compile shader with uniform blocks without error"); + return; + } + + var blockIndex = gl.getUniformBlockIndex(program, "UBOData"); + var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE); + var uniformIndices = gl.getUniformIndices(program, ["UBORed", "UBOGreen", "UBOBlue"]); + var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET); + + if (uniformOffsets.length < 3) { + testFailed("Could not query uniform offsets"); + return; + } + + var uboArray = new ArrayBuffer(blockSize); + var uboFloatView = new Float32Array(uboArray); + uboFloatView[uniformOffsets[0] / Float32Array.BYTES_PER_ELEMENT] = 1.0; // UBORed + uboFloatView[uniformOffsets[1] / Float32Array.BYTES_PER_ELEMENT] = 0.0; // UBOGreen + uboFloatView[uniformOffsets[2] / Float32Array.BYTES_PER_ELEMENT] = 0.0; // UBOBlue + + var binding = 1; + gl.uniformBlockBinding(program, blockIndex, binding); + + wtu.setupUnitQuad(gl); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Set up succeeded"); + + var buffer = gl.createBuffer(); + gl.bindBuffer(gl.UNIFORM_BUFFER, buffer); + + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: UniformBlock is not backed by a buffer"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArraysInstanced: UniformBlock is not backed by a buffer"); + + gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, buffer); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: UniformBlock is backed by a buffer with no data store"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArraysInstanced: UniformBlock is backed by a buffer with no data store"); + + var arrayNotLargeEnough = new ArrayBuffer(blockSize - 1); + gl.bufferData(gl.UNIFORM_BUFFER, arrayNotLargeEnough, gl.DYNAMIC_DRAW); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: UniformBlock not populated with a large enough buffer"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArraysInstanced: UniformBlock not populated with a large enough buffer"); + + gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView, gl.DYNAMIC_DRAW); + gl.clearColor(0, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays: should be able to draw with sufficient data for UniformBlock"); + wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced: should be able to draw with sufficient data for UniformBlock"); + wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2); + + gl.bindBufferRange(gl.UNIFORM_BUFFER, binding, buffer, 0, blockSize -1); + gl.drawArrays(gl.TRIANGLES, 0, 6); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: bindBufferRange set size too small for UniformBlock"); + gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArraysInstanced: bindBufferRange set size too small for UniformBlock"); +} + +function runDrawElementsTests() { + debug(""); + debug("Testing drawElements, drawRangeElements and drawElementsInstanced"); + + var instanceCount = 4; + + var program = wtu.setupProgram(gl, ['vshader', 'fshader']); + if (!program) { + testFailed("Could not compile shader with uniform blocks without error"); + return; + } + + var blockIndex = gl.getUniformBlockIndex(program, "UBOData"); + var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE); + var uniformIndices = gl.getUniformIndices(program, ["UBORed", "UBOGreen", "UBOBlue"]); + var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET); + + if (uniformOffsets.length < 3) { + testFailed("Could not query uniform offsets"); + return; + } + + var uboArray = new ArrayBuffer(blockSize); + var uboFloatView = new Float32Array(uboArray); + uboFloatView[uniformOffsets[0] / Float32Array.BYTES_PER_ELEMENT] = 1.0; // UBORed + uboFloatView[uniformOffsets[1] / Float32Array.BYTES_PER_ELEMENT] = 0.0; // UBOGreen + uboFloatView[uniformOffsets[2] / Float32Array.BYTES_PER_ELEMENT] = 0.0; // UBOBlue + + var binding = 1; + gl.uniformBlockBinding(program, blockIndex, binding); + + wtu.setupIndexedQuad(gl, 1, 0); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Set up succeeded"); + + var buffer = gl.createBuffer(); + gl.bindBuffer(gl.UNIFORM_BUFFER, buffer); + + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: UniformBlock is not backed by a buffer"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawRangeElements: UniformBlock is not backed by a buffer"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElementsInstanced: UniformBlock is not backed a buffer"); + + gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, buffer); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: UniformBlock is populated with a buffer with no data store"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawRangeElements: UniformBlock is populated with a buffer with no data store"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElementsInstanced: UniformBlock is populated with a buffer with no data store"); + + var arrayNotLargeEnough = new ArrayBuffer(blockSize - 1); + gl.bufferData(gl.UNIFORM_BUFFER, arrayNotLargeEnough, gl.DYNAMIC_DRAW); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: UniformBlock not populated with a large enough buffer"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawRangeElements: UniformBlock not populated with a large enough buffer"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElementsInstanced: UniformBlock not populated with a large enough buffer"); + + gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView, gl.DYNAMIC_DRAW); + gl.clearColor(0, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements: should be able to draw with sufficient data for UniformBlock"); + wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawRangeElements: should be able to draw with sufficient data for UniformBlock"); + wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced: should be able to draw with sufficient data for UniformBlock"); + wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2); + + gl.bindBufferRange(gl.UNIFORM_BUFFER, binding, buffer, 0, blockSize -1); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: bindBufferRange set size too small for UniformBlock"); + gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawRangeElements: bindBufferRange set size too small for UniformBlock"); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElementsInstanced: bindBufferRange set size too small for UniformBlock"); +} + +debug(""); +wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> |