@woosh/meep-engine 3.63.2 → 3.64.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 (148) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/package.json +1 -1
  3. package/src/core/color/xyz/m3_chromatic_adaptation_bradford.d.ts +14 -0
  4. package/src/core/color/xyz/m3_chromatic_adaptation_bradford.d.ts.map +1 -0
  5. package/src/core/color/xyz/m3_chromatic_adaptation_bradford.js +51 -0
  6. package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts +2 -1
  7. package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts.map +1 -1
  8. package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.js +51 -70
  9. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.d.ts.map +1 -1
  10. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.js +8 -64
  11. package/src/core/math/linalg/eigen/matrix_symmetric_jacobi_rotate_in_place.d.ts +17 -0
  12. package/src/core/math/linalg/eigen/matrix_symmetric_jacobi_rotate_in_place.d.ts.map +1 -0
  13. package/src/core/math/linalg/eigen/matrix_symmetric_jacobi_rotate_in_place.js +64 -0
  14. package/src/core/math/linalg/solve_box_constrained_qp.d.ts +30 -0
  15. package/src/core/math/linalg/solve_box_constrained_qp.d.ts.map +1 -0
  16. package/src/core/math/linalg/solve_box_constrained_qp.js +205 -0
  17. package/src/engine/physics/constraint/soft_spring_coefficients.d.ts +24 -0
  18. package/src/engine/physics/constraint/soft_spring_coefficients.d.ts.map +1 -0
  19. package/src/engine/physics/constraint/soft_spring_coefficients.js +38 -0
  20. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  21. package/src/engine/physics/constraint/solve_constraints.js +16 -8
  22. package/src/engine/physics/ecs/PhysicsSystem.d.ts +54 -0
  23. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  24. package/src/engine/physics/ecs/PhysicsSystem.js +192 -7
  25. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  26. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +3 -5
  27. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
  28. package/src/engine/physics/inertia/world_inverse_inertia.js +3 -5
  29. package/src/engine/physics/vehicle/RaycastVehicle.d.ts +183 -12
  30. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  31. package/src/engine/physics/vehicle/RaycastVehicle.js +1046 -121
  32. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts +17 -0
  33. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts.map +1 -1
  34. package/src/shade/device/mock/SoftwareGPUCommandEncoder.js +46 -0
  35. package/src/shade/playground/tonemap_sdr/README.md +11 -8
  36. package/src/shade/playground/tonemap_sdr/ToneMapCompare.js +2 -2
  37. package/src/shade/renderer/Renderer.d.ts +5 -6
  38. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  39. package/src/shade/renderer/Renderer.js +15 -88
  40. package/src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.d.ts +14 -0
  41. package/src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.d.ts.map +1 -0
  42. package/src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.js +62 -0
  43. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts +12 -0
  44. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  45. package/src/shade/renderer/buffer/table/GPUDatabase.js +85 -0
  46. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts +2 -1
  47. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts.map +1 -1
  48. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.js +2 -1
  49. package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts +158 -0
  50. package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts.map +1 -0
  51. package/src/shade/renderer/deferred/tonemap/ColorGrade.js +337 -0
  52. package/src/shade/renderer/deferred/tonemap/SAMPLER_TONEMAP_LUT.d.ts +9 -0
  53. package/src/shade/renderer/deferred/tonemap/SAMPLER_TONEMAP_LUT.d.ts.map +1 -0
  54. package/src/shade/renderer/deferred/tonemap/SAMPLER_TONEMAP_LUT.js +15 -0
  55. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_ACES.d.ts +6 -0
  56. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_ACES.d.ts.map +1 -0
  57. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_ACES.js +84 -0
  58. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_GT7.d.ts +10 -0
  59. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_GT7.d.ts.map +1 -0
  60. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_GT7.js +25 -0
  61. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_NONE.d.ts +9 -0
  62. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_NONE.d.ts.map +1 -0
  63. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_NONE.js +20 -0
  64. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_PBR_NEUTRAL.d.ts +14 -0
  65. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_PBR_NEUTRAL.d.ts.map +1 -0
  66. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_PBR_NEUTRAL.js +30 -0
  67. package/src/shade/renderer/deferred/tonemap/ToneMapOperator.d.ts +54 -0
  68. package/src/shade/renderer/deferred/tonemap/ToneMapOperator.d.ts.map +1 -0
  69. package/src/shade/renderer/deferred/tonemap/ToneMapOperator.js +63 -0
  70. package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts +106 -0
  71. package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts.map +1 -0
  72. package/src/shade/renderer/deferred/tonemap/ToneMapper.js +474 -0
  73. package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts +5 -13
  74. package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts.map +1 -1
  75. package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.js +5 -44
  76. package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.d.ts +7 -25
  77. package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.d.ts.map +1 -1
  78. package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.js +11 -51
  79. package/src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.d.ts +20 -0
  80. package/src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.d.ts.map +1 -0
  81. package/src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.js +103 -0
  82. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts +9 -0
  83. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts.map +1 -0
  84. package/src/shade/renderer/deferred/tonemap/{shader_tonemap_HDR_none.js → shader_tonemap_HDR_lut.js} +22 -18
  85. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts +9 -0
  86. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts.map +1 -0
  87. package/src/shade/renderer/deferred/tonemap/{shader_tonemap_LDR_aces.js → shader_tonemap_LDR_lut.js} +24 -24
  88. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.d.ts +23 -0
  89. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.d.ts.map +1 -0
  90. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.js +92 -0
  91. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.d.ts +15 -0
  92. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.d.ts.map +1 -0
  93. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.js +73 -0
  94. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  95. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  96. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  97. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  98. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  99. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +1 -1
  100. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  101. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  102. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts +22 -0
  103. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts.map +1 -0
  104. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.js +62 -0
  105. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts +13 -0
  106. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts.map +1 -0
  107. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.js +140 -0
  108. package/src/shade/renderer/shader/chunk/color/oklab/chunk_oklab_compute_max_saturation.d.ts +11 -0
  109. package/src/shade/renderer/shader/chunk/color/oklab/chunk_oklab_compute_max_saturation.d.ts.map +1 -0
  110. package/src/shade/renderer/shader/chunk/color/oklab/chunk_oklab_compute_max_saturation.js +65 -0
  111. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_bt2390_eetf.d.ts +14 -0
  112. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_bt2390_eetf.d.ts.map +1 -0
  113. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_bt2390_eetf.js +38 -0
  114. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_lut.d.ts +16 -0
  115. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_lut.d.ts.map +1 -0
  116. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_lut.js +41 -0
  117. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  118. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +8 -8
  119. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  120. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +2 -0
  121. package/src/shade/renderer/ShadeToneMappingMode.d.ts +0 -15
  122. package/src/shade/renderer/ShadeToneMappingMode.d.ts.map +0 -1
  123. package/src/shade/renderer/ShadeToneMappingMode.js +0 -41
  124. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.d.ts +0 -9
  125. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.d.ts.map +0 -1
  126. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.js +0 -79
  127. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts +0 -17
  128. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts.map +0 -1
  129. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.js +0 -101
  130. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_none.d.ts +0 -9
  131. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_none.d.ts.map +0 -1
  132. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.d.ts +0 -10
  133. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.d.ts.map +0 -1
  134. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.js +0 -80
  135. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.d.ts +0 -9
  136. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.d.ts.map +0 -1
  137. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.js +0 -80
  138. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts +0 -10
  139. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts.map +0 -1
  140. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.d.ts +0 -9
  141. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.d.ts.map +0 -1
  142. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.js +0 -71
  143. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.d.ts +0 -10
  144. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.d.ts.map +0 -1
  145. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.js +0 -76
  146. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_hdr_bt2390.d.ts +0 -3
  147. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_hdr_bt2390.d.ts.map +0 -1
  148. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_hdr_bt2390.js +0 -44
@@ -30,6 +30,23 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase implements
30
30
  * @type {(SoftwareGPUComputePassEncoder|SoftwareGPURenderPassEncoder)[]}
31
31
  */
32
32
  passes: (SoftwareGPUComputePassEncoder | SoftwareGPURenderPassEncoder)[];
33
+ /**
34
+ * Everything encoded on this encoder, in the order it was encoded: each pass begun and each copy,
35
+ * clear and query resolve the encoder accepted. A device runs them in this order, so what one
36
+ * command finds in a buffer depends on where it sits among the rest — which {@link passes} alone
37
+ * cannot show for a pass and a copy or clear around it.
38
+ *
39
+ * Each entry names its method and carries that call's arguments, with any size the caller left
40
+ * out filled in:
41
+ * - `{ method: 'beginComputePass' | 'beginRenderPass', pass }`
42
+ * - `{ method: 'copyBufferToBuffer', source, source_offset, destination, destination_offset, size }`
43
+ * - `{ method: 'clearBuffer', buffer, offset, size }`
44
+ * - `{ method: 'copyTextureToTexture' | 'copyBufferToTexture' | 'copyTextureToBuffer', source, destination, size }`
45
+ * - `{ method: 'resolveQuerySet', query_set, first_query, query_count, destination, destination_offset }`
46
+ *
47
+ * @type {Object[]}
48
+ */
49
+ operations: any[];
33
50
  finish(): SoftwareGPUCommandBuffer;
34
51
  /**
35
52
  * Called by a pass this encoder opened, when that pass ends. Releases the lock.
@@ -1 +1 @@
1
- {"version":3,"file":"SoftwareGPUCommandEncoder.d.ts","sourceRoot":"","sources":["../../../../../src/shade/device/mock/SoftwareGPUCommandEncoder.js"],"names":[],"mappings":"AAgGA;;;;GAIG;AACH,gFAFgB,iBAAiB;IA+D7B;;;;OAIG;IACH,iFAIC;IAzDD;;;;OAIG;IACH,gBAFU,6BAA6B,EAAE,CAErB;IAEpB;;;;OAIG;IACH,eAFU,4BAA4B,EAAE,CAErB;IAEnB;;;;;;OAMG;IACH,QAFU,CAAC,6BAA6B,GAAC,4BAA4B,CAAC,EAAE,CAE5D;IA0EZ,mCAiBC;IAqBD;;;;;OAKG;IACH,wBAHW,6BAA6B,GAAC,4BAA4B,GACxD,IAAI,CAMhB;IAED;;;;;OAKG;IACH,gCAEC;IAED;;;;;;;;;OASG;IACH,sCAHW,MAAM,GACJ,IAAI,CAIhB;IAED;;;;;;;OAOG;IACH,+EAeC;IAED;;;;;;;;;;;;;OAaG;IACH,4BAHW,CAAC,sCAAoC,CAAC,EAAE,GACtC,IAAI,CAUhB;IAkBD;;;;;;;OAOG;IACH,4EAmCC;IAED;;;;;;;;OAQG;IACH,oHAFa,IAAI,CAuBhB;IAED;;;;;OAKG;IACH,kHAFa,IAAI,CAuBhB;IAED;;;;;OAKG;IACH,kHAFa,IAAI,CAuBhB;IAED;;;;;;;;;OASG;IACH,2DANW,MAAM,cACN,MAAM,qDAEN,MAAM,GACJ,IAAI,CAwBhB;IAwCD;;;;OAIG;IACH,sBAFW,MAAM,QAIhB;IAED,sBAEC;IAED;;OAEG;IACH,yBAFW,MAAM,QAIhB;IAyED;;;;;;;;OAQG;IACH,4DANW,MAAM,qDAEN,MAAM,QACN,MAAM,GACJ,IAAI,CAgChB;IAED;;;;;;;OAOG;IACH,gDAJW,MAAM,SACN,MAAM,GACJ,IAAI,CA6BhB;IAGL;;;OAGG;IACH,sCAFU,OAAO,CAE8C;;CAN9D;sCA/sBqC,4BAA4B;8CAFpB,oCAAoC;6CAGrC,mCAAmC;yCAJvC,+BAA+B"}
1
+ {"version":3,"file":"SoftwareGPUCommandEncoder.d.ts","sourceRoot":"","sources":["../../../../../src/shade/device/mock/SoftwareGPUCommandEncoder.js"],"names":[],"mappings":"AAgGA;;;;GAIG;AACH,gFAFgB,iBAAiB;IAiF7B;;;;OAIG;IACH,iFAIC;IA3ED;;;;OAIG;IACH,gBAFU,6BAA6B,EAAE,CAErB;IAEpB;;;;OAIG;IACH,eAFU,4BAA4B,EAAE,CAErB;IAEnB;;;;;;OAMG;IACH,QAFU,CAAC,6BAA6B,GAAC,4BAA4B,CAAC,EAAE,CAE5D;IAEZ;;;;;;;;;;;;;;;OAeG;IACH,YAFU,KAAQ,CAEF;IA0EhB,mCAiBC;IAqBD;;;;;OAKG;IACH,wBAHW,6BAA6B,GAAC,4BAA4B,GACxD,IAAI,CAMhB;IAED;;;;;OAKG;IACH,gCAEC;IAED;;;;;;;;;OASG;IACH,sCAHW,MAAM,GACJ,IAAI,CAIhB;IAED;;;;;;;OAOG;IACH,+EAgBC;IAED;;;;;;;;;;;;;OAaG;IACH,4BAHW,CAAC,sCAAoC,CAAC,EAAE,GACtC,IAAI,CAUhB;IAkBD;;;;;;;OAOG;IACH,4EAoCC;IAED;;;;;;;;OAQG;IACH,oHAFa,IAAI,CAyBhB;IAED;;;;;OAKG;IACH,kHAFa,IAAI,CAyBhB;IAED;;;;;OAKG;IACH,kHAFa,IAAI,CAyBhB;IAED;;;;;;;;;OASG;IACH,2DANW,MAAM,cACN,MAAM,qDAEN,MAAM,GACJ,IAAI,CAiChB;IAwCD;;;;OAIG;IACH,sBAFW,MAAM,QAIhB;IAED,sBAEC;IAED;;OAEG;IACH,yBAFW,MAAM,QAIhB;IAyED;;;;;;;;OAQG;IACH,4DANW,MAAM,qDAEN,MAAM,QACN,MAAM,GACJ,IAAI,CAyChB;IAED;;;;;;;OAOG;IACH,gDAJW,MAAM,SACN,MAAM,GACJ,IAAI,CA+BhB;IAGL;;;OAGG;IACH,sCAFU,OAAO,CAE8C;;CAN9D;sCA7vBqC,4BAA4B;8CAFpB,oCAAoC;6CAGrC,mCAAmC;yCAJvC,+BAA+B"}
@@ -135,6 +135,24 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase {
135
135
  */
136
136
  passes = [];
137
137
 
138
+ /**
139
+ * Everything encoded on this encoder, in the order it was encoded: each pass begun and each copy,
140
+ * clear and query resolve the encoder accepted. A device runs them in this order, so what one
141
+ * command finds in a buffer depends on where it sits among the rest — which {@link passes} alone
142
+ * cannot show for a pass and a copy or clear around it.
143
+ *
144
+ * Each entry names its method and carries that call's arguments, with any size the caller left
145
+ * out filled in:
146
+ * - `{ method: 'beginComputePass' | 'beginRenderPass', pass }`
147
+ * - `{ method: 'copyBufferToBuffer', source, source_offset, destination, destination_offset, size }`
148
+ * - `{ method: 'clearBuffer', buffer, offset, size }`
149
+ * - `{ method: 'copyTextureToTexture' | 'copyBufferToTexture' | 'copyTextureToBuffer', source, destination, size }`
150
+ * - `{ method: 'resolveQuerySet', query_set, first_query, query_count, destination, destination_offset }`
151
+ *
152
+ * @type {Object[]}
153
+ */
154
+ operations = [];
155
+
138
156
  /**
139
157
  * The pass currently open on this encoder, `null` when none is.
140
158
  *
@@ -302,6 +320,7 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase {
302
320
 
303
321
  this.compute_passes.push(pass);
304
322
  this.passes.push(pass);
323
+ this.operations.push({ method: 'beginComputePass', pass });
305
324
 
306
325
  return pass;
307
326
  }
@@ -387,6 +406,7 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase {
387
406
 
388
407
  this.render_passes.push(pass);
389
408
  this.passes.push(pass);
409
+ this.operations.push({ method: 'beginRenderPass', pass });
390
410
 
391
411
  return pass;
392
412
  }
@@ -421,6 +441,8 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase {
421
441
  texture_copy_execute({ texture_source: source, texture_destination: destination, size: copySize });
422
442
  }
423
443
  });
444
+
445
+ this.operations.push({ method: 'copyTextureToTexture', source, destination, size: copySize });
424
446
  }
425
447
 
426
448
  /**
@@ -450,6 +472,8 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase {
450
472
  texture_copy_execute({ buffer_source: source, texture_destination: destination, size: copySize });
451
473
  }
452
474
  });
475
+
476
+ this.operations.push({ method: 'copyBufferToTexture', source, destination, size: copySize });
453
477
  }
454
478
 
455
479
  /**
@@ -479,6 +503,8 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase {
479
503
  texture_copy_execute({ texture_source: source, buffer_destination: destination, size: copySize });
480
504
  }
481
505
  });
506
+
507
+ this.operations.push({ method: 'copyTextureToBuffer', source, destination, size: copySize });
482
508
  }
483
509
 
484
510
  /**
@@ -513,6 +539,15 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase {
513
539
  .set(querySet.read(firstQuery, queryCount));
514
540
  }
515
541
  });
542
+
543
+ this.operations.push({
544
+ method: 'resolveQuerySet',
545
+ query_set: querySet,
546
+ first_query: firstQuery,
547
+ query_count: queryCount,
548
+ destination,
549
+ destination_offset: destinationOffset,
550
+ });
516
551
  }
517
552
 
518
553
  /**
@@ -683,6 +718,15 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase {
683
718
  array_buffer_copy(source.data, sourceOffset, destination.data, destinationOffset, _size);
684
719
  }
685
720
  });
721
+
722
+ this.operations.push({
723
+ method: 'copyBufferToBuffer',
724
+ source,
725
+ source_offset: sourceOffset,
726
+ destination,
727
+ destination_offset: destinationOffset,
728
+ size: _size,
729
+ });
686
730
  }
687
731
 
688
732
  /**
@@ -720,6 +764,8 @@ export class SoftwareGPUCommandEncoder extends SoftwareGPUObjectBase {
720
764
  new Uint8Array(buffer.data, offset, clear_size).fill(0);
721
765
  }
722
766
  });
767
+
768
+ this.operations.push({ method: 'clearBuffer', buffer, offset, size: clear_size });
723
769
  }
724
770
  }
725
771
 
@@ -1,14 +1,17 @@
1
1
  # Tone mapping: GT7 and PBR Neutral, SDR and HDR
2
2
 
3
- The renderer has four tone mapping modes, each one choice for every output (`ShadeToneMappingMode`):
3
+ The renderer's `ToneMapper` has four built-in operators, each one choice for every output (`renderer.tone_mapper.operator`):
4
4
 
5
- - `ACES`, the default: Unreal Engine's look;
6
- - `GT7`;
7
- - `PBR_NEUTRAL`;
8
- - `NONE`.
5
+ - `TONE_MAP_OPERATOR_ACES`, the default: Unreal Engine's look;
6
+ - `TONE_MAP_OPERATOR_GT7`;
7
+ - `TONE_MAP_OPERATOR_PBR_NEUTRAL`;
8
+ - `TONE_MAP_OPERATOR_NONE`.
9
+
10
+ The tone mapper bakes the operator into a 3D LUT per output and draws through it; this page evaluates the operators
11
+ directly.
9
12
 
10
13
  This page compares GT7 and PBR Neutral, and shows each one's HDR form beside its SDR form. ACES is not one of its
11
- views; the engine's own canvas shows it, and `shader_tonemap_aces.spec.js` holds it to Unreal's and OpenColorIO's numbers.
14
+ views; the engine's own canvas shows it, and `TONE_MAP_OPERATOR_ACES.spec.js` holds it to Unreal's and OpenColorIO's numbers.
12
15
 
13
16
  The engine renders and tonemaps each frame as usual. Two extensions then redraw the canvas from the HDR colour the
14
17
  tonemapper was given:
@@ -16,8 +19,8 @@ tonemapper was given:
16
19
  | | operator | source |
17
20
  |---|---|---|
18
21
  | 1 | GT7, Polyphony's sample | `chunk_tonemap_gt7_sdr_reference.js` beside this page: the sample code's `initializeAsSDR()`, SDR only |
19
- | 2 | GT7, engine | `tonemap_gt7_rec2020` at `PAPER_WHITE_NITS · peak` and `PAPER_WHITE_NITS`, back in Rec.709, what `ShadeToneMappingMode.GT7` runs |
20
- | 3 | PBR Neutral, engine | `tonemap_khronos_pbr(c, peak)`, what `ShadeToneMappingMode.PBR_NEUTRAL` runs; at peak 1 the Khronos specification |
22
+ | 2 | GT7, engine | `tonemap_gt7_rec2020` at `PAPER_WHITE_NITS · peak` and `PAPER_WHITE_NITS`, back in Rec.709, what `TONE_MAP_OPERATOR_GT7` runs |
23
+ | 3 | PBR Neutral, engine | `tonemap_khronos_pbr(c, peak)`, what `TONE_MAP_OPERATOR_PBR_NEUTRAL` runs; at peak 1 the Khronos specification |
21
24
 
22
25
  All of them see the same input. Exposure is the page's own and fixed per scene, with the engine's automatic exposure off.
23
26
 
@@ -35,11 +35,11 @@ export const CompareOperator = {
35
35
  GT7Reference: 0,
36
36
  /**
37
37
  * the engine's `tonemap_gt7` with the paper white at `PAPER_WHITE_NITS` and the peak at the headroom times that:
38
- * what `ShadeToneMappingMode.GT7` runs
38
+ * what `TONE_MAP_OPERATOR_GT7` runs
39
39
  */
40
40
  GT7: 1,
41
41
  /**
42
- * the engine's `tonemap_khronos_pbr` at the headroom: what `ShadeToneMappingMode.PBR_NEUTRAL` runs, and at
42
+ * the engine's `tonemap_khronos_pbr` at the headroom: what `TONE_MAP_OPERATOR_PBR_NEUTRAL` runs, and at
43
43
  * headroom 1 the Khronos specification
44
44
  */
45
45
  PBRNeutral: 2,
@@ -54,12 +54,11 @@ export class Renderer {
54
54
  */
55
55
  transparency_mode: ShadeTransparencyMode;
56
56
  /**
57
- * How the exposed scene colour becomes display colour, on every output. An SDR and an HDR display run the same
58
- * mode, so a scene looks alike on both; see {@link ShadeToneMappingMode}. ACES, Unreal's default look, unless set. Read every frame, so it can be flipped
59
- * at runtime. A mode not in use at {@link initialize} compiles its pass on the first frame that draws with it.
60
- * @type {ShadeToneMappingMode}
57
+ * How the exposed scene colour becomes display colour, on every output: its operator, the resolution of its LUTs,
58
+ * and LUTs of the user's own. Made by {@link initialize}.
59
+ * @type {ToneMapper}
61
60
  */
62
- tone_mapping_mode: ShadeToneMappingMode;
61
+ tone_mapper: ToneMapper;
63
62
  /**
64
63
  * Switches of the AVBOIT mode, read every frame while {@link transparency_mode} selects it.
65
64
  * @type {AVBOITSettings}
@@ -579,7 +578,7 @@ import { ShadeIndirectLightingMode } from "./ShadeIndirectLightingMode.js";
579
578
  import { MaterialDispatch } from "./material/dispatch/MaterialDispatch.js";
580
579
  import { ProbeClipmapSettings } from "./global_illumination/probe_clipmap/ProbeClipmapSettings.js";
581
580
  import { ShadeTransparencyMode } from "./ShadeTransparencyMode.js";
582
- import { ShadeToneMappingMode } from "./ShadeToneMappingMode.js";
581
+ import { ToneMapper } from "./deferred/tonemap/ToneMapper.js";
583
582
  import { AVBOITSettings } from "./rasterize/native/avboit/AVBOITSettings.js";
584
583
  import { ShaderSwitchSet } from "./shader/compiler/ShaderSwitchSet.js";
585
584
  import { MotionBlur } from "./postprocess/motion_blur/MotionBlur.js";
@@ -1 +1 @@
1
- {"version":3,"file":"Renderer.d.ts","sourceRoot":"","sources":["../../../../src/shade/renderer/Renderer.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Renderer.d.ts","sourceRoot":"","sources":["../../../../src/shade/renderer/Renderer.js"],"names":[],"mappings":"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"}
@@ -22,16 +22,7 @@ import { shader_composite_volumetrics } from "./deferred/shader_composite_volume
22
22
  import { shader_deferred_main } from "./deferred/shader_deferred_main.js";
23
23
  import { LOCAL_LIGHT_SHADING } from "./deferred/LOCAL_LIGHT_SHADING.js";
24
24
  import { LocalLightShading } from "./deferred/LocalLightShading.js";
25
- import { shader_tonemap_HDR } from "./deferred/tonemap/shader_tonemap_HDR.js";
26
- import { shader_tonemap_HDR_aces } from "./deferred/tonemap/shader_tonemap_HDR_aces.js";
27
- import { shader_tonemap_HDR_none } from "./deferred/tonemap/shader_tonemap_HDR_none.js";
28
- import { shader_tonemap_HDR_pbr_neutral } from "./deferred/tonemap/shader_tonemap_HDR_pbr_neutral.js";
29
- import { shader_tonemap_LDR } from "./deferred/tonemap/shader_tonemap_LDR.js";
30
- import { shader_tonemap_LDR_aces } from "./deferred/tonemap/shader_tonemap_LDR_aces.js";
31
- import { shader_tonemap_LDR_none } from "./deferred/tonemap/shader_tonemap_LDR_none.js";
32
- import { shader_tonemap_LDR_pbr_neutral } from "./deferred/tonemap/shader_tonemap_LDR_pbr_neutral.js";
33
- import { TonemapAces2Tables } from "./deferred/tonemap/TonemapAces2Tables.js";
34
- import { TonemapDisplaySettings } from "./deferred/tonemap/TonemapDisplaySettings.js";
25
+ import { ToneMapper } from "./deferred/tonemap/ToneMapper.js";
35
26
  import { FrameContext } from "./extension/FrameContext.js";
36
27
  import { FramePhase } from "./extension/FramePhase.js";
37
28
  import { GBufferTextures } from "./extension/GBufferTextures.js";
@@ -102,7 +93,6 @@ import { GPUParticleSystem } from "./particles/GPUParticleSystem.js";
102
93
  import { SceneManager } from "./scene/SceneManager.js";
103
94
  import { ShadeIndirectLightingMode } from "./ShadeIndirectLightingMode.js";
104
95
  import { MaterialDispatch } from "./material/dispatch/MaterialDispatch.js";
105
- import { ShadeToneMappingMode } from "./ShadeToneMappingMode.js";
106
96
  import { ShadeTransparencyMode } from "./ShadeTransparencyMode.js";
107
97
  import { AVBOITSettings } from "./rasterize/native/avboit/AVBOITSettings.js";
108
98
  import { ShaderSwitchSet } from "./shader/compiler/ShaderSwitchSet.js";
@@ -264,12 +254,11 @@ export class Renderer {
264
254
  transparency_mode = ShadeTransparencyMode.AVBOIT;
265
255
 
266
256
  /**
267
- * How the exposed scene colour becomes display colour, on every output. An SDR and an HDR display run the same
268
- * mode, so a scene looks alike on both; see {@link ShadeToneMappingMode}. ACES, Unreal's default look, unless set. Read every frame, so it can be flipped
269
- * at runtime. A mode not in use at {@link initialize} compiles its pass on the first frame that draws with it.
270
- * @type {ShadeToneMappingMode}
257
+ * How the exposed scene colour becomes display colour, on every output: its operator, the resolution of its LUTs,
258
+ * and LUTs of the user's own. Made by {@link initialize}.
259
+ * @type {ToneMapper}
271
260
  */
272
- tone_mapping_mode = ShadeToneMappingMode.ACES;
261
+ tone_mapper;
273
262
 
274
263
  /**
275
264
  * Switches of the AVBOIT mode, read every frame while {@link transparency_mode} selects it.
@@ -1651,21 +1640,6 @@ export class Renderer {
1651
1640
 
1652
1641
  #hdr_supported = false;
1653
1642
 
1654
- /**
1655
- * What every tonemap pass is told about the display: the primaries the canvas was actually configured with, and
1656
- * the peak brightness, which only the HDR passes read.
1657
- *
1658
- * @type {TonemapDisplaySettings}
1659
- */
1660
- #tonemap_settings = new TonemapDisplaySettings();
1661
-
1662
- /**
1663
- * The ACES HDR pass's two output transforms, built for the display in {@link #tonemap_settings}.
1664
- *
1665
- * @type {TonemapAces2Tables}
1666
- */
1667
- #tonemap_aces2_tables = new TonemapAces2Tables();
1668
-
1669
1643
  #update_presentation_format() {
1670
1644
 
1671
1645
  const format8bit = navigator.gpu.getPreferredCanvasFormat();
@@ -1690,16 +1664,9 @@ export class Renderer {
1690
1664
  const previous_value = this.#hdr_supported;
1691
1665
 
1692
1666
 
1667
+ // the browser has no way to report the display's peak, so the tone mapper keeps its assumption
1693
1668
  this.#hdr_supported = isHDR;
1694
1669
 
1695
- if (isHDR) {
1696
- // Currently, there is no way to interrogate this from the browser, so going with an assumption
1697
- this.#tonemap_settings.peak_nits = 1000;
1698
- } else {
1699
- // Assume SDR nits
1700
- this.#tonemap_settings.peak_nits = 80;
1701
- }
1702
-
1703
1670
  if (isHDR === previous_value) {
1704
1671
  // no change
1705
1672
  return;
@@ -1842,6 +1809,8 @@ export class Renderer {
1842
1809
  this.context = context;
1843
1810
  this.device = device;
1844
1811
 
1812
+ this.tone_mapper = new ToneMapper(device);
1813
+
1845
1814
  this.#pixel_ratio = pixelRatio;
1846
1815
 
1847
1816
  // clientWidth/clientHeight are 0 for a canvas that is not attached to the DOM,
@@ -2014,31 +1983,7 @@ export class Renderer {
2014
1983
 
2015
1984
  this.#extensions.enquirePipelines(enquiry);
2016
1985
 
2017
- enquiry.render.push(this.#tonemap_shader().pipeline_for([this.#presentation_format]));
2018
- }
2019
-
2020
- /**
2021
- * The pass that writes the canvas: the output's dynamic range picks the SDR or the HDR form, and
2022
- * {@link tone_mapping_mode} picks the operator.
2023
- *
2024
- * @returns {import("./shader/ImageShader.js").ImageShader}
2025
- */
2026
- #tonemap_shader() {
2027
- assert.enum(this.tone_mapping_mode, ShadeToneMappingMode, 'tone_mapping_mode');
2028
-
2029
- if (this.tone_mapping_mode === ShadeToneMappingMode.NONE) {
2030
- return this.#hdr_supported ? shader_tonemap_HDR_none : shader_tonemap_LDR_none;
2031
- }
2032
-
2033
- if (this.tone_mapping_mode === ShadeToneMappingMode.ACES) {
2034
- return this.#hdr_supported ? shader_tonemap_HDR_aces : shader_tonemap_LDR_aces;
2035
- }
2036
-
2037
- if (this.tone_mapping_mode === ShadeToneMappingMode.PBR_NEUTRAL) {
2038
- return this.#hdr_supported ? shader_tonemap_HDR_pbr_neutral : shader_tonemap_LDR_pbr_neutral;
2039
- }
2040
-
2041
- return this.#hdr_supported ? shader_tonemap_HDR : shader_tonemap_LDR;
1986
+ this.tone_mapper.enquire_pipelines(enquiry, this.#hdr_supported, this.#presentation_format);
2042
1987
  }
2043
1988
 
2044
1989
  /**
@@ -2115,7 +2060,7 @@ export class Renderer {
2115
2060
  this.#scene_sdfs.clear();
2116
2061
 
2117
2062
  this.#autoexposure?.destroy();
2118
- this.#tonemap_aces2_tables.destroy();
2063
+ this.tone_mapper?.destroy();
2119
2064
  this.#depth_of_field?.destroy();
2120
2065
  this.#depth_of_field_unreal?.destroy();
2121
2066
  this.#restir_di?.destroy();
@@ -2242,7 +2187,7 @@ export class Renderer {
2242
2187
  configured_color_space = configuration.colorSpace ?? 'srgb';
2243
2188
  }
2244
2189
 
2245
- this.#tonemap_settings.set_canvas_color_space(configured_color_space);
2190
+ this.tone_mapper.display.set_canvas_color_space(configured_color_space);
2246
2191
  }
2247
2192
 
2248
2193
  #apply_size() {
@@ -3525,30 +3470,12 @@ export class Renderer {
3525
3470
 
3526
3471
  current_color_out = record_scene_color.color;
3527
3472
 
3528
- const tonemap_shader = this.#tonemap_shader();
3529
-
3530
- // every pass reads from the settings only the members its immediate struct names: the canvas's primaries
3531
- // from its working space, and, on an HDR display, the peak
3532
- const tonemap_inputs = {
3473
+ current_color_out = this.tone_mapper.render({
3474
+ graph,
3533
3475
  input_color: current_color_out,
3534
- settings: this.#tonemap_settings,
3535
3476
  exposure,
3536
- };
3537
-
3538
- if (tonemap_shader === shader_tonemap_HDR_aces) {
3539
- // the two ACES 2.0 transforms for this display, rebuilt only when the display changed
3540
- const display = this.#tonemap_settings;
3541
- const tables = this.#tonemap_aces2_tables;
3542
-
3543
- tables.update(display.peak_nits);
3544
- tonemap_inputs.aces2_tables = graph_import_buffer(graph, tables.gpu_buffer(this.device), "tonemap/aces2 tables");
3545
- }
3546
-
3547
- [current_color_out] = graph_image_pass({
3548
- graph,
3549
- shader: tonemap_shader,
3550
- inputs: tonemap_inputs,
3551
- output: [gr_texture_canvas]
3477
+ hdr: this.#hdr_supported,
3478
+ target: gr_texture_canvas,
3552
3479
  });
3553
3480
 
3554
3481
  /*
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `animation_curve_evaluate_keys(keys, first, count, time)`: one curve at `time`, as `AnimationCurve.evaluate`
3
+ * evaluates it, from a run of `count` keyframes of a plain storage array, `first` onwards, in ascending time order.
4
+ * `count` is at least 1.
5
+ *
6
+ * The same answer as {@link chunk_animation_curve_evaluate}, which reads its keyframes from the animation database:
7
+ * the first key's value at or before the first key, the last key's at or past the last, and between them the Hermite
8
+ * piece from the last key at or before `time`, so two keys at one time are a step there. ⌈log2(count - 1)⌉ probes.
9
+ *
10
+ * @type {CodeChunk}
11
+ */
12
+ export const chunk_animation_curve_evaluate_keys: CodeChunk;
13
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
14
+ //# sourceMappingURL=chunk_animation_curve_evaluate_keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_animation_curve_evaluate_keys.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.js"],"names":[],"mappings":"AAKA;;;;;;;;;;GAUG;AACH,kDAFU,SAAS,CA+CjB;0BA5DwB,iCAAiC"}
@@ -0,0 +1,62 @@
1
+ import { chunk_inverse_lerp } from "../shader/chunk/math/chunk_inverse_lerp.js";
2
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
3
+ import { ANIMATION_CURVE_KEYFRAME_STRUCT } from "./ANIMATION_CURVE_KEYFRAME_STRUCT.js";
4
+ import { chunk_animation_curve_evaluate_piece } from "./chunk_animation_curve_evaluate_piece.js";
5
+
6
+ /**
7
+ * `animation_curve_evaluate_keys(keys, first, count, time)`: one curve at `time`, as `AnimationCurve.evaluate`
8
+ * evaluates it, from a run of `count` keyframes of a plain storage array, `first` onwards, in ascending time order.
9
+ * `count` is at least 1.
10
+ *
11
+ * The same answer as {@link chunk_animation_curve_evaluate}, which reads its keyframes from the animation database:
12
+ * the first key's value at or before the first key, the last key's at or past the last, and between them the Hermite
13
+ * piece from the last key at or before `time`, so two keys at one time are a step there. ⌈log2(count - 1)⌉ probes.
14
+ *
15
+ * @type {CodeChunk}
16
+ */
17
+ export const chunk_animation_curve_evaluate_keys = CodeChunk.from(
18
+ //language=WGSL
19
+ `
20
+ fn animation_curve_evaluate_keys(
21
+ keys: ptr<storage, array<${ANIMATION_CURVE_KEYFRAME_STRUCT.wgsl_ref}>, read>,
22
+ first: u32,
23
+ count: u32,
24
+ time: f32,
25
+ ) -> f32 {
26
+ if (count <= 1u || time <= (*keys)[first].time) {
27
+ return (*keys)[first].value;
28
+ }
29
+
30
+ let last = first + count - 1u;
31
+
32
+ if (time >= (*keys)[last].time) {
33
+ return (*keys)[last].value;
34
+ }
35
+
36
+ // time(lo) <= time < time(hi), closed in until they are neighbours
37
+ var lo = first;
38
+ var hi = last;
39
+
40
+ loop {
41
+ if (hi - lo <= 1u) { break; }
42
+
43
+ let mid = lo + ((hi - lo) >> 1u);
44
+
45
+ if ((*keys)[mid].time <= time) {
46
+ lo = mid;
47
+ } else {
48
+ hi = mid;
49
+ }
50
+ }
51
+
52
+ let key0 = (*keys)[lo];
53
+ let key1 = (*keys)[hi];
54
+
55
+ return animation_curve_evaluate_piece(inverse_lerp(key0.time, key1.time, time), key0, key1);
56
+ }
57
+ `, [
58
+ ANIMATION_CURVE_KEYFRAME_STRUCT.declaration_chunk,
59
+ chunk_animation_curve_evaluate_piece,
60
+ chunk_inverse_lerp,
61
+ ]
62
+ );
@@ -7,6 +7,18 @@
7
7
  * Note: GPU and CPU-side states are allowed to diverge but must eventually be synchronized.
8
8
  * This means that a modification on one side must propagate to the other.
9
9
  * see "Rendering 'Assassin's Creed Shadows'" GDC 2025 by Nicolas Lopez
10
+ *
11
+ * **What a row nobody occupies reads as on the GPU.** A shader may read a row by its index without
12
+ * asking the page's occupancy bitmap. To GPU work encoded after {@link update} on the same encoder:
13
+ * - a row of a page that has no slot reads as a record of zeros: the generated readers refuse it;
14
+ * - a row nothing has written, on a page that has a slot, reads as zeros too: a page's records are
15
+ * cleared when it is given a slot, whichever page of whichever table held that slot before;
16
+ * - a row freed with {@link GPUTypedTable#remove} reads as the freed record: zeros, with
17
+ * `GPU_DATABASE_NULL` in its link words and in the first word of its ranges.
18
+ *
19
+ * So a link word of an unoccupied row holds 0 or NULL depending on the row's history, and a reader
20
+ * that skips occupancy must not follow one. {@link GPUTypedTable#clear} sends nothing, so the rows it
21
+ * frees keep their last record on a page that stays allocated.
10
22
  */
11
23
  export class GPUDatabase {
12
24
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"GPUDatabase.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/buffer/table/GPUDatabase.js"],"names":[],"mappings":"AA4CA;;;;;;;;;GASG;AACH;IAEI;;;;OAIG;IACH,iCAFW,eAAe,QAKzB;IA8FD;;;;;;OAMG;IACH;QAL0C,UAAU,EAAzC,qBAAqB;QACF,MAAM;QACR,KAAK,GAAtB,MAAM;QACW,uBAAuB,GAAxC,MAAM;OAkJhB;IAlPD;;;OAGG;IACH,YAFU,qBAAqB,CAEpB;IAEX;;;;OAIG;IACH,QAFU,oBAAe,CAElB;IASP;;;OAGG;IACH,kBAAO;IAmDP;;OAEG;IACH,8BAEC;IAED;;;;OAIG;IACH,oBAEC;IA2JD;;;;;OAKG;IACH,UAHW,MAAM,GACJ,qBAAc,SAAS,CAUnC;IAGD;;;;;;;;;;;OAWG;IACH,oCAcC;IAED;;;;;OAKG;IACH,gCAEC;IAoPD;;;;;;;;;;;OAWG;IACH,kCAeC;IAED;;;OAGG;IACH,gBAFW,sBAAsB,QA6FhC;IAkPD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,2BAJW,MAAM,GACJ,QAAQ,KAAG,CAAC,CA6HxB;IAED;;;;;;;OAOG;IACH,+BAJW,MAAM,iBACN,MAAM,GACJ,YAAU,CAkCtB;IAED;;;OAGG;IACH,+BAQC;IAED;;OAEG;IACH,gBASC;;CACJ;8BAvpCY,OAAO,6CAA6C,EAAE,eAAe;qCACrE,OAAO,2CAA2C,EAAE,sBAAsB;oCAC1E,OAAO,4BAA4B,EAAE,qBAAqB;8BAPzC,oBAAoB;oCALd,0BAA0B"}
1
+ {"version":3,"file":"GPUDatabase.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/buffer/table/GPUDatabase.js"],"names":[],"mappings":"AA4CA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;IAEI;;;;OAIG;IACH,iCAFW,eAAe,QAKzB;IA8GD;;;;;;OAMG;IACH;QAL0C,UAAU,EAAzC,qBAAqB;QACF,MAAM;QACR,KAAK,GAAtB,MAAM;QACW,uBAAuB,GAAxC,MAAM;OAkJhB;IAlQD;;;OAGG;IACH,YAFU,qBAAqB,CAEpB;IAEX;;;;OAIG;IACH,QAFU,oBAAe,CAElB;IASP;;;OAGG;IACH,kBAAO;IAmEP;;OAEG;IACH,8BAEC;IAED;;;;OAIG;IACH,oBAEC;IA2JD;;;;;OAKG;IACH,UAHW,MAAM,GACJ,qBAAc,SAAS,CAUnC;IAGD;;;;;;;;;;;OAWG;IACH,oCAcC;IAED;;;;;OAKG;IACH,gCAEC;IA4PD;;;;;;;;;;;OAWG;IACH,kCAeC;IAED;;;OAGG;IACH,gBAFW,sBAAsB,QAgGhC;IAgSD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,2BAJW,MAAM,GACJ,QAAQ,KAAG,CAAC,CA6HxB;IAED;;;;;;;OAOG;IACH,+BAJW,MAAM,iBACN,MAAM,GACJ,YAAU,CAkCtB;IAED;;;OAGG;IACH,+BAQC;IAED;;OAEG;IACH,gBASC;;CACJ;8BA5uCY,OAAO,6CAA6C,EAAE,eAAe;qCACrE,OAAO,2CAA2C,EAAE,sBAAsB;oCAC1E,OAAO,4BAA4B,EAAE,qBAAqB;8BAPzC,oBAAoB;oCALd,0BAA0B"}
@@ -51,6 +51,18 @@ const UPLOAD_CHUNK_SIZE = 256 * KILOBYTE;
51
51
  * Note: GPU and CPU-side states are allowed to diverge but must eventually be synchronized.
52
52
  * This means that a modification on one side must propagate to the other.
53
53
  * see "Rendering 'Assassin's Creed Shadows'" GDC 2025 by Nicolas Lopez
54
+ *
55
+ * **What a row nobody occupies reads as on the GPU.** A shader may read a row by its index without
56
+ * asking the page's occupancy bitmap. To GPU work encoded after {@link update} on the same encoder:
57
+ * - a row of a page that has no slot reads as a record of zeros: the generated readers refuse it;
58
+ * - a row nothing has written, on a page that has a slot, reads as zeros too: a page's records are
59
+ * cleared when it is given a slot, whichever page of whichever table held that slot before;
60
+ * - a row freed with {@link GPUTypedTable#remove} reads as the freed record: zeros, with
61
+ * `GPU_DATABASE_NULL` in its link words and in the first word of its ranges.
62
+ *
63
+ * So a link word of an unoccupied row holds 0 or NULL depending on the row's history, and a reader
64
+ * that skips occupancy must not follow one. {@link GPUTypedTable#clear} sends nothing, so the rows it
65
+ * frees keep their last record on a page that stays allocated.
54
66
  */
55
67
  export class GPUDatabase {
56
68
 
@@ -130,6 +142,22 @@ export class GPUDatabase {
130
142
  */
131
143
  #page_buffer_pool;
132
144
 
145
+ /**
146
+ * The pages given a slot since {@link #clear_new_page_records} last ran, each after its table,
147
+ * flattened as `[table, page, table, page, …]` over the first {@link #pages_given_slots_length}
148
+ * entries. Entries past that are `null`. The array is never shortened, so it keeps its storage
149
+ * from one update to the next.
150
+ *
151
+ * @type {Array<GPUTypedTable|GPUPageMetadata|null>}
152
+ */
153
+ #pages_given_slots = [];
154
+
155
+ /**
156
+ * How many entries of {@link #pages_given_slots} are live: twice the number of pages.
157
+ * @type {number}
158
+ */
159
+ #pages_given_slots_length = 0;
160
+
133
161
  /**
134
162
  * Batched row readback, built on first use.
135
163
  *
@@ -557,6 +585,14 @@ export class GPUDatabase {
557
585
 
558
586
  page.slot_offset = slot_offset;
559
587
 
588
+ const given = this.#pages_given_slots;
589
+ const given_length = this.#pages_given_slots_length;
590
+
591
+ given[given_length] = table;
592
+ given[given_length + 1] = page;
593
+
594
+ this.#pages_given_slots_length = given_length + 2;
595
+
560
596
  const alloc_idx = table.descriptor.page_lookup_address + page_index;
561
597
 
562
598
  this.#allocation_table[alloc_idx] = slot_offset + this.#data_start_offset;
@@ -675,6 +711,9 @@ export class GPUDatabase {
675
711
  this.#deallocate_empty_pages(table);
676
712
  }
677
713
 
714
+ // after every page has its slot, and before the record uploads that land on top
715
+ this.#clear_new_page_records(encoder);
716
+
678
717
  // update allocation table — only the dirty range
679
718
  if (this.#alloc_table_dirty_min <= this.#alloc_table_dirty_max) {
680
719
  const min_byte = this.#alloc_table_dirty_min * Uint32Array.BYTES_PER_ELEMENT;
@@ -732,6 +771,52 @@ export class GPUDatabase {
732
771
  }
733
772
  }
734
773
 
774
+ /**
775
+ * Clear the records of every page given a slot since this last ran, so that a row nothing has
776
+ * written reads as a record of zeros and not as whatever the slot's previous page, of this table
777
+ * or any other, left there. See the class documentation for what an unoccupied row reads as.
778
+ *
779
+ * Called once every page has its slot: growing the buffer moves pages to new slots, so a clear
780
+ * encoded before the move would land in the buffer being replaced. The header is left alone
781
+ * because it goes up through the queue, and a queue write lands ahead of the whole submission —
782
+ * a clear over it would erase it. The record uploads, encoded after this, land on top.
783
+ *
784
+ * @param {ShadeGPUCommandContext} encoder
785
+ */
786
+ #clear_new_page_records(encoder) {
787
+ const pages = this.#pages_given_slots;
788
+ const length = this.#pages_given_slots_length;
789
+
790
+ if (length === 0) {
791
+ return;
792
+ }
793
+
794
+ const word_size = GPU_DATABASE_BUFFER_ELEMENT_TYPE.size;
795
+ const data_start = this.#data_start_offset;
796
+
797
+ for (let i = 0; i < length; i += 2) {
798
+ const descriptor = /** @type {GPUTypedTable} */ (pages[i]).descriptor;
799
+ const slot_offset = /** @type {GPUPageMetadata} */ (pages[i + 1]).slot_offset;
800
+
801
+ // let go of both, so a freed page is not kept alive by the list
802
+ pages[i] = null;
803
+ pages[i + 1] = null;
804
+
805
+ if (slot_offset === -1) {
806
+ // emptied in the same update, and its slot already given back
807
+ continue;
808
+ }
809
+
810
+ encoder.clearBuffer(
811
+ this.buffer,
812
+ (slot_offset + data_start + descriptor.page_header_words) * word_size,
813
+ descriptor.elements_per_page * descriptor.packed_element_size_bytes
814
+ );
815
+ }
816
+
817
+ this.#pages_given_slots_length = 0;
818
+ }
819
+
735
820
  /**
736
821
  * Dispatch a table's pending whole-record writes, chunked so no single transient buffer grows
737
822
  * past {@link UPLOAD_CHUNK_SIZE}. Rewinds the buffer.
@@ -48,7 +48,8 @@ export class GPUDatabaseDefinition {
48
48
  * it into every link word the row has, whatever `nullable` says, because a freed row points
49
49
  * nowhere; a new page starts with it in every link word too. So a link no write has touched names
50
50
  * no row, on a row never written as on one freed, and a value that leaves a link out leaves it
51
- * naming nothing.
51
+ * naming nothing. That holds on the GPU for every occupied row and every freed one; a row the GPU
52
+ * has never been sent reads 0 there instead (see {@link GPUDatabase}).
52
53
  *
53
54
  * `owning` means one thing: removing the row that holds the link removes the row it names, and
54
55
  * that row's owned rows in turn ({@link GPUTypedTable#remove}). Nothing else follows it.