Skip to content

feat: Immediates - #2812

Open
reczkok wants to merge 2 commits into
mainfrom
feat/tgpu-immediates
Open

feat: Immediates#2812
reczkok wants to merge 2 commits into
mainfrom
feat/tgpu-immediates

Conversation

@reczkok

@reczkok reczkok commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

github-actions Bot commented Aug 8, 2026

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@3ed038b64b8d0eff6cac97360d16431f7df0ffdd
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/gl@3ed038b64b8d0eff6cac97360d16431f7df0ffdd

benchmark
view benchmark

commit
view commit

@github-actions

github-actions Bot commented Aug 8, 2026

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.89, 1.68, 3.58, 5.27, 6.47, 10.65, 20.33, 20.24]
  line [0.84, 1.68, 3.76, 5.58, 6.85, 10.79, 20.66, 22.56]
  line [0.88, 1.70, 3.67, 5.85, 6.03, 10.28, 21.53, 21.40]
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.28, 0.47, 0.66, 0.77, 0.99, 1.09, 1.24, 1.41]
  line [0.32, 0.48, 0.64, 0.70, 0.92, 1.00, 1.18, 1.34]
  line [0.27, 0.42, 0.61, 0.71, 0.93, 1.05, 1.23, 1.39]
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.73, 2.02, 3.05, 5.98, 10.63, 22.51, 48.64, 99.14]
  line [0.83, 1.94, 2.96, 5.85, 10.88, 23.47, 47.52, 97.19]
  line [0.83, 1.98, 3.21, 5.79, 10.43, 22.55, 49.04, 96.74]
Loading

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

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

🟢 Decreased ➖ Unchanged 🔴 Increased (max 1.77%) ❔ Unknown
0 39 286 0

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

Test tsdown
STATIC_tgpu.ts 277.66 kB ($${\color{red}+1.8\%}$$)
tgpu_initFromDevice.ts 267.04 kB ($${\color{red}+1.6\%}$$)
tgpu_init.ts 267.58 kB ($${\color{red}+1.6\%}$$)
STATIC_allImports.ts 303.91 kB ($${\color{red}+1.6\%}$$)
d_ref.ts 5.03 kB ($${\color{red}+0.9\%}$$)

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

@reczkok
reczkok force-pushed the feat/tgpu-immediates branch from dbf4cea to 9af8a36 Compare August 8, 2026 13:57
@iwoplaza iwoplaza linked an issue Aug 12, 2026 that may be closed by this pull request
@reczkok
reczkok force-pushed the feat/tgpu-immediates branch from 868be67 to e991685 Compare September 1, 2026 23:42
@reczkok
reczkok marked this pull request as ready for review September 1, 2026 23:45
Copilot AI lite review requested due to automatic review settings September 1, 2026 23:45

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.

🟡 Changes recommended

Immediate WGSL emission/validation is incomplete (extension directive handling and size/limit validation), which can cause runtime shader/layout failures.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds experimental “immediates” support to TypeGPU via tgpu['~unstable'].immediateVar, integrating WebGPU’s var<immediate> / pass.setImmediates workflow into resolution, pipelines, pass state, serialization, and docs.

Changes:

  • Introduces immediateVar resource type (schema validation, resolution-time constraints, snapshots/caching, serialization “souls”).
  • Plumbs immediate usage through resolution and pipeline compilation (pipeline layout immediateSize, draw/dispatch-time setImmediates writes, snapshot dedup behavior).
  • Adds extensive test coverage and documentation for immediates and fallback patterns.
File summaries
File Description
packages/typegpu/tests/tgsl/letDeclaration.test.ts Adds regression test for disallowing handle-space aliasing in const declarations.
packages/typegpu/tests/serial.test.ts Verifies immediate vars and pipeline-held immediate data serialize/restore correctly.
packages/typegpu/tests/immediates.test.ts New test suite covering resolution, validation, runtime writes, overrides, caching, and accessors.
packages/typegpu/src/wgslExtensions.ts Adds constants for WGSL language extensions (e.g. immediate_address_space).
packages/typegpu/src/types.ts Extends ResolutionCtx with registerImmediate to enforce 1 immediate per module.
packages/typegpu/src/tgsl/wgslGenerator.ts Adds immediate address space support; improves error for invalid pointer aliasing; blocks immediate mutation.
packages/typegpu/src/tgsl/shaderGenerator.ts Expands variable scope typing to include immediate.
packages/typegpu/src/tgpuUnstable.ts Exports immediateVar from the unstable barrel.
packages/typegpu/src/serial/restore.ts Adds restore support for immediate-var souls.
packages/typegpu/src/resolutionCtx.ts Tracks and returns usedImmediate; enforces single immediate var per shader module.
packages/typegpu/src/indexNamedExports.ts Exposes MissingImmediatesError, isImmediateVar, and TgpuImmediateVar publicly.
packages/typegpu/src/errors.ts Adds MissingImmediatesError with guidance on providing values.
packages/typegpu/src/data/wgslTypes.ts Adds immediate to AddressSpace.
packages/typegpu/src/data/snippet.ts Adds immediate origin and pointer params mapping.
packages/typegpu/src/core/slot/slotTypes.ts Allows immediates to fulfill accessor/slot inputs.
packages/typegpu/src/core/root/rootTypes.ts Adds enabledWgslLanguageFeatures API for language-feature detection.
packages/typegpu/src/core/root/init.ts Implements enabledWgslLanguageFeatures via navigator.gpu.wgslLanguageFeatures.
packages/typegpu/src/core/pipeline/renderPipeline.ts Supports pipeline-held immediates, soul/priors plumbing, and immediateSize in layout creation.
packages/typegpu/src/core/pipeline/priors.ts Marks immediatesMap as transferable prior state.
packages/typegpu/src/core/pipeline/drawState.ts Adds immediate snapshot state + write/dedup behavior for render/compute passes.
packages/typegpu/src/core/pipeline/computePipeline.ts Supports pipeline-held immediates, soul/priors plumbing, and immediateSize in layout creation.
packages/typegpu/src/core/immediate/immediateVar.ts Implements immediateVar, schema validation, snapshots, caching, and usage validation.
packages/typegpu/src/core/commandEncoder/renderPass.ts Adds typed pass.setImmediates(immediate, value) and resets immediate cache on executeBundles.
packages/typegpu/src/core/commandEncoder/computePass.ts Adds typed pass.setImmediates(immediate, value) for compute passes.
packages/typegpu-testing-utility/src/extendedIt.ts Extends mocks to include setImmediates and wgslLanguageFeatures.
packages/typegpu-gl/tests/glslGenerator.test.ts Adds test ensuring GLSL generation rejects immediates.
apps/typegpu-docs/src/content/docs/apis/pipelines.mdx Documents immediates API, performance notes, constraints, and feature-detection fallback.
apps/typegpu-docs/src/content/docs/apis/accessors.mdx Documents immediates as an accessor fulfillment option + updates comparison table.
Review details
  • Files reviewed: 28/28 changed files
  • Comments generated: 3
  • Review effort level: Lite

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

Comment thread packages/typegpu/src/core/pipeline/computePipeline.ts
Comment thread packages/typegpu/src/core/pipeline/renderPipeline.ts
Comment thread packages/typegpu/src/core/immediate/immediateVar.ts
@reczkok
reczkok force-pushed the feat/tgpu-immediates branch from e991685 to 3ed038b Compare September 1, 2026 23:56

@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.

Important

Two things worth addressing before merge: the schema-size constraints are documented but never enforced (cryptic browser OperationError/GPU validation errors for valid-looking schemas like d.f16), and restored pipeline souls can silently substitute the default immediate value when a host serializer doesn't preserve object identity across the soul graph.

Reviewed changes

  • immediateVar core — new TgpuImmediateVar type (var<immediate> codegen, $gpuValueOf/$ access), schema validation rejecting arrays/atomics/booleans, capture-at-provide-time snapshots with a verbatim byte-copy path for typed arrays, default values, and MissingImmediatesError.
  • Pass/pipeline state wiringpass.setImmediates and pipeline.with(immediate, value) with a shared-snapshot + (identity, generation) dedup cache inside the typed draw/dispatch state machine (raw-accessed passes and executeBundles handled), immediateSize threaded into createPipelineLayout.
  • Single-immediate-per-shader rule — enforced in ResolutionCtx.registerImmediate (stricter than WGSL's per-entry-point limit; deliberate and tested).
  • Serialization/restore + feature detectionimmediate-var soul restorer, immediatesMap as a transferable prior, root.enabledWgslLanguageFeatures.
  • Docs/tests — accessors + pipelines docs, GLSL rejection, ~50 mock and snapshot tests including struct-padding immediateSize.

⚠️ Restored pipeline souls silently swap pipeline-held immediates for the default

INTERNAL_restoreRenderPipeline/INTERNAL_restoreComputePipeline rebuild usedImmediate (into the core memo) and the immediatesMap keys (new Map(soul.immediates)) from two separate points in the transferred soul graph. When a host serializer re-claims each nested TgpuImmediateVarSoul independently — exactly the model of the repo's own deepRoundTrip harness — the two decode to distinct instances, state.immediates.get(memo.usedImmediate) misses, and writeImmediates falls back to defaultSnapshots: the pipeline-provided value is silently replaced by the default, or the draw throws MissingImmediatesError when there is no default. Bind groups suffer the same split but fail loudly (MissingBindGroupsError); immediates are the first pipeline-held state that degrades silently. The new serial test round-trips the pipeline only by reference (roundTrip), so the split is unpinned.

Technical details
# Restore identity split between `usedImmediate` and `immediatesMap` keys

## Affected sites
- packages/typegpu/src/serial/restore.ts — `'immediate-var': (soul) => immediateVar(...)` recreates a fresh instance per occurrence.
- packages/typegpu/src/core/pipeline/computePipeline.ts:193,197 (`INTERNAL_restoreComputePipeline`): `usedImmediate: soul.usedImmediate` and `immediatesMap: new Map(soul.immediates)` are rebuilt as separate instances.
- packages/typegpu/src/core/pipeline/renderPipeline.ts:397,401 (same pattern for render pipelines).
- packages/typegpu/src/core/immediate/immediateVar.ts:192-196 (`writeImmediates`): `snapshots.get(immediate) ?? defaultSnapshots.get(immediate)` — the map miss silently degrades to the default (or throws `MissingImmediatesError`).

## Required outcome
- After `restoreResource` of a pipeline that holds `.with(immediate, value)`, drawing/dispatching it must write the same bytes it held before the transfer.
- When identity cannot be preserved, degrade loudly (throw) rather than silently substituting the default.

## Suggested approach
- During restore, key the `immediatesMap` with the same instance used for `memo.usedImmediate` (e.g. rebuild the map from `soul.immediates` but re-keyed by the restored `usedImmediate` on a match, or store the map keyed by an identity that survives transfer, like the schema).
- Add a `deepRoundTrip`-style test (serial.test.ts:38 `deepRoundTrip`) for a pipeline holding immediates that asserts the written bytes match the pipeline-held value even when the var appears in several soul fields.

## Open questions for the human
- Does the React Native serialization path (packages/typegpu-react/src/react-native/serialization/register-serializables.ts + transfer-cache) actually preserve object identity across claimed resources, or does it exhibit the split? If it preserves identity, this is latent rather than live, but a non-deduping serializer still corrupts silently.

ℹ️ Nitpicks

  • In setImmediateSnapshot, a typed array shorter than the schema skips the fast path and goes through writeToArrayBuffer, whose calculateOffsets treats the short input as fully consuming its own bytes — it copies fewer bytes with no warning, leaving stale tail bytes in the reused snapshot buffer (longer inputs do get the logger.warn). Asymmetric; consider warning on short inputs too. (immediateVar.ts:149-165)

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

);
}

return sizeOf(immediate.dataType);

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.

The schema-size constraints documented in this PR ("size must be a multiple of 4 bytes", "limited by the device's maxImmediateSize") are never enforced. assertValidImmediateSchema accepts d.f16 (sizeOf 2) and d.vec3h (6), so immediateVar(d.f16) constructs happily and only fails later, cryptically: immediateSize not a multiple of 4 / over the limit is a createPipelineLayout validation error, and a non-multiple-of-4 setImmediates data size throws a raw browser OperationError at draw time. validateImmediateUsage already receives the root with device here, so both checks are cheap to add at pipeline creation, and the construction-time % 4 check gives the same friendly early failure the array/atomic/bool checks provide.

@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.

Reviewed changes (incremental since e991685)

  • Docs cleanup — removed the .$name('colorImmediate') / .$name('viewProj') calls from the accessors and fallback examples in accessors.mdx/pipelines.mdx, matching the rest of the snippets (errors still fall back to <unnamed>, so the dropped names don't lose anything).

No new issues in this delta; the two findings from the full review stand.

Pullfrog  | Fix it ➔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.

[RFC] feat: Immediates

2 participants