| <!-- |
| Copyright (c) 2021 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 2 Blend Integer 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 id="outputVertexShader" type="x-shader/x-vertex"> |
| #version 300 es |
| in vec4 vPosition; |
| void main() |
| { |
| gl_Position = vPosition; |
| } |
| </script> |
| <script id="outputFragmentShaderSigned" type="x-shader/x-fragment"> |
| #version 300 es |
| layout(location = 1) out highp vec4 o_drawBuffer1; |
| layout(location = 2) out highp ivec4 o_drawBuffer2; |
| layout(location = 3) out highp vec4 o_drawBuffer3; |
| void main(void) |
| { |
| o_drawBuffer1 = vec4(0, 0, 0, 0); |
| o_drawBuffer2 = ivec4(0, 0, 0, 0); |
| o_drawBuffer3 = vec4(0, 0, 0, 0); |
| } |
| </script> |
| <script id="outputFragmentShaderUnsigned" type="x-shader/x-fragment"> |
| #version 300 es |
| layout(location = 1) out highp vec4 o_drawBuffer1; |
| layout(location = 2) out highp uvec4 o_drawBuffer2; |
| layout(location = 3) out highp vec4 o_drawBuffer3; |
| void main(void) |
| { |
| o_drawBuffer1 = vec4(0, 0, 0, 0); |
| o_drawBuffer2 = uvec4(0, 0, 0, 0); |
| o_drawBuffer3 = vec4(0, 0, 0, 0); |
| } |
| </script> |
| |
| <script> |
| "use strict"; |
| description("This test verifies correct behavior of min/max blending operations on integer attachments."); |
| |
| debug(""); |
| |
| const wtu = WebGLTestUtils; |
| const gl = wtu.create3DContext(null, undefined, 2); |
| |
| if (!gl) { |
| testFailed("WebGL context does not exist"); |
| } else { |
| testPassed("WebGL context exists"); |
| |
| debug("") |
| debug("GL_MIN"); |
| runTest(false, gl.MIN); |
| runTest(true, gl.MIN); |
| |
| debug("") |
| debug("GL_MAX"); |
| runTest(false, gl.MAX); |
| runTest(true, gl.MAX); |
| } |
| |
| function compareValue(value, attachment, isSigned) { |
| const pixel = isSigned ? new Int32Array(4) : new Uint32Array(4); |
| gl.readBuffer(attachment); |
| gl.readPixels(0, 0, 1, 1, gl.RGBA_INTEGER, isSigned ? gl.INT : gl.UNSIGNED_INT, pixel); |
| let pass = true; |
| for (let i = 0; i < 4; i++) { |
| if (value[i] != pixel[i]) { |
| testFailed(`Read value of channel ${i} should be ${pixel[i]}, was ${value[i]}.`); |
| pass = false; |
| } |
| } |
| return pass; |
| } |
| |
| function runTest(isSigned, operation) { |
| gl.viewport(0, 0, 1, 1); |
| gl.disable(gl.BLEND); |
| |
| const program = wtu.setupProgram(gl, |
| ["outputVertexShader", |
| isSigned ? "outputFragmentShaderSigned" : "outputFragmentShaderUnsigned"], |
| ['vPosition'], [0]); |
| const quadParameters = wtu.setupUnitQuad(gl, 0, 1); |
| |
| // Setup render targets |
| const fb = gl.createFramebuffer(); |
| gl.bindFramebuffer(gl.FRAMEBUFFER, fb); |
| |
| const rb1 = gl.createRenderbuffer(); |
| gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); |
| gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 50, 50); |
| gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1); |
| |
| const rb2 = gl.createRenderbuffer(); |
| gl.bindRenderbuffer(gl.RENDERBUFFER, rb2); |
| gl.renderbufferStorage(gl.RENDERBUFFER, isSigned ? gl.RGBA32I : gl.RGBA32UI, 50, 50); |
| gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.RENDERBUFFER, rb2); |
| |
| const rb3 = gl.createRenderbuffer(); |
| gl.bindRenderbuffer(gl.RENDERBUFFER, rb3); |
| gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 50, 50); |
| gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT3, gl.RENDERBUFFER, rb3); |
| |
| gl.drawBuffers([gl.NONE, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3]); |
| |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Pipeline setup complete."); |
| |
| if (isSigned) { |
| const clearValue = new Int32Array([-1, 2, -3, 4]); |
| gl.clearBufferiv(gl.COLOR, 2, clearValue); |
| if (compareValue(clearValue, gl.COLOR_ATTACHMENT2, isSigned)) { |
| testPassed("Signed clear passed."); |
| } else { |
| testFailed("Signed clear failed."); |
| } |
| } else { |
| const clearValue = new Uint32Array([1, 2, 3, 4]); |
| gl.clearBufferuiv(gl.COLOR, 2, clearValue); |
| if (compareValue(clearValue, gl.COLOR_ATTACHMENT2, isSigned)) { |
| testPassed("Unsigned clear passed."); |
| } else { |
| testFailed("Unsigned clear failed."); |
| } |
| } |
| |
| gl.blendEquation(operation); |
| gl.enable(gl.BLEND); |
| |
| wtu.drawUnitQuad(gl); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Draw complete."); |
| |
| if (isSigned) { |
| const drawValue = new Int32Array([0, 0, 0, 0]); |
| if (compareValue(drawValue, gl.COLOR_ATTACHMENT2, isSigned)) { |
| testPassed("Signed draw passed."); |
| } else { |
| testFailed("Signed draw failed."); |
| } |
| } else { |
| const drawValue = new Uint32Array([0, 0, 0, 0]); |
| if (compareValue(drawValue, gl.COLOR_ATTACHMENT2, isSigned)) { |
| testPassed("Unsigned draw passed."); |
| } else { |
| testFailed("Unsigned draw failed."); |
| } |
| } |
| gl.deleteRenderbuffer(rb1); |
| gl.deleteRenderbuffer(rb2); |
| gl.deleteRenderbuffer(rb3); |
| gl.deleteFramebuffer(fb); |
| gl.deleteProgram(program); |
| } |
| |
| debug(""); |
| var successfullyParsed = true; |
| </script> |
| <script src="../../js/js-test-post.js"></script> |
| |
| </body> |
| </html> |