UNPKG

typegpu

Version:

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

94 lines (93 loc) 3.88 kB
import { stitch } from "../../core/resolve/stitch.js"; import { shaderStageSlot } from "../../core/slot/internalSlots.js"; import { arrayOf } from "../../data/array.js"; import { atomic } from "../../data/atomic.js"; import { UnknownData, unptr } from "../../data/dataTypes.js"; import { u32 } from "../../data/numeric.js"; import { snip } from "../../data/snippet.js"; import { struct } from "../../data/struct.js"; import { Void, } from "../../data/wgslTypes.js"; import { invariant } from "../../errors.js"; import { $internal } from "../../shared/symbols.js"; import { logger } from "../../tgpuLogger.js"; import { convertToCommonType } from "../conversion.js"; import { concretizeSnippet } from "../generationHelpers.js"; import { createLoggingFunction } from "./serializers.js"; import {} from "./types.js"; const defaultOptions = { logCountLimit: 64, logSizeLimit: 252, messagePrefix: ' GPU ', }; const fallbackSnippet = snip('/* console.log() */', Void, /* origin */ 'runtime'); export class LogGeneratorNullImpl { get logResources() { return undefined; } generateLog() { logger.warn('fallback', "'console.log' is only supported when resolving pipelines."); return fallbackSnippet; } } export class LogGeneratorImpl { #options; #logIdToMeta; #firstUnusedId = 1; #indexBuffer; #dataBuffer; constructor(root) { this.#options = { ...defaultOptions, ...root[$internal].logOptions }; this.#logIdToMeta = new Map(); const SerializedLogData = struct({ id: u32, serializedData: arrayOf(u32, Math.ceil(this.#options.logSizeLimit / 4)), }).$name('SerializedLogData'); this.#dataBuffer = root .createMutable(arrayOf(SerializedLogData, this.#options.logCountLimit)) .$name('dataBuffer'); this.#indexBuffer = root.createMutable(atomic(u32)).$name('indexBuffer'); } /** * Generates all necessary resources for serializing arguments for logging purposes. * * @param ctx Resolution context. * @param args Argument snippets. Snippets of UnknownType will be treated as string literals. * @returns A snippet containing the call to the logging function. */ generateLog(ctx, op, args) { if (shaderStageSlot.$ === 'vertex') { logger.warn('suspicious', `'console' operations are not supported in vertex shaders.`); return fallbackSnippet; } const id = this.#firstUnusedId++; const concreteArgsWithStrings = args .map((arg) => { if (arg.dataType === UnknownData) { return arg; } const converted = convertToCommonType(ctx, [arg], [unptr(arg.dataType)])?.[0]; invariant(converted, `Internal error. Expected type ${arg.dataType} to be convertible to ${unptr(arg.dataType)}`); return converted; }) .map(concretizeSnippet); const concreteArgs = concreteArgsWithStrings.filter((arg) => arg.dataType !== UnknownData); const logFn = createLoggingFunction(id, concreteArgs.map((e) => e.dataType), this.#dataBuffer, this.#indexBuffer, this.#options); const functionSnippet = snip(stitch `${ctx.resolve(logFn).value}(${concreteArgs})`, Void, /* origin */ 'runtime'); this.#logIdToMeta.set(id, { op, argTypes: concreteArgsWithStrings.map((e) => e?.dataType === UnknownData ? e?.value : e?.dataType), }); return functionSnippet; } get logResources() { return this.#firstUnusedId === 1 ? undefined : { dataBuffer: this.#dataBuffer, indexBuffer: this.#indexBuffer, options: this.#options, logIdToMeta: this.#logIdToMeta, }; } }