@giraphics/grpkggfx
Version:
171 lines (168 loc) • 7.68 kB
JavaScript
import SceneGraph from './../base/scenegraph';
import { TYPE_SIZE } from './../renderer/constants';
const geometryShaders = {
vertex: `
[[block]] struct Uniforms {
modelViewProjectionMatrix : mat4x4<f32>;
};
[[binding(0), group(0)]] var<uniform> uniforms : Uniforms;
struct VSOut {
[[builtin(position)]] Position: vec4<f32>;
[[location(0)]] color: vec4<f32>;
};
[[stage(vertex)]]
fn main([[location(0)]] inPos: vec4<f32>,
[[location(1)]] inColor: vec4<f32>) -> VSOut {
var vsOut: VSOut;
vsOut.Position = uniforms.modelViewProjectionMatrix * inPos;
vsOut.color = inColor;
return vsOut;
}
`,
fragment: `
[[stage(fragment)]]
fn main([[location(0)]] inColor: vec4<f32>) -> [[location(0)]] vec4<f32> {
return inColor;
}
`,
};
export class MultiGeometry extends SceneGraph {
constructor(device, primitiveType, vertexUppperLimit) {
// presently type info is 10 elements fixed vertex 4, color 4, uv 2
super(primitiveType, /*typeInfo*/ [TYPE_SIZE.float32x4, TYPE_SIZE.float32x4, TYPE_SIZE.float32x2]);
this.vertexUppperLimit = 0xFFFFFFFF; // Possible upper limit: 26843545
this.indexUppperLimit = 0xFFFFFFFF; // Max of index,
this.vertexInitLimit = 150000; // Possible upper limit: 26843545
this.indexInitLimit = 0xFFFFF; // Max of index,
this.totalVertexCount = 0;
this.totalIndexCount = 0;
this.isDirty = false;
this.isMemoryQuotaExausted = false;
// Resources
this.deviceVertexBufferSize = 0;
this.deviceIndexBufferSize = 0;
this.VERTEX_BYTES_PER_ELEMENT = 4;
this.INDEX_BYTES_PER_ELEMENT = 4;
this.resizeFactor = 0.25;
this.scaleFactor = 2;
this.device = device;
if (vertexUppperLimit) {
this.vertexInitLimit = vertexUppperLimit;
}
this.allocateVertexBuffersIfNeeded(this.vertexInitLimit);
this.allocateIndexBuffersIfNeeded(this.indexInitLimit);
this.initialize();
}
allocateVertexBuffersIfNeeded(verterCount) {
let requiredVertexSize = verterCount * this.elementCount * this.VERTEX_BYTES_PER_ELEMENT;
if (this.deviceVertexBufferSize * this.resizeFactor <= requiredVertexSize) {
console.log("Available Size: " + this.deviceVertexBufferSize + "Required Size: " + requiredVertexSize);
if (this.deviceVertexBufferSize == 0) {
this.deviceVertexBufferSize = verterCount * this.elementCount * this.VERTEX_BYTES_PER_ELEMENT;
}
// Scale buffer size by scaleFactor
this.deviceVertexBufferSize *= this.scaleFactor;
if (this.deviceVertexBuffer)
this.deviceVertexBuffer.destroy();
this.deviceVertexBuffer = this.device.createBuffer({
size: this.deviceVertexBufferSize,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
this.hostVertexBuffer = null;
this.hostVertexBuffer = new Float32Array(this.deviceVertexBufferSize / this.VERTEX_BYTES_PER_ELEMENT);
console.log("Allocating... " + this.deviceVertexBufferSize);
}
}
allocateIndexBuffersIfNeeded(indexCount) {
let requiredIndexSize = ((indexCount + 3) & ~3) * this.INDEX_BYTES_PER_ELEMENT;
if (this.deviceIndexBufferSize * this.resizeFactor <= requiredIndexSize) {
console.log("Available index buffer size: " + this.deviceIndexBufferSize + "Required Size: " + requiredIndexSize);
if (this.deviceIndexBufferSize == 0) {
this.deviceIndexBufferSize = ((indexCount + 3) & ~3) * this.INDEX_BYTES_PER_ELEMENT; // Aligned to 4 bytes
}
// Scale buffer size by scaleFactor
this.deviceIndexBufferSize *= this.scaleFactor;
if (this.indexBuffer)
this.indexBuffer.destroy();
this.indexBuffer = this.device.createBuffer({
size: this.deviceIndexBufferSize,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
});
this.hostIndexBuffer = null;
this.hostIndexBuffer = new Uint32Array(this.deviceIndexBufferSize / this.INDEX_BYTES_PER_ELEMENT); // this an array of 2 bytes
}
}
updateBuffers() {
if (!this.isDirty)
return;
this.allocateVertexBuffersIfNeeded(this.totalVertexCount);
this.allocateIndexBuffersIfNeeded(this.totalIndexCount);
this.device.queue.writeBuffer(this.deviceVertexBuffer, 0, this.hostVertexBuffer, 0, this.totalVertexCount * this.hostVertexBuffer.BYTES_PER_ELEMENT * this.elementCount);
this.device.queue.writeBuffer(this.indexBuffer, 0, this.hostIndexBuffer, 0, this.totalIndexCount * this.hostIndexBuffer.BYTES_PER_ELEMENT);
}
drawGeometry(geometryVertexArray, indexArray) {
if (this.isMemoryQuotaExausted) {
this.isDirty = false;
console.log("Warning: Reached maxmium limit of drawing.");
return;
}
this.hostVertexBuffer.set(geometryVertexArray, this.totalVertexCount * this.elementCount);
this.hostIndexBuffer.set(indexArray.map(x => x + this.totalVertexCount), this.totalIndexCount);
this.totalVertexCount += geometryVertexArray.length / this.elementCount;
this.totalIndexCount += indexArray.length;
if (this.isPrimtiveTypeStrip) {
this.hostIndexBuffer[this.totalIndexCount] = 0xFFFFFFFF;
this.totalIndexCount++;
}
this.isDirty = true;
}
resetIndex() {
this.isMemoryQuotaExausted = (this.totalIndexCount >= this.indexUppperLimit) && (this.totalVertexCount >= this.vertexUppperLimit);
if (!this.isMemoryQuotaExausted) {
this.totalVertexCount = 0;
this.totalIndexCount = 0;
}
}
initialize() {
super.initialize();
// super.createDefaultPipeline(vertShaderCode, fragShaderCode);
super.createDefaultPipeline(geometryShaders.vertex, geometryShaders.fragment);
this.uniformBindGroup = this.device.createBindGroup({
layout: this.pipeline.getBindGroupLayout(0),
entries: [
{
binding: 0,
resource: {
buffer: this.uniformBuffer,
offset: 0,
size: this.matrixSize,
},
},
],
});
}
draw(passEncoder, camera) {
super.draw(passEncoder, camera);
passEncoder.setPipeline(this.pipeline);
this.device.queue.writeBuffer(this.uniformBuffer, 0, this.modelViewProjectionMatrix.buffer, this.modelViewProjectionMatrix.byteOffset, this.modelViewProjectionMatrix.byteLength);
passEncoder.setVertexBuffer(0, this.deviceVertexBuffer);
passEncoder.setBindGroup(0, this.uniformBindGroup);
passEncoder.setIndexBuffer(this.indexBuffer, 'uint32');
passEncoder.drawIndexed(this.totalIndexCount, 1);
//console.log(this.totalVertexCount);
//console.log(this.totalIndexCount);
if (this.isDirty) {
this.resetIndex();
}
}
}
export class StaticGeometry extends MultiGeometry {
constructor(device, primitiveType, vertexUppperLimit) {
super(device, primitiveType, vertexUppperLimit);
}
}
export class DynamicGeometry extends MultiGeometry {
constructor(device, primitiveType, vertexUppperLimit) {
super(device, primitiveType, vertexUppperLimit);
}
}