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.
6 GLSLConformanceTester = (function(){
8 var wtu = WebGLTestUtils;
9 var defaultVertexShader = [
10 "attribute vec4 vPosition;",
13 " gl_Position = vPosition;",
17 var defaultFragmentShader = [
18 "precision mediump float;",
21 " gl_FragColor = vec4(1.0,0.0,0.0,1.0);",
25 var defaultESSL3VertexShader = [
30 " gl_Position = vPosition;",
34 var defaultESSL3FragmentShader = [
36 "precision mediump float;",
37 "out vec4 my_FragColor;",
40 " my_FragColor = vec4(1.0,0.0,0.0,1.0);",
45 bufferedLogToConsole(msg);
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
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
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
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:
74 * value: value of the uniform to set.
76 function runOneTest(gl, info) {
77 var passMsg = info.passMsg
79 debug("test: " + passMsg);
81 var consoleDiv = document.getElementById("console");
83 var vIsDefault = false;
84 var fIsDefault = false;
86 if (info.vShaderSource === undefined) {
88 info.vShaderSource = document.getElementById(info.vShaderId).text;
93 if (info.fShaderSource === undefined) {
95 info.fShaderSource = document.getElementById(info.fShaderId).text;
101 var vLabel = (vIsDefault ? "default" : "test") + " vertex shader";
102 var fLabel = (fIsDefault ? "default" : "test") + " fragment shader";
104 info.vShaderSource = defaultVertexShader;
105 info.vShaderSuccess = true;
108 info.fShaderSource = defaultFragmentShader;
109 info.fShaderSuccess = true;
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.
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;
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;
132 var vSource = info.vShaderPrep ? info.vShaderPrep(info.vShaderSource) :
136 wtu.addShaderSource(consoleDiv, vLabel, vSource);
139 // Reuse identical shaders so we test shared shader.
140 var vShader = vShaderDB[vSource];
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;
148 if (info.vShaderTest) {
149 if (!info.vShaderTest(compiledVShader)) {
150 testFailed("[vertex shader test] " + passMsg);
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);
164 // Save the shaders so we test shared shader.
165 if (compiledVShader) {
166 vShaderDB[vSource] = compiledVShader;
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));
178 var fSource = info.fShaderPrep ? info.fShaderPrep(info.fShaderSource) :
182 wtu.addShaderSource(consoleDiv, fLabel, fSource);
185 // Reuse identical shaders so we test shared shader.
186 var fShader = fShaderDB[fSource];
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;
194 if (info.fShaderTest) {
195 if (!info.fShaderTest(compiledFShader)) {
196 testFailed("[fragment shader test] " + passMsg);
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);
213 // Safe the shaders so we test shared shader.
214 if (compiledFShader) {
215 fShaderDB[fSource] = compiledFShader;
221 if (debugShaders && fShader && !quietMode()) {
222 wtu.addShaderSource(consoleDiv, fLabel + " translated for driver",
223 debugShaders.getTranslatedShaderSource(fShader));
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");
234 if (vSource.indexOf("texCoord0") >= 0) {
235 gl.bindAttribLocation(program, 1, "texCoord0");
237 gl.linkProgram(program);
238 var linked = (gl.getProgramParameter(program, gl.LINK_STATUS) != 0);
240 var error = gl.getProgramInfoLog(program);
241 log("*** Error linking program '"+program+"':"+error);
243 if (!info.ignoreResults && linked != info.linkSuccess) {
244 testFailed("[unexpected link status] (expected: " +
245 info.linkSuccess + ") " + passMsg);
249 if (!info.ignoreResults && info.linkSuccess) {
250 testFailed("[link failed] " + passMsg);
255 if (parseInt(wtu.getUrlOptions().dumpShaders)) {
258 shaderSuccess: info.vShaderSuccess,
264 shaderSuccess: info.fShaderSuccess,
268 wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vInfo, fInfo);
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);
286 gl[uniform.functionName](uniformLocation, uniform.value);
288 debug(uniform.name + ' set to ' + uniform.value);
290 debug('uniform ' + uniform.name + ' had null location and was not set');
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);
306 debug('uniform block' + info.uniformBlocks[i].name + ' had null block index and was not set');
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);
321 if (info.renderTolerance !== undefined) {
322 tolerance = info.renderTolerance;
324 if (info.renderColor !== undefined) {
325 wtu.checkCanvas(gl, info.renderColor, "should be expected color " + info.renderColor, tolerance);
327 wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green", tolerance);
331 function runTests(shaderInfos, opt_contextVersion) {
332 var wtu = WebGLTestUtils;
333 var canvas = document.createElement('canvas');
336 var gl = wtu.create3DContext(canvas, undefined, opt_contextVersion);
338 testFailed("context does not exist");
343 for (var i = 0; i < shaderInfos.length; i++) {
344 runOneTest(gl, shaderInfos[i]);
350 function getSource(elem) {
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) {
364 if (msg.indexOf("succeed") >= 0) {
367 testFailed("bad test description. Must have 'fail' or 'succeed'");
370 function setupTest() {
373 var vShaderElem = document.getElementById('vertexShader');
375 info.vShaderSource = getSource(vShaderElem);
376 info.passMsg = getPassMessage(info.vShaderSource);
377 info.vShaderSuccess = getSuccess(info.passMsg);
380 var fShaderElem = document.getElementById('fragmentShader');
382 info.fShaderSource = getSource(fShaderElem);
383 info.passMsg = getPassMessage(info.fShaderSource);
384 info.fShaderSuccess = getSuccess(info.passMsg);
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.");
400 var info = setupTest();
401 description(info.passMsg);
405 function runRenderTests(tests, opt_contextVersion) {
406 for (var ii = 0; ii < tests.length; ++ii) {
407 tests[ii].render = true
409 runTests(tests, opt_contextVersion);
412 function runRenderTest() {
413 var info = setupTest();
414 description(info.passMsg);
415 runRenderTests([info]);
421 runRenderTest: runRenderTest,
422 runRenderTests: runRenderTests