Skip to content

Commit 365676b

Browse files
authored
Merge branch 'main' into feat/texture-unwrap
2 parents 4bde706 + 731d6f5 commit 365676b

File tree

87 files changed

+4995
-744
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+4995
-744
lines changed

README.md

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,41 @@
88

99
</div>
1010

11-
**TypeGPU** is a TypeScript library that enhances the WebGPU API, allowing
12-
resource management in a type-safe, declarative way.
11+
**TypeGPU** is a modular and open-ended toolkit for WebGPU, with advanced type
12+
inference and the ability to write shaders in TypeScript.
13+
14+
```ts
15+
const neighborhood = (a: number, r: number) => {
16+
'use gpu';
17+
return d.vec2f(a - r, a + r);
18+
};
19+
20+
//
21+
// #1) Can be called in JS
22+
//
23+
const range = neighborhood(1.1, 0.5);
24+
// ^? d.v2f
25+
26+
//
27+
// #2) Used to generate WGSL
28+
//
29+
const main = () => {
30+
'use gpu';
31+
return neighborhood(1.1, 0.5);
32+
};
33+
34+
const wgsl = tgpu.resolve({ externals: { main } });
35+
// ^? string
36+
37+
//
38+
// #3) Executed on the GPU (generates WGSL underneath)
39+
//
40+
root['~unstable']
41+
.createGuardedComputePipeline(main)
42+
.dispatchThreads();
43+
```
1344

1445
<div align="center">
15-
<video width="512" autoplay muted loop playsinline src="https://github.com/user-attachments/assets/5bca716d-477d-44a1-a839-5df0c8d9044c"></video>
1646

1747
<!-- automd:badges color="plum" license name="typegpu" bundlephobia no-npmDownloads -->
1848

apps/typegpu-docs/astro.config.mjs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,6 @@ export default defineConfig({
131131
label: 'Functions',
132132
slug: 'fundamentals/functions',
133133
},
134-
{
135-
label: 'TGSL',
136-
slug: 'fundamentals/tgsl',
137-
badge: { text: 'new' },
138-
},
139134
{
140135
label: 'Pipelines',
141136
slug: 'fundamentals/pipelines',
@@ -145,6 +140,11 @@ export default defineConfig({
145140
label: 'Buffers',
146141
slug: 'fundamentals/buffers',
147142
},
143+
{
144+
label: 'Textures',
145+
slug: 'fundamentals/textures',
146+
badge: { text: 'new' },
147+
},
148148
{
149149
label: 'Variables',
150150
slug: 'fundamentals/variables',

apps/typegpu-docs/ec.config.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ export default {
88
twoslashOptions: {
99
strict: true,
1010
compilerOptions: { moduleResolution: ts.ModuleResolutionKind.Bundler },
11+
extraFiles: {
12+
'global.d.ts': `
13+
/// <reference lib="dom" />
14+
/// <reference types="@webgpu/types" />
15+
`,
16+
},
1117
},
1218
}),
1319
],

apps/typegpu-docs/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"lz-string": "^1.5.0",
4242
"monaco-editor": "^0.53.0",
4343
"morphcharts": "^1.3.2",
44-
"motion": "^12.23.7",
44+
"motion": "^12.23.24",
4545
"pathe": "^2.0.3",
4646
"react": "^19.1.0",
4747
"react-dom": "^19.1.0",
@@ -50,10 +50,10 @@
5050
"remeda": "^2.21.2",
5151
"sharp": "^0.34.2",
5252
"starlight-blog": "^0.23.2",
53-
"starlight-typedoc": "^0.21.4",
53+
"starlight-typedoc": "^0.19.0",
5454
"tinybench": "^3.1.0",
55-
"typedoc": "^0.28.13",
56-
"typedoc-plugin-markdown": "^4.3.0",
55+
"typedoc": "^0.27.9",
56+
"typedoc-plugin-markdown": "4.3.0",
5757
"typegpu": "workspace:*",
5858
"typescript": "catalog:types",
5959
"unplugin-typegpu": "workspace:*",

apps/typegpu-docs/src/components/ExampleCard.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export function ExampleCard({ example }: { example: Example }) {
2020
src={example.thumbnails.large}
2121
alt={example.metadata.title}
2222
className='h-full w-full object-cover'
23+
loading='lazy'
2324
/>
2425
</picture>
2526
)

apps/typegpu-docs/src/components/shaderhunt/ChallengesSignupPopover.astro

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,23 @@
3636
return;
3737
}
3838

39+
// Check if URL hash indicates popover should be open
40+
if (window.location.hash === '#challenges-signup') {
41+
dialogElement?.showModal();
42+
}
43+
3944
linkElement.addEventListener('click', (e) => {
4045
e.preventDefault();
46+
window.location.hash = '#challenges-signup';
4147
dialogElement?.showModal();
4248
});
4349

50+
dialogElement.addEventListener('close', () => {
51+
if (window.location.hash === '#challenges-signup') {
52+
window.location.hash = '';
53+
}
54+
});
55+
4456
formElement.addEventListener('submit', async (e) => {
4557
e.preventDefault();
4658
const formData = new FormData(formElement);

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

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ Since the buffer is already created, you are responsible for the buffer's lifecy
195195

196196
## Writing to a buffer
197197

198-
To write data to a buffer, you can use the `.write(value)` method. The typed schema enables auto-complete as well as static validation of this
198+
To write data to a buffer from the CPU, you can use the `.write(value)` method. The typed schema enables auto-complete as well as static validation of this
199199
method's arguments.
200200

201201
```ts twoslash
@@ -285,7 +285,7 @@ backupParticleBuffer.copyFrom(particleBuffer);
285285

286286
## Reading from a buffer
287287

288-
To read data from a buffer, you can use the `.read()` method.
288+
To read data from a buffer on the CPU, you can use the `.read()` method.
289289
It returns a promise that resolves to the data read from the buffer.
290290

291291
```ts twoslash
@@ -348,32 +348,25 @@ import * as d from 'typegpu/data';
348348

349349
const root = await tgpu.init();
350350
// ---cut---
351-
const pointsBuffer = root
352-
.createBuffer(d.arrayOf(d.vec2i, 100))
353-
.$usage('storage');
354-
355-
const bindGroupLayout = tgpu.bindGroupLayout({
356-
points: { storage: d.arrayOf(d.vec2i, 100), access: 'mutable' },
351+
const layout = tgpu.bindGroupLayout({
352+
points: { storage: d.arrayOf(d.vec2i), access: 'mutable' },
357353
});
358354

359-
const bindGroup = root
360-
.createBindGroup(bindGroupLayout, { points: pointsBuffer });
361-
362-
const mainCompute = tgpu['~unstable'].computeFn({
363-
in: { gid: d.builtin.globalInvocationId },
364-
workgroupSize: [1],
365-
})((input) => {
355+
const pipeline = root['~unstable'].createGuardedComputePipeline((x) => {
356+
'use gpu';
366357
// Access and modify the bound buffer via the layout
367-
bindGroupLayout.$.points[input.gid[0]] = d.vec2i(1, 2);
358+
layout.$.points[x] = d.vec2i(1, 2);
368359
});
369360

370-
const pipeline = root['~unstable']
371-
.withCompute(mainCompute)
372-
.createPipeline();
361+
const pointsBuffer = root
362+
.createBuffer(d.arrayOf(d.vec2i, 100))
363+
.$usage('storage');
364+
365+
const bindGroup = root.createBindGroup(layout, {
366+
points: pointsBuffer
367+
});
373368

374-
pipeline
375-
.with(bindGroupLayout, bindGroup)
376-
.dispatchWorkgroups(100);
369+
pipeline.with(bindGroup).dispatchThreads(100);
377370
```
378371

379372
### Using fixed resources
@@ -394,18 +387,15 @@ import * as d from 'typegpu/data';
394387

395388
const root = await tgpu.init();
396389
// ---cut---
397-
const pointsBuffer = root.createMutable(d.arrayOf(d.vec2i, 100));
390+
const pointsMutable = root.createMutable(d.arrayOf(d.vec2i, 100));
398391

399-
const mainCompute = tgpu['~unstable'].computeFn({
400-
in: { gid: d.builtin.globalInvocationId },
401-
workgroupSize: [1],
402-
})((input) => {
392+
const pipeline = root['~unstable'].createGuardedComputePipeline((x) => {
393+
'use gpu';
403394
// Access and modify the fixed buffer directly
404-
pointsBuffer.$[input.gid[0]] = d.vec2i();
395+
pointsMutable.$[x] = d.vec2i();
405396
});
406397

407-
const pipeline = root['~unstable'].withCompute(mainCompute).createPipeline();
408-
pipeline.dispatchWorkgroups(100);
398+
pipeline.dispatchThreads(100);
409399
```
410400

411401
TypeGPU automatically generates a "catch-all" bind group and populates it with the fixed resources.

apps/typegpu-docs/src/content/docs/fundamentals/data-schemas.mdx

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,116 @@ const array = ArrayPartialSchema(2)([1.2, 19.29]);
343343
// ^?
344344
```
345345

346+
## Textures
347+
348+
Texture schemas serve two main purposes:
349+
- defining texture views (both fixed and in layouts)
350+
- providing argument types for user defined functions
351+
352+
```ts twoslash
353+
import tgpu from 'typegpu';
354+
import * as d from 'typegpu/data';
355+
import * as std from 'typegpu/std';
356+
357+
const root = await tgpu.init();
358+
const texture = root['~unstable'].createTexture({
359+
size: [256, 256],
360+
format: 'rgba8unorm',
361+
}).$usage('sampled', 'storage');
362+
363+
// ---cut---
364+
const storeOnes = (tex: d.textureStorage2d<'rgba8unorm'>, coords: d.v2u) => {
365+
'use gpu';
366+
std.textureStore(tex, coords, d.vec4f(1));
367+
};
368+
369+
const storeOnesShelled = tgpu.fn([d.textureStorage2d('rgba8unorm'), d.vec2u])(
370+
(tex, coords) => {
371+
std.textureStore(tex, coords, d.vec4f(1));
372+
},
373+
);
374+
375+
const sampledView = texture.createView(d.texture2d(d.f32));
376+
// ^?
377+
378+
const storageView = texture.createView(d.textureStorage2d('rgba8unorm', 'read-only'));
379+
// ^?
380+
381+
const layout = tgpu.bindGroupLayout({
382+
// ^?
383+
sampled: { texture: d.texture2d() },
384+
storage: { storageTexture: d.textureStorage2d('rgba8unorm', 'read-only') },
385+
});
386+
```
387+
388+
### Sampled Textures
389+
390+
Sampled texture schemas are created using one of the following constructors:
391+
392+
- **`d.texture1d(sampleType?)`** - A 1D texture
393+
- **`d.texture2d(sampleType?)`** - A 2D texture
394+
- **`d.texture2dArray(sampleType?)`** - A 2D array texture
395+
- **`d.texture3d(sampleType?)`** - A 3D texture
396+
- **`d.textureCube(sampleType?)`** - A cube texture
397+
- **`d.textureCubeArray(sampleType?)`** - A cube array texture
398+
- **`d.textureMultisampled2d(sampleType?)`** - A 2D multisampled texture
399+
400+
The `sampleType` parameter can be `d.f32`, `d.i32`, or `d.u32`, determining how the texture data will be interpreted. If omitted, it defaults to `d.f32`.
401+
402+
```ts twoslash
403+
import * as d from 'typegpu/data';
404+
// ---cut---
405+
const tex1 = d.texture2d(d.f32); // float texture (default)
406+
// ^?
407+
408+
const tex2 = d.texture2d(d.u32); // unsigned integer texture
409+
// ^?
410+
411+
const tex3 = d.texture2dArray(); // defaults to f32
412+
// ^?
413+
```
414+
415+
#### Depth Textures
416+
417+
For depth comparison operations, TypeGPU provides specialized depth texture schemas:
418+
419+
- **`d.textureDepth2d()`** - A 2D depth texture
420+
- **`d.textureDepthMultisampled2d()`** - A 2D multisampled depth texture
421+
- **`d.textureDepth2dArray()`** - A 2D array depth texture
422+
- **`d.textureDepthCube()`** - A cube depth texture
423+
- **`d.textureDepthCubeArray()`** - A cube array depth texture
424+
425+
```ts twoslash
426+
import * as d from 'typegpu/data';
427+
// ---cut---
428+
const depthTex = d.textureDepth2d();
429+
// ^?
430+
```
431+
432+
### Storage Textures
433+
434+
Storage texture schemas are created using dimension-specific constructors, with required `format` and optional `access` parameters:
435+
436+
- **`d.textureStorage1d(format, access?)`** - A 1D storage texture
437+
- **`d.textureStorage2d(format, access?)`** - A 2D storage texture
438+
- **`d.textureStorage2dArray(format, access?)`** - A 2D array storage texture
439+
- **`d.textureStorage3d(format, access?)`** - A 3D storage texture
440+
441+
The `format` parameter specifies the texture format (e.g., `'rgba8unorm'`, `'rgba16float'`, `'r32float'`), and the `access` parameter can be `'write-only'`, `'read-only'`, or `'read-write'`. If `access` is omitted, it defaults to `'write-only'`.
442+
443+
```ts twoslash
444+
import * as d from 'typegpu/data';
445+
// ---cut---
446+
const storageTex1 = d.textureStorage2d('rgba8unorm');
447+
// ^?
448+
449+
const storageTex2 = d.textureStorage2d('rgba8unorm', 'read-only');
450+
// ^?
451+
452+
const storageTex3 = d.textureStorage3d('r32float', 'read-write');
453+
// ^?
454+
```
455+
346456
## Atomics
347457

348458
To create a schema corresponding to an atomic data type, wrap `d.i32` or `d.u32` with `d.atomic`.

0 commit comments

Comments
 (0)