tor-browser

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

xrWebGLLayer_opaque_framebuffer_stencil.https.html (7686B)


      1 <!DOCTYPE html>
      2 <script src="/resources/testharness.js"></script>
      3 <script src="/resources/testharnessreport.js"></script>
      4 <script src="resources/webxr_util.js"></script>
      5 <script src="resources/webxr_test_constants.js"></script>
      6 
      7 <script>
      8 let immersiveTestName = "Ensure that the framebuffer given by the WebGL layer" +
      9  " works with stencil for immersive";
     10 let nonImmersiveTestName = "Ensure that the framebuffer given by the WebGL layer" +
     11  " works with stencil for non-immersive";
     12 
     13 let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
     14 
     15 function createShader(gl, type, source) {
     16  var shader = gl.createShader(type);
     17  gl.shaderSource(shader, source);
     18  gl.compileShader(shader);
     19  var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
     20  if (success) {
     21    return shader;
     22  }
     23 
     24  gl.deleteShader(shader);
     25 }
     26 
     27 function createProgram(gl, vertexShader, fragmentShader) {
     28  var program = gl.createProgram();
     29  gl.attachShader(program, vertexShader);
     30  gl.attachShader(program, fragmentShader);
     31  gl.linkProgram(program);
     32  var success = gl.getProgramParameter(program, gl.LINK_STATUS);
     33  if (success) {
     34    return program;
     35  }
     36 
     37  gl.deleteProgram(program);
     38 }
     39 
     40 let testFunction =
     41  (session, fakeDeviceController, t, sessionObjects) => new Promise((resolve, reject) => {
     42  const gl = sessionObjects.gl;
     43  const webglLayer = sessionObjects.glLayer;
     44  const xrFramebuffer = webglLayer.framebuffer;
     45  const webglCanvas = sessionObjects.gl.canvas;
     46 
     47  session.requestAnimationFrame((time, xrFrame) => {
     48    t.step(() => {
     49      // Make sure we're starting with a clean error slate.
     50      gl.getError();
     51      assert_equals(gl.getError(), gl.NO_ERROR, "Should not initially have any errors");
     52 
     53      if (session.mode === 'inline') {
     54        // Creating a layer with an inline session should return a framebuffer of
     55        // null, and as such most of these tests won't apply.
     56        assert_equals(xrFramebuffer, null, 'inline, fbo = null');
     57        // We need to set canvas size here for inline session testing, since
     58        // xrFramebuffer is null.
     59        webglCanvas.width = webglCanvas.height = 300;
     60        gl.bindFramebuffer(gl.FRAMEBUFFER, xrFramebuffer);
     61        assert_equals(gl.getError(), gl.NO_ERROR, "Binding default framebuffer for inline session");
     62      } else {
     63        assert_not_equals(xrFramebuffer, null, 'immersive, fbo != null');
     64        gl.bindFramebuffer(gl.FRAMEBUFFER, xrFramebuffer);
     65        assert_equals(gl.getError(), gl.NO_ERROR, "Binding WebGLLayer framebuffer");
     66      }
     67 
     68      // Framebuffer status must be complete inside of a XR frame callback.
     69      assert_equals(gl.checkFramebufferStatus(gl.FRAMEBUFFER), gl.FRAMEBUFFER_COMPLETE, "FBO complete");
     70    });
     71    gl.clearColor(1, 1, 1, 1);
     72 
     73    const vs = `
     74    attribute vec4 position;
     75    uniform mat4 matrix;
     76    void main() {
     77      gl_Position = matrix * position;
     78    }
     79    `;
     80 
     81    const fs = `
     82    precision mediump float;
     83    uniform vec4 color;
     84    void main() {
     85      gl_FragColor = color;
     86    }
     87    `;
     88    const vertexShader = createShader(gl, gl.VERTEX_SHADER, vs);
     89    const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fs);
     90    const program = createProgram(gl, vertexShader, fragmentShader);
     91 
     92    const posLoc = gl.getAttribLocation(program, 'position');
     93    const matLoc = gl.getUniformLocation(program, 'matrix');
     94    const colorLoc = gl.getUniformLocation(program, 'color');
     95 
     96    const buf = gl.createBuffer();
     97    gl.bindBuffer(gl.ARRAY_BUFFER, buf);
     98    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
     99       0, -1,
    100       1,  1,
    101      -1,  1,
    102    ]), gl.STATIC_DRAW);
    103 
    104    gl.enableVertexAttribArray(posLoc);
    105    gl.vertexAttribPointer(
    106        posLoc,    // attribute location
    107        2,         // 2 value per vertex
    108        gl.FLOAT,  // 32bit floating point values
    109        false,     // don't normalize
    110        0,         // stride (0 = base on type and size)
    111        0,         // offset into buffer
    112    );
    113 
    114    let xrViewport;
    115    if (session.mode == 'inline') {
    116      xrViewport = { x: 0, y: 0, width: webglCanvas.width, height: webglCanvas.height };
    117    } else {
    118      xrViewport = { x: 0, y: 0, width: webglLayer.framebufferWidth, height: webglLayer.framebufferHeight };
    119    }
    120 
    121    gl.viewport(xrViewport.x, xrViewport.y, xrViewport.width, xrViewport.height);
    122    gl.scissor(xrViewport.x, xrViewport.y, xrViewport.width, xrViewport.height);
    123 
    124    // clear the stencil to 0 (the default)
    125    gl.stencilMask(0xFF);
    126    gl.clearStencil(0x0);
    127    gl.disable( gl.SCISSOR_TEST );
    128    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
    129 
    130    gl.useProgram(program);
    131    let m4 = [1, 0, 0, 0,
    132              0, 1, 0, 0,
    133              0, 0, 1, 0,
    134              0, 0, 0, 1];
    135 
    136    // turn on the stencil
    137    gl.enable(gl.STENCIL_TEST);
    138 
    139    // Drawing into a stencil, always passes, ref val 1, mask 0xFF
    140    gl.stencilFunc(
    141       gl.ALWAYS,
    142       1,
    143       0xFF,
    144    );
    145    // Set it to replace with the ref val (which is 1)
    146    gl.stencilOp(
    147       gl.KEEP,     // stencil test fails
    148       gl.KEEP,     // depth test fails
    149       gl.REPLACE,  // both tests pass
    150    );
    151 
    152    m4[0] = 0.2; m4[5] = 0.2; // scale x and y
    153    // draw a white triangle
    154    gl.uniform4fv(colorLoc, [1, 1, 1, 1]); // white
    155    gl.uniformMatrix4fv(matLoc, false, m4);
    156    gl.colorMask(false, false, false, false);
    157    gl.drawArrays(gl.TRIANGLES, 0, 3);
    158 
    159    gl.colorMask(true, true, true, true);
    160 
    161    // Stencil must be 0
    162    gl.stencilFunc(
    163       gl.EQUAL,
    164       0,
    165       0xFF,
    166    );
    167    // keep stencil unmodified during the draw pass
    168    gl.stencilOp(
    169       gl.KEEP,     // stencil test fails
    170       gl.KEEP,     // depth test fails
    171       gl.KEEP,     // both tests pass
    172    );
    173 
    174    m4[0] = 0.9; m4[5] = -0.9; // scale x and y
    175    // draw a large green triangle
    176    gl.uniform4fv(colorLoc, [0, 1, 0, 1]); // green
    177    gl.uniformMatrix4fv(matLoc, false, m4);
    178    gl.drawArrays(gl.TRIANGLES, 0, 3);
    179 
    180    gl.flush();
    181    gl.finish();
    182    let pixels = new Uint8Array(4);
    183 
    184    // check that the main color is used correctly (green)
    185    pixels[0] = pixels[1] = pixels[2] = pixels[3] = 30;
    186    gl.readPixels(xrViewport.x + xrViewport.width / 2, xrViewport.y + xrViewport.height/4, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    187    if (pixels[0] == 0x0 && pixels[1] == 0xFF && pixels[2] == 0x0) { // green?
    188      // PASSED.
    189    } else if (pixels[0] == 0xFF && pixels[1] == 0xFF && pixels[2] == 0xFF) { // white?
    190      reject("Failed, white detected, must be green");
    191    } else {
    192      reject("Failed, readPixels (1) didn't work, gl error = " + gl.getError() + ", pixel = " +pixels[0] + " " +pixels[1] + " " +pixels[2]);
    193    }
    194 
    195    // check if stencil worked, i.e. white pixels in the center
    196    pixels[0] = pixels[1] = pixels[2] = pixels[3] = 20;
    197    gl.readPixels(xrViewport.x + xrViewport.width / 2, xrViewport.y + xrViewport.height/2, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    198    if (pixels[0] == 0xFF && pixels[1] == 0xFF && pixels[2] == 0xFF) { // white?
    199      // PASSED.
    200    } else if (pixels[0] == 0x0 && pixels[1] == 0xFF && pixels[2] == 0x0) { // green?
    201      reject("Failed, green detected, must be white");
    202    } else {
    203      reject("Failed, readPixels (2) didn't work, gl error = " + gl.getError() + ", pixel = " +pixels[0] + " " +pixels[1] + " " +pixels[2]);
    204    }
    205 
    206    // Finished.
    207    resolve();
    208  });
    209 });
    210 
    211 const gl_props = { antialias: false, alpha: false, stencil: true, depth: true };
    212 
    213 xr_session_promise_test(
    214  nonImmersiveTestName, testFunction, fakeDeviceInitParams, 'inline', {}, {}, gl_props, gl_props);
    215 
    216 xr_session_promise_test(
    217  immersiveTestName, testFunction, fakeDeviceInitParams, 'immersive-vr', {}, {}, gl_props, gl_props);
    218 
    219 </script>