tor-browser

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

oes-texture-float.html (23043B)


      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>OES_texture_float/WEBGL_color_buffer_float</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/ext-float-blend.js"></script>
     16 </head>
     17 <body>
     18 <div id="description"></div>
     19 <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
     20 <div id="console"></div>
     21 <!-- Shaders for testing floating-point textures -->
     22 <script id="testFragmentShader" type="x-shader/x-fragment">
     23 precision mediump float;
     24 uniform sampler2D tex;
     25 uniform vec4 subtractor;
     26 varying vec2 texCoord;
     27 void main()
     28 {
     29    vec4 color = texture2D(tex, texCoord);
     30    if (abs(color.r - subtractor.r) +
     31        abs(color.g - subtractor.g) +
     32        abs(color.b - subtractor.b) +
     33        abs(color.a - subtractor.a) < 8.0) {
     34        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
     35    } else {
     36        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
     37    }
     38 }
     39 </script>
     40 <!-- Shaders for testing floating-point render targets -->
     41 <script id="positionVertexShader" type="x-shader/x-vertex">
     42 attribute vec4 vPosition;
     43 void main()
     44 {
     45    gl_Position = vPosition;
     46 }
     47 </script>
     48 <script id="floatingPointFragmentShader" type="x-shader/x-fragment">
     49 void main()
     50 {
     51    gl_FragColor = vec4(10000.0, 10000.0, 10000.0, 10000.0);
     52 }
     53 </script>
     54 <script>
     55 "use strict";
     56 description("This test verifies the functionality of the OES_texture_float and WEBGL_color_buffer_float extensions, if available.");
     57 
     58 debug("");
     59 
     60 var wtu = WebGLTestUtils;
     61 var canvas = document.getElementById("canvas");
     62 var gl = wtu.create3DContext(canvas);
     63 var ext = null;
     64 
     65 if (!gl) {
     66    testFailed("WebGL context does not exist");
     67 } else {
     68    testPassed("WebGL context exists");
     69 
     70    var texturedShaders = [
     71        wtu.simpleTextureVertexShader,
     72        "testFragmentShader"
     73    ];
     74    var testProgram =
     75        wtu.setupProgram(gl,
     76                         texturedShaders,
     77                         ['vPosition', 'texCoord0'],
     78                         [0, 1]);
     79    var quadParameters = wtu.setupUnitQuad(gl, 0, 1);
     80 
     81    // First verify that allocation of floating-point textures fails if
     82    // the extension has not been enabled yet.
     83    runTextureCreationTest(testProgram, false);
     84 
     85    {
     86        debug("");
     87        debug("Testing that component type framebuffer attachment queries are rejected with the extension disabled");
     88        const fbo = gl.createFramebuffer();
     89        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
     90 
     91        const rbo = gl.createRenderbuffer();
     92        gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
     93        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,gl.RENDERBUFFER, rbo);
     94        gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 8, 8);
     95        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup renderbuffer should succeed.");
     96        shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8211 /* FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT */)');
     97        wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Query must fail.");
     98        gl.deleteRenderbuffer(rbo);
     99 
    100        const tex = gl.createTexture();
    101        gl.bindTexture(gl.TEXTURE_2D, tex);
    102        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
    103        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    104        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup texture should succeed.");
    105        shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8211 /* FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT */)');
    106        wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Query must fail.");
    107        gl.deleteTexture(tex);
    108 
    109        gl.deleteFramebuffer(fbo);
    110    }
    111 
    112    if (!gl.getExtension("OES_texture_float")) {
    113        testPassed("No OES_texture_float support -- this is legal");
    114    } else {
    115        testPassed("Successfully enabled OES_texture_float extension");
    116        // If alpha value is missing from a texture it gets filled to 1 when sampling according to GLES2.0 table 3.12
    117        runTextureCreationTest(testProgram, true, gl.RGBA, 4, [10000, 10000, 10000, 10000]);
    118        runTextureCreationTest(testProgram, true, gl.RGB, 3, [10000, 10000, 10000, 1]);
    119        runTextureCreationTest(testProgram, true, gl.LUMINANCE, 1, [10000, 10000, 10000, 1]);
    120        runTextureCreationTest(testProgram, true, gl.ALPHA, 1, [0, 0, 0, 10000]);
    121        runTextureCreationTest(testProgram, true, gl.LUMINANCE_ALPHA, 2, [10000, 10000, 10000, 10000]);
    122 
    123        (function() {
    124            debug("");
    125            var renderable = isRenderable(gl);
    126            var renderableExtName = "WEBGL_color_buffer_float";
    127            var supported = gl.getSupportedExtensions().includes(renderableExtName);
    128            if (renderable && !supported) {
    129                testFailed("RGBA/FLOAT is color renderable but " + renderableExtName + " not exposed");
    130            } else if (supported && !renderable) {
    131                testFailed(renderableExtName + " is exposed but RGBA/FLOAT is not color renderable");
    132            }
    133            if (supported) {
    134                runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 0, true);
    135                runRenderTargetAndReadbackTest(testProgram, gl.RGB, 3, [10000, 10000, 10000, 1], 0, false);
    136                runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 1, true);
    137                runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 0.5, true);
    138                runFramebufferTest();
    139 
    140                {
    141                    debug("");
    142                    debug("Testing that component type framebuffer attachment queries are accepted with the extension enabled");
    143                    ext = gl.getExtension("WEBGL_color_buffer_float");
    144                    shouldBeNonNull('ext');
    145                    const fbo = gl.createFramebuffer();
    146                    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    147 
    148                    const rbo = gl.createRenderbuffer();
    149                    gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
    150                    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,gl.RENDERBUFFER, rbo);
    151                    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 8, 8);
    152                    shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'ext.UNSIGNED_NORMALIZED_EXT');
    153                    gl.renderbufferStorage(gl.RENDERBUFFER, ext.RGBA32F_EXT, 8, 8);
    154                    shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'gl.FLOAT');
    155                    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after valid renderbuffer attachment queries.");
    156 
    157                    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT,gl.RENDERBUFFER, rbo);
    158                    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, 8, 8);
    159                    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after depth-stencil renderbuffer setup.");
    160                    shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)');
    161                    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Component type query is not allowed for combined depth-stencil attachments.");
    162                    gl.deleteRenderbuffer(rbo);
    163 
    164                    const tex = gl.createTexture();
    165                    gl.bindTexture(gl.TEXTURE_2D, tex);
    166                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
    167                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    168                    shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'ext.UNSIGNED_NORMALIZED_EXT');
    169                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.FLOAT, null);
    170                    shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'gl.FLOAT');
    171                    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after valid texture attachment queries.");
    172                    gl.deleteTexture(tex);
    173 
    174                    gl.deleteFramebuffer(fbo);
    175                }
    176 
    177                debug("");
    178                debug("Test float32 blending without EXT_float_blend.");
    179                testExtFloatBlend(gl.RGBA);
    180 
    181                debug("");
    182                debug("Testing that float32 blending succeeds with EXT_float_blend.");
    183                if (!gl.getExtension("EXT_float_blend")) {
    184                    testPassed("No EXT_float_blend support -- this is legal");
    185                    return;
    186                }
    187                testExtFloatBlend(gl.RGBA);
    188            }
    189        })();
    190 
    191        runUniqueObjectTest();
    192    }
    193 }
    194 
    195 function isRenderable(gl) {
    196    var tex = gl.createTexture();
    197    gl.bindTexture(gl.TEXTURE_2D, tex);
    198    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
    199 
    200    var fb = gl.createFramebuffer();
    201    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    202    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
    203 
    204    var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
    205    gl.deleteFramebuffer(fb);
    206    gl.deleteTexture(tex);
    207 
    208    return status == gl.FRAMEBUFFER_COMPLETE;
    209 }
    210 
    211 function allocateTexture()
    212 {
    213    var texture = gl.createTexture();
    214    gl.bindTexture(gl.TEXTURE_2D, texture);
    215    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    216    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    217    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    218    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    219    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture parameter setup should succeed");
    220    return texture;
    221 }
    222 
    223 function checkRenderingResults()
    224 {
    225    wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
    226 }
    227 
    228 function runTextureCreationTest(testProgram, extensionEnabled, opt_format, opt_numChannels, opt_subtractor)
    229 {
    230    var format = opt_format || gl.RGBA;
    231    var numberOfChannels = opt_numChannels || 4;
    232    var expectFailure = !extensionEnabled;
    233    var subtractor = opt_subtractor || [10000, 10000, 10000, 10000];
    234 
    235    debug("");
    236    debug("testing format: " + wtu.glEnumToString(gl, format) +
    237          " expect:" + (extensionEnabled ? "success" : "failure"));
    238 
    239    var texture = allocateTexture();
    240    // Generate data.
    241    var width = 2;
    242    var height = 2;
    243    var data = new Float32Array(width * height * numberOfChannels);
    244    for (var ii = 0; ii < data.length; ++ii) {
    245        data[ii] = 10000;
    246    }
    247    gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, gl.FLOAT, data);
    248    if (expectFailure) {
    249        wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "floating-point texture allocation must be disallowed if OES_texture_float isn't enabled");
    250        return;
    251    } else {
    252        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "floating-point texture allocation should succeed if OES_texture_float is enabled");
    253    }
    254    // Verify that the texture actually works for sampling and contains the expected data.
    255    gl.uniform4fv(gl.getUniformLocation(testProgram, "subtractor"), subtractor);
    256    wtu.clearAndDrawUnitQuad(gl);
    257    checkRenderingResults();
    258 
    259    // Check that linear fails.
    260    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    261    wtu.clearAndDrawUnitQuad(gl);
    262    wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
    263 }
    264 
    265 function arrayToString(arr, size) {
    266    var mySize;
    267    if (!size)
    268        mySize = arr.length;
    269    else
    270        mySize = size;
    271    var out = "[";
    272    for (var ii = 0; ii < mySize; ++ii) {
    273    if (ii > 0) {
    274        out += ", ";
    275    }
    276    out += arr[ii];
    277    }
    278    return out + "]";
    279 }
    280 
    281 function runRenderTargetAndReadbackTest(testProgram, format, numberOfChannels, subtractor, texSubImageCover, requireRenderable)
    282 {
    283    var formatString = wtu.glEnumToString(gl, format);
    284    debug("");
    285    debug("testing floating-point " + formatString + " render target" + (texSubImageCover > 0 ? " after calling texSubImage" : ""));
    286 
    287    var texture = allocateTexture();
    288    var width = 2;
    289    var height = 2;
    290    gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, gl.FLOAT, null);
    291    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "floating-point texture allocation should succeed if OES_texture_float is enabled");
    292 
    293    // Try to use this texture as a render target.
    294    var fbo = gl.createFramebuffer();
    295    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    296    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
    297    gl.bindTexture(gl.TEXTURE_2D, null);
    298    // It is legal for a WebGL implementation exposing the OES_texture_float extension to
    299    // support floating-point textures but not as attachments to framebuffer objects.
    300    if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
    301        if (requireRenderable)
    302            testFailed("floating-point " + formatString + " render target not supported");
    303        else
    304            debug("floating-point " + formatString + " render target not supported -- this is legal");
    305        return;
    306    }
    307 
    308    if (texSubImageCover > 0) {
    309        // Ensure that replacing the whole texture or a part of it with texSubImage2D doesn't affect renderability
    310        gl.bindTexture(gl.TEXTURE_2D, texture);
    311        var data = new Float32Array(width * height * numberOfChannels * texSubImageCover);
    312        gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height * texSubImageCover, format, gl.FLOAT, data);
    313        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texSubImage2D should succeed if OES_texture_float is enabled");
    314        gl.bindTexture(gl.TEXTURE_2D, null);
    315        if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
    316            testFailed("render target support changed after calling texSubImage2D");
    317            return;
    318        }
    319    }
    320 
    321    var renderProgram =
    322        wtu.setupProgram(gl,
    323                         ["positionVertexShader", "floatingPointFragmentShader"],
    324                         ['vPosition'],
    325                         [0]);
    326    wtu.clearAndDrawUnitQuad(gl);
    327    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "rendering to floating-point texture should succeed");
    328 
    329    // Now sample from the floating-point texture and verify we got the correct values.
    330    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    331    gl.bindTexture(gl.TEXTURE_2D, texture);
    332    gl.useProgram(testProgram);
    333    gl.uniform1i(gl.getUniformLocation(testProgram, "tex"), 0);
    334    gl.uniform4fv(gl.getUniformLocation(testProgram, "subtractor"), subtractor);
    335    wtu.clearAndDrawUnitQuad(gl);
    336    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "rendering from floating-point texture should succeed");
    337    checkRenderingResults();
    338 
    339    // Finally, if the implementation supports floating-point readback, verify it.
    340    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    341    var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
    342    var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
    343    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "getParameter of IMPLEMENTATION_COLOR_READ_{FORMAT|TYPE} should succeed");
    344    if ((implFormat == gl.RGBA || implFormat == gl.RGB) && implType == gl.FLOAT) {
    345    debug("Checking readback of floating-point values");
    346    var arraySize = (implFormat == gl.RGBA) ? 4 : 3
    347    var buf = new Float32Array(arraySize);
    348    gl.readPixels(0, 0, 1, 1, implFormat, implType , buf);
    349    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels from floating-point renderbuffer should succeed");
    350    var ok = true;
    351    var tolerance = 8.0; // TODO: factor this out from both this test and the subtractor shader above.
    352    for (var ii = 0; ii < buf.length; ++ii) {
    353        if (Math.abs(buf[ii] - subtractor[ii]) > tolerance) {
    354        ok = false;
    355        break;
    356        }
    357    }
    358    if (ok) {
    359        testPassed("readPixels of float-type data from floating-point renderbuffer succeeded");
    360    } else {
    361        testFailed("readPixels of float-type data from floating-point renderbuffer failed: expected "
    362               + arrayToString(subtractor, arraySize) + ", got " + arrayToString(buf));
    363    }
    364    }
    365 }
    366 
    367 function runUniqueObjectTest()
    368 {
    369    debug("");
    370    debug("Testing that getExtension() returns the same object each time");
    371    gl.getExtension("OES_texture_float").myProperty = 2;
    372    webglHarnessCollectGarbage();
    373    shouldBe('gl.getExtension("OES_texture_float").myProperty', '2');
    374 }
    375 
    376 // Make sure we can call readPixels with the passed in arrayBufferConstructor and that the color
    377 // channels are the ones we expect. If there is a mismatch between the glType and arrayBuffer type,
    378 // fail the test.
    379 function verifyReadPixelsColors(red, green, blue, alpha, alphaRGB, glFormat, glType, arrayBufferConstructor) {
    380    var typeName = wtu.glEnumToString(gl, glType);
    381 
    382    debug(wtu.glEnumToString(gl, glFormat) + " framebuffer with " + typeName + " readback.");
    383 
    384    var arrayBuffer = new arrayBufferConstructor(4);
    385    gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
    386    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels should return NO_ERROR when reading " + typeName + " data.");
    387 
    388    assertMsg(arrayBuffer[0] === red, "Red channel should be " + red + " for " + typeName + " readPixels. Received: " + arrayBuffer[0]);
    389    assertMsg(arrayBuffer[1] === green, "Green channel should be " + green + " for " + typeName + " readPixels. Received: " + arrayBuffer[1]);
    390    assertMsg(arrayBuffer[2] === blue, "Blue channel should be " + blue + " for " + typeName + " readPixels. Received: " + arrayBuffer[2]);
    391    if (glFormat === gl.RGBA) {
    392        assertMsg(arrayBuffer[3] === alpha, "Alpha channel should be " + alpha + " for " + typeName + " readPixels. Received: " + arrayBuffer[3]);
    393    } else if (glFormat === gl.RGB) {
    394        assertMsg(arrayBuffer[3] === alphaRGB, "Alpha channel should be " + alphaRGB + " for " + typeName + " readPixels. Received: " + arrayBuffer[3]);
    395    }
    396 
    397    // Make sure any arrayBuffer types that are not equal to arrayBufferConstructor fail readPixels.
    398    if (arrayBufferConstructor !== Uint8Array) {
    399        arrayBuffer = new Uint8Array(4);
    400        gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
    401        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Uint8Array.toString());
    402    }
    403    if (arrayBufferConstructor !== Float32Array) {
    404        arrayBuffer = new Float32Array(4);
    405        gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
    406        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Float32Array.toString());
    407    }
    408    if (arrayBufferConstructor !== Uint16Array) {
    409        arrayBuffer = new Uint16Array(4);
    410        gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
    411        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Uint16Array.toString());
    412    }
    413 }
    414 
    415 // Verify that float textures attached to frame buffers function correctly with regard to framebuffer
    416 // completness, IMPLEMENTATION_COLOR_READ_FORMAT/TYPE and readPixels
    417 function runFramebufferTest() {
    418    debug("");
    419    debug("Framebuffer Tests");
    420 
    421    var texture = allocateTexture();
    422    gl.bindTexture(gl.TEXTURE_2D, texture);
    423 
    424    var fbo = gl.createFramebuffer();
    425    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    426    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
    427 
    428    debug("Ensure non-color-renderable formats [LUMINANCE, LUMINANCE_ALPHA, ALPHA] fail.");
    429    var arrayBufferFloatOutput = new Float32Array(4); // 4 color channels
    430    [gl.LUMINANCE, gl.LUMINANCE_ALPHA, gl.ALPHA].forEach(function(badFormat) {
    431        debug(wtu.glEnumToString(gl, badFormat) + " framebuffer");
    432 
    433        gl.texImage2D(gl.TEXTURE_2D, 0, badFormat, 1, 1, 0, badFormat, gl.FLOAT, null);
    434        shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
    435 
    436        shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT)");
    437        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "IMPLEMENTATION_COLOR_READ_FORMAT should fail for incomplete framebuffers.");
    438 
    439        shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE)");
    440        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "IMPLEMENTATION_COLOR_READ_TYPE should fail for incomplete framebuffers.");
    441 
    442        gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, arrayBufferFloatOutput);
    443        wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION , "readPixels should fail on incomplete framebuffers.");
    444        debug("");
    445    });
    446 
    447    debug("Ensure color renderable formats [RGBA, RGB] succeed.");
    448    var arrayBufferFloatInput = new Float32Array(4); // 4 color channels
    449    arrayBufferFloatInput[0] = 0;
    450    arrayBufferFloatInput[1] = .25;
    451    arrayBufferFloatInput[2] = .50;
    452    arrayBufferFloatInput[3] = .75;
    453 
    454    [gl.RGBA, gl.RGB].forEach(function(goodFormat) {
    455        debug("");
    456        debug(wtu.glEnumToString(gl, goodFormat) + " framebuffer tests");
    457 
    458        gl.texImage2D(gl.TEXTURE_2D, 0, goodFormat, 1, 1, 0, goodFormat, gl.FLOAT, arrayBufferFloatInput);
    459        if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
    460            testPassed("Format is not renderable. This is allowed.");
    461            return;
    462        }
    463        verifyReadPixelsColors(
    464            0.00, // red
    465            0.25, // green
    466            0.50, // blue
    467            0.75, // alpha
    468            1.0,  // alphaRGB
    469            goodFormat,
    470            gl.FLOAT,
    471            Float32Array);
    472 
    473        var implementationColorReadFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
    474        assertMsg(implementationColorReadFormat === gl.RGBA || implementationColorReadFormat === gl.RGB,
    475            "IMPLEMENTATION_COLOR_READ_FORMAT should be color renderable: RGBA or RGB. Received: " + wtu.glEnumToString(gl, implementationColorReadFormat));
    476 
    477        var implementationColorReadType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
    478        assertMsg(implementationColorReadType === gl.UNSIGNED_BYTE ||
    479                  implementationColorReadType === gl.FLOAT ||
    480                  "IMPLEMENTATION_COLOR_READ_TYPE must be one of UNSIGNED_BYTE or FLOAT " +
    481                  "Received: " + wtu.glEnumToString(gl, implementationColorReadType));
    482    });
    483 }
    484 
    485 debug("");
    486 var successfullyParsed = true;
    487 </script>
    488 <script src="../../js/js-test-post.js"></script>
    489 
    490 </body>
    491 </html>