@motion-core/motion-gpu
Version:
Framework-agnostic WebGPU runtime for fullscreen WGSL shaders with explicit Svelte, React, and Vue adapter entrypoints.
128 lines (127 loc) • 3.42 kB
JavaScript
//#region src/lib/passes/FullscreenPass.ts
/**
* Shared base for fullscreen texture sampling passes.
*/
var FullscreenPass = class {
enabled;
needsSwap;
input;
output;
clear;
clearColor;
preserve;
filter;
device = null;
sampler = null;
bindGroupLayout = null;
shaderModule = null;
pipelineByFormat = /* @__PURE__ */ new Map();
bindGroupByView = /* @__PURE__ */ new WeakMap();
constructor(options = {}) {
this.enabled = options.enabled ?? true;
this.needsSwap = options.needsSwap ?? true;
this.input = options.input ?? "source";
this.output = options.output ?? (this.needsSwap ? "target" : "source");
this.clear = options.clear ?? false;
this.clearColor = options.clearColor ?? [
0,
0,
0,
1
];
this.preserve = options.preserve ?? true;
this.filter = options.filter ?? "linear";
}
invalidateFullscreenCache() {
this.shaderModule = null;
this.pipelineByFormat.clear();
this.bindGroupByView = /* @__PURE__ */ new WeakMap();
}
ensureResources(device, format) {
if (this.device !== device) {
this.device = device;
this.sampler = null;
this.bindGroupLayout = null;
this.invalidateFullscreenCache();
}
if (!this.sampler) this.sampler = device.createSampler({
magFilter: this.filter,
minFilter: this.filter,
addressModeU: "clamp-to-edge",
addressModeV: "clamp-to-edge"
});
if (!this.bindGroupLayout) this.bindGroupLayout = device.createBindGroupLayout({ entries: [{
binding: 0,
visibility: GPUShaderStage.FRAGMENT,
sampler: { type: "filtering" }
}, {
binding: 1,
visibility: GPUShaderStage.FRAGMENT,
texture: {
sampleType: "float",
viewDimension: "2d",
multisampled: false
}
}] });
if (!this.shaderModule) this.shaderModule = device.createShaderModule({ code: this.getProgram() });
let pipeline = this.pipelineByFormat.get(format);
if (!pipeline) {
const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [this.bindGroupLayout] });
pipeline = device.createRenderPipeline({
layout: pipelineLayout,
vertex: {
module: this.shaderModule,
entryPoint: this.getVertexEntryPoint()
},
fragment: {
module: this.shaderModule,
entryPoint: this.getFragmentEntryPoint(),
targets: [{ format }]
},
primitive: { topology: "triangle-list" }
});
this.pipelineByFormat.set(format, pipeline);
}
return {
sampler: this.sampler,
bindGroupLayout: this.bindGroupLayout,
pipeline
};
}
setSize(width, height) {}
renderFullscreen(context) {
const { sampler, bindGroupLayout, pipeline } = this.ensureResources(context.device, context.output.format);
const inputView = context.input.view;
let bindGroup = this.bindGroupByView.get(inputView);
if (!bindGroup) {
bindGroup = context.device.createBindGroup({
layout: bindGroupLayout,
entries: [{
binding: 0,
resource: sampler
}, {
binding: 1,
resource: inputView
}]
});
this.bindGroupByView.set(inputView, bindGroup);
}
const pass = context.beginRenderPass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.draw(3);
pass.end();
}
render(context) {
this.renderFullscreen(context);
}
dispose() {
this.device = null;
this.sampler = null;
this.bindGroupLayout = null;
this.invalidateFullscreenCache();
}
};
//#endregion
export { FullscreenPass };
//# sourceMappingURL=FullscreenPass.js.map