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
package/src/types.ts CHANGED
@@ -1,6 +1,7 @@
1
- import type { EventState, Nested } from 'reev'
1
+ import type { EventState } from 'reev'
2
2
  import type { Queue, Frame } from 'refr'
3
3
  import type { Vec4, Void } from './node'
4
+ import type { Binding } from './webgpu/utils'
4
5
 
5
6
  export type GL = EventState<{
6
7
  /**
@@ -13,16 +14,17 @@ export type GL = EventState<{
13
14
  isDebug: boolean
14
15
  isDepth: boolean
15
16
  wireframe: boolean
16
- isGL: true
17
17
  width?: number
18
18
  height?: number
19
19
  size: [number, number]
20
20
  mouse: [number, number]
21
21
  count: number
22
+ triangleCount: number
22
23
  instanceCount: number
23
24
  particleCount: number | [number, number] | [number, number, number]
24
25
  precision: 'lowp' | 'mediump' | 'highp'
25
- loading: number
26
+ element?: HTMLCanvasElement
27
+ elem?: HTMLCanvasElement
26
28
  el: HTMLCanvasElement
27
29
  vs?: string | Vec4
28
30
  cs?: string | Void
@@ -33,12 +35,19 @@ export type GL = EventState<{
33
35
  vertex?: string | Vec4
34
36
  compute?: string | Void
35
37
  fragment?: string | Vec4
38
+ program: WebGLProgram
39
+ gl: WebGL2RenderingContext
40
+ gpu: GPUCanvasContext
41
+ device: GPUDevice
42
+ format: GPUTextureFormat
43
+ encoder: GPUCommandEncoder
44
+ binding: Binding
36
45
 
37
46
  /**
38
47
  * core state
39
48
  */
40
- webgpu: WebGPUState
41
- webgl: WebGLState
49
+ // webgpu: WebGPUState
50
+ // webgl: WebGLState
42
51
  queue: Queue
43
52
  frame: Frame
44
53
 
@@ -52,7 +61,6 @@ export type GL = EventState<{
52
61
  render(): void
53
62
  resize(e?: Event): void
54
63
  mousemove(e: MouseEvent): void
55
- loop(): void
56
64
 
57
65
  /**
58
66
  * setter
@@ -112,19 +120,19 @@ export interface StorageData {
112
120
  group: number
113
121
  }
114
122
 
115
- export interface WebGPUState {
116
- device: GPUDevice
117
- uniforms: Nested<UniformData>
118
- textures: Nested<TextureData>
119
- attribs: Nested<AttribData>
120
- storages: Nested<StorageData>
121
- }
122
-
123
- /**
124
- * for webgl
125
- */
126
- export interface WebGLState {
127
- context: WebGL2RenderingContext
128
- program: WebGLProgram
129
- uniforms: Nested<WebGLUniformLocation | null>
130
- }
123
+ // export interface WebGPUState {
124
+ // device: GPUDevice
125
+ // uniforms: Nested<UniformData>
126
+ // textures: Nested<TextureData>
127
+ // attribs: Nested<AttribData>
128
+ // storages: Nested<StorageData>
129
+ // }
130
+ //
131
+ // /**
132
+ // * for webgl
133
+ // */
134
+ // export interface WebGLState {
135
+ // context: WebGL2RenderingContext
136
+ // program: WebGLProgram
137
+ // uniforms: Nested<WebGLUniformLocation | null>
138
+ // }
@@ -0,0 +1,56 @@
1
+ import { nested } from 'reev'
2
+ import { cleanStorage, createAttachment, createProgram, createStorage, storageSize, updateUniform } from './utils'
3
+ import { GLSL_VS, is } from '../helpers'
4
+ import type { GL } from '../types'
5
+
6
+ export const compute = (gl: GL) => {
7
+ if (!gl.cs) return
8
+ const c = gl.gl
9
+ c.getExtension('EXT_color_buffer_float') // Enable high precision GPGPU by writing to float textures
10
+
11
+ let _texture = 0 // for texture active units
12
+ let _storage = 0 // for storage current num
13
+
14
+ const units = nested(() => _texture++)
15
+ const cs = is.str(gl.cs) ? gl.cs : gl.cs!.compute({ isWebGL: true, gl, units })
16
+ const pg = createProgram(c, cs, GLSL_VS, gl)!
17
+ const size = storageSize(gl.particleCount)
18
+
19
+ const uniforms = nested((key) => c.getUniformLocation(pg, key)!)
20
+ const storages = nested((key) => {
21
+ const array = new Float32Array(size.x * size.y * 4) // RGBA texture data
22
+ const ping = { texture: c.createTexture(), buffer: c.createFramebuffer() }
23
+ const pong = { texture: c.createTexture(), buffer: c.createFramebuffer() }
24
+ return { ping, pong, array, loc: uniforms(key), unit: units(key) }
25
+ })
26
+
27
+ gl('_uniform', (key: string, value: number | number[]) => {
28
+ c.useProgram((gl.program = pg))
29
+ updateUniform(c, uniforms(key), value)
30
+ })
31
+
32
+ gl('_storage', (key: string, value: number[]) => {
33
+ c.useProgram((gl.program = pg))
34
+ const { ping, pong, unit, array } = storages(key)
35
+ createStorage(c, value, size.x, size.y, ping, pong, unit, array)
36
+ })
37
+
38
+ gl('clean', () => {
39
+ c.deleteProgram(pg)
40
+ cleanStorage(c, storages.map.values())
41
+ })
42
+
43
+ gl('render', () => {
44
+ c.useProgram((gl.program = pg))
45
+ const attachments = storages.map.values().map(({ ping, pong, loc, unit }, index) => {
46
+ const [i, o] = _storage % 2 ? [ping, pong] : [pong, ping]
47
+ return createAttachment(c, i, o, loc, unit, index)
48
+ })
49
+ c.drawBuffers(attachments)
50
+ c.drawArrays(c.TRIANGLES, 0, 3)
51
+ c.bindFramebuffer(c.FRAMEBUFFER, null)
52
+ _storage++
53
+ })
54
+ }
55
+
56
+ export type WebGLCompute = ReturnType<typeof compute>
@@ -0,0 +1,65 @@
1
+ import { nested } from 'reev'
2
+ import { getStride, GLSL_FS, GLSL_VS, is, loadingTexture } from '../helpers'
3
+ import { createBuffer, createProgram, createTexture, updateAttrib, updateBuffer, updateInstance, updateUniform } from './utils'
4
+ import type { GL } from '../types'
5
+
6
+ export const graphic = (gl: GL) => {
7
+ const config = { isWebGL: true, gl }
8
+ const c = gl.gl
9
+ const fs = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs.fragment(config)) : GLSL_FS
10
+ const vs = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs.vertex(config)) : GLSL_VS
11
+ const pg = createProgram(c, fs, vs, gl)!
12
+ let activeUnit = 0
13
+
14
+ const units = nested(() => activeUnit++)
15
+ const uniforms = nested((key) => c.getUniformLocation(pg, key))
16
+ const attributes = nested((key, value: number[], isInstance = false) => {
17
+ const stride = getStride(value.length, isInstance ? gl.instanceCount : gl.triangleCount, gl.error)
18
+ return { stride, location: c.getAttribLocation(pg, key), ...createBuffer(c, value) }
19
+ })
20
+
21
+ gl('_attribute', (key: string, value: number[]) => {
22
+ c.useProgram((gl.program = pg))
23
+ const a = attributes(key, value)
24
+ updateBuffer(c, a.array, a.buffer, value)
25
+ updateAttrib(c, a.location, a.stride, a.buffer)
26
+ })
27
+
28
+ gl('_instance', (key: string, value: number[]) => {
29
+ c.useProgram((gl.program = pg))
30
+ const a = attributes(key, value, true)
31
+ updateBuffer(c, a.array, a.buffer, value)
32
+ updateInstance(c, a.location, a.stride, a.buffer)
33
+ })
34
+
35
+ gl('_uniform', (key: string, value: number | number[]) => {
36
+ c.useProgram((gl.program = pg))
37
+ updateUniform(c, uniforms(key), value)
38
+ })
39
+
40
+ gl('_texture', (key: string, src: string) => {
41
+ c.useProgram((gl.program = pg))
42
+ const location = uniforms(key)
43
+ const unit = units(key)
44
+ createTexture(c, null, location, unit, false)
45
+ loadingTexture(src, (source, isVideo) => {
46
+ c.useProgram((gl.program = pg))
47
+ const render = createTexture(c, source, location, unit, isVideo)
48
+ if (render) gl({ render })
49
+ })
50
+ })
51
+
52
+ gl('clean', () => {
53
+ c.deleteProgram(pg)
54
+ })
55
+
56
+ gl('render', () => {
57
+ c.useProgram((gl.program = pg))
58
+ if (gl.instanceCount > 1) {
59
+ c.drawArraysInstanced(c.TRIANGLES, 0, gl.triangleCount, gl.instanceCount)
60
+ } else c.drawArrays(c.TRIANGLES, 0, gl.triangleCount)
61
+ c.bindFramebuffer(c.FRAMEBUFFER, null)
62
+ })
63
+ }
64
+
65
+ export type WebGLGraphic = ReturnType<typeof graphic>
@@ -0,0 +1,21 @@
1
+ import { compute } from './compute'
2
+ import { graphic } from './graphic'
3
+ import { enableDepth, enableWireframe, loseContext } from './utils'
4
+ import type { GL } from '../types'
5
+
6
+ export const webgl = (gl: GL) => {
7
+ const isInit = !gl.gl
8
+ if (isInit) {
9
+ const c = (gl.gl = gl.el.getContext('webgl2')!)
10
+ gl('render', () => c.viewport(0, 0, ...gl.size!)) // Run before other renderers' events to prevent flickering
11
+ }
12
+
13
+ compute(gl)
14
+ graphic(gl)
15
+
16
+ if (isInit) {
17
+ gl('clean', () => loseContext(gl.gl))
18
+ if (gl.isDepth) enableDepth(gl.gl)
19
+ if (gl.wireframe) enableWireframe(gl.gl)
20
+ }
21
+ }
@@ -1,4 +1,4 @@
1
- import { is } from './helpers'
1
+ import { is } from '../helpers'
2
2
  import type { GL } from '../types'
3
3
 
4
4
  const createShader = (c: WebGL2RenderingContext, source: string, type: number, onError = console.warn) => {
@@ -26,13 +26,13 @@ export const createProgram = (c: WebGL2RenderingContext, frag: string, vert: str
26
26
  gl.error(`Could not link program: ${error}`)
27
27
  }
28
28
 
29
- export const createArrayBuffer = (c: WebGL2RenderingContext, data: number[]) => {
29
+ export const createBuffer = (c: WebGL2RenderingContext, data: number[]) => {
30
30
  const array = new Float32Array(data)
31
31
  const buffer = c.createBuffer()
32
32
  return { array, buffer }
33
33
  }
34
34
 
35
- export const setArrayBuffer = (c: WebGL2RenderingContext, array: Float32Array, buffer: WebGLBuffer, value: number[]) => {
35
+ export const updateBuffer = (c: WebGL2RenderingContext, array: Float32Array, buffer: WebGLBuffer, value: number[]) => {
36
36
  array.set(value)
37
37
  c.bindBuffer(c.ARRAY_BUFFER, buffer)
38
38
  c.bufferData(c.ARRAY_BUFFER, array, c.STATIC_DRAW)
@@ -52,7 +52,8 @@ export const updateInstance = (c: WebGL2RenderingContext, loc: number, stride: n
52
52
  c.vertexAttribDivisor(loc, 1) // divisor is 1
53
53
  }
54
54
 
55
- export const updateUniform = (c: WebGL2RenderingContext, loc: WebGLUniformLocation, value: number | number[]) => {
55
+ export const updateUniform = (c: WebGL2RenderingContext, loc: WebGLUniformLocation | null, value: number | number[]) => {
56
+ if (is.nul(loc)) return
56
57
  if (is.num(value)) return c.uniform1f(loc, value)
57
58
  let l = value.length
58
59
  if (l <= 4) return c[`uniform${l as 2}fv`](loc, value)
@@ -60,11 +61,15 @@ export const updateUniform = (c: WebGL2RenderingContext, loc: WebGLUniformLocati
60
61
  c[`uniformMatrix${l as 2}fv`](loc, false, value)
61
62
  }
62
63
 
63
- export const createTexture = (c: WebGL2RenderingContext, el: HTMLImageElement | HTMLVideoElement, loc: WebGLUniformLocation, unit: number, isVideo = false) => {
64
+ export const createTexture = (c: WebGL2RenderingContext, el: HTMLImageElement | HTMLVideoElement | null, loc: WebGLUniformLocation | null, unit: number, isVideo = false) => {
64
65
  const texture = c.createTexture()
65
66
  c.bindTexture(c.TEXTURE_2D, texture)
66
- c.texImage2D(c.TEXTURE_2D, 0, c.RGBA, c.RGBA, c.UNSIGNED_BYTE, el)
67
- if (!isVideo) c.generateMipmap(c.TEXTURE_2D)
67
+ if (el) {
68
+ c.texImage2D(c.TEXTURE_2D, 0, c.RGBA, c.RGBA, c.UNSIGNED_BYTE, el)
69
+ if (!isVideo) c.generateMipmap(c.TEXTURE_2D)
70
+ } else {
71
+ c.texImage2D(c.TEXTURE_2D, 0, c.RGBA, 1, 1, 0, c.RGBA, c.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 0]))
72
+ }
68
73
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.LINEAR)
69
74
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.LINEAR)
70
75
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
@@ -77,7 +82,7 @@ export const createTexture = (c: WebGL2RenderingContext, el: HTMLImageElement |
77
82
  return () => {
78
83
  c.activeTexture(c.TEXTURE0 + unit)
79
84
  c.bindTexture(c.TEXTURE_2D, texture)
80
- c.texImage2D(c.TEXTURE_2D, 0, c.RGBA, c.RGBA, c.UNSIGNED_BYTE, el)
85
+ c.texImage2D(c.TEXTURE_2D, 0, c.RGBA, c.RGBA, c.UNSIGNED_BYTE, el!)
81
86
  }
82
87
  }
83
88
 
@@ -149,3 +154,20 @@ export const storageSize = (particleCount: number | number[] = 1024) => {
149
154
  }
150
155
  return { x, y }
151
156
  }
157
+
158
+ export const loseContext = (c: WebGL2RenderingContext) => {
159
+ const ext = c.getExtension('WEBGL_lose_context')
160
+ if (ext) ext.loseContext()
161
+ }
162
+
163
+ export const enableDepth = (c: WebGL2RenderingContext) => {
164
+ c.enable(c.DEPTH_TEST)
165
+ c.depthFunc(c.LEQUAL)
166
+ c.enable(c.CULL_FACE)
167
+ c.cullFace(c.BACK)
168
+ }
169
+
170
+ export const enableWireframe = (c: WebGL2RenderingContext) => {
171
+ const ext = c.getExtension('WEBGL_polygon_mode')
172
+ if (ext) ext.polygonModeWEBGL(c.FRONT_AND_BACK, ext.LINE_WEBGL)
173
+ }
@@ -0,0 +1,39 @@
1
+ import { nested } from 'reev'
2
+ import { createBuffer, updateBuffer, workgroupCount } from './utils'
3
+ import type { Binding } from './utils'
4
+ import type { GL } from '../types'
5
+
6
+ export const compute = (gl: GL, bindings: Binding) => {
7
+ let pipeline: GPUComputePipeline | undefined
8
+ let bindGroups: GPUBindGroup[] | undefined
9
+
10
+ const storages = nested((key, value: number[] | Float32Array) => {
11
+ return { ...bindings.storage(key), ...createBuffer(gl.device, value, 'storage') }
12
+ })
13
+
14
+ gl('_storage', (key: string, value: number[] | Float32Array) => {
15
+ const { array, buffer } = storages(key, value)
16
+ updateBuffer(gl.device, value, array, buffer)
17
+ })
18
+
19
+ gl('render', () => {
20
+ if (!pipeline || !bindGroups) return
21
+ const pass = gl.encoder.beginComputePass()
22
+ pass.setPipeline(pipeline)
23
+ bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
24
+ const { x, y, z } = workgroupCount(gl.particleCount)
25
+ pass.dispatchWorkgroups(x, y, z)
26
+ pass.end()
27
+ })
28
+
29
+ gl('clean', () => {
30
+ for (const { buffer } of storages.map.values()) buffer.destroy()
31
+ })
32
+
33
+ const set = (_pipeline?: GPUComputePipeline, _bindGroups?: GPUBindGroup[]) => {
34
+ pipeline = _pipeline
35
+ bindGroups = _bindGroups
36
+ }
37
+
38
+ return { storages, set }
39
+ }
@@ -0,0 +1,89 @@
1
+ import { nested } from 'reev'
2
+ import { is, getStride, loadingTexture } from '../helpers'
3
+ import { createBuffer, createDepthTexture, createDescriptor, createTextureSampler, updateBuffer } from './utils'
4
+ import type { Binding } from './utils'
5
+ import type { GL } from '../types'
6
+
7
+ export const graphic = (gl: GL, bindings: Binding, update = () => {}) => {
8
+ let pipeline: GPURenderPipeline
9
+ let bindGroups: GPUBindGroup[]
10
+ let vertexBuffers: GPUBuffer[]
11
+ let depthTexture: GPUTexture
12
+
13
+ const attributes = nested((key, value: number[], isInstance = false, stride = getStride(value.length, isInstance ? gl.instanceCount : gl.triangleCount)) => {
14
+ update()
15
+ return { ...bindings.attrib(key), ...createBuffer(gl.device, value, 'attrib'), isInstance, stride }
16
+ })
17
+
18
+ const uniforms = nested((key, value: number[] | Float32Array) => {
19
+ update()
20
+ return { ...bindings.uniform(key), ...createBuffer(gl.device, value, 'uniform') }
21
+ })
22
+
23
+ const textures = nested((key, width = 1, height = 1) => {
24
+ update()
25
+ return { ...bindings.texture(key), ...createTextureSampler(gl.device, width, height) }
26
+ })
27
+
28
+ gl('_attribute', (key: string, value: number[] | Float32Array) => {
29
+ const a = attributes(key, value)
30
+ updateBuffer(gl.device, value, a.array, a.buffer)
31
+ })
32
+
33
+ gl('_instance', (key: string, value: number[] | Float32Array) => {
34
+ const a = attributes(key, value, true)
35
+ updateBuffer(gl.device, value, a.array, a.buffer)
36
+ })
37
+
38
+ gl('_uniform', (key: string, value: number | number[] | Float32Array) => {
39
+ if (is.num(value)) value = [value]
40
+ const u = uniforms(key, value)
41
+ updateBuffer(gl.device, value, u.array, u.buffer)
42
+ })
43
+
44
+ gl('_texture', (key: string, src: string) => {
45
+ const t = textures(key)
46
+ loadingTexture(src, (source, isVideo) => {
47
+ const [width, height] = isVideo ? [source.videoWidth, source.videoHeight] : [source.width, source.height]
48
+ if (t.texture.width !== width || t.texture.height !== height) {
49
+ t.texture.destroy()
50
+ Object.assign(t, createTextureSampler(gl.device, width, height))
51
+ update() // Rebuilding BindGroups because the texture size has changed
52
+ }
53
+ const render = () => void gl.device.queue.copyExternalImageToTexture({ source }, { texture: t.texture }, { width, height })
54
+ if (isVideo) gl({ render })
55
+ else render()
56
+ })
57
+ })
58
+
59
+ gl('render', () => {
60
+ if (!pipeline || !bindGroups || !vertexBuffers) return
61
+ const pass = gl.encoder.beginRenderPass(createDescriptor(gl.gpu, depthTexture))
62
+ pass.setPipeline(pipeline)
63
+ bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
64
+ vertexBuffers.forEach((v, i) => pass.setVertexBuffer(i, v))
65
+ pass.draw(gl.triangleCount, gl.instanceCount, 0, 0)
66
+ pass.end()
67
+ })
68
+
69
+ gl('resize', () => {
70
+ const canvas = gl.el as HTMLCanvasElement
71
+ depthTexture?.destroy()
72
+ depthTexture = createDepthTexture(gl.device, canvas.width, canvas.height)
73
+ })
74
+
75
+ gl('clean', () => {
76
+ depthTexture?.destroy()
77
+ for (const { buffer } of attributes.map.values()) buffer.destroy()
78
+ for (const { texture } of textures.map.values()) texture.destroy()
79
+ for (const { buffer } of uniforms.map.values()) buffer.destroy()
80
+ })
81
+
82
+ const set = (_pipeline: GPURenderPipeline, _bindGroups: GPUBindGroup[], _vertexBuffers: GPUBuffer[]) => {
83
+ pipeline = _pipeline
84
+ bindGroups = _bindGroups
85
+ vertexBuffers = _vertexBuffers
86
+ }
87
+
88
+ return { uniforms, textures, attributes, set }
89
+ }
@@ -0,0 +1,42 @@
1
+ import { compute } from './compute'
2
+ import { graphic } from './graphic'
3
+ import { createBinding, createDevice, updatePipeline } from './utils'
4
+ import { is, WGSL_FS, WGSL_VS } from '../helpers'
5
+ import type { GL } from '../types'
6
+
7
+ export const webgpu = async (gl: GL) => {
8
+ let isUpdate = false
9
+ const isInit = !gl.gl
10
+ if (isInit) {
11
+ const gpu = gl.el!.getContext('webgpu') as GPUCanvasContext
12
+ const { device, format } = await createDevice(gpu, gl.error)
13
+ gl({ device, format, gpu })
14
+ }
15
+
16
+ gl('render', () => {
17
+ if (isUpdate) update()
18
+ gl.encoder = gl.device.createCommandEncoder()
19
+ })
20
+
21
+ const binding = createBinding()
22
+ const c = compute(gl, binding)
23
+ const g = graphic(gl, binding, () => (isUpdate = true))
24
+ const update = () => {
25
+ isUpdate = false
26
+ const config = { isWebGL: false, gl, binding }
27
+ const fs = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs.fragment(config)) : WGSL_FS
28
+ const vs = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs.vertex(config)) : WGSL_VS
29
+ const cs = gl.cs ? (is.str(gl.cs) ? gl.cs : gl.cs.compute(config)) : ''
30
+ const p = updatePipeline(gl.device, gl.format, g.attributes.map.values(), g.uniforms.map.values(), g.textures.map.values(), c.storages.map.values(), fs, cs, vs)
31
+ c.set(p.computePipeline, p.bindGroups)
32
+ g.set(p.graphicPipeline, p.bindGroups, p.vertexBuffers)
33
+ }
34
+
35
+ gl('render', () => {
36
+ if (gl.encoder) gl.device.queue.submit([gl.encoder.finish()])
37
+ })
38
+
39
+ gl('clean', () => {
40
+ gl.device.destroy()
41
+ })
42
+ }