| <!DOCTYPE html> |
| <meta charset="utf-8"> |
| <title>WebGPU Hello Triangles</title> |
| <meta name="assert" content="WebGPU correctly renders a green canvas."> |
| <link rel="match" href="viewport-scissor-rect-triangle-strip-expected.html"> |
| <p>Pass if square canvas below is a 4 by 4 blue/green checkerboard.</p> |
| <canvas width="400" height="400"></canvas> |
| <script src="js/webgpu-functions.js"></script> |
| <script> |
| if (window.testRunner) |
| testRunner.waitUntilDone(); |
| |
| const shaderCode = ` |
| #include <metal_stdlib> |
| |
| using namespace metal; |
| |
| struct Vertex |
| { |
| float4 position [[position]]; |
| }; |
| |
| vertex Vertex vertex_main(uint vid [[vertex_id]]) |
| { |
| Vertex v; |
| switch (vid) { |
| case 0: |
| v.position = float4(-1, 1, 0, 1); |
| break; |
| case 1: |
| v.position = float4(-1, -1, 0, 1); |
| break; |
| case 2: |
| v.position = float4(1, 1, 0, 1); |
| break; |
| default: |
| v.position = float4(1, -1, 0, 1); |
| } |
| return v; |
| } |
| |
| fragment float4 fragment_main(Vertex vertexIn [[stage_in]]) |
| { |
| return float4(0.0, 1.0, 0.0, 1.0); |
| } |
| `; |
| |
| async function test() { |
| const device = await getBasicDevice(); |
| const canvas = document.querySelector("canvas"); |
| const swapChain = createBasicSwapChain(canvas, device); |
| // FIXME: Replace with non-MSL shaders. |
| const shaderModule = device.createShaderModule({ code: shaderCode }); |
| const pipeline = createBasicPipeline(shaderModule, device); |
| const commandEncoder = device.createCommandEncoder(); |
| const blueAttachment = { |
| attachment: swapChain.getCurrentTexture().createDefaultView(), |
| loadOp: "clear", |
| storeOp: "store", |
| clearColor: { r: 0, g: 0, b: 1, a: 1 } |
| }; |
| const passEncoder = commandEncoder.beginRenderPass({ colorAttachments: [blueAttachment] }); |
| passEncoder.setPipeline(pipeline); |
| |
| function drawViewport(x, y) { |
| passEncoder.setViewport(x, y, 100, 100, 0, 1); |
| passEncoder.draw(4, 1, 0, 0); |
| } |
| |
| function drawScissorRect(x, y) { |
| passEncoder.setScissorRect(x, y, 100, 100); |
| passEncoder.draw(4, 1, 0, 0); |
| } |
| |
| passEncoder.setScissorRect(0, 0, 200, 400); |
| drawViewport(100, 0); |
| drawViewport(0, 100); |
| drawViewport(100, 200); |
| drawViewport(0, 300); |
| |
| // Draw outside of scissor rect should not appear. |
| drawViewport(200, 100); |
| |
| passEncoder.setViewport(200, 0, 200, 400, 0, 1); |
| drawScissorRect(300, 0); |
| drawScissorRect(200, 100); |
| drawScissorRect(300, 200); |
| drawScissorRect(200, 300); |
| |
| // Draw outside of viewport should not appear. |
| drawScissorRect(0, 0); |
| |
| passEncoder.endPass(); |
| const queue = device.getQueue(); |
| |
| queue.submit([commandEncoder.finish()]); |
| |
| requestAnimationFrame(() => { |
| if (window.testRunner) |
| testRunner.notifyDone(); |
| }); |
| } |
| |
| test(); |
| </script> |