tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

oes-standard-derivatives.html (16251B)


      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 
      7 <!DOCTYPE html>
      8 <html>
      9 <head>
     10 <meta charset="utf-8">
     11 <title>WebGL OES_standard_derivatives Conformance Tests</title>
     12 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
     13 <script src="../../js/js-test-pre.js"></script>
     14 <script src="../../js/webgl-test-utils.js"></script>
     15 </head>
     16 <body>
     17 <div id="description"></div>
     18 <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
     19 <div id="console"></div>
     20 <!-- Shaders for testing standard derivatives -->
     21 
     22 <!-- Shader omitting the required #extension pragma -->
     23 <script id="missingPragmaFragmentShader" type="x-shader/x-fragment">
     24 precision mediump float;
     25 varying vec2 texCoord;
     26 void main() {
     27    float dx = dFdx(texCoord.x);
     28    float dy = dFdy(texCoord.y);
     29    float w = fwidth(texCoord.x);
     30    gl_FragColor = vec4(dx, dy, w, 1.0);
     31 }
     32 </script>
     33 
     34 <!-- Shader to test macro definition -->
     35 <script id="macroFragmentShader" type="x-shader/x-fragment">
     36 precision mediump float;
     37 void main() {
     38 #ifdef GL_OES_standard_derivatives
     39    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
     40 #else
     41    // Error expected
     42    #error no GL_OES_standard_derivatives;
     43 #endif
     44 }
     45 </script>
     46 
     47 <!-- Shader with required #extension pragma -->
     48 <script id="testFragmentShader" type="x-shader/x-fragment">
     49 #extension GL_OES_standard_derivatives : enable
     50 precision mediump float;
     51 varying vec2 texCoord;
     52 void main() {
     53    float dx = dFdx(texCoord.x);
     54    float dy = dFdy(texCoord.y);
     55    float w = fwidth(texCoord.x);
     56    gl_FragColor = vec4(dx, dy, w, 1.0);
     57 }
     58 </script>
     59 <!-- Shader with #extension after other code -->
     60 <script id="testFragmentShaderWithExtensionNotAtTop" type="x-shader/x-fragment">
     61 precision mediump float;
     62 varying vec2 texCoord;
     63 void main() {
     64 #extension GL_OES_standard_derivatives : enable
     65    float dx = dFdx(texCoord.x);
     66    float dy = dFdy(texCoord.y);
     67    float w = fwidth(texCoord.x);
     68    gl_FragColor = vec4(dx, dy, w, 1.0);
     69 }
     70 </script>
     71 <!-- Shaders to link with test fragment shaders -->
     72 <script id="goodVertexShader" type="x-shader/x-vertex">
     73 attribute vec4 vPosition;
     74 varying vec2 texCoord;
     75 void main() {
     76    texCoord = vPosition.xy;
     77    gl_Position = vPosition;
     78 }
     79 </script>
     80 <!-- Shaders to test output -->
     81 <script id="outputVertexShader" type="x-shader/x-vertex">
     82 attribute vec4 vPosition;
     83 varying vec4 position;
     84 void main() {
     85    position = vPosition;
     86    gl_Position = vPosition;
     87 }
     88 </script>
     89 <script id="outputFragmentShader" type="x-shader/x-fragment">
     90 #extension GL_OES_standard_derivatives : enable
     91 precision mediump float;
     92 varying vec4 position;
     93 void main() {
     94    float dzdx = dFdx(position.z);
     95    float dzdy = dFdy(position.z);
     96    float fw = fwidth(position.z);
     97    gl_FragColor = vec4(abs(dzdx) * 40.0, abs(dzdy) * 40.0, fw * 40.0, 1.0);
     98 }
     99 </script>
    100 
    101 <script>
    102 "use strict";
    103 description("This test verifies the functionality of the OES_standard_derivatives extension, if it is available.");
    104 
    105 debug("");
    106 
    107 var wtu = WebGLTestUtils;
    108 var canvas = document.getElementById("canvas");
    109 var gl = wtu.create3DContext(canvas);
    110 var ext = null;
    111 
    112 // Run all tests once.
    113 runAllTests();
    114 
    115 // Run all tests against with a new context to test for any cache issues.
    116 debug("");
    117 debug("Testing new context to catch cache errors");
    118 gl = wtu.create3DContext();
    119 ext = null;
    120 runAllTests();
    121 
    122 function runAllTests() {
    123    if (!gl) {
    124        testFailed("WebGL context does not exist");
    125    } else {
    126        testPassed("WebGL context exists");
    127 
    128        // Run tests with extension disabled
    129        runHintTestDisabled();
    130        runShaderTests(false);
    131 
    132        // Query the extension and store globally so shouldBe can access it
    133        ext = gl.getExtension("OES_standard_derivatives");
    134        if (!ext) {
    135            testPassed("No OES_standard_derivatives support -- this is legal");
    136 
    137            runSupportedTest(false);
    138        } else {
    139            testPassed("Successfully enabled OES_standard_derivatives extension");
    140 
    141            runSupportedTest(true);
    142 
    143            runHintTestEnabled();
    144            runShaderTests(true);
    145            runOutputTests();
    146            runUniqueObjectTest();
    147 
    148            // Run deferred link tests.
    149            runDeferredLinkTests();
    150        }
    151    }
    152 
    153 }
    154 
    155 function runSupportedTest(extensionEnabled) {
    156    var supported = gl.getSupportedExtensions();
    157    if (supported.indexOf("OES_standard_derivatives") >= 0) {
    158        if (extensionEnabled) {
    159            testPassed("OES_standard_derivatives listed as supported and getExtension succeeded");
    160        } else {
    161            testFailed("OES_standard_derivatives listed as supported but getExtension failed");
    162        }
    163    } else {
    164        if (extensionEnabled) {
    165            testFailed("OES_standard_derivatives not listed as supported but getExtension succeeded");
    166        } else {
    167            testPassed("OES_standard_derivatives not listed as supported and getExtension failed -- this is legal");
    168        }
    169    }
    170 }
    171 
    172 function runHintTestDisabled() {
    173    debug("Testing FRAGMENT_SHADER_DERIVATIVE_HINT_OES with extension disabled");
    174 
    175    // Use the constant directly as we don't have the extension
    176    var FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B;
    177 
    178    gl.getParameter(FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
    179    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "FRAGMENT_SHADER_DERIVATIVE_HINT_OES should not be queryable if extension is disabled");
    180 
    181    gl.hint(FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.DONT_CARE);
    182    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "hint should not accept FRAGMENT_SHADER_DERIVATIVE_HINT_OES if extension is disabled");
    183 }
    184 
    185 function runHintTestEnabled() {
    186    debug("Testing FRAGMENT_SHADER_DERIVATIVE_HINT_OES with extension enabled");
    187 
    188    shouldBe("ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES", "0x8B8B");
    189 
    190    gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
    191    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "FRAGMENT_SHADER_DERIVATIVE_HINT_OES query should succeed if extension is enabled");
    192 
    193    // Default value is DONT_CARE
    194    if (gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES) == gl.DONT_CARE) {
    195        testPassed("Default value of FRAGMENT_SHADER_DERIVATIVE_HINT_OES is DONT_CARE");
    196    } else {
    197        testFailed("Default value of FRAGMENT_SHADER_DERIVATIVE_HINT_OES is not DONT_CARE");
    198    }
    199 
    200    // Ensure that we can set the target
    201    gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.DONT_CARE);
    202    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "hint should accept FRAGMENT_SHADER_DERIVATIVE_HINT_OES");
    203 
    204    // Test all the hint modes
    205    var validModes = ["FASTEST", "NICEST", "DONT_CARE"];
    206    var anyFailed = false;
    207    for (var n = 0; n < validModes.length; n++) {
    208        var mode = validModes[n];
    209        gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl[mode]);
    210        if (gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES) != gl[mode]) {
    211            testFailed("Round-trip of hint()/getParameter() failed on mode " + mode);
    212            anyFailed = true;
    213        }
    214    }
    215    if (!anyFailed) {
    216        testPassed("Round-trip of hint()/getParameter() with all supported modes");
    217    }
    218 }
    219 
    220 function runShaderTests(extensionEnabled) {
    221    debug("");
    222    debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled"));
    223 
    224    // Expect the macro shader to succeed ONLY if enabled
    225    {
    226        const macroFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "macroFragmentShader");
    227        if (extensionEnabled) {
    228            if (macroFragmentProgram) {
    229                // Expected result
    230                testPassed("GL_OES_standard_derivatives defined in shaders when extension is enabled");
    231            } else {
    232                testFailed("GL_OES_standard_derivatives not defined in shaders when extension is enabled");
    233            }
    234        } else {
    235            if (macroFragmentProgram) {
    236                testFailed("GL_OES_standard_derivatives defined in shaders when extension is disabled");
    237            } else {
    238                testPassed("GL_OES_standard_derivatives not defined in shaders when extension disabled");
    239            }
    240        }
    241    }
    242 
    243    // Always expect the shader missing the #pragma to fail (whether enabled or not)
    244    {
    245        const missingPragmaFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "missingPragmaFragmentShader");
    246        if (missingPragmaFragmentProgram) {
    247            testFailed("Shader built-ins allowed without #extension pragma");
    248        } else {
    249            testPassed("Shader built-ins disallowed without #extension pragma");
    250        }
    251    }
    252 
    253    // Try to compile a shader using the built-ins that should only succeed if enabled
    254    {
    255        const testFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "testFragmentShader");
    256        if (extensionEnabled) {
    257            if (testFragmentProgram) {
    258                testPassed("Shader built-ins compiled successfully when extension enabled");
    259            } else {
    260                testFailed("Shader built-ins failed to compile when extension enabled");
    261            }
    262        } else {
    263            if (testFragmentProgram) {
    264                testFailed("Shader built-ins compiled successfully when extension disabled");
    265            } else {
    266                testPassed("Shader built-ins failed to compile when extension disabled");
    267            }
    268        }
    269    }
    270 
    271    // This tests specifically that #extension directives after other code are
    272    // valid, per spec (6.35 GLSL ES #extension directive location).
    273    //
    274    // This test actually has nothing to do with OES_standard_derivatives, but
    275    // is inserted here because this extension is ubiquitous.
    276    //
    277    // This test is not as strict as the spec - it doesn't require that "the
    278    // scope ... is always the whole shader", because implementations (ANGLE
    279    // shader translator) do not actually implement this correctly. The test
    280    // coverage is intentionally left incomplete - in practice, all WebGL
    281    // shaders already work with the current implementation, so there's no
    282    // practical reason to update them to match the spec. Conversely, the
    283    // currently implemented rules are too complex to formalize in spec.
    284    //
    285    // Regression test for https://crbug.com/971660 .
    286    {
    287        const testFragmentProgramWithExtensionNotAtTop = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "testFragmentShaderWithExtensionNotAtTop");
    288        if (extensionEnabled) {
    289            if (testFragmentProgramWithExtensionNotAtTop) {
    290                testPassed("Shader with #extension after non-preprocessor code: compiled successfully when extension enabled");
    291            } else {
    292                testFailed("Shader with #extension after non-preprocessor code: failed to compile when extension enabled");
    293            }
    294        }
    295    }
    296 }
    297 
    298 function runOutputTests() {
    299    // This tests does several draws with various values of z.
    300    // The output of the fragment shader is:
    301    // [dFdx(z), dFdy(z), fwidth(z), 1.0]
    302    // The expected math: (note the conversion to uint8)
    303    //    canvas.width = canvas.height = 50
    304    //    dFdx = totalChange.x / canvas.width  = 0.5 / 50.0 = 0.01
    305    //    dFdy = totalChange.y / canvas.height = 0.5 / 50.0 = 0.01
    306    //    fw = abs(dFdx + dFdy) = 0.01 + 0.01 = 0.02
    307    //    r = floor(dFdx * 40.0 * 255) = 102
    308    //    g = floor(dFdy * 40.0 * 255) = 102
    309    //    b = floor(fw * 40.0 * 255) = 204
    310 
    311    var e = 5; // Amount of variance to allow in result pixels - may need to be tweaked higher
    312 
    313    debug("Testing various draws for valid built-in function behavior");
    314 
    315    canvas.width = 50; canvas.height = 50;
    316    gl.viewport(0, 0, canvas.width, canvas.height);
    317    gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.NICEST);
    318 
    319    var positionLoc = 0;
    320    var texcoordLoc = 1;
    321    var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['vPosition', 'texCoord0'], [0, 1]);
    322    var quadParameters = wtu.setupUnitQuad(gl, positionLoc, texcoordLoc);
    323 
    324    function expectResult(target, message) {
    325        var locations = [
    326            [ 0.1, 0.1 ],
    327            [ 0.9, 0.1 ],
    328            [ 0.1, 0.9 ],
    329            [ 0.9, 0.9 ],
    330            [ 0.5, 0.5 ]
    331        ];
    332        for (var n = 0; n < locations.length; n++) {
    333            var loc = locations[n];
    334            var px = Math.floor(loc[0] * canvas.width);
    335            var py = Math.floor(loc[1] * canvas.height);
    336            wtu.checkCanvasRect(gl, px, py, 1, 1, target, message, 4);
    337        }
    338    };
    339 
    340    function setupBuffers(tl, tr, bl, br) {
    341        gl.bindBuffer(gl.ARRAY_BUFFER, quadParameters[0]);
    342        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    343           1.0,  1.0, tr,
    344          -1.0,  1.0, tl,
    345          -1.0, -1.0, bl,
    346           1.0,  1.0, tr,
    347          -1.0, -1.0, bl,
    348           1.0, -1.0, br]), gl.STATIC_DRAW);
    349        gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0);
    350    };
    351 
    352    // Draw 1: (no variation)
    353    setupBuffers(0.0, 0.0, 0.0, 0.0);
    354    wtu.clearAndDrawUnitQuad(gl);
    355    expectResult([0, 0, 0, 255],
    356                 "Draw 1 (no variation) should pass");
    357 
    358    // Draw 2: (variation in x)
    359    setupBuffers(1.0, 0.0, 1.0, 0.0);
    360    wtu.clearAndDrawUnitQuad(gl);
    361    expectResult([204, 0, 204, 255],
    362                 "Draw 2 (variation in x) should pass");
    363 
    364    // Draw 3: (variation in y)
    365    setupBuffers(1.0, 1.0, 0.0, 0.0);
    366    wtu.clearAndDrawUnitQuad(gl);
    367    expectResult([0, 204, 204, 255],
    368                 "Draw 3 (variation in y) should pass");
    369 
    370    // Draw 4: (variation in x & y)
    371    setupBuffers(1.0, 0.5, 0.5, 0.0);
    372    wtu.clearAndDrawUnitQuad(gl);
    373    expectResult([102, 102, 204, 255],
    374                 "Draw 4 (variation in x & y) should pass");
    375 }
    376 
    377 function runUniqueObjectTest()
    378 {
    379    debug("Testing that getExtension() returns the same object each time");
    380    ext = null;
    381    gl.getExtension("OES_standard_derivatives").myProperty = 2;
    382    webglHarnessCollectGarbage();
    383    shouldBe('gl.getExtension("OES_standard_derivatives").myProperty', '2');
    384 }
    385 
    386 function runDeferredLinkTests() {
    387    debug("");
    388    debug("Testing deferred shader compilation tests.");
    389 
    390    // Test for compilation failures that are caused by missing extensions
    391    // do not succeed if extensions are enabled during linking. This would
    392    // only happen for deferred shader compilations.
    393 
    394    // First test if link succeeds with extension enabled.
    395    var glEnabled = wtu.create3DContext();
    396    var extEnabled = glEnabled.getExtension("OES_standard_derivatives");
    397    if (!extEnabled) {
    398        testFailed("Deferred link test expects the extension to be supported");
    399    }
    400 
    401    var vertexShader = wtu.loadShaderFromScript(glEnabled, "goodVertexShader");
    402    var fragmentShader = wtu.loadShaderFromScript(glEnabled, "macroFragmentShader");
    403 
    404    if (!vertexShader || !fragmentShader) {
    405        testFailed("Could not create good shaders.");
    406        return;
    407    }
    408 
    409    var program = wtu.setupProgram(glEnabled, [vertexShader, fragmentShader]);
    410 
    411    if (!program) {
    412        testFailed("Compilation with extension enabled failed.");
    413        return;
    414    }
    415 
    416    // Create new context to test link failure without extension enabled.
    417    var glDeferred = wtu.create3DContext();
    418 
    419    var vertexShader = wtu.loadShaderFromScript(glDeferred, "goodVertexShader", glDeferred.VERTEX_SHADER, undefined, undefined, true);
    420    var fragmentShader = wtu.loadShaderFromScript(glDeferred, "macroFragmentShader", glDeferred.FRAGMENT_SHADER, undefined, undefined, true);
    421 
    422    if (vertexShader == null || fragmentShader == null) {
    423        testFailed("Could not create shaders.");
    424        return;
    425    }
    426 
    427    // Shader compilations should have failed due to extensions not enabled.
    428    glDeferred.getExtension("OES_standard_derivatives");
    429    var program = wtu.setupProgram(glDeferred, [vertexShader, fragmentShader]);
    430    if (program) {
    431        testFailed("Compilation with extension disabled then linking with extension enabled should have failed.");
    432        return;
    433    }
    434 
    435    testPassed("Compilation with extension disabled then linking with extension enabled.");
    436 }
    437 
    438 debug("");
    439 var successfullyParsed = true;
    440 </script>
    441 <script src="../../js/js-test-post.js"></script>
    442 
    443 </body>
    444 </html>