@motion-core/motion-gpu 0.1.0 → 0.3.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 +37 -11
- package/dist/advanced.d.ts +3 -11
- package/dist/advanced.js +3 -6
- package/dist/core/advanced.d.ts +6 -0
- package/dist/core/advanced.js +5 -0
- package/dist/core/current-value.d.ts +23 -0
- package/dist/core/current-value.js +36 -0
- package/dist/core/error-diagnostics.d.ts +15 -1
- package/dist/core/error-diagnostics.js +41 -1
- package/dist/core/error-report.d.ts +37 -0
- package/dist/core/error-report.js +62 -3
- package/dist/{frame-context.d.ts → core/frame-registry.d.ts} +3 -17
- package/dist/{frame-context.js → core/frame-registry.js} +2 -37
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.js +12 -0
- package/dist/core/material-preprocess.d.ts +1 -1
- package/dist/core/material-preprocess.js +1 -1
- package/dist/core/material.d.ts +4 -4
- package/dist/core/material.js +3 -3
- package/dist/core/recompile-policy.d.ts +1 -1
- package/dist/core/render-graph.d.ts +1 -1
- package/dist/core/render-targets.d.ts +1 -1
- package/dist/core/render-targets.js +1 -1
- package/dist/core/renderer.d.ts +11 -1
- package/dist/core/renderer.js +72 -10
- package/dist/core/runtime-loop.d.ts +34 -0
- package/dist/core/runtime-loop.js +365 -0
- package/dist/{advanced-scheduler.d.ts → core/scheduler-helpers.d.ts} +6 -2
- package/dist/core/shader.d.ts +2 -2
- package/dist/core/shader.js +1 -1
- package/dist/core/texture-loader.d.ts +1 -1
- package/dist/core/textures.d.ts +1 -1
- package/dist/core/textures.js +1 -1
- package/dist/core/types.d.ts +4 -0
- package/dist/core/uniforms.d.ts +1 -1
- package/dist/index.d.ts +3 -14
- package/dist/index.js +3 -8
- package/dist/passes/BlitPass.d.ts +6 -27
- package/dist/passes/BlitPass.js +10 -121
- package/dist/passes/CopyPass.d.ts +1 -1
- package/dist/passes/CopyPass.js +1 -1
- package/dist/passes/FullscreenPass.d.ts +37 -0
- package/dist/passes/FullscreenPass.js +131 -0
- package/dist/passes/ShaderPass.d.ts +6 -26
- package/dist/passes/ShaderPass.js +10 -121
- package/dist/passes/index.d.ts +3 -3
- package/dist/passes/index.js +3 -3
- package/dist/svelte/FragCanvas.svelte +263 -0
- package/dist/{FragCanvas.svelte.d.ts → svelte/FragCanvas.svelte.d.ts} +5 -3
- package/dist/{MotionGPUErrorOverlay.svelte → svelte/MotionGPUErrorOverlay.svelte} +11 -20
- package/dist/{MotionGPUErrorOverlay.svelte.d.ts → svelte/MotionGPUErrorOverlay.svelte.d.ts} +1 -1
- package/dist/svelte/advanced.d.ts +11 -0
- package/dist/svelte/advanced.js +6 -0
- package/dist/svelte/frame-context.d.ts +14 -0
- package/dist/svelte/frame-context.js +32 -0
- package/dist/svelte/index.d.ts +15 -0
- package/dist/svelte/index.js +9 -0
- package/dist/{motiongpu-context.d.ts → svelte/motiongpu-context.d.ts} +5 -7
- package/dist/{use-motiongpu-user-context.d.ts → svelte/use-motiongpu-user-context.d.ts} +2 -2
- package/dist/{use-motiongpu-user-context.js → svelte/use-motiongpu-user-context.js} +1 -1
- package/dist/{use-texture.d.ts → svelte/use-texture.d.ts} +7 -2
- package/dist/{use-texture.js → svelte/use-texture.js} +9 -3
- package/package.json +25 -5
- package/dist/FragCanvas.svelte +0 -511
- package/dist/current-writable.d.ts +0 -31
- package/dist/current-writable.js +0 -27
- /package/dist/{advanced-scheduler.js → core/scheduler-helpers.js} +0 -0
- /package/dist/{Portal.svelte → svelte/Portal.svelte} +0 -0
- /package/dist/{Portal.svelte.d.ts → svelte/Portal.svelte.d.ts} +0 -0
- /package/dist/{motiongpu-context.js → svelte/motiongpu-context.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Root package entrypoint.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Framework-agnostic core entrypoint.
|
|
5
5
|
*/
|
|
6
|
-
export
|
|
7
|
-
export { defineMaterial } from './core/material';
|
|
8
|
-
export { BlitPass, CopyPass, ShaderPass } from './passes';
|
|
9
|
-
export { useMotionGPU } from './motiongpu-context';
|
|
10
|
-
export { useFrame } from './frame-context';
|
|
11
|
-
export { useTexture } from './use-texture';
|
|
6
|
+
export * from './core/index.js';
|
|
@@ -1,32 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
export
|
|
3
|
-
enabled?: boolean;
|
|
4
|
-
needsSwap?: boolean;
|
|
5
|
-
input?: RenderPassInputSlot;
|
|
6
|
-
output?: RenderPassOutputSlot;
|
|
7
|
-
filter?: GPUFilterMode;
|
|
8
|
-
}
|
|
1
|
+
import { FullscreenPass, type FullscreenPassOptions } from './FullscreenPass.js';
|
|
2
|
+
export type BlitPassOptions = FullscreenPassOptions;
|
|
9
3
|
/**
|
|
10
4
|
* Fullscreen texture blit pass.
|
|
11
5
|
*/
|
|
12
|
-
export declare class BlitPass
|
|
13
|
-
|
|
14
|
-
needsSwap: boolean;
|
|
15
|
-
input: RenderPassInputSlot;
|
|
16
|
-
output: RenderPassOutputSlot;
|
|
17
|
-
clear: boolean;
|
|
18
|
-
clearColor: [number, number, number, number];
|
|
19
|
-
preserve: boolean;
|
|
20
|
-
private readonly filter;
|
|
21
|
-
private device;
|
|
22
|
-
private sampler;
|
|
23
|
-
private bindGroupLayout;
|
|
24
|
-
private shaderModule;
|
|
25
|
-
private readonly pipelineByFormat;
|
|
26
|
-
private bindGroupByView;
|
|
6
|
+
export declare class BlitPass extends FullscreenPass {
|
|
7
|
+
protected getProgram(): string;
|
|
27
8
|
constructor(options?: BlitPassOptions);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
render(context: RenderPassContext): void;
|
|
31
|
-
dispose(): void;
|
|
9
|
+
protected getVertexEntryPoint(): string;
|
|
10
|
+
protected getFragmentEntryPoint(): string;
|
|
32
11
|
}
|
package/dist/passes/BlitPass.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FullscreenPass } from './FullscreenPass.js';
|
|
1
2
|
const FULLSCREEN_BLIT_SHADER = `
|
|
2
3
|
struct MotionGPUVertexOut {
|
|
3
4
|
@builtin(position) position: vec4f,
|
|
@@ -30,129 +31,17 @@ fn motiongpuBlitFragment(in: MotionGPUVertexOut) -> @location(0) vec4f {
|
|
|
30
31
|
/**
|
|
31
32
|
* Fullscreen texture blit pass.
|
|
32
33
|
*/
|
|
33
|
-
export class BlitPass {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
input;
|
|
37
|
-
output;
|
|
38
|
-
clear;
|
|
39
|
-
clearColor;
|
|
40
|
-
preserve;
|
|
41
|
-
filter;
|
|
42
|
-
device = null;
|
|
43
|
-
sampler = null;
|
|
44
|
-
bindGroupLayout = null;
|
|
45
|
-
shaderModule = null;
|
|
46
|
-
pipelineByFormat = new Map();
|
|
47
|
-
bindGroupByView = new WeakMap();
|
|
48
|
-
constructor(options = {}) {
|
|
49
|
-
this.enabled = options.enabled ?? true;
|
|
50
|
-
this.needsSwap = options.needsSwap ?? true;
|
|
51
|
-
this.input = options.input ?? 'source';
|
|
52
|
-
this.output = options.output ?? (this.needsSwap ? 'target' : 'source');
|
|
53
|
-
this.clear = options.clear ?? false;
|
|
54
|
-
this.clearColor = options.clearColor ?? [0, 0, 0, 1];
|
|
55
|
-
this.preserve = options.preserve ?? true;
|
|
56
|
-
this.filter = options.filter ?? 'linear';
|
|
57
|
-
}
|
|
58
|
-
ensureResources(device, format) {
|
|
59
|
-
if (this.device !== device) {
|
|
60
|
-
this.device = device;
|
|
61
|
-
this.sampler = null;
|
|
62
|
-
this.bindGroupLayout = null;
|
|
63
|
-
this.shaderModule = null;
|
|
64
|
-
this.pipelineByFormat.clear();
|
|
65
|
-
this.bindGroupByView = new WeakMap();
|
|
66
|
-
}
|
|
67
|
-
if (!this.sampler) {
|
|
68
|
-
this.sampler = device.createSampler({
|
|
69
|
-
magFilter: this.filter,
|
|
70
|
-
minFilter: this.filter,
|
|
71
|
-
addressModeU: 'clamp-to-edge',
|
|
72
|
-
addressModeV: 'clamp-to-edge'
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
if (!this.bindGroupLayout) {
|
|
76
|
-
this.bindGroupLayout = device.createBindGroupLayout({
|
|
77
|
-
entries: [
|
|
78
|
-
{
|
|
79
|
-
binding: 0,
|
|
80
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
81
|
-
sampler: { type: 'filtering' }
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
binding: 1,
|
|
85
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
86
|
-
texture: {
|
|
87
|
-
sampleType: 'float',
|
|
88
|
-
viewDimension: '2d',
|
|
89
|
-
multisampled: false
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
if (!this.shaderModule) {
|
|
96
|
-
this.shaderModule = device.createShaderModule({
|
|
97
|
-
code: FULLSCREEN_BLIT_SHADER
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
let pipeline = this.pipelineByFormat.get(format);
|
|
101
|
-
if (!pipeline) {
|
|
102
|
-
const pipelineLayout = device.createPipelineLayout({
|
|
103
|
-
bindGroupLayouts: [this.bindGroupLayout]
|
|
104
|
-
});
|
|
105
|
-
pipeline = device.createRenderPipeline({
|
|
106
|
-
layout: pipelineLayout,
|
|
107
|
-
vertex: {
|
|
108
|
-
module: this.shaderModule,
|
|
109
|
-
entryPoint: 'motiongpuBlitVertex'
|
|
110
|
-
},
|
|
111
|
-
fragment: {
|
|
112
|
-
module: this.shaderModule,
|
|
113
|
-
entryPoint: 'motiongpuBlitFragment',
|
|
114
|
-
targets: [{ format }]
|
|
115
|
-
},
|
|
116
|
-
primitive: { topology: 'triangle-list' }
|
|
117
|
-
});
|
|
118
|
-
this.pipelineByFormat.set(format, pipeline);
|
|
119
|
-
}
|
|
120
|
-
return {
|
|
121
|
-
sampler: this.sampler,
|
|
122
|
-
bindGroupLayout: this.bindGroupLayout,
|
|
123
|
-
pipeline
|
|
124
|
-
};
|
|
34
|
+
export class BlitPass extends FullscreenPass {
|
|
35
|
+
getProgram() {
|
|
36
|
+
return FULLSCREEN_BLIT_SHADER;
|
|
125
37
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
void height;
|
|
38
|
+
constructor(options = {}) {
|
|
39
|
+
super(options);
|
|
129
40
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const inputView = context.input.view;
|
|
133
|
-
let bindGroup = this.bindGroupByView.get(inputView);
|
|
134
|
-
if (!bindGroup) {
|
|
135
|
-
bindGroup = context.device.createBindGroup({
|
|
136
|
-
layout: bindGroupLayout,
|
|
137
|
-
entries: [
|
|
138
|
-
{ binding: 0, resource: sampler },
|
|
139
|
-
{ binding: 1, resource: inputView }
|
|
140
|
-
]
|
|
141
|
-
});
|
|
142
|
-
this.bindGroupByView.set(inputView, bindGroup);
|
|
143
|
-
}
|
|
144
|
-
const pass = context.beginRenderPass();
|
|
145
|
-
pass.setPipeline(pipeline);
|
|
146
|
-
pass.setBindGroup(0, bindGroup);
|
|
147
|
-
pass.draw(3);
|
|
148
|
-
pass.end();
|
|
41
|
+
getVertexEntryPoint() {
|
|
42
|
+
return 'motiongpuBlitVertex';
|
|
149
43
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
this.sampler = null;
|
|
153
|
-
this.bindGroupLayout = null;
|
|
154
|
-
this.shaderModule = null;
|
|
155
|
-
this.pipelineByFormat.clear();
|
|
156
|
-
this.bindGroupByView = new WeakMap();
|
|
44
|
+
getFragmentEntryPoint() {
|
|
45
|
+
return 'motiongpuBlitFragment';
|
|
157
46
|
}
|
|
158
47
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RenderPass, RenderPassContext, RenderPassFlags, RenderPassInputSlot, RenderPassOutputSlot } from '../core/types';
|
|
1
|
+
import type { RenderPass, RenderPassContext, RenderPassFlags, RenderPassInputSlot, RenderPassOutputSlot } from '../core/types.js';
|
|
2
2
|
export interface CopyPassOptions extends RenderPassFlags {
|
|
3
3
|
enabled?: boolean;
|
|
4
4
|
needsSwap?: boolean;
|
package/dist/passes/CopyPass.js
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { RenderPass, RenderPassContext, RenderPassFlags, RenderPassInputSlot, RenderPassOutputSlot } from '../core/types.js';
|
|
2
|
+
export interface FullscreenPassOptions extends RenderPassFlags {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
needsSwap?: boolean;
|
|
5
|
+
input?: RenderPassInputSlot;
|
|
6
|
+
output?: RenderPassOutputSlot;
|
|
7
|
+
filter?: GPUFilterMode;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Shared base for fullscreen texture sampling passes.
|
|
11
|
+
*/
|
|
12
|
+
export declare abstract class FullscreenPass implements RenderPass {
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
needsSwap: boolean;
|
|
15
|
+
input: RenderPassInputSlot;
|
|
16
|
+
output: RenderPassOutputSlot;
|
|
17
|
+
clear: boolean;
|
|
18
|
+
clearColor: [number, number, number, number];
|
|
19
|
+
preserve: boolean;
|
|
20
|
+
private readonly filter;
|
|
21
|
+
private device;
|
|
22
|
+
private sampler;
|
|
23
|
+
private bindGroupLayout;
|
|
24
|
+
private shaderModule;
|
|
25
|
+
private readonly pipelineByFormat;
|
|
26
|
+
private bindGroupByView;
|
|
27
|
+
protected constructor(options?: FullscreenPassOptions);
|
|
28
|
+
protected abstract getProgram(): string;
|
|
29
|
+
protected abstract getVertexEntryPoint(): string;
|
|
30
|
+
protected abstract getFragmentEntryPoint(): string;
|
|
31
|
+
protected invalidateFullscreenCache(): void;
|
|
32
|
+
private ensureResources;
|
|
33
|
+
setSize(width: number, height: number): void;
|
|
34
|
+
protected renderFullscreen(context: RenderPassContext): void;
|
|
35
|
+
render(context: RenderPassContext): void;
|
|
36
|
+
dispose(): void;
|
|
37
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared base for fullscreen texture sampling passes.
|
|
3
|
+
*/
|
|
4
|
+
export class FullscreenPass {
|
|
5
|
+
enabled;
|
|
6
|
+
needsSwap;
|
|
7
|
+
input;
|
|
8
|
+
output;
|
|
9
|
+
clear;
|
|
10
|
+
clearColor;
|
|
11
|
+
preserve;
|
|
12
|
+
filter;
|
|
13
|
+
device = null;
|
|
14
|
+
sampler = null;
|
|
15
|
+
bindGroupLayout = null;
|
|
16
|
+
shaderModule = null;
|
|
17
|
+
pipelineByFormat = new Map();
|
|
18
|
+
bindGroupByView = new WeakMap();
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
this.enabled = options.enabled ?? true;
|
|
21
|
+
this.needsSwap = options.needsSwap ?? true;
|
|
22
|
+
this.input = options.input ?? 'source';
|
|
23
|
+
this.output = options.output ?? (this.needsSwap ? 'target' : 'source');
|
|
24
|
+
this.clear = options.clear ?? false;
|
|
25
|
+
this.clearColor = options.clearColor ?? [0, 0, 0, 1];
|
|
26
|
+
this.preserve = options.preserve ?? true;
|
|
27
|
+
this.filter = options.filter ?? 'linear';
|
|
28
|
+
}
|
|
29
|
+
invalidateFullscreenCache() {
|
|
30
|
+
this.shaderModule = null;
|
|
31
|
+
this.pipelineByFormat.clear();
|
|
32
|
+
this.bindGroupByView = new WeakMap();
|
|
33
|
+
}
|
|
34
|
+
ensureResources(device, format) {
|
|
35
|
+
if (this.device !== device) {
|
|
36
|
+
this.device = device;
|
|
37
|
+
this.sampler = null;
|
|
38
|
+
this.bindGroupLayout = null;
|
|
39
|
+
this.invalidateFullscreenCache();
|
|
40
|
+
}
|
|
41
|
+
if (!this.sampler) {
|
|
42
|
+
this.sampler = device.createSampler({
|
|
43
|
+
magFilter: this.filter,
|
|
44
|
+
minFilter: this.filter,
|
|
45
|
+
addressModeU: 'clamp-to-edge',
|
|
46
|
+
addressModeV: 'clamp-to-edge'
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (!this.bindGroupLayout) {
|
|
50
|
+
this.bindGroupLayout = device.createBindGroupLayout({
|
|
51
|
+
entries: [
|
|
52
|
+
{
|
|
53
|
+
binding: 0,
|
|
54
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
55
|
+
sampler: { type: 'filtering' }
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
binding: 1,
|
|
59
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
60
|
+
texture: {
|
|
61
|
+
sampleType: 'float',
|
|
62
|
+
viewDimension: '2d',
|
|
63
|
+
multisampled: false
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (!this.shaderModule) {
|
|
70
|
+
this.shaderModule = device.createShaderModule({ code: this.getProgram() });
|
|
71
|
+
}
|
|
72
|
+
let pipeline = this.pipelineByFormat.get(format);
|
|
73
|
+
if (!pipeline) {
|
|
74
|
+
const pipelineLayout = device.createPipelineLayout({
|
|
75
|
+
bindGroupLayouts: [this.bindGroupLayout]
|
|
76
|
+
});
|
|
77
|
+
pipeline = device.createRenderPipeline({
|
|
78
|
+
layout: pipelineLayout,
|
|
79
|
+
vertex: {
|
|
80
|
+
module: this.shaderModule,
|
|
81
|
+
entryPoint: this.getVertexEntryPoint()
|
|
82
|
+
},
|
|
83
|
+
fragment: {
|
|
84
|
+
module: this.shaderModule,
|
|
85
|
+
entryPoint: this.getFragmentEntryPoint(),
|
|
86
|
+
targets: [{ format }]
|
|
87
|
+
},
|
|
88
|
+
primitive: { topology: 'triangle-list' }
|
|
89
|
+
});
|
|
90
|
+
this.pipelineByFormat.set(format, pipeline);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
sampler: this.sampler,
|
|
94
|
+
bindGroupLayout: this.bindGroupLayout,
|
|
95
|
+
pipeline
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
setSize(width, height) {
|
|
99
|
+
void width;
|
|
100
|
+
void height;
|
|
101
|
+
}
|
|
102
|
+
renderFullscreen(context) {
|
|
103
|
+
const { sampler, bindGroupLayout, pipeline } = this.ensureResources(context.device, context.output.format);
|
|
104
|
+
const inputView = context.input.view;
|
|
105
|
+
let bindGroup = this.bindGroupByView.get(inputView);
|
|
106
|
+
if (!bindGroup) {
|
|
107
|
+
bindGroup = context.device.createBindGroup({
|
|
108
|
+
layout: bindGroupLayout,
|
|
109
|
+
entries: [
|
|
110
|
+
{ binding: 0, resource: sampler },
|
|
111
|
+
{ binding: 1, resource: inputView }
|
|
112
|
+
]
|
|
113
|
+
});
|
|
114
|
+
this.bindGroupByView.set(inputView, bindGroup);
|
|
115
|
+
}
|
|
116
|
+
const pass = context.beginRenderPass();
|
|
117
|
+
pass.setPipeline(pipeline);
|
|
118
|
+
pass.setBindGroup(0, bindGroup);
|
|
119
|
+
pass.draw(3);
|
|
120
|
+
pass.end();
|
|
121
|
+
}
|
|
122
|
+
render(context) {
|
|
123
|
+
this.renderFullscreen(context);
|
|
124
|
+
}
|
|
125
|
+
dispose() {
|
|
126
|
+
this.device = null;
|
|
127
|
+
this.sampler = null;
|
|
128
|
+
this.bindGroupLayout = null;
|
|
129
|
+
this.invalidateFullscreenCache();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -1,40 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
export interface ShaderPassOptions extends
|
|
1
|
+
import { FullscreenPass, type FullscreenPassOptions } from './FullscreenPass.js';
|
|
2
|
+
export interface ShaderPassOptions extends FullscreenPassOptions {
|
|
3
3
|
fragment: string;
|
|
4
|
-
enabled?: boolean;
|
|
5
|
-
needsSwap?: boolean;
|
|
6
|
-
input?: RenderPassInputSlot;
|
|
7
|
-
output?: RenderPassOutputSlot;
|
|
8
|
-
filter?: GPUFilterMode;
|
|
9
4
|
}
|
|
10
5
|
/**
|
|
11
6
|
* Fullscreen programmable shader pass.
|
|
12
7
|
*/
|
|
13
|
-
export declare class ShaderPass
|
|
14
|
-
enabled: boolean;
|
|
15
|
-
needsSwap: boolean;
|
|
16
|
-
input: RenderPassInputSlot;
|
|
17
|
-
output: RenderPassOutputSlot;
|
|
18
|
-
clear: boolean;
|
|
19
|
-
clearColor: [number, number, number, number];
|
|
20
|
-
preserve: boolean;
|
|
21
|
-
private readonly filter;
|
|
8
|
+
export declare class ShaderPass extends FullscreenPass {
|
|
22
9
|
private fragment;
|
|
23
10
|
private program;
|
|
24
|
-
private device;
|
|
25
|
-
private sampler;
|
|
26
|
-
private bindGroupLayout;
|
|
27
|
-
private shaderModule;
|
|
28
|
-
private readonly pipelineByFormat;
|
|
29
|
-
private bindGroupByView;
|
|
30
11
|
constructor(options: ShaderPassOptions);
|
|
31
12
|
/**
|
|
32
13
|
* Replaces current shader fragment and invalidates pipeline cache.
|
|
33
14
|
*/
|
|
34
15
|
setFragment(fragment: string): void;
|
|
35
16
|
getFragment(): string;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
dispose(): void;
|
|
17
|
+
protected getProgram(): string;
|
|
18
|
+
protected getVertexEntryPoint(): string;
|
|
19
|
+
protected getFragmentEntryPoint(): string;
|
|
40
20
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FullscreenPass } from './FullscreenPass.js';
|
|
1
2
|
const SHADER_PASS_CONTRACT = /\bfn\s+shade\s*\(\s*inputColor\s*:\s*vec4f\s*,\s*uv\s*:\s*vec2f\s*\)\s*->\s*vec4f/;
|
|
2
3
|
function buildShaderPassProgram(fragment) {
|
|
3
4
|
if (!SHADER_PASS_CONTRACT.test(fragment)) {
|
|
@@ -39,32 +40,11 @@ fn motiongpuShaderPassFragment(in: MotionGPUVertexOut) -> @location(0) vec4f {
|
|
|
39
40
|
/**
|
|
40
41
|
* Fullscreen programmable shader pass.
|
|
41
42
|
*/
|
|
42
|
-
export class ShaderPass {
|
|
43
|
-
enabled;
|
|
44
|
-
needsSwap;
|
|
45
|
-
input;
|
|
46
|
-
output;
|
|
47
|
-
clear;
|
|
48
|
-
clearColor;
|
|
49
|
-
preserve;
|
|
50
|
-
filter;
|
|
43
|
+
export class ShaderPass extends FullscreenPass {
|
|
51
44
|
fragment;
|
|
52
45
|
program;
|
|
53
|
-
device = null;
|
|
54
|
-
sampler = null;
|
|
55
|
-
bindGroupLayout = null;
|
|
56
|
-
shaderModule = null;
|
|
57
|
-
pipelineByFormat = new Map();
|
|
58
|
-
bindGroupByView = new WeakMap();
|
|
59
46
|
constructor(options) {
|
|
60
|
-
|
|
61
|
-
this.needsSwap = options.needsSwap ?? true;
|
|
62
|
-
this.input = options.input ?? 'source';
|
|
63
|
-
this.output = options.output ?? (this.needsSwap ? 'target' : 'source');
|
|
64
|
-
this.clear = options.clear ?? false;
|
|
65
|
-
this.clearColor = options.clearColor ?? [0, 0, 0, 1];
|
|
66
|
-
this.preserve = options.preserve ?? true;
|
|
67
|
-
this.filter = options.filter ?? 'linear';
|
|
47
|
+
super(options);
|
|
68
48
|
this.fragment = options.fragment;
|
|
69
49
|
this.program = buildShaderPassProgram(options.fragment);
|
|
70
50
|
}
|
|
@@ -74,109 +54,18 @@ export class ShaderPass {
|
|
|
74
54
|
setFragment(fragment) {
|
|
75
55
|
this.fragment = fragment;
|
|
76
56
|
this.program = buildShaderPassProgram(fragment);
|
|
77
|
-
this.
|
|
78
|
-
this.pipelineByFormat.clear();
|
|
79
|
-
this.bindGroupByView = new WeakMap();
|
|
57
|
+
this.invalidateFullscreenCache();
|
|
80
58
|
}
|
|
81
59
|
getFragment() {
|
|
82
60
|
return this.fragment;
|
|
83
61
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
this.device = device;
|
|
87
|
-
this.sampler = null;
|
|
88
|
-
this.bindGroupLayout = null;
|
|
89
|
-
this.shaderModule = null;
|
|
90
|
-
this.pipelineByFormat.clear();
|
|
91
|
-
this.bindGroupByView = new WeakMap();
|
|
92
|
-
}
|
|
93
|
-
if (!this.sampler) {
|
|
94
|
-
this.sampler = device.createSampler({
|
|
95
|
-
magFilter: this.filter,
|
|
96
|
-
minFilter: this.filter,
|
|
97
|
-
addressModeU: 'clamp-to-edge',
|
|
98
|
-
addressModeV: 'clamp-to-edge'
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
if (!this.bindGroupLayout) {
|
|
102
|
-
this.bindGroupLayout = device.createBindGroupLayout({
|
|
103
|
-
entries: [
|
|
104
|
-
{
|
|
105
|
-
binding: 0,
|
|
106
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
107
|
-
sampler: { type: 'filtering' }
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
binding: 1,
|
|
111
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
112
|
-
texture: {
|
|
113
|
-
sampleType: 'float',
|
|
114
|
-
viewDimension: '2d',
|
|
115
|
-
multisampled: false
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
]
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
if (!this.shaderModule) {
|
|
122
|
-
this.shaderModule = device.createShaderModule({ code: this.program });
|
|
123
|
-
}
|
|
124
|
-
let pipeline = this.pipelineByFormat.get(format);
|
|
125
|
-
if (!pipeline) {
|
|
126
|
-
const pipelineLayout = device.createPipelineLayout({
|
|
127
|
-
bindGroupLayouts: [this.bindGroupLayout]
|
|
128
|
-
});
|
|
129
|
-
pipeline = device.createRenderPipeline({
|
|
130
|
-
layout: pipelineLayout,
|
|
131
|
-
vertex: {
|
|
132
|
-
module: this.shaderModule,
|
|
133
|
-
entryPoint: 'motiongpuShaderPassVertex'
|
|
134
|
-
},
|
|
135
|
-
fragment: {
|
|
136
|
-
module: this.shaderModule,
|
|
137
|
-
entryPoint: 'motiongpuShaderPassFragment',
|
|
138
|
-
targets: [{ format }]
|
|
139
|
-
},
|
|
140
|
-
primitive: { topology: 'triangle-list' }
|
|
141
|
-
});
|
|
142
|
-
this.pipelineByFormat.set(format, pipeline);
|
|
143
|
-
}
|
|
144
|
-
return {
|
|
145
|
-
sampler: this.sampler,
|
|
146
|
-
bindGroupLayout: this.bindGroupLayout,
|
|
147
|
-
pipeline
|
|
148
|
-
};
|
|
62
|
+
getProgram() {
|
|
63
|
+
return this.program;
|
|
149
64
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
void height;
|
|
65
|
+
getVertexEntryPoint() {
|
|
66
|
+
return 'motiongpuShaderPassVertex';
|
|
153
67
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const inputView = context.input.view;
|
|
157
|
-
let bindGroup = this.bindGroupByView.get(inputView);
|
|
158
|
-
if (!bindGroup) {
|
|
159
|
-
bindGroup = context.device.createBindGroup({
|
|
160
|
-
layout: bindGroupLayout,
|
|
161
|
-
entries: [
|
|
162
|
-
{ binding: 0, resource: sampler },
|
|
163
|
-
{ binding: 1, resource: inputView }
|
|
164
|
-
]
|
|
165
|
-
});
|
|
166
|
-
this.bindGroupByView.set(inputView, bindGroup);
|
|
167
|
-
}
|
|
168
|
-
const pass = context.beginRenderPass();
|
|
169
|
-
pass.setPipeline(pipeline);
|
|
170
|
-
pass.setBindGroup(0, bindGroup);
|
|
171
|
-
pass.draw(3);
|
|
172
|
-
pass.end();
|
|
173
|
-
}
|
|
174
|
-
dispose() {
|
|
175
|
-
this.device = null;
|
|
176
|
-
this.sampler = null;
|
|
177
|
-
this.bindGroupLayout = null;
|
|
178
|
-
this.shaderModule = null;
|
|
179
|
-
this.pipelineByFormat.clear();
|
|
180
|
-
this.bindGroupByView = new WeakMap();
|
|
68
|
+
getFragmentEntryPoint() {
|
|
69
|
+
return 'motiongpuShaderPassFragment';
|
|
181
70
|
}
|
|
182
71
|
}
|
package/dist/passes/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { BlitPass, type BlitPassOptions } from './BlitPass';
|
|
2
|
-
export { CopyPass, type CopyPassOptions } from './CopyPass';
|
|
3
|
-
export { ShaderPass, type ShaderPassOptions } from './ShaderPass';
|
|
1
|
+
export { BlitPass, type BlitPassOptions } from './BlitPass.js';
|
|
2
|
+
export { CopyPass, type CopyPassOptions } from './CopyPass.js';
|
|
3
|
+
export { ShaderPass, type ShaderPassOptions } from './ShaderPass.js';
|
package/dist/passes/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { BlitPass } from './BlitPass';
|
|
2
|
-
export { CopyPass } from './CopyPass';
|
|
3
|
-
export { ShaderPass } from './ShaderPass';
|
|
1
|
+
export { BlitPass } from './BlitPass.js';
|
|
2
|
+
export { CopyPass } from './CopyPass.js';
|
|
3
|
+
export { ShaderPass } from './ShaderPass.js';
|