glre 0.31.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/types.ts CHANGED
@@ -1,16 +1,7 @@
1
- import { EventState } from 'reev'
1
+ import type { EventState, Nested } from 'reev'
2
2
  import type { Fun, Queue, Frame } from 'refr'
3
3
  import type { NodeProxy } from './node'
4
4
  export type { Fun, Queue, Frame }
5
- export type GPUContext = any // GPUCanvasContext https://developer.mozilla.org/en-US/docs/Web/API/GPUCanvasContext
6
- export type GPUDevice = any //
7
- export type GPUBuffer = any //
8
- export type GPUPipeline = any //
9
- export type GPUBindGroup = any
10
- export type Uniform = number | number[]
11
- export type Attribute = number[]
12
- export type Attributes = Record<string, Attribute>
13
- export type Uniforms = Record<string, Uniform>
14
5
  export type PrecisionMode = 'highp' | 'mediump' | 'lowp'
15
6
  export type GLClearMode = 'COLOR_BUFFER_BIT' | 'DEPTH_BUFFER_BIT' | 'STENCIL_BUFFER_BIT'
16
7
  export type GLDrawType = 'UNSIGNED_BYTE' | 'UNSIGNED_SHORT' | 'UNSIGNED_INT'
@@ -23,6 +14,28 @@ export type GLDrawMode =
23
14
  | 'TRIANGLE_FAN'
24
15
  | 'TRIANGLES'
25
16
 
17
+ export interface UniformData {
18
+ array: Float32Array
19
+ buffer: GPUBuffer
20
+ binding: number
21
+ group: number
22
+ }
23
+
24
+ export interface TextureData {
25
+ binding: number
26
+ group: number
27
+ texture: GPUTexture
28
+ sampler: GPUSampler
29
+ view: GPUTextureView
30
+ }
31
+
32
+ export interface AttribData {
33
+ array: Float32Array
34
+ buffer: GPUBuffer
35
+ location: number
36
+ stride: number
37
+ }
38
+
26
39
  export interface WebGLState {
27
40
  context: WebGLRenderingContext
28
41
  program: WebGLProgram
@@ -30,14 +43,16 @@ export interface WebGLState {
30
43
 
31
44
  export interface WebGPUState {
32
45
  device: GPUDevice
33
- context: GPUContext
34
- pipeline: GPUPipeline
35
- groups: any[]
36
- resources: any[]
37
- loadingImg: number
38
- needsUpdate: boolean
46
+ uniforms: Nested<UniformData>
47
+ textures: Nested<TextureData>
48
+ attribs: Nested<AttribData>
39
49
  }
40
50
 
51
+ export type Uniform = number | number[]
52
+ export type Attribute = number[]
53
+ export type Attributes = Record<string, Attribute>
54
+ export type Uniforms = Record<string, Uniform>
55
+
41
56
  export type GL = EventState<{
42
57
  /**
43
58
  * initial value
@@ -84,6 +99,7 @@ export type GL = EventState<{
84
99
  */
85
100
  _uniform?(key: string, value: Uniform, isMatrix?: boolean): GL
86
101
  uniform(key: string, value: Uniform, isMatrix?: boolean): GL
102
+ uniform(node: NodeProxy): GL
87
103
  uniform(target: { [key: string]: Uniform }): GL
88
104
  _texture?(key: string, value: string): GL
89
105
  texture(key: string, value: string): GL
@@ -1,135 +1,176 @@
1
- import { fragment, isNodeProxy, vertex } from '../node'
2
- import type { NodeProxy } from '../node'
3
- import type { GPUContext, GPUDevice, GPUPipeline } from '../types'
1
+ import type { AttribData, TextureData, UniformData } from '../types'
4
2
 
5
- const defaultVertexWGSL = `
6
- @vertex
7
- fn main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4f {
8
- let x = f32(vertex_index % 2u) * 4.0 - 1.0;
9
- let y = f32(vertex_index / 2u) * 4.0 - 1.0;
10
- return vec4f(x, y, 0.0, 1.0);
3
+ /**
4
+ * initialize
5
+ */
6
+ export const createDevice = async (c: GPUCanvasContext) => {
7
+ const gpu = navigator.gpu
8
+ const format = gpu.getPreferredCanvasFormat()
9
+ const adapter = await gpu.requestAdapter()
10
+ const device = await adapter!.requestDevice()
11
+ c.configure({ device, format, alphaMode: 'opaque' })
12
+ return { device, format }
11
13
  }
12
- `
13
14
 
14
- const defaultFragmentWGSL = `
15
- @group(0) @binding(0) var<uniform> iResolution: vec2f;
15
+ export const createBindings = () => {
16
+ let uniform = 0
17
+ let texture = 0
18
+ let attrib = 0
19
+ return {
20
+ uniform: () => {
21
+ const group = Math.floor(uniform / 12)
22
+ const binding = uniform % 12
23
+ uniform++
24
+ return { group, binding }
25
+ },
26
+ texture: () => {
27
+ const baseGroup = Math.floor(uniform / 12) + 1
28
+ const group = baseGroup + Math.floor(texture / 6)
29
+ const binding = (texture % 6) * 2
30
+ texture++
31
+ return { group, binding }
32
+ },
33
+ attrib: () => {
34
+ const location = attrib
35
+ attrib++
36
+ return { location }
37
+ },
38
+ }
39
+ }
16
40
 
17
- @fragment
18
- fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
19
- return vec4f(position.xy / iResolution, 0.0, 1.0);
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'
20
49
  }
21
- `
22
50
 
23
- export const createDevice = async (c: GPUContext) => {
24
- const gpu = (navigator as any).gpu
25
- const format = gpu.getPreferredCanvasFormat()
26
- const adapter = await gpu.requestAdapter()
27
- const device = await adapter.requestDevice()
28
- c.configure({ device, format, alphaMode: 'opaque' })
29
- return { device, format }
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
30
95
  }
31
96
 
32
97
  export const createPipeline = (
33
98
  device: GPUDevice,
34
- format: string,
35
- bufferLayouts: any[],
36
- bindGroupLayouts: any[],
37
- vs: string | NodeProxy = defaultVertexWGSL,
38
- fs: string | NodeProxy = defaultFragmentWGSL
99
+ format: GPUTextureFormat,
100
+ bufferLayouts: GPUVertexBufferLayout[],
101
+ bindGroupLayouts: GPUBindGroupLayout[],
102
+ vs: string,
103
+ fs: string
39
104
  ) => {
40
- if (isNodeProxy(vs)) vs = vertex(vs, { isWebGL: false })
41
- if (isNodeProxy(fs)) fs = fragment(fs, { isWebGL: false })
42
- const layout = device.createPipelineLayout({ bindGroupLayouts })
43
105
  return device.createRenderPipeline({
44
106
  vertex: {
45
- module: device.createShaderModule({ code: vs.trim() }),
107
+ module: device.createShaderModule({ label: 'vert', code: vs }),
46
108
  entryPoint: 'main',
47
109
  buffers: bufferLayouts,
48
110
  },
49
111
  fragment: {
50
- module: device.createShaderModule({ code: fs.trim() }),
112
+ module: device.createShaderModule({ label: 'frag', code: fs }),
51
113
  entryPoint: 'main',
52
114
  targets: [{ format }],
53
115
  },
54
- layout,
116
+ layout: device.createPipelineLayout({ bindGroupLayouts }),
55
117
  primitive: { topology: 'triangle-list' },
56
- }) as GPUPipeline
118
+ depthStencil: {
119
+ depthWriteEnabled: true,
120
+ depthCompare: 'less',
121
+ format: 'depth24plus',
122
+ },
123
+ })
57
124
  }
58
125
 
59
- export const createBindGroup = (device: GPUDevice, resources: any[]) => {
60
- const entries0 = [] as any[]
61
- const entries1 = [] as any[]
62
- resources.forEach((resource, binding) => {
63
- if (!resource) return
64
- const isUniform = 'buffer' in resource // @ts-ignore
65
- const isTexture = resource instanceof GPUTextureView // @ts-ignore
66
- const isSampler = resource instanceof GPUSampler // @ts-ignore
67
- if (isUniform) entries0.push({ binding, visibility: 3, buffer: { type: 'uniform' } })
68
- else if (isTexture) entries0.push({ binding, visibility: 2, texture: {} })
69
- else if (isSampler) entries0.push({ binding, visibility: 2, sampler: {} })
70
- else return
71
- entries1.push({ binding, resource })
72
- })
73
- const layout = device.createBindGroupLayout({ entries: entries0 })
74
- const bindGroup = device.createBindGroup({ layout, entries: entries1 })
75
- return { layout, bindGroup }
126
+ /**
127
+ * buffers
128
+ */
129
+ export const createUniformBuffer = (device: GPUDevice, value: number[]) => {
130
+ const array = new Float32Array(value)
131
+ const size = Math.ceil(array.byteLength / 256) * 256
132
+ const buffer = device.createBuffer({ size, usage: 72 }) // 72 is GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
133
+ return { array, buffer }
134
+ }
135
+
136
+ export const createAttribBuffer = (device: GPUDevice, value: number[]) => {
137
+ const array = new Float32Array(value)
138
+ const buffer = device.createBuffer({ size: array.byteLength, usage: 40 }) // 40 is GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
139
+ return { array, buffer }
76
140
  }
77
141
 
78
- export const createDescriptor = (c: GPUContext) => {
142
+ export const createDescriptor = (c: GPUCanvasContext, depthTexture: GPUTexture) => {
79
143
  return {
80
144
  colorAttachments: [
81
145
  {
82
146
  view: c.getCurrentTexture().createView(),
83
147
  clearValue: { r: 0, g: 0, b: 0, a: 1 },
84
- loadOp: 'clear',
85
- storeOp: 'store',
148
+ loadOp: 'clear' as GPULoadOp,
149
+ storeOp: 'store' as GPUStoreOp,
86
150
  },
87
151
  ],
88
- }
89
- }
90
-
91
- export const alignTo256 = (size: number) => Math.ceil(size / 256) * 256
92
-
93
- export const createVertexBuffer = (device: GPUDevice, value: number[]) => {
94
- const array = new Float32Array(value)
95
- const buffer = device.createBuffer({ size: array.byteLength, usage: 40 }) // 40 === // GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
96
- return { array, buffer }
97
- }
98
-
99
- export const createUniformBuffer = (device: GPUDevice, value: number[]) => {
100
- const array = new Float32Array(value)
101
- const size = alignTo256(array.byteLength)
102
- const buffer = device.createBuffer({ size, usage: 72 }) as Buffer // 72 === GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
103
- return { array, buffer }
152
+ depthStencilAttachment: {
153
+ view: depthTexture.createView(),
154
+ depthClearValue: 1.0,
155
+ depthLoadOp: 'clear' as GPULoadOp,
156
+ depthStoreOp: 'store' as GPUStoreOp,
157
+ },
158
+ } as GPURenderPassDescriptor
104
159
  }
105
160
 
161
+ /**
162
+ * textures
163
+ */
106
164
  export const createTextureSampler = (device: GPUDevice, width = 1280, height = 800) => {
107
- const texture = device.createTexture({ size: [width, height], format: 'rgba8unorm', usage: 22 })
165
+ const texture = device.createTexture({ size: [width, height], format: 'rgba8unorm', usage: 22 }) // 22 is GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
108
166
  const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' })
109
167
  return { texture, sampler }
110
168
  }
111
169
 
112
- const getVertexStride = (dataLength: number, vertexCount: number) => {
113
- return dataLength / vertexCount
114
- }
115
-
116
- const getVertexFormat = (stride: number) => {
117
- if (stride === 2) return 'float32x2'
118
- if (stride === 3) return 'float32x3'
119
- if (stride === 4) return 'float32x4'
120
- return 'float32'
121
- }
122
-
123
- export const createBufferLayout = (shaderLocation: number, dataLength: number, count = 6) => {
124
- const stride = getVertexStride(dataLength, count)
125
- return {
126
- arrayStride: stride * 4,
127
- attributes: [
128
- {
129
- shaderLocation,
130
- offset: 0,
131
- format: getVertexFormat(stride),
132
- },
133
- ],
134
- }
170
+ export const createDepthTexture = (device: GPUDevice, width: number, height: number) => {
171
+ return device.createTexture({
172
+ size: [width, height],
173
+ format: 'depth24plus',
174
+ usage: GPUTextureUsage.RENDER_ATTACHMENT,
175
+ })
135
176
  }
@@ -1,25 +1,3 @@
1
- import { fragment, isNodeProxy, vertex } from '../node'
2
- import type { NodeProxy } from '../node'
3
-
4
- export const defaultVertexGLSL = /* cpp */ `
5
- #version 300 es
6
- void main() {
7
- float x = float(gl_VertexID % 2) * 4.0 - 1.0;
8
- float y = float(gl_VertexID / 2) * 4.0 - 1.0;
9
- gl_Position = vec4(x, y, 0.0, 1.0);
10
- }
11
- `
12
-
13
- export const defaultFragmentGLSL = /* cpp */ `
14
- #version 300 es
15
- precision mediump float;
16
- uniform vec2 iResolution;
17
- out vec4 fragColor;
18
- void main() {
19
- fragColor = vec4(fract(gl_FragCoord.xy / iResolution), 0, 1);
20
- }
21
- `
22
-
23
1
  const createShader = (c: WebGLRenderingContext, source: string, type: number) => {
24
2
  const shader = c.createShader(type)
25
3
  if (!shader) throw new Error('Failed to create shader')
@@ -31,26 +9,19 @@ const createShader = (c: WebGLRenderingContext, source: string, type: number) =>
31
9
  console.warn(`Could not compile shader: ${error}`)
32
10
  }
33
11
 
34
- export const createProgram = (
35
- c: WebGLRenderingContext,
36
- vs: string | NodeProxy = defaultVertexGLSL,
37
- fs: string | NodeProxy = defaultFragmentGLSL,
38
- onError = () => {}
39
- ) => {
40
- if (isNodeProxy(fs)) fs = fragment(fs, { isWebGL: true })
41
- if (isNodeProxy(vs)) vs = vertex(fs, { isWebGL: true })
12
+ export const createProgram = (c: WebGLRenderingContext, vert: string, frag: string, onError = () => {}) => {
42
13
  const pg = c.createProgram()
43
- const _vs = createShader(c, vs, c.VERTEX_SHADER)
44
- const _fs = createShader(c, fs, c.FRAGMENT_SHADER)
45
- if (!_vs || !_fs) return onError()
46
- c.attachShader(pg, _vs)
47
- 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)
48
19
  c.linkProgram(pg)
49
20
  if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
50
21
  const error = c.getProgramInfoLog(pg)
51
22
  c.deleteProgram(pg)
52
23
  onError()
53
- console.warn(`Could not link pg: ${error}`)
24
+ console.warn(`Could not link program: ${error}`)
54
25
  }
55
26
 
56
27
  export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
package/src/webgl.ts CHANGED
@@ -1,17 +1,21 @@
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))!
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))
13
18
  const units = cached(() => _activeUnit++)
14
- const state = { context: c, program: pg } as WebGLState
15
19
 
16
20
  const clean = () => c.deleteProgram(pg)
17
21
 
@@ -48,5 +52,5 @@ export const webgl = async (gl: Partial<GL>) => {
48
52
  })
49
53
  }
50
54
 
51
- return { webgl: state, render, clean, _attribute, _uniform, _texture }
55
+ return { render, clean, _attribute, _uniform, _texture, webgl: { context: c, program: pg } as WebGLState }
52
56
  }
package/src/webgpu.ts CHANGED
@@ -1,84 +1,97 @@
1
1
  import { nested as cached } from 'reev'
2
2
  import { is } from './utils/helpers'
3
3
  import {
4
+ createAttribBuffer,
5
+ createBindings,
6
+ createBindGroup,
7
+ createDepthTexture,
8
+ createDescriptor,
4
9
  createDevice,
5
10
  createPipeline,
6
- createDescriptor,
7
- createUniformBuffer,
8
- createBindGroup,
9
11
  createTextureSampler,
10
- createVertexBuffer,
11
- createBufferLayout,
12
+ createUniformBuffer,
13
+ createVertexBuffers,
12
14
  } from './utils/pipeline'
13
15
  import type { GL, WebGPUState } from './types'
16
+ import { fragment, vertex } from './node'
14
17
 
15
18
  export const webgpu = async (gl: Partial<GL>) => {
16
- const c = gl.el!.getContext('webgpu') as any
17
- const { device, format } = await createDevice(c)
18
- const state = {
19
- device,
20
- context: c,
21
- resources: [[], []],
22
- loadingImg: 0,
23
- needsUpdate: true,
24
- } as WebGPUState
25
-
26
- const bindGroups = [] as any[]
27
- const vertexBuffers = [] as any[]
28
- const bufferLayouts = [] as any[]
29
-
30
- const attributes = cached((_, value: number[]) => {
31
- const { array, buffer } = createVertexBuffer(device, value)
32
- vertexBuffers.push(buffer)
33
- bufferLayouts.push(createBufferLayout(bufferLayouts.length, array.length, gl.count))
34
- state.needsUpdate = true
35
- return { array, buffer }
36
- })
19
+ const context = gl.el!.getContext('webgpu') as GPUCanvasContext
20
+ const { device, format } = await createDevice(context)
21
+ const bindings = createBindings()
22
+ let frag: string
23
+ let vert: string
24
+ let flush = (_pass: GPURenderPassEncoder) => {}
25
+ let imageLoading = 0
26
+ let needsUpdate = true
27
+ let depthTexture: GPUTexture
37
28
 
38
- const uniforms = cached((_, value: number[]) => {
29
+ const uniforms = cached((_key, value: number[]) => {
30
+ needsUpdate = true
39
31
  const { array, buffer } = createUniformBuffer(device, value)
40
- state.resources[0].push({ buffer })
41
- state.needsUpdate = true
42
- return { array, buffer }
32
+ const { binding, group } = bindings.uniform()
33
+ return { binding, group, array, buffer }
43
34
  })
44
35
 
45
- const textures = cached((_, { width, height }: HTMLImageElement) => {
36
+ const textures = cached((_key, width = 0, height = 0) => {
37
+ needsUpdate = true
46
38
  const { texture, sampler } = createTextureSampler(device, width, height)
47
- state.resources[1].push(sampler, texture.createView())
48
- state.needsUpdate = true
49
- return { texture, width, height }
39
+ const { binding, group } = bindings.texture()
40
+ return { binding, group, texture, sampler, view: texture.createView() }
41
+ })
42
+
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 }
50
49
  })
51
50
 
52
51
  const update = () => {
53
- const bindGroupLayouts = [] as any
54
- bindGroups.length = 0
55
- state.resources.forEach((resource) => {
56
- if (!resource.length) return
57
- const { layout, bindGroup } = createBindGroup(device, resource)
58
- bindGroupLayouts.push(layout)
59
- bindGroups.push(bindGroup)
60
- })
61
- state.pipeline = createPipeline(device, format, bufferLayouts, bindGroupLayouts, gl.vs, gl.fs)
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) => {
60
+ pass.setPipeline(pipeline)
61
+ bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
62
+ vertexBuffers.forEach((v, i) => pass.setVertexBuffer(i, v))
63
+ pass.draw(gl.count!, 1, 0, 0)
64
+ pass.end()
65
+ }
62
66
  }
63
67
 
64
68
  const render = () => {
65
- if (state.loadingImg) return // ignore if loading img
66
- if (state.needsUpdate) update() // first rendering
67
- state.needsUpdate = false
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
75
+ if (needsUpdate) update()
76
+ needsUpdate = false
68
77
  const encoder = device.createCommandEncoder()
69
- const pass = encoder.beginRenderPass(createDescriptor(c))
70
- pass.setPipeline(state.pipeline)
71
- bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
72
- vertexBuffers.forEach((v, i) => pass.setVertexBuffer(i, v))
73
- pass.draw(gl.count, 1, 0, 0)
74
- pass.end()
78
+ flush(encoder.beginRenderPass(createDescriptor(context, depthTexture)))
75
79
  device.queue.submit([encoder.finish()])
76
80
  }
77
81
 
78
- const clean = () => {}
82
+ const resize = () => {
83
+ const canvas = gl.el as HTMLCanvasElement
84
+ depthTexture?.destroy()
85
+ depthTexture = createDepthTexture(device, canvas.width, canvas.height)
86
+ }
87
+
88
+ const clean = () => {
89
+ depthTexture?.destroy()
90
+ }
79
91
 
80
92
  const _attribute = (key = '', value: number[]) => {
81
- const { array, buffer } = attributes(key, value)
93
+ const { array, buffer } = attribs(key, value)
94
+ array.set(value)
82
95
  device.queue.writeBuffer(buffer, 0, array)
83
96
  }
84
97
 
@@ -90,14 +103,25 @@ export const webgpu = async (gl: Partial<GL>) => {
90
103
  }
91
104
 
92
105
  const _texture = (key: string, src: string) => {
93
- state.loadingImg++
106
+ imageLoading++
94
107
  const source = Object.assign(new Image(), { src, crossOrigin: 'anonymous' })
95
108
  source.decode().then(() => {
96
- const { texture, width, height } = textures(key, source)
109
+ const { width, height } = source
110
+ const { texture } = textures(key, width, height)
97
111
  device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
98
- state.loadingImg--
112
+ imageLoading--
99
113
  })
100
114
  }
101
115
 
102
- return { webgpu: state, render, clean, _attribute, _uniform, _texture }
116
+ resize()
117
+
118
+ return {
119
+ webgpu: { device, uniforms, textures, attribs } as WebGPUState,
120
+ render,
121
+ resize,
122
+ clean,
123
+ _attribute,
124
+ _uniform,
125
+ _texture,
126
+ }
103
127
  }