136 lines
3.6 KiB
JavaScript
136 lines
3.6 KiB
JavaScript
const canvas = document.querySelector("#canvas");
|
|
const context = canvas.getContext("webgpu");
|
|
const frameTime = document.querySelector("#frame_time");
|
|
|
|
const adapter = await navigator.gpu.requestAdapter();
|
|
const adapterInfo = await adapter.requestAdapterInfo();
|
|
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 module = device.createShaderModule({
|
|
code: await (await fetch("raytracing.wgsl")).text(),
|
|
});
|
|
|
|
const pipeline = device.createRenderPipeline({
|
|
layout: pipelineLayout,
|
|
vertex: {
|
|
module,
|
|
entry: "vs_main",
|
|
},
|
|
fragment: {
|
|
module,
|
|
entry: "fs_main",
|
|
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 = 0;
|
|
let time_history = [];
|
|
let elapsed_time = 0;
|
|
function frame() {
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
|
|
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();
|
|
let frame_time = end_time - time;
|
|
elapsed_time += frame_time / 1000;
|
|
time = end_time;
|
|
time_history.push(frame_time);
|
|
if(time_history.length > 10) time_history.shift();
|
|
let avg_frame_time = time_history.reduce((acc, v) => acc + v) / time_history.length;
|
|
frameTime.innerText = `FPS: ${(1 / (avg_frame_time / 1000)).toFixed(2)}
|
|
Frame time: ${avg_frame_time.toFixed(1)}ms
|
|
|
|
${adapterInfo.vendor} ${adapterInfo.device} (${adapterInfo.architecture})`;
|
|
|
|
requestAnimationFrame(frame);
|
|
}
|
|
|
|
requestAnimationFrame(frame);
|