glre 0.36.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/webgpu.ts CHANGED
@@ -2,8 +2,8 @@ import { nested as cached } from 'reev'
2
2
  import { is, loadingImage } from './utils/helpers'
3
3
  import {
4
4
  createArrayBuffer,
5
- createBindings,
6
5
  createBindGroup,
6
+ createBindings,
7
7
  createComputePipeline,
8
8
  createDepthTexture,
9
9
  createDescriptor,
@@ -15,15 +15,53 @@ import {
15
15
  import type { GL, WebGPUState } from './types'
16
16
  import { compute, fragment, vertex } from './node'
17
17
 
18
+ const WORKING_GROUP_SIZE = 32
19
+
20
+ const computeProgram = (gl: GL, device: GPUDevice, bindings: any) => {
21
+ let flush = (_pass: GPUComputePassEncoder) => {}
22
+
23
+ const storages = cached((_key, value: number[] | Float32Array) => {
24
+ const { array, buffer } = createArrayBuffer(device, value, 'storage')
25
+ const { binding, group } = bindings.storage()
26
+ return { array, buffer, binding, group }
27
+ })
28
+
29
+ const _storage = (key: string, value: number[] | Float32Array) => {
30
+ const { array, buffer } = storages(key, value)
31
+ device.queue.writeBuffer(buffer, 0, array as any)
32
+ }
33
+
34
+ const update = (bindGroups: GPUBindGroup[], bindGroupLayouts: GPUBindGroupLayout[], comp: string) => {
35
+ const pipeline = createComputePipeline(device, bindGroupLayouts, comp!)
36
+ flush = (pass) => {
37
+ pass.setPipeline(pipeline)
38
+ bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
39
+ const workgroupCount = Math.ceil(gl.particles / WORKING_GROUP_SIZE)
40
+ pass.dispatchWorkgroups(workgroupCount, 1, 1)
41
+ pass.end()
42
+ }
43
+ }
44
+
45
+ const render = (pass: GPUComputePassEncoder) => {
46
+ flush(pass)
47
+ }
48
+
49
+ const clean = () => {
50
+ for (const { buffer } of storages.map.values()) buffer.destroy()
51
+ }
52
+
53
+ return { storages, _storage, update, render, clean }
54
+ }
55
+
18
56
  export const webgpu = async (gl: GL) => {
19
57
  const context = gl.el!.getContext('webgpu') as GPUCanvasContext
20
58
  const { device, format } = await createDevice(context, gl.error)
21
59
  const bindings = createBindings()
60
+ const cp = computeProgram(gl, device, bindings)
22
61
  let frag: string
23
- let vert: string
24
62
  let comp: string
63
+ let vert: string
25
64
  let flush = (_pass: GPURenderPassEncoder) => {}
26
- let computeFlush = (_pass: GPUComputePassEncoder) => {}
27
65
  let needsUpdate = true
28
66
  let depthTexture: GPUTexture
29
67
 
@@ -35,13 +73,6 @@ export const webgpu = async (gl: GL) => {
35
73
  return { array, buffer, location, stride }
36
74
  })
37
75
 
38
- const storages = cached((_key, value: number[] | Float32Array) => {
39
- needsUpdate = true
40
- const { array, buffer } = createArrayBuffer(device, value, 'storage')
41
- const { binding, group } = bindings.storage()
42
- return { array, buffer, binding, group }
43
- })
44
-
45
76
  const uniforms = cached((_key, value: number[]) => {
46
77
  needsUpdate = true
47
78
  const { binding, group } = bindings.uniform()
@@ -61,14 +92,10 @@ export const webgpu = async (gl: GL) => {
61
92
  device.queue.writeBuffer(buffer, 0, array as any)
62
93
  }
63
94
 
64
- const _storage = (key: string, value: number[] | Float32Array) => {
65
- const { array, buffer } = storages(key, value)
66
- device.queue.writeBuffer(buffer, 0, array as any)
67
- }
68
-
69
95
  const _uniform = (key: string, value: number | number[]) => {
70
96
  if (is.num(value)) value = [value]
71
97
  const { array, buffer } = uniforms(key, value)
98
+ array.set(value) // needs to set leatest value
72
99
  device.queue.writeBuffer(buffer, 0, array as any)
73
100
  }
74
101
 
@@ -86,7 +113,7 @@ export const webgpu = async (gl: GL) => {
86
113
  device,
87
114
  uniforms.map.values(),
88
115
  textures.map.values(),
89
- storages.map.values()
116
+ cp.storages.map.values()
90
117
  )
91
118
  const pipeline = createPipeline(device, format, bufferLayouts, bindGroupLayouts, vert, frag)
92
119
  flush = (pass) => {
@@ -96,33 +123,21 @@ export const webgpu = async (gl: GL) => {
96
123
  pass.draw(gl.count, 1, 0, 0)
97
124
  pass.end()
98
125
  }
99
- if (comp) {
100
- const computePipeline = createComputePipeline(device, bindGroupLayouts, comp)
101
- computeFlush = (pass) => {
102
- pass.setPipeline(computePipeline)
103
- bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
104
- let maxElements = 1
105
- for (const { array } of storages.map.values())
106
- maxElements = Math.max(maxElements, array.length)
107
- const workgroupCount = Math.ceil(maxElements / 64)
108
- pass.dispatchWorkgroups(workgroupCount)
109
- pass.end()
110
- }
111
- }
126
+ if (gl.cs) cp.update(bindGroups, bindGroupLayouts, comp)
112
127
  }
113
128
 
114
129
  const render = () => {
115
130
  if (!frag || !vert) {
116
131
  const config = { isWebGL: false, gl }
117
132
  frag = fragment(gl.fs, config) // needs to be before vertex
118
- comp = compute(gl.cs, config)
119
133
  vert = vertex(gl.vs, config)
134
+ comp = compute(gl.cs, config)
120
135
  }
121
136
  if (gl.loading) return // MEMO: loading after build node
122
137
  if (needsUpdate) update()
123
138
  needsUpdate = false
124
139
  const encoder = device.createCommandEncoder()
125
- if (comp) computeFlush(encoder.beginComputePass())
140
+ if (gl.cs) cp.render(encoder.beginComputePass())
126
141
  flush(encoder.beginRenderPass(createDescriptor(context, depthTexture)))
127
142
  device.queue.submit([encoder.finish()])
128
143
  }
@@ -139,19 +154,12 @@ export const webgpu = async (gl: GL) => {
139
154
  for (const { texture } of textures.map.values()) texture.destroy()
140
155
  for (const { buffer } of uniforms.map.values()) buffer.destroy()
141
156
  for (const { buffer } of attribs.map.values()) buffer.destroy()
142
- for (const { buffer } of storages.map.values()) buffer.destroy()
157
+ cp.clean()
143
158
  }
144
159
 
145
160
  resize()
146
161
 
147
- return {
148
- webgpu: { device, uniforms, textures, attribs, storages } as WebGPUState,
149
- render,
150
- resize,
151
- clean,
152
- _attribute,
153
- _uniform,
154
- _texture,
155
- _storage,
156
- }
162
+ const webgpu = { device, uniforms, textures, attribs, storages: cp.storages } as WebGPUState
163
+
164
+ return { webgpu, render, resize, clean, _attribute, _uniform, _texture, _storage: cp._storage }
157
165
  }