UNPKG

typegpu

Version:

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

126 lines (125 loc) 4.92 kB
import { snip } from "../../data/snippet.js"; import { getName, setName } from "../../shared/meta.js"; import { $gpuValueOf, $internal, $repr, $resolve, $soul } from "../../shared/symbols.js"; import { comparisonSampler as wgslComparisonSampler, sampler as wgslSampler, } from "../../data/sampler.js"; import { makeDereferenceable } from "../../tgsl/makeDereferenceable.js"; import { makeResolvable } from "../../tgsl/makeResolvable.js"; export function INTERNAL_createSampler(props, root) { return new TgpuFixedSamplerImpl(wgslSampler(), props, root); } export function INTERNAL_createComparisonSampler(props, root) { return new TgpuFixedSamplerImpl(wgslComparisonSampler(), props, root); } export function isSampler(resource) { const maybe = resource; return maybe?.resourceType === 'sampler' && !!maybe[$internal]; } export function isComparisonSampler(resource) { const maybe = resource; return maybe?.resourceType === 'sampler-comparison' && !!maybe[$internal]; } // -------------- // Implementation // -------------- export class TgpuLaidOutSamplerImpl { [$internal] = { materialize: undefined }; resourceType; schema; #membership; static { makeDereferenceable(makeResolvable(TgpuLaidOutSamplerImpl.prototype, { asString() { return `${this.resourceType}:${getName(this) ?? '<unnamed>'}`; }, resolve(ctx) { const id = ctx.makeUniqueIdentifier(getName(this), 'global'); const group = ctx.allocateLayoutEntry(this.#membership.layout); ctx.addDeclaration(`@group(${group}) @binding(${this.#membership.idx}) var ${id}: ${ctx.resolve(this.schema).value};`, id); return snip(id, this.schema, /* origin */ 'handle'); }, }), { codegenMode: { getBaseSnippet(trackingProxy) { return snip(trackingProxy, this.schema, /* origin */ 'handle', false); }, }, normalMode: { get() { throw new Error('Direct access to sampler values is possible only as part of a compute dispatch or draw call.'); }, }, }); } constructor(schema, membership) { this.schema = schema; this.#membership = membership; this.resourceType = (schema.type === 'sampler_comparison' ? 'sampler-comparison' : 'sampler'); setName(this, membership.key); } } class TgpuFixedSamplerImpl { [$internal]; [$soul]; resourceType; schema; #filtering; static { makeDereferenceable(makeResolvable(TgpuFixedSamplerImpl.prototype, { asString() { return `${this.resourceType}:${getName(this) ?? '<unnamed>'}`; }, resolve(ctx) { const id = ctx.makeUniqueIdentifier(getName(this), 'global'); const { group, binding } = ctx.allocateFixedEntry(this.schema.type === 'sampler_comparison' ? { sampler: 'comparison' } : { sampler: this.#filtering ? 'filtering' : 'non-filtering' }, this); ctx.addDeclaration(`@group(${group}) @binding(${binding}) var ${id}: ${ctx.resolve(this.schema).value};`, id); return snip(id, this.schema, /* origin */ 'handle'); }, }), { codegenMode: { getBaseSnippet(trackingProxy) { return snip(trackingProxy, this.schema, /* origin */ 'handle', false); }, }, normalMode: { get() { throw new Error('Direct access to sampler values is possible only as part of a compute dispatch or draw call.'); }, }, }); } constructor(schema, props, root) { this.schema = schema; this.resourceType = (schema.type === 'sampler_comparison' ? 'sampler-comparison' : 'sampler'); this[$soul] = { type: this.resourceType, device: root.device, props, raw: undefined, label: undefined, }; this[$internal] = { root, materialize: () => { const soul = this[$soul]; if (!soul.raw) { soul.raw = soul.device.createSampler({ ...soul.props, label: getName(this) ?? '<unnamed>', }); } return soul.raw; }, }; // Based on https://www.w3.org/TR/webgpu/#sampler-creation this.#filtering = props.minFilter === 'linear' || props.magFilter === 'linear' || props.mipmapFilter === 'linear'; } $name(label) { setName(this, label); return this; } }