Skip to content

feat: layout.value #1098

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

Merged
merged 5 commits into from
Apr 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ import tgpu from 'typegpu';
import * as d from 'typegpu/data';
import * as std from 'typegpu/std';
import * as p from './params';
import { computeBindGroupLayout } from './schemas';
import { computeBindGroupLayout as layout } from './schemas';
import { distanceVectorFromLine } from './tgsl-helpers';

const { currentFishData, nextFishData, mouseRay, timePassed } =
computeBindGroupLayout.bound;

export const computeShader = tgpu['~unstable']
.computeFn({
in: { gid: d.builtin.globalInvocationId },
workgroupSize: [p.workGroupSize],
})((input) => {
const fishIndex = input.gid.x;
const fishData = currentFishData.value[fishIndex];
const fishData = layout.$.currentFishData[fishIndex];
let separation = d.vec3f();
let alignment = d.vec3f();
let alignmentCount = 0;
Expand All @@ -28,7 +25,7 @@ export const computeShader = tgpu['~unstable']
continue;
}

const other = currentFishData.value[i];
const other = layout.$.currentFishData[i];
const dist = std.length(std.sub(fishData.position, other.position));
if (dist < p.fishSeparationDistance) {
separation = std.add(
Expand Down Expand Up @@ -73,10 +70,10 @@ export const computeShader = tgpu['~unstable']
}
}

if (mouseRay.value.activated === 1) {
if (layout.$.mouseRay.activated === 1) {
const distanceVector = distanceVectorFromLine({
lineStart: mouseRay.value.pointX,
lineEnd: mouseRay.value.pointY,
lineStart: layout.$.mouseRay.pointX,
lineEnd: layout.$.mouseRay.pointY,
point: fishData.position,
});
const limit = p.fishMouseRayRepulsionDistance;
Expand Down Expand Up @@ -112,10 +109,10 @@ export const computeShader = tgpu['~unstable']
);

const translation = std.mul(
d.f32(std.min(999, timePassed.value)) / 8,
d.f32(std.min(999, layout.$.timePassed)) / 8,
fishData.direction,
);
fishData.position = std.add(fishData.position, translation);
nextFishData.value[fishIndex] = fishData;
layout.$.nextFishData[fishIndex] = fishData;
})
.$name('compute shader');
27 changes: 12 additions & 15 deletions apps/typegpu-docs/src/content/examples/rendering/3d-fish/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,18 @@ import * as p from './params';
import {
ModelVertexInput,
ModelVertexOutput,
renderBindGroupLayout,
renderBindGroupLayout as layout,
} from './schemas';
import { applySinWave } from './tgsl-helpers';

const { camera, modelTexture, sampler, modelData, currentTime } =
renderBindGroupLayout.bound;

export const vertexShader = tgpu['~unstable']
.vertexFn({
in: { ...ModelVertexInput, instanceIndex: d.builtin.instanceIndex },
out: ModelVertexOutput,
})((input) => {
// rotate the model so that it aligns with model's direction of movement
// https://simple.wikipedia.org/wiki/Pitch,_yaw,_and_roll
const currentModelData = modelData.value[input.instanceIndex];
const currentModelData = layout.$.modelData[input.instanceIndex];

// apply sin wave

Expand All @@ -29,7 +26,7 @@ export const vertexShader = tgpu['~unstable']
if (currentModelData.applySinWave === 1) {
const wavedResults = applySinWave(
input.instanceIndex,
currentTime.value,
layout.$.currentTime,
input.modelPosition,
input.modelNormal,
);
Expand Down Expand Up @@ -73,8 +70,8 @@ export const vertexShader = tgpu['~unstable']
// project the world position into the camera
const worldPositionUniform = d.vec4f(worldPosition.xyz, 1);
const canvasPosition = std.mul(
camera.value.projection,
std.mul(camera.value.view, worldPositionUniform),
layout.$.camera.projection,
std.mul(layout.$.camera.view, worldPositionUniform),
);

return {
Expand All @@ -87,17 +84,17 @@ export const vertexShader = tgpu['~unstable']
variant: currentModelData.variant,
};
})
.$name('vertex shader');
.$name('vertexShader');

const sampleTexture = tgpu['~unstable']
.fn(
{ uv: d.vec2f },
d.vec4f,
)(/* wgsl */ `{
return textureSample(shaderTexture, shaderSampler, uv);
return textureSample(layout.$.modelTexture, layout.$.sampler, uv);
}`)
.$uses({ shaderTexture: modelTexture, shaderSampler: sampler })
.$name('sampleShader');
.$uses({ layout })
.$name('sampleTexture');

export const fragmentShader = tgpu['~unstable']
.fragmentFn({
Expand All @@ -120,7 +117,7 @@ export const fragmentShader = tgpu['~unstable']
);

const viewSource = std.normalize(
std.sub(camera.value.position.xyz, input.worldPosition),
std.sub(layout.$.camera.position.xyz, input.worldPosition),
);
const reflectSource = std.normalize(
std.reflect(std.mul(-1, p.lightDirection), input.worldNormal),
Expand All @@ -135,7 +132,7 @@ export const fragmentShader = tgpu['~unstable']

// apply desaturation
const distanceFromCamera = std.length(
std.sub(camera.value.position.xyz, input.worldPosition),
std.sub(layout.$.camera.position.xyz, input.worldPosition),
);

let desaturatedColor = lightedColor;
Expand All @@ -159,4 +156,4 @@ export const fragmentShader = tgpu['~unstable']

return d.vec4f(foggedColor.xyz, 1);
})
.$name('fragment shader');
.$name('fragmentShader');
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ const boxSizeUniform = root['~unstable']

// bind groups and layouts

const renderBindGroupLayout = tgpu.bindGroupLayout({
const renderLayout = tgpu.bindGroupLayout({
boxMatrix: { storage: boxMatrixBuffer.dataType },
cameraPosition: { storage: cameraPositionBuffer.dataType },
cameraAxes: { storage: cameraAxesBuffer.dataType },
});

const renderBindGroup = root.createBindGroup(renderBindGroupLayout, {
const renderBindGroup = root.createBindGroup(renderLayout, {
boxMatrix: boxMatrixBuffer,
cameraPosition: cameraPositionBuffer,
cameraAxes: cameraAxesBuffer,
Expand Down Expand Up @@ -252,7 +252,7 @@ const fragmentFunction = tgpu['~unstable']
return color;
}`)
.$uses({
...renderBindGroupLayout.bound,
...renderLayout.bound,
RayStruct,
getBoxIntersection,
X,
Expand Down Expand Up @@ -281,7 +281,7 @@ const pipeline = root['~unstable']
.withVertex(vertexFunction, {})
.withFragment(fragmentFunction, { format: presentationFormat })
.createPipeline()
.with(renderBindGroupLayout, renderBindGroup);
.with(renderLayout, renderBindGroup);

// UI

Expand Down
4 changes: 2 additions & 2 deletions packages/typegpu/src/core/resolve/externals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export function addReturnTypeToExternals(

function identifierRegex(name: string) {
return new RegExp(
`(?<![\\w_.])${name.replaceAll('.', '\\.')}(?![\\w_])`,
`(?<![\\w\\$_.])${name.replaceAll('.', '\\.').replaceAll('$', '\\$')}(?![\\w\\$_])`,
'g',
);
}
Expand Down Expand Up @@ -100,7 +100,7 @@ export function replaceExternalsInWgsl(
[
...wgsl.matchAll(
new RegExp(
`${externalName.replaceAll('.', '\\.')}\\.(?<prop>.*?)(?![\\w_])`,
`${externalName.replaceAll('.', '\\.').replaceAll('$', '\\$')}\\.(?<prop>.*?)(?![\\w\\$_])`,
'g',
),
),
Expand Down
58 changes: 56 additions & 2 deletions packages/typegpu/src/tgpuBindGroupLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import {
type Sampled,
isUsableAsSampled,
} from './core/texture/usageExtension';
import type { AnyData } from './data';
import type { AnyData } from './data/dataTypes.js';
import type { AnyWgslData, BaseData } from './data/wgslTypes';
import { NotUniformError } from './errors';
import {
Expand All @@ -57,6 +57,7 @@ import {
isUsableAsStorage,
} from './extension';
import type { TgpuNamable } from './namable';
import type { Infer } from './shared/repr.js';
import type { Default, OmitProps, Prettify } from './shared/utilityTypes';
import type { TgpuShaderStage } from './types';
import type { Unwrapper } from './unwrapper';
Expand Down Expand Up @@ -164,6 +165,12 @@ export interface TgpuBindGroupLayout<
readonly bound: {
[K in keyof Entries]: BindLayoutEntry<Entries[K]>;
};
readonly value: {
[K in keyof Entries]: InferLayoutEntry<Entries[K]>;
};
readonly $: {
[K in keyof Entries]: InferLayoutEntry<Entries[K]>;
};

/**
* An explicit numeric index assigned to this bind group layout. If undefined, a unique
Expand Down Expand Up @@ -309,7 +316,7 @@ export type LayoutEntryToInput<T extends TgpuLayoutEntry | null> =

export type BindLayoutEntry<T extends TgpuLayoutEntry | null> =
T extends TgpuLayoutUniform
? TgpuBufferUniform<UnwrapRuntimeConstructor<T['uniform']>>
? TgpuBufferUniform<T['uniform']>
: T extends TgpuLayoutStorage
? StorageUsageForEntry<T>
: T extends TgpuLayoutSampler
Expand All @@ -325,6 +332,24 @@ export type BindLayoutEntry<T extends TgpuLayoutEntry | null> =
? StorageTextureUsageForEntry<T>
: never;

export type InferLayoutEntry<T extends TgpuLayoutEntry | null> =
T extends TgpuLayoutUniform
? Infer<T['uniform']>
: T extends TgpuLayoutStorage
? Infer<UnwrapRuntimeConstructor<T['storage']>>
: T extends TgpuLayoutSampler
? TgpuSampler
: T extends TgpuLayoutComparisonSampler
? TgpuComparisonSampler
: T extends TgpuLayoutTexture
? TgpuSampledTexture<
Default<GetDimension<T['viewDimension']>, '2d'>,
ChannelFormatToSchema[T['texture']]
>
: T extends TgpuLayoutStorageTexture
? StorageTextureUsageForEntry<T>
: never;

export type TgpuBindGroup<
Entries extends Record<string, TgpuLayoutEntry | null> = Record<
string,
Expand Down Expand Up @@ -392,6 +417,14 @@ class TgpuBindGroupLayoutImpl<
[K in keyof Entries]: BindLayoutEntry<Entries[K]>;
};

public readonly value = {} as {
[K in keyof Entries]: InferLayoutEntry<Entries[K]>;
};

public readonly $ = this.value as {
[K in keyof Entries]: InferLayoutEntry<Entries[K]>;
};

constructor(public readonly entries: Entries) {
let idx = 0;

Expand Down Expand Up @@ -461,10 +494,31 @@ class TgpuBindGroupLayoutImpl<
}
}

if (
'texture' in entry ||
'storageTexture' in entry ||
'externalTexture' in entry ||
'sampler' in entry
) {
// biome-ignore lint/suspicious/noExplicitAny: <no need for type magic>
(this.value as any)[key] = this.bound[key];
} else {
Object.defineProperty(this.value, key, {
get: () => {
// biome-ignore lint/suspicious/noExplicitAny: <no need for type magic>
return (this.bound[key] as any).value;
},
});
}

idx++;
}
}

toString(): string {
return `bindGroupLayout:${this._label ?? '<unnamed>'}`;
}

get label(): string | undefined {
return this._label;
}
Expand Down