Skip to content

Commit e264361

Browse files
committed
feat: Route more definitions through the shader generator
1 parent 6c84c37 commit e264361

6 files changed

Lines changed: 91 additions & 25 deletions

File tree

packages/typegpu/src/core/buffer/bufferUsage.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,6 @@ export function isUsableAsUniform<T extends TgpuBuffer<BaseData>>(
8686
// Implementation
8787
// --------------
8888

89-
const usageToVarTemplateMap: Record<BindableBufferUsage, string> = {
90-
uniform: 'uniform',
91-
mutable: 'storage, read_write',
92-
readonly: 'storage, read',
93-
};
94-
9589
class TgpuFixedBufferImpl<TData extends BaseData, TUsage extends BindableBufferUsage>
9690
implements TgpuBufferUsage<TData, TUsage>, SelfResolvable, TgpuFixedBufferUsage<TData>
9791
{
@@ -123,10 +117,16 @@ class TgpuFixedBufferImpl<TData extends BaseData, TUsage extends BindableBufferU
123117
this.usage === 'uniform' ? { uniform: dataType } : { storage: dataType, access: this.usage },
124118
this.buffer,
125119
);
126-
const usage = usageToVarTemplateMap[this.usage];
127120

128121
ctx.addDeclaration(
129-
`@group(${group}) @binding(${binding}) var<${usage}> ${id}: ${ctx.resolve(dataType).value};`,
122+
ctx.gen.globalVarDefinition({
123+
scope: this.usage,
124+
name: id,
125+
dataType,
126+
group: group,
127+
binding: binding,
128+
init: undefined,
129+
}),
130130
);
131131

132132
return snip(id, dataType, isNaturallyEphemeral(dataType) ? 'runtime' : this.usage);
@@ -243,12 +243,16 @@ export class TgpuLaidOutBufferImpl<TData extends BaseData, TUsage extends Bindab
243243
[$resolve](ctx: ResolutionCtx): ResolvedSnippet {
244244
const id = ctx.makeUniqueIdentifier(getName(this), 'global');
245245
const group = ctx.allocateLayoutEntry(this.#membership.layout);
246-
const usage = usageToVarTemplateMap[this.usage];
247246

248247
ctx.addDeclaration(
249-
`@group(${group}) @binding(${this.#membership.idx}) var<${usage}> ${id}: ${
250-
ctx.resolve(this.dataType).value
251-
};`,
248+
ctx.gen.globalVarDefinition({
249+
scope: this.usage,
250+
name: id,
251+
dataType: this.dataType,
252+
group: group,
253+
binding: this.#membership.idx,
254+
init: undefined,
255+
}),
252256
);
253257

254258
return snip(id, this.dataType, isNaturallyEphemeral(this.dataType) ? 'runtime' : this.usage);

packages/typegpu/src/core/constant/tgpuConstant.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,14 @@ class TgpuConstImpl<TDataType extends BaseData> implements TgpuConst<TDataType>,
114114

115115
[$resolve](ctx: ResolutionCtx): ResolvedSnippet {
116116
const id = ctx.makeUniqueIdentifier(getName(this), 'global');
117-
const resolvedDataType = ctx.resolve(this.dataType).value;
118-
const resolvedValue = ctx.resolve(this.#value, this.dataType).value;
119117

120-
ctx.addDeclaration(`const ${id}: ${resolvedDataType} = ${resolvedValue};`);
118+
ctx.addDeclaration(
119+
ctx.gen.globalConstDefinition(
120+
id,
121+
this.dataType,
122+
snip(this.#value, this.dataType, 'constant'),
123+
),
124+
);
121125

122126
return snip(
123127
id,

packages/typegpu/src/core/variable/tgpuVariable.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,13 @@ class TgpuVarImpl<TScope extends VariableScope, TDataType extends BaseData>
8888

8989
[$resolve](ctx: ResolutionCtx): ResolvedSnippet {
9090
const id = ctx.makeUniqueIdentifier(getName(this), 'global');
91-
const pre = `var<${this.#scope}> ${id}: ${ctx.resolve(this.#dataType).value}`;
91+
const init = this.#initialValue
92+
? snip(this.#initialValue, this.#dataType, 'constant')
93+
: undefined;
9294

93-
if (this.#initialValue) {
94-
ctx.addDeclaration(`${pre} = ${ctx.resolve(this.#initialValue, this.#dataType).value};`);
95-
} else {
96-
ctx.addDeclaration(`${pre};`);
97-
}
95+
ctx.addDeclaration(
96+
ctx.gen.globalVarDefinition({ scope: this.#scope, name: id, dataType: this.#dataType, init }),
97+
);
9898

9999
return snip(id, this.#dataType, isNaturallyEphemeral(this.#dataType) ? 'runtime' : this.#scope);
100100
}

packages/typegpu/src/tgsl/shaderGenerator.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import type { BaseData } from '../data/wgslTypes.ts';
22
import type { GenerationCtx } from './generationHelpers.ts';
33
import type { ResolvedSnippet, Snippet } from '../data/snippet.ts';
4-
import type { FunctionDefinitionOptions } from './shaderGenerator_members.ts';
4+
import type {
5+
FunctionDefinitionOptions,
6+
VariableDefinitionOptions,
7+
} from './shaderGenerator_members.ts';
58

69
/**
710
* **NOTE: This is an unstable API and may change in the future.**
@@ -12,7 +15,10 @@ import type { FunctionDefinitionOptions } from './shaderGenerator_members.ts';
1215
export interface ShaderGenerator {
1316
initGenerator(ctx: GenerationCtx): void;
1417

18+
globalConstDefinition(id: string, schema: BaseData, init: Snippet): string;
19+
globalVarDefinition(options: VariableDefinitionOptions): string;
1520
functionDefinition(options: FunctionDefinitionOptions): string;
21+
1622
typeInstantiation(schema: BaseData, args: readonly Snippet[]): ResolvedSnippet;
1723
typeAnnotation(schema: BaseData): string;
1824
}

packages/typegpu/src/tgsl/shaderGenerator_members.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import type { Block } from 'tinyest';
22
import type { BaseData } from '../data/wgslTypes.ts';
3-
import type { FunctionArgument, TgpuShaderStage } from '../types.ts';
3+
import type { BindableBufferUsage, FunctionArgument, TgpuShaderStage } from '../types.ts';
4+
import type { VariableScope } from '../core/variable/tgpuVariable.ts';
5+
import type { Snippet } from '../data/snippet.ts';
46

57
export { UnknownData } from '../data/dataTypes.ts';
68
export { getName } from '../shared/meta.ts';
@@ -19,3 +21,12 @@ export interface FunctionDefinitionOptions {
1921

2022
determineReturnType(): BaseData;
2123
}
24+
25+
export interface VariableDefinitionOptions {
26+
readonly scope: VariableScope | BindableBufferUsage;
27+
readonly name: string;
28+
readonly dataType: BaseData;
29+
readonly init: Snippet | undefined;
30+
readonly group?: string | undefined;
31+
readonly binding?: number | undefined;
32+
}

packages/typegpu/src/tgsl/wgslGenerator.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ import { $gpuCallable, $internal, $providing, isMarkedInternal } from '../shared
2020
import { safeStringify } from '../shared/stringify.ts';
2121
import { pow } from '../std/numeric.ts';
2222
import { add, div, mul, neg, sub } from '../std/operators.ts';
23-
import { isGPUCallable, isKnownAtComptime, type DualFn } from '../types.ts';
23+
import {
24+
isGPUCallable,
25+
isKnownAtComptime,
26+
type BindableBufferUsage,
27+
type DualFn,
28+
} from '../types.ts';
2429
import { convertStructValues, convertToCommonType, tryConvertSnippet } from './conversion.ts';
2530
import {
2631
ArrayExpression,
@@ -45,8 +50,12 @@ import type { ExternalMap } from '../core/resolve/externals.ts';
4550
import * as forOfUtils from './forOfUtils.ts';
4651
import { isTgpuRange } from '../std/range.ts';
4752
import { stringifyNode } from '../shared/tseynit.ts';
48-
import type { FunctionDefinitionOptions } from './shaderGenerator_members.ts';
53+
import type {
54+
FunctionDefinitionOptions,
55+
VariableDefinitionOptions,
56+
} from './shaderGenerator_members.ts';
4957
import { getAttributesString } from '../data/attributes.ts';
58+
import type { VariableScope } from '../core/variable/tgpuVariable.ts';
5059

5160
const { NodeTypeCatalog: NODE } = tinyest;
5261

@@ -192,6 +201,14 @@ const binaryOpCodeToCodegen = {
192201
'**': pow[$gpuCallable].call.bind(pow),
193202
} satisfies Partial<Record<tinyest.BinaryOperator, (...args: never[]) => unknown>>;
194203

204+
const usageToVarTemplateMap: Record<VariableScope | BindableBufferUsage, string> = {
205+
private: 'private',
206+
workgroup: 'workgroup',
207+
uniform: 'uniform',
208+
mutable: 'storage, read_write',
209+
readonly: 'storage, read',
210+
};
211+
195212
export class WgslGenerator implements ShaderGenerator {
196213
#ctx: GenerationCtx | undefined = undefined;
197214
// used to detect `continue` and `break` nodes in loop body
@@ -867,6 +884,30 @@ ${this.ctx.pre}}`;
867884
assertExhaustive(expression);
868885
}
869886

887+
public globalConstDefinition(id: string, schema: wgsl.BaseData, init: Snippet): string {
888+
const resolvedDataType = this.ctx.resolve(schema).value;
889+
const resolvedValue = this.ctx.resolveSnippet(init).value;
890+
891+
return `const ${id}: ${resolvedDataType} = ${resolvedValue};`;
892+
}
893+
894+
public globalVarDefinition(options: VariableDefinitionOptions): string {
895+
let pre = `var<${usageToVarTemplateMap[options.scope]}> ${options.name}: ${this.ctx.resolve(options.dataType).value}`;
896+
897+
if (options.binding !== undefined) {
898+
pre = `@binding(${options.binding}) ` + pre;
899+
}
900+
901+
if (options.group !== undefined) {
902+
pre = `@group(${options.group}) ` + pre;
903+
}
904+
905+
if (options.init) {
906+
return `${pre} = ${this.ctx.resolveSnippet(options.init).value};`;
907+
}
908+
return `${pre};`;
909+
}
910+
870911
public functionDefinition(options: FunctionDefinitionOptions): string {
871912
// Function body
872913
const body = this._block(options.body);

0 commit comments

Comments
 (0)