@woosh/meep-engine 3.46.0 → 3.47.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 (230) hide show
  1. package/editor/actions/concrete/TransformModifyAction.d.ts.map +1 -1
  2. package/editor/actions/concrete/TransformModifyAction.js +10 -2
  3. package/editor/ecs/component/FieldDescriptor.js +15 -0
  4. package/editor/ecs/component/createObjectEditor.js +41 -12
  5. package/editor/ecs/component/editors/ecs/Transform64Editor.d.ts.map +1 -1
  6. package/editor/ecs/component/editors/ecs/Transform64Editor.js +77 -70
  7. package/editor/tools/TransformToolV2.d.ts.map +1 -1
  8. package/editor/tools/TransformToolV2.js +4 -0
  9. package/editor/tools/v2/TransformControls.d.ts.map +1 -1
  10. package/editor/tools/v2/TransformControls.js +7 -0
  11. package/editor/view/ecs/EntityEditor.d.ts.map +1 -1
  12. package/editor/view/ecs/EntityEditor.js +4 -2
  13. package/package.json +1 -1
  14. package/src/core/collection/array/array_insert_at.d.ts +16 -0
  15. package/src/core/collection/array/array_insert_at.d.ts.map +1 -0
  16. package/src/core/collection/array/array_insert_at.js +32 -0
  17. package/src/core/collection/array/array_remove_at.d.ts +15 -0
  18. package/src/core/collection/array/array_remove_at.d.ts.map +1 -0
  19. package/src/core/collection/array/array_remove_at.js +30 -0
  20. package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts +37 -0
  21. package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts.map +1 -0
  22. package/src/core/geom/3d/quaternion/quat3_look_rotation.js +172 -0
  23. package/src/core/geom/Quaternion.d.ts +1 -0
  24. package/src/core/geom/Quaternion.d.ts.map +1 -1
  25. package/src/core/geom/Quaternion.js +12 -48
  26. package/src/engine/Engine.d.ts.map +1 -1
  27. package/src/engine/Engine.js +9 -4
  28. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  29. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +10 -0
  30. package/src/engine/ecs/transform/t64_look_rotation.d.ts +4 -4
  31. package/src/engine/ecs/transform/t64_look_rotation.d.ts.map +1 -1
  32. package/src/engine/ecs/transform/t64_look_rotation.js +7 -18
  33. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  34. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +30 -1
  35. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +6 -0
  36. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
  37. package/src/engine/graphics3/GPUParticleEmitterSystem.js +72 -29
  38. package/src/engine/input/devices/KeyboardDevice.d.ts +1 -0
  39. package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
  40. package/src/engine/input/devices/KeyboardDevice.js +7 -6
  41. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  42. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +15 -2
  43. package/src/engine/network/CONGESTION_CONTROL.md +9 -9
  44. package/src/engine/network/MESSAGE_TRANSPORT.md +364 -0
  45. package/src/engine/network/NetworkSession.d.ts +31 -11
  46. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  47. package/src/engine/network/NetworkSession.js +453 -286
  48. package/src/engine/network/README.md +77 -27
  49. package/src/engine/network/SMOOTHNESS_DESIGN.md +13 -5
  50. package/src/engine/network/diagnostics/BandwidthMeter.d.ts +1 -1
  51. package/src/engine/network/diagnostics/BandwidthMeter.js +1 -1
  52. package/src/engine/network/orchestrator/HostJoin.d.ts +111 -0
  53. package/src/engine/network/orchestrator/HostJoin.d.ts.map +1 -0
  54. package/src/engine/network/orchestrator/HostJoin.js +271 -0
  55. package/src/engine/network/orchestrator/NetworkPeer.d.ts +151 -112
  56. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  57. package/src/engine/network/orchestrator/NetworkPeer.js +450 -499
  58. package/src/engine/network/orchestrator/PendingSlices.d.ts +30 -0
  59. package/src/engine/network/orchestrator/PendingSlices.d.ts.map +1 -0
  60. package/src/engine/network/orchestrator/PendingSlices.js +83 -0
  61. package/src/engine/network/orchestrator/ReliableFrames.d.ts +34 -0
  62. package/src/engine/network/orchestrator/ReliableFrames.d.ts.map +1 -0
  63. package/src/engine/network/orchestrator/ReliableFrames.js +96 -0
  64. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +77 -10
  65. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  66. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +236 -61
  67. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +20 -6
  68. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  69. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +33 -8
  70. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  71. package/src/engine/network/replication/Replicator.js +7 -1
  72. package/src/engine/network/sim/ActionLog.d.ts +32 -5
  73. package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
  74. package/src/engine/network/sim/ActionLog.js +47 -5
  75. package/src/engine/network/sim/SimActionExecutor.d.ts +42 -2
  76. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  77. package/src/engine/network/sim/SimActionExecutor.js +100 -4
  78. package/src/engine/network/sim/Snapshotter.d.ts +12 -0
  79. package/src/engine/network/sim/Snapshotter.d.ts.map +1 -1
  80. package/src/engine/network/sim/Snapshotter.js +43 -0
  81. package/src/engine/network/state/Baseline.d.ts +1 -1
  82. package/src/engine/network/state/Baseline.js +1 -1
  83. package/src/engine/network/state/FrameBufferRing.d.ts +25 -6
  84. package/src/engine/network/state/FrameBufferRing.d.ts.map +1 -1
  85. package/src/engine/network/state/FrameBufferRing.js +51 -6
  86. package/src/engine/network/state/InputRing.d.ts +4 -0
  87. package/src/engine/network/state/InputRing.d.ts.map +1 -1
  88. package/src/engine/network/state/InputRing.js +7 -0
  89. package/src/engine/network/transport/DeferredTransport.d.ts.map +1 -1
  90. package/src/engine/network/transport/DeferredTransport.js +1 -0
  91. package/src/engine/network/transport/LoopbackTransport.d.ts.map +1 -1
  92. package/src/engine/network/transport/LoopbackTransport.js +4 -2
  93. package/src/engine/network/transport/Transport.d.ts +7 -0
  94. package/src/engine/network/transport/Transport.d.ts.map +1 -1
  95. package/src/engine/network/transport/Transport.js +8 -0
  96. package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
  97. package/src/engine/network/transport/adapters/NodeUDPTransport.js +20 -5
  98. package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.d.ts.map +1 -1
  99. package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.js +8 -0
  100. package/src/engine/network/transport/adapters/WebTransportTransport.d.ts.map +1 -1
  101. package/src/engine/network/transport/adapters/WebTransportTransport.js +6 -0
  102. package/src/engine/network/transport/connection/Connection.d.ts +191 -0
  103. package/src/engine/network/transport/connection/Connection.d.ts.map +1 -0
  104. package/src/engine/network/transport/connection/Connection.js +1262 -0
  105. package/src/engine/network/transport/connection/RangeSet.d.ts +94 -0
  106. package/src/engine/network/transport/connection/RangeSet.d.ts.map +1 -0
  107. package/src/engine/network/transport/connection/RangeSet.js +260 -0
  108. package/src/engine/network/transport/connection/RxStream.d.ts +48 -0
  109. package/src/engine/network/transport/connection/RxStream.d.ts.map +1 -0
  110. package/src/engine/network/transport/connection/RxStream.js +211 -0
  111. package/src/engine/network/transport/connection/TxStream.d.ts +90 -0
  112. package/src/engine/network/transport/connection/TxStream.d.ts.map +1 -0
  113. package/src/engine/network/transport/connection/TxStream.js +243 -0
  114. package/src/engine/network/transport/connection/bytes_copy.d.ts +17 -0
  115. package/src/engine/network/transport/connection/bytes_copy.d.ts.map +1 -0
  116. package/src/engine/network/transport/connection/bytes_copy.js +34 -0
  117. package/src/engine/network/transport/connection/varint.d.ts +46 -0
  118. package/src/engine/network/transport/connection/varint.d.ts.map +1 -0
  119. package/src/engine/network/transport/connection/varint.js +107 -0
  120. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  121. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts +38 -7
  122. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts.map +1 -1
  123. package/src/engine/sound/ecs/audio/AudioEmitter.js +35 -7
  124. package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.d.ts.map +1 -1
  125. package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.js +5 -1
  126. package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts +18 -0
  127. package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts.map +1 -0
  128. package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.js +48 -0
  129. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts +12 -2
  130. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts.map +1 -1
  131. package/src/engine/sound/ecs/audio/AudioEmitterSystem.js +173 -9
  132. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts +9 -3
  133. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -1
  134. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +28 -8
  135. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts +8 -0
  136. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts.map +1 -1
  137. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.d.ts.map +1 -1
  138. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.js +5 -1
  139. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts +18 -0
  140. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts.map +1 -0
  141. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.js +51 -0
  142. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.d.ts.map +1 -1
  143. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.js +15 -1
  144. package/src/engine/sound/sopra/README.md +768 -644
  145. package/src/engine/sound/sopra/SopraEngine.d.ts +104 -8
  146. package/src/engine/sound/sopra/SopraEngine.d.ts.map +1 -1
  147. package/src/engine/sound/sopra/SopraEngine.js +327 -12
  148. package/src/engine/sound/sopra/definition/EventDescription.d.ts +28 -2
  149. package/src/engine/sound/sopra/definition/EventDescription.d.ts.map +1 -1
  150. package/src/engine/sound/sopra/definition/EventDescription.js +55 -5
  151. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts +10 -0
  152. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts.map +1 -1
  153. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.js +77 -55
  154. package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts +31 -0
  155. package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts.map +1 -0
  156. package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.js +75 -0
  157. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts +38 -9
  158. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts.map +1 -1
  159. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.js +34 -5
  160. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts +7 -2
  161. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts.map +1 -1
  162. package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +137 -122
  163. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts +3 -1
  164. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts.map +1 -1
  165. package/src/engine/sound/sopra/definition/effect/EqEffect.js +146 -131
  166. package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts +1 -0
  167. package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts.map +1 -1
  168. package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +6 -1
  169. package/src/engine/sound/sopra/runtime/BusGraph.d.ts +44 -2
  170. package/src/engine/sound/sopra/runtime/BusGraph.d.ts.map +1 -1
  171. package/src/engine/sound/sopra/runtime/BusGraph.js +83 -43
  172. package/src/engine/sound/sopra/runtime/EffectChain.d.ts +96 -0
  173. package/src/engine/sound/sopra/runtime/EffectChain.d.ts.map +1 -0
  174. package/src/engine/sound/sopra/runtime/EffectChain.js +286 -0
  175. package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts +123 -0
  176. package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts.map +1 -0
  177. package/src/engine/sound/sopra/runtime/EffectParamOverrides.js +320 -0
  178. package/src/engine/sound/sopra/runtime/EventInstance.d.ts +55 -5
  179. package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
  180. package/src/engine/sound/sopra/runtime/EventInstance.js +201 -26
  181. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts +2 -1
  182. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts.map +1 -1
  183. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.js +6 -1
  184. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts +15 -0
  185. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts.map +1 -1
  186. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.js +32 -0
  187. package/src/engine/sound/sopra/util/MockAudioContext.d.ts.map +1 -1
  188. package/src/engine/sound/sopra/util/MockAudioContext.js +3 -0
  189. package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts +13 -3
  190. package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts.map +1 -1
  191. package/src/engine/sound/sopra/util/fadeOutAndStop.js +25 -13
  192. package/src/shade/RENDERER_CONTRACT.md +6 -3
  193. package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts +24 -0
  194. package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts.map +1 -0
  195. package/src/shade/device/SHADE_DEVICE_FLOOR.js +34 -0
  196. package/src/shade/device/ShadeDeviceFailure.d.ts +12 -5
  197. package/src/shade/device/ShadeDeviceFailure.d.ts.map +1 -1
  198. package/src/shade/device/ShadeDeviceFailure.js +17 -8
  199. package/src/shade/device/ShadeDeviceFailureReason.d.ts +1 -1
  200. package/src/shade/device/ShadeDeviceFailureReason.js +2 -2
  201. package/src/shade/device/shade_device_floor_unmet.d.ts +13 -0
  202. package/src/shade/device/shade_device_floor_unmet.d.ts.map +1 -0
  203. package/src/shade/device/shade_device_floor_unmet.js +32 -0
  204. package/src/shade/renderer/Renderer.d.ts +2 -0
  205. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  206. package/src/shade/renderer/Renderer.js +29 -55
  207. package/src/shade/renderer/buffer/GPUBufferAllocator.d.ts.map +1 -1
  208. package/src/shade/renderer/buffer/GPUBufferAllocator.js +9 -0
  209. package/src/shade/renderer/buffer/buffer_pool_ops.d.ts +21 -12
  210. package/src/shade/renderer/buffer/buffer_pool_ops.d.ts.map +1 -1
  211. package/src/shade/renderer/buffer/buffer_pool_ops.js +18 -19
  212. package/src/shade/renderer/gpu_primitive/test/gpu_test.d.ts.map +1 -1
  213. package/src/shade/renderer/gpu_primitive/test/gpu_test.js +8 -11
  214. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  215. package/src/shade/renderer/pool/TransientResourcePool.d.ts +24 -0
  216. package/src/shade/renderer/pool/TransientResourcePool.d.ts.map +1 -1
  217. package/src/shade/renderer/pool/TransientResourcePool.js +41 -10
  218. package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
  219. package/src/shade/renderer/shader/ComputeShader.js +18 -2
  220. package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
  221. package/src/shade/renderer/shader/ImageShader.js +230 -218
  222. package/src/view/graphics/GraphicsContextFailureView.d.ts +1 -2
  223. package/src/view/graphics/GraphicsContextFailureView.d.ts.map +1 -1
  224. package/src/view/graphics/GraphicsContextFailureView.js +1 -2
  225. package/src/engine/network/transport/Channel.js +0 -336
  226. package/src/engine/network/transport/ReliableCommandPipeline.js +0 -335
  227. package/src/engine/network/transport/fragments/FragmentAssembler.js +0 -350
  228. package/src/engine/network/transport/fragments/FragmentRetention.js +0 -191
  229. package/src/engine/network/transport/fragments/fragment_send.js +0 -157
  230. package/src/engine/network/transport/fragments/packet_size.js +0 -107
@@ -2,12 +2,18 @@
2
2
  * Why there is no usable device, in a form a host can act on.
3
3
  *
4
4
  * It is an `Error` because that is what the failure paths already throw and callers already
5
- * `catch`, and it carries a {@link ShadeDeviceFailureReason} because a host showing this to a player
5
+ * `catch`, and it carries a {@link ShadeDeviceFailureReason} because a host showing this to a person
6
6
  * needs to distinguish "your browser cannot do this at all" from "your GPU is below what this needs"
7
7
  * from "the GPU went away" — three different things to tell somebody, and none of them a stack
8
8
  * trace.
9
9
  *
10
- * `detail` holds the specific thing that was missing, for the log rather than the player.
10
+ * The `message` is written to be shown as it is. Where the specifics are something a person can act
11
+ * on — which features and limits the hardware lacks, what the browser refused — it names them, so
12
+ * that what reaches a support thread is the answer rather than a request for logs. `detail` holds
13
+ * the specifics alone, for a host that phrases its own message.
14
+ *
15
+ * Nothing here assumes what the application is: the same engine runs games, CAD tools and product
16
+ * visualizers, and they all show these messages.
11
17
  */
12
18
  export class ShadeDeviceFailure extends Error {
13
19
  /**
@@ -19,12 +25,13 @@ export class ShadeDeviceFailure extends Error {
19
25
  */
20
26
  static adapter_unavailable(): ShadeDeviceFailure;
21
27
  /**
22
- * @param {string} detail what was missing
28
+ * @param {string[]} unmet every requirement the adapter falls short of, as
29
+ * {@link shade_device_floor_unmet} phrases them
23
30
  * @returns {ShadeDeviceFailure}
24
31
  */
25
- static below_floor(detail: string): ShadeDeviceFailure;
32
+ static below_floor(unmet: string[]): ShadeDeviceFailure;
26
33
  /**
27
- * @param {string} detail
34
+ * @param {string} detail what the browser said when it refused
28
35
  * @returns {ShadeDeviceFailure}
29
36
  */
30
37
  static device_request_failed(detail: string): ShadeDeviceFailure;
@@ -1 +1 @@
1
- {"version":3,"file":"ShadeDeviceFailure.d.ts","sourceRoot":"","sources":["../../../../src/shade/device/ShadeDeviceFailure.js"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH;IA2BI;;OAEG;IACH,6BAFa,kBAAkB,CAQ9B;IAED;;OAEG;IACH,8BAFa,kBAAkB,CAQ9B;IAED;;;OAGG;IACH,2BAHW,MAAM,GACJ,kBAAkB,CAQ9B;IAED;;;OAGG;IACH,qCAHW,MAAM,GACJ,kBAAkB,CAQ9B;IAED;;;OAGG;IACH,2BAHW,MAAM,GACJ,kBAAkB,CAQ9B;IArED;;;;OAIG;IACH,oBAJW,wBAAwB,WACxB,MAAM,WACN,MAAM,EAQhB;IAxBD;;OAEG;IACH,QAFU,wBAAwB,CAEkB;IAEpD;;;;;OAKG;IACH,QAFU,MAAM,CAEJ;IA0EhB;;;OAGG;IACH,+BAFU,OAAO,CAEgC;CANhD;yCAjGwC,+BAA+B"}
1
+ {"version":3,"file":"ShadeDeviceFailure.d.ts","sourceRoot":"","sources":["../../../../src/shade/device/ShadeDeviceFailure.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH;IA2BI;;OAEG;IACH,6BAFa,kBAAkB,CAQ9B;IAED;;OAEG;IACH,8BAFa,kBAAkB,CAQ9B;IAED;;;;OAIG;IACH,0BAJW,MAAM,EAAE,GAEN,kBAAkB,CAU9B;IAED;;;OAGG;IACH,qCAHW,MAAM,GACJ,kBAAkB,CAQ9B;IAED;;;OAGG;IACH,2BAHW,MAAM,GACJ,kBAAkB,CAQ9B;IAxED;;;;OAIG;IACH,oBAJW,wBAAwB,WACxB,MAAM,WACN,MAAM,EAQhB;IAxBD;;OAEG;IACH,QAFU,wBAAwB,CAEkB;IAEpD;;;;;OAKG;IACH,QAFU,MAAM,CAEJ;IA6EhB;;;OAGG;IACH,+BAFU,OAAO,CAEgC;CANhD;yCA1GwC,+BAA+B"}
@@ -4,12 +4,18 @@ import { ShadeDeviceFailureReason } from "./ShadeDeviceFailureReason.js";
4
4
  * Why there is no usable device, in a form a host can act on.
5
5
  *
6
6
  * It is an `Error` because that is what the failure paths already throw and callers already
7
- * `catch`, and it carries a {@link ShadeDeviceFailureReason} because a host showing this to a player
7
+ * `catch`, and it carries a {@link ShadeDeviceFailureReason} because a host showing this to a person
8
8
  * needs to distinguish "your browser cannot do this at all" from "your GPU is below what this needs"
9
9
  * from "the GPU went away" — three different things to tell somebody, and none of them a stack
10
10
  * trace.
11
11
  *
12
- * `detail` holds the specific thing that was missing, for the log rather than the player.
12
+ * The `message` is written to be shown as it is. Where the specifics are something a person can act
13
+ * on — which features and limits the hardware lacks, what the browser refused — it names them, so
14
+ * that what reaches a support thread is the answer rather than a request for logs. `detail` holds
15
+ * the specifics alone, for a host that phrases its own message.
16
+ *
17
+ * Nothing here assumes what the application is: the same engine runs games, CAD tools and product
18
+ * visualizers, and they all show these messages.
13
19
  */
14
20
  export class ShadeDeviceFailure extends Error {
15
21
  /**
@@ -44,7 +50,7 @@ export class ShadeDeviceFailure extends Error {
44
50
  static webgpu_unavailable() {
45
51
  return new ShadeDeviceFailure(
46
52
  ShadeDeviceFailureReason.WebGPUUnavailable,
47
- "This browser does not support WebGPU, which this game requires.",
53
+ "This browser does not support WebGPU, which this application requires.",
48
54
  "navigator.gpu is undefined"
49
55
  );
50
56
  }
@@ -61,25 +67,28 @@ export class ShadeDeviceFailure extends Error {
61
67
  }
62
68
 
63
69
  /**
64
- * @param {string} detail what was missing
70
+ * @param {string[]} unmet every requirement the adapter falls short of, as
71
+ * {@link shade_device_floor_unmet} phrases them
65
72
  * @returns {ShadeDeviceFailure}
66
73
  */
67
- static below_floor(detail) {
74
+ static below_floor(unmet) {
75
+ const detail = unmet.join('; ');
76
+
68
77
  return new ShadeDeviceFailure(
69
78
  ShadeDeviceFailureReason.BelowFloor,
70
- "This graphics hardware is below the minimum this game requires.",
79
+ `This graphics hardware does not meet this application's minimum requirements: ${detail}.`,
71
80
  detail
72
81
  );
73
82
  }
74
83
 
75
84
  /**
76
- * @param {string} detail
85
+ * @param {string} detail what the browser said when it refused
77
86
  * @returns {ShadeDeviceFailure}
78
87
  */
79
88
  static device_request_failed(detail) {
80
89
  return new ShadeDeviceFailure(
81
90
  ShadeDeviceFailureReason.DeviceRequestFailed,
82
- "The graphics device could not be created.",
91
+ `The graphics device could not be created: ${detail}`,
83
92
  detail
84
93
  );
85
94
  }
@@ -4,7 +4,7 @@
4
4
  * The device floor is deliberate and fixed (D6/I-8): there are no degradation tiers, no WebGL
5
5
  * fallback and no feature-detection branches. Hardware below the floor is not accommodated — it is
6
6
  * told, clearly, that it cannot run this. That makes the *message* the entire below-floor
7
- * behaviour the engine owes, and a reason code is what lets a host phrase it for a player rather
7
+ * behaviour the engine owes, and a reason code is what lets a host phrase it for a person rather
8
8
  * than showing them a stack trace.
9
9
  */
10
10
  export type ShadeDeviceFailureReason = number;
@@ -4,7 +4,7 @@
4
4
  * The device floor is deliberate and fixed (D6/I-8): there are no degradation tiers, no WebGL
5
5
  * fallback and no feature-detection branches. Hardware below the floor is not accommodated — it is
6
6
  * told, clearly, that it cannot run this. That makes the *message* the entire below-floor
7
- * behaviour the engine owes, and a reason code is what lets a host phrase it for a player rather
7
+ * behaviour the engine owes, and a reason code is what lets a host phrase it for a person rather
8
8
  * than showing them a stack trace.
9
9
  *
10
10
  * @enum {number}
@@ -23,7 +23,7 @@ export const ShadeDeviceFailureReason = {
23
23
 
24
24
  /**
25
25
  * An adapter exists and is below the floor — a required feature or limit is missing. The
26
- * failure names which one.
26
+ * failure names every one.
27
27
  */
28
28
  BelowFloor: 2,
29
29
 
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Every way `adapter` falls short of {@link SHADE_DEVICE_FLOOR}, one phrase per gap, naming the
3
+ * feature or the limit and, for a limit, what the adapter offers against what is required. Empty
4
+ * when the adapter meets the floor.
5
+ *
6
+ * All of them rather than the first: somebody told about one gap at a time has to come back once per
7
+ * gap to learn whether their hardware can ever run this.
8
+ *
9
+ * @param {GPUAdapter} adapter
10
+ * @returns {string[]}
11
+ */
12
+ export function shade_device_floor_unmet(adapter: GPUAdapter): string[];
13
+ //# sourceMappingURL=shade_device_floor_unmet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shade_device_floor_unmet.d.ts","sourceRoot":"","sources":["../../../../src/shade/device/shade_device_floor_unmet.js"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,+DAFa,MAAM,EAAE,CAoBpB"}
@@ -0,0 +1,32 @@
1
+ import { SHADE_DEVICE_FLOOR } from "./SHADE_DEVICE_FLOOR.js";
2
+
3
+ /**
4
+ * Every way `adapter` falls short of {@link SHADE_DEVICE_FLOOR}, one phrase per gap, naming the
5
+ * feature or the limit and, for a limit, what the adapter offers against what is required. Empty
6
+ * when the adapter meets the floor.
7
+ *
8
+ * All of them rather than the first: somebody told about one gap at a time has to come back once per
9
+ * gap to learn whether their hardware can ever run this.
10
+ *
11
+ * @param {GPUAdapter} adapter
12
+ * @returns {string[]}
13
+ */
14
+ export function shade_device_floor_unmet(adapter) {
15
+ const unmet = [];
16
+
17
+ for (const feature of SHADE_DEVICE_FLOOR.features) {
18
+ if (!adapter.features.has(feature)) {
19
+ unmet.push(`feature '${feature}' is not supported`);
20
+ }
21
+ }
22
+
23
+ for (const [name, required] of Object.entries(SHADE_DEVICE_FLOOR.limits)) {
24
+ const offered = adapter.limits[name];
25
+
26
+ if (offered < required) {
27
+ unmet.push(`limit ${name} is ${offered}, at least ${required} is required`);
28
+ }
29
+ }
30
+
31
+ return unmet;
32
+ }
@@ -421,6 +421,8 @@ export class Renderer {
421
421
  */
422
422
  get nss(): NSS;
423
423
  /**
424
+ * Rejects with a {@link ShadeDeviceFailure} when there is no usable device — no WebGPU, no
425
+ * adapter, an adapter below {@link SHADE_DEVICE_FLOOR}, or a refused device request.
424
426
  *
425
427
  * @param {Object} [options]
426
428
  * @param {GPUCanvasContext} [options.context] Optional, if not provided - one will be created.
@@ -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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"}
@@ -11,6 +11,8 @@ import {
11
11
  import { FrameGraph } from "../../engine/graphics/render/frame_graph/FrameGraph.js";
12
12
  import { TextureDescriptor } from "../descriptor/texture/TextureDescriptor.js";
13
13
  import { WebGPUExtensionType } from "../descriptor/WebGPUExtensionType.js";
14
+ import { SHADE_DEVICE_FLOOR } from "../device/SHADE_DEVICE_FLOOR.js";
15
+ import { shade_device_floor_unmet } from "../device/shade_device_floor_unmet.js";
14
16
  import { ShadeDeviceFailure } from "../device/ShadeDeviceFailure.js";
15
17
  import { ShadeGPUCommandContext } from "../device/ShadeGPUCommandContext.js";
16
18
  import { CameraManager } from "./camera/CameraManager.js";
@@ -1375,6 +1377,8 @@ export class Renderer {
1375
1377
  }
1376
1378
 
1377
1379
  /**
1380
+ * Rejects with a {@link ShadeDeviceFailure} when there is no usable device — no WebGPU, no
1381
+ * adapter, an adapter below {@link SHADE_DEVICE_FLOOR}, or a refused device request.
1378
1382
  *
1379
1383
  * @param {Object} [options]
1380
1384
  * @param {GPUCanvasContext} [options.context] Optional, if not provided - one will be created.
@@ -1387,8 +1391,8 @@ export class Renderer {
1387
1391
  pixelRatio = window.devicePixelRatio,
1388
1392
  } = {}) {
1389
1393
 
1390
- if (!('gpu' in navigator)) {
1391
- throw new Error('navigator.gpu not available — WebGPU disabled or unsupported');
1394
+ if (navigator.gpu === undefined) {
1395
+ throw ShadeDeviceFailure.webgpu_unavailable();
1392
1396
  }
1393
1397
 
1394
1398
  this.#update_presentation_format();
@@ -1414,13 +1418,7 @@ export class Renderer {
1414
1418
  if (device === undefined) {
1415
1419
  // no device present, let's create one
1416
1420
 
1417
- const gpu = navigator.gpu;
1418
-
1419
- if (gpu === undefined) {
1420
- throw ShadeDeviceFailure.webgpu_unavailable();
1421
- }
1422
-
1423
- const adapter = await gpu.requestAdapter({
1421
+ const adapter = await navigator.gpu.requestAdapter({
1424
1422
  powerPreference: "high-performance",
1425
1423
  });
1426
1424
 
@@ -1441,27 +1439,22 @@ export class Renderer {
1441
1439
  //
1442
1440
  // console.warn('adapter limits:', adapter.limits);
1443
1441
 
1444
- const maxStorageBuffersPerShaderStage = adapter.limits.maxStorageBuffersPerShaderStage;
1442
+ // The whole floor is checked before a device is asked for, so a refusal names every gap,
1443
+ // with the numbers this adapter offers, rather than whichever one requestDevice trips on.
1444
+ const unmet = shade_device_floor_unmet(adapter);
1445
1445
 
1446
- if (maxStorageBuffersPerShaderStage < 10) {
1447
- throw ShadeDeviceFailure.below_floor(
1448
- `requires at least 10 storage buffers per shader stage, adapter offers ${maxStorageBuffersPerShaderStage}`
1449
- );
1446
+ if (unmet.length > 0) {
1447
+ throw ShadeDeviceFailure.below_floor(unmet);
1450
1448
  }
1451
1449
 
1452
- const requiredFeatures = [
1453
- // required for indirect draw that's used extensively in Shade
1454
- WebGPUExtensionType.IndirectFirstInstance,
1455
- // required for OIT (might be unavailable)
1456
- WebGPUExtensionType.Float32Blendable,
1457
- ];
1450
+ const requiredFeatures = SHADE_DEVICE_FLOOR.features.slice();
1458
1451
 
1459
1452
  // add features if they are available
1460
1453
  const optional_desired = [
1461
1454
  // Profiling only, and some browsers withhold it on hardware that is otherwise
1462
1455
  // fine — so it is taken when offered and the timers go quiet when it is not
1463
1456
  // (E7, sponsor 2026-08-16). Requiring it would refuse to start on those browsers
1464
- // for the sake of a feature the game does not need to run.
1457
+ // for the sake of a feature the renderer does not need to run.
1465
1458
  WebGPUExtensionType.TimestampQuery,
1466
1459
  WebGPUExtensionType.Subgroups,
1467
1460
  WebGPUExtensionType.TextureFormatsTier1,
@@ -1475,35 +1468,28 @@ export class Renderer {
1475
1468
  WebGPUExtensionType.TextureCompressionASTC,
1476
1469
  ];
1477
1470
 
1478
- // valid required features
1479
- for (const feature of requiredFeatures) {
1480
- if (!adapter.features.has(feature)) {
1481
- throw ShadeDeviceFailure.below_floor(`adapter does not support required feature '${feature}'`);
1482
- }
1483
- }
1484
-
1485
1471
  for (const feature of optional_desired) {
1486
1472
  if (adapter.features.has(feature)) {
1487
1473
  requiredFeatures.push(feature);
1488
1474
  }
1489
1475
  }
1490
1476
 
1477
+ try {
1478
+ device = await adapter.requestDevice({
1479
+ requiredLimits: {
1480
+ ...SHADE_DEVICE_FLOOR.limits,
1491
1481
 
1492
- device = await adapter.requestDevice({
1493
- requiredLimits: {
1494
- // required for large G-buffers
1495
- maxColorAttachmentBytesPerSample: 32,
1496
-
1497
- /*
1498
- grab the largest buffer limit we can get, default limits are super-low
1499
- */
1500
- maxBufferSize: adapter.limits.maxBufferSize,
1501
- maxStorageBufferBindingSize: adapter.limits.maxStorageBufferBindingSize,
1502
-
1503
- maxStorageBuffersPerShaderStage: 10,
1504
- },
1505
- requiredFeatures
1506
- });
1482
+ /*
1483
+ grab the largest buffer limit we can get, default limits are super-low
1484
+ */
1485
+ maxBufferSize: adapter.limits.maxBufferSize,
1486
+ maxStorageBufferBindingSize: adapter.limits.maxStorageBufferBindingSize,
1487
+ },
1488
+ requiredFeatures
1489
+ });
1490
+ } catch (error) {
1491
+ throw ShadeDeviceFailure.device_request_failed(error.message);
1492
+ }
1507
1493
 
1508
1494
  // NOTE: according to spec (as of 2025/09/19) - adapter can only be used to create one device, after which it becomes "consumed"
1509
1495
  // see https://www.w3.org/TR/webgpu/#adapters
@@ -1515,18 +1501,6 @@ export class Renderer {
1515
1501
  this.#handle_device_lost(info);
1516
1502
  })
1517
1503
 
1518
- if (context === undefined) {
1519
- const canvas = document.createElement('canvas');
1520
- canvas.width = window.innerWidth;
1521
- canvas.height = window.innerHeight;
1522
-
1523
- context = canvas.getContext('webgpu');
1524
-
1525
- if (context === null) {
1526
- throw new Error('Failed to bind GPUCanvasContext');
1527
- }
1528
- }
1529
-
1530
1504
  assert.ok(device.features.has("indirect-first-instance"), '"indirect-first-instance" feature needs to be enabled for non-zero firstInstance values to be used.')
1531
1505
  assert.isInstanceOf(context, GPUCanvasContext, 'context', 'GPUCanvasContext');
1532
1506
 
@@ -1 +1 @@
1
- {"version":3,"file":"GPUBufferAllocator.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/buffer/GPUBufferAllocator.js"],"names":[],"mappings":"AAUA;;;;;;;;GAQG;AACH;IAOI;;OAEG;IACH,+BAKC;IAED,8BAEC;IAED,gCAEC;IAED,yBAEC;IAED,2BAWC;IAED,mCAEC;;CAoDJ;sCAlHqC,kCAAkC"}
1
+ {"version":3,"file":"GPUBufferAllocator.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/buffer/GPUBufferAllocator.js"],"names":[],"mappings":"AAUA;;;;;;;;GAQG;AACH;IAOI;;OAEG;IACH,+BAKC;IAED,8BAEC;IAED,gCAEC;IAWD,yBAEC;IAED,2BAWC;IAED,mCAEC;;CAoDJ;sCA3HqC,kCAAkC"}
@@ -42,6 +42,15 @@ export class GPUBufferAllocator extends TransientResourcePool {
42
42
  return buffer_compare(a, b);
43
43
  }
44
44
 
45
+ /**
46
+ * The usage the buffer was made with, kept on its record beside the size the pool keeps: the order
47
+ * and the match read both, and a `GPUBuffer`'s are native reads.
48
+ * @param {import("../pool/TransientResourcePool.js").PoolRecord} record
49
+ */
50
+ describeRecord(record) {
51
+ record.usage = record.resource.usage;
52
+ }
53
+
45
54
  sizeOf(buffer) {
46
55
  return buffer.size;
47
56
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Total order over `{usage, size}`-bearing specs (a request descriptor or a live GPUBuffer).
2
+ * Total order over `{usage, size}`-bearing specs: a request descriptor, or a pool record.
3
3
  *
4
4
  * Sorted by size first (so the binary search lands on the smallest fitting buffer), then by usage
5
5
  * *bit-count* (so the narrowest-usage buffer is preferred — wide-usage buffers map to slower driver
@@ -16,29 +16,30 @@ export function compare_memory_spec(a: {
16
16
  usage: number;
17
17
  size: number;
18
18
  }): number;
19
+ /**
20
+ * A pool record as {@link GPUBufferAllocator} keeps one: the buffer, and its `size` and `usage` as they
21
+ * were when it entered the pool. Ordering and matching read those, never the buffer, whose `size` and
22
+ * `usage` are native reads and are visited by the binary search and the scan many times a frame.
23
+ *
24
+ * @typedef {import("../pool/TransientResourcePool.js").PoolRecord & {usage: number}} BufferPoolRecord
25
+ */
19
26
  /**
20
27
  * Record ordering for the pool's sorted insert.
21
28
  *
22
- * @param {{resource:GPUBuffer}} a
23
- * @param {{resource:GPUBuffer}} b
29
+ * @param {BufferPoolRecord} a
30
+ * @param {BufferPoolRecord} b
24
31
  * @returns {number}
25
32
  */
26
- export function buffer_compare(a: {
27
- resource: GPUBuffer;
28
- }, b: {
29
- resource: GPUBuffer;
30
- }): number;
33
+ export function buffer_compare(a: BufferPoolRecord, b: BufferPoolRecord): number;
31
34
  /**
32
35
  * Approximate first-fit: the smallest pooled buffer with `size >= request` and a usage *superset* of
33
36
  * the request, bounded against handing out a much-larger buffer.
34
37
  *
35
- * @param {{resource:GPUBuffer}[]} records sorted under {@link buffer_compare}
38
+ * @param {BufferPoolRecord[]} records sorted under {@link buffer_compare}
36
39
  * @param {{size:number, usage:number}} descriptor
37
40
  * @returns {number} index of a satisfying record, or -1
38
41
  */
39
- export function buffer_find(records: {
40
- resource: GPUBuffer;
41
- }[], descriptor: {
42
+ export function buffer_find(records: BufferPoolRecord[], descriptor: {
42
43
  size: number;
43
44
  usage: number;
44
45
  }): number;
@@ -63,4 +64,12 @@ export const ALLOW_LARGER_LIMIT_SCALE: number;
63
64
  * @type {number}
64
65
  */
65
66
  export const ALLOW_LARGER_LIMIT_FIXED: number;
67
+ /**
68
+ * A pool record as {@link GPUBufferAllocator } keeps one: the buffer, and its `size` and `usage` as they
69
+ * were when it entered the pool. Ordering and matching read those, never the buffer, whose `size` and
70
+ * `usage` are native reads and are visited by the binary search and the scan many times a frame.
71
+ */
72
+ export type BufferPoolRecord = import("../pool/TransientResourcePool.js").PoolRecord & {
73
+ usage: number;
74
+ };
66
75
  //# sourceMappingURL=buffer_pool_ops.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"buffer_pool_ops.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/buffer/buffer_pool_ops.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;GAUG;AACH,uCAJW;IAAC,KAAK,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,MAAM,CAAA;CAAC,KAC3B;IAAC,KAAK,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,MAAM,CAAA;CAAC,GACzB,MAAM,CAqBlB;AAED;;;;;;GAMG;AACH,kCAJW;IAAC,QAAQ,YAAU;CAAC,KACpB;IAAC,QAAQ,YAAU;CAAC,GAClB,MAAM,CAIlB;AAWD;;;;;;;GAOG;AACH,qCAJW;IAAC,QAAQ,YAAU;CAAC,EAAE,cACtB;IAAC,IAAI,EAAC,MAAM,CAAC;IAAC,KAAK,EAAC,MAAM,CAAA;CAAC,GACzB,MAAM,CAmClB;AAED;;;GAGG;AACH,mDAFa,MAAM,CAIlB;AAvHD;;;GAGG;AAEH;;;;GAIG;AACH,uCAFU,MAAM,CAE0B;AAC1C;;;;GAIG;AACH,uCAFU,MAAM,CAE6B"}
1
+ {"version":3,"file":"buffer_pool_ops.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/buffer/buffer_pool_ops.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;GAUG;AACH,uCAJW;IAAC,KAAK,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,MAAM,CAAA;CAAC,KAC3B;IAAC,KAAK,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,MAAM,CAAA;CAAC,GACzB,MAAM,CAqBlB;AAED;;;;;;GAMG;AAEH;;;;;;GAMG;AACH,kCAJW,gBAAgB,KAChB,gBAAgB,GACd,MAAM,CAIlB;AAED;;;;;;;GAOG;AACH,qCAJW,gBAAgB,EAAE,cAClB;IAAC,IAAI,EAAC,MAAM,CAAC;IAAC,KAAK,EAAC,MAAM,CAAA;CAAC,GACzB,MAAM,CAmClB;AAED;;;GAGG;AACH,mDAFa,MAAM,CAIlB;AAtHD;;;GAGG;AAEH;;;;GAIG;AACH,uCAFU,MAAM,CAE0B;AAC1C;;;;GAIG;AACH,uCAFU,MAAM,CAE6B;;;;;;+BAuChC,OAAO,kCAAkC,EAAE,UAAU,GAAG;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC"}
@@ -20,7 +20,7 @@ export const ALLOW_LARGER_LIMIT_SCALE = 2;
20
20
  export const ALLOW_LARGER_LIMIT_FIXED = 1024;
21
21
 
22
22
  /**
23
- * Total order over `{usage, size}`-bearing specs (a request descriptor or a live GPUBuffer).
23
+ * Total order over `{usage, size}`-bearing specs: a request descriptor, or a pool record.
24
24
  *
25
25
  * Sorted by size first (so the binary search lands on the smallest fitting buffer), then by usage
26
26
  * *bit-count* (so the narrowest-usage buffer is preferred — wide-usage buffers map to slower driver
@@ -52,37 +52,36 @@ export function compare_memory_spec(a, b) {
52
52
  }
53
53
 
54
54
  /**
55
- * Record ordering for the pool's sorted insert.
55
+ * A pool record as {@link GPUBufferAllocator} keeps one: the buffer, and its `size` and `usage` as they
56
+ * were when it entered the pool. Ordering and matching read those, never the buffer, whose `size` and
57
+ * `usage` are native reads and are visited by the binary search and the scan many times a frame.
56
58
  *
57
- * @param {{resource:GPUBuffer}} a
58
- * @param {{resource:GPUBuffer}} b
59
- * @returns {number}
59
+ * @typedef {import("../pool/TransientResourcePool.js").PoolRecord & {usage: number}} BufferPoolRecord
60
60
  */
61
- export function buffer_compare(a, b) {
62
- return compare_memory_spec(a.resource, b.resource);
63
- }
64
61
 
65
62
  /**
66
- * @param {{resource:GPUBuffer}} record
67
- * @param {{size:number}} descriptor
63
+ * Record ordering for the pool's sorted insert.
64
+ *
65
+ * @param {BufferPoolRecord} a
66
+ * @param {BufferPoolRecord} b
68
67
  * @returns {number}
69
68
  */
70
- function compare_descriptor_to_record(descriptor, record) {
71
- return compare_memory_spec(descriptor, record.resource);
69
+ export function buffer_compare(a, b) {
70
+ return compare_memory_spec(a, b);
72
71
  }
73
72
 
74
73
  /**
75
74
  * Approximate first-fit: the smallest pooled buffer with `size >= request` and a usage *superset* of
76
75
  * the request, bounded against handing out a much-larger buffer.
77
76
  *
78
- * @param {{resource:GPUBuffer}[]} records sorted under {@link buffer_compare}
77
+ * @param {BufferPoolRecord[]} records sorted under {@link buffer_compare}
79
78
  * @param {{size:number, usage:number}} descriptor
80
79
  * @returns {number} index of a satisfying record, or -1
81
80
  */
82
81
  export function buffer_find(records, descriptor) {
83
82
  const count = records.length;
84
83
 
85
- let index = binarySearchHighIndex(records, descriptor, compare_descriptor_to_record);
84
+ let index = binarySearchHighIndex(records, descriptor, compare_memory_spec);
86
85
 
87
86
  if (index >= count) {
88
87
  return -1;
@@ -93,19 +92,19 @@ export function buffer_find(records, descriptor) {
93
92
  }
94
93
 
95
94
  for (; index < count; index++) {
96
- const buffer = records[index].resource;
95
+ const record = records[index];
97
96
 
98
97
  if (
99
- buffer.size > descriptor.size * ALLOW_LARGER_LIMIT_SCALE
100
- && (buffer.size - descriptor.size) > ALLOW_LARGER_LIMIT_FIXED
98
+ record.size > descriptor.size * ALLOW_LARGER_LIMIT_SCALE
99
+ && (record.size - descriptor.size) > ALLOW_LARGER_LIMIT_FIXED
101
100
  ) {
102
101
  // records are sorted by size: everything from here on is too large
103
102
  break;
104
103
  }
105
104
 
106
105
  if (
107
- (buffer.usage & descriptor.usage) === descriptor.usage
108
- && buffer.size >= descriptor.size
106
+ (record.usage & descriptor.usage) === descriptor.usage
107
+ && record.size >= descriptor.size
109
108
  ) {
110
109
  return index;
111
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gpu_test.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/gpu_primitive/test/gpu_test.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,sCAJW,MAAM,cAEL,QAAQ,IAAI,CAAC,CA+DxB"}
1
+ {"version":3,"file":"gpu_test.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/gpu_primitive/test/gpu_test.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,sCAJW,MAAM,cAEL,QAAQ,IAAI,CAAC,CAyDxB"}
@@ -1,4 +1,7 @@
1
1
  import { WebGPUExtensionType } from "../../../descriptor/WebGPUExtensionType.js";
2
+ import { SHADE_DEVICE_FLOOR } from "../../../device/SHADE_DEVICE_FLOOR.js";
3
+ import { shade_device_floor_unmet } from "../../../device/shade_device_floor_unmet.js";
4
+ import { ShadeDeviceFailure } from "../../../device/ShadeDeviceFailure.js";
2
5
  import { GraphicsContext } from "../../GraphicsContext.js";
3
6
 
4
7
  /**
@@ -36,32 +39,26 @@ export async function gpu_test(description, body) {
36
39
  //
37
40
  // console.warn('adapter limits:', adapter.limits);
38
41
 
39
- const maxStorageBuffersPerShaderStage = adapter.limits.maxStorageBuffersPerShaderStage;
42
+ const unmet = shade_device_floor_unmet(adapter);
40
43
 
41
- if (maxStorageBuffersPerShaderStage < 10) {
42
- throw new Error(`Engine requires at least 10 storage buffers per shader stage, actual is ${maxStorageBuffersPerShaderStage}`);
44
+ if (unmet.length > 0) {
45
+ throw ShadeDeviceFailure.below_floor(unmet);
43
46
  }
44
47
 
45
48
  const device = await adapter.requestDevice({
46
49
  requiredLimits: {
47
- // required for large G-buffers
48
- maxColorAttachmentBytesPerSample: 32,
50
+ ...SHADE_DEVICE_FLOOR.limits,
49
51
 
50
52
  /*
51
53
  grab the largest buffer limit we can get, default limits are super-low
52
54
  */
53
55
  maxBufferSize: adapter.limits.maxBufferSize,
54
56
  maxStorageBufferBindingSize: adapter.limits.maxStorageBufferBindingSize,
55
-
56
- maxStorageBuffersPerShaderStage: 10,
57
57
  },
58
58
  requiredFeatures: [
59
+ ...SHADE_DEVICE_FLOOR.features,
59
60
  // required for timers
60
61
  WebGPUExtensionType.TimestampQuery,
61
- // required for indirect draw that's used extensively in Shade
62
- WebGPUExtensionType.IndirectFirstInstance,
63
- // required for OIT
64
- WebGPUExtensionType.Float32Blendable,
65
62
  ]
66
63
  });
67
64
 
@@ -13,7 +13,7 @@ export class TinyGltf {
13
13
  * @readonly
14
14
  * @type {TextureFormat}
15
15
  */
16
- static readonly "__#265@#UNCOMPRESSED_TARGET": TextureFormat;
16
+ static readonly "__#267@#UNCOMPRESSED_TARGET": TextureFormat;
17
17
  /**
18
18
  * @param {AssetManager} assetManager
19
19
  * @param {AssetRequestScope} [scope]