export const description = `
copyToTexture with HTMLVideoElement and VideoFrame.

- videos with various encodings/formats (webm vp8, webm vp9, ogg theora, mp4), video color spaces
  (bt.601, bt.709, bt.2020) and dst color spaces(display-p3, srgb).

  TODO: Test video in BT.2020 color space
`;

import { makeTestGroup } from '../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../gpu_test.js';
import * as ttu from '../../texture_test_utils.js';
import {
  startPlayingAndWaitForVideo,
  getVideoElement,
  getVideoFrameFromVideoElement,
  convertToUnorm8,
  kPredefinedColorSpace,
  kVideoNames,
  kVideoInfo,
  kVideoExpectedColors,
} from '../../web_platform/util.js';

const kFormat = 'rgba8unorm';

export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);

g.test('copy_from_video')
  .desc(
    `
Test HTMLVideoElement and VideoFrame can be copied to WebGPU texture correctly.

It creates HTMLVideoElement with videos under Resource folder.

  Then call copyExternalImageToTexture() to do a full copy to the 0 mipLevel
  of dst texture, and read the contents out to compare with the ImageBitmap contents.

  If 'flipY' in 'GPUCopyExternalImageSourceInfo' is set to 'true', copy will ensure the result
  is flipped.

  The tests covers:
  - Video comes from different color spaces.
  - Valid 'flipY' config in 'GPUCopyExternalImageSourceInfo' (named 'srcDoFlipYDuringCopy' in cases)
  - TODO: partial copy tests should be added
  - TODO: all valid dstColorFormat tests should be added.
`
  )
  .params(u =>
    u //
      .combine('videoName', kVideoNames)
      .combine('sourceType', ['VideoElement', 'VideoFrame'] as const)
      .combine('srcDoFlipYDuringCopy', [true, false])
      .combine('dstColorSpace', kPredefinedColorSpace)
  )
  .fn(async t => {
    const { videoName, sourceType, srcDoFlipYDuringCopy, dstColorSpace } = t.params;

    if (sourceType === 'VideoFrame' && typeof VideoFrame === 'undefined') {
      t.skip('WebCodec is not supported');
    }

    const videoElement = getVideoElement(t, videoName);

    await startPlayingAndWaitForVideo(videoElement, async () => {
      let source, width, height;
      if (sourceType === 'VideoFrame') {
        source = await getVideoFrameFromVideoElement(t, videoElement);
        width = source.displayWidth;
        height = source.displayHeight;
      } else {
        source = videoElement;
        width = source.videoWidth;
        height = source.videoHeight;
      }

      const dstTexture = t.createTextureTracked({
        format: kFormat,
        size: { width, height, depthOrArrayLayers: 1 },
        usage:
          GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
      });

      t.queue.copyExternalImageToTexture(
        {
          source,
          origin: { x: 0, y: 0 },
          flipY: srcDoFlipYDuringCopy,
        },
        {
          texture: dstTexture,
          origin: { x: 0, y: 0 },
          colorSpace: dstColorSpace,
          premultipliedAlpha: true,
        },
        { width, height, depthOrArrayLayers: 1 }
      );

      const srcColorSpace = kVideoInfo[videoName].colorSpace;
      const presentColors = kVideoExpectedColors[srcColorSpace][dstColorSpace];

      // visible rect is whole frame, no clipping.
      const expect = kVideoInfo[videoName].display;

      if (srcDoFlipYDuringCopy) {
        ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: dstTexture }, [
          // Flipped top-left.
          {
            coord: { x: width * 0.25, y: height * 0.25 },
            exp: convertToUnorm8(presentColors[expect.bottomLeftColor]),
          },
          // Flipped top-right.
          {
            coord: { x: width * 0.75, y: height * 0.25 },
            exp: convertToUnorm8(presentColors[expect.bottomRightColor]),
          },
          // Flipped bottom-left.
          {
            coord: { x: width * 0.25, y: height * 0.75 },
            exp: convertToUnorm8(presentColors[expect.topLeftColor]),
          },
          // Flipped bottom-right.
          {
            coord: { x: width * 0.75, y: height * 0.75 },
            exp: convertToUnorm8(presentColors[expect.topRightColor]),
          },
        ]);
      } else {
        ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: dstTexture }, [
          // Top-left.
          {
            coord: { x: width * 0.25, y: height * 0.25 },
            exp: convertToUnorm8(presentColors[expect.topLeftColor]),
          },
          // Top-right.
          {
            coord: { x: width * 0.75, y: height * 0.25 },
            exp: convertToUnorm8(presentColors[expect.topRightColor]),
          },
          // Bottom-left.
          {
            coord: { x: width * 0.25, y: height * 0.75 },
            exp: convertToUnorm8(presentColors[expect.bottomLeftColor]),
          },
          // Bottom-right.
          {
            coord: { x: width * 0.75, y: height * 0.75 },
            exp: convertToUnorm8(presentColors[expect.bottomRightColor]),
          },
        ]);
      }

      if (source instanceof VideoFrame) {
        source.close();
      }
    });
  });
