or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

commands.mdconfiguration.mdcore-types.mdgpu-interfaces.mdindex.mdpipelines.mdrender-bundles.mdresources.md

pipelines.mddocs/

0

# Pipelines and Shaders

1

2

Render pipelines, compute pipelines, and shader modules for defining GPU programs and rendering state.

3

4

## Capabilities

5

6

### GPU Shader Module

7

8

Compiled shader code that can be used in pipelines.

9

10

```typescript { .api }

11

interface GPUShaderModule {

12

/** Optional debug label */

13

readonly label: string | undefined;

14

15

/**

16

* Gets compilation information including errors and warnings

17

* @returns Promise resolving to compilation info

18

*/

19

getCompilationInfo(): Promise<GPUCompilationInfo>;

20

}

21

22

interface GPUShaderModuleDescriptor extends GPUObjectDescriptorBase {

23

/** WGSL shader code */

24

code: string;

25

26

/** Optional compilation hints */

27

hints?: Record<string, GPUShaderModuleCompilationHint>;

28

}

29

30

interface GPUShaderModuleCompilationHint {

31

/** Entry point name */

32

entryPoint?: string;

33

34

/** Pipeline layout for optimization */

35

layout?: GPUPipelineLayout | "auto";

36

}

37

38

interface GPUCompilationInfo {

39

/** Array of compilation messages */

40

readonly messages: ReadonlyArray<GPUCompilationMessage>;

41

}

42

43

interface GPUCompilationMessage {

44

/** Message text */

45

readonly message: string;

46

47

/** Message type */

48

readonly type: GPUCompilationMessageType;

49

50

/** Line number (1-based) */

51

readonly lineNum: number;

52

53

/** Line position (1-based) */

54

readonly linePos: number;

55

56

/** Byte offset in source */

57

readonly offset: number;

58

59

/** Length of the relevant source region */

60

readonly length: number;

61

}

62

63

type GPUCompilationMessageType = "error" | "warning" | "info";

64

```

65

66

### GPU Pipeline Layout

67

68

Defines the resource binding layout for a pipeline.

69

70

```typescript { .api }

71

interface GPUPipelineLayout {

72

/** Optional debug label */

73

readonly label: string | undefined;

74

}

75

76

interface GPUPipelineLayoutDescriptor extends GPUObjectDescriptorBase {

77

/** Array of bind group layouts */

78

bindGroupLayouts: Iterable<GPUBindGroupLayout>;

79

}

80

```

81

82

### GPU Render Pipeline

83

84

Graphics pipeline for vertex processing and fragment shading.

85

86

```typescript { .api }

87

interface GPURenderPipeline {

88

/** Optional debug label */

89

readonly label: string | undefined;

90

91

/**

92

* Gets bind group layout at the specified index

93

* @param index - Bind group index

94

* @returns The bind group layout

95

*/

96

getBindGroupLayout(index: number): GPUBindGroupLayout;

97

}

98

99

interface GPURenderPipelineDescriptor extends GPUPipelineDescriptorBase {

100

/** Vertex stage configuration */

101

vertex: GPUVertexState;

102

103

/** Primitive assembly configuration */

104

primitive?: GPUPrimitiveState;

105

106

/** Depth/stencil state */

107

depthStencil?: GPUDepthStencilState;

108

109

/** Multisample state */

110

multisample?: GPUMultisampleState;

111

112

/** Fragment stage configuration */

113

fragment?: GPUFragmentState;

114

}

115

116

interface GPUPipelineDescriptorBase extends GPUObjectDescriptorBase {

117

/** Pipeline layout */

118

layout: GPUPipelineLayout | "auto";

119

}

120

121

interface GPUVertexState extends GPUProgrammableStage {

122

/** Vertex buffer layouts */

123

buffers?: Iterable<GPUVertexBufferLayout | null>;

124

}

125

126

interface GPUProgrammableStage {

127

/** Shader module */

128

module: GPUShaderModule;

129

130

/** Entry point function name */

131

entryPoint?: string;

132

133

/** Pipeline constants */

134

constants?: Record<string, GPUPipelineConstantValue>;

135

}

136

137

interface GPUVertexBufferLayout {

138

/** Stride between vertices in bytes */

139

arrayStride: GPUSize64;

140

141

/** Step mode for vertex fetching */

142

stepMode?: GPUVertexStepMode;

143

144

/** Vertex attributes */

145

attributes: Iterable<GPUVertexAttribute>;

146

}

147

148

interface GPUVertexAttribute {

149

/** Vertex format */

150

format: GPUVertexFormat;

151

152

/** Byte offset within vertex */

153

offset: GPUSize64;

154

155

/** Shader location binding */

156

shaderLocation: GPUIndex32;

157

}

158

159

interface GPUPrimitiveState {

160

/** Primitive topology */

161

topology?: GPUPrimitiveTopology;

162

163

/** Strip index format */

164

stripIndexFormat?: GPUIndexFormat;

165

166

/** Front face winding */

167

frontFace?: GPUFrontFace;

168

169

/** Face culling mode */

170

cullMode?: GPUCullMode;

171

172

/** Whether to enable conservative rasterization */

173

unclippedDepth?: boolean;

174

}

175

176

interface GPUMultisampleState {

177

/** Number of samples */

178

count?: GPUSize32;

179

180

/** Sample mask */

181

mask?: GPUSampleMask;

182

183

/** Alpha to coverage */

184

alphaToCoverageEnabled?: boolean;

185

}

186

187

interface GPUFragmentState extends GPUProgrammableStage {

188

/** Color target states */

189

targets: Iterable<GPUColorTargetState | null>;

190

}

191

192

interface GPUColorTargetState {

193

/** Color format */

194

format: GPUTextureFormat;

195

196

/** Blend state */

197

blend?: GPUBlendState;

198

199

/** Write mask */

200

writeMask?: GPUColorWriteFlags;

201

}

202

203

interface GPUBlendState {

204

/** Color blend component */

205

color: GPUBlendComponent;

206

207

/** Alpha blend component */

208

alpha: GPUBlendComponent;

209

}

210

211

interface GPUBlendComponent {

212

/** Blend operation */

213

operation?: GPUBlendOperation;

214

215

/** Source factor */

216

srcFactor?: GPUBlendFactor;

217

218

/** Destination factor */

219

dstFactor?: GPUBlendFactor;

220

}

221

222

interface GPUDepthStencilState {

223

/** Depth/stencil format */

224

format: GPUTextureFormat;

225

226

/** Whether depth writes are enabled */

227

depthWriteEnabled?: boolean;

228

229

/** Depth comparison function */

230

depthCompare?: GPUCompareFunction;

231

232

/** Stencil front face state */

233

stencilFront?: GPUStencilFaceState;

234

235

/** Stencil back face state */

236

stencilBack?: GPUStencilFaceState;

237

238

/** Stencil read mask */

239

stencilReadMask?: GPUStencilValue;

240

241

/** Stencil write mask */

242

stencilWriteMask?: GPUStencilValue;

243

244

/** Depth bias constant */

245

depthBias?: GPUDepthBias;

246

247

/** Depth bias slope scale */

248

depthBiasSlopeScale?: number;

249

250

/** Depth bias clamp */

251

depthBiasClamp?: number;

252

}

253

254

interface GPUStencilFaceState {

255

/** Comparison function */

256

compare?: GPUCompareFunction;

257

258

/** Fail operation */

259

failOp?: GPUStencilOperation;

260

261

/** Depth fail operation */

262

depthFailOp?: GPUStencilOperation;

263

264

/** Pass operation */

265

passOp?: GPUStencilOperation;

266

}

267

268

type GPUStencilOperation =

269

| "keep" | "zero" | "replace" | "invert"

270

| "increment-clamp" | "decrement-clamp"

271

| "increment-wrap" | "decrement-wrap";

272

```

273

274

### GPU Compute Pipeline

275

276

Compute shader pipeline for general-purpose GPU computing.

277

278

```typescript { .api }

279

interface GPUComputePipeline {

280

/** Optional debug label */

281

readonly label: string | undefined;

282

283

/**

284

* Gets bind group layout at the specified index

285

* @param index - Bind group index

286

* @returns The bind group layout

287

*/

288

getBindGroupLayout(index: number): GPUBindGroupLayout;

289

}

290

291

interface GPUComputePipelineDescriptor extends GPUPipelineDescriptorBase {

292

/** Compute stage configuration */

293

compute: GPUProgrammableStage;

294

}

295

```

296

297

### Pipeline Base Interface

298

299

Common functionality shared by all pipeline types.

300

301

```typescript { .api }

302

interface GPUPipelineBase {

303

/** Optional debug label */

304

readonly label: string | undefined;

305

306

/**

307

* Gets bind group layout at the specified index

308

* @param index - Bind group index

309

* @returns The bind group layout

310

*/

311

getBindGroupLayout(index: number): GPUBindGroupLayout;

312

}

313

```

314

315

## Usage Examples

316

317

### Shader Module Creation

318

319

```typescript

320

// Create a vertex shader

321

const vertexShader = device.createShaderModule({

322

code: `

323

struct VertexInput {

324

@location(0) position: vec3<f32>,

325

@location(1) normal: vec3<f32>,

326

@location(2) uv: vec2<f32>,

327

}

328

329

struct VertexOutput {

330

@builtin(position) position: vec4<f32>,

331

@location(0) normal: vec3<f32>,

332

@location(1) uv: vec2<f32>,

333

}

334

335

@group(0) @binding(0) var<uniform> mvpMatrix: mat4x4<f32>;

336

337

@vertex

338

fn main(input: VertexInput) -> VertexOutput {

339

var output: VertexOutput;

340

output.position = mvpMatrix * vec4<f32>(input.position, 1.0);

341

output.normal = input.normal;

342

output.uv = input.uv;

343

return output;

344

}

345

`,

346

label: "Vertex Shader"

347

});

348

349

// Create a fragment shader

350

const fragmentShader = device.createShaderModule({

351

code: `

352

struct FragmentInput {

353

@location(0) normal: vec3<f32>,

354

@location(1) uv: vec2<f32>,

355

}

356

357

@group(1) @binding(0) var baseColorTexture: texture_2d<f32>;

358

@group(1) @binding(1) var baseColorSampler: sampler;

359

360

@fragment

361

fn main(input: FragmentInput) -> @location(0) vec4<f32> {

362

let baseColor = textureSample(baseColorTexture, baseColorSampler, input.uv);

363

let lighting = max(dot(normalize(input.normal), vec3<f32>(0.0, 1.0, 0.0)), 0.1);

364

return vec4<f32>(baseColor.rgb * lighting, baseColor.a);

365

}

366

`,

367

label: "Fragment Shader"

368

});

369

370

// Check compilation info

371

const vertexInfo = await vertexShader.getCompilationInfo();

372

for (const message of vertexInfo.messages) {

373

if (message.type === "error") {

374

console.error(`Shader error at line ${message.lineNum}: ${message.message}`);

375

}

376

}

377

```

378

379

### Render Pipeline Creation

380

381

```typescript

382

// Create pipeline layout

383

const pipelineLayout = device.createPipelineLayout({

384

bindGroupLayouts: [

385

uniformsBindGroupLayout,

386

materialBindGroupLayout

387

],

388

label: "Render Pipeline Layout"

389

});

390

391

// Create render pipeline

392

const renderPipeline = device.createRenderPipeline({

393

layout: pipelineLayout,

394

vertex: {

395

module: vertexShader,

396

entryPoint: "main",

397

buffers: [

398

{

399

arrayStride: 32, // 3 * 4 + 3 * 4 + 2 * 4 = position + normal + uv

400

attributes: [

401

{

402

format: "float32x3",

403

offset: 0,

404

shaderLocation: 0 // position

405

},

406

{

407

format: "float32x3",

408

offset: 12,

409

shaderLocation: 1 // normal

410

},

411

{

412

format: "float32x2",

413

offset: 24,

414

shaderLocation: 2 // uv

415

}

416

]

417

}

418

]

419

},

420

fragment: {

421

module: fragmentShader,

422

entryPoint: "main",

423

targets: [

424

{

425

format: "bgra8unorm",

426

blend: {

427

color: {

428

srcFactor: "src-alpha",

429

dstFactor: "one-minus-src-alpha",

430

operation: "add"

431

},

432

alpha: {

433

srcFactor: "one",

434

dstFactor: "one-minus-src-alpha",

435

operation: "add"

436

}

437

}

438

}

439

]

440

},

441

primitive: {

442

topology: "triangle-list",

443

cullMode: "back",

444

frontFace: "ccw"

445

},

446

depthStencil: {

447

format: "depth24plus-stencil8",

448

depthWriteEnabled: true,

449

depthCompare: "less"

450

},

451

multisample: {

452

count: 4,

453

alphaToCoverageEnabled: false

454

},

455

label: "Mesh Render Pipeline"

456

});

457

```

458

459

### Compute Pipeline Creation

460

461

```typescript

462

// Create compute shader

463

const computeShader = device.createShaderModule({

464

code: `

465

@group(0) @binding(0) var<storage, read> inputData: array<f32>;

466

@group(0) @binding(1) var<storage, read_write> outputData: array<f32>;

467

468

@compute @workgroup_size(64)

469

fn main(@builtin(global_invocation_id) globalId: vec3<u32>) {

470

let index = globalId.x;

471

if (index >= arrayLength(&inputData)) {

472

return;

473

}

474

475

outputData[index] = inputData[index] * 2.0;

476

}

477

`,

478

label: "Double Values Compute Shader"

479

});

480

481

// Create compute pipeline

482

const computePipeline = device.createComputePipeline({

483

layout: "auto",

484

compute: {

485

module: computeShader,

486

entryPoint: "main"

487

},

488

label: "Double Values Pipeline"

489

});

490

491

// Get the auto-generated bind group layout

492

const computeBindGroupLayout = computePipeline.getBindGroupLayout(0);

493

```

494

495

### Advanced Shader Features

496

497

```typescript

498

// Shader with constants

499

const advancedShader = device.createShaderModule({

500

code: `

501

override workgroupSize: u32 = 64;

502

override multiplier: f32 = 1.0;

503

504

@group(0) @binding(0) var<storage, read_write> data: array<f32>;

505

506

@compute @workgroup_size(workgroupSize, 1, 1)

507

fn main(@builtin(global_invocation_id) globalId: vec3<u32>) {

508

let index = globalId.x;

509

if (index >= arrayLength(&data)) {

510

return;

511

}

512

513

data[index] = data[index] * multiplier;

514

}

515

`,

516

label: "Parameterized Compute Shader"

517

});

518

519

// Create pipeline with constants

520

const parameterizedPipeline = device.createComputePipeline({

521

layout: "auto",

522

compute: {

523

module: advancedShader,

524

entryPoint: "main",

525

constants: {

526

workgroupSize: 128,

527

multiplier: 2.5

528

}

529

},

530

label: "Parameterized Pipeline"

531

});

532

```

533

534

### Pipeline with Multiple Render Targets

535

536

```typescript

537

const multiTargetPipeline = device.createRenderPipeline({

538

layout: pipelineLayout,

539

vertex: {

540

module: vertexShader,

541

entryPoint: "main",

542

buffers: [vertexBufferLayout]

543

},

544

fragment: {

545

module: multiTargetFragmentShader,

546

entryPoint: "main",

547

targets: [

548

{ format: "rgba8unorm" }, // Color target 0

549

{ format: "rgba16float" }, // Color target 1 (HDR)

550

{ format: "rg16float" }, // Color target 2 (normals)

551

null, // Skip target 3

552

{ format: "r8uint" } // Color target 4 (object ID)

553

]

554

},

555

primitive: {

556

topology: "triangle-list"

557

},

558

label: "G-Buffer Pipeline"

559

});

560

```

561

562

### Async Pipeline Creation

563

564

```typescript

565

// Create pipelines asynchronously for better performance

566

const [renderPipelineAsync, computePipelineAsync] = await Promise.all([

567

device.createRenderPipelineAsync({

568

layout: renderPipelineLayout,

569

vertex: { module: vertexShader, entryPoint: "main" },

570

fragment: {

571

module: fragmentShader,

572

entryPoint: "main",

573

targets: [{ format: "bgra8unorm" }]

574

},

575

label: "Async Render Pipeline"

576

}),

577

578

device.createComputePipelineAsync({

579

layout: "auto",

580

compute: { module: computeShader, entryPoint: "main" },

581

label: "Async Compute Pipeline"

582

})

583

]);

584

585

console.log("Both pipelines created asynchronously");

586

```

587

588

### Error Handling in Shaders

589

590

```typescript

591

// Create shader with potential compilation issues

592

const shaderWithError = device.createShaderModule({

593

code: `

594

@vertex

595

fn main() -> @builtin(position) vec4<f32> {

596

// Missing required vertex output

597

return vec4<f32>(0.0, 0.0, 0.0, 1.0);

598

}

599

`,

600

label: "Test Shader"

601

});

602

603

// Check for compilation errors

604

const compilationInfo = await shaderWithError.getCompilationInfo();

605

if (compilationInfo.messages.length > 0) {

606

console.log("Compilation messages:");

607

for (const message of compilationInfo.messages) {

608

const level = message.type.toUpperCase();

609

console.log(`${level} at line ${message.lineNum}:${message.linePos} - ${message.message}`);

610

}

611

}

612

613

// Handle pipeline creation errors

614

device.pushErrorScope("validation");

615

616

const pipeline = device.createRenderPipeline({

617

layout: "auto",

618

vertex: { module: shaderWithError, entryPoint: "main" },

619

fragment: {

620

module: fragmentShader,

621

entryPoint: "main",

622

targets: [{ format: "bgra8unorm" }]

623

}

624

});

625

626

const error = await device.popErrorScope();

627

if (error) {

628

console.error("Pipeline creation failed:", error.message);

629

}

630

```

631

632

### Pipeline Specialization

633

634

```typescript

635

// Create multiple specialized pipelines from the same shader

636

const basePipelineDesc: GPURenderPipelineDescriptor = {

637

layout: pipelineLayout,

638

vertex: {

639

module: vertexShader,

640

entryPoint: "main",

641

buffers: [vertexBufferLayout]

642

},

643

fragment: {

644

module: fragmentShader,

645

entryPoint: "main",

646

targets: [{ format: "bgra8unorm" }]

647

}

648

};

649

650

// Opaque rendering pipeline

651

const opaquePipeline = device.createRenderPipeline({

652

...basePipelineDesc,

653

primitive: {

654

topology: "triangle-list",

655

cullMode: "back"

656

},

657

depthStencil: {

658

format: "depth24plus",

659

depthWriteEnabled: true,

660

depthCompare: "less"

661

},

662

label: "Opaque Pipeline"

663

});

664

665

// Transparent rendering pipeline

666

const transparentPipeline = device.createRenderPipeline({

667

...basePipelineDesc,

668

primitive: {

669

topology: "triangle-list",

670

cullMode: "none"

671

},

672

fragment: {

673

...basePipelineDesc.fragment!,

674

targets: [{

675

format: "bgra8unorm",

676

blend: {

677

color: {

678

srcFactor: "src-alpha",

679

dstFactor: "one-minus-src-alpha"

680

},

681

alpha: {

682

srcFactor: "one",

683

dstFactor: "one-minus-src-alpha"

684

}

685

}

686

}]

687

},

688

depthStencil: {

689

format: "depth24plus",

690

depthWriteEnabled: false,

691

depthCompare: "less-equal"

692

},

693

label: "Transparent Pipeline"

694

});

695

```