tor-browser

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

webgl-clip-cull-distance.html (14832B)


      1 <!--
      2 Copyright (c) 2022 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 WEBGL_clip_cull_distance 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 <canvas width="32" height="32" id="c"></canvas>
     18 <div id="description"></div>
     19 <div id="console"></div>
     20 <script>
     21 "use strict";
     22 description("This test verifies the functionality of the WEBGL_clip_cull_distance extension, if it is available.");
     23 
     24 debug("");
     25 
     26 var wtu = WebGLTestUtils;
     27 var gl = wtu.create3DContext("c", null, 2);
     28 var ext;
     29 const w = gl.drawingBufferWidth;
     30 const h = gl.drawingBufferHeight;
     31 
     32 function runTestNoExtension() {
     33  debug("");
     34  debug("Check parameters and capabilities without the extension");
     35 
     36  shouldBeNull("gl.getParameter(0x0D32 /* MAX_CLIP_DISTANCES_WEBGL */)");
     37  wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension");
     38  shouldBeNull("gl.getParameter(0x82F9 /* MAX_CULL_DISTANCES_WEBGL */)");
     39  wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension");
     40  shouldBeNull("gl.getParameter(0x82FA /* MAX_COMBINED_CLIP_AND_CULL_DISTANCES_WEBGL */)");
     41  wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension");
     42 
     43  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
     44 
     45  const assertState = (i) => {
     46    shouldBeFalse(`gl.isEnabled(${0x3000 + i} /* CLIP_DISTANCE${i}_WEBGL */)`);
     47    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension");
     48 
     49    shouldBeNull(`gl.getParameter(${0x3000 + i} /* CLIP_DISTANCE${i}_WEBGL */)`);
     50    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension");
     51  };
     52 
     53  for (let i = 0; i < 8; i++) {
     54    assertState(i);
     55 
     56    gl.enable(0x3000 + i /* CLIP_DISTANCEi_WEBGL */);
     57    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "capability unknown without enabling the extension");
     58 
     59    assertState(i);
     60 
     61    gl.disable(0x3000 + i /* CLIP_DISTANCEi_WEBGL */);
     62    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "capability unknown without enabling the extension");
     63 
     64    assertState(i);
     65  }
     66 
     67  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
     68  debug("");
     69 }
     70 
     71 function checkEnums() {
     72  debug("");
     73  debug("Check enums");
     74  shouldBe("ext.MAX_CLIP_DISTANCES_WEBGL", "0x0D32");
     75  shouldBe("ext.MAX_CULL_DISTANCES_WEBGL", "0x82F9");
     76  shouldBe("ext.MAX_COMBINED_CLIP_AND_CULL_DISTANCES_WEBGL", "0x82FA");
     77  shouldBe("ext.CLIP_DISTANCE0_WEBGL", "0x3000");
     78  shouldBe("ext.CLIP_DISTANCE1_WEBGL", "0x3001");
     79  shouldBe("ext.CLIP_DISTANCE2_WEBGL", "0x3002");
     80  shouldBe("ext.CLIP_DISTANCE3_WEBGL", "0x3003");
     81  shouldBe("ext.CLIP_DISTANCE4_WEBGL", "0x3004");
     82  shouldBe("ext.CLIP_DISTANCE5_WEBGL", "0x3005");
     83  shouldBe("ext.CLIP_DISTANCE6_WEBGL", "0x3006");
     84  shouldBe("ext.CLIP_DISTANCE7_WEBGL", "0x3007");
     85 }
     86 
     87 function checkQueries() {
     88  debug("");
     89  debug("Check parameters");
     90  shouldBeGreaterThanOrEqual('gl.getParameter(ext.MAX_CLIP_DISTANCES_WEBGL)', '8');
     91  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
     92 
     93  const maxCullDistances = gl.getParameter(ext.MAX_CULL_DISTANCES_WEBGL);
     94  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
     95 
     96  if (maxCullDistances == 0) {
     97    testPassed("No cull distance support");
     98    shouldBe("gl.getParameter(ext.MAX_COMBINED_CLIP_AND_CULL_DISTANCES_WEBGL)", "0");
     99    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    100  } else if (maxCullDistances >= 8) {
    101    testPassed("Optional cull distance support");
    102    shouldBeGreaterThanOrEqual("gl.getParameter(ext.MAX_COMBINED_CLIP_AND_CULL_DISTANCES_WEBGL)", "8");
    103    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    104  } else {
    105    testFailed("Invalid number of supported cull distances");
    106  }
    107 
    108  debug("");
    109  debug("Check clip distance capabilities");
    110 
    111  const assertState = (i, s) => {
    112    shouldBe(`gl.isEnabled(${0x3000 + i} /* CLIP_DISTANCE${i}_WEBGL */)`, s ? "true" : "false");
    113    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    114 
    115    shouldBe(`gl.getParameter(${0x3000 + i} /* CLIP_DISTANCE${i}_WEBGL */)`, s ? "true" : "false");
    116    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    117  };
    118 
    119  for (let i = 0; i < 8; i++) {
    120    assertState(i, false);
    121 
    122    gl.enable(ext.CLIP_DISTANCE0_WEBGL + i);
    123    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    124 
    125    assertState(i, true);
    126 
    127    gl.disable(ext.CLIP_DISTANCE0_WEBGL + i);
    128    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    129 
    130    assertState(i, false);
    131  }
    132 }
    133 
    134 function checkClipDistance() {
    135  debug("");
    136  debug("Check clip distance operation");
    137 
    138  const vs = `#version 300 es
    139 #extension GL_ANGLE_clip_cull_distance : require
    140 
    141 uniform vec4 u_plane;
    142 in vec2 a_position;
    143 void main()
    144 {
    145    gl_Position = vec4(a_position, 0.0, 1.0);
    146    gl_ClipDistance[0] = dot(gl_Position, u_plane);
    147 }`;
    148 
    149  const program = wtu.setupProgram(gl, [vs, wtu.simpleColorFragmentShaderESSL300]);
    150  gl.useProgram(program);
    151  gl.uniform4fv(gl.getUniformLocation(program, 'u_color'), [1.0, 0.0, 0.0, 1.0]);
    152 
    153  gl.enable(ext.CLIP_DISTANCE0_WEBGL);
    154 
    155  // Clear to blue
    156  gl.clearColor(0, 0, 1, 1);
    157  gl.clear(gl.COLOR_BUFFER_BIT);
    158 
    159  wtu.setupUnitQuad(gl);
    160 
    161  // Draw full screen quad with color red
    162  gl.uniform4f(gl.getUniformLocation(program, "u_plane"), 1, 0, 0, 0.5);
    163  wtu.drawUnitQuad(gl);
    164  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    165 
    166  // All pixels on the left of the plane x = -0.5 must be blue
    167  let x      = 0;
    168  let y      = 0;
    169  let width  = w / 4 - 1;
    170  let height = h;
    171  wtu.checkCanvasRect(gl, x, y, width, height,
    172                      [0, 0, 255, 255], "should be blue");
    173 
    174  // All pixels on the right of the plane x = -0.5 must be red
    175  x      = w / 4 + 2;
    176  y      = 0;
    177  width  = w - x;
    178  height = h;
    179  wtu.checkCanvasRect(gl, x, y, width, height,
    180                      [255, 0, 0, 255], "should be red");
    181 
    182  // Clear to green
    183  gl.clearColor(0, 1, 0, 1);
    184  gl.clear(gl.COLOR_BUFFER_BIT);
    185 
    186  // Draw full screen quad with color red
    187  gl.uniform4f(gl.getUniformLocation(program, "u_plane"), -1, 0, 0, -0.5);
    188  wtu.drawUnitQuad(gl);
    189  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    190 
    191  // All pixels on the left of the plane x = -0.5 must be red
    192  x      = 0;
    193  y      = 0;
    194  width  = w / 4 - 1;
    195  height = h;
    196  wtu.checkCanvasRect(gl, x, y, width, height,
    197                      [255, 0, 0, 255], "should be red");
    198 
    199  // All pixels on the right of the plane x = -0.5 must be green
    200  x      = w / 4 + 2;
    201  y      = 0;
    202  width  = w - x;
    203  height = h;
    204  wtu.checkCanvasRect(gl, x, y, width, height,
    205                      [0, 255, 0, 255], "should be green");
    206 
    207  // Disable CLIP_DISTANCE0 and draw again
    208  gl.disable(ext.CLIP_DISTANCE0_WEBGL);
    209  wtu.drawUnitQuad(gl);
    210 
    211  // All pixels must be red
    212  wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
    213 }
    214 
    215 function checkClipDistanceInterpolation() {
    216  debug("");
    217  debug("Check clip distance interpolation");
    218 
    219  const vs = `#version 300 es
    220 #extension GL_ANGLE_clip_cull_distance : require
    221 in vec2 a_position;
    222 void main()
    223 {
    224  gl_Position = vec4(a_position, 0.0, 1.0);
    225  gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
    226  gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
    227  gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
    228  gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
    229  gl_ClipDistance[4] = gl_ClipDistance[0];
    230  gl_ClipDistance[5] = gl_ClipDistance[1];
    231  gl_ClipDistance[6] = gl_ClipDistance[2];
    232  gl_ClipDistance[7] = gl_ClipDistance[3];
    233 }`;
    234 
    235  const fs = `#version 300 es
    236 #extension GL_ANGLE_clip_cull_distance : require
    237 precision highp float;
    238 out vec4 my_FragColor;
    239 void main()
    240 {
    241  float r = gl_ClipDistance[0] + gl_ClipDistance[1];
    242  float g = gl_ClipDistance[2] + gl_ClipDistance[3];
    243  float b = gl_ClipDistance[4] + gl_ClipDistance[5];
    244  float a = gl_ClipDistance[6] + gl_ClipDistance[7];
    245  my_FragColor = vec4(r, g, b, a) * 0.5;
    246 }`;
    247 
    248  const program = wtu.setupProgram(gl, [vs, fs]);
    249  gl.useProgram(program);
    250 
    251  gl.enable(ext.CLIP_DISTANCE0_WEBGL);
    252  gl.enable(ext.CLIP_DISTANCE1_WEBGL);
    253  gl.enable(ext.CLIP_DISTANCE2_WEBGL);
    254  gl.enable(ext.CLIP_DISTANCE3_WEBGL);
    255  gl.enable(ext.CLIP_DISTANCE4_WEBGL);
    256  gl.enable(ext.CLIP_DISTANCE5_WEBGL);
    257  gl.enable(ext.CLIP_DISTANCE6_WEBGL);
    258  gl.enable(ext.CLIP_DISTANCE7_WEBGL);
    259 
    260  wtu.setupUnitQuad(gl);
    261 
    262  // Clear to blue
    263  gl.clearColor(0, 0, 1, 1);
    264  gl.clear(gl.COLOR_BUFFER_BIT);
    265 
    266  // Draw full screen quad with color gray
    267  wtu.drawUnitQuad(gl);
    268  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    269 
    270  const data = new Uint8Array(w * h * 4);
    271  gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, data);
    272  let passed = true;
    273  for (let x = 0; x < w; x++) {
    274    for (let y = 0; y < h; y++) {
    275      const currentPosition = (y * h + x) * 4;
    276      const inside = (x >= w / 4 && x < w * 3 / 4 && y >= h / 4 && y < h * 3 / 4);
    277      const expected = inside ? [127, 127, 127, 127] : [0, 0, 255, 255];
    278      const actual = data.slice(currentPosition, currentPosition + 4);
    279      if (Math.abs(actual[0] - expected[0]) > 1 ||
    280          Math.abs(actual[1] - expected[1]) > 1 ||
    281          Math.abs(actual[2] - expected[2]) > 1 ||
    282          Math.abs(actual[3] - expected[3]) > 1) {
    283        passed = false;
    284      }
    285    }
    286  }
    287  if (passed) {
    288    testPassed("Correct clip distance interpolation");
    289  } else {
    290    testFailed("Incorrect clip distance interpolation");
    291  }
    292 }
    293 
    294 function checkCullDistance() {
    295  debug("");
    296  debug("Check cull distance operation");
    297 
    298  if (gl.getParameter(ext.MAX_CULL_DISTANCES_WEBGL) == 0) {
    299    testPassed("No cull distance support");
    300    return;
    301  }
    302 
    303  const vs = `#version 300 es
    304 #extension GL_ANGLE_clip_cull_distance : require
    305 
    306 uniform vec4 u_plane;
    307 in vec2 a_position;
    308 void main()
    309 {
    310    gl_Position = vec4(a_position, 0.0, 1.0);
    311    gl_CullDistance[0] = dot(gl_Position, u_plane);
    312 }`;
    313 
    314  const program = wtu.setupProgram(gl, [vs, wtu.simpleColorFragmentShaderESSL300]);
    315  gl.useProgram(program);
    316  gl.uniform4fv(gl.getUniformLocation(program, 'u_color'), [1.0, 0.0, 0.0, 1.0]);
    317 
    318  // Clear to blue
    319  gl.clearColor(0, 0, 1, 1);
    320  gl.clear(gl.COLOR_BUFFER_BIT);
    321 
    322  wtu.setupUnitQuad(gl);
    323 
    324  // Draw full screen quad with color red
    325  gl.uniform4f(gl.getUniformLocation(program, "u_plane"), 1, 0, 0, 0.5);
    326  wtu.drawUnitQuad(gl);
    327  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    328 
    329  // All pixels must be red
    330  wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
    331 
    332  // Clear to green
    333  gl.clearColor(0, 1, 0, 1);
    334  gl.clear(gl.COLOR_BUFFER_BIT);
    335 
    336  // Draw full screen quad with color red
    337  gl.uniform4f(gl.getUniformLocation(program, "u_plane"), -1, 1, 0, -0.5);
    338  wtu.drawUnitQuad(gl);
    339  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    340 
    341  // All pixels above the y > x line must be red
    342  const data = new Uint8Array(w * h * 4);
    343  gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, data);
    344  let passed = true;
    345  for (let x = 0; x < w; ++x) {
    346    for (let y = 0; y < h; ++y) {
    347      if (y <= x + 2 && y >= x - 2) continue; // skip the edge
    348      const currentPosition = (y * h + x) * 4;
    349      const actual = data.slice(currentPosition, currentPosition + 2);
    350      const expected = (y > x) ? [255, 0] : [0, 255];
    351      if (actual[0] != expected[0] || actual[1] != expected[1]) {
    352        passed = false;
    353      }
    354    }
    355  }
    356  if (passed) {
    357    testPassed("Correct cull distance operation");
    358  } else {
    359    testFailed("Incorrect cull distance operation");
    360  }
    361 }
    362 
    363 function checkCullDistanceInterpolation() {
    364  debug("");
    365  debug("Check cull distance interpolation");
    366 
    367  if (gl.getParameter(ext.MAX_CULL_DISTANCES_WEBGL) == 0) {
    368    testPassed("No cull distance support");
    369    return;
    370  }
    371 
    372  const vs = `#version 300 es
    373 #extension GL_ANGLE_clip_cull_distance : require
    374 in vec2 a_position;
    375 void main()
    376 {
    377  gl_Position = vec4(a_position, 0.0, 1.0);
    378  gl_CullDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 1));
    379  gl_CullDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 1));
    380  gl_CullDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 1));
    381  gl_CullDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 1));
    382  gl_CullDistance[4] = gl_CullDistance[0];
    383  gl_CullDistance[5] = gl_CullDistance[1];
    384  gl_CullDistance[6] = gl_CullDistance[2];
    385  gl_CullDistance[7] = gl_CullDistance[3];
    386 }`;
    387 
    388  const fs = `#version 300 es
    389 #extension GL_ANGLE_clip_cull_distance : require
    390 precision highp float;
    391 out vec4 my_FragColor;
    392 void main()
    393 {
    394  float r = gl_CullDistance[0] + gl_CullDistance[1];
    395  float g = gl_CullDistance[2] + gl_CullDistance[3];
    396  float b = gl_CullDistance[4] + gl_CullDistance[5];
    397  float a = gl_CullDistance[6] + gl_CullDistance[7];
    398  my_FragColor = vec4(r, g, b, a) * 0.25;
    399 }`;
    400 
    401  const program = wtu.setupProgram(gl, [vs, fs]);
    402  gl.useProgram(program);
    403 
    404  // Clear to blue
    405  gl.clearColor(0, 0, 1, 1);
    406  gl.clear(gl.COLOR_BUFFER_BIT);
    407 
    408  wtu.setupQuad(gl, {scale: 0.5});
    409 
    410  // Draw a small quad with color gray
    411  wtu.drawUnitQuad(gl);
    412  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    413 
    414  const data = new Uint8Array(w * h * 4);
    415  gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, data);
    416  let passed = true;
    417  for (let x = 0; x < w; x++) {
    418    for (let y = 0; y < h; y++) {
    419      const currentPosition = (y * h + x) * 4;
    420      const inside = (x >= w / 4 && x < w * 3 / 4 && y >= h / 4 && y < h * 3 / 4);
    421      const expected = inside ? [127, 127, 127, 127] : [0, 0, 255, 255];
    422      const actual = data.slice(currentPosition, currentPosition + 4);
    423      if (Math.abs(actual[0] - expected[0]) > 1 ||
    424          Math.abs(actual[1] - expected[1]) > 1 ||
    425          Math.abs(actual[2] - expected[2]) > 1 ||
    426          Math.abs(actual[3] - expected[3]) > 1) {
    427        passed = false;
    428      }
    429    }
    430  }
    431  if (passed) {
    432    testPassed("Correct cull distance interpolation");
    433  } else {
    434    testFailed("Incorrect cull distance interpolation");
    435  }
    436 }
    437 
    438 function runTestExtension() {
    439  checkEnums();
    440  checkQueries();
    441 
    442  checkClipDistance();
    443  checkClipDistanceInterpolation();
    444 
    445  checkCullDistance();
    446  checkCullDistanceInterpolation();
    447 }
    448 
    449 function runTest() {
    450  if (!gl) {
    451    testFailed("context does not exist");
    452  } else {
    453    testPassed("context exists");
    454 
    455    runTestNoExtension();
    456 
    457    ext = gl.getExtension("WEBGL_clip_cull_distance");
    458 
    459    wtu.runExtensionSupportedTest(gl, "WEBGL_clip_cull_distance", ext !== null);
    460 
    461    if (ext !== null) {
    462      runTestExtension();
    463    } else {
    464      testPassed("No WEBGL_clip_cull_distance support -- this is legal");
    465    }
    466  }
    467 }
    468 
    469 runTest();
    470 
    471 var successfullyParsed = true;
    472 </script>
    473 <script src="../../js/js-test-post.js"></script>
    474 </body>
    475 </html>