Skip to content

Commit 7c1fe79

Browse files
authored
Merge pull request #603 from software-mansion/0.3
0.3
2 parents e1bc670 + e83f973 commit 7c1fe79

File tree

26 files changed

+385
-154
lines changed

26 files changed

+385
-154
lines changed

apps/typegpu-docs/astro.config.mjs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ export default defineConfig({
109109
{
110110
label: 'Roots',
111111
slug: 'fundamentals/roots',
112-
badge: { text: '0.2' },
113112
},
114113
{
115114
label: 'Buffers',
@@ -122,7 +121,11 @@ export default defineConfig({
122121
{
123122
label: 'Bind Groups',
124123
slug: 'fundamentals/bind-groups',
125-
badge: { text: '0.2' },
124+
},
125+
{
126+
label: 'Resolve',
127+
slug: 'fundamentals/resolve',
128+
badge: { text: '0.3' },
126129
},
127130
DEV && {
128131
label: 'Slots',
@@ -145,15 +148,14 @@ export default defineConfig({
145148
{
146149
label: 'Integration',
147150
items: stripFalsy([
148-
DEV && {
151+
{
149152
label: 'WebGPU Interoperability',
150153
slug: 'integration/webgpu-interoperability',
151154
badge: { text: 'new' },
152155
},
153156
{
154157
label: 'Working with wgpu-matrix',
155158
slug: 'integration/working-with-wgpu-matrix',
156-
badge: { text: 'new' },
157159
},
158160
]),
159161
},
@@ -163,7 +165,6 @@ export default defineConfig({
163165
{
164166
label: 'Generator CLI',
165167
slug: 'tooling/tgpu-gen',
166-
badge: { text: 'new' },
167168
},
168169
]),
169170
},

apps/typegpu-docs/src/components/roadmap/MilestoneLinkerBadge.astro

Lines changed: 29 additions & 0 deletions
Large diffs are not rendered by default.

apps/typegpu-docs/src/content/docs/fundamentals/bind-groups.mdx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const fooBuffer = ...;
2626
const barTexture = ...;
2727

2828
// Create a bind group that can fulfill the required layout.
29-
const fooBindGroup = fooLayout.populate({
29+
const fooBindGroup = root.createBindGroup(fooLayout, {
3030
foo: fooBuffer,
3131
bar: barTexture,
3232
});
@@ -124,6 +124,10 @@ Matching WGSL statement:
124124
Apart from being able to specify any data type, we can signal that the shader is generalized to work on
125125
arbitrarily sized data by passing a function.
126126

127+
:::note
128+
Runtime-sized arrays are only usable with **storage** buffers.
129+
:::
130+
127131
```ts
128132
// main.ts
129133
const Filter = (n: number) =>
@@ -195,7 +199,7 @@ You can see the list of supported storage texture formats [here](https://www.w3.
195199
## Bind Groups
196200

197201
Before execution of a pipeline, any bind group that matches a given layout can be put in its place and used by the shader.
198-
To create a bind group, you can call the `populate` method on the bind group layout and associate each named key with
202+
To create a bind group, you can call the `createBindGroup` method on the [root object](/TypeGPU/fundamentals/roots) and associate each named key with
199203
a proper resource.
200204

201205
```ts
@@ -205,13 +209,13 @@ const fooLayout = tgpu.bindGroupLayout({
205209
// ...
206210
});
207211

208-
const fooBindGroup0 = fooLayout.populate({
212+
const fooBindGroup0 = root.createBindGroup(fooLayout, {
209213
key1: ...,
210214
key0: ...,
211215
// ...
212216
});
213217

214-
const fooBindGroup1 = fooLayout.populate({
218+
const fooBindGroup1 = root.createBindGroup(fooLayout, {
215219
key0: ...,
216220
key1: ...,
217221
// ...

apps/typegpu-docs/src/content/docs/fundamentals/buffers.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,14 @@ If you pass an unmapped buffer, the data will be written to the buffer using `GP
189189
If you passed your own buffer to the `root.createBuffer` function, you need to ensure it has the `GPUBufferUsage.COPY_DST` usage flag if you want to write to it using the `write` method.
190190
:::
191191

192+
There's also an option to copy value from another typed buffer using the `.copyFrom(buffer)` method,
193+
as long as both buffers have a matching data schema.
194+
195+
```ts
196+
const backupParticleBuffer = root.createBuffer(Particle);
197+
backupParticleBuffer.copyFrom(particleBuffer);
198+
```
199+
192200
## Reading from a buffer
193201

194202
To read data from a buffer, you can use the `.read()` method.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
---
2+
title: Resolve
3+
description: Resolve API can be used to extend shader code with WGSL definitions of TypeGPU-defined objects.
4+
---
5+
6+
Defining shader schemas and objects in JS/TS has lots of benefits, but having to keep them in sync with the corresponding WGSL code is hard to maintain.
7+
The `tgpu.resolve` API takes in a WGSL template, all TypeGPU schemas that you want to use in the shader, and generates a ready-to-use WGSL bundle.
8+
9+
:::note
10+
`tgpu.resolve` is essentially a dedicated TypeGPU linker.
11+
:::
12+
13+
Here's an example:
14+
```ts
15+
import tgpu from 'typegpu';
16+
import * as d from 'typegpu/data';
17+
18+
const LightSource = d
19+
.struct({
20+
ambientColor: d.vec3f,
21+
intensity: d.f32,
22+
})
23+
.$name('Source');
24+
// ^ giving the struct an explicit name (optional)
25+
26+
const layout = tgpu
27+
.bindGroupLayout({
28+
lightSource: { uniform: LightSource },
29+
sampling: { sampler: 'filtering' },
30+
bgTexture: { externalTexture: {} },
31+
})
32+
.$idx(0);
33+
// ^ forces code-gen to assign `0` as the group index (optional)
34+
35+
const rawShader = /* wgsl */ `
36+
@fragment
37+
fn main(@location(0) uv: vec2f) -> @location(0) vec4f {
38+
var bgColor = textureSampleBaseClampToEdge(bgTexture, sampling, uv).rgb;
39+
40+
var newSource: LightSource;
41+
newSource.ambientColor = (bgColor + lightSource.ambientColor) * factor;
42+
newSource.intensity = 0.6;
43+
44+
return vec4f(newSource.ambientColor, newSource.intensity);
45+
}
46+
`;
47+
48+
const resolved = tgpu.resolve({
49+
template: rawShader,
50+
externals: {
51+
// mapping names in the template to corresponding resources/values
52+
LightSource,
53+
factor: d.vec3f(0.4, 0.6, 1.0),
54+
...layout.bound,
55+
},
56+
});
57+
```
58+
59+
Resolved WGSL shader code is as follows:
60+
61+
```wgsl
62+
struct Source_0 {
63+
ambientColor: vec3f,
64+
intensity: f32,
65+
}
66+
67+
@group(0) @binding(0) var<uniform> lightSource_1: Source_0;
68+
@group(0) @binding(1) var sampling_2: sampler;
69+
@group(0) @binding(2) var bgTexture_3: texture_external;
70+
71+
@fragment
72+
fn main(@location(0) uv: vec2f) -> @location(0) vec4f {
73+
var bgColor = textureSampleBaseClampToEdge(bgTexture_3, sampling_2, uv).rgb;
74+
75+
var newSource: Source_0; // identifiers for references are generated based on the chosen naming scheme
76+
newSource.ambientColor = (bgColor + lightSource_1.ambientColor) * vec3f(0.4, 0.6, 1);
77+
newSource.intensity = 0.6;
78+
79+
return vec4f(newSource.ambientColor, newSource.intensity);
80+
}
81+
```
82+
83+
## Template
84+
85+
This optional property of the `tgpu.resolve` function argument is a string containing WGSL code, that is meant to be extended with additional definitions.
86+
It can contain references to objects passed in the `externals` record.
87+
88+
## Externals
89+
90+
This is a record with TypeGPU objects that are to be included in the final resolved shader code.
91+
The values in the mapping are the objects themselves, while the keys are the names by which they are referenced in the template code.
92+
Each object is resolved to its WGSL declaration, which is included in the final shader code.
93+
Moreover each reference to the object in the template is replaced with the name used in its newly generated declaration.
94+
95+
If an object is being referenced only by another TypeGPU object in *externals*, it doesn't have to be included in the record.
96+
Any passed-in object's dependencies are automatically resolved and included in the final result.
97+
98+
:::note
99+
To resolve bindings you can access each entry of a [bindGroupLayout](/TypeGPU/fundamentals/bind-groups) via the `layout.bound` property.
100+
101+
```ts
102+
externals: {
103+
lightSource: layout.bound.lightSource,
104+
sampling: layout.bound.sampling,
105+
bgTexture: layout.bound.bgTexture,
106+
}
107+
108+
// As long as the names in the shader match the
109+
// layout keys, it can be shortened to:
110+
externals: {
111+
...layout.bound,
112+
}
113+
```
114+
:::
115+
116+
## Naming scheme
117+
118+
When externals are being resolved, they are given new names based on the specified naming scheme (`names` parameter).
119+
120+
The default naming scheme is `"random"`. It uses labels assigned to the objects via `.$name("foo")` method or, if they aren't present, the keys in the *externals* record.
121+
In this mode labels are later transformed to match the allowed identifier pattern, as well as include some unique suffix to ensure that no identifiers conflict with each other.
122+
123+
Another allowed value of the parameter is `"strict"` which names resolved objects in the WGSL code exactly as they are labeled by the user in JS,
124+
unless there is a name conflict, in which case a suffix is added.
125+
If there is no explicit *.$name* call, an object is named based on its associated key in *externals*.
126+
This approach makes all of the generated identifiers predictable, but demands that all labels are valid identifiers
127+
and requires explicit naming (via `.$name`) of all objects that aren't immediate values in the *externals* record.

apps/typegpu-docs/src/content/docs/fundamentals/roots.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,17 @@ untyped value of a typed resource, use the `root.unwrap` function.
5252

5353
| Function | Description |
5454
| --- | --- |
55-
| `root.unwrap(resource: TgpuBuffer<AnyTgpuData>)` | Returns a `GPUBuffer`. |
55+
| `root.unwrap(resource: TgpuBuffer<AnyData>)` | Returns a `GPUBuffer`. |
5656
| `root.unwrap(resource: TgpuBindGroupLayout)` | Returns a `GPUBindGroupLayout`. |
5757
| `root.unwrap(resource: TgpuBindGroup)` | Returns a `GPUBindGroup`. |
58+
{/* | `root.unwrap(resource: TgpuTexture)` | Returns a `GPUTexture`. | */}
59+
{/* | `root.unwrap(resource: TgpuReadonlyTexture \| TgpuWriteonlyTexture \| TgpuMutableTexture \| TgpuSampledTexture)` | Returns a `GPUTextureView`. | */}
5860

5961

6062
## Destroying resources
6163

6264
Calling `root.destroy()` will destroy all resources created with it.
65+
It will also destroy the underlying WebGPU device, if it wasn't originally passed in via the `initFromDevice` function.
6366

6467
```ts
6568
root.destroy(); // <- frees up all the resources

apps/typegpu-docs/src/content/docs/integration/webgpu-interoperability.mdx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---
22
title: WebGPU Interoperability
3-
draft: true
43
---
54

65
TypeGPU is built in a way that allows you to pick and choose the primitives you need, incrementally adopt them into your project and have a working app at each step
@@ -46,13 +45,6 @@ const rawNumbersBuffer = root.unwrap(numbersBuffer); // => GPUBuffer
4645
// they are essentially the same resource.
4746
```
4847

49-
```ts
50-
const fooTexture = root.createTexture({ ... }).$usage('sampled');
51-
// ^? TgpuTexture<...> & Sampled
52-
53-
const rawFooTexture = root.unwrap(fooTexture); // => GPUTexture
54-
```
55-
5648
```ts
5749
const bindGroup = root.createBindGroup(layout, { ... });
5850
// ^? TgpuBindGroup<...>
@@ -291,13 +283,13 @@ const layout = tgpu.bindGroupLayout({
291283
-});
292284
+}).$idx(0); // <- forces code-gen to assign `0` as the group index.
293285

294-
const rawShader = /* wgsl*/ `
286+
const rawShader = /* wgsl */ `
295287
- @group(0) @binding(0) var<uniform> ambientColor: vec3f;
296288
- @group(0) @binding(1) var<uniform> intensity: f32;
297289
-
298290
@fragment
299291
fn main() -> @location(0) vec4f {
300-
return vec4f(ambientColor * intensity), 1.);
292+
return vec4f(ambientColor * intensity, 1.);
301293
}
302294
`;
303295

@@ -322,5 +314,5 @@ Benefits gained:
322314
- **Reduced fragility** - binding indices are now being handled end-to-end by TypeGPU, leaving human-readable keys
323315
as the way to connect the shader with JavaScript.
324316
- **Single source of truth** - typed bind group layouts not only describe JS behavior, but also WGSL behavior. This
325-
allows `tgpu.resolve` to generate the appropriate WGSL code. Definitions of structs used as part of the layout will
317+
allows [`tgpu.resolve`](/TypeGPU/fundamentals/resolve) to generate the appropriate WGSL code. Definitions of structs used as part of the layout will
326318
also be included in the returned shader code.

apps/typegpu-docs/src/content/docs/tutorials/game-of-life/index.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,13 +328,13 @@ buffer1 = root
328328
.createBuffer(arrayOf(u32, length))
329329
.$usage("storage", "vertex");
330330

331-
const bindGroup0 = bindGroupLayoutCompute.populate({
331+
const bindGroup0 = root.createBindGroup(bindGroupLayoutCompute, {
332332
size: sizeBuffer,
333333
current: buffer0,
334334
next: buffer1,
335335
});
336336

337-
const bindGroup1 = bindGroupLayoutCompute.populate({
337+
const bindGroup1 = root.createBindGroup(bindGroupLayoutCompute, {
338338
size: sizeBuffer,
339339
current: buffer1,
340340
next: buffer0,

0 commit comments

Comments
 (0)