|
1 GLSLConformanceTester = (function(){ |
|
2 |
|
3 var wtu = WebGLTestUtils; |
|
4 var defaultVertexShader = [ |
|
5 "attribute vec4 vPosition;", |
|
6 "void main()", |
|
7 "{", |
|
8 " gl_Position = vPosition;", |
|
9 "}" |
|
10 ].join('\n'); |
|
11 |
|
12 var defaultFragmentShader = [ |
|
13 "precision mediump float;", |
|
14 "void main()", |
|
15 "{", |
|
16 " gl_FragColor = vec4(1.0,0.0,0.0,1.0);", |
|
17 "}" |
|
18 ].join('\n'); |
|
19 |
|
20 function log(msg) { |
|
21 if (window.console && window.console.log) { |
|
22 window.console.log(msg); |
|
23 } |
|
24 } |
|
25 |
|
26 var vShaderDB = {}; |
|
27 var fShaderDB = {}; |
|
28 |
|
29 /** |
|
30 * vShaderSource: the source code for vertex shader |
|
31 * vShaderSuccess: true if vertex shader compiliation should |
|
32 * succeed. |
|
33 * fShaderSource: the source code for fragment shader |
|
34 * fShaderSuccess: true if fragment shader compiliation should |
|
35 * succeed. |
|
36 * linkSuccess: true of link should succeed |
|
37 * passMsg: msg to describe success condition. |
|
38 * render: if true render to unit quad. Green = success |
|
39 * |
|
40 */ |
|
41 function runOneTest(gl, info) { |
|
42 var passMsg = info.passMsg |
|
43 debug("test: " + passMsg); |
|
44 |
|
45 var console = document.getElementById("console"); |
|
46 |
|
47 if (info.vShaderSource === undefined) { |
|
48 if (info.vShaderId) { |
|
49 info.vShaderSource = document.getElementById(info.vShaderId).text; |
|
50 } else { |
|
51 info.vShader = 'defaultVertexShader'; |
|
52 info.vShaderSource = defaultVertexShader; |
|
53 } |
|
54 } |
|
55 if (info.fShaderSource === undefined) { |
|
56 if (info.fShaderId) { |
|
57 info.fShaderSource = document.getElementById(info.fShaderId).text; |
|
58 } else { |
|
59 info.fShader = 'defaultFragmentShader'; |
|
60 info.fShaderSource = defaultFragmentShader; |
|
61 } |
|
62 } |
|
63 |
|
64 var vLabel = (info.vShaderSource == defaultVertexShader ? "default" : "test") + " vertex shader"; |
|
65 var fLabel = (info.fShaderSource == defaultFragmentShader ? "default" : "test") + " fragment shader"; |
|
66 |
|
67 var vSource = info.vShaderPrep ? info.vShaderPrep(info.vShaderSource) : |
|
68 info.vShaderSource; |
|
69 |
|
70 wtu.addShaderSource(console, vLabel, vSource); |
|
71 |
|
72 // Reuse identical shaders so we test shared shader. |
|
73 var vShader = vShaderDB[vSource]; |
|
74 if (!vShader) { |
|
75 vShader = wtu.loadShader(gl, vSource, gl.VERTEX_SHADER); |
|
76 if (info.vShaderTest) { |
|
77 if (!info.vShaderTest(vShader)) { |
|
78 testFailed("[vertex shader test] " + passMsg); |
|
79 return; |
|
80 } |
|
81 } |
|
82 // As per GLSL 1.0.17 10.27 we can only check for success on |
|
83 // compileShader, not failure. |
|
84 if (info.vShaderSuccess && !vShader) { |
|
85 testFailed("[unexpected vertex shader compile status] (expected: " + |
|
86 info.vShaderSuccess + ") " + passMsg); |
|
87 } |
|
88 // Save the shaders so we test shared shader. |
|
89 if (vShader) { |
|
90 vShaderDB[vSource] = vShader; |
|
91 } |
|
92 } |
|
93 |
|
94 var fSource = info.fShaderPrep ? info.fShaderPrep(info.fShaderSource) : |
|
95 info.fShaderSource; |
|
96 |
|
97 wtu.addShaderSource(console, fLabel, fSource); |
|
98 |
|
99 // Reuse identical shaders so we test shared shader. |
|
100 var fShader = fShaderDB[fSource]; |
|
101 if (!fShader) { |
|
102 fShader = wtu.loadShader(gl, fSource, gl.FRAGMENT_SHADER); |
|
103 if (info.fShaderTest) { |
|
104 if (!info.fShaderTest(fShader)) { |
|
105 testFailed("[fragment shdaer test] " + passMsg); |
|
106 return; |
|
107 } |
|
108 } |
|
109 //debug(fShader == null ? "fail" : "succeed"); |
|
110 // As per GLSL 1.0.17 10.27 we can only check for success on |
|
111 // compileShader, not failure. |
|
112 if (info.fShaderSuccess && !fShader) { |
|
113 testFailed("[unexpected fragment shader compile status] (expected: " + |
|
114 info.fShaderSuccess + ") " + passMsg); |
|
115 return; |
|
116 } |
|
117 // Safe the shaders so we test shared shader. |
|
118 if (fShader) { |
|
119 fShaderDB[fSource] = fShader; |
|
120 } |
|
121 } |
|
122 |
|
123 if (vShader && fShader) { |
|
124 var program = gl.createProgram(); |
|
125 gl.attachShader(program, vShader); |
|
126 gl.attachShader(program, fShader); |
|
127 gl.bindAttribLocation(program, 0, "vPosition"); |
|
128 gl.bindAttribLocation(program, 1, "texCoord0"); |
|
129 gl.linkProgram(program); |
|
130 var linked = (gl.getProgramParameter(program, gl.LINK_STATUS) != 0); |
|
131 if (!linked) { |
|
132 var error = gl.getProgramInfoLog(program); |
|
133 log("*** Error linking program '"+program+"':"+error); |
|
134 } |
|
135 if (linked != info.linkSuccess) { |
|
136 testFailed("[unexpected link status] " + passMsg); |
|
137 return; |
|
138 } |
|
139 } else { |
|
140 if (info.linkSuccess) { |
|
141 testFailed("[link failed] " + passMsg); |
|
142 return; |
|
143 } |
|
144 } |
|
145 |
|
146 if (!info.render) { |
|
147 testPassed(passMsg); |
|
148 return; |
|
149 } |
|
150 |
|
151 gl.useProgram(program); |
|
152 wtu.setupUnitQuad(gl); |
|
153 wtu.drawQuad(gl); |
|
154 |
|
155 var div = document.createElement("div"); |
|
156 div.className = "testimages"; |
|
157 wtu.insertImage(div, "result", wtu.makeImage(gl.canvas)); |
|
158 div.appendChild(document.createElement('br')); |
|
159 console.appendChild(div); |
|
160 wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green", 0); |
|
161 } |
|
162 |
|
163 function runTests(shaderInfos) { |
|
164 var wtu = WebGLTestUtils; |
|
165 var canvas = document.createElement('canvas'); |
|
166 canvas.width = 32; |
|
167 canvas.height = 32; |
|
168 var gl = wtu.create3DContext(canvas); |
|
169 if (!gl) { |
|
170 testFailed("context does not exist"); |
|
171 finishTest(); |
|
172 return; |
|
173 } |
|
174 |
|
175 for (var ii = 0; ii < shaderInfos.length; ++ii) { |
|
176 runOneTest(gl, shaderInfos[ii]); |
|
177 } |
|
178 |
|
179 finishTest(); |
|
180 }; |
|
181 |
|
182 function loadExternalShaders(filename, passMsg) { |
|
183 var shaderInfos = []; |
|
184 var lines = wtu.readFileList(filename); |
|
185 for (var ii = 0; ii < lines.length; ++ii) { |
|
186 var info = { |
|
187 vShaderSource: defaultVertexShader, |
|
188 vShaderSuccess: true, |
|
189 fShaderSource: defaultFragmentShader, |
|
190 fShaderSuccess: true, |
|
191 linkSuccess: true, |
|
192 }; |
|
193 |
|
194 var line = lines[ii]; |
|
195 var files = line.split(/ +/); |
|
196 var passMsg = ""; |
|
197 for (var jj = 0; jj < files.length; ++jj) { |
|
198 var file = files[jj]; |
|
199 var shaderSource = wtu.readFile(file); |
|
200 var firstLine = shaderSource.split("\n")[0]; |
|
201 var success = undefined; |
|
202 if (firstLine.indexOf("fail") >= 0) { |
|
203 success = false; |
|
204 } else if (firstLine.indexOf("succeed") >= 0) { |
|
205 success = true; |
|
206 } |
|
207 if (success === undefined) { |
|
208 testFailed("bad first line in " + file + ":" + firstLine); |
|
209 continue; |
|
210 } |
|
211 if (!wtu.startsWith(firstLine, "// ")) { |
|
212 testFailed("bad first line in " + file + ":" + firstLine); |
|
213 continue; |
|
214 } |
|
215 passMsg = passMsg + (passMsg.length ? ", " : "") + firstLine.substr(3); |
|
216 if (wtu.endsWith(file, ".vert")) { |
|
217 info.vShaderSource = shaderSource; |
|
218 info.vShaderSuccess = success; |
|
219 } else if (wtu.endsWith(file, ".frag")) { |
|
220 info.fShaderSource = shaderSource; |
|
221 info.fShaderSuccess = success; |
|
222 } |
|
223 } |
|
224 info.linkSuccess = info.vShaderSuccess && info.fShaderSuccess; |
|
225 info.passMsg = passMsg; |
|
226 shaderInfos.push(info); |
|
227 } |
|
228 return shaderInfos; |
|
229 } |
|
230 |
|
231 function getSource(elem) { |
|
232 var str = elem.text; |
|
233 return str.replace(/^\s*/, '').replace(/\s*$/, ''); |
|
234 } |
|
235 |
|
236 function getPassMessage(source) { |
|
237 var lines = source.split('\n'); |
|
238 return lines[0].substring(3); |
|
239 } |
|
240 |
|
241 function getSuccess(msg) { |
|
242 if (msg.indexOf("fail") >= 0) { |
|
243 return false; |
|
244 } |
|
245 if (msg.indexOf("succeed") >= 0) { |
|
246 return true; |
|
247 } |
|
248 testFailed("bad test description. Must have 'fail' or 'success'"); |
|
249 } |
|
250 |
|
251 function setupTest() { |
|
252 var vShaderElem = document.getElementById('vertexShader'); |
|
253 var vShaderSource = defaultVertexShader; |
|
254 var vShaderSuccess = true; |
|
255 |
|
256 var fShaderElem = document.getElementById('fragmentShader'); |
|
257 var fShaderSource = defaultFragmentShader; |
|
258 var fShaderSuccess = true; |
|
259 |
|
260 var passMsg = undefined; |
|
261 |
|
262 if (vShaderElem) { |
|
263 vShaderSource = getSource(vShaderElem); |
|
264 passMsg = getPassMessage(vShaderSource); |
|
265 vShaderSuccess = getSuccess(passMsg); |
|
266 } |
|
267 |
|
268 if (fShaderElem) { |
|
269 fShaderSource = getSource(fShaderElem); |
|
270 passMsg = getPassMessage(fShaderSource); |
|
271 fShaderSuccess = getSuccess(passMsg); |
|
272 } |
|
273 |
|
274 var linkSuccess = vShaderSuccess && fShaderSuccess; |
|
275 |
|
276 if (passMsg === undefined) { |
|
277 testFailed("no test shader found."); |
|
278 finishTest(); |
|
279 return; |
|
280 } |
|
281 |
|
282 var info = { |
|
283 vShaderSource: vShaderSource, |
|
284 vShaderSuccess: vShaderSuccess, |
|
285 fShaderSource: fShaderSource, |
|
286 fShaderSuccess: fShaderSuccess, |
|
287 linkSuccess: linkSuccess, |
|
288 passMsg: passMsg |
|
289 }; |
|
290 |
|
291 return info; |
|
292 } |
|
293 |
|
294 function runTest() { |
|
295 var info = setupTest(); |
|
296 description(info.passMsg); |
|
297 runTests([info]); |
|
298 } |
|
299 |
|
300 function runRenderTests(tests) { |
|
301 for (var ii = 0; ii < tests.length; ++ii) { |
|
302 tests[ii].render = true |
|
303 } |
|
304 runTests(tests); |
|
305 } |
|
306 |
|
307 function runRenderTest() { |
|
308 var info = setupTest(); |
|
309 description(info.passMsg); |
|
310 runRenderTests([info]); |
|
311 } |
|
312 |
|
313 return { |
|
314 runTest: runTest, |
|
315 runTests: runTests, |
|
316 runRenderTest: runRenderTest, |
|
317 runRenderTests: runRenderTests, |
|
318 loadExternalShaders: loadExternalShaders, |
|
319 |
|
320 none: false, |
|
321 }; |
|
322 }()); |