'use strict'; const trivialVsSrc = ` void main() { gl_Position = vec4(0,0,0,1); } `; const trivialFsSrc = ` void main() { gl_FragColor = vec4(0,1,0,1); } `; const trivialVsMrtSrc100 = ` void main() { gl_Position = vec4(0,0,0,1); } `; const trivialFsMrtSrc100 = ` #extension GL_EXT_draw_buffers : require precision mediump float; void main() { gl_FragData[0] = vec4(1, 0, 0, 1); gl_FragData[1] = vec4(0, 1, 0, 1); } `; const trivialVsMrtSrc300 = `#version 300 es void main() { gl_Position = vec4(0,0,0,1); } `; const trivialFsMrtSrc300 = `#version 300 es precision mediump float; layout(location = 0) out vec4 o_color0; layout(location = 1) out vec4 o_color1; void main() { o_color0 = vec4(1, 0, 0, 1); o_color1 = vec4(0, 1, 0, 1); } `; function testExtFloatBlend(internalFormat) { const shouldBlend = gl.getSupportedExtensions().indexOf('EXT_float_blend') != -1; const prog = wtu.setupProgram(gl, [trivialVsSrc, trivialFsSrc]); gl.useProgram(prog); const tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null); const fb = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fb); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); gl.disable(gl.BLEND); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, 0, 'Float32 draw target without blending'); gl.enable(gl.BLEND); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION, 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed '); gl.deleteFramebuffer(fb); gl.deleteTexture(tex); } function testExtFloatBlendMRTImpl(version, internalFormat, shaders, attachments, drawBuffers) { const shouldBlend = gl.getSupportedExtensions().indexOf('EXT_float_blend') != -1; const prog = wtu.setupProgram(gl, shaders); gl.useProgram(prog); 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); 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); const texF1 = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texF1); gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null); const texF2 = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texF2); gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null); 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'); drawBuffers(attachments); gl.enable(gl.BLEND); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, 0, 'No Float32 color attachment'); if (version < 2) { // EXT_draw_buffers require all color buffers having the same number of bitplanes gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, texF1, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, texF2, 0); shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION, 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed '); } else { gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, texF1, 0); shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION, 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed '); gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, texF2, 0); shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION, 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed '); gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, tex1, 0); shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION, 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed '); drawBuffers([attachments[0]]); shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, 0, 'Float32 color attachment draw buffer is not enabled'); drawBuffers(attachments); gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, tex2, 0); shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, 0, 'No Float32 color attachment'); } gl.deleteFramebuffer(fb); gl.deleteTexture(tex1); gl.deleteTexture(tex2); gl.deleteTexture(texF1); gl.deleteTexture(texF2); } function testExtFloatBlendMRT(version, drawBuffersExt) { if (version < 2) { if (!drawBuffersExt) return; testExtFloatBlendMRTImpl( version, gl.RGBA, [trivialVsMrtSrc100, trivialFsMrtSrc100], [drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, drawBuffersExt.COLOR_ATTACHMENT1_WEBGL], drawBuffersExt.drawBuffersWEBGL.bind(drawBuffersExt) ); } else { testExtFloatBlendMRTImpl( version, gl.RGBA32F, [trivialVsMrtSrc300, trivialFsMrtSrc300], [gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.drawBuffers.bind(gl) ); } } function testExtFloatBlendNonFloat32TypeImpl(internalFormat, formats) { const shouldBlend = gl.getSupportedExtensions().indexOf('EXT_float_blend') != -1; const prog = wtu.setupProgram(gl, [trivialVsSrc, trivialFsSrc]); gl.useProgram(prog); gl.enable(gl.BLEND); const tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null); const fb = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fb); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION, 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed '); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, 0, 'UNSIGNED_BYTE should blend anyway'); for (let i = 0, len = formats.length; i < len; i++) { gl.texImage2D(gl.TEXTURE_2D, 0, formats[i][0], 1, 1, 0, formats[i][1], formats[i][2], null); gl.drawArrays(gl.POINTS, 0, 1); wtu.glErrorShouldBe(gl, 0, 'Any other float type which is not 32-bit-Float should blend anyway'); } gl.deleteFramebuffer(fb); gl.deleteTexture(tex); } function testExtFloatBlendNonFloat32Type(version, oesTextureHalfFloat) { if (version < 2) { if (!oesTextureHalfFloat) return; const formats = [ [gl.RGBA, gl.RGBA, oesTextureHalfFloat.HALF_FLOAT_OES] ]; testExtFloatBlendNonFloat32TypeImpl(gl.RGBA, formats); } else { const formats = [ [gl.RGBA16F, gl.RGBA, gl.HALF_FLOAT], [gl.RGBA16F, gl.RGBA, gl.FLOAT], [gl.RG16F, gl.RG, gl.FLOAT], [gl.R16F, gl.RED, gl.FLOAT], [gl.R11F_G11F_B10F, gl.RGB, gl.FLOAT] ]; testExtFloatBlendNonFloat32TypeImpl(gl.RGBA32F, formats); } } /* Copyright (c) 2019 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. */