<!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="vertex-buffer-triangle-strip-expected.html">
<p>Pass if square canvas below is completely green.</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 VertexIn
{
    float4 position [[attribute(0)]];
};

struct VertexOut
{
    float4 position [[position]];
    float4 color;
};

vertex VertexOut vertex_main(VertexIn vertexIn [[stage_in]], uint iid [[instance_id]])
{
    VertexOut vOut;
    vOut.position = vertexIn.position;

    if (iid == 0) {
        vOut.position.z = 0.5;
        vOut.color = float4(1, 0, 0, 1);
    } else {
        vOut.color = float4(0, 1, 0, 1);
    }

    return vOut;
}

fragment float4 fragment_main(VertexOut v [[stage_in]])
{
    return v.color;
}
`

function createVertexBuffer(device) {
    const vertexArray = new Float32Array([
        // float4 xyzw
        -1, 1, 0, 1,
        -1, -1, 0, 1,
        1, 1, 0, 1,
        1, -1, 0, 1
    ]);
    return createBufferWithData(device, { size: vertexArray.byteLength, usage: GPUBufferUsage.VERTEX }, vertexArray.buffer);
}

function createVertexInputDescriptor() {
    return {
        indexFormat: "uint32",
        vertexBuffers: [{
            stride: 4 * 4,
            attributeSet: [{
                format: "float4",
                shaderLocation: 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 vertexBuffer = createVertexBuffer(device);
    const vertexInputDescriptor = createVertexInputDescriptor();
    const depthStateDescriptor = createBasicDepthStateDescriptor();
    const pipeline = createBasicPipeline(shaderModule, device, null, null, vertexInputDescriptor, depthStateDescriptor);
    const commandEncoder = device.createCommandEncoder();

    const basicAttachment = {
        attachment: swapChain.getCurrentTexture().createDefaultView(),
        loadOp: "clear",
        storeOp: "store",
        clearColor: { r: 1.0, g: 0, b: 0, a: 1.0 }
    };

    const depthAttachment = {
        attachment: createBasicDepthTexture(canvas, device).createDefaultView(),
        depthLoadOp: "clear",
        depthStoreOp: "store",
        clearDepth: 1.0
    };

    const encoder = commandEncoder.beginRenderPass({
        colorAttachments: [basicAttachment],
        depthStencilAttachment: depthAttachment
    });

    encoder.setVertexBuffers(0, [vertexBuffer], [0]);
    encoder.setPipeline(pipeline);
    encoder.draw(4, 2, 0, 0);
    encoder.endPass();

    device.getQueue().submit([commandEncoder.finish()]);
}

test().then(function() {
    if (window.testRunner)
        testRunner.notifyDone();
}, function() {
    if (window.testRunner)
        testRunner.notifyDone();
});
</script>
