-
-
Notifications
You must be signed in to change notification settings - Fork 76
feat: Route function calls through the shader generator #2800
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,6 +8,8 @@ import { | |||||||||||||||||||||
| type ResolutionCtx, | ||||||||||||||||||||||
| type TgpuShaderStage, | ||||||||||||||||||||||
| type FunctionDefinitionOptions, | ||||||||||||||||||||||
| type Snippet, | ||||||||||||||||||||||
| snip, | ||||||||||||||||||||||
| } from 'typegpu/~internal'; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // ---------- | ||||||||||||||||||||||
|
|
@@ -68,6 +70,21 @@ ${Object.entries(struct.propTypes) | |||||||||||||||||||||
| return id; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| function correspondingBooleanVectorSchema(dataType: d.BaseData) { | ||||||||||||||||||||||
| if (dataType.type.includes('2')) { | ||||||||||||||||||||||
| return d.vec2b; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| if (dataType.type.includes('3')) { | ||||||||||||||||||||||
| return d.vec3b; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| if (dataType.type.includes('4')) { | ||||||||||||||||||||||
| return d.vec4b; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| throw new Error( | ||||||||||||||||||||||
| `Internal error: schema of type '${dataType.type}' does not have a corresponding boolean vector.`, | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const gl_PositionSnippet = tgpu['~unstable'].rawCodeSnippet('gl_Position', d.vec4f, 'private'); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| interface EntryFnState { | ||||||||||||||||||||||
|
|
@@ -105,6 +122,84 @@ export class GlslGenerator extends WgslGenerator { | |||||||||||||||||||||
| return super.typeAnnotation(data); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| override call( | ||||||||||||||||||||||
| name: string, | ||||||||||||||||||||||
| templateParams: readonly Snippet[], | ||||||||||||||||||||||
| args: readonly Snippet[], | ||||||||||||||||||||||
| ): string { | ||||||||||||||||||||||
| if (name === 'bitcast') { | ||||||||||||||||||||||
| const [target] = templateParams; | ||||||||||||||||||||||
| if (!target || !d.isWgslData(target.value)) { | ||||||||||||||||||||||
| throw new Error(`Expected bitcast() to be called with a data type template parameter`); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| const [source] = args; | ||||||||||||||||||||||
| if (!source || source.dataType === UnknownData) { | ||||||||||||||||||||||
| throw new Error(`Invalid argument passed to bitcast()`); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| const targetSchema = target.value; | ||||||||||||||||||||||
| const sourceSchema = source.dataType; | ||||||||||||||||||||||
| const targetPrimitive = targetSchema.type.startsWith('vec') | ||||||||||||||||||||||
| ? (targetSchema as d.Vec3f).primitive | ||||||||||||||||||||||
| : targetSchema; | ||||||||||||||||||||||
| const sourcePrimitive = sourceSchema.type.startsWith('vec') | ||||||||||||||||||||||
| ? (sourceSchema as d.Vec3f).primitive | ||||||||||||||||||||||
| : sourceSchema; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (sourcePrimitive.type === 'u32' && targetPrimitive.type === 'f32') { | ||||||||||||||||||||||
| return super.call('uintBitsToFloat', [], [source]); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| if (sourcePrimitive.type === 'i32' && targetPrimitive.type === 'f32') { | ||||||||||||||||||||||
| return super.call('intBitsToFloat', [], [source]); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| if (sourcePrimitive.type === 'f32' && targetPrimitive.type === 'u32') { | ||||||||||||||||||||||
| return super.call('floatBitsToUint', [], [source]); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| if (sourcePrimitive.type === 'f32' && targetPrimitive.type === 'i32') { | ||||||||||||||||||||||
| return super.call('floatBitsToInt', [], [source]); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| if (sourceSchema.type === targetSchema.type) { | ||||||||||||||||||||||
| return this.ctx.resolveSnippet(source).value; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| throw new Error(`Cannot bitcast from ${String(sourceSchema)} to ${String(targetSchema)}`); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (name === 'select') { | ||||||||||||||||||||||
| const [falsy, truthy, cond] = args; | ||||||||||||||||||||||
| if (!falsy || !truthy || !cond) { | ||||||||||||||||||||||
| throw new Error(`Invalid number of arguments for 'select'`); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (falsy.dataType !== UnknownData && falsy.dataType.type.startsWith('vec')) { | ||||||||||||||||||||||
| if (cond.dataType !== UnknownData && cond.dataType.type.startsWith('vec')) { | ||||||||||||||||||||||
| return super.call('mix', templateParams, args); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| return super.call('mix', templateParams, [ | ||||||||||||||||||||||
| falsy, | ||||||||||||||||||||||
| truthy, | ||||||||||||||||||||||
| this.typeInstantiation(correspondingBooleanVectorSchema(falsy.dataType), [cond]), | ||||||||||||||||||||||
| ]); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Generating a ternary expression, which is supported in GLSL (scalar condition only) | ||||||||||||||||||||||
| if (cond.dataType !== UnknownData && cond.dataType.type.startsWith('vec')) { | ||||||||||||||||||||||
| throw new Error(`GLSL select() with scalar branches requires a scalar boolean condition`); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return `(${this.ctx.resolveSnippet(cond).value} ? ${this.ctx.resolveSnippet(truthy).value} : ${this.ctx.resolveSnippet(falsy).value})`; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (name === 'saturate') { | ||||||||||||||||||||||
| const [arg] = args; | ||||||||||||||||||||||
| if (!arg) { | ||||||||||||||||||||||
| throw new Error(`Invalid number of arguments for 'saturate'`); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| return super.call('clamp', [], [arg, snip(0, d.f32, 'constant'), snip(1, d.f32, 'constant')]); | ||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This emits
Suggested change
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. frog is right about
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The fix for proper GLSL constants is in a PR that's stacked on top of this one |
||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return super.call(name, templateParams, args); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| override _emitVarDecl( | ||||||||||||||||||||||
| _keyword: 'var' | 'let' | 'const', | ||||||||||||||||||||||
| name: string, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1089,6 +1089,18 @@ ${this.ctx.pre}}`; | |
| return snip(base, schema, /* origin */ 'constant', false); | ||
| } | ||
|
|
||
| public call(name: string, templateParams: readonly Snippet[], args: readonly Snippet[]): string { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we plan on routing all calls through here? Is there an issue for tracking that?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just made one #2829 |
||
| const resolvedTemplateParams = templateParams | ||
| .map((arg) => this.ctx.resolveSnippet(arg).value) | ||
| .join(', '); | ||
| const resolvedArgs = args.map((arg) => this.ctx.resolveSnippet(arg).value).join(', '); | ||
|
|
||
| if (resolvedTemplateParams.length > 0) { | ||
| return `${name}<${resolvedTemplateParams}>(${resolvedArgs})`; | ||
| } | ||
| return `${name}(${resolvedArgs})`; | ||
| } | ||
|
|
||
| protected _return(statement: tinyest.Return): string { | ||
| const returnNode = statement[1]; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GLSL ES 3.0 only supports
mix(genType, genType, genBType)for floating-point vectors, not forgenITypeorgenUType. This means integer-vectorstd.selectwill still emit invalid GLSL here (it was already invalid before this PR, just viaselect(...)). Consider guarding non-float vector selects or adding a dedicated integer/unsigned path.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
???