glre 0.30.0 → 0.32.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 +30 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +571 -0
- package/dist/index.js +30 -64
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +30 -64
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +54 -0
- package/dist/native.js +30 -64
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +30 -64
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +8 -0
- package/dist/react.js +30 -64
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +30 -64
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +8 -0
- package/dist/solid.js +30 -64
- package/dist/solid.js.map +1 -1
- package/package.json +7 -6
- package/src/index.ts +20 -5
- package/src/node/code.ts +66 -69
- package/src/node/const.ts +2 -0
- package/src/node/index.ts +78 -8
- package/src/node/infer.ts +19 -14
- package/src/node/node.ts +12 -14
- package/src/node/parse.ts +118 -0
- package/src/node/scope.ts +37 -18
- package/src/node/types.ts +90 -56
- package/src/node/utils.ts +9 -92
- package/src/types.ts +31 -16
- package/src/utils/pipeline.ts +135 -83
- package/src/utils/program.ts +7 -29
- package/src/webgl.ts +2 -3
- package/src/webgpu.ts +67 -58
- package/dist/index-q8W5cl04.d.cts +0 -358
- package/dist/index.d.cts +0 -3
- package/dist/native.d.cts +0 -53
- package/dist/react.d.cts +0 -8
- package/dist/solid.d.cts +0 -8
package/src/node/types.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WebGPUState } from '../types'
|
|
1
2
|
import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS } from './const'
|
|
2
3
|
|
|
3
4
|
export type Constants = (typeof CONSTANTS)[number] | 'void'
|
|
@@ -17,23 +18,60 @@ export interface FnLayout {
|
|
|
17
18
|
}>
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Node
|
|
23
|
+
*/
|
|
24
|
+
export type NodeTypes =
|
|
25
|
+
// headers
|
|
26
|
+
| 'attribute'
|
|
27
|
+
| 'uniform'
|
|
28
|
+
| 'constant'
|
|
29
|
+
// variables
|
|
30
|
+
| 'variable'
|
|
31
|
+
| 'varying'
|
|
32
|
+
| 'swizzle'
|
|
33
|
+
| 'ternary'
|
|
34
|
+
| 'builtin'
|
|
35
|
+
| 'conversion'
|
|
36
|
+
| 'operator'
|
|
37
|
+
| 'function'
|
|
38
|
+
// scopes
|
|
39
|
+
| 'scope'
|
|
40
|
+
| 'assign'
|
|
41
|
+
| 'loop'
|
|
42
|
+
| 'define'
|
|
43
|
+
| 'if'
|
|
44
|
+
| 'switch'
|
|
45
|
+
| 'declare'
|
|
46
|
+
| 'return'
|
|
47
|
+
|
|
20
48
|
export interface NodeProps {
|
|
21
49
|
id?: string
|
|
22
50
|
args?: X[]
|
|
23
51
|
type?: string
|
|
24
52
|
children?: X[]
|
|
25
|
-
inferFrom?: X
|
|
53
|
+
inferFrom?: X[]
|
|
26
54
|
layout?: FnLayout
|
|
55
|
+
parent?: NodeProxy
|
|
27
56
|
}
|
|
28
57
|
|
|
29
|
-
export interface
|
|
58
|
+
export interface NodeContext {
|
|
59
|
+
isFrag?: boolean
|
|
30
60
|
isWebGL?: boolean
|
|
31
61
|
binding?: number
|
|
32
62
|
infers?: WeakMap<NodeProxy, Constants>
|
|
33
|
-
headers?: Map<string, string>
|
|
34
63
|
onMount?: (name: string) => void
|
|
64
|
+
webgpu?: WebGPUState
|
|
65
|
+
headers?: Map<string, string>
|
|
66
|
+
fragInputs?: Map<string, string>
|
|
67
|
+
vertInputs?: Map<string, string>
|
|
68
|
+
vertOutputs?: Map<string, string>
|
|
69
|
+
vertVaryings?: Map<string, string>
|
|
35
70
|
}
|
|
36
71
|
|
|
72
|
+
/**
|
|
73
|
+
* NodeProxy
|
|
74
|
+
*/
|
|
37
75
|
type _Swizzles<T extends string> = T | `${T}${T}` | `${T}${T}${T}` | `${T}${T}${T}${T}`
|
|
38
76
|
|
|
39
77
|
export type Swizzles =
|
|
@@ -42,31 +80,33 @@ export type Swizzles =
|
|
|
42
80
|
| _Swizzles<'p' | 'q'>
|
|
43
81
|
| _Swizzles<'s' | 't'>
|
|
44
82
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
| '
|
|
53
|
-
| '
|
|
54
|
-
| 'ternary'
|
|
55
|
-
| 'builtin'
|
|
56
|
-
| 'conversion'
|
|
57
|
-
| 'operator'
|
|
58
|
-
| 'function'
|
|
59
|
-
// scopes
|
|
60
|
-
| 'scope'
|
|
83
|
+
type NodeProxyMethods =
|
|
84
|
+
| Functions
|
|
85
|
+
| Operators
|
|
86
|
+
| Conversions
|
|
87
|
+
| Swizzles
|
|
88
|
+
// system property
|
|
89
|
+
| 'type'
|
|
90
|
+
| 'props'
|
|
91
|
+
| 'isProxy'
|
|
61
92
|
| 'assign'
|
|
62
|
-
| '
|
|
63
|
-
| '
|
|
64
|
-
| 'if'
|
|
65
|
-
| 'switch'
|
|
66
|
-
| 'declare'
|
|
93
|
+
| 'toVar'
|
|
94
|
+
| 'toString'
|
|
67
95
|
|
|
68
|
-
export
|
|
69
|
-
|
|
96
|
+
export type DynamicProperties = {
|
|
97
|
+
[K in string as K extends NodeProxyMethods ? never : K]: NodeProxy
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface BaseNodeProxy extends Record<Swizzles, NodeProxy> {
|
|
101
|
+
// System properties
|
|
102
|
+
assign(n: X): NodeProxy
|
|
103
|
+
toVar(name?: string): NodeProxy
|
|
104
|
+
toString(c?: NodeContext): string
|
|
105
|
+
type: NodeTypes
|
|
106
|
+
props: NodeProps
|
|
107
|
+
isProxy: true
|
|
108
|
+
|
|
109
|
+
// Operators methods
|
|
70
110
|
add(n: X): NodeProxy
|
|
71
111
|
sub(n: X): NodeProxy
|
|
72
112
|
mul(n: X): NodeProxy
|
|
@@ -82,11 +122,29 @@ export interface NodeProxy extends Record<Swizzles, NodeProxy> {
|
|
|
82
122
|
or(n: X): NodeProxy
|
|
83
123
|
not(): NodeProxy
|
|
84
124
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
125
|
+
// Conversations methods
|
|
126
|
+
toBool(): NodeProxy
|
|
127
|
+
toUint(): NodeProxy
|
|
128
|
+
toInt(): NodeProxy
|
|
129
|
+
toFloat(): NodeProxy
|
|
130
|
+
toBvec2(): NodeProxy
|
|
131
|
+
toIvec2(): NodeProxy
|
|
132
|
+
toUvec2(): NodeProxy
|
|
133
|
+
toVec2(): NodeProxy
|
|
134
|
+
toBvec3(): NodeProxy
|
|
135
|
+
toIvec3(): NodeProxy
|
|
136
|
+
toUvec3(): NodeProxy
|
|
137
|
+
toVec3(): NodeProxy
|
|
138
|
+
toBvec4(): NodeProxy
|
|
139
|
+
toIvec4(): NodeProxy
|
|
140
|
+
toUvec4(): NodeProxy
|
|
141
|
+
toVec4(): NodeProxy
|
|
142
|
+
toColor(): NodeProxy
|
|
143
|
+
toMat2(): NodeProxy
|
|
144
|
+
toMat3(): NodeProxy
|
|
145
|
+
toMat4(): NodeProxy
|
|
88
146
|
|
|
89
|
-
//
|
|
147
|
+
// Function methods
|
|
90
148
|
abs(): NodeProxy
|
|
91
149
|
sin(): NodeProxy
|
|
92
150
|
cos(): NodeProxy
|
|
@@ -131,32 +189,8 @@ export interface NodeProxy extends Record<Swizzles, NodeProxy> {
|
|
|
131
189
|
dFdx(): NodeProxy
|
|
132
190
|
dFdy(): NodeProxy
|
|
133
191
|
fwidth(): NodeProxy
|
|
134
|
-
|
|
135
|
-
// System properties
|
|
136
|
-
toBool(): NodeProxy
|
|
137
|
-
toUint(): NodeProxy
|
|
138
|
-
toInt(): NodeProxy
|
|
139
|
-
toFloat(): NodeProxy
|
|
140
|
-
toBvec2(): NodeProxy
|
|
141
|
-
toIvec2(): NodeProxy
|
|
142
|
-
toUvec2(): NodeProxy
|
|
143
|
-
toVec2(): NodeProxy
|
|
144
|
-
toBvec3(): NodeProxy
|
|
145
|
-
toIvec3(): NodeProxy
|
|
146
|
-
toUvec3(): NodeProxy
|
|
147
|
-
toVec3(): NodeProxy
|
|
148
|
-
toBvec4(): NodeProxy
|
|
149
|
-
toIvec4(): NodeProxy
|
|
150
|
-
toUvec4(): NodeProxy
|
|
151
|
-
toVec4(): NodeProxy
|
|
152
|
-
toColor(): NodeProxy
|
|
153
|
-
toMat2(): NodeProxy
|
|
154
|
-
toMat3(): NodeProxy
|
|
155
|
-
toMat4(): NodeProxy
|
|
156
|
-
toString(c?: NodeConfig): string
|
|
157
|
-
type: NodeTypes
|
|
158
|
-
props: NodeProps
|
|
159
|
-
isProxy: true
|
|
160
192
|
}
|
|
161
193
|
|
|
194
|
+
export type NodeProxy = BaseNodeProxy & DynamicProperties
|
|
195
|
+
|
|
162
196
|
export type X = NodeProxy | number | string | boolean | undefined
|
package/src/node/utils.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { is } from '../utils/helpers'
|
|
2
2
|
import { code } from './code'
|
|
3
|
-
import { infer } from './infer'
|
|
4
3
|
import {
|
|
5
4
|
CONSTANTS,
|
|
6
5
|
CONVERSIONS,
|
|
@@ -10,17 +9,7 @@ import {
|
|
|
10
9
|
TYPE_MAPPING,
|
|
11
10
|
WGSL_TO_GLSL_BUILTIN,
|
|
12
11
|
} from './const'
|
|
13
|
-
import type {
|
|
14
|
-
Constants,
|
|
15
|
-
Conversions,
|
|
16
|
-
Functions,
|
|
17
|
-
NodeConfig,
|
|
18
|
-
NodeProps,
|
|
19
|
-
NodeProxy,
|
|
20
|
-
Operators,
|
|
21
|
-
Swizzles,
|
|
22
|
-
X,
|
|
23
|
-
} from './types'
|
|
12
|
+
import type { Constants, Conversions, Functions, NodeContext, NodeProxy, Operators, Swizzles, X } from './types'
|
|
24
13
|
|
|
25
14
|
export const isSwizzle = (key: unknown): key is Swizzles => {
|
|
26
15
|
return is.str(key) && /^[xyzwrgbastpq]{1,4}$/.test(key)
|
|
@@ -44,6 +33,12 @@ export const isNodeProxy = (x: unknown): x is NodeProxy => {
|
|
|
44
33
|
return x.isProxy
|
|
45
34
|
}
|
|
46
35
|
|
|
36
|
+
export const isConstantsType = (type?: Constants | 'auto'): type is Constants => {
|
|
37
|
+
if (!type) return false
|
|
38
|
+
if (type === 'auto') return false
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
|
|
47
42
|
export const hex2rgb = (hex: number) => {
|
|
48
43
|
const r = ((hex >> 16) & 0xff) / 255
|
|
49
44
|
const g = ((hex >> 8) & 0xff) / 255
|
|
@@ -55,14 +50,14 @@ let count = 0
|
|
|
55
50
|
|
|
56
51
|
export const getId = () => `i${count++}`
|
|
57
52
|
|
|
58
|
-
export const joins = (children: X[], c:
|
|
53
|
+
export const joins = (children: X[], c: NodeContext) => {
|
|
59
54
|
return children
|
|
60
55
|
.filter((x) => !is.und(x) && !is.nul(x))
|
|
61
56
|
.map((x) => code(x, c))
|
|
62
57
|
.join(', ')
|
|
63
58
|
}
|
|
64
59
|
|
|
65
|
-
export const formatConversions = (x: X, c?:
|
|
60
|
+
export const formatConversions = (x: X, c?: NodeContext) => {
|
|
66
61
|
if (!is.str(x)) return ''
|
|
67
62
|
if (c?.isWebGL) return x
|
|
68
63
|
return TYPE_MAPPING[x as keyof typeof TYPE_MAPPING]
|
|
@@ -80,81 +75,3 @@ export const conversionToConstant = (conversionKey: string): Constants => {
|
|
|
80
75
|
const index = CONVERSIONS.indexOf(conversionKey as Conversions)
|
|
81
76
|
return index !== -1 ? CONSTANTS[index] : 'float'
|
|
82
77
|
}
|
|
83
|
-
|
|
84
|
-
const generateHead = (c: NodeConfig) => {
|
|
85
|
-
return Array.from(c.headers!)
|
|
86
|
-
.map(([, v]) => v)
|
|
87
|
-
.join('\n')
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export const generateDefine = (props: NodeProps, c: NodeConfig) => {
|
|
91
|
-
const { id, children = [], layout } = props
|
|
92
|
-
const [x, y, ...args] = children
|
|
93
|
-
const returnType = layout?.type && layout?.type !== 'auto' ? layout?.type : y ? infer(y, c) : 'void'
|
|
94
|
-
const argParams: [name: string, type: string][] = []
|
|
95
|
-
const params: string[] = []
|
|
96
|
-
if (layout?.inputs)
|
|
97
|
-
for (const input of layout.inputs) {
|
|
98
|
-
argParams.push([input.name, input.type])
|
|
99
|
-
}
|
|
100
|
-
else
|
|
101
|
-
for (let i = 0; i < args.length; i++) {
|
|
102
|
-
argParams.push([`p${i}`, infer(args[i], c)])
|
|
103
|
-
}
|
|
104
|
-
let ret = ''
|
|
105
|
-
if (c?.isWebGL) {
|
|
106
|
-
for (const [id, type] of argParams) params.push(`${type} ${id}`)
|
|
107
|
-
ret += `${returnType} ${id}(${params}) {\n`
|
|
108
|
-
} else {
|
|
109
|
-
for (const [id, type] of argParams) params.push(`${id}: ${formatConversions(type, c)}`)
|
|
110
|
-
ret += `fn ${id}(${params}) -> ${formatConversions(returnType, c)} {\n`
|
|
111
|
-
}
|
|
112
|
-
const scopeCode = code(x, c)
|
|
113
|
-
if (scopeCode) ret += scopeCode + '\n'
|
|
114
|
-
if (y) ret += `return ${code(y, c)};`
|
|
115
|
-
ret += '\n}'
|
|
116
|
-
return ret
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const GLSL_FRAGMENT_HEAD = `
|
|
120
|
-
#version 300 es
|
|
121
|
-
precision mediump float;
|
|
122
|
-
out vec4 fragColor;
|
|
123
|
-
`.trim()
|
|
124
|
-
|
|
125
|
-
const WGSL_FRAGMENT_HEAD = `
|
|
126
|
-
@fragment
|
|
127
|
-
fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
128
|
-
`.trim()
|
|
129
|
-
|
|
130
|
-
const generateFragmentMain = (body: string, head: string, isWebGL = true) => {
|
|
131
|
-
let ret = ''
|
|
132
|
-
if (isWebGL) ret += GLSL_FRAGMENT_HEAD
|
|
133
|
-
if (head) ret += '\n' + head + '\n'
|
|
134
|
-
if (isWebGL) ret += `void main() {\n fragColor = ${body};`
|
|
135
|
-
else {
|
|
136
|
-
ret += WGSL_FRAGMENT_HEAD + '\n'
|
|
137
|
-
ret += ` return ${body};`
|
|
138
|
-
}
|
|
139
|
-
ret += '\n}'
|
|
140
|
-
return ret
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const generateVertexMain = (_body: string, _head: string, isWebGL = true) => {
|
|
144
|
-
if (isWebGL) return ``
|
|
145
|
-
return ``
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export const fragment = (x: X, c: NodeConfig = {}) => {
|
|
149
|
-
const body = code(x, c)
|
|
150
|
-
const head = generateHead(c)
|
|
151
|
-
const main = generateFragmentMain(body, head, c.isWebGL)
|
|
152
|
-
console.log(`// ↓↓↓ generated ↓↓↓\n\n${main}\n\n`)
|
|
153
|
-
return main
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export const vertex = (x: X, c: NodeConfig) => {
|
|
157
|
-
const body = code(x, c)
|
|
158
|
-
const head = generateHead(c)
|
|
159
|
-
return generateVertexMain(body, head, c.isWebGL)
|
|
160
|
-
}
|
package/src/types.ts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { EventState } from 'reev'
|
|
1
|
+
import type { EventState, Nested } from 'reev'
|
|
2
2
|
import type { Fun, Queue, Frame } from 'refr'
|
|
3
3
|
import type { NodeProxy } from './node'
|
|
4
4
|
export type { Fun, Queue, Frame }
|
|
5
|
-
export type GPUContext = any // GPUCanvasContext https://developer.mozilla.org/en-US/docs/Web/API/GPUCanvasContext
|
|
6
|
-
export type GPUDevice = any //
|
|
7
|
-
export type GPUBuffer = any //
|
|
8
|
-
export type GPUPipeline = any //
|
|
9
|
-
export type GPUBindGroup = any
|
|
10
|
-
export type Uniform = number | number[]
|
|
11
|
-
export type Attribute = number[]
|
|
12
|
-
export type Attributes = Record<string, Attribute>
|
|
13
|
-
export type Uniforms = Record<string, Uniform>
|
|
14
5
|
export type PrecisionMode = 'highp' | 'mediump' | 'lowp'
|
|
15
6
|
export type GLClearMode = 'COLOR_BUFFER_BIT' | 'DEPTH_BUFFER_BIT' | 'STENCIL_BUFFER_BIT'
|
|
16
7
|
export type GLDrawType = 'UNSIGNED_BYTE' | 'UNSIGNED_SHORT' | 'UNSIGNED_INT'
|
|
@@ -23,6 +14,27 @@ export type GLDrawMode =
|
|
|
23
14
|
| 'TRIANGLE_FAN'
|
|
24
15
|
| 'TRIANGLES'
|
|
25
16
|
|
|
17
|
+
export interface UniformData {
|
|
18
|
+
array: Float32Array
|
|
19
|
+
buffer: GPUBuffer
|
|
20
|
+
binding: number
|
|
21
|
+
group: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TextureData {
|
|
25
|
+
binding: number
|
|
26
|
+
group: number
|
|
27
|
+
texture: GPUTexture
|
|
28
|
+
sampler: GPUSampler
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AttribData {
|
|
32
|
+
array: Float32Array
|
|
33
|
+
buffer: GPUBuffer
|
|
34
|
+
location: number
|
|
35
|
+
stride: number
|
|
36
|
+
}
|
|
37
|
+
|
|
26
38
|
export interface WebGLState {
|
|
27
39
|
context: WebGLRenderingContext
|
|
28
40
|
program: WebGLProgram
|
|
@@ -30,14 +42,16 @@ export interface WebGLState {
|
|
|
30
42
|
|
|
31
43
|
export interface WebGPUState {
|
|
32
44
|
device: GPUDevice
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
resources: any[]
|
|
37
|
-
loadingImg: number
|
|
38
|
-
needsUpdate: boolean
|
|
45
|
+
uniforms: Nested<UniformData>
|
|
46
|
+
textures: Nested<TextureData>
|
|
47
|
+
attribs: Nested<AttribData>
|
|
39
48
|
}
|
|
40
49
|
|
|
50
|
+
export type Uniform = number | number[]
|
|
51
|
+
export type Attribute = number[]
|
|
52
|
+
export type Attributes = Record<string, Attribute>
|
|
53
|
+
export type Uniforms = Record<string, Uniform>
|
|
54
|
+
|
|
41
55
|
export type GL = EventState<{
|
|
42
56
|
/**
|
|
43
57
|
* initial value
|
|
@@ -84,6 +98,7 @@ export type GL = EventState<{
|
|
|
84
98
|
*/
|
|
85
99
|
_uniform?(key: string, value: Uniform, isMatrix?: boolean): GL
|
|
86
100
|
uniform(key: string, value: Uniform, isMatrix?: boolean): GL
|
|
101
|
+
uniform(node: NodeProxy): GL
|
|
87
102
|
uniform(target: { [key: string]: Uniform }): GL
|
|
88
103
|
_texture?(key: string, value: string): GL
|
|
89
104
|
texture(key: string, value: string): GL
|
package/src/utils/pipeline.ts
CHANGED
|
@@ -1,44 +1,58 @@
|
|
|
1
|
-
import { fragment,
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import { fragment, vertex } from '../node'
|
|
2
|
+
import type { X } from '../node'
|
|
3
|
+
import type { AttribData, TextureData, UniformData, WebGPUState } from '../types'
|
|
4
|
+
import { is } from './helpers'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return vec4f(x, y, 0.0, 1.0);
|
|
11
|
-
}
|
|
12
|
-
`
|
|
13
|
-
|
|
14
|
-
const defaultFragmentWGSL = `
|
|
15
|
-
@group(0) @binding(0) var<uniform> iResolution: vec2f;
|
|
16
|
-
|
|
17
|
-
@fragment
|
|
18
|
-
fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
19
|
-
return vec4f(position.xy / iResolution, 0.0, 1.0);
|
|
20
|
-
}
|
|
21
|
-
`
|
|
22
|
-
|
|
23
|
-
export const createDevice = async (c: GPUContext) => {
|
|
24
|
-
const gpu = (navigator as any).gpu
|
|
6
|
+
/**
|
|
7
|
+
* initialize
|
|
8
|
+
*/
|
|
9
|
+
export const createDevice = async (c: GPUCanvasContext) => {
|
|
10
|
+
const gpu = navigator.gpu
|
|
25
11
|
const format = gpu.getPreferredCanvasFormat()
|
|
26
12
|
const adapter = await gpu.requestAdapter()
|
|
27
|
-
const device = await adapter
|
|
13
|
+
const device = await adapter!.requestDevice()
|
|
28
14
|
c.configure({ device, format, alphaMode: 'opaque' })
|
|
29
15
|
return { device, format }
|
|
30
16
|
}
|
|
31
17
|
|
|
18
|
+
export const createBindings = () => {
|
|
19
|
+
let uniform = 0
|
|
20
|
+
let texture = 0
|
|
21
|
+
let attrib = 0
|
|
22
|
+
return {
|
|
23
|
+
uniform: () => {
|
|
24
|
+
const group = Math.floor(uniform / 12)
|
|
25
|
+
const binding = uniform % 12
|
|
26
|
+
uniform++
|
|
27
|
+
return { group, binding }
|
|
28
|
+
},
|
|
29
|
+
texture: () => {
|
|
30
|
+
const baseGroup = Math.floor(uniform / 12) + 1
|
|
31
|
+
const group = baseGroup + Math.floor(texture / 6)
|
|
32
|
+
const binding = (texture % 6) * 2
|
|
33
|
+
texture++
|
|
34
|
+
return { group, binding }
|
|
35
|
+
},
|
|
36
|
+
attrib: () => {
|
|
37
|
+
const location = attrib
|
|
38
|
+
attrib++
|
|
39
|
+
return { location }
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
export const createPipeline = (
|
|
33
45
|
device: GPUDevice,
|
|
34
|
-
format:
|
|
35
|
-
bufferLayouts:
|
|
36
|
-
bindGroupLayouts:
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
format: GPUTextureFormat,
|
|
47
|
+
bufferLayouts: GPUVertexBufferLayout[],
|
|
48
|
+
bindGroupLayouts: GPUBindGroupLayout[],
|
|
49
|
+
webgpu: WebGPUState,
|
|
50
|
+
vs: string | X,
|
|
51
|
+
fs: string | X
|
|
39
52
|
) => {
|
|
40
|
-
|
|
41
|
-
if (
|
|
53
|
+
const config = { isWebGL: false, webgpu }
|
|
54
|
+
if (!is.str(fs)) fs = fragment(fs, config)
|
|
55
|
+
if (!is.str(vs)) vs = vertex(vs, config)
|
|
42
56
|
const layout = device.createPipelineLayout({ bindGroupLayouts })
|
|
43
57
|
return device.createRenderPipeline({
|
|
44
58
|
vertex: {
|
|
@@ -53,83 +67,121 @@ export const createPipeline = (
|
|
|
53
67
|
},
|
|
54
68
|
layout,
|
|
55
69
|
primitive: { topology: 'triangle-list' },
|
|
56
|
-
|
|
70
|
+
depthStencil: {
|
|
71
|
+
depthWriteEnabled: true,
|
|
72
|
+
depthCompare: 'less',
|
|
73
|
+
format: 'depth24plus',
|
|
74
|
+
},
|
|
75
|
+
})
|
|
57
76
|
}
|
|
58
77
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (isUniform) entries0.push({ binding, visibility: 3, buffer: { type: 'uniform' } })
|
|
68
|
-
else if (isTexture) entries0.push({ binding, visibility: 2, texture: {} })
|
|
69
|
-
else if (isSampler) entries0.push({ binding, visibility: 2, sampler: {} })
|
|
70
|
-
else return
|
|
71
|
-
entries1.push({ binding, resource })
|
|
72
|
-
})
|
|
73
|
-
const layout = device.createBindGroupLayout({ entries: entries0 })
|
|
74
|
-
const bindGroup = device.createBindGroup({ layout, entries: entries1 })
|
|
75
|
-
return { layout, bindGroup }
|
|
78
|
+
/**
|
|
79
|
+
* buffers
|
|
80
|
+
*/
|
|
81
|
+
export const createUniformBuffer = (device: GPUDevice, value: number[]) => {
|
|
82
|
+
const array = new Float32Array(value)
|
|
83
|
+
const size = Math.ceil(array.byteLength / 256) * 256
|
|
84
|
+
const buffer = device.createBuffer({ size, usage: 72 }) // 72 is GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
85
|
+
return { array, buffer }
|
|
76
86
|
}
|
|
77
87
|
|
|
78
|
-
export const
|
|
88
|
+
export const createAttribBuffer = (device: GPUDevice, value: number[]) => {
|
|
89
|
+
const array = new Float32Array(value)
|
|
90
|
+
const buffer = device.createBuffer({ size: array.byteLength, usage: 40 }) // 40 is GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
91
|
+
return { array, buffer }
|
|
92
|
+
}
|
|
93
|
+
|
|
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
|
+
export const createDescriptor = (c: GPUCanvasContext, depthTexture: GPUTexture) => {
|
|
79
128
|
return {
|
|
80
129
|
colorAttachments: [
|
|
81
130
|
{
|
|
82
131
|
view: c.getCurrentTexture().createView(),
|
|
83
132
|
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
84
|
-
loadOp: 'clear',
|
|
85
|
-
storeOp: 'store',
|
|
133
|
+
loadOp: 'clear' as GPULoadOp,
|
|
134
|
+
storeOp: 'store' as GPUStoreOp,
|
|
86
135
|
},
|
|
87
136
|
],
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const buffer = device.createBuffer({ size: array.byteLength, usage: 40 }) // 40 === // GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
96
|
-
return { array, buffer }
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export const createUniformBuffer = (device: GPUDevice, value: number[]) => {
|
|
100
|
-
const array = new Float32Array(value)
|
|
101
|
-
const size = alignTo256(array.byteLength)
|
|
102
|
-
const buffer = device.createBuffer({ size, usage: 72 }) as Buffer // 72 === GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
103
|
-
return { array, buffer }
|
|
137
|
+
depthStencilAttachment: {
|
|
138
|
+
view: depthTexture.createView(),
|
|
139
|
+
depthClearValue: 1.0,
|
|
140
|
+
depthLoadOp: 'clear' as GPULoadOp,
|
|
141
|
+
depthStoreOp: 'store' as GPUStoreOp,
|
|
142
|
+
},
|
|
143
|
+
} as GPURenderPassDescriptor
|
|
104
144
|
}
|
|
105
145
|
|
|
106
146
|
export const createTextureSampler = (device: GPUDevice, width = 1280, height = 800) => {
|
|
107
|
-
const texture = device.createTexture({ size: [width, height], format: 'rgba8unorm', usage: 22 })
|
|
147
|
+
const texture = device.createTexture({ size: [width, height], format: 'rgba8unorm', usage: 22 }) // 22 is GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
|
|
108
148
|
const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' })
|
|
109
149
|
return { texture, sampler }
|
|
110
150
|
}
|
|
111
151
|
|
|
112
|
-
const
|
|
113
|
-
return
|
|
152
|
+
export const createDepthTexture = (device: GPUDevice, width: number, height: number) => {
|
|
153
|
+
return device.createTexture({
|
|
154
|
+
size: [width, height],
|
|
155
|
+
format: 'depth24plus',
|
|
156
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
157
|
+
})
|
|
114
158
|
}
|
|
115
159
|
|
|
116
|
-
|
|
160
|
+
/**
|
|
161
|
+
* attribs
|
|
162
|
+
*/
|
|
163
|
+
const getVertexFormat = (stride: number): GPUVertexFormat => {
|
|
117
164
|
if (stride === 2) return 'float32x2'
|
|
118
165
|
if (stride === 3) return 'float32x3'
|
|
119
166
|
if (stride === 4) return 'float32x4'
|
|
120
167
|
return 'float32'
|
|
121
168
|
}
|
|
122
169
|
|
|
123
|
-
export const
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
+
}
|
|
134
185
|
}
|
|
186
|
+
return { vertexBuffers, bufferLayouts }
|
|
135
187
|
}
|