diff options
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/api/operation/render_pipeline/culling_tests.spec.ts')
-rw-r--r-- | dom/webgpu/tests/cts/checkout/src/webgpu/api/operation/render_pipeline/culling_tests.spec.ts | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/api/operation/render_pipeline/culling_tests.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/api/operation/render_pipeline/culling_tests.spec.ts new file mode 100644 index 0000000000..521cf7b208 --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/api/operation/render_pipeline/culling_tests.spec.ts @@ -0,0 +1,185 @@ +export const description = `Test culling and rasterization state. + +Test coverage: +Test all culling combinations of GPUFrontFace and GPUCullMode show the correct output. + +Use 2 triangles with different winding orders: + +- Test that the counter-clock wise triangle has correct output for: + - All FrontFaces (ccw, cw) + - All CullModes (none, front, back) + - All depth stencil attachment types (none, depth24plus, depth32float, depth24plus-stencil8) + - Some primitive topologies (triangle-list, TODO: triangle-strip) + +- Test that the clock wise triangle has correct output for: + - All FrontFaces (ccw, cw) + - All CullModes (none, front, back) + - All depth stencil attachment types (none, depth24plus, depth32float, depth24plus-stencil8) + - Some primitive topologies (triangle-list, TODO: triangle-strip) +`; + +import { makeTestGroup } from '../../../../common/framework/test_group.js'; +import { kTextureFormatInfo } from '../../../capability_info.js'; +import { GPUTest } from '../../../gpu_test.js'; + +function faceIsCulled(face: 'cw' | 'ccw', frontFace: GPUFrontFace, cullMode: GPUCullMode): boolean { + return cullMode !== 'none' && (frontFace === face) === (cullMode === 'front'); +} + +function faceColor(face: 'cw' | 'ccw', frontFace: GPUFrontFace, cullMode: GPUCullMode): Uint8Array { + // front facing color is green, non front facing is red, background is blue + const isCulled = faceIsCulled(face, frontFace, cullMode); + if (!isCulled && face === frontFace) { + return new Uint8Array([0x00, 0xff, 0x00, 0xff]); + } else if (isCulled) { + return new Uint8Array([0x00, 0x00, 0xff, 0xff]); + } else { + return new Uint8Array([0xff, 0x00, 0x00, 0xff]); + } +} + +export const g = makeTestGroup(GPUTest); + +g.test('culling') + .desc( + ` +TODO: test triangle-strip as well [1] +TODO: check the contents of the depth and stencil outputs [2] +` + ) + .params( + u => + u + .combine('frontFace', ['ccw', 'cw'] as const) + .combine('cullMode', ['none', 'front', 'back'] as const) + .beginSubcases() + .combine('depthStencilFormat', [ + null, + 'depth24plus', + 'depth32float', + 'depth24plus-stencil8', + ] as const) + .combine('primitiveTopology', ['triangle-list'] as const) // [1] + ) + .fn(t => { + const size = 4; + const format = 'rgba8unorm'; + + const texture = t.device.createTexture({ + size: { width: size, height: size, depthOrArrayLayers: 1 }, + format, + usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, + }); + + let depthTexture: GPUTexture | undefined = undefined; + let depthStencilAttachment: GPURenderPassDepthStencilAttachment | undefined = undefined; + if (t.params.depthStencilFormat) { + depthTexture = t.device.createTexture({ + size: { width: size, height: size, depthOrArrayLayers: 1 }, + format: t.params.depthStencilFormat, + usage: GPUTextureUsage.RENDER_ATTACHMENT, + }); + + depthStencilAttachment = { + view: depthTexture.createView(), + depthClearValue: 1.0, + depthLoadOp: 'clear', + depthStoreOp: 'store', + }; + + if (t.params.depthStencilFormat && kTextureFormatInfo[t.params.depthStencilFormat].stencil) { + depthStencilAttachment.stencilClearValue = 0; + depthStencilAttachment.stencilLoadOp = 'clear'; + depthStencilAttachment.stencilStoreOp = 'store'; + } + } + + const encoder = t.device.createCommandEncoder(); + const pass = encoder.beginRenderPass({ + colorAttachments: [ + { + view: texture.createView(), + clearValue: { r: 0.0, g: 0.0, b: 1.0, a: 1.0 }, + loadOp: 'clear', + storeOp: 'store', + }, + ], + depthStencilAttachment, + }); + + // Draw two triangles with different winding orders: + // 1. The top-left one is counterclockwise (CCW) + // 2. The bottom-right one is clockwise (CW) + pass.setPipeline( + t.device.createRenderPipeline({ + layout: 'auto', + vertex: { + module: t.device.createShaderModule({ + code: ` + @vertex fn main( + @builtin(vertex_index) VertexIndex : u32 + ) -> @builtin(position) vec4<f32> { + var pos : array<vec2<f32>, 6> = array<vec2<f32>, 6>( + vec2<f32>(-1.0, 1.0), + vec2<f32>(-1.0, 0.0), + vec2<f32>( 0.0, 1.0), + vec2<f32>( 0.0, -1.0), + vec2<f32>( 1.0, 0.0), + vec2<f32>( 1.0, -1.0)); + return vec4<f32>(pos[VertexIndex], 0.0, 1.0); + }`, + }), + entryPoint: 'main', + }, + fragment: { + module: t.device.createShaderModule({ + code: ` + @fragment fn main( + @builtin(front_facing) FrontFacing : bool + ) -> @location(0) vec4<f32> { + var color : vec4<f32>; + if (FrontFacing) { + color = vec4<f32>(0.0, 1.0, 0.0, 1.0); + } else { + color = vec4<f32>(1.0, 0.0, 0.0, 1.0); + } + return color; + }`, + }), + entryPoint: 'main', + targets: [{ format }], + }, + primitive: { + topology: t.params.primitiveTopology, + frontFace: t.params.frontFace, + cullMode: t.params.cullMode, + }, + depthStencil: depthTexture + ? { format: t.params.depthStencilFormat as GPUTextureFormat } + : undefined, + }) + ); + + pass.draw(6, 1, 0, 0); + pass.end(); + + t.device.queue.submit([encoder.finish()]); + + // front facing color is green, non front facing is red, background is blue + const kCCWTriangleTopLeftColor = faceColor('ccw', t.params.frontFace, t.params.cullMode); + t.expectSinglePixelIn2DTexture( + texture, + format, + { x: 0, y: 0 }, + { exp: kCCWTriangleTopLeftColor } + ); + + const kCWTriangleBottomRightColor = faceColor('cw', t.params.frontFace, t.params.cullMode); + t.expectSinglePixelIn2DTexture( + texture, + format, + { x: size - 1, y: size - 1 }, + { exp: kCWTriangleBottomRightColor } + ); + // [2]: check the contents of the depth and stencil outputs + }); |