143 lines
4.4 KiB
JavaScript
143 lines
4.4 KiB
JavaScript
class Uniform {
|
|
constructor(float32Array) {
|
|
if (float32Array && float32Array.length != 64) {
|
|
console.log("Incorrect backing store for Uniform");
|
|
return;
|
|
}
|
|
|
|
this.array = float32Array || new Float32Array(64);
|
|
}
|
|
// Layout is
|
|
// 0-1 = resolution (float2)
|
|
// 2 = time (float)
|
|
get buffer() {
|
|
return this.array;
|
|
}
|
|
get resolution() {
|
|
return this.array.subarray(0, 2);
|
|
}
|
|
get time() {
|
|
return this.array[2];
|
|
}
|
|
set resolution(value) {
|
|
this.array[0] = value[0];
|
|
this.array[1] = value[1];
|
|
}
|
|
set time(value) {
|
|
this.array[2] = value;
|
|
}
|
|
copyValuesTo(buffer) {
|
|
var bufferData = new Float32Array(buffer.contents);
|
|
for (let i = 0; i < 3; i++) {
|
|
bufferData[i] = this.array[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
const vertexData = new Float32Array(
|
|
[
|
|
-1, -1, 0, 1,
|
|
1, -1, 0, 1,
|
|
1, 1, 0, 1,
|
|
-1, -1, 0, 1,
|
|
-1, 1, 0, 1,
|
|
1, 1, 0, 1,
|
|
]);
|
|
|
|
let gpu;
|
|
let commandQueue;
|
|
let renderPassDescriptor;
|
|
let renderPipelineState;
|
|
|
|
const NumActiveUniformBuffers = 3;
|
|
let uniforms = new Array(NumActiveUniformBuffers);
|
|
let uniformBuffers = new Array(NumActiveUniformBuffers);
|
|
let currentUniformBufferIndex = 0;
|
|
|
|
window.addEventListener("load", init, false);
|
|
|
|
function init() {
|
|
|
|
if (!checkForWebMetal()) {
|
|
return;
|
|
}
|
|
|
|
let canvas = document.querySelector("canvas");
|
|
let canvasSize = canvas.getBoundingClientRect();
|
|
canvas.width = canvasSize.width;
|
|
canvas.height = canvasSize.height;
|
|
|
|
gpu = canvas.getContext("webmetal");
|
|
commandQueue = gpu.createCommandQueue();
|
|
|
|
let library = gpu.createLibrary(document.getElementById("library").text);
|
|
let vertexFunction = library.functionWithName("vertex_main");
|
|
let fragmentFunction = library.functionWithName("fragment_main");
|
|
|
|
if (!library || !fragmentFunction || !vertexFunction) {
|
|
return;
|
|
}
|
|
|
|
let pipelineDescriptor = new WebMetalRenderPipelineDescriptor();
|
|
pipelineDescriptor.vertexFunction = vertexFunction;
|
|
pipelineDescriptor.fragmentFunction = fragmentFunction;
|
|
// NOTE: Our API proposal has these values as enums, not constant numbers.
|
|
// We haven't got around to implementing the enums yet.
|
|
pipelineDescriptor.colorAttachments[0].pixelFormat = gpu.PixelFormatBGRA8Unorm;
|
|
|
|
renderPipelineState = gpu.createRenderPipelineState(pipelineDescriptor);
|
|
|
|
for (let i = 0; i < NumActiveUniformBuffers; i++) {
|
|
let uniform = new Uniform();
|
|
uniform.resolution = new Float32Array([canvasSize.width, canvasSize.height]);
|
|
uniforms[i] = uniform;
|
|
uniformBuffers[i] = gpu.createBuffer(uniform.buffer);
|
|
}
|
|
|
|
renderPassDescriptor = new WebMetalRenderPassDescriptor();
|
|
// NOTE: Our API proposal has some of these values as enums, not constant numbers.
|
|
// We haven't got around to implementing the enums yet.
|
|
renderPassDescriptor.colorAttachments[0].loadAction = gpu.LoadActionClear;
|
|
renderPassDescriptor.colorAttachments[0].storeAction = gpu.StoreActionStore;
|
|
renderPassDescriptor.colorAttachments[0].clearColor = [0.35, 0.65, 0.85, 1.0];
|
|
|
|
vertexBuffer = gpu.createBuffer(vertexData);
|
|
render();
|
|
}
|
|
|
|
function render() {
|
|
|
|
updateUniformData(currentUniformBufferIndex);
|
|
|
|
let commandBuffer = commandQueue.createCommandBuffer();
|
|
|
|
let drawable = gpu.nextDrawable();
|
|
|
|
renderPassDescriptor.colorAttachments[0].texture = drawable.texture;
|
|
|
|
let commandEncoder = commandBuffer.createRenderCommandEncoderWithDescriptor(renderPassDescriptor);
|
|
commandEncoder.setRenderPipelineState(renderPipelineState);
|
|
commandEncoder.setVertexBuffer(vertexBuffer, 0, 0);
|
|
commandEncoder.setVertexBuffer(uniformBuffers[currentUniformBufferIndex], 0, 1);
|
|
commandEncoder.setFragmentBuffer(uniformBuffers[currentUniformBufferIndex], 0, 0);
|
|
|
|
// NOTE: Our API proposal uses the enum value "triangle" here. We haven't got around to implementing the enums yet.
|
|
commandEncoder.drawPrimitives(gpu.PrimitiveTypeTriangle, 0, 6);
|
|
|
|
commandEncoder.endEncoding();
|
|
commandBuffer.presentDrawable(drawable);
|
|
commandBuffer.commit();
|
|
|
|
currentUniformBufferIndex = (currentUniformBufferIndex + 1) % NumActiveUniformBuffers;
|
|
requestAnimationFrame(render);
|
|
}
|
|
|
|
function updateUniformData(index) {
|
|
var now = Date.now() % 100000 / 500;
|
|
let uniform = uniforms[index];
|
|
uniform.time = now;
|
|
|
|
uniform.copyValuesTo(uniformBuffers[index]);
|
|
|
|
}
|