173 lines
6.0 KiB
JavaScript
173 lines
6.0 KiB
JavaScript
const vertexData = new Float32Array(
|
|
[
|
|
// float4 position, float4 color
|
|
1, -1, 1, 1, 1, 0, 1, 1,
|
|
-1, -1, 1, 1, 0, 0, 1, 1,
|
|
-1, -1, -1, 1, 0, 0, 0, 1,
|
|
1, -1, -1, 1, 1, 0, 0, 1,
|
|
1, -1, 1, 1, 1, 0, 1, 1,
|
|
-1, -1, -1, 1, 0, 0, 0, 1,
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, -1, 1, 1, 1, 0, 1, 1,
|
|
1, -1, -1, 1, 1, 0, 0, 1,
|
|
1, 1, -1, 1, 1, 1, 0, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, -1, -1, 1, 1, 0, 0, 1,
|
|
|
|
-1, 1, 1, 1, 0, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, -1, 1, 1, 1, 0, 1,
|
|
-1, 1, -1, 1, 0, 1, 0, 1,
|
|
-1, 1, 1, 1, 0, 1, 1, 1,
|
|
1, 1, -1, 1, 1, 1, 0, 1,
|
|
|
|
-1, -1, 1, 1, 0, 0, 1, 1,
|
|
-1, 1, 1, 1, 0, 1, 1, 1,
|
|
-1, 1, -1, 1, 0, 1, 0, 1,
|
|
-1, -1, -1, 1, 0, 0, 0, 1,
|
|
-1, -1, 1, 1, 0, 0, 1, 1,
|
|
-1, 1, -1, 1, 0, 1, 0, 1,
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
-1, 1, 1, 1, 0, 1, 1, 1,
|
|
-1, -1, 1, 1, 0, 0, 1, 1,
|
|
-1, -1, 1, 1, 0, 0, 1, 1,
|
|
1, -1, 1, 1, 1, 0, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
|
|
1, -1, -1, 1, 1, 0, 0, 1,
|
|
-1, -1, -1, 1, 0, 0, 0, 1,
|
|
-1, 1, -1, 1, 0, 1, 0, 1,
|
|
1, 1, -1, 1, 1, 1, 0, 1,
|
|
1, -1, -1, 1, 1, 0, 0, 1,
|
|
-1, 1, -1, 1, 0, 1, 0, 1,
|
|
]);
|
|
|
|
const NumActiveUniformBuffers = 3;
|
|
|
|
let gpu;
|
|
let commandQueue;
|
|
let renderPassDescriptor;
|
|
let renderPipelineState;
|
|
let depthStencilState;
|
|
let projectionMatrix = mat4.create();
|
|
|
|
let uniformBuffers = new Array(NumActiveUniformBuffers);
|
|
var 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;
|
|
|
|
let aspect = Math.abs(canvasSize.width / canvasSize.height);
|
|
mat4.perspective(projectionMatrix, (2 * Math.PI) / 5, aspect, 1, 100.0);
|
|
|
|
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;
|
|
pipelineDescriptor.depthAttachmentPixelFormat = gpu.PixelFormatDepth32Float;
|
|
|
|
renderPipelineState = gpu.createRenderPipelineState(pipelineDescriptor);
|
|
|
|
let depthStencilDescriptor = new WebMetalDepthStencilDescriptor();
|
|
depthStencilDescriptor.depthWriteEnabled = true;
|
|
depthStencilDescriptor.depthCompareFunction = "less";
|
|
|
|
depthStencilState = gpu.createDepthStencilState(depthStencilDescriptor);
|
|
|
|
for (let i = 0; i < NumActiveUniformBuffers; i++) {
|
|
uniformBuffers[i] = gpu.createBuffer(new Float32Array(16));
|
|
}
|
|
|
|
let depthTextureDescriptor = new WebMetalTextureDescriptor(gpu.PixelFormatDepth32Float, canvasSize.width, canvasSize.height, false);
|
|
// NOTE: Our API proposal has some of these values as enums, not constant numbers.
|
|
// We haven't got around to implementing the enums yet.
|
|
depthTextureDescriptor.textureType = gpu.TextureType2D;
|
|
depthTextureDescriptor.sampleCount = 1;
|
|
depthTextureDescriptor.usage = gpu.TextureUsageUnknown;
|
|
depthTextureDescriptor.storageMode = gpu.StorageModePrivate;
|
|
|
|
let depthTexture = gpu.createTexture(depthTextureDescriptor);
|
|
|
|
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];
|
|
renderPassDescriptor.depthAttachment.loadAction = gpu.LoadActionClear;
|
|
renderPassDescriptor.depthAttachment.storeAction = gpu.StoreActionDontCare;
|
|
renderPassDescriptor.depthAttachment.clearDepth = 1.0;
|
|
renderPassDescriptor.depthAttachment.texture = depthTexture;
|
|
|
|
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.setDepthStencilState(depthStencilState);
|
|
commandEncoder.setRenderPipelineState(renderPipelineState);
|
|
commandEncoder.setVertexBuffer(vertexBuffer, 0, 0);
|
|
commandEncoder.setVertexBuffer(uniformBuffers[currentUniformBufferIndex], 0, 1);
|
|
|
|
// 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, 36);
|
|
|
|
commandEncoder.endEncoding();
|
|
commandBuffer.presentDrawable(drawable);
|
|
commandBuffer.commit();
|
|
|
|
currentUniformBufferIndex = (currentUniformBufferIndex + 1) % NumActiveUniformBuffers;
|
|
requestAnimationFrame(render);
|
|
}
|
|
|
|
function updateUniformData(index) {
|
|
|
|
let viewMatrix = mat4.create();
|
|
mat4.translate(viewMatrix, viewMatrix, vec3.fromValues(0, 0, -5));
|
|
let now = Date.now() / 1000;
|
|
mat4.rotate(viewMatrix, viewMatrix, 1, vec3.fromValues(Math.sin(now), Math.cos(now), 0));
|
|
|
|
let modelViewProjectionMatrix = mat4.create();
|
|
mat4.multiply(modelViewProjectionMatrix, projectionMatrix, viewMatrix);
|
|
|
|
let uniform = new Float32Array(uniformBuffers[index].contents);
|
|
for (let i = 0; i < 16; i++) {
|
|
uniform[i] = modelViewProjectionMatrix[i];
|
|
}
|
|
}
|