387 lines
7.6 KiB
Markdown
387 lines
7.6 KiB
Markdown
Below is a clean, concise **AGENTS.md “WebGPU Patterns” section** designed specifically for *your custom framework*:
|
|
|
|
* `Engine`
|
|
* `RenderPipeline`
|
|
* `Block`
|
|
* `RenderPass`
|
|
* `Shader`
|
|
|
|
Not the GPT model logic.
|
|
Not embeddings or inference.
|
|
Only the architectural usage patterns you want Codex to follow.
|
|
|
|
You can **copy this directly** into your existing AGENTS.md under “Example Patterns”, or use it to replace that section entirely.
|
|
|
|
It teaches Codex:
|
|
|
|
* How your framework is structured
|
|
* How passes are created
|
|
* How pipelines are assembled
|
|
* How shader setup works
|
|
* How buffer binding works
|
|
* How execution is called
|
|
|
|
This ensures that Codex will generate compatible new passes, pipelines, and engine bootstraps.
|
|
|
|
---
|
|
|
|
# **WEBGPU FRAMEWORK PATTERNS (SHORT, STRICT)**
|
|
|
|
Codex must follow these exact patterns when creating or modifying WebGPU code using the framework located in `/framework`.
|
|
|
|
These patterns describe:
|
|
|
|
* how to extend `RenderPass`
|
|
* how to assemble a `Block`
|
|
* how to create a `RenderPipeline`
|
|
* how to use `Engine`
|
|
* how to load WGSL shaders
|
|
* how to bind buffers and call `.execute()`
|
|
|
|
No ML logic included.
|
|
Only architectural usage patterns.
|
|
|
|
---
|
|
|
|
# paths
|
|
|
|
```
|
|
/framework/RenderPass.js
|
|
|
|
/framework/WebGpu.js
|
|
|
|
/framework/Block.js
|
|
|
|
/framework/EventManager.js
|
|
|
|
/framework/Camera.js
|
|
|
|
/framework/Matrix4.js
|
|
|
|
/framework/vector3.js
|
|
```
|
|
|
|
|
|
# **1. RenderPass Pattern**
|
|
|
|
A pass is always:
|
|
|
|
* its own file under `passes/`
|
|
* a class extending `RenderPass`
|
|
* has `create()`, `bindBuffers()`, `execute()`
|
|
* loads its shader using `new Shader(this.device)`
|
|
* sets WGSL variables using `.setVariable()`
|
|
|
|
```javascript
|
|
import { RenderPass } from "framework/RenderPass.js";
|
|
|
|
import Shader from "framework/WebGpu.js";
|
|
|
|
|
|
export class ExamplePass extends RenderPass {
|
|
|
|
async create( ) {
|
|
|
|
this.shader = new Shader( this.device );
|
|
|
|
await this.shader.setup( "shaders/example.wgsl" );
|
|
|
|
}
|
|
|
|
|
|
bindBuffers( ) {
|
|
|
|
var inputData = this.pipeline.memory.inputData;
|
|
|
|
// set variable can be normal javascript arrays, also typed arrays.
|
|
this.shader.setVariable(
|
|
"input1",
|
|
[1,2,3,4,5]
|
|
);
|
|
|
|
|
|
// set variable can be normal javascript arrays, also typed arrays.
|
|
this.shader.setVariable(
|
|
"input2",
|
|
new Float32Array( [ 1,2,3,4 ] )
|
|
);
|
|
|
|
const texture = this.shader.createTextureFromData(
|
|
width,
|
|
height,
|
|
[ 1,2,3... ]
|
|
);
|
|
|
|
this.shader.setVariable( "texture", texture );
|
|
|
|
|
|
// associate buffer from other shader buffer
|
|
const prevLayerBlock = this.pipeline.getBlockByName("blockName");
|
|
|
|
const pass = prevLayerBlock.getPass("passName");
|
|
|
|
const buffer = pass.shader.getBuffer("outputVector");
|
|
|
|
this.shader.setBuffer("inputHiddenState", buffer);
|
|
|
|
}
|
|
|
|
|
|
async execute( ) {
|
|
|
|
await this.shader.execute( 1 );
|
|
|
|
}
|
|
|
|
}
|
|
```
|
|
|
|
Rules Codex must preserve:
|
|
|
|
* One blank line between imports.
|
|
* Tab-aligned imports before each `from`.
|
|
* No arrow functions.
|
|
* `await this.shader.setup( path )`.
|
|
* `this.shader.setVariable( name, data )` only in `bindBuffers()` or incremental calls.
|
|
* `execute()` always calls `this.shader.execute( workgroups )`.
|
|
|
|
---
|
|
|
|
# **2. Block Pattern**
|
|
|
|
A block is a logical grouping of passes.
|
|
Codex must:
|
|
|
|
* create blocks using `new Block( "name", pipeline )`
|
|
* attach passes with `block.addPass( "Name", instance )`
|
|
* add block to pipeline with `pipeline.addBlock( block )`
|
|
|
|
```
|
|
import { Block } from "./framework/Block.js";
|
|
|
|
import { ExamplePass } from "../passes/ExamplePass.js";
|
|
|
|
|
|
const block = new Block( "example", this );
|
|
|
|
const pass = new ExamplePass( );
|
|
|
|
block.addPass( "Example", pass );
|
|
|
|
this.addBlock( block );
|
|
```
|
|
|
|
---
|
|
|
|
# **3. Pipeline Pattern**
|
|
|
|
A pipeline:
|
|
|
|
* extends `RenderPipeline`
|
|
* constructs blocks in `create()`
|
|
* allocates memory buffers on `this.memory`
|
|
* always calls `await super.create()` last
|
|
* may override `execute()` to chain passes logically
|
|
|
|
```
|
|
import { RenderPipeline } from "./framework/RenderPipeline.js";
|
|
|
|
import { Block } from "./framework/Block.js";
|
|
|
|
import { ExamplePass } from "../passes/ExamplePass.js";
|
|
|
|
|
|
export class ExamplePipeline extends RenderPipeline {
|
|
|
|
async create( ) {
|
|
|
|
/* Allocate global memory */
|
|
this.memory.input = new Float32Array( 1024 );
|
|
|
|
this.memory.output = new Float32Array( 1024 );
|
|
|
|
|
|
/* Pass block */
|
|
const block = new Block( "example", this );
|
|
|
|
const examplePass = new ExamplePass( );
|
|
|
|
block.addPass( "Example", examplePass );
|
|
|
|
this.addBlock( block );
|
|
|
|
|
|
/* Build GPU resources (mandatory) */
|
|
await super.create();
|
|
|
|
}
|
|
|
|
|
|
async execute( ) {
|
|
|
|
const block = this.blocks[0];
|
|
|
|
const pass = block.getPass( "Example" );
|
|
|
|
await pass.execute();
|
|
|
|
}
|
|
|
|
}
|
|
```
|
|
|
|
|
|
# **3. Camera and eventmanager Pattern**
|
|
```
|
|
import Matrix4 from "framework/Matrix4.js"
|
|
|
|
import Vector3 from "framework/Vector3.js"
|
|
|
|
|
|
this.camera = new Camera( [0, 0, 1115], [0, -.3, 0], [0, 1, 0] );
|
|
|
|
this.eventManager.setup( canvas, this.camera );
|
|
|
|
|
|
|
|
const viewMatrixData = this.camera.getViewMatrix();
|
|
|
|
const projectionMatrixData = Matrix4.createProjectionMatrix( this.camera, this.canvas )
|
|
|
|
const viewProjectionMatrix = Matrix4.multiply( projectionMatrixData, viewMatrixData );
|
|
|
|
const cameraWorldMatrix = Matrix4.invert( viewMatrixData );
|
|
|
|
const cameraPosition = Matrix4.getColumn( cameraWorldMatrix, 3 );
|
|
|
|
this.renderShader.setVariable( "viewProjectionMatrix", viewProjectionMatrix );
|
|
|
|
this.renderShader.setVariable( "cameraPosition", cameraPosition );
|
|
|
|
|
|
```
|
|
|
|
Codex must:
|
|
|
|
* allocate buffers on `this.memory.*`
|
|
* assemble blocks before `super.create()`
|
|
* not reorder pipeline structure automatically
|
|
|
|
---
|
|
|
|
# **4. Engine Usage Pattern**
|
|
|
|
The entrypoint must follow this shape whenever Codex creates a new WebGPU project:
|
|
|
|
```
|
|
import { Engine } from "./framework/Engine.js";
|
|
|
|
import { ExamplePipeline } from "./pipelines/ExamplePipeline.js";
|
|
|
|
|
|
async function main( ) {
|
|
|
|
|
|
const adapter = await navigator.gpu.requestAdapter( );
|
|
|
|
const device = await adapter.requestDevice( );
|
|
|
|
const engine = new Engine( device );
|
|
|
|
|
|
/* Pipeline */
|
|
const pipeline = new ExamplePipeline( engine );
|
|
|
|
pipeline.memory.set( "inputData", new Float32Array( 1024 ) );
|
|
|
|
|
|
await pipeline.create();
|
|
|
|
|
|
await pipeline.bindBuffers();
|
|
|
|
|
|
await pipeline.execute();
|
|
|
|
|
|
}
|
|
|
|
main( );
|
|
```
|
|
|
|
Codex must always:
|
|
|
|
* request adapter → requestDevice
|
|
* create `new Engine(device)`
|
|
* instantiate pipeline with `(engine)`
|
|
* set memory with `pipeline.memory.set( key, value )`
|
|
* call `await pipeline.create()`
|
|
* call `await pipeline.bindBuffers()`
|
|
* call `await pipeline.execute()`
|
|
|
|
---
|
|
|
|
# **5. Shader Usage Pattern**
|
|
|
|
Codex must use the Shader class exactly like this:
|
|
|
|
```
|
|
this.shader = new Shader( this.device );
|
|
|
|
await this.shader.setup( "shaders/example.wgsl" );
|
|
|
|
this.shader.setVariable( "bufferA", floatArray );
|
|
|
|
await this.shader.execute( workgroups );
|
|
```
|
|
|
|
Always:
|
|
|
|
* One shader instance per pass
|
|
* WGSL path passed to `.setup()`
|
|
* `.setVariable()` before `.execute()`
|
|
* No arrow functions
|
|
* Spaces inside parentheses
|
|
|
|
---
|
|
|
|
# **6. Memory Allocation Pattern**
|
|
|
|
All buffers are allocated as plain typed arrays under:
|
|
|
|
```
|
|
this.memory.X = new Float32Array( size );
|
|
```
|
|
|
|
Codex must never use ArrayBuffer directly unless required.
|
|
|
|
---
|
|
|
|
# **7. Execution Flow Rule**
|
|
|
|
Every pipeline execution must follow:
|
|
|
|
1. `await pipeline.create()`
|
|
2. `await pipeline.bindBuffers()`
|
|
3. `await pipeline.execute()`
|
|
|
|
Never run execute before create.
|
|
Never omit bindBuffers if pass needs it.
|
|
|
|
---
|
|
|
|
# **8. Codex MUST NOT Generate**
|
|
|
|
* Raw WebGPU API calls (`device.createBuffer`) unless inside Shader class
|
|
* Inline WGSL; always stored in `.wgsl` files
|
|
* Arrow functions
|
|
* Inline callbacks
|
|
* Different architecture than this:
|
|
|
|
* Engine
|
|
* Pipeline
|
|
* Block
|
|
* RenderPass
|
|
* Shader
|
|
|