tor-browser

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

read-pixels-from-fbo-test.html (19541B)


      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 2 ReadPixels Test.</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 </head>
     16 <body>
     17 <div id="description"></div>
     18 <div id="console"></div>
     19 <script>
     20 "use strict";
     21 description("Checks that ReadPixels from a fbo works as expected.");
     22 
     23 var wtu = WebGLTestUtils;
     24 var gl = wtu.create3DContext(undefined, undefined, 2);
     25 gl.pixelStorei(gl.PACK_ALIGNMENT, 1);
     26 
     27 function getChannelCount(format) {
     28  switch (format) {
     29    case gl.RED:
     30    case gl.RED_INTEGER:
     31    case gl.ALPHA:
     32    case gl.LUMINANCE:
     33      return 1;
     34    case gl.RB:
     35    case gl.RB_INTEGER:
     36    case gl.LUMINANCE_ALPHA:
     37      return 2;
     38    case gl.RGB:
     39    case gl.RGB_INTEGER:
     40      return 3;
     41    case gl.RGBA:
     42    case gl.RGBA_INTEGER:
     43      return 4;
     44    default:
     45      return 0;
     46  }
     47 }
     48 
     49 function getUnpackInfo(type) {
     50  switch (type) {
     51    case gl.UNSIGNED_SHORT_5_6_5:
     52      return {bitsCount: [5, 6, 5], isReverse: false};
     53    case gl.UNSIGNED_SHORT_4_4_4_4:
     54      return {bitsCount: [4, 4, 4, 4], isReverse: false};
     55    case gl.UNSIGNED_SHORT_5_5_5_1:
     56      return {bitsCount: [5, 5, 5, 1], isReverse: false};
     57    case gl.UNSIGNED_INT_2_10_10_10_REV:
     58      return {bitsCount: [2, 10, 10, 10], isReverse: true};
     59    case gl.UNSIGNED_INT_10F_11F_11F_REV:
     60      return {bitsCount: [10, 11, 11], isReverse: true};
     61    case gl.UNSIGNED_INT_5_9_9_9_REV:
     62      return {bitsCount: [5, 9, 9, 9], isReverse: true};
     63    default:
     64      return null;
     65  }
     66 }
     67 
     68 // bitsCount is an array contains bit count for each component.
     69 function unpack(value, channelCount, bitsCount, isReverse) {
     70  var result = new Array(channelCount);
     71 
     72  var accumBitsCount = 0;
     73  for (var i = channelCount - 1; i >= 0; --i) {
     74    var currentChannel = isReverse ? (channelCount - i - 1) : i;
     75    var mask = 0xFFFFFFFF >>> (32 - bitsCount[i]);
     76    result[currentChannel] = ((value >> accumBitsCount) & mask);
     77    accumBitsCount += bitsCount[i];
     78  }
     79 
     80  return result;
     81 }
     82 
     83 function getColor(buf, index, readFormat, readType) {
     84  var channelCount = getChannelCount(readFormat);
     85  var result = new Array(channelCount);
     86 
     87  var unpackInfo = getUnpackInfo(readType);
     88  if (unpackInfo) {
     89    result = unpack(buf[index], channelCount, unpackInfo.bitsCount, unpackInfo.isReverse);
     90  } else {
     91    for (var i = 0; i < channelCount; ++i) {
     92      result[i] = buf[index + i];
     93    }
     94  }
     95 
     96  return result;
     97 }
     98 
     99 function convertToSRGB(val) {
    100  if (val <= 0) {
    101    return 0;
    102  } else if (val < 0.0031308) {
    103    return 12.92 * val;
    104  } else if (val < 1) {
    105    return 1.055 * Math.pow(val, 0.41666) - 0.055;
    106  } else {
    107    return 1;
    108  }
    109 }
    110 
    111 function denormalizeColor(srcInternalFormat, destType, color) {
    112  var result = color.slice();
    113  var tol = 0;
    114 
    115  var srcIsNormalized = false;
    116 
    117  switch (srcInternalFormat) {
    118    case gl.R8:
    119    case gl.RG8:
    120    case gl.RGB8:
    121    case gl.RGBA8:
    122    case gl.RGB5_A1:
    123    case gl.SRGB8_ALPHA8:
    124    case gl.RGB10_A2:
    125      srcIsNormalized = true;
    126      tol = 6;
    127      break;
    128    case gl.RGB565:
    129      // RGB565 needs slightly extra tolerance, at least on Google Pixel. crbug.com/682753
    130      srcIsNormalized = true;
    131      tol = 7;
    132      break;
    133    case gl.RGBA4:
    134      srcIsNormalized = true;
    135      tol = 10;
    136      break;
    137  }
    138 
    139  if (!srcIsNormalized) {
    140    return { color: result, tol: tol };
    141  }
    142 
    143  if (srcInternalFormat == gl.SRGB8_ALPHA8) {
    144    for (var i = 0; i < 3; ++i) {
    145      result[i] = convertToSRGB(result[i]);
    146    }
    147  }
    148 
    149  switch (destType) {
    150    case gl.UNSIGNED_BYTE:
    151      result = result.map(val => { return val * 0xFF});
    152      break;
    153    case gl.UNSIGNED_SHORT:
    154      // On Linux NVIDIA, tol of 33 is necessary to pass the test.
    155      tol = 40;
    156      result = result.map(val => { return val * 0xFFFF});
    157      break;
    158    case gl.UNSIGNED_INT:
    159      tol = 40;
    160      result = result.map(val => { return val * 0xFFFFFFFF});
    161      break;
    162    case gl.UNSIGNED_SHORT_4_4_4_4:
    163      result = result.map(val => { return val * 0xF});
    164      break;
    165    case gl.UNSIGNED_SHORT_5_5_5_1:
    166      result[0] = result[0] * 0x1F;
    167      result[1] = result[1] * 0x1F;
    168      result[2] = result[2] * 0x1F;
    169      result[3] = result[3] * 0x1;
    170      break;
    171    case gl.UNSIGNED_SHORT_5_6_5:
    172      result[0] = result[0] * 0x1F;
    173      result[1] = result[1] * 0x3F;
    174      result[2] = result[2] * 0x1F;
    175      break;
    176    case gl.UNSIGNED_INT_2_10_10_10_REV:
    177      tol = 25;
    178      result[0] = result[0] * 0x3FF;
    179      result[1] = result[1] * 0x3FF;
    180      result[2] = result[2] * 0x3FF;
    181      result[3] = result[3] * 0x3;
    182      break;
    183    case gl.UNSIGNED_INT_5_9_9_9_REV:
    184      result[0] = result[0] * 0x1FF;
    185      result[1] = result[1] * 0x1FF;
    186      result[2] = result[2] * 0x1FF;
    187      result[3] = result[3] * 0x1F;
    188      break;
    189  }
    190 
    191  return { color: result, tol: tol };
    192 }
    193 
    194 function compareColor(buf, index, expectedColor, srcInternalFormat,
    195                      srcFormat, srcType, readFormat, readType) {
    196  var srcChannelCount = getChannelCount(srcFormat);
    197  var readChannelCount = getChannelCount(readFormat);
    198 
    199  var color = getColor(buf, index, readFormat, readType);
    200  expectedColor = denormalizeColor(srcInternalFormat, readType, expectedColor);
    201 
    202  var minChannel = Math.min(srcChannelCount, readChannelCount);
    203  for (var i = 0; i < minChannel; ++i) {
    204    if (Math.abs(expectedColor.color[i] - color[i]) > expectedColor.tol) {
    205      testFailed("Expected color = " + expectedColor.color + ", was = " + color);
    206      return false;
    207    }
    208  }
    209 
    210  return true;
    211 }
    212 
    213 var textureTestCases = [
    214  {
    215    texInternalFormat: 'R8', texFormat: 'RED', texType: 'UNSIGNED_BYTE',
    216    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    217    clearColor: [0.5, 0.0, 0.0, 0],
    218  },
    219  {
    220    texInternalFormat: 'R8UI', texFormat: 'RED_INTEGER', texType: 'UNSIGNED_BYTE',
    221    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    222    clearColor: [250, 0, 0, 0],
    223  },
    224  {
    225    texInternalFormat: 'R8I', texFormat: 'RED_INTEGER', texType: 'BYTE',
    226    readFormat: 'RGBA_INTEGER', readType: 'INT',
    227    clearColor: [-126, 0, 0, 0],
    228  },
    229  {
    230    texInternalFormat: 'R16UI', texFormat: 'RED_INTEGER', texType: 'UNSIGNED_SHORT',
    231    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    232    clearColor: [30001, 0, 0, 0],
    233  },
    234  {
    235    texInternalFormat: 'R16I', texFormat: 'RED_INTEGER', texType: 'SHORT',
    236    readFormat: 'RGBA_INTEGER', readType: 'INT',
    237    clearColor: [-14189, 0, 0, 0],
    238  },
    239  {
    240    texInternalFormat: 'R32UI', texFormat: 'RED_INTEGER', texType: 'UNSIGNED_INT',
    241    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    242    clearColor: [126726, 0, 0, 0],
    243  },
    244  {
    245    texInternalFormat: 'R32I', texFormat: 'RED_INTEGER', texType: 'INT',
    246    readFormat: 'RGBA_INTEGER', readType: 'INT',
    247    clearColor: [-126726, 0, 0, 0],
    248  },
    249 
    250  {
    251    texInternalFormat: 'RG8', texFormat: 'RG', texType: 'UNSIGNED_BYTE',
    252    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    253    clearColor: [0.5, 0.7, 0.0, 0],
    254  },
    255  {
    256    texInternalFormat: 'RG8UI', texFormat: 'RG_INTEGER', texType: 'UNSIGNED_BYTE',
    257    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    258    clearColor: [250, 124, 0, 0],
    259  },
    260  {
    261    texInternalFormat: 'RG8I', texFormat: 'RG_INTEGER', texType: 'BYTE',
    262    readFormat: 'RGBA_INTEGER', readType: 'INT',
    263    clearColor: [-55, 124, 0, 0],
    264  },
    265  {
    266    texInternalFormat: 'RG16UI', texFormat: 'RG_INTEGER', texType: 'UNSIGNED_SHORT',
    267    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    268    clearColor: [30001, 18, 0, 0],
    269  },
    270  {
    271    texInternalFormat: 'RG16I', texFormat: 'RG_INTEGER', texType: 'SHORT',
    272    readFormat: 'RGBA_INTEGER', readType: 'INT',
    273    clearColor: [-14189, 6735, 0, 0],
    274  },
    275  {
    276    texInternalFormat: 'RG32UI', texFormat: 'RG_INTEGER', texType: 'UNSIGNED_INT',
    277    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    278    clearColor: [126726, 1976, 0, 0],
    279  },
    280  {
    281    texInternalFormat: 'RG32I', texFormat: 'RG_INTEGER', texType: 'INT',
    282    readFormat: 'RGBA_INTEGER', readType: 'INT',
    283    clearColor: [-126726, 126726, 0, 0],
    284  },
    285 
    286  {
    287    texInternalFormat: 'RGB8', texFormat: 'RGB', texType: 'UNSIGNED_BYTE',
    288    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    289    clearColor: [0.5, 1, 0, 0],
    290  },
    291  {
    292    texInternalFormat: 'RGB565', texFormat: 'RGB', texType: 'UNSIGNED_BYTE',
    293    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    294    clearColor: [0.5, 0.7, 0.2, 0],
    295  },
    296  {
    297    texInternalFormat: 'RGB565', texFormat: 'RGB', texType: 'UNSIGNED_SHORT_5_6_5',
    298    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    299    clearColor: [0.5, 0.7, 0.2, 0],
    300  },
    301 
    302  {
    303    texInternalFormat: 'RGBA8', texFormat: 'RGBA', texType: 'UNSIGNED_BYTE',
    304    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    305    clearColor: [0.5, 0, 1, 0.7],
    306  },
    307  {
    308    texInternalFormat: 'SRGB8_ALPHA8', texFormat: 'RGBA', texType: 'UNSIGNED_BYTE',
    309    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    310    clearColor: [0.5, 0, 1, 0.7],
    311  },
    312  {
    313    texInternalFormat: 'RGB5_A1', texFormat: 'RGBA', texType: 'UNSIGNED_BYTE',
    314    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    315    clearColor: [0.5, 0, 0.7, 1],
    316  },
    317  {
    318    texInternalFormat: 'RGB5_A1', texFormat: 'RGBA', texType: 'UNSIGNED_SHORT_5_5_5_1',
    319    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    320    clearColor: [0.5, 0.7, 1, 0],
    321  },
    322  {
    323    texInternalFormat: 'RGB5_A1', texFormat: 'RGBA', texType: 'UNSIGNED_INT_2_10_10_10_REV',
    324    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    325    clearColor: [0.5, 0.7, 0, 1],
    326  },
    327  {
    328    texInternalFormat: 'RGBA4', texFormat: 'RGBA', texType: 'UNSIGNED_BYTE',
    329    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    330    clearColor: [0.5, 0.7, 1, 0],
    331  },
    332  {
    333    texInternalFormat: 'RGBA4', texFormat: 'RGBA', texType: 'UNSIGNED_SHORT_4_4_4_4',
    334    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    335    clearColor: [1, 0, 0.5, 0.7],
    336  },
    337  {
    338    texInternalFormat: 'RGBA8UI', texFormat: 'RGBA_INTEGER', texType: 'UNSIGNED_BYTE',
    339    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    340    clearColor: [127, 0, 255, 178],
    341  },
    342  {
    343    texInternalFormat: 'RGBA8I', texFormat: 'RGBA_INTEGER', texType: 'BYTE',
    344    readFormat: 'RGBA_INTEGER', readType: 'INT',
    345    clearColor: [-55, 56, 80, 127],
    346  },
    347  {
    348    texInternalFormat: 'RGB10_A2UI', texFormat: 'RGBA_INTEGER', texType: 'UNSIGNED_INT_2_10_10_10_REV',
    349    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    350    clearColor: [178, 0, 127, 3],
    351  },
    352  {
    353    texInternalFormat: 'RGBA16UI', texFormat: 'RGBA_INTEGER', texType: 'UNSIGNED_SHORT',
    354    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    355    clearColor: [14189, 6735, 0, 19],
    356  },
    357  {
    358    texInternalFormat: 'RGBA16I', texFormat: 'RGBA_INTEGER', texType: 'SHORT',
    359    readFormat: 'RGBA_INTEGER', readType: 'INT',
    360    clearColor: [14189, -6735, 0, 19],
    361  },
    362  {
    363    texInternalFormat: 'RGBA32UI', texFormat: 'RGBA_INTEGER', texType: 'UNSIGNED_INT',
    364    readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
    365    clearColor: [126726, 6726, 98765, 2015],
    366  },
    367  {
    368    texInternalFormat: 'RGBA32I', texFormat: 'RGBA_INTEGER', texType: 'INT',
    369    readFormat: 'RGBA_INTEGER', readType: 'INT',
    370    clearColor: [126726, -6726, -98765, 2015],
    371  },
    372 
    373  {
    374    texInternalFormat: 'RGB10_A2', texFormat: 'RGBA', texType: 'UNSIGNED_INT_2_10_10_10_REV',
    375    readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
    376    clearColor: [0.7, 0, 0.5, 1],
    377  },
    378 
    379  // TODO(zmo): add float/half_float test cases with extension supports.
    380 ];
    381 
    382 function getArrayTypeFromReadPixelsType(gl, type) {
    383  switch (type) {
    384    case gl.UNSIGNED_BYTE:
    385      return Uint8Array;
    386    case gl.BYTE:
    387      return Int8Array;
    388    case gl.UNSIGNED_SHORT:
    389    case gl.UNSIGNED_SHORT_5_6_5:
    390    case gl.UNSIGNED_SHORT_4_4_4_4:
    391    case gl.UNSIGNED_SHORT_5_5_5_1:
    392      return Uint16Array;
    393    case gl.SHORT:
    394      return Int16Array;
    395    case gl.UNSIGNED_INT:
    396    case gl.UNSIGNED_INT_2_10_10_10_REV:
    397    case gl.UNSIGNED_INT_10F_11F_11F_REV:
    398    case gl.UNSIGNED_INT_5_9_9_9_REV:
    399      return Uint32Array;
    400    case gl.INT:
    401      return Int32Array;
    402    case gl.HALF_FLOAT:
    403      return Uint16Array;
    404    case gl.FLOAT:
    405      return Float32Array;
    406    default:
    407      return null;
    408  }
    409 }
    410 
    411 function getFormatString(gl, format) {
    412  switch (format) {
    413    case gl.RED:
    414      return 'RED';
    415    case gl.RED_INTEGER:
    416      return 'RED_INTEGER';
    417    case gl.RG:
    418      return 'RG';
    419    case gl.RG_INTEGER:
    420      return 'RG_INTEGER';
    421    case gl.RGB:
    422      return 'RGB';
    423    case gl.RGB_INTEGER:
    424      return 'RGB_INTEGER';
    425    case gl.RGBA:
    426      return 'RGBA';
    427    case gl.RGBA_INTEGER:
    428      return 'RGBA_INTEGER';
    429    case gl.LUMINANCE:
    430      return 'LUMINANCE';
    431    case gl.LUMINANCE_ALPHA:
    432      return 'LUMINANCE_ALPHA';
    433    case gl.ALPHA:
    434      return 'ALPHA';
    435    default:
    436      return '';
    437  };
    438 }
    439 
    440 function getTypeString(gl, type) {
    441  switch (type) {
    442    case gl.UNSIGNED_BYTE:
    443      return 'UNSIGNED_BYTE';
    444    case gl.BYTE:
    445      return 'BYTE';
    446    case gl.UNSIGNED_SHORT:
    447      return 'UNSIGNED_SHORT';
    448    case gl.SHORT:
    449      return 'SHORT';
    450    case gl.UNSIGNED_INT:
    451      return 'UNSIGNED_INT';
    452    case gl.INT:
    453      return 'INT';
    454    case gl.UNSIGNED_SHORT_5_6_5:
    455      return 'UNSIGNED_SHORT_5_6_5';
    456    case gl.UNSIGNED_SHORT_5_5_5_1:
    457      return 'UNSIGNED_SHORT_5_5_5_1';
    458    case gl.UNSIGNED_INT_2_10_10_10_REV:
    459      return 'UNSIGNED_INT_2_10_10_10_REV';
    460    case gl.UNSIGNED_SHORT_4_4_4_4:
    461      return 'UNSIGNED_SHORT_4_4_4_4';
    462    case gl.UNSIGNED_INT_10F_11F_11F_REV:
    463      return 'UNSIGNED_INT_10F_11F_11F_REV';
    464    case gl.UNSIGNED_INT_5_9_9_9_REV:
    465      return 'UNSIGNED_INT_5_9_9_9_REV';
    466    default:
    467      return '';
    468  };
    469 }
    470 
    471 function elementCountPerPixel(gl, readFormat, readType) {
    472  switch (readFormat) {
    473    case gl.RED:
    474    case gl.RED_INTEGER:
    475    case gl.ALPHA:
    476    case gl.LUMINANCE:
    477      return 1;
    478    case gl.RG:
    479    case gl.RG_INTEGER:
    480    case gl.LUMINANCE_ALPHA:
    481      return 2;
    482    case gl.RGB:
    483    case gl.RGB_INTEGER:
    484      switch (readType) {
    485        case gl.UNSIGNED_SHORT_5_6_5:
    486          return 1;
    487        default:
    488          return 3;
    489      }
    490    case gl.RGBA:
    491    case gl.RGBA_INTEGER:
    492      switch (readType) {
    493        case gl.UNSIGNED_SHORT_4_4_4_4:
    494        case gl.UNSIGNED_SHORT_5_5_5_1:
    495        case gl.UNSIGNED_INT_2_10_10_10_REV:
    496        case gl.UNSIGNED_INT_10F_11F_11F_REV:
    497        case gl.UNSIGNED_INT_5_9_9_9_REV:
    498          return 1;
    499        default:
    500          return 4;
    501      }
    502    default:
    503      testFailed("Unexpected read format/type = " + readFormat + "/" + readType);
    504      return 0;
    505  }
    506 }
    507 
    508 function testReadPixels(gl, srcInternalFormat, srcFormat, srcType,
    509                        readFormat, readType, expectedColor) {
    510  var arrayType = getArrayTypeFromReadPixelsType(gl, readType);
    511  var buf = new arrayType(width * height * 4);
    512  gl.readPixels(0, 0, width, height, readFormat, readType, buf);
    513  wtu.glErrorShouldBe(
    514      gl, gl.NO_ERROR, "readPixels should generate no error");
    515  var diffFound = false;
    516  for (var ii = 0; ii < width * height; ++ii) {
    517    var offset = ii * elementCountPerPixel(gl, readFormat, readType);
    518    if (!compareColor(buf, offset, expectedColor, srcInternalFormat, srcFormat, srcType,
    519                      readFormat, readType)) {
    520      diffFound = true;
    521      break;
    522    }
    523  }
    524  if (!diffFound) {
    525    testPassed("Color read back as expected");
    526  }
    527 }
    528 
    529 function clearBuffer(gl, texInternalFormat, clearColor) {
    530  var value;
    531  switch (texInternalFormat) {
    532    case gl.R8UI:
    533    case gl.R16UI:
    534    case gl.R32UI:
    535    case gl.RG8UI:
    536    case gl.RG16UI:
    537    case gl.RG32UI:
    538    case gl.RGBA8UI:
    539    case gl.RGBA16UI:
    540    case gl.RGBA32UI:
    541    case gl.RGB10_A2UI:
    542      value = new Uint32Array(4);
    543      for (var ii = 0; ii < 4; ++ii)
    544        value[ii] = clearColor[ii];
    545      gl.clearBufferuiv(gl.COLOR, 0, value);
    546      break;
    547    case gl.R8I:
    548    case gl.R16I:
    549    case gl.R32I:
    550    case gl.RG8I:
    551    case gl.RG16I:
    552    case gl.RG32I:
    553    case gl.RGBA8I:
    554    case gl.RGBA16I:
    555    case gl.RGBA32I:
    556      value = new Int32Array(4);
    557      for (var ii = 0; ii < 4; ++ii)
    558        value[ii] = clearColor[ii];
    559      gl.clearBufferiv(gl.COLOR, 0, value);
    560      break;
    561    default:
    562      gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
    563      gl.clear(gl.COLOR_BUFFER_BIT);
    564      break;
    565  }
    566 }
    567 
    568 for (var tt = 0; tt < textureTestCases.length; ++tt) {
    569  var test = textureTestCases[tt];
    570  debug("");
    571  debug("ReadPixels from fbo with texture = (" + test.texInternalFormat +
    572        ", " + test.texFormat + ", " + test.texType +
    573        "), format = " + test.readFormat + ", type = " + test.readType);
    574  var width = 2;
    575  var height = 2;
    576  var fbo = gl.createFramebuffer();
    577  gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    578  var colorImage = gl.createTexture();
    579  gl.bindTexture(gl.TEXTURE_2D, colorImage);
    580  gl.texImage2D(gl.TEXTURE_2D, 0, gl[test.texInternalFormat], width, height, 0,
    581                gl[test.texFormat], gl[test.texType], null);
    582  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
    583                          gl.TEXTURE_2D, colorImage, 0);
    584  wtu.glErrorShouldBe(
    585      gl, gl.NO_ERROR, "Setting up fbo should generate no error");
    586  if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
    587    debug("fbo is not complete, skip");
    588    continue;
    589  }
    590  clearBuffer(gl, gl[test.texInternalFormat], test.clearColor);
    591  wtu.glErrorShouldBe(
    592      gl, gl.NO_ERROR, "Clear color should generate no error");
    593 
    594  var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
    595  var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
    596  var implFormatString = getFormatString(gl, implFormat);
    597  var implTypeString = getTypeString(gl, implType);
    598 
    599  if (gl[test.texInternalFormat] == gl.RGB10_A2) {
    600    // This is a special case where three read format/type are supported.
    601    var readTypes = [gl.UNSIGNED_BYTE, gl.UNSIGNED_INT_2_10_10_10_REV];
    602    var readTypeStrings = ['UNSIGNED_BYTE', 'UNSIGNED_INT_2_10_10_10_REV'];
    603    if (implFormat == gl.RGBA && implTypeString != '') {
    604      readTypes.push(implType);
    605      readTypeStrings.push(implTypeString);
    606    } else {
    607      testFailed("Unimplemented Implementation dependent color read format/type = " +
    608                 implFormat + "/" + implType);
    609    }
    610    for (var rr = 0; rr < readTypes.length; ++rr) {
    611      debug("Special case RGB10_A2, format = RGBA, type = " + readTypeStrings[rr]);
    612      testReadPixels(gl, gl[test.texInternalFormat], gl[test.texFormat], gl[test.texType],
    613                     gl.RGBA, readTypes[rr], test.clearColor);
    614    }
    615  } else {
    616    testReadPixels(gl, gl[test.texInternalFormat], gl[test.texFormat], gl[test.texType],
    617                   gl[test.readFormat], gl[test.readType], test.clearColor);
    618 
    619    debug("Testing implementation dependent color read format = " + implFormatString +
    620          ", type = " + implTypeString);
    621    if (implFormatString == '') {
    622      testFailed("Invalid IMPLEMENTATION_COLOR_READ_FORMAT = " + implFormat);
    623      continue;
    624    }
    625    if (implTypeString == '') {
    626      testFailed("Invalid IMPLEMENTATION_COLOR_READ_TYPE = " + implType);
    627      continue;
    628    }
    629    testReadPixels(gl, gl[test.texInternalFormat], gl[test.texFormat], gl[test.texType],
    630                   implFormat, implType, test.clearColor);
    631 
    632    gl.deleteTexture(colorImage);
    633    gl.deleteFramebuffer(fbo);
    634  }
    635 }
    636 
    637 debug("")
    638 var successfullyParsed = true;
    639 </script>
    640 <script src="../../js/js-test-post.js"></script>
    641 </body>
    642 </html>