From 7da1fa8366655b83c9655a4b098f7f12fe5e7e50 Mon Sep 17 00:00:00 2001 From: mekanoe <1581674+mekanoe@users.noreply.github.com> Date: Sat, 7 Oct 2023 10:34:40 -0400 Subject: [PATCH] tiny iteration --- html/001-platform-provenance/main.js | 2 +- html/002-webgpu-instead/main.js | 2 +- html/chunk-0cd54990cab7d3a5.js | 5 +++ html/chunk-32eefd9b41c928dd.js | 5 --- src/002-webgpu-instead/main.ts | 1 + src/renderer/telemetry.ts | 18 ++++++--- src/renderer/webgpu.ts | 55 ++++++++++++++++++++++++++++ 7 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 html/chunk-0cd54990cab7d3a5.js delete mode 100644 html/chunk-32eefd9b41c928dd.js diff --git a/html/001-platform-provenance/main.js b/html/001-platform-provenance/main.js index d1b453f..98b33ca 100644 --- a/html/001-platform-provenance/main.js +++ b/html/001-platform-provenance/main.js @@ -1,4 +1,4 @@ -import{a as Y} from"../chunk-32eefd9b41c928dd.js";class E{constructor(C){this.gl=C.gl,this.app=C,this.program=this.gl.createProgram()}attach(C,D){console.log("attaching shader",{type:C,source:D});const R=this.gl.createShader(C);if(this.gl.shaderSource(R,D),this.gl.compileShader(R),!this.gl.getShaderParameter(R,this.gl.COMPILE_STATUS))throw new Error("An error occurred compiling the shaders: "+this.gl.getShaderInfoLog(R));return this.gl.attachShader(this.program,R),this}link(){if(this.gl.linkProgram(this.program),!this.gl.getProgramParameter(this.program,this.gl.LINK_STATUS))throw new Error("Unable to initialize the shader program: "+this.gl.getProgramInfoLog(this.program));return console.log("shader linked"),this}location(C){if(C[0]==="a")return this.gl.getAttribLocation(this.program,C);else if(C[0]==="u")return this.gl.getUniformLocation(this.program,C)}updateTime(){const C=this.app.now(),D=Math.sin(C),R=Math.cos(C);this.gl.uniform1f(this.location("uTime"),C),this.gl.uniform1f(this.location("uSinTime"),D),this.gl.uniform1f(this.location("uCosTime"),R)}activate(C,D){this.gl.useProgram(this.program),this.gl.uniformMatrix4fv(this.location("uProjectionMatrix"),!1,C),this.gl.uniformMatrix4fv(this.location("uModelViewMatrix"),!1,D),this.updateTime()}}class I{constructor(C){this.gl=C.gl,this.app=C,this.vertexPositions=new Float32Array([]),this.positionBuffer=null,this.textureBuffer=null}initBuffer(C,D=this.gl.STATIC_DRAW){const R=this.gl.createBuffer();return this.gl.bindBuffer(this.gl.ARRAY_BUFFER,R),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array(C),D),R}attachShader(C){return this.shader=C,this.vertexPosition=C.location("aVertexPosition"),this.textureCoord=C.location("aTextureCoord"),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.gl.vertexAttribPointer(this.vertexPosition,2,this.gl.FLOAT,!1,0,0),this.gl.enableVertexAttribArray(this.vertexPosition),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.textureBuffer),this.gl.vertexAttribPointer(this.textureCoord,2,this.gl.FLOAT,!1,0,0),this.gl.enableVertexAttribArray(this.textureCoord),this}draw2D(){this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.shader.activate(this.app.projectionMatrix,this.app.modelViewMatrix),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,this.vertexPositions.length/2)}draw3D(){this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.shader.activate(this.app.projectionMatrix,this.app.modelViewMatrix),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,this.vertexPositions.length/3)}}class K extends I{constructor(C){super(C);this.vertexPositions=new Float32Array([-1,-1,1,-1,-1,1,1,1]),this.positionBuffer=this.initBuffer(this.vertexPositions),this.textureBuffer=this.initBuffer(new Float32Array([0,0,1,0,0,1,1,1])),this.app.onUpdate(()=>this.draw2D())}}class L{constructor(C={fov:45}){if(this._now=0,this.registry={onStart:[],onUpdate:[],onBeforeUpdate:[],onAfterUpdate:[]},this.config=C,this.canvas=document.querySelector("canvas"),this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight,this.gl=this.canvas.getContext("webgl2"),this.gl===null)throw document.querySelector("main").innerHTML="
your browser didn't let me set up webgl
",new Error("Unable to initialize WebGL. Your browser or machine may not support it.");const D=this.gl,R=this.config.fov*Math.PI/180,G=D.canvas.clientWidth/D.canvas.clientHeight,H=0.1,J=100,P=glMatrix.mat4.create();glMatrix.mat4.perspective(P,R,G,H,J);const q=glMatrix.mat4.create();glMatrix.mat4.translate(q,q,[-0,0,-6]),this.projectionMatrix=P,this.modelViewMatrix=q,this.clear(),this.onBeforeUpdate(()=>this.clear()),this.telemetry=new Y(this)}clear(){const C=this.gl;C.clearColor(0,0,0,1),C.clearDepth(1),C.enable(C.DEPTH_TEST),C.depthFunc(C.LEQUAL),C.clear(C.COLOR_BUFFER_BIT|C.DEPTH_BUFFER_BIT)}onStart(C){this.registry.onStart.push(C)}onUpdate(C){this.registry.onUpdate.push(C)}onBeforeUpdate(C){this.registry.onBeforeUpdate.push(C)}onAfterUpdate(C){this.registry.onAfterUpdate.push(C)}start(){this.registry.onStart.forEach((C)=>C(this))}update(){this.registry.onBeforeUpdate.forEach((C)=>C(this)),this.registry.onUpdate.forEach((C)=>C(this)),this.registry.onAfterUpdate.forEach((C)=>C(this))}oneShot(){requestAnimationFrame((C)=>{this._now=C,this.start(),this.update()})}loop(){const C=(D)=>{this._now=D,this.update(),requestAnimationFrame(C)};requestAnimationFrame(C)}now(){return this._now}}var k=`precision highp float; +import{a as Y} from"../chunk-0cd54990cab7d3a5.js";class E{constructor(C){this.gl=C.gl,this.app=C,this.program=this.gl.createProgram()}attach(C,D){console.log("attaching shader",{type:C,source:D});const R=this.gl.createShader(C);if(this.gl.shaderSource(R,D),this.gl.compileShader(R),!this.gl.getShaderParameter(R,this.gl.COMPILE_STATUS))throw new Error("An error occurred compiling the shaders: "+this.gl.getShaderInfoLog(R));return this.gl.attachShader(this.program,R),this}link(){if(this.gl.linkProgram(this.program),!this.gl.getProgramParameter(this.program,this.gl.LINK_STATUS))throw new Error("Unable to initialize the shader program: "+this.gl.getProgramInfoLog(this.program));return console.log("shader linked"),this}location(C){if(C[0]==="a")return this.gl.getAttribLocation(this.program,C);else if(C[0]==="u")return this.gl.getUniformLocation(this.program,C)}updateTime(){const C=this.app.now(),D=Math.sin(C),R=Math.cos(C);this.gl.uniform1f(this.location("uTime"),C),this.gl.uniform1f(this.location("uSinTime"),D),this.gl.uniform1f(this.location("uCosTime"),R)}activate(C,D){this.gl.useProgram(this.program),this.gl.uniformMatrix4fv(this.location("uProjectionMatrix"),!1,C),this.gl.uniformMatrix4fv(this.location("uModelViewMatrix"),!1,D),this.updateTime()}}class I{constructor(C){this.gl=C.gl,this.app=C,this.vertexPositions=new Float32Array([]),this.positionBuffer=null,this.textureBuffer=null}initBuffer(C,D=this.gl.STATIC_DRAW){const R=this.gl.createBuffer();return this.gl.bindBuffer(this.gl.ARRAY_BUFFER,R),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array(C),D),R}attachShader(C){return this.shader=C,this.vertexPosition=C.location("aVertexPosition"),this.textureCoord=C.location("aTextureCoord"),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.gl.vertexAttribPointer(this.vertexPosition,2,this.gl.FLOAT,!1,0,0),this.gl.enableVertexAttribArray(this.vertexPosition),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.textureBuffer),this.gl.vertexAttribPointer(this.textureCoord,2,this.gl.FLOAT,!1,0,0),this.gl.enableVertexAttribArray(this.textureCoord),this}draw2D(){this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.shader.activate(this.app.projectionMatrix,this.app.modelViewMatrix),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,this.vertexPositions.length/2)}draw3D(){this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.shader.activate(this.app.projectionMatrix,this.app.modelViewMatrix),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,this.vertexPositions.length/3)}}class K extends I{constructor(C){super(C);this.vertexPositions=new Float32Array([-1,-1,1,-1,-1,1,1,1]),this.positionBuffer=this.initBuffer(this.vertexPositions),this.textureBuffer=this.initBuffer(new Float32Array([0,0,1,0,0,1,1,1])),this.app.onUpdate(()=>this.draw2D())}}class L{constructor(C={fov:45}){if(this._now=0,this.registry={onStart:[],onUpdate:[],onBeforeUpdate:[],onAfterUpdate:[]},this.config=C,this.canvas=document.querySelector("canvas"),this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight,this.gl=this.canvas.getContext("webgl2"),this.gl===null)throw document.querySelector("main").innerHTML="
your browser didn't let me set up webgl
",new Error("Unable to initialize WebGL. Your browser or machine may not support it.");const D=this.gl,R=this.config.fov*Math.PI/180,G=D.canvas.clientWidth/D.canvas.clientHeight,H=0.1,J=100,P=glMatrix.mat4.create();glMatrix.mat4.perspective(P,R,G,H,J);const q=glMatrix.mat4.create();glMatrix.mat4.translate(q,q,[-0,0,-6]),this.projectionMatrix=P,this.modelViewMatrix=q,this.clear(),this.onBeforeUpdate(()=>this.clear()),this.telemetry=new Y(this)}clear(){const C=this.gl;C.clearColor(0,0,0,1),C.clearDepth(1),C.enable(C.DEPTH_TEST),C.depthFunc(C.LEQUAL),C.clear(C.COLOR_BUFFER_BIT|C.DEPTH_BUFFER_BIT)}onStart(C){this.registry.onStart.push(C)}onUpdate(C){this.registry.onUpdate.push(C)}onBeforeUpdate(C){this.registry.onBeforeUpdate.push(C)}onAfterUpdate(C){this.registry.onAfterUpdate.push(C)}start(){this.registry.onStart.forEach((C)=>C(this))}update(){this.registry.onBeforeUpdate.forEach((C)=>C(this)),this.registry.onUpdate.forEach((C)=>C(this)),this.registry.onAfterUpdate.forEach((C)=>C(this))}oneShot(){requestAnimationFrame((C)=>{this._now=C,this.start(),this.update()})}loop(){const C=(D)=>{this._now=D,this.update(),requestAnimationFrame(C)};requestAnimationFrame(C)}now(){return this._now}}var k=`precision highp float; uniform float uTime; uniform float uSinTime; diff --git a/html/002-webgpu-instead/main.js b/html/002-webgpu-instead/main.js index 3a1eb9f..c480528 100644 --- a/html/002-webgpu-instead/main.js +++ b/html/002-webgpu-instead/main.js @@ -1 +1 @@ -import{a as s} from"../chunk-32eefd9b41c928dd.js";class i{a;canvas;_adapter;_device;_context;telemetry;constructor(a={}){this.config=a;this.config={fov:45,...a},this.canvas=document.querySelector("canvas"),this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight,this.telemetry=new s(this),this.init().catch((c)=>{const v=document.querySelector("main");if(v)v.innerHTML="
your browser didn't let me set up webgpu. firefox nightly or enable dom.webgpu.enable.
";throw new Error("Unable to initialize WebGPU. Your browser or machine may not support it.",c)})}async init(){if(!navigator.gpu)throw new Error("WebGPU not supported");if(this._adapter=await navigator.gpu.requestAdapter(),!this._adapter)throw new Error("No GPU adapter found");if(this._device=await this.adapter.requestDevice(),!this._device)throw new Error("No GPU device found");this._context=this.canvas.getContext("webgpu"),this.context.configure({device:this.device,format:"bgra8unorm"})}get context(){if(!this._context)throw new Error("WebGPU context not initialized");return this._context}get adapter(){if(!this._adapter)throw new Error("WebGPU adapter not initialized");return this._adapter}get device(){if(!this._device)throw new Error("WebGPU device not initialized");return this._device}}var G=new i({fov:20}); +import{a as V} from"../chunk-0cd54990cab7d3a5.js";class w{s;canvas;_adapter;_device;_context;telemetry;registry={onBeforeUpdate:[],onAfterUpdate:[],onUpdate:[],onStart:[]};constructor(s={}){this.config=s;this.config={fov:45,...s},this.canvas=document.querySelector("canvas"),this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight,this.telemetry=new V(this),this.init().catch((o)=>{const x=document.querySelector("main");if(x)x.innerHTML="
your browser didn't let me set up webgpu. firefox nightly or enable dom.webgpu.enable.
";throw new Error("Unable to initialize WebGPU. Your browser or machine may not support it.",o)})}async init(){if(!navigator.gpu)throw new Error("WebGPU not supported");if(this._adapter=await navigator.gpu.requestAdapter(),!this._adapter)throw new Error("No GPU adapter found");if(this._device=await this.adapter.requestDevice(),!this._device)throw new Error("No GPU device found");this._context=this.canvas.getContext("webgpu"),this.context.configure({device:this.device,format:"bgra8unorm",alphaMode:"premultiplied",...this.config.context})}get context(){if(!this._context)throw new Error("WebGPU context not initialized");return this._context}get adapter(){if(!this._adapter)throw new Error("WebGPU adapter not initialized");return this._adapter}get device(){if(!this._device)throw new Error("WebGPU device not initialized");return this._device}onBeforeUpdate(s){this.registry.onBeforeUpdate.push(s)}onAfterUpdate(s){this.registry.onAfterUpdate.push(s)}onUpdate(s){this.registry.onUpdate.push(s)}onStart(s){this.registry.onStart.push(s)}doUpdate(s){this.registry.onBeforeUpdate.forEach((o)=>o(s,this)),this.registry.onUpdate.forEach((o)=>o(s,this)),this.registry.onAfterUpdate.forEach((o)=>o(s,this))}doStart(s=0){this.registry.onStart.forEach((o)=>o(this,s))}async oneShot(s=0){this.doStart(s),this.doUpdate(s)}start(){this.doStart();const s=(o)=>{this.doUpdate(o),requestAnimationFrame(s)};requestAnimationFrame(s)}}var _=new w({fov:20});_.start(); diff --git a/html/chunk-0cd54990cab7d3a5.js b/html/chunk-0cd54990cab7d3a5.js new file mode 100644 index 0000000..1e0da9f --- /dev/null +++ b/html/chunk-0cd54990cab7d3a5.js @@ -0,0 +1,5 @@ +class j{p;el;frameTimes=[];maxFrameTimes=100;lastFrameTime=0;constructor(p,x="#telemetry"){this.app=p;if(this.el=document.querySelector(x),this.el&&location.search.includes("telemetry"))this.el.style.display="block",this.app.onAfterUpdate((s)=>this.onAfterUpdate(s)),this.app.onStart(()=>this.onStart())}insertTime(p){if(this.frameTimes.push(p),this.frameTimes.length>this.maxFrameTimes)this.frameTimes.shift()}onStart(){this.lastFrameTime=0,this.frameTimes=[]}onAfterUpdate(p){const x=p-this.lastFrameTime;this.insertTime(x);const s=this.frameTimes.reduce((d,h)=>d+h,0)/this.frameTimes.length,$=1000/s;this.el.innerHTML=` + ${$.toFixed(1)} FPS (${s.toFixed(3)} ms)
+ bU: ${this.app.registry.onBeforeUpdate.length} | U: ${this.app.registry.onUpdate.length} | aU: ${this.app.registry.onAfterUpdate.length} + `,this.lastFrameTime=p}} +export{j as a}; diff --git a/html/chunk-32eefd9b41c928dd.js b/html/chunk-32eefd9b41c928dd.js deleted file mode 100644 index 7964611..0000000 --- a/html/chunk-32eefd9b41c928dd.js +++ /dev/null @@ -1,5 +0,0 @@ -class h{n;el;frameTimes=[];maxFrameTimes=100;lastFrameTime=0;constructor(n,u="#telemetry"){this.app=n;if(this.el=document.querySelector(u),this.el&&location.search.includes("telemetry"))this.el.style.display="block",this.app.onAfterUpdate(()=>this.onAfterUpdate())}insertTime(n){if(this.frameTimes.push(n),this.frameTimes.length>this.maxFrameTimes)this.frameTimes.shift()}onAfterUpdate(){const n=this.app.now()-this.lastFrameTime;this.insertTime(n);const u=this.frameTimes.reduce((w,d)=>w+d,0)/this.frameTimes.length,p=1000/u;this.el.innerHTML=` - ${p.toFixed(1)} FPS (${u.toFixed(3)} ms)
- bU: ${this.app.registry.onBeforeUpdate.length} | U: ${this.app.registry.onUpdate.length} | aU: ${this.app.registry.onAfterUpdate.length} - `,this.lastFrameTime=this.app.now()}} -export{h as a}; diff --git a/src/002-webgpu-instead/main.ts b/src/002-webgpu-instead/main.ts index b63e8d4..02d2b65 100644 --- a/src/002-webgpu-instead/main.ts +++ b/src/002-webgpu-instead/main.ts @@ -2,6 +2,7 @@ import { WebGPUApp } from "../renderer/webgpu"; const app = new WebGPUApp({ fov: 20 }); +app.start(); // TODO: // - plane // - white shader diff --git a/src/renderer/telemetry.ts b/src/renderer/telemetry.ts index bc6e8ac..6454f90 100644 --- a/src/renderer/telemetry.ts +++ b/src/renderer/telemetry.ts @@ -1,16 +1,19 @@ +import { WebGPUApp } from "./webgpu"; + export class Telemetry { public el: HTMLElement; public frameTimes: number[] = []; public maxFrameTimes: number = 100; public lastFrameTime: number = 0; constructor( - public app: any, + public app: WebGPUApp, selector = "#telemetry" ) { this.el = document.querySelector(selector) as HTMLElement; if (this.el && location.search.includes("telemetry")) { this.el.style.display = "block"; - this.app.onAfterUpdate(() => this.onAfterUpdate()); + this.app.onAfterUpdate((time) => this.onAfterUpdate(time)); + this.app.onStart(() => this.onStart()); } } @@ -22,8 +25,13 @@ export class Telemetry { } } - onAfterUpdate() { - const frameTime = this.app.now() - this.lastFrameTime; + onStart() { + this.lastFrameTime = 0; + this.frameTimes = []; + } + + onAfterUpdate(time: number) { + const frameTime = time - this.lastFrameTime; this.insertTime(frameTime); const averageFrameTime = @@ -40,6 +48,6 @@ export class Telemetry { } | aU: ${this.app.registry.onAfterUpdate.length} `; - this.lastFrameTime = this.app.now(); + this.lastFrameTime = time; } } diff --git a/src/renderer/webgpu.ts b/src/renderer/webgpu.ts index 63c92db..e992052 100644 --- a/src/renderer/webgpu.ts +++ b/src/renderer/webgpu.ts @@ -5,6 +5,8 @@ export type WebGPUAppConfig = { context?: GPUCanvasConfiguration; }; +export type RenderHandle = (time: number, app: WebGPUApp) => void; + export class WebGPUApp { public canvas: HTMLCanvasElement; private _adapter?: GPUAdapter; @@ -12,6 +14,18 @@ export class WebGPUApp { private _context?: GPUCanvasContext; public telemetry: Telemetry; + public registry: { + onBeforeUpdate: RenderHandle[]; + onAfterUpdate: RenderHandle[]; + onUpdate: RenderHandle[]; + onStart: RenderHandle[]; + } = { + onBeforeUpdate: [], + onAfterUpdate: [], + onUpdate: [], + onStart: [], + }; + constructor(public config: WebGPUAppConfig = {}) { this.config = { fov: 45, @@ -83,4 +97,45 @@ export class WebGPUApp { return this._device; } + + onBeforeUpdate(handle: RenderHandle) { + this.registry.onBeforeUpdate.push(handle); + } + + onAfterUpdate(handle: RenderHandle) { + this.registry.onAfterUpdate.push(handle); + } + + onUpdate(handle: RenderHandle) { + this.registry.onUpdate.push(handle); + } + + onStart(handle: RenderHandle) { + this.registry.onStart.push(handle); + } + + doUpdate(time: number) { + this.registry.onBeforeUpdate.forEach((handle) => handle(time, this)); + this.registry.onUpdate.forEach((handle) => handle(time, this)); + this.registry.onAfterUpdate.forEach((handle) => handle(time, this)); + } + + doStart(time: number = 0) { + this.registry.onStart.forEach((handle) => handle(this, time)); + } + + async oneShot(time: number = 0) { + this.doStart(time); + this.doUpdate(time); + } + + start() { + this.doStart(); + + const run = (time: number) => { + this.doUpdate(time); + requestAnimationFrame(run); + }; + requestAnimationFrame(run); + } }