Skip to content

feat: Add missing std functions - #2925

Open
reczkok wants to merge 1 commit into
mainfrom
impr/add-missing-std
Open

feat: Add missing std functions#2925
reczkok wants to merge 1 commit into
mainfrom
impr/add-missing-std

Conversation

@reczkok

@reczkok reczkok commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI lite review requested due to automatic review settings August 26, 2026 14:02
@github-actions

Copy link
Copy Markdown

pkg.pr.new

packages
Ready to be installed by your favorite package manager ⬇️

https://pkg.pr.new/software-mansion/TypeGPU/typegpu@250fdd9105ffaed02a286febd4bd9e5e1df16a08

benchmark
view benchmark

commit
view commit

@github-actions

Copy link
Copy Markdown

Bundle size comparison (import * as ... in PR vs import * as ... in target):

🟢 Decreased ➖ Unchanged 🔴 Increased (max 17.74%) ❔ Unknown
0 276 49 23

import * as ... in PR vs import * as ... in target (did bundle size increase?):

Click to reveal the results table (72 entries).
Test tsdown
std_textureBarrier.ts 20.86 kB ($${\color{red}+17.7\%}$$)
std_atomicLoad.ts 20.85 kB ($${\color{red}+17.7\%}$$)
std_atomicStore.ts 20.85 kB ($${\color{red}+17.7\%}$$)
std_atomicAdd.ts 20.86 kB ($${\color{red}+17.7\%}$$)
std_atomicAnd.ts 20.86 kB ($${\color{red}+17.7\%}$$)
std_atomicMax.ts 20.86 kB ($${\color{red}+17.7\%}$$)
std_atomicMin.ts 20.86 kB ($${\color{red}+17.7\%}$$)
std_atomicOr.ts 20.86 kB ($${\color{red}+17.7\%}$$)
std_atomicSub.ts 20.86 kB ($${\color{red}+17.7\%}$$)
std_atomicXor.ts 20.86 kB ($${\color{red}+17.7\%}$$)
std_storageBarrier.ts 20.86 kB ($${\color{red}+17.7\%}$$)
std_workgroupBarrier.ts 20.85 kB ($${\color{red}+17.7\%}$$)
std_pack2x16float.ts 40.86 kB ($${\color{red}+8.1\%}$$)
std_pack4x8unorm.ts 40.86 kB ($${\color{red}+8.1\%}$$)
std_unpack2x16float.ts 40.86 kB ($${\color{red}+8.1\%}$$)
std_unpack4x8unorm.ts 40.86 kB ($${\color{red}+8.1\%}$$)
STATIC_std.ts 103.68 kB ($${\color{red}+6.3\%}$$)
std_textureDimensions.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureGather.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureLoad.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureSample.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureSampleBaseClampToEdge.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureSampleBias.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureSampleCompare.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureSampleCompareLevel.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureSampleGrad.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureSampleLevel.ts 28.99 kB ($${\color{red}+4.3\%}$$)
std_textureStore.ts 28.99 kB ($${\color{red}+4.3\%}$$)
STATIC_allImports.ts 305.05 kB ($${\color{red}+2.1\%}$$)
STATIC_tgpu.ts 275.56 kB ($${\color{red}+1.1\%}$$)
tgpu_fn.ts 275.56 kB ($${\color{red}+1.1\%}$$)
tgpu_init.ts 275.56 kB ($${\color{red}+1.1\%}$$)
tgpu_lazy.ts 275.56 kB ($${\color{red}+1.1\%}$$)
tgpu_slot.ts 275.56 kB ($${\color{red}+1.1\%}$$)
tgpu_const.ts 275.56 kB ($${\color{red}+1.1\%}$$)
tgpu_unroll.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_resolve.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_accessor.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_comptime.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_vertexFn.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_computeFn.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_fragmentFn.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_privateVar.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_vertexLayout.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_workgroupVar.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_initFromDevice.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_bindGroupLayout.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_mutableAccessor.ts 275.57 kB ($${\color{red}+1.1\%}$$)
tgpu_resolveWithContext.ts 275.58 kB ($${\color{red}+1.1\%}$$)
std_atomicCompareExchangeWeak.ts 20.85 kB
std_atomicExchange.ts 20.85 kB
std_pack2x16snorm.ts 40.86 kB
std_pack2x16unorm.ts 40.86 kB
std_pack4x8snorm.ts 40.86 kB
std_pack4xI8.ts 40.86 kB
std_pack4xI8Clamp.ts 40.86 kB
std_pack4xU8.ts 40.86 kB
std_pack4xU8Clamp.ts 40.86 kB
std_quadBroadcast.ts 16.56 kB
std_quadSwapDiagonal.ts 16.57 kB
std_quadSwapX.ts 16.57 kB
std_quadSwapY.ts 16.57 kB
std_textureGatherCompare.ts 28.99 kB
std_textureNumLayers.ts 28.99 kB
std_textureNumLevels.ts 28.99 kB
std_textureNumSamples.ts 28.99 kB
std_unpack2x16snorm.ts 40.86 kB
std_unpack2x16unorm.ts 40.86 kB
std_unpack4x8snorm.ts 40.86 kB
std_unpack4xI8.ts 40.86 kB
std_unpack4xU8.ts 40.86 kB
std_workgroupUniformLoad.ts 20.85 kB

import { ... } in PR vs import * as ... in PR (is the library tree-Shakeable?):

Test tsdown
tgpu_init.ts 266.03 kB ($${\color{green}-3.5\%}$$)
tgpu_initFromDevice.ts 265.49 kB ($${\color{green}-3.7\%}$$)
tgpu_resolve.ts 161.75 kB ($${\color{green}-41.3\%}$$)
tgpu_resolveWithContext.ts 161.68 kB ($${\color{green}-41.3\%}$$)
tgpu_bindGroupLayout.ts 62.32 kB ($${\color{green}-77.4\%}$$)
tgpu_mutableAccessor.ts 57.04 kB ($${\color{green}-79.3\%}$$)
tgpu_accessor.ts 57.04 kB ($${\color{green}-79.3\%}$$)
tgpu_privateVar.ts 55.73 kB ($${\color{green}-79.8\%}$$)
tgpu_workgroupVar.ts 55.73 kB ($${\color{green}-79.8\%}$$)
tgpu_const.ts 55.15 kB ($${\color{green}-80.0\%}$$)
tgpu_lazy.ts 54.95 kB ($${\color{green}-80.1\%}$$)
tgpu_fragmentFn.ts 39.68 kB ($${\color{green}-85.6\%}$$)
tgpu_fn.ts 39.62 kB ($${\color{green}-85.6\%}$$)
tgpu_vertexFn.ts 39.50 kB ($${\color{green}-85.7\%}$$)
tgpu_computeFn.ts 39.20 kB ($${\color{green}-85.8\%}$$)
tgpu_vertexLayout.ts 28.33 kB ($${\color{green}-89.7\%}$$)
tgpu_comptime.ts 15.93 kB ($${\color{green}-94.2\%}$$)
tgpu_unroll.ts 1.75 kB ($${\color{green}-99.4\%}$$)
tgpu_slot.ts 1.70 kB ($${\color{green}-99.4\%}$$)

If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.

@github-actions

Copy link
Copy Markdown

Resolution Time Benchmark

---
config:
  themeVariables:
    xyChart:
      plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
  title "Random Branching (🔴 PR | 🔵 main | 🟢 release)"
  x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
  y-axis "time (ms)"
  line [0.88, 1.77, 4.04, 5.27, 6.33, 11.13, 21.27, 21.82]
  line [0.85, 1.79, 3.75, 5.59, 6.72, 11.76, 20.51, 21.20]
  line [0.82, 1.65, 3.26, 5.94, 6.33, 9.31, 19.55, 22.05]
Loading
---
config:
  themeVariables:
    xyChart:
      plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
  title "Linear Recursion (🔴 PR | 🔵 main | 🟢 release)"
  x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
  y-axis "time (ms)"
  line [0.32, 0.51, 0.64, 0.72, 1.02, 1.06, 1.26, 1.45]
  line [0.26, 0.47, 0.61, 0.76, 1.18, 1.04, 1.27, 1.42]
  line [0.31, 0.46, 0.56, 0.71, 1.00, 1.02, 1.16, 1.34]
Loading
---
config:
  themeVariables:
    xyChart:
      plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
  title "Full Tree (🔴 PR | 🔵 main | 🟢 release)"
  x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
  y-axis "time (ms)"
  line [0.81, 2.08, 3.49, 6.23, 10.92, 23.36, 49.02, 100.29]
  line [0.78, 1.84, 3.16, 6.58, 10.52, 23.09, 48.96, 99.39]
  line [0.82, 1.83, 2.98, 5.52, 10.46, 23.09, 48.13, 96.34]
Loading

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands TypeGPU’s std surface area by adding several missing WGSL builtins (texture queries, gather-compare, quad ops, additional packing/unpacking, and atomic helpers) and introduces snapshot/unit tests to validate codegen and typing.

Changes:

  • Add texture query builtins (textureNumLayers/Levels/Samples) and textureGatherCompare, with coverage tests.
  • Add quad subgroup builtins (quadBroadcast, quadSwapDiagonal/X/Y) and atomic builtins (atomicExchange, atomicCompareExchangeWeak, workgroupUniformLoad) with tests.
  • Extend packing std with additional WGSL pack/unpack builtins and broaden packing test coverage.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/typegpu/tests/std/texture/textureQueries.test.ts Adds snapshot/type tests for texture query and gather-compare builtins.
packages/typegpu/tests/std/quad.test.ts Adds snapshot/type tests for quad subgroup builtins (requires subgroups).
packages/typegpu/tests/std/packing.test.ts Adds tests for new pack/unpack functions and rounding/clamping expectations.
packages/typegpu/tests/std/atomic.test.ts Adds snapshot/type tests for new atomic and workgroupUniformLoad builtins.
packages/typegpu/src/std/texture.ts Implements missing texture query builtins and textureGatherCompare codegen/signatures.
packages/typegpu/src/std/quad.ts Implements quad subgroup builtins via dualImpl.
packages/typegpu/src/std/packing.ts Refactors packing internals and adds multiple missing WGSL pack/unpack builtins.
packages/typegpu/src/std/index.ts Re-exports the newly added std functions.
packages/typegpu/src/std/atomic.ts Adds atomicExchange, atomicCompareExchangeWeak, and workgroupUniformLoad.
Suppressed comments (3)

packages/typegpu/src/std/packing.ts:89

  • pack2x16unorm uses Math.floor(0.5 + x) rounding, which disagrees with the project’s WGSL round (ties-to-even) semantics (see cpuRound in std/numeric.ts). This can produce different packed results for values that land exactly on .5 after scaling.
  normalImpl: (e: v2f): number => {
    const x = Math.floor(0.5 + 65535 * clampScalar(e.x, 0, 1));
    const y = Math.floor(0.5 + 65535 * clampScalar(e.y, 0, 1));
    return writePacked((writer) => {
      writer.writeUint16(x);

packages/typegpu/src/std/packing.ts:231

  • pack4x8snorm uses Math.floor(0.5 + x) rounding, which doesn’t implement WGSL round (ties-to-even) semantics used elsewhere in the codebase (cpuRound in std/numeric.ts). This is particularly visible for negative .5 cases (e.g. -63.5), where the current logic rounds toward zero instead of to the even integer.
export const pack4x8snorm = dualImpl({
  name: 'pack4x8snorm',
  normalImpl: (e: v4f): number =>
    writePacked((writer) => {
      writer.writeInt8(Math.floor(0.5 + 127 * clampScalar(e.x, -1, 1)));
      writer.writeInt8(Math.floor(0.5 + 127 * clampScalar(e.y, -1, 1)));
      writer.writeInt8(Math.floor(0.5 + 127 * clampScalar(e.z, -1, 1)));
      writer.writeInt8(Math.floor(0.5 + 127 * clampScalar(e.w, -1, 1)));
    }),

packages/typegpu/src/std/packing.ts:212

  • pack4x8unorm currently rounds with Math.floor(0.5 + x), which isn’t ties-to-even and can disagree with WGSL round semantics used elsewhere in the codebase (cpuRound in std/numeric.ts). This can yield different results for values that scale to N + 0.5 where N is even/odd (e.g. 2.5).
export const pack4x8unorm = dualImpl({
  name: 'pack4x8unorm',
  normalImpl: (e: v4f): number =>
    writePacked((writer) => {
      writer.writeUint8(Math.floor(0.5 + 255 * clampScalar(e.x, 0, 1)));
      writer.writeUint8(Math.floor(0.5 + 255 * clampScalar(e.y, 0, 1)));
      writer.writeUint8(Math.floor(0.5 + 255 * clampScalar(e.z, 0, 1)));
      writer.writeUint8(Math.floor(0.5 + 255 * clampScalar(e.w, 0, 1)));

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 66 to +70
normalImpl: (e: v2f): number => {
const buffer = new ArrayBuffer(4);
const writer = new TB.BufferWriter(buffer);
writeFloat16(writer, e.x);
writeFloat16(writer, e.y);
const reader = new TB.BufferReader(buffer);
return u32(reader.readUint32());
const x = Math.floor(0.5 + 32767 * clampScalar(e.x, -1, 1));
const y = Math.floor(0.5 + 32767 * clampScalar(e.y, -1, 1));
return writePacked((writer) => {
writer.writeInt16(x);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Comment thread packages/typegpu/tests/std/packing.test.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Atomics (std/atomic.ts) — adds workgroupUniformLoad, atomicExchange, and atomicCompareExchangeWeak (returning an abstruct result with old_value/exchanged), all consistent with the existing atomicOpSignature/isAtomic/atomicNormalError helpers.
  • Packing (std/packing.ts) — replaces per-call ArrayBuffer churn with shared packedBuffer/packedWriter/packedReader helpers (explicit little endianness) and adds pack/unpack2x16(snorm|unorm), pack/unpack4x8(snorm|unorm), pack/unpack4xI8, pack/unpack4xU8, and the two Clamp variants.
  • Quad (std/quad.ts, new) — quadBroadcast (2nd arg validated as i32/u32 via unify), quadSwapDiagonal, quadSwapX, quadSwapY.
  • Texture (std/texture.ts) — textureNumLayers/textureNumLevels/textureNumSamples with typed texture-category unions, and textureGatherCompare (array layer index coerced to [u32, i32], mirroring the existing textureGather signature).
  • Exports (std/index.ts) — all new builtins exported.
  • Tests — inline WGSL snapshots plus if (false) expectTypeOf assertions for atomics, quad, packing, and texture queries; all 9 pass.

I hand-verified the pack arithmetic (little-endian byte order, snorm -1 → -max symmetric mapping via coefficient 32767/127, clamp semantics, and writeInt8/writeUint8 wraparound for the non-clamp variants) against the WGSL spec and the expected values in the tests — all consistent, and the GPU codegenImpl emits the corresponding WGSL builtins.

ℹ️ Piggy-back notes for the author (nothing blocking)

  • Forcing little endianness in the shared helpers is actually a correctness fix: the pre-existing pack2x16float/unpack* used new TB.BufferWriter(buffer) with the system default endianness, which diverges from WGSL's little-endian packing on a big-endian host. No-op on the (effectively universal) little-endian case.
  • The CPU pack* rounding uses Math.round/floor(0.5 + x) (round-half-up), which can differ from WGSL's round-to-nearest-ties-to-even at exact .5 boundary values — so CPU and GPU results can disagree on that narrow input set. This matches an existing repo-wide known convention (jsPolyfills.ts already notes the JS/WGSL round divergence), so it's fine to leave as-is.

ℹ️ Nitpicks

  • std/quad.ts redeclares IdentityNumOrVec, which already exists in std/subgroup.ts — harmless duplication, but worth hoisting to a shared location if more quad-mirroring subgroup APIs land later.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants