chromium/third_party/blink/web_tests/fast/arraybuffer/webgl2_size_check.html

<!DOCTYPE html>
<html crossorigin>
<head>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script type="x-shader/x-vertex" id="vertex">
#version 100
uniform mat4 overflow;

void main() {
  gl_Position = overflow * vec4(0.11, 0.22, 0.33, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragment">
#version 100
void main() {
  gl_FragColor = vec4(0.11, 0.22, 0.33, 1.0);
}
</script>
</head>
<body>
  <canvas id="canvas1" width="64px" height="64px">
  </canvas>
  <script>
test(() => {
  const kWasmPage = 1 << 16;
  const kNumPages = 33000;
  const kMemSizeInBytes =  kNumPages * kWasmPage;
  const kMemSizeInWords = kMemSizeInBytes / 4;

  // Maximum allowed size of an ArrayBuffer as defined by PartitionAlloc.
  const kArrayBufferSizeLimitInBytes = 2145386496;
  let mem;
  try {
    mem = new WebAssembly.Memory({initial: kNumPages, maximum: kNumPages});
  } catch (e) {
    // We failed to allocate the WebAssembly memory. We can just return.
    assert_equals(e.constructor, RangeError);
    assert_equals(e.message,
      "WebAssembly.Memory(): could not allocate memory");
    return;
  }
  let canvas = document.getElementById("canvas1");
  let gl = canvas.getContext("webgl2");
  let vertexShader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vertexShader, document.querySelector("#vertex").innerHTML);
  gl.compileShader(vertexShader);

  let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fragmentShader, document.querySelector("#fragment").innerHTML);
  gl.compileShader(fragmentShader);

  let program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);

  overflow = gl.getUniformLocation(program, "overflow");
  gl.useProgram(program);

  let fData = new Float32Array(mem.buffer, 8);
  let iData = new Int32Array(mem.buffer, 8);
  let uData = new Uint32Array(mem.buffer, 8);
  let u8Data = new Uint8Array(mem.buffer, 8);

  const kTooBigBufferData = (kArrayBufferSizeLimitInBytes / 4) + 32;
  let tooBigView = new Uint32Array(mem.buffer, 8, kTooBigBufferData);

  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, tooBigView, gl.STATIC_READ);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.bufferData(gl.ARRAY_BUFFER, mem.buffer, gl.STATIC_READ);
  assert_not_equals(gl.getError(), gl.NO_ERROR);

  gl.bufferSubData(gl.ARRAY_BUFFER, 0, tooBigView);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.bufferSubData(gl.ARRAY_BUFFER, 0, mem.buffer);
  assert_not_equals(gl.getError(), gl.NO_ERROR);

  gl.bufferData(gl.ARRAY_BUFFER, iData, gl.STATIC_READ, 16, 1296);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.bufferData(gl.ARRAY_BUFFER, iData, gl.STATIC_READ, 16, kTooBigBufferData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.bufferSubData(gl.ARRAY_BUFFER, 0, iData, 16, 1296);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.bufferSubData(gl.ARRAY_BUFFER, 0, iData, 16, kTooBigBufferData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.getBufferSubData(gl.ARRAY_BUFFER, 0, iData, 16, 1296);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.getBufferSubData(gl.ARRAY_BUFFER, 0, iData, 16, kTooBigBufferData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  // TODO(crbug.com/1353652): Make the following `uniform*` operations pass.
  gl.uniform1fv(overflow, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniform2fv(overflow, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniform3fv(overflow, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniform4fv(overflow, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);

  gl.uniform1iv(overflow, iData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniform2iv(overflow, iData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniform3iv(overflow, iData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniform4iv(overflow, iData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);

  gl.uniform1uiv(overflow, uData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniform2uiv(overflow, uData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniform3uiv(overflow, uData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniform4uiv(overflow, uData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);

  gl.uniformMatrix2fv(overflow, false, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniformMatrix3fv(overflow, false, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniformMatrix4fv(overflow, false, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniformMatrix2x3fv(overflow, false, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniformMatrix3x2fv(overflow, false, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniformMatrix2x4fv(overflow, false, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniformMatrix4x2fv(overflow, false, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniformMatrix3x4fv(overflow, false, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.uniformMatrix4x3fv(overflow, false, fData, 16, 1296);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);

  const kTooBigInWords = kMemSizeInWords - 32;

  gl.uniform1fv(overflow, fData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform2fv(overflow, fData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform3fv(overflow, fData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform4fv(overflow, fData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.uniform1iv(overflow, iData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform2iv(overflow, iData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform3iv(overflow, iData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform4iv(overflow, iData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.uniformMatrix2fv(overflow, false, fData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix3fv(overflow, false, fData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix4fv(overflow, false, fData);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.uniform1fv(overflow, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform2fv(overflow, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform3fv(overflow, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform4fv(overflow, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.uniform1iv(overflow, iData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform2iv(overflow, iData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform3iv(overflow, iData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform4iv(overflow, iData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.uniform1uiv(overflow, uData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform2uiv(overflow, uData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform3uiv(overflow, uData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniform4uiv(overflow, uData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.uniformMatrix2fv(overflow, false, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix3fv(overflow, false, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix4fv(overflow, false, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix2x3fv(overflow, false, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix3x2fv(overflow, false, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix2x4fv(overflow, false, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix4x2fv(overflow, false, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix3x4fv(overflow, false, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.uniformMatrix4x3fv(overflow, false, fData, 16, kTooBigInWords);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.vertexAttrib1fv(0, fData);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.vertexAttrib2fv(0, fData);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.vertexAttrib3fv(0, fData);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.vertexAttrib4fv(0, fData);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.vertexAttribI4iv(0, iData);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.vertexAttribI4uiv(0, uData);
  assert_equals(gl.getError(), gl.NO_ERROR);

  const clear_offset = kMemSizeInWords - 100;
  gl.clearBufferfv(gl.COLOR, 0, fData);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.clearBufferfv(gl.COLOR, 0, fData, clear_offset);
  assert_equals(gl.getError(), gl.NO_ERROR);
  // TODO(crbug.com/1353652): Make the following `clearBuffer*` operations pass.
  gl.clearBufferiv(gl.COLOR, 0, iData);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.clearBufferiv(gl.COLOR, 0, iData, clear_offset);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.clearBufferuiv(gl.COLOR, 0, uData);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);
  gl.clearBufferuiv(gl.COLOR, 0, uData, clear_offset);
  assert_equals(gl.getError(), gl.INVALID_OPERATION);

  // The read data (8x12=96) should still fit in.
  const read_offset = kMemSizeInWords - 100;
  const too_big_width = 16895999;
  const too_big_height_in_words = 32;
  const too_big_height_in_bytes = 128;
  assert_greater_than(too_big_width * too_big_height_in_words,
                      kArrayBufferSizeLimitInBytes / 4);
  gl.readPixels(0, 0, 8, 12, gl.RGBA, gl.UNSIGNED_BYTE, u8Data);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.readPixels(0, 0, too_big_width, too_big_height_in_words, gl.RGBA, gl.UNSIGNED_BYTE, u8Data);
  assert_equals(gl.getError(), gl.INVALID_VALUE);
  gl.readPixels(0, 0, 8, 12, gl.RGBA, gl.UNSIGNED_BYTE, u8Data, 16);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.readPixels(0, 0, 8, 12, gl.RGBA, gl.UNSIGNED_BYTE, u8Data, read_offset);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.readPixels(0, 0, too_big_width, too_big_height_in_words, gl.RGBA, gl.UNSIGNED_BYTE, u8Data, 4);
  assert_equals(gl.getError(), gl.INVALID_VALUE);

  let texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);

  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 12, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data);
  assert_equals(gl.getError(), gl.NO_ERROR);
// TODO(crbug.com/1353652): Fix this test of texImage2D so that more data than
// kArrayBufferSizeLimitInBytes is required. This should result in
// INVALID_VALUE.
//   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, too_big_width,
//                 too_big_height_in_bytes, 0, gl.RGBA, gl.UNSIGNED_BYTE,
//                 u8Data);
//   assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 12, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data, 16);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 12, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data, read_offset);
  assert_equals(gl.getError(), gl.NO_ERROR);
// TODO(crbug.com/1353652): Fix this test to texImage2D so that more data than
// kArrayBufferSizeLimitInBytes is required. This should result in
// INVALID_VALUE.
//   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, too_big_width,
//                 too_big_height_in_bytes, 0, gl.RGBA, gl.UNSIGNED_BYTE,
//                 u8Data, 16);
//   assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 8, 12, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data);
  assert_equals(gl.getError(), gl.NO_ERROR);
// TODO(crbug.com/1353652): Fix this test of texSubImage2D so that more data than
// kArrayBufferSizeLimitInBytes is required. This should result in
// INVALID_VALUE.
//   gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, too_big_width,
//                    too_big_height_in_bytes, gl.RGBA, gl.UNSIGNED_BYTE,
//                 u8Data);
//   assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 8, 12, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data, 16);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 8, 12, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data, read_offset);
  assert_equals(gl.getError(), gl.NO_ERROR);
// TODO(crbug.com/1353652): Fix this test of texSubImage2D so that more data than
// kArrayBufferSizeLimitInBytes is required. This should result in
// INVALID_VALUE.
//   gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, too_big_width,
//                    too_big_height_in_bytes, gl.RGBA, gl.UNSIGNED_BYTE,
//                 u8Data, 16);
//   assert_equals(gl.getError(), gl.INVALID_VALUE);

  texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_3D, texture);

  gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, 8, 12, 6, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data);
  assert_equals(gl.getError(), gl.NO_ERROR);
// TODO(crbug.com/1353652): Fix this test of texImage3D so that more data than
// kArrayBufferSizeLimitInBytes is required. This should result in
// INVALID_VALUE.
//   gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, too_big_width,
//                 too_big_height_in_bytes, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
//                 u8Data);
//   assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, 8, 12, 6, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data, 16);
  assert_equals(gl.getError(), gl.NO_ERROR);
  gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, 8, 12, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data, read_offset);
  assert_equals(gl.getError(), gl.NO_ERROR);
// TODO(crbug.com/1353652): Fix this test of texImage3D so that more data than
// kArrayBufferSizeLimitInBytes is required. This should result in
// INVALID_VALUE.
//   gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, too_big_width,
//                 too_big_height_in_bytes, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
//                 u8Data, 16);
//   assert_equals(gl.getError(), gl.INVALID_VALUE);

  gl.texSubImage3D(gl.TEXTURE_3D, 0, 0, 0, 0, 8, 12, 6, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data, 16);
  // assert_equals(gl.getError(), gl.NO_ERROR);
// TODO(crbug.com/1353652): Fix this test of texSubImage3D so that more data than
// kArrayBufferSizeLimitInBytes is required. This should result in
// INVALID_VALUE.
//   gl.texSubImage3D(gl.TEXTURE_3D, 0, 0, 0, 0, too_big_width,
//                    too_big_height_in_bytes, 1, gl.RGBA, gl.UNSIGNED_BYTE,
//                 u8Data);
//   assert_equals(gl.getError(), gl.INVALID_VALUE);

// TODO(crbug.com/1353652): Fix the following tests of texSubImage3D so that
// they pass without error.  At the moment they pass the ArrayBuffer size check
// but fail in the webgl backend.
   gl.texSubImage3D(gl.TEXTURE_3D, 0, 0, 0, 0, 8, 12, 6, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data, 16);
//   assert_equals(gl.getError(), gl.NO_ERROR);
   gl.texSubImage3D(gl.TEXTURE_3D, 0, 0, 0, 0, 8, 12, 1, gl.RGBA, gl.UNSIGNED_BYTE,
                u8Data, read_offset);
//   assert_equals(gl.getError(), gl.NO_ERROR);

// TODO(crbug.com/1353652): Fix this test of texSubImage3D so that more data than
// kArrayBufferSizeLimitInBytes is required. This should result in
// INVALID_VALUE.
//   gl.texSubImage3D(gl.TEXTURE_3D, 0, 0, 0, 0, too_big_width,
//                    too_big_height_in_bytes, gl.RGBA, gl.UNSIGNED_BYTE,
//                 u8Data, 16);
//   assert_equals(gl.getError(), gl.INVALID_VALUE);

// TODO(crbug.com/1353652): Add tests for the following functions:
// * webgl's compressedTexImage2D
// * webgl2's compressedTexImage2D
// * webgl's compressedTexSubImage2D
// * webgl2's compressedTexSubImage2D
// * compressedTexImage3D
// * compressedTexSubImage3D
}, "Test that webgl accepts a small view of ArrayBuffer bigger than 2GB.");
  </script>
</body>
</html>