const canvas = document.querySelector("#canvas");
const context = canvas.getContext("webgpu");
const frameTime = document.querySelector("#frame_time");

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();

const devicePixelRatio = window.devicePixelRatio;
canvas.width = canvas.clientWidth * devicePixelRatio;
canvas.height = canvas.clientHeight * devicePixelRatio;
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();

context.configure({
    device,
    format: presentationFormat,
    alphaMode: 'premultiplied',
});

const bindGroupLayout = device.createBindGroupLayout({
    entries: [
    {
        binding: 0,
        visibility: GPUShaderStage.FRAGMENT,
        buffer: {},
    },
    {
        binding: 1,
        visibility: GPUShaderStage.FRAGMENT,
        buffer: {},
    }]
});

const pipelineLayout = device.createPipelineLayout({
  bindGroupLayouts: [
    bindGroupLayout,
  ]
});

const pipeline = device.createRenderPipeline({
    layout: pipelineLayout,
    vertex: {
        module: device.createShaderModule({
            code: await (await fetch("triangle.vert.wgsl")).text(),
        }),
    },
    fragment: {
        module: device.createShaderModule({
            code: await (await fetch("red.frag.wgsl")).text(),
        }),
        targets: [
            {
                format: presentationFormat,
            },
        ],
    },
    primitive: {
        topology: 'triangle-list',
    },
});

const timeBuffer = device.createBuffer({
    size: 4,
    usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});

const aspectBuffer = device.createBuffer({
    size: 4,
    usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});

const bindGroup = device.createBindGroup({
    layout: bindGroupLayout,
    entries: [
        { binding: 0, resource: { buffer: timeBuffer }},
        { binding: 1, resource: { buffer: aspectBuffer }}
    ],
});

const timeArray = new Float32Array(1);
const aspectArray = new Float32Array(1);

let time = Date.now();
let time_history = [];
let elapsed_time = 0;
function frame() {
    timeArray.set([Math.sin(elapsed_time)]);
    device.queue.writeBuffer(timeBuffer, 0, timeArray);

    aspectArray.set([window.innerWidth / window.innerHeight]);
    device.queue.writeBuffer(aspectBuffer, 0, aspectArray);

    const commandEncoder = device.createCommandEncoder();
    const textureView = context.getCurrentTexture().createView();

    const renderPassDescriptor = {
        colorAttachments: [
            {
                view: textureView,
                clearValue: [0, 0, 0, 1],
                loadOp: 'clear',
                storeOp: 'store',
            },
        ],
    };

    const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
    passEncoder.setPipeline(pipeline);
    passEncoder.setBindGroup(0, bindGroup);
    passEncoder.draw(6);
    passEncoder.end();

    device.queue.submit([commandEncoder.finish()]);

    let end_time = Date.now() / 1000;
    let frame_time = end_time - time;
    elapsed_time += frame_time;
    time = end_time;
    time_history.push(frame_time);
    if(time_history.length > 10) time_history.shift();
    frameTime.innerText = 
        (1.0 / (time_history.reduce((acc, v) => acc + v) / time_history.length)).toFixed(2) + " FPS";
    //frameTime.innerText = 1.0 / (frame_time / 1000);

    requestAnimationFrame(frame);
}

requestAnimationFrame(frame);