typegpu 0.10.2 → 0.11.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/_virtual/_rolldown/runtime.js +6 -11
  2. package/builtin.js +1 -3
  3. package/common/fullScreenTriangle.d.ts +1 -5
  4. package/common/fullScreenTriangle.js +1 -3
  5. package/common/index.d.ts +3 -2
  6. package/common/index.js +6 -4
  7. package/common/writeSoA.d.ts +16 -0
  8. package/common/writeSoA.js +90 -0
  9. package/core/buffer/buffer.d.ts +12 -7
  10. package/core/buffer/buffer.js +102 -53
  11. package/core/buffer/bufferShorthand.d.ts +5 -5
  12. package/core/buffer/bufferShorthand.js +9 -5
  13. package/core/buffer/bufferUsage.d.ts +0 -2
  14. package/core/buffer/bufferUsage.js +6 -4
  15. package/core/constant/tgpuConstant.d.ts +2 -1
  16. package/core/constant/tgpuConstant.js +8 -7
  17. package/core/declare/tgpuDeclare.js +8 -9
  18. package/core/function/autoIO.d.ts +7 -6
  19. package/core/function/autoIO.js +1 -3
  20. package/core/function/comptime.js +1 -3
  21. package/core/function/createCallableSchema.js +4 -6
  22. package/core/function/dualImpl.js +1 -3
  23. package/core/function/entryInputRouter.js +39 -0
  24. package/core/function/extractArgs.js +2 -2
  25. package/core/function/fnCore.js +19 -8
  26. package/core/function/fnTypes.d.ts +14 -8
  27. package/core/function/ioSchema.js +24 -3
  28. package/core/function/shelllessImpl.js +1 -3
  29. package/core/function/templateUtils.js +1 -2
  30. package/core/function/tgpuComputeFn.d.ts +2 -3
  31. package/core/function/tgpuComputeFn.js +9 -16
  32. package/core/function/tgpuFn.d.ts +2 -2
  33. package/core/function/tgpuFn.js +1 -3
  34. package/core/function/tgpuFragmentFn.d.ts +5 -1
  35. package/core/function/tgpuFragmentFn.js +5 -10
  36. package/core/function/tgpuVertexFn.d.ts +4 -0
  37. package/core/function/tgpuVertexFn.js +6 -12
  38. package/core/pipeline/applyPipelineState.js +1 -3
  39. package/core/pipeline/computePipeline.d.ts +2 -6
  40. package/core/pipeline/computePipeline.js +64 -63
  41. package/core/pipeline/connectAttachmentToShader.js +1 -3
  42. package/core/pipeline/connectTargetsToShader.js +1 -3
  43. package/core/pipeline/limitsOverflow.js +1 -2
  44. package/core/pipeline/pipelineUtils.js +29 -0
  45. package/core/pipeline/renderPipeline.d.ts +23 -5
  46. package/core/pipeline/renderPipeline.js +32 -14
  47. package/core/pipeline/timeable.d.ts +0 -3
  48. package/core/pipeline/timeable.js +3 -9
  49. package/core/pipeline/typeGuards.js +1 -3
  50. package/core/querySet/querySet.d.ts +0 -2
  51. package/core/querySet/querySet.js +37 -36
  52. package/core/rawCodeSnippet/tgpuRawCodeSnippet.js +1 -3
  53. package/core/resolve/externals.d.ts +0 -2
  54. package/core/resolve/externals.js +2 -4
  55. package/core/resolve/namespace.js +1 -3
  56. package/core/resolve/resolveData.js +1 -3
  57. package/core/resolve/stitch.js +1 -3
  58. package/core/resolve/tgpuResolve.d.ts +3 -1
  59. package/core/resolve/tgpuResolve.js +3 -5
  60. package/core/root/configurableImpl.js +2 -3
  61. package/core/root/init.d.ts +0 -5
  62. package/core/root/init.js +35 -28
  63. package/core/root/rootTypes.d.ts +25 -5
  64. package/core/sampler/sampler.d.ts +0 -4
  65. package/core/sampler/sampler.js +3 -3
  66. package/core/simulate/tgpuSimulate.js +1 -3
  67. package/core/slot/accessor.d.ts +0 -4
  68. package/core/slot/accessor.js +1 -3
  69. package/core/slot/internalSlots.js +1 -3
  70. package/core/slot/lazy.js +1 -3
  71. package/core/slot/slot.js +2 -3
  72. package/core/slot/slotTypes.js +1 -3
  73. package/core/texture/externalTexture.d.ts +0 -6
  74. package/core/texture/externalTexture.js +2 -3
  75. package/core/texture/texture.d.ts +0 -4
  76. package/core/texture/texture.js +5 -3
  77. package/core/texture/textureFormats.js +1 -3
  78. package/core/texture/textureUtils.js +1 -3
  79. package/core/texture/usageExtension.js +1 -3
  80. package/core/unroll/tgpuUnroll.d.ts +58 -3
  81. package/core/unroll/tgpuUnroll.js +63 -5
  82. package/core/valueProxyUtils.js +1 -3
  83. package/core/variable/tgpuVariable.js +1 -3
  84. package/core/vertexLayout/connectAttributesToShader.js +1 -3
  85. package/core/vertexLayout/vertexLayout.js +9 -9
  86. package/data/alignIO.js +1 -2
  87. package/data/alignmentOf.d.ts +0 -1
  88. package/data/alignmentOf.js +1 -3
  89. package/data/array.d.ts +1 -3
  90. package/data/array.js +2 -4
  91. package/data/atomic.js +2 -3
  92. package/data/attributes.js +3 -3
  93. package/data/autoStruct.d.ts +1 -3
  94. package/data/autoStruct.js +1 -3
  95. package/data/compiledIO.js +83 -86
  96. package/data/dataIO.js +46 -39
  97. package/data/dataTypes.d.ts +7 -7
  98. package/data/dataTypes.js +6 -3
  99. package/data/deepEqual.js +1 -3
  100. package/data/disarray.d.ts +1 -3
  101. package/data/disarray.js +1 -3
  102. package/data/getLongestContiguousPrefix.d.ts +0 -1
  103. package/data/getLongestContiguousPrefix.js +1 -3
  104. package/data/index.d.ts +3 -3
  105. package/data/index.js +10 -3
  106. package/data/isContiguous.d.ts +0 -1
  107. package/data/isContiguous.js +1 -3
  108. package/data/matrix.d.ts +8 -10
  109. package/data/matrix.js +32 -18
  110. package/data/numberOps.js +1 -2
  111. package/data/numeric.js +16 -29
  112. package/data/offsetUtils.d.ts +2 -2
  113. package/data/offsetUtils.js +3 -5
  114. package/data/offsets.js +1 -3
  115. package/data/partialIO.js +84 -39
  116. package/data/ptr.d.ts +0 -1
  117. package/data/ptr.js +1 -3
  118. package/data/ref.d.ts +0 -3
  119. package/data/ref.js +1 -3
  120. package/data/sampler.js +1 -3
  121. package/data/schemaCallWrapper.js +1 -3
  122. package/data/schemaMemoryLayout.js +1 -3
  123. package/data/sizeOf.d.ts +0 -1
  124. package/data/sizeOf.js +1 -3
  125. package/data/snippet.js +12 -3
  126. package/data/struct.js +1 -3
  127. package/data/texture.js +1 -3
  128. package/data/unstruct.js +1 -3
  129. package/data/vector.js +4 -12
  130. package/data/vectorImpl.js +27 -28
  131. package/data/vectorOps.js +20 -3
  132. package/data/vertexFormatData.js +2 -3
  133. package/data/wgslTypes.d.ts +39 -11
  134. package/data/wgslTypes.js +10 -3
  135. package/errors.js +6 -3
  136. package/execMode.js +1 -3
  137. package/extension.js +1 -3
  138. package/getGPUValue.js +1 -3
  139. package/index.d.ts +4 -2
  140. package/index.js +3 -3
  141. package/indexNamedExports.d.ts +3 -1
  142. package/mathUtils.js +1 -2
  143. package/memo.js +8 -8
  144. package/nameRegistry.js +1 -3
  145. package/package.js +2 -3
  146. package/package.json +5 -5
  147. package/resolutionCtx.d.ts +0 -10
  148. package/resolutionCtx.js +84 -18
  149. package/shared/env.js +1 -2
  150. package/shared/generators.js +1 -2
  151. package/shared/meta.js +1 -3
  152. package/shared/repr.d.ts +32 -2
  153. package/shared/stringify.js +1 -3
  154. package/shared/symbols.d.ts +10 -1
  155. package/shared/symbols.js +10 -33
  156. package/shared/utilityTypes.d.ts +6 -2
  157. package/shared/utilityTypes.js +1 -2
  158. package/shared/vertexFormat.js +1 -2
  159. package/std/array.d.ts +1 -1
  160. package/std/array.js +1 -3
  161. package/std/atomic.d.ts +12 -12
  162. package/std/atomic.js +1 -3
  163. package/std/bitcast.d.ts +2 -2
  164. package/std/bitcast.js +1 -3
  165. package/std/boolean.d.ts +30 -16
  166. package/std/boolean.js +37 -12
  167. package/std/derivative.d.ts +9 -9
  168. package/std/derivative.js +1 -3
  169. package/std/discard.d.ts +1 -1
  170. package/std/discard.js +1 -3
  171. package/std/extensions.d.ts +1 -3
  172. package/std/extensions.js +1 -3
  173. package/std/index.d.ts +5 -4
  174. package/std/index.js +8 -5
  175. package/std/matrix.d.ts +5 -5
  176. package/std/matrix.js +1 -3
  177. package/std/numeric.d.ts +78 -132
  178. package/std/numeric.js +1 -3
  179. package/std/operators.d.ts +16 -8
  180. package/std/operators.js +80 -6
  181. package/std/packing.d.ts +4 -4
  182. package/std/packing.js +1 -3
  183. package/std/range.d.ts +24 -0
  184. package/std/range.js +38 -0
  185. package/std/subgroup.d.ts +21 -21
  186. package/std/subgroup.js +1 -3
  187. package/std/texture.d.ts +20 -11
  188. package/std/texture.js +13 -3
  189. package/tgpu.js +1 -3
  190. package/tgpuBindGroupLayout.js +9 -8
  191. package/tgpuUnstable.js +1 -3
  192. package/tgsl/accessIndex.js +2 -4
  193. package/tgsl/accessProp.js +8 -6
  194. package/tgsl/consoleLog/deserializers.js +1 -3
  195. package/tgsl/consoleLog/logGenerator.js +2 -4
  196. package/tgsl/consoleLog/serializers.js +24 -26
  197. package/tgsl/consoleLog/types.d.ts +0 -2
  198. package/tgsl/consoleLog/types.js +1 -2
  199. package/tgsl/conversion.js +1 -3
  200. package/tgsl/forOfUtils.js +35 -9
  201. package/tgsl/generationHelpers.js +3 -3
  202. package/tgsl/math.js +1 -3
  203. package/tgsl/shaderGenerator.d.ts +10 -8
  204. package/tgsl/shaderGenerator_members.d.ts +2 -0
  205. package/tgsl/shaderGenerator_members.js +6 -0
  206. package/tgsl/shellless.js +1 -8
  207. package/tgsl/wgslGenerator.d.ts +36 -0
  208. package/tgsl/wgslGenerator.js +135 -81
  209. package/types.d.ts +14 -4
  210. package/types.js +3 -3
  211. package/wgslExtensions.js +1 -2
@@ -1,10 +1,9 @@
1
1
  import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
2
- import { getName, isNamable, setName } from "../../shared/meta.js";
3
- import { createIoSchema } from "./ioSchema.js";
2
+ import { getName, setName } from "../../shared/meta.js";
3
+ import { createIoSchema, separateAllAsPositional } from "./ioSchema.js";
4
4
  import { createFnCore } from "./fnCore.js";
5
5
  import { stripTemplate } from "./templateUtils.js";
6
6
  import { shaderStageSlot } from "../slot/internalSlots.js";
7
-
8
7
  //#region src/core/function/tgpuVertexFn.ts
9
8
  /**
10
9
  * Creates a shell of a typed entry function for the vertex shader stage. Any function
@@ -33,7 +32,7 @@ function isTgpuVertexFn(value) {
33
32
  }
34
33
  function createVertexFn(shell, implementation) {
35
34
  const core = createFnCore(implementation, "@vertex ");
36
- const inputType = shell.argTypes[0];
35
+ const entryInput = separateAllAsPositional(shell.in ?? {});
37
36
  return {
38
37
  shell,
39
38
  $uses(newExternals) {
@@ -44,22 +43,17 @@ function createVertexFn(shell, implementation) {
44
43
  [$getNameForward]: core,
45
44
  $name(newLabel) {
46
45
  setName(this, newLabel);
47
- if (isNamable(inputType)) inputType.$name(`${newLabel}_Input`);
48
46
  return this;
49
47
  },
50
48
  [$resolve](ctx) {
51
49
  const outputWithLocation = createIoSchema(shell.out, ctx.varyingLocations).$name(`${getName(this) ?? ""}_Output`);
52
- if (typeof implementation === "string") {
53
- if (inputType) core.applyExternals({ In: inputType });
54
- core.applyExternals({ Out: outputWithLocation });
55
- }
56
- return ctx.withSlots([[shaderStageSlot, "vertex"]], () => core.resolve(ctx, shell.argTypes, outputWithLocation));
50
+ if (typeof implementation === "string") core.applyExternals({ Out: outputWithLocation });
51
+ return ctx.withSlots([[shaderStageSlot, "vertex"]], () => core.resolve(ctx, [], outputWithLocation, entryInput));
57
52
  },
58
53
  toString() {
59
54
  return `vertexFn:${getName(core) ?? "<unnamed>"}`;
60
55
  }
61
56
  };
62
57
  }
63
-
64
58
  //#endregion
65
- export { isTgpuVertexFn, vertexFn };
59
+ export { isTgpuVertexFn, vertexFn };
@@ -2,7 +2,6 @@ import { MissingBindGroupsError, MissingVertexBuffersError } from "../../errors.
2
2
  import { isBuffer } from "../buffer/buffer.js";
3
3
  import { isBindGroup } from "../../tgpuBindGroupLayout.js";
4
4
  import { warnIfOverflow } from "./limitsOverflow.js";
5
-
6
5
  //#region src/core/pipeline/applyPipelineState.ts
7
6
  function applyBindGroups(encoder, root, usedBindGroupLayouts, catchall, resolveBindGroup) {
8
7
  const missingBindGroups = new Set(usedBindGroupLayouts);
@@ -32,6 +31,5 @@ function applyVertexBuffers(encoder, root, usedVertexLayouts, resolveVertexBuffe
32
31
  });
33
32
  if (missingVertexLayouts.size > 0) throw new MissingVertexBuffersError(missingVertexLayouts);
34
33
  }
35
-
36
34
  //#endregion
37
- export { applyBindGroups, applyVertexBuffers };
35
+ export { applyBindGroups, applyVertexBuffers };
@@ -1,12 +1,8 @@
1
1
  import { TgpuNamable } from "../../shared/meta.js";
2
2
  import { $internal } from "../../shared/symbols.js";
3
3
  import { AnyComputeBuiltin } from "../../builtin.js";
4
- import "../querySet/querySet.js";
5
- import "../../data/snippet.js";
6
- import "../../tgsl/consoleLog/types.js";
7
4
  import { IORecord } from "../function/fnTypes.js";
8
5
  import { TgpuComputeFn } from "../function/tgpuComputeFn.js";
9
- import "../slot/slotTypes.js";
10
6
  import { PrimitiveOffsetInfo } from "../../data/offsetUtils.js";
11
7
  import { Timeable, TimestampWritesPriors } from "./timeable.js";
12
8
  import { TgpuBindGroup, TgpuBindGroupLayout, TgpuLayoutEntry } from "../../tgpuBindGroupLayout.js";
@@ -39,10 +35,10 @@ interface TgpuComputePipeline extends TgpuNamable, SelfResolvable, Timeable {
39
35
  * The buffer must contain 3 consecutive u32 values (x, y, z workgroup counts).
40
36
  * To get the correct offset within complex data structures, use `d.memoryLayoutOf(...)`.
41
37
  *
42
- * @param indirectBuffer - Buffer marked with 'indirect' usage containing dispatch parameters
38
+ * @param indirectBuffer - Buffer marked with 'indirect' usage containing dispatch parameters or raw GPUBuffer
43
39
  * @param start - PrimitiveOffsetInfo pointing to the first dispatch parameter. If not provided, starts at offset 0. To obtain safe offsets, use `d.memoryLayoutOf(...)`.
44
40
  */
45
- dispatchWorkgroupsIndirect<T extends AnyWgslData>(indirectBuffer: TgpuBuffer<T> & IndirectFlag, start?: PrimitiveOffsetInfo | number): void;
41
+ dispatchWorkgroupsIndirect<T extends AnyWgslData>(indirectBuffer: (TgpuBuffer<T> & IndirectFlag) | GPUBuffer, start?: PrimitiveOffsetInfo | number): void;
46
42
  }
47
43
  declare namespace TgpuComputePipeline {
48
44
  type Descriptor<Input extends IORecord<AnyComputeBuiltin> = IORecord<AnyComputeBuiltin>> = {
@@ -2,7 +2,7 @@ import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
2
2
  import { PERF, getName, setName } from "../../shared/meta.js";
3
3
  import { Void } from "../../data/wgslTypes.js";
4
4
  import { snip } from "../../data/snippet.js";
5
- import { sizeOf } from "../../data/sizeOf.js";
5
+ import { isGPUBuffer } from "../../types.js";
6
6
  import { namespace } from "../resolve/namespace.js";
7
7
  import { isBindGroup } from "../../tgpuBindGroupLayout.js";
8
8
  import { resolve } from "../../resolutionCtx.js";
@@ -10,125 +10,121 @@ import { isGPUCommandEncoder, isGPUComputePassEncoder } from "./typeGuards.js";
10
10
  import { applyBindGroups } from "./applyPipelineState.js";
11
11
  import { logDataFromGPU } from "../../tgsl/consoleLog/deserializers.js";
12
12
  import { wgslExtensionToFeatureName, wgslExtensions } from "../../wgslExtensions.js";
13
- import { memoryLayoutOf } from "../../data/offsetUtils.js";
13
+ import { resolveIndirectOffset } from "./pipelineUtils.js";
14
14
  import { createWithPerformanceCallback, createWithTimestampWrites, setupTimestampWrites, triggerPerformanceCallback } from "./timeable.js";
15
-
16
15
  //#region src/core/pipeline/computePipeline.ts
17
16
  function INTERNAL_createComputePipeline(branch, slotBindings, descriptor) {
18
17
  return new TgpuComputePipelineImpl(new ComputePipelineCore(branch, slotBindings, descriptor), {});
19
18
  }
20
- function validateIndirectBufferSize(bufferSize, offset, requiredBytes, operation) {
21
- if (offset + requiredBytes > bufferSize) throw new Error(`Buffer too small for ${operation}. Required: ${requiredBytes} bytes at offset ${offset}, but buffer is only ${bufferSize} bytes.`);
22
- if (offset % 4 !== 0) throw new Error(`Indirect buffer offset must be a multiple of 4. Got: ${offset}`);
23
- }
24
19
  const _lastAppliedCompute = /* @__PURE__ */ new WeakMap();
25
20
  var TgpuComputePipelineImpl = class TgpuComputePipelineImpl {
26
21
  [$internal];
27
22
  resourceType = "compute-pipeline";
28
23
  [$getNameForward];
29
- constructor(_core, _priors) {
30
- this._core = _core;
31
- this._priors = _priors;
24
+ #core;
25
+ #priors;
26
+ constructor(core, priors) {
27
+ this.#core = core;
28
+ this.#priors = priors;
32
29
  this[$internal] = {
33
30
  get rawPipeline() {
34
- return _core.unwrap().pipeline;
31
+ return core.unwrap().pipeline;
35
32
  },
36
33
  get priors() {
37
- return _priors;
34
+ return priors;
38
35
  },
39
36
  get root() {
40
- return _core.root;
37
+ return core.root;
41
38
  }
42
39
  };
43
- this[$getNameForward] = _core;
40
+ this[$getNameForward] = core;
44
41
  }
45
42
  [$resolve](ctx) {
46
- return ctx.resolve(this._core);
43
+ return ctx.resolve(this.#core);
47
44
  }
48
45
  toString() {
49
46
  return `computePipeline:${getName(this) ?? "<unnamed>"}`;
50
47
  }
51
48
  get rawPipeline() {
52
- return this._core.unwrap().pipeline;
49
+ return this.#core.unwrap().pipeline;
53
50
  }
54
51
  with(first, bindGroup) {
55
- if (isGPUComputePassEncoder(first)) return new TgpuComputePipelineImpl(this._core, {
56
- ...this._priors,
52
+ if (isGPUComputePassEncoder(first)) return new TgpuComputePipelineImpl(this.#core, {
53
+ ...this.#priors,
57
54
  externalPass: first,
58
55
  externalEncoder: void 0
59
56
  });
60
- if (isGPUCommandEncoder(first)) return new TgpuComputePipelineImpl(this._core, {
61
- ...this._priors,
57
+ if (isGPUCommandEncoder(first)) return new TgpuComputePipelineImpl(this.#core, {
58
+ ...this.#priors,
62
59
  externalEncoder: first,
63
60
  externalPass: void 0
64
61
  });
65
- if (isBindGroup(first)) return new TgpuComputePipelineImpl(this._core, {
66
- ...this._priors,
67
- bindGroupLayoutMap: new Map([...this._priors.bindGroupLayoutMap ?? [], [first.layout, first]])
62
+ if (isBindGroup(first)) return new TgpuComputePipelineImpl(this.#core, {
63
+ ...this.#priors,
64
+ bindGroupLayoutMap: new Map([...this.#priors.bindGroupLayoutMap ?? [], [first.layout, first]])
68
65
  });
69
- return new TgpuComputePipelineImpl(this._core, {
70
- ...this._priors,
71
- bindGroupLayoutMap: new Map([...this._priors.bindGroupLayoutMap ?? [], [first, bindGroup]])
66
+ return new TgpuComputePipelineImpl(this.#core, {
67
+ ...this.#priors,
68
+ bindGroupLayoutMap: new Map([...this.#priors.bindGroupLayoutMap ?? [], [first, bindGroup]])
72
69
  });
73
70
  }
74
71
  withPerformanceCallback(callback) {
75
- const newPriors = createWithPerformanceCallback(this._priors, callback, this._core.root);
76
- return new TgpuComputePipelineImpl(this._core, newPriors);
72
+ if (this.#priors.timestampWrites) return new TgpuComputePipelineImpl(this.#core, {
73
+ ...this.#priors,
74
+ performanceCallback: callback
75
+ });
76
+ const querySet = this.#core.performanceCallbackQuerySet;
77
+ if (!querySet) {
78
+ console.warn("Performance callback cannot be used because the timestamp-query feature is not enabled on the root.");
79
+ return this;
80
+ }
81
+ const newPriors = createWithPerformanceCallback(this.#priors, callback, querySet);
82
+ return new TgpuComputePipelineImpl(this.#core, newPriors);
77
83
  }
78
84
  withTimestampWrites(options) {
79
- const newPriors = createWithTimestampWrites(this._priors, options, this._core.root);
80
- return new TgpuComputePipelineImpl(this._core, newPriors);
85
+ const newPriors = createWithTimestampWrites(this.#priors, options, this.#core.root);
86
+ return new TgpuComputePipelineImpl(this.#core, newPriors);
81
87
  }
82
88
  dispatchWorkgroups(x, y, z) {
83
89
  this._executeComputePass((pass) => pass.dispatchWorkgroups(x, y, z));
84
90
  }
85
91
  dispatchWorkgroupsIndirect(indirectBuffer, start) {
86
92
  const DISPATCH_SIZE = 12;
87
- let offsetInfo = start ?? memoryLayoutOf(indirectBuffer.dataType);
88
- if (typeof offsetInfo === "number") if (offsetInfo === 0) offsetInfo = memoryLayoutOf(indirectBuffer.dataType);
89
- else {
90
- console.warn(`dispatchWorkgroupsIndirect: Provided start offset ${offsetInfo} as a raw number. Use d.memoryLayoutOf(...) to include contiguous padding info for safer validation.`);
91
- offsetInfo = {
92
- offset: offsetInfo,
93
- contiguous: DISPATCH_SIZE
94
- };
95
- }
96
- const { offset, contiguous } = offsetInfo;
97
- validateIndirectBufferSize(sizeOf(indirectBuffer.dataType), offset, DISPATCH_SIZE, "dispatchWorkgroupsIndirect");
98
- if (contiguous < DISPATCH_SIZE) console.warn(`dispatchWorkgroupsIndirect: Starting at offset ${offset}, only ${contiguous} contiguous bytes are available before padding. Dispatch requires ${DISPATCH_SIZE} bytes (3 x u32). Reading across padding may result in undefined behavior.`);
99
- this._executeComputePass((pass) => pass.dispatchWorkgroupsIndirect(indirectBuffer.buffer, offset));
93
+ const rawBuffer = isGPUBuffer(indirectBuffer) ? indirectBuffer : indirectBuffer.buffer;
94
+ const offset = resolveIndirectOffset(indirectBuffer, start, DISPATCH_SIZE, "dispatchWorkgroupsIndirect");
95
+ this._executeComputePass((pass) => pass.dispatchWorkgroupsIndirect(rawBuffer, offset));
100
96
  }
101
97
  _applyComputeState(pass) {
102
- const memo = this._core.unwrap();
103
- const { root } = this._core;
98
+ const memo = this.#core.unwrap();
99
+ const { root } = this.#core;
104
100
  pass.setPipeline(memo.pipeline);
105
- applyBindGroups(pass, root, memo.usedBindGroupLayouts, memo.catchall, (layout) => this._priors.bindGroupLayoutMap?.get(layout));
101
+ applyBindGroups(pass, root, memo.usedBindGroupLayouts, memo.catchall, (layout) => this.#priors.bindGroupLayoutMap?.get(layout));
106
102
  }
107
103
  _executeComputePass(dispatch) {
108
- const { root } = this._core;
109
- if (this._priors.externalPass) {
110
- if (_lastAppliedCompute.get(this._priors.externalPass) !== this) {
111
- this._applyComputeState(this._priors.externalPass);
112
- _lastAppliedCompute.set(this._priors.externalPass, this);
104
+ const { root } = this.#core;
105
+ if (this.#priors.externalPass) {
106
+ if (_lastAppliedCompute.get(this.#priors.externalPass) !== this) {
107
+ this._applyComputeState(this.#priors.externalPass);
108
+ _lastAppliedCompute.set(this.#priors.externalPass, this);
113
109
  }
114
- dispatch(this._priors.externalPass);
110
+ dispatch(this.#priors.externalPass);
115
111
  return;
116
112
  }
117
- if (this._priors.externalEncoder) {
113
+ if (this.#priors.externalEncoder) {
118
114
  const passDescriptor = {
119
- label: getName(this._core) ?? "<unnamed>",
120
- ...setupTimestampWrites(this._priors, root)
115
+ label: getName(this.#core) ?? "<unnamed>",
116
+ ...setupTimestampWrites(this.#priors, root)
121
117
  };
122
- const pass = this._priors.externalEncoder.beginComputePass(passDescriptor);
118
+ const pass = this.#priors.externalEncoder.beginComputePass(passDescriptor);
123
119
  this._applyComputeState(pass);
124
120
  dispatch(pass);
125
121
  pass.end();
126
122
  return;
127
123
  }
128
- const memo = this._core.unwrap();
124
+ const memo = this.#core.unwrap();
129
125
  const passDescriptor = {
130
- label: getName(this._core) ?? "<unnamed>",
131
- ...setupTimestampWrites(this._priors, root)
126
+ label: getName(this.#core) ?? "<unnamed>",
127
+ ...setupTimestampWrites(this.#priors, root)
132
128
  };
133
129
  const commandEncoder = root.device.createCommandEncoder();
134
130
  const pass = commandEncoder.beginComputePass(passDescriptor);
@@ -137,9 +133,9 @@ var TgpuComputePipelineImpl = class TgpuComputePipelineImpl {
137
133
  pass.end();
138
134
  root.device.queue.submit([commandEncoder.finish()]);
139
135
  if (memo.logResources) logDataFromGPU(memo.logResources);
140
- if (this._priors.performanceCallback) triggerPerformanceCallback({
136
+ if (this.#priors.performanceCallback) triggerPerformanceCallback({
141
137
  root,
142
- priors: this._priors
138
+ priors: this.#priors
143
139
  });
144
140
  }
145
141
  $name(label) {
@@ -149,9 +145,11 @@ var TgpuComputePipelineImpl = class TgpuComputePipelineImpl {
149
145
  };
150
146
  var ComputePipelineCore = class {
151
147
  [$internal] = true;
148
+ root;
152
149
  _memo;
153
150
  #slotBindings;
154
151
  #descriptor;
152
+ #performanceCallbackQuerySet;
155
153
  constructor(root, slotBindings, descriptor) {
156
154
  this.root = root;
157
155
  this.#slotBindings = slotBindings;
@@ -166,6 +164,10 @@ var ComputePipelineCore = class {
166
164
  toString() {
167
165
  return "computePipelineCore";
168
166
  }
167
+ get performanceCallbackQuerySet() {
168
+ if (!this.root.enabledFeatures.has("timestamp-query")) return;
169
+ return this.#performanceCallbackQuerySet ??= this.root.createQuerySet("timestamp", 2);
170
+ }
169
171
  unwrap() {
170
172
  if (this._memo === void 0) {
171
173
  const device = this.root.device;
@@ -221,6 +223,5 @@ var ComputePipelineCore = class {
221
223
  return this._memo;
222
224
  }
223
225
  };
224
-
225
226
  //#endregion
226
- export { INTERNAL_createComputePipeline };
227
+ export { INTERNAL_createComputePipeline };
@@ -1,6 +1,5 @@
1
1
  import { isWgslStruct } from "../../data/wgslTypes.js";
2
2
  import { isBuiltin } from "../../data/attributes.js";
3
-
4
3
  //#region src/core/pipeline/connectAttachmentToShader.ts
5
4
  function isColorAttachment(value) {
6
5
  return !!value?.view;
@@ -21,6 +20,5 @@ function connectAttachmentToShader(fragmentOut, attachment) {
21
20
  if (!isColorAttachment(attachment)) throw new Error("Expected a single color attachment, not a record.");
22
21
  return [attachment];
23
22
  }
24
-
25
23
  //#endregion
26
- export { connectAttachmentToShader };
24
+ export { connectAttachmentToShader };
@@ -1,6 +1,5 @@
1
1
  import { isVoid, isWgslStruct } from "../../data/wgslTypes.js";
2
2
  import { isBuiltin } from "../../data/attributes.js";
3
-
4
3
  //#region src/core/pipeline/connectTargetsToShader.ts
5
4
  function connectTargetsToShader(fragmentOut, targets) {
6
5
  let presentationFormat;
@@ -24,6 +23,5 @@ function connectTargetsToShader(fragmentOut, targets) {
24
23
  format: singleTarget?.format ?? (presentationFormat ??= navigator.gpu.getPreferredCanvasFormat())
25
24
  }];
26
25
  }
27
-
28
26
  //#endregion
29
- export { connectTargetsToShader };
27
+ export { connectTargetsToShader };
@@ -8,6 +8,5 @@ function warnIfOverflow(layouts, limits) {
8
8
  2. Increasing the limit when requesting a device or creating a root.`);
9
9
  if (storage > limits.maxStorageBuffersPerShaderStage) console.warn(`Total number of storage buffers (${storage}) exceeds maxStorageBuffersPerShaderStage (${limits.maxStorageBuffersPerShaderStage}).`);
10
10
  }
11
-
12
11
  //#endregion
13
- export { warnIfOverflow };
12
+ export { warnIfOverflow };
@@ -0,0 +1,29 @@
1
+ import { isGPUBuffer } from "../../types.js";
2
+ import { sizeOf } from "../../data/sizeOf.js";
3
+ import { memoryLayoutOf } from "../../data/offsetUtils.js";
4
+ //#region src/core/pipeline/pipelineUtils.ts
5
+ const IndirectOperationToRequiredData = {
6
+ dispatchWorkgroupsIndirect: "3 x u32",
7
+ drawIndirect: "4 x u32",
8
+ drawIndexedIndirect: "3 x u32, i32, u32"
9
+ };
10
+ function validateIndirectBufferSize(bufferSize, offset, requiredBytes, operation) {
11
+ if (offset + requiredBytes > bufferSize) throw new Error(`Buffer too small for ${operation}. Required: ${requiredBytes} bytes at offset ${offset}, but buffer is only ${bufferSize} bytes.`);
12
+ if (offset % 4 !== 0) throw new Error(`Indirect buffer offset must be a multiple of 4. Got: ${offset}`);
13
+ }
14
+ function resolveIndirectOffset(indirectBuffer, start, requiredSize, operation) {
15
+ if (isGPUBuffer(indirectBuffer)) {
16
+ const offset = typeof start === "number" ? start : start?.offset ?? 0;
17
+ validateIndirectBufferSize(indirectBuffer.size, offset, requiredSize, operation);
18
+ return offset;
19
+ }
20
+ const { offset, contiguous } = start ? typeof start === "number" ? {
21
+ offset: start,
22
+ contiguous: requiredSize
23
+ } : start : memoryLayoutOf(indirectBuffer.dataType);
24
+ validateIndirectBufferSize(sizeOf(indirectBuffer.dataType), offset, requiredSize, operation);
25
+ if (contiguous < requiredSize) console.warn(`${operation}: Starting at offset ${offset}, only ${contiguous} contiguous bytes are available before padding. '${operation}' requires ${requiredSize} bytes (${IndirectOperationToRequiredData[operation]}). Reading across padding may result in undefined behavior.`);
26
+ return offset;
27
+ }
28
+ //#endregion
29
+ export { resolveIndirectOffset };
@@ -1,10 +1,11 @@
1
1
  import { TgpuNamable } from "../../shared/meta.js";
2
2
  import { $internal, $resolve } from "../../shared/symbols.js";
3
3
  import { AnyBuiltin, OmitBuiltins } from "../../builtin.js";
4
- import "../querySet/querySet.js";
4
+ import { TgpuQuerySet } from "../querySet/querySet.js";
5
5
  import { ResolvedSnippet } from "../../data/snippet.js";
6
6
  import { LogResources } from "../../tgsl/consoleLog/types.js";
7
7
  import { TgpuSlot } from "../slot/slotTypes.js";
8
+ import { PrimitiveOffsetInfo } from "../../data/offsetUtils.js";
8
9
  import { Timeable, TimestampWritesPriors } from "./timeable.js";
9
10
  import { AnyVertexAttribs } from "../../shared/vertexFormat.js";
10
11
  import { AnyAutoCustoms, AutoFragmentIn, AutoFragmentOut, AutoVertexIn, AutoVertexOut } from "../function/autoIO.js";
@@ -14,7 +15,7 @@ import { RenderFlag } from "../texture/usageExtension.js";
14
15
  import { TgpuVertexLayout } from "../vertexLayout/vertexLayout.js";
15
16
  import { TgpuBindGroup, TgpuBindGroupLayout, TgpuLayoutEntry } from "../../tgpuBindGroupLayout.js";
16
17
  import { ExperimentalTgpuRoot } from "../root/rootTypes.js";
17
- import { IndexFlag, TgpuBuffer, VertexFlag } from "../buffer/buffer.js";
18
+ import { IndexFlag, IndirectFlag, TgpuBuffer, VertexFlag } from "../buffer/buffer.js";
18
19
  import { ResolutionCtx, SelfResolvable } from "../../types.js";
19
20
  import { AnyVecInstance, BaseData, U16, U32, Void, WgslArray, v4f } from "../../data/wgslTypes.js";
20
21
  import { WgslTexture, WgslTextureDepth2d, WgslTextureDepthMultisampled2d } from "../../data/texture.js";
@@ -77,8 +78,24 @@ interface TgpuRenderPipeline<in Targets = never> extends TgpuNamable, SelfResolv
77
78
  withIndexBuffer(buffer: TgpuBuffer<BaseData> & IndexFlag, offsetElements?: number, sizeElements?: number): this & HasIndexBuffer;
78
79
  withIndexBuffer(buffer: GPUBuffer, indexFormat: GPUIndexFormat, offsetBytes?: number, sizeBytes?: number): this & HasIndexBuffer;
79
80
  draw(vertexCount: number, instanceCount?: number, firstVertex?: number, firstInstance?: number): void;
80
- drawIndirect(indirectBuffer: TgpuBuffer<BaseData> | GPUBuffer, indirectOffset?: GPUSize64): void;
81
- drawIndexedIndirect(indirectBuffer: TgpuBuffer<BaseData> | GPUBuffer, indirectOffset?: GPUSize64): void;
81
+ /**
82
+ * Draws primitives using parameters read from a buffer.
83
+ * The buffer must contain 4 consecutive u32 values (vertexCount, instanceCount, firstVertex, firstInstance).
84
+ * To get the correct offset within complex data structures, use `d.memoryLayoutOf(...)`.
85
+ *
86
+ * @param indirectBuffer - Buffer marked with 'indirect' usage containing draw parameters or raw GPUBuffer
87
+ * @param indirectOffset - PrimitiveOffsetInfo pointing to the first draw parameter. If not provided, starts at offset 0. To obtain safe offsets, use `d.memoryLayoutOf(...)`.
88
+ */
89
+ drawIndirect(indirectBuffer: (TgpuBuffer<BaseData> & IndirectFlag) | GPUBuffer, indirectOffset?: PrimitiveOffsetInfo | number): void;
90
+ /**
91
+ * Draws indexed primitives using parameters read from a buffer.
92
+ * The buffer must contain 5 consecutive 32-bit integer values (indexCount u32, instanceCount u32, firstIndex u32, baseVertex i32, firstInstance u32).
93
+ * To get the correct offset within complex data structures, use `d.memoryLayoutOf(...)`.
94
+ *
95
+ * @param indirectBuffer - Buffer marked with 'indirect' usage containing draw parameters or raw GPUBuffer
96
+ * @param indirectOffset - PrimitiveOffsetInfo pointing to the first draw parameter. If not provided, starts at offset 0. To obtain safe offsets, use `d.memoryLayoutOf(...)`.
97
+ */
98
+ drawIndexedIndirect(indirectBuffer: (TgpuBuffer<BaseData> & IndirectFlag) | GPUBuffer, indirectOffset?: PrimitiveOffsetInfo | number): void;
82
99
  }
83
100
  declare namespace TgpuRenderPipeline {
84
101
  interface DescriptorBase {
@@ -250,12 +267,13 @@ type Memo = {
250
267
  };
251
268
  declare class RenderPipelineCore implements SelfResolvable {
252
269
  #private;
253
- readonly options: RenderPipelineCoreOptions;
254
270
  readonly [$internal] = true;
271
+ readonly options: RenderPipelineCoreOptions;
255
272
  private _memo;
256
273
  constructor(options: RenderPipelineCoreOptions);
257
274
  [$resolve](ctx: ResolutionCtx): ResolvedSnippet;
258
275
  toString(): string;
276
+ get performanceCallbackQuerySet(): TgpuQuerySet<"timestamp"> | undefined;
259
277
  unwrap(): Memo;
260
278
  }
261
279
  /**
@@ -8,21 +8,23 @@ import { formatToWGSLType } from "../../data/vertexFormatData.js";
8
8
  import { sizeOf } from "../../data/sizeOf.js";
9
9
  import { isBuiltin } from "../../data/attributes.js";
10
10
  import { namespace } from "../resolve/namespace.js";
11
- import { connectAttributesToShader } from "../vertexLayout/connectAttributesToShader.js";
12
11
  import { isTexture, isTextureView } from "../texture/texture.js";
13
12
  import { isBindGroup, isBindGroupLayout } from "../../tgpuBindGroupLayout.js";
13
+ import { connectAttributesToShader } from "../vertexLayout/connectAttributesToShader.js";
14
14
  import { resolve } from "../../resolutionCtx.js";
15
15
  import { isGPUCommandEncoder, isGPURenderBundleEncoder, isGPURenderPassEncoder } from "./typeGuards.js";
16
16
  import { applyBindGroups, applyVertexBuffers } from "./applyPipelineState.js";
17
17
  import { logDataFromGPU } from "../../tgsl/consoleLog/deserializers.js";
18
18
  import { wgslExtensionToFeatureName, wgslExtensions } from "../../wgslExtensions.js";
19
+ import { resolveIndirectOffset } from "./pipelineUtils.js";
19
20
  import { createWithPerformanceCallback, createWithTimestampWrites, setupTimestampWrites, triggerPerformanceCallback } from "./timeable.js";
20
21
  import { AutoFragmentFn, AutoVertexFn } from "../function/autoIO.js";
21
22
  import { isVertexLayout } from "../vertexLayout/vertexLayout.js";
22
23
  import { connectAttachmentToShader } from "./connectAttachmentToShader.js";
23
24
  import { connectTargetsToShader } from "./connectTargetsToShader.js";
24
-
25
25
  //#region src/core/pipeline/renderPipeline.ts
26
+ const DRAW_INDIRECT_SIZE = 16;
27
+ const DRAW_INDEXED_INDIRECT_SIZE = 20;
26
28
  function INTERNAL_createRenderPipeline(options) {
27
29
  return new TgpuRenderPipelineImpl(new RenderPipelineCore(options), {});
28
30
  }
@@ -78,7 +80,16 @@ var TgpuRenderPipelineImpl = class TgpuRenderPipelineImpl {
78
80
  }
79
81
  withPerformanceCallback(callback) {
80
82
  const internals = this[$internal];
81
- const newPriors = createWithPerformanceCallback(internals.priors, callback, internals.core.options.root);
83
+ if (internals.priors.timestampWrites) return new TgpuRenderPipelineImpl(internals.core, {
84
+ ...internals.priors,
85
+ performanceCallback: callback
86
+ });
87
+ const querySet = internals.core.performanceCallbackQuerySet;
88
+ if (!querySet) {
89
+ console.warn("Performance callback cannot be used because the timestamp-query feature is not enabled on the root.");
90
+ return this;
91
+ }
92
+ const newPriors = createWithPerformanceCallback(internals.priors, callback, querySet);
82
93
  return new TgpuRenderPipelineImpl(internals.core, newPriors);
83
94
  }
84
95
  withTimestampWrites(options) {
@@ -254,22 +265,23 @@ var TgpuRenderPipelineImpl = class TgpuRenderPipelineImpl {
254
265
  priors: internals.priors
255
266
  });
256
267
  }
257
- drawIndirect(indirectBuffer, indirectOffset = 0) {
268
+ drawIndirect(indirectBuffer, indirectOffset) {
258
269
  const internals = this[$internal];
259
270
  const { root } = internals.core.options;
260
- const rawBuffer = isGPUBuffer(indirectBuffer) ? indirectBuffer : root.unwrap(indirectBuffer);
271
+ const rawBuffer = isGPUBuffer(indirectBuffer) ? indirectBuffer : indirectBuffer.buffer;
272
+ const offset = resolveIndirectOffset(indirectBuffer, indirectOffset, DRAW_INDIRECT_SIZE, "drawIndirect");
261
273
  if (internals.priors.externalRenderEncoder) {
262
274
  if (_lastAppliedRender.get(internals.priors.externalRenderEncoder) !== this) {
263
275
  this._applyRenderState(internals.priors.externalRenderEncoder);
264
276
  _lastAppliedRender.set(internals.priors.externalRenderEncoder, this);
265
277
  }
266
- internals.priors.externalRenderEncoder.drawIndirect(rawBuffer, indirectOffset);
278
+ internals.priors.externalRenderEncoder.drawIndirect(rawBuffer, offset);
267
279
  return;
268
280
  }
269
281
  if (internals.priors.externalEncoder) {
270
282
  const pass = this._createRenderPass(internals.priors.externalEncoder);
271
283
  this._applyRenderState(pass);
272
- pass.drawIndirect(rawBuffer, indirectOffset);
284
+ pass.drawIndirect(rawBuffer, offset);
273
285
  pass.end();
274
286
  return;
275
287
  }
@@ -277,7 +289,7 @@ var TgpuRenderPipelineImpl = class TgpuRenderPipelineImpl {
277
289
  const commandEncoder = root.device.createCommandEncoder();
278
290
  const pass = this._createRenderPass(commandEncoder);
279
291
  this._applyRenderState(pass);
280
- pass.drawIndirect(rawBuffer, indirectOffset);
292
+ pass.drawIndirect(rawBuffer, offset);
281
293
  pass.end();
282
294
  root.device.queue.submit([commandEncoder.finish()]);
283
295
  if (logResources) logDataFromGPU(logResources);
@@ -286,24 +298,25 @@ var TgpuRenderPipelineImpl = class TgpuRenderPipelineImpl {
286
298
  priors: internals.priors
287
299
  });
288
300
  }
289
- drawIndexedIndirect(indirectBuffer, indirectOffset = 0) {
301
+ drawIndexedIndirect(indirectBuffer, indirectOffset) {
290
302
  const internals = this[$internal];
291
303
  const { root } = internals.core.options;
292
304
  const rawBuffer = isGPUBuffer(indirectBuffer) ? indirectBuffer : root.unwrap(indirectBuffer);
305
+ const offset = resolveIndirectOffset(indirectBuffer, indirectOffset, DRAW_INDEXED_INDIRECT_SIZE, "drawIndexedIndirect");
293
306
  if (internals.priors.externalRenderEncoder) {
294
307
  if (_lastAppliedRender.get(internals.priors.externalRenderEncoder) !== this) {
295
308
  this._applyRenderState(internals.priors.externalRenderEncoder);
296
309
  this._setIndexBuffer(internals.priors.externalRenderEncoder);
297
310
  _lastAppliedRender.set(internals.priors.externalRenderEncoder, this);
298
311
  }
299
- internals.priors.externalRenderEncoder.drawIndexedIndirect(rawBuffer, indirectOffset);
312
+ internals.priors.externalRenderEncoder.drawIndexedIndirect(rawBuffer, offset);
300
313
  return;
301
314
  }
302
315
  if (internals.priors.externalEncoder) {
303
316
  const pass = this._createRenderPass(internals.priors.externalEncoder);
304
317
  this._applyRenderState(pass);
305
318
  this._setIndexBuffer(pass);
306
- pass.drawIndexedIndirect(rawBuffer, indirectOffset);
319
+ pass.drawIndexedIndirect(rawBuffer, offset);
307
320
  pass.end();
308
321
  return;
309
322
  }
@@ -312,7 +325,7 @@ var TgpuRenderPipelineImpl = class TgpuRenderPipelineImpl {
312
325
  const pass = this._createRenderPass(commandEncoder);
313
326
  this._applyRenderState(pass);
314
327
  this._setIndexBuffer(pass);
315
- pass.drawIndexedIndirect(rawBuffer, indirectOffset);
328
+ pass.drawIndexedIndirect(rawBuffer, offset);
316
329
  pass.end();
317
330
  root.device.queue.submit([commandEncoder.finish()]);
318
331
  if (logResources) logDataFromGPU(logResources);
@@ -324,9 +337,11 @@ var TgpuRenderPipelineImpl = class TgpuRenderPipelineImpl {
324
337
  };
325
338
  var RenderPipelineCore = class {
326
339
  [$internal] = true;
340
+ options;
327
341
  _memo;
328
342
  #latestAutoVertexIn;
329
343
  #latestAutoFragmentOut;
344
+ #performanceCallbackQuerySet;
330
345
  constructor(options) {
331
346
  this.options = options;
332
347
  }
@@ -354,6 +369,10 @@ var RenderPipelineCore = class {
354
369
  toString() {
355
370
  return "renderPipelineCore";
356
371
  }
372
+ get performanceCallbackQuerySet() {
373
+ if (!this.options.root.enabledFeatures.has("timestamp-query")) return;
374
+ return this.#performanceCallbackQuerySet ??= this.options.root.createQuerySet("timestamp", 2);
375
+ }
357
376
  unwrap() {
358
377
  if (this._memo !== void 0) return this._memo;
359
378
  const { root, descriptor: tgpuDescriptor } = this.options;
@@ -466,6 +485,5 @@ function matchUpVaryingLocations(vertexOut = {}, fragmentIn = {}, vertexFnName,
466
485
  function isGPUCanvasContext(value) {
467
486
  return typeof value?.getCurrentTexture === "function";
468
487
  }
469
-
470
488
  //#endregion
471
- export { INTERNAL_createRenderPipeline };
489
+ export { INTERNAL_createRenderPipeline };
@@ -1,6 +1,4 @@
1
1
  import { TgpuQuerySet } from "../querySet/querySet.js";
2
- import "../root/rootTypes.js";
3
-
4
2
  //#region src/core/pipeline/timeable.d.ts
5
3
  interface Timeable {
6
4
  withPerformanceCallback(callback: (start: bigint, end: bigint) => void | Promise<void>): this;
@@ -17,7 +15,6 @@ type TimestampWritesPriors = {
17
15
  endOfPassWriteIndex?: number;
18
16
  };
19
17
  readonly performanceCallback?: (start: bigint, end: bigint) => void | Promise<void>;
20
- readonly hasAutoQuerySet?: boolean;
21
18
  };
22
19
  //#endregion
23
20
  export { Timeable, TimestampWritesPriors };