diff options
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_composite_alpha.html.ts')
-rw-r--r-- | dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_composite_alpha.html.ts | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_composite_alpha.html.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_composite_alpha.html.ts new file mode 100644 index 0000000000..5819ca5d77 --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/reftests/canvas_composite_alpha.html.ts @@ -0,0 +1,177 @@ +import { assert, unreachable } from '../../../common/util/util.js'; + +import { runRefTest } from './gpu_ref_test.js'; + +type WriteCanvasMethod = 'draw' | 'copy'; + +export function run( + format: GPUTextureFormat, + alphaMode: GPUCanvasAlphaMode, + writeCanvasMethod: WriteCanvasMethod +) { + runRefTest(async t => { + const module = t.device.createShaderModule({ + code: ` +struct VertexOutput { +@builtin(position) Position : vec4<f32>, +@location(0) fragColor : vec4<f32>, +} + +@vertex +fn mainVS(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput { +var pos = array<vec2<f32>, 6>( + vec2<f32>( 0.75, 0.75), + vec2<f32>( 0.75, -0.75), + vec2<f32>(-0.75, -0.75), + vec2<f32>( 0.75, 0.75), + vec2<f32>(-0.75, -0.75), + vec2<f32>(-0.75, 0.75)); + +var offset = array<vec2<f32>, 4>( +vec2<f32>( -0.25, 0.25), +vec2<f32>( 0.25, 0.25), +vec2<f32>(-0.25, -0.25), +vec2<f32>( 0.25, -0.25)); + +// Alpha channel value is set to 0.5 regardless of the canvas alpha mode. +// For 'opaque' mode, it shouldn't affect the end result, as the alpha channel should always get cleared to 1.0. +var color = array<vec4<f32>, 4>( + vec4<f32>(0.4, 0.0, 0.0, 0.5), + vec4<f32>(0.0, 0.4, 0.0, 0.5), + vec4<f32>(0.0, 0.0, 0.4, 0.5), + vec4<f32>(0.4, 0.4, 0.0, 0.5)); // 0.4 -> 0x66 + +var output : VertexOutput; +output.Position = vec4<f32>(pos[VertexIndex % 6u] + offset[VertexIndex / 6u], 0.0, 1.0); +output.fragColor = color[VertexIndex / 6u]; +return output; +} + +@fragment +fn mainFS(@location(0) fragColor: vec4<f32>) -> @location(0) vec4<f32> { +return fragColor; +} + `, + }); + + document.querySelectorAll('canvas').forEach(canvas => { + const ctx = canvas.getContext('webgpu'); + assert(ctx instanceof GPUCanvasContext, 'Failed to get WebGPU context from canvas'); + + switch (format) { + case 'bgra8unorm': + case 'bgra8unorm-srgb': + case 'rgba8unorm': + case 'rgba8unorm-srgb': + case 'rgba16float': + break; + default: + unreachable(); + } + + let usage = 0; + switch (writeCanvasMethod) { + case 'draw': + usage = GPUTextureUsage.RENDER_ATTACHMENT; + break; + case 'copy': + usage = GPUTextureUsage.COPY_DST; + break; + } + ctx.configure({ + device: t.device, + format, + usage, + alphaMode, + }); + + // The blending behavior here is to mimic 2d context blending behavior + // of drawing rects in order + // https://drafts.fxtf.org/compositing/#porterduffcompositingoperators_srcover + const kBlendStateSourceOver = { + color: { + srcFactor: 'src-alpha', + dstFactor: 'one-minus-src-alpha', + operation: 'add', + }, + alpha: { + srcFactor: 'one', + dstFactor: 'one-minus-src-alpha', + operation: 'add', + }, + } as const; + + const pipeline = t.device.createRenderPipeline({ + layout: 'auto', + vertex: { + module, + entryPoint: 'mainVS', + }, + fragment: { + module, + entryPoint: 'mainFS', + targets: [ + { + format, + blend: { premultiplied: kBlendStateSourceOver, opaque: undefined }[alphaMode], + }, + ], + }, + primitive: { + topology: 'triangle-list', + }, + }); + + let renderTarget: GPUTexture; + switch (writeCanvasMethod) { + case 'draw': + renderTarget = ctx.getCurrentTexture(); + break; + case 'copy': + renderTarget = t.device.createTexture({ + size: [ctx.canvas.width, ctx.canvas.height], + format, + usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, + }); + break; + } + const renderPassDescriptor: GPURenderPassDescriptor = { + colorAttachments: [ + { + view: renderTarget.createView(), + clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }, + loadOp: 'clear', + storeOp: 'store', + }, + ], + }; + + const commandEncoder = t.device.createCommandEncoder(); + const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); + passEncoder.setPipeline(pipeline); + passEncoder.draw(6, 1, 0, 0); + passEncoder.draw(6, 1, 6, 0); + passEncoder.draw(6, 1, 12, 0); + passEncoder.draw(6, 1, 18, 0); + passEncoder.end(); + + switch (writeCanvasMethod) { + case 'draw': + break; + case 'copy': + commandEncoder.copyTextureToTexture( + { + texture: renderTarget, + }, + { + texture: ctx.getCurrentTexture(), + }, + [ctx.canvas.width, ctx.canvas.height] + ); + break; + } + + t.device.queue.submit([commandEncoder.finish()]); + }); + }); +} |