OLD | NEW |
| (Empty) |
1 <!-- | |
2 Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
3 Use of this source code is governed by a BSD-style license that can be | |
4 found in the LICENSE file. | |
5 --> | |
6 <!DOCTYPE html> | |
7 <html> | |
8 <head> | |
9 <meta charset="utf-8"> | |
10 <title>WebGL OES_standard_derivatives Conformance Tests</title> | |
11 <link rel="stylesheet" href="../../resources/js-test-style.css"/> | |
12 <script src="../../resources/desktop-gl-constants.js" type="text/javascript"></s
cript> | |
13 <script src="../../resources/js-test-pre.js"></script> | |
14 <script src="../resources/webgl-test.js"></script> | |
15 <script src="../resources/webgl-test-utils.js"></script> | |
16 </head> | |
17 <body> | |
18 <div id="description"></div> | |
19 <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas> | |
20 <div id="console"></div> | |
21 <!-- Shaders for testing standard derivatives --> | |
22 | |
23 <!-- Shader omitting the required #extension pragma --> | |
24 <script id="missingPragmaFragmentShader" type="x-shader/x-fragment"> | |
25 precision mediump float; | |
26 varying vec2 texCoord; | |
27 void main() { | |
28 float dx = dFdx(texCoord.x); | |
29 float dy = dFdy(texCoord.y); | |
30 float w = fwidth(texCoord.x); | |
31 gl_FragColor = vec4(dx, dy, w, 1.0); | |
32 } | |
33 </script> | |
34 | |
35 <!-- Shader to test macro definition --> | |
36 <script id="macroFragmentShader" type="x-shader/x-fragment"> | |
37 precision mediump float; | |
38 void main() { | |
39 #ifdef GL_OES_standard_derivatives | |
40 gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); | |
41 #else | |
42 // Error expected | |
43 #error no GL_OES_standard_derivatives; | |
44 #endif | |
45 } | |
46 </script> | |
47 | |
48 <!-- Shader with required #extension pragma --> | |
49 <script id="testFragmentShader" type="x-shader/x-fragment"> | |
50 #extension GL_OES_standard_derivatives : enable | |
51 precision mediump float; | |
52 varying vec2 texCoord; | |
53 void main() { | |
54 float dx = dFdx(texCoord.x); | |
55 float dy = dFdy(texCoord.y); | |
56 float w = fwidth(texCoord.x); | |
57 gl_FragColor = vec4(dx, dy, w, 1.0); | |
58 } | |
59 </script> | |
60 | |
61 <!-- Shaders to test output --> | |
62 <script id="outputVertexShader" type="x-shader/x-vertex"> | |
63 attribute vec4 vPosition; | |
64 varying vec4 position; | |
65 void main() { | |
66 position = vPosition; | |
67 gl_Position = vPosition; | |
68 } | |
69 </script> | |
70 <script id="outputFragmentShader" type="x-shader/x-fragment"> | |
71 #extension GL_OES_standard_derivatives : enable | |
72 precision mediump float; | |
73 varying vec4 position; | |
74 void main() { | |
75 float dzdx = dFdx(position.z); | |
76 float dzdy = dFdy(position.z); | |
77 float fw = fwidth(position.z); | |
78 gl_FragColor = vec4(abs(dzdx), abs(dzdy), fw, 1.0); | |
79 } | |
80 </script> | |
81 | |
82 <script> | |
83 description("This test verifies the functionality of the OES_standard_derivative
s extension, if it is available."); | |
84 | |
85 debug(""); | |
86 | |
87 var wtu = WebGLTestUtils; | |
88 var canvas = document.getElementById("canvas"); | |
89 var gl = create3DContext(canvas); | |
90 var ext = null; | |
91 | |
92 if (!gl) { | |
93 testFailed("WebGL context does not exist"); | |
94 } else { | |
95 testPassed("WebGL context exists"); | |
96 | |
97 // Run tests with extension disabled | |
98 runHintTestDisabled(); | |
99 runShaderTests(false); | |
100 | |
101 // Query the extension and store globally so shouldBe can access it | |
102 ext = gl.getExtension("OES_standard_derivatives"); | |
103 if (!ext) { | |
104 testPassed("No OES_standard_derivatives support -- this is legal"); | |
105 | |
106 runSupportedTest(false); | |
107 } else { | |
108 testPassed("Successfully enabled OES_standard_derivatives extension"); | |
109 | |
110 runSupportedTest(true); | |
111 | |
112 runHintTestEnabled(); | |
113 runShaderTests(true); | |
114 runOutputTests(); | |
115 runUniqueObjectTest(); | |
116 } | |
117 } | |
118 | |
119 function runSupportedTest(extensionEnabled) { | |
120 var supported = gl.getSupportedExtensions(); | |
121 if (supported.indexOf("OES_standard_derivatives") >= 0) { | |
122 if (extensionEnabled) { | |
123 testPassed("OES_standard_derivatives listed as supported and getExte
nsion succeeded"); | |
124 } else { | |
125 testFailed("OES_standard_derivatives listed as supported but getExte
nsion failed"); | |
126 } | |
127 } else { | |
128 if (extensionEnabled) { | |
129 testFailed("OES_standard_derivatives not listed as supported but get
Extension succeeded"); | |
130 } else { | |
131 testPassed("OES_standard_derivatives not listed as supported and get
Extension failed -- this is legal"); | |
132 } | |
133 } | |
134 } | |
135 | |
136 function runHintTestDisabled() { | |
137 debug("Testing FRAGMENT_SHADER_DERIVATIVE_HINT_OES with extension disabled")
; | |
138 | |
139 // Use the constant directly as we don't have the extension | |
140 var FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B; | |
141 | |
142 gl.getParameter(FRAGMENT_SHADER_DERIVATIVE_HINT_OES); | |
143 glErrorShouldBe(gl, gl.INVALID_ENUM, "FRAGMENT_SHADER_DERIVATIVE_HINT_OES sh
ould not be queryable if extension is disabled"); | |
144 | |
145 gl.hint(FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.DONT_CARE); | |
146 glErrorShouldBe(gl, gl.INVALID_ENUM, "hint should not accept FRAGMENT_SHADER
_DERIVATIVE_HINT_OES if extension is disabled"); | |
147 } | |
148 | |
149 function runHintTestEnabled() { | |
150 debug("Testing FRAGMENT_SHADER_DERIVATIVE_HINT_OES with extension enabled"); | |
151 | |
152 shouldBe("ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES", "0x8B8B"); | |
153 | |
154 gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES); | |
155 glErrorShouldBe(gl, gl.NO_ERROR, "FRAGMENT_SHADER_DERIVATIVE_HINT_OES query
should succeed if extension is enabled"); | |
156 | |
157 // Default value is DONT_CARE | |
158 if (gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES) == gl.DONT_CARE
) { | |
159 testPassed("Default value of FRAGMENT_SHADER_DERIVATIVE_HINT_OES is DONT
_CARE"); | |
160 } else { | |
161 testFailed("Default value of FRAGMENT_SHADER_DERIVATIVE_HINT_OES is not
DONT_CARE"); | |
162 } | |
163 | |
164 // Ensure that we can set the target | |
165 gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.DONT_CARE); | |
166 glErrorShouldBe(gl, gl.NO_ERROR, "hint should accept FRAGMENT_SHADER_DERIVAT
IVE_HINT_OES"); | |
167 | |
168 // Test all the hint modes | |
169 var validModes = ["FASTEST", "NICEST", "DONT_CARE"]; | |
170 var anyFailed = false; | |
171 for (var n = 0; n < validModes.length; n++) { | |
172 var mode = validModes[n]; | |
173 gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl[mode]); | |
174 if (gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES) != gl[mode]
) { | |
175 testFailed("Round-trip of hint()/getParameter() failed on mode " + m
ode); | |
176 anyFailed = true; | |
177 } | |
178 } | |
179 if (!anyFailed) { | |
180 testPassed("Round-trip of hint()/getParameter() with all supported modes
"); | |
181 } | |
182 } | |
183 | |
184 function runShaderTests(extensionEnabled) { | |
185 debug("Testing various shader compiles with extension " + (extensionEnabled
? "enabled" : "disabled")); | |
186 | |
187 // Expect the macro shader to succeed ONLY if enabled | |
188 var macroFragmentShader = wtu.loadShaderFromScript(gl, "macroFragmentShader"
); | |
189 if (extensionEnabled) { | |
190 if (macroFragmentShader) { | |
191 // Expected result | |
192 testPassed("GL_OES_standard_derivatives defined in shaders when exte
nsion is enabled"); | |
193 } else { | |
194 testFailed("GL_OES_standard_derivatives not defined in shaders when
extension is enabled"); | |
195 } | |
196 } else { | |
197 if (macroFragmentShader) { | |
198 testFailed("GL_OES_standard_derivatives defined in shaders when exte
nsion is disabled"); | |
199 } else { | |
200 testPassed("GL_OES_standard_derivatives not defined in shaders when
extension disabled"); | |
201 } | |
202 } | |
203 | |
204 // Always expect the shader missing the #pragma to fail (whether enabled or
not) | |
205 var missingPragmaFragmentShader = wtu.loadShaderFromScript(gl, "missingPragm
aFragmentShader"); | |
206 if (missingPragmaFragmentShader) { | |
207 testFailed("Shader built-ins allowed without #extension pragma"); | |
208 } else { | |
209 testPassed("Shader built-ins disallowed without #extension pragma"); | |
210 } | |
211 | |
212 // Try to compile a shader using the built-ins that should only succeed if e
nabled | |
213 var testFragmentShader = wtu.loadShaderFromScript(gl, "testFragmentShader"); | |
214 if (extensionEnabled) { | |
215 if (testFragmentShader) { | |
216 testPassed("Shader built-ins compiled successfully when extension en
abled"); | |
217 } else { | |
218 testFailed("Shader built-ins failed to compile when extension enable
d"); | |
219 } | |
220 } else { | |
221 if (testFragmentShader) { | |
222 testFailed("Shader built-ins compiled successfully when extension di
sabled"); | |
223 } else { | |
224 testPassed("Shader built-ins failed to compile when extension disabl
ed"); | |
225 } | |
226 } | |
227 } | |
228 | |
229 function runOutputTests() { | |
230 // This tests does several draws with various values of z. | |
231 // The output of the fragment shader is: | |
232 // [dFdx(z), dFdy(z), fwidth(z), 1.0] | |
233 // The expected math: (note the conversion to uint8) | |
234 // canvas.width = canvas.height = 50 | |
235 // dFdx = totalChange.x / canvas.width = 0.5 / 50.0 = 0.01 | |
236 // dFdy = totalChange.y / canvas.height = 0.5 / 50.0 = 0.01 | |
237 // fw = abs(dFdx + dFdy) = 0.01 + 0.01 = 0.02 | |
238 // r = floor(dFdx * 255) = 3 | |
239 // g = floor(dFdy * 255) = 3 | |
240 // b = floor(fw * 255) = 5 | |
241 | |
242 var e = 2; // Amount of variance to allow in result pixels - may need to be
tweaked higher | |
243 | |
244 debug("Testing various draws for valid built-in function behavior"); | |
245 | |
246 canvas.width = 50; canvas.height = 50; | |
247 gl.viewport(0, 0, canvas.width, canvas.height); | |
248 gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.NICEST); | |
249 | |
250 var shaders = [ | |
251 wtu.loadShaderFromScript(gl, "outputVertexShader"), | |
252 wtu.loadShaderFromScript(gl, "outputFragmentShader") | |
253 ]; | |
254 var program = wtu.setupProgram(gl, shaders, ['vPosition', 'texCoord0'], [0,
1]); | |
255 var quadParameters = wtu.setupUnitQuad(gl, 0, 1); | |
256 | |
257 function readLocation(x, y) { | |
258 var pixels = new Uint8Array(1 * 1 * 4); | |
259 var px = Math.floor(x * canvas.width); | |
260 var py = Math.floor(y * canvas.height); | |
261 gl.readPixels(px, py, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); | |
262 return pixels; | |
263 }; | |
264 function toString(arr) { | |
265 var s = "["; | |
266 for (var n = 0; n < arr.length; n++) { | |
267 s += arr[n]; | |
268 if (n < arr.length - 1) { | |
269 s += ", "; | |
270 } | |
271 } | |
272 return s + "]"; | |
273 }; | |
274 function expectResult(target, successMessage, failureMessage) { | |
275 var locations = [ | |
276 readLocation(0.1, 0.1), | |
277 readLocation(0.9, 0.1), | |
278 readLocation(0.1, 0.9), | |
279 readLocation(0.9, 0.9), | |
280 readLocation(0.5, 0.5) | |
281 ]; | |
282 var anyDiffer = false; | |
283 for (var n = 0; n < locations.length; n++) { | |
284 var source = locations[n]; | |
285 for (var m = 0; m < 4; m++) { | |
286 if (Math.abs(source[m] - target[m]) > e) { | |
287 anyDiffer = true; | |
288 testFailed(failureMessage + "; should be " + toString(target
) + ", was " + toString(source)); | |
289 break; | |
290 } | |
291 } | |
292 } | |
293 if (!anyDiffer) { | |
294 testPassed(successMessage); | |
295 } | |
296 }; | |
297 | |
298 function setupBuffers(tl, tr, bl, br) { | |
299 gl.bindBuffer(gl.ARRAY_BUFFER, quadParameters[0]); | |
300 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ | |
301 1.0, 1.0, tr, | |
302 -1.0, 1.0, tl, | |
303 -1.0, -1.0, bl, | |
304 1.0, 1.0, tr, | |
305 -1.0, -1.0, bl, | |
306 1.0, -1.0, br]), gl.STATIC_DRAW); | |
307 }; | |
308 | |
309 // Draw 1: (no variation) | |
310 setupBuffers(0.0, 0.0, 0.0, 0.0); | |
311 wtu.drawQuad(gl); | |
312 expectResult([0, 0, 0, 255], | |
313 "Draw 1 (no variation) returned the correct data", | |
314 "Draw 1 (no variation) returned incorrect data"); | |
315 | |
316 // Draw 2: (variation in x) | |
317 setupBuffers(1.0, 0.0, 1.0, 0.0); | |
318 wtu.drawQuad(gl); | |
319 expectResult([5, 0, 5, 255], | |
320 "Draw 2 (variation in x) returned the correct data", | |
321 "Draw 2 (variation in x) returned incorrect data"); | |
322 | |
323 // Draw 3: (variation in y) | |
324 setupBuffers(1.0, 1.0, 0.0, 0.0); | |
325 wtu.drawQuad(gl); | |
326 expectResult([0, 5, 5, 255], | |
327 "Draw 3 (variation in y) returned the correct data", | |
328 "Draw 3 (variation in y) returned incorrect data"); | |
329 | |
330 // Draw 4: (variation in x & y) | |
331 setupBuffers(1.0, 0.5, 0.5, 0.0); | |
332 wtu.drawQuad(gl); | |
333 expectResult([3, 3, 5, 255], | |
334 "Draw 4 (variation in x & y) returned the correct data", | |
335 "Draw 4 (variation in x & y) returned incorrect data"); | |
336 | |
337 } | |
338 | |
339 function attemptToForceGC() | |
340 { | |
341 var holderArray = []; | |
342 var tempArray; | |
343 window.tempArray = holderArray; | |
344 for (var i = 0; i < 12; ++i) { | |
345 tempArray = []; | |
346 for (var j = 0; j < 1024 * 1024; ++j) { | |
347 tempArray.push(0); | |
348 } | |
349 holderArray.push(tempArray); | |
350 } | |
351 window.tempArray = null; | |
352 } | |
353 | |
354 function runUniqueObjectTest() | |
355 { | |
356 debug("Testing that getExtension() returns the same object each time"); | |
357 gl.getExtension("OES_standard_derivatives").myProperty = 2; | |
358 if (window.GCController) { | |
359 window.GCController.collect(); | |
360 } else if (window.opera && window.opera.collect) { | |
361 window.opera.collect(); | |
362 } else { | |
363 attemptToForceGC(); | |
364 } | |
365 shouldBe('gl.getExtension("OES_standard_derivatives").myProperty', '2'); | |
366 } | |
367 | |
368 | |
369 debug(""); | |
370 successfullyParsed = true; | |
371 </script> | |
372 <script src="../../resources/js-test-post.js"></script> | |
373 | |
374 </body> | |
375 </html> | |
OLD | NEW |