Skip to content

Commit

Permalink
refactors and break change createRenderer; tag 0.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
tiye committed Nov 19, 2024
1 parent b1b95ae commit acdc9fe
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 91 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@triadica/lagopus",
"version": "0.1.4",
"version": "0.2.0",
"type": "module",
"module": "./lib/index.mjs",
"scripts": {
Expand Down
34 changes: 15 additions & 19 deletions src/alias.mts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ export let object = (options: LagopusObjectOptions): LagopusRenderObject => {
if (pointer + v.length > buffer.length) {
throw new Error(`Buffer overflow: trying to write ${v.length} elements at position ${pointer} in buffer of length ${buffer.length}`);
}
for (let j = 0; j < v.length; j++) {
buffer[pointer] = v[j];
pointer += 1;
}
buffer.set(v, pointer);
pointer += v.length;
} else {
if (pointer >= buffer.length) {
throw new Error(`Buffer overflow: trying to write at position ${pointer} in buffer of length ${buffer.length}`);
Expand All @@ -46,21 +44,19 @@ export let object = (options: LagopusObjectOptions): LagopusRenderObject => {
indices = u32buffer(options.indices);
}

let getParams = options.getParams || options.addUniform;

return createRenderer(
options.shader,
options.topology,
options.attrsList,
data.length,
buffers,
options.hitRegion,
indices,
getParams,
options.textures,
options.label || "default",
options.computeOptions
);
return createRenderer({
shader: options.shader,
topology: options.topology,
attrsList: options.attrsList,
verticesLength: data.length,
vertices: buffers,
hitRegion: options.hitRegion,
indices: indices,
getParams: options.getParams,
textures: options.textures,
label: options.label || "lagopus-object",
computeOptions: options.computeOptions,
});
};

export type NestedData<T> = NestedData<T>[] | T;
Expand Down
5 changes: 2 additions & 3 deletions src/clear.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { atomClearColor, atomCommandEncoder, atomContext, atomDevice } from "./global.mjs";
import { atomClearColor, atomContext, atomDevice } from "./global.mjs";

/** renders on lya single point, which consists no triangle */
let triangleWgsl = `
Expand All @@ -23,10 +23,9 @@ fn main_frag() -> @location(0) vec4<f32> {
/** when no command is emitted in a render pass, we need to clear canvas since nothing is re-draw.
* used in hot swapping.
*/
export let clearCanvas = () => {
export let clearCanvas = (commandEncoder: GPUCommandEncoder) => {
let device = atomDevice.deref();
let context = atomContext.deref();
const commandEncoder = atomCommandEncoder.deref();
const presentationFormat = window.navigator.gpu.getPreferredCanvasFormat();

const pipeline = device.createRenderPipeline({
Expand Down
2 changes: 0 additions & 2 deletions src/global.mts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ export var atomMouseHoldingPaths = new Atom<number[][]>([]);

export let atomObjectsBuffer = new Atom<LagopusObjectBuffer[]>([]);

export let atomCommandEncoder = new Atom<GPUCommandEncoder>(null);

export function wLog<T extends any>(message: string, a: T): T {
console.warn(message, a);
return a;
Expand Down
43 changes: 22 additions & 21 deletions src/paint.mts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
atomBufferNeedClear,
atomClearColor,
atomCanvasTexture,
atomCommandEncoder,
atomBloomEnabled,
atomLagopusTree,
} from "./global.mjs";
Expand All @@ -24,8 +23,8 @@ let blendState: GPUBlendState = {
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha", operation: "add" },
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
};
export let makePainter = (info: LagopusObjectData): ((l: number) => void) => {
let { topology, shaderModule, vertexBuffersDescriptors, vertexBuffers, indices } = info;
export let makePainter = (info: LagopusObjectData): ((l: number, b: GPUCommandEncoder) => void) => {
let { topology, shaderModule, vertexBuffersDescriptors, vertexBuffers } = info;
let { computeOptions } = info;

let device = atomDevice.deref();
Expand Down Expand Up @@ -114,7 +113,8 @@ export let makePainter = (info: LagopusObjectData): ((l: number) => void) => {
// Create render pass descriptor
//

let texturesInfo = prepareTextures(device, info.textures, info.label);
/** not useful without bloom effect enabled */
let texturesInfo = info.textures ? prepareTextures(device, info.textures, info.label) : undefined;

let renderUniformBindGroupLayout = device.createBindGroupLayout({
label: info.label + "@render-uniform",
Expand All @@ -128,7 +128,11 @@ export let makePainter = (info: LagopusObjectData): ((l: number) => void) => {
label: info.label + "@render",
layout: device.createPipelineLayout({
label: info.label + "@render",
bindGroupLayouts: [renderUniformBindGroupLayout, texturesInfo.layout, computeOptions ? renderParticlesLayout : undefined].filter(Boolean),
bindGroupLayouts: [
renderUniformBindGroupLayout,
info.textures ? texturesInfo.layout : undefined,
computeOptions ? renderParticlesLayout : undefined,
].filter(Boolean),
}),
vertex: { module: shaderModule, entryPoint: "vertex_main", buffers: vertexBuffersDescriptors },
fragment: { module: shaderModule, entryPoint: "fragment_main", targets: [{ format: presentationFormat, blend: blendState }] },
Expand All @@ -139,7 +143,7 @@ export let makePainter = (info: LagopusObjectData): ((l: number) => void) => {

// Encode render pass

return (loopTimes) => {
return (loopTimes, commandEncoder) => {
// create uniforms
// based on code from https://alain.xyz/blog/raw-webgpu

Expand All @@ -163,8 +167,6 @@ export let makePainter = (info: LagopusObjectData): ((l: number) => void) => {
{ binding: 1, resource: { buffer: customParamsBuffer } },
];

const commandEncoder = atomCommandEncoder.deref();

// now compute
if (computeOptions) {
const computePassEncoder = commandEncoder.beginComputePass();
Expand Down Expand Up @@ -218,7 +220,7 @@ export let makePainter = (info: LagopusObjectData): ((l: number) => void) => {

renderEncoder.setPipeline(renderPipeline);
renderEncoder.setBindGroup(0, renderUniformBindGroup);
if (texturesInfo.bindGroup) {
if (info.textures) {
// occupies 1 for texture
renderEncoder.setBindGroup(1, texturesInfo.bindGroup);
}
Expand All @@ -234,23 +236,23 @@ export let makePainter = (info: LagopusObjectData): ((l: number) => void) => {
renderEncoder.setVertexBuffer(idx, vertexBuffer);
});

if (indices) {
if (info.indices) {
// just use uint32, skip uint16
renderEncoder.setIndexBuffer(indices, "uint32");
renderEncoder.drawIndexed(indices.size / 4);
renderEncoder.setIndexBuffer(info.indices, "uint32");
renderEncoder.drawIndexed(info.indicesCount);
} else {
renderEncoder.draw(info.length);
renderEncoder.draw(info.verticesLength);
}
renderEncoder.end();
};
};

export let triggerRendering = (t: number, el: LagopusRenderObject) => {
export let callTreeRenderers = (t: number, c: GPUCommandEncoder, el: LagopusRenderObject) => {
if (el == null) return;
if (el.type === "object") {
el.renderer(t);
el.renderer(t, c);
} else {
el.children.forEach((child) => triggerRendering(t, child));
el.children.forEach((child) => callTreeRenderers(t, c, child));
}
};

Expand All @@ -259,20 +261,19 @@ let counter = 0;
/** send command buffer to device and render */
export function paintLagopusTree() {
let device = atomDevice.deref();
atomCommandEncoder.reset(device.createCommandEncoder({ label: "lagopus shared" }));
let commandEncoder = device.createCommandEncoder({ label: "lagopus shared" });

atomBufferNeedClear.reset(true);
let tree = atomLagopusTree.deref();
triggerRendering(counter, tree);
callTreeRenderers(counter, commandEncoder, tree);
counter += 1;

if (atomBufferNeedClear.deref()) {
clearCanvas();
clearCanvas(commandEncoder);
} else if (atomBloomEnabled.deref()) {
postRendering();
postRendering(commandEncoder);
}
// load shared device
let commandEncoder = atomCommandEncoder.deref();
device.queue.submit([commandEncoder.finish()]);
}

Expand Down
15 changes: 2 additions & 13 deletions src/post-rendering.mts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,7 @@ import fullscreenWgsl from "../shaders/fullscreen.wgsl";
import blurWGSL from "../shaders/blur.wgsl";
import screenFilterWgsl from "../shaders/screen-filter.wgsl";

import {
atomContext,
atomDevice,
atomCanvasTexture,
atomCommandEncoder,
atomPingBuffer,
atomPongBuffer,
atomFilterTexture,
atomPingTexture,
atomPongTexture,
} from "./global.mjs";
import { atomContext, atomDevice, atomCanvasTexture, atomPingBuffer, atomPongBuffer, atomFilterTexture, atomPingTexture, atomPongTexture } from "./global.mjs";

/** based on code https://webgpu.github.io/webgpu-samples/?sample=imageBlur#fullscreenTexturedQuad.wgsl */
export function prepareTextures(device: GPUDevice, textures: GPUTexture[], label: string) {
Expand Down Expand Up @@ -69,7 +59,7 @@ export function prepareTextures(device: GPUDevice, textures: GPUTexture[], label
}

/** was an experimental feature that is not enabled */
export function postRendering() {
export function postRendering(commandEncoder: GPUCommandEncoder) {
let canvasTexture = atomCanvasTexture.deref();
let device = atomDevice.deref();
let context = atomContext.deref();
Expand All @@ -81,7 +71,6 @@ export function postRendering() {
minFilter: "linear",
});
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
const commandEncoder = atomCommandEncoder.deref();

let pingTexture = atomPingTexture.deref();
let pongTexture = atomPongTexture.deref();
Expand Down
7 changes: 3 additions & 4 deletions src/primes.mts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ export interface LagopusObjectOptions {
hitRegion?: LagopusHitRegion;
indices?: number[];
getParams?: () => number[];
/** @deprecated use `getParams` now */
addUniform?: () => number[];
textures?: GPUTexture[];
computeOptions?: ComputeOptions;
}
Expand All @@ -39,9 +37,10 @@ export interface LagopusObjectData {
vertexBuffersDescriptors: Iterable<GPUVertexBufferLayout | null>;
shaderModule: GPUShaderModule;
vertexBuffers: GPUBuffer[];
length: number;
verticesLength: number;
hitRegion?: LagopusHitRegion;
indices?: GPUBuffer;
indicesCount?: number;
getParams?: () => number[];
textures?: GPUTexture[];
label: string;
Expand All @@ -50,7 +49,7 @@ export interface LagopusObjectData {

export interface LagopusRenderObject {
type: "object" | "group";
renderer?: (t: number) => void;
renderer?: (t: number, c: GPUCommandEncoder) => void;
children?: LagopusRenderObject[];
hitRegion?: LagopusHitRegion;
}
Expand Down
57 changes: 29 additions & 28 deletions src/renderer.mts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,26 @@ import { atomDevice, atomProxiedDispatch, atomLagopusTree } from "./global.mjs";
import { makePainter } from "./paint.mjs";

/** prepare vertex buffer from object */
export let createRenderer = (
shaderCode: string,
topology: GPUPrimitiveTopology,
attrsList: LagopusAttribute[],
verticesLength: number,
vertices: (Float32Array | Uint32Array)[],
hitRegion: LagopusHitRegion,
indices: Uint32Array,
getParams: () => number[],
textures: GPUTexture[],
label: string,
computeOptions?: ComputeOptions
): LagopusRenderObject => {
export let createRenderer = (options: {
shader: string;
topology: GPUPrimitiveTopology;
attrsList: LagopusAttribute[];
verticesLength: number;
vertices: (Float32Array | Uint32Array)[];
hitRegion: LagopusHitRegion;
indices: Uint32Array;
getParams: () => number[];
textures: GPUTexture[];
label: string;
computeOptions?: ComputeOptions;
}): LagopusRenderObject => {
// load shared device
let device = atomDevice.deref();

let vertexBuffers = vertices.map((v) => createBuffer(v, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, "vertex"));
let indicesBuffer = indices ? createBuffer(indices, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, "index") : null;
let vertexBuffers = options.vertices.map((v) => createBuffer(v, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, "vertex"));
let indicesBuffer = options.indices ? createBuffer(options.indices, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, "index") : null;

const vertexBuffersDescriptors = attrsList.map((info, idx) => {
const vertexBuffersDescriptors = options.attrsList.map((info, idx) => {
let stride = readFormatSize(info.format);
return {
attributes: [{ shaderLocation: idx, offset: 0, format: info.format }],
Expand All @@ -35,31 +35,32 @@ export let createRenderer = (

// ~~ DEFINE BASIC SHADERS ~~
const shaderModule = device.createShaderModule({
label,
code: shaderCode,
label: options.label,
code: options.shader,
});

shaderModule.getCompilationInfo().then((e) => {
// a dirty hook to expose build messages
globalThis.__lagopusHandleCompilationInfo?.(e, shaderCode);
globalThis.__lagopusHandleCompilationInfo?.(e, options.shader);
});

return {
type: "object",
hitRegion,
hitRegion: options.hitRegion,
renderer: makePainter({
type: "object",
topology: topology,
topology: options.topology,
shaderModule: shaderModule,
vertexBuffersDescriptors: vertexBuffersDescriptors,
vertexBuffersDescriptors,
vertexBuffers,
length: verticesLength,
hitRegion: hitRegion,
verticesLength: options.verticesLength,
hitRegion: options.hitRegion,
indices: indicesBuffer,
getParams,
textures,
label,
computeOptions,
indicesCount: options.indices ? options.indices.length : 0,
getParams: options.getParams,
textures: options.textures,
label: options.label,
computeOptions: options.computeOptions,
}),
};
};
Expand Down

0 comments on commit acdc9fe

Please sign in to comment.