UNPKG

typegpu

Version:

A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.

87 lines (86 loc) 3.72 kB
import { $gpuValueOf, $internal, $ownSnippet, $resolve } from "../shared/symbols.js"; import { valueProxyHandler } from "../core/valueProxyUtils.js"; import { getExecMode } from "../execMode.js"; import { assertExhaustive } from "../shared/utilityTypes.js"; /** * WARNING: This is an API that touches a lot of internals, and is not stable * (can change between patches). You should probably talk to the TypeGPU team * before using this, maybe we can provide a better public API for your use case. * * Defines additional properties on `value` (mutates it) that makes TypeGPU * understand how it should handle using .$ on that object. All dereferenceable * value must also be made resolvable (through the makeResolvable API). * * `value` can in particular be the prototype of a class, meaning all instances * of that class will be dereferenceable. */ export function makeDereferenceable(value, options) { Object.defineProperty(value, $gpuValueOf, { get() { if ('get' in options.codegenMode) { return options.codegenMode.get.apply(this); } // oxlint-disable-next-line typescript/no-this-alias const resource = this; return new Proxy({ [$internal]: true, get [$ownSnippet]() { if (!('getBaseSnippet' in options.codegenMode)) { throw new Error(`Expected 'getBaseSnippet' to be defined.`); } return options.codegenMode.getBaseSnippet.apply(resource, [this]); }, [$resolve]: (ctx) => ctx.resolve(resource), toString: () => `${resource.toString()}.$`, }, valueProxyHandler); }, }); Object.defineProperty(value, '$', { get() { const mode = getExecMode(); if (mode.type === 'codegen') { return this[$gpuValueOf]; } if (mode.type === 'simulate') { if (options.simulateMode?.get) { return options.simulateMode.get.apply(this, [mode]); } return options.normalMode.get.apply(this); } if (mode.type === 'normal') { return options.normalMode.get.apply(this); } return assertExhaustive(mode, 'makeDereferenceable.ts#$ (get)'); }, set(value) { const mode = getExecMode(); if (mode.type === 'normal') { if (!options.normalMode.set) { throw new Error(`'${this.toString()}' cannot be set in normal mode`); } options.normalMode.set.apply(this, [value]); return; } if (mode.type === 'simulate') { if (options.simulateMode?.set) { options.simulateMode.set.apply(this, [mode, value]); } else if (options.normalMode.set) { // Falling back to the 'normal' set options.normalMode.set.apply(this, [value]); } else { throw new Error(`'${this.toString()}' cannot be set in simulate mode`); } return; } if (mode.type === 'codegen') { // The shader generator handles assignment, and does not defer to // whatever's being assigned to generate the shader code. throw new Error('Unreachable makeDerefenceable.ts#$ (set)'); } return assertExhaustive(mode, 'makeDereferenceable.ts#$ (set)'); }, }); return value; }