| <!-- |
| Copyright (c) 2020 The Khronos Group Inc. |
| Use of this source code is governed by an MIT-style license that can be |
| found in the LICENSE.txt file. |
| --> |
| |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <title>WebGL OES_draw_buffers_indexed 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> |
| <div id="console"></div> |
| <script> |
| "use strict"; |
| description("This test verifies the functionality of the OES_draw_buffers_indexed extension, if it is available."); |
| |
| debug(""); |
| |
| var wtu = WebGLTestUtils; |
| var canvas = document.getElementById("canvas"); |
| var gl = wtu.create3DContext(null, null, 2); |
| var ext; |
| |
| const vs = `#version 300 es |
| layout(location=0) in vec4 vPosition; |
| void main() |
| { |
| gl_Position = vPosition; |
| } |
| `; |
| |
| const fs = `#version 300 es |
| precision lowp float; |
| layout(location = 0) out vec4 o_color0; |
| layout(location = 1) out vec4 o_color1; |
| void main() |
| { |
| o_color0 = vec4(1, 0, 0, 0); |
| o_color1 = vec4(1, 0, 0, 0); |
| } |
| `; |
| |
| function setup() { |
| const program = wtu.setupProgram(gl, [vs, fs]); |
| gl.useProgram(program); |
| wtu.setupUnitQuad(gl, 0); |
| wtu.glErrorShouldBe(gl, 0, 'No errors from program'); |
| |
| const tex1 = gl.createTexture(); |
| gl.bindTexture(gl.TEXTURE_2D, tex1); |
| gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); |
| wtu.glErrorShouldBe(gl, 0, 'Create texture 1 successfully'); |
| |
| const tex2 = gl.createTexture(); |
| gl.bindTexture(gl.TEXTURE_2D, tex2); |
| gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); |
| wtu.glErrorShouldBe(gl, 0, 'Create texture 2 successfully'); |
| |
| const attachments = [gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]; |
| |
| const fb = gl.createFramebuffer(); |
| gl.bindFramebuffer(gl.FRAMEBUFFER, fb); |
| gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, tex1, 0); |
| gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, tex2, 0); |
| shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); |
| |
| gl.drawBuffers(attachments); |
| wtu.glErrorShouldBe(gl, 0, 'Set draw buffers without errors'); |
| } |
| |
| function enableDisableTest() { |
| debug("Testing enableiOES/disableiOES"); |
| |
| // Invalid input |
| ext.enableiOES(gl.DEPTH_TEST, 0); |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'target could only be gl.BLEND'); |
| |
| ext.disableiOES(gl.DEPTH_TEST, 0); |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'target could only be gl.BLEND'); |
| |
| gl.disable(gl.BLEND); |
| |
| // Valid input |
| ext.enableiOES(gl.BLEND, 0); |
| shouldBe('gl.isEnabled(gl.BLEND)', 'true'); |
| ext.disableiOES(gl.BLEND, 0); |
| ext.enableiOES(gl.BLEND, 1); |
| shouldBe('gl.isEnabled(gl.BLEND)', 'false'); |
| gl.enable(gl.BLEND); |
| shouldBe('gl.isEnabled(gl.BLEND)', 'true'); |
| wtu.glErrorShouldBe(gl, 0, 'No errors from enable and disable draw buffers blend state'); |
| } |
| |
| function constantAlphaBlendColorValidationTest() { |
| debug("Testing CONSTANT_COLOR/ALPHA blend functions limit validation"); |
| function isConstantColorAndAlphaBlendFunctions(first, second) |
| { |
| return (first == gl.CONSTANT_COLOR || first == gl.ONE_MINUS_CONSTANT_COLOR) && |
| (second == gl.CONSTANT_ALPHA || second == gl.ONE_MINUS_CONSTANT_ALPHA); |
| } |
| |
| function checkBlendFunctions(src, dst) |
| { |
| if (isConstantColorAndAlphaBlendFunctions(src, dst) || |
| isConstantColorAndAlphaBlendFunctions(dst, src)) |
| { |
| wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, 'invalid combinations'); |
| return false; |
| } |
| else |
| { |
| wtu.glErrorShouldBe(gl, 0, 'No error'); |
| return true; |
| } |
| } |
| |
| const srcFunc = [ |
| gl.ZERO, |
| gl.ONE, |
| gl.SRC_COLOR, |
| gl.ONE_MINUS_SRC_COLOR, |
| gl.DST_COLOR, |
| gl.ONE_MINUS_DST_COLOR, |
| gl.SRC_ALPHA, |
| gl.ONE_MINUS_SRC_ALPHA, |
| gl.DST_ALPHA, |
| gl.ONE_MINUS_DST_ALPHA, |
| gl.CONSTANT_COLOR, |
| gl.ONE_MINUS_CONSTANT_COLOR, |
| gl.CONSTANT_ALPHA, |
| gl.ONE_MINUS_CONSTANT_ALPHA, |
| gl.SRC_ALPHA_SATURATE, |
| ]; |
| |
| const dstFunc = [ |
| gl.ZERO, gl.ONE, |
| gl.SRC_COLOR, gl.ONE_MINUS_SRC_COLOR, |
| gl.DST_COLOR, gl.ONE_MINUS_DST_COLOR, |
| gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, |
| gl.DST_ALPHA, gl.ONE_MINUS_DST_ALPHA, |
| gl.CONSTANT_COLOR, gl.ONE_MINUS_CONSTANT_COLOR, |
| gl.CONSTANT_ALPHA, gl.ONE_MINUS_CONSTANT_ALPHA, |
| ]; |
| |
| let src, dst; |
| |
| // CONSTANT_COLOR/ALPHA invalid combination check |
| for (let i = 0, leni = srcFunc.length; i < leni; i++) |
| { |
| src = srcFunc[i]; |
| for (let j = 0, lenj = dstFunc.length; j < lenj; j++) |
| { |
| dst = dstFunc[j]; |
| ext.blendFunciOES(0, src, dst); |
| checkBlendFunctions(src, dst); |
| ext.blendFuncSeparateiOES(0, src, dst, gl.ONE, gl.ONE); |
| checkBlendFunctions(src, dst); |
| } |
| } |
| } |
| |
| function indexedBlendColorTest() { |
| debug(''); |
| debug("Testing blendEquationiOES and blendFunciOES"); |
| wtu.glErrorShouldBe(gl, 0, 'top of indexedBlendColorTest'); |
| |
| gl.clearColor(0, 0, 1, 1); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| |
| ext.blendEquationiOES(0, gl.FUNC_ADD); |
| ext.blendFunciOES(0, gl.ONE, gl.ONE); |
| ext.blendEquationiOES(1, gl.FUNC_ADD); |
| ext.blendFunciOES(1, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); |
| gl.drawArrays(gl.TRIANGLES, 0, 6); |
| wtu.glErrorShouldBe(gl, 0, 'Draw quad without errors'); |
| |
| gl.readBuffer(gl.COLOR_ATTACHMENT0); |
| wtu.checkCanvasRect(gl, 0, 0, 1, 1, [255, 0, 255, 255]); |
| |
| gl.readBuffer(gl.COLOR_ATTACHMENT1); |
| wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 255, 255]); |
| |
| debug("Testing blendEquationSeparateiOES and blendFuncSeparateiOES"); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| |
| ext.blendEquationSeparateiOES(0, gl.FUNC_ADD, gl.FUNC_SUBTRACT); |
| ext.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ZERO, gl.ZERO); |
| ext.blendEquationSeparateiOES(1, gl.FUNC_ADD, gl.FUNC_SUBTRACT); |
| ext.blendFuncSeparateiOES(1, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ZERO); |
| gl.drawArrays(gl.TRIANGLES, 0, 6); |
| wtu.glErrorShouldBe(gl, 0, 'Draw quad without errors'); |
| |
| gl.readBuffer(gl.COLOR_ATTACHMENT0); |
| wtu.checkCanvasRect(gl, 0, 0, 1, 1, [255, 0, 255, 0]); |
| |
| gl.readBuffer(gl.COLOR_ATTACHMENT1); |
| wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 255, 0]); |
| |
| debug("Testing colorMaskiOES"); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| ext.colorMaskiOES(0, false, false, false, false); |
| ext.colorMaskiOES(1, true, true, true, true); |
| |
| gl.drawArrays(gl.TRIANGLES, 0, 6); |
| wtu.glErrorShouldBe(gl, 0, 'Draw quad without errors'); |
| |
| gl.readBuffer(gl.COLOR_ATTACHMENT0); |
| wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 255, 255]); |
| |
| gl.readBuffer(gl.COLOR_ATTACHMENT1); |
| wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 255, 0]); |
| |
| debug(''); |
| debug(`Testing that new tokens aren't on the extension.`); |
| shouldBe('ext.BLEND_EQUATION_RGB', 'undefined'); |
| shouldBe('ext.BLEND_EQUATION_ALPHA', 'undefined'); |
| shouldBe('ext.BLEND_SRC_RGB', 'undefined'); |
| shouldBe('ext.BLEND_SRC_ALPHA', 'undefined'); |
| shouldBe('ext.BLEND_DST_RGB', 'undefined'); |
| shouldBe('ext.BLEND_DST_ALPHA', 'undefined'); |
| shouldBe('ext.COLOR_WRITEMASK', 'undefined'); |
| |
| debug("Testing new tokens for getIndexedParameterTest"); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 0)', 'gl.FUNC_ADD'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_ALPHA, 0)', 'gl.FUNC_SUBTRACT'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)', 'gl.ONE'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)', 'gl.ONE'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)', 'gl.ZERO'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)', 'gl.ZERO'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 1)', 'gl.FUNC_ADD'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_ALPHA, 1)', 'gl.FUNC_SUBTRACT'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_RGB, 1)', 'gl.SRC_ALPHA'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_DST_RGB, 1)', 'gl.ONE_MINUS_SRC_ALPHA'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 1)', 'gl.ZERO'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 1)', 'gl.ZERO'); |
| |
| shouldBe('gl.getIndexedParameter(gl.COLOR_WRITEMASK, 0)', '[false, false, false, false]'); |
| shouldBe('gl.getIndexedParameter(gl.COLOR_WRITEMASK, 1)', '[true, true, true, true]'); |
| |
| debug("Testing non-indexed getParamter get state from draw buffer 0"); |
| shouldBe('gl.getParameter(gl.BLEND_SRC_RGB)', 'gl.ONE'); |
| shouldBe('gl.getParameter(gl.BLEND_DST_RGB)', 'gl.ONE'); |
| shouldBe('gl.getParameter(gl.BLEND_SRC_ALPHA)', 'gl.ZERO'); |
| shouldBe('gl.getParameter(gl.BLEND_DST_ALPHA)', 'gl.ZERO'); |
| shouldBe('gl.getParameter(gl.BLEND_EQUATION_RGB)', 'gl.FUNC_ADD'); |
| shouldBe('gl.getParameter(gl.BLEND_EQUATION_ALPHA)', 'gl.FUNC_SUBTRACT'); |
| shouldBe('gl.getParameter(gl.COLOR_WRITEMASK)', '[false, false, false, false]'); |
| |
| debug("Testing non-indexed calls modify all draw buffers state"); |
| gl.blendEquationSeparate(gl.FUNC_SUBTRACT, gl.FUNC_ADD); |
| gl.blendFuncSeparate(gl.ONE_MINUS_DST_ALPHA, gl.DST_ALPHA, gl.ONE, gl.ONE); |
| gl.colorMask(true, false, true, false); |
| wtu.glErrorShouldBe(gl, 0, 'Non-indexed state set without errors'); |
| |
| shouldBe('gl.getParameter(gl.BLEND_EQUATION_RGB)', 'gl.FUNC_SUBTRACT'); |
| shouldBe('gl.getParameter(gl.BLEND_EQUATION_ALPHA)', 'gl.FUNC_ADD'); |
| shouldBe('gl.getParameter(gl.BLEND_SRC_RGB)', 'gl.ONE_MINUS_DST_ALPHA'); |
| shouldBe('gl.getParameter(gl.BLEND_DST_RGB)', 'gl.DST_ALPHA'); |
| shouldBe('gl.getParameter(gl.BLEND_SRC_ALPHA)', 'gl.ONE'); |
| shouldBe('gl.getParameter(gl.BLEND_DST_ALPHA)', 'gl.ONE'); |
| shouldBe('gl.getParameter(gl.COLOR_WRITEMASK)', '[true, false, true, false]'); |
| |
| shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 0)', 'gl.FUNC_SUBTRACT'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_ALPHA, 0)', 'gl.FUNC_ADD'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)', 'gl.ONE_MINUS_DST_ALPHA'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)', 'gl.DST_ALPHA'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)', 'gl.ONE'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)', 'gl.ONE'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 1)', 'gl.FUNC_SUBTRACT'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_ALPHA, 1)', 'gl.FUNC_ADD'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_RGB, 1)', 'gl.ONE_MINUS_DST_ALPHA'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_DST_RGB, 1)', 'gl.DST_ALPHA'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 1)', 'gl.ONE'); |
| shouldBe('gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 1)', 'gl.ONE'); |
| |
| shouldBe('gl.getIndexedParameter(gl.COLOR_WRITEMASK, 0)', '[true, false, true, false]'); |
| shouldBe('gl.getIndexedParameter(gl.COLOR_WRITEMASK, 1)', '[true, false, true, false]'); |
| } |
| |
| function runTestExtension() { |
| setup(); |
| |
| testInvalidValues(); |
| |
| enableDisableTest(); |
| |
| // blending should be enabled for drawBuffers 0 and 1 at this point |
| |
| constantAlphaBlendColorValidationTest(); |
| |
| indexedBlendColorTest(); |
| |
| testColorMaskDrawNoOp(); |
| } |
| |
| function runInvalidEnumsTest() { |
| debug("Testing new enums for getIndexedParameterTest being invalid before requesting the extension"); |
| gl.getIndexedParameter(0x8009, 0); // BLEND_EQUATION_RGB |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_EQUATION_RGB'); |
| gl.getIndexedParameter(0x883D, 0); // BLEND_EQUATION_ALPHA |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_EQUATION_ALPHA'); |
| gl.getIndexedParameter(0x80C9, 0); // BLEND_SRC_RGB |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_SRC_RGB'); |
| gl.getIndexedParameter(0x80CB, 0); // BLEND_SRC_ALPHA |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_SRC_ALPHA'); |
| gl.getIndexedParameter(0x80C8, 0); // BLEND_DST_RGB |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_DST_RGB'); |
| gl.getIndexedParameter(0x80CA, 0); // BLEND_DST_ALPHA |
| wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_DST_ALPHA'); |
| gl.getIndexedParameter(0x0C23, 0); // COLOR_WRITEMASK |
| wtu.glErrorShouldBe(gl, [gl.INVALID_OPERATION, gl.INVALID_ENUM], 'invalid operations or invalid enums for COLOR_WRITEMASK'); |
| } |
| |
| function testInvalidValues() { |
| const numDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS); |
| if (!numDrawBuffers) throw new Error('!numDrawBuffers'); |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.enableiOES(gl.BLEND, -1)`); |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.enableiOES(gl.BLEND, ${numDrawBuffers})`); |
| wtu.shouldGenerateGLError(gl, 0, `ext.enableiOES(gl.BLEND, ${numDrawBuffers-1})`); |
| |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.disableiOES(gl.BLEND, -1)`); |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.disableiOES(gl.BLEND, ${numDrawBuffers})`); |
| wtu.shouldGenerateGLError(gl, 0, `ext.disableiOES(gl.BLEND, ${numDrawBuffers-1})`); |
| |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendEquationiOES(-1, gl.FUNC_ADD)`); |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendEquationiOES(${numDrawBuffers}, gl.FUNC_ADD)`); |
| wtu.shouldGenerateGLError(gl, 0, `ext.blendEquationiOES(${numDrawBuffers-1}, gl.FUNC_ADD)`); |
| |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendEquationSeparateiOES(-1, gl.FUNC_ADD, gl.FUNC_ADD)`); |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendEquationSeparateiOES(${numDrawBuffers}, gl.FUNC_ADD, gl.FUNC_ADD)`); |
| wtu.shouldGenerateGLError(gl, 0, `ext.blendEquationSeparateiOES(${numDrawBuffers-1}, gl.FUNC_ADD, gl.FUNC_ADD)`); |
| |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendFunciOES(-1, gl.ONE, gl.ONE)`); |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendFunciOES(${numDrawBuffers}, gl.ONE, gl.ONE)`); |
| wtu.shouldGenerateGLError(gl, 0, `ext.blendFunciOES(${numDrawBuffers-1}, gl.ONE, gl.ONE)`); |
| |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendFuncSeparateiOES(-1, gl.ONE, gl.ZERO, gl.ONE, gl.ZERO)`); |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendFuncSeparateiOES(${numDrawBuffers}, gl.ONE, gl.ZERO, gl.ONE, gl.ZERO)`); |
| wtu.shouldGenerateGLError(gl, 0, `ext.blendFuncSeparateiOES(${numDrawBuffers-1}, gl.ONE, gl.ZERO, gl.ONE, gl.ZERO)`); |
| |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.colorMaskiOES(-1, 1,1,1,1)`); |
| wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.colorMaskiOES(${numDrawBuffers}, 1,1,1,1)`); |
| wtu.shouldGenerateGLError(gl, 0, `ext.colorMaskiOES(${numDrawBuffers-1}, 1,1,1,1)`); |
| } |
| |
| function* range(n) { |
| for (let i = 0; i < n; i++) { |
| yield i; |
| } |
| } |
| |
| function testColorMaskDrawNoOp() { |
| debug(''); |
| debug('testColorMaskDrawNoOp') |
| // > If any draw buffer with an attachment does not have a defined |
| // fragment shader output, draws generate INVALID_OPERATION, |
| // unless all 4 channels of colorMask are set to false. |
| const NUM_OUTPUTS = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS); |
| shouldBeTrue(`${NUM_OUTPUTS} > 1`); |
| |
| const fb = gl.createFramebuffer(); |
| gl.bindFramebuffer(gl.FRAMEBUFFER, fb); |
| gl.viewport(0,0,1,1); |
| |
| const DRAW_BUFFERS = []; |
| for (const i of range(NUM_OUTPUTS)) { |
| const tex = gl.createTexture(); |
| gl.bindTexture(gl.TEXTURE_2D, tex); |
| gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1); |
| const ca = gl.COLOR_ATTACHMENT0+i; |
| DRAW_BUFFERS.push(ca) |
| gl.framebufferTexture2D(gl.FRAMEBUFFER, ca, |
| gl.TEXTURE_2D, tex, 0); |
| } |
| shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); |
| |
| gl.drawBuffers(DRAW_BUFFERS); |
| gl.colorMask(1, 1, 1, 1); |
| gl.disable(gl.BLEND); |
| |
| gl.clearColor(0, 0, 0, 0); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| |
| for (const i of range(NUM_OUTPUTS)) { |
| gl.readBuffer(gl.COLOR_ATTACHMENT0+i); |
| wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 0, 0], `COLOR_ATTACHMENT${i} initially black`); |
| } |
| |
| for (const validOutput of range(NUM_OUTPUTS)) { |
| const invalidOutput = validOutput ^ 0b11; |
| debug(`validOutput: ${validOutput}, invalidOutput: ${invalidOutput}`); |
| const prog = wtu.setupProgram(gl, [ |
| `\ |
| #version 300 es |
| void main() { |
| gl_Position = vec4(0,0,0,1); |
| gl_PointSize = 1.0f; |
| } |
| `, |
| `\ |
| #version 300 es |
| precision mediump float; |
| layout(location=${validOutput}) out vec4 o_color; |
| void main() { |
| o_color = vec4(1,1,1,1); |
| } |
| ` |
| ]); |
| gl.useProgram(prog); |
| |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, |
| 'After init.'); |
| |
| gl.colorMask(1,1,1,1); |
| gl.drawBuffers(DRAW_BUFFERS); |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, |
| 'Drawing with unmasked undefined color outputs.'); |
| |
| gl.colorMask(0,0,0,0); |
| gl.drawBuffers(DRAW_BUFFERS); |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, |
| 'Drawing with colorMask-masked-out undefined color outputs.'); |
| |
| gl.colorMask(1,1,1,1); |
| gl.drawBuffers(DRAW_BUFFERS.map((x,i) => (i == invalidOutput) ? x : 0)); |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, |
| 'Drawing with wrong-id drawBuffer-masked-out undefined color outputs.'); |
| |
| gl.drawBuffers(DRAW_BUFFERS.map((x,i) => (i == validOutput) ? x : 0)); |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, |
| 'Drawing with drawBuffer-masked-out undefined color outputs.'); |
| |
| gl.colorMask(0,0,0,0); |
| gl.drawBuffers([]); |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, |
| 'Drawing with colorMask+drawBuffer-masked-out undefined color outputs.'); |
| |
| const testMask = (r,g,b,a) => { |
| debug(`testMask(${[r,g,b,a]})`); |
| gl.drawBuffers(DRAW_BUFFERS); |
| |
| gl.colorMask(1,1,1,1); |
| gl.clearColor(0, 0, 0, 0); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| gl.colorMask(0,0,0,0); |
| ext.colorMaskiOES(validOutput, r,g,b,a); |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, |
| `Drawing with sole defined color${validOutput} output writemask: ${[r,g,b,a]}.`); |
| |
| for (const i of range(NUM_OUTPUTS)) { |
| gl.readBuffer(gl.COLOR_ATTACHMENT0+i); |
| let expect = [0,0,0,0]; |
| if (i == validOutput) { |
| expect = [r,g,b,a].map(x => 0xff*x); |
| } |
| wtu.checkCanvasRect(gl, 0, 0, 1, 1, expect, `COLOR_ATTACHMENT${i}: [${expect}]`); |
| } |
| |
| gl.colorMask(1,1,1,1); |
| gl.clearColor(0, 0, 0, 0); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| gl.colorMask(r,g,b,a); |
| for (const i of range(NUM_OUTPUTS)) { |
| if (i == validOutput) continue; |
| ext.colorMaskiOES(i, 0,0,0,0); |
| } |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, |
| `Drawing with sole remaining defined color${validOutput} output writemask: ${[r,g,b,a]}.`); |
| |
| for (const i of range(NUM_OUTPUTS)) { |
| gl.readBuffer(gl.COLOR_ATTACHMENT0+i); |
| let expect = [0,0,0,0]; |
| if (i == validOutput) { |
| expect = [r,g,b,a].map(x => 0xff*x); |
| } |
| wtu.checkCanvasRect(gl, 0, 0, 1, 1, expect, `COLOR_ATTACHMENT${i}: [${expect}]`); |
| } |
| |
| if (r || g || b || a) { |
| gl.colorMask(0,0,0,0); |
| ext.colorMaskiOES(invalidOutput, r,g,b,a); |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, |
| `Drawing with wrong-id undefined color output color masked: ${[r,g,b,a]}.`); |
| |
| gl.drawBuffers([]); |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, |
| 'Drawing with wrong-id colorMask, but all-off drawBuffers.'); |
| |
| gl.drawBuffers(DRAW_BUFFERS.map((x,i) => (i == validOutput) ? x : 0)); |
| gl.drawArrays(gl.POINTS, 0, 1); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, |
| 'Drawing with wrong-id colorMask, but right-id drawBuffers masked.'); |
| } |
| }; |
| |
| testMask(0,0,0,0); |
| testMask(1,0,0,0); |
| testMask(0,1,0,0); |
| testMask(0,0,1,0); |
| testMask(0,0,0,1); |
| testMask(1,1,1,1); |
| } |
| } |
| |
| function runTest() { |
| if (!gl) { |
| testFailed("context does not exist"); |
| } else { |
| testPassed("context exists"); |
| |
| runInvalidEnumsTest(); |
| |
| ext = gl.getExtension("OES_draw_buffers_indexed"); |
| |
| wtu.runExtensionSupportedTest(gl, "OES_draw_buffers_indexed", ext !== null); |
| |
| if (ext !== null) { |
| runTestExtension(); |
| } else { |
| testPassed("No OES_draw_buffers_indexed support -- this is legal"); |
| } |
| } |
| } |
| |
| runTest(); |
| |
| var successfullyParsed = true; |
| </script> |
| <script src="../../js/js-test-post.js"></script> |
| </body> |
| </html> |