Skip to content

Commit 9d90e63

Browse files
committed
feat: Route more definitions through the shader generator
1 parent 299c9a5 commit 9d90e63

7 files changed

Lines changed: 114 additions & 42 deletions

File tree

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

Lines changed: 16 additions & 20 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,13 +117,15 @@ 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];
127-
128-
ctx.addDeclaration(
129-
`@group(${group}) @binding(${binding}) var<${usage}> ${id}: ${ctx.resolve(dataType).value};`,
130-
);
131120

132-
return snip(id, dataType, this.usage);
121+
return ctx.gen.declareGlobalVar({
122+
group,
123+
binding,
124+
scope: this.usage,
125+
id,
126+
dataType,
127+
init: undefined,
128+
});
133129
}
134130

135131
toString(): string {
@@ -243,15 +239,15 @@ export class TgpuLaidOutBufferImpl<TData extends BaseData, TUsage extends Bindab
243239
[$resolve](ctx: ResolutionCtx): ResolvedSnippet {
244240
const id = ctx.makeUniqueIdentifier(getName(this), 'global');
245241
const group = ctx.allocateLayoutEntry(this.#membership.layout);
246-
const usage = usageToVarTemplateMap[this.usage];
247-
248-
ctx.addDeclaration(
249-
`@group(${group}) @binding(${this.#membership.idx}) var<${usage}> ${id}: ${
250-
ctx.resolve(this.dataType).value
251-
};`,
252-
);
253242

254-
return snip(id, this.dataType, this.usage);
243+
return ctx.gen.declareGlobalVar({
244+
group,
245+
binding: this.#membership.idx,
246+
scope: this.usage,
247+
id,
248+
dataType: this.dataType,
249+
init: undefined,
250+
});
255251
}
256252

257253
toString(): string {

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,12 @@ class TgpuConstImpl<TDataType extends BaseData> implements TgpuConst<TDataType>,
109109

110110
[$resolve](ctx: ResolutionCtx): ResolvedSnippet {
111111
const id = ctx.makeUniqueIdentifier(getName(this), 'global');
112-
const resolvedDataType = ctx.resolve(this.dataType).value;
113-
const resolvedValue = ctx.resolve(this.#value, this.dataType).value;
114112

115-
ctx.addDeclaration(`const ${id}: ${resolvedDataType} = ${resolvedValue};`);
116-
117-
return snip(id, this.dataType, 'constant-immutable-def');
113+
return ctx.gen.declareGlobalConst({
114+
id,
115+
dataType: this.dataType,
116+
init: snip(this.#value, this.dataType, 'constant'),
117+
});
118118
}
119119

120120
toString() {

packages/typegpu/src/core/texture/texture.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -613,11 +613,14 @@ class TgpuFixedTextureViewImpl<T extends WgslTexture | WgslStorageTexture>
613613
this,
614614
);
615615

616-
ctx.addDeclaration(
617-
`@group(${group}) @binding(${binding}) var ${id}: ${ctx.resolve(this.schema).value};`,
618-
);
619-
620-
return snip(id, this.schema, /* origin */ 'handle');
616+
return ctx.gen.declareGlobalVar({
617+
group,
618+
binding,
619+
id,
620+
dataType: this.schema,
621+
scope: 'handle',
622+
init: undefined,
623+
});
621624
}
622625
}
623626

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,11 @@ 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-
}
98-
99-
return snip(id, this.#dataType, this.#scope);
95+
return ctx.gen.declareGlobalVar({ scope: this.#scope, id, dataType: this.#dataType, init });
10096
}
10197

10298
$name(label: string) {

packages/typegpu/src/tgsl/shaderGenerator.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
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+
ConstantDefinitionOptions,
6+
FunctionDefinitionOptions,
7+
VariableDefinitionOptions,
8+
} from './shaderGenerator_members.ts';
59

610
/**
711
* **NOTE: This is an unstable API and may change in the future.**
@@ -12,7 +16,10 @@ import type { FunctionDefinitionOptions } from './shaderGenerator_members.ts';
1216
export interface ShaderGenerator {
1317
initGenerator(ctx: GenerationCtx): void;
1418

19+
declareGlobalConst(options: ConstantDefinitionOptions): ResolvedSnippet;
20+
declareGlobalVar(options: VariableDefinitionOptions): ResolvedSnippet;
1521
functionDefinition(options: FunctionDefinitionOptions): string;
22+
1623
typeInstantiation(schema: BaseData, args: readonly Snippet[]): ResolvedSnippet;
1724
typeAnnotation(schema: BaseData): string;
1825
}

packages/typegpu/src/tgsl/shaderGenerator_members.ts

Lines changed: 18 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,18 @@ export interface FunctionDefinitionOptions {
1921

2022
determineReturnType(): BaseData;
2123
}
24+
25+
export interface ConstantDefinitionOptions {
26+
readonly id: string;
27+
readonly dataType: BaseData;
28+
readonly init: Snippet;
29+
}
30+
31+
export interface VariableDefinitionOptions {
32+
readonly scope: VariableScope | BindableBufferUsage | 'handle';
33+
readonly id: string;
34+
readonly dataType: BaseData;
35+
readonly init: Snippet | undefined;
36+
readonly group?: string | undefined;
37+
readonly binding?: number | undefined;
38+
}

packages/typegpu/src/tgsl/wgslGenerator.ts

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ import { $gpuCallable, $internal, $providing, isMarkedInternal } from '../shared
1919
import { safeStringify } from '../shared/stringify.ts';
2020
import { pow } from '../std/numeric.ts';
2121
import { add, div, mul, neg, sub } from '../std/operators.ts';
22-
import { isGPUCallable, isKnownAtComptime, type DualFn } from '../types.ts';
22+
import {
23+
isGPUCallable,
24+
isKnownAtComptime,
25+
type BindableBufferUsage,
26+
type DualFn,
27+
} from '../types.ts';
2328
import { convertStructValues, convertToCommonType, tryConvertSnippet } from './conversion.ts';
2429
import {
2530
ArrayExpression,
@@ -44,10 +49,15 @@ import type { ExternalMap } from '../core/resolve/externals.ts';
4449
import * as forOfUtils from './forOfUtils.ts';
4550
import { isTgpuRange } from '../std/range.ts';
4651
import { stringifyNode } from '../shared/tseynit.ts';
47-
import type { FunctionDefinitionOptions } from './shaderGenerator_members.ts';
52+
import type {
53+
ConstantDefinitionOptions,
54+
FunctionDefinitionOptions,
55+
VariableDefinitionOptions,
56+
} from './shaderGenerator_members.ts';
4857
import { getAttributesString } from '../data/attributes.ts';
4958
import { validSelectBranchTypes } from '../std/boolean.ts';
5059
import { isInfixDispatch } from './infixDispatch.ts';
60+
import type { VariableScope } from '../core/variable/tgpuVariable.ts';
5161

5262
const { NodeTypeCatalog: NODE } = tinyest;
5363

@@ -193,6 +203,14 @@ const binaryOpCodeToCodegen = {
193203
'**': pow[$gpuCallable].call.bind(pow),
194204
} satisfies Partial<Record<tinyest.BinaryOperator, (...args: never[]) => unknown>>;
195205

206+
const usageToVarTemplateMap: Record<VariableScope | BindableBufferUsage, string> = {
207+
private: 'private',
208+
workgroup: 'workgroup',
209+
uniform: 'uniform',
210+
mutable: 'storage, read_write',
211+
readonly: 'storage, read',
212+
};
213+
196214
export class WgslGenerator implements ShaderGenerator {
197215
#ctx: GenerationCtx | undefined = undefined;
198216
// used to detect `continue` and `break` nodes in loop body
@@ -844,6 +862,41 @@ ${this.ctx.pre}}`;
844862
assertExhaustive(expression);
845863
}
846864

865+
public declareGlobalConst(options: ConstantDefinitionOptions): ResolvedSnippet {
866+
const resolvedDataType = this.ctx.resolve(options.dataType).value;
867+
const resolvedValue = this.ctx.resolveSnippet(options.init).value;
868+
869+
this.ctx.addDeclaration(`const ${options.id}: ${resolvedDataType} = ${resolvedValue};`);
870+
871+
return snip(options.id, options.dataType, 'constant-immutable-def');
872+
}
873+
874+
public declareGlobalVar(options: VariableDefinitionOptions): ResolvedSnippet {
875+
let pre = '';
876+
877+
if (options.group !== undefined) {
878+
pre += `@group(${options.group}) `;
879+
}
880+
881+
if (options.binding !== undefined) {
882+
pre += `@binding(${options.binding}) `;
883+
}
884+
885+
if (options.scope in usageToVarTemplateMap) {
886+
pre += `var<${usageToVarTemplateMap[options.scope as keyof typeof usageToVarTemplateMap]}> `;
887+
} else {
888+
pre += `var `;
889+
}
890+
891+
pre += `${options.id}: ${this.ctx.resolve(options.dataType).value}`;
892+
893+
this.ctx.addDeclaration(
894+
options.init ? `${pre} = ${this.ctx.resolveSnippet(options.init).value};` : `${pre};`,
895+
);
896+
897+
return snip(options.id, options.dataType, options.scope);
898+
}
899+
847900
public functionDefinition(options: FunctionDefinitionOptions): string {
848901
// Function body
849902
let body = this._block(options.body);

0 commit comments

Comments
 (0)