glre 0.46.0 → 0.48.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 +1017 -29
- package/dist/addons.d.ts +3 -2
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +27 -26
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/native.d.ts +8 -5
- package/dist/node.cjs +42 -42
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +3 -2
- package/dist/node.js +15 -15
- package/dist/node.js.map +1 -1
- package/dist/react.d.ts +27 -26
- package/dist/solid.d.ts +27 -26
- package/package.json +1 -1
- package/src/helpers.ts +2 -2
- package/src/index.ts +5 -3
- package/src/node/types.ts +0 -2
- package/src/node/utils/index.ts +4 -1
- package/src/node/utils/infer.ts +13 -14
- package/src/node/utils/parse.ts +5 -5
- package/src/node/utils/utils.ts +13 -8
- package/src/types.ts +6 -4
- package/src/webgl/compute.ts +4 -4
- package/src/webgl/graphic.ts +6 -6
- package/src/webgpu/compute.ts +5 -5
- package/src/webgpu/graphic.ts +15 -27
- package/src/webgpu/index.ts +36 -17
- package/src/webgpu/utils.ts +23 -27
package/dist/react.d.ts
CHANGED
|
@@ -69,28 +69,6 @@ declare const OPERATOR_TYPE_RULES: readonly [readonly ["float", "vec2", "vec2"],
|
|
|
69
69
|
*/
|
|
70
70
|
declare const FUNCTIONS: readonly [...("texture" | "all" | "any" | "determinant" | "distance" | "dot" | "length" | "lengthSq" | "luminance" | "cross" | "cubeTexture" | "texelFetch" | "textureLod")[], "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "ceil", "cos", "cosh", "dFdx", "dFdy", "degrees", "exp", "exp2", "floor", "fract", "fwidth", "inverse", "inverseSqrt", "log", "log2", "negate", "normalize", "oneMinus", "radians", "reciprocal", "round", "sign", "sin", "sinh", "sqrt", "tan", "tanh", "trunc", "saturate", "atan2", "clamp", "max", "min", "mix", "pow", "reflect", "refract", "smoothstep", "step"];
|
|
71
71
|
|
|
72
|
-
/**
|
|
73
|
-
* binding
|
|
74
|
-
*/
|
|
75
|
-
declare const createBinding: () => {
|
|
76
|
-
uniform: reev.Nested<{
|
|
77
|
-
group: number;
|
|
78
|
-
binding: number;
|
|
79
|
-
}, []>;
|
|
80
|
-
texture: reev.Nested<{
|
|
81
|
-
group: number;
|
|
82
|
-
binding: number;
|
|
83
|
-
}, []>;
|
|
84
|
-
storage: reev.Nested<{
|
|
85
|
-
group: number;
|
|
86
|
-
binding: number;
|
|
87
|
-
}, []>;
|
|
88
|
-
attrib: reev.Nested<{
|
|
89
|
-
location: number;
|
|
90
|
-
}, []>;
|
|
91
|
-
};
|
|
92
|
-
type Binding = ReturnType<typeof createBinding>;
|
|
93
|
-
|
|
94
72
|
type Constants = (typeof CONSTANTS)[number] | 'void';
|
|
95
73
|
type Conversions = (typeof CONVERSIONS)[number];
|
|
96
74
|
type Functions = (typeof FUNCTIONS)[number];
|
|
@@ -123,7 +101,6 @@ interface NodeProps {
|
|
|
123
101
|
}
|
|
124
102
|
interface NodeContext {
|
|
125
103
|
gl?: Partial<GL>;
|
|
126
|
-
binding?: Binding;
|
|
127
104
|
label?: 'vert' | 'frag' | 'compute';
|
|
128
105
|
isWebGL?: boolean;
|
|
129
106
|
units?: any;
|
|
@@ -408,6 +385,28 @@ interface _X<T extends C> {
|
|
|
408
385
|
step<U extends C>(edge: number | X<U>): X<InferOperator<T, U>>;
|
|
409
386
|
}
|
|
410
387
|
|
|
388
|
+
/**
|
|
389
|
+
* binding
|
|
390
|
+
*/
|
|
391
|
+
declare const createBinding: () => {
|
|
392
|
+
uniform: reev.Nested<{
|
|
393
|
+
group: number;
|
|
394
|
+
binding: number;
|
|
395
|
+
}, []>;
|
|
396
|
+
texture: reev.Nested<{
|
|
397
|
+
group: number;
|
|
398
|
+
binding: number;
|
|
399
|
+
}, []>;
|
|
400
|
+
storage: reev.Nested<{
|
|
401
|
+
group: number;
|
|
402
|
+
binding: number;
|
|
403
|
+
}, []>;
|
|
404
|
+
attrib: reev.Nested<{
|
|
405
|
+
location: number;
|
|
406
|
+
}, []>;
|
|
407
|
+
};
|
|
408
|
+
type Binding = ReturnType<typeof createBinding>;
|
|
409
|
+
|
|
411
410
|
type GL = EventState<{
|
|
412
411
|
/**
|
|
413
412
|
* initial value
|
|
@@ -445,7 +444,9 @@ type GL = EventState<{
|
|
|
445
444
|
gpu: GPUCanvasContext;
|
|
446
445
|
device: GPUDevice;
|
|
447
446
|
format: GPUTextureFormat;
|
|
448
|
-
|
|
447
|
+
passEncoder: GPURenderPassEncoder;
|
|
448
|
+
commandEncoder: GPUCommandEncoder;
|
|
449
|
+
depthTexture?: GPUTexture;
|
|
449
450
|
binding: Binding;
|
|
450
451
|
/**
|
|
451
452
|
* core state
|
|
@@ -499,10 +500,10 @@ type Storage = number[] | Float32Array;
|
|
|
499
500
|
* for webgpu
|
|
500
501
|
*/
|
|
501
502
|
interface UniformData {
|
|
502
|
-
array: Float32Array;
|
|
503
|
-
buffer: GPUBuffer;
|
|
504
503
|
binding: number;
|
|
505
504
|
group: number;
|
|
505
|
+
array: Float32Array;
|
|
506
|
+
buffer: GPUBuffer;
|
|
506
507
|
}
|
|
507
508
|
interface TextureData {
|
|
508
509
|
binding: number;
|
package/dist/solid.d.ts
CHANGED
|
@@ -69,28 +69,6 @@ declare const OPERATOR_TYPE_RULES: readonly [readonly ["float", "vec2", "vec2"],
|
|
|
69
69
|
*/
|
|
70
70
|
declare const FUNCTIONS: readonly [...("texture" | "all" | "any" | "determinant" | "distance" | "dot" | "length" | "lengthSq" | "luminance" | "cross" | "cubeTexture" | "texelFetch" | "textureLod")[], "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "ceil", "cos", "cosh", "dFdx", "dFdy", "degrees", "exp", "exp2", "floor", "fract", "fwidth", "inverse", "inverseSqrt", "log", "log2", "negate", "normalize", "oneMinus", "radians", "reciprocal", "round", "sign", "sin", "sinh", "sqrt", "tan", "tanh", "trunc", "saturate", "atan2", "clamp", "max", "min", "mix", "pow", "reflect", "refract", "smoothstep", "step"];
|
|
71
71
|
|
|
72
|
-
/**
|
|
73
|
-
* binding
|
|
74
|
-
*/
|
|
75
|
-
declare const createBinding: () => {
|
|
76
|
-
uniform: reev.Nested<{
|
|
77
|
-
group: number;
|
|
78
|
-
binding: number;
|
|
79
|
-
}, []>;
|
|
80
|
-
texture: reev.Nested<{
|
|
81
|
-
group: number;
|
|
82
|
-
binding: number;
|
|
83
|
-
}, []>;
|
|
84
|
-
storage: reev.Nested<{
|
|
85
|
-
group: number;
|
|
86
|
-
binding: number;
|
|
87
|
-
}, []>;
|
|
88
|
-
attrib: reev.Nested<{
|
|
89
|
-
location: number;
|
|
90
|
-
}, []>;
|
|
91
|
-
};
|
|
92
|
-
type Binding = ReturnType<typeof createBinding>;
|
|
93
|
-
|
|
94
72
|
type Constants = (typeof CONSTANTS)[number] | 'void';
|
|
95
73
|
type Conversions = (typeof CONVERSIONS)[number];
|
|
96
74
|
type Functions = (typeof FUNCTIONS)[number];
|
|
@@ -123,7 +101,6 @@ interface NodeProps {
|
|
|
123
101
|
}
|
|
124
102
|
interface NodeContext {
|
|
125
103
|
gl?: Partial<GL>;
|
|
126
|
-
binding?: Binding;
|
|
127
104
|
label?: 'vert' | 'frag' | 'compute';
|
|
128
105
|
isWebGL?: boolean;
|
|
129
106
|
units?: any;
|
|
@@ -408,6 +385,28 @@ interface _X<T extends C> {
|
|
|
408
385
|
step<U extends C>(edge: number | X<U>): X<InferOperator<T, U>>;
|
|
409
386
|
}
|
|
410
387
|
|
|
388
|
+
/**
|
|
389
|
+
* binding
|
|
390
|
+
*/
|
|
391
|
+
declare const createBinding: () => {
|
|
392
|
+
uniform: reev.Nested<{
|
|
393
|
+
group: number;
|
|
394
|
+
binding: number;
|
|
395
|
+
}, []>;
|
|
396
|
+
texture: reev.Nested<{
|
|
397
|
+
group: number;
|
|
398
|
+
binding: number;
|
|
399
|
+
}, []>;
|
|
400
|
+
storage: reev.Nested<{
|
|
401
|
+
group: number;
|
|
402
|
+
binding: number;
|
|
403
|
+
}, []>;
|
|
404
|
+
attrib: reev.Nested<{
|
|
405
|
+
location: number;
|
|
406
|
+
}, []>;
|
|
407
|
+
};
|
|
408
|
+
type Binding = ReturnType<typeof createBinding>;
|
|
409
|
+
|
|
411
410
|
type GL = EventState<{
|
|
412
411
|
/**
|
|
413
412
|
* initial value
|
|
@@ -445,7 +444,9 @@ type GL = EventState<{
|
|
|
445
444
|
gpu: GPUCanvasContext;
|
|
446
445
|
device: GPUDevice;
|
|
447
446
|
format: GPUTextureFormat;
|
|
448
|
-
|
|
447
|
+
passEncoder: GPURenderPassEncoder;
|
|
448
|
+
commandEncoder: GPUCommandEncoder;
|
|
449
|
+
depthTexture?: GPUTexture;
|
|
449
450
|
binding: Binding;
|
|
450
451
|
/**
|
|
451
452
|
* core state
|
|
@@ -499,10 +500,10 @@ type Storage = number[] | Float32Array;
|
|
|
499
500
|
* for webgpu
|
|
500
501
|
*/
|
|
501
502
|
interface UniformData {
|
|
502
|
-
array: Float32Array;
|
|
503
|
-
buffer: GPUBuffer;
|
|
504
503
|
binding: number;
|
|
505
504
|
group: number;
|
|
505
|
+
array: Float32Array;
|
|
506
|
+
buffer: GPUBuffer;
|
|
506
507
|
}
|
|
507
508
|
interface TextureData {
|
|
508
509
|
binding: number;
|
package/package.json
CHANGED
package/src/helpers.ts
CHANGED
|
@@ -64,9 +64,9 @@ const calcStride = (arrayLength: number, count = 3) => {
|
|
|
64
64
|
return -1
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
export const getStride = (arrayLength: number, count = 1, error = console.warn) => {
|
|
67
|
+
export const getStride = (arrayLength: number, count = 1, error = console.warn, id = '') => {
|
|
68
68
|
const ret = calcStride(arrayLength, count)
|
|
69
|
-
if (!isValidStride(ret)) error(`glre attribute error: Invalid attribute length ${arrayLength}
|
|
69
|
+
if (!isValidStride(ret)) error(`glre attribute error: Invalid attribute length ${arrayLength}, ${id ? `${id} ` : ' '}must divide by vertex count (${count}) with valid stride (1,2,3,4,9,16)`)
|
|
70
70
|
return ret
|
|
71
71
|
}
|
|
72
72
|
|
package/src/index.ts
CHANGED
|
@@ -55,17 +55,19 @@ export const createGL = (...args: Partial<GL>[]) => {
|
|
|
55
55
|
gl.el = findElement(gl) || el || args.map(findElement).find(Boolean)
|
|
56
56
|
const isAppend = !gl.el // Check first: canvas may unmount during WebGPU async processing
|
|
57
57
|
if (isAppend && !gl.isNative) gl.el = document.createElement('canvas')
|
|
58
|
-
for (
|
|
58
|
+
for (let i = 0; i < args.length; i++) {
|
|
59
|
+
const arg = args[i]
|
|
59
60
|
gl.fs = arg.fs || arg.frag || arg.fragment || undefined
|
|
60
61
|
gl.cs = arg.cs || arg.comp || arg.compute || undefined
|
|
61
62
|
gl.vs = arg.vs || arg.vert || arg.vertex || undefined
|
|
62
|
-
gl.triangleCount = arg.triangleCount ||
|
|
63
|
+
gl.triangleCount = arg.triangleCount || 2
|
|
63
64
|
gl.instanceCount = arg.instanceCount || 1
|
|
64
65
|
gl.particleCount = arg.particleCount || 1024
|
|
66
|
+
gl.count = arg.count || gl.triangleCount * 3 || 6
|
|
65
67
|
gl(arg)
|
|
66
68
|
if (is.bol(arg.isWebGL)) gl.isWebGL = arg.isWebGL || !isWebGPUSupported()
|
|
67
69
|
if (gl.isWebGL) webgl(gl)
|
|
68
|
-
else await webgpu(gl)
|
|
70
|
+
else await webgpu(gl, i === args.length - 1)
|
|
69
71
|
if (arg.mount) arg.mount() // events added in mount phase need explicit call to execute
|
|
70
72
|
}
|
|
71
73
|
if (!gl.el || gl.isError) return // stop if error or canvas was unmounted during async
|
package/src/node/types.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS, OPERATOR_TYPE_RULES } from './utils/const'
|
|
2
2
|
import type { GL } from '../types'
|
|
3
|
-
import type { Binding } from '../webgpu/utils'
|
|
4
3
|
|
|
5
4
|
export type Constants = (typeof CONSTANTS)[number] | 'void'
|
|
6
5
|
export type Conversions = (typeof CONVERSIONS)[number]
|
|
@@ -81,7 +80,6 @@ export interface NodeProps {
|
|
|
81
80
|
|
|
82
81
|
export interface NodeContext {
|
|
83
82
|
gl?: Partial<GL>
|
|
84
|
-
binding?: Binding
|
|
85
83
|
label?: 'vert' | 'frag' | 'compute'
|
|
86
84
|
isWebGL?: boolean
|
|
87
85
|
units?: any // @TODO FIX
|
package/src/node/utils/index.ts
CHANGED
|
@@ -114,7 +114,10 @@ export const code = <T extends C>(target: Y<T>, c?: NodeContext | null): string
|
|
|
114
114
|
setupEvent(c, id, varType, target, x)
|
|
115
115
|
head = parseUniformHead(c, id, varType)
|
|
116
116
|
}
|
|
117
|
-
if (type === 'storage')
|
|
117
|
+
if (type === 'storage') {
|
|
118
|
+
setupEvent(c, id, type, target, x)
|
|
119
|
+
head = parseStorageHead(c, id, infer(target, c))
|
|
120
|
+
}
|
|
118
121
|
if (type === 'constant') head = parseConstantHead(c, id, infer(target, c), code(x, c))
|
|
119
122
|
if (head) {
|
|
120
123
|
c.code?.headers.set(id, head)
|
package/src/node/utils/infer.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isConstants, isElement, isX, isSwizzle } from './utils'
|
|
2
2
|
import { BUILTIN_TYPES, COMPONENT_COUNT_TO_TYPE, FUNCTION_RETURN_TYPES, getOperatorResultType, validateOperatorTypes } from './const'
|
|
3
|
-
import { is, getStride } from '../../helpers'
|
|
3
|
+
import { is, getStride, isFloat32 } from '../../helpers'
|
|
4
4
|
import type { Constants as C, NodeContext, X, Y } from '../types'
|
|
5
5
|
|
|
6
6
|
const inferBuiltin = <T extends C>(id: string | undefined) => {
|
|
@@ -16,14 +16,14 @@ export const inferPrimitiveType = <T extends C>(x: Y<T>) => {
|
|
|
16
16
|
if (is.bol(x)) return 'bool' as T
|
|
17
17
|
if (is.str(x)) return 'texture' as T
|
|
18
18
|
if (is.num(x)) return 'float' as T // @TODO FIX: Number.isInteger(x) ? 'int' : 'float'
|
|
19
|
-
if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] as T
|
|
19
|
+
if (is.arr(x) || isFloat32(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] as T
|
|
20
20
|
if (isElement(x)) return 'texture' as T
|
|
21
21
|
return 'void' as T
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const inferFromCount = <T extends C>(count: number) => {
|
|
24
|
+
const inferFromCount = <T extends C>(count: number, error = console.warn, id = '') => {
|
|
25
25
|
const ret = COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE] as T
|
|
26
|
-
if (!ret)
|
|
26
|
+
if (!ret) console.warn(`glre node system error: Cannot infer ${id ? `${id} ` : ''} type from array length ${count}. Check your data size. Supported: 1(float), 2(vec2), 3(vec3), 4(vec4), 9(mat3), 16(mat4)`)
|
|
27
27
|
return ret
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -54,16 +54,15 @@ export const inferImpl = <T extends C>(target: X<T>, c: NodeContext): T => {
|
|
|
54
54
|
if (!inferFrom || inferFrom.length === 0) return 'void' as T
|
|
55
55
|
return inferFromArray(inferFrom, c)
|
|
56
56
|
}
|
|
57
|
-
if (type === 'attribute'
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
57
|
+
if (type === 'attribute' || type === 'instance')
|
|
58
|
+
if (is.arr(x)) {
|
|
59
|
+
const count = type === 'instance' ? c.gl?.instanceCount : c.gl?.count
|
|
60
|
+
const stride = getStride(x.length, count, c.gl?.error, id)
|
|
61
|
+
return inferFromCount(stride, c.gl?.error, id)
|
|
62
|
+
}
|
|
63
|
+
|
|
65
64
|
if (type === 'member') {
|
|
66
|
-
if (isSwizzle(y)) return inferFromCount(y.length)
|
|
65
|
+
if (isSwizzle(y)) return inferFromCount(y.length, c.gl?.error, id)
|
|
67
66
|
if (isX(x)) {
|
|
68
67
|
const structType = infer(x, c)
|
|
69
68
|
const fields = c.code?.structStructFields?.get(structType)
|
|
@@ -78,7 +77,7 @@ export const inferImpl = <T extends C>(target: X<T>, c: NodeContext): T => {
|
|
|
78
77
|
export const infer = <T extends C>(target: Y<T>, c?: NodeContext | null): T => {
|
|
79
78
|
if (!c) c = {}
|
|
80
79
|
if (!isX(target)) return inferPrimitiveType(target)
|
|
81
|
-
if (is.arr(target)) return inferFromCount(target.length)
|
|
80
|
+
if (is.arr(target)) return inferFromCount(target.length, c.gl?.error, target.props.id)
|
|
82
81
|
if (!c.infers) c.infers = new WeakMap<X<T>, C>()
|
|
83
82
|
if (c.infers.has(target)) return c.infers.get(target) as T
|
|
84
83
|
const ret = inferImpl(target, c)
|
package/src/node/utils/parse.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { code } from '.'
|
|
|
2
2
|
import { infer } from './infer'
|
|
3
3
|
import { getConversions, addDependency } from './utils'
|
|
4
4
|
import { is } from '../../helpers'
|
|
5
|
-
import type { Constants, NodeContext, NodeProps, StructFields, Y } from '../types'
|
|
6
5
|
import { storageSize } from '../../webgl/utils'
|
|
6
|
+
import type { Constants, NodeContext, NodeProps, StructFields, Y } from '../types'
|
|
7
7
|
|
|
8
8
|
export const parseArray = (children: Y[], c: NodeContext) => {
|
|
9
9
|
return children
|
|
@@ -159,7 +159,7 @@ export const parseVaryingHead = (c: NodeContext, id: string, type: Constants) =>
|
|
|
159
159
|
|
|
160
160
|
export const parseAttribHead = (c: NodeContext, id: string, type: Constants) => {
|
|
161
161
|
if (c.isWebGL) return `${type} ${id};`
|
|
162
|
-
const { location = 0 } = c.binding?.attrib(id) || {}
|
|
162
|
+
const { location = 0 } = c.gl?.binding?.attrib(id) || {}
|
|
163
163
|
const wgslType = getConversions(type, c)
|
|
164
164
|
return `@location(${location}) ${id}: ${wgslType}`
|
|
165
165
|
}
|
|
@@ -171,10 +171,10 @@ export const parseUniformHead = (c: NodeContext, id: string, type: Constants) =>
|
|
|
171
171
|
? `uniform sampler2D ${id};`
|
|
172
172
|
: `uniform ${type} ${id};`
|
|
173
173
|
if (isTexture) {
|
|
174
|
-
const { group = 1, binding = 0 } = c.binding?.texture(id) || {}
|
|
174
|
+
const { group = 1, binding = 0 } = c.gl?.binding?.texture(id) || {}
|
|
175
175
|
return `@group(${group}) @binding(${binding}) var ${id}Sampler: sampler;\n` + `@group(${group}) @binding(${binding + 1}) var ${id}: texture_2d<f32>;`
|
|
176
176
|
}
|
|
177
|
-
const { group = 0, binding = 0 } = c.binding?.uniform(id) || {}
|
|
177
|
+
const { group = 0, binding = 0 } = c.gl?.binding?.uniform(id) || {}
|
|
178
178
|
const wgslType = getConversions(type, c)
|
|
179
179
|
return `@group(${group}) @binding(${binding}) var<uniform> ${id}: ${wgslType};`
|
|
180
180
|
}
|
|
@@ -186,7 +186,7 @@ export const parseStorageHead = (c: NodeContext, id: string, type: Constants) =>
|
|
|
186
186
|
const location = c.units?.(id)
|
|
187
187
|
return `${ret}\nlayout(location = ${location}) out vec4 _${id};` // out texture buffer
|
|
188
188
|
}
|
|
189
|
-
const { group = 0, binding = 0 } = c.binding?.storage(id) || {}
|
|
189
|
+
const { group = 0, binding = 0 } = c.gl?.binding?.storage(id) || {}
|
|
190
190
|
const wgslType = getConversions(type, c)
|
|
191
191
|
return `@group(${group}) @binding(${binding}) var<storage, read_write> ${id}: array<${wgslType}>;`
|
|
192
192
|
}
|
package/src/node/utils/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS, OPERATORS, TYPE_MAPPING, WGSL_TO_GLSL_BUILTIN } from './const'
|
|
2
|
-
import { is } from '../../helpers'
|
|
2
|
+
import { is, isFloat32 } from '../../helpers'
|
|
3
3
|
import { storageSize } from '../../webgl/utils'
|
|
4
4
|
import type { Constants as C, Conversions, Functions, NodeContext, Operators, Swizzles, X, Y } from '../types'
|
|
5
5
|
|
|
@@ -103,28 +103,33 @@ export const addDependency = (c: NodeContext, id = '', type: string) => {
|
|
|
103
103
|
*/
|
|
104
104
|
const getEventFun = (c: NodeContext, id: string, type: string) => {
|
|
105
105
|
if (c.isWebGL) {
|
|
106
|
-
if (type === 'attribute') return
|
|
107
|
-
if (type === 'instance') return
|
|
108
|
-
if (type === 'texture') return
|
|
106
|
+
if (type === 'attribute') return c.gl?.attribute?.bind(null, id as any)
|
|
107
|
+
if (type === 'instance') return c.gl?.instance?.bind(null, id as any)
|
|
108
|
+
if (type === 'texture') return c.gl?.texture?.bind(null, id as any)
|
|
109
|
+
if (type === 'storage') return c.gl?.storage?.bind(null, id as any)
|
|
109
110
|
return (value: any) => c.gl?.uniform?.(id, value)
|
|
110
111
|
}
|
|
111
|
-
if (type === 'attribute') return
|
|
112
|
-
if (type === 'instance') return
|
|
113
|
-
if (type === 'texture') return
|
|
112
|
+
if (type === 'attribute') return c.gl?._attribute?.bind(null, id)
|
|
113
|
+
if (type === 'instance') return c.gl?._instance?.bind(null, id)
|
|
114
|
+
if (type === 'texture') return c.gl?._texture?.bind(null, id)
|
|
115
|
+
if (type === 'storage') return c.gl?._storage?.bind(null, id)
|
|
114
116
|
return (value: any) => c.gl?._uniform?.(id, value)
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
const safeEventCall = <T extends C>(x: X<T>, fun: (value:
|
|
119
|
+
const safeEventCall = <T extends C>(x: X<T>, fun: (value: any) => void) => {
|
|
118
120
|
if (is.und(x)) return
|
|
119
121
|
if (!isX(x)) return fun(x) // for uniform(0) or uniform([0, 1])
|
|
120
122
|
if (x.type !== 'conversion') return
|
|
121
123
|
const args = x.props.children?.slice(1)
|
|
122
124
|
if (is.und(args?.[0])) return // ignore if uniform(vec2())
|
|
125
|
+
if (is.arr(args[0])) return fun(args[0]) // for attribute(vec2([0, 0.73, -1, -1, 1, -1]))
|
|
126
|
+
if (isFloat32(args[0])) return fun(args[0]) // for storage(float(new Float32Array(1024)))
|
|
123
127
|
fun(args.map((x) => x ?? args[0])) // for uniform(vec2(1)) or uniform(vec2(1, 1))
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
export const setupEvent = (c: NodeContext, id: string, type: string, target: X, child: X) => {
|
|
127
131
|
const fun = getEventFun(c, id, type)
|
|
132
|
+
if (!fun) return
|
|
128
133
|
safeEventCall(child, fun)
|
|
129
134
|
target.listeners.add(fun)
|
|
130
135
|
return fun
|
package/src/types.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type GL = EventState<{
|
|
|
18
18
|
height?: number
|
|
19
19
|
size: [number, number]
|
|
20
20
|
mouse: [number, number]
|
|
21
|
-
count: number
|
|
21
|
+
count: number // triangleCount × 3
|
|
22
22
|
triangleCount: number
|
|
23
23
|
instanceCount: number
|
|
24
24
|
particleCount: number | [number, number] | [number, number, number]
|
|
@@ -40,7 +40,9 @@ export type GL = EventState<{
|
|
|
40
40
|
gpu: GPUCanvasContext
|
|
41
41
|
device: GPUDevice
|
|
42
42
|
format: GPUTextureFormat
|
|
43
|
-
|
|
43
|
+
passEncoder: GPURenderPassEncoder
|
|
44
|
+
commandEncoder: GPUCommandEncoder
|
|
45
|
+
depthTexture?: GPUTexture
|
|
44
46
|
binding: Binding
|
|
45
47
|
|
|
46
48
|
/**
|
|
@@ -91,10 +93,10 @@ type Storage = number[] | Float32Array
|
|
|
91
93
|
* for webgpu
|
|
92
94
|
*/
|
|
93
95
|
export interface UniformData {
|
|
94
|
-
array: Float32Array
|
|
95
|
-
buffer: GPUBuffer
|
|
96
96
|
binding: number
|
|
97
97
|
group: number
|
|
98
|
+
array: Float32Array
|
|
99
|
+
buffer: GPUBuffer
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
export interface TextureData {
|
package/src/webgl/compute.ts
CHANGED
|
@@ -4,17 +4,17 @@ import { GLSL_VS, is } from '../helpers'
|
|
|
4
4
|
import type { GL } from '../types'
|
|
5
5
|
|
|
6
6
|
export const compute = (gl: GL) => {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
let { cs, particleCount, gl: c } = gl
|
|
8
|
+
if (!cs) return
|
|
9
9
|
c.getExtension('EXT_color_buffer_float') // Enable high precision GPGPU by writing to float textures
|
|
10
10
|
|
|
11
11
|
let _texture = 0 // for texture active units
|
|
12
12
|
let _storage = 0 // for storage current num
|
|
13
13
|
|
|
14
14
|
const units = nested(() => _texture++)
|
|
15
|
-
|
|
15
|
+
cs = is.str(cs) ? cs : cs!.compute({ isWebGL: true, gl, units })
|
|
16
16
|
const pg = createProgram(c, cs, GLSL_VS, gl)!
|
|
17
|
-
const size = storageSize(
|
|
17
|
+
const size = storageSize(particleCount)
|
|
18
18
|
|
|
19
19
|
const uniforms = nested((key) => c.getUniformLocation(pg, key)!)
|
|
20
20
|
const storages = nested((key) => {
|
package/src/webgl/graphic.ts
CHANGED
|
@@ -4,17 +4,17 @@ import { createBuffer, createProgram, createTexture, updateAttrib, updateBuffer,
|
|
|
4
4
|
import type { GL } from '../types'
|
|
5
5
|
|
|
6
6
|
export const graphic = (gl: GL) => {
|
|
7
|
+
let { fs, vs, gl: c } = gl // @TODO Save this WebGPU instance's count (overwritten per args) but no change now for top page
|
|
7
8
|
const config = { isWebGL: true, gl }
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const vs = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs.vertex(config)) : GLSL_VS
|
|
9
|
+
fs = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs.fragment(config)) : GLSL_FS
|
|
10
|
+
vs = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs.vertex(config)) : GLSL_VS
|
|
11
11
|
const pg = createProgram(c, fs, vs, gl)!
|
|
12
12
|
let activeUnit = 0
|
|
13
13
|
|
|
14
14
|
const units = nested(() => activeUnit++)
|
|
15
15
|
const uniforms = nested((key) => c.getUniformLocation(pg, key))
|
|
16
16
|
const attributes = nested((key, value: number[], isInstance = false) => {
|
|
17
|
-
const stride = getStride(value.length, isInstance ? gl.instanceCount : gl.
|
|
17
|
+
const stride = getStride(value.length, isInstance ? gl.instanceCount : gl.count, gl.error, key)
|
|
18
18
|
return { stride, location: c.getAttribLocation(pg, key), ...createBuffer(c, value) }
|
|
19
19
|
})
|
|
20
20
|
|
|
@@ -56,8 +56,8 @@ export const graphic = (gl: GL) => {
|
|
|
56
56
|
gl('render', () => {
|
|
57
57
|
c.useProgram((gl.program = pg))
|
|
58
58
|
if (gl.instanceCount > 1) {
|
|
59
|
-
c.drawArraysInstanced(c.TRIANGLES, 0, gl.
|
|
60
|
-
} else c.drawArrays(c.TRIANGLES, 0, gl.
|
|
59
|
+
c.drawArraysInstanced(c.TRIANGLES, 0, gl.count, gl.instanceCount)
|
|
60
|
+
} else c.drawArrays(c.TRIANGLES, 0, gl.count)
|
|
61
61
|
c.bindFramebuffer(c.FRAMEBUFFER, null)
|
|
62
62
|
})
|
|
63
63
|
}
|
package/src/webgpu/compute.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { nested } from 'reev'
|
|
2
2
|
import { createBuffer, updateBuffer, workgroupCount } from './utils'
|
|
3
|
-
import type { Binding } from './utils'
|
|
4
3
|
import type { GL } from '../types'
|
|
5
4
|
|
|
6
|
-
export const compute = (gl: GL
|
|
5
|
+
export const compute = (gl: GL) => {
|
|
6
|
+
const { particleCount } = gl // Save this WebGPU instance's particleCount (overwritten per args)
|
|
7
7
|
let pipeline: GPUComputePipeline | undefined
|
|
8
8
|
let bindGroups: GPUBindGroup[] | undefined
|
|
9
9
|
|
|
10
10
|
const storages = nested((key, value: number[] | Float32Array) => {
|
|
11
|
-
return { ...
|
|
11
|
+
return { ...gl.binding.storage(key), ...createBuffer(gl.device, value, 'storage') }
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
gl('_storage', (key: string, value: number[] | Float32Array) => {
|
|
@@ -18,10 +18,10 @@ export const compute = (gl: GL, bindings: Binding) => {
|
|
|
18
18
|
|
|
19
19
|
gl('render', () => {
|
|
20
20
|
if (!pipeline || !bindGroups) return
|
|
21
|
-
const pass = gl.
|
|
21
|
+
const pass = gl.commandEncoder.beginComputePass()
|
|
22
22
|
pass.setPipeline(pipeline)
|
|
23
23
|
bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
|
|
24
|
-
const { x, y, z } = workgroupCount(
|
|
24
|
+
const { x, y, z } = workgroupCount(particleCount)
|
|
25
25
|
pass.dispatchWorkgroups(x, y, z)
|
|
26
26
|
pass.end()
|
|
27
27
|
})
|
package/src/webgpu/graphic.ts
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
import { nested } from 'reev'
|
|
2
|
-
import {
|
|
3
|
-
import { createBuffer,
|
|
4
|
-
import type { Binding } from './utils'
|
|
2
|
+
import { getStride, is, loadingTexture } from '../helpers'
|
|
3
|
+
import { createBuffer, createTextureSampler, updateBuffer } from './utils'
|
|
5
4
|
import type { GL } from '../types'
|
|
6
5
|
|
|
7
|
-
export const graphic = (gl: GL,
|
|
6
|
+
export const graphic = (gl: GL, update = () => {}) => {
|
|
7
|
+
const { count, instanceCount } = gl // // Save this WebGPU item's count (overwritten per args)
|
|
8
8
|
let pipeline: GPURenderPipeline
|
|
9
9
|
let bindGroups: GPUBindGroup[]
|
|
10
10
|
let vertexBuffers: GPUBuffer[]
|
|
11
|
-
let depthTexture: GPUTexture
|
|
12
11
|
|
|
13
|
-
const attributes = nested((key, value: number[], isInstance = false, stride = getStride(value.length, isInstance ?
|
|
12
|
+
const attributes = nested((key, value: number[], isInstance = false, stride = getStride(value.length, isInstance ? instanceCount : count, gl.error, key)) => {
|
|
14
13
|
update()
|
|
15
|
-
return { ...
|
|
14
|
+
return { ...gl.binding.attrib(key), ...createBuffer(gl.device, value, 'attrib'), isInstance, stride }
|
|
16
15
|
})
|
|
17
16
|
|
|
18
17
|
const uniforms = nested((key, value: number[] | Float32Array) => {
|
|
19
18
|
update()
|
|
20
|
-
return { ...
|
|
19
|
+
return { ...gl.binding.uniform(key), ...createBuffer(gl.device, value, 'uniform') }
|
|
21
20
|
})
|
|
22
21
|
|
|
23
22
|
const textures = nested((key, width = 1, height = 1) => {
|
|
24
23
|
update()
|
|
25
|
-
return { ...
|
|
24
|
+
return { ...gl.binding.texture(key), ...createTextureSampler(gl.device, width, height) }
|
|
26
25
|
})
|
|
27
26
|
|
|
28
27
|
gl('_attribute', (key: string, value: number[] | Float32Array) => {
|
|
@@ -45,11 +44,9 @@ export const graphic = (gl: GL, bindings: Binding, update = () => {}) => {
|
|
|
45
44
|
const t = textures(key)
|
|
46
45
|
loadingTexture(src, (source, isVideo) => {
|
|
47
46
|
const [width, height] = isVideo ? [source.videoWidth, source.videoHeight] : [source.width, source.height]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
update() // Rebuilding BindGroups because the texture size has changed
|
|
52
|
-
}
|
|
47
|
+
t.texture.destroy()
|
|
48
|
+
Object.assign(t, createTextureSampler(gl.device, width, height))
|
|
49
|
+
update() // Rebuilding BindGroups because the texture size has changed
|
|
53
50
|
const render = () => void gl.device.queue.copyExternalImageToTexture({ source }, { texture: t.texture }, { width, height })
|
|
54
51
|
if (isVideo) gl({ render })
|
|
55
52
|
else render()
|
|
@@ -58,22 +55,13 @@ export const graphic = (gl: GL, bindings: Binding, update = () => {}) => {
|
|
|
58
55
|
|
|
59
56
|
gl('render', () => {
|
|
60
57
|
if (!pipeline || !bindGroups || !vertexBuffers) return
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
pass.draw(gl.triangleCount, gl.instanceCount, 0, 0)
|
|
66
|
-
pass.end()
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
gl('resize', () => {
|
|
70
|
-
const canvas = gl.el as HTMLCanvasElement
|
|
71
|
-
depthTexture?.destroy()
|
|
72
|
-
depthTexture = createDepthTexture(gl.device, canvas.width, canvas.height)
|
|
58
|
+
gl.passEncoder.setPipeline(pipeline)
|
|
59
|
+
bindGroups.forEach((v, i) => gl.passEncoder.setBindGroup(i, v))
|
|
60
|
+
vertexBuffers.forEach((v, i) => gl.passEncoder.setVertexBuffer(i, v))
|
|
61
|
+
gl.passEncoder.draw(count, instanceCount, 0, 0)
|
|
73
62
|
})
|
|
74
63
|
|
|
75
64
|
gl('clean', () => {
|
|
76
|
-
depthTexture?.destroy()
|
|
77
65
|
for (const { buffer } of attributes.map.values()) buffer.destroy()
|
|
78
66
|
for (const { texture } of textures.map.values()) texture.destroy()
|
|
79
67
|
for (const { buffer } of uniforms.map.values()) buffer.destroy()
|