Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: verify
- Manifest: dom/webgpu/mochitest/mochitest.toml
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script type="text/javascript">
"use strict";
ok(
SpecialPowers.getBoolPref("dom.webgpu.enabled"),
"WebGPU pref should be enabled."
);
SimpleTest.waitForExplicitFinish();
function requestAnimationFramePromise() {
return new Promise(requestAnimationFrame);
}
function createSourceCanvasWebgl() {
const offscreenCanvas = new OffscreenCanvas(200, 200);
const gl = offscreenCanvas.getContext("webgl");
const COLOR_VALUE = 127.0 / 255.0;
const ALPHA_VALUE = 127.0 / 255.0;
gl.enable(gl.SCISSOR_TEST);
gl.scissor(0, 0, 100, 100);
gl.clearColor(COLOR_VALUE, 0.0, 0.0, ALPHA_VALUE);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.scissor(100, 0, 100, 100);
gl.clearColor(0.0, COLOR_VALUE, 0.0, ALPHA_VALUE);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.scissor(0, 100, 100, 100);
gl.clearColor(0.0, 0.0, COLOR_VALUE, ALPHA_VALUE);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.scissor(100, 100, 100, 100);
gl.clearColor(0.0, 0.0, 0.0, ALPHA_VALUE);
gl.clear(gl.COLOR_BUFFER_BIT);
return {
source: offscreenCanvas,
origin: { x: 0, y: 0 },
flipY: true,
};
}
function createSourceCanvas2d() {
const offscreenCanvas = new OffscreenCanvas(200, 200);
const context = offscreenCanvas.getContext("2d");
context.fillStyle = "rgba(255,0,0,0.498)";
context.fillRect(0, 0, 100, 100);
context.fillStyle = "rgba(0,255,0,0.498)";
context.fillRect(100, 0, 100, 100);
context.fillStyle = "rgba(0,0,255,0.498)";
context.fillRect(0, 100, 100, 100);
context.fillStyle = "rgba(0,0,0,0.498)";
context.fillRect(100, 100, 100, 100);
return {
source: offscreenCanvas,
origin: { x: 0, y: 0 },
flipY: false,
};
}
function createSourceImageBitmap() {
const sourceCanvas = createSourceCanvas2d();
return {
source: sourceCanvas.source.transferToImageBitmap(),
origin: { x: 0, y: 0 },
flipY: false,
};
}
async function mapDestTexture(
device,
source,
destFormat,
premultiply,
copySize
) {
const bytesPerRow = 256 * 4; // 256 aligned for 200 pixels
const texture = device.createTexture({
format: destFormat,
size: copySize,
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
});
device.queue.copyExternalImageToTexture(
source,
{ texture, premultipliedAlpha: premultiply },
copySize
);
const buffer = device.createBuffer({
size: 1024 * 200,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});
const encoder = device.createCommandEncoder();
encoder.copyTextureToBuffer(
{ texture },
{ buffer, bytesPerRow },
copySize
);
device.queue.submit([encoder.finish()]);
await buffer.mapAsync(GPUMapMode.READ);
return buffer;
}
async function verifyBuffer(
test,
device,
source,
format,
premultiply,
copyDim,
topLeftPixelData
) {
try {
const buffer = await mapDestTexture(
device,
source,
format,
premultiply,
copyDim
);
const arrayBuffer = buffer.getMappedRange();
const view = new Uint8Array(arrayBuffer);
for (let i = 0; i < topLeftPixelData.length; ++i) {
is(
view[i],
topLeftPixelData[i],
test +
" " +
format +
" (" +
source.origin.x +
"," +
source.origin.y +
") channel " +
i
);
}
} catch (e) {
ok(false, "WebGPU exception: " + e);
}
}
async function verifySourceCanvas(test, device, source) {
await verifyBuffer(
test,
device,
source,
"rgba8unorm",
/* premultiply */ true,
{ width: 200, height: 200 },
[127, 0, 0, 127]
);
await verifyBuffer(
test,
device,
source,
"bgra8unorm",
/* premultiply */ true,
{ width: 200, height: 200 },
[0, 0, 127, 127]
);
await verifyBuffer(
test,
device,
source,
"rgba8unorm",
/* premultiply */ false,
{ width: 200, height: 200 },
[255, 0, 0, 127]
);
await verifyBuffer(
test,
device,
source,
"bgra8unorm",
/* premultiply */ false,
{ width: 200, height: 200 },
[0, 0, 255, 127]
);
// The copy is flipped but the origin is relative to the original source data,
// so we need to invert for WebGL.
const topRightPixelData =
test === "webgl" ? [0, 0, 0, 127] : [0, 127, 0, 127];
const topRightOrigin = { origin: { x: 100, y: 0 } };
await verifyBuffer(
test,
device,
{ ...source, ...topRightOrigin },
"bgra8unorm",
/* premultiply */ true,
{ width: 100, height: 100 },
topRightPixelData
);
const bottomLeftPixelData =
test === "webgl" ? [0, 0, 127, 127] : [127, 0, 0, 127];
const bottomLeftOrigin = { origin: { x: 0, y: 100 } };
await verifyBuffer(
test,
device,
{ ...source, ...bottomLeftOrigin },
"bgra8unorm",
/* premultiply */ true,
{ width: 100, height: 100 },
bottomLeftPixelData
);
}
async function writeDestCanvas(source2d, sourceWebgl, sourceImageBitmap) {
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
await verifySourceCanvas("2d", device, source2d);
await verifySourceCanvas("imageBitmap", device, sourceImageBitmap);
await verifySourceCanvas("webgl", device, sourceWebgl);
}
async function runTest() {
try {
const source2d = createSourceCanvas2d();
const sourceWebgl = createSourceCanvasWebgl();
const sourceImageBitmap = createSourceImageBitmap();
await requestAnimationFramePromise();
await requestAnimationFramePromise();
await writeDestCanvas(source2d, sourceWebgl, sourceImageBitmap);
} catch (e) {
ok(false, "Uncaught exception: " + e);
} finally {
SimpleTest.finish();
}
}
runTest();
</script>
</body>
</html>