File size: 1,912 Bytes
5ca276f
709f56b
5ca276f
 
 
 
 
f672c5a
709f56b
5ca276f
709f56b
5ca276f
f672c5a
5ca276f
 
 
4648f7d
709f56b
2fa7c78
709f56b
 
 
5ca276f
 
 
 
709f56b
5ca276f
709f56b
 
5ca276f
709f56b
 
f672c5a
709f56b
 
 
 
 
 
 
 
f672c5a
709f56b
 
5ca276f
709f56b
 
2fa7c78
5ca276f
f672c5a
709f56b
5ca276f
709f56b
 
5ca276f
709f56b
 
5ca276f
4648f7d
709f56b
4648f7d
5ca276f
 
 
709f56b
5ca276f
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import { createCompute } from "./gpu.js";
import shader from "./world.wgsl?raw";

export class World {
  constructor(canvas, gpu) {
    this.ctx = canvas.getContext("2d");
    this.gpu = gpu;
    this.power = 8.0;
    this.time = 0;

    this.image = this.ctx.createImageData(256, 256);

    if (gpu.mode === "gpu") this.initGPU();
  }

  async initGPU() {
    const d = this.gpu.device;
    this.pipeline = createCompute(d, shader);

    this.param = d.createBuffer({ size: 8, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
    this.buf = d.createBuffer({ size: 256*256*4*4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });
    this.read = d.createBuffer({ size: 256*256*4*4, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ });
  }

  update(dt) {
    this.time += dt;
    if (this.gpu.mode !== "gpu") return;

    const d = this.gpu.device;
    d.queue.writeBuffer(this.param, 0, new Float32Array([this.time, this.power]));

    const enc = d.createCommandEncoder();
    const pass = enc.beginComputePass();

    pass.setPipeline(this.pipeline);
    pass.setBindGroup(0, d.createBindGroup({
      layout: this.pipeline.getBindGroupLayout(0),
      entries: [
        { binding: 0, resource: { buffer: this.param } },
        { binding: 1, resource: { buffer: this.buf } }
      ]
    }));

    pass.dispatchWorkgroups(32, 32);
    pass.end();

    enc.copyBufferToBuffer(this.buf, 0, this.read, 0, 256*256*4*4);
    d.queue.submit([enc.finish()]);
  }

  async render() {
    if (this.gpu.mode !== "gpu") return;

    await this.read.mapAsync(GPUMapMode.READ);
    const f = new Float32Array(this.read.getMappedRange());

    for (let i = 0; i < f.length; i++) {
      this.image.data[i] = Math.min(255, f[i] * 255);
    }

    this.read.unmap();
    this.ctx.putImageData(this.image, 0, 0);
  }

  apply(cmd) {
    if (cmd.payload?.power) this.power = cmd.payload.power;
  }
}