framebuffer-mismatched-attachment-targets.html (5247B)
1 <!-- 2 Copyright (c) 2020 The Khronos Group Inc. 3 Use of this source code is governed by an MIT-style license that can be 4 found in the LICENSE.txt file. 5 --> 6 7 <!DOCTYPE html> 8 <html> 9 <head> 10 <meta charset="utf-8"> 11 <title>WebGL2 can render to framebuffer attachments with different targets</title> 12 <link rel="stylesheet" href="../../resources/js-test-style.css"/> 13 <script src="../../js/js-test-pre.js"></script> 14 <script src="../../js/webgl-test-utils.js"></script> 15 <script id="vshader" type="x-shader/x-vertex">#version 300 es 16 void main(void) { 17 gl_Position = vec4(-0.5, -0.5, 0, 1); 18 gl_PointSize = 1.0; 19 } 20 </script> 21 <script id="fshader" type="x-shader/x-fragment">#version 300 es 22 precision mediump float; 23 out vec4 outColor; 24 void main() { 25 outColor = vec4(0, 1, 0, 1); 26 } 27 </script> 28 </head> 29 <body> 30 <canvas id="example" width="1", height="1"></canvas> 31 <div id="description"></div> 32 <div id="console"></div> 33 <script> 34 "use strict"; 35 debug(""); 36 37 description("Test framebuffer attachments with different targets"); 38 39 const wtu = WebGLTestUtils; 40 const gl = wtu.create3DContext("example", undefined, 2); 41 42 if (!gl) { 43 testFailed("WebGL context creation failed"); 44 } else { 45 testPassed("WebGL context creation succeeded"); 46 runTest(); 47 } 48 49 function newResource(target, mipLevels, format, size) { 50 let ret; 51 switch (target) { 52 case gl.RENDERBUFFER: { 53 ret = gl.createRenderbuffer(); 54 ret.mips = [ ret ]; 55 for (let i = 1; i < mipLevels; i++) { 56 ret.mips.push(gl.createRenderbuffer()); 57 } 58 for (const i in ret.mips) { 59 const rb = ret.mips[i]; 60 gl.bindRenderbuffer(target, rb); 61 gl.renderbufferStorage(target, format, size>>i, size>>i); 62 } 63 ret.attach = (attachEnum, mipLevel) => { 64 const rb = ret.mips[mipLevel]; 65 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachEnum, gl.RENDERBUFFER, rb); 66 }; 67 break; 68 } 69 case gl.TEXTURE_2D: 70 case gl.TEXTURE_CUBE_MAP: { 71 ret = gl.createTexture(); 72 gl.bindTexture(target, ret); 73 gl.texStorage2D(target, mipLevels, format, size, size); 74 let imageTarget = target; 75 if (imageTarget == gl.TEXTURE_CUBE_MAP) { 76 imageTarget = gl.TEXTURE_CUBE_MAP_POSITIVE_X+2; // Deliberately don't choose the first image. 77 } 78 ret.attach = (attachEnum, mipLevel) => { 79 gl.framebufferTexture2D(gl.FRAMEBUFFER, attachEnum, imageTarget, ret, mipLevel); 80 }; 81 break; 82 } 83 case gl.TEXTURE_3D: 84 case gl.TEXTURE_2D_ARRAY: { 85 ret = gl.createTexture(); 86 gl.bindTexture(target, ret); 87 gl.texStorage3D(target, mipLevels, format, size, size, 1); 88 ret.attach = (attachEnum, mipLevel) => { 89 gl.framebufferTextureLayer(gl.FRAMEBUFFER, attachEnum, ret, mipLevel, 0); 90 }; 91 break; 92 } 93 default: 94 throw new Error(); 95 } 96 ret.target = wtu.glEnumToString(gl, target); 97 ret.format = wtu.glEnumToString(gl, format); 98 return ret; 99 } 100 101 function runTest() { 102 const MIP_LEVELS = 2; 103 const SIZE = 2; 104 105 gl.clearColor(1, 0, 0, 1); 106 107 const program = wtu.setupProgram(gl, ['vshader','fshader'], [], console.log.bind(console)); 108 gl.useProgram(program); 109 110 const colorResList = [ 111 newResource(gl.RENDERBUFFER, MIP_LEVELS, gl.RGBA8, SIZE), 112 newResource(gl.TEXTURE_2D, MIP_LEVELS, gl.RGBA8, SIZE), 113 newResource(gl.TEXTURE_CUBE_MAP, MIP_LEVELS, gl.RGBA8, SIZE), 114 newResource(gl.TEXTURE_3D, MIP_LEVELS, gl.RGBA8, SIZE), 115 newResource(gl.TEXTURE_2D_ARRAY, MIP_LEVELS, gl.RGBA8, SIZE), 116 ]; 117 118 const depthResList = [ 119 newResource(gl.RENDERBUFFER, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE), 120 newResource(gl.TEXTURE_2D, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE), 121 newResource(gl.TEXTURE_CUBE_MAP, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE), 122 //newResource(gl.TEXTURE_3D, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE), // Depth formats forbidden for TEXTURE_3D. 123 newResource(gl.TEXTURE_2D_ARRAY, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE), 124 ]; 125 126 const fb = gl.createFramebuffer(); 127 gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 128 for (const color of colorResList) { 129 for (const depth of depthResList) { 130 debug(`\ncolor: ${color.target}; depth: ${depth.target}`); 131 for (let mipLevel = 0; mipLevel < MIP_LEVELS; mipLevel++) { 132 debug(`mipLevel: ${mipLevel}`); 133 color.attach(gl.COLOR_ATTACHMENT0, mipLevel); 134 depth.attach(gl.DEPTH_ATTACHMENT, mipLevel); 135 const maybeStatus = wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, [gl.FRAMEBUFFER_COMPLETE, gl.FRAMEBUFFER_UNSUPPORTED]); 136 if (!maybeStatus || maybeStatus[0] != gl.FRAMEBUFFER_COMPLETE) { 137 continue; 138 } 139 140 gl.clear(gl.COLOR_BUFFER_BIT); 141 wtu.checkCanvas(gl, [255, 0, 0, 255], `framebuffer layer ${mipLevel} should be cleared red`); 142 143 gl.drawArrays(gl.POINTS, 0, 1); 144 wtu.checkCanvas(gl, [0, 255, 0, 255], `framebuffer layer ${mipLevel} should be drawn green`); 145 146 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors`); 147 } 148 } 149 } 150 151 // make sure we were not rendering to the canvas. 152 gl.bindFramebuffer(gl.FRAMEBUFFER, null) 153 wtu.checkCanvas(gl, [0, 0, 0, 0], "canvas should be zero"); 154 } 155 156 debug(""); 157 var successfullyParsed = true; 158 </script> 159 <script src="../../js/js-test-post.js"></script> 160 161 </body> 162 </html>