@woosh/meep-engine 3.31.0 → 3.33.0

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 (117) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/collection/table/RowFirstTable.d.ts +8 -0
  4. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  5. package/src/core/collection/table/RowFirstTable.js +40 -11
  6. package/src/engine/graphics/ecs/sprite/Sprite.d.ts +3 -0
  7. package/src/engine/graphics/ecs/sprite/Sprite.d.ts.map +1 -1
  8. package/src/engine/graphics/ecs/sprite/Sprite.js +3 -0
  9. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts +3 -0
  10. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
  11. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +3 -0
  12. package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
  13. package/src/engine/graphics3/DebugDrawSystem.js +6 -2
  14. package/src/engine/graphics3/PathDisplaySystem.d.ts.map +1 -1
  15. package/src/engine/graphics3/PathDisplaySystem.js +311 -307
  16. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  17. package/src/shade/RENDERER_CONTRACT.md +15 -2
  18. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +5 -0
  19. package/src/shade/device/ShadeGPUCommandContext.d.ts +15 -2
  20. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  21. package/src/shade/device/ShadeGPUCommandContext.js +154 -25
  22. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts +20 -3
  23. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
  24. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +21 -3
  25. package/src/shade/renderer/GraphicsContext.d.ts +20 -1
  26. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  27. package/src/shade/renderer/GraphicsContext.js +105 -52
  28. package/src/shade/renderer/Renderer.d.ts +19 -4
  29. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  30. package/src/shade/renderer/Renderer.js +113 -2
  31. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +10 -7
  32. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  33. package/src/shade/renderer/animation/GPUAnimationManager.js +147 -45
  34. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts +6 -5
  35. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts.map +1 -1
  36. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.js +241 -240
  37. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts +62 -2
  38. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts.map +1 -1
  39. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.js +306 -38
  40. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts +60 -0
  41. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts.map +1 -0
  42. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.js +202 -0
  43. package/src/shade/renderer/buffer/GPUUploadBlock.d.ts +68 -0
  44. package/src/shade/renderer/buffer/GPUUploadBlock.d.ts.map +1 -0
  45. package/src/shade/renderer/buffer/GPUUploadBlock.js +97 -0
  46. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts +2 -1
  47. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts.map +1 -1
  48. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.js +19 -17
  49. package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.d.ts +70 -0
  50. package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.d.ts.map +1 -0
  51. package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.js +257 -0
  52. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts +20 -7
  53. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts.map +1 -1
  54. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +39 -41
  55. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts +6 -20
  56. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts.map +1 -1
  57. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +42 -36
  58. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts +2 -1
  59. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts.map +1 -1
  60. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js +4 -3
  61. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts +4 -3
  62. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts.map +1 -1
  63. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.js +7 -4
  64. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts +14 -15
  65. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts.map +1 -1
  66. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js +49 -83
  67. package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts +19 -3
  68. package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts.map +1 -1
  69. package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +26 -6
  70. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts +2 -1
  71. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts.map +1 -1
  72. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.js +12 -6
  73. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts +3 -2
  74. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts.map +1 -1
  75. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +21 -13
  76. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts +5 -0
  77. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +19 -0
  79. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  80. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  81. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +3 -1
  82. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -1
  83. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +3 -1
  84. package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.d.ts.map +1 -1
  85. package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.js +134 -88
  86. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
  87. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +57 -26
  88. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  89. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +28 -20
  90. package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts +38 -0
  91. package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts.map +1 -0
  92. package/src/shade/renderer/rasterize/graph_clear_raster_targets.js +105 -0
  93. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +20 -0
  94. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts +1 -1
  95. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  96. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +21 -1
  97. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  98. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +12 -20
  99. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts +2 -1
  100. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts.map +1 -1
  101. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.js +15 -28
  102. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  103. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +8 -1
  104. package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts +0 -73
  105. package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts.map +0 -1
  106. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts +0 -59
  107. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts.map +0 -1
  108. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts +0 -22
  109. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts.map +0 -1
  110. package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts +0 -26
  111. package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts.map +0 -1
  112. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts +0 -25
  113. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts.map +0 -1
  114. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts +0 -26
  115. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts.map +0 -1
  116. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts +0 -29
  117. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts.map +0 -1
@@ -200,8 +200,8 @@ export class GPUAnimationManager {
200
200
  *
201
201
  * Lazily allocated on first {@link add_skin}; both grow together
202
202
  * by doubling. After a grow both buffers are zero-initialised and
203
- * {@link #first_frame_skin_matrices} is set so the next prep
204
- * dispatch seeds the "previous" buffer with a copy of the freshly
203
+ * {@link #skin_matrix_seed_all} is set so the next prep dispatch
204
+ * seeds all of the "previous" buffer with a copy of the freshly
205
205
  * written "current" — without this, the first velocity readback
206
206
  * after a grow would interpolate against zero matrices.
207
207
  *
@@ -217,15 +217,31 @@ export class GPUAnimationManager {
217
217
  #skin_matrices_current_index = 0;
218
218
 
219
219
  /**
220
- * When true, the next prep dispatch will copy the freshly-written
221
- * "current" buffer into the "previous" buffer at the end of the
222
- * pass — set when a run of joints is handed out, when a pending
223
- * skin's joints are named, and when the buffers grow, so the first
224
- * velocity computation over those rows has matching prev/current
225
- * matrices (zero velocity).
220
+ * The runs of matrix rows the next prep dispatch seeds "previous" from "current" over, each
221
+ * `[first_row, count]`: a run handed out, and a pending skin's run whose joints were just
222
+ * named. The frame before either is not a pose — "previous" over those rows holds zeros, or
223
+ * the last pose of a skin that had them — so the first velocity read over them has to see
224
+ * matching matrices, which is zero velocity.
225
+ *
226
+ * Only those rows: a settled skin's rows of "previous" hold its pose last frame, which is what
227
+ * its motion is measured from.
228
+ *
229
+ * A skin given back takes its queued runs with it ({@link unregister_skin}), so every run here
230
+ * belongs to a skin still registered and not yet seeded — however long no prep runs, as while
231
+ * a loading screen draws nothing and the game goes on spawning.
232
+ *
233
+ * @type {Array<[number, number]>}
234
+ */
235
+ #skin_matrix_seed_runs = [];
236
+
237
+ /**
238
+ * When true, the next prep dispatch seeds all of "previous" from "current", whatever
239
+ * {@link #skin_matrix_seed_runs} holds. Set when the buffers grow: both are made again,
240
+ * zeroed, so no row has a last frame left to keep.
241
+ *
226
242
  * @type {boolean}
227
243
  */
228
- #first_frame_skin_matrices = true;
244
+ #skin_matrix_seed_all = false;
229
245
 
230
246
  /**
231
247
  * Capacity of each of {@link #skin_matrices_buffers} in matrices
@@ -1056,7 +1072,7 @@ export class GPUAnimationManager {
1056
1072
  // The joints' matrices are written from the next prep on, and "previous" over their rows
1057
1073
  // holds whatever was there before — zeros, or the last pose of a skin that had them — so
1058
1074
  // it is seeded, as it is for a run just handed out.
1059
- this.#first_frame_skin_matrices = true;
1075
+ this.#skin_matrix_seed_runs.push([pending.joints_first, pending.joint_count]);
1060
1076
 
1061
1077
  return true;
1062
1078
  }
@@ -1436,10 +1452,34 @@ export class GPUAnimationManager {
1436
1452
  return;
1437
1453
  }
1438
1454
 
1455
+ // Its rows go back owed no seed. Left queued, a run outlives its skin until the next prep,
1456
+ // and while nothing draws that is every spawn since drawing stopped.
1457
+ this.#drop_seed_runs(skins_table.get_word(skin_id, SKIN_JOINTS_FIRST_WORD));
1458
+
1439
1459
  // The joints go with the skin — a pending skin's too, nodes or not.
1440
1460
  skins_table.remove(skin_id);
1441
1461
  }
1442
1462
 
1463
+ /**
1464
+ * Drop every queued seed run starting at `first_row`: the run of a skin being given back,
1465
+ * queued when it was handed out, and again if its joints have been named since.
1466
+ *
1467
+ * No other skin's run can start there, since a skin's rows are its own until it is given back.
1468
+ *
1469
+ * @param {number} first_row
1470
+ */
1471
+ #drop_seed_runs(first_row) {
1472
+ const runs = this.#skin_matrix_seed_runs;
1473
+
1474
+ // the prep sorts what it finds, so a dropped run's place goes to the last one
1475
+ for (let i = runs.length - 1; i >= 0; i--) {
1476
+ if (runs[i][0] === first_row) {
1477
+ runs[i] = runs[runs.length - 1];
1478
+ runs.pop();
1479
+ }
1480
+ }
1481
+ }
1482
+
1443
1483
  /**
1444
1484
  * Cached wrapper around {@link add_curve}: one upload per distinct curve, where distinct means
1445
1485
  * distinct *content*.
@@ -1541,25 +1581,31 @@ export class GPUAnimationManager {
1541
1581
  // its rows are fresh or some despawned skin's, so the next prep dispatch has to seed
1542
1582
  // "previous" from "current" for it.
1543
1583
  //
1544
- // This flag used to be set only inside #ensure_skin_matrices_capacity, i.e. only when the
1545
- // buffer actually grew. Rows given back by another skin never grow the buffer, and fresh
1546
- // rows below the current capacity hit that helper's early-out - so in both cases the
1547
- // `previous` buffer over the run still held either all-zero matrices or the last pose of
1548
- // the skin that had those rows before. The skinning pass reads
1549
- // `prev_skin_matrices[skin_base + j]` unconditionally, so the new character's first frame
1550
- // produced motion vectors from someone else's pose - a screen-crossing smear through TAA
1551
- // and motion blur - on exactly the spawn/despawn loop that reuses rows.
1552
- this.#first_frame_skin_matrices = true;
1584
+ // Whether or not the buffers grew: rows given back by another skin never grow them, and
1585
+ // neither do fresh rows below the capacity, so "previous" over the run holds all-zero
1586
+ // matrices or the last pose of the skin that had those rows before. The skinning pass
1587
+ // reads `prev_skin_matrices[skin_base + j]` unconditionally, so unseeded, the new
1588
+ // character's first frame would take its motion vectors from someone else's pose — a
1589
+ // screen-crossing smear through TAA and motion blur — on exactly the spawn/despawn loop
1590
+ // that reuses rows.
1591
+ this.#skin_matrix_seed_runs.push([joints_first, joints.length]);
1553
1592
 
1554
1593
  return joints_first;
1555
1594
  }
1556
1595
 
1557
1596
  /**
1558
- * Grow the skinning-matrix scratch buffer if `required_count`
1559
- * exceeds current capacity. Doubles on grow until the requirement
1560
- * fits. The buffer's contents are scratch (rewritten every frame by
1561
- * the prep pass), so growth doesn't need to copy old data — but it
1562
- * does invalidate the previous {@link #skin_matrices_buffer}
1597
+ * Grow the skinning-matrix buffers if `required_count` exceeds
1598
+ * current capacity. Doubles on grow until the requirement fits.
1599
+ *
1600
+ * Nothing is copied across. "Current" would be rewritten by the
1601
+ * next prep anyway, but "previous" held every skin's pose last
1602
+ * frame, which its motion is measured from: the grow loses that,
1603
+ * and the next prep seeds all of "previous" from "current" instead
1604
+ * ({@link #skin_matrix_seed_all}), so every skinned character has
1605
+ * zero motion vectors for that one frame. Capacity doubles, so
1606
+ * that is a handful of frames over a session.
1607
+ *
1608
+ * The grow also invalidates the {@link #skin_matrices_buffer}
1563
1609
  * reference, which is why callers re-fetch through the getter.
1564
1610
  *
1565
1611
  * @param {number} required_count number of matrices that must fit
@@ -1578,8 +1624,9 @@ export class GPUAnimationManager {
1578
1624
  // capacity. After grow both are zero-initialised, so the next
1579
1625
  // prep dispatch needs to seed "previous" from "current"
1580
1626
  // (otherwise velocity would interpolate against zero
1581
- // matrices). The flag below tells dispatch_skin_matrix_prep
1582
- // to issue that copy.
1627
+ // matrices), and all of it: no row has a last frame left to
1628
+ // keep. The flag below tells dispatch_skin_matrix_prep to
1629
+ // issue that copy.
1583
1630
  for (let i = 0; i < 2; i++) {
1584
1631
  if (this.#skin_matrices_buffers[i] !== null) {
1585
1632
  this.#skin_matrices_buffers[i].destroy();
@@ -1591,7 +1638,7 @@ export class GPUAnimationManager {
1591
1638
  });
1592
1639
  }
1593
1640
  this.#skin_matrices_capacity = new_capacity;
1594
- this.#first_frame_skin_matrices = true;
1641
+ this.#skin_matrix_seed_all = true;
1595
1642
  }
1596
1643
 
1597
1644
  /**
@@ -1643,8 +1690,10 @@ export class GPUAnimationManager {
1643
1690
  * correct ping-pong behaviour across frames without leaking the
1644
1691
  * buffer-role bookkeeping into every caller.
1645
1692
  *
1646
- * No-op when the joints table has no rows to walk
1647
- * (`group_count_x === 0`).
1693
+ * No-op when the joints table has no page for it to walk
1694
+ * (`group_count_x === 0`), which is never while a skin is
1695
+ * registered: a page emptied of joints goes at the next database
1696
+ * update.
1648
1697
  *
1649
1698
  * Per-frame ordering:
1650
1699
  * 1. Flip {@link #skin_matrices_current_index}: last frame's
@@ -1652,11 +1701,12 @@ export class GPUAnimationManager {
1652
1701
  * ({@link prev_skin_matrices_buffer}), and the buffer that
1653
1702
  * held the frame before it becomes the write target.
1654
1703
  * 2. Dispatch the prep shader into the new "current".
1655
- * 3. If {@link #first_frame_skin_matrices} is set — a run handed
1656
- * out, a pending skin's joints named, or the buffers grown
1657
- * since the last dispatch — copy all of "current" over
1658
- * "previous", so the first velocity read over those rows sees
1659
- * matching matrices and produces zero velocity.
1704
+ * 3. Copy "current" over "previous" on the rows that have no last
1705
+ * frame — every run handed out and every pending skin's run
1706
+ * named since the last dispatch, or all of it after a grow —
1707
+ * so the first velocity read over those rows sees matching
1708
+ * matrices and produces zero velocity. Every other row of
1709
+ * "previous" keeps last frame's matrices.
1660
1710
  *
1661
1711
  * @param {ShadeGPUCommandContext} cmd_ctx
1662
1712
  */
@@ -1665,6 +1715,9 @@ export class GPUAnimationManager {
1665
1715
  .get('animation_skin_joints')
1666
1716
  .dispatch_group_count(SKIN_MATRIX_PREP_WORKGROUP_SIZE);
1667
1717
  if (groups === 0) {
1718
+ // no page to walk means no skin registered, and a skin given back takes its runs
1719
+ assert.equal(this.#skin_matrix_seed_runs.length, 0, 'seed runs queued for skins no longer registered');
1720
+
1668
1721
  return;
1669
1722
  }
1670
1723
 
@@ -1689,20 +1742,69 @@ export class GPUAnimationManager {
1689
1742
  },
1690
1743
  });
1691
1744
 
1692
- // First-frame init (or post-grow): "previous" buffer is
1693
- // zero-initialised, which would have the velocity pass
1694
- // interpolate against the origin and produce huge nonsense
1695
- // on the first frame the skin appears. Seed prev from
1696
- // current — first velocity reads then yield zero, which is
1697
- // the right answer (no motion has happened yet).
1698
- if (this.#first_frame_skin_matrices) {
1745
+ this.#seed_previous_skin_matrices(cmd_ctx, current, previous);
1746
+ }
1747
+
1748
+ /**
1749
+ * Copy "current" over "previous" on the rows where "previous" holds no pose of the frame
1750
+ * before: all of it after a grow, otherwise the runs queued since the last prep. Zeros there,
1751
+ * or the last pose of a skin that had the rows, would have the velocity pass produce huge
1752
+ * nonsense on the first frame the skin appears; seeded, the first velocity read yields zero,
1753
+ * which is the right answer — no motion has happened yet.
1754
+ *
1755
+ * Every other row is left alone: a settled skin's rows hold its pose last frame, which its
1756
+ * motion is measured from, and the rest are read by no one. Seeded too, every skinned
1757
+ * character on screen would lose its motion vectors for the frame whenever one spawned.
1758
+ *
1759
+ * Runs are coalesced by sorting — a frame's worth of spawns is a handful of runs — and adjacent
1760
+ * or overlapping ones go as one copy.
1761
+ *
1762
+ * @param {ShadeGPUCommandContext} cmd_ctx
1763
+ * @param {GPUBuffer} current
1764
+ * @param {GPUBuffer} previous
1765
+ */
1766
+ #seed_previous_skin_matrices(cmd_ctx, current, previous) {
1767
+ const runs = this.#skin_matrix_seed_runs;
1768
+
1769
+ if (this.#skin_matrix_seed_all) {
1770
+ cmd_ctx.copyBufferToBuffer(current, 0, previous, 0, current.size);
1771
+
1772
+ this.#skin_matrix_seed_all = false;
1773
+ runs.length = 0;
1774
+
1775
+ return;
1776
+ }
1777
+
1778
+ if (runs.length === 0) {
1779
+ // a settled frame: every row of "previous" is last frame's
1780
+ return;
1781
+ }
1782
+
1783
+ runs.sort((a, b) => a[0] - b[0]);
1784
+
1785
+ let i = 0;
1786
+
1787
+ while (i < runs.length) {
1788
+ const first = runs[i][0];
1789
+ let end = first + runs[i][1];
1790
+
1791
+ i++;
1792
+
1793
+ // a run starting at or before this copy's end is part of it
1794
+ while (i < runs.length && runs[i][0] <= end) {
1795
+ end = Math.max(end, runs[i][0] + runs[i][1]);
1796
+
1797
+ i++;
1798
+ }
1799
+
1699
1800
  cmd_ctx.copyBufferToBuffer(
1700
- current, 0,
1701
- previous, 0,
1702
- current.size,
1801
+ current, first * SKIN_MATRIX_BYTES,
1802
+ previous, first * SKIN_MATRIX_BYTES,
1803
+ (end - first) * SKIN_MATRIX_BYTES,
1703
1804
  );
1704
- this.#first_frame_skin_matrices = false;
1705
1805
  }
1806
+
1807
+ runs.length = 0;
1706
1808
  }
1707
1809
 
1708
1810
  /**
@@ -2,11 +2,12 @@
2
2
  * Persistent `MAP_READ | COPY_DST` buffers for reading GPU data back — {@link GPUBufferStagingAllocator}
3
3
  * run the other way.
4
4
  *
5
- * The same shape on purpose: a size-sorted free list, `get(min_size)` serving the smallest buffer
6
- * that fits and creating one when none does, `release(buffer)` putting it back. Where the staging
7
- * pool re-maps a buffer on release because the next writer needs it mapped, this one *unmaps*,
8
- * because the next copy into it needs it unmapped; the mapping is the holder's, taken after the
9
- * copy has landed and read at the holder's own apply point.
5
+ * The same shape: a size-sorted free list, `get(min_size)` serving the smallest buffer that fits
6
+ * and creating one when none does, `release(buffer)` putting it back. Where the staging pool re-maps
7
+ * a buffer on release because the next writer needs it mapped, this one *unmaps*, because the next
8
+ * copy into it needs it unmapped; the mapping is the holder's, taken after the copy has landed and
9
+ * read at the holder's own apply point. Unlike the staging pool, this one has no bound on how much
10
+ * larger than the request a buffer it serves may be, no size classes and no reclaim.
10
11
  *
11
12
  * Why not `buffer_allocator_main`: `TransientResourcePool`'s reuse safety rests on transients being
12
13
  * GPU-only, and a readback buffer is held by the CPU across frames.
@@ -1 +1 @@
1
- {"version":3,"file":"GPUBufferReadbackAllocator.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/buffer/GPUBufferReadbackAllocator.js"],"names":[],"mappings":"AAoCA;;;;;;;;;;;;;;;;;;GAkBG;AACH;IA4BI;;;;OAIG;IACH;QAF4B,YAAY,GAA7B,MAAM;OAQhB;IAED;;;OAGG;IACH,+BAEC;IAED;;;OAGG;IACH,8BAEC;IAED;;;OAGG;IACH,6BAEC;IAED;;;OAGG;IACH,0BAEC;IAED;;;;;;OAMG;IACH,oBAHW,MAAM,aAkChB;IAED;;;;;OAKG;IACH,iCAsBC;IAED;;;;;OAKG;IACH,iCAMC;IAkBD,gBAUC;;CACJ"}
1
+ {"version":3,"file":"GPUBufferReadbackAllocator.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/buffer/GPUBufferReadbackAllocator.js"],"names":[],"mappings":"AAoCA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IA4BI;;;;OAIG;IACH;QAF4B,YAAY,GAA7B,MAAM;OAQhB;IAED;;;OAGG;IACH,+BAEC;IAED;;;OAGG;IACH,8BAEC;IAED;;;OAGG;IACH,6BAEC;IAED;;;OAGG;IACH,0BAEC;IAED;;;;;;OAMG;IACH,oBAHW,MAAM,aAkChB;IAED;;;;;OAKG;IACH,iCAsBC;IAED;;;;;OAKG;IACH,iCAMC;IAkBD,gBAUC;;CACJ"}