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.
- package/README.md +4 -26
- package/dist/addons.d.ts +41 -51
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +43 -91
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +1 -1
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +51 -94
- package/dist/native.js +1 -1
- package/dist/native.js.map +1 -1
- package/dist/node.cjs +15 -15
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +41 -52
- package/dist/node.js +14 -14
- package/dist/node.js.map +1 -1
- package/dist/react.cjs +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +43 -92
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +1 -1
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +43 -92
- package/dist/solid.js +1 -1
- package/dist/solid.js.map +1 -1
- package/package.json +1 -1
- package/src/{utils/helpers.ts → helpers.ts} +10 -32
- package/src/index.ts +45 -42
- package/src/native.ts +6 -7
- package/src/node/build.ts +6 -21
- package/src/node/create.ts +2 -4
- package/src/node/index.ts +8 -20
- package/src/node/types.ts +9 -1
- package/src/node/utils/index.ts +5 -25
- package/src/node/utils/infer.ts +4 -12
- package/src/node/utils/parse.ts +18 -34
- package/src/node/utils/utils.ts +3 -11
- package/src/react.ts +9 -12
- package/src/solid.ts +3 -10
- package/src/types.ts +30 -22
- package/src/webgl/compute.ts +56 -0
- package/src/webgl/graphic.ts +65 -0
- package/src/webgl/index.ts +21 -0
- package/src/{utils/program.ts → webgl/utils.ts} +30 -8
- package/src/webgpu/compute.ts +39 -0
- package/src/webgpu/graphic.ts +89 -0
- package/src/webgpu/index.ts +42 -0
- package/src/{utils/pipeline.ts → webgpu/utils.ts} +75 -78
- package/src/utils/webgl.ts +0 -135
- package/src/utils/webgpu.ts +0 -178
|
@@ -1,53 +1,68 @@
|
|
|
1
|
-
import {
|
|
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: '
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
/**
|
package/src/utils/webgl.ts
DELETED
|
@@ -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
|
-
}
|
package/src/utils/webgpu.ts
DELETED
|
@@ -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
|
-
}
|