typegpu
Version:
A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.
270 lines (269 loc) • 15.6 kB
TypeScript
import type { AnyBuiltin, OmitBuiltins } from '../../builtin.ts';
import type { IndexFlag, IndirectFlag, TgpuBuffer, VertexFlag } from '../buffer/buffer.ts';
import type { TgpuQuerySet } from '../querySet/querySet.ts';
import { type Disarray, type UndecorateRecord } from '../../data/dataTypes.ts';
import { type ResolvedSnippet } from '../../data/snippet.ts';
import { type AnyVecInstance, type BaseData, type U16, type U32, type v4f, Void, type WgslArray, type WgslStruct } from '../../data/wgslTypes.ts';
import type { TgpuNamable } from '../../shared/meta.ts';
import type { TgpuDeviceOwningSoul } from '../../shared/soul.ts';
import { $getNameForward, $internal, $resolve, $soul } from '../../shared/symbols.ts';
import type { AnyVertexAttribs } from '../../shared/vertexFormat.ts';
import { type TgpuBindGroup, type TgpuBindGroupLayout, type TgpuLayoutEntry } from '../../tgpuBindGroupLayout.ts';
import type { LogResources } from '../../tgsl/consoleLog/types.ts';
import type { ResolutionCtx, SelfResolvable } from '../../types.ts';
import { type AnyAutoCustoms, type AutoFragmentIn, type AutoFragmentOut, type AutoVertexIn, type AutoVertexOut } from '../function/autoIO.ts';
import type { TgpuFragmentFn } from '../function/tgpuFragmentFn.ts';
import type { TgpuVertexFn } from '../function/tgpuVertexFn.ts';
import type { ExperimentalTgpuRoot } from '../root/rootTypes.ts';
import type { TgpuSlot } from '../slot/slotTypes.ts';
import { type TgpuVertexLayout } from '../vertexLayout/vertexLayout.ts';
import { type TgpuCommandEncoder } from '../commandEncoder/commandEncoder.ts';
import type { ColorAttachment, DepthStencilAttachment } from '../commandEncoder/attachments.ts';
import { type TgpuRenderCommands } from '../commandEncoder/renderPass.ts';
import { type Timeable, type TimestampWritesPriors } from './timeable.ts';
import { type PrimitiveOffsetInfo } from '../../data/offsetUtils.ts';
import type { RestoreContext } from '../../serial/types.ts';
export interface RenderPipelineInternals {
readonly core: RenderPipelineCore;
readonly priors: TgpuRenderPipelinePriors & TimestampWritesPriors;
readonly root: ExperimentalTgpuRoot;
readonly materialize: () => GPURenderPipeline;
}
export interface TgpuRenderPipelineSoul extends TgpuDeviceOwningSoul<'render-pipeline', GPURenderPipeline> {
usedBindGroupLayouts?: TgpuBindGroupLayout[] | undefined;
usedVertexLayouts?: TgpuVertexLayout[] | undefined;
fragmentOut?: BaseData | undefined;
bindGroups?: [TgpuBindGroupLayout, TgpuBindGroup | GPUBindGroup][] | undefined;
vertexBuffers?: [TgpuVertexLayout, (TgpuBuffer<BaseData> & VertexFlag) | GPUBuffer][] | undefined;
indexBuffer?: {
buffer: (TgpuBuffer<BaseData> & IndexFlag) | GPUBuffer;
indexFormat: GPUIndexFormat;
offsetBytes?: number | undefined;
sizeBytes?: number | undefined;
} | undefined;
stencilReference?: GPUStencilValue | undefined;
timestampWrites?: TimestampWritesPriors['timestampWrites'];
performanceCallback?: TimestampWritesPriors['performanceCallback'];
nonTransferablePriors?: string[] | undefined;
}
export type TgpuPrimitiveState = GPUPrimitiveState | (Omit<GPUPrimitiveState, 'stripIndexFormat'> & {
stripIndexFormat?: U32 | U16;
}) | undefined;
export type TgpuColorTargetState = (Omit<GPUColorTargetState, 'format'> & {
/**
* The {@link GPUTextureFormat} of this color target. The pipeline will only be compatible with
* {@link GPURenderPassEncoder}s which use a {@link GPUTextureView} of this format in the
* corresponding color attachment.
*
* @default navigator.gpu.getPreferredCanvasFormat()
*/
format?: GPUTextureFormat | undefined;
}) | undefined;
export interface HasIndexBuffer {
readonly hasIndexBuffer: true;
drawIndexed(indexCount: number, instanceCount?: number, firstIndex?: number, baseVertex?: number, firstInstance?: number): void;
}
export interface TgpuRenderPipeline<in Targets = never> extends TgpuNamable, SelfResolvable, Timeable {
readonly [$internal]: RenderPipelineInternals;
readonly [$soul]: TgpuRenderPipelineSoul;
readonly resourceType: 'render-pipeline';
readonly hasIndexBuffer: boolean;
with<TData extends WgslArray | Disarray>(vertexLayout: TgpuVertexLayout<TData>, buffer: (TgpuBuffer<TData> & VertexFlag) | GPUBuffer): this;
/**
* @deprecated This overload is outdated.
* Call `pipeline.with(bindGroup)` instead.
*/
with<Entries extends Record<string, TgpuLayoutEntry | null>>(bindGroupLayout: TgpuBindGroupLayout<Entries>, bindGroup: TgpuBindGroup<Entries>): this;
with(bindGroupLayout: TgpuBindGroupLayout, bindGroup: GPUBindGroup): this;
with(bindGroup: TgpuBindGroup): this;
/**
* Directs subsequent draw calls into the given render pass or render bundle
* encoder, letting multiple pipelines share one pass (and one submission).
*/
with(pass: TgpuRenderCommands): this;
/**
* Directs subsequent draw calls into the given command encoder. Each draw
* records its own render pass; the caller owns the submission.
*/
with(encoder: TgpuCommandEncoder): this;
with(encoder: GPUCommandEncoder): this;
with(pass: GPURenderPassEncoder): this;
with(bundleEncoder: GPURenderBundleEncoder): this;
/**
* Attaches texture views to the pipeline's targets (outputs).
*
* @example
* // Draw 3 vertices onto the context's canvas
* pipeline
* .withColorAttachment({ view: context })
* .draw(3)
*
* @param attachment The object should match the shape
* returned by the fragment shader, with values matching the {@link ColorAttachment} type.
*/
withColorAttachment(attachment: FragmentOutToColorAttachment<Targets>): this;
withDepthStencilAttachment(attachment: DepthStencilAttachment): this;
withStencilReference(reference: GPUStencilValue): this;
withIndexBuffer(buffer: TgpuBuffer<BaseData> & IndexFlag, offsetElements?: number, sizeElements?: number): this & HasIndexBuffer;
withIndexBuffer(buffer: GPUBuffer, indexFormat: GPUIndexFormat, offsetBytes?: number, sizeBytes?: number): this & HasIndexBuffer;
draw(vertexCount: number, instanceCount?: number, firstVertex?: number, firstInstance?: number): void;
/**
* Immediately resolves the pipeline, then awaits `device.createRenderPipelineAsync()`.
* NOTE: it is not necessary to initialize pipelines manually.
*/
initAsync(): Promise<void>;
/**
* Immediately resolves the pipeline and creates WebGPU resources.
* NOTE: it is not necessary to initialize pipelines manually.
*/
initSync(): void;
/**
* Draws primitives using parameters read from a buffer.
* The buffer must contain 4 consecutive u32 values (vertexCount, instanceCount, firstVertex, firstInstance).
* To get the correct offset within complex data structures, use `d.memoryLayoutOf(...)`.
*
* @param indirectBuffer - Buffer marked with 'indirect' usage containing draw parameters or raw GPUBuffer
* @param indirectOffset - PrimitiveOffsetInfo pointing to the first draw parameter. If not provided, starts at offset 0. To obtain safe offsets, use `d.memoryLayoutOf(...)`.
*/
drawIndirect(indirectBuffer: (TgpuBuffer<BaseData> & IndirectFlag) | GPUBuffer, indirectOffset?: PrimitiveOffsetInfo | number): void;
/**
* Draws indexed primitives using parameters read from a buffer.
* The buffer must contain 5 consecutive 32-bit integer values (indexCount u32, instanceCount u32, firstIndex u32, baseVertex i32, firstInstance u32).
* To get the correct offset within complex data structures, use `d.memoryLayoutOf(...)`.
*
* @param indirectBuffer - Buffer marked with 'indirect' usage containing draw parameters or raw GPUBuffer
* @param indirectOffset - PrimitiveOffsetInfo pointing to the first draw parameter. If not provided, starts at offset 0. To obtain safe offsets, use `d.memoryLayoutOf(...)`.
*/
drawIndexedIndirect(indirectBuffer: (TgpuBuffer<BaseData> & IndirectFlag) | GPUBuffer, indirectOffset?: PrimitiveOffsetInfo | number): void;
}
export declare namespace TgpuRenderPipeline {
interface DescriptorBase {
/**
* Describes the primitive-related properties of the pipeline.
*/
primitive?: TgpuPrimitiveState | undefined;
/**
* Describes the optional depth-stencil properties, including the testing, operations, and bias.
*/
depthStencil?: GPUDepthStencilState | undefined;
/**
* Describes the multi-sampling properties of the pipeline.
*/
multisample?: GPUMultisampleState | undefined;
}
interface Descriptor extends DescriptorBase {
vertex: TgpuVertexFn | ((input: AutoVertexIn<Record<string, never>>) => AutoVertexOut<AnyAutoCustoms>);
fragment?: TgpuFragmentFn | ((input: AutoFragmentIn<Record<string, never>>) => AutoFragmentOut<undefined | v4f | AnyAutoCustoms>) | undefined;
attribs?: AnyVertexAttribs | undefined;
targets?: AnyFragmentTargets | undefined;
}
}
export type FragmentOutToTargets<T> = T extends undefined | AnyBuiltin | Void | Record<string, never> ? Record<string, never> | undefined : T extends {
readonly [$internal]: unknown;
} | number | boolean | AnyVecInstance ? TgpuColorTargetState : T extends Record<string, unknown> ? {
[Key in keyof OmitBuiltins<T>]?: TgpuColorTargetState;
} | undefined : TgpuColorTargetState | Record<string, TgpuColorTargetState>;
export type FragmentOutToColorAttachment<T> = T extends {
readonly [$internal]: unknown;
} ? ColorAttachment : T extends Record<string, unknown> ? {
[Key in keyof UndecorateRecord<T>]: ColorAttachment;
} : Record<string, never>;
export type AnyFragmentTargets = TgpuColorTargetState | Record<string, TgpuColorTargetState>;
export type AnyFragmentColorAttachment = ColorAttachment | Record<string, ColorAttachment>;
export type RenderPipelineCoreOptions = {
root: ExperimentalTgpuRoot;
slotBindings: [TgpuSlot<unknown>, unknown][];
/** Undefined for precompiled pipelines, which are never resolved again */
descriptor: TgpuRenderPipeline.Descriptor | undefined;
};
export declare function INTERNAL_createRenderPipeline(options: RenderPipelineCoreOptions): TgpuRenderPipelineImpl;
export declare function INTERNAL_restoreRenderPipeline(soul: TgpuRenderPipelineSoul, ctx: RestoreContext): TgpuRenderPipeline;
type TgpuRenderPipelinePriors = {
readonly vertexLayoutMap?: Map<TgpuVertexLayout, (TgpuBuffer<BaseData> & VertexFlag) | GPUBuffer> | undefined;
readonly bindGroupLayoutMap?: Map<TgpuBindGroupLayout, TgpuBindGroup | GPUBindGroup> | undefined;
readonly colorAttachment?: AnyFragmentColorAttachment | undefined;
readonly depthStencilAttachment?: DepthStencilAttachment | undefined;
readonly stencilReference?: GPUStencilValue | undefined;
readonly indexBuffer?: {
buffer: (TgpuBuffer<BaseData> & IndexFlag) | GPUBuffer;
indexFormat: GPUIndexFormat;
offsetBytes?: number | undefined;
sizeBytes?: number | undefined;
} | undefined;
/** A pass the pipeline draws into, but does not own */
readonly pass?: TgpuRenderCommands | undefined;
/** An encoder the pipeline records its own passes into, but does not submit */
readonly encoder?: TgpuCommandEncoder | undefined;
} & TimestampWritesPriors;
type Memo = {
pipeline: GPURenderPipeline;
usedBindGroupLayouts: TgpuBindGroupLayout[];
catchall: [number, TgpuBindGroup] | undefined;
logResources: LogResources | undefined;
usedVertexLayouts: TgpuVertexLayout[];
fragmentOut: BaseData | undefined;
};
declare class TgpuRenderPipelineImpl implements TgpuRenderPipeline {
#private;
readonly [$internal]: RenderPipelineInternals;
readonly [$soul]: TgpuRenderPipelineSoul;
readonly resourceType = "render-pipeline";
[$getNameForward]: RenderPipelineCore;
constructor(core: RenderPipelineCore, priors: TgpuRenderPipelinePriors);
[$resolve](ctx: ResolutionCtx): ResolvedSnippet;
toString(): string;
$name(label: string): this;
with<TData extends WgslArray>(vertexLayout: TgpuVertexLayout<TData>, buffer: TgpuBuffer<TData> & VertexFlag): this;
with(bindGroupLayout: TgpuBindGroupLayout, bindGroup: TgpuBindGroup): this;
with(bindGroupLayout: TgpuBindGroupLayout, bindGroup: GPUBindGroup): this;
with(bindGroup: TgpuBindGroup): this;
with<TData extends WgslArray | Disarray>(vertexLayout: TgpuVertexLayout<TData>, buffer: GPUBuffer): this;
with(pass: TgpuRenderCommands): this;
with(encoder: TgpuCommandEncoder): this;
with(encoder: GPUCommandEncoder): this;
with(pass: GPURenderPassEncoder): this;
with(bundleEncoder: GPURenderBundleEncoder): this;
withPerformanceCallback(callback: (start: bigint, end: bigint) => void | Promise<void>): this;
withTimestampWrites(options: {
querySet: TgpuQuerySet<'timestamp'> | GPUQuerySet;
beginningOfPassWriteIndex?: number;
endOfPassWriteIndex?: number;
}): this;
withColorAttachment(attachment: AnyFragmentColorAttachment): this;
withDepthStencilAttachment(attachment: DepthStencilAttachment): this;
withStencilReference(reference: GPUStencilValue): this;
withIndexBuffer(buffer: TgpuBuffer<BaseData> & IndexFlag, offsetElements?: number, sizeElements?: number): this & HasIndexBuffer;
withIndexBuffer(buffer: GPUBuffer, indexFormat: GPUIndexFormat, offsetBytes?: number, sizeBytes?: number): this & HasIndexBuffer;
initAsync(): Promise<void>;
initSync(): void;
get hasIndexBuffer(): boolean;
draw(vertexCount: number, instanceCount?: number, firstVertex?: number, firstInstance?: number): void;
drawIndexed(indexCount: number, instanceCount?: number, firstIndex?: number, baseVertex?: number, firstInstance?: number): void;
drawIndirect(indirectBuffer: (TgpuBuffer<BaseData> & IndirectFlag) | GPUBuffer, indirectOffset?: PrimitiveOffsetInfo | number): void;
drawIndexedIndirect(indirectBuffer: (TgpuBuffer<BaseData> & IndirectFlag) | GPUBuffer, indirectOffset?: PrimitiveOffsetInfo | number): void;
}
declare class RenderPipelineCore implements SelfResolvable {
#private;
readonly [$internal] = true;
readonly options: RenderPipelineCoreOptions;
constructor(options: RenderPipelineCoreOptions);
static precompiled(root: ExperimentalTgpuRoot, memo: Memo): RenderPipelineCore;
[$resolve](ctx: ResolutionCtx): ResolvedSnippet;
toString(): string;
get performanceCallbackQuerySet(): TgpuQuerySet<"timestamp"> | undefined;
initAsync(): Promise<void>;
initSync(): void;
unwrap(): Memo;
resolveAndCreateShaderModule(): {
resolutionResult: import("../../resolutionCtx.ts").ResolutionResult;
descriptor: GPURenderPipelineDescriptor;
connectedAttribs: import("../vertexLayout/connectAttributesToShader.ts").ConnectAttributesToShaderResult;
fragmentOut: WgslStruct<import("../function/ioSchema.ts").WithLocations<Record<string, BaseData>>>;
};
}
/**
* Assumes vertexOut and fragmentIn are matching when it comes to the keys, that is fragmentIn's keyset is a subset of vertexOut's
* Logs a warning, when they don't match in terms of custom locations
*/
export declare function matchUpVaryingLocations(vertexOut: TgpuVertexFn.Out | undefined, fragmentIn: TgpuFragmentFn.In | undefined, vertexFnName: string, fragmentFnName: string): Record<string, number>;
export {};