glre 0.35.0 → 0.37.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/dist/index.cjs +37 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +256 -301
- package/dist/index.js +37 -29
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +37 -29
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +18 -9
- package/dist/native.js +37 -29
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +37 -29
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +37 -29
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +37 -29
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +1 -1
- package/dist/solid.js +37 -29
- package/dist/solid.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +5 -4
- package/src/node/core.ts +121 -0
- package/src/node/index.ts +80 -159
- package/src/node/node.ts +32 -21
- package/src/node/scope.ts +7 -13
- package/src/node/types.ts +168 -139
- package/src/node/{const.ts → utils/const.ts} +111 -119
- package/src/node/{code.ts → utils/index.ts} +29 -12
- package/src/node/{infer.ts → utils/infer.ts} +12 -8
- package/src/node/{parse.ts → utils/parse.ts} +60 -16
- package/src/node/{utils.ts → utils/utils.ts} +30 -39
- package/src/types.ts +60 -50
- package/src/utils/helpers.ts +16 -0
- package/src/utils/pipeline.ts +41 -12
- package/src/utils/program.ts +95 -13
- package/src/webgl.ts +95 -38
- package/src/webgpu.ts +87 -53
package/src/utils/program.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { is } from './helpers'
|
|
2
|
+
import type { GL } from '../types'
|
|
3
|
+
|
|
1
4
|
const createShader = (c: WebGLRenderingContext, source: string, type: number, onError = console.warn) => {
|
|
2
5
|
const shader = c.createShader(type)
|
|
3
6
|
if (!shader) return onError('Failed to create shader')
|
|
@@ -9,21 +12,21 @@ const createShader = (c: WebGLRenderingContext, source: string, type: number, on
|
|
|
9
12
|
onError(`Could not compile shader: ${error}`)
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
export const createProgram = (c: WebGLRenderingContext,
|
|
15
|
+
export const createProgram = (c: WebGLRenderingContext, frag: string, vert: string, gl: GL) => {
|
|
13
16
|
const pg = c.createProgram()
|
|
14
|
-
const fs = createShader(c, frag, c.FRAGMENT_SHADER,
|
|
15
|
-
const vs = createShader(c, vert, c.VERTEX_SHADER,
|
|
17
|
+
const fs = createShader(c, frag, c.FRAGMENT_SHADER, gl.error)
|
|
18
|
+
const vs = createShader(c, vert, c.VERTEX_SHADER, gl.error)
|
|
16
19
|
if (!fs || !vs) return
|
|
17
|
-
c.attachShader(pg, vs!)
|
|
18
20
|
c.attachShader(pg, fs!)
|
|
21
|
+
c.attachShader(pg, vs!)
|
|
19
22
|
c.linkProgram(pg)
|
|
20
23
|
if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
|
|
21
24
|
const error = c.getProgramInfoLog(pg)
|
|
22
25
|
c.deleteProgram(pg)
|
|
23
|
-
|
|
26
|
+
gl.error(`Could not link program: ${error}`)
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
const createVbo = (c: WebGLRenderingContext, data: number[]) => {
|
|
27
30
|
const buffer = c.createBuffer()
|
|
28
31
|
c.bindBuffer(c.ARRAY_BUFFER, buffer)
|
|
29
32
|
c.bufferData(c.ARRAY_BUFFER, new Float32Array(data), c.STATIC_DRAW)
|
|
@@ -31,7 +34,7 @@ export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
|
|
|
31
34
|
return buffer
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
const createIbo = (c: WebGLRenderingContext, data: number[]) => {
|
|
35
38
|
const buffer = c.createBuffer()
|
|
36
39
|
c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, buffer)
|
|
37
40
|
c.bufferData(c.ELEMENT_ARRAY_BUFFER, new Int16Array(data), c.STATIC_DRAW)
|
|
@@ -39,7 +42,7 @@ export const createIbo = (c: WebGLRenderingContext, data: number[]) => {
|
|
|
39
42
|
return buffer
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
const getStride = (count: number, value: number[], iboValue?: number[]) => {
|
|
43
46
|
if (iboValue) count = Math.max(...iboValue) + 1
|
|
44
47
|
const stride = value.length / count
|
|
45
48
|
return Math.floor(stride)
|
|
@@ -47,17 +50,28 @@ export const getStride = (count: number, value: number[], iboValue?: number[]) =
|
|
|
47
50
|
|
|
48
51
|
export const createAttrib = (
|
|
49
52
|
c: WebGLRenderingContext,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
loc: number,
|
|
54
|
+
count: number,
|
|
55
|
+
value: number[],
|
|
56
|
+
iboValue: number[]
|
|
54
57
|
) => {
|
|
58
|
+
const vbo = createVbo(c, value)
|
|
59
|
+
const ibo = createIbo(c, iboValue)
|
|
60
|
+
const str = getStride(count, value, iboValue)
|
|
55
61
|
c.bindBuffer(c.ARRAY_BUFFER, vbo)
|
|
56
62
|
c.enableVertexAttribArray(loc)
|
|
57
|
-
c.vertexAttribPointer(loc,
|
|
63
|
+
c.vertexAttribPointer(loc, str, c.FLOAT, false, 0, 0)
|
|
58
64
|
if (ibo) c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, ibo)
|
|
59
65
|
}
|
|
60
66
|
|
|
67
|
+
export const createUniform = (c: WebGLRenderingContext, loc: WebGLUniformLocation, value: number | number[]) => {
|
|
68
|
+
if (is.num(value)) return c.uniform1f(loc, value)
|
|
69
|
+
let l = value.length
|
|
70
|
+
if (l <= 4) return c[`uniform${l as 2}fv`](loc, value)
|
|
71
|
+
l = Math.sqrt(l) << 0
|
|
72
|
+
c[`uniformMatrix${l as 2}fv`](loc, false, value)
|
|
73
|
+
}
|
|
74
|
+
|
|
61
75
|
export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement, loc: any, unit: number) => {
|
|
62
76
|
const texture = c.createTexture()
|
|
63
77
|
c.bindTexture(c.TEXTURE_2D, texture)
|
|
@@ -72,3 +86,71 @@ export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement, l
|
|
|
72
86
|
c.activeTexture(c.TEXTURE0 + unit)
|
|
73
87
|
c.bindTexture(c.TEXTURE_2D, texture)
|
|
74
88
|
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* for gpgpu
|
|
92
|
+
*/
|
|
93
|
+
interface TextureBuffer {
|
|
94
|
+
texture: WebGLTexture
|
|
95
|
+
buffer: WebGLFramebuffer
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const createStorage = (
|
|
99
|
+
c: WebGL2RenderingContext,
|
|
100
|
+
value: number[],
|
|
101
|
+
size: number,
|
|
102
|
+
ping: TextureBuffer,
|
|
103
|
+
pong: TextureBuffer,
|
|
104
|
+
unit: number,
|
|
105
|
+
array: Float32Array
|
|
106
|
+
) => {
|
|
107
|
+
const particles = size * size
|
|
108
|
+
const vectorSize = value.length / particles
|
|
109
|
+
for (let i = 0; i < particles; i++) {
|
|
110
|
+
for (let j = 0; j < Math.min(vectorSize, 4); j++) {
|
|
111
|
+
array[4 * i + j] = value[i * vectorSize + j] || 0
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
c.activeTexture(c.TEXTURE0 + unit)
|
|
115
|
+
c.bindTexture(c.TEXTURE_2D, ping.texture)
|
|
116
|
+
c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, array)
|
|
117
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
|
|
118
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
|
|
119
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
|
|
120
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
|
|
121
|
+
c.bindTexture(c.TEXTURE_2D, pong.texture)
|
|
122
|
+
c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, array)
|
|
123
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
|
|
124
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
|
|
125
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
|
|
126
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export const cleanStorage = (
|
|
130
|
+
c: WebGL2RenderingContext,
|
|
131
|
+
map: Iterable<{ ping: TextureBuffer; pong: TextureBuffer }>
|
|
132
|
+
) => {
|
|
133
|
+
for (const { ping, pong } of map) {
|
|
134
|
+
c.deleteTexture(ping.texture)
|
|
135
|
+
c.deleteTexture(pong.texture)
|
|
136
|
+
c.deleteFramebuffer(ping.buffer)
|
|
137
|
+
c.deleteFramebuffer(pong.buffer)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export const createAttachment = (
|
|
142
|
+
c: WebGL2RenderingContext,
|
|
143
|
+
i: TextureBuffer,
|
|
144
|
+
o: TextureBuffer,
|
|
145
|
+
loc: WebGLUniformLocation,
|
|
146
|
+
unit: number,
|
|
147
|
+
index: number
|
|
148
|
+
) => {
|
|
149
|
+
c.activeTexture(c.TEXTURE0 + unit)
|
|
150
|
+
c.bindTexture(c.TEXTURE_2D, i.texture)
|
|
151
|
+
c.uniform1i(loc, unit)
|
|
152
|
+
if (index === 0) c.bindFramebuffer(c.FRAMEBUFFER, o.buffer)
|
|
153
|
+
const attachment = c.COLOR_ATTACHMENT0 + index
|
|
154
|
+
c.framebufferTexture2D(c.FRAMEBUFFER, attachment, c.TEXTURE_2D, o.texture, 0)
|
|
155
|
+
return attachment
|
|
156
|
+
}
|
package/src/webgl.ts
CHANGED
|
@@ -1,65 +1,122 @@
|
|
|
1
1
|
import { nested as cached } from 'reev'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
2
|
+
import { loadingImage } from './utils/helpers'
|
|
3
|
+
import {
|
|
4
|
+
cleanStorage,
|
|
5
|
+
createAttachment,
|
|
6
|
+
createAttrib,
|
|
7
|
+
createProgram,
|
|
8
|
+
createStorage,
|
|
9
|
+
createTexture,
|
|
10
|
+
createUniform,
|
|
11
|
+
} from './utils/program'
|
|
12
|
+
import { compute, fragment, vertex } from './node'
|
|
5
13
|
import type { GL, WebGLState } from './types'
|
|
6
14
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
const vert = /* cpp */ `
|
|
16
|
+
#version 300 es
|
|
17
|
+
void main() {
|
|
18
|
+
float x = float(gl_VertexID % 2) * 4.0 - 1.0;
|
|
19
|
+
float y = float(gl_VertexID / 2) * 4.0 - 1.0;
|
|
20
|
+
gl_Position = vec4(x, y, 0.0, 1.0);
|
|
21
|
+
}`.trim()
|
|
22
|
+
|
|
23
|
+
const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
|
|
24
|
+
if (!gl.cs) return null // ignore if no compute shader
|
|
25
|
+
c.getExtension('EXT_color_buffer_float')
|
|
26
|
+
|
|
27
|
+
let activeUnit = 0 // for texture units
|
|
28
|
+
let currentNum = 0 // for storage buffers
|
|
14
29
|
|
|
15
|
-
let activeUnit = 0
|
|
16
|
-
const uniforms = cached((key) => c.getUniformLocation(pg, key))
|
|
17
|
-
const attribs = cached((key) => c.getAttribLocation(pg, key))
|
|
18
30
|
const units = cached(() => activeUnit++)
|
|
31
|
+
const config = { isWebGL: true, gl, units }
|
|
32
|
+
|
|
33
|
+
const pg = createProgram(c, compute(gl.cs, config), vert, gl)!
|
|
34
|
+
const size = Math.ceil(Math.sqrt(gl.particles))
|
|
35
|
+
|
|
36
|
+
const uniforms = cached((key) => c.getUniformLocation(pg, key)!)
|
|
37
|
+
const storages = cached((key) => {
|
|
38
|
+
const array = new Float32Array(size * size * 4) // RGBA texture data
|
|
39
|
+
const ping = { texture: c.createTexture(), buffer: c.createFramebuffer() }
|
|
40
|
+
const pong = { texture: c.createTexture(), buffer: c.createFramebuffer() }
|
|
41
|
+
return { ping, pong, array, loc: uniforms(key), unit: units(key) }
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const _uniform = (key: string, value: number | number[]) => {
|
|
45
|
+
c.useProgram(pg)
|
|
46
|
+
createUniform(c, uniforms(key), value)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const _storage = (key: string, value: number[]) => {
|
|
50
|
+
const { ping, pong, unit, array } = storages(key)
|
|
51
|
+
createStorage(c, value, size, ping, pong, unit, array)
|
|
52
|
+
}
|
|
19
53
|
|
|
20
54
|
const clean = () => {
|
|
21
55
|
c.deleteProgram(pg)
|
|
22
|
-
c.
|
|
23
|
-
gl.el.width = 1
|
|
24
|
-
gl.el.height = 1
|
|
56
|
+
cleanStorage(c, storages.map.values())
|
|
25
57
|
}
|
|
26
58
|
|
|
27
59
|
const render = () => {
|
|
28
|
-
c.
|
|
29
|
-
|
|
60
|
+
c.useProgram(pg)
|
|
61
|
+
const attachments = storages.map.values().map(({ ping, pong, loc, unit }, index) => {
|
|
62
|
+
const [i, o] = currentNum % 2 ? [ping, pong] : [pong, ping]
|
|
63
|
+
return createAttachment(c, i, o, loc, unit, index)
|
|
64
|
+
})
|
|
65
|
+
c.drawBuffers(attachments)
|
|
30
66
|
c.drawArrays(c.TRIANGLES, 0, 3)
|
|
67
|
+
c.bindFramebuffer(c.FRAMEBUFFER, null)
|
|
68
|
+
currentNum++
|
|
31
69
|
}
|
|
32
70
|
|
|
71
|
+
return { render, clean, _uniform, _storage, storages }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const webgl = async (gl: GL) => {
|
|
75
|
+
const config = { isWebGL: true, gl }
|
|
76
|
+
const c = gl.el!.getContext('webgl2')!
|
|
77
|
+
const cp = computeProgram(gl, c)
|
|
78
|
+
const pg = createProgram(c, fragment(gl.fs, config), vertex(gl.vs, config), gl)!
|
|
79
|
+
c.useProgram(pg)
|
|
80
|
+
|
|
81
|
+
let activeUnit = 0 // for texture units
|
|
82
|
+
|
|
83
|
+
const units = cached(() => activeUnit++)
|
|
84
|
+
const attribs = cached((key) => c.getAttribLocation(pg, key))
|
|
85
|
+
const uniforms = cached((key) => c.getUniformLocation(pg, key))
|
|
86
|
+
|
|
33
87
|
const _attribute = (key = '', value: number[], iboValue: number[]) => {
|
|
34
88
|
const loc = attribs(key, true)
|
|
35
|
-
|
|
36
|
-
const ibo = createIbo(c, iboValue)
|
|
37
|
-
const str = getStride(gl.count, value, iboValue)
|
|
38
|
-
createAttrib(c, str, loc, vbo, ibo)
|
|
89
|
+
createAttrib(c, loc, gl.count, value, iboValue)
|
|
39
90
|
}
|
|
40
91
|
|
|
41
92
|
const _uniform = (key: string, value: number | number[]) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (l <= 4) return c[`uniform${l as 2}fv`](loc, value)
|
|
46
|
-
l = Math.sqrt(l) << 0
|
|
47
|
-
c[`uniformMatrix${l as 2}fv`](loc, false, value)
|
|
93
|
+
c.useProgram(pg)
|
|
94
|
+
createUniform(c, uniforms(key)!, value)
|
|
95
|
+
cp?._uniform(key, value)
|
|
48
96
|
}
|
|
49
97
|
|
|
50
98
|
const _texture = (key: string, src: string) => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
image.decode().then(() => {
|
|
55
|
-
const loc = uniforms(key)
|
|
56
|
-
const unit = units(key)
|
|
57
|
-
createTexture(c, image, loc, unit)
|
|
58
|
-
gl.loading--
|
|
99
|
+
c.useProgram(pg)
|
|
100
|
+
loadingImage(gl, src, (source) => {
|
|
101
|
+
createTexture(c, source, uniforms(key), units(key))
|
|
59
102
|
})
|
|
60
103
|
}
|
|
61
104
|
|
|
62
|
-
const
|
|
105
|
+
const clean = () => {
|
|
106
|
+
cp?.clean()
|
|
107
|
+
c.deleteProgram(pg)
|
|
108
|
+
c.getExtension('WEBGL_lose_context')?.loseContext()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const render = () => {
|
|
112
|
+
cp?.render()
|
|
113
|
+
c.useProgram(pg)
|
|
114
|
+
c.viewport(0, 0, ...gl.size)
|
|
115
|
+
c.drawArrays(c.TRIANGLES, 0, gl.count)
|
|
116
|
+
c.bindFramebuffer(c.FRAMEBUFFER, null)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const webgl: WebGLState = { context: c, program: pg, storages: cp?.storages }
|
|
63
120
|
|
|
64
|
-
return { webgl, render, clean, _attribute, _uniform, _texture }
|
|
121
|
+
return { webgl, render, clean, _attribute, _uniform, _texture, _storage: cp?._storage }
|
|
65
122
|
}
|
package/src/webgpu.ts
CHANGED
|
@@ -1,59 +1,119 @@
|
|
|
1
1
|
import { nested as cached } from 'reev'
|
|
2
|
-
import { is } from './utils/helpers'
|
|
2
|
+
import { is, loadingImage } from './utils/helpers'
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
createBindings,
|
|
4
|
+
createArrayBuffer,
|
|
6
5
|
createBindGroup,
|
|
6
|
+
createBindings,
|
|
7
|
+
createComputePipeline,
|
|
7
8
|
createDepthTexture,
|
|
8
9
|
createDescriptor,
|
|
9
10
|
createDevice,
|
|
10
11
|
createPipeline,
|
|
11
12
|
createTextureSampler,
|
|
12
|
-
createUniformBuffer,
|
|
13
13
|
createVertexBuffers,
|
|
14
14
|
} from './utils/pipeline'
|
|
15
15
|
import type { GL, WebGPUState } from './types'
|
|
16
|
-
import { fragment, vertex } from './node'
|
|
16
|
+
import { compute, fragment, vertex } from './node'
|
|
17
|
+
|
|
18
|
+
const WORKING_GROUP_SIZE = 32
|
|
19
|
+
|
|
20
|
+
const computeProgram = (gl: GL, device: GPUDevice, bindings: any) => {
|
|
21
|
+
let flush = (_pass: GPUComputePassEncoder) => {}
|
|
22
|
+
|
|
23
|
+
const storages = cached((_key, value: number[] | Float32Array) => {
|
|
24
|
+
const { array, buffer } = createArrayBuffer(device, value, 'storage')
|
|
25
|
+
const { binding, group } = bindings.storage()
|
|
26
|
+
return { array, buffer, binding, group }
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const _storage = (key: string, value: number[] | Float32Array) => {
|
|
30
|
+
const { array, buffer } = storages(key, value)
|
|
31
|
+
device.queue.writeBuffer(buffer, 0, array as any)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const update = (bindGroups: GPUBindGroup[], bindGroupLayouts: GPUBindGroupLayout[], comp: string) => {
|
|
35
|
+
const pipeline = createComputePipeline(device, bindGroupLayouts, comp!)
|
|
36
|
+
flush = (pass) => {
|
|
37
|
+
pass.setPipeline(pipeline)
|
|
38
|
+
bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
|
|
39
|
+
const workgroupCount = Math.ceil(gl.particles / WORKING_GROUP_SIZE)
|
|
40
|
+
pass.dispatchWorkgroups(workgroupCount, 1, 1)
|
|
41
|
+
pass.end()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const render = (pass: GPUComputePassEncoder) => {
|
|
46
|
+
flush(pass)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const clean = () => {
|
|
50
|
+
for (const { buffer } of storages.map.values()) buffer.destroy()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { storages, _storage, update, render, clean }
|
|
54
|
+
}
|
|
17
55
|
|
|
18
56
|
export const webgpu = async (gl: GL) => {
|
|
19
57
|
const context = gl.el!.getContext('webgpu') as GPUCanvasContext
|
|
20
|
-
const { device, format } = await createDevice(context)
|
|
21
|
-
device.onuncapturederror = (e) => gl.error(e.error.message)
|
|
58
|
+
const { device, format } = await createDevice(context, gl.error)
|
|
22
59
|
const bindings = createBindings()
|
|
60
|
+
const cp = computeProgram(gl, device, bindings)
|
|
23
61
|
let frag: string
|
|
62
|
+
let comp: string
|
|
24
63
|
let vert: string
|
|
25
64
|
let flush = (_pass: GPURenderPassEncoder) => {}
|
|
26
65
|
let needsUpdate = true
|
|
27
66
|
let depthTexture: GPUTexture
|
|
28
67
|
|
|
68
|
+
const attribs = cached((_key, value: number[]) => {
|
|
69
|
+
needsUpdate = true
|
|
70
|
+
const stride = value.length / gl.count
|
|
71
|
+
const { location } = bindings.attrib()
|
|
72
|
+
const { array, buffer } = createArrayBuffer(device, value, 'attrib')
|
|
73
|
+
return { array, buffer, location, stride }
|
|
74
|
+
})
|
|
75
|
+
|
|
29
76
|
const uniforms = cached((_key, value: number[]) => {
|
|
30
77
|
needsUpdate = true
|
|
31
|
-
const { array, buffer } = createUniformBuffer(device, value)
|
|
32
78
|
const { binding, group } = bindings.uniform()
|
|
33
|
-
|
|
79
|
+
const { array, buffer } = createArrayBuffer(device, value, 'uniform')
|
|
80
|
+
return { array, buffer, binding, group }
|
|
34
81
|
})
|
|
35
82
|
|
|
36
83
|
const textures = cached((_key, width = 0, height = 0) => {
|
|
37
84
|
needsUpdate = true
|
|
38
|
-
const { texture, sampler } = createTextureSampler(device, width, height)
|
|
39
85
|
const { binding, group } = bindings.texture()
|
|
40
|
-
|
|
86
|
+
const { texture, sampler } = createTextureSampler(device, width, height)
|
|
87
|
+
return { texture, sampler, binding, group, view: texture.createView() }
|
|
41
88
|
})
|
|
42
89
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
90
|
+
const _attribute = (key = '', value: number[]) => {
|
|
91
|
+
const { array, buffer } = attribs(key, value)
|
|
92
|
+
device.queue.writeBuffer(buffer, 0, array as any)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const _uniform = (key: string, value: number | number[]) => {
|
|
96
|
+
if (is.num(value)) value = [value]
|
|
97
|
+
const { array, buffer } = uniforms(key, value)
|
|
98
|
+
array.set(value) // needs to set leatest value
|
|
99
|
+
device.queue.writeBuffer(buffer, 0, array as any)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const _texture = (key: string, src: string) => {
|
|
103
|
+
loadingImage(gl, src, (source) => {
|
|
104
|
+
const { width, height } = source
|
|
105
|
+
const { texture } = textures(key, width, height)
|
|
106
|
+
device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
|
|
107
|
+
})
|
|
108
|
+
}
|
|
50
109
|
|
|
51
110
|
const update = () => {
|
|
52
111
|
const { vertexBuffers, bufferLayouts } = createVertexBuffers(attribs.map.values())
|
|
53
112
|
const { bindGroups, bindGroupLayouts } = createBindGroup(
|
|
54
113
|
device,
|
|
55
114
|
uniforms.map.values(),
|
|
56
|
-
textures.map.values()
|
|
115
|
+
textures.map.values(),
|
|
116
|
+
cp.storages.map.values()
|
|
57
117
|
)
|
|
58
118
|
const pipeline = createPipeline(device, format, bufferLayouts, bindGroupLayouts, vert, frag)
|
|
59
119
|
flush = (pass) => {
|
|
@@ -63,18 +123,21 @@ export const webgpu = async (gl: GL) => {
|
|
|
63
123
|
pass.draw(gl.count, 1, 0, 0)
|
|
64
124
|
pass.end()
|
|
65
125
|
}
|
|
126
|
+
if (gl.cs) cp.update(bindGroups, bindGroupLayouts, comp)
|
|
66
127
|
}
|
|
67
128
|
|
|
68
129
|
const render = () => {
|
|
69
130
|
if (!frag || !vert) {
|
|
70
131
|
const config = { isWebGL: false, gl }
|
|
71
|
-
frag = fragment(gl.fs, config)
|
|
132
|
+
frag = fragment(gl.fs, config) // needs to be before vertex
|
|
72
133
|
vert = vertex(gl.vs, config)
|
|
134
|
+
comp = compute(gl.cs, config)
|
|
73
135
|
}
|
|
74
136
|
if (gl.loading) return // MEMO: loading after build node
|
|
75
137
|
if (needsUpdate) update()
|
|
76
138
|
needsUpdate = false
|
|
77
139
|
const encoder = device.createCommandEncoder()
|
|
140
|
+
if (gl.cs) cp.render(encoder.beginComputePass())
|
|
78
141
|
flush(encoder.beginRenderPass(createDescriptor(context, depthTexture)))
|
|
79
142
|
device.queue.submit([encoder.finish()])
|
|
80
143
|
}
|
|
@@ -91,41 +154,12 @@ export const webgpu = async (gl: GL) => {
|
|
|
91
154
|
for (const { texture } of textures.map.values()) texture.destroy()
|
|
92
155
|
for (const { buffer } of uniforms.map.values()) buffer.destroy()
|
|
93
156
|
for (const { buffer } of attribs.map.values()) buffer.destroy()
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const _attribute = (key = '', value: number[]) => {
|
|
97
|
-
const { array, buffer } = attribs(key, value)
|
|
98
|
-
array.set(value)
|
|
99
|
-
device.queue.writeBuffer(buffer, 0, array)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const _uniform = (key: string, value: number | number[]) => {
|
|
103
|
-
if (is.num(value)) value = [value]
|
|
104
|
-
const { array, buffer } = uniforms(key, value)
|
|
105
|
-
array.set(value)
|
|
106
|
-
device.queue.writeBuffer(buffer, 0, array)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const _texture = (key: string, src: string) => {
|
|
110
|
-
gl.loading++
|
|
111
|
-
const source = Object.assign(new Image(), { src, crossOrigin: 'anonymous' })
|
|
112
|
-
source.decode().then(() => {
|
|
113
|
-
const { width, height } = source
|
|
114
|
-
const { texture } = textures(key, width, height)
|
|
115
|
-
device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
|
|
116
|
-
gl.loading--
|
|
117
|
-
})
|
|
157
|
+
cp.clean()
|
|
118
158
|
}
|
|
119
159
|
|
|
120
160
|
resize()
|
|
121
161
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
resize,
|
|
126
|
-
clean,
|
|
127
|
-
_attribute,
|
|
128
|
-
_uniform,
|
|
129
|
-
_texture,
|
|
130
|
-
}
|
|
162
|
+
const webgpu = { device, uniforms, textures, attribs, storages: cp.storages } as WebGPUState
|
|
163
|
+
|
|
164
|
+
return { webgpu, render, resize, clean, _attribute, _uniform, _texture, _storage: cp._storage }
|
|
131
165
|
}
|