From c5f8d7b27bdf18e1a3f02706ad93d6ec005652d8 Mon Sep 17 00:00:00 2001 From: Kimmo Kinnunen <89392548+kkinnunen-apple@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:14:34 +0200 Subject: [PATCH] Test OffscreenCanvas.transferToImageBitmap compositing steps (#3612) (#3643) Test following spec clarifications: * the value of preserveDrawingBuffer will have no effect * the contents of any depth and/or stencil buffers will be cleared to initial values --- ...offscreencanvas-transfer-image-bitmap.html | 21 +-- ...offscreencanvas-transfer-image-bitmap.html | 21 +-- .../offscreencanvas-transfer-image-bitmap.js | 178 ++++++++++++++++++ 3 files changed, 180 insertions(+), 40 deletions(-) diff --git a/sdk/tests/conformance/offscreencanvas/offscreencanvas-transfer-image-bitmap.html b/sdk/tests/conformance/offscreencanvas/offscreencanvas-transfer-image-bitmap.html index 70b359216b..8a2ee6e287 100644 --- a/sdk/tests/conformance/offscreencanvas/offscreencanvas-transfer-image-bitmap.html +++ b/sdk/tests/conformance/offscreencanvas/offscreencanvas-transfer-image-bitmap.html @@ -17,18 +17,6 @@
- diff --git a/sdk/tests/conformance2/offscreencanvas/offscreencanvas-transfer-image-bitmap.html b/sdk/tests/conformance2/offscreencanvas/offscreencanvas-transfer-image-bitmap.html index cb9232b65a..0c6b16f748 100644 --- a/sdk/tests/conformance2/offscreencanvas/offscreencanvas-transfer-image-bitmap.html +++ b/sdk/tests/conformance2/offscreencanvas/offscreencanvas-transfer-image-bitmap.html @@ -17,18 +17,6 @@
- diff --git a/sdk/tests/js/tests/offscreencanvas-transfer-image-bitmap.js b/sdk/tests/js/tests/offscreencanvas-transfer-image-bitmap.js index b25a7dd026..ea01ae0777 100644 --- a/sdk/tests/js/tests/offscreencanvas-transfer-image-bitmap.js +++ b/sdk/tests/js/tests/offscreencanvas-transfer-image-bitmap.js @@ -1,3 +1,181 @@ +let wtu = WebGLTestUtils; +function draw(gl) { + let vs = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(vs, "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0.0, 1.0); }"); + gl.compileShader(vs); + let fs = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(fs, "precision mediump float; void main() { gl_FragColor = vec4(1., 1., 1., 1.); }"); + gl.compileShader(fs); + let p = gl.createProgram(); + gl.attachShader(p, vs); + gl.attachShader(p, fs); + gl.bindAttribLocation(p, 0, "a_pos"); + gl.linkProgram(p); + gl.useProgram(p); + gl.viewport(0, 0, 128, 128); + let verts = [ + 1.0, 1.0, + -1.0, 1.0, + -1.0, -1.0, + -1.0, -1.0, + 1.0, -1.0, + 1.0, 1.0 + ]; + let vbo = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vbo); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW); + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + gl.useProgram(null); +} + +function testContent({contextType, depth, stencil, antialias, preserveDrawingBuffer}) { + var canvas = new OffscreenCanvas(128, 128); + var gl = canvas.getContext(contextType, {depth, stencil, antialias, preserveDrawingBuffer}); + if (!gl) + return `Skipped, could not create ${contextType} context`; + + // Draw the yellow contents and modify the depth and stencil buffers. + gl.clearColor(1.0, 1.0, 0.0, 1.0); + gl.clearDepth(0.0); + gl.clearStencil(255); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + let bitmap = canvas.transferToImageBitmap(); + + // Test that color buffer was cleared. + var buf = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); + let colorClear = buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0; + gl.clearColor(0.0, 0.0, 0.0, 0.0); + gl.clear(gl.COLOR_BUFFER_BIT); + + // Test that depth buffer was cleared to 1.0. + let depthClear = true; + if (gl.getContextAttributes().depth) { + gl.enable(gl.DEPTH_TEST); + gl.depthFunc(gl.GREATER); + draw(gl); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); + depthClear = buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0; + gl.disable(gl.DEPTH_TEST); + gl.clear(gl.COLOR_BUFFER_BIT); + } + + // Test that stencil buffer was cleared to 0. + let stencilClear = true; + if (gl.getContextAttributes().stencil) { + gl.enable(gl.STENCIL_TEST); + gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); + gl.stencilFunc(gl.NOTEQUAL, 0, 0xffffffff); + draw(gl); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); + stencilClear = buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0; + } + // Test that the context does not flip preserveDrawingBuffer. + let preserveDrawingBufferPreserved = preserveDrawingBuffer == gl.getContextAttributes().preserveDrawingBuffer; + return { bitmap, colorClear, depthClear, stencilClear, preserveDrawingBufferPreserved }; +} + +function workerScript(subcase) { + return ` +${draw} +${testContent} +let result = testContent({contextType: "${subcase.contextType}", depth: ${subcase.depth}, stencil: ${subcase.stencil}, antialias: ${subcase.antialias}, preserveDrawingBuffer: ${subcase.preserveDrawingBuffer}}); +self.postMessage(result, [ result.bitmap ]); +`; +} + +function nestedWorkerScript(subcase) { + return ` +${draw} +${testContent} +${workerScript} +try { + let subcase = { contextType: "${subcase.contextType}", depth: ${subcase.depth}, stencil: ${subcase.stencil}, antialias: ${subcase.antialias}, preserveDrawingBuffer: ${subcase.preserveDrawingBuffer} }; + let worker = new Worker(URL.createObjectURL(new Blob([workerScript(subcase)]))); + worker.onmessage = function(msg) { + self.postMessage(msg.data, [msg.data.bitmap]); + }; +} catch (e) { + self.postMessage("Failed, got exception: " + e); +} +`; +} + +function testMain(subcase) { + return testContent(subcase); +} + +function testWorker(subcase) { + return new Promise((resolve) => { + let worker = new Worker(URL.createObjectURL(new Blob([workerScript(subcase)]))); + worker.onmessage = function(msg) { + resolve(msg.data); + }; + }); +} + +function testNestedWorker(subcase) { + return new Promise((resolve) => { + let worker = new Worker(URL.createObjectURL(new Blob([nestedWorkerScript(subcase)]))); + worker.onmessage = function(msg) { + resolve(msg.data); + }; + }); +} + +let tests = [ + testMain, + testWorker, + testNestedWorker, +]; + +let contextType = wtu.getDefault3DContextVersion() == 2 ? "webgl2" : "webgl"; +let subcases = []; +for (let test of tests) { + for (let preserveDrawingBuffer of [true, false]) { + for (let antialias of [true, false]) { + for (let depth of [true, false]) { + for (let stencil of [true, false]) + subcases.push({test, contextType, preserveDrawingBuffer, antialias, depth, stencil}); + } + } + } +} +// To debug one case: +// subcases = [{preserveDrawingBuffer: false, antialias: false, depth: true, stencil: false, contextType, test: testMain}]; + +let colorClear; +let depthClear; +let stencilClear; +let preserveDrawingBufferPreserved; + +async function runTest() { + for (let subcase of subcases) { + debug(`test ${subcase.test.name}, contextType: ${subcase.contextType}, depth: ${subcase.depth}, stencil: ${subcase.stencil}, antialias: ${subcase.antialias}, preserveDrawingBuffer:${subcase.preserveDrawingBuffer}`); + let result = await subcase.test(subcase); + if (typeof result === "string") { + if (result.startsWith("Skipped")) + debug(result); + else + testFailed(result); + continue; + } + testTransferToImageBitmap("webgl", result.bitmap); + colorClear = result.colorClear; + shouldBeTrue("colorClear"); + depthClear = result.depthClear; + shouldBeTrue("depthClear"); + stencilClear = result.stencilClear; + shouldBeTrue("stencilClear"); + preserveDrawingBufferPreserved = result.preserveDrawingBufferPreserved; + shouldBeTrue("preserveDrawingBufferPreserved"); + } + finishTest(); +} + function testTransferToImageBitmap(webglContextVersion, bitmap) { var internalFormat = "RGBA"; var pixelFormat = "RGBA";