tor-browser

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

ovr_multiview2.html (22842B)


      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 OVR_multiview2 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 <script src="../../js/tests/ovr_multiview2_util.js"></script>
     16 <script id="requireDefine_GL_OVR_multiview2" type="x-shader/x-fragment">#version 300 es
     17 #ifndef GL_OVR_multiview2
     18    #error no GL_OVR_multiview2
     19 #endif
     20 precision highp float;
     21 out vec4 my_FragColor;
     22 void main() {
     23    my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
     24 }
     25 </script>
     26 <script id="forbidDefine_GL_OVR_multiview" type="x-shader/x-fragment">#version 300 es
     27 #ifdef GL_OVR_multiview
     28    #error legacy GL_OVR_multiview support must be forbidden
     29 #endif
     30 precision highp float;
     31 out vec4 my_FragColor;
     32 void main() {
     33    my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
     34 }
     35 </script>
     36 <script id="legacyMultiview1Shader" type="x-shader/x-fragment">#version 300 es
     37 #extension GL_OVR_multiview: require
     38 precision highp float;
     39 out vec4 my_FragColor;
     40 void main() {
     41    my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
     42 }
     43 </script>
     44 </head>
     45 <body>
     46 <div id="description"></div>
     47 <div id="console"></div>
     48 <script>
     49 "use strict";
     50 
     51 let wtu = WebGLTestUtils;
     52 let gl = wtu.create3DContext(null, null, 2);
     53 let ext = null;
     54 
     55 function runExtensionDisabledTest()
     56 {
     57    debug("");
     58    debug("Testing queries with extension disabled");
     59 
     60    let maxViews = gl.getParameter(0x9631);
     61    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Can't query MAX_VIEWS_OVR without enabling OVR_multiview2");
     62 
     63    let baseViewIndex = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, 0x9630);
     64    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Can't query FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR without enabling OVR_multiview2");
     65    let numViews = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, 0x9632);
     66    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Can't query FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR without enabling OVR_multiview2");
     67 }
     68 
     69 function runQueryTest()
     70 {
     71    debug("");
     72    debug("Testing querying MAX_VIEWS_OVR");
     73 
     74    let maxViews = gl.getParameter(ext.MAX_VIEWS_OVR);
     75    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from querying MAX_VIEWS_OVR");
     76    if (typeof maxViews != 'number') {
     77        testFailed("Type of the value of MAX_VIEWS_OVR should be number, was " + (typeof maxViews));
     78    }
     79    if (maxViews < 2) {
     80        testFailed("Value of MAX_VIEWS_OVR should be at least two, was: " + maxViews);
     81    }
     82 }
     83 
     84 function runDefaultFramebufferQueryTest()
     85 {
     86    debug("");
     87    debug("Testing querying base view index and num views on the default framebuffer");
     88    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
     89    // Same behavior as FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
     90    gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, ext.FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR);
     91    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR is INVALID_ENUM for default framebuffer");
     92    gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, ext.FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR);
     93    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR is INVALID_ENUM for default framebuffer");
     94 }
     95 
     96 function runInvalidTextureTypeTest()
     97 {
     98    debug("");
     99    debug("Testing invalid texture types");
    100    let tex2D = createTextureWithNearestFiltering(gl.TEXTURE_2D);
    101    gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 128, 128);
    102    ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
    103    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should not be possible to create a multiview framebuffer against a 2D texture");
    104 
    105    let texCube = createTextureWithNearestFiltering(gl.TEXTURE_CUBE_MAP);
    106    gl.texStorage2D(gl.TEXTURE_CUBE_MAP, 1, gl.RGBA8, 128, 128);
    107    ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texCube, 0, 0, 1);
    108    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should not be possible to create a multiview framebuffer against a cube map texture");
    109 
    110    let tex3D = createTextureWithNearestFiltering(gl.TEXTURE_3D);
    111    gl.texStorage3D(gl.TEXTURE_3D, 1, gl.RGBA8, 128, 128, 2);
    112    ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex3D, 0, 0, 2);
    113    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should not be possible to create a multiview framebuffer against a 3D texture");
    114 }
    115 
    116 /**
    117 * If allocateStorage is true, the test will allocate texture storage. If it is false, attachments are done without allocations.
    118 */
    119 function runFramebufferQueryTest(allocateStorage)
    120 {
    121    debug("");
    122    debug("Testing querying attachment object type, baseViewIndex, numViews and framebuffer status. Texture storage is " + (allocateStorage ? "allocated" : "not allocated") + ".");
    123 
    124    let checkQueryResult = function(actual, expected, name) {
    125        if (actual != expected) {
    126            testFailed('Unexpected ' + name + ': ' + actual + ' when it was set to ' + expected);
    127        }  else {
    128            testPassed(name + ' was ' + actual + ' when queried from the framebuffer');
    129        }
    130    }
    131 
    132    let setupAndQuery = function(colorTex, levelSet, baseViewIndexSet, numViewsSet) {
    133        ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, levelSet, baseViewIndexSet, numViewsSet);
    134        let objectType = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
    135        if (objectType != gl.TEXTURE) {
    136            testFailed('Unexpected FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE ' + wtu.glEnumToString(gl, objectType) + ', should be TEXTURE');
    137        } else {
    138            testPassed('FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE was TEXTURE');
    139        }
    140 
    141        let level = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL);
    142        checkQueryResult(level, levelSet, "level");
    143 
    144        let textureName = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
    145        checkQueryResult(textureName, colorTex, "texture object");
    146 
    147        let baseViewIndex = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR);
    148        checkQueryResult(baseViewIndex, baseViewIndexSet, "baseViewIndex");
    149 
    150        let numViews = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR);
    151        checkQueryResult(numViews, numViewsSet, "numViews");
    152 
    153        let layer = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER);
    154        checkQueryResult(layer, baseViewIndexSet, "texture layer (should match baseViewIndex)");
    155    }
    156 
    157    let setupSecondAttachmentAndQueryStatus = function(colorTex2, baseViewIndex, numViews, expectedStatus, msg) {
    158        ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, colorTex2, 0, baseViewIndex, numViews);
    159        let status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
    160        if (status != expectedStatus) {
    161            testFailed('Framebuffer status: ' + wtu.glEnumToString(gl, status) + ' did not match with the expected value: ' + wtu.glEnumToString(gl, expectedStatus) + ' - ' + msg);
    162        }  else {
    163            testPassed('Framebuffer status: ' + wtu.glEnumToString(gl, status) + ' matched with the expected value - ' + msg);
    164        }
    165    }
    166 
    167    let maxViews = gl.getParameter(ext.MAX_VIEWS_OVR);
    168 
    169    let fb = gl.createFramebuffer();
    170    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    171    let baseViewIndex = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR);
    172    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Querying baseViewIndex from a nonexistent attachment");
    173    if (baseViewIndex != null) {
    174        testFailed('Unexpected baseViewIndex ' + baseViewIndex + ' on a framebuffer without attachments');
    175    }  else {
    176        testPassed('Querying baseViewIndex returned null on a framebuffer without attachments');
    177    }
    178    let numViews = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR);
    179    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Querying numViews from a nonexistent attachment");
    180    if (numViews != null) {
    181        testFailed('Unexpected numViews ' + numViews + ' on a framebuffer without attachments');
    182    } else {
    183        testPassed('Querying numViews returned null on a framebuffer without attachments');
    184    }
    185 
    186    let colorTex = createTextureWithNearestFiltering(gl.TEXTURE_2D_ARRAY);
    187    if (allocateStorage) {
    188        gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 2, gl.RGBA8, 128, 128, maxViews);
    189    }
    190    setupAndQuery(colorTex, 0, 0, maxViews);
    191    setupAndQuery(colorTex, 1, 0, 2);
    192    setupAndQuery(colorTex, 0, 1, maxViews - 1);
    193 
    194    // Test matching and mismatching attachments for framebuffer status.
    195    let colorTex2 = createTextureWithNearestFiltering(gl.TEXTURE_2D_ARRAY);
    196    if (allocateStorage) {
    197        gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, 128, 128, maxViews);
    198    }
    199    setupSecondAttachmentAndQueryStatus(colorTex2, 1, maxViews - 1, allocateStorage ? gl.FRAMEBUFFER_COMPLETE : gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT, 'matching baseViewIndex and numViews on different attachments');
    200    if (allocateStorage) {
    201        setupSecondAttachmentAndQueryStatus(colorTex2, 0, maxViews - 1, ext.FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR, 'baseViewIndex mismatch');
    202        ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, maxViews);
    203        setupSecondAttachmentAndQueryStatus(colorTex2, 0, maxViews - 1, ext.FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR, 'numViews mismatch');
    204    }
    205 
    206    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from framebuffer queries");
    207 }
    208 
    209 function runInvalidViewsTest()
    210 {
    211    debug("");
    212    debug("Testing invalid out-of-range values for baseViewIndex and numViews");
    213 
    214    let maxViews = gl.getParameter(ext.MAX_VIEWS_OVR);
    215    let maxLayers = gl.getParameter(gl.MAX_ARRAY_TEXTURE_LAYERS);
    216 
    217    let fb = gl.createFramebuffer();
    218    gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb);
    219    let colorTex = createTextureWithNearestFiltering(gl.TEXTURE_2D_ARRAY);
    220    // Don't allocate storage since it's not needed for the validation.
    221    ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, maxViews + 1);
    222    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "Specified too many views");
    223    ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, 0);
    224    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "Specified zero views");
    225    ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, -1, 2);
    226    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "Specified negative baseViewIndex");
    227 
    228    let colorTex2 = createTextureWithNearestFiltering(gl.TEXTURE_2D_ARRAY);
    229    ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex2, 0, maxLayers - maxViews + 1, maxViews);
    230    // baseViewIndex + numViews  =  (maxLayers - maxViews + 1) + maxViews  =  maxLayers + 1
    231    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "Specified so many views that baseViewIndex + numViews is greater than MAX_ARRAY_TEXTURE_LAYERS");
    232    ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex2, 0, maxLayers - maxViews, maxViews);
    233    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "baseViewIndex + numViews is exactly MAX_ARRAY_TEXTURE_LAYERS");
    234 }
    235 
    236 function runDetachTest()
    237 {
    238    debug("");
    239    debug("Testing detaching multiview attachments");
    240 
    241    let maxViews = gl.getParameter(ext.MAX_VIEWS_OVR);
    242    let maxLayers = gl.getParameter(gl.MAX_ARRAY_TEXTURE_LAYERS);
    243 
    244    let fb = gl.createFramebuffer();
    245    gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb);
    246    let colorTex = createTextureWithNearestFiltering(gl.TEXTURE_2D_ARRAY);
    247    ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, maxViews);
    248    ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, null, 0, maxLayers + 1, 0);
    249    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "baseViewIndex and numViews are not validated when detaching");
    250    let objectType = gl.getFramebufferAttachmentParameter(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
    251    if (objectType != gl.NONE) {
    252        testFailed('Unexpected FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE ' + wtu.glEnumToString(gl, objectType) + ' after detach, should be NONE');
    253    } else {
    254        testPassed('FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE was NONE after detach');
    255    }
    256 
    257    ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, maxViews);
    258    gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0);
    259    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Can detach with framebufferTexture2D as well.");
    260    objectType = gl.getFramebufferAttachmentParameter(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
    261    if (objectType != gl.NONE) {
    262        testFailed('Unexpected FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE ' + wtu.glEnumToString(gl, objectType) + ' after detach, should be NONE');
    263    } else {
    264        testPassed('FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE was NONE after detach');
    265    }
    266 }
    267 
    268 function runShaderCompileTest(extensionEnabled)
    269 {
    270    debug("");
    271    debug("Testing shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled"));
    272 
    273    let prog = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, "requireDefine_GL_OVR_multiview2"], undefined, undefined, true);
    274    expectTrue(!extensionEnabled == !prog,
    275               "GL_OVR_multiview2 must be defined by the preprocessor iff OVR_multiview2 is enabled by getExtension.");
    276    if (extensionEnabled) {
    277        prog = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, "forbidDefine_GL_OVR_multiview"], undefined, undefined, true);
    278        expectTrue(prog, "GL_OVR_multiview must never be defined by the preprocessor.");
    279 
    280        prog = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, "legacyMultiview1Shader"], undefined, undefined, true);
    281        expectTrue(!prog, "#extension GL_OVR_multiview must be forbidden.");
    282    }
    283 
    284    if (!extensionEnabled) {
    285        let multiviewShaders = [
    286          getMultiviewPassthroughVertexShader(2),
    287          getMultiviewColorFragmentShader()
    288        ];
    289        let testProgram = wtu.setupProgram(gl, multiviewShaders, ['a_position'], [0], true);
    290        if (testProgram) {
    291            testFailed("Compilation of shaders using extension functionality succeeded when the extension is disabled, should fail.");
    292        } else {
    293            testPassed("Compilation of shaders using extension functionality should fail when the extension is disabled.");
    294        }
    295    }
    296 }
    297 
    298 function runClearTest()
    299 {
    300    debug("");
    301    debug("Testing that calling clear() clears all views");
    302 
    303    let width = 256;
    304    let height = 256;
    305 
    306    let views = gl.getParameter(ext.MAX_VIEWS_OVR);
    307 
    308    let fb = gl.createFramebuffer();
    309    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    310    let colorTex = createTextureWithNearestFiltering(gl.TEXTURE_2D_ARRAY);
    311    gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, width, height, views);
    312    ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, views);
    313 
    314    gl.viewport(0, 0, width, height);
    315 
    316    gl.clearColor(0, 1, 1, 1);
    317    gl.clear(gl.COLOR_BUFFER_BIT);
    318    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from clear");
    319 
    320    let readFb = gl.createFramebuffer();
    321    gl.bindFramebuffer(gl.READ_FRAMEBUFFER, readFb);
    322    for (let viewIndex = 0; viewIndex < views; ++viewIndex) {
    323        gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, viewIndex);
    324        let expectedColor = [0, 255, 255, 255];
    325        wtu.checkCanvasRect(gl, 0, 0, width, height, expectedColor, 'view ' + viewIndex + ' should be cyan');
    326    }
    327 }
    328 
    329 function runFragmentShaderRenderTest()
    330 {
    331    debug("");
    332    debug("Testing rendering with different colors in fragment shader");
    333 
    334    let width = 256;
    335    let height = 256;
    336 
    337    let views = gl.getParameter(ext.MAX_VIEWS_OVR);
    338 
    339    let multiviewShaders = [
    340      getMultiviewPassthroughVertexShader(views),
    341      getMultiviewColorFragmentShader()
    342    ];
    343    let testProgram = wtu.setupProgram(gl, multiviewShaders, ['a_position'], [0], true);
    344    if (!testProgram) {
    345        testFailed("Compilation with extension enabled failed.");
    346        return;
    347    }
    348 
    349    let fb = gl.createFramebuffer();
    350    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    351    let colorTex = createTextureWithNearestFiltering(gl.TEXTURE_2D_ARRAY);
    352    gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, width, height, views);
    353    ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, views);
    354 
    355    gl.viewport(0, 0, width, height);
    356    wtu.drawUnitQuad(gl);
    357    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from draw");
    358 
    359    let readFb = gl.createFramebuffer();
    360    gl.bindFramebuffer(gl.READ_FRAMEBUFFER, readFb);
    361    for (let viewIndex = 0; viewIndex < views; ++viewIndex) {
    362        gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, viewIndex);
    363        let expectedColor = getExpectedColor(viewIndex);
    364        wtu.checkCanvasRect(gl, 0, 0, width, height, expectedColor, 'view ' + viewIndex + ' should be colored ' + expectedColor);
    365    }
    366 }
    367 
    368 function runVertexShaderRenderTest()
    369 {
    370    debug("");
    371    debug("Testing rendering with different colors in fragment shader, different offsets in vertex shader");
    372 
    373    let width = 256;
    374    let height = 256;
    375 
    376    let views = gl.getParameter(ext.MAX_VIEWS_OVR);
    377 
    378    let multiviewShaders = [
    379      getMultiviewOffsetVertexShader(views),
    380      getMultiviewColorFragmentShader()
    381    ];
    382 
    383    let testProgram = wtu.setupProgram(gl, multiviewShaders, ['a_position'], [0], true);
    384    if (!testProgram) {
    385        testFailed("Compilation with extension enabled failed.");
    386        return;
    387    }
    388 
    389    let fb = gl.createFramebuffer();
    390    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    391    let colorTex = createTextureWithNearestFiltering(gl.TEXTURE_2D_ARRAY);
    392    gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, width, height, views);
    393    ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, views);
    394 
    395    gl.viewport(0, 0, width, height);
    396    wtu.drawUnitQuad(gl);
    397    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from draw");
    398 
    399    let readFb = gl.createFramebuffer();
    400    gl.bindFramebuffer(gl.READ_FRAMEBUFFER, readFb);
    401    for (let viewIndex = 0; viewIndex < views; ++viewIndex) {
    402        gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, viewIndex);
    403        let expectedColor = getExpectedColor(viewIndex);
    404 
    405        checkVerticalStrip(width, height, views, viewIndex, expectedColor, 'view ' + viewIndex);
    406    }
    407 }
    408 
    409 function runRealisticUseCaseRenderTest()
    410 {
    411    debug("");
    412    debug("Testing rendering with a different transformation matrix chosen from a uniform array according to ViewID");
    413 
    414    let width = 256;
    415    let height = 256;
    416 
    417    let views = gl.getParameter(ext.MAX_VIEWS_OVR);
    418 
    419    let multiviewShaders = [
    420      getMultiviewRealisticUseCaseVertexShader(views),
    421      getMultiviewColorFragmentShader()
    422    ];
    423 
    424    let testProgram = wtu.setupProgram(gl, multiviewShaders, ['a_position'], [0], true);
    425    if (!testProgram) {
    426        testFailed("Compilation with extension enabled failed.");
    427        return;
    428    }
    429 
    430    let fb = gl.createFramebuffer();
    431    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    432    let colorTex = createTextureWithNearestFiltering(gl.TEXTURE_2D_ARRAY);
    433    gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, width, height, views);
    434    ext.framebufferTextureMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, views);
    435 
    436    gl.viewport(0, 0, width, height);
    437 
    438    let transformLocation = gl.getUniformLocation(testProgram, 'transform');
    439    let transformData = new Float32Array (views * 16);
    440    for (let viewIndex = 0; viewIndex < views; ++viewIndex) {
    441        let scaleX = 1.0 / views;
    442        // offsetX is the position of the left edge of the quad we want to get in normalized device coordinates
    443        let offsetX = viewIndex / views * 2.0 - 1.0;
    444 
    445        setupTranslateAndScaleXMatrix(transformData, viewIndex * 16, scaleX, offsetX);
    446    }
    447    gl.uniformMatrix4fv(transformLocation, false, transformData);
    448 
    449    wtu.drawUnitQuad(gl);
    450    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from draw");
    451 
    452    let readFb = gl.createFramebuffer();
    453    gl.bindFramebuffer(gl.READ_FRAMEBUFFER, readFb);
    454    for (let viewIndex = 0; viewIndex < views; ++viewIndex) {
    455        gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, viewIndex);
    456        let expectedColor = getExpectedColor(viewIndex);
    457 
    458        checkVerticalStrip(width, height, views, viewIndex, expectedColor, 'view ' + viewIndex);
    459    }
    460 }
    461 
    462 function runUniqueObjectTest()
    463 {
    464    debug("");
    465    debug("Testing that getExtension() returns the same object each time");
    466    gl.getExtension("OVR_multiview2").myProperty = 2;
    467    webglHarnessCollectGarbage();
    468    shouldBe('gl.getExtension("OVR_multiview2").myProperty', '2');
    469 }
    470 
    471 description("This test verifies the functionality of the OVR_multiview2 extension, if it is available.");
    472 
    473 debug("");
    474 
    475 if (!gl) {
    476  testFailed("WebGL context does not exist");
    477 } else {
    478  testPassed("WebGL context exists");
    479 
    480  runExtensionDisabledTest();
    481 
    482  runShaderCompileTest(false);
    483 
    484  debug("");
    485 
    486  if (!gl.getExtension("OVR_multiview2")) {
    487      testPassed("No OVR_multiview2 support -- this is legal");
    488  } else {
    489      testPassed("Successfully enabled OVR_multiview2 extension");
    490      ext = gl.getExtension('OVR_multiview2');
    491 
    492      runShaderCompileTest(true);
    493 
    494      runQueryTest();
    495 
    496      runDefaultFramebufferQueryTest();
    497 
    498      runInvalidTextureTypeTest();
    499 
    500      runFramebufferQueryTest(true);
    501      runFramebufferQueryTest(false);
    502 
    503      runInvalidViewsTest();
    504 
    505      runDetachTest();
    506 
    507      runClearTest();
    508 
    509      wtu.setupUnitQuad(gl, 0, 1);
    510 
    511      runFragmentShaderRenderTest();
    512      runVertexShaderRenderTest();
    513      runRealisticUseCaseRenderTest();
    514      runUniqueObjectTest();
    515  }
    516 }
    517 
    518 debug("");
    519 var successfullyParsed = true;
    520 </script>
    521 <script src="../../js/js-test-post.js"></script>
    522 
    523 </body>
    524 </html>