glre 0.32.0 → 0.34.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 +31 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1851 -254
- package/dist/index.js +32 -28
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +31 -27
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +9 -9
- package/dist/native.js +32 -28
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +31 -27
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +32 -28
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +31 -27
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +1 -1
- package/dist/solid.js +32 -28
- package/dist/solid.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/node/code.ts +44 -37
- package/src/node/const.ts +84 -76
- package/src/node/index.ts +134 -106
- package/src/node/infer.ts +59 -64
- package/src/node/node.ts +26 -23
- package/src/node/parse.ts +70 -26
- package/src/node/scope.ts +28 -18
- package/src/node/types.ts +237 -104
- package/src/node/utils.ts +68 -16
- package/src/types.ts +8 -7
- package/src/utils/pipeline.ts +65 -76
- package/src/utils/program.ts +7 -14
- package/src/webgl.ts +6 -1
- package/src/webgpu.ts +39 -24
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,
|
|
@@ -27,16 +26,15 @@ export const isConversion = (key: unknown): key is Conversions => {
|
|
|
27
26
|
return CONVERSIONS.includes(key as Conversions)
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
export const isNodeProxy = (x: unknown): x is NodeProxy => {
|
|
29
|
+
export const isNodeProxy = <T extends Constants>(x: unknown): x is NodeProxy<T> => {
|
|
31
30
|
if (!x) return false
|
|
32
31
|
if (typeof x !== 'object') return false // @ts-ignore
|
|
33
32
|
return x.isProxy
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
export const
|
|
37
|
-
if (!type) return false
|
|
38
|
-
|
|
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,20 +48,13 @@ let count = 0
|
|
|
50
48
|
|
|
51
49
|
export const getId = () => `i${count++}`
|
|
52
50
|
|
|
53
|
-
export const
|
|
54
|
-
return children
|
|
55
|
-
.filter((x) => !is.und(x) && !is.nul(x))
|
|
56
|
-
.map((x) => code(x, c))
|
|
57
|
-
.join(', ')
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export const formatConversions = (x: X, c?: NodeContext) => {
|
|
51
|
+
export const formatConversions = <T extends Constants>(x: X<T>, 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
|
-
export const getOperator = (op: X) => {
|
|
57
|
+
export const getOperator = (op: X<string>) => {
|
|
67
58
|
return OPERATORS[op as keyof typeof OPERATORS] || op
|
|
68
59
|
}
|
|
69
60
|
|
|
@@ -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 = <T extends Constants>(x: X<T>, 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EventState, Nested } from 'reev'
|
|
2
2
|
import type { Fun, Queue, Frame } from 'refr'
|
|
3
|
-
import type { NodeProxy } from './node'
|
|
3
|
+
import type { NodeProxy, Vec4 } from './node'
|
|
4
4
|
export type { Fun, Queue, Frame }
|
|
5
5
|
export type PrecisionMode = 'highp' | 'mediump' | 'lowp'
|
|
6
6
|
export type GLClearMode = 'COLOR_BUFFER_BIT' | 'DEPTH_BUFFER_BIT' | 'STENCIL_BUFFER_BIT'
|
|
@@ -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 {
|
|
@@ -66,12 +67,12 @@ export type GL = EventState<{
|
|
|
66
67
|
mouse: [number, number]
|
|
67
68
|
count: number
|
|
68
69
|
el: HTMLCanvasElement
|
|
69
|
-
vs: string |
|
|
70
|
-
fs: string |
|
|
71
|
-
vert: string |
|
|
72
|
-
frag: string |
|
|
73
|
-
vertex: string |
|
|
74
|
-
fragment: string |
|
|
70
|
+
vs: string | Vec4
|
|
71
|
+
fs: string | Vec4
|
|
72
|
+
vert: string | Vec4
|
|
73
|
+
frag: string | Vec4
|
|
74
|
+
vertex: string | Vec4
|
|
75
|
+
fragment: string | Vec4
|
|
75
76
|
|
|
76
77
|
/**
|
|
77
78
|
* core state
|
package/src/utils/pipeline.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
50
|
-
|
|
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
|
|
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
|
|
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
|
-
}
|
package/src/utils/program.ts
CHANGED
|
@@ -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,
|
|
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
|
|
22
|
-
const
|
|
23
|
-
if (!
|
|
24
|
-
c.attachShader(pg,
|
|
25
|
-
c.attachShader(pg,
|
|
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
|
|
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
|
|
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
|
|
19
|
-
const { device, format } = await createDevice(
|
|
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
|
-
|
|
32
|
+
const { binding, group } = bindings.uniform()
|
|
33
|
+
return { binding, group, array, buffer }
|
|
31
34
|
})
|
|
32
35
|
|
|
33
|
-
const textures = cached((_key,
|
|
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
|
-
|
|
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(
|
|
51
|
-
|
|
52
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
}
|