// META: global=window,dedicatedworker
// META: script=/webcodecs/utils.js
// META: script=/webcodecs/webgl-test-utils.js

function testGLCanvas(gl, width, height, expectedPixel, assertCompares) {
  var colorData =
      new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
  gl.readPixels(
      0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA,
      gl.UNSIGNED_BYTE, colorData);
  assertCompares(gl.getError(), gl.NO_ERROR);

  const kMaxPixelToCheck = 128 * 96;
  let step = width * height / kMaxPixelToCheck;
  step = Math.round(step);
  step = (step < 1) ? 1 : step;
  for (let i = 0; i < 4 * width * height; i += (4 * step)) {
    assertCompares(colorData[i], expectedPixel[0]);
    assertCompares(colorData[i + 1], expectedPixel[1]);
    assertCompares(colorData[i + 2], expectedPixel[2]);
    assertCompares(colorData[i + 3], expectedPixel[3]);
  }
}

function testTexImage2DFromVideoFrame(
    width, height, useTexSubImage2D, expectedPixel) {
  let vfInit =
      {format: 'RGBA', timestamp: 0, codedWidth: width, codedHeight: height};
  let argbData = new Uint32Array(vfInit.codedWidth * vfInit.codedHeight);
  argbData.fill(0xFF966432);  // 'rgb(50, 100, 150)';
  let frame = new VideoFrame(argbData, vfInit);

  let canvas;
  if (self.HTMLCanvasElement) {
    canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
  } else
    canvas = new OffscreenCanvas(width, height);
  let gl = canvas.getContext('webgl');

  let program = WebGLTestUtils.setupTexturedQuad(gl);
  gl.clearColor(0, 0, 0, 1);
  gl.clearDepth(1);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.colorMask(1, 1, 1, 0);  // Disable any writes to the alpha channel.
  let textureLoc = gl.getUniformLocation(program, 'tex');

  let texture = gl.createTexture();

  // Bind the texture to texture unit 0.
  gl.bindTexture(gl.TEXTURE_2D, texture);

  // Set up texture parameters.
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

  // Set up pixel store parameters.
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
  gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);

  // Upload the videoElement into the texture
  if (useTexSubImage2D) {
    // Initialize the texture to black first
    gl.texImage2D(
        gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE,
        null);
    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, frame);
  } else {
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, frame);
  }

  frame.close();

  assert_equals(gl.getError(), gl.NO_ERROR);

  // Point the uniform sampler to texture unit 0
  gl.uniform1i(textureLoc, 0);

  // Draw the triangles
  WebGLTestUtils.drawQuad(gl, [0, 0, 0, 255]);

  // Wait for drawing to complete.
  gl.finish();

  testGLCanvas(gl, width, height, expectedPixel, assert_equals);
}

function testTexImageWithClosedVideoFrame(useTexSubImage2D) {
  let width = 128;
  let height = 128;
  let vfInit =
      {format: 'RGBA', timestamp: 0, codedWidth: width, codedHeight: height};
  let argbData = new Uint32Array(vfInit.codedWidth * vfInit.codedHeight);
  argbData.fill(0xFF966432);  // 'rgb(50, 100, 150)';
  let frame = new VideoFrame(argbData, vfInit);

  let canvas;
  if (self.HTMLCanvasElement) {
    canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
  } else
    canvas = new OffscreenCanvas(width, height);
  let gl = canvas.getContext('webgl');

  frame.close();
  if (useTexSubImage2D) {
    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, frame);
  } else {
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, frame);
  }

  assert_equals(gl.getError(), gl.INVALID_OPERATION);
}

test(_ => {
  testTexImage2DFromVideoFrame(48, 36, false, kSRGBPixel);
}, 'texImage2D with 48x36 srgb VideoFrame.');

test(_ => {
  testTexImage2DFromVideoFrame(48, 36, true, kSRGBPixel);
}, 'texSubImage2D with 48x36 srgb VideoFrame.');

test(_ => {
  testTexImage2DFromVideoFrame(480, 360, false, kSRGBPixel);
}, 'texImage2D with 480x360 srgb VideoFrame.');

test(_ => {
  testTexImage2DFromVideoFrame(480, 360, true, kSRGBPixel);
}, 'texSubImage2D with 480x360 srgb VideoFrame.');

test(_ => {
  testTexImageWithClosedVideoFrame(false);
}, 'texImage2D with a closed VideoFrame.');

test(_ => {
  testTexImageWithClosedVideoFrame(true);
}, 'texSubImage2D with a closed VideoFrame.');
