glre 0.35.0 → 0.36.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
@@ -1,59 +1,92 @@
1
1
  import { nested as cached } from 'reev'
2
- import { is } from './utils/helpers'
2
+ import { is, loadingImage } from './utils/helpers'
3
3
  import {
4
- createAttribBuffer,
4
+ createArrayBuffer,
5
5
  createBindings,
6
6
  createBindGroup,
7
+ createComputePipeline,
7
8
  createDepthTexture,
8
9
  createDescriptor,
9
10
  createDevice,
10
11
  createPipeline,
11
12
  createTextureSampler,
12
- createUniformBuffer,
13
13
  createVertexBuffers,
14
14
  } from './utils/pipeline'
15
15
  import type { GL, WebGPUState } from './types'
16
- import { fragment, vertex } from './node'
16
+ import { compute, fragment, vertex } from './node'
17
17
 
18
18
  export const webgpu = async (gl: GL) => {
19
19
  const context = gl.el!.getContext('webgpu') as GPUCanvasContext
20
- const { device, format } = await createDevice(context)
21
- device.onuncapturederror = (e) => gl.error(e.error.message)
20
+ const { device, format } = await createDevice(context, gl.error)
22
21
  const bindings = createBindings()
23
22
  let frag: string
24
23
  let vert: string
24
+ let comp: string
25
25
  let flush = (_pass: GPURenderPassEncoder) => {}
26
+ let computeFlush = (_pass: GPUComputePassEncoder) => {}
26
27
  let needsUpdate = true
27
28
  let depthTexture: GPUTexture
28
29
 
30
+ const attribs = cached((_key, value: number[]) => {
31
+ needsUpdate = true
32
+ const stride = value.length / gl.count
33
+ const { location } = bindings.attrib()
34
+ const { array, buffer } = createArrayBuffer(device, value, 'attrib')
35
+ return { array, buffer, location, stride }
36
+ })
37
+
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
+
29
45
  const uniforms = cached((_key, value: number[]) => {
30
46
  needsUpdate = true
31
- const { array, buffer } = createUniformBuffer(device, value)
32
47
  const { binding, group } = bindings.uniform()
33
- return { binding, group, array, buffer }
48
+ const { array, buffer } = createArrayBuffer(device, value, 'uniform')
49
+ return { array, buffer, binding, group }
34
50
  })
35
51
 
36
52
  const textures = cached((_key, width = 0, height = 0) => {
37
53
  needsUpdate = true
38
- const { texture, sampler } = createTextureSampler(device, width, height)
39
54
  const { binding, group } = bindings.texture()
40
- return { binding, group, texture, sampler, view: texture.createView() }
55
+ const { texture, sampler } = createTextureSampler(device, width, height)
56
+ return { texture, sampler, binding, group, view: texture.createView() }
41
57
  })
42
58
 
43
- const attribs = cached((_key, value: number[]) => {
44
- needsUpdate = true
45
- const stride = value.length / gl.count
46
- const { location } = bindings.attrib()
47
- const { array, buffer } = createAttribBuffer(device, value)
48
- return { array, buffer, location, stride }
49
- })
59
+ const _attribute = (key = '', value: number[]) => {
60
+ const { array, buffer } = attribs(key, value)
61
+ device.queue.writeBuffer(buffer, 0, array as any)
62
+ }
63
+
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
+ const _uniform = (key: string, value: number | number[]) => {
70
+ if (is.num(value)) value = [value]
71
+ const { array, buffer } = uniforms(key, value)
72
+ device.queue.writeBuffer(buffer, 0, array as any)
73
+ }
74
+
75
+ const _texture = (key: string, src: string) => {
76
+ loadingImage(gl, src, (source) => {
77
+ const { width, height } = source
78
+ const { texture } = textures(key, width, height)
79
+ device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
80
+ })
81
+ }
50
82
 
51
83
  const update = () => {
52
84
  const { vertexBuffers, bufferLayouts } = createVertexBuffers(attribs.map.values())
53
85
  const { bindGroups, bindGroupLayouts } = createBindGroup(
54
86
  device,
55
87
  uniforms.map.values(),
56
- textures.map.values()
88
+ textures.map.values(),
89
+ storages.map.values()
57
90
  )
58
91
  const pipeline = createPipeline(device, format, bufferLayouts, bindGroupLayouts, vert, frag)
59
92
  flush = (pass) => {
@@ -63,18 +96,33 @@ export const webgpu = async (gl: GL) => {
63
96
  pass.draw(gl.count, 1, 0, 0)
64
97
  pass.end()
65
98
  }
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
+ }
66
112
  }
67
113
 
68
114
  const render = () => {
69
115
  if (!frag || !vert) {
70
116
  const config = { isWebGL: false, gl }
71
- frag = fragment(gl.fs, config)
117
+ frag = fragment(gl.fs, config) // needs to be before vertex
118
+ comp = compute(gl.cs, config)
72
119
  vert = vertex(gl.vs, config)
73
120
  }
74
121
  if (gl.loading) return // MEMO: loading after build node
75
122
  if (needsUpdate) update()
76
123
  needsUpdate = false
77
124
  const encoder = device.createCommandEncoder()
125
+ if (comp) computeFlush(encoder.beginComputePass())
78
126
  flush(encoder.beginRenderPass(createDescriptor(context, depthTexture)))
79
127
  device.queue.submit([encoder.finish()])
80
128
  }
@@ -91,41 +139,19 @@ export const webgpu = async (gl: GL) => {
91
139
  for (const { texture } of textures.map.values()) texture.destroy()
92
140
  for (const { buffer } of uniforms.map.values()) buffer.destroy()
93
141
  for (const { buffer } of attribs.map.values()) buffer.destroy()
94
- }
95
-
96
- const _attribute = (key = '', value: number[]) => {
97
- const { array, buffer } = attribs(key, value)
98
- array.set(value)
99
- device.queue.writeBuffer(buffer, 0, array)
100
- }
101
-
102
- const _uniform = (key: string, value: number | number[]) => {
103
- if (is.num(value)) value = [value]
104
- const { array, buffer } = uniforms(key, value)
105
- array.set(value)
106
- device.queue.writeBuffer(buffer, 0, array)
107
- }
108
-
109
- const _texture = (key: string, src: string) => {
110
- gl.loading++
111
- const source = Object.assign(new Image(), { src, crossOrigin: 'anonymous' })
112
- source.decode().then(() => {
113
- const { width, height } = source
114
- const { texture } = textures(key, width, height)
115
- device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
116
- gl.loading--
117
- })
142
+ for (const { buffer } of storages.map.values()) buffer.destroy()
118
143
  }
119
144
 
120
145
  resize()
121
146
 
122
147
  return {
123
- webgpu: { device, uniforms, textures, attribs } as WebGPUState,
148
+ webgpu: { device, uniforms, textures, attribs, storages } as WebGPUState,
124
149
  render,
125
150
  resize,
126
151
  clean,
127
152
  _attribute,
128
153
  _uniform,
129
154
  _texture,
155
+ _storage,
130
156
  }
131
157
  }
File without changes