summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_colorspace.html.ts
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_colorspace.html.ts')
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_colorspace.html.ts139
1 files changed, 139 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_colorspace.html.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_colorspace.html.ts
new file mode 100644
index 0000000000..3a763e8c28
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_colorspace.html.ts
@@ -0,0 +1,139 @@
+import { kUnitCaseParamsBuilder } from '../../../common/framework/params_builder.js';
+import { Float16Array } from '../../../external/petamoriken/float16/float16.js';
+import { kCanvasAlphaModes, kCanvasColorSpaces } from '../../capability_info.js';
+
+import { runRefTest } from './gpu_ref_test.js';
+
+function bgra8UnormFromRgba8Unorm(rgba8Unorm: Uint8Array) {
+ // This is used only once. May need to optimize if reused.
+ const bgra8Unorm = rgba8Unorm.slice();
+ for (let i = 0; i < bgra8Unorm.length; i += 4) {
+ [bgra8Unorm[i], bgra8Unorm[i + 2]] = [bgra8Unorm[i + 2], bgra8Unorm[i]];
+ }
+ return bgra8Unorm;
+}
+
+function rgba16floatFromRgba8unorm(rgba8Unorm: Uint8Array) {
+ // This is used only once. May need to optimize if reused.
+ const rgba16Float = new Float16Array(rgba8Unorm.length);
+ for (let i = 0; i < rgba8Unorm.length; ++i) {
+ rgba16Float[i] = rgba8Unorm[i] / 255;
+ }
+ return rgba16Float;
+}
+
+type Transferable = {
+ canvas: HTMLCanvasElement | OffscreenCanvas;
+ textureData: ArrayBuffer;
+ format: GPUTextureFormat;
+ colorSpace: PredefinedColorSpace;
+ alphaMode: GPUCanvasAlphaMode;
+};
+
+function render(
+ device: GPUDevice,
+ { canvas, format, alphaMode, colorSpace, textureData }: Transferable
+) {
+ const context = canvas.getContext('webgpu') as GPUCanvasContext;
+ context.configure({
+ device,
+ format,
+ usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
+ alphaMode,
+ colorSpace,
+ });
+
+ const texture = context.getCurrentTexture();
+ device.queue.writeTexture({ texture }, textureData, {}, { width: 4, height: 1 });
+}
+
+export function runColorSpaceTest(format: GPUTextureFormat) {
+ runRefTest(async t => {
+ // prettier-ignore
+ const kRGBA8UnormData = new Uint8Array([
+ 0, 255, 0, 255,
+ 117, 251, 7, 255,
+ 170, 35, 209, 255,
+ 80, 150, 200, 255,
+ ]);
+ const kBGRA8UnormData = bgra8UnormFromRgba8Unorm(kRGBA8UnormData);
+ const kRGBA16FloatData = rgba16floatFromRgba8unorm(kRGBA8UnormData);
+ const width = kRGBA8UnormData.length / 4;
+
+ const testData: { [id: string]: Uint8Array | Float16Array } = {
+ rgba8unorm: kRGBA8UnormData,
+ bgra8unorm: kBGRA8UnormData,
+ rgba16float: kRGBA16FloatData,
+ };
+ const textureData = testData[format].buffer;
+
+ async function createCanvas(
+ creation: string,
+ alphaMode: GPUCanvasAlphaMode,
+ format: GPUTextureFormat,
+ colorSpace: PredefinedColorSpace
+ ) {
+ const canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = 1;
+ document.body.appendChild(canvas);
+
+ switch (creation) {
+ case 'canvas':
+ render(t.device, { canvas, format, alphaMode, colorSpace, textureData });
+ break;
+
+ case 'transferControlToOffscreen': {
+ const offscreenCanvas = canvas.transferControlToOffscreen();
+ render(t.device, { canvas: offscreenCanvas, format, alphaMode, colorSpace, textureData });
+ break;
+ }
+
+ case 'transferControlToOffscreenWorker': {
+ const offscreenCanvas = canvas.transferControlToOffscreen();
+ const source = `
+ ${render.toString()}
+
+ onmessage = async (event) => {
+ try {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+ render(device, event.data);
+ postMessage(true);
+ } catch (e) {
+ postMessage(false);
+ }
+ };
+ `;
+ const blob = new Blob([source], { type: 'application/javascript' });
+ const url = URL.createObjectURL(blob);
+ const worker = new Worker(url);
+ let resolve: (success: boolean) => void;
+ const promise = new Promise(_resolve => (resolve = _resolve));
+ worker.onmessage = event => {
+ resolve(event.data);
+ };
+ worker.postMessage(
+ { canvas: offscreenCanvas, format, alphaMode, colorSpace, textureData },
+ [offscreenCanvas]
+ );
+ await promise;
+ break;
+ }
+ }
+ }
+
+ const u = kUnitCaseParamsBuilder
+ .combine('alphaMode', kCanvasAlphaModes)
+ .combine('colorSpace', kCanvasColorSpaces)
+ .combine('creation', [
+ 'canvas',
+ 'transferControlToOffscreen',
+ 'transferControlToOffscreenWorker',
+ ]);
+
+ for (const { alphaMode, colorSpace, creation } of u) {
+ await createCanvas(creation, alphaMode, format, colorSpace);
+ }
+ });
+}