@aardworx/wombat.rendering 0.19.12 → 0.19.14

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.
@@ -52,6 +52,9 @@ export interface HeapSamplerBinding {
52
52
  readonly name: string;
53
53
  /** WGSL type — "sampler" or "sampler_comparison". */
54
54
  readonly wgslType: string;
55
+ /** Shader-defined sampler state (filter/address) from the IR; the adapter
56
+ * builds the GPUSamplerDescriptor from it, overriding the scene default. */
57
+ readonly state?: { readonly filter: string; readonly addressU: string; readonly addressV: string } | undefined;
55
58
  }
56
59
 
57
60
  export interface HeapEffectSchema {
@@ -90,7 +93,7 @@ export interface FragmentOutputLayout {
90
93
  // and on quota; every failure simply degrades to "recompute".
91
94
 
92
95
  /** Cache-generation stamp for the persistent (localStorage) tier. */
93
- export const HEAP_PERSIST_VERSION = "h1";
96
+ export const HEAP_PERSIST_VERSION = "h2";
94
97
  export const HEAP_PERSIST_PREFIX = "wbt.heapfx.";
95
98
 
96
99
  export function persistKey(version: string, kind: string, contentKey: string): string {
@@ -242,6 +245,7 @@ function buildSchema(iface: ProgramInterface): HeapEffectSchema {
242
245
  }));
243
246
  const samplers: HeapSamplerBinding[] = iface.samplers.map(s => ({
244
247
  name: s.name, wgslType: "sampler",
248
+ ...(s.state !== undefined ? { state: s.state } : {}),
245
249
  }));
246
250
  return { attributes, uniforms, varyings, fragmentOutputs, textures, samplers };
247
251
  }
@@ -713,11 +717,22 @@ fn atlasSampleAtMip(
713
717
  k: u32,
714
718
  uv: vec2<f32>,
715
719
  addrU: u32, addrV: u32,
720
+ filterNearest: u32,
716
721
  ) -> vec4<f32> {
717
722
  let mip_o = atlasMipOriginPx(origin_px, size_px, k);
718
723
  let mip_s = atlasMipSizePx(size_px, k);
719
- let px = atlasAxisAt(uv.x, mip_o.x, mip_s.x, addrU);
720
- let py = atlasAxisAt(uv.y, mip_o.y, mip_s.y, addrV);
724
+ var px = atlasAxisAt(uv.x, mip_o.x, mip_s.x, addrU);
725
+ var py = atlasAxisAt(uv.y, mip_o.y, mip_s.y, addrV);
726
+ // Nearest (point) filtering: the atlas has no per-sub-rect GPUSampler —
727
+ // every sub-rect shares one hardware-linear atlasSampler — so point
728
+ // filtering is done here by snapping the atlas-pixel coord to the texel
729
+ // center. Bilinear evaluated exactly at a texel center returns that
730
+ // single texel, i.e. nearest. (Shader-defined sampler state: the
731
+ // mag/min filter bits ride in formatBits, see samplerStateBits.)
732
+ if (filterNearest == 1u) {
733
+ px = floor(px) + 0.5;
734
+ py = floor(py) + 0.5;
735
+ }
721
736
  let atlasUv = vec2<f32>(px, py) / ${atlasPageSizeConst()}.0;
722
737
  ${generateAtlasSwitch()}
723
738
  return vec4<f32>(0.0);
@@ -732,6 +747,10 @@ fn atlasSample(
732
747
  let numMips = (formatBits >> 1u) & 0x7u;
733
748
  let addrU = (formatBits >> 4u) & 0x3u;
734
749
  let addrV = (formatBits >> 6u) & 0x3u;
750
+ // mag/min filter bits (samplerStateBits): linear=1, nearest=0. The atlas
751
+ // filters in software, so the mag bit drives a single texel-snap flag for
752
+ // both axes — enough to distinguish MinMagMipPoint from MinMagMipLinear.
753
+ let filterNearest = u32(((formatBits >> 8u) & 0x3u) == 0u);
735
754
  // LOD on pre-wrap UV. dpdx/dpdy on the wrapped value spikes at the
736
755
  // fract/mirror seam (discontinuity → bogus huge derivative → tiny
737
756
  // mip selected → blurred band). Multiply by size_px to get
@@ -744,9 +763,9 @@ fn atlasSample(
744
763
  let lo = u32(floor(lod));
745
764
  let hi = min(lo + 1u, max(numMips, 1u) - 1u);
746
765
  let t = lod - f32(lo);
747
- let a = atlasSampleAtMip(pageRef, format, origin_px, size_px, lo, uv, addrU, addrV);
766
+ let a = atlasSampleAtMip(pageRef, format, origin_px, size_px, lo, uv, addrU, addrV, filterNearest);
748
767
  if (numMips <= 1u) { return a; }
749
- let b = atlasSampleAtMip(pageRef, format, origin_px, size_px, hi, uv, addrU, addrV);
768
+ let b = atlasSampleAtMip(pageRef, format, origin_px, size_px, hi, uv, addrU, addrV, filterNearest);
750
769
  return mix(a, b, t);
751
770
  }
752
771
  `;