Bug 1932347 - Adjust positioning of tab preview for vertical tabs r=tabbrowser-review...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / js / glsl-conformance-test.js
blob12a056ce214498919a3b95f9a36d6e97e64112d6
1 /*
2 Copyright (c) 2019 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 GLSLConformanceTester = (function(){
8 var wtu = WebGLTestUtils;
9 var defaultVertexShader = [
10   "attribute vec4 vPosition;",
11   "void main()",
12   "{",
13   "    gl_Position = vPosition;",
14   "}"
15 ].join('\n');
17 var defaultFragmentShader = [
18   "precision mediump float;",
19   "void main()",
20   "{",
21   "    gl_FragColor = vec4(1.0,0.0,0.0,1.0);",
22   "}"
23 ].join('\n');
25 var defaultESSL3VertexShader = [
26   "#version 300 es",
27   "in vec4 vPosition;",
28   "void main()",
29   "{",
30   "    gl_Position = vPosition;",
31   "}"
32 ].join('\n');
34 var defaultESSL3FragmentShader = [
35   "#version 300 es",
36   "precision mediump float;",
37   "out vec4 my_FragColor;",
38   "void main()",
39   "{",
40   "    my_FragColor = vec4(1.0,0.0,0.0,1.0);",
41   "}"
42 ].join('\n');
44 function log(msg) {
45   bufferedLogToConsole(msg);
48 var vShaderDB = {};
49 var fShaderDB = {};
51 /**
52  * The info parameter should contain the following keys. Note that you may leave
53  * the parameters for one shader out, in which case the default shader will be
54  * used.
55  * vShaderSource: the source code for vertex shader
56  * vShaderId: id of an element containing vertex shader source code. Used if
57  *   vShaderSource is not specified.
58  * vShaderSuccess: true if vertex shader compilation should
59  *   succeed.
60  * fShaderSource: the source code for fragment shader
61  * fShaderId: id of an element containing fragment shader source code. Used if
62  *   fShaderSource is not specified.
63  * fShaderSuccess: true if fragment shader compilation should
64  *   succeed.
65  * linkSuccess: true if link should succeed
66  * passMsg: msg to describe success condition.
67  * render: if true render to unit quad. Green = success
68  * uniforms: an array of objects specifying uniforms to set prior to rendering.
69  *   Each object should have the following keys:
70  *     name: uniform variable name in the shader source. Uniform location will
71  *       be queried based on its name.
72  *     functionName: name of the function used to set the uniform. For example:
73  *       'uniform1i'
74  *     value: value of the uniform to set.
75  */
76 function runOneTest(gl, info) {
77   var passMsg = info.passMsg
78   debug("");
79   debug("test: " + passMsg);
81   var consoleDiv = document.getElementById("console");
83   var vIsDefault = false;
84   var fIsDefault = false;
86   if (info.vShaderSource === undefined) {
87     if (info.vShaderId) {
88       info.vShaderSource = document.getElementById(info.vShaderId).text;
89     } else {
90       vIsDefault = true;
91     }
92   }
93   if (info.fShaderSource === undefined) {
94     if (info.fShaderId) {
95       info.fShaderSource = document.getElementById(info.fShaderId).text;
96     } else {
97       fIsDefault = true;
98     }
99   }
101   var vLabel = (vIsDefault ? "default" : "test") + " vertex shader";
102   var fLabel = (fIsDefault ? "default" : "test") + " fragment shader";
103   if (vIsDefault) {
104     info.vShaderSource = defaultVertexShader;
105     info.vShaderSuccess = true;
106   }
107   if (fIsDefault) {
108     info.fShaderSource = defaultFragmentShader;
109     info.fShaderSuccess = true;
110   }
112   if (vIsDefault != fIsDefault) {
113     // The language version of the default shader is chosen
114     // according to the language version of the other shader.
115     // We rely on "#version 300 es" being in this usual format.
116     // It must be on the first line of the shader according to the spec.
117     if (fIsDefault) {
118       // If we're using the default fragment shader, we need to make sure that
119       // it's language version matches with the vertex shader.
120       if (info.vShaderSource.split('\n')[0] == '#version 300 es') {
121         info.fShaderSource = defaultESSL3FragmentShader;
122       }
123     } else {
124       // If we're using the default vertex shader, we need to make sure that
125       // it's language version matches with the fragment shader.
126       if (info.fShaderSource.split('\n')[0] == '#version 300 es') {
127         info.vShaderSource = defaultESSL3VertexShader;
128       }
129     }
130   }
132   var vSource = info.vShaderPrep ? info.vShaderPrep(info.vShaderSource) :
133     info.vShaderSource;
135   if (!quietMode()) {
136     wtu.addShaderSource(consoleDiv, vLabel, vSource);
137   }
139   // Reuse identical shaders so we test shared shader.
140   var vShader = vShaderDB[vSource];
141   if (!vShader) {
142     // loadShader, with opt_skipCompileStatus: true.
143     vShader = wtu.loadShader(gl, vSource, gl.VERTEX_SHADER, null, null, null, null, true);
144     let compiledVShader = vShader;
145     if (vShader && !gl.getShaderParameter(vShader, gl.COMPILE_STATUS)) {
146       compiledVShader = null;
147     }
148     if (info.vShaderTest) {
149       if (!info.vShaderTest(compiledVShader)) {
150         testFailed("[vertex shader test] " + passMsg);
151         return;
152       }
153     }
154     // As per GLSL 1.0.17 10.27 we can only check for success on
155     // compileShader, not failure.
156     if (!info.ignoreResults && info.vShaderSuccess && !compiledVShader) {
157       testFailed("[unexpected vertex shader compile status] (expected: " +
158                  info.vShaderSuccess + ") " + passMsg);
159       if (!quietMode() && vShader) {
160         const info = gl.getShaderInfoLog(vShader);
161         wtu.addShaderSource(consoleDiv, vLabel + " info log", info);
162       }
163     }
164     // Save the shaders so we test shared shader.
165     if (compiledVShader) {
166       vShaderDB[vSource] = compiledVShader;
167     } else {
168       vShader = null;
169     }
170   }
172   var debugShaders = gl.getExtension('WEBGL_debug_shaders');
173   if (debugShaders && vShader && !quietMode()) {
174     wtu.addShaderSource(consoleDiv, vLabel + " translated for driver",
175                         debugShaders.getTranslatedShaderSource(vShader));
176   }
178   var fSource = info.fShaderPrep ? info.fShaderPrep(info.fShaderSource) :
179     info.fShaderSource;
181   if (!quietMode()) {
182     wtu.addShaderSource(consoleDiv, fLabel, fSource);
183   }
185   // Reuse identical shaders so we test shared shader.
186   var fShader = fShaderDB[fSource];
187   if (!fShader) {
188     // loadShader, with opt_skipCompileStatus: true.
189     fShader = wtu.loadShader(gl, fSource, gl.FRAGMENT_SHADER, null, null, null, null, true);
190     let compiledFShader = fShader;
191     if (fShader && !gl.getShaderParameter(fShader, gl.COMPILE_STATUS)) {
192       compiledFShader = null;
193     }
194     if (info.fShaderTest) {
195       if (!info.fShaderTest(compiledFShader)) {
196         testFailed("[fragment shader test] " + passMsg);
197         return;
198       }
199     }
200     //debug(fShader == null ? "fail" : "succeed");
201     // As per GLSL 1.0.17 10.27 we can only check for success on
202     // compileShader, not failure.
203     if (!info.ignoreResults && info.fShaderSuccess && !compiledFShader) {
204       testFailed("[unexpected fragment shader compile status] (expected: " +
205                 info.fShaderSuccess + ") " + passMsg);
206       if (!quietMode() && fShader) {
207         const info = gl.getShaderInfoLog(fShader);
208         wtu.addShaderSource(consoleDiv, fLabel + " info log", info);
209       }
210       return;
211     }
213     // Safe the shaders so we test shared shader.
214     if (compiledFShader) {
215       fShaderDB[fSource] = compiledFShader;
216     } else {
217       fShader = null;
218     }
219   }
221   if (debugShaders && fShader && !quietMode()) {
222     wtu.addShaderSource(consoleDiv, fLabel + " translated for driver",
223                         debugShaders.getTranslatedShaderSource(fShader));
224   }
226   if (vShader && fShader) {
227     var program = gl.createProgram();
228     gl.attachShader(program, vShader);
229     gl.attachShader(program, fShader);
231     if (vSource.indexOf("vPosition") >= 0) {
232       gl.bindAttribLocation(program, 0, "vPosition");
233     }
234     if (vSource.indexOf("texCoord0") >= 0) {
235       gl.bindAttribLocation(program, 1, "texCoord0");
236     }
237     gl.linkProgram(program);
238     var linked = (gl.getProgramParameter(program, gl.LINK_STATUS) != 0);
239     if (!linked) {
240       var error = gl.getProgramInfoLog(program);
241       log("*** Error linking program '"+program+"':"+error);
242     }
243     if (!info.ignoreResults && linked != info.linkSuccess) {
244       testFailed("[unexpected link status] (expected: " +
245                 info.linkSuccess + ") " + passMsg);
246       return;
247     }
248   } else {
249     if (!info.ignoreResults && info.linkSuccess) {
250       testFailed("[link failed] " + passMsg);
251       return;
252     }
253   }
255   if (parseInt(wtu.getUrlOptions().dumpShaders)) {
256     var vInfo = {
257       shader: vShader,
258       shaderSuccess: info.vShaderSuccess,
259       label: vLabel,
260       source: vSource
261     };
262     var fInfo = {
263       shader: fShader,
264       shaderSuccess: info.fShaderSuccess,
265       label: fLabel,
266       source: fSource
267     };
268     wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vInfo, fInfo);
269   }
271   if (!info.render) {
272     testPassed(passMsg);
273     return;
274   }
276   gl.useProgram(program);
278   if (info.uniforms !== undefined) {
279     for (var i = 0; i < info.uniforms.length; ++i) {
280       var uniform = info.uniforms[i];
281       var uniformLocation = gl.getUniformLocation(program, uniform.name);
282       if (uniformLocation !== null) {
283         if (uniform.functionName.includes("Matrix")) {
284           gl[uniform.functionName](uniformLocation, false, uniform.value);
285         } else {
286           gl[uniform.functionName](uniformLocation, uniform.value);
287         }
288         debug(uniform.name + ' set to ' + uniform.value);
289       } else {
290         debug('uniform ' + uniform.name + ' had null location and was not set');
291       }
292     }
293   }
295   if (info.uniformBlocks !== undefined) {
296     for (var i = 0; i < info.uniformBlocks.length; ++i) {
297       var uniformBlockIndex = gl.getUniformBlockIndex(program, info.uniformBlocks[i].name);
298       if (uniformBlockIndex !== null) {
299         gl.uniformBlockBinding(program, uniformBlockIndex, i);
300         debug(info.uniformBlocks[i].name + ' (index ' + uniformBlockIndex + ') bound to slot ' + i);
302         var uboValueBuffer = gl.createBuffer();
303         gl.bindBufferBase(gl.UNIFORM_BUFFER, i, uboValueBuffer);
304         gl.bufferData(gl.UNIFORM_BUFFER, info.uniformBlocks[i].value, info.uniformBlocks[i].usage || gl.STATIC_DRAW);
305       } else {
306         debug('uniform block' + info.uniformBlocks[i].name + ' had null block index and was not set');
307       }
308     }
309   }
311   wtu.setupUnitQuad(gl);
312   wtu.clearAndDrawUnitQuad(gl);
314   var div = document.createElement("div");
315   div.className = "testimages";
316   wtu.insertImage(div, "result", wtu.makeImageFromCanvas(gl.canvas));
317   div.appendChild(document.createElement('br'));
318   consoleDiv.appendChild(div);
320   var tolerance = 0;
321   if (info.renderTolerance !== undefined) {
322     tolerance = info.renderTolerance;
323   }
324   if (info.renderColor !== undefined) {
325     wtu.checkCanvas(gl, info.renderColor, "should be expected color " + info.renderColor, tolerance);
326   } else {
327     wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green", tolerance);
328   }
331 function runTests(shaderInfos, opt_contextVersion) {
332   var wtu = WebGLTestUtils;
333   var canvas = document.createElement('canvas');
334   canvas.width = 32;
335   canvas.height = 32;
336   var gl = wtu.create3DContext(canvas, undefined, opt_contextVersion);
337   if (!gl) {
338     testFailed("context does not exist");
339     finishTest();
340     return;
341   }
343   for (var i = 0; i < shaderInfos.length; i++) {
344     runOneTest(gl, shaderInfos[i]);
345   }
347   finishTest();
350 function getSource(elem) {
351   var str = elem.text;
352   return str.replace(/^\s*/, '').replace(/\s*$/, '');
355 function getPassMessage(source) {
356   var lines = source.split('\n');
357   return lines[0].substring(3);
360 function getSuccess(msg) {
361   if (msg.indexOf("fail") >= 0) {
362     return false;
363   }
364   if (msg.indexOf("succeed") >= 0) {
365     return true;
366   }
367   testFailed("bad test description. Must have 'fail' or 'succeed'");
370 function setupTest() {
371   var info = {};
373   var vShaderElem = document.getElementById('vertexShader');
374   if (vShaderElem) {
375     info.vShaderSource = getSource(vShaderElem);
376     info.passMsg = getPassMessage(info.vShaderSource);
377     info.vShaderSuccess = getSuccess(info.passMsg);
378   }
380   var fShaderElem = document.getElementById('fragmentShader');
381   if (fShaderElem) {
382     info.fShaderSource = getSource(fShaderElem);
383     info.passMsg = getPassMessage(info.fShaderSource);
384     info.fShaderSuccess = getSuccess(info.passMsg);
385   }
387   // linkSuccess should be true if shader success value is undefined or true for both shaders.
388   info.linkSuccess = info.vShaderSuccess !== false && info.fShaderSuccess !== false;
390   if (info.passMsg === undefined) {
391     testFailed("no test shader found.");
392     finishTest();
393     return;
394   }
396   return info;
399 function runTest() {
400   var info = setupTest();
401   description(info.passMsg);
402   runTests([info]);
405 function runRenderTests(tests, opt_contextVersion) {
406   for (var ii = 0; ii < tests.length; ++ii) {
407     tests[ii].render = true
408   }
409   runTests(tests, opt_contextVersion);
412 function runRenderTest() {
413   var info = setupTest();
414   description(info.passMsg);
415   runRenderTests([info]);
418 return {
419   runTest: runTest,
420   runTests: runTests,
421   runRenderTest: runRenderTest,
422   runRenderTests: runRenderTests
424 }());