@woosh/meep-engine 3.31.0 → 3.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/collection/table/RowFirstTable.d.ts +8 -0
  4. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  5. package/src/core/collection/table/RowFirstTable.js +40 -11
  6. package/src/engine/graphics/ecs/sprite/Sprite.d.ts +3 -0
  7. package/src/engine/graphics/ecs/sprite/Sprite.d.ts.map +1 -1
  8. package/src/engine/graphics/ecs/sprite/Sprite.js +3 -0
  9. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts +3 -0
  10. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
  11. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +3 -0
  12. package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
  13. package/src/engine/graphics3/DebugDrawSystem.js +6 -2
  14. package/src/engine/graphics3/PathDisplaySystem.d.ts.map +1 -1
  15. package/src/engine/graphics3/PathDisplaySystem.js +311 -307
  16. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  17. package/src/shade/RENDERER_CONTRACT.md +15 -2
  18. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +5 -0
  19. package/src/shade/device/ShadeGPUCommandContext.d.ts +15 -2
  20. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  21. package/src/shade/device/ShadeGPUCommandContext.js +154 -25
  22. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts +20 -3
  23. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
  24. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +21 -3
  25. package/src/shade/renderer/GraphicsContext.d.ts +20 -1
  26. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  27. package/src/shade/renderer/GraphicsContext.js +105 -52
  28. package/src/shade/renderer/Renderer.d.ts +19 -4
  29. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  30. package/src/shade/renderer/Renderer.js +113 -2
  31. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +10 -7
  32. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  33. package/src/shade/renderer/animation/GPUAnimationManager.js +147 -45
  34. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts +6 -5
  35. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts.map +1 -1
  36. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.js +241 -240
  37. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts +62 -2
  38. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts.map +1 -1
  39. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.js +306 -38
  40. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts +60 -0
  41. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts.map +1 -0
  42. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.js +202 -0
  43. package/src/shade/renderer/buffer/GPUUploadBlock.d.ts +68 -0
  44. package/src/shade/renderer/buffer/GPUUploadBlock.d.ts.map +1 -0
  45. package/src/shade/renderer/buffer/GPUUploadBlock.js +97 -0
  46. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts +2 -1
  47. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts.map +1 -1
  48. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.js +19 -17
  49. package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.d.ts +70 -0
  50. package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.d.ts.map +1 -0
  51. package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.js +257 -0
  52. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts +20 -7
  53. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts.map +1 -1
  54. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +39 -41
  55. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts +6 -20
  56. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts.map +1 -1
  57. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +42 -36
  58. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts +2 -1
  59. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts.map +1 -1
  60. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js +4 -3
  61. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts +4 -3
  62. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts.map +1 -1
  63. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.js +7 -4
  64. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts +14 -15
  65. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts.map +1 -1
  66. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js +49 -83
  67. package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts +19 -3
  68. package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts.map +1 -1
  69. package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +26 -6
  70. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts +2 -1
  71. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts.map +1 -1
  72. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.js +12 -6
  73. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts +3 -2
  74. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts.map +1 -1
  75. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +21 -13
  76. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts +5 -0
  77. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +19 -0
  79. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  80. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  81. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +3 -1
  82. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -1
  83. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +3 -1
  84. package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.d.ts.map +1 -1
  85. package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.js +134 -88
  86. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
  87. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +57 -26
  88. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  89. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +28 -20
  90. package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts +38 -0
  91. package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts.map +1 -0
  92. package/src/shade/renderer/rasterize/graph_clear_raster_targets.js +105 -0
  93. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +20 -0
  94. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts +1 -1
  95. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  96. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +21 -1
  97. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  98. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +12 -20
  99. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts +2 -1
  100. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts.map +1 -1
  101. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.js +15 -28
  102. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  103. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +8 -1
  104. package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts +0 -73
  105. package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts.map +0 -1
  106. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts +0 -59
  107. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts.map +0 -1
  108. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts +0 -22
  109. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts.map +0 -1
  110. package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts +0 -26
  111. package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts.map +0 -1
  112. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts +0 -25
  113. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts.map +0 -1
  114. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts +0 -26
  115. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts.map +0 -1
  116. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts +0 -29
  117. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts.map +0 -1
@@ -398,14 +398,18 @@ class PathExtension extends RenderExtension {
398
398
  }
399
399
 
400
400
  const scene = frame.get(SceneColor);
401
+ const view = frame.get(ViewTextures);
401
402
 
402
- scene.color = this.#renderer.graph_draw({
403
+ const drawn = this.#renderer.graph_draw({
403
404
  graph: frame.graph,
404
405
  batch: this.#batch,
405
406
  color: scene.color,
406
- depth: frame.get(ViewTextures).depth,
407
+ depth: view.depth,
407
408
  camera: frame.view.camera.buffer
408
409
  });
410
+
411
+ scene.color = drawn.color;
412
+ view.depth = drawn.depth;
409
413
  }
410
414
  }
411
415
 
@@ -590,6 +594,15 @@ which is what effects want. Set it and the pass writes depth instead: a solid su
590
594
  build behind it has no depth ordering otherwise, and no CPU sort can give it one, because a painter's
591
595
  order over triangles is wrong wherever two of them interpenetrate.
592
596
 
597
+ `graph_draw` hands back `{ color, depth }`, and an extension publishes both, as in §6. The depth is a
598
+ new handle when the pass wrote it. Anything reading the scene depth after you — depth of field,
599
+ motion blur, the NSS upscaler, the next extension — has to be given that handle; a development build
600
+ refuses the frame when it is not. Left `false`, the depth comes back as it went in.
601
+
602
+ That is also what decides the phase for solid content. At `AfterLighting` transparency has not run
603
+ yet, and it tests against the depth you published, so glass in front of the batch covers it. At
604
+ `AfterTransparency` the glass is already resolved into the colour, and the batch is drawn over it.
605
+
593
606
  Residency is keyed on **the geometry**, not on batch membership, so a mesh that blinks off for a
594
607
  frame or is removed and re-added keeps its buffers.
595
608
 
@@ -562,3 +562,8 @@ harness. Keeping the door open costs nothing; walking through it preemptively co
562
562
  call sites are the strongest case for immediates, but the standing TODO there is a separate bug —
563
563
  the 2025-09-13 note says the obvious fix produced garbage and was never chased down. Immediates
564
564
  route around it for the ≤64-byte cases without explaining it.
565
+ Answered 2026-09-26: fixed independently. The garbage was frame-graph aliasing — a `queue.writeBuffer`
566
+ into a pooled buffer lands ahead of the whole submission, and a pass earlier in it had written that
567
+ buffer for another resource. The import now writes with `writeValueBuffer`, in order, and creates no
568
+ buffer per frame; `graph_import_typed_buffer.spec.js` pins both. Immediates would still drop the
569
+ buffer altogether for the ≤64-byte cases.
@@ -268,6 +268,8 @@ export class ShadeGPUCommandContext {
268
268
  */
269
269
  allocateTransientValueBuffer<T>(type: WebGPUType, value: T, usage?: number | GPUBufferUsage): GPUBuffer;
270
270
  /**
271
+ * Like {@link writeBuffer}, with the bytes serialised from `value` as `type` lays them out.
272
+ *
271
273
  * @template T
272
274
  * @param {GPUBuffer} buffer
273
275
  * @param {number} buffer_offset
@@ -276,12 +278,22 @@ export class ShadeGPUCommandContext {
276
278
  */
277
279
  writeValueBuffer<T_1>(buffer: GPUBuffer, buffer_offset: number, type: WebGPUType, value: T_1): void;
278
280
  /**
279
- * Very similar to {@link GPUQueue.writeBuffer}, but instead of doing the operation direction on the queue - uses a staging buffer under the hood and performs the actual write operation as part of the commmand buffer
281
+ * Write bytes into `buffer` at this point in the command stream: after everything recorded
282
+ * before this call, and before everything recorded after it.
283
+ *
284
+ * That is the difference from {@link GPUQueue#writeBuffer}, which lands ahead of the whole
285
+ * submission — ahead of passes recorded earlier in it that may still need the old contents. Here
286
+ * the bytes are staged, and a copy out of the staging is recorded in their place. Small writes
287
+ * are staged in this context's upload blocks, which reach the GPU with one queue write each when
288
+ * the context finishes, so a frame of thousands of them costs no mapping at all; writes of
289
+ * {@link MAPPED_UPLOAD_THRESHOLD} bytes or more go through a mapped staging buffer each, which is
290
+ * the faster road for bytes.
291
+ *
280
292
  * @param {GPUBuffer} buffer
281
293
  * @param {number} buffer_offset
282
294
  * @param {ArrayBuffer} data
283
295
  * @param {number} data_offset
284
- * @param {number} size
296
+ * @param {number} size a multiple of 4, as for any buffer copy
285
297
  */
286
298
  writeBuffer(buffer: GPUBuffer, buffer_offset: number, data: ArrayBuffer, data_offset: number, size: number): void;
287
299
  /**
@@ -297,6 +309,7 @@ export type GraphicsContext = import("../renderer/GraphicsContext.js").GraphicsC
297
309
  export type ShaderResourceSetDescriptor = import("../renderer/shader/resource/ShaderResourceSetDescriptor.js").ShaderResourceSetDescriptor;
298
310
  export type WebGPUType = import("../renderer/shader/type/WebGPUType.js").WebGPUType;
299
311
  export type TextureManager = import("../renderer/texture/TextureManager.js").TextureManager;
312
+ export type GPUUploadBlock = import("../renderer/buffer/GPUUploadBlock.js").GPUUploadBlock;
300
313
  export type GPUFrameRecorder = import("./timing/profile/GPUFrameRecorder.js").GPUFrameRecorder;
301
314
  import { GraphicsExecutionContext } from "./graph/GraphicsExecutionContext.js";
302
315
  import { ShadeGPUComputePassEncoder } from "./pass/ShadeGPUComputePassEncoder.js";
@@ -1 +1 @@
1
- {"version":3,"file":"ShadeGPUCommandContext.d.ts","sourceRoot":"","sources":["../../../../src/shade/device/ShadeGPUCommandContext.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ShadeGPUCommandContext.d.ts","sourceRoot":"","sources":["../../../../src/shade/device/ShadeGPUCommandContext.js"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ import { ShadeGPURenderPassEncoder } from "./pass/ShadeGPURenderPassEncoder.js";
10
10
  import { ShadeGPUContextProfiler } from "./timing/ShadeGPUContextProfiler.js";
11
11
  import { warn_limited } from "../util/warn_limited.js";
12
12
  import { write_gpu_typed_buffer } from "../renderer/shader/type/serde/write_gpu_typed_buffer.js";
13
+ import { MAPPED_UPLOAD_THRESHOLD } from "../renderer/buffer/GPUBufferUploadAllocator.js";
13
14
  import { BufferResourceDescriptor } from "./graph/BufferResourceDescriptor.js";
14
15
  import { GraphicsExecutionContext } from "./graph/GraphicsExecutionContext.js";
15
16
 
@@ -24,6 +25,7 @@ import { GraphicsExecutionContext } from "./graph/GraphicsExecutionContext.js";
24
25
  * @typedef {import("../renderer/shader/resource/ShaderResourceSetDescriptor.js").ShaderResourceSetDescriptor} ShaderResourceSetDescriptor
25
26
  * @typedef {import("../renderer/shader/type/WebGPUType.js").WebGPUType} WebGPUType
26
27
  * @typedef {import("../renderer/texture/TextureManager.js").TextureManager} TextureManager
28
+ * @typedef {import("../renderer/buffer/GPUUploadBlock.js").GPUUploadBlock} GPUUploadBlock
27
29
  * @typedef {import("./timing/profile/GPUFrameRecorder.js").GPUFrameRecorder} GPUFrameRecorder
28
30
  */
29
31
 
@@ -180,6 +182,17 @@ export class ShadeGPUCommandContext {
180
182
  #transient_buffers = [];
181
183
 
182
184
  /**
185
+ * Upload blocks this context has written its small uploads into, the one being filled last. Sent
186
+ * to the GPU just before the submit, one queue write per block, and given back when the context
187
+ * finishes.
188
+ *
189
+ * @type {GPUUploadBlock[]}
190
+ */
191
+ #upload_blocks = [];
192
+
193
+ /**
194
+ * Mapped staging buffers this context's large uploads went through, one each. Given back when the
195
+ * context finishes, and mapped again by their pool before it hands them out anew.
183
196
  *
184
197
  * @type {GPUBuffer[]}
185
198
  */
@@ -727,6 +740,8 @@ export class ShadeGPUCommandContext {
727
740
  }
728
741
 
729
742
  /**
743
+ * Like {@link writeBuffer}, with the bytes serialised from `value` as `type` lays them out.
744
+ *
730
745
  * @template T
731
746
  * @param {GPUBuffer} buffer
732
747
  * @param {number} buffer_offset
@@ -737,30 +752,48 @@ export class ShadeGPUCommandContext {
737
752
 
738
753
  assert.notOk(this.#finished, 'already finished');
739
754
 
740
- const gfx = this.#graphics;
741
-
742
755
  const size = type.aligned_size;
743
756
 
744
- const stage = gfx.buffer_allocator_staging.get(size);
757
+ if (size >= MAPPED_UPLOAD_THRESHOLD) {
758
+ const stage = this.#graphics.buffer_allocator_staging.get(size);
759
+
760
+ // recorded before it is filled, so a fill that throws still gives it back
761
+ this.#staging_buffers.push(stage);
745
762
 
746
- const mapped = stage.getMappedRange(0, size);
763
+ write_gpu_typed_buffer(value, type, stage.getMappedRange(0, size), 0);
747
764
 
748
- write_gpu_typed_buffer(value, type, mapped, 0);
765
+ stage.unmap();
749
766
 
750
- stage.unmap();
767
+ this.copyBufferToBuffer(stage, 0, buffer, buffer_offset, size);
751
768
 
752
- this.#staging_buffers.push(stage);
769
+ return;
770
+ }
771
+
772
+ const block = this.#upload_block_with_room(size);
773
+ const offset = block.allocate(size);
774
+
775
+ write_gpu_typed_buffer(value, type, block.data, offset);
753
776
 
754
- this.copyBufferToBuffer(stage, 0, buffer, buffer_offset, size);
777
+ this.copyBufferToBuffer(block.buffer, offset, buffer, buffer_offset, size);
755
778
  }
756
779
 
757
780
  /**
758
- * Very similar to {@link GPUQueue.writeBuffer}, but instead of doing the operation direction on the queue - uses a staging buffer under the hood and performs the actual write operation as part of the commmand buffer
781
+ * Write bytes into `buffer` at this point in the command stream: after everything recorded
782
+ * before this call, and before everything recorded after it.
783
+ *
784
+ * That is the difference from {@link GPUQueue#writeBuffer}, which lands ahead of the whole
785
+ * submission — ahead of passes recorded earlier in it that may still need the old contents. Here
786
+ * the bytes are staged, and a copy out of the staging is recorded in their place. Small writes
787
+ * are staged in this context's upload blocks, which reach the GPU with one queue write each when
788
+ * the context finishes, so a frame of thousands of them costs no mapping at all; writes of
789
+ * {@link MAPPED_UPLOAD_THRESHOLD} bytes or more go through a mapped staging buffer each, which is
790
+ * the faster road for bytes.
791
+ *
759
792
  * @param {GPUBuffer} buffer
760
793
  * @param {number} buffer_offset
761
794
  * @param {ArrayBuffer} data
762
795
  * @param {number} data_offset
763
- * @param {number} size
796
+ * @param {number} size a multiple of 4, as for any buffer copy
764
797
  */
765
798
  writeBuffer(buffer, buffer_offset, data, data_offset, size) {
766
799
  assert.defined(buffer, 'buffer');
@@ -769,20 +802,95 @@ export class ShadeGPUCommandContext {
769
802
  assert.isNonNegativeInteger(data_offset, 'data_offset');
770
803
  assert.isNonNegativeInteger(size, 'size');
771
804
 
772
- const gfx = this.#graphics;
805
+ assert.notOk(this.#finished, 'already finished');
806
+
807
+ if (size % 4 !== 0) {
808
+ // Refused here rather than left to the copy, as a mapped staging buffer of this size
809
+ // always was: a copy moves whole 4-byte words, and one that cannot takes the context's
810
+ // whole submission down with it, later, without naming the write that did it.
811
+ throw new RangeError(`writeBuffer: size ${size} is not a multiple of 4`);
812
+ }
813
+
814
+ if (size === 0) {
815
+ // a copy of nothing changes nothing
816
+ return;
817
+ }
818
+
819
+ if (size >= MAPPED_UPLOAD_THRESHOLD) {
820
+ const stage = this.#graphics.buffer_allocator_staging.get(size);
773
821
 
774
- const stage = gfx.buffer_allocator_staging.get(size);
822
+ // recorded before it is filled, so a fill that throws still gives it back
823
+ this.#staging_buffers.push(stage);
775
824
 
776
- const mapped = stage.getMappedRange(0, size);
825
+ array_buffer_copy(data, data_offset, stage.getMappedRange(0, size), 0, size);
777
826
 
778
- array_buffer_copy(data, data_offset, mapped, 0, size);
827
+ stage.unmap();
779
828
 
780
- stage.unmap();
829
+ this.copyBufferToBuffer(stage, 0, buffer, buffer_offset, size);
781
830
 
782
- this.#staging_buffers.push(stage);
831
+ return;
832
+ }
783
833
 
784
- this.copyBufferToBuffer(stage, 0, buffer, buffer_offset, size);
834
+ const block = this.#upload_block_with_room(size);
835
+ const offset = block.allocate(size);
785
836
 
837
+ array_buffer_copy(data, data_offset, block.data, offset, size);
838
+
839
+ this.copyBufferToBuffer(block.buffer, offset, buffer, buffer_offset, size);
840
+ }
841
+
842
+ /**
843
+ * The block to take the next `size` bytes of upload from: the one being filled, or a fresh one
844
+ * when that is full. Every write that comes here is smaller than
845
+ * {@link MAPPED_UPLOAD_THRESHOLD}, so any empty block holds it.
846
+ *
847
+ * A block that cannot take the next write is not revisited: what is left in it is wasted until
848
+ * the context finishes, which bounds the waste at one block's tail per block and keeps every
849
+ * write a single contiguous copy.
850
+ *
851
+ * @param {number} size
852
+ * @returns {GPUUploadBlock}
853
+ */
854
+ #upload_block_with_room(size) {
855
+ const blocks = this.#upload_blocks;
856
+ const last = blocks.length - 1;
857
+
858
+ if (last >= 0 && blocks[last].fits(size)) {
859
+ return blocks[last];
860
+ }
861
+
862
+ const block = this.#graphics.buffer_allocator_upload.get();
863
+
864
+ blocks.push(block);
865
+
866
+ return block;
867
+ }
868
+
869
+ /**
870
+ * Put this context's upload blocks on the GPU: one queue write per block, of the part written.
871
+ *
872
+ * Must come immediately before the submit, and this is the whole of why a block can go back to
873
+ * its pool the moment its context finishes rather than when the GPU is done with it. The queue
874
+ * runs its operations in order, so a write issued here lands after everything submitted before
875
+ * this context — including the copies of any earlier context that held the same block — and
876
+ * before this context's own copies read it. Nothing is mapped, so nothing is waited for.
877
+ *
878
+ * A queue write lands ahead of its whole submission, which is why it goes only into a block and
879
+ * never into a destination: blocks come from a pool of their own that nothing aliases, while
880
+ * the frame graph's buffers are aliased within a submission, and a queue write into one of those
881
+ * would overwrite what an earlier pass in it still needs.
882
+ *
883
+ * @param {GPUQueue} queue
884
+ */
885
+ #send_uploads(queue) {
886
+ const blocks = this.#upload_blocks;
887
+ const count = blocks.length;
888
+
889
+ for (let i = 0; i < count; i++) {
890
+ const block = blocks[i];
891
+
892
+ queue.writeBuffer(block.buffer, 0, block.data, 0, block.used);
893
+ }
786
894
  }
787
895
 
788
896
  #cleanup() {
@@ -802,11 +910,29 @@ export class ShadeGPUCommandContext {
802
910
 
803
911
  }
804
912
 
805
- // staging buffers
913
+ // Blocks go back now rather than when the GPU is done with them — see #send_uploads.
914
+ const buffer_allocator_upload = this.#graphics.buffer_allocator_upload;
915
+
916
+ for (const block of this.#upload_blocks) {
917
+ buffer_allocator_upload.release(block);
918
+ }
919
+
920
+ this.#upload_blocks.length = 0;
921
+
922
+ // staging buffers are mapped again by their pool, which is when they are free again
806
923
  const buffer_allocator_staging = this.#graphics.buffer_allocator_staging;
924
+
807
925
  for (const staging of this.#staging_buffers) {
926
+ if (staging.mapState === "mapped") {
927
+ // a write that threw while filling it, so no copy out of it was recorded; unmapped
928
+ // here so its pool maps it afresh rather than handing out a range already given out
929
+ staging.unmap();
930
+ }
931
+
808
932
  buffer_allocator_staging.release(staging);
809
933
  }
934
+
935
+ this.#staging_buffers.length = 0;
810
936
  }
811
937
 
812
938
  /**
@@ -844,19 +970,22 @@ export class ShadeGPUCommandContext {
844
970
 
845
971
  GPUCommandEncoder.finish() throws when the encoder is locked — any pass left un-end()ed
846
972
  anywhere in the frame graph — and queue.submit throws on a malformed argument. This used
847
- to be a bare sequence, so either throw skipped #cleanup() and every buffer in
848
- #transient_buffers and #staging_buffers stayed checked out of its allocator for good: one
849
- staging buffer per writeBuffer call, which is most of the uniform traffic, every frame,
850
- until the process ran out of GPU memory. onFinished never fired either, so a promise
851
- already awaiting done never woke and profiling_absorbed hung with it — a recoverable
852
- encoding bug turned into an unbounded leak plus a hung frame, with the original error
853
- hidden behind the hang.
973
+ to be a bare sequence, so either throw skipped #cleanup() and every buffer the context held
974
+ stayed checked out of its allocator for good — then, a staging buffer per writeBuffer
975
+ call, which is most of the uniform traffic, every frame, until the process ran out of GPU
976
+ memory. onFinished never fired either, so a promise already awaiting done never woke and
977
+ profiling_absorbed hung with it — a recoverable encoding bug turned into an unbounded leak
978
+ plus a hung frame, with the original error hidden behind the hang.
854
979
 
855
980
  The error still propagates: it is the thing that names the misplaced end().
856
981
  */
857
982
  try {
858
983
  const command_buffer = encoder.finish();
859
984
 
985
+ // after finish(), so a command buffer that could not be made sends nothing, and
986
+ // immediately before the submit, which is what makes the blocks safe to hand back
987
+ this.#send_uploads(queue);
988
+
860
989
  queue.submit([command_buffer]);
861
990
  } finally {
862
991
  // cleanup allocated memory
@@ -27,7 +27,11 @@ export class SoftwareGPURenderPassEncoder extends SoftwareGPUObjectBase implemen
27
27
  * `-1` rather than a number read out of a buffer nobody filled — the same admission
28
28
  * {@link SoftwareGPUComputePassEncoder#dispatchWorkgroupsIndirect} makes.
29
29
  *
30
- * @type {{pipeline: GPURenderPipeline|null, bind_groups: GPUBindGroup[], dynamic_offsets: number[][], vertex_buffers: object[], index_buffer: object|null, viewport: object|null, scissor: object|null, vertex_count: number, instance_count: number, indexed: boolean, indirect: boolean}[]}
30
+ * A direct draw also records where it starts — `first_vertex` and `first_instance`, or for an
31
+ * indexed one `first_index`, `base_vertex` and `first_instance` — with WebGPU's defaults of 0
32
+ * where they were left out. An indirect one records none of them: they are in the buffer too.
33
+ *
34
+ * @type {{pipeline: GPURenderPipeline|null, bind_groups: GPUBindGroup[], dynamic_offsets: number[][], vertex_buffers: object[], index_buffer: object|null, viewport: object|null, scissor: object|null, vertex_count: number, instance_count: number, first_vertex?: number, first_index?: number, base_vertex?: number, first_instance?: number, indexed: boolean, indirect: boolean}[]}
31
35
  */
32
36
  draws: {
33
37
  pipeline: GPURenderPipeline | null;
@@ -39,6 +43,10 @@ export class SoftwareGPURenderPassEncoder extends SoftwareGPUObjectBase implemen
39
43
  scissor: object | null;
40
44
  vertex_count: number;
41
45
  instance_count: number;
46
+ first_vertex?: number;
47
+ first_index?: number;
48
+ base_vertex?: number;
49
+ first_instance?: number;
42
50
  indexed: boolean;
43
51
  indirect: boolean;
44
52
  }[];
@@ -118,15 +126,24 @@ export class SoftwareGPURenderPassEncoder extends SoftwareGPUObjectBase implemen
118
126
  setStencilReference(reference: number): void;
119
127
  stencil_reference: number;
120
128
  /**
129
+ * Where the draw starts is recorded with its counts: a direct draw's `instance_index` counts from
130
+ * `first_instance`, and a draw that picks its row of a table through it names that row nowhere
131
+ * else.
132
+ *
121
133
  * @param {number} vertex_count
122
134
  * @param {number} [instance_count]
135
+ * @param {number} [first_vertex]
136
+ * @param {number} [first_instance]
123
137
  */
124
- draw(vertex_count: number, instance_count?: number): void;
138
+ draw(vertex_count: number, instance_count?: number, first_vertex?: number, first_instance?: number): void;
125
139
  /**
126
140
  * @param {number} index_count
127
141
  * @param {number} [instance_count]
142
+ * @param {number} [first_index]
143
+ * @param {number} [base_vertex]
144
+ * @param {number} [first_instance]
128
145
  */
129
- drawIndexed(index_count: number, instance_count?: number): void;
146
+ drawIndexed(index_count: number, instance_count?: number, first_index?: number, base_vertex?: number, first_instance?: number): void;
130
147
  /**
131
148
  * @param {GPUBuffer} indirect_buffer
132
149
  * @param {number} indirect_offset
@@ -1 +1 @@
1
- {"version":3,"file":"SoftwareGPURenderPassEncoder.d.ts","sourceRoot":"","sources":["../../../../../src/shade/device/mock/SoftwareGPURenderPassEncoder.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;GAcG;AACH,mFAFgB,oBAAoB;IAmFhC;;;OAGG;IACH,sFAQC;IA5FD;;;;;;;;;OASG;IACH,OAFU;QAAC,QAAQ,EAAE,oBAAkB,IAAI,CAAC;QAAC,WAAW,EAAE,cAAc,CAAC;QAAC,eAAe,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,cAAc,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,EAAE,MAAM,GAAC,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAC,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,GAAC,IAAI,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAC,EAAE,CAElR;IAEX;;;;;;OAMG;IACH,oCAAW;IAoDX;;;;OAIG;IACH,uBAEC;IAsBD;;OAEG;IACH,+CAIC;IAED;;;;;;;;OAQG;IACH,oBANW,MAAM,8CAEN,MAAM,EAAE,GAAC,WAAW,0BACpB,MAAM,2BACN,MAAM,QA0BhB;IAED;;;;;OAKG;IACH,4BALW,MAAM,QACN,WAAW,GAAC,eAAe,gBAC3B,MAAM,cACN,MAAM,QAUhB;IAED;;;;;OAKG;IACH,sBALW,MAAM,8BAEN,MAAM,SACN,MAAM,QAShB;IAED;;;;;OAKG;IACH,yEAHW,MAAM,SACN,MAAM,QAQhB;IAED;;;;;;;OAOG;IACH,eAPW,MAAM,KACN,MAAM,SACN,MAAM,UACN,MAAM,aACN,MAAM,aACN,MAAM,QAMhB;IAED;;;;;OAKG;IACH,kBALW,MAAM,KACN,MAAM,SACN,MAAM,UACN,MAAM,QAMhB;IAED;;OAEG;IACH,wCAIC;IADG,yBAA2B;IAG/B;;OAEG;IACH,+BAFW,MAAM,QAMhB;IADG,0BAAkC;IAwCtC;;;OAGG;IACH,mBAHW,MAAM,mBACN,MAAM,QAahB;IAED;;;OAGG;IACH,yBAHW,MAAM,mBACN,MAAM,QAahB;IAED;;;OAGG;IACH,0DAFW,MAAM,QAkBhB;IAED;;;OAGG;IACH,iEAFW,MAAM,QAiBhB;IAED;;OAEG;IACH,sBAFW,MAAM,QAIhB;IAED,sBAEC;IAED;;OAEG;IACH,yBAFW,MAAM,QAIhB;IAED,YAQC;IAGL;;;OAGG;IACH,yCAFU,OAAO,CAEoD;;CANpE;sCAzYqC,4BAA4B"}
1
+ {"version":3,"file":"SoftwareGPURenderPassEncoder.d.ts","sourceRoot":"","sources":["../../../../../src/shade/device/mock/SoftwareGPURenderPassEncoder.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;GAcG;AACH,mFAFgB,oBAAoB;IAuFhC;;;OAGG;IACH,sFAQC;IAhGD;;;;;;;;;;;;;OAaG;IACH,OAFU;QAAC,QAAQ,EAAE,oBAAkB,IAAI,CAAC;QAAC,WAAW,EAAE,cAAc,CAAC;QAAC,eAAe,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,cAAc,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,EAAE,MAAM,GAAC,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAC,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,GAAC,IAAI,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAC,EAAE,CAE9W;IAEX;;;;;;OAMG;IACH,oCAAW;IAoDX;;;;OAIG;IACH,uBAEC;IAsBD;;OAEG;IACH,+CAIC;IAED;;;;;;;;OAQG;IACH,oBANW,MAAM,8CAEN,MAAM,EAAE,GAAC,WAAW,0BACpB,MAAM,2BACN,MAAM,QA0BhB;IAED;;;;;OAKG;IACH,4BALW,MAAM,QACN,WAAW,GAAC,eAAe,gBAC3B,MAAM,cACN,MAAM,QAUhB;IAED;;;;;OAKG;IACH,sBALW,MAAM,8BAEN,MAAM,SACN,MAAM,QAShB;IAED;;;;;OAKG;IACH,yEAHW,MAAM,SACN,MAAM,QAQhB;IAED;;;;;;;OAOG;IACH,eAPW,MAAM,KACN,MAAM,SACN,MAAM,UACN,MAAM,aACN,MAAM,aACN,MAAM,QAMhB;IAED;;;;;OAKG;IACH,kBALW,MAAM,KACN,MAAM,SACN,MAAM,UACN,MAAM,QAMhB;IAED;;OAEG;IACH,wCAIC;IADG,yBAA2B;IAG/B;;OAEG;IACH,+BAFW,MAAM,QAMhB;IADG,0BAAkC;IAwCtC;;;;;;;;;OASG;IACH,mBALW,MAAM,mBACN,MAAM,iBACN,MAAM,mBACN,MAAM,QAehB;IAED;;;;;;OAMG;IACH,yBANW,MAAM,mBACN,MAAM,gBACN,MAAM,gBACN,MAAM,mBACN,MAAM,QAgBhB;IAED;;;OAGG;IACH,0DAFW,MAAM,QAkBhB;IAED;;;OAGG;IACH,iEAFW,MAAM,QAiBhB;IAED;;OAEG;IACH,sBAFW,MAAM,QAIhB;IAED,sBAEC;IAED;;OAEG;IACH,yBAFW,MAAM,QAIhB;IAED,YAQC;IAGL;;;OAGG;IACH,yCAFU,OAAO,CAEoD;;CANpE;sCA3ZqC,4BAA4B"}
@@ -28,7 +28,11 @@ export class SoftwareGPURenderPassEncoder extends SoftwareGPUObjectBase {
28
28
  * `-1` rather than a number read out of a buffer nobody filled — the same admission
29
29
  * {@link SoftwareGPUComputePassEncoder#dispatchWorkgroupsIndirect} makes.
30
30
  *
31
- * @type {{pipeline: GPURenderPipeline|null, bind_groups: GPUBindGroup[], dynamic_offsets: number[][], vertex_buffers: object[], index_buffer: object|null, viewport: object|null, scissor: object|null, vertex_count: number, instance_count: number, indexed: boolean, indirect: boolean}[]}
31
+ * A direct draw also records where it starts — `first_vertex` and `first_instance`, or for an
32
+ * indexed one `first_index`, `base_vertex` and `first_instance` — with WebGPU's defaults of 0
33
+ * where they were left out. An indirect one records none of them: they are in the buffer too.
34
+ *
35
+ * @type {{pipeline: GPURenderPipeline|null, bind_groups: GPUBindGroup[], dynamic_offsets: number[][], vertex_buffers: object[], index_buffer: object|null, viewport: object|null, scissor: object|null, vertex_count: number, instance_count: number, first_vertex?: number, first_index?: number, base_vertex?: number, first_instance?: number, indexed: boolean, indirect: boolean}[]}
32
36
  */
33
37
  draws = [];
34
38
 
@@ -291,10 +295,16 @@ export class SoftwareGPURenderPassEncoder extends SoftwareGPUObjectBase {
291
295
  }
292
296
 
293
297
  /**
298
+ * Where the draw starts is recorded with its counts: a direct draw's `instance_index` counts from
299
+ * `first_instance`, and a draw that picks its row of a table through it names that row nowhere
300
+ * else.
301
+ *
294
302
  * @param {number} vertex_count
295
303
  * @param {number} [instance_count]
304
+ * @param {number} [first_vertex]
305
+ * @param {number} [first_instance]
296
306
  */
297
- draw(vertex_count, instance_count = 1) {
307
+ draw(vertex_count, instance_count = 1, first_vertex = 0, first_instance = 0) {
298
308
  this.#assert_encoding();
299
309
  this.#validate_immediates();
300
310
 
@@ -302,6 +312,8 @@ export class SoftwareGPURenderPassEncoder extends SoftwareGPUObjectBase {
302
312
  ...this.#snapshot(),
303
313
  vertex_count,
304
314
  instance_count,
315
+ first_vertex,
316
+ first_instance,
305
317
  indexed: false,
306
318
  indirect: false,
307
319
  });
@@ -310,8 +322,11 @@ export class SoftwareGPURenderPassEncoder extends SoftwareGPUObjectBase {
310
322
  /**
311
323
  * @param {number} index_count
312
324
  * @param {number} [instance_count]
325
+ * @param {number} [first_index]
326
+ * @param {number} [base_vertex]
327
+ * @param {number} [first_instance]
313
328
  */
314
- drawIndexed(index_count, instance_count = 1) {
329
+ drawIndexed(index_count, instance_count = 1, first_index = 0, base_vertex = 0, first_instance = 0) {
315
330
  this.#assert_encoding();
316
331
  this.#validate_immediates();
317
332
 
@@ -319,6 +334,9 @@ export class SoftwareGPURenderPassEncoder extends SoftwareGPUObjectBase {
319
334
  ...this.#snapshot(),
320
335
  vertex_count: index_count,
321
336
  instance_count,
337
+ first_index,
338
+ base_vertex,
339
+ first_instance,
322
340
  indexed: true,
323
341
  indirect: false,
324
342
  });
@@ -64,10 +64,17 @@ export class GraphicsContext {
64
64
  */
65
65
  buffer_allocator_native: GPUBufferAllocatorNative;
66
66
  /**
67
- * Used to upload data to the GPU
67
+ * Mapped `MAP_WRITE` buffers, one per upload: where a {@link ShadeGPUCommandContext} sends its
68
+ * large writes, for which a mapping is the faster road (see `MAPPED_UPLOAD_THRESHOLD`).
68
69
  * @type {GPUBufferStagingAllocator}
69
70
  */
70
71
  buffer_allocator_staging: GPUBufferStagingAllocator;
72
+ /**
73
+ * Upload blocks for {@link ShadeGPUCommandContext}'s small writes — every uniform a pass is
74
+ * handed by value among them. Sent with one queue write per block, not mapped.
75
+ * @type {GPUBufferUploadAllocator}
76
+ */
77
+ buffer_allocator_upload: GPUBufferUploadAllocator;
71
78
  /**
72
79
  * Used to read data back from the GPU: `MAP_READ` buffers, held by the CPU across frames, which
73
80
  * is why they cannot come from {@link buffer_allocator_main}.
@@ -104,6 +111,17 @@ export class GraphicsContext {
104
111
  offset: number;
105
112
  size: number;
106
113
  }): void;
114
+ /**
115
+ * Set one bind group of `pipeline`'s layout, leaving the others as they are — for a pass whose
116
+ * groups change at different rates, where {@link setPipelineBindings} would set every group up
117
+ * to the last one on each change.
118
+ *
119
+ * @param {GPUBindingCommandsMixin} pass
120
+ * @param {PipelineDescriptorBase} pipeline
121
+ * @param {number} index the group's index in the pipeline's layout
122
+ * @param {GPUBindingResource[]} resources the group's entries, in binding order
123
+ */
124
+ setPipelineBindGroup(pass: GPUBindingCommandsMixin, pipeline: PipelineDescriptorBase, index: number, resources: GPUBindingResource[]): void;
107
125
  /**
108
126
  *
109
127
  * @param {BufferDescriptor} buffer_descriptor
@@ -142,6 +160,7 @@ import { BindGroupManager } from "./binding/BindGroupManager.js";
142
160
  import { GPUBufferAllocator } from "./buffer/GPUBufferAllocator.js";
143
161
  import { GPUBufferAllocatorNative } from "./buffer/GPUBufferAllocatorNative.js";
144
162
  import { GPUBufferStagingAllocator } from "./buffer/GPUBufferStagingAllocator.js";
163
+ import { GPUBufferUploadAllocator } from "./buffer/GPUBufferUploadAllocator.js";
145
164
  import { GPUBufferReadbackAllocator } from "./buffer/GPUBufferReadbackAllocator.js";
146
165
  import { GPUTextureAllocator } from "./texture/GPUTextureAllocator.js";
147
166
  import { GPUBufferContext } from "./buffer/GPUBufferContext.js";
@@ -1 +1 @@
1
- {"version":3,"file":"GraphicsContext.d.ts","sourceRoot":"","sources":["../../../../src/shade/renderer/GraphicsContext.js"],"names":[],"mappings":"AAkCA;IA2JI,yBAgCC;IA1LD;;OAEG;IACH,YAFU,kBAAkB,CAEjB;IAEX;;OAEG;IACH,WAFU,kBAAkB,CAElB;IAOV;;OAEG;IACH,UAFU,iBAAiB,CAElB;IAET;;;OAGG;IACH,qDAOC;IAOD;;;OAGG;IACH,6CAEC;IAED;;OAEG;IACH,kBAFU,qBAAqB,CAEd;IAEjB;;OAEG;IACH,kBAFU,qBAAqB,CAEd;IAEjB;;OAEG;IACH,mBAFU,sBAAsB,CAEd;IAGlB;;OAEG;IACH,gBAFU,oBAAoB,CAEf;IAEf;;OAEG;IACH,UAFU,cAAc,CAEf;IAET;;;;OAIG;IACH,kBAFU,qBAAqB,CAEd;IAEjB;;OAEG;IACH,aAFU,gBAAgB,CAEd;IAQZ;;;OAGG;IACH,uBAFU,kBAAkB,CAEN;IAEtB;;;;OAIG;IACH,yBAFU,wBAAwB,CAEV;IAExB;;;OAGG;IACH,0BAFU,yBAAyB,CAEV;IAEzB;;;;OAIG;IACH,2BAFU,0BAA0B,CAEV;IAE1B;;;OAGG;IACH,oBAFU,mBAAmB,CAEV;IAUnB;;;OAGG;IACH,8BAEC;IAED,uBAMC;IAED;;;OAGG;IACH,wBAEC;IAoCD;;;;;;;;OAQG;IACH,6DANW,sBAAsB,aACtB,oBAAoB,EAAE,cACtB;QAAC,MAAM,EAAE,YAAY,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,QAmE9D;IAED;;;;OAIG;IACH,gCAHW,gBAAgB,GACd,gBAAgB,CAI5B;IAED;;OAEG;IACH,+BAeC;IAED,4BAEC;IAED,eAyBC;IAED,gBAmBC;IAGL;;;OAGG;IACH,4BAFU,OAAO,CAE0B;;CAN1C;+BAjWY,OAAO,0CAA0C,EAAE,gBAAgB;qCACnE,OAAO,kDAAkD,EAAE,sBAAsB;2BAKjF,OAAO,mCAAmC,EAAE,YAAY;mCAjBlC,kCAAkC;mCAGlC,kCAAkC;kCADnC,wBAAwB;2CAEf,mDAAmD;oCAH1D,2CAA2C;sCAZzC,6CAA6C;sCAC7C,6CAA6C;uCAF5C,8CAA8C;qCAIhD,0CAA0C;+BAehD,6BAA6B;sCACtB,4CAA4C;iCAdjD,+BAA+B;mCAC7B,gCAAgC;yCAC1B,sCAAsC;0CAGrC,uCAAuC;2CADtC,wCAAwC;oCAQ/C,kCAAkC;iCATtB,8BAA8B"}
1
+ {"version":3,"file":"GraphicsContext.d.ts","sourceRoot":"","sources":["../../../../src/shade/renderer/GraphicsContext.js"],"names":[],"mappings":"AAmCA;IAqKI,yBAiCC;IArMD;;OAEG;IACH,YAFU,kBAAkB,CAEjB;IAEX;;OAEG;IACH,WAFU,kBAAkB,CAElB;IAOV;;OAEG;IACH,UAFU,iBAAiB,CAElB;IAET;;;OAGG;IACH,qDAOC;IAOD;;;OAGG;IACH,6CAEC;IAED;;OAEG;IACH,kBAFU,qBAAqB,CAEd;IAEjB;;OAEG;IACH,kBAFU,qBAAqB,CAEd;IAEjB;;OAEG;IACH,mBAFU,sBAAsB,CAEd;IAGlB;;OAEG;IACH,gBAFU,oBAAoB,CAEf;IAEf;;OAEG;IACH,UAFU,cAAc,CAEf;IAET;;;;OAIG;IACH,kBAFU,qBAAqB,CAEd;IAEjB;;OAEG;IACH,aAFU,gBAAgB,CAEd;IAQZ;;;OAGG;IACH,uBAFU,kBAAkB,CAEN;IAEtB;;;;OAIG;IACH,yBAFU,wBAAwB,CAEV;IAExB;;;;OAIG;IACH,0BAFU,yBAAyB,CAEV;IAEzB;;;;OAIG;IACH,yBAFU,wBAAwB,CAEV;IAExB;;;;OAIG;IACH,2BAFU,0BAA0B,CAEV;IAE1B;;;OAGG;IACH,oBAFU,mBAAmB,CAEV;IAUnB;;;OAGG;IACH,8BAEC;IAED,uBAQC;IAED;;;OAGG;IACH,wBAEC;IAqCD;;;;;;;;OAQG;IACH,6DANW,sBAAsB,aACtB,oBAAoB,EAAE,cACtB;QAAC,MAAM,EAAE,YAAY,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,QA2B9D;IAED;;;;;;;;;OASG;IACH,8DAJW,sBAAsB,SACtB,MAAM,aACN,oBAAoB,QA0C9B;IAED;;;;OAIG;IACH,gCAHW,gBAAgB,GACd,gBAAgB,CAI5B;IAED;;OAEG;IACH,+BAgBC;IAED,4BAEC;IAED,eAoDC;IAED,gBAoBC;IAGL;;;OAGG;IACH,4BAFU,OAAO,CAE0B;;CAN1C;+BArZY,OAAO,0CAA0C,EAAE,gBAAgB;qCACnE,OAAO,kDAAkD,EAAE,sBAAsB;2BAKjF,OAAO,mCAAmC,EAAE,YAAY;mCAjBlC,kCAAkC;mCAGlC,kCAAkC;kCADnC,wBAAwB;2CAEf,mDAAmD;oCAH1D,2CAA2C;sCAbzC,6CAA6C;sCAC7C,6CAA6C;uCAF5C,8CAA8C;qCAIhD,0CAA0C;+BAgBhD,6BAA6B;sCACtB,4CAA4C;iCAfjD,+BAA+B;mCAC7B,gCAAgC;yCAC1B,sCAAsC;0CAGrC,uCAAuC;yCACxC,sCAAsC;2CAFpC,wCAAwC;oCAS/C,kCAAkC;iCAVtB,8BAA8B"}