glre 0.25.0 → 0.27.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 +9 -8
- package/dist/index.d.ts +209 -155
- package/dist/index.js +35 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +35 -22
- package/dist/index.mjs.map +1 -1
- package/dist/native.d.ts +1 -1
- package/dist/native.js +35 -22
- package/dist/native.js.map +1 -1
- package/dist/native.mjs +35 -22
- package/dist/native.mjs.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +35 -22
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +35 -22
- package/dist/react.mjs.map +1 -1
- package/dist/solid.d.ts +1 -1
- package/dist/solid.js +35 -22
- package/dist/solid.js.map +1 -1
- package/dist/solid.mjs +35 -22
- package/dist/solid.mjs.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -3
- package/src/native.ts +2 -2
- package/src/node/code.ts +74 -0
- package/src/node/const.ts +45 -48
- package/src/node/index.ts +85 -87
- package/src/node/node.ts +40 -94
- package/src/node/scope.ts +68 -0
- package/src/node/types.ts +53 -88
- package/src/node/utils.ts +102 -0
- package/src/types.ts +1 -3
- package/src/utils/pipeline.ts +40 -17
- package/src/utils/program.ts +10 -8
- package/src/webgl.ts +10 -11
- package/src/webgpu.ts +34 -23
- package/src/code/glsl.ts +0 -148
- package/src/code/wgsl.ts +0 -134
- package/src/node/cache.ts +0 -60
- package/src/node/conv.ts +0 -111
- package/src/node/uniform.ts +0 -92
package/src/node/types.ts
CHANGED
|
@@ -1,101 +1,66 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FUNCTIONS, NODE_TYPES, OPERATOR_KEYS } from './const'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
export interface Node {
|
|
5
|
-
id: string
|
|
6
|
-
type: NodeType
|
|
7
|
-
value?: any
|
|
8
|
-
property?: string
|
|
9
|
-
parent?: Node
|
|
10
|
-
children?: Node[]
|
|
11
|
-
operator?: Operator
|
|
12
|
-
mathFunction?: MathFunction
|
|
13
|
-
}
|
|
3
|
+
export type NodeType = (typeof NODE_TYPES)[number]
|
|
14
4
|
|
|
15
|
-
|
|
16
|
-
export interface ProxyCallback {
|
|
17
|
-
path: string[]
|
|
18
|
-
args: any[]
|
|
19
|
-
}
|
|
5
|
+
export type Functions = (typeof FUNCTIONS)[number]
|
|
20
6
|
|
|
21
|
-
|
|
22
|
-
export type NodeCreator = (value?: any) => X
|
|
7
|
+
export type Operators = (typeof OPERATOR_KEYS)[number]
|
|
23
8
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
mul(x: X | number): X
|
|
29
|
-
div(x: X | number): X
|
|
30
|
-
mod(x: X | number): X
|
|
31
|
-
equal(x: X | number): X
|
|
32
|
-
notEqual(x: X | number): X
|
|
33
|
-
lessThan(x: X | number): X
|
|
34
|
-
lessThanEqual(x: X | number): X
|
|
35
|
-
greaterThan(x: X | number): X
|
|
36
|
-
greaterThanEqual(x: X | number): X
|
|
37
|
-
and(x: X): X
|
|
38
|
-
or(x: X): X
|
|
39
|
-
not(): X
|
|
9
|
+
export interface NodeProps {
|
|
10
|
+
id?: string
|
|
11
|
+
children?: X[]
|
|
12
|
+
defaultValue?: number | number[]
|
|
40
13
|
}
|
|
41
14
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
asin(): X
|
|
47
|
-
atan(): X
|
|
48
|
-
ceil(): X
|
|
49
|
-
cos(): X
|
|
50
|
-
floor(): X
|
|
51
|
-
fract(): X
|
|
52
|
-
length(): X
|
|
53
|
-
normalize(): X
|
|
54
|
-
sin(): X
|
|
55
|
-
sqrt(): X
|
|
56
|
-
tan(): X
|
|
57
|
-
toVar(): X
|
|
15
|
+
export interface NodeConfig {
|
|
16
|
+
isWebGL?: boolean
|
|
17
|
+
uniforms?: Set<string>
|
|
18
|
+
onUniform?: (name: string, value: any) => void
|
|
58
19
|
}
|
|
59
20
|
|
|
60
|
-
|
|
21
|
+
type _Swizzles<T extends string> = T | `${T}${T}` | `${T}${T}${T}` | `${T}${T}${T}${T}`
|
|
61
22
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
23
|
+
export type Swizzles =
|
|
24
|
+
| _Swizzles<'x' | 'y' | 'z' | 'w'>
|
|
25
|
+
| _Swizzles<'r' | 'g' | 'b' | 'a'>
|
|
26
|
+
| _Swizzles<'p' | 'q'>
|
|
27
|
+
| _Swizzles<'s' | 't'>
|
|
66
28
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
29
|
+
export type NodeTypes =
|
|
30
|
+
| 'uniform'
|
|
31
|
+
| 'variable'
|
|
32
|
+
| 'swizzle'
|
|
33
|
+
| 'operator'
|
|
34
|
+
| 'node_type'
|
|
35
|
+
| 'math_fun'
|
|
36
|
+
| 'declare'
|
|
37
|
+
| 'assign'
|
|
38
|
+
| 'fn'
|
|
39
|
+
| 'if'
|
|
40
|
+
| 'loop'
|
|
41
|
+
| 'scope'
|
|
75
42
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
43
|
+
export interface NodeProxy extends Record<Swizzles, NodeProxy> {
|
|
44
|
+
add(n: X): NodeProxy
|
|
45
|
+
sub(n: X): NodeProxy
|
|
46
|
+
mul(n: X): NodeProxy
|
|
47
|
+
div(n: X): NodeProxy
|
|
48
|
+
mod(n: X): NodeProxy
|
|
49
|
+
equal(n: X): NodeProxy
|
|
50
|
+
notEqual(n: X): NodeProxy
|
|
51
|
+
lessThan(n: X): NodeProxy
|
|
52
|
+
lessThanEqual(n: X): NodeProxy
|
|
53
|
+
greaterThan(n: X): NodeProxy
|
|
54
|
+
greaterThanEqual(n: X): NodeProxy
|
|
55
|
+
and(n: X): NodeProxy
|
|
56
|
+
or(n: X): NodeProxy
|
|
57
|
+
not(): NodeProxy
|
|
58
|
+
assign(n: X): NodeProxy
|
|
59
|
+
toVar(name?: string): NodeProxy
|
|
60
|
+
toString(c?: NodeConfig): string
|
|
61
|
+
type: NodeTypes
|
|
62
|
+
props: NodeProps
|
|
63
|
+
isProxy: true
|
|
81
64
|
}
|
|
82
65
|
|
|
83
|
-
|
|
84
|
-
export interface FunctionNode {
|
|
85
|
-
(...args: any[]): X
|
|
86
|
-
call(x: X[]): X
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// 条件分岐の型
|
|
90
|
-
export interface ConditionalNode {
|
|
91
|
-
ElseIf(condition: X, callback: () => void): ConditionalNode
|
|
92
|
-
Else(callback: () => void): void
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// WebGL/WebGPU変換コンテキスト
|
|
96
|
-
export interface ConversionContext {
|
|
97
|
-
target: 'webgl' | 'webgpu'
|
|
98
|
-
nodes: Map<string, Node>
|
|
99
|
-
variables: Map<string, string>
|
|
100
|
-
functions: Map<string, string>
|
|
101
|
-
}
|
|
66
|
+
export type X = NodeProxy | number | string | null | undefined
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { is } from '../utils/helpers'
|
|
2
|
+
import { code } from './code'
|
|
3
|
+
import { FUNCTIONS, NODE_TYPES, OPERATOR_KEYS } from './const'
|
|
4
|
+
import type { Functions, NodeConfig, NodeType, Operators, Swizzles, X } from './types'
|
|
5
|
+
|
|
6
|
+
export const isSwizzle = (key: unknown): key is Swizzles => {
|
|
7
|
+
return is.str(key) && /^[xyzwrgbastpq]{1,4}$/.test(key)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const isOperator = (key: unknown): key is Operators => {
|
|
11
|
+
return OPERATOR_KEYS.includes(key as Operators)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const isNodeType = (key: unknown): key is NodeType => {
|
|
15
|
+
return NODE_TYPES.includes(key as NodeType)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const isFunction = (key: unknown): key is Functions => {
|
|
19
|
+
return FUNCTIONS.includes(key as Functions)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let count = 0
|
|
23
|
+
|
|
24
|
+
export const getId = () => `i${count++}`
|
|
25
|
+
|
|
26
|
+
export const joins = (children: X[], c: NodeConfig) => {
|
|
27
|
+
return children
|
|
28
|
+
.filter((x) => !is.und(x) && !is.nul(x))
|
|
29
|
+
.map((x) => code(x, c))
|
|
30
|
+
.join(', ')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const inferType = (target: X, c: NodeConfig): string => {
|
|
34
|
+
if (!target || typeof target !== 'object') return 'float'
|
|
35
|
+
const { type, props } = target
|
|
36
|
+
const { children = [] } = props
|
|
37
|
+
const [x, y, z] = children
|
|
38
|
+
if (type === 'node_type') return x as string
|
|
39
|
+
if (type === 'operator') {
|
|
40
|
+
const left = inferType(y, c)
|
|
41
|
+
const right = inferType(z, c)
|
|
42
|
+
if (left === right) return left
|
|
43
|
+
if (left.includes('vec')) return left
|
|
44
|
+
if (right.includes('vec')) return right
|
|
45
|
+
return 'float'
|
|
46
|
+
}
|
|
47
|
+
if (type === 'math_fun') {
|
|
48
|
+
if (['normalize', 'cross', 'reflect'].includes(x as string)) return inferType(children[1], c)
|
|
49
|
+
if (['dot', 'distance', 'length'].includes(x as string)) return 'float'
|
|
50
|
+
return 'float'
|
|
51
|
+
}
|
|
52
|
+
return 'float'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const generateUniforms = (c: NodeConfig): string => {
|
|
56
|
+
if (!c.uniforms || c.uniforms.size === 0) return ''
|
|
57
|
+
const uniformList = Array.from(c.uniforms)
|
|
58
|
+
return (
|
|
59
|
+
uniformList
|
|
60
|
+
.map((name, i) => {
|
|
61
|
+
if (c.isWebGL) return `uniform vec2 ${name};`
|
|
62
|
+
else return `@group(0) @binding(${i}) var<uniform> ${name}: vec2f;`
|
|
63
|
+
})
|
|
64
|
+
.join('\n') + '\n'
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const generateFragmentMain = (body: string, uniforms: string, isWebGL = true) => {
|
|
69
|
+
if (isWebGL)
|
|
70
|
+
return `
|
|
71
|
+
${uniforms}
|
|
72
|
+
#version 300 es
|
|
73
|
+
precision mediump float;
|
|
74
|
+
uniform vec2 iResolution;
|
|
75
|
+
uniform vec2 iMouse;
|
|
76
|
+
uniform float iTime;
|
|
77
|
+
out vec4 fragColor;
|
|
78
|
+
void main() {
|
|
79
|
+
${body}
|
|
80
|
+
}`.trim()
|
|
81
|
+
return `
|
|
82
|
+
@group(0) @binding(0) var<uniform> iResolution: vec2f;
|
|
83
|
+
@group(0) @binding(1) var<uniform> iMouse: vec2f;
|
|
84
|
+
@group(0) @binding(2) var<uniform> iTime: f32;
|
|
85
|
+
${uniforms}
|
|
86
|
+
@fragment
|
|
87
|
+
fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
88
|
+
${body}
|
|
89
|
+
}`.trim()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const fragment = (x: X, c: NodeConfig) => {
|
|
93
|
+
const body = code(x, c)
|
|
94
|
+
const uniforms = generateUniforms(c)
|
|
95
|
+
return generateFragmentMain(body, uniforms, c.isWebGL)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const vertex = (x: X, c: NodeConfig) => {
|
|
99
|
+
const body = code(x, c)
|
|
100
|
+
const uniforms = generateUniforms(c)
|
|
101
|
+
return generateFragmentMain(body, uniforms, c.isWebGL)
|
|
102
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -29,12 +29,10 @@ export interface WebGLState {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export interface WebGPUState {
|
|
32
|
-
uniforms: any
|
|
33
|
-
textures: any
|
|
34
32
|
device: GPUDevice
|
|
35
33
|
context: GPUContext
|
|
36
|
-
groups: any[]
|
|
37
34
|
pipeline: GPUPipeline
|
|
35
|
+
groups: any[]
|
|
38
36
|
resources: any[]
|
|
39
37
|
loadingImg: number
|
|
40
38
|
needsUpdate: boolean
|
package/src/utils/pipeline.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { X } from '../node'
|
|
1
|
+
import { fragment, vertex, X } from '../node'
|
|
3
2
|
import { is } from './helpers'
|
|
4
3
|
import type { GPUContext, GPUDevice, GPUPipeline } from '../types'
|
|
5
4
|
|
|
@@ -21,7 +20,7 @@ fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
|
21
20
|
}
|
|
22
21
|
`
|
|
23
22
|
|
|
24
|
-
export const
|
|
23
|
+
export const createDevice = async (c: GPUContext) => {
|
|
25
24
|
const gpu = (navigator as any).gpu
|
|
26
25
|
const format = gpu.getPreferredCanvasFormat()
|
|
27
26
|
const adapter = await gpu.requestAdapter()
|
|
@@ -33,19 +32,19 @@ export const createDevive = async (c: GPUContext) => {
|
|
|
33
32
|
export const createPipeline = (
|
|
34
33
|
device: GPUDevice,
|
|
35
34
|
format: string,
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
bufferLayouts: any[],
|
|
36
|
+
bindGroupLayouts: any[],
|
|
38
37
|
vs: string | X = defaultVertexWGSL,
|
|
39
38
|
fs: string | X = defaultFragmentWGSL
|
|
40
39
|
) => {
|
|
41
|
-
if (is.
|
|
42
|
-
if (is.
|
|
43
|
-
const layout = device.createPipelineLayout({ bindGroupLayouts
|
|
40
|
+
if (!is.str(fs)) fs = fragment(fs, { isWebGL: false })
|
|
41
|
+
if (!is.str(vs)) vs = vertex(vs, { isWebGL: false })
|
|
42
|
+
const layout = device.createPipelineLayout({ bindGroupLayouts })
|
|
44
43
|
return device.createRenderPipeline({
|
|
45
44
|
vertex: {
|
|
46
45
|
module: device.createShaderModule({ code: vs.trim() }),
|
|
47
46
|
entryPoint: 'main',
|
|
48
|
-
buffers,
|
|
47
|
+
buffers: bufferLayouts,
|
|
49
48
|
},
|
|
50
49
|
fragment: {
|
|
51
50
|
module: device.createShaderModule({ code: fs.trim() }),
|
|
@@ -73,7 +72,7 @@ export const createBindGroup = (device: GPUDevice, resources: any[]) => {
|
|
|
73
72
|
})
|
|
74
73
|
const layout = device.createBindGroupLayout({ entries: entries0 })
|
|
75
74
|
const bindGroup = device.createBindGroup({ layout, entries: entries1 })
|
|
76
|
-
return
|
|
75
|
+
return { layout, bindGroup }
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
export const createDescriptor = (c: GPUContext) => {
|
|
@@ -91,6 +90,12 @@ export const createDescriptor = (c: GPUContext) => {
|
|
|
91
90
|
|
|
92
91
|
export const alignTo256 = (size: number) => Math.ceil(size / 256) * 256
|
|
93
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
|
+
|
|
94
99
|
export const createUniformBuffer = (device: GPUDevice, value: number[]) => {
|
|
95
100
|
const array = new Float32Array(value)
|
|
96
101
|
const size = alignTo256(array.byteLength)
|
|
@@ -101,12 +106,30 @@ export const createUniformBuffer = (device: GPUDevice, value: number[]) => {
|
|
|
101
106
|
export const createTextureSampler = (device: GPUDevice, width = 1280, height = 800) => {
|
|
102
107
|
const texture = device.createTexture({ size: [width, height], format: 'rgba8unorm', usage: 22 })
|
|
103
108
|
const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' })
|
|
104
|
-
return
|
|
109
|
+
return { texture, sampler }
|
|
110
|
+
}
|
|
111
|
+
|
|
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'
|
|
105
121
|
}
|
|
106
122
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
+
}
|
|
135
|
+
}
|
package/src/utils/program.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { X } from '../node'
|
|
1
|
+
import { fragment, vertex, X } from '../node'
|
|
3
2
|
import { is } from './helpers'
|
|
4
3
|
|
|
5
4
|
export const defaultVertexGLSL = /* cpp */ `
|
|
@@ -29,7 +28,7 @@ const createShader = (c: WebGLRenderingContext, source: string, type: number) =>
|
|
|
29
28
|
if (c.getShaderParameter(shader, c.COMPILE_STATUS)) return shader
|
|
30
29
|
const error = c.getShaderInfoLog(shader)
|
|
31
30
|
c.deleteShader(shader)
|
|
32
|
-
|
|
31
|
+
console.warn(`Could not compile shader: ${error}`)
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
export const createProgram = (
|
|
@@ -37,16 +36,19 @@ export const createProgram = (
|
|
|
37
36
|
vs: string | X = defaultVertexGLSL,
|
|
38
37
|
fs: string | X = defaultFragmentGLSL
|
|
39
38
|
) => {
|
|
40
|
-
if (is.
|
|
41
|
-
if (is.
|
|
39
|
+
if (!is.str(fs)) fs = fragment(fs, { isWebGL: true })
|
|
40
|
+
if (!is.str(vs)) vs = vertex(fs, { isWebGL: true })
|
|
42
41
|
const pg = c.createProgram()
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const _vs = createShader(c, vs, c.VERTEX_SHADER)
|
|
43
|
+
const _fs = createShader(c, fs, c.FRAGMENT_SHADER)
|
|
44
|
+
if (!_vs || !_fs) return
|
|
45
|
+
c.attachShader(pg, _vs)
|
|
46
|
+
c.attachShader(pg, _fs)
|
|
45
47
|
c.linkProgram(pg)
|
|
46
48
|
if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
|
|
47
49
|
const error = c.getProgramInfoLog(pg)
|
|
48
50
|
c.deleteProgram(pg)
|
|
49
|
-
|
|
51
|
+
console.warn(`Could not link pg: ${error}`)
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
|
package/src/webgl.ts
CHANGED
|
@@ -5,15 +5,14 @@ import type { GL, WebGLState } from './types'
|
|
|
5
5
|
|
|
6
6
|
export const webgl = async (gl: Partial<GL>) => {
|
|
7
7
|
const c = gl.el!.getContext('webgl2')!
|
|
8
|
-
const pg = createProgram(c, gl.vs, gl.fs)
|
|
8
|
+
const pg = createProgram(c, gl.vs, gl.fs)!
|
|
9
9
|
const state = { context: c, program: pg } as WebGLState
|
|
10
10
|
c.useProgram(pg)
|
|
11
11
|
|
|
12
12
|
let _activeUnit = 0
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const attribLocations = cached((key) => c.getAttribLocation(pg, key))
|
|
13
|
+
const uniforms = cached((key) => c.getUniformLocation(pg, key))
|
|
14
|
+
const attribs = cached((key) => c.getAttribLocation(pg, key))
|
|
15
|
+
const units = cached(() => _activeUnit++)
|
|
17
16
|
|
|
18
17
|
const clean = () => c.deleteProgram(pg)
|
|
19
18
|
|
|
@@ -24,7 +23,7 @@ export const webgl = async (gl: Partial<GL>) => {
|
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
const _attribute = (key = '', value: number[], iboValue: number[]) => {
|
|
27
|
-
const loc =
|
|
26
|
+
const loc = attribs(key, true)
|
|
28
27
|
const vbo = createVbo(c, value)
|
|
29
28
|
const ibo = createIbo(c, iboValue)
|
|
30
29
|
const str = getStride(gl.count!, value, iboValue)
|
|
@@ -32,7 +31,7 @@ export const webgl = async (gl: Partial<GL>) => {
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
const _uniform = (key: string, value: number | number[]) => {
|
|
35
|
-
const loc =
|
|
34
|
+
const loc = uniforms(key)
|
|
36
35
|
if (is.num(value)) return c.uniform1f(loc, value)
|
|
37
36
|
let l = value.length
|
|
38
37
|
if (l <= 4) return c[`uniform${l as 2}fv`](loc, value)
|
|
@@ -40,12 +39,12 @@ export const webgl = async (gl: Partial<GL>) => {
|
|
|
40
39
|
c[`uniformMatrix${l as 2}fv`](loc, false, value)
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
const _texture = (
|
|
42
|
+
const _texture = (key: string, src: string) => {
|
|
44
43
|
const image = new Image()
|
|
45
|
-
Object.assign(image, { src,
|
|
44
|
+
Object.assign(image, { src, crossOrigin: 'anonymous' })
|
|
46
45
|
image.decode().then(() => {
|
|
47
|
-
const loc =
|
|
48
|
-
const unit =
|
|
46
|
+
const loc = uniforms(key)
|
|
47
|
+
const unit = units(key)
|
|
49
48
|
createTexture(c, image, loc, unit)
|
|
50
49
|
})
|
|
51
50
|
}
|
package/src/webgpu.ts
CHANGED
|
@@ -1,52 +1,64 @@
|
|
|
1
|
+
import { nested as cached } from 'reev'
|
|
1
2
|
import { is } from './utils/helpers'
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
+
createDevice,
|
|
4
5
|
createPipeline,
|
|
5
6
|
createDescriptor,
|
|
6
7
|
createUniformBuffer,
|
|
7
8
|
createBindGroup,
|
|
8
9
|
createTextureSampler,
|
|
10
|
+
createVertexBuffer,
|
|
11
|
+
createBufferLayout,
|
|
9
12
|
} from './utils/pipeline'
|
|
10
13
|
import type { GL, WebGPUState } from './types'
|
|
11
14
|
|
|
12
15
|
export const webgpu = async (gl: Partial<GL>) => {
|
|
13
16
|
const c = gl.el!.getContext('webgpu') as any
|
|
14
|
-
const { device, format } = await
|
|
17
|
+
const { device, format } = await createDevice(c)
|
|
15
18
|
const state = {
|
|
16
19
|
device,
|
|
17
20
|
context: c,
|
|
18
|
-
uniforms: {},
|
|
19
|
-
textures: {},
|
|
20
21
|
resources: [[], []],
|
|
21
22
|
loadingImg: 0,
|
|
22
23
|
needsUpdate: true,
|
|
23
24
|
} as WebGPUState
|
|
24
25
|
|
|
25
|
-
const
|
|
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
|
+
})
|
|
37
|
+
|
|
38
|
+
const uniforms = cached((_, value: number[]) => {
|
|
26
39
|
const { array, buffer } = createUniformBuffer(device, value)
|
|
27
40
|
state.resources[0].push({ buffer })
|
|
28
41
|
state.needsUpdate = true
|
|
29
42
|
return { array, buffer }
|
|
30
|
-
}
|
|
43
|
+
})
|
|
31
44
|
|
|
32
|
-
const
|
|
33
|
-
const {
|
|
34
|
-
const [texture, sampler] = createTextureSampler(device, width, height)
|
|
45
|
+
const textures = cached((_, { width, height }: HTMLImageElement) => {
|
|
46
|
+
const { texture, sampler } = createTextureSampler(device, width, height)
|
|
35
47
|
state.resources[1].push(sampler, texture.createView())
|
|
36
48
|
state.needsUpdate = true
|
|
37
49
|
return { texture, width, height }
|
|
38
|
-
}
|
|
50
|
+
})
|
|
39
51
|
|
|
40
52
|
const update = () => {
|
|
41
|
-
const
|
|
42
|
-
|
|
53
|
+
const bindGroupLayouts = [] as any
|
|
54
|
+
bindGroups.length = 0
|
|
43
55
|
state.resources.forEach((resource) => {
|
|
44
56
|
if (!resource.length) return
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
const { layout, bindGroup } = createBindGroup(device, resource)
|
|
58
|
+
bindGroupLayouts.push(layout)
|
|
59
|
+
bindGroups.push(bindGroup)
|
|
48
60
|
})
|
|
49
|
-
state.pipeline = createPipeline(device, format,
|
|
61
|
+
state.pipeline = createPipeline(device, format, bufferLayouts, bindGroupLayouts, gl.vs, gl.fs)
|
|
50
62
|
}
|
|
51
63
|
|
|
52
64
|
const render = () => {
|
|
@@ -56,7 +68,8 @@ export const webgpu = async (gl: Partial<GL>) => {
|
|
|
56
68
|
const encoder = device.createCommandEncoder()
|
|
57
69
|
const pass = encoder.beginRenderPass(createDescriptor(c))
|
|
58
70
|
pass.setPipeline(state.pipeline)
|
|
59
|
-
|
|
71
|
+
bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
|
|
72
|
+
vertexBuffers.forEach((v, i) => pass.setVertexBuffer(i, v))
|
|
60
73
|
pass.draw(gl.count, 1, 0, 0)
|
|
61
74
|
pass.end()
|
|
62
75
|
device.queue.submit([encoder.finish()])
|
|
@@ -65,14 +78,13 @@ export const webgpu = async (gl: Partial<GL>) => {
|
|
|
65
78
|
const clean = () => {}
|
|
66
79
|
|
|
67
80
|
const _attribute = (key = '', value: number[]) => {
|
|
68
|
-
|
|
69
|
-
|
|
81
|
+
const { array, buffer } = attributes(key, value)
|
|
82
|
+
device.queue.writeBuffer(buffer, 0, array)
|
|
70
83
|
}
|
|
71
84
|
|
|
72
85
|
const _uniform = (key: string, value: number | number[]) => {
|
|
73
86
|
if (is.num(value)) value = [value]
|
|
74
|
-
|
|
75
|
-
const { array, buffer } = state.uniforms[key]
|
|
87
|
+
const { array, buffer } = uniforms(key, value)
|
|
76
88
|
array.set(value)
|
|
77
89
|
device.queue.writeBuffer(buffer, 0, array)
|
|
78
90
|
}
|
|
@@ -81,8 +93,7 @@ export const webgpu = async (gl: Partial<GL>) => {
|
|
|
81
93
|
state.loadingImg++
|
|
82
94
|
const source = Object.assign(new Image(), { src, crossOrigin: 'anonymous' })
|
|
83
95
|
source.decode().then(() => {
|
|
84
|
-
|
|
85
|
-
const { texture, width, height } = state.textures[key]
|
|
96
|
+
const { texture, width, height } = textures(key, source)
|
|
86
97
|
device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
|
|
87
98
|
state.loadingImg--
|
|
88
99
|
})
|