tor-browser

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

framebuffer-object-attachment.html (30256B)


      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 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
     12 <script src="../../js/js-test-pre.js"></script>
     13 <script src="../../js/webgl-test-utils.js"></script>
     14 </head>
     15 <body>
     16 <div id="description"></div>
     17 <div id="console"></div>
     18 
     19 <script>
     20 "use strict";
     21 var wtu = WebGLTestUtils;
     22 var gl;
     23 
     24 function checkFramebuffer(expected) {
     25    var actual = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
     26    if (expected.indexOf(actual) < 0) {
     27        var msg = "checkFramebufferStatus expects [";
     28        for (var index = 0; index < expected.length; ++index) {
     29            msg += wtu.glEnumToString(gl, expected[index]);
     30            if (index + 1 < expected.length)
     31                msg += ", ";
     32        }
     33        msg += "], was " + wtu.glEnumToString(gl, actual);
     34        testFailed(msg);
     35    } else {
     36        var msg = "checkFramebufferStatus got " + wtu.glEnumToString(gl, actual) +
     37                  " as expected";
     38        testPassed(msg);
     39    }
     40 }
     41 
     42 function checkBufferBits(attachment0, attachment1) {
     43    if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
     44        return;
     45    var haveDepthBuffer = attachment0 == gl.DEPTH_ATTACHMENT ||
     46                          attachment0 == gl.DEPTH_STENCIL_ATTACHMENT ||
     47                          attachment1 == gl.DEPTH_ATTACHMENT ||
     48                          attachment1 == gl.DEPTH_STENCIL_ATTACHMENT;
     49    var haveStencilBuffer = attachment0 == gl.STENCIL_ATTACHMENT ||
     50                            attachment0 == gl.DEPTH_STENCIL_ATTACHMENT ||
     51                            attachment1 == gl.STENCIL_ATTACHMENT ||
     52                            attachment1 == gl.DEPTH_STENCIL_ATTACHMENT;
     53    shouldBeTrue("gl.getParameter(gl.RED_BITS) + gl.getParameter(gl.GREEN_BITS) + " +
     54                 "gl.getParameter(gl.BLUE_BITS) + gl.getParameter(gl.ALPHA_BITS) >= 16");
     55    if (haveDepthBuffer)
     56        shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) >= 16");
     57    else
     58        shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) == 0");
     59    if (haveStencilBuffer)
     60        shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) >= 8");
     61    else
     62        shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) == 0");
     63 }
     64 
     65 
     66 function testFramebufferWebGL1RequiredCombinations() {
     67    debug("Checking combinations of framebuffer attachments required to be valid by WebGL 1");
     68 
     69    // Per discussion with the OpenGL ES working group, the following framebuffer attachment
     70    // combinations are required to work in all WebGL 1 implementations:
     71    // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
     72    // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
     73    // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer
     74 
     75    var fbo = gl.createFramebuffer();
     76    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
     77 
     78    var width = 64;
     79    var height = 64;
     80 
     81    // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
     82    var texture = gl.createTexture();
     83    gl.bindTexture(gl.TEXTURE_2D, texture);
     84    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
     85    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
     86    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
     87    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
     88    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
     89    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
     90    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
     91    checkBufferBits();
     92 
     93    // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
     94    var renderbuffer = gl.createRenderbuffer();
     95    gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
     96    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
     97    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
     98    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
     99    checkBufferBits(gl.DEPTH_ATTACHMENT);
    100    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null);
    101 
    102    // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer
    103    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
    104    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
    105    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    106    checkBufferBits(gl.DEPTH_STENCIL_ATTACHMENT);
    107 
    108    // Clean up
    109    gl.deleteRenderbuffer(renderbuffer);
    110    gl.deleteTexture(texture);
    111    gl.deleteFramebuffer(fbo);
    112 }
    113 
    114 function testDepthStencilAttachmentBehaviors(testOrphanedRenderbuffers) {
    115    let suffix = testOrphanedRenderbuffers ? " with deleted renderbuffer" : "";
    116    debug("");
    117    debug("Checking ES3 DEPTH_STENCIL_ATTACHMENT behaviors are implemented for WebGL 2" + suffix);
    118    // DEPTH_STENCIL_ATTACHMENT is treated as an independent attachment point in WebGL 1;
    119    // however, in WebGL 2, it is treated as an alias for DEPTH_ATTACHMENT + STENCIL_ATTACHMENT.
    120    var size = 16;
    121 
    122    var fbo = gl.createFramebuffer();
    123    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    124    var colorBuffer = gl.createRenderbuffer();
    125    gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
    126    gl.framebufferRenderbuffer(
    127        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
    128    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, size, size);
    129    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    130 
    131    function createDepthBuffer() {
    132        let buffer = gl.createRenderbuffer();
    133        gl.bindRenderbuffer(gl.RENDERBUFFER, buffer);
    134        gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size);
    135        gl.bindRenderbuffer(gl.RENDERBUFFER, null);
    136        return buffer;
    137    }
    138 
    139    function createStencilBuffer() {
    140        let buffer = gl.createRenderbuffer();
    141        gl.bindRenderbuffer(gl.RENDERBUFFER, buffer);
    142        gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, size, size);
    143        gl.bindRenderbuffer(gl.RENDERBUFFER, null);
    144        return buffer;
    145    }
    146 
    147    function createDepthStencilBuffer() {
    148        let buffer = gl.createRenderbuffer();
    149        gl.bindRenderbuffer(gl.RENDERBUFFER, buffer);
    150        gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, size, size);
    151        gl.bindRenderbuffer(gl.RENDERBUFFER, null);
    152        return buffer;
    153    }
    154 
    155    function orphan(renderbuffer) {
    156        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    157        gl.deleteRenderbuffer(renderbuffer);
    158        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    159    }
    160 
    161    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    162 
    163    debug("");
    164    debug("color + depth" + suffix);
    165    var depthBuffer = createDepthBuffer();
    166    gl.framebufferRenderbuffer(
    167        gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
    168    if (testOrphanedRenderbuffers)
    169        orphan(depthBuffer);
    170    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer);
    171    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    172    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    173    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
    174    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    175    checkBufferBits(gl.DEPTH_ATTACHMENT);
    176 
    177    debug("");
    178    debug("color + depth + stencil: depth != stencil" + suffix);
    179    var stencilBuffer = createStencilBuffer();
    180    gl.framebufferRenderbuffer(
    181        gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, stencilBuffer);
    182    if (testOrphanedRenderbuffers)
    183        orphan(stencilBuffer);
    184    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer);
    185    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", stencilBuffer);
    186    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    187    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
    188    checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]);
    189 
    190    gl.framebufferRenderbuffer(
    191        gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null);
    192    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer);
    193    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    194    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    195    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
    196 
    197    debug("");
    198    debug("color + depth: DEPTH_STENCIL for DEPTH_ATTACHMENT" + suffix);
    199    var depthStencilBuffer = createDepthStencilBuffer();
    200    gl.framebufferRenderbuffer(
    201        gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
    202    if (testOrphanedRenderbuffers)
    203        orphan(depthStencilBuffer);
    204    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    205    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    206    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    207    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
    208    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    209    checkBufferBits(gl.DEPTH_ATTACHMENT);
    210 
    211    debug("");
    212    debug("color + depth + stencil: DEPTH_STENCIL for DEPTH_ATTACHMENT and STENCIL_ATTACHMENT" + suffix);
    213    if (testOrphanedRenderbuffers) {
    214        depthStencilBuffer = createDepthStencilBuffer();
    215        gl.framebufferRenderbuffer(
    216            gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
    217    }
    218    gl.framebufferRenderbuffer(
    219        gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
    220    if (testOrphanedRenderbuffers)
    221        orphan(depthStencilBuffer);
    222    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    223    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    224    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    225    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    226    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    227    checkBufferBits(gl.DEPTH_STENCIL_ATTACHMENT);
    228 
    229    debug("");
    230    debug("color + depth_stencil" + suffix);
    231    var texture = gl.createTexture();
    232    gl.bindTexture(gl.TEXTURE_2D, texture);
    233    gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH24_STENCIL8, size, size, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null);
    234    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, texture, 0);
    235    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texture);
    236    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texture);
    237    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texture);
    238    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    239    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    240 
    241    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, null, 0);
    242    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    243    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    244    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    245    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    246 
    247    if (testOrphanedRenderbuffers)
    248        depthStencilBuffer = createDepthStencilBuffer();
    249    gl.framebufferRenderbuffer(
    250        gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
    251    if (testOrphanedRenderbuffers)
    252        orphan(depthStencilBuffer);
    253    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    254    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    255    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    256    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    257    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    258    checkBufferBits(gl.DEPTH_STENCIL_ATTACHMENT);
    259 
    260    debug("");
    261    debug("DEPTH_STENCIL_ATTACHMENT overwrites DEPTH_ATTACHMENT/STENCIL_ATTACHMENT" + suffix);
    262    if (testOrphanedRenderbuffers)
    263        depthBuffer = createDepthBuffer();
    264    gl.framebufferRenderbuffer(
    265        gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
    266    if (testOrphanedRenderbuffers)
    267        orphan(depthBuffer);
    268    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer);
    269    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    270    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    271    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
    272 
    273    if (testOrphanedRenderbuffers)
    274        depthStencilBuffer = createDepthStencilBuffer();
    275    gl.framebufferRenderbuffer(
    276        gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
    277    if (testOrphanedRenderbuffers)
    278        orphan(depthStencilBuffer);
    279    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    280    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    281    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    282    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    283 
    284    gl.framebufferRenderbuffer(
    285        gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, null);
    286    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    287    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    288    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    289    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    290    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    291    checkBufferBits();
    292 
    293    debug("");
    294    debug("STENCIL_ATTACHMENT overwrites stencil set by DEPTH_STENCIL_ATTACHMENT" + suffix);
    295    if (testOrphanedRenderbuffers)
    296        depthStencilBuffer = createDepthStencilBuffer();
    297    gl.framebufferRenderbuffer(
    298        gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
    299    if (testOrphanedRenderbuffers)
    300        orphan(depthStencilBuffer);
    301    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    302    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    303    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    304    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    305 
    306    gl.framebufferRenderbuffer(
    307        gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null);
    308    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    309    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    310    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    311    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
    312    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    313    checkBufferBits(gl.DEPTH_ATTACHMENT);
    314 
    315    debug("");
    316    debug("DEPTH_ATTACHMENT overwrites depth set by DEPTH_STENCIL_ATTACHMENT" + suffix);
    317    if (testOrphanedRenderbuffers)
    318        depthStencilBuffer = createDepthStencilBuffer();
    319    gl.framebufferRenderbuffer(
    320        gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
    321    if (testOrphanedRenderbuffers)
    322        orphan(depthStencilBuffer);
    323    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    324    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    325    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    326    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    327 
    328    gl.framebufferRenderbuffer(
    329        gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null);
    330    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    331    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer);
    332    shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
    333    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
    334    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    335    checkBufferBits(gl.STENCIL_ATTACHMENT);
    336 }
    337 
    338 function testFramebufferIncompleteAttachment() {
    339    var fbo = gl.createFramebuffer();
    340    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    341    var colorBuffer = gl.createRenderbuffer();
    342    gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
    343    gl.framebufferRenderbuffer(
    344        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
    345    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
    346    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    347 
    348    debug("");
    349    debug("Wrong storage type for type of attachment should be FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
    350    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 16, 16);
    351    checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT]);
    352 
    353    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
    354    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    355 
    356    debug("");
    357    debug("0 size attachment should be FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
    358    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0);
    359    checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT]);
    360 
    361    gl.deleteRenderbuffer(colorBuffer);
    362    gl.deleteFramebuffer(fbo);
    363    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    364 }
    365 
    366 function testFramebufferIncompleteMissingAttachment() {
    367    debug("");
    368    debug("No attachments should be INCOMPLETE_FRAMEBUFFER_MISSING_ATTACHMENT");
    369    var fbo = gl.createFramebuffer();
    370    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    371    checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT]);
    372 
    373    var colorBuffer = gl.createRenderbuffer();
    374    gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
    375    gl.framebufferRenderbuffer(
    376        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
    377    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
    378    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    379 
    380    gl.framebufferRenderbuffer(
    381        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, null);
    382    checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT]);
    383 
    384    gl.deleteRenderbuffer(colorBuffer);
    385    gl.deleteFramebuffer(fbo);
    386    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    387 }
    388 
    389 function testFramebufferWithImagesOfDifferentSizes() {
    390    debug("");
    391    debug("Attachments of different sizes should NOT be allowed");
    392 
    393    var fbo = gl.createFramebuffer();
    394    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    395    var colorBuffer = gl.createRenderbuffer();
    396    gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
    397    gl.framebufferRenderbuffer(
    398        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
    399    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
    400 
    401    var depthBuffer = gl.createRenderbuffer();
    402    gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
    403    gl.framebufferRenderbuffer(
    404        gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
    405    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 16, 16);
    406    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    407    checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
    408 
    409    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 32, 16);
    410    checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS]);
    411    gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
    412    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 32);
    413    checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS]);
    414    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    415 
    416    var tex = gl.createTexture();
    417    gl.bindTexture(gl.TEXTURE_2D, tex);
    418    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    419    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
    420    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    421    if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
    422        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 32, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    423        checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS]);
    424    }
    425 
    426    gl.deleteTexture(tex);
    427    gl.deleteRenderbuffer(depthBuffer);
    428    gl.deleteRenderbuffer(colorBuffer);
    429    gl.deleteFramebuffer(fbo);
    430    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    431 }
    432 
    433 function testUsingIncompleteFramebuffer() {
    434    debug("");
    435    debug("Test drawing or reading from an incomplete framebuffer");
    436    var program = wtu.setupTexturedQuad(gl);
    437    var tex = gl.createTexture();
    438    wtu.fillTexture(gl, tex, 1, 1, [0,255,0,255]);
    439 
    440    var fbo = gl.createFramebuffer();
    441    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    442    checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT]);
    443    debug("");
    444    debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
    445    testRenderingAndReading();
    446 
    447    var colorBuffer = gl.createRenderbuffer();
    448    gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
    449    gl.framebufferRenderbuffer(
    450        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
    451    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0);
    452    checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT]);
    453    debug("");
    454    debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
    455    testRenderingAndReading();
    456 
    457    function testRenderingAndReading() {
    458        wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    459        wtu.clearAndDrawUnitQuad(gl);
    460        wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "drawArrays with incomplete framebuffer");
    461        gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
    462        wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "readPixels from incomplete framebuffer");
    463        // copyTexImage and copyTexSubImage can be either INVALID_FRAMEBUFFER_OPERATION because
    464        // the framebuffer is invalid OR INVALID_OPERATION because in the case of no attachments
    465        // the framebuffer is not of a compatible type.
    466        gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
    467        wtu.glErrorShouldBe(gl, [gl.INVALID_FRAMEBUFFER_OPERATION, gl.INVALID_OPERATION],
    468            "copyTexImage2D from incomplete framebuffer");
    469        gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 1, 1, 0);
    470        wtu.glErrorShouldBe(gl, [gl.INVALID_FRAMEBUFFER_OPERATION, gl.INVALID_OPERATION],
    471            "copyTexSubImage2D from incomplete framebuffer");
    472        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    473        wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "clear with incomplete framebuffer");
    474    }
    475 
    476    gl.deleteRenderbuffer(colorBuffer);
    477    gl.deleteFramebuffer(fbo);
    478    gl.deleteTexture(tex);
    479    gl.deleteProgram(program);
    480 }
    481 
    482 function testReadingFromMissingAttachment() {
    483    debug("");
    484    debug("Test drawing or reading from a framebuffer with no color image");
    485 
    486    var fbo = gl.createFramebuffer();
    487    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    488    var object_type = gl.getFramebufferAttachmentParameter(
    489        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
    490    if (object_type != gl.NONE)
    491        testFailed("object type from empty attachment point should be NONE");
    492    else
    493        testPassed("object type from empty attachment point is NONE");
    494    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Query should not generate error");
    495 
    496    var object_name = gl.getFramebufferAttachmentParameter(
    497        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
    498    if (object_name)
    499        testFailed("object name from empty attachment point should be null");
    500    else
    501        testPassed("object name from empty attachment point is null");
    502    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Query should not generate error");
    503 
    504    var size = 16;
    505 
    506    // The only scenario we can verify is an attempt to read or copy
    507    // from a missing color attachment while the framebuffer is still
    508    // complete.
    509    var depthBuffer = gl.createRenderbuffer();
    510    gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
    511    gl.framebufferRenderbuffer(
    512        gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
    513    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size);
    514    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After depth renderbuffer setup");
    515    if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
    516        // The FBO has no color attachment. ReadPixels, CopyTexImage2D,
    517        // and CopyTexSubImage2D should all generate INVALID_OPERATION.
    518        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Before ReadPixels from missing attachment");
    519        gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
    520        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "After ReadPixels from missing attachment");
    521 
    522        var tex = gl.createTexture();
    523        gl.bindTexture(gl.TEXTURE_2D, tex);
    524        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Before CopyTexImage2D from missing attachment");
    525        gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, size, size, 0);
    526        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "After CopyTexImage2D from missing attachment");
    527 
    528        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    529        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Before CopyTexSubImage2D from missing attachment");
    530        gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, size, size);
    531        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "After CopyTexSubImage2D from missing attachment");
    532 
    533        gl.deleteTexture(tex);
    534    }
    535 
    536    gl.deleteRenderbuffer(depthBuffer);
    537    gl.deleteFramebuffer(fbo);
    538 }
    539 
    540 description("Test framebuffer object attachment behaviors");
    541 
    542 shouldBeNonNull("gl = wtu.create3DContext(undefined, undefined, 2)");
    543 
    544 testFramebufferWebGL1RequiredCombinations();
    545 testDepthStencilAttachmentBehaviors(false);
    546 testDepthStencilAttachmentBehaviors(true);
    547 testFramebufferIncompleteAttachment();
    548 testFramebufferIncompleteMissingAttachment();
    549 testFramebufferWithImagesOfDifferentSizes();
    550 testUsingIncompleteFramebuffer();
    551 testReadingFromMissingAttachment();
    552 
    553 // -
    554 
    555 debug("");
    556 debug("Test calling framebufferTexture2D with impossible mip levels.");
    557 
    558 const fb = gl.createFramebuffer();
    559 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    560 
    561 const tex = gl.createTexture();
    562 gl.bindTexture(gl.TEXTURE_2D, tex);
    563 
    564 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 1000);
    565 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "Mip level attachment impossibly high.");
    566 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 10);
    567 wtu.glErrorShouldBe(gl, 0, "Mip level attachment within acceptable range.");
    568 
    569 // Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1636517 :
    570 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 1000);
    571 wtu.glErrorShouldBe(gl, 0, "Mip level detachment can be impossibly high.");
    572 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "0");
    573 
    574 // -
    575 
    576 debug("")
    577 var successfullyParsed = true;
    578 </script>
    579 
    580 <script src="../../js/js-test-post.js"></script>
    581 </body>
    582 </html>