@motion-core/motion-gpu
Version:
Framework-agnostic WebGPU runtime for fullscreen WGSL shaders with explicit Svelte, React, and Vue adapter entrypoints.
108 lines (96 loc) • 2.79 kB
text/typescript
import { assertUniformName } from './uniforms.js';
import type { RenderTargetDefinitionMap } from './types.js';
/**
* Concrete render target configuration resolved for current canvas size.
*/
export interface ResolvedRenderTargetDefinition {
/**
* Render target key.
*/
key: string;
/**
* Resolved width in pixels.
*/
width: number;
/**
* Resolved height in pixels.
*/
height: number;
/**
* Resolved format.
*/
format: GPUTextureFormat;
}
/**
* Asserts positive finite numeric input for render target options.
*/
function assertPositiveFinite(name: string, value: number): void {
if (!Number.isFinite(value) || value <= 0) {
throw new Error(`${name} must be a finite number greater than 0`);
}
}
/**
* Resolves a render target dimension from explicit value or scaled canvas size.
*/
function resolveDimension(
explicitValue: number | undefined,
canvasDimension: number,
scale: number
): number {
if (explicitValue !== undefined) {
assertPositiveFinite('RenderTarget dimension', explicitValue);
return Math.max(1, Math.floor(explicitValue));
}
return Math.max(1, Math.floor(canvasDimension * scale));
}
/**
* Resolves all render target definitions for a specific canvas size.
*
* @param definitions - Declarative definitions.
* @param canvasWidth - Current canvas width in pixels.
* @param canvasHeight - Current canvas height in pixels.
* @param defaultFormat - Fallback texture format.
* @returns Sorted concrete render target definitions.
*/
export function resolveRenderTargetDefinitions(
definitions: RenderTargetDefinitionMap | undefined,
canvasWidth: number,
canvasHeight: number,
defaultFormat: GPUTextureFormat
): ResolvedRenderTargetDefinition[] {
if (!definitions) {
return [];
}
const keys = Object.keys(definitions).sort();
const resolved: ResolvedRenderTargetDefinition[] = [];
for (const key of keys) {
assertUniformName(key);
const definition = definitions[key];
const scale = definition?.scale ?? 1;
assertPositiveFinite('RenderTarget scale', scale);
const width = resolveDimension(definition?.width, canvasWidth, scale);
const height = resolveDimension(definition?.height, canvasHeight, scale);
resolved.push({
key,
width,
height,
format: definition?.format ?? defaultFormat
});
}
return resolved;
}
/**
* Builds a deterministic signature used to detect render target topology changes.
*
* @param resolvedDefinitions - Concrete target definitions.
* @returns Stable signature string.
*/
export function buildRenderTargetSignature(
resolvedDefinitions: ResolvedRenderTargetDefinition[]
): string {
return resolvedDefinitions
.map((definition) => {
return `${definition.key}:${definition.format}:${definition.width}x${definition.height}`;
})
.join('|');
}