glre 0.32.0 → 0.33.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/node/scope.ts CHANGED
@@ -36,6 +36,16 @@ export const Return = (x: X) => {
36
36
  return y
37
37
  }
38
38
 
39
+ // Struct functions
40
+ export const struct = (fields: Record<string, NodeProxy>, id = getId()) => {
41
+ return (initialValues: Record<string, NodeProxy> = {}, instanceId = getId()) => {
42
+ const x = node('variable', { id: instanceId, inferFrom: [id] })
43
+ const y = node('struct', { id, fields, initialValues }, x)
44
+ addToScope(y)
45
+ return x
46
+ }
47
+ }
48
+
39
49
  const scoped = (x: NodeProxy, fun: () => NodeProxy | void, y = define) => {
40
50
  // cache to revert
41
51
  const _scope = scope
@@ -98,7 +108,6 @@ export const Switch = (x: X) => {
98
108
  switchNode.props.children!.push(scope)
99
109
  },
100
110
  })
101
-
102
111
  return ret()
103
112
  }
104
113
 
@@ -122,9 +131,6 @@ export const Fn = (fun: (paramVars: NodeProxy[]) => NodeProxy) => {
122
131
  scoped(x, () => fun(paramVars), y)
123
132
  return y
124
133
  }
125
- ret.setLayout = (newLayout: FnLayout) => {
126
- layout = newLayout
127
- return ret
128
- }
134
+ ret.setLayout = (_layout: FnLayout) => void (layout = _layout)
129
135
  return ret
130
136
  }
package/src/node/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { WebGPUState } from '../types'
1
+ import { GL } from '../types'
2
2
  import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS } from './const'
3
3
 
4
4
  export type Constants = (typeof CONSTANTS)[number] | 'void'
@@ -29,12 +29,14 @@ export type NodeTypes =
29
29
  // variables
30
30
  | 'variable'
31
31
  | 'varying'
32
- | 'swizzle'
33
32
  | 'ternary'
34
33
  | 'builtin'
35
34
  | 'conversion'
36
35
  | 'operator'
37
36
  | 'function'
37
+ // struct
38
+ | 'struct'
39
+ | 'member'
38
40
  // scopes
39
41
  | 'scope'
40
42
  | 'assign'
@@ -53,20 +55,26 @@ export interface NodeProps {
53
55
  inferFrom?: X[]
54
56
  layout?: FnLayout
55
57
  parent?: NodeProxy
58
+ // for struct
59
+ fields?: Record<string, NodeProxy>
60
+ initialValues?: Record<string, NodeProxy>
56
61
  }
57
62
 
58
63
  export interface NodeContext {
64
+ gl?: Partial<GL>
59
65
  isFrag?: boolean
60
66
  isWebGL?: boolean
61
67
  binding?: number
62
68
  infers?: WeakMap<NodeProxy, Constants>
63
69
  onMount?: (name: string) => void
64
- webgpu?: WebGPUState
65
- headers?: Map<string, string>
66
- fragInputs?: Map<string, string>
67
- vertInputs?: Map<string, string>
68
- vertOutputs?: Map<string, string>
69
- vertVaryings?: Map<string, string>
70
+ code?: {
71
+ headers: Map<string, string>
72
+ fragInputs: Map<string, string>
73
+ vertInputs: Map<string, string>
74
+ vertOutputs: Map<string, string>
75
+ vertVaryings: Map<string, string>
76
+ dependencies: Map<string, Set<string>>
77
+ }
70
78
  }
71
79
 
72
80
  /**
@@ -93,8 +101,8 @@ type NodeProxyMethods =
93
101
  | 'toVar'
94
102
  | 'toString'
95
103
 
96
- export type DynamicProperties = {
97
- [K in string as K extends NodeProxyMethods ? never : K]: NodeProxy
104
+ export type ReadNodeProxy = {
105
+ [K in string as K extends NodeProxyMethods ? never : K]: X
98
106
  }
99
107
 
100
108
  export interface BaseNodeProxy extends Record<Swizzles, NodeProxy> {
@@ -105,6 +113,7 @@ export interface BaseNodeProxy extends Record<Swizzles, NodeProxy> {
105
113
  type: NodeTypes
106
114
  props: NodeProps
107
115
  isProxy: true
116
+ listeners: Set<(value: any) => void>
108
117
 
109
118
  // Operators methods
110
119
  add(n: X): NodeProxy
@@ -191,6 +200,6 @@ export interface BaseNodeProxy extends Record<Swizzles, NodeProxy> {
191
200
  fwidth(): NodeProxy
192
201
  }
193
202
 
194
- export type NodeProxy = BaseNodeProxy & DynamicProperties
203
+ export type NodeProxy = BaseNodeProxy & ReadNodeProxy
195
204
 
196
- export type X = NodeProxy | number | string | boolean | undefined
205
+ export type X = X[] | (NodeProxy | number | string | boolean | undefined)
package/src/node/utils.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { is } from '../utils/helpers'
2
- import { code } from './code'
3
2
  import {
4
3
  CONSTANTS,
5
4
  CONVERSIONS,
@@ -33,10 +32,9 @@ export const isNodeProxy = (x: unknown): x is NodeProxy => {
33
32
  return x.isProxy
34
33
  }
35
34
 
36
- export const isConstantsType = (type?: Constants | 'auto'): type is Constants => {
37
- if (!type) return false
38
- if (type === 'auto') return false
39
- return true
35
+ export const isConstants = (type?: unknown): type is Constants => {
36
+ if (!is.str(type)) return false
37
+ return CONSTANTS.includes(type)
40
38
  }
41
39
 
42
40
  export const hex2rgb = (hex: number) => {
@@ -50,17 +48,10 @@ let count = 0
50
48
 
51
49
  export const getId = () => `i${count++}`
52
50
 
53
- export const joins = (children: X[], c: NodeContext) => {
54
- return children
55
- .filter((x) => !is.und(x) && !is.nul(x))
56
- .map((x) => code(x, c))
57
- .join(', ')
58
- }
59
-
60
51
  export const formatConversions = (x: X, c?: NodeContext) => {
61
52
  if (!is.str(x)) return ''
62
53
  if (c?.isWebGL) return x
63
- return TYPE_MAPPING[x as keyof typeof TYPE_MAPPING]
54
+ return TYPE_MAPPING[x as keyof typeof TYPE_MAPPING] || x // for struct type
64
55
  }
65
56
 
66
57
  export const getOperator = (op: X) => {
@@ -75,3 +66,64 @@ export const conversionToConstant = (conversionKey: string): Constants => {
75
66
  const index = CONVERSIONS.indexOf(conversionKey as Conversions)
76
67
  return index !== -1 ? CONSTANTS[index] : 'float'
77
68
  }
69
+
70
+ export const getEventFun = (c: NodeContext, id: string, isAttribute = false, isTexture = false) => {
71
+ if (c.isWebGL) {
72
+ if (isAttribute) return (value: any) => c.gl?.attribute?.(id, value)
73
+ if (isTexture) return (value: any) => c.gl?.texture?.(id, value)
74
+ return (value: any) => c.gl?.uniform?.(id, value)
75
+ }
76
+ if (isAttribute) return (value: any) => c.gl?._attribute?.(id, value)
77
+ if (isTexture) return (value: any) => c.gl?._texture?.(id, value)
78
+ return (value: any) => c.gl?._uniform?.(id, value)
79
+ }
80
+
81
+ export const safeEventCall = (x: X, fun: (value: unknown) => void) => {
82
+ if (!x) return
83
+ if (!isNodeProxy(x)) return fun(x) // for uniform(1)
84
+ if (x.type !== 'conversion') return
85
+ const value = x.props.children?.slice(1).filter(Boolean)
86
+ if (!value?.length) return // for uniform(vec2())
87
+ fun(value)
88
+ }
89
+
90
+ export const initNodeContext = (c: NodeContext) => {
91
+ if (!c.code) {
92
+ c.code = {
93
+ headers: new Map(),
94
+ fragInputs: new Map(),
95
+ vertInputs: new Map(),
96
+ vertOutputs: new Map(),
97
+ vertVaryings: new Map(),
98
+ dependencies: new Map(),
99
+ }
100
+ if (!c.isWebGL) {
101
+ c.code.fragInputs.set('position', '@builtin(position) position: vec4f')
102
+ c.code.vertOutputs.set('position', '@builtin(position) position: vec4f')
103
+ }
104
+ }
105
+ return c
106
+ }
107
+
108
+ export const addDependency = (c: NodeContext, id = '', type: string) => {
109
+ if (!c.code?.dependencies?.has(id)) c.code!.dependencies.set(id, new Set())
110
+ if (!isConstants(type)) c.code!.dependencies.get(id)!.add(type)
111
+ }
112
+
113
+ export const sortHeadersByDependencies = (headers: Map<string, string>, dependencies: Map<string, Set<string>>) => {
114
+ const sorted: [string, string][] = []
115
+ const visited = new Set<string>()
116
+ const visiting = new Set<string>()
117
+ const visit = (id: string) => {
118
+ if (visiting.has(id)) return
119
+ if (visited.has(id)) return
120
+ visiting.add(id)
121
+ const deps = dependencies.get(id) || new Set()
122
+ for (const dep of deps) if (headers.has(dep)) visit(dep)
123
+ visiting.delete(id)
124
+ visited.add(id)
125
+ if (headers.has(id)) sorted.push([id, headers.get(id)!])
126
+ }
127
+ for (const [id] of headers) visit(id)
128
+ return sorted
129
+ }
package/src/types.ts CHANGED
@@ -26,6 +26,7 @@ export interface TextureData {
26
26
  group: number
27
27
  texture: GPUTexture
28
28
  sampler: GPUSampler
29
+ view: GPUTextureView
29
30
  }
30
31
 
31
32
  export interface AttribData {
@@ -1,7 +1,4 @@
1
- import { fragment, vertex } from '../node'
2
- import type { X } from '../node'
3
- import type { AttribData, TextureData, UniformData, WebGPUState } from '../types'
4
- import { is } from './helpers'
1
+ import type { AttribData, TextureData, UniformData } from '../types'
5
2
 
6
3
  /**
7
4
  * initialize
@@ -41,31 +38,82 @@ export const createBindings = () => {
41
38
  }
42
39
  }
43
40
 
41
+ /**
42
+ * pipeline update
43
+ */
44
+ const getVertexFormat = (stride: number): GPUVertexFormat => {
45
+ if (stride === 2) return 'float32x2'
46
+ if (stride === 3) return 'float32x3'
47
+ if (stride === 4) return 'float32x4'
48
+ return 'float32'
49
+ }
50
+
51
+ export const createVertexBuffers = (attribs: Iterable<AttribData>) => {
52
+ const vertexBuffers: GPUBuffer[] = []
53
+ const bufferLayouts: GPUVertexBufferLayout[] = []
54
+ for (const { buffer, location, stride } of attribs) {
55
+ vertexBuffers[location] = buffer
56
+ bufferLayouts[location] = {
57
+ arrayStride: stride * 4,
58
+ attributes: [
59
+ {
60
+ shaderLocation: location,
61
+ offset: 0,
62
+ format: getVertexFormat(stride),
63
+ },
64
+ ],
65
+ }
66
+ }
67
+ return { vertexBuffers, bufferLayouts }
68
+ }
69
+
70
+ export const createBindGroup = (
71
+ device: GPUDevice,
72
+ uniforms: Iterable<UniformData>,
73
+ textures: Iterable<TextureData>
74
+ ) => {
75
+ const groups = new Map<number, { layouts: GPUBindGroupLayoutEntry[]; bindings: GPUBindGroupEntry[] }>()
76
+ const ret = { bindGroups: [] as GPUBindGroup[], bindGroupLayouts: [] as GPUBindGroupLayout[] }
77
+ const add = (i: number, layout: GPUBindGroupLayoutEntry, binding: GPUBindGroupEntry) => {
78
+ if (!groups.has(i)) groups.set(i, { layouts: [], bindings: [] })
79
+ const { layouts, bindings } = groups.get(i)!
80
+ layouts.push(layout)
81
+ bindings.push(binding)
82
+ }
83
+ for (const { binding, buffer, group: i } of uniforms) {
84
+ add(i, { binding, visibility: 3, buffer: { type: 'uniform' } }, { binding, resource: { buffer } })
85
+ }
86
+ for (const { binding: b, group: i, sampler, view } of textures) {
87
+ add(i, { binding: b, visibility: 2, sampler: {} }, { binding: b, resource: sampler })
88
+ add(i, { binding: b + 1, visibility: 2, texture: {} }, { binding: b + 1, resource: view })
89
+ }
90
+ for (const [i, { layouts, bindings }] of groups) {
91
+ ret.bindGroupLayouts[i] = device.createBindGroupLayout({ entries: layouts })
92
+ ret.bindGroups[i] = device.createBindGroup({ layout: ret.bindGroupLayouts[i], entries: bindings })
93
+ }
94
+ return ret
95
+ }
96
+
44
97
  export const createPipeline = (
45
98
  device: GPUDevice,
46
99
  format: GPUTextureFormat,
47
100
  bufferLayouts: GPUVertexBufferLayout[],
48
101
  bindGroupLayouts: GPUBindGroupLayout[],
49
- webgpu: WebGPUState,
50
- vs: string | X,
51
- fs: string | X
102
+ vs: string,
103
+ fs: string
52
104
  ) => {
53
- const config = { isWebGL: false, webgpu }
54
- if (!is.str(fs)) fs = fragment(fs, config)
55
- if (!is.str(vs)) vs = vertex(vs, config)
56
- const layout = device.createPipelineLayout({ bindGroupLayouts })
57
105
  return device.createRenderPipeline({
58
106
  vertex: {
59
- module: device.createShaderModule({ code: vs.trim() }),
107
+ module: device.createShaderModule({ label: 'vert', code: vs }),
60
108
  entryPoint: 'main',
61
109
  buffers: bufferLayouts,
62
110
  },
63
111
  fragment: {
64
- module: device.createShaderModule({ code: fs.trim() }),
112
+ module: device.createShaderModule({ label: 'frag', code: fs }),
65
113
  entryPoint: 'main',
66
114
  targets: [{ format }],
67
115
  },
68
- layout,
116
+ layout: device.createPipelineLayout({ bindGroupLayouts }),
69
117
  primitive: { topology: 'triangle-list' },
70
118
  depthStencil: {
71
119
  depthWriteEnabled: true,
@@ -91,39 +139,6 @@ export const createAttribBuffer = (device: GPUDevice, value: number[]) => {
91
139
  return { array, buffer }
92
140
  }
93
141
 
94
- /**
95
- * uniforms
96
- */
97
- export const createBindGroup = (
98
- device: GPUDevice,
99
- uniforms: Map<string, UniformData>,
100
- textures: Map<string, TextureData>
101
- ) => {
102
- const groups = new Map<number, any>()
103
- const getGroup = (i = 0) => {
104
- if (!groups.has(i)) groups.set(i, { entries0: [], entries1: [] })
105
- return groups.get(i)
106
- }
107
- for (const { binding, buffer, group: i } of uniforms.values()) {
108
- const { entries0, entries1 } = getGroup(i)
109
- entries0.push({ binding, visibility: 3, buffer: { type: 'uniform' } })
110
- entries1.push({ binding, resource: { buffer } })
111
- }
112
- for (const { binding, group: i, sampler, texture } of textures.values()) {
113
- const { entries0, entries1 } = getGroup(i)
114
- entries0.push({ binding, visibility: 2, sampler: {} })
115
- entries0.push({ binding: binding + 1, visibility: 2, texture: {} })
116
- entries1.push({ binding, resource: sampler })
117
- entries1.push({ binding: binding + 1, resource: texture.createView() })
118
- }
119
- const ret = { bindGroups: [] as GPUBindGroup[], bindGroupLayouts: [] as GPUBindGroupLayout[] }
120
- for (const [i, { entries0, entries1 }] of groups) {
121
- ret.bindGroupLayouts[i] = device.createBindGroupLayout({ entries: entries0 })
122
- ret.bindGroups[i] = device.createBindGroup({ layout: ret.bindGroupLayouts[i], entries: entries1 })
123
- }
124
- return ret
125
- }
126
-
127
142
  export const createDescriptor = (c: GPUCanvasContext, depthTexture: GPUTexture) => {
128
143
  return {
129
144
  colorAttachments: [
@@ -143,6 +158,9 @@ export const createDescriptor = (c: GPUCanvasContext, depthTexture: GPUTexture)
143
158
  } as GPURenderPassDescriptor
144
159
  }
145
160
 
161
+ /**
162
+ * textures
163
+ */
146
164
  export const createTextureSampler = (device: GPUDevice, width = 1280, height = 800) => {
147
165
  const texture = device.createTexture({ size: [width, height], format: 'rgba8unorm', usage: 22 }) // 22 is GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
148
166
  const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' })
@@ -156,32 +174,3 @@ export const createDepthTexture = (device: GPUDevice, width: number, height: num
156
174
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
157
175
  })
158
176
  }
159
-
160
- /**
161
- * attribs
162
- */
163
- const getVertexFormat = (stride: number): GPUVertexFormat => {
164
- if (stride === 2) return 'float32x2'
165
- if (stride === 3) return 'float32x3'
166
- if (stride === 4) return 'float32x4'
167
- return 'float32'
168
- }
169
-
170
- export const createVertexBuffers = (attribs: Map<string, AttribData>) => {
171
- const vertexBuffers: GPUBuffer[] = []
172
- const bufferLayouts: GPUVertexBufferLayout[] = []
173
- for (const [, { buffer, location, stride }] of attribs) {
174
- vertexBuffers[location] = buffer
175
- bufferLayouts[location] = {
176
- arrayStride: stride * 4,
177
- attributes: [
178
- {
179
- shaderLocation: location,
180
- offset: 0,
181
- format: getVertexFormat(stride),
182
- },
183
- ],
184
- }
185
- }
186
- return { vertexBuffers, bufferLayouts }
187
- }
@@ -1,7 +1,3 @@
1
- import { fragment, vertex } from '../node'
2
- import type { X } from '../node'
3
- import { is } from './helpers'
4
-
5
1
  const createShader = (c: WebGLRenderingContext, source: string, type: number) => {
6
2
  const shader = c.createShader(type)
7
3
  if (!shader) throw new Error('Failed to create shader')
@@ -13,22 +9,19 @@ const createShader = (c: WebGLRenderingContext, source: string, type: number) =>
13
9
  console.warn(`Could not compile shader: ${error}`)
14
10
  }
15
11
 
16
- export const createProgram = (c: WebGLRenderingContext, vs: X, fs: string | X, onError = () => {}, gl?: any) => {
17
- const config = { isWebGL: true, gl }
18
- if (!is.str(fs)) fs = fragment(fs, config)
19
- if (!is.str(vs)) vs = vertex(vs, config)
12
+ export const createProgram = (c: WebGLRenderingContext, vert: string, frag: string, onError = () => {}) => {
20
13
  const pg = c.createProgram()
21
- const _vs = createShader(c, vs, c.VERTEX_SHADER)
22
- const _fs = createShader(c, fs, c.FRAGMENT_SHADER)
23
- if (!_vs || !_fs) return onError()
24
- c.attachShader(pg, _vs)
25
- c.attachShader(pg, _fs)
14
+ const fs = createShader(c, frag, c.FRAGMENT_SHADER)
15
+ const vs = createShader(c, vert, c.VERTEX_SHADER)
16
+ if (!fs || !vs) return onError()
17
+ c.attachShader(pg, vs)
18
+ c.attachShader(pg, fs)
26
19
  c.linkProgram(pg)
27
20
  if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
28
21
  const error = c.getProgramInfoLog(pg)
29
22
  c.deleteProgram(pg)
30
23
  onError()
31
- console.warn(`Could not link pg: ${error}`)
24
+ console.warn(`Could not link program: ${error}`)
32
25
  }
33
26
 
34
27
  export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
package/src/webgl.ts CHANGED
@@ -1,12 +1,17 @@
1
1
  import { nested as cached } from 'reev'
2
+ import { fragment, vertex } from './node'
2
3
  import { is } from './utils/helpers'
3
4
  import { createAttrib, createIbo, createProgram, createTexture, createVbo, getStride } from './utils/program'
4
5
  import type { GL, WebGLState } from './types'
5
6
 
6
7
  export const webgl = async (gl: Partial<GL>) => {
7
8
  const c = gl.el!.getContext('webgl2')!
8
- const pg = createProgram(c, gl.vs, gl.fs, () => void (gl.isLoop = false), gl)!
9
+ const config = { isWebGL: true, gl }
10
+ const fs = fragment(gl.fs, config)
11
+ const vs = vertex(gl.vs, config)
12
+ const pg = createProgram(c, vs, fs, () => void (gl.isLoop = false))!
9
13
  c.useProgram(pg)
14
+
10
15
  let _activeUnit = 0
11
16
  const uniforms = cached((key) => c.getUniformLocation(pg, key))
12
17
  const attribs = cached((key) => c.getAttribLocation(pg, key))
package/src/webgpu.ts CHANGED
@@ -2,8 +2,8 @@ import { nested as cached } from 'reev'
2
2
  import { is } from './utils/helpers'
3
3
  import {
4
4
  createAttribBuffer,
5
- createBindGroup,
6
5
  createBindings,
6
+ createBindGroup,
7
7
  createDepthTexture,
8
8
  createDescriptor,
9
9
  createDevice,
@@ -13,28 +13,31 @@ import {
13
13
  createVertexBuffers,
14
14
  } from './utils/pipeline'
15
15
  import type { GL, WebGPUState } from './types'
16
+ import { fragment, vertex } from './node'
16
17
 
17
18
  export const webgpu = async (gl: Partial<GL>) => {
18
- const c = gl.el!.getContext('webgpu') as GPUCanvasContext
19
- const { device, format } = await createDevice(c)
19
+ const context = gl.el!.getContext('webgpu') as GPUCanvasContext
20
+ const { device, format } = await createDevice(context)
20
21
  const bindings = createBindings()
22
+ let frag: string
23
+ let vert: string
24
+ let flush = (_pass: GPURenderPassEncoder) => {}
21
25
  let imageLoading = 0
22
26
  let needsUpdate = true
23
27
  let depthTexture: GPUTexture
24
- let _render = (_pass: GPURenderPassEncoder) => {}
25
28
 
26
29
  const uniforms = cached((_key, value: number[]) => {
27
30
  needsUpdate = true
28
- const { group, binding } = bindings.uniform()
29
31
  const { array, buffer } = createUniformBuffer(device, value)
30
- return { array, buffer, binding, group }
32
+ const { binding, group } = bindings.uniform()
33
+ return { binding, group, array, buffer }
31
34
  })
32
35
 
33
- const textures = cached((_key, { width, height }: HTMLImageElement) => {
36
+ const textures = cached((_key, width = 0, height = 0) => {
34
37
  needsUpdate = true
35
- const { group, binding } = bindings.texture()
36
38
  const { texture, sampler } = createTextureSampler(device, width, height)
37
- return { texture, sampler, binding, group }
39
+ const { binding, group } = bindings.texture()
40
+ return { binding, group, texture, sampler, view: texture.createView() }
38
41
  })
39
42
 
40
43
  const attribs = cached((_key, value: number[]) => {
@@ -46,10 +49,14 @@ export const webgpu = async (gl: Partial<GL>) => {
46
49
  })
47
50
 
48
51
  const update = () => {
49
- const { vertexBuffers, bufferLayouts } = createVertexBuffers(attribs.map)
50
- const { bindGroups, bindGroupLayouts } = createBindGroup(device, uniforms.map, textures.map)
51
- const pipeline = createPipeline(device, format, bufferLayouts, bindGroupLayouts, webgpu, gl.vs, gl.fs)
52
- _render = (pass) => {
52
+ const { vertexBuffers, bufferLayouts } = createVertexBuffers(attribs.map.values())
53
+ const { bindGroups, bindGroupLayouts } = createBindGroup(
54
+ device,
55
+ uniforms.map.values(),
56
+ textures.map.values()
57
+ )
58
+ const pipeline = createPipeline(device, format, bufferLayouts, bindGroupLayouts, vert, frag)
59
+ flush = (pass) => {
53
60
  pass.setPipeline(pipeline)
54
61
  bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
55
62
  vertexBuffers.forEach((v, i) => pass.setVertexBuffer(i, v))
@@ -59,11 +66,16 @@ export const webgpu = async (gl: Partial<GL>) => {
59
66
  }
60
67
 
61
68
  const render = () => {
62
- if (imageLoading) return
69
+ if (!frag || !vert) {
70
+ const config = { isWebGL: false, gl }
71
+ frag = fragment(gl.fs, config)
72
+ vert = vertex(gl.vs, config)
73
+ }
74
+ if (imageLoading) return // MEMO: loading after build node
63
75
  if (needsUpdate) update()
64
76
  needsUpdate = false
65
77
  const encoder = device.createCommandEncoder()
66
- _render(encoder.beginRenderPass(createDescriptor(c, depthTexture)))
78
+ flush(encoder.beginRenderPass(createDescriptor(context, depthTexture)))
67
79
  device.queue.submit([encoder.finish()])
68
80
  }
69
81
 
@@ -94,19 +106,22 @@ export const webgpu = async (gl: Partial<GL>) => {
94
106
  imageLoading++
95
107
  const source = Object.assign(new Image(), { src, crossOrigin: 'anonymous' })
96
108
  source.decode().then(() => {
97
- const texture = textures(key, source)
98
- device.queue.copyExternalImageToTexture(
99
- { source },
100
- { texture: texture.texture },
101
- { width: source.width, height: source.height }
102
- )
109
+ const { width, height } = source
110
+ const { texture } = textures(key, width, height)
111
+ device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
103
112
  imageLoading--
104
113
  })
105
114
  }
106
115
 
107
116
  resize()
108
117
 
109
- const webgpu = { device, uniforms, textures, attribs } as WebGPUState
110
-
111
- return { webgpu, render, resize, clean, _attribute, _uniform, _texture }
118
+ return {
119
+ webgpu: { device, uniforms, textures, attribs } as WebGPUState,
120
+ render,
121
+ resize,
122
+ clean,
123
+ _attribute,
124
+ _uniform,
125
+ _texture,
126
+ }
112
127
  }