1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/canvas/test/webgl-conformance/conformance/extensions/oes-standard-derivatives.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,374 @@ 1.4 +<!-- 1.5 +Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.6 +Use of this source code is governed by a BSD-style license that can be 1.7 +found in the LICENSE file. 1.8 + --> 1.9 +<!DOCTYPE html> 1.10 +<html> 1.11 +<head> 1.12 +<meta charset="utf-8"> 1.13 +<title>WebGL OES_standard_derivatives Conformance Tests</title> 1.14 +<link rel="stylesheet" href="../../resources/js-test-style.css"/> 1.15 +<script src="../../resources/desktop-gl-constants.js" type="text/javascript"></script> 1.16 +<script src="../../resources/js-test-pre.js"></script> 1.17 +<script src="../resources/webgl-test.js"></script> 1.18 +<script src="../resources/webgl-test-utils.js"></script> 1.19 +</head> 1.20 +<body> 1.21 +<div id="description"></div> 1.22 +<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas> 1.23 +<div id="console"></div> 1.24 +<!-- Shaders for testing standard derivatives --> 1.25 + 1.26 +<!-- Shader omitting the required #extension pragma --> 1.27 +<script id="missingPragmaFragmentShader" type="x-shader/x-fragment"> 1.28 +precision mediump float; 1.29 +varying vec2 texCoord; 1.30 +void main() { 1.31 + float dx = dFdx(texCoord.x); 1.32 + float dy = dFdy(texCoord.y); 1.33 + float w = fwidth(texCoord.x); 1.34 + gl_FragColor = vec4(dx, dy, w, 1.0); 1.35 +} 1.36 +</script> 1.37 + 1.38 +<!-- Shader to test macro definition --> 1.39 +<script id="macroFragmentShader" type="x-shader/x-fragment"> 1.40 +precision mediump float; 1.41 +void main() { 1.42 +#ifdef GL_OES_standard_derivatives 1.43 + gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); 1.44 +#else 1.45 + // Error expected 1.46 + #error no GL_OES_standard_derivatives; 1.47 +#endif 1.48 +} 1.49 +</script> 1.50 + 1.51 +<!-- Shader with required #extension pragma --> 1.52 +<script id="testFragmentShader" type="x-shader/x-fragment"> 1.53 +#extension GL_OES_standard_derivatives : enable 1.54 +precision mediump float; 1.55 +varying vec2 texCoord; 1.56 +void main() { 1.57 + float dx = dFdx(texCoord.x); 1.58 + float dy = dFdy(texCoord.y); 1.59 + float w = fwidth(texCoord.x); 1.60 + gl_FragColor = vec4(dx, dy, w, 1.0); 1.61 +} 1.62 +</script> 1.63 +<!-- Shaders to link with test fragment shaders --> 1.64 +<script id="goodVertexShader" type="x-shader/x-vertex"> 1.65 +attribute vec4 vPosition; 1.66 +varying vec2 texCoord; 1.67 +void main() { 1.68 + texCoord = vPosition.xy; 1.69 + gl_Position = vPosition; 1.70 +} 1.71 +</script> 1.72 +<!-- Shaders to test output --> 1.73 +<script id="outputVertexShader" type="x-shader/x-vertex"> 1.74 +attribute vec4 vPosition; 1.75 +varying vec4 position; 1.76 +void main() { 1.77 + position = vPosition; 1.78 + gl_Position = vPosition; 1.79 +} 1.80 +</script> 1.81 +<script id="outputFragmentShader" type="x-shader/x-fragment"> 1.82 +#extension GL_OES_standard_derivatives : enable 1.83 +precision mediump float; 1.84 +varying vec4 position; 1.85 +void main() { 1.86 + float dzdx = dFdx(position.z); 1.87 + float dzdy = dFdy(position.z); 1.88 + float fw = fwidth(position.z); 1.89 + gl_FragColor = vec4(abs(dzdx), abs(dzdy), fw, 1.0); 1.90 +} 1.91 +</script> 1.92 + 1.93 +<script> 1.94 +description("This test verifies the functionality of the OES_standard_derivatives extension, if it is available."); 1.95 + 1.96 +debug(""); 1.97 + 1.98 +var wtu = WebGLTestUtils; 1.99 +var canvas = document.getElementById("canvas"); 1.100 +var gl = create3DContext(canvas); 1.101 +var ext = null; 1.102 + 1.103 +if (!gl) { 1.104 + testFailed("WebGL context does not exist"); 1.105 +} else { 1.106 + testPassed("WebGL context exists"); 1.107 + 1.108 + // Run tests with extension disabled 1.109 + runHintTestDisabled(); 1.110 + runShaderTests(false); 1.111 + 1.112 + // Query the extension and store globally so shouldBe can access it 1.113 + ext = gl.getExtension("OES_standard_derivatives"); 1.114 + if (!ext) { 1.115 + testPassed("No OES_standard_derivatives support -- this is legal"); 1.116 + 1.117 + runSupportedTest(false); 1.118 + } else { 1.119 + testPassed("Successfully enabled OES_standard_derivatives extension"); 1.120 + 1.121 + runSupportedTest(true); 1.122 + 1.123 + runHintTestEnabled(); 1.124 + runShaderTests(true); 1.125 + runOutputTests(); 1.126 + runUniqueObjectTest(); 1.127 + runReferenceCycleTest(); 1.128 + } 1.129 +} 1.130 + 1.131 +function runSupportedTest(extensionEnabled) { 1.132 + var supported = gl.getSupportedExtensions(); 1.133 + if (supported.indexOf("OES_standard_derivatives") >= 0) { 1.134 + if (extensionEnabled) { 1.135 + testPassed("OES_standard_derivatives listed as supported and getExtension succeeded"); 1.136 + } else { 1.137 + testFailed("OES_standard_derivatives listed as supported but getExtension failed"); 1.138 + } 1.139 + } else { 1.140 + if (extensionEnabled) { 1.141 + testFailed("OES_standard_derivatives not listed as supported but getExtension succeeded"); 1.142 + } else { 1.143 + testPassed("OES_standard_derivatives not listed as supported and getExtension failed -- this is legal"); 1.144 + } 1.145 + } 1.146 +} 1.147 + 1.148 +function runHintTestDisabled() { 1.149 + debug("Testing FRAGMENT_SHADER_DERIVATIVE_HINT_OES with extension disabled"); 1.150 + 1.151 + // Use the constant directly as we don't have the extension 1.152 + var FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B; 1.153 + 1.154 + gl.getParameter(FRAGMENT_SHADER_DERIVATIVE_HINT_OES); 1.155 + glErrorShouldBe(gl, gl.INVALID_ENUM, "FRAGMENT_SHADER_DERIVATIVE_HINT_OES should not be queryable if extension is disabled"); 1.156 + 1.157 + gl.hint(FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.DONT_CARE); 1.158 + glErrorShouldBe(gl, gl.INVALID_ENUM, "hint should not accept FRAGMENT_SHADER_DERIVATIVE_HINT_OES if extension is disabled"); 1.159 +} 1.160 + 1.161 +function runHintTestEnabled() { 1.162 + debug("Testing FRAGMENT_SHADER_DERIVATIVE_HINT_OES with extension enabled"); 1.163 + 1.164 + shouldBe("ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES", "0x8B8B"); 1.165 + 1.166 + gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES); 1.167 + glErrorShouldBe(gl, gl.NO_ERROR, "FRAGMENT_SHADER_DERIVATIVE_HINT_OES query should succeed if extension is enabled"); 1.168 + 1.169 + // Default value is DONT_CARE 1.170 + if (gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES) == gl.DONT_CARE) { 1.171 + testPassed("Default value of FRAGMENT_SHADER_DERIVATIVE_HINT_OES is DONT_CARE"); 1.172 + } else { 1.173 + testFailed("Default value of FRAGMENT_SHADER_DERIVATIVE_HINT_OES is not DONT_CARE"); 1.174 + } 1.175 + 1.176 + // Ensure that we can set the target 1.177 + gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.DONT_CARE); 1.178 + glErrorShouldBe(gl, gl.NO_ERROR, "hint should accept FRAGMENT_SHADER_DERIVATIVE_HINT_OES"); 1.179 + 1.180 + // Test all the hint modes 1.181 + var validModes = ["FASTEST", "NICEST", "DONT_CARE"]; 1.182 + var anyFailed = false; 1.183 + for (var n = 0; n < validModes.length; n++) { 1.184 + var mode = validModes[n]; 1.185 + gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl[mode]); 1.186 + if (gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES) != gl[mode]) { 1.187 + testFailed("Round-trip of hint()/getParameter() failed on mode " + mode); 1.188 + anyFailed = true; 1.189 + } 1.190 + } 1.191 + if (!anyFailed) { 1.192 + testPassed("Round-trip of hint()/getParameter() with all supported modes"); 1.193 + } 1.194 +} 1.195 + 1.196 +function runShaderTests(extensionEnabled) { 1.197 + debug(""); 1.198 + debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled")); 1.199 + 1.200 + // Expect the macro shader to succeed ONLY if enabled 1.201 + var macroFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "macroFragmentShader"); 1.202 + if (extensionEnabled) { 1.203 + if (macroFragmentProgram) { 1.204 + // Expected result 1.205 + testPassed("GL_OES_standard_derivatives defined in shaders when extension is enabled"); 1.206 + } else { 1.207 + testFailed("GL_OES_standard_derivatives not defined in shaders when extension is enabled"); 1.208 + } 1.209 + } else { 1.210 + if (macroFragmentProgram) { 1.211 + testFailed("GL_OES_standard_derivatives defined in shaders when extension is disabled"); 1.212 + } else { 1.213 + testPassed("GL_OES_standard_derivatives not defined in shaders when extension disabled"); 1.214 + } 1.215 + } 1.216 + 1.217 + // Always expect the shader missing the #pragma to fail (whether enabled or not) 1.218 + var missingPragmaFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "missingPragmaFragmentShader"); 1.219 + if (missingPragmaFragmentProgram) { 1.220 + testFailed("Shader built-ins allowed without #extension pragma"); 1.221 + } else { 1.222 + testPassed("Shader built-ins disallowed without #extension pragma"); 1.223 + } 1.224 + 1.225 + // Try to compile a shader using the built-ins that should only succeed if enabled 1.226 + var testFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "testFragmentShader"); 1.227 + if (extensionEnabled) { 1.228 + if (testFragmentProgram) { 1.229 + testPassed("Shader built-ins compiled successfully when extension enabled"); 1.230 + } else { 1.231 + testFailed("Shader built-ins failed to compile when extension enabled"); 1.232 + } 1.233 + } else { 1.234 + if (testFragmentProgram) { 1.235 + testFailed("Shader built-ins compiled successfully when extension disabled"); 1.236 + } else { 1.237 + testPassed("Shader built-ins failed to compile when extension disabled"); 1.238 + } 1.239 + } 1.240 +} 1.241 + 1.242 +function runOutputTests() { 1.243 + // This tests does several draws with various values of z. 1.244 + // The output of the fragment shader is: 1.245 + // [dFdx(z), dFdy(z), fwidth(z), 1.0] 1.246 + // The expected math: (note the conversion to uint8) 1.247 + // canvas.width = canvas.height = 50 1.248 + // dFdx = totalChange.x / canvas.width = 0.5 / 50.0 = 0.01 1.249 + // dFdy = totalChange.y / canvas.height = 0.5 / 50.0 = 0.01 1.250 + // fw = abs(dFdx + dFdy) = 0.01 + 0.01 = 0.02 1.251 + // r = floor(dFdx * 255) = 3 1.252 + // g = floor(dFdy * 255) = 3 1.253 + // b = floor(fw * 255) = 5 1.254 + 1.255 + var e = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher 1.256 + 1.257 + debug("Testing various draws for valid built-in function behavior"); 1.258 + 1.259 + canvas.width = 50; canvas.height = 50; 1.260 + gl.viewport(0, 0, canvas.width, canvas.height); 1.261 + gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.NICEST); 1.262 + 1.263 + var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['vPosition', 'texCoord0'], [0, 1]); 1.264 + var quadParameters = wtu.setupUnitQuad(gl, 0, 1); 1.265 + 1.266 + function readLocation(x, y) { 1.267 + var pixels = new Uint8Array(1 * 1 * 4); 1.268 + var px = Math.floor(x * canvas.width); 1.269 + var py = Math.floor(y * canvas.height); 1.270 + gl.readPixels(px, py, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); 1.271 + return pixels; 1.272 + }; 1.273 + function toString(arr) { 1.274 + var s = "["; 1.275 + for (var n = 0; n < arr.length; n++) { 1.276 + s += arr[n]; 1.277 + if (n < arr.length - 1) { 1.278 + s += ", "; 1.279 + } 1.280 + } 1.281 + return s + "]"; 1.282 + }; 1.283 + function expectResult(target, successMessage, failureMessage) { 1.284 + var locations = [ 1.285 + readLocation(0.1, 0.1), 1.286 + readLocation(0.9, 0.1), 1.287 + readLocation(0.1, 0.9), 1.288 + readLocation(0.9, 0.9), 1.289 + readLocation(0.5, 0.5) 1.290 + ]; 1.291 + var anyDiffer = false; 1.292 + for (var n = 0; n < locations.length; n++) { 1.293 + var source = locations[n]; 1.294 + for (var m = 0; m < 4; m++) { 1.295 + if (Math.abs(source[m] - target[m]) > e) { 1.296 + anyDiffer = true; 1.297 + testFailed(failureMessage + "; should be " + toString(target) + ", was " + toString(source)); 1.298 + break; 1.299 + } 1.300 + } 1.301 + } 1.302 + if (!anyDiffer) { 1.303 + testPassed(successMessage); 1.304 + } 1.305 + }; 1.306 + 1.307 + function setupBuffers(tl, tr, bl, br) { 1.308 + gl.bindBuffer(gl.ARRAY_BUFFER, quadParameters[0]); 1.309 + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 1.310 + 1.0, 1.0, tr, 1.311 + -1.0, 1.0, tl, 1.312 + -1.0, -1.0, bl, 1.313 + 1.0, 1.0, tr, 1.314 + -1.0, -1.0, bl, 1.315 + 1.0, -1.0, br]), gl.STATIC_DRAW); 1.316 + }; 1.317 + 1.318 + // Draw 1: (no variation) 1.319 + setupBuffers(0.0, 0.0, 0.0, 0.0); 1.320 + wtu.drawQuad(gl); 1.321 + expectResult([0, 0, 0, 255], 1.322 + "Draw 1 (no variation) returned the correct data", 1.323 + "Draw 1 (no variation) returned incorrect data"); 1.324 + 1.325 + // Draw 2: (variation in x) 1.326 + setupBuffers(1.0, 0.0, 1.0, 0.0); 1.327 + wtu.drawQuad(gl); 1.328 + expectResult([5, 0, 5, 255], 1.329 + "Draw 2 (variation in x) returned the correct data", 1.330 + "Draw 2 (variation in x) returned incorrect data"); 1.331 + 1.332 + // Draw 3: (variation in y) 1.333 + setupBuffers(1.0, 1.0, 0.0, 0.0); 1.334 + wtu.drawQuad(gl); 1.335 + expectResult([0, 5, 5, 255], 1.336 + "Draw 3 (variation in y) returned the correct data", 1.337 + "Draw 3 (variation in y) returned incorrect data"); 1.338 + 1.339 + // Draw 4: (variation in x & y) 1.340 + setupBuffers(1.0, 0.5, 0.5, 0.0); 1.341 + wtu.drawQuad(gl); 1.342 + expectResult([3, 3, 5, 255], 1.343 + "Draw 4 (variation in x & y) returned the correct data", 1.344 + "Draw 4 (variation in x & y) returned incorrect data"); 1.345 + 1.346 +} 1.347 + 1.348 +function runUniqueObjectTest() 1.349 +{ 1.350 + debug("Testing that getExtension() returns the same object each time"); 1.351 + gl.getExtension("OES_standard_derivatives").myProperty = 2; 1.352 + gc(); 1.353 + shouldBe('gl.getExtension("OES_standard_derivatives").myProperty', '2'); 1.354 +} 1.355 + 1.356 +function runReferenceCycleTest() 1.357 +{ 1.358 + // create some reference cycles. The goal is to see if they cause leaks. The point is that 1.359 + // some browser test runners have instrumentation to detect leaked refcounted objects. 1.360 + 1.361 + debug("Testing reference cycles between context and extension objects"); 1.362 + var ext = gl.getExtension("OES_standard_derivatives"); 1.363 + 1.364 + // create cycle between extension and context, since the context has to hold a reference to the extension 1.365 + ext.context = gl; 1.366 + 1.367 + // create a self-cycle on the extension object 1.368 + ext.ext = ext; 1.369 +} 1.370 + 1.371 +debug(""); 1.372 +successfullyParsed = true; 1.373 +</script> 1.374 +<script>finishTest();</script> 1.375 + 1.376 +</body> 1.377 +</html>