Skip to content

Commit 96efef2

Browse files
committed
Merge branch 'main' into impr/operator-!
2 parents b7cb36f + 4636de8 commit 96efef2

11 files changed

Lines changed: 164 additions & 58 deletions

File tree

packages/typegpu/src/core/function/autoIO.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type { BaseData, v4f } from '../../data/wgslTypes.ts';
77
import { getName, setName } from '../../shared/meta.ts';
88
import type { InferGPU, InferGPURecord, InferRecord } from '../../shared/repr.ts';
99
import { $internal, $resolve } from '../../shared/symbols.ts';
10-
import type { Assume } from '../../shared/utilityTypes.ts';
10+
import type { Assume, RemoveIndexSignature } from '../../shared/utilityTypes.ts';
1111
import type { TgpuVertexAttrib } from '../../shared/vertexFormat.ts';
1212
import type { ResolutionCtx, SelfResolvable } from '../../types.ts';
1313
import { shaderStageSlot } from '../slot/internalSlots.ts';
@@ -21,7 +21,8 @@ const builtinVertexIn = {
2121
$instanceIndex: builtin.instanceIndex,
2222
} as const;
2323

24-
export type AutoVertexIn<T extends AnyAutoCustoms> = T & InferRecord<typeof builtinVertexIn>;
24+
export type AutoVertexIn<T extends AnyAutoCustoms> = RemoveIndexSignature<T> &
25+
InferRecord<typeof builtinVertexIn>;
2526

2627
export type _AutoVertexIn<T> = AutoVertexIn<{
2728
[Key in keyof T]: T[Key] extends TgpuVertexAttrib
@@ -47,7 +48,8 @@ const builtinFragmentIn = {
4748
$subgroupSize: builtin.subgroupSize,
4849
} as const;
4950

50-
export type AutoFragmentIn<T extends AnyAutoCustoms> = T & InferRecord<typeof builtinFragmentIn>;
51+
export type AutoFragmentIn<T extends AnyAutoCustoms> = RemoveIndexSignature<T> &
52+
InferRecord<typeof builtinFragmentIn>;
5153

5254
const builtinFragmentOut = {
5355
$fragDepth: builtin.fragDepth,

packages/typegpu/src/core/function/fnTypes.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import type {
2323
Vec4u,
2424
Void,
2525
} from '../../data/wgslTypes.ts';
26-
import type { Infer } from '../../shared/repr.ts';
26+
import type { InferGPU } from '../../shared/repr.ts';
2727

2828
export type AnyFn = (...args: never[]) => unknown;
2929

@@ -41,7 +41,7 @@ export type TranspilationResult = {
4141
};
4242

4343
export type InferArgs<T extends unknown[]> = {
44-
[Idx in keyof T]: Infer<T[Idx]>;
44+
[Idx in keyof T]: InferGPU<T[Idx]>;
4545
};
4646

4747
type InheritTupleValues<T, From> = {
@@ -65,7 +65,7 @@ export type InheritArgNames<T extends AnyFn, From extends AnyFn> = {
6565

6666
export type InferImplSchema<ImplSchema extends AnyFn> = (
6767
...args: InferArgs<Parameters<ImplSchema>>
68-
) => Infer<ReturnType<ImplSchema>>;
68+
) => InferGPU<ReturnType<ImplSchema>>;
6969

7070
export type Implementation<ImplSchema extends AnyFn = AnyFn> = string | InferImplSchema<ImplSchema>;
7171

@@ -101,9 +101,9 @@ export type IOLayout<TElementType extends IOData = IOData> =
101101
| Void;
102102

103103
export type InferIO<T> = T extends { type: string }
104-
? Infer<T>
104+
? InferGPU<T>
105105
: T extends Record<string, unknown>
106-
? { [K in keyof T]: Infer<T[K]> }
106+
? { [K in keyof T]: InferGPU<T[K]> }
107107
: T;
108108

109109
export interface PositionalArgInfo {

packages/typegpu/src/core/function/tgpuFn.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { provideInsideTgpuFn } from '../../execMode.ts';
66
import type { TgpuNamable } from '../../shared/meta.ts';
77
import { getName, setName } from '../../shared/meta.ts';
88
import { isMarkedInternal } from '../../shared/symbols.ts';
9-
import type { Infer } from '../../shared/repr.ts';
9+
import type { InferGPU } from '../../shared/repr.ts';
1010
import { $getNameForward, $internal, $providing, $resolve } from '../../shared/symbols.ts';
1111
import type { Prettify } from '../../shared/utilityTypes.ts';
1212
import type { DualFn, ResolutionCtx, SelfResolvable } from '../../types.ts';
@@ -56,7 +56,7 @@ export type TgpuFnShell<Args extends BaseData[], Return extends BaseData> = Tgpu
5656
Args,
5757
Return
5858
> &
59-
(<T extends (...args: InferArgs<Args>) => Infer<Return>>(
59+
(<T extends (...args: InferArgs<Args>) => InferGPU<Return>>(
6060
implementation: T,
6161
) => TgpuFn<Prettify<InheritArgNames<(...args: Args) => Return, T>>['result']>) &
6262
((implementation: string) => TgpuFn<(...args: Args) => Return>) &

packages/typegpu/src/core/function/tgpuFragmentFn.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ export declare namespace TgpuFragmentFn {
121121
type Out = Record<string, BaseData> | BaseData;
122122
type AutoIn<T extends AnyAutoCustoms> = AutoFragmentIn<T>;
123123
type AutoOut<T extends AnyAutoCustoms = AnyAutoCustoms> = AutoFragmentOut<T>;
124+
125+
type AutoInEmpty = AutoFragmentIn<Record<string, never>>;
124126
}
125127

126128
export function fragmentFn<FragmentOut extends FragmentOutConstrained>(options: {

packages/typegpu/src/core/function/tgpuVertexFn.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ export declare namespace TgpuVertexFn {
8686
type Out = Record<string, BaseData>;
8787
type AutoIn<T> = _AutoVertexIn<T>;
8888
type AutoOut<T extends AnyAutoCustoms = AnyAutoCustoms> = AutoVertexOut<T>;
89+
90+
type AutoInEmpty = _AutoVertexIn<Record<string, never>>;
8991
}
9092

9193
export function vertexFn<VertexOut extends VertexOutConstrained>(options: {

packages/typegpu/src/core/pipeline/computePipeline.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,21 @@ class TgpuComputePipelineImpl implements TgpuComputePipeline {
220220
}
221221

222222
withPerformanceCallback(callback: (start: bigint, end: bigint) => void | Promise<void>): this {
223-
const newPriors = createWithPerformanceCallback(this.#priors, callback, this.#core.root);
223+
if (this.#priors.timestampWrites) {
224+
return new TgpuComputePipelineImpl(this.#core, {
225+
...this.#priors,
226+
performanceCallback: callback,
227+
}) as this;
228+
}
229+
230+
const querySet = this.#core.performanceCallbackQuerySet;
231+
if (!querySet) {
232+
console.warn(
233+
'Performance callback cannot be used because the timestamp-query feature is not enabled on the root.',
234+
);
235+
return this;
236+
}
237+
const newPriors = createWithPerformanceCallback(this.#priors, callback, querySet);
224238
return new TgpuComputePipelineImpl(this.#core, newPriors) as this;
225239
}
226240

@@ -353,6 +367,7 @@ class ComputePipelineCore implements SelfResolvable {
353367

354368
#slotBindings: [TgpuSlot<unknown>, unknown][];
355369
#descriptor: TgpuComputePipeline.Descriptor;
370+
#performanceCallbackQuerySet: TgpuQuerySet<'timestamp'> | undefined;
356371

357372
constructor(
358373
root: ExperimentalTgpuRoot,
@@ -375,6 +390,13 @@ class ComputePipelineCore implements SelfResolvable {
375390
return 'computePipelineCore';
376391
}
377392

393+
get performanceCallbackQuerySet() {
394+
if (!this.root.enabledFeatures.has('timestamp-query')) {
395+
return undefined;
396+
}
397+
return (this.#performanceCallbackQuerySet ??= this.root.createQuerySet('timestamp', 2));
398+
}
399+
378400
public unwrap(): Memo {
379401
if (this._memo === undefined) {
380402
const device = this.root.device;

packages/typegpu/src/core/pipeline/renderPipeline.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -550,11 +550,22 @@ class TgpuRenderPipelineImpl implements TgpuRenderPipeline {
550550

551551
withPerformanceCallback(callback: (start: bigint, end: bigint) => void | Promise<void>): this {
552552
const internals = this[$internal];
553-
const newPriors = createWithPerformanceCallback(
554-
internals.priors,
555-
callback,
556-
internals.core.options.root,
557-
);
553+
554+
if (internals.priors.timestampWrites) {
555+
return new TgpuRenderPipelineImpl(internals.core, {
556+
...internals.priors,
557+
performanceCallback: callback,
558+
}) as this;
559+
}
560+
561+
const querySet = internals.core.performanceCallbackQuerySet;
562+
if (!querySet) {
563+
console.warn(
564+
'Performance callback cannot be used because the timestamp-query feature is not enabled on the root.',
565+
);
566+
return this;
567+
}
568+
const newPriors = createWithPerformanceCallback(internals.priors, callback, querySet);
558569
return new TgpuRenderPipelineImpl(internals.core, newPriors) as this;
559570
}
560571

@@ -955,6 +966,7 @@ class RenderPipelineCore implements SelfResolvable {
955966

956967
#latestAutoVertexIn: TgpuVertexFn.In | undefined;
957968
#latestAutoFragmentOut: BaseData | undefined;
969+
#performanceCallbackQuerySet: TgpuQuerySet<'timestamp'> | undefined;
958970

959971
constructor(options: RenderPipelineCoreOptions) {
960972
this.options = options;
@@ -1011,6 +1023,13 @@ class RenderPipelineCore implements SelfResolvable {
10111023
return 'renderPipelineCore';
10121024
}
10131025

1026+
get performanceCallbackQuerySet() {
1027+
if (!this.options.root.enabledFeatures.has('timestamp-query')) {
1028+
return undefined;
1029+
}
1030+
return (this.#performanceCallbackQuerySet ??= this.options.root.createQuerySet('timestamp', 2));
1031+
}
1032+
10141033
public unwrap(): Memo {
10151034
if (this._memo !== undefined) {
10161035
return this._memo;

packages/typegpu/src/core/pipeline/timeable.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,19 @@ export type TimestampWritesPriors = {
1919
endOfPassWriteIndex?: number;
2020
};
2121
readonly performanceCallback?: (start: bigint, end: bigint) => void | Promise<void>;
22-
readonly hasAutoQuerySet?: boolean;
2322
};
2423

2524
export function createWithPerformanceCallback<T extends TimestampWritesPriors>(
2625
currentPriors: T,
2726
callback: (start: bigint, end: bigint) => void | Promise<void>,
28-
root: ExperimentalTgpuRoot,
27+
querySet: TgpuQuerySet<'timestamp'>,
2928
): T {
30-
if (!root.enabledFeatures.has('timestamp-query')) {
31-
throw new Error(
32-
'Performance callback requires the "timestamp-query" feature to be enabled on GPU device.',
33-
);
34-
}
35-
3629
if (!currentPriors.timestampWrites) {
3730
return {
3831
...currentPriors,
3932
performanceCallback: callback,
40-
hasAutoQuerySet: true,
4133
timestampWrites: {
42-
querySet: root.createQuerySet('timestamp', 2),
34+
querySet,
4335
beginningOfPassWriteIndex: 0,
4436
endOfPassWriteIndex: 1,
4537
},
@@ -67,10 +59,6 @@ export function createWithTimestampWrites<T extends TimestampWritesPriors>(
6759
);
6860
}
6961

70-
if (currentPriors.hasAutoQuerySet && currentPriors.timestampWrites) {
71-
currentPriors.timestampWrites.querySet.destroy();
72-
}
73-
7462
const timestampWrites: TimestampWritesPriors['timestampWrites'] = {
7563
querySet: options.querySet,
7664
};
@@ -84,7 +72,6 @@ export function createWithTimestampWrites<T extends TimestampWritesPriors>(
8472

8573
return {
8674
...currentPriors,
87-
hasAutoQuerySet: false,
8875
timestampWrites,
8976
};
9077
}

packages/typegpu/src/shared/utilityTypes.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export type Mutable<T> = {
5656
};
5757

5858
/**
59-
* Source: https://code.lol/post/programming/higher-kinded-types/
59+
* Source: https://code.lol/post/programming/higher-kinded-types
6060
*/
6161
export type Assume<T, U> = T extends U ? T : U;
6262

@@ -74,3 +74,16 @@ export type TypedArray =
7474
export function assertExhaustive(x: never, location: string): never {
7575
throw new Error(`Failed to handle ${x} at ${location}`);
7676
}
77+
78+
/**
79+
* Source: https://futurestud.io/tutorials/typescript-how-to-remove-index-signature-from-a-type
80+
*/
81+
export type RemoveIndexSignature<T> = {
82+
[K in keyof T as string extends K
83+
? never
84+
: number extends K
85+
? never
86+
: symbol extends K
87+
? never
88+
: K]: T[K];
89+
};

packages/typegpu/tests/computePipeline.test.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,23 +141,24 @@ describe('TgpuComputePipeline', () => {
141141
expect(pipeline[$internal].priors.performanceCallback).not.toBe(callback1);
142142
});
143143

144-
it('should throw error if timestamp-query feature is not enabled', ({ root, device }) => {
145-
const originalFeatures = device.features;
146-
//@ts-expect-error
144+
it('should warn if timestamp-query feature is not enabled', ({ root, device }) => {
145+
// @ts-expect-error
147146
device.features = new Set();
147+
using consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
148148

149149
const entryFn = tgpu.computeFn({ workgroupSize: [1] })(() => {});
150150

151151
const callback = vi.fn();
152152

153153
expect(() => {
154-
root.createComputePipeline({ compute: entryFn }).withPerformanceCallback(callback);
155-
}).toThrow(
156-
'Performance callback requires the "timestamp-query" feature to be enabled on GPU device.',
154+
const before = root.createComputePipeline({ compute: entryFn });
155+
const after = before.withPerformanceCallback(callback);
156+
// no-op
157+
expect(after).toBe(before);
158+
}).not.toThrow();
159+
expect(consoleWarnSpy).toHaveBeenCalledWith(
160+
'Performance callback cannot be used because the timestamp-query feature is not enabled on the root.',
157161
);
158-
159-
//@ts-expect-error
160-
device.features = originalFeatures;
161162
});
162163
});
163164

@@ -331,6 +332,7 @@ describe('TgpuComputePipeline', () => {
331332
describe('Combined Performance callback and Timestamp Writes', () => {
332333
it('should work with both performance callback and custom timestamp writes', ({
333334
root,
335+
device,
334336
commandEncoder,
335337
}) => {
336338
const entryFn = tgpu.computeFn({ workgroupSize: [1] })(() => {});
@@ -371,6 +373,12 @@ describe('TgpuComputePipeline', () => {
371373
querySet[$internal].resolveBuffer,
372374
0,
373375
);
376+
377+
expect(device.mock.createQuerySet).toHaveBeenCalledTimes(1);
378+
expect(device.mock.createQuerySet).toHaveBeenCalledWith({
379+
type: 'timestamp',
380+
count: 10,
381+
});
374382
});
375383

376384
it('should prioritize custom timestamp writes over automatic ones', ({
@@ -394,8 +402,6 @@ describe('TgpuComputePipeline', () => {
394402
endOfPassWriteIndex: 5,
395403
});
396404

397-
expect((autoQuerySet as TgpuQuerySet<'timestamp'>).destroyed).toBe(true);
398-
399405
const priors = pipeline[$internal].priors;
400406
expect(priors.performanceCallback).toBe(callback);
401407
expect(priors.timestampWrites?.querySet).toBe(querySet);

0 commit comments

Comments
 (0)