tor-browser

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

context-lost-restored.html (10112B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4 <meta charset="utf-8">
      5 <!--
      6 Copyright (c) 2019 The Khronos Group Inc.
      7 Use of this source code is governed by an MIT-style license that can be
      8 found in the LICENSE.txt file.
      9 -->
     10 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
     11 <script src="../../js/js-test-pre.js"></script>
     12 <script src="../../js/webgl-test-utils.js"></script>
     13 <script>
     14 "use strict";
     15 var wtu = WebGLTestUtils;
     16 var canvas;
     17 var gl;
     18 var shouldGenerateGLError;
     19 var WEBGL_lose_context;
     20 var new_WEBGL_lose_context;
     21 var bufferObjects;
     22 var program;
     23 var texture;
     24 var texColor = [255, 10, 20, 255];
     25 var allowRestore;
     26 var contextLostEventFired;
     27 var contextRestoredEventFired;
     28 var OES_vertex_array_object;
     29 var old_OES_vertex_array_object;
     30 var vertexArrayObject;
     31 var OES_texture_float;
     32 var newExtension;
     33 
     34 function init()
     35 {
     36    enableJSTestPreVerboseLogging();
     37    description("Tests behavior under a restored context.");
     38 
     39    shouldGenerateGLError = wtu.shouldGenerateGLError;
     40    testLosingContext();
     41 }
     42 
     43 function setupTest()
     44 {
     45    canvas = document.createElement("canvas");
     46    canvas.width = 1;
     47    canvas.height = 1;
     48    gl = wtu.create3DContext(canvas);
     49    WEBGL_lose_context = getExtensionAndAddProperty(gl, "WEBGL_lose_context");
     50    if (!WEBGL_lose_context) {
     51        debug("Could not find WEBGL_lose_context extension");
     52        return false;
     53    }
     54 
     55    // Try to get a few extensions
     56    OES_vertex_array_object = getExtensionAndAddProperty(gl, "OES_vertex_array_object");
     57    OES_texture_float = getExtensionAndAddProperty(gl, "OES_texture_float");
     58 
     59    return true;
     60 }
     61 
     62 function getExtensionAndAddProperty(gl, name) {
     63  var ext = wtu.getExtensionWithKnownPrefixes(gl, name);
     64  if (ext) {
     65    ext.webglTestProperty = true;
     66  }
     67  return ext;
     68 }
     69 
     70 function reGetExtensionAndTestForProperty(gl, name, expectProperty) {
     71  newExtension = wtu.getExtensionWithKnownPrefixes(gl, name);
     72  // NOTE: while getting a extension after context lost/restored is allowed to fail
     73  // for the purpose the conformance tests it is not.
     74  //
     75  // Hypothetically the user can switch GPUs live. For example on Windows, install 2 GPUs,
     76  // then in the control panen enable 1, disable the others and visa versa. Since the GPUs
     77  // have different capabilities one or the other may not support a particlar extension.
     78  //
     79  // But, for the purpose of the conformance tests the context is expected to restore
     80  // on the same GPU and therefore the extensions that succeeded previously should
     81  // succeed on restore.
     82  shouldBeTrue("newExtension != null");
     83  if (expectProperty) {
     84    shouldBeTrue("newExtension.webglTestProperty === true");
     85  } else {
     86    shouldBeTrue("newExtension.webglTestProperty === undefined");
     87  }
     88  return newExtension;
     89 }
     90 
     91 function testLosingContext()
     92 {
     93    if (!setupTest()) {
     94        finishTest();
     95        return;
     96    }
     97 
     98    debug("Test losing a context and inability to restore it.");
     99 
    100    canvas.addEventListener("webglcontextlost", function(e) {
    101       testLostContext(e);
    102       // restore the context after this event has exited.
    103       setTimeout(function() {
    104         // we didn't call prevent default so we should not be able to restore the context
    105         shouldGenerateGLError(gl, gl.INVALID_OPERATION, "WEBGL_lose_context.restoreContext()");
    106         testLosingAndRestoringContext();
    107       }, 0);
    108    });
    109    canvas.addEventListener("webglcontextrestored", testShouldNotRestoreContext);
    110    allowRestore = false;
    111    contextLostEventFired = false;
    112    contextRestoredEventFired = false;
    113 
    114    testOriginalContext();
    115    WEBGL_lose_context.loseContext();
    116    // The context should be lost immediately.
    117    shouldBeTrue("gl.isContextLost()");
    118    shouldBe("gl.getError()", "gl.CONTEXT_LOST_WEBGL");
    119    shouldBe("gl.getError()", "gl.NO_ERROR");
    120    // gl methods should be no-ops
    121    shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)");
    122    // but the event should not have been fired.
    123    shouldBeFalse("contextLostEventFired");
    124 }
    125 
    126 function testLosingAndRestoringContext()
    127 {
    128    if (!setupTest())
    129        finishTest();
    130 
    131    debug("");
    132    debug("Test losing and restoring a context.");
    133 
    134    canvas.addEventListener("webglcontextlost", function(e) {
    135      testLostContext(e);
    136      // restore the context after this event has exited.
    137      setTimeout(function() {
    138        shouldGenerateGLError(gl, gl.NO_ERROR, "WEBGL_lose_context.restoreContext()");
    139        // Calling restoreContext() twice should not cause error or crash
    140        shouldGenerateGLError(gl, gl.NO_ERROR, "WEBGL_lose_context.restoreContext()");
    141        // The context should still be lost. It will not get restored until the
    142        // webglrestorecontext event is fired.
    143        shouldBeTrue("gl.isContextLost()");
    144        shouldBe("gl.getError()", "gl.NO_ERROR");
    145        // gl methods should still be no-ops
    146        shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)");
    147      }, 0);
    148    });
    149    canvas.addEventListener("webglcontextrestored", function() {
    150      testRestoredContext();
    151      finishTest();
    152    });
    153    allowRestore = true;
    154    contextLostEventFired = false;
    155    contextRestoredEventFired = false;
    156 
    157    testOriginalContext();
    158    WEBGL_lose_context.loseContext();
    159    // The context should be lost immediately.
    160    shouldBeTrue("gl.isContextLost()");
    161    shouldBe("gl.getError()", "gl.CONTEXT_LOST_WEBGL");
    162    shouldBe("gl.getError()", "gl.NO_ERROR");
    163    // gl methods should be no-ops
    164    shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)");
    165    // but the event should not have been fired.
    166    shouldBeFalse("contextLostEventFired");
    167 }
    168 
    169 function testRendering()
    170 {
    171    gl.clearColor(0, 0, 0, 255);
    172    gl.colorMask(1, 1, 1, 0);
    173    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    174 
    175    program = wtu.setupSimpleTextureProgram(gl);
    176    bufferObjects = wtu.setupUnitQuad(gl);
    177    texture = wtu.createColoredTexture(gl, canvas.width, canvas.height, texColor);
    178 
    179    gl.uniform1i(gl.getUniformLocation(program, "tex"), 0);
    180    wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
    181 
    182    var compare = texColor.slice(0, 3);
    183    wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, compare, "shouldBe " + compare);
    184 
    185    shouldBe("gl.getError()", "gl.NO_ERROR");
    186 }
    187 
    188 function testOriginalContext()
    189 {
    190    debug("Test valid context");
    191    shouldBeFalse("gl.isContextLost()");
    192    shouldBe("gl.getError()", "gl.NO_ERROR");
    193    testRendering();
    194    debug("");
    195 }
    196 
    197 function testLostContext(e)
    198 {
    199    debug("Test lost context");
    200    shouldBeFalse("contextLostEventFired");
    201    contextLostEventFired = true;
    202    shouldBeTrue("gl.isContextLost()");
    203    shouldBe("gl.getError()", "gl.NO_ERROR");
    204    debug("");
    205    if (allowRestore)
    206      e.preventDefault();
    207 }
    208 
    209 function testShouldNotRestoreContext(e)
    210 {
    211    testFailed("Should not restore the context unless preventDefault is called on the context lost event");
    212    debug("");
    213 }
    214 
    215 function testResources(expected)
    216 {
    217    var tests = [
    218        "gl.bindTexture(gl.TEXTURE_2D, texture)",
    219        "gl.useProgram(program)",
    220        "gl.bindBuffer(gl.ARRAY_BUFFER, bufferObjects[0])",
    221    ];
    222 
    223    for (var i = 0; i < tests.length; ++i)
    224        shouldGenerateGLError(gl, expected, tests[i]);
    225 }
    226 
    227 function testOESTextureFloat() {
    228  if (OES_texture_float) {
    229    // Extension must still be lost.
    230    var tex = gl.createTexture();
    231    gl.bindTexture(gl.TEXTURE_2D, tex);
    232    shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)");
    233    // Try re-enabling extension
    234    OES_texture_float = reGetExtensionAndTestForProperty(gl, "OES_texture_float", false);
    235    shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)");
    236  }
    237 }
    238 
    239 function testOESVertexArrayObject() {
    240  if (OES_vertex_array_object) {
    241    // Extension must still be lost.
    242    let vao = OES_vertex_array_object.createVertexArrayOES();
    243    assertMsg(vao, "[with extension lost] createVertexArrayOES() -> non-null");
    244    assertMsg(!OES_vertex_array_object.isVertexArrayOES(vao), "[with context lost] isVertexArrayOES(createVertexArrayOES()) -> false");
    245    // Try re-enabling extension
    246 
    247    old_OES_vertex_array_object = OES_vertex_array_object;
    248    OES_vertex_array_object = reGetExtensionAndTestForProperty(gl, "OES_vertex_array_object", false);
    249 
    250    vao = OES_vertex_array_object.createVertexArrayOES();
    251    assertMsg(vao, "[with new non-lost extension] createVertexArrayOES() -> non-null");
    252    assertMsg(!OES_vertex_array_object.isVertexArrayOES(vao), "[with new non-lost extension, before bindVAO] isVertexArrayOES(createVertexArrayOES()) -> false");
    253    OES_vertex_array_object.bindVertexArrayOES(vao);
    254    OES_vertex_array_object.bindVertexArrayOES(null);
    255    assertMsg(OES_vertex_array_object.isVertexArrayOES(vao), "[with new non-lost extension, after bindVAO] isVertexArrayOES(createVertexArrayOES()) -> true");
    256 
    257    vao = old_OES_vertex_array_object.createVertexArrayOES();
    258    assertMsg(vao, "[with old lost extension] createVertexArrayOES() -> non-null");
    259    assertMsg(!old_OES_vertex_array_object.isVertexArrayOES(vao), "[with old lost extension] isVertexArrayOES(createVertexArrayOES()) -> false");
    260  }
    261 }
    262 
    263 function testExtensions() {
    264  testOESTextureFloat();
    265  testOESVertexArrayObject();
    266  // Only the WEBGL_lose_context extension should be the same object after context lost.
    267  new_WEBGL_lose_context = reGetExtensionAndTestForProperty(gl, "WEBGL_lose_context", true);
    268 }
    269 
    270 function testRestoredContext()
    271 {
    272    debug("Test restored context");
    273    shouldBeFalse("contextRestoredEventFired");
    274    contextRestoredEventFired = true;
    275    shouldBeFalse("gl.isContextLost()");
    276    shouldBe("gl.getError()", "gl.NO_ERROR");
    277 
    278    // Validate that using old resources fails.
    279    testResources(gl.INVALID_OPERATION);
    280 
    281    testRendering();
    282 
    283    // Validate new resources created in testRendering().
    284    testResources(gl.NO_ERROR);
    285 
    286    testExtensions();
    287 
    288    debug("");
    289 }
    290 
    291 
    292 </script>
    293 </head>
    294 <body onload="init()">
    295 <div id="description"></div>
    296 <div id="console"></div>
    297 </body>
    298 </html>