summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/webgpu/util/copy_to_texture.ts
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/util/copy_to_texture.ts')
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/util/copy_to_texture.ts194
1 files changed, 194 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/util/copy_to_texture.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/util/copy_to_texture.ts
new file mode 100644
index 0000000000..2f751ff6a2
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/util/copy_to_texture.ts
@@ -0,0 +1,194 @@
+import { assert, memcpy } from '../../common/util/util.js';
+import { RegularTextureFormat } from '../capability_info.js';
+import { GPUTest } from '../gpu_test.js';
+import { reifyExtent3D, reifyOrigin3D } from '../util/unions.js';
+
+import { makeInPlaceColorConversion } from './color_space_conversion.js';
+import { TexelView } from './texture/texel_view.js';
+import { TexelCompareOptions, textureContentIsOKByT2B } from './texture/texture_ok.js';
+
+/**
+ * Predefined copy sub rect meta infos.
+ */
+export const kCopySubrectInfo = [
+ {
+ srcOrigin: { x: 2, y: 2 },
+ dstOrigin: { x: 0, y: 0, z: 0 },
+ srcSize: { width: 16, height: 16 },
+ dstSize: { width: 4, height: 4 },
+ copyExtent: { width: 4, height: 4, depthOrArrayLayers: 1 },
+ },
+ {
+ srcOrigin: { x: 10, y: 2 },
+ dstOrigin: { x: 0, y: 0, z: 0 },
+ srcSize: { width: 16, height: 16 },
+ dstSize: { width: 4, height: 4 },
+ copyExtent: { width: 4, height: 4, depthOrArrayLayers: 1 },
+ },
+ {
+ srcOrigin: { x: 2, y: 10 },
+ dstOrigin: { x: 0, y: 0, z: 0 },
+ srcSize: { width: 16, height: 16 },
+ dstSize: { width: 4, height: 4 },
+ copyExtent: { width: 4, height: 4, depthOrArrayLayers: 1 },
+ },
+ {
+ srcOrigin: { x: 10, y: 10 },
+ dstOrigin: { x: 0, y: 0, z: 0 },
+ srcSize: { width: 16, height: 16 },
+ dstSize: { width: 4, height: 4 },
+ copyExtent: { width: 4, height: 4, depthOrArrayLayers: 1 },
+ },
+ {
+ srcOrigin: { x: 2, y: 2 },
+ dstOrigin: { x: 2, y: 2, z: 0 },
+ srcSize: { width: 16, height: 16 },
+ dstSize: { width: 16, height: 16 },
+ copyExtent: { width: 4, height: 4, depthOrArrayLayers: 1 },
+ },
+ {
+ srcOrigin: { x: 10, y: 2 },
+ dstOrigin: { x: 2, y: 2, z: 0 },
+ srcSize: { width: 16, height: 16 },
+ dstSize: { width: 16, height: 16 },
+ copyExtent: { width: 4, height: 4, depthOrArrayLayers: 1 },
+ },
+] as const;
+
+export class CopyToTextureUtils extends GPUTest {
+ doFlipY(
+ sourcePixels: Uint8ClampedArray,
+ width: number,
+ height: number,
+ bytesPerPixel: number
+ ): Uint8ClampedArray {
+ const dstPixels = new Uint8ClampedArray(width * height * bytesPerPixel);
+ for (let i = 0; i < height; ++i) {
+ for (let j = 0; j < width; ++j) {
+ const srcPixelPos = i * width + j;
+ // WebGL readPixel returns pixels from bottom-left origin. Using CopyExternalImageToTexture
+ // to copy from WebGL Canvas keeps top-left origin. So the expectation from webgl.readPixel should
+ // be flipped.
+ const dstPixelPos = (height - i - 1) * width + j;
+
+ memcpy(
+ { src: sourcePixels, start: srcPixelPos * bytesPerPixel, length: bytesPerPixel },
+ { dst: dstPixels, start: dstPixelPos * bytesPerPixel }
+ );
+ }
+ }
+
+ return dstPixels;
+ }
+
+ getExpectedDstPixelsFromSrcPixels({
+ srcPixels,
+ srcOrigin,
+ srcSize,
+ dstOrigin,
+ dstSize,
+ subRectSize,
+ format,
+ flipSrcBeforeCopy,
+ srcDoFlipYDuringCopy,
+ conversion,
+ }: {
+ srcPixels: Uint8ClampedArray;
+ srcOrigin: GPUOrigin2D;
+ srcSize: GPUExtent3D;
+ dstOrigin: GPUOrigin3D;
+ dstSize: GPUExtent3D;
+ subRectSize: GPUExtent3D;
+ format: RegularTextureFormat;
+ flipSrcBeforeCopy: boolean;
+ srcDoFlipYDuringCopy: boolean;
+ conversion: {
+ srcPremultiplied: boolean;
+ dstPremultiplied: boolean;
+ srcColorSpace?: PredefinedColorSpace;
+ dstColorSpace?: PredefinedColorSpace;
+ };
+ }): TexelView {
+ const applyConversion = makeInPlaceColorConversion(conversion);
+
+ const reifySrcOrigin = reifyOrigin3D(srcOrigin);
+ const reifySrcSize = reifyExtent3D(srcSize);
+ const reifyDstOrigin = reifyOrigin3D(dstOrigin);
+ const reifyDstSize = reifyExtent3D(dstSize);
+ const reifySubRectSize = reifyExtent3D(subRectSize);
+
+ assert(
+ reifyDstOrigin.x + reifySubRectSize.width <= reifyDstSize.width &&
+ reifyDstOrigin.y + reifySubRectSize.height <= reifyDstSize.height,
+ 'subrect is out of bounds'
+ );
+
+ const divide = 255.0;
+ return TexelView.fromTexelsAsColors(
+ format,
+ coords => {
+ assert(
+ coords.x >= reifyDstOrigin.x &&
+ coords.y >= reifyDstOrigin.y &&
+ coords.x < reifyDstOrigin.x + reifySubRectSize.width &&
+ coords.y < reifyDstOrigin.y + reifySubRectSize.height &&
+ coords.z === 0,
+ 'out of bounds'
+ );
+ // Map dst coords to get candidate src pixel position in y.
+ let yInSubRect = coords.y - reifyDstOrigin.y;
+
+ // If srcDoFlipYDuringCopy is true, a flipY op has been applied to src during copy.
+ // WebGPU spec requires origin option relative to the top-left corner of the source image,
+ // increasing downward consistently.
+ // https://www.w3.org/TR/webgpu/#dom-gpuimagecopyexternalimage-flipy
+ // Flip only happens in copy rect contents and src origin always top-left.
+ // Get candidate src pixel position in y by mirroring in copy sub rect.
+ if (srcDoFlipYDuringCopy) yInSubRect = reifySubRectSize.height - 1 - yInSubRect;
+
+ let src_y = yInSubRect + reifySrcOrigin.y;
+
+ // Test might generate flipped source based on srcPixels, e.g. Create ImageBitmap based on srcPixels but set orientation to 'flipY'
+ // Get candidate src pixel position in y by mirroring in source.
+ if (flipSrcBeforeCopy) src_y = reifySrcSize.height - src_y - 1;
+
+ const pixelPos =
+ src_y * reifySrcSize.width + (coords.x - reifyDstOrigin.x) + reifySrcOrigin.x;
+
+ const rgba = {
+ R: srcPixels[pixelPos * 4] / divide,
+ G: srcPixels[pixelPos * 4 + 1] / divide,
+ B: srcPixels[pixelPos * 4 + 2] / divide,
+ A: srcPixels[pixelPos * 4 + 3] / divide,
+ };
+ applyConversion(rgba);
+ return rgba;
+ },
+ { clampToFormatRange: true }
+ );
+ }
+
+ doTestAndCheckResult(
+ imageCopyExternalImage: GPUImageCopyExternalImage,
+ dstTextureCopyView: GPUImageCopyTextureTagged,
+ expTexelView: TexelView,
+ copySize: Required<GPUExtent3DDict>,
+ texelCompareOptions: TexelCompareOptions
+ ): void {
+ this.device.queue.copyExternalImageToTexture(
+ imageCopyExternalImage,
+ dstTextureCopyView,
+ copySize
+ );
+
+ const resultPromise = textureContentIsOKByT2B(
+ this,
+ { texture: dstTextureCopyView.texture, origin: dstTextureCopyView.origin },
+ copySize,
+ { expTexelView },
+ texelCompareOptions
+ );
+ this.eventualExpectOK(resultPromise);
+ this.trackForCleanup(dstTextureCopyView.texture);
+ }
+}