@motion-core/motion-gpu
Version:
Framework-agnostic WebGPU runtime for fullscreen WGSL shaders with explicit Svelte, React, and Vue adapter entrypoints.
94 lines (93 loc) • 3.99 kB
JavaScript
import { assertFloatRenderableFormat, assertFloatSampledFormat, assertRenderableFormat, createFormatCapabilityError } from "./format-capabilities.js";
import { builtInRenderPassBrand } from "./pass-brand.js";
import { isBuiltInRenderPass, isManagedComputePass, isManagedFeedbackPass } from "./pass-contract.js";
//#region src/lib/core/render-format-validation.ts
/** Validates the renderer-owned working texture used by scene and presentation pipelines. */
function validateWorkingFormat(format, deviceFeatures) {
const diagnostic = {
format,
target: "workingFormat",
pass: "Scene pipeline",
deviceFeatures
};
assertFloatRenderableFormat(diagnostic);
assertFloatSampledFormat(diagnostic);
}
/** Validates named color targets and returns their effective formats. */
function validateRenderTargetFormats(definitions, defaultFormat, deviceFeatures) {
const formats = {};
for (const key of Object.keys(definitions ?? {}).sort()) {
const format = definitions?.[key]?.format ?? defaultFormat;
assertRenderableFormat({
format,
target: key,
pass: "Named render target",
deviceFeatures
});
formats[key] = format;
}
return formats;
}
function resolveInputFormat(slot, workingFormat, namedFormats) {
return slot === "source" || slot === "target" ? workingFormat : namedFormats[slot];
}
function resolveOutputFormat(slot, workingFormat, namedFormats) {
if (slot === "source" || slot === "target") return workingFormat;
if (slot === "canvas") return workingFormat;
return namedFormats[slot];
}
/** Validates only nominally branded MotionGPU render passes; structural custom passes stay open. */
function validateBuiltInRenderPassFormats(input) {
for (const candidate of input.passes) {
if (candidate.enabled === false || !isBuiltInRenderPass(candidate)) continue;
const pass = candidate;
const contract = candidate[builtInRenderPassBrand];
const inputSlot = pass.input ?? "source";
const outputSlot = pass.output ?? (pass.needsSwap ?? true ? "target" : "source");
const inputFormat = resolveInputFormat(inputSlot, input.workingFormat, input.namedFormats);
const outputFormat = resolveOutputFormat(outputSlot, input.workingFormat, input.namedFormats);
if (inputFormat !== void 0) assertFloatSampledFormat({
format: inputFormat,
target: String(inputSlot),
pass: contract.passName,
deviceFeatures: input.deviceFeatures
});
if (outputFormat !== void 0) assertFloatRenderableFormat({
format: outputFormat,
target: String(outputSlot),
pass: contract.passName,
deviceFeatures: input.deviceFeatures
});
}
}
/** Resolves the slot sampled by the implicit presentation pass for a static pass list. */
function resolvePresentationSourceSlot(passes) {
let finalOutput = null;
for (const candidate of passes) {
if (candidate.enabled === false || isManagedComputePass(candidate) || isManagedFeedbackPass(candidate)) continue;
const pass = candidate;
finalOutput = pass.needsSwap ?? true ? "source" : pass.output ?? "source";
}
return finalOutput;
}
/** Validates the implicit fullscreen presentation pass input before graph execution. */
function validatePresentationSourceFormat(input) {
const format = resolveOutputFormat(input.slot, input.workingFormat, input.namedFormats);
if (format === void 0) return;
const capabilities = assertFloatSampledFormat({
format,
target: String(input.slot),
pass: "Presentation pass",
deviceFeatures: input.deviceFeatures
});
if (input.requiresFilterableInput && !capabilities.filterable) throw createFormatCapabilityError({
target: String(input.slot),
format,
pass: "Presentation pass",
capability: "filterable float texture sampling",
detail: "End the graph on workingFormat or enable the format-specific filtering feature."
});
}
//#endregion
export { resolvePresentationSourceSlot, validateBuiltInRenderPassFormats, validatePresentationSourceFormat, validateRenderTargetFormats, validateWorkingFormat };
//# sourceMappingURL=render-format-validation.js.map