glre 0.44.0 → 0.46.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.
Files changed (52) hide show
  1. package/README.md +4 -26
  2. package/dist/addons.d.ts +41 -51
  3. package/dist/index.cjs +6 -6
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +43 -91
  6. package/dist/index.js +6 -6
  7. package/dist/index.js.map +1 -1
  8. package/dist/native.cjs +1 -1
  9. package/dist/native.cjs.map +1 -1
  10. package/dist/native.d.ts +51 -94
  11. package/dist/native.js +1 -1
  12. package/dist/native.js.map +1 -1
  13. package/dist/node.cjs +15 -15
  14. package/dist/node.cjs.map +1 -1
  15. package/dist/node.d.ts +41 -52
  16. package/dist/node.js +14 -14
  17. package/dist/node.js.map +1 -1
  18. package/dist/react.cjs +1 -1
  19. package/dist/react.cjs.map +1 -1
  20. package/dist/react.d.ts +43 -92
  21. package/dist/react.js +1 -1
  22. package/dist/react.js.map +1 -1
  23. package/dist/solid.cjs +1 -1
  24. package/dist/solid.cjs.map +1 -1
  25. package/dist/solid.d.ts +43 -92
  26. package/dist/solid.js +1 -1
  27. package/dist/solid.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/{utils/helpers.ts → helpers.ts} +10 -32
  30. package/src/index.ts +45 -42
  31. package/src/native.ts +6 -7
  32. package/src/node/build.ts +6 -21
  33. package/src/node/create.ts +2 -4
  34. package/src/node/index.ts +8 -20
  35. package/src/node/types.ts +9 -1
  36. package/src/node/utils/index.ts +5 -25
  37. package/src/node/utils/infer.ts +4 -12
  38. package/src/node/utils/parse.ts +18 -34
  39. package/src/node/utils/utils.ts +3 -11
  40. package/src/react.ts +9 -12
  41. package/src/solid.ts +3 -10
  42. package/src/types.ts +30 -22
  43. package/src/webgl/compute.ts +56 -0
  44. package/src/webgl/graphic.ts +65 -0
  45. package/src/webgl/index.ts +21 -0
  46. package/src/{utils/program.ts → webgl/utils.ts} +30 -8
  47. package/src/webgpu/compute.ts +39 -0
  48. package/src/webgpu/graphic.ts +89 -0
  49. package/src/webgpu/index.ts +42 -0
  50. package/src/{utils/pipeline.ts → webgpu/utils.ts} +75 -78
  51. package/src/utils/webgl.ts +0 -135
  52. package/src/utils/webgpu.ts +0 -178
@@ -1,53 +1,68 @@
1
- import { is, isFloat32 } from './helpers'
1
+ import { nested } from 'reev'
2
+ import { is, isFloat32 } from '../helpers'
2
3
  import type { AttribData, TextureData, UniformData, StorageData } from '../types'
3
4
 
5
+ type IAttribs = Iterable<AttribData & { isInstance?: boolean }>
6
+ type IUniforms = Iterable<UniformData>
7
+ type ITextures = Iterable<TextureData>
8
+ type IStorages = Iterable<StorageData>
9
+
10
+ /**
11
+ * binding
12
+ */
13
+ export const createBinding = () => {
14
+ let _uniform = 0
15
+ let _texture = 0
16
+ let _storage = 0
17
+ let _attrib = 0
18
+ const uniform = nested(() => {
19
+ const group = Math.floor(_uniform / 12)
20
+ const binding = _uniform % 12
21
+ _uniform++
22
+ return { group, binding }
23
+ })
24
+ const texture = nested(() => {
25
+ const baseGroup = Math.floor(_uniform / 12) + 1
26
+ const group = baseGroup + Math.floor(_texture / 6)
27
+ const binding = (_texture % 6) * 2
28
+ _texture++
29
+ return { group, binding }
30
+ })
31
+ const storage = nested(() => {
32
+ const baseGroup = Math.floor(_uniform / 12) + Math.floor(_texture / 6) + 2
33
+ const group = baseGroup + Math.floor(_storage / 12)
34
+ const binding = _storage % 12
35
+ _storage++
36
+ return { group, binding }
37
+ })
38
+ const attrib = nested(() => {
39
+ const location = _attrib
40
+ _attrib++
41
+ return { location }
42
+ })
43
+ return { uniform, texture, storage, attrib }
44
+ }
45
+
46
+ export type Binding = ReturnType<typeof createBinding>
47
+
4
48
  /**
5
49
  * initialize
6
50
  */
7
- export const createDevice = async (c: GPUCanvasContext, log = console.log) => {
51
+ export const createDevice = async (c: GPUCanvasContext, log = console.log, signal?: AbortSignal) => {
8
52
  const gpu = navigator.gpu
9
53
  const format = gpu.getPreferredCanvasFormat()
10
54
  const adapter = await gpu.requestAdapter()
55
+ if (signal?.aborted) throw new DOMException('Aborted', 'AbortError')
11
56
  const device = await adapter!.requestDevice()
57
+ if (signal?.aborted) {
58
+ device.destroy()
59
+ if (signal?.aborted) throw new DOMException('Aborted', 'AbortError')
60
+ }
12
61
  device.onuncapturederror = (e) => log(e.error.message)
13
- c.configure({ device, format, alphaMode: 'opaque' })
62
+ c.configure({ device, format, alphaMode: 'premultiplied' })
14
63
  return { device, format }
15
64
  }
16
65
 
17
- export const createBindings = () => {
18
- let uniform = 0
19
- let texture = 0
20
- let storage = 0
21
- let attrib = 0
22
- return {
23
- uniform: () => {
24
- const group = Math.floor(uniform / 12)
25
- const binding = uniform % 12
26
- uniform++
27
- return { group, binding }
28
- },
29
- texture: () => {
30
- const baseGroup = Math.floor(uniform / 12) + 1
31
- const group = baseGroup + Math.floor(texture / 6)
32
- const binding = (texture % 6) * 2
33
- texture++
34
- return { group, binding }
35
- },
36
- storage: () => {
37
- const baseGroup = Math.floor(uniform / 12) + Math.floor(texture / 6) + 2
38
- const group = baseGroup + Math.floor(storage / 12)
39
- const binding = storage % 12
40
- storage++
41
- return { group, binding }
42
- },
43
- attrib: () => {
44
- const location = attrib
45
- attrib++
46
- return { location }
47
- },
48
- }
49
- }
50
-
51
66
  /**
52
67
  * pipeline update
53
68
  */
@@ -58,7 +73,7 @@ const getVertexFormat = (stride: number): GPUVertexFormat => {
58
73
  return 'float32'
59
74
  }
60
75
 
61
- export const createVertexBuffers = (attribs: Iterable<AttribData & { isInstance?: boolean }>) => {
76
+ const createVertexBuffers = (attribs: IAttribs) => {
62
77
  const vertexBuffers: GPUBuffer[] = []
63
78
  const bufferLayouts: GPUVertexBufferLayout[] = []
64
79
  for (const { buffer, location, stride, isInstance } of attribs) {
@@ -80,12 +95,7 @@ export const createVertexBuffers = (attribs: Iterable<AttribData & { isInstance?
80
95
  return { vertexBuffers, bufferLayouts }
81
96
  }
82
97
 
83
- export const createBindGroup = (
84
- device: GPUDevice,
85
- uniforms: Iterable<UniformData>,
86
- textures: Iterable<TextureData>,
87
- storages: Iterable<StorageData> = []
88
- ) => {
98
+ const createBindGroup = (device: GPUDevice, uniforms: IUniforms, textures: ITextures, storages: IStorages = []) => {
89
99
  const groups = new Map<number, { layouts: GPUBindGroupLayoutEntry[]; bindings: GPUBindGroupEntry[] }>()
90
100
  const ret = { bindGroups: [] as GPUBindGroup[], bindGroupLayouts: [] as GPUBindGroupLayout[] }
91
101
  const add = (i: number, layout: GPUBindGroupLayoutEntry, binding: GPUBindGroupEntry) => {
@@ -111,14 +121,7 @@ export const createBindGroup = (
111
121
  return ret
112
122
  }
113
123
 
114
- export const createPipeline = (
115
- device: GPUDevice,
116
- format: GPUTextureFormat,
117
- bufferLayouts: GPUVertexBufferLayout[],
118
- bindGroupLayouts: GPUBindGroupLayout[],
119
- vs: string,
120
- fs: string
121
- ) => {
124
+ const createPipeline = (device: GPUDevice, format: GPUTextureFormat, bufferLayouts: GPUVertexBufferLayout[], bindGroupLayouts: GPUBindGroupLayout[], vs: string, fs: string) => {
122
125
  return device.createRenderPipeline({
123
126
  vertex: {
124
127
  module: device.createShaderModule({ label: 'vert', code: vs.trim() }),
@@ -140,7 +143,8 @@ export const createPipeline = (
140
143
  })
141
144
  }
142
145
 
143
- export const createComputePipeline = (device: GPUDevice, bindGroupLayouts: GPUBindGroupLayout[], cs: string) => {
146
+ const createComputePipeline = (device: GPUDevice, bindGroupLayouts: GPUBindGroupLayout[], cs: string) => {
147
+ if (!cs) return
144
148
  return device.createComputePipeline({
145
149
  compute: {
146
150
  module: device.createShaderModule({ label: 'compute', code: cs.trim() }),
@@ -150,6 +154,14 @@ export const createComputePipeline = (device: GPUDevice, bindGroupLayouts: GPUBi
150
154
  })
151
155
  }
152
156
 
157
+ export const updatePipeline = (device: GPUDevice, format: GPUTextureFormat, attribs: IAttribs, uniforms: IUniforms, textures: ITextures, storages: IStorages, fs: string, cs: string, vs: string) => {
158
+ const { vertexBuffers, bufferLayouts } = createVertexBuffers(attribs)
159
+ const { bindGroups, bindGroupLayouts } = createBindGroup(device, uniforms, textures, storages)
160
+ const computePipeline = createComputePipeline(device, bindGroupLayouts, cs)
161
+ const graphicPipeline = createPipeline(device, format, bufferLayouts, bindGroupLayouts, vs, fs)
162
+ return { bindGroups, vertexBuffers, computePipeline, graphicPipeline }
163
+ }
164
+
153
165
  /**
154
166
  * buffers
155
167
  */
@@ -159,11 +171,7 @@ const bufferUsage = (type: 'uniform' | 'storage' | 'attrib') => {
159
171
  return 140 // GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST
160
172
  }
161
173
 
162
- export const createArrayBuffer = (
163
- device: GPUDevice,
164
- array: number[] | Float32Array,
165
- type: 'uniform' | 'storage' | 'attrib'
166
- ) => {
174
+ export const createBuffer = (device: GPUDevice, array: number[] | Float32Array, type: 'uniform' | 'storage' | 'attrib') => {
167
175
  if (!isFloat32(array)) array = new Float32Array(array)
168
176
  const usage = bufferUsage(type)
169
177
  const size = type === 'uniform' ? Math.ceil(array.byteLength / 256) * 256 : array.byteLength
@@ -171,22 +179,15 @@ export const createArrayBuffer = (
171
179
  return { array, buffer }
172
180
  }
173
181
 
182
+ export const updateBuffer = (device: GPUDevice, value: number[] | Float32Array, array: Float32Array, buffer: GPUBuffer) => {
183
+ array.set(value)
184
+ device.queue.writeBuffer(buffer, 0, array as GPUAllowSharedBufferSource)
185
+ }
186
+
174
187
  export const createDescriptor = (c: GPUCanvasContext, depthTexture: GPUTexture) => {
175
188
  return {
176
- colorAttachments: [
177
- {
178
- view: c.getCurrentTexture().createView(),
179
- clearValue: { r: 0, g: 0, b: 0, a: 1 },
180
- loadOp: 'clear' as GPULoadOp,
181
- storeOp: 'store' as GPUStoreOp,
182
- },
183
- ],
184
- depthStencilAttachment: {
185
- view: depthTexture.createView(),
186
- depthClearValue: 1.0,
187
- depthLoadOp: 'clear' as GPULoadOp,
188
- depthStoreOp: 'store' as GPUStoreOp,
189
- },
189
+ colorAttachments: [{ view: c.getCurrentTexture().createView(), clearValue: { r: 0, g: 0, b: 0, a: 0 }, loadOp: 'clear', storeOp: 'store' }],
190
+ depthStencilAttachment: { view: depthTexture.createView(), depthClearValue: 1.0, depthLoadOp: 'clear', depthStoreOp: 'store' },
190
191
  } as GPURenderPassDescriptor
191
192
  }
192
193
 
@@ -196,15 +197,11 @@ export const createDescriptor = (c: GPUCanvasContext, depthTexture: GPUTexture)
196
197
  export const createTextureSampler = (device: GPUDevice, width = 1280, height = 800) => {
197
198
  const texture = device.createTexture({ size: [width, height], format: 'rgba8unorm', usage: 22 }) // 22 is GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
198
199
  const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' })
199
- return { texture, sampler }
200
+ return { texture, sampler, view: texture.createView() }
200
201
  }
201
202
 
202
203
  export const createDepthTexture = (device: GPUDevice, width: number, height: number) => {
203
- return device.createTexture({
204
- size: [width, height],
205
- format: 'depth24plus',
206
- usage: GPUTextureUsage.RENDER_ATTACHMENT,
207
- })
204
+ return device.createTexture({ size: [width, height], format: 'depth24plus', usage: 16 }) // 16 is GPUTextureUsage.RENDER_ATTACHMENT
208
205
  }
209
206
 
210
207
  /**
@@ -1,135 +0,0 @@
1
- import { nested as cached } from 'reev'
2
- import { is, getStride, GLSL_VS, GLSL_FS, loadingTexture } from './helpers'
3
- import { createArrayBuffer, cleanStorage, createAttachment, createProgram, createStorage, createTexture, setArrayBuffer, storageSize, updateAttrib, updateInstance, updateUniform } from './program'
4
- import type { GL } from '../types'
5
-
6
- const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
7
- if (!gl.cs) return null // ignore if no compute shader
8
- c.getExtension('EXT_color_buffer_float')
9
-
10
- let activeUnit = 0 // for texture units
11
- let currentNum = 0 // for storage buffers
12
-
13
- const units = cached(() => activeUnit++)
14
- const cs = is.str(gl.cs) ? gl.cs : gl.cs!.compute({ isWebGL: true, gl, units })
15
- const pg = createProgram(c, cs, GLSL_VS, gl)!
16
- const size = storageSize(gl.particleCount)
17
-
18
- const uniforms = cached((key) => c.getUniformLocation(pg, key)!)
19
- const storages = cached((key) => {
20
- const array = new Float32Array(size.x * size.y * 4) // RGBA texture data
21
- const ping = { texture: c.createTexture(), buffer: c.createFramebuffer() }
22
- const pong = { texture: c.createTexture(), buffer: c.createFramebuffer() }
23
- return { ping, pong, array, loc: uniforms(key), unit: units(key) }
24
- })
25
-
26
- const _uniform = (key: string, value: number | number[]) => {
27
- c.useProgram(pg)
28
- updateUniform(c, uniforms(key), value)
29
- }
30
-
31
- const _storage = (key: string, value: number[]) => {
32
- const { ping, pong, unit, array } = storages(key)
33
- createStorage(c, value, size.x, size.y, ping, pong, unit, array)
34
- }
35
-
36
- const clean = () => {
37
- c.deleteProgram(pg)
38
- cleanStorage(c, storages.map.values())
39
- }
40
-
41
- const render = () => {
42
- c.useProgram(pg)
43
- const attachments = storages.map.values().map(({ ping, pong, loc, unit }, index) => {
44
- const [i, o] = currentNum % 2 ? [ping, pong] : [pong, ping]
45
- return createAttachment(c, i, o, loc, unit, index)
46
- })
47
- c.drawBuffers(attachments)
48
- c.drawArrays(c.TRIANGLES, 0, 3)
49
- c.bindFramebuffer(c.FRAMEBUFFER, null)
50
- currentNum++
51
- }
52
-
53
- return { render, clean, _uniform, _storage, storages }
54
- }
55
-
56
- export const webgl = async (gl: GL) => {
57
- const config = { isWebGL: true, gl }
58
- const c = (gl.webgl.context = gl.el!.getContext('webgl2')!)
59
- const cp = computeProgram(gl, c)
60
- const fs = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs!.fragment(config)) : GLSL_FS
61
- const vs = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs!.vertex(config)) : GLSL_VS
62
- const pg = (gl.webgl.program = createProgram(c, fs, vs, gl)!)
63
- c.useProgram(pg)
64
-
65
- let activeUnit = 0 // for texture units
66
-
67
- const units = cached(() => activeUnit++)
68
- const uniforms = (gl.webgl.uniforms = cached((key) => c.getUniformLocation(pg, key)))
69
-
70
- const attribs = cached((key, value: number[], isInstance = false) => {
71
- const stride = getStride(value.length, isInstance ? gl.instanceCount : gl.count, gl.error)
72
- const location = c.getAttribLocation(pg, key)
73
- const { array, buffer } = createArrayBuffer(c, value)
74
- return { array, buffer, location, stride }
75
- })
76
-
77
- const _attribute = (key = '', value: number[]) => {
78
- const { array, buffer, location, stride } = attribs(key, value)
79
- setArrayBuffer(c, array, buffer, value)
80
- updateAttrib(c, location, stride, buffer)
81
- }
82
-
83
- const _instance = (key: string, value: number[]) => {
84
- const { array, buffer, location, stride } = attribs(key, value, true)
85
- setArrayBuffer(c, array, buffer, value)
86
- updateInstance(c, location, stride, buffer)
87
- }
88
-
89
- const _uniform = (key: string, value: number | number[]) => {
90
- c.useProgram(pg)
91
- updateUniform(c, uniforms(key)!, value)
92
- cp?._uniform(key, value)
93
- }
94
-
95
- const _texture = (key: string, src: string) => {
96
- gl.loading++
97
- c.useProgram(pg)
98
- loadingTexture(src, (source, isVideo) => {
99
- const unit = units(key)
100
- const loop = createTexture(c, source, uniforms(key)!, unit, isVideo)
101
- if (loop) gl({ loop })
102
- gl.loading--
103
- })
104
- }
105
-
106
- const clean = () => {
107
- cp?.clean()
108
- c.deleteProgram(pg)
109
- c.getExtension('WEBGL_lose_context')?.loseContext()
110
- }
111
-
112
- const render = () => {
113
- cp?.render()
114
- c.useProgram(pg)
115
- c.viewport(0, 0, ...gl.size)
116
- if (gl.instanceCount > 1) {
117
- c.drawArraysInstanced(c.TRIANGLES, 0, gl.count, gl.instanceCount)
118
- } else c.drawArrays(c.TRIANGLES, 0, gl.count)
119
- c.bindFramebuffer(c.FRAMEBUFFER, null)
120
- }
121
-
122
- if (gl.isDepth) {
123
- c.enable(c.DEPTH_TEST)
124
- c.depthFunc(c.LEQUAL)
125
- c.enable(c.CULL_FACE)
126
- c.cullFace(c.BACK)
127
- }
128
-
129
- if (gl.wireframe) {
130
- const ext = c.getExtension('WEBGL_polygon_mode')
131
- ext.polygonModeWEBGL(c.FRONT_AND_BACK, ext.LINE_WEBGL)
132
- }
133
-
134
- return { render, clean, _attribute, _instance, _uniform, _texture, _storage: cp?._storage }
135
- }
@@ -1,178 +0,0 @@
1
- import { nested as cached } from 'reev'
2
- import { is, getStride, WGSL_FS, WGSL_VS, loadingTexture } from './helpers'
3
- import {
4
- createArrayBuffer,
5
- createBindGroup,
6
- createBindings,
7
- createComputePipeline,
8
- createDepthTexture,
9
- createDescriptor,
10
- createDevice,
11
- createPipeline,
12
- createTextureSampler,
13
- createVertexBuffers,
14
- workgroupCount,
15
- } from './pipeline'
16
- import type { GL, WebGPUState } from '../types'
17
-
18
- const computeProgram = (gl: GL, device: GPUDevice, bindings: any) => {
19
- let flush = (_pass: GPUComputePassEncoder) => {}
20
-
21
- const storages = cached((_key, value: number[] | Float32Array) => {
22
- const { array, buffer } = createArrayBuffer(device, value, 'storage')
23
- const { binding, group } = bindings.storage()
24
- return { array, buffer, binding, group }
25
- })
26
-
27
- const _storage = (key: string, value: number[] | Float32Array) => {
28
- const { array, buffer } = storages(key, value)
29
- device.queue.writeBuffer(buffer, 0, array as any)
30
- }
31
-
32
- const update = (bindGroups: GPUBindGroup[], bindGroupLayouts: GPUBindGroupLayout[], comp: string) => {
33
- const pipeline = createComputePipeline(device, bindGroupLayouts, comp!)
34
- flush = (pass) => {
35
- pass.setPipeline(pipeline)
36
- bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
37
- const { x, y, z } = workgroupCount(gl.particleCount)
38
- pass.dispatchWorkgroups(x, y, z)
39
- pass.end()
40
- }
41
- }
42
-
43
- const render = (pass: GPUComputePassEncoder) => {
44
- flush(pass)
45
- }
46
-
47
- const clean = () => {
48
- for (const { buffer } of storages.map.values()) buffer.destroy()
49
- }
50
-
51
- return { storages, _storage, update, render, clean }
52
- }
53
-
54
- export const webgpu = async (gl: GL) => {
55
- const context = gl.el!.getContext('webgpu') as GPUCanvasContext
56
- const { device, format } = await createDevice(context, gl.error)
57
- const bindings = createBindings()
58
- const cp = computeProgram(gl, device, bindings)
59
- let frag: string
60
- let comp: string
61
- let vert: string
62
- let flush = (_pass: GPURenderPassEncoder) => {}
63
- let needsUpdate = true
64
- let depthTexture: GPUTexture
65
-
66
- const attribs = cached((_key, value: number[], isInstance = false) => {
67
- needsUpdate = true
68
- const stride = getStride(value.length, isInstance ? gl.instanceCount : gl.count)
69
- const { location } = bindings.attrib()
70
- const { array, buffer } = createArrayBuffer(device, value, 'attrib')
71
- return { array, buffer, location, stride, isInstance }
72
- })
73
-
74
- const uniforms = cached((_key, value: number[]) => {
75
- needsUpdate = true
76
- const { binding, group } = bindings.uniform()
77
- const { array, buffer } = createArrayBuffer(device, value, 'uniform')
78
- return { array, buffer, binding, group }
79
- })
80
-
81
- const textures = cached((_key, width = 0, height = 0) => {
82
- needsUpdate = true
83
- const { binding, group } = bindings.texture()
84
- const { texture, sampler } = createTextureSampler(device, width, height)
85
- return { texture, sampler, binding, group, view: texture.createView() }
86
- })
87
-
88
- const _attribute = (key = '', value: number[]) => {
89
- const { array, buffer } = attribs(key, value)
90
- array.set(value)
91
- device.queue.writeBuffer(buffer, 0, array as any)
92
- }
93
-
94
- const _instance = (key: string, value: number[]) => {
95
- const { array, buffer } = attribs(key, value, true)
96
- array.set(value)
97
- device.queue.writeBuffer(buffer, 0, array as any)
98
- }
99
-
100
- const _uniform = (key: string, value: number | number[]) => {
101
- if (is.num(value)) value = [value]
102
- const { array, buffer } = uniforms(key, value)
103
- array.set(value)
104
- device.queue.writeBuffer(buffer, 0, array as any)
105
- }
106
-
107
- const _texture = (key: string, src: string) => {
108
- gl.loading++
109
- loadingTexture(src, (source, isVideo) => {
110
- const [width, height] = isVideo
111
- ? [source.videoWidth, source.videoHeight]
112
- : [source.width, source.height]
113
- const { texture } = textures(key, width, height)
114
- const loop = () => {
115
- device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
116
- }
117
- loop()
118
- if (isVideo) gl({ loop })
119
- gl.loading--
120
- })
121
- }
122
-
123
- const update = () => {
124
- const { vertexBuffers, bufferLayouts } = createVertexBuffers(attribs.map.values())
125
- const { bindGroups, bindGroupLayouts } = createBindGroup(
126
- device,
127
- uniforms.map.values(),
128
- textures.map.values(),
129
- cp.storages.map.values()
130
- )
131
- const pipeline = createPipeline(device, format, bufferLayouts, bindGroupLayouts, vert, frag)
132
- flush = (pass) => {
133
- pass.setPipeline(pipeline)
134
- bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
135
- vertexBuffers.forEach((v, i) => pass.setVertexBuffer(i, v))
136
- pass.draw(gl.count, gl.instanceCount, 0, 0)
137
- pass.end()
138
- }
139
- if (gl.cs) cp.update(bindGroups, bindGroupLayouts, comp)
140
- }
141
-
142
- const render = () => {
143
- if (!frag || !vert) {
144
- const config = { isWebGL: false, gl }
145
- frag = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs.fragment(config)) : WGSL_FS
146
- vert = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs.vertex(config)) : WGSL_VS
147
- comp = gl.cs ? (is.str(gl.cs) ? gl.cs : gl.cs.compute(config)) : ''
148
- }
149
- if (gl.loading) return // MEMO: loading after build node
150
- if (needsUpdate) update()
151
- needsUpdate = false
152
- const encoder = device.createCommandEncoder()
153
- if (gl.cs) cp.render(encoder.beginComputePass())
154
- flush(encoder.beginRenderPass(createDescriptor(context, depthTexture)))
155
- device.queue.submit([encoder.finish()])
156
- }
157
-
158
- const resize = () => {
159
- const canvas = gl.el as HTMLCanvasElement
160
- depthTexture?.destroy()
161
- depthTexture = createDepthTexture(device, canvas.width, canvas.height)
162
- }
163
-
164
- const clean = () => {
165
- device.destroy()
166
- depthTexture?.destroy()
167
- for (const { texture } of textures.map.values()) texture.destroy()
168
- for (const { buffer } of uniforms.map.values()) buffer.destroy()
169
- for (const { buffer } of attribs.map.values()) buffer.destroy()
170
- cp.clean()
171
- }
172
-
173
- resize()
174
-
175
- const webgpu = { device, uniforms, textures, attribs, storages: cp.storages } as WebGPUState
176
-
177
- return { webgpu, render, resize, clean, _attribute, _instance, _uniform, _texture, _storage: cp._storage }
178
- }