tor-browser

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

draw-buffers.html (22117B)


      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 Draw Buffers 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/webgl-draw-buffers-utils.js"></script>
     16 </head>
     17 <body>
     18 <div id="description"></div>
     19 <canvas id="canvas" width="64" height="64"> </canvas>
     20 <div id="console"></div>
     21 <script id="vshaderESSL3" type="x-shader/x-vertex">#version 300 es
     22 in vec4 a_position;
     23 void main() {
     24    gl_Position = a_position;
     25 }
     26 </script>
     27 <script id="vshaderESSL1" type="x-shader/x-vertex">
     28 attribute vec4 a_position;
     29 void main() {
     30    gl_Position = a_position;
     31 }
     32 </script>
     33 <script id="fshader" type="x-shader/x-fragment">#version 300 es
     34 precision mediump float;
     35 uniform vec4 u_colors[$(numDrawingBuffers)];
     36 
     37 // Only one out variable - does not need explicit output layout (ESSL 3 section 4.3.8.2)
     38 out vec4 my_FragData[$(numDrawingBuffers)];
     39 void main() {
     40 $(assignUColorsToFragData)
     41 }
     42 </script>
     43 <script id="fshaderDiscard" type="x-shader/x-fragment">#version 300 es
     44 precision mediump float;
     45 uniform vec4 u_colors[$(numDrawingBuffers)];
     46 uniform float u_zero;
     47 
     48 // Only one out variable - does not need explicit output layout (ESSL 3 section 4.3.8.2)
     49 out vec4 my_FragData[$(numDrawingBuffers)];
     50 void main() {
     51 $(assignUColorsToFragData)
     52    if (u_zero < 1.0) {
     53        discard;
     54    }
     55 }
     56 </script>
     57 <script id="fshaderRed" type="x-shader/x-fragment">#version 300 es
     58 precision mediump float;
     59 
     60 out vec4 my_FragColor;
     61 void main() {
     62    my_FragColor = vec4(1, 0, 0, 1);
     63 }
     64 </script>
     65 <script id="fshaderBlueESSL1" type="x-shader/x-fragment">
     66 precision mediump float;
     67 
     68 void main() {
     69    gl_FragColor = vec4(0, 0, 1, 1);
     70 }
     71 </script>
     72 <script id="fshaderBuiltInConstEnabled" type="x-shader/x-fragment">#version 300 es
     73 precision mediump float;
     74 
     75 out vec4 my_FragColor;
     76 void main() {
     77    my_FragColor = (gl_MaxDrawBuffers == $(numDrawingBuffers)) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
     78 }
     79 </script>
     80 <script>
     81 "use strict";
     82 description("This test verifies the functionality of Multiple Render Targets.");
     83 
     84 debug("");
     85 
     86 var wtu = WebGLTestUtils;
     87 var canvas = document.getElementById("canvas");
     88 var gl = wtu.create3DContext(canvas, null, 2);
     89 var drawBuffersUtils;
     90 let fb;
     91 
     92 if (!gl) {
     93  testFailed("WebGL context does not exist");
     94 } else {
     95  testPassed("WebGL context exists");
     96  drawBuffersUtils = WebGLDrawBuffersUtils(gl);
     97 
     98  if (testParameters()) {
     99    runShadersTest();
    100    runAttachmentTest();
    101    runDrawTests();
    102  }
    103 
    104  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    105 }
    106 
    107 function createDrawBuffersProgram(scriptId, sub) {
    108  var fsource = wtu.getScript(scriptId);
    109  fsource = wtu.replaceParams(fsource, sub);
    110  return wtu.setupProgram(gl, ["vshaderESSL3", fsource], ["a_position"], undefined, true);
    111 }
    112 
    113 function runShadersTest() {
    114  debug("");
    115  debug("test shaders");
    116 
    117  var sub = {numDrawingBuffers: gl.getParameter(gl.MAX_DRAW_BUFFERS)};
    118  var program = createDrawBuffersProgram("fshaderBuiltInConstEnabled", sub);
    119  wtu.setupUnitQuad(gl);
    120  wtu.clearAndDrawUnitQuad(gl);
    121  wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
    122  gl.deleteProgram(program);
    123  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    124 }
    125 
    126 function makeArray(size, value) {
    127  var array = []
    128  for (var ii = 0; ii < size; ++ii) {
    129    array.push(value);
    130  }
    131  return array;
    132 }
    133 
    134 function runAttachmentTest() {
    135  debug("");
    136  debug("test attachment enabled");
    137 
    138  var maxDrawingBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS);
    139  var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
    140 
    141  var tex = gl.createTexture();
    142  fb = gl.createFramebuffer();
    143  gl.bindTexture(gl.TEXTURE_2D, tex);
    144  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    145  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments, gl.TEXTURE_2D, tex, 0);
    146  wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "should not be able to attach pass the max attachment point: gl.COLOR_ATTACHMENT0 + " + maxColorAttachments);
    147  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments - 1, gl.TEXTURE_2D, tex, 0);
    148  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to attach to the max attachment point: gl.COLOR_ATTACHMENT0 + " + (maxColorAttachments - 1));
    149  gl.drawBuffers(makeArray(maxDrawingBuffers, gl.NONE));
    150  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with array NONE of size " + maxColorAttachments);
    151  var bufs = drawBuffersUtils.makeColorAttachmentArray(maxDrawingBuffers);
    152  gl.drawBuffers(bufs);
    153  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with array attachments of size " + maxColorAttachments);
    154  bufs[0] = gl.NONE;
    155  gl.drawBuffers(bufs);
    156  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with mixed array attachments of size " + maxColorAttachments);
    157  if (maxDrawingBuffers > 1) {
    158    bufs[0] = gl.COLOR_ATTACHMENT1;
    159    bufs[1] = gl.COLOR_ATTACHMENT0;
    160    gl.drawBuffers(bufs);
    161    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should not be able to call drawBuffers with out of order attachments of size " + maxColorAttachments);
    162    var bufs = drawBuffersUtils.makeColorAttachmentArray(Math.floor(maxDrawingBuffers / 2));
    163    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with short array of attachments of size " + bufs.length);
    164  }
    165 
    166  gl.deleteFramebuffer(fb);
    167  gl.deleteTexture(tex);
    168  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    169 
    170  debug("Testing drawBuffers and getParameter with bindFramebuffer, without drawing.");
    171  fb = gl.createFramebuffer();
    172  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    173  shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0");
    174  shouldBe("gl.getParameter(gl.DRAW_BUFFER0+1)", "gl.NONE");
    175  wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawBuffers([gl.NONE])");
    176  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    177  shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.BACK");
    178  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    179  shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.NONE");
    180 
    181  wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawBuffers([gl.NONE,gl.COLOR_ATTACHMENT0+1])");
    182  shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.NONE");
    183  shouldBe("gl.getParameter(gl.DRAW_BUFFER0+1)", "gl.COLOR_ATTACHMENT0+1");
    184 
    185  wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawBuffers([gl.COLOR_ATTACHMENT0,gl.COLOR_ATTACHMENT0+1])");
    186  shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0");
    187  shouldBe("gl.getParameter(gl.DRAW_BUFFER0+1)", "gl.COLOR_ATTACHMENT0+1");
    188 
    189  wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteFramebuffer(fb)");
    190  shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.BACK");
    191 }
    192 
    193 function makeColorByIndex(index) {
    194  var low = (index - 1) % 15 + 1;
    195  var high = (index - 1) / 15;
    196 
    197  var zeroOrOne = function(v) {
    198    return v ? 1 : 0;
    199  };
    200 
    201  var oneOrTwo = function(v) {
    202    return v ? 2 : 1;
    203  }
    204 
    205  var makeComponent = function(b0, b1, b2) {
    206    return Math.floor(255 * zeroOrOne(b0) / oneOrTwo(b1) / oneOrTwo(b2));
    207  };
    208  return [
    209    makeComponent(low & (1 << 0), high & (1 << 0), high & (1 << 4)),
    210    makeComponent(low & (1 << 1), high & (1 << 1), high & (1 << 5)),
    211    makeComponent(low & (1 << 2), high & (1 << 2), high & (1 << 6)),
    212    makeComponent(low & (1 << 3), high & (1 << 3), high & (1 << 7)),
    213  ];
    214 }
    215 
    216 function runDrawTests() {
    217  debug("");
    218  debug("--------- draw tests -----------");
    219  var fb = gl.createFramebuffer();
    220  var fb2 = gl.createFramebuffer();
    221  var halfFB1 = gl.createFramebuffer();
    222  var halfFB2 = gl.createFramebuffer();
    223  var endsFB = gl.createFramebuffer();
    224  var middleFB = gl.createFramebuffer();
    225 
    226  var maxDrawingBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS);
    227  var maxUsable = drawBuffersUtils.getMaxUsableColorAttachments();
    228  var half = Math.floor(maxUsable / 2);
    229  var bufs = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
    230  var nones = makeArray(maxUsable, gl.NONE);
    231 
    232  [fb, fb2, halfFB1, halfFB2, endsFB, middleFB].forEach(function(fbo) {
    233    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    234    gl.drawBuffers(bufs);
    235  });
    236 
    237  var checkProgram = wtu.setupTexturedQuad(gl);
    238  var redProgram = wtu.setupProgram(gl, ["vshaderESSL3", "fshaderRed"], ["a_position"]);
    239  var blueProgramESSL1 = wtu.setupProgram(gl, ["vshaderESSL1", "fshaderBlueESSL1"], ["a_position"]);
    240 
    241  var assignCode = [];
    242  for (var i = 0; i < maxDrawingBuffers; ++i) {
    243    assignCode.push("    my_FragData[" + i + "] = u_colors[" + i + "];");
    244  }
    245 
    246  var drawProgram = createDrawBuffersProgram("fshader",
    247      {numDrawingBuffers: maxDrawingBuffers, assignUColorsToFragData: assignCode.join("\n")});
    248  var width = 64;
    249  var height = 64;
    250  var attachments = [];
    251  // Makes 6 framebuffers.
    252  // fb and fb2 have all the attachments.
    253  // halfFB1 has the first half of the attachments
    254  // halfFB2 has the second half of the attachments
    255  // endsFB has the first and last attachments
    256  // middleFB has all but the first and last attachments
    257  for (var ii = 0; ii < maxUsable; ++ii) {
    258    var tex = gl.createTexture();
    259    gl.bindTexture(gl.TEXTURE_2D, tex);
    260    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    261    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    262    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    263    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    264    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    265    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    266    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
    267    gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
    268    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
    269    gl.bindFramebuffer(gl.FRAMEBUFFER, ii < half ? halfFB1 : halfFB2);
    270    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
    271    gl.bindFramebuffer(gl.FRAMEBUFFER, (ii == 0 || ii == (maxUsable - 1)) ? endsFB : middleFB);
    272    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
    273    var location = gl.getUniformLocation(drawProgram, "u_colors[" + ii + "]");
    274    var color = makeColorByIndex(ii + 1);
    275    var floatColor = [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255];
    276    gl.uniform4fv(location, floatColor);
    277    attachments.push({
    278      texture: tex,
    279      color: color
    280    });
    281  }
    282  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    283  shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
    284  gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
    285  shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
    286 
    287  var drawAndCheckAttachments = function(testFB, msg, testFn) {
    288    debug("test clearing " + msg);
    289 
    290    gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
    291 
    292    attachments.forEach(function(attachment, index) {
    293      debug("attachment: " + index + " = " + wtu.glEnumToString(gl, gl.getParameter(gl.DRAW_BUFFER0 + index)) +
    294            ", " + wtu.glEnumToString(gl, gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + index, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)));
    295    });
    296 
    297    if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
    298      debug("framebuffer not complete");
    299      debug("");
    300      return;
    301    }
    302 
    303    // Clear all the attachments
    304    gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
    305    gl.clearColor(0, 0, 0, 0);
    306    gl.clear(gl.COLOR_BUFFER_BIT);
    307    //drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
    308    //  return [0, 0, 0, 0];
    309    //});
    310    //debug("--");
    311 
    312    // Clear some attachments using testFB
    313    gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
    314 
    315    gl.clearColor(0, 1, 0, 1);
    316    gl.clear(gl.COLOR_BUFFER_BIT);
    317    drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
    318      return testFn(attachment, index) ? [0, 255, 0, 255] : [0, 0, 0, 0];
    319    });
    320 
    321    debug("test drawing to " + msg);
    322 
    323    // Draw to some attachments using testFB
    324    gl.useProgram(drawProgram);
    325    gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
    326    wtu.drawUnitQuad(gl);
    327 
    328    drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
    329      return testFn(attachment, index) ? attachment.color : [0, 0, 0, 0];
    330    });
    331  };
    332 
    333  gl.useProgram(drawProgram);
    334  gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
    335  gl.drawBuffers(bufs);
    336  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    337  gl.drawBuffers(bufs);
    338 
    339  wtu.drawUnitQuad(gl);
    340 
    341  debug("test that each texture got the correct color.");
    342 
    343  drawBuffersUtils.checkAttachmentsForColor(attachments);
    344 
    345  debug("test clearing clears all the textures");
    346  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    347  gl.clearColor(0, 1, 0, 1);
    348  gl.clear(gl.COLOR_BUFFER_BIT);
    349 
    350  drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
    351 
    352  debug("test that NONE draws nothing");
    353  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    354  gl.drawBuffers(nones);
    355  gl.useProgram(redProgram);
    356  wtu.clearAndDrawUnitQuad(gl);
    357 
    358  drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
    359 
    360  // GLES3 spec section 3.9.2 Shader Outputs
    361  debug("test that gl_FragColor only writes to color number zero");
    362  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    363  gl.drawBuffers(bufs);
    364  gl.useProgram(blueProgramESSL1);
    365 
    366  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    367  wtu.drawUnitQuad(gl);
    368  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Active draw buffers with missing frag outputs.");
    369  gl.enable(gl.RASTERIZER_DISCARD);
    370  wtu.drawUnitQuad(gl);
    371  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors when RASTERIZER_DISCARD is enabled.");
    372  gl.disable(gl.RASTERIZER_DISCARD);
    373  gl.colorMask(false, false, false, false);
    374  wtu.drawUnitQuad(gl);
    375  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors when all 4 channels of color mask are disabled.");
    376  gl.colorMask(false, true, false, false);
    377  wtu.drawUnitQuad(gl);
    378  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "partially diabled color mask shall have no impact.");
    379  gl.colorMask(true, true, true, true);
    380 
    381  gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
    382  wtu.drawUnitQuad(gl);
    383 
    384  drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
    385    return (index == 0) ? [0, 0, 255, 255] : [0, 255, 0, 255];
    386  });
    387 
    388  // If there is only a single output, the location defaults to zero if not specified.
    389  // See GLSL ES Spec 3.00.4, Section 4.3.8.2, Output Layout Qualifiers.
    390  debug("test that an OpenGL ES Shading Language 3.00 shader with a single output color defaults to color number zero");
    391  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    392  gl.drawBuffers(bufs);
    393  gl.useProgram(redProgram);
    394 
    395  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    396  wtu.drawUnitQuad(gl);
    397  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Active draw buffers with missing frag outputs.");
    398 
    399  gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
    400  wtu.drawUnitQuad(gl);
    401 
    402  drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
    403    return (index == 0) ? [255, 0, 0, 255] : [0, 255, 0, 255];
    404  });
    405 
    406  if (maxUsable > 1) {
    407    // Prepare for following tests by clearing all attachments to red.
    408    debug("prepare by clearing all attachments to red");
    409    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    410    gl.drawBuffers(bufs);
    411    gl.clearColor(1, 0, 0, 1);
    412    gl.clear(gl.COLOR_BUFFER_BIT);
    413    drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
    414 
    415    var bufs1 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
    416    var bufs2 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
    417    for (var ii = 0; ii < maxUsable; ++ii) {
    418      if (ii < half) {
    419        bufs1[ii] = gl.NONE;
    420      } else {
    421        bufs2[ii] = gl.NONE;
    422      }
    423    }
    424 
    425    debug("test setting first half to NONE and clearing");
    426 
    427    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    428    gl.drawBuffers(bufs1);
    429    gl.clearColor(0, 1, 0, 1);
    430    gl.clear(gl.COLOR_BUFFER_BIT);
    431 
    432    drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
    433      return index < half ? [255, 0, 0, 255] : [0, 255, 0, 255];
    434    });
    435 
    436    debug("test setting first half to NONE and drawing");
    437 
    438    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    439    gl.useProgram(drawProgram);
    440    wtu.drawUnitQuad(gl);
    441 
    442    drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
    443      return index < half ? [255, 0, 0, 255] : attachment.color;
    444    });
    445 
    446    debug("test setting second half to NONE and clearing");
    447 
    448    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    449    gl.drawBuffers(bufs);
    450    gl.clearColor(1, 0, 0, 1);
    451    gl.clear(gl.COLOR_BUFFER_BIT);
    452    gl.drawBuffers(bufs2);
    453    gl.clearColor(0, 0, 1, 1);
    454    gl.clear(gl.COLOR_BUFFER_BIT);
    455    drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
    456      return index < half ? [0, 0, 255, 255] : [255, 0, 0, 255];
    457    });
    458 
    459    debug("test setting second half to NONE and drawing");
    460 
    461    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    462    gl.useProgram(drawProgram);
    463    wtu.drawUnitQuad(gl);
    464 
    465    drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
    466      return index < half ? attachment.color : [255, 0, 0, 255];
    467    });
    468 
    469    gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB1);
    470    gl.drawBuffers(bufs);
    471    drawAndCheckAttachments(
    472      halfFB1, "framebuffer that only has first half of attachments",
    473      function(attachment, index) {
    474        return index < half;
    475      });
    476 
    477    gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB2);
    478    gl.drawBuffers(bufs);
    479    drawAndCheckAttachments(
    480      halfFB2, "framebuffer that only has second half of attachments",
    481      function(attachment, index) {
    482        return index >= half;
    483      });
    484 
    485    if (maxUsable > 2) {
    486      gl.bindFramebuffer(gl.FRAMEBUFFER, endsFB);
    487      gl.drawBuffers(bufs);
    488      drawAndCheckAttachments(
    489        endsFB, "framebuffer that only has first and last attachments",
    490        function(attachment, index) {
    491          return index == 0 || index == (maxUsable - 1);
    492        });
    493 
    494      gl.bindFramebuffer(gl.FRAMEBUFFER, middleFB);
    495      gl.drawBuffers(bufs);
    496      drawAndCheckAttachments(
    497        middleFB,
    498        "framebuffer that has all but the first and last attachments",
    499        function(attachment, index) {
    500          return index != 0 && index != (maxUsable - 1);
    501        });
    502    }
    503  }
    504 
    505  debug("test switching between fbos keeps drawbuffer state");
    506  gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
    507  gl.drawBuffers(nones);
    508 
    509  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    510  gl.drawBuffers(bufs);
    511  gl.clearColor(1, 0, 0, 1);
    512  gl.clear(gl.COLOR_BUFFER_BIT);
    513  drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
    514 
    515  gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
    516  gl.useProgram(drawProgram);
    517  wtu.drawUnitQuad(gl);
    518  drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
    519 
    520  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    521  gl.useProgram(drawProgram);
    522  wtu.drawUnitQuad(gl);
    523  drawBuffersUtils.checkAttachmentsForColor(attachments);
    524 
    525  debug("test that none of the attachments are written in case the fragment shader discards");
    526  var discardProgram = createDrawBuffersProgram("fshaderDiscard",
    527      {numDrawingBuffers: maxDrawingBuffers, assignUColorsToFragData: assignCode.join("\n")});
    528  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    529  gl.drawBuffers(bufs);
    530  gl.clearColor(0, 0, 0, 0);
    531  gl.clear(gl.COLOR_BUFFER_BIT);
    532  gl.useProgram(discardProgram);
    533  wtu.drawUnitQuad(gl);
    534  drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 0, 0, 0]);
    535 
    536  debug("test queries");
    537  debug("check framebuffer with all attachments on");
    538  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    539  for (var ii = 0; ii < maxUsable; ++ii) {
    540    shouldBe("gl.getParameter(gl.DRAW_BUFFER0 + " + ii + ")", "gl.COLOR_ATTACHMENT0 + " + ii);
    541  }
    542 
    543  debug("check framebuffer with all attachments off");
    544  gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
    545  for (var ii = 0; ii < maxUsable; ++ii) {
    546    shouldBe("gl.getParameter(gl.DRAW_BUFFER0 + " + ii + ")", "gl.NONE");
    547  }
    548 
    549  // WebGL generates FRAMEBUFFER_INCOMPLETE_DIMENSIONS when attached images have different sizes.
    550  // This behavior differs from GLES 3.
    551  debug("");
    552  debug("test attachment size mis-match");
    553  gl.bindTexture(gl.TEXTURE_2D, attachments[0].texture);
    554  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width * 2, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    555  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    556  shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
    557  gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
    558  shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
    559 
    560  // TODO: Rendering when framebuffer attachments have mismatched size should be tested, maybe in a separate test.
    561 
    562  gl.deleteFramebuffer(fb);
    563  gl.deleteFramebuffer(fb2);
    564  gl.deleteFramebuffer(halfFB1);
    565  gl.deleteFramebuffer(halfFB2);
    566  attachments.forEach(function(attachment) {
    567    gl.deleteTexture(attachment.texture);
    568  });
    569  gl.deleteProgram(checkProgram);
    570  gl.deleteProgram(redProgram);
    571  gl.deleteProgram(drawProgram);
    572 }
    573 
    574 function testParameters() {
    575  debug("");
    576  debug("check that MAX_DRAW_BUFFERS and MAX_COLOR_ATTACHMENTS are valid");
    577  var maxDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS);
    578  var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
    579  debug("MAX_DRAW_BUFFERS = " + maxDrawBuffers);
    580  debug("MAX_COLOR_ATTACHMENTS = " + maxColorAttachments);
    581  if (maxDrawBuffers != maxColorAttachments) {
    582    testFailed("MAX_DRAW_BUFFERS and MAX_COLOR_ATTACHMENTS should be the same");
    583    return false;
    584  }
    585  if (maxDrawBuffers < 4) {
    586    testFailed("MAX_DRAW_BUFFERS should be at least 4");
    587    return false;
    588  }
    589  return true;
    590 }
    591 
    592 debug("");
    593 var successfullyParsed = true;
    594 </script>
    595 <script src="../../js/js-test-post.js"></script>
    596 
    597 </body>
    598 </html>