Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
michael@0 | 1 | <!-- |
michael@0 | 2 | Copyright (c) 2011 Mozilla Foundation. All rights reserved. |
michael@0 | 3 | Use of this source code is governed by a BSD-style license that can be |
michael@0 | 4 | found in the LICENSE file. |
michael@0 | 5 | --> |
michael@0 | 6 | <!DOCTYPE html> |
michael@0 | 7 | <html> |
michael@0 | 8 | <head> |
michael@0 | 9 | <meta charset="utf-8"> |
michael@0 | 10 | <title>WebGL Program Compiling/Linking Conformance Test</title> |
michael@0 | 11 | <link rel="stylesheet" href="../../resources/js-test-style.css"/> |
michael@0 | 12 | <script src="../../resources/js-test-pre.js" type="text/javascript"></script> |
michael@0 | 13 | <script src="../resources/webgl-test.js" type="text/javascript"></script> |
michael@0 | 14 | </head> |
michael@0 | 15 | <body> |
michael@0 | 16 | <div id="description"></div> |
michael@0 | 17 | <div id="console"></div> |
michael@0 | 18 | <canvas id="canvas" width="2" height="2"> </canvas> |
michael@0 | 19 | <script type="text/javascript"> |
michael@0 | 20 | function go() { |
michael@0 | 21 | description("Tests that program compiling/linking/using works correctly."); |
michael@0 | 22 | |
michael@0 | 23 | debug(""); |
michael@0 | 24 | debug("Canvas.getContext"); |
michael@0 | 25 | |
michael@0 | 26 | var gl = create3DContext(document.getElementById("canvas")); |
michael@0 | 27 | if (!gl) { |
michael@0 | 28 | testFailed("context does not exist"); |
michael@0 | 29 | return; |
michael@0 | 30 | } |
michael@0 | 31 | |
michael@0 | 32 | testPassed("context exists"); |
michael@0 | 33 | |
michael@0 | 34 | gl.clearColor(0.0, 0.0, 0.0, 0.0); |
michael@0 | 35 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
michael@0 | 36 | |
michael@0 | 37 | function doArraysHaveSameContents(a, b) { |
michael@0 | 38 | var flags = []; |
michael@0 | 39 | function hasUnusedValue(a, value) { |
michael@0 | 40 | for (var ii = 0; ii < a.length; ++ii) { |
michael@0 | 41 | if (a[ii] === value && !flags[ii]) { |
michael@0 | 42 | flags[ii] = true; |
michael@0 | 43 | return true; |
michael@0 | 44 | } |
michael@0 | 45 | } |
michael@0 | 46 | return false; |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | try { |
michael@0 | 50 | if (a.length !== b.length) { |
michael@0 | 51 | return false; |
michael@0 | 52 | } |
michael@0 | 53 | for (var ii = 0; ii < a.length; ii++) { |
michael@0 | 54 | if (!hasUnusedValue(b, a[ii])) { |
michael@0 | 55 | return false; |
michael@0 | 56 | } |
michael@0 | 57 | } |
michael@0 | 58 | } catch (ex) { |
michael@0 | 59 | return false; |
michael@0 | 60 | } |
michael@0 | 61 | return true; |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | /////// Check compileShader() ///////////////////////////// |
michael@0 | 65 | |
michael@0 | 66 | var vs = gl.createShader(gl.VERTEX_SHADER); |
michael@0 | 67 | gl.shaderSource(vs, "attribute vec4 aVertex; attribute vec4 aColor; varying vec4 vColor; void main() { vColor = aColor; gl_Position = aVertex; }"); |
michael@0 | 68 | gl.compileShader(vs); |
michael@0 | 69 | |
michael@0 | 70 | assertMsg(gl.getShaderParameter(vs, gl.COMPILE_STATUS) == true, |
michael@0 | 71 | "good vertex shader should compile"); |
michael@0 | 72 | |
michael@0 | 73 | var vs2 = gl.createShader(gl.VERTEX_SHADER); |
michael@0 | 74 | gl.shaderSource(vs2, "attribute vec4 aVertex; attribute vec4 aColor; varying vec4 vColor; void main() { vColor = aColor; gl_Position = aVertex * 0.5; }"); |
michael@0 | 75 | gl.compileShader(vs2); |
michael@0 | 76 | |
michael@0 | 77 | assertMsg(gl.getShaderParameter(vs2, gl.COMPILE_STATUS) == true, |
michael@0 | 78 | "good vertex shader #2 should compile"); |
michael@0 | 79 | |
michael@0 | 80 | var vsBad = gl.createShader(gl.VERTEX_SHADER); |
michael@0 | 81 | gl.shaderSource(vsBad, "WILL NOT COMPILE;"); |
michael@0 | 82 | gl.compileShader(vsBad); |
michael@0 | 83 | |
michael@0 | 84 | // GLSL 1.0.17 section 10.27. compile shader does not have to return failure. |
michael@0 | 85 | //assertMsg(gl.getShaderParameter(vsBad, gl.COMPILE_STATUS) == false, |
michael@0 | 86 | // "bad vertex shader should fail to compile"); |
michael@0 | 87 | |
michael@0 | 88 | var fs = gl.createShader(gl.FRAGMENT_SHADER); |
michael@0 | 89 | gl.shaderSource(fs, "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }"); |
michael@0 | 90 | gl.compileShader(fs); |
michael@0 | 91 | |
michael@0 | 92 | assertMsg(gl.getShaderParameter(fs, gl.COMPILE_STATUS) == true, |
michael@0 | 93 | "good fragment shader should compile"); |
michael@0 | 94 | |
michael@0 | 95 | var fs2 = gl.createShader(gl.FRAGMENT_SHADER); |
michael@0 | 96 | gl.shaderSource(fs2, "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor * 0.5; }"); |
michael@0 | 97 | gl.compileShader(fs2); |
michael@0 | 98 | |
michael@0 | 99 | assertMsg(gl.getShaderParameter(fs2, gl.COMPILE_STATUS) == true, |
michael@0 | 100 | "good fragment shader #2 should compile"); |
michael@0 | 101 | |
michael@0 | 102 | var fsBad = gl.createShader(gl.FRAGMENT_SHADER); |
michael@0 | 103 | gl.shaderSource(fsBad, "WILL NOT COMPILE;"); |
michael@0 | 104 | gl.compileShader(fsBad); |
michael@0 | 105 | |
michael@0 | 106 | // GLSL 1.0.17 section 10.27. compile shader does not have to return failure. |
michael@0 | 107 | //assertMsg(gl.getShaderParameter(fsBad, gl.COMPILE_STATUS) == false, |
michael@0 | 108 | // "bad fragment shader should fail to compile"); |
michael@0 | 109 | |
michael@0 | 110 | glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors at this point"); |
michael@0 | 111 | |
michael@0 | 112 | /////// Check attachShader() ///////////////////////////// |
michael@0 | 113 | |
michael@0 | 114 | function checkAttachShader(already_attached_shaders, shader, expected_error_code, errmsg) { |
michael@0 | 115 | var prog = gl.createProgram(); |
michael@0 | 116 | for (var i = 0; i < already_attached_shaders.length; ++i) |
michael@0 | 117 | gl.attachShader(prog, already_attached_shaders[i]); |
michael@0 | 118 | if(gl.getError() != gl.NO_ERROR) |
michael@0 | 119 | assertMsg(false, "unexpected error in attachShader()"); |
michael@0 | 120 | gl.attachShader(prog, shader); |
michael@0 | 121 | glErrorShouldBe(gl, expected_error_code, errmsg); |
michael@0 | 122 | } |
michael@0 | 123 | |
michael@0 | 124 | checkAttachShader([], vs, gl.NO_ERROR, "attaching a vertex shader should succeed"); |
michael@0 | 125 | checkAttachShader([vs], vs, gl.INVALID_OPERATION, |
michael@0 | 126 | "attaching an already attached vertex shader should generate INVALID_OPERATION"); |
michael@0 | 127 | checkAttachShader([], fs, gl.NO_ERROR, "attaching a fragment shader should succeed"); |
michael@0 | 128 | checkAttachShader([fs], fs, gl.INVALID_OPERATION, |
michael@0 | 129 | "attaching an already attached fragment shader should generate INVALID_OPERATION"); |
michael@0 | 130 | checkAttachShader([vs], vs2, gl.INVALID_OPERATION, |
michael@0 | 131 | "attaching shaders of the same type to a program should generate INVALID_OPERATION"); |
michael@0 | 132 | checkAttachShader([fs], fs2, gl.INVALID_OPERATION, |
michael@0 | 133 | "attaching shaders of the same type to a program should generate INVALID_OPERATION"); |
michael@0 | 134 | |
michael@0 | 135 | /////// Check detachShader() ///////////////////////////// |
michael@0 | 136 | |
michael@0 | 137 | function checkDetachShader(already_attached_shaders, shader, expected_error_code, errmsg) { |
michael@0 | 138 | var prog = gl.createProgram(); |
michael@0 | 139 | for (var i = 0; i < already_attached_shaders.length; ++i) |
michael@0 | 140 | gl.attachShader(prog, already_attached_shaders[i]); |
michael@0 | 141 | if(gl.getError() != gl.NO_ERROR) |
michael@0 | 142 | assertMsg(false, "unexpected error in attachShader()"); |
michael@0 | 143 | gl.detachShader(prog, shader); |
michael@0 | 144 | glErrorShouldBe(gl, expected_error_code, errmsg); |
michael@0 | 145 | } |
michael@0 | 146 | |
michael@0 | 147 | checkDetachShader([vs], vs, gl.NO_ERROR, "detaching a vertex shader should succeed"); |
michael@0 | 148 | checkDetachShader([fs], vs, gl.INVALID_OPERATION, |
michael@0 | 149 | "detaching a not already attached vertex shader should generate INVALID_OPERATION"); |
michael@0 | 150 | checkDetachShader([fs], fs, gl.NO_ERROR, "detaching a fragment shader should succeed"); |
michael@0 | 151 | checkDetachShader([vs], fs, gl.INVALID_OPERATION, |
michael@0 | 152 | "detaching a not already attached fragment shader should generate INVALID_OPERATION"); |
michael@0 | 153 | |
michael@0 | 154 | /////// Check getAttachedShaders() ///////////////////////////// |
michael@0 | 155 | |
michael@0 | 156 | function checkGetAttachedShaders(shaders_to_attach, shaders_to_detach, expected_shaders, errmsg) { |
michael@0 | 157 | var prog = gl.createProgram(); |
michael@0 | 158 | for (var i = 0; i < shaders_to_attach.length; ++i) |
michael@0 | 159 | gl.attachShader(prog, shaders_to_attach[i]); |
michael@0 | 160 | if(gl.getError() != gl.NO_ERROR) |
michael@0 | 161 | assertMsg(false, "unexpected error in attachShader()"); |
michael@0 | 162 | for (var i = 0; i < shaders_to_detach.length; ++i) |
michael@0 | 163 | gl.detachShader(prog, shaders_to_detach[i]); |
michael@0 | 164 | if(gl.getError() != gl.NO_ERROR) |
michael@0 | 165 | assertMsg(false, "unexpected error in detachShader()"); |
michael@0 | 166 | assertMsg(doArraysHaveSameContents(gl.getAttachedShaders(prog), expected_shaders), errmsg); |
michael@0 | 167 | } |
michael@0 | 168 | checkGetAttachedShaders([], [], [], "getAttachedShaders should return an empty list by default"); |
michael@0 | 169 | checkGetAttachedShaders([fs], [], [fs], "attaching a single shader should give the expected list"); |
michael@0 | 170 | checkGetAttachedShaders([fs, vs], [], [fs, vs], |
michael@0 | 171 | "attaching some shaders should give the expected list"); |
michael@0 | 172 | checkGetAttachedShaders([fs], [fs], [], "attaching a shader and detaching it shoud leave an empty list"); |
michael@0 | 173 | checkGetAttachedShaders([fs, vs], [fs, vs], [], |
michael@0 | 174 | "attaching some shaders and detaching them in same order shoud leave an empty list"); |
michael@0 | 175 | checkGetAttachedShaders([fs, vs], [vs, fs], [], |
michael@0 | 176 | "attaching some shaders and detaching them in random order shoud leave an empty list"); |
michael@0 | 177 | checkGetAttachedShaders([fs, vs], [vs], [fs], |
michael@0 | 178 | "attaching and detaching some shaders should leave the difference list"); |
michael@0 | 179 | checkGetAttachedShaders([fs, vs], [fs], [vs], |
michael@0 | 180 | "attaching and detaching some shaders should leave the difference list"); |
michael@0 | 181 | checkGetAttachedShaders([fsBad], [], [fsBad], |
michael@0 | 182 | "attaching a shader that failed to compile should still show it in the list"); |
michael@0 | 183 | checkGetAttachedShaders([fs, vsBad], [], [fs, vsBad], |
michael@0 | 184 | "attaching shaders, including one that failed to compile, should still show the it in the list"); |
michael@0 | 185 | |
michael@0 | 186 | /////// Check linkProgram() and useProgram ///////////////////////////// |
michael@0 | 187 | |
michael@0 | 188 | function checkLinkAndUse(shaders, deleteShaderAfterAttach, expected_status, errmsg) { |
michael@0 | 189 | var prog = gl.createProgram(); |
michael@0 | 190 | for (var i = 0; i < shaders.length; ++i) { |
michael@0 | 191 | gl.attachShader(prog, shaders[i]); |
michael@0 | 192 | if (deleteShaderAfterAttach) |
michael@0 | 193 | gl.deleteShader(shaders[i]); |
michael@0 | 194 | } |
michael@0 | 195 | gl.bindAttribLocation(prog, 0, "aVertex"); |
michael@0 | 196 | gl.bindAttribLocation(prog, 1, "aColor"); |
michael@0 | 197 | gl.linkProgram(prog); |
michael@0 | 198 | if (gl.getError() != gl.NO_ERROR) |
michael@0 | 199 | assertMsg(false, "unexpected error in linkProgram()"); |
michael@0 | 200 | assertMsg(gl.getProgramParameter(prog, gl.LINK_STATUS) == expected_status, errmsg); |
michael@0 | 201 | var infolog = gl.getProgramInfoLog(prog); |
michael@0 | 202 | if (gl.getError() != gl.NO_ERROR) |
michael@0 | 203 | assertMsg(false, "unexpected error in getProgramInfoLog()"); |
michael@0 | 204 | if (typeof(infolog) != "string") |
michael@0 | 205 | assertMsg(false, "getProgramInfoLog() did not return a string"); |
michael@0 | 206 | if (expected_status == true && gl.getProgramParameter(prog, gl.LINK_STATUS) == false) |
michael@0 | 207 | debug(infolog); |
michael@0 | 208 | if (gl.getError() != gl.NO_ERROR) |
michael@0 | 209 | assertMsg(false, "unexpected error in getProgramParameter()"); |
michael@0 | 210 | gl.useProgram(prog); |
michael@0 | 211 | if (expected_status == true) |
michael@0 | 212 | glErrorShouldBe(gl, gl.NO_ERROR, "using a valid program should succeed"); |
michael@0 | 213 | if (expected_status == false) |
michael@0 | 214 | glErrorShouldBe(gl, gl.INVALID_OPERATION, "using an invalid program should generate INVALID_OPERATION"); |
michael@0 | 215 | return prog; |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | var progGood1 = checkLinkAndUse([vs, fs], false, true, "valid program should link"); |
michael@0 | 219 | var progGood2 = checkLinkAndUse([vs, fs2], false, true, "valid program #2 should link"); |
michael@0 | 220 | var progBad1 = checkLinkAndUse([vs], false, false, "program with no fragment shader should fail to link"); |
michael@0 | 221 | var progBad2 = checkLinkAndUse([fs], false, false, "program with no vertex shader should fail to link"); |
michael@0 | 222 | var progBad3 = checkLinkAndUse([vsBad, fs], false, false, "program with bad vertex shader should fail to link"); |
michael@0 | 223 | var progBad4 = checkLinkAndUse([vs, fsBad], false, false, "program with bad fragment shader should fail to link"); |
michael@0 | 224 | var progBad5 = checkLinkAndUse([vsBad, fsBad], false, false, "program with bad shaders should fail to link"); |
michael@0 | 225 | |
michael@0 | 226 | gl.useProgram(progGood1); |
michael@0 | 227 | glErrorShouldBe(gl, gl.NO_ERROR, "using a valid program shouldn't generate a GL error"); |
michael@0 | 228 | |
michael@0 | 229 | var vbuf = gl.createBuffer(); |
michael@0 | 230 | gl.bindBuffer(gl.ARRAY_BUFFER, vbuf); |
michael@0 | 231 | gl.bufferData(gl.ARRAY_BUFFER, |
michael@0 | 232 | new Float32Array([ |
michael@0 | 233 | 0.0, 0.0, 0.0, 1.0, |
michael@0 | 234 | 1.0, 0.0, 0.0, 1.0, |
michael@0 | 235 | 1.0, 1.0, 0.0, 1.0, |
michael@0 | 236 | 0.0, 1.0, 0.0, 1.0]), |
michael@0 | 237 | gl.STATIC_DRAW); |
michael@0 | 238 | gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0); |
michael@0 | 239 | gl.enableVertexAttribArray(0); |
michael@0 | 240 | gl.vertexAttrib3f(1, 1.0, 0.0, 0.0); |
michael@0 | 241 | |
michael@0 | 242 | glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors at this point #2"); |
michael@0 | 243 | |
michael@0 | 244 | gl.useProgram(progGood1); |
michael@0 | 245 | gl.drawArrays(gl.TRIANGLES, 0, 3); |
michael@0 | 246 | glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid program shouldn't generate a GL error"); |
michael@0 | 247 | |
michael@0 | 248 | gl.useProgram(progBad1); |
michael@0 | 249 | glErrorShouldBe(gl, gl.INVALID_OPERATION, "using an invalid program should generate INVALID_OPERATION"); |
michael@0 | 250 | gl.drawArrays(gl.TRIANGLES, 0, 3); |
michael@0 | 251 | glErrorShouldBe(gl, gl.NO_ERROR, "Try to use an invalid program should not change the current rendering state"); |
michael@0 | 252 | |
michael@0 | 253 | gl.useProgram(progGood2); |
michael@0 | 254 | gl.drawArrays(gl.TRIANGLES, 0, 3); |
michael@0 | 255 | glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid program shouldn't generate a GL error"); |
michael@0 | 256 | gl.detachShader(progGood2, fs2); |
michael@0 | 257 | gl.attachShader(progGood2, fsBad); |
michael@0 | 258 | gl.linkProgram(progGood2); |
michael@0 | 259 | assertMsg(gl.getProgramParameter(progGood2, gl.LINK_STATUS) == false, |
michael@0 | 260 | "linking should fail with in-use formerly good program, with new bad shader attached"); |
michael@0 | 261 | |
michael@0 | 262 | // Invalid link leaves previous valid program intact. |
michael@0 | 263 | gl.drawArrays(gl.TRIANGLES, 0, 3); |
michael@0 | 264 | glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid program shouldn't generate a GL error"); |
michael@0 | 265 | |
michael@0 | 266 | gl.useProgram(progGood1); |
michael@0 | 267 | gl.drawArrays(gl.TRIANGLES, 0, 4); |
michael@0 | 268 | glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid when last used program shouldn't generate a GL error"); |
michael@0 | 269 | |
michael@0 | 270 | var progGood1 = checkLinkAndUse([vs, fs], true, true, "delete shaders after attaching them and before linking program should not affect linkProgram"); |
michael@0 | 271 | gl.useProgram(progGood1); |
michael@0 | 272 | gl.drawArrays(gl.TRIANGLES, 0, 4); |
michael@0 | 273 | glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid when last used program shouldn't generate a GL error"); |
michael@0 | 274 | |
michael@0 | 275 | /////// Check deleteProgram() and deleteShader() ///////////////////////////// |
michael@0 | 276 | |
michael@0 | 277 | gl.useProgram(progGood1); |
michael@0 | 278 | gl.deleteProgram(progGood1); |
michael@0 | 279 | gl.drawArrays(gl.TRIANGLES, 0, 4); |
michael@0 | 280 | glErrorShouldBe(gl, gl.NO_ERROR, "delete the current program shouldn't change the current rendering state"); |
michael@0 | 281 | |
michael@0 | 282 | gl.linkProgram(progGood1); |
michael@0 | 283 | glErrorShouldBe(gl, gl.NO_ERROR, "The current program shouldn't be deleted"); |
michael@0 | 284 | |
michael@0 | 285 | var fs3 = gl.createShader(gl.FRAGMENT_SHADER); |
michael@0 | 286 | gl.shaderSource(fs3, "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }"); |
michael@0 | 287 | gl.compileShader(fs3); |
michael@0 | 288 | |
michael@0 | 289 | assertMsg(gl.getShaderParameter(fs3, gl.COMPILE_STATUS) == true, |
michael@0 | 290 | "good fragment shader should compile"); |
michael@0 | 291 | |
michael@0 | 292 | gl.deleteShader(fs3); |
michael@0 | 293 | gl.compileShader(fs3); |
michael@0 | 294 | glErrorShouldBe(gl, gl.INVALID_VALUE, "an unattached shader should be deleted immediately"); |
michael@0 | 295 | |
michael@0 | 296 | fs3 = gl.createShader(gl.FRAGMENT_SHADER); |
michael@0 | 297 | gl.shaderSource(fs3, "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }"); |
michael@0 | 298 | gl.compileShader(fs3); |
michael@0 | 299 | |
michael@0 | 300 | assertMsg(gl.getShaderParameter(fs3, gl.COMPILE_STATUS) == true, |
michael@0 | 301 | "good fragment shader should compile"); |
michael@0 | 302 | |
michael@0 | 303 | gl.detachShader(progGood1, fs); |
michael@0 | 304 | gl.attachShader(progGood1, fs3); |
michael@0 | 305 | |
michael@0 | 306 | gl.deleteShader(fs3); |
michael@0 | 307 | gl.compileShader(fs3); |
michael@0 | 308 | assertMsg(gl.getShaderParameter(fs3, gl.COMPILE_STATUS) == true, |
michael@0 | 309 | "an attached shader shouldn't be deleted"); |
michael@0 | 310 | |
michael@0 | 311 | gl.useProgram(null); |
michael@0 | 312 | gl.linkProgram(progGood1); |
michael@0 | 313 | glErrorShouldBe(gl, gl.INVALID_VALUE, "a delete-marked program should be deleted once it's no longer the current program"); |
michael@0 | 314 | |
michael@0 | 315 | gl.compileShader(fs3); |
michael@0 | 316 | glErrorShouldBe(gl, gl.INVALID_VALUE, "a delete-marked shader should be deleted once all its attachments are removed"); |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | debug(""); |
michael@0 | 320 | go(); |
michael@0 | 321 | |
michael@0 | 322 | successfullyParsed = true; |
michael@0 | 323 | </script> |
michael@0 | 324 | <script>finishTest();</script> |
michael@0 | 325 | |
michael@0 | 326 | </body> |
michael@0 | 327 | </html> |