@forgeax/engine-render 0.1.34 → 0.1.36

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 (273) hide show
  1. package/README.md +69 -3
  2. package/dist/assembly/device-feature-admission.d.ts +2 -2
  3. package/dist/assembly/host-contract.d.ts +3 -2
  4. package/dist/assembly/host-contract.d.ts.map +1 -1
  5. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  6. package/dist/assembly/render-target-host.d.ts +5 -0
  7. package/dist/assembly/render-target-host.d.ts.map +1 -1
  8. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  9. package/dist/assembly/webgpu-renderer.d.ts +1 -0
  10. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  11. package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
  12. package/dist/authoring.mjs +2 -4
  13. package/dist/authoring.mjs.map +1 -1
  14. package/dist/chunk-2OZAS3WU.mjs +3489 -0
  15. package/dist/chunk-2OZAS3WU.mjs.map +1 -0
  16. package/dist/{chunk-UI5SFODX.mjs → chunk-BZQ4CDRF.mjs} +2338 -1991
  17. package/dist/chunk-BZQ4CDRF.mjs.map +1 -0
  18. package/dist/{chunk-MKDIT2EM.mjs → chunk-CJOV2XLO.mjs} +216 -261
  19. package/dist/chunk-CJOV2XLO.mjs.map +1 -0
  20. package/dist/chunk-D6WSBXJ2.mjs +1842 -0
  21. package/dist/chunk-D6WSBXJ2.mjs.map +1 -0
  22. package/dist/{chunk-HEB564WF.mjs → chunk-DRF6OULX.mjs} +4 -4
  23. package/dist/{chunk-HEB564WF.mjs.map → chunk-DRF6OULX.mjs.map} +1 -1
  24. package/dist/{chunk-OCDLEI6I.mjs → chunk-OB5WAFYH.mjs} +117 -5
  25. package/dist/chunk-OB5WAFYH.mjs.map +1 -0
  26. package/dist/{chunk-ODZWR6JQ.mjs → chunk-OEYKKMXG.mjs} +2042 -27
  27. package/dist/chunk-OEYKKMXG.mjs.map +1 -0
  28. package/dist/chunk-RIPAEGI6.mjs +48 -0
  29. package/dist/chunk-RIPAEGI6.mjs.map +1 -0
  30. package/dist/{chunk-ELJFJ2BU.mjs → chunk-X2KA6WHM.mjs} +29 -4
  31. package/dist/chunk-X2KA6WHM.mjs.map +1 -0
  32. package/dist/{chunk-BLXGONR2.mjs → chunk-XSFB7XXQ.mjs} +51 -4
  33. package/dist/chunk-XSFB7XXQ.mjs.map +1 -0
  34. package/dist/cloud/frame-context.d.ts +2 -2
  35. package/dist/cloud/frame-context.d.ts.map +1 -1
  36. package/dist/construct-renderer.mjs +936 -2140
  37. package/dist/construct-renderer.mjs.map +1 -1
  38. package/dist/device/device-scope.d.ts.map +1 -1
  39. package/dist/device/gpu-residency.d.ts +19 -19
  40. package/dist/device/gpu-residency.d.ts.map +1 -1
  41. package/dist/errors/render.d.ts +3 -2
  42. package/dist/errors/render.d.ts.map +1 -1
  43. package/dist/extract/material-context.d.ts +7 -0
  44. package/dist/extract/material-context.d.ts.map +1 -0
  45. package/dist/features/host.d.ts +5 -0
  46. package/dist/features/host.d.ts.map +1 -1
  47. package/dist/features/particle-mesh-layout.d.ts +19 -0
  48. package/dist/features/particle-mesh-layout.d.ts.map +1 -0
  49. package/dist/features/plan.d.ts +2 -0
  50. package/dist/features/plan.d.ts.map +1 -1
  51. package/dist/features/types.d.ts +8 -0
  52. package/dist/features/types.d.ts.map +1 -1
  53. package/dist/glyph-text-layout-system.d.ts +1 -1
  54. package/dist/glyph-text-layout-system.d.ts.map +1 -1
  55. package/dist/gpu-driven/production-raster.d.ts +1 -1
  56. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  57. package/dist/gpu-driven/shadow-ownership.d.ts +3 -3
  58. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -1
  59. package/dist/gpu-driven/shadow-views.d.ts +1 -1
  60. package/dist/gpu-driven/shadow-views.d.ts.map +1 -1
  61. package/dist/gpu-driven/view-gpu.d.ts +1 -1
  62. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  63. package/dist/ibl/frame-resources.d.ts.map +1 -1
  64. package/dist/ibl/skylight-bind-group.d.ts +4 -4
  65. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  66. package/dist/index.d.ts +3 -0
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.mjs +542 -9
  69. package/dist/index.mjs.map +1 -1
  70. package/dist/instances.d.ts +3 -4
  71. package/dist/instances.d.ts.map +1 -1
  72. package/dist/internal.mjs +7 -8
  73. package/dist/internal.mjs.map +1 -1
  74. package/dist/pbr-pipeline.d.ts +3 -3
  75. package/dist/pbr-pipeline.d.ts.map +1 -1
  76. package/dist/pipeline/standard-output/lut-gpu.d.ts +2 -2
  77. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -1
  78. package/dist/pipeline/standard-output/resources.d.ts +2 -2
  79. package/dist/pipeline/standard-output/resources.d.ts.map +1 -1
  80. package/dist/publication/contract.d.ts +77 -0
  81. package/dist/publication/contract.d.ts.map +1 -0
  82. package/dist/publication/dependencies.d.ts +7 -0
  83. package/dist/publication/dependencies.d.ts.map +1 -0
  84. package/dist/publication/prepare-geometry.d.ts +9 -0
  85. package/dist/publication/prepare-geometry.d.ts.map +1 -0
  86. package/dist/publication/programs.d.ts +5 -0
  87. package/dist/publication/programs.d.ts.map +1 -0
  88. package/dist/publication/publisher.d.ts +34 -0
  89. package/dist/publication/publisher.d.ts.map +1 -0
  90. package/dist/publication/receiver.d.ts +29 -0
  91. package/dist/publication/receiver.d.ts.map +1 -0
  92. package/dist/publication/resource-scope.d.ts +18 -0
  93. package/dist/publication/resource-scope.d.ts.map +1 -0
  94. package/dist/publication/targets.d.ts +33 -0
  95. package/dist/publication/targets.d.ts.map +1 -0
  96. package/dist/publication/video.d.ts +5 -0
  97. package/dist/publication/video.d.ts.map +1 -0
  98. package/dist/record/fold-buckets.d.ts +3 -3
  99. package/dist/record/fold-buckets.d.ts.map +1 -1
  100. package/dist/record/frame-snapshot.d.ts +6 -6
  101. package/dist/record/frame-snapshot.d.ts.map +1 -1
  102. package/dist/record/frame.d.ts +5 -4
  103. package/dist/record/frame.d.ts.map +1 -1
  104. package/dist/record/helpers.d.ts +2 -2
  105. package/dist/record/helpers.d.ts.map +1 -1
  106. package/dist/record/main-pass-geometry.d.ts +2 -2
  107. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  108. package/dist/record/main-pass-material.d.ts +7 -9
  109. package/dist/record/main-pass-material.d.ts.map +1 -1
  110. package/dist/record/main-pass-sprite-draws.d.ts +3 -16
  111. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  112. package/dist/record/main-pass.d.ts.map +1 -1
  113. package/dist/record/prepared-material-bindings.d.ts +2 -3
  114. package/dist/record/prepared-material-bindings.d.ts.map +1 -1
  115. package/dist/record/render-context.d.ts +4 -2
  116. package/dist/record/render-context.d.ts.map +1 -1
  117. package/dist/record/shadow-pass.d.ts +2 -2
  118. package/dist/record/shadow-pass.d.ts.map +1 -1
  119. package/dist/record/sprite-instance-buffer.d.ts +31 -0
  120. package/dist/record/sprite-instance-buffer.d.ts.map +1 -0
  121. package/dist/record/target-capture-graph.d.ts +19 -0
  122. package/dist/record/target-capture-graph.d.ts.map +1 -0
  123. package/dist/record/typed-frame-graph.d.ts +2 -13
  124. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  125. package/dist/record/view-ubo.d.ts.map +1 -1
  126. package/dist/record/volume-params.d.ts +2 -2
  127. package/dist/record/volume-params.d.ts.map +1 -1
  128. package/dist/recovery/render-system-candidate.d.ts +5 -12
  129. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  130. package/dist/render-contract.d.ts +4 -1
  131. package/dist/render-contract.d.ts.map +1 -1
  132. package/dist/render-system-extract-tail.d.ts.map +1 -1
  133. package/dist/render-system-extract.d.ts +2 -0
  134. package/dist/render-system-extract.d.ts.map +1 -1
  135. package/dist/render-system-presentation.d.ts +2 -2
  136. package/dist/render-system-presentation.d.ts.map +1 -1
  137. package/dist/render-system-projections.d.ts +3 -2
  138. package/dist/render-system-projections.d.ts.map +1 -1
  139. package/dist/render-system-residency.d.ts +2 -2
  140. package/dist/render-system-residency.d.ts.map +1 -1
  141. package/dist/render-system.d.ts +3 -7
  142. package/dist/render-system.d.ts.map +1 -1
  143. package/dist/scene/render-scene.d.ts +8 -4
  144. package/dist/scene/render-scene.d.ts.map +1 -1
  145. package/dist/scene/render-source.d.ts +42 -0
  146. package/dist/scene/render-source.d.ts.map +1 -0
  147. package/dist/scene/source-systems.d.ts +6 -0
  148. package/dist/scene/source-systems.d.ts.map +1 -0
  149. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  150. package/dist/systems/skin-palette-types.d.ts +10 -0
  151. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  152. package/dist/systems/transparent-dispatch.d.ts +2 -2
  153. package/dist/systems/transparent-dispatch.d.ts.map +1 -1
  154. package/dist/systems/transparent-sort-config.d.ts +2 -1
  155. package/dist/systems/transparent-sort-config.d.ts.map +1 -1
  156. package/dist/temporal/index.mjs +6 -7
  157. package/dist/typed-shadow-passes.d.ts.map +1 -1
  158. package/package.json +21 -21
  159. package/src/__tests__/auto-exposure-transaction.integration.test.ts +4 -9
  160. package/src/__tests__/device-feature-admission.unit.test.ts +3 -2
  161. package/src/__tests__/device-scope-lifecycle.unit.test.ts +26 -0
  162. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +3 -4
  163. package/src/__tests__/gpu-driven-production.integration.test.ts +18 -1
  164. package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +23 -0
  165. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +4 -1
  166. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +0 -1
  167. package/src/__tests__/material-vertex-texture.browser.test.ts +7 -0
  168. package/src/__tests__/material-vertex-texture.dawn.test.ts +7 -0
  169. package/src/__tests__/material-vertex-texture.fixture.ts +31 -0
  170. package/src/__tests__/materials-standard-contract.unit.test.ts +0 -1
  171. package/src/__tests__/physical-clearcoat.integration.test.ts +23 -23
  172. package/src/__tests__/physical-material-budget.unit.test.ts +40 -0
  173. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +5 -0
  174. package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
  175. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +107 -5
  176. package/src/__tests__/runtime-material-program.integration.test.ts +79 -0
  177. package/src/__tests__/vertex-layouts-ssot.unit.test.ts +23 -3
  178. package/src/assembly/device-feature-admission.ts +2 -2
  179. package/src/assembly/host-contract.ts +5 -2
  180. package/src/assembly/recovery/renderer-recover.ts +9 -0
  181. package/src/assembly/render-target-host.ts +57 -47
  182. package/src/assembly/renderer-facade.ts +3 -1
  183. package/src/assembly/webgpu-ready.ts +1 -1
  184. package/src/assembly/webgpu-renderer.ts +101 -70
  185. package/src/assembly/webgpu-vertex-layouts.ts +2 -9
  186. package/src/cloud/frame-context.ts +2 -2
  187. package/src/device/device-scope.ts +3 -0
  188. package/src/device/gpu-residency.ts +26 -25
  189. package/src/errors/render.ts +3 -1
  190. package/src/extract/material-context.ts +21 -0
  191. package/src/features/host.ts +13 -5
  192. package/src/features/particle-mesh-layout.ts +25 -0
  193. package/src/features/plan.ts +2 -0
  194. package/src/features/types.ts +8 -0
  195. package/src/glyph-text-layout-system.ts +2 -2
  196. package/src/gpu-driven/production-raster.ts +9 -3
  197. package/src/gpu-driven/shadow-ownership.ts +3 -3
  198. package/src/gpu-driven/shadow-views.ts +27 -2
  199. package/src/gpu-driven/view-gpu.ts +5 -0
  200. package/src/ibl/frame-resources.ts +0 -1
  201. package/src/ibl/skylight-bind-group.ts +13 -25
  202. package/src/index.ts +9 -0
  203. package/src/instances.ts +9 -6
  204. package/src/pbr-pipeline.ts +15 -18
  205. package/src/pipeline/standard-output/lut-gpu.ts +3 -3
  206. package/src/pipeline/standard-output/resources.ts +2 -2
  207. package/src/publication/__tests__/derived-geometry.integration.test.ts +177 -0
  208. package/src/publication/__tests__/features.integration.test.ts +173 -0
  209. package/src/publication/__tests__/programs.unit.test.ts +25 -0
  210. package/src/publication/__tests__/publication.integration.test.ts +415 -0
  211. package/src/publication/__tests__/targets.integration.test.ts +120 -0
  212. package/src/publication/__tests__/video.browser.test.ts +50 -0
  213. package/src/publication/contract.ts +104 -0
  214. package/src/publication/dependencies.ts +54 -0
  215. package/src/publication/prepare-geometry.ts +94 -0
  216. package/src/publication/programs.ts +45 -0
  217. package/src/publication/publisher.ts +645 -0
  218. package/src/publication/receiver.ts +297 -0
  219. package/src/publication/resource-scope.ts +31 -0
  220. package/src/publication/targets.ts +182 -0
  221. package/src/publication/video.ts +33 -0
  222. package/src/record/__tests__/material-bg-cache.unit.test.ts +15 -1
  223. package/src/record/__tests__/prepared-runtime-material.integration.test.ts +134 -0
  224. package/src/record/__tests__/sprite-material-abi.unit.test.ts +8 -10
  225. package/src/record/__tests__/video-texture-view.unit.test.ts +9 -9
  226. package/src/record/fold-buckets.ts +8 -5
  227. package/src/record/frame-snapshot.ts +6 -6
  228. package/src/record/frame.ts +87 -28
  229. package/src/record/helpers.ts +2 -2
  230. package/src/record/main-pass-geometry.ts +21 -2
  231. package/src/record/main-pass-material.ts +37 -33
  232. package/src/record/main-pass-sprite-draws.ts +6 -152
  233. package/src/record/main-pass.ts +8 -7
  234. package/src/record/prepared-material-bindings.ts +16 -37
  235. package/src/record/render-context.ts +4 -2
  236. package/src/record/shadow-pass.ts +65 -7
  237. package/src/record/sprite-instance-buffer.ts +155 -0
  238. package/src/record/target-capture-graph.ts +258 -0
  239. package/src/record/typed-frame-graph.ts +11 -207
  240. package/src/record/view-ubo.ts +1 -1
  241. package/src/record/volume-params.ts +6 -6
  242. package/src/recovery/render-system-candidate.ts +10 -18
  243. package/src/render-contract.ts +6 -1
  244. package/src/render-system-extract-tail.ts +48 -23
  245. package/src/render-system-extract.ts +11 -2
  246. package/src/render-system-presentation.ts +2 -2
  247. package/src/render-system-projections.ts +3 -2
  248. package/src/render-system-residency.ts +2 -2
  249. package/src/render-system.ts +82 -54
  250. package/src/scene/render-scene.ts +110 -100
  251. package/src/scene/render-source.ts +90 -0
  252. package/src/scene/source-systems.ts +33 -0
  253. package/src/systems/skin-palette-allocator.ts +1 -0
  254. package/src/systems/skin-palette-types.ts +11 -0
  255. package/src/systems/transparent-dispatch.ts +2 -2
  256. package/src/systems/transparent-sort-config.ts +3 -1
  257. package/src/typed-shadow-passes.ts +36 -5
  258. package/dist/chunk-BLXGONR2.mjs.map +0 -1
  259. package/dist/chunk-ELJFJ2BU.mjs.map +0 -1
  260. package/dist/chunk-ILQ5MEZF.mjs +0 -32
  261. package/dist/chunk-ILQ5MEZF.mjs.map +0 -1
  262. package/dist/chunk-MKDIT2EM.mjs.map +0 -1
  263. package/dist/chunk-OCDLEI6I.mjs.map +0 -1
  264. package/dist/chunk-ODZWR6JQ.mjs.map +0 -1
  265. package/dist/chunk-RXZ3RGOU.mjs +0 -53
  266. package/dist/chunk-RXZ3RGOU.mjs.map +0 -1
  267. package/dist/chunk-SHFUFJ5N.mjs +0 -1781
  268. package/dist/chunk-SHFUFJ5N.mjs.map +0 -1
  269. package/dist/chunk-UI5SFODX.mjs.map +0 -1
  270. package/dist/chunk-UINHLCZA.mjs +0 -2389
  271. package/dist/chunk-UINHLCZA.mjs.map +0 -1
  272. package/dist/chunk-WEX45HKH.mjs +0 -1524
  273. package/dist/chunk-WEX45HKH.mjs.map +0 -1
@@ -1,28 +1,25 @@
1
- import { BARREL_DISTORTION_FEATURE_IDENTITY, createBarrelDistortionRenderFeature, inspectVolumetricFog, resolveSsrAdmissionGeneration, inspectLodOcclusion, zeroSsrAdmissionWork, projectSsrSpatialInspection, createDynamicGeometryLifecycle, inspectReflectionFallback, admitReflectionProbe, DEFAULT_REFLECTION_PROBE_LIMITS, buildReflectionProbeTable, advanceProbeFilter, commitProbeFilterStep, resolveReflectionFallbackSource, deriveReflectionFallbackProjection, reflectionFallbackCoverage, reflectionFallbackSourceKey, reflectionFallbackProjectionSignature, createProbeFilterState, ReflectionProbeProjection, admitPointsLines, projectSsrDependencies, admitSsrSpatial, BARREL_DISTORTION_POST_PROCESS_ID, inspectPointShadow, admitSingleLayerMediumSubmission, createCloudShadowProjection, CLOUD_LAYER_FEATURE_IDENTITY, ReadonlyDynamicInputPage, DynamicGeometryError, sameCandidateCredential } from './chunk-ODZWR6JQ.mjs';
2
- import { createExtendedLightingState, promoteExtendedLightingCandidate, glyphTextLayoutSystem, emptyBloomInspection, projectExtendedLightingInspection, OcclusionRenderRuntime, extractFrames, viewKey, primitiveKey, projectBarrelDistortionInspection, viewKeyId, primitiveKeyId, ProbeBlendSceneProjection, InstanceBoundsCache, fingerprintNumericArray, buildShadowFrusta, createSsrHistoryOwner, createSsrSpatialResources, createCookieProjectionMatrixData } from './chunk-UI5SFODX.mjs';
3
- import './chunk-ILQ5MEZF.mjs';
4
- import { DEFAULT_DEPTH_OF_FIELD_PARAMS, projectMeshMaterialBindingObservation, resolveDepthOfFieldFrameParams, buildCubeCameraFaceViews, MeshFilter, MeshRenderer, Instances, Layer, Visibility, Points, Lines, SortKey, SKYLIGHT_RECOVERY_FALLBACK, hasVolumetricFogCapability, packDepthOfFieldParams, Camera, CAMERA_PROJECTION_ORTHOGRAPHIC, cloudShadowResolutionForQuality, CUBE_CAMERA_FACE_ORDER, createBarrelDistortionMapping, attachBarrelDistortionCameraFrame, MAX_VOLUMETRIC_FOG_OWNERS } from './chunk-UINHLCZA.mjs';
5
- import { TileLayer, decodeSortScope, SpriteInstances, SpriteRegionOverride, Tilemap } from './chunk-ELJFJ2BU.mjs';
6
- import { GPU_SCENE_LAYOUTS, deviceOptionsForAdapter, PipelineSpecError, assertStorageBufferCap, STANDARD_PBR_REQUIRED_SAMPLED_TEXTURES, GpuBuffer, GpuTexture, deriveRenderDataTexture, deriveRenderDataMesh, deriveRenderDataCubemap, createIblPipelines, CUBEMAP_FACE_VERTICES, runIblPrecompute, SurfaceSubmissionObservationOwner, createClusterBinScratch, resetSsaoResources, resetHdrpBuffers, retireTemporalGpuState, PostProcessError, entryHasDepthRead, DEPTH_MIN_PARAMS_BYTE_SIZE, postProcessShaderModuleLabel, resolveSsaoParameters, buildPerFrameBindGroups, resolveMaterialSkylight, postProcessShaderEntrySignature, standardBloomAdmitted, selectSwapChainFormat, setIblComposedShaders, POINTS_LINES_MATERIAL_SHADER_ID, selectStandardPbrTransmissionPrewarmVariants, selectHdrpPbrPrewarmVariants, prewarmMaterialShaderVariants, selectProbePrewarmVariants, createHdrpClusterMembershipBindGroupLayoutDescriptor, createSkylightFallback, buildSpecConstTable, buildLinearLdrMaterialSpecTable, getOrBuildPipeline, cacheKeyOf, HDR_COLOR_ATTACHMENT_FORMAT, configureSurface, CAPTURE_VIEW_PROJS, PREFILTER_MIP_LEVELS, REFLECTION_PROBE_VIEW_SLOT_BASE, VIEW_UNIFORM_SLOT_STRIDE, getOrCreateIblCache, decideVisibility, BatchTopology, postProcessShaderPipelineLabel, createPointsLinesLaneAdapter, computeViewMatrix, computeProjectionMatrix, prepareFrameLighting, warnMultiSkylight, warnMultiSkybox, selectLazyEquirectHandle, driveLazyEquirectProjection, warnZeroLightStandard, writeShadowParamsBuffer, ensureProbeBlendRecordBuffer, deriveRenderExtent, writeSpotModifierTextures, writeHdrpClusterAndSsaoBuffers, resolveSkyboxActive, computeSplitLdrSprite, writeViewUbo, writePointsLinesViewUbo, writeShadowCasterUniforms, uploadMeshSsboBatch, passKindPolicyTable, colorFormatsForPassKind, GPU_DRIVEN_VIEW_WGSL, selectGpuDrivenSceneIndexVariant, selectSkinPrewarmVariants, transmissionBackdropAvailable, VIEW_UBO_BYTES, POINTS_LINES_VIEW_BUFFER_SIZE, SHADOW_CASTER_BUFFER_SIZE, FALLBACK_BYTES_PER_ROW, MIPMAP_PREWARM_FORMATS, getIblProbeBackgroundSource, OcclusionConfidenceScheduler, shouldIssueRetest, selectGpuLodLane, ShadowViewStatePool, GpuDrivenView, MATERIAL_PER_ENTITY_STRIDE, shadowViewIdentityKey, combineGpuResourceAllocationInspections, inspectResourceClassSplits, createPointsLinesLaneContract, foldDispatchBuckets, CUBE_CAPTURE_VIEW_SLOT_BASE, variantSetFromDefines, resolveReflectionProbeBinding, cleanPerEntityCache, ensureMeshSsboCapacity, buildFoldDispatchPlan, evaluateFoldBucketUniformCap, incrementFoldedDrawsMetric, writePbrMaterialUboPayload, applyParamSnapshotToUbo, applyMaterialTextureUvScales, residentTextureView, detectNineSliceScaleTooSmall, DEPTH_TEXTURE_FORMAT, PREFILTER_SIZE, gpuSceneFieldOffset, projectedHeightForCandidate, geometryRenderStateForTopology, packInstanceStorageBuffer, GpuResourceAllocationLedger, MESH_PER_ENTITY_STRIDE, MESH_SSBO_BYTES, standardTopologyVariantSet, resolveGeometryInstanceBuffer, buildFullscreenPostProcessPass, getTemporalGpuState, getTemporalParamsBuffer, getTemporalBindGroupResources, TEMPORAL_HISTORY_FORMATS, resolveSurfaceFormatPair, resolveSurfaceProfile, createRenderPipelineTarget, encodeMainPass, STANDARD_PBR_UBO_SIZE, abortTemporalGpuSubmit, commitTemporalGpuSubmit, retireTemporalGpuStateAfterFence, hasPendingTemporalGpuSubmit, importRenderPipelineSurface, renderExtentSize, DEFERRED_COLOR_FORMATS, aggregateTemporalDemand, standardTemporalLaneAdmission, addTypedScenePass, addTypedSsaoPasses, addTypedSkyboxPass, renderPipelineCloudHistoryTargets, createStandardSceneDataTarget, addStandardSceneDataPass, VIEW_UNIFORM_BYTES, addTypedFrameObservationPass, addReflectionFallbackObservationPass, selectLod, temporalReadIndex, temporalWriteIndex, CLOUD_HISTORY_FORMATS, prepareMaterialSkylight, BYTES_PER_DIRECT_LIGHT_SLOT, shadowViewRasterAccesses, encodeDirectionalShadowPass, encodePointShadowPass, encodeSpotShadowPass, getOrCreateFromChain, addTypedFullscreenPass, resolveOutputDither, addTypedTemporalResolvePass, addTypedBloomPasses, addTypedOutputTransformPass, addTypedCompositePostEffects, geometryRenderStateForPass, standardStorageVariantSet, getOrCreateHdrpBuffers, variantSetFromVertexLayoutProjection, createStandardSurfaceLightingBindGroup, BLOOM_DOWNSAMPLE_PARAMS_BYTES, BLOOM_UPSAMPLE_PARAMS_BYTES, BLOOM_COMPOSITE_PARAMS_BYTES, isTemporalFullscreenBinding, createFullscreenBindGroup, stageTemporalGpuSubmit, applyParamSchemaDefaultsToUbo, defaultViewForUserRegionField, assembleMaterialWithSkylightEntries, TYPED_BLOOM_PASS_NAMES } from './chunk-MKDIT2EM.mjs';
7
- import { getTransparentSortConfig, TRANSPARENT_SORT_MODE_DISTANCE, TRANSPARENT_SORT_MODE_LAYER_Z, TRANSPARENT_SORT_MODE_LAYER_Y, TRANSPARENT_SORT_MODE_LAYER_YZ } from './chunk-RXZ3RGOU.mjs';
8
- import { DEFAULT_STANDARD_PROFILE, DEFAULT_CLUSTER_GRID, STANDARD_PIPELINE_ID, STANDARD_LIGHT_COUNTS, STANDARD_POST_STAGE_NAMES, createSceneDataCatalog, isSceneDataTarget, resolveVolumetricFogProfile, SCENE_DATA_TEMPORAL_V1_SCHEMA } from './chunk-OCDLEI6I.mjs';
9
- import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from './chunk-BLXGONR2.mjs';
10
- import { DeviceScope, SKIN_MATERIAL_SHADER_ID, EXTENDED_LIGHTING_TOPOLOGY, getTextureIdentity, GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_MAP_READ, resolveRenderTargetMaterialSource, createRenderTargetMaterialSource, deriveExtendedLightingCapability, GPU_BUFFER_USAGE_VERTEX, GPU_BUFFER_USAGE_INDEX, IES_SLICE_WIDTH, IES_SLICE_HEIGHT, COOKIE_SLICE_SIZE, COOKIE_MATRIX_BYTES, GPU_BUFFER_USAGE_UNIFORM, worldEntityKey, createHdrpBindGroupLayoutDescriptor, createHdrpSkinBindGroupLayoutDescriptor, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_COPY_SRC, gpuDrivenShadowDrawKey, makeZeroCameraFallbackSnapshot, buildPbrPipelineLayouts, buildPbrSkinLayouts, buildGpuDrivenPbrInstancesBindGroupLayout, buildSurfaceDirectInstancesBindGroupLayout, buildGpuDrivenPbrPipelineLayout, buildGpuDrivenPbrSkinPipelineLayout, GPU_BUFFER_USAGE_STORAGE, resolvePipelineGroup2Contract, GPU_SHADER_STAGE_FRAGMENT, isCanonicalStandardPbrMaterialShader, getOpaqueResourceIdentity, gpuDrivenDrawKey, gpuDrivenSourceDrawItemIndex, instanceCollectionCacheKey, validateGraphTargetCaptureReadback, createTemporalCoverage, isStandardPbrMaterialShader, buildBindGroupLayoutDescriptor, gpuDrivenMaterialArtifactKey, hasRequiredVertexInputs, buildPbrMaterialUserRegionEntries, extendedLightingSampledTextureCapacityAvailable, PROBE_BLEND_RECORD_BYTE_SIZE, GPU_SHADER_STAGE_VERTEX, SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET, SHADOW_CASTER_SHADER_ID, shadowCasterVariantSet, GPU_SHADER_STAGE_COMPUTE, LifecycleTransaction } from './chunk-SHFUFJ5N.mjs';
11
- import { RendererContractFailureError, RendererOperationError, MotionBlurValidationError, STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, FrameReceiptStaleError, RenderFeatureStageFailedError, RenderFeatureCapabilityMissingError, RenderTargetStateInvalidError, RenderTargetOperationFailedError, RenderTargetCapabilityMissingError, RenderTargetDescriptorInvalidError, GPU_TEXTURE_USAGE_TEXTURE_BINDING, GPU_TEXTURE_USAGE_COPY_DST, RENDER_PHASE_CATALOG, InstanceProjectionStore, motionBlurTemporalDemand, createAutoExposureInspection, RenderFeatureRegistrationConflictError, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING, GPU_TEXTURE_USAGE_COPY_SRC, createVisibilityBudget, EnvironmentGenerationFailedError, PointsLinesMaterialUnsupportedError, StandardProfileInvalidError, TransmissionCapabilityMissingError, motionBlurSampleDelta, isMotionBlurIntervalValid, MOTION_BLUR_PARAMS_BYTE_SIZE, effectiveMotionBlurSampleCount, motionBlurExposureScale, SHADOW_ATLAS_DEFAULT_LAYERS, DEFAULT_MOTION_BLUR_PARAMS, FXAA_POST_PROCESS_ID, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT, GpuDrivenPreparationError, TemporalFrameSubmitError, ObservationUnavailableError, RenderFeaturePreparationFailedError, AutoExposureInvalidParameterError, PointsLinesPrepareFailedError, validateMotionBlurParams, SHADOW_ATLAS_DEFAULT_FACE_SIZE, SceneDataUnavailableError, SkinPaletteOverflowError, GPU_TEXTURE_USAGE_STORAGE_BINDING, RenderFeatureDrawRecordingFailedError, PointShadowAtlasUninitializedError, RenderFeaturePreparedStateMismatchError } from './chunk-WEX45HKH.mjs';
1
+ import { RenderPublicationError, BARREL_DISTORTION_FEATURE_IDENTITY, createBarrelDistortionRenderFeature, createRenderTargetHost, RenderPublicationTargetReceiver, registerRenderSourceSystems, publicationFrameDependencies, publicationDependencies, inspectVolumetricFog, renderMaterialContext, resolveSsrAdmissionGeneration, inspectLodOcclusion, zeroSsrAdmissionWork, projectSsrSpatialInspection, createDynamicGeometryLifecycle, inspectReflectionFallback, admitReflectionProbe, DEFAULT_REFLECTION_PROBE_LIMITS, buildReflectionProbeTable, advanceProbeFilter, commitProbeFilterStep, resolveReflectionFallbackSource, deriveReflectionFallbackProjection, reflectionFallbackCoverage, reflectionFallbackSourceKey, reflectionFallbackProjectionSignature, createProbeFilterState, ReflectionProbeProjection, RENDERABLE_SOURCE_COMPONENTS, isRenderableMember, createRenderSourceState, createGlobalTransformChangeQuery, admitPointsLines, projectSsrDependencies, resolveShadowMapSize, resolveSpotShadowMapSize, admitSsrSpatial, acquireSwapChainTarget, BARREL_DISTORTION_POST_PROCESS_ID, graphExecutionPhase, inspectPointShadow, admitSingleLayerMediumSubmission, createCloudShadowProjection, CLOUD_LAYER_FEATURE_IDENTITY, ReadonlyDynamicInputPage, DynamicGeometryError, resolveDirectionalShadowAtlasGrid, sameCandidateCredential } from './chunk-OEYKKMXG.mjs';
2
+ import { createExtendedLightingState, promoteExtendedLightingCandidate, emptyBloomInspection, projectExtendedLightingInspection, OcclusionRenderRuntime, viewKey, primitiveKey, projectBarrelDistortionInspection, viewKeyId, primitiveKeyId, ProbeBlendSceneProjection, createSsrHistoryOwner, createSsrSpatialResources } from './chunk-D6WSBXJ2.mjs';
3
+ import { DEFAULT_DEPTH_OF_FIELD_PARAMS, extractFrames, projectMeshMaterialBindingObservation, resolveDepthOfFieldFrameParams, buildCubeCameraFaceViews, Instances, Visibility, SKYLIGHT_RECOVERY_FALLBACK, hasVolumetricFogCapability, packDepthOfFieldParams, Points, Lines, buildShadowFrusta, cloudShadowResolutionForQuality, CUBE_CAMERA_FACE_ORDER, createBarrelDistortionMapping, attachBarrelDistortionCameraFrame, MeshFilter, MAX_VOLUMETRIC_FOG_OWNERS, MeshRenderer, createCookieProjectionMatrixData, internSharedRefFromGuid } from './chunk-BZQ4CDRF.mjs';
4
+ import { SpriteInstances } from './chunk-X2KA6WHM.mjs';
5
+ import { GPU_SCENE_LAYOUTS, deviceOptionsForAdapter, PipelineSpecError, assertStorageBufferCap, STANDARD_PBR_REQUIRED_SAMPLED_TEXTURES, GpuBuffer, GpuTexture, deriveRenderDataTexture, deriveRenderDataMesh, deriveRenderDataCubemap, createIblPipelines, CUBEMAP_FACE_VERTICES, runIblPrecompute, SurfaceSubmissionObservationOwner, createClusterBinScratch, resetSsaoResources, resetHdrpBuffers, retireTemporalGpuState, PostProcessError, entryHasDepthRead, DEPTH_MIN_PARAMS_BYTE_SIZE, postProcessShaderModuleLabel, resolveSsaoParameters, buildPerFrameBindGroups, resolveMaterialSkylight, postProcessShaderEntrySignature, standardBloomAdmitted, setIblComposedShaders, POINTS_LINES_MATERIAL_SHADER_ID, selectStandardPbrTransmissionPrewarmVariants, selectHdrpPbrPrewarmVariants, prewarmMaterialShaderVariants, selectProbePrewarmVariants, createHdrpClusterMembershipBindGroupLayoutDescriptor, createSkylightFallback, buildSpecConstTable, buildLinearLdrMaterialSpecTable, getOrBuildPipeline, cacheKeyOf, HDR_COLOR_ATTACHMENT_FORMAT, CAPTURE_VIEW_PROJS, PREFILTER_MIP_LEVELS, REFLECTION_PROBE_VIEW_SLOT_BASE, VIEW_UNIFORM_SLOT_STRIDE, getOrCreateIblCache, decideVisibility, BatchTopology, postProcessShaderPipelineLabel, createPointsLinesLaneAdapter, computeViewMatrix, computeProjectionMatrix, prepareFrameLighting, warnMultiSkylight, warnMultiSkybox, selectLazyEquirectHandle, driveLazyEquirectProjection, warnZeroLightStandard, writeShadowParamsBuffer, ensureProbeBlendRecordBuffer, deriveRenderExtent, writeSpotModifierTextures, writeHdrpClusterAndSsaoBuffers, resolveSkyboxActive, computeSplitLdrSprite, writeViewUbo, writePointsLinesViewUbo, writeShadowCasterUniforms, uploadMeshSsboBatch, passKindPolicyTable, colorFormatsForPassKind, GPU_DRIVEN_VIEW_WGSL, selectGpuDrivenSceneIndexVariant, selectSkinPrewarmVariants, transmissionBackdropAvailable, VIEW_UBO_BYTES, POINTS_LINES_VIEW_BUFFER_SIZE, SHADOW_CASTER_BUFFER_SIZE, FALLBACK_BYTES_PER_ROW, MIPMAP_PREWARM_FORMATS, getIblProbeBackgroundSource, OcclusionConfidenceScheduler, shouldIssueRetest, selectGpuLodLane, ShadowViewStatePool, GpuDrivenView, shadowViewIdentityKey, combineGpuResourceAllocationInspections, inspectResourceClassSplits, createPointsLinesLaneContract, foldDispatchBuckets, CUBE_CAPTURE_VIEW_SLOT_BASE, variantSetFromDefines, resolveReflectionProbeBinding, cleanPerEntityCache, ensureMeshSsboCapacity, buildFoldDispatchPlan, evaluateFoldBucketUniformCap, incrementFoldedDrawsMetric, writePbrMaterialUboPayload, applyParamSnapshotToUbo, applyMaterialTextureUvScales, residentTextureView, detectNineSliceScaleTooSmall, DEPTH_TEXTURE_FORMAT, PREFILTER_SIZE, gpuSceneFieldOffset, projectedHeightForCandidate, geometryRenderStateForTopology, packInstanceStorageBuffer, GpuResourceAllocationLedger, MESH_PER_ENTITY_STRIDE, MESH_SSBO_BYTES, standardTopologyVariantSet, resolveGeometryInstanceBuffer, buildFullscreenPostProcessPass, getTemporalGpuState, getTemporalParamsBuffer, getTemporalBindGroupResources, TEMPORAL_HISTORY_FORMATS, createRenderPipelineTarget, encodeMainPass, abortTemporalGpuSubmit, commitTemporalGpuSubmit, retireTemporalGpuStateAfterFence, hasPendingTemporalGpuSubmit, importRenderPipelineSurface, renderExtentSize, DEFERRED_COLOR_FORMATS, aggregateTemporalDemand, standardTemporalLaneAdmission, addTypedScenePass, addTypedSsaoPasses, addTypedSkyboxPass, renderPipelineCloudHistoryTargets, createStandardSceneDataTarget, addStandardSceneDataPass, VIEW_UNIFORM_BYTES, addTypedFrameObservationPass, addReflectionFallbackObservationPass, selectLod, temporalReadIndex, temporalWriteIndex, CLOUD_HISTORY_FORMATS, prepareMaterialSkylight, BYTES_PER_DIRECT_LIGHT_SLOT, shadowViewRasterAccesses, encodeDirectionalShadowPass, encodePointShadowPass, encodeSpotShadowPass, getOrCreateFromChain, addTypedFullscreenPass, resolveOutputDither, addTypedTemporalResolvePass, addTypedBloomPasses, addTypedOutputTransformPass, addTypedCompositePostEffects, geometryRenderStateForPass, standardStorageVariantSet, getOrCreateHdrpBuffers, variantSetFromVertexLayoutProjection, createStandardSurfaceLightingBindGroup, BLOOM_DOWNSAMPLE_PARAMS_BYTES, BLOOM_UPSAMPLE_PARAMS_BYTES, BLOOM_COMPOSITE_PARAMS_BYTES, isTemporalFullscreenBinding, createFullscreenBindGroup, stageTemporalGpuSubmit, applyParamSchemaDefaultsToUbo, defaultViewForUserRegionField, assembleMaterialWithSkylightEntries, TYPED_BLOOM_PASS_NAMES } from './chunk-CJOV2XLO.mjs';
6
+ import { DEFAULT_STANDARD_PROFILE, DEFAULT_CLUSTER_GRID, selectSwapChainFormat, configureSurface, STANDARD_PIPELINE_ID, STANDARD_LIGHT_COUNTS, STANDARD_POST_STAGE_NAMES, createSceneDataCatalog, MATERIAL_PER_ENTITY_STRIDE, isSceneDataTarget, resolveSurfaceFormatPair, resolveSurfaceProfile, resolveVolumetricFogProfile, STANDARD_PBR_UBO_SIZE, SCENE_DATA_TEMPORAL_V1_SCHEMA } from './chunk-OB5WAFYH.mjs';
7
+ import { getTransparentSortConfig, TRANSPARENT_SORT_MODE_DISTANCE, TRANSPARENT_SORT_MODE_LAYER_Z, TRANSPARENT_SORT_MODE_LAYER_Y, TRANSPARENT_SORT_MODE_LAYER_YZ, SPRITE_PREMULTIPLIED_ALPHA_BLEND } from './chunk-XSFB7XXQ.mjs';
8
+ import { createTemporalCoverage, PROBE_BLEND_RECORD_BYTE_SIZE } from './chunk-RIPAEGI6.mjs';
9
+ import { RendererContractFailureError, RendererOperationError, MotionBlurValidationError, DeviceScope, SKIN_MATERIAL_SHADER_ID, STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, EXTENDED_LIGHTING_TOPOLOGY, FrameReceiptStaleError, getTextureIdentity, RenderFeatureStageFailedError, RenderFeatureCapabilityMissingError, deriveExtendedLightingCapability, GPU_TEXTURE_USAGE_TEXTURE_BINDING, GPU_TEXTURE_USAGE_COPY_DST, GPU_BUFFER_USAGE_VERTEX, GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_INDEX, IES_SLICE_WIDTH, IES_SLICE_HEIGHT, COOKIE_SLICE_SIZE, COOKIE_MATRIX_BYTES, RENDER_PHASE_CATALOG, InstanceProjectionStore, GPU_BUFFER_USAGE_UNIFORM, worldEntityKey, motionBlurTemporalDemand, createAutoExposureInspection, createHdrpBindGroupLayoutDescriptor, createHdrpSkinBindGroupLayoutDescriptor, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_COPY_SRC, GPU_BUFFER_USAGE_MAP_READ, RenderFeatureRegistrationConflictError, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING, GPU_TEXTURE_USAGE_COPY_SRC, createVisibilityBudget, gpuDrivenShadowDrawKey, EnvironmentGenerationFailedError, PointsLinesMaterialUnsupportedError, StandardProfileInvalidError, buildGpuDrivenDraws, TransmissionCapabilityMissingError, motionBlurSampleDelta, isMotionBlurIntervalValid, makeZeroCameraFallbackSnapshot, MOTION_BLUR_PARAMS_BYTE_SIZE, effectiveMotionBlurSampleCount, motionBlurExposureScale, SHADOW_ATLAS_DEFAULT_LAYERS, DEFAULT_MOTION_BLUR_PARAMS, FXAA_POST_PROCESS_ID, buildPbrPipelineLayouts, buildPbrSkinLayouts, buildGpuDrivenPbrInstancesBindGroupLayout, buildSurfaceDirectInstancesBindGroupLayout, buildGpuDrivenPbrPipelineLayout, buildGpuDrivenPbrSkinPipelineLayout, GPU_BUFFER_USAGE_STORAGE, resolvePipelineGroup2Contract, GPU_SHADER_STAGE_FRAGMENT, RenderTargetStateInvalidError, InstanceBoundsCache, fingerprintNumericArray, GpuDrivenPreparationError, isCanonicalStandardPbrMaterialShader, getOpaqueResourceIdentity, gpuDrivenDrawKey, gpuDrivenSourceDrawItemIndex, TemporalFrameSubmitError, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT, ObservationUnavailableError, RenderFeaturePreparationFailedError, AutoExposureInvalidParameterError, instanceCollectionCacheKey, validateGraphTargetCaptureReadback, isStandardPbrMaterialShader, buildBindGroupLayoutDescriptor, gpuDrivenMaterialArtifactKey, PointsLinesPrepareFailedError, validateMotionBlurParams, hasRequiredVertexInputs, SHADOW_ATLAS_DEFAULT_FACE_SIZE, resolveRenderTargetMaterialSource, buildPbrMaterialUserRegionEntries, extendedLightingSampledTextureCapacityAvailable, SceneDataUnavailableError, SkinPaletteOverflowError, GPU_TEXTURE_USAGE_STORAGE_BINDING, RenderFeatureDrawRecordingFailedError, GPU_SHADER_STAGE_VERTEX, PointShadowAtlasUninitializedError, SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET, SHADOW_CASTER_SHADER_ID, shadowCasterVariantSet, RenderFeaturePreparedStateMismatchError, GPU_SHADER_STAGE_COMPUTE, RenderTargetOperationFailedError, LifecycleTransaction } from './chunk-2OZAS3WU.mjs';
12
10
  import { ok, err, RhiError, validateDrawArgs } from '@forgeax/engine-rhi';
13
- import { AssetRegistry, DynamicTextureStore, adaptDynamicTextureDevice, getOrCreateMipmapPipeline, prepareMipmaps, blitMipmapsSync, HANDLE_CUBE, HANDLE_TRIANGLE, HANDLE_QUAD, HANDLE_SPHERE, HANDLE_NINESLICE_QUAD, BuiltinAssetRegistry, RuntimeMaterialValue, RuntimeMeshVertices, resolveAssetHandle, numMipLevels, encodeMipmapLevel, resolveTilesetRuntime, MeshSsboCeilingReachedError, MeshSsboCapacityExceededError } from '@forgeax/engine-assets-runtime';
11
+ import { AssetRegistry, DynamicTextureStore, adaptDynamicTextureDevice, getOrCreateMipmapPipeline, prepareMipmaps, blitMipmapsSync, HANDLE_CUBE, HANDLE_TRIANGLE, HANDLE_QUAD, HANDLE_SPHERE, HANDLE_NINESLICE_QUAD, BuiltinAssetRegistry, RuntimeMaterialValue, RuntimeMeshVertices, resolveAssetHandle, numMipLevels, encodeMipmapLevel, MeshSsboCeilingReachedError, MeshSsboCapacityExceededError } from '@forgeax/engine-assets-runtime';
14
12
  import { audioLoader } from '@forgeax/engine-audio-webaudio';
15
- import { Update, Time, FixedTime } from '@forgeax/engine-ecs';
16
- import { createRenderReadLease, createStateProjection } from '@forgeax/engine-ecs/projection';
17
- import { buildMeshAttributeMapForUvSets, deriveVertexBufferLayout, DEFAULT_VERTEX_ATTRIBUTE_MAP, deriveVertexCount, deriveVertexLayoutProjection, SKIN_VERTEX_ATTRIBUTE_MAP, deriveVertexBufferLayoutFromProjection } from '@forgeax/engine-geometry';
18
- import { registerPropagateTransforms, collectSubtree, Name, ChildOf, Children, MorphWeights, GlobalTransform, Transform } from '@forgeax/engine-scene';
19
- import { STANDARD_PIPELINE_PARAM_SCHEMA, createStandardPbrArtifactReceipt, SINGLE_LAYER_MEDIUM_RAW_DEPTH_WGSL, SINGLE_LAYER_MEDIUM_MSAA_PAIRED_COLOR_WGSL, SINGLE_LAYER_MEDIUM_MSAA_RAW_DEPTH_WGSL, ShaderCatalog, findVariantByKey, LTC_TABLES, standardPhysicalTextureFields, LTC_TABLE_HEIGHT, LTC_TABLE_WIDTH, DEFAULT_STANDARD_PBR_PARAM_SCHEMA, AUTO_EXPOSURE_METER_WGSL } from '@forgeax/engine-shader';
20
- import { halfFloat, frustum, mat4, vec3, box3, mat3 } from '@forgeax/engine-math';
21
- import { derive, err as err$1, ok as ok$1, handleSlot, deriveTextureLayout, ASSET_ERROR_HINTS, countExtraUvSets, toShared, RenderQueue, IMAGE_ERROR_HINTS, BUILTIN_BASE, unwrapHandle, materialValuesToLinearRuntime } from '@forgeax/engine-types';
13
+ import { createRenderReadLease } from '@forgeax/engine-ecs/projection';
14
+ import { deriveVertexLayoutProjection, buildMeshAttributeMapForUvSets, deriveVertexCount, DEFAULT_VERTEX_ATTRIBUTE_MAP, SKIN_VERTEX_ATTRIBUTE_MAP, deriveVertexBufferLayoutFromProjection, deriveVertexBufferLayout } from '@forgeax/engine-geometry';
15
+ import { STANDARD_PIPELINE_PARAM_SCHEMA, createStandardPbrArtifactReceipt, SINGLE_LAYER_MEDIUM_RAW_DEPTH_WGSL, SINGLE_LAYER_MEDIUM_MSAA_PAIRED_COLOR_WGSL, SINGLE_LAYER_MEDIUM_MSAA_RAW_DEPTH_WGSL, ShaderCatalog, findVariantByKey, MaterialArtifactRegistry, ShaderRegistry, LTC_TABLES, standardPhysicalTextureFields, LTC_TABLE_HEIGHT, LTC_TABLE_WIDTH, DEFAULT_STANDARD_PBR_PARAM_SCHEMA, AUTO_EXPOSURE_METER_WGSL } from '@forgeax/engine-shader';
16
+ import { AssetGuid } from '@forgeax/engine-pack/guid';
17
+ import { derive, ok as ok$1, err as err$1, handleSlot, deriveTextureLayout, ASSET_ERROR_HINTS, countExtraUvSets, toShared, AssetError, RenderQueue, IMAGE_ERROR_HINTS, BUILTIN_BASE, materialValuesToLinearRuntime } from '@forgeax/engine-types';
18
+ import { halfFloat, mat4, vec3, box3, frustum, mat3 } from '@forgeax/engine-math';
22
19
  import { createCurrentFrameObservationLease, RenderGraphBuilder, RenderGraphError } from '@forgeax/engine-render-graph';
20
+ import { Time, FixedTime } from '@forgeax/engine-ecs';
21
+ import { collectSubtree, Name, ChildOf, Children, GlobalTransform, MorphWeights, Transform } from '@forgeax/engine-scene';
23
22
  import { Skin } from '@forgeax/engine-skinning';
24
- import { decodeTileBits } from '@forgeax/engine-graphics-extras';
25
- import { AssetGuid } from '@forgeax/engine-pack/guid';
26
23
  import '@forgeax/engine-pack/material-cook';
27
24
 
28
25
  // src/assembly/backend-contract.ts
@@ -268,7 +265,8 @@ function exposeRenderer(renderer) {
268
265
  cause: structuredRendererCause(cause, "renderer-event")
269
266
  });
270
267
  const drawError = (cause) => {
271
- if (cause instanceof MotionBlurValidationError) return cause;
268
+ if (cause instanceof MotionBlurValidationError || cause instanceof RenderPublicationError)
269
+ return cause;
272
270
  if (cause instanceof RendererOperationError) return cause;
273
271
  if (cause instanceof RendererContractFailureError) {
274
272
  return new RendererOperationError("device-operation-failed", {
@@ -543,6 +541,237 @@ function freezeRenderProfile(profile) {
543
541
  postStages: Object.freeze([...profile.postStages])
544
542
  });
545
543
  }
544
+ function installPublicationPrograms(assets, programs) {
545
+ if (programs.length === 0) return;
546
+ const validation = new MaterialArtifactRegistry();
547
+ const shaders = new ShaderRegistry({ manifestUrl: void 0 });
548
+ const keys = /* @__PURE__ */ new Set();
549
+ for (const row of programs) {
550
+ if (keys.has(row.key) || row.artifact !== void 0 && row.artifact.key !== row.key)
551
+ throw new RenderPublicationError({
552
+ reason: "shape",
553
+ subject: "duplicate or mismatched program key"
554
+ });
555
+ keys.add(row.key);
556
+ shaders.installMaterialArtifact(row.key, row.shader);
557
+ const previous = assets.shaderRegistry.findMaterialArtifact(row.key);
558
+ if (previous.ok && (previous.value.source !== row.shader.source || JSON.stringify(previous.value.paramSchema) !== JSON.stringify(row.shader.paramSchema) || JSON.stringify(previous.value.receipt) !== JSON.stringify(row.shader.receipt))) {
559
+ throw new RenderPublicationError({
560
+ reason: "shape",
561
+ subject: `conflicting immutable shader ${row.key}`
562
+ });
563
+ }
564
+ if (row.artifact !== void 0) {
565
+ const existing = assets.getMaterialArtifact(row.key);
566
+ if (existing !== void 0) validation.register(existing).unwrap();
567
+ validation.register(row.artifact).unwrap();
568
+ }
569
+ }
570
+ for (const row of programs) {
571
+ if (row.artifact !== void 0) assets.materialArtifactRegistry.register(row.artifact).unwrap();
572
+ if (!assets.shaderRegistry.findMaterialArtifact(row.key).ok)
573
+ assets.shaderRegistry.installMaterialArtifact(row.key, row.shader);
574
+ }
575
+ }
576
+ var RenderPublicationReceiver = class {
577
+ constructor(identity) {
578
+ this.identity = identity;
579
+ const resolveAsset = (handle) => {
580
+ const value = this.assets.get(handle);
581
+ return value === void 0 ? err$1(
582
+ new AssetError({
583
+ code: "asset-not-found",
584
+ expected: "the accepted publication contains the referenced asset generation",
585
+ hint: "publish the asset closure before drawing its consumer"
586
+ })
587
+ ) : ok$1(value);
588
+ };
589
+ this.resources = {
590
+ identity: `${identity.source}:${identity.epoch}`,
591
+ time: { delta: 0, elapsed: 0, maxDeltaSeconds: 0 },
592
+ transparentSort: { mode: 0, yzAlpha: 1 },
593
+ resolveAsset,
594
+ videoFrame: (entity, clip) => this.videoFrames.get(`${entity}:${clip}`),
595
+ handleForGuid: (guid) => this.guidHandles.get(guid.toLowerCase()),
596
+ lookupAsset: (guid) => {
597
+ const handle = this.guidHandles.get(guid.toLowerCase());
598
+ return handle === void 0 ? void 0 : this.assets.get(handle);
599
+ }
600
+ };
601
+ }
602
+ identity;
603
+ revision = 0;
604
+ videoFrames = /* @__PURE__ */ new Map();
605
+ entities = /* @__PURE__ */ new Set();
606
+ assets = /* @__PURE__ */ new Map();
607
+ resources;
608
+ guidHandles = /* @__PURE__ */ new Map();
609
+ accept(packet) {
610
+ const reject = (reason2, subject) => err$1(new RenderPublicationError({ reason: reason2, subject }));
611
+ if (packet.source !== this.identity.source || packet.epoch !== this.identity.epoch)
612
+ return reject("identity", "source/epoch");
613
+ if (packet.base !== this.revision || packet.baseline !== (this.revision === 0))
614
+ return reject("base", "accepted revision");
615
+ if (!Number.isSafeInteger(packet.revision) || packet.revision !== this.revision + 1)
616
+ return reject("revision", "next revision");
617
+ if (!(packet.upserts instanceof Uint32Array) || packet.upserts.length % 2 !== 0 || !(packet.removed instanceof Uint32Array) || !(packet.transformEntities instanceof Uint32Array) || !(packet.transforms instanceof Float32Array) || packet.transforms.length !== packet.transformEntities.length * 16 || !packet.transforms.every(Number.isFinite) || !Number.isFinite(packet.sampleTimeSeconds))
618
+ return reject("shape", "numeric columns");
619
+ if (!Array.isArray(packet.videoFrames) || !Array.isArray(packet.targets) || !Array.isArray(packet.targetSources) || !Array.isArray(packet.features) || !Array.isArray(packet.templates) || !Array.isArray(packet.programs) || !Array.isArray(packet.assets) || !Array.isArray(packet.retiredAssets) || !Array.isArray(packet.invalidatedAssets) || packet.metadata === null || typeof packet.metadata !== "object" || !Array.isArray(packet.metadata.cameras) || !Number.isFinite(packet.time?.elapsed) || !Number.isFinite(packet.time?.delta))
620
+ return reject("shape", "frame metadata");
621
+ const videoKeys = /* @__PURE__ */ new Set();
622
+ for (const row of packet.videoFrames) {
623
+ const key = `${row.entity}:${row.clip}`;
624
+ if (!Number.isSafeInteger(row.entity) || !Number.isSafeInteger(row.clip) || typeof VideoFrame === "undefined" || !(row.frame instanceof VideoFrame) || row.frame.displayWidth <= 0 || row.frame.displayHeight <= 0 || videoKeys.has(key))
625
+ return reject("shape", "video frame");
626
+ videoKeys.add(key);
627
+ }
628
+ const targetIds = /* @__PURE__ */ new Set();
629
+ const targetTokens = /* @__PURE__ */ new Set();
630
+ for (const row of packet.targets) {
631
+ if (!Number.isSafeInteger(row.id) || row.id <= 0 || targetIds.has(row.id) || typeof row.token !== "object" || row.token === null || targetTokens.has(row.token) || typeof row.descriptor !== "object" || row.descriptor === null)
632
+ return reject("shape", "target identity/descriptor");
633
+ targetIds.add(row.id);
634
+ targetTokens.add(row.token);
635
+ }
636
+ for (const camera of [
637
+ ...packet.metadata.cameras,
638
+ ...packet.metadata.auxiliaryCameras,
639
+ ...packet.metadata.cubeCameras
640
+ ])
641
+ if (camera.target !== void 0 && !targetTokens.has(camera.target))
642
+ return reject("shape", "missing target descriptor");
643
+ const sourceTokens = /* @__PURE__ */ new Set();
644
+ for (const row of packet.targetSources) {
645
+ if (!targetTokens.has(row.target) || typeof row.token !== "object" || row.token === null || sourceTokens.has(row.token))
646
+ return reject("shape", "target source");
647
+ sourceTokens.add(row.token);
648
+ }
649
+ const featureIdentities = /* @__PURE__ */ new Set();
650
+ for (const row of packet.features) {
651
+ if (typeof row.identity !== "string" || featureIdentities.has(row.identity))
652
+ return reject("shape", "feature identity");
653
+ featureIdentities.add(row.identity);
654
+ }
655
+ const matrices = /* @__PURE__ */ new Map();
656
+ for (let i = 0; i < packet.transformEntities.length; i++) {
657
+ const entity = packet.transformEntities[i];
658
+ if (matrices.has(entity)) return reject("shape", "duplicate transform identity");
659
+ matrices.set(entity, packet.transforms.slice(i * 16, i * 16 + 16));
660
+ }
661
+ const operations = [];
662
+ const renderables = [];
663
+ const dispatch = [];
664
+ const updated = /* @__PURE__ */ new Set();
665
+ for (let i = 0; i < packet.upserts.length; i += 2) {
666
+ const entityKey = packet.upserts[i];
667
+ const template = packet.templates[packet.upserts[i + 1]];
668
+ const world = matrices.get(entityKey);
669
+ if (template === void 0 || world === void 0 || updated.has(entityKey))
670
+ return reject("shape", "upsert template/transform");
671
+ if (!Array.isArray(template.snapshot?.materials) || !Array.isArray(template.dispatch))
672
+ return reject("shape", "template");
673
+ for (const material of template.snapshot.materials)
674
+ for (const source of material.textureSources?.values() ?? [])
675
+ if (!sourceTokens.has(source)) return reject("shape", "missing target source");
676
+ if (template.snapshot.skin !== void 0) return reject("shape", "source GPU skin receipt");
677
+ const pose = template.snapshot.skinPose;
678
+ if (pose !== void 0 && (!Number.isInteger(pose.jointCount) || pose.jointCount <= 0 || pose.inverseBindMatrices.length !== pose.jointCount || pose.jointWorlds.length !== pose.jointCount || [...pose.inverseBindMatrices, ...pose.jointWorlds].some(
679
+ (matrix) => !(matrix instanceof Float32Array) || matrix.length !== 16 || !matrix.every(Number.isFinite)
680
+ )))
681
+ return reject("shape", "skin pose");
682
+ updated.add(entityKey);
683
+ const snapshot = {
684
+ ...template.snapshot,
685
+ worldId: 0,
686
+ entityKey,
687
+ transform: { world }
688
+ };
689
+ for (const item of template.dispatch)
690
+ dispatch.push({ ...item, entityIndex: entityKey, renderableIndex: renderables.length });
691
+ renderables.push(snapshot);
692
+ operations.push({ kind: "update", worldId: 0, entityKey, snapshot });
693
+ }
694
+ const removed = /* @__PURE__ */ new Set();
695
+ for (const entityKey of packet.removed) {
696
+ if (!this.entities.has(entityKey) || updated.has(entityKey) || removed.has(entityKey))
697
+ return reject("shape", "duplicate removal");
698
+ removed.add(entityKey);
699
+ operations.push({ kind: "remove", worldId: 0, entityKey });
700
+ }
701
+ for (const [entityKey, world] of matrices) {
702
+ if (removed.has(entityKey)) return reject("shape", "removed transform");
703
+ if (!updated.has(entityKey) && !this.entities.has(entityKey))
704
+ return reject("shape", "unknown transform identity");
705
+ if (!updated.has(entityKey))
706
+ operations.push({ kind: "update", worldId: 0, entityKey, world });
707
+ }
708
+ const assetHandles = /* @__PURE__ */ new Set();
709
+ for (const row of packet.assets) {
710
+ if (row.value === null || typeof row.value !== "object" || !Number.isSafeInteger(row.handle) || assetHandles.has(row.handle) || packet.retiredAssets.includes(row.handle))
711
+ return reject("shape", "asset payload");
712
+ assetHandles.add(row.handle);
713
+ }
714
+ for (const handles of [
715
+ publicationFrameDependencies(packet.metadata),
716
+ ...renderables.map(publicationDependencies)
717
+ ]) {
718
+ if (handles.some(
719
+ (handle) => !assetHandles.has(handle) && (!this.assets.has(handle) || packet.retiredAssets.includes(handle))
720
+ ))
721
+ return reject("shape", "missing asset dependency");
722
+ }
723
+ const guidHandles = new Map(this.guidHandles);
724
+ for (const [guid, handle] of guidHandles)
725
+ if (packet.retiredAssets.includes(handle)) guidHandles.delete(guid);
726
+ for (const row of packet.assets)
727
+ if (row.guid !== void 0) guidHandles.set(row.guid.toLowerCase(), row.handle);
728
+ for (const row of renderables)
729
+ if (row.lods?.some((lod) => !guidHandles.has(AssetGuid.format(lod.mesh).toLowerCase())))
730
+ return reject("shape", "missing LOD dependency");
731
+ for (const entity of removed) this.entities.delete(entity);
732
+ for (const entity of updated) this.entities.add(entity);
733
+ if (packet.baseline) this.assets.clear();
734
+ this.guidHandles.clear();
735
+ for (const [guid, handle] of guidHandles) this.guidHandles.set(guid, handle);
736
+ for (const handle of packet.retiredAssets) this.assets.delete(handle);
737
+ for (const row of packet.assets) this.assets.set(row.handle, row.value);
738
+ Object.assign(this.resources, { time: packet.time, transparentSort: packet.transparentSort });
739
+ this.releaseVideoFrames();
740
+ this.videoFrames = new Map(
741
+ packet.videoFrames.map((row) => [`${row.entity}:${row.clip}`, row.frame])
742
+ );
743
+ this.revision = packet.revision;
744
+ return ok$1({
745
+ resources: this.resources,
746
+ packet,
747
+ operations,
748
+ frame: {
749
+ ...packet.metadata,
750
+ renderables,
751
+ dispatch,
752
+ visibilitySnapshots: [],
753
+ featureVisibilitySnapshots: [],
754
+ hiddenEntityReports: [],
755
+ shadowCasterEntityKeys: /* @__PURE__ */ new Set(),
756
+ shadowCasterDrawKeys: /* @__PURE__ */ new Set()
757
+ }
758
+ });
759
+ }
760
+ /** copyExternalImageToTexture consumes native sources synchronously during draw. */
761
+ releaseVideoFrames() {
762
+ for (const frame of this.videoFrames.values()) frame.close();
763
+ this.videoFrames.clear();
764
+ }
765
+ dispose() {
766
+ this.releaseVideoFrames();
767
+ this.assets.clear();
768
+ this.guidHandles.clear();
769
+ this.entities.clear();
770
+ }
771
+ get acceptedRevision() {
772
+ return this.revision;
773
+ }
774
+ };
546
775
 
547
776
  // src/device/mesh-residency-lifetime.ts
548
777
  var MeshResidencyLifetime = class {
@@ -899,9 +1128,9 @@ var GpuResidencyCache = class {
899
1128
  this.meshLifetime(entry).retire();
900
1129
  }
901
1130
  /**
902
- * Compose a cache key from the raw handle slot and its owning World. The
1131
+ * Compose a cache key from the raw handle slot and its owning RenderResourceScope. The
903
1132
  * draw-time world index is only a position in one frame's `worlds[]`; it is
904
- * not an asset identity and can be reused by a later World. World objects
1133
+ * not an asset identity and can be reused by a later RenderResourceScope. RenderResourceScope objects
905
1134
  * therefore receive a renderer-local namespace, while numeric callers keep
906
1135
  * the legacy namespace for low-level tests and built-in upload paths.
907
1136
  */
@@ -1874,12 +2103,12 @@ var GpuResidencyCache = class {
1874
2103
  });
1875
2104
  if (!equirectViewResult.ok) return recordFailed(equirectViewResult.error);
1876
2105
  const equirectView = equirectViewResult.value;
1877
- const bytesPerPixel2 = tex.format === "rgba32float" ? 16 : tex.format === "rgba16float" ? 8 : 4;
2106
+ const bytesPerPixel = tex.format === "rgba32float" ? 16 : tex.format === "rgba16float" ? 8 : 4;
1878
2107
  const equirectWriteResult = device.queue.writeTexture(
1879
2108
  { texture: equirectGpuTex },
1880
2109
  tex.data,
1881
2110
  {
1882
- bytesPerRow: tex.shape.extent.width * bytesPerPixel2,
2111
+ bytesPerRow: tex.shape.extent.width * bytesPerPixel,
1883
2112
  rowsPerImage: tex.shape.extent.height
1884
2113
  },
1885
2114
  {
@@ -1945,7 +2174,7 @@ var GpuResidencyCache = class {
1945
2174
  view: cubeView,
1946
2175
  faceViews
1947
2176
  });
1948
- const regResult = registerCube(world, cubeAsset);
2177
+ const regResult = registerCube(world, cubeAsset, sourceHandle);
1949
2178
  if (!regResult.ok) return recordFailed(regResult.error);
1950
2179
  const cubeHandle = regResult.value;
1951
2180
  const cubeId = handleSlot(cubeHandle);
@@ -2566,8 +2795,8 @@ function cloneSignatureNode(value, previous) {
2566
2795
  values
2567
2796
  });
2568
2797
  }
2569
- const token2 = stablePrimitiveToken(value);
2570
- return previous?.kind === "primitive" && previous.token === token2 ? previous : { kind: "primitive", token: token2 };
2798
+ const token = stablePrimitiveToken(value);
2799
+ return previous?.kind === "primitive" && previous.token === token ? previous : { kind: "primitive", token };
2571
2800
  }
2572
2801
  function signatureResourceValue(resource) {
2573
2802
  if (resource.kind !== "buffer") return resource;
@@ -4292,7 +4521,10 @@ function runRenderFeatureFrame(host, input) {
4292
4521
  const extracted = invokeStage(
4293
4522
  slot,
4294
4523
  "extract",
4295
- () => slot.feature.extract(extractContext),
4524
+ () => {
4525
+ const published = input.publishedFeatures?.find((row) => row.identity === identity);
4526
+ return published === void 0 ? slot.feature.extract(extractContext) : ok$1(published.data);
4527
+ },
4296
4528
  stageEvents,
4297
4529
  errors
4298
4530
  );
@@ -4447,12 +4679,14 @@ function runRenderFeatureFrame(host, input) {
4447
4679
  continue;
4448
4680
  }
4449
4681
  planExecutionProjections.set(plannedFrame, projected.value);
4450
- if (feature.onFrameSubmitted !== void 0) {
4682
+ if (feature.onFrameSubmitted !== void 0 || feature.onSourceFrameSubmitted !== void 0) {
4451
4683
  submissionSensitivePlans.add(plannedFrame);
4452
- submissionAcknowledgments.set(
4453
- plannedFrame,
4454
- () => feature.onFrameSubmitted?.(extracted.value, projected.value)
4455
- );
4684
+ submissionAcknowledgments.set(plannedFrame, () => {
4685
+ feature.onFrameSubmitted?.(extracted.value, projected.value);
4686
+ if (input.publishedFeatures?.some((row) => row.identity === identity))
4687
+ input.onFeatureSourceSubmitted?.(identity, declared.value.sourceFeedback);
4688
+ else feature.onSourceFrameSubmitted?.(extracted.value, declared.value.sourceFeedback);
4689
+ });
4456
4690
  }
4457
4691
  plans.push(plannedFrame);
4458
4692
  if (feature.onFrameAborted !== void 0) {
@@ -6370,16 +6604,6 @@ function addTransmissionBackdropTemporalPass(graph, source) {
6370
6604
  encode: () => void 0
6371
6605
  });
6372
6606
  }
6373
-
6374
- // src/typed-shadow-atlas.ts
6375
- function resolveDirectionalShadowAtlasGrid(cascadeCount) {
6376
- const count = Math.max(1, Math.min(4, Math.round(cascadeCount)));
6377
- if (count === 1) return { columns: 1, rows: 1 };
6378
- if (count === 2) return { columns: 2, rows: 1 };
6379
- return { columns: 2, rows: 2 };
6380
- }
6381
-
6382
- // src/typed-shadow-passes.ts
6383
6607
  function shadowViewCacheReuse(frame, identity) {
6384
6608
  const context = frame;
6385
6609
  const gpuShadowViews = context.gpuDrivenShadowViews;
@@ -6428,6 +6652,8 @@ function addTypedShadowPasses(graph, topology, projectGpuDrivenShadowOrFeatures,
6428
6652
  index: cascade
6429
6653
  });
6430
6654
  if (shadowProjection !== void 0 && !shadowProjection.ok) return shadowProjection;
6655
+ let forceRasterPending = true;
6656
+ let forceRasterEncodePending = false;
6431
6657
  const added = recordShadowPass(
6432
6658
  graph,
6433
6659
  `shadowCascade${cascade}`,
@@ -6443,9 +6669,18 @@ function addTypedShadowPasses(graph, topology, projectGpuDrivenShadowOrFeatures,
6443
6669
  w: mapSize,
6444
6670
  h: mapSize
6445
6671
  },
6446
- shadowFeatures === void 0 ? void 0 : (view) => shadowFeatures.encode(pass, frame, resources, view)
6672
+ shadowFeatures === void 0 ? void 0 : (view) => shadowFeatures.encode(pass, frame, resources, view),
6673
+ forceRasterEncodePending
6447
6674
  ),
6448
- (frame) => shadowFeatures !== void 0 || !shadowViewCacheReuse(frame, { kind: "directional", index: cascade }),
6675
+ (frame) => {
6676
+ forceRasterEncodePending = false;
6677
+ if (forceRasterPending) {
6678
+ forceRasterPending = false;
6679
+ forceRasterEncodePending = true;
6680
+ return true;
6681
+ }
6682
+ return shadowFeatures !== void 0 || !shadowViewCacheReuse(frame, { kind: "directional", index: cascade });
6683
+ },
6449
6684
  [
6450
6685
  ...shadowProjection?.ok === true && shadowProjection.value?.graphResources !== void 0 ? shadowViewRasterAccesses(shadowProjection.value.graphResources) : [],
6451
6686
  ...shadowFeatures?.accesses ?? []
@@ -6508,6 +6743,7 @@ function addTypedShadowPasses(graph, topology, projectGpuDrivenShadowOrFeatures,
6508
6743
  face
6509
6744
  });
6510
6745
  if (shadowProjection !== void 0 && !shadowProjection.ok) return shadowProjection;
6746
+ let forceRasterPending = true;
6511
6747
  const identity = { kind: "point", index: pointIndex, face };
6512
6748
  const cacheReuse = (frame) => shadowViewCacheReuse(frame, identity);
6513
6749
  const faceView = graph.view(texture.value, {
@@ -6532,7 +6768,13 @@ function addTypedShadowPasses(graph, topology, projectGpuDrivenShadowOrFeatures,
6532
6768
  face,
6533
6769
  shadowFeatures === void 0 ? void 0 : (view) => shadowFeatures.encode(pass, frame, resources, view)
6534
6770
  ),
6535
- (frame) => shadowFeatures !== void 0 || !cacheReuse(frame),
6771
+ (frame) => {
6772
+ if (forceRasterPending) {
6773
+ forceRasterPending = false;
6774
+ return true;
6775
+ }
6776
+ return shadowFeatures !== void 0 || !cacheReuse(frame);
6777
+ },
6536
6778
  [
6537
6779
  ...shadowProjection?.ok === true && shadowProjection.value?.graphResources !== void 0 ? shadowViewRasterAccesses(shadowProjection.value.graphResources) : [],
6538
6780
  ...shadowFeatures?.accesses ?? []
@@ -6550,6 +6792,7 @@ function addTypedShadowPasses(graph, topology, projectGpuDrivenShadowOrFeatures,
6550
6792
  for (let spotIndex = 0; spotIndex < Math.max(1, topology.shadow.spotCount); spotIndex += 1) {
6551
6793
  const shadowProjection = projectGpuDrivenShadow?.({ kind: "spot", index: spotIndex });
6552
6794
  if (shadowProjection !== void 0 && !shadowProjection.ok) return shadowProjection;
6795
+ let forceRasterPending = true;
6553
6796
  const identity = { kind: "spot", index: spotIndex };
6554
6797
  const cacheReuse = (frame) => shadowViewCacheReuse(frame, identity);
6555
6798
  const added = recordShadowPass(
@@ -6563,7 +6806,13 @@ function addTypedShadowPasses(graph, topology, projectGpuDrivenShadowOrFeatures,
6563
6806
  spotIndex,
6564
6807
  shadowFeatures === void 0 ? void 0 : (view) => shadowFeatures.encode(pass, frame, resources, view)
6565
6808
  ),
6566
- (frame) => shadowFeatures !== void 0 || !cacheReuse(frame),
6809
+ (frame) => {
6810
+ if (forceRasterPending) {
6811
+ forceRasterPending = false;
6812
+ return true;
6813
+ }
6814
+ return shadowFeatures !== void 0 || !cacheReuse(frame);
6815
+ },
6567
6816
  [
6568
6817
  ...shadowProjection?.ok === true && shadowProjection.value?.graphResources !== void 0 ? shadowViewRasterAccesses(shadowProjection.value.graphResources) : [],
6569
6818
  ...shadowFeatures?.accesses ?? []
@@ -9592,7 +9841,7 @@ function prepareStandardLutGpu(input) {
9592
9841
  if (!asset.ok) {
9593
9842
  return failure2(
9594
9843
  "standard-lut-residency-failed",
9595
- "the authored TextureAsset handle resolves in the active World",
9844
+ "the authored TextureAsset handle resolves in the active RenderResourceScope",
9596
9845
  "register or rebuild the TextureAsset, then retry the same camera generation",
9597
9846
  causeDetail(asset.error)
9598
9847
  );
@@ -13033,6 +13282,75 @@ function projectCaptureScene(retained, visible, displayDispatch) {
13033
13282
  })
13034
13283
  };
13035
13284
  }
13285
+ function renderTime(source) {
13286
+ return "resolveAsset" in source ? source.time : source.getResource(Time);
13287
+ }
13288
+ function renderAssetByGuid(source, assets, guid) {
13289
+ return "resolveAsset" in source ? source.lookupAsset(typeof guid === "string" ? guid : AssetGuid.format(guid)) : assets.lookup(guid);
13290
+ }
13291
+
13292
+ // src/publication/prepare-geometry.ts
13293
+ function preparePublicationGeometry(input, scene, palette, assets, instances, getMaterialShaderArtifact) {
13294
+ const replacements = /* @__PURE__ */ new Map();
13295
+ for (const operation of input.operations) {
13296
+ if (operation.kind !== "remove" && operation.snapshot === void 0) continue;
13297
+ if (operation.kind === "remove" || operation.snapshot?.instances === void 0)
13298
+ instances.release(input.resources, operation.entityKey);
13299
+ const prior = scene.compositionSlot(0, operation.entityKey)?.snapshot.skin;
13300
+ const pose = operation.kind === "remove" ? void 0 : operation.snapshot?.skinPose;
13301
+ if (prior !== void 0 && prior.identity !== pose?.identity)
13302
+ palette?.releasePersistentSlice(prior.identity);
13303
+ }
13304
+ for (const row of input.frame.renderables) {
13305
+ const { skinPose, ...source } = row;
13306
+ let skin = row.skin;
13307
+ if (skinPose !== void 0) {
13308
+ if (palette == null)
13309
+ throw new RenderPublicationError({
13310
+ reason: "unsupported",
13311
+ subject: "skin palette allocator"
13312
+ });
13313
+ palette.observePersistentJoints(
13314
+ skinPose.identity,
13315
+ skinPose.inverseBindMatrices,
13316
+ skinPose.jointWorlds
13317
+ );
13318
+ skin = palette.allocatePersistentSlice(skinPose);
13319
+ palette.writePersistentJointPalette(skin, skinPose.inverseBindMatrices, skinPose.jointWorlds);
13320
+ }
13321
+ const projected = row.instances === void 0 ? void 0 : instances.project(input.resources, row.entityKey, row.instances.transforms);
13322
+ const snapshot = {
13323
+ ...source,
13324
+ ...skin === void 0 ? {} : { skin },
13325
+ ...projected === void 0 || row.instances === void 0 ? {} : { instances: { ...row.instances, ...projected, archVersion: 0 } }
13326
+ };
13327
+ if (projected !== void 0) instances.accept(input.resources, row.entityKey, projected);
13328
+ const mesh = input.resources.resolveAsset(
13329
+ row.assetHandle
13330
+ );
13331
+ if (!mesh.ok) throw mesh.error;
13332
+ const gpuDrivenDraws = row.morph === void 0 ? buildGpuDrivenDraws({
13333
+ mesh: mesh.value,
13334
+ materials: row.materials,
13335
+ fallbackMaterial: row.material,
13336
+ baseSnapshot: snapshot,
13337
+ ...getMaterialShaderArtifact === void 0 ? {} : { getMaterialShaderArtifact },
13338
+ ...row.lods === void 0 ? {} : {
13339
+ lodMeshes: row.lods.map(
13340
+ (lod) => renderAssetByGuid(input.resources, assets, lod.mesh)
13341
+ )
13342
+ }
13343
+ }) : [];
13344
+ replacements.set(row.entityKey, { ...snapshot, gpuDrivenDraws });
13345
+ }
13346
+ return {
13347
+ ...input,
13348
+ frame: { ...input.frame, renderables: [...replacements.values()] },
13349
+ operations: input.operations.map(
13350
+ (operation) => operation.kind !== "remove" && operation.snapshot !== void 0 ? { ...operation, snapshot: replacements.get(operation.entityKey) } : operation
13351
+ )
13352
+ };
13353
+ }
13036
13354
 
13037
13355
  // src/assembly/directional-shadow-inspection.ts
13038
13356
  function deepFreeze2(value, seen = /* @__PURE__ */ new WeakSet()) {
@@ -14641,8 +14959,8 @@ var MaterialAbiRasterAdapter = class _MaterialAbiRasterAdapter {
14641
14959
  return;
14642
14960
  }
14643
14961
  if (!this.pendingProjectionRetirements.add(buffer)) return;
14644
- const token2 = this.allocationTokens.get(buffer);
14645
- if (token2 !== void 0) this.allocationLedger.retire(token2);
14962
+ const token = this.allocationTokens.get(buffer);
14963
+ if (token !== void 0) this.allocationLedger.retire(token);
14646
14964
  void this.device.queue.onSubmittedWorkDone().then(
14647
14965
  () => {
14648
14966
  this.pendingProjectionRetirements.delete(buffer);
@@ -14659,8 +14977,8 @@ var MaterialAbiRasterAdapter = class _MaterialAbiRasterAdapter {
14659
14977
  this.destroyedProjectionBuffers.add(buffer);
14660
14978
  this.projectionBuffers.delete(buffer);
14661
14979
  this.surfaceInputBuffers.delete(buffer);
14662
- const token2 = this.allocationTokens.get(buffer);
14663
- if (token2 !== void 0) this.allocationLedger.release(token2);
14980
+ const token = this.allocationTokens.get(buffer);
14981
+ if (token !== void 0) this.allocationLedger.release(token);
14664
14982
  this.device.destroyBuffer(buffer);
14665
14983
  }
14666
14984
  trackOwnedBuffer(buffer, bytes2) {
@@ -14673,8 +14991,8 @@ var MaterialAbiRasterAdapter = class _MaterialAbiRasterAdapter {
14673
14991
  this.projectionBuffers.delete(buffer);
14674
14992
  this.surfaceInputBuffers.delete(buffer);
14675
14993
  this.pendingProjectionRetirements.delete(buffer);
14676
- const token2 = this.allocationTokens.get(buffer);
14677
- if (token2 !== void 0) this.allocationLedger.rollback(token2);
14994
+ const token = this.allocationTokens.get(buffer);
14995
+ if (token !== void 0) this.allocationLedger.rollback(token);
14678
14996
  this.device.destroyBuffer(buffer);
14679
14997
  }
14680
14998
  get instancesFrameGroup() {
@@ -16267,7 +16585,14 @@ var GpuDrivenProduction = class _GpuDrivenProduction {
16267
16585
  };
16268
16586
  }
16269
16587
  const shadowTopologySignature = () => this.shadowViews?.inspect().map(
16270
- (entry) => `${shadowViewIdentityKey(entry.identity)}:${entry.cache}:${entry.generation}:${entry.sourceRevision}:${entry.resourceGeneration}`
16588
+ (entry) => (
16589
+ // Cache decisions and logical update generations are frame-local
16590
+ // producer state. They must not feed the compiled graph key: a
16591
+ // graph replacement may intentionally invalidate a shadow view
16592
+ // once without creating a graph-rebuild feedback loop. Resource
16593
+ // and source-plan generations remain real graph dependencies.
16594
+ `${shadowViewIdentityKey(entry.identity)}:${entry.sourceRevision}:${entry.resourceGeneration}`
16595
+ )
16271
16596
  ).join("|") ?? "";
16272
16597
  const production = this;
16273
16598
  const surfaceDynamicInputForCommit = this.surfaceSubmission !== void 0 && input.surfaceDynamicInput !== void 0 ? {
@@ -16368,10 +16693,10 @@ var GpuDrivenProduction = class _GpuDrivenProduction {
16368
16693
  frameNumber
16369
16694
  )
16370
16695
  },
16371
- projectShadow: (graph, identity) => {
16696
+ projectShadow: (graph, identity, forceCompute = false) => {
16372
16697
  if (!shadowViewPool.isActive(identity) || shadowViewPool.submission(identity) === void 0)
16373
16698
  return ok(void 0);
16374
- return shadowViewPool.project(graph, identity);
16699
+ return shadowViewPool.project(graph, identity, forceCompute);
16375
16700
  },
16376
16701
  updateShadowViews: (views) => shadowFiltered.plan.batches.length > 0 ? this.updateShadowViews(
16377
16702
  views,
@@ -20189,7 +20514,9 @@ function validateRenderables(internals, world, worlds, pipelineState, frameState
20189
20514
  }
20190
20515
  const meshAssetHandle = toShared(r.assetHandle);
20191
20516
  let meshHandles = internals.gpuStore.getMeshGpuHandles(meshAssetHandle, renderableWorld);
20192
- const lodMeshes = r.lods?.map((lod) => internals.assets.lookup(lod.mesh));
20517
+ const lodMeshes = r.lods?.map(
20518
+ (lod) => renderAssetByGuid(renderableWorld, internals.assets, lod.mesh)
20519
+ );
20193
20520
  const resolvedLodMeshes = lodMeshes?.every((lod) => lod?.kind === "mesh") === true ? lodMeshes : void 0;
20194
20521
  if (meshHandles === void 0 && r.assetHandle > handleSlot(HANDLE_NINESLICE_QUAD)) {
20195
20522
  const residentRes = internals.gpuStore.ensureResident(
@@ -21008,157 +21335,197 @@ function inspectBarrelDistortionState(state, deviceGeneration) {
21008
21335
  lastKnownGood: mapping !== void 0 && state.compiledFrameGraph !== null && state.barrelDistortionGraphResolution === "retained"
21009
21336
  });
21010
21337
  }
21011
-
21012
- // src/record/frame-targets.ts
21013
- function graphExecutionPhase(passName) {
21014
- if (passName.startsWith("shadowCascade")) return "record/graph-execute/shadow";
21015
- if (passName.startsWith("point-shadow")) return "record/graph-execute/point-shadow";
21016
- if (passName.startsWith("spot-shadow")) return "record/graph-execute/spot-shadow";
21017
- if (passName === "ssr-hiz-seed" || passName.startsWith("ssr-hiz-reduce-")) {
21018
- return "record/graph-execute/ssr-hiz";
21019
- }
21020
- if (passName === "ssr-trace") return "record/graph-execute/ssr-trace";
21021
- if (passName === "ssr-temporal") return "record/graph-execute/ssr-temporal";
21022
- if (passName.startsWith("ssr-reflection-mip-")) {
21023
- return "record/graph-execute/ssr-reflection-mip";
21024
- }
21025
- if (passName === "ssr-compose") return "record/graph-execute/ssr-compose";
21026
- if (passName.startsWith("bloom-downsample-")) {
21027
- return "record/graph-execute/bloom-downsample";
21028
- }
21029
- if (passName.startsWith("bloom-upsample-")) {
21030
- return "record/graph-execute/bloom-upsample";
21031
- }
21032
- switch (passName) {
21033
- case "cluster-binner-upload":
21034
- case "cluster-membership-producer":
21035
- return "record/graph-execute/cluster-binner-upload";
21036
- case "g-buffer":
21037
- return "record/graph-execute/g-buffer";
21038
- case "ssao-calc":
21039
- return "record/graph-execute/ssao-calc";
21040
- case "ssao-blur":
21041
- return "record/graph-execute/ssao-blur";
21042
- case "lighting":
21043
- return "record/graph-execute/lighting";
21044
- case "forward":
21045
- case "transmission-forward":
21046
- return "record/graph-execute/forward";
21047
- case "output-transform":
21048
- return "record/graph-execute/output-transform";
21049
- case "present":
21050
- return "record/graph-execute/present";
21051
- case "debug-overlay":
21052
- return "record/graph-execute/debug-overlay";
21053
- case "shadow":
21054
- return "record/graph-execute/shadow";
21055
- case "skybox":
21056
- return "record/graph-execute/skybox";
21057
- case "main":
21058
- return "record/graph-execute/main";
21059
- case "fxaa":
21060
- return "record/graph-execute/fxaa";
21061
- case "bloom-downsample":
21062
- return "record/graph-execute/bloom-downsample";
21063
- case "bloom-upsample":
21064
- return "record/graph-execute/bloom-upsample";
21065
- case "bloom-composite":
21066
- return "record/graph-execute/bloom-composite";
21067
- default:
21068
- return "record/graph-execute/other";
21069
- }
21338
+ function renderTargetMipCount(work) {
21339
+ const { descriptor } = work.physical;
21340
+ return descriptor.mipLevels === 1 ? 1 : Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
21070
21341
  }
21071
- function resolveRenderTargetMipExtent(descriptor, mipLevel) {
21072
- const mipCount2 = descriptor.mipLevels === 1 ? 1 : Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
21073
- const level = Math.max(0, Math.min(mipLevel, mipCount2 - 1));
21074
- return {
21075
- width: Math.max(1, descriptor.width >> level),
21076
- height: Math.max(1, descriptor.height >> level)
21077
- };
21078
- }
21079
- function acquireSwapChainTarget(internals, pipelineState) {
21080
- const canvasContext = internals.context;
21081
- if (canvasContext === null) return null;
21082
- let currentTextureResult = canvasContext.getCurrentTexture();
21083
- if (!currentTextureResult.ok) {
21084
- const configuredDevice = internals.resolveSurfaceDevice?.(internals.device);
21085
- if (configuredDevice !== void 0 && !configuredDevice.ok) {
21086
- internals.errorRegistry.fire(configuredDevice.error);
21087
- internals.healthRegistry.fire({
21088
- reason: "internal-fault",
21089
- detail: { message: "surface device resolution failed; current frame skipped" },
21090
- recoverable: true
21091
- });
21092
- return null;
21093
- }
21094
- const configured = configureSurface(
21095
- canvasContext,
21096
- configuredDevice?.value ?? internals.device,
21097
- pipelineState.format,
21098
- pipelineState.colorAttachmentFormat
21342
+ function addTargetCaptureGraphPasses(builder, state) {
21343
+ for (let index = 0; index < state.work.length; index += 1) {
21344
+ const slot = index;
21345
+ const initial = state.work[slot];
21346
+ if (initial === void 0) continue;
21347
+ const current = () => state.work[slot] ?? initial;
21348
+ const texture = builder.importTexture(
21349
+ `cube-capture.${slot}.texture`,
21350
+ {
21351
+ format: initial.physical.descriptor.format,
21352
+ size: {
21353
+ width: initial.physical.descriptor.width,
21354
+ height: initial.physical.descriptor.height,
21355
+ depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 || initial.physical.descriptor.shape === "2d" ? 1 : 6
21356
+ },
21357
+ mipLevelCount: initial.physical.descriptor.sampleCount === 4 ? 1 : renderTargetMipCount(initial),
21358
+ sampleCount: initial.physical.descriptor.sampleCount,
21359
+ dimension: "2d",
21360
+ usage: 16 | 4 | 1
21361
+ },
21362
+ () => current().physical.colorTextures[current().faceIndex] ?? initial.physical.texture
21099
21363
  );
21100
- if (!configured.ok) {
21101
- internals.errorRegistry.fire(configured.error);
21102
- internals.healthRegistry.fire({
21103
- reason: "internal-fault",
21104
- detail: { message: "surface configure candidate failed; current frame skipped" },
21105
- recoverable: true
21106
- });
21107
- return null;
21108
- }
21109
- pipelineState.perPassResources.configured = true;
21110
- globalThis.__forgeaxSwapChainFormat = pipelineState.format;
21111
- const retry = canvasContext.getCurrentTexture();
21112
- if (!retry.ok) {
21113
- internals.errorRegistry.fire(retry.error);
21114
- internals.healthRegistry.fire({
21115
- reason: "internal-fault",
21116
- detail: {
21117
- message: "surface-configure-failed after retry: getCurrentTexture failed twice consecutively"
21364
+ if (!texture.ok) return texture;
21365
+ const color = builder.importView(
21366
+ texture.value,
21367
+ {
21368
+ label: `cube-capture.${slot}.color`,
21369
+ dimension: "2d",
21370
+ baseMipLevel: 0,
21371
+ mipLevelCount: 1,
21372
+ baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
21373
+ arrayLayerCount: 1
21374
+ },
21375
+ () => current().physical.faceViews[current().faceIndex] ?? initial.physical.faceViews[initial.faceIndex] ?? initial.physical.view
21376
+ );
21377
+ if (!color.ok) return color;
21378
+ const depthTexture = builder.importTexture(
21379
+ `cube-capture.${slot}.depth-texture`,
21380
+ {
21381
+ format: "depth24plus-stencil8",
21382
+ size: {
21383
+ width: initial.physical.descriptor.width,
21384
+ height: initial.physical.descriptor.height,
21385
+ depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 || initial.physical.descriptor.shape === "2d" ? 1 : 6
21118
21386
  },
21119
- recoverable: false
21120
- });
21121
- return null;
21122
- }
21123
- currentTextureResult = retry;
21124
- }
21125
- const viewDescriptor = pipelineState.colorAttachmentFormat === pipelineState.format ? {} : { format: pipelineState.colorAttachmentFormat };
21126
- const viewResult = internals.device.createTextureView(currentTextureResult.value, viewDescriptor);
21127
- if (!viewResult.ok) {
21128
- internals.errorRegistry.fire(viewResult.error);
21129
- return null;
21387
+ mipLevelCount: 1,
21388
+ sampleCount: initial.physical.descriptor.sampleCount,
21389
+ dimension: "2d",
21390
+ usage: 16
21391
+ },
21392
+ () => current().physical.depthTextures[current().faceIndex]
21393
+ );
21394
+ if (!depthTexture.ok) return depthTexture;
21395
+ const depth = builder.importView(
21396
+ depthTexture.value,
21397
+ {
21398
+ label: `cube-capture.${slot}.depth`,
21399
+ dimension: "2d",
21400
+ baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
21401
+ arrayLayerCount: 1
21402
+ },
21403
+ () => current().physical.depthViews[current().faceIndex]
21404
+ );
21405
+ if (!depth.ok) return depth;
21406
+ const resolveTexture = initial.physical.descriptor.sampleCount === 4 ? builder.importTexture(
21407
+ `cube-capture.${slot}.resolve-texture`,
21408
+ {
21409
+ format: initial.physical.descriptor.format,
21410
+ size: {
21411
+ width: initial.physical.descriptor.width,
21412
+ height: initial.physical.descriptor.height,
21413
+ depthOrArrayLayers: initial.physical.descriptor.shape === "cube" ? 6 : 1
21414
+ },
21415
+ mipLevelCount: renderTargetMipCount(initial),
21416
+ sampleCount: 1,
21417
+ dimension: "2d",
21418
+ usage: 16 | 4 | 1
21419
+ },
21420
+ () => current().physical.resolveTexture ?? initial.physical.resolveTexture ?? initial.physical.texture
21421
+ ) : void 0;
21422
+ if (resolveTexture !== void 0 && !resolveTexture.ok) return resolveTexture;
21423
+ const resolve = resolveTexture === void 0 ? void 0 : builder.importView(
21424
+ resolveTexture.value,
21425
+ {
21426
+ label: `cube-capture.${slot}.resolve`,
21427
+ dimension: "2d",
21428
+ baseMipLevel: 0,
21429
+ mipLevelCount: 1,
21430
+ baseArrayLayer: initial.faceIndex,
21431
+ arrayLayerCount: 1
21432
+ },
21433
+ () => current().physical.resolveFaceViews[current().faceIndex] ?? initial.physical.resolveFaceViews[initial.faceIndex] ?? initial.physical.resolveView
21434
+ );
21435
+ if (resolve !== void 0 && !resolve.ok) return resolve;
21436
+ const added = builder.addRasterPass(`cube-capture-face.${slot}`, {
21437
+ accesses: [
21438
+ { resource: color.value, usage: "color-attachment" },
21439
+ { resource: depth.value, usage: "depth-stencil-write" },
21440
+ ...resolve === void 0 ? [] : [{ resource: resolve.value, usage: "color-attachment" }]
21441
+ ],
21442
+ colorAttachments: [
21443
+ {
21444
+ view: color.value,
21445
+ ...resolve === void 0 ? {} : { resolveTarget: resolve.value },
21446
+ loadOp: "clear",
21447
+ storeOp: "store",
21448
+ clearValue: () => {
21449
+ const clear = current().physical.descriptor.shape === "2d" ? current().faceCamera.clearColor : [0, 0, 0, 1];
21450
+ return { r: clear[0] ?? 0, g: clear[1] ?? 0, b: clear[2] ?? 0, a: clear[3] ?? 1 };
21451
+ }
21452
+ }
21453
+ ],
21454
+ depthStencilAttachment: {
21455
+ view: depth.value,
21456
+ depthClearValue: 1,
21457
+ depthLoadOp: "clear",
21458
+ depthStoreOp: "store",
21459
+ stencilClearValue: 0,
21460
+ stencilLoadOp: "clear",
21461
+ stencilStoreOp: "store"
21462
+ },
21463
+ encode: ({ pass, frame, resources }) => {
21464
+ const internal = frame;
21465
+ const captureColor = resources.textureView(color.value);
21466
+ if (!captureColor.ok) return;
21467
+ const captureDepth = resources.textureView(depth.value);
21468
+ if (!captureDepth.ok) return;
21469
+ const captureResolve = resolve === void 0 ? void 0 : resources.textureView(resolve.value);
21470
+ if (resolve !== void 0 && (captureResolve === void 0 || !captureResolve.ok)) return;
21471
+ const captureResolveView = captureResolve?.ok ? captureResolve.value : null;
21472
+ const selfSampling = /* @__PURE__ */ new Map();
21473
+ for (const row of internal.validatedOrdered) {
21474
+ for (const material of row.source.materials) {
21475
+ if (![...material.textureSources?.values() ?? []].some(
21476
+ (source) => resolveRenderTargetMaterialSource(source)?.target === current().target
21477
+ ))
21478
+ continue;
21479
+ let handles = selfSampling.get(row.renderableIndex);
21480
+ if (handles === void 0) {
21481
+ handles = /* @__PURE__ */ new Set();
21482
+ selfSampling.set(row.renderableIndex, handles);
21483
+ }
21484
+ handles.add(material.materialHandle ?? 0);
21485
+ }
21486
+ }
21487
+ const captureContext = {
21488
+ ...internal,
21489
+ camera: current().faceCamera,
21490
+ targetW: current().physical.descriptor.width,
21491
+ targetH: current().physical.descriptor.height,
21492
+ dispatch: (internal.captureDispatch ?? internal.dispatch).filter(
21493
+ (entry) => !selfSampling.get(entry.renderableIndex)?.has(entry.materialHandle)
21494
+ ),
21495
+ foldDispatchPlan: null,
21496
+ // Cube faces are raw scene captures, not display-camera HDR output.
21497
+ // Select the PSO against the actual target attachment so an LDR
21498
+ // cube target is rendered by a compatible forward pipeline.
21499
+ tonemapActive: false,
21500
+ skyboxActive: false,
21501
+ transparentColorFormat: initial.physical.descriptor.format,
21502
+ msaaActive: initial.physical.descriptor.sampleCount === 4,
21503
+ viewBindGroupDynamicOffset: current().viewBindGroupDynamicOffset,
21504
+ geometryColorView: captureColor.value,
21505
+ geometryDepthView: captureDepth.value,
21506
+ geometryColorResolveView: captureResolveView,
21507
+ splitLdrSprite: false,
21508
+ ldrSpritePassView: null
21509
+ };
21510
+ delete captureContext.gpuDrivenDrawKeys;
21511
+ delete captureContext.gpuDrivenStandardPbrFrameResources;
21512
+ encodeMainPass(
21513
+ captureContext,
21514
+ pass,
21515
+ { LightMode: ["Forward"] },
21516
+ {
21517
+ colorViews: [captureColor.value],
21518
+ colorFormats: [initial.physical.descriptor.format],
21519
+ depthView: captureDepth.value,
21520
+ passKind: "forward",
21521
+ clearColor: current().physical.descriptor.shape === "2d" ? current().faceCamera.clearColor : [0, 0, 0, 1]
21522
+ }
21523
+ );
21524
+ }
21525
+ });
21526
+ if (!added.ok) return added;
21130
21527
  }
21131
- return {
21132
- currentTexture: currentTextureResult.value,
21133
- view: viewResult.value,
21134
- targetW: internals.canvas.width | 0,
21135
- targetH: internals.canvas.height | 0
21136
- };
21137
- }
21138
- function resolveShadowMapSize(internals, lights) {
21139
- if (lights.cascadeCount === void 0) return void 0;
21140
- const requested = lights.shadowMapSize;
21141
- if (!(requested !== void 0 && requested > 0)) return requested;
21142
- const cascades = Math.max(1, Math.min(4, Math.round(lights.cascadeCount ?? 1)));
21143
- const atlasGrid = resolveDirectionalShadowAtlasGrid(cascades);
21144
- const maxDimension = internals.device.limits.maxTextureDimension2D;
21145
- if (!(maxDimension > 0)) return Math.floor(requested);
21146
- const depthTextureDimension = internals.device.caps?.backendKind === "wgpu-webgl2" ? Math.max(1, Math.floor(maxDimension / 2)) : maxDimension;
21147
- const maxPerTile = Math.max(
21148
- 1,
21149
- Math.floor(depthTextureDimension / Math.max(atlasGrid.columns, atlasGrid.rows))
21150
- );
21151
- return Math.max(1, Math.min(Math.floor(requested), maxPerTile));
21152
- }
21153
- function resolveSpotShadowMapSize(internals, lights) {
21154
- const requested = lights.spot.find(
21155
- (spot) => spot.shadowAtlasTile >= 0 && spot.lightViewProj !== void 0
21156
- )?.mapSize;
21157
- if (!(requested !== void 0 && requested > 0)) return requested;
21158
- const maxDimension = internals.device.limits.maxTextureDimension2D;
21159
- if (!(maxDimension > 0)) return Math.floor(requested);
21160
- const maxPerTile = Math.max(1, Math.floor(maxDimension / 2));
21161
- return Math.max(1, Math.min(Math.floor(requested), maxPerTile));
21528
+ return ok$1(void 0);
21162
21529
  }
21163
21530
 
21164
21531
  // src/assembly/renderer-frame-transaction.ts
@@ -22195,169 +22562,6 @@ function isMotionBlurTemporalDemand(motionBlur) {
22195
22562
  targetFps: motionBlur.targetFps ?? 60
22196
22563
  });
22197
22564
  }
22198
- function renderTargetMipCount(work) {
22199
- const { descriptor } = work.physical;
22200
- return descriptor.mipLevels === 1 ? 1 : Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
22201
- }
22202
- function addCubeCaptureGraphPasses(builder, state) {
22203
- for (let index = 0; index < state.work.length; index += 1) {
22204
- const slot = index;
22205
- const initial = state.work[slot];
22206
- if (initial === void 0) continue;
22207
- const current = () => state.work[slot] ?? initial;
22208
- const texture = builder.importTexture(
22209
- `cube-capture.${slot}.texture`,
22210
- {
22211
- format: initial.physical.descriptor.format,
22212
- size: {
22213
- width: initial.physical.descriptor.width,
22214
- height: initial.physical.descriptor.height,
22215
- depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 ? 1 : 6
22216
- },
22217
- mipLevelCount: initial.physical.descriptor.sampleCount === 4 ? 1 : renderTargetMipCount(initial),
22218
- sampleCount: initial.physical.descriptor.sampleCount,
22219
- dimension: "2d",
22220
- usage: 16 | 4 | 1
22221
- },
22222
- () => current().physical.colorTextures[current().faceIndex] ?? initial.physical.texture
22223
- );
22224
- if (!texture.ok) return texture;
22225
- const color = builder.importView(
22226
- texture.value,
22227
- {
22228
- label: `cube-capture.${slot}.color`,
22229
- dimension: "2d",
22230
- baseMipLevel: 0,
22231
- mipLevelCount: 1,
22232
- baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
22233
- arrayLayerCount: 1
22234
- },
22235
- () => current().physical.faceViews[current().faceIndex] ?? initial.physical.faceViews[initial.faceIndex] ?? initial.physical.view
22236
- );
22237
- if (!color.ok) return color;
22238
- const depthTexture = builder.importTexture(
22239
- `cube-capture.${slot}.depth-texture`,
22240
- {
22241
- format: "depth24plus-stencil8",
22242
- size: {
22243
- width: initial.physical.descriptor.width,
22244
- height: initial.physical.descriptor.height,
22245
- depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 ? 1 : 6
22246
- },
22247
- mipLevelCount: 1,
22248
- sampleCount: initial.physical.descriptor.sampleCount,
22249
- dimension: "2d",
22250
- usage: 16
22251
- },
22252
- () => current().physical.depthTextures[current().faceIndex]
22253
- );
22254
- if (!depthTexture.ok) return depthTexture;
22255
- const depth = builder.importView(
22256
- depthTexture.value,
22257
- {
22258
- label: `cube-capture.${slot}.depth`,
22259
- dimension: "2d",
22260
- baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
22261
- arrayLayerCount: 1
22262
- },
22263
- () => current().physical.depthViews[current().faceIndex]
22264
- );
22265
- if (!depth.ok) return depth;
22266
- const resolveTexture = initial.physical.descriptor.sampleCount === 4 ? builder.importTexture(
22267
- `cube-capture.${slot}.resolve-texture`,
22268
- {
22269
- format: initial.physical.descriptor.format,
22270
- size: {
22271
- width: initial.physical.descriptor.width,
22272
- height: initial.physical.descriptor.height,
22273
- depthOrArrayLayers: 6
22274
- },
22275
- mipLevelCount: renderTargetMipCount(initial),
22276
- sampleCount: 1,
22277
- dimension: "2d",
22278
- usage: 16 | 4 | 1
22279
- },
22280
- () => current().physical.resolveTexture ?? initial.physical.resolveTexture ?? initial.physical.texture
22281
- ) : void 0;
22282
- if (resolveTexture !== void 0 && !resolveTexture.ok) return resolveTexture;
22283
- const resolve = resolveTexture === void 0 ? void 0 : builder.importView(
22284
- resolveTexture.value,
22285
- {
22286
- label: `cube-capture.${slot}.resolve`,
22287
- dimension: "2d",
22288
- baseMipLevel: 0,
22289
- mipLevelCount: 1,
22290
- baseArrayLayer: initial.faceIndex,
22291
- arrayLayerCount: 1
22292
- },
22293
- () => current().physical.resolveFaceViews[current().faceIndex] ?? initial.physical.resolveFaceViews[initial.faceIndex] ?? initial.physical.resolveView
22294
- );
22295
- if (resolve !== void 0 && !resolve.ok) return resolve;
22296
- const added = builder.addRasterPass(`cube-capture-face.${slot}`, {
22297
- accesses: [
22298
- { resource: color.value, usage: "color-attachment" },
22299
- { resource: depth.value, usage: "depth-stencil-write" },
22300
- ...resolve === void 0 ? [] : [{ resource: resolve.value, usage: "color-attachment" }]
22301
- ],
22302
- colorAttachments: [
22303
- {
22304
- view: color.value,
22305
- ...resolve === void 0 ? {} : { resolveTarget: resolve.value },
22306
- loadOp: "clear",
22307
- storeOp: "store",
22308
- clearValue: () => {
22309
- return { r: 0, g: 0, b: 0, a: 1 };
22310
- }
22311
- }
22312
- ],
22313
- depthStencilAttachment: {
22314
- view: depth.value,
22315
- depthClearValue: 1,
22316
- depthLoadOp: "clear",
22317
- depthStoreOp: "store",
22318
- stencilClearValue: 0,
22319
- stencilLoadOp: "clear",
22320
- stencilStoreOp: "store"
22321
- },
22322
- encode: ({ pass, frame, resources }) => {
22323
- const internal = frame;
22324
- const captureColor = resources.textureView(color.value);
22325
- if (!captureColor.ok) return;
22326
- const captureDepth = resources.textureView(depth.value);
22327
- if (!captureDepth.ok) return;
22328
- const captureResolve = resolve === void 0 ? void 0 : resources.textureView(resolve.value);
22329
- if (resolve !== void 0 && (captureResolve === void 0 || !captureResolve.ok)) return;
22330
- const captureResolveView = captureResolve?.ok ? captureResolve.value : null;
22331
- const captureContext = {
22332
- ...internal,
22333
- camera: current().faceCamera,
22334
- // Cube faces are raw scene captures, not display-camera HDR output.
22335
- // Select the PSO against the actual target attachment so an LDR
22336
- // cube target is rendered by a compatible forward pipeline.
22337
- tonemapActive: false,
22338
- skyboxActive: false,
22339
- transparentColorFormat: initial.physical.descriptor.format,
22340
- msaaActive: initial.physical.descriptor.sampleCount === 4,
22341
- viewBindGroupDynamicOffset: current().viewBindGroupDynamicOffset,
22342
- geometryColorView: captureColor.value,
22343
- geometryDepthView: captureDepth.value,
22344
- geometryColorResolveView: captureResolveView,
22345
- splitLdrSprite: false,
22346
- ldrSpritePassView: null
22347
- };
22348
- encodeMainPass(captureContext, pass, void 0, {
22349
- colorViews: [captureColor.value],
22350
- colorFormats: [initial.physical.descriptor.format],
22351
- depthView: captureDepth.value,
22352
- passKind: "forward",
22353
- clearColor: [0, 0, 0, 1]
22354
- });
22355
- }
22356
- });
22357
- if (!added.ok) return added;
22358
- }
22359
- return ok$1(void 0);
22360
- }
22361
22565
  function addReflectionProbeGraphPasses(builder, state, environmentCube) {
22362
22566
  const accesses = [];
22363
22567
  for (const work of state.work) {
@@ -23581,7 +23785,7 @@ function ensureCompiledFrameGraph(internals, frameState, pipelineState, camera,
23581
23785
  // renderer-owned and read dynamically by the compiled pass, so a page
23582
23786
  // rotation must not invalidate the graph or its cached bind groups.
23583
23787
  occlusionQuery: occlusion === void 0 ? void 0 : { active: true, sampleCount: occlusion.sampleCount },
23584
- cubeCaptureSlots: cubeCaptureState?.work.length ?? 0,
23788
+ cubeCaptureSlots: cubeCaptureState?.work.map((work) => work.physical.descriptor),
23585
23789
  reflectionProbeSlots: cubeCaptureState?.reflectionProbes?.work.map((work) => [
23586
23790
  work.probeIndex,
23587
23791
  work.rawCaptureFace ?? -1,
@@ -23717,7 +23921,13 @@ function ensureCompiledFrameGraph(internals, frameState, pipelineState, camera,
23717
23921
  );
23718
23922
  },
23719
23923
  ...gpuDriven?.projectShadow === void 0 ? {} : {
23720
- projectGpuDrivenShadow: (identity) => gpuDriven.projectShadow?.(builder, identity) ?? ok$1(void 0)
23924
+ projectGpuDrivenShadow: (identity) => (
23925
+ // A newly compiled graph must include the shadow compute passes
23926
+ // even when the producer cache hit. The graph owns its pass
23927
+ // list; importing only the cached view resources would reuse
23928
+ // stale indirect arguments after a topology replacement.
23929
+ gpuDriven.projectShadow?.(builder, identity, true) ?? ok$1(void 0)
23930
+ )
23721
23931
  },
23722
23932
  contributeShadowFeatures: () => featureShadows ??= projectRenderFeatureShadows(
23723
23933
  builder,
@@ -23765,7 +23975,7 @@ function ensureCompiledFrameGraph(internals, frameState, pipelineState, camera,
23765
23975
  environmentCube
23766
23976
  );
23767
23977
  if (!reflectionProbes.ok) return reflectionProbes;
23768
- return cubeCaptureState === void 0 ? ok$1(void 0) : addCubeCaptureGraphPasses(builder, cubeCaptureState);
23978
+ return cubeCaptureState === void 0 ? ok$1(void 0) : addTargetCaptureGraphPasses(builder, cubeCaptureState);
23769
23979
  },
23770
23980
  hasFeature: (identity) => projectedFeaturePlans.value.some((execution) => execution.featureIdentity === identity),
23771
23981
  hasFeatureWork: (identity, placement) => projectedFeaturePlans.value.some(
@@ -24822,7 +25032,7 @@ function gpuDrivenMeshesForFrame(internals, pipelineState, worlds, scene) {
24822
25032
  const asset = resolveAssetHandle(world, sharedHandle);
24823
25033
  if (asset.ok) {
24824
25034
  const lodMeshes = slot.snapshot.lods?.map(
24825
- (lod) => internals.assets.lookup(lod.mesh)
25035
+ (lod) => renderAssetByGuid(world, internals.assets, lod.mesh)
24826
25036
  );
24827
25037
  const resolvedLodMeshes = lodMeshes?.every((lod) => lod?.kind === "mesh") === true ? lodMeshes : void 0;
24828
25038
  const resident = internals.gpuStore.ensureResident(
@@ -24883,6 +25093,18 @@ function prepareCubeCapture(internals, input, displayCamera) {
24883
25093
  viewBindGroupDynamicOffset: (CUBE_CAPTURE_VIEW_SLOT_BASE + physicalWork.length) * VIEW_UNIFORM_SLOT_STRIDE
24884
25094
  });
24885
25095
  }
25096
+ for (const camera of input.auxiliaryCameras) {
25097
+ if (camera.target === void 0) continue;
25098
+ const physical = internals.getRenderTargetPhysical?.(camera.target);
25099
+ if (physical?.descriptor.shape !== "2d") continue;
25100
+ physicalWork.push({
25101
+ target: camera.target,
25102
+ faceIndex: 0,
25103
+ physical,
25104
+ faceCamera: camera,
25105
+ viewBindGroupDynamicOffset: (CUBE_CAPTURE_VIEW_SLOT_BASE + 6) * VIEW_UNIFORM_SLOT_STRIDE
25106
+ });
25107
+ }
24886
25108
  input.state.work = physicalWork;
24887
25109
  return physicalWork;
24888
25110
  }
@@ -24904,8 +25126,32 @@ function runRecordProfilePhase(runner, phase, action) {
24904
25126
  function shadowPlanes(matrix) {
24905
25127
  return frustum.fromViewProjection(frustum.create(), matrix);
24906
25128
  }
24907
- function shadowViewToken(matrix) {
24908
- return Array.from(matrix).join(",");
25129
+ function shadowViewPlanesByView(lights) {
25130
+ const views = /* @__PURE__ */ new Map();
25131
+ for (const [index, matrix] of (lights.lightViewProj ?? []).entries()) {
25132
+ views.set(shadowViewIdentityKey({ kind: "directional", index }), shadowPlanes(matrix));
25133
+ }
25134
+ for (const [index, point] of lights.pointShadow.entries()) {
25135
+ for (let face = 0; face < 6; face += 1) {
25136
+ views.set(
25137
+ shadowViewIdentityKey({ kind: "point", index, face }),
25138
+ shadowPlanes(point.shadowMatrices.subarray(face * 16, face * 16 + 16))
25139
+ );
25140
+ }
25141
+ }
25142
+ let spotIndex = 0;
25143
+ for (const spot of lights.spot) {
25144
+ if (spot.lightViewProj === void 0) continue;
25145
+ views.set(
25146
+ shadowViewIdentityKey({ kind: "spot", index: spotIndex }),
25147
+ shadowPlanes(spot.lightViewProj)
25148
+ );
25149
+ spotIndex += 1;
25150
+ }
25151
+ return views;
25152
+ }
25153
+ function shadowViewToken(matrix, targetSize, graphGeneration) {
25154
+ return `${Array.from(matrix).join(",")}|target:${targetSize}|graph:${graphGeneration}`;
24909
25155
  }
24910
25156
  function halfFloatToNumber(bits) {
24911
25157
  const sign = (bits & 32768) === 0 ? 1 : -1;
@@ -25270,7 +25516,7 @@ function frameClockSample(world, worlds, camera, sampleTimeSeconds) {
25270
25516
  const owner = worlds[camera.worldId ?? 0] ?? world;
25271
25517
  const invalidSampleTime = sampleTimeSeconds !== void 0 && !Number.isFinite(sampleTimeSeconds);
25272
25518
  try {
25273
- const clock = owner.getResource(Time);
25519
+ const clock = renderTime(owner);
25274
25520
  return {
25275
25521
  deltaSeconds: Number.isFinite(clock.delta) ? Math.max(0, clock.delta) : 0,
25276
25522
  // Keep the raw host sample even when ECS accepted only a clamped
@@ -25807,7 +26053,7 @@ function recordFrame(internals, world, cameras, lights, renderables, transparent
25807
26053
  shadowViews.push({
25808
26054
  identity: { kind: "directional", index },
25809
26055
  planes: shadowPlanes(matrix),
25810
- cacheToken: `${shadowViewToken(matrix)}|target:${graphShadowMapSize}:${frameState.graphGeneration}`
26056
+ cacheToken: shadowViewToken(matrix, graphShadowMapSize, frameState.graphGeneration)
25811
26057
  });
25812
26058
  }
25813
26059
  for (const [index, point] of lights.pointShadow.entries()) {
@@ -25816,7 +26062,7 @@ function recordFrame(internals, world, cameras, lights, renderables, transparent
25816
26062
  shadowViews.push({
25817
26063
  identity: { kind: "point", index, face },
25818
26064
  planes: shadowPlanes(matrix),
25819
- cacheToken: `${shadowViewToken(matrix)}|target:${graphShadowMapSize}:${frameState.graphGeneration}`
26065
+ cacheToken: shadowViewToken(matrix, graphShadowMapSize, frameState.graphGeneration)
25820
26066
  });
25821
26067
  }
25822
26068
  }
@@ -25826,7 +26072,11 @@ function recordFrame(internals, world, cameras, lights, renderables, transparent
25826
26072
  shadowViews.push({
25827
26073
  identity: { kind: "spot", index: shadowSpotIndex },
25828
26074
  planes: shadowPlanes(spot.lightViewProj),
25829
- cacheToken: `${shadowViewToken(spot.lightViewProj)}|target:${graphShadowMapSize}:${frameState.graphGeneration}`
26075
+ cacheToken: shadowViewToken(
26076
+ spot.lightViewProj,
26077
+ graphShadowMapSize,
26078
+ frameState.graphGeneration
26079
+ )
25830
26080
  });
25831
26081
  shadowSpotIndex += 1;
25832
26082
  }
@@ -26380,6 +26630,7 @@ function recordFrame(internals, world, cameras, lights, renderables, transparent
26380
26630
  gpuDrivenShadowDrawKeysByView: rasterGpuDriven.shadowDrawKeysByView
26381
26631
  }
26382
26632
  },
26633
+ shadowViewPlanesByView: shadowViewPlanesByView(lights),
26383
26634
  ...frameGpuDriven?.scene === void 0 ? {} : { gpuDrivenSceneMaterialBuffer: frameGpuDriven.scene.scene.materialBuffer },
26384
26635
  ...cubeCapture?.reflectionProbes === void 0 ? {} : { reflectionProbes: cubeCapture.reflectionProbes },
26385
26636
  ...cubeCapture?.captureDispatch === void 0 ? {} : { captureDispatch: cubeCapture.captureDispatch },
@@ -26487,7 +26738,7 @@ function recordFrame(internals, world, cameras, lights, renderables, transparent
26487
26738
  }
26488
26739
  acknowledgeRenderFeatureSubmission(getRenderFeatureGraphState(internals).plans);
26489
26740
  }
26490
- if (cubeCapture !== void 0 && cubeCaptureWork.length > 0) {
26741
+ if (cubeCapture !== void 0 && cubeCaptureWork.some((work) => work.physical.descriptor.shape === "cube")) {
26491
26742
  const completed = cubeCapture.scheduler.completeSubmission(submitted, completion);
26492
26743
  if (!completed.ok) internals.errorRegistry.fire(completed.error);
26493
26744
  }
@@ -27393,7 +27644,6 @@ function createRenderSystemRecovery(deps) {
27393
27644
  if (pendingOutput !== void 0) retireAutoExposureGpuResources(pendingOutput);
27394
27645
  candidateFrameState.pendingAutoExposureGpuResources = void 0;
27395
27646
  for (const work of setupWorks) work.discard();
27396
- setupWorks.length = 0;
27397
27647
  const graph = candidateFrameState.compiledFrameGraph;
27398
27648
  candidateFrameState.compiledFrameGraph = null;
27399
27649
  candidateFrameState.perFrameGraph = null;
@@ -27639,7 +27889,7 @@ function createRenderSystemRecovery(deps) {
27639
27889
  cloudHistory: seed.frame.cloudLayer !== void 0
27640
27890
  });
27641
27891
  const featureFrame = runRenderFeatureFrame(candidateFeatureHost, {
27642
- worlds: seed.worlds,
27892
+ worlds: seed.worlds.filter((world) => !("resolveAsset" in world)),
27643
27893
  owner: seed.resourceOwner,
27644
27894
  frameNumber: candidateFrameState.frameNumber,
27645
27895
  selectedCamera: camera,
@@ -29113,11 +29363,11 @@ var ReflectionProbeRecordOwner = class {
29113
29363
  prefilterGroup0Bgl: cache.prefilterGroup0Bgl
29114
29364
  };
29115
29365
  }
29116
- createCubeSet(label, size, mipCount2 = PREFILTER_MIP_LEVELS) {
29366
+ createCubeSet(label, size, mipCount = PREFILTER_MIP_LEVELS) {
29117
29367
  const texture = this.internals.device.createTexture({
29118
29368
  label,
29119
29369
  size: { width: size, height: size, depthOrArrayLayers: 6 },
29120
- mipLevelCount: mipCount2,
29370
+ mipLevelCount: mipCount,
29121
29371
  sampleCount: 1,
29122
29372
  dimension: "2d",
29123
29373
  format: this.outputFormat,
@@ -29130,7 +29380,7 @@ var ReflectionProbeRecordOwner = class {
29130
29380
  label: `${label}-cube`,
29131
29381
  dimension: "cube",
29132
29382
  baseMipLevel: 0,
29133
- mipLevelCount: mipCount2,
29383
+ mipLevelCount: mipCount,
29134
29384
  arrayLayerCount: 6
29135
29385
  });
29136
29386
  if (!cubeView.ok) {
@@ -29139,7 +29389,7 @@ var ReflectionProbeRecordOwner = class {
29139
29389
  }
29140
29390
  const faceViews = [];
29141
29391
  const mipViews = [];
29142
- for (let mip = 0; mip < mipCount2; mip += 1) {
29392
+ for (let mip = 0; mip < mipCount; mip += 1) {
29143
29393
  const faces = [];
29144
29394
  for (let face = 0; face < 6; face += 1) {
29145
29395
  const view = this.internals.device.createTextureView(texture.value, {
@@ -29661,32 +29911,25 @@ function createPreparedResolverCaches() {
29661
29911
  preparedMaterialPipelineShaders: /* @__PURE__ */ new WeakMap(),
29662
29912
  preparedGroup0Pipelines: /* @__PURE__ */ new WeakSet(),
29663
29913
  preparedViewOnlyPipelines: /* @__PURE__ */ new WeakSet(),
29664
- preparedRenderMaterialPipelines: /* @__PURE__ */ new WeakSet(),
29665
- preparedAssetHandles: /* @__PURE__ */ new WeakMap()
29666
- };
29667
- }
29668
- function preparedHandle(runtime, caches, world, guid, brand) {
29669
- let handles = caches.preparedAssetHandles.get(world);
29670
- if (handles === void 0) {
29671
- handles = /* @__PURE__ */ new Map();
29672
- caches.preparedAssetHandles.set(world, handles);
29673
- }
29674
- const key = `${brand}:${guid.toLowerCase()}`;
29675
- const cached = handles.get(key);
29676
- if (cached !== void 0) return cached;
29677
- const asset = runtime.assets.lookup(guid);
29678
- if (asset === void 0) return void 0;
29679
- const handle = world.allocSharedRef(brand, asset);
29680
- handles.set(key, handle);
29681
- return handle;
29682
- }
29683
- function preparedMaterialBindings(runtime, caches, worlds, materialShaderId, worldIndex, materialGuid, layout, skylightResources) {
29914
+ preparedRenderMaterialPipelines: /* @__PURE__ */ new WeakSet()
29915
+ };
29916
+ }
29917
+ function preparedHandle(runtime, world, guid, brand) {
29918
+ if ("resolveAsset" in world)
29919
+ return world.handleForGuid(guid);
29920
+ return internSharedRefFromGuid(world, runtime.assets, guid, brand);
29921
+ }
29922
+ function preparedMaterialBindings(runtime, worlds, materialShaderId, worldIndex, materialGuid, layout, skylightResources) {
29684
29923
  const world = worlds[worldIndex];
29685
- const material = runtime.assets.lookup(materialGuid);
29924
+ const handle = world === void 0 ? void 0 : preparedHandle(runtime, world, materialGuid, "MaterialAsset");
29686
29925
  const pipelineState = runtime.getPipelineState();
29687
- if (world === void 0 || material?.kind !== "material" || pipelineState === null) {
29926
+ if (world === void 0 || handle === void 0 || pipelineState === null) {
29688
29927
  return err(new Error("prepared material asset is unavailable"));
29689
29928
  }
29929
+ const resolved2 = resolveAssetHandle(world, handle);
29930
+ if (!resolved2.ok) return resolved2;
29931
+ const material = resolved2.value;
29932
+ if (material.kind !== "material") return err(new Error("prepared material asset is unavailable"));
29690
29933
  const schema = runtime.getParamSchema?.(materialShaderId) ?? [];
29691
29934
  const values = materialValuesToLinearRuntime(
29692
29935
  material.values,
@@ -29726,32 +29969,20 @@ function preparedMaterialBindings(runtime, caches, worlds, materialShaderId, wor
29726
29969
  const textureValue = typeof value === "object" && value !== null && "texture" in value ? value : void 0;
29727
29970
  let sampler = pipelineState.defaultSampler;
29728
29971
  if (textureValue?.sampler !== void 0) {
29729
- const handle = preparedHandle(
29730
- runtime,
29731
- caches,
29732
- world,
29733
- String(textureValue.sampler),
29734
- "SamplerAsset"
29735
- );
29736
- if (handle !== void 0) {
29737
- const asset = resolveAssetHandle(world, handle);
29972
+ const handle2 = preparedHandle(runtime, world, String(textureValue.sampler), "SamplerAsset");
29973
+ if (handle2 !== void 0) {
29974
+ const asset = resolveAssetHandle(world, handle2);
29738
29975
  if (asset.ok) {
29739
- const resident = runtime.gpuStore.ensureSamplerResident(handle, asset.value, world);
29976
+ const resident = runtime.gpuStore.ensureSamplerResident(handle2, asset.value, world);
29740
29977
  if (resident.ok) sampler = resident.value;
29741
29978
  }
29742
29979
  }
29743
29980
  }
29744
29981
  let view = defaultViewForUserRegionField(field, pipelineState, schema);
29745
29982
  if (textureValue !== void 0) {
29746
- const handle = preparedHandle(
29747
- runtime,
29748
- caches,
29749
- world,
29750
- String(textureValue.texture),
29751
- "TextureAsset"
29752
- );
29753
- if (handle !== void 0) {
29754
- view = residentTextureView(world, runtime.gpuStore, runtime, handle) ?? view;
29983
+ const handle2 = preparedHandle(runtime, world, String(textureValue.texture), "TextureAsset");
29984
+ if (handle2 !== void 0) {
29985
+ view = residentTextureView(world, runtime.gpuStore, runtime, handle2) ?? view;
29755
29986
  }
29756
29987
  }
29757
29988
  textureResources.push({ sampler, view });
@@ -29799,7 +30030,6 @@ function preparedMaterialBindings(runtime, caches, worlds, materialShaderId, wor
29799
30030
  prefilterView: fallback.prefilterView,
29800
30031
  prefilterSampler: fallback.sampler,
29801
30032
  brdfLutView: fallback.brdfLutView,
29802
- brdfLutSampler: fallback.sampler,
29803
30033
  intensityBuffer: fallback.intensityBuffer
29804
30034
  },
29805
30035
  transmissionBackdropAvailable(runtime.device.limits.maxSampledTexturesPerShaderStage) ? void 0 : null
@@ -32263,56 +32493,6 @@ var RenderScene = class {
32263
32493
  return slot === void 0 ? worldBounds(snapshot) : this.cullingWorldBoundsAt(slot);
32264
32494
  }
32265
32495
  };
32266
- var RENDERABLE_SOURCE_COMPONENTS = [
32267
- ChildOf,
32268
- MeshFilter,
32269
- MeshRenderer,
32270
- Instances,
32271
- SpriteInstances,
32272
- SpriteRegionOverride,
32273
- Skin,
32274
- Layer,
32275
- Visibility,
32276
- MorphWeights,
32277
- Points,
32278
- Lines,
32279
- SortKey
32280
- ];
32281
- function createGlobalTransformChangeQuery(world) {
32282
- const result = world.query({ read: [GlobalTransform], changed: [GlobalTransform] });
32283
- if (!result.ok) throw result.error;
32284
- const query = result.value;
32285
- for (const _span of query.spans().unwrap()) {
32286
- }
32287
- return query;
32288
- }
32289
- function createRenderSourceState(world) {
32290
- const components = [...RENDERABLE_SOURCE_COMPONENTS, RuntimeMaterialValue, RuntimeMeshVertices];
32291
- const projection = createStateProjection(world, components, [
32292
- ...components,
32293
- Transform,
32294
- GlobalTransform
32295
- ]);
32296
- const entities = /* @__PURE__ */ new Map();
32297
- const contentHandles = /* @__PURE__ */ new Map();
32298
- const batch = projection.read();
32299
- for (const index of batch.indices) {
32300
- const entity = projection.entity(index);
32301
- if (entity !== void 0) {
32302
- entities.set(index, entity);
32303
- const handles = [];
32304
- const material = world.hasComponent(entity, RuntimeMaterialValue) ? world.get(entity, RuntimeMaterialValue) : void 0;
32305
- const mesh = world.hasComponent(entity, RuntimeMeshVertices) ? world.get(entity, RuntimeMeshVertices) : void 0;
32306
- if (material?.ok) handles.push(Number(material.value.asset));
32307
- if (mesh?.ok) handles.push(Number(mesh.value.asset));
32308
- if (handles.length > 0) contentHandles.set(index, handles);
32309
- }
32310
- }
32311
- return { projection, entities, contentHandles, batch };
32312
- }
32313
- function isRenderableMember(world, entity) {
32314
- return world.hasComponent(entity, MeshRenderer) && world.hasComponent(entity, Transform) && world.hasComponent(entity, MeshFilter);
32315
- }
32316
32496
  function sourceMembershipChanged(world, slot) {
32317
32497
  const entity = slot.entityKey;
32318
32498
  const snapshot = slot.snapshot;
@@ -32593,6 +32773,9 @@ var PersistentRenderScene = class {
32593
32773
  compositionSlots() {
32594
32774
  return this.composition?.projection.slotsSnapshot() ?? [];
32595
32775
  }
32776
+ compositionSlot(worldId, entityKey) {
32777
+ return this.composition?.projection.slot(worldId, entityKey);
32778
+ }
32596
32779
  shadowCasterProjection() {
32597
32780
  return this.shadowProjection;
32598
32781
  }
@@ -32799,11 +32982,81 @@ var PersistentRenderScene = class {
32799
32982
  reflectionProbeProjection() {
32800
32983
  return this.reflectionProbes.snapshot();
32801
32984
  }
32985
+ consumePublication(input) {
32986
+ const { resources, packet, frame } = input;
32987
+ let entry = this.composition;
32988
+ if (entry === void 0 || packet.baseline) {
32989
+ this.invalidate();
32990
+ const projection = new RenderScene();
32991
+ entry = {
32992
+ token: {},
32993
+ worlds: [resources],
32994
+ projection,
32995
+ topology: new BatchTopology(),
32996
+ transmissionDemand: new PersistentTransmissionDemandProjection(),
32997
+ hiddenEntityReports: [],
32998
+ worldKeys: this.visibilityWorldKeysFor([resources]),
32999
+ readVersions: [],
33000
+ leaseIdentities: [],
33001
+ transformQueries: [],
33002
+ sourceStates: [],
33003
+ dispatchBySlot: /* @__PURE__ */ new Map(),
33004
+ dispatchRevision: 0,
33005
+ dispatchCache: void 0,
33006
+ skinConsumersByJoint: /* @__PURE__ */ new Map(),
33007
+ pendingRenderableEntitiesByWorld: [],
33008
+ unavailableSlots: /* @__PURE__ */ new Set(),
33009
+ catalogEpoch: 0,
33010
+ probeProjection: new ProbeBlendSceneProjection(),
33011
+ probeObjects: void 0,
33012
+ temporalDemanded: false,
33013
+ gpuDrivenSceneRequired: true
33014
+ };
33015
+ this.composition = entry;
33016
+ this.fullRebuilds++;
33017
+ this.lastResyncReason = "attach";
33018
+ }
33019
+ this.worldEntitiesScanned = 0;
33020
+ this.sceneTableUploadBytes = 0;
33021
+ const removedDemand = [];
33022
+ for (const operation of input.operations) {
33023
+ if (operation.kind !== "remove" && operation.snapshot === void 0) continue;
33024
+ const previous = entry.projection.slot(0, operation.entityKey);
33025
+ for (let index = 0; index < (previous?.snapshot.materials.length ?? 0); index++)
33026
+ removedDemand.push({ kind: "remove", key: `0:${operation.entityKey}:${index}` });
33027
+ }
33028
+ const delta = entry.projection.apply(input.operations);
33029
+ for (const removed of delta.removedSlots) {
33030
+ entry.dispatchBySlot.delete(removed.slot);
33031
+ this.stableSlotByEntity.delete(worldEntityKey(entry.worldKeys[0] ?? 0, removed.entityKey));
33032
+ }
33033
+ for (const recreated of delta.recreatedSlots) entry.dispatchBySlot.delete(recreated.slot);
33034
+ for (const [slot, dispatch] of dispatchEntriesBySlot(frame, entry.projection))
33035
+ entry.dispatchBySlot.set(slot, dispatch);
33036
+ if (frame.renderables.length || packet.removed.length) {
33037
+ entry.dispatchRevision++;
33038
+ entry.dispatchCache = void 0;
33039
+ this.visibilityFacets.clear();
33040
+ this.invalidateActiveEntityRevision();
33041
+ }
33042
+ for (const slot of [...delta.createdSlots, ...delta.updatedSlots, ...delta.recreatedSlots])
33043
+ this.stableSlotByEntity.set(worldEntityKey(entry.worldKeys[0] ?? 0, slot.entityKey), slot);
33044
+ entry.transmissionDemand.apply([
33045
+ ...removedDemand,
33046
+ ...transmissionDemandOperations(frame.renderables)
33047
+ ]);
33048
+ entry.topology.apply(delta);
33049
+ this.syncGpuOwner(entry.token, entry.projection, delta);
33050
+ if (input.operations.length) this.deltaFrames++;
33051
+ else this.noChangeFrames++;
33052
+ this.transformUpdates += delta.updated;
33053
+ return this.deriveFramePlan(entry, frame);
33054
+ }
32802
33055
  extractComposition(worlds, owner, catalogEpoch, buildCandidateFrame, leases) {
32803
33056
  this.worldEntitiesScanned = 0;
32804
33057
  this.sceneTableUploadBytes = 0;
32805
33058
  const entry = this.composition;
32806
- const sameWorldSet = entry !== void 0 && entry.worlds.length === worlds.length && entry.worlds.every((world) => worlds.includes(world));
33059
+ const sameWorldSet = entry !== void 0 && entry.worlds.length === worlds.length && entry.worlds.every((world) => worlds.some((local) => local === world));
32807
33060
  const worldOrderChanged = entry !== void 0 && sameWorldSet && entry.worlds.some((world, index) => world !== worlds[index]);
32808
33061
  const leaseSetPreserved = entry !== void 0 && leases !== void 0 && leases.length === worlds.length && entry.leaseIdentities.length === leases.length && entry.leaseIdentities.every(
32809
33062
  (identity) => leases.some((lease) => lease.worldIdentity === identity)
@@ -33452,7 +33705,7 @@ var PersistentRenderScene = class {
33452
33705
  }
33453
33706
  reconcileComposition(worlds, _owner, catalogEpoch, buildCandidateFrame, leases, preserveVisibilityOnReorder = false) {
33454
33707
  const previousEntry = this.composition;
33455
- const sourceStates = worlds.map(createRenderSourceState);
33708
+ const sourceStates = worlds.map((world) => createRenderSourceState(world));
33456
33709
  const candidateFrame = buildCandidateFrame({
33457
33710
  kind: "partial",
33458
33711
  entitiesByWorld: sourceStates.map((source) => new Set(source.entities.values()))
@@ -33484,7 +33737,11 @@ var PersistentRenderScene = class {
33484
33737
  const renderables = candidateFrame.renderables;
33485
33738
  const projection = previousEntry?.projection ?? new RenderScene();
33486
33739
  if (previousEntry !== void 0) {
33487
- projection.remapWorlds(previousEntry.worlds.map((world) => worlds.indexOf(world)));
33740
+ projection.remapWorlds(
33741
+ previousEntry.worlds.map(
33742
+ (world) => worlds.indexOf(world)
33743
+ )
33744
+ );
33488
33745
  }
33489
33746
  const desired = new Set(
33490
33747
  renderables.map((snapshot) => identityKey(snapshot.worldId, snapshot.entityKey))
@@ -33529,9 +33786,9 @@ var PersistentRenderScene = class {
33529
33786
  for (const snapshot of stableCandidateFrame.renderables) {
33530
33787
  if (snapshot.skinJointEntities !== void 0) addSkinConsumer(skinConsumersByJoint, snapshot);
33531
33788
  }
33532
- const token2 = previousEntry?.token ?? {};
33789
+ const token = previousEntry?.token ?? {};
33533
33790
  const entry = {
33534
- token: token2,
33791
+ token,
33535
33792
  worlds: [...worlds],
33536
33793
  projection,
33537
33794
  topology,
@@ -33558,7 +33815,7 @@ var PersistentRenderScene = class {
33558
33815
  projection.setTemporalTracking(entry.temporalDemanded);
33559
33816
  this.projectReflectionProbes(candidateFrame.reflectionProbes ?? []);
33560
33817
  this.projectProbes(entry, candidateFrame);
33561
- this.syncGpuOwner(token2, projection, delta);
33818
+ this.syncGpuOwner(token, projection, delta);
33562
33819
  if (previousEntry === void 0) this.fullRebuilds += 1;
33563
33820
  this.lastResyncReason = "attach";
33564
33821
  const materialized = projection.materialize();
@@ -33602,7 +33859,7 @@ var PersistentRenderScene = class {
33602
33859
  const candidateFrame = {
33603
33860
  ...resourceFrame,
33604
33861
  hiddenEntityReports: entry.hiddenEntityReports,
33605
- visibilityStats: { explicitlyHidden: entry.hiddenEntityReports.length },
33862
+ visibilityStats: entry.sourceStates.length === 0 ? resourceFrame.visibilityStats : { explicitlyHidden: entry.hiddenEntityReports.length },
33606
33863
  dispatch
33607
33864
  };
33608
33865
  entry.temporalDemanded = frameDemandsTemporal(candidateFrame);
@@ -33940,12 +34197,12 @@ function assertExtent(extent) {
33940
34197
  function mipExtent(value, level) {
33941
34198
  return Math.max(1, Math.floor(value / 2 ** level));
33942
34199
  }
33943
- function estimateTransmissionBackdropBytes(extent, mipCount2, format = "rgba16float") {
34200
+ function estimateTransmissionBackdropBytes(extent, mipCount, format = "rgba16float") {
33944
34201
  assertExtent(extent);
33945
- assertNonNegativeInteger("transmission inspection mipCount", mipCount2);
33946
- if (format !== "rgba16float" || mipCount2 === 0) return 0;
34202
+ assertNonNegativeInteger("transmission inspection mipCount", mipCount);
34203
+ if (format !== "rgba16float" || mipCount === 0) return 0;
33947
34204
  let bytes2 = 0;
33948
- for (let level = 0; level < mipCount2; level += 1) {
34205
+ for (let level = 0; level < mipCount; level += 1) {
33949
34206
  bytes2 += mipExtent(extent.width, level) * mipExtent(extent.height, level);
33950
34207
  }
33951
34208
  return bytes2 * RGBA16FLOAT_BYTES_PER_PIXEL;
@@ -33971,9 +34228,9 @@ function inspectTransmission(input) {
33971
34228
  assertExtent(input.extent);
33972
34229
  const format = input.format ?? "rgba16float";
33973
34230
  const resourcePresent = input.resourcePresent ?? input.lastKnownGood;
33974
- const mipCount2 = resourcePresent ? input.mipCount ?? input.topology.mipCount + 1 : 0;
33975
- assertNonNegativeInteger("transmission inspection mipCount", mipCount2);
33976
- const bytes2 = resourcePresent ? input.bytes ?? estimateTransmissionBackdropBytes(input.extent, mipCount2, format) : 0;
34231
+ const mipCount = resourcePresent ? input.mipCount ?? input.topology.mipCount + 1 : 0;
34232
+ assertNonNegativeInteger("transmission inspection mipCount", mipCount);
34233
+ const bytes2 = resourcePresent ? input.bytes ?? estimateTransmissionBackdropBytes(input.extent, mipCount, format) : 0;
33977
34234
  assertNonNegativeInteger("transmission inspection bytes", bytes2);
33978
34235
  const copyCount = resourcePresent ? input.topology.copyCount : 0;
33979
34236
  if (copyCount !== (resourcePresent ? 1 : 0)) {
@@ -33984,7 +34241,7 @@ function inspectTransmission(input) {
33984
34241
  needsRoughMips: active && input.demand.needsRoughMips,
33985
34242
  extent: Object.freeze({ ...input.extent }),
33986
34243
  format,
33987
- mipCount: mipCount2,
34244
+ mipCount,
33988
34245
  bytes: bytes2,
33989
34246
  copyCount,
33990
34247
  transmissionDrawCount: input.transmissionDrawCount ?? 0,
@@ -35003,7 +35260,6 @@ function createRenderSystem(internals) {
35003
35260
  if (group === 1 && layout !== void 0 && materialShaderId !== void 0 && typeof material === "object" && material !== null && "world" in material && "guid" in material && typeof material.world === "number" && typeof material.guid === "string") {
35004
35261
  return preparedMaterialBindings(
35005
35262
  runtime,
35006
- caches,
35007
35263
  worlds,
35008
35264
  materialShaderId,
35009
35265
  material.world,
@@ -35315,9 +35571,10 @@ function createRenderSystem(internals) {
35315
35571
  }
35316
35572
  persistentRenderScene.detach(world);
35317
35573
  },
35318
- draw(worlds, opts, renderReadLeases, timingCapture) {
35574
+ draw(worlds, opts, renderReadLeases, timingCapture, publication) {
35319
35575
  const composition = canonicalizeWorldComposition(worlds, opts, renderReadLeases);
35320
- const compositionWorlds = composition.worlds;
35576
+ const sourceWorlds = composition.worlds;
35577
+ const compositionWorlds = publication === void 0 ? sourceWorlds : [publication.resources];
35321
35578
  const compositionLeases = composition.leases;
35322
35579
  preparedWorlds = compositionWorlds;
35323
35580
  const profileSession = internals.profiler?.activeSession();
@@ -35340,19 +35597,41 @@ function createRenderSystem(internals) {
35340
35597
  if (frameState.installedPipelineHandle !== lastBuiltPipelineHandle) {
35341
35598
  resetRenderFeatureGraphState(internals);
35342
35599
  lastBuiltPipelineHandle = frameState.installedPipelineHandle;
35343
- persistentRenderScene.invalidate();
35600
+ if (publication === void 0) persistentRenderScene.invalidate();
35344
35601
  }
35345
35602
  dispatchCounts.unlit = 0;
35346
35603
  const resourceWorld = compositionWorlds[resourceOwner];
35347
35604
  let frame;
35348
35605
  try {
35349
35606
  frame = runProfiledRenderPhase(profileSession, "extract", () => {
35607
+ if (publication !== void 0) {
35608
+ for (const handle of [
35609
+ ...publication.packet.invalidatedAssets,
35610
+ ...publication.packet.retiredAssets
35611
+ ]) {
35612
+ internals.gpuStore.invalidateMesh(handle, publication.resources);
35613
+ internals.gpuStore.evictTexture(
35614
+ handle,
35615
+ publication.resources
35616
+ );
35617
+ }
35618
+ return persistentRenderScene.consumePublication(
35619
+ preparePublicationGeometry(
35620
+ publication,
35621
+ persistentRenderScene,
35622
+ internals.getPipelineState()?.skinPaletteAllocator,
35623
+ internals.assets,
35624
+ instanceCollections,
35625
+ internals.device.caps.storageBuffer ? internals.getMaterialShaderArtifact : void 0
35626
+ )
35627
+ );
35628
+ }
35350
35629
  return persistentRenderScene.extractComposition(
35351
- compositionWorlds,
35630
+ sourceWorlds,
35352
35631
  { cameraOwner, resourceOwner },
35353
35632
  internals.assets.catalogEpoch,
35354
35633
  (renderables2) => extractFrames(
35355
- compositionWorlds,
35634
+ sourceWorlds,
35356
35635
  {
35357
35636
  cameraOwner,
35358
35637
  resourceOwner,
@@ -35362,18 +35641,7 @@ function createRenderSystem(internals) {
35362
35641
  internals.getPipelineState(),
35363
35642
  persistentRenderScene.materialSnapshotCacheStore(),
35364
35643
  {
35365
- ...internals.device.caps.backendKind === "null" ? {} : {
35366
- materialContext: {
35367
- backend: internals.device.caps.backendKind === "wgpu-webgl2" ? "webgl2" : internals.device.caps.backendKind,
35368
- capability: internals.device.caps.storageBuffer ? "storage-buffer" : "uniform-fallback",
35369
- pipeline: "forward",
35370
- geometry: "mesh",
35371
- pass: "forward",
35372
- profile: "forgeax-material-wgsl-v1",
35373
- toolchain: "naga-oil",
35374
- instrumentation: "none"
35375
- }
35376
- },
35644
+ ...renderMaterialContext(internals.device.caps),
35377
35645
  cull: "none",
35378
35646
  retainHidden: true,
35379
35647
  renderables: renderables2,
@@ -35396,6 +35664,7 @@ function createRenderSystem(internals) {
35396
35664
  lastMotionBlurInvalidParams = void 0;
35397
35665
  const {
35398
35666
  cameras: extractedCameras,
35667
+ auxiliaryCameras,
35399
35668
  cubeCameras,
35400
35669
  lights,
35401
35670
  environment,
@@ -35818,7 +36087,7 @@ function createRenderSystem(internals) {
35818
36087
  const motionBlurParams = cameras[0]?.motionBlur;
35819
36088
  let motionBlurDelta = 0;
35820
36089
  try {
35821
- const delta = compositionWorlds[cameraOwner].getResource(Time).delta;
36090
+ const delta = renderTime(compositionWorlds[cameraOwner]).delta;
35822
36091
  motionBlurDelta = Number.isFinite(delta) ? Math.max(0, delta) : 0;
35823
36092
  } catch {
35824
36093
  motionBlurDelta = 0;
@@ -35850,9 +36119,22 @@ function createRenderSystem(internals) {
35850
36119
  preparedFeatureSkylightResources = preparedPipelineState === null ? void 0 : resolveMaterialSkylight(internals, preparedPipelineState, skylight, skylightCount).skylightResources;
35851
36120
  let featureGraphCandidate;
35852
36121
  const preparedResourceBatches = runProfiledRenderPhase(profileSession, "features", () => {
36122
+ if (publication?.packet.features.some(
36123
+ (row) => !internals.featureHost?.features.some(
36124
+ (feature) => feature.identity === row.identity
36125
+ )
36126
+ ))
36127
+ throw new RenderPublicationError({
36128
+ reason: "shape",
36129
+ subject: "published feature has no receiver implementation"
36130
+ });
35853
36131
  if (internals.featureHost === void 0) return [];
35854
36132
  const featureFrame = runRenderFeatureFrame(internals.featureHost, {
35855
- worlds: compositionWorlds,
36133
+ worlds: sourceWorlds,
36134
+ ...publication === void 0 ? {} : {
36135
+ publishedFeatures: publication.packet.features,
36136
+ ...publication.onFeatureSourceSubmitted === void 0 ? {} : { onFeatureSourceSubmitted: publication.onFeatureSourceSubmitted }
36137
+ },
35856
36138
  owner: resourceOwner,
35857
36139
  frameNumber: frameState.frameNumber,
35858
36140
  ...cameras[0] === void 0 ? {} : { selectedCamera: cameras[0] },
@@ -35984,7 +36266,7 @@ function createRenderSystem(internals) {
35984
36266
  const hasLiveFeatureState = liveOutput !== void 0 || frameState.autoExposureGpuResources !== void 0 || frameState.pendingAutoExposureGpuResources !== void 0 || frameState.autoExposureState !== void 0 || frameState.pendingAutoExposureState !== void 0 || frameState.standardLutGpuResources !== void 0 || frameState.pendingStandardLutGpuResources !== void 0 || frameState.standardLutState.resident !== null || frameState.pendingStandardLutState !== void 0;
35985
36267
  if (hasLiveFeatureState) {
35986
36268
  const cameraWorld = compositionWorlds[cameraOwner];
35987
- const deltaTime = cameraWorld.getResource(Time).delta;
36269
+ const deltaTime = renderTime(cameraWorld).delta;
35988
36270
  stageLiveFeatureState(
35989
36271
  cameras[0],
35990
36272
  Number.isFinite(deltaTime) ? Math.max(0, deltaTime) : 0
@@ -35997,10 +36279,10 @@ function createRenderSystem(internals) {
35997
36279
  resourceGeneration: gpuDrivenProduction.inspect().resourceGeneration
35998
36280
  });
35999
36281
  frameState.surfaceSubmissionObservation = surfaceSubmissionCandidate;
36000
- const probeCaptureScene = shadowCasterProjection !== void 0 && reflectionProbeRecord.graph.work.some((work) => work.rawCaptureFace !== void 0) ? projectCaptureScene(shadowCasterProjection, submissionRenderables, orderedDispatch) : void 0;
36282
+ const probeCaptureScene = shadowCasterProjection !== void 0 && (auxiliaryCameras.length > 0 || cubeCameras.length > 0 || reflectionProbeRecord.graph.work.some((work) => work.rawCaptureFace !== void 0)) ? projectCaptureScene(shadowCasterProjection, submissionRenderables, orderedDispatch) : void 0;
36001
36283
  const presentedRenderableKeys = /* @__PURE__ */ new Set();
36002
36284
  const presentedSubmeshKeys = /* @__PURE__ */ new Set();
36003
- const consumeDynamicGeometry = dynamicGeometryFrames.onRenderableDraw(compositionWorlds);
36285
+ const consumeDynamicGeometry = dynamicGeometryFrames.onRenderableDraw(sourceWorlds);
36004
36286
  const markPresentedRenderable = (entry, submeshIndex, receipt) => {
36005
36287
  const entityKey = worldEntityKey(
36006
36288
  worldKeys[entry.source.worldId] ?? entry.source.worldId,
@@ -36049,7 +36331,9 @@ function createRenderSystem(internals) {
36049
36331
  },
36050
36332
  ...occlusionProjection === void 0 ? {} : { occlusion: occlusionProjection },
36051
36333
  frameTime: (() => {
36052
- const elapsed = compositionWorlds[cameraOwner].getResource(Time).elapsed;
36334
+ const elapsed = renderTime(
36335
+ compositionWorlds[cameraOwner]
36336
+ ).elapsed;
36053
36337
  return Number.isFinite(elapsed) ? elapsed : 0;
36054
36338
  })(),
36055
36339
  deviceGeneration: internals.deviceScope.generation,
@@ -36061,6 +36345,7 @@ function createRenderSystem(internals) {
36061
36345
  pointsLinesOwner,
36062
36346
  {
36063
36347
  snapshots: cubeCameras,
36348
+ auxiliaryCameras,
36064
36349
  scheduler: cubeCaptureScheduler,
36065
36350
  state: cubeCaptureState,
36066
36351
  reflectionProbes: reflectionProbeRecord,
@@ -36204,7 +36489,9 @@ function createRenderSystem(internals) {
36204
36489
  width: Math.max(1, internals.canvas.width),
36205
36490
  height: Math.max(1, internals.canvas.height),
36206
36491
  frameTime: (() => {
36207
- const elapsed = compositionWorlds[cameraOwner].getResource(Time).elapsed;
36492
+ const elapsed = renderTime(
36493
+ compositionWorlds[cameraOwner]
36494
+ ).elapsed;
36208
36495
  return Number.isFinite(elapsed) ? elapsed : 0;
36209
36496
  })(),
36210
36497
  ...surfaceDynamicInputFrame === void 0 ? {} : { surfaceDynamicInput: surfaceDynamicInputFrame },
@@ -36279,20 +36566,20 @@ function createRenderSystem(internals) {
36279
36566
  if (!retired.ok) internals.errorRegistry.fire(retired.error);
36280
36567
  }
36281
36568
  }
36282
- } catch (err57) {
36569
+ } catch (err58) {
36283
36570
  discardLiveFeatureState();
36284
36571
  if (!submitted) {
36285
36572
  internals.getPipelineState()?.perPassResources.discardBloomResources?.();
36286
36573
  }
36287
- const innerError = err57 instanceof PipelineSpecError ? {
36288
- name: err57.name,
36289
- code: err57.code,
36290
- message: err57.message,
36291
- detail: err57.detail
36292
- } : err57 instanceof RhiError ? err57 : {
36574
+ const innerError = err58 instanceof PipelineSpecError ? {
36575
+ name: err58.name,
36576
+ code: err58.code,
36577
+ message: err58.message,
36578
+ detail: err58.detail
36579
+ } : err58 instanceof RhiError ? err58 : {
36293
36580
  code: "unknown",
36294
- message: String(err57),
36295
- name: err57?.name
36581
+ message: String(err58),
36582
+ name: err58?.name
36296
36583
  };
36297
36584
  internals.errorRegistry.fire(
36298
36585
  new RhiError({
@@ -37022,578 +37309,6 @@ function postSpawnResolveJoints(world, resolver, spawnRoot) {
37022
37309
  }
37023
37310
  return { ok: true };
37024
37311
  }
37025
- var atlasMaterialCache = /* @__PURE__ */ new WeakMap();
37026
- var atlasOnlyMaterialCache = /* @__PURE__ */ new WeakMap();
37027
- var streamingCacheByWorld = /* @__PURE__ */ new WeakMap();
37028
- function streamingCache(world) {
37029
- let cache = streamingCacheByWorld.get(world);
37030
- if (cache === void 0) {
37031
- cache = {
37032
- layers: /* @__PURE__ */ new Map(),
37033
- chunkEntities: /* @__PURE__ */ new Map(),
37034
- activeChunks: /* @__PURE__ */ new Map()
37035
- };
37036
- streamingCacheByWorld.set(world, cache);
37037
- }
37038
- return cache;
37039
- }
37040
- function encodeTilemapLayerValue(layerOrder, chunkIndex, sortScope = "layer") {
37041
- if (sortScope === "per-cell") return layerOrder << 20 | 0;
37042
- return layerOrder << 20 | chunkIndex & 1048575 | 0;
37043
- }
37044
- function resolveTilesetMaterial(world, tileset, regionIndex, lookup) {
37045
- const region = tileset.regions[regionIndex];
37046
- if (region === void 0) return toShared(0);
37047
- const atlasIndex = region.atlasIndex ?? 0;
37048
- const atlasGuid = tileset.atlases[atlasIndex];
37049
- if (atlasGuid === void 0) return toShared(0);
37050
- const atlas = resolveTilesetRuntime(world, atlasGuid, lookup);
37051
- if (!atlas.ok) return toShared(0);
37052
- const atlasHandle = atlas.value.handle;
37053
- const atlasId = unwrapHandle(atlasHandle);
37054
- const cacheKey = `${atlasId}|${regionIndex}`;
37055
- const cache = atlasMaterialCache.get(world) ?? /* @__PURE__ */ new Map();
37056
- atlasMaterialCache.set(world, cache);
37057
- const cached = cache.get(cacheKey);
37058
- if (cached !== void 0) return cached;
37059
- const atlasSize = tileset.atlasSizes?.[atlasIndex];
37060
- const atlasWidth = Math.max(
37061
- 1,
37062
- atlasSize !== void 0 ? atlasSize.pixelWidth : tileset.columns * tileset.tileWidth
37063
- );
37064
- const atlasHeight = Math.max(
37065
- 1,
37066
- atlasSize !== void 0 ? atlasSize.pixelHeight : tileset.rows * tileset.tileHeight
37067
- );
37068
- const halfTexelU = 0.5 / atlasWidth;
37069
- const halfTexelV = 0.5 / atlasHeight;
37070
- const u = region.x / atlasWidth + halfTexelU;
37071
- const v = region.y / atlasHeight + halfTexelV;
37072
- const w = region.width / atlasWidth - 2 * halfTexelU;
37073
- const h = region.height / atlasHeight - 2 * halfTexelV;
37074
- const matPayload = {
37075
- kind: "material",
37076
- passes: [
37077
- {
37078
- name: "Forward",
37079
- program: { module: "forgeax::sprite" },
37080
- renderState: {
37081
- ...{ blend: SPRITE_PREMULTIPLIED_ALPHA_BLEND },
37082
- tags: { LightMode: "Forward" },
37083
- queue: 3e3
37084
- }
37085
- }
37086
- ],
37087
- values: {
37088
- colorTint: [1, 1, 1, 1],
37089
- baseColorTexture: atlasHandle,
37090
- region: [u, v, w, h],
37091
- pivotAndSize: [0.5, 0.5, 1, 1],
37092
- flipY: 1
37093
- }
37094
- };
37095
- const matHandle = world.allocSharedRef(
37096
- "MaterialAsset",
37097
- matPayload
37098
- );
37099
- cache.set(cacheKey, matHandle);
37100
- return matHandle;
37101
- }
37102
- function resolveAtlasOnlyMaterial(world, tileset, atlasIndex, lookup) {
37103
- const atlasGuid = tileset.atlases[atlasIndex];
37104
- if (atlasGuid === void 0) return toShared(0);
37105
- const atlas = resolveTilesetRuntime(world, atlasGuid, lookup);
37106
- if (!atlas.ok) return toShared(0);
37107
- const atlasHandle = atlas.value.handle;
37108
- const atlasId = unwrapHandle(atlasHandle);
37109
- const cacheKey = String(atlasId);
37110
- const cache = atlasOnlyMaterialCache.get(world) ?? /* @__PURE__ */ new Map();
37111
- atlasOnlyMaterialCache.set(world, cache);
37112
- const cached = cache.get(cacheKey);
37113
- if (cached !== void 0) return cached;
37114
- const matPayload = {
37115
- kind: "material",
37116
- passes: [
37117
- {
37118
- name: "Forward",
37119
- program: { module: "forgeax::sprite" },
37120
- renderState: {
37121
- ...{ blend: SPRITE_PREMULTIPLIED_ALPHA_BLEND },
37122
- tags: { LightMode: "Forward" },
37123
- queue: 3e3
37124
- }
37125
- }
37126
- ],
37127
- values: {
37128
- colorTint: [1, 1, 1, 1],
37129
- baseColorTexture: atlasHandle,
37130
- region: [0, 0, 1, 1],
37131
- pivotAndSize: [0.5, 0.5, 1, 1],
37132
- flipY: 1
37133
- }
37134
- };
37135
- const matHandle = world.allocSharedRef(
37136
- "MaterialAsset",
37137
- matPayload
37138
- );
37139
- cache.set(cacheKey, matHandle);
37140
- return matHandle;
37141
- }
37142
- function computeRegionUv(tileset, region, atlasIndex) {
37143
- const atlasSize = tileset.atlasSizes?.[atlasIndex];
37144
- const atlasWidth = Math.max(
37145
- 1,
37146
- atlasSize !== void 0 ? atlasSize.pixelWidth : tileset.columns * tileset.tileWidth
37147
- );
37148
- const atlasHeight = Math.max(
37149
- 1,
37150
- atlasSize !== void 0 ? atlasSize.pixelHeight : tileset.rows * tileset.tileHeight
37151
- );
37152
- const halfTexelU = 0.5 / atlasWidth;
37153
- const halfTexelV = 0.5 / atlasHeight;
37154
- return [
37155
- region.x / atlasWidth + halfTexelU,
37156
- region.y / atlasHeight + halfTexelV,
37157
- region.width / atlasWidth - 2 * halfTexelU,
37158
- region.height / atlasHeight - 2 * halfTexelV
37159
- ];
37160
- }
37161
- var SQRT1_2 = Math.SQRT1_2;
37162
- function effectivePivotYForTilemapFlip(pivotY, pivotX, flipV, flipDiagonal) {
37163
- const base = flipDiagonal ? pivotX : pivotY;
37164
- return flipV ? 1 - base : base;
37165
- }
37166
- function specFor(layerCols, chunkSize, cellIndex, packedTile, materialHandle, entry, atlasIndex) {
37167
- const cellX = cellIndex % layerCols;
37168
- const cellY = Math.floor(cellIndex / layerCols);
37169
- const chunkX = Math.floor(cellX / chunkSize);
37170
- const chunkY = Math.floor(cellY / chunkSize);
37171
- const chunksPerRow = Math.max(1, Math.ceil(layerCols / chunkSize));
37172
- const chunkIndex = chunkY * chunksPerRow + chunkX;
37173
- const { tileId } = decodeTileBits(packedTile);
37174
- return {
37175
- cellX,
37176
- cellY,
37177
- tileId,
37178
- packedTile,
37179
- materialHandle,
37180
- chunkIndex,
37181
- widthCells: entry.widthCells ?? 1,
37182
- heightCells: entry.heightCells ?? 1,
37183
- pivotX: entry.pivotX ?? 0.5,
37184
- pivotY: entry.pivotY ?? 0.5,
37185
- atlasIndex,
37186
- regionIndex: entry.regionIndex
37187
- };
37188
- }
37189
- function computeTileTrs(tilemap, spec, packedTile) {
37190
- const { flipH, flipV, flipDiagonal } = decodeTileBits(packedTile);
37191
- const basePivotForX = flipDiagonal ? spec.pivotY : spec.pivotX;
37192
- const effectivePivotX = flipH ? 1 - basePivotForX : basePivotForX;
37193
- const effectivePivotY = effectivePivotYForTilemapFlip(
37194
- spec.pivotY,
37195
- spec.pivotX,
37196
- flipV,
37197
- flipDiagonal
37198
- );
37199
- const tileSizeX = tilemap.tileSize[0] ?? 1;
37200
- const tileSizeY = tilemap.tileSize[1] ?? 1;
37201
- return {
37202
- posX: (spec.cellX + effectivePivotX + (0.5 - effectivePivotX) * spec.widthCells) * tileSizeX,
37203
- posY: (spec.cellY + effectivePivotY + (0.5 - effectivePivotY) * spec.heightCells) * tileSizeY,
37204
- scaleX: (flipH ? -1 : 1) * spec.widthCells * tileSizeX,
37205
- scaleY: (flipV ? -1 : 1) * spec.heightCells * tileSizeY,
37206
- quatZ: flipDiagonal ? SQRT1_2 : 0,
37207
- quatW: flipDiagonal ? SQRT1_2 : 1
37208
- };
37209
- }
37210
- function spawnDerivedRenderEntities(world, tilemap, layerEntity, layerOrder, spec, packedTile, sortScope = "layer") {
37211
- const { posX, posY, scaleX, scaleY, quatZ, quatW } = computeTileTrs(tilemap, spec, packedTile);
37212
- const layerValue = encodeTilemapLayerValue(layerOrder, spec.chunkIndex, sortScope);
37213
- return world.spawn(
37214
- {
37215
- component: Transform,
37216
- data: {
37217
- pos: [posX, posY, 0],
37218
- quat: [0, 0, quatZ, quatW],
37219
- scale: [scaleX, scaleY, 1]
37220
- }
37221
- },
37222
- { component: MeshFilter, data: { assetHandle: HANDLE_QUAD } },
37223
- {
37224
- component: MeshRenderer,
37225
- data: {
37226
- materials: [spec.materialHandle]
37227
- }
37228
- },
37229
- { component: Layer, data: { value: layerValue } },
37230
- { component: ChildOf, data: { parent: layerEntity } }
37231
- ).unwrap();
37232
- }
37233
- function spawnSpriteInstancesGroup(world, tilemap, tileset, layerEntity, layerOrder, chunkIndex, atlasIndex, materialHandle, cellSpecs) {
37234
- if (cellSpecs.length === 0) return void 0;
37235
- const N = cellSpecs.length;
37236
- const transforms = new Float32Array(N * 16);
37237
- const regions = new Float32Array(N * 4);
37238
- const tmpMat = mat4.create();
37239
- const tmpT = [0, 0, 0];
37240
- const tmpR = [0, 0, 0, 1];
37241
- const tmpS = [1, 1, 1];
37242
- const chunksPerRow = Math.max(1, Math.ceil(tilemap.cols / tilemap.chunkSize));
37243
- const chunkX = chunkIndex % chunksPerRow;
37244
- const chunkY = Math.floor(chunkIndex / chunksPerRow);
37245
- const chunkScaleX = tilemap.chunkSize * (tilemap.tileSize[0] ?? 1);
37246
- const chunkScaleY = tilemap.chunkSize * (tilemap.tileSize[1] ?? 1);
37247
- const chunkCenterX = (chunkX + 0.5) * chunkScaleX;
37248
- const chunkCenterY = (chunkY + 0.5) * chunkScaleY;
37249
- const invSX = chunkScaleX > 0 ? 1 / chunkScaleX : 1;
37250
- const invSY = chunkScaleY > 0 ? 1 / chunkScaleY : 1;
37251
- for (let i = 0; i < N; i++) {
37252
- const spec = cellSpecs[i];
37253
- const { posX, posY, scaleX, scaleY, quatZ, quatW } = computeTileTrs(
37254
- tilemap,
37255
- spec,
37256
- spec.packedTile
37257
- );
37258
- tmpT[0] = posX;
37259
- tmpT[1] = posY;
37260
- tmpT[2] = 0;
37261
- tmpR[0] = 0;
37262
- tmpR[1] = 0;
37263
- tmpR[2] = quatZ;
37264
- tmpR[3] = quatW;
37265
- tmpS[0] = scaleX;
37266
- tmpS[1] = scaleY;
37267
- tmpS[2] = 1;
37268
- mat4.compose(tmpMat, tmpT, tmpR, tmpS);
37269
- const dst = i * 16;
37270
- for (let c = 0; c < 4; c++) {
37271
- const base = c * 4;
37272
- const w3 = tmpMat[base + 3] ?? 0;
37273
- transforms[dst + base + 0] = ((tmpMat[base + 0] ?? 0) - chunkCenterX * w3) * invSX;
37274
- transforms[dst + base + 1] = ((tmpMat[base + 1] ?? 0) - chunkCenterY * w3) * invSY;
37275
- transforms[dst + base + 2] = tmpMat[base + 2] ?? 0;
37276
- transforms[dst + base + 3] = w3;
37277
- }
37278
- const region = tileset.regions[spec.regionIndex];
37279
- if (region !== void 0) {
37280
- const [u, v, w, h] = computeRegionUv(tileset, region, atlasIndex);
37281
- regions[i * 4 + 0] = u;
37282
- regions[i * 4 + 1] = v;
37283
- regions[i * 4 + 2] = w;
37284
- regions[i * 4 + 3] = h;
37285
- }
37286
- }
37287
- const layerValue = encodeTilemapLayerValue(layerOrder, chunkIndex, "layer");
37288
- return world.spawn(
37289
- {
37290
- component: Transform,
37291
- data: {
37292
- pos: [chunkCenterX, chunkCenterY, 0],
37293
- quat: [0, 0, 0, 1],
37294
- scale: [chunkScaleX, chunkScaleY, 1]
37295
- }
37296
- },
37297
- { component: MeshFilter, data: { assetHandle: HANDLE_QUAD } },
37298
- {
37299
- component: MeshRenderer,
37300
- data: {
37301
- materials: [materialHandle]
37302
- }
37303
- },
37304
- { component: SpriteInstances, data: { transforms, regions } },
37305
- { component: Layer, data: { value: layerValue } },
37306
- { component: ChildOf, data: { parent: layerEntity } }
37307
- ).unwrap();
37308
- }
37309
- function bucketTileLayer(world, layerEntity, parentEntity, lookup) {
37310
- const tilemapRes = world.get(parentEntity, Tilemap);
37311
- if (!tilemapRes.ok) return void 0;
37312
- const tilemap = tilemapRes.value;
37313
- const tilesetPayload = lookup(tilemap.tileset);
37314
- if (tilesetPayload === void 0 || "code" in tilesetPayload) return void 0;
37315
- if (tilesetPayload.kind !== "tileset") return void 0;
37316
- const tileset = tilesetPayload;
37317
- const layerRes = world.get(layerEntity, TileLayer);
37318
- if (!layerRes.ok) return void 0;
37319
- const layer = layerRes.value;
37320
- const tiles = layer.tiles;
37321
- const sortScope = decodeSortScope(layer.sortScope);
37322
- const useSpriteInstances = sortScope === "layer";
37323
- const specs = [];
37324
- for (let i = 0; i < tiles.length; i++) {
37325
- const packed = tiles[i] ?? 0;
37326
- if (packed === 0) continue;
37327
- const { tileId } = decodeTileBits(packed);
37328
- if (tileId === 0) continue;
37329
- const entry = tileset.tiles[tileId - 1];
37330
- if (entry === void 0) continue;
37331
- const region = tileset.regions[entry.regionIndex];
37332
- if (region === void 0) continue;
37333
- const atlasIndex = region.atlasIndex ?? 0;
37334
- const materialHandle = useSpriteInstances ? resolveAtlasOnlyMaterial(world, tileset, atlasIndex, lookup) : resolveTilesetMaterial(world, tileset, entry.regionIndex, lookup);
37335
- const spec = specFor(
37336
- tilemap.cols,
37337
- tilemap.chunkSize,
37338
- i,
37339
- packed,
37340
- materialHandle,
37341
- entry,
37342
- atlasIndex
37343
- );
37344
- specs.push(spec);
37345
- }
37346
- return {
37347
- tilemap,
37348
- layerOrder: layer.layerOrder,
37349
- sortScope,
37350
- tileset,
37351
- specs
37352
- };
37353
- }
37354
- function buildCameraFrustumPlanes(world) {
37355
- const query = world.query({ with: [Camera, Transform, GlobalTransform] }).unwrap();
37356
- let result = null;
37357
- for (const row of query) {
37358
- const camEntity = row.entity;
37359
- const camRes = world.get(camEntity, Camera);
37360
- const trRes = world.get(camEntity, GlobalTransform);
37361
- if (!camRes.ok || !trRes.ok) continue;
37362
- const cam = camRes.value;
37363
- const tr = trRes.value;
37364
- const { near, far } = cam;
37365
- if (near >= far) continue;
37366
- const proj = mat4.create();
37367
- if (cam.projection === CAMERA_PROJECTION_ORTHOGRAPHIC) {
37368
- mat4.orthographic(
37369
- proj,
37370
- cam.left,
37371
- cam.right,
37372
- cam.top,
37373
- cam.bottom,
37374
- near,
37375
- far
37376
- );
37377
- } else {
37378
- mat4.perspective(
37379
- proj,
37380
- cam.fov,
37381
- cam.aspect,
37382
- near,
37383
- far
37384
- );
37385
- }
37386
- const view = mat4.create();
37387
- mat4.invert(
37388
- view,
37389
- tr.world
37390
- );
37391
- const vp = mat4.create();
37392
- mat4.multiply(
37393
- vp,
37394
- proj,
37395
- view
37396
- );
37397
- const f = frustum.create();
37398
- frustum.fromViewProjection(f, vp);
37399
- result = f;
37400
- break;
37401
- }
37402
- return result;
37403
- }
37404
- function computeChunkStreamBounds(tilemap, specs) {
37405
- let minX = Number.MAX_VALUE;
37406
- let minY = Number.MAX_VALUE;
37407
- let maxX = -Number.MAX_VALUE;
37408
- let maxY = -Number.MAX_VALUE;
37409
- for (const spec of specs) {
37410
- const { posX, posY, scaleX, scaleY } = computeTileTrs(tilemap, spec, spec.packedTile);
37411
- const halfW = Math.abs(scaleX) * 0.5;
37412
- const halfH = Math.abs(scaleY) * 0.5;
37413
- const x0 = posX - halfW;
37414
- const x1 = posX + halfW;
37415
- const y0 = posY - halfH;
37416
- const y1 = posY + halfH;
37417
- if (x0 < minX) minX = x0;
37418
- if (y0 < minY) minY = y0;
37419
- if (x1 > maxX) maxX = x1;
37420
- if (y1 > maxY) maxY = y1;
37421
- }
37422
- return [minX, minY, -1, maxX, maxY, 1];
37423
- }
37424
- function purgeDerivedEntities(world, layerEntity) {
37425
- const r = world.get(layerEntity, Children);
37426
- if (!r.ok) return;
37427
- const snap = r.value.entities;
37428
- for (let i = 0; i < snap.length; i++) {
37429
- const e = snap[i];
37430
- if (e !== void 0) world.despawn(e);
37431
- }
37432
- }
37433
- function evictDeadPerCellStreamingCaches(work, world) {
37434
- const cache = streamingCache(world);
37435
- const aliveLayerKeys = /* @__PURE__ */ new Set();
37436
- for (const w of work) {
37437
- aliveLayerKeys.add(String(w.layerEntity));
37438
- }
37439
- const deadLayerKeys = /* @__PURE__ */ new Set();
37440
- for (const layerKey of cache.activeChunks.keys()) {
37441
- if (!aliveLayerKeys.has(layerKey)) deadLayerKeys.add(layerKey);
37442
- }
37443
- for (const layerKey of cache.layers.keys()) {
37444
- if (!aliveLayerKeys.has(layerKey)) deadLayerKeys.add(layerKey);
37445
- }
37446
- for (const deadKey of deadLayerKeys) {
37447
- const activeSet = cache.activeChunks.get(deadKey);
37448
- if (activeSet !== void 0) {
37449
- for (const chunkIdx of activeSet) {
37450
- cache.chunkEntities.delete(`${deadKey}:${chunkIdx}`);
37451
- }
37452
- cache.activeChunks.delete(deadKey);
37453
- }
37454
- cache.layers.delete(deadKey);
37455
- }
37456
- }
37457
- function tilemapChunkExtractSystem(world, lookup = () => void 0) {
37458
- const streaming = streamingCache(world);
37459
- const work = [];
37460
- const tileLayerQuery = world.query({ read: [TileLayer, ChildOf] }).unwrap();
37461
- for (const row of tileLayerQuery) {
37462
- const layer = row.get(TileLayer);
37463
- const parent = row.get(ChildOf).parent;
37464
- if (parent === null) continue;
37465
- work.push({
37466
- layerEntity: row.entity,
37467
- parentEntity: parent,
37468
- dirty: layer.dirty,
37469
- sortScopeRaw: layer.sortScope
37470
- });
37471
- }
37472
- evictDeadPerCellStreamingCaches(work, world);
37473
- let frustumPlanes;
37474
- for (const w of work) {
37475
- const layerKey = String(w.layerEntity);
37476
- const isStreaming = decodeSortScope(w.sortScopeRaw) === "per-cell";
37477
- if (!isStreaming) {
37478
- const childrenRes = world.get(w.layerEntity, Children);
37479
- const childCount = childrenRes.ok ? childrenRes.value.entities.length : 0;
37480
- if (childCount > 0 && w.dirty === 0) continue;
37481
- purgeDerivedEntities(world, w.layerEntity);
37482
- const bucket = bucketTileLayer(world, w.layerEntity, w.parentEntity, lookup);
37483
- if (bucket === void 0) continue;
37484
- const byChunkAtlas = /* @__PURE__ */ new Map();
37485
- for (const spec of bucket.specs) {
37486
- const key = (spec.chunkIndex & 1048575) << 16 | spec.atlasIndex & 65535;
37487
- const list = byChunkAtlas.get(key);
37488
- if (list === void 0) {
37489
- byChunkAtlas.set(key, [spec]);
37490
- } else {
37491
- list.push(spec);
37492
- }
37493
- }
37494
- for (const groupSpecs of byChunkAtlas.values()) {
37495
- const first = groupSpecs[0];
37496
- if (first === void 0) continue;
37497
- spawnSpriteInstancesGroup(
37498
- world,
37499
- bucket.tilemap,
37500
- bucket.tileset,
37501
- w.layerEntity,
37502
- bucket.layerOrder,
37503
- first.chunkIndex,
37504
- first.atlasIndex,
37505
- first.materialHandle,
37506
- groupSpecs
37507
- );
37508
- }
37509
- if (w.dirty !== 0) {
37510
- world.set(w.layerEntity, TileLayer, { dirty: 0 }).unwrap();
37511
- }
37512
- continue;
37513
- }
37514
- if (w.dirty !== 0 || !streaming.layers.has(layerKey)) {
37515
- const activeSet2 = streaming.activeChunks.get(layerKey);
37516
- if (activeSet2 !== void 0) {
37517
- for (const chunkIdx of activeSet2) {
37518
- const key = `${layerKey}:${chunkIdx}`;
37519
- const entities = streaming.chunkEntities.get(key);
37520
- if (entities !== void 0) {
37521
- for (const e of entities) world.despawn(e);
37522
- streaming.chunkEntities.delete(key);
37523
- }
37524
- }
37525
- activeSet2.clear();
37526
- }
37527
- streaming.layers.delete(layerKey);
37528
- const bucket = bucketTileLayer(world, w.layerEntity, w.parentEntity, lookup);
37529
- if (bucket !== void 0) {
37530
- const byChunkSpecs = /* @__PURE__ */ new Map();
37531
- for (const spec of bucket.specs) {
37532
- const list = byChunkSpecs.get(spec.chunkIndex);
37533
- if (list === void 0) {
37534
- byChunkSpecs.set(spec.chunkIndex, [spec]);
37535
- } else {
37536
- list.push(spec);
37537
- }
37538
- }
37539
- const byChunk = /* @__PURE__ */ new Map();
37540
- for (const [chunkIdx, specs] of byChunkSpecs) {
37541
- byChunk.set(chunkIdx, {
37542
- specs,
37543
- bounds: computeChunkStreamBounds(bucket.tilemap, specs)
37544
- });
37545
- }
37546
- streaming.layers.set(layerKey, {
37547
- byChunk,
37548
- tilemap: bucket.tilemap,
37549
- layerOrder: bucket.layerOrder,
37550
- sortScope: bucket.sortScope
37551
- });
37552
- }
37553
- if (w.dirty !== 0) {
37554
- world.set(w.layerEntity, TileLayer, { dirty: 0 }).unwrap();
37555
- }
37556
- }
37557
- const cache = streaming.layers.get(layerKey);
37558
- if (cache === void 0) continue;
37559
- if (frustumPlanes === void 0) {
37560
- frustumPlanes = buildCameraFrustumPlanes(world);
37561
- }
37562
- const activeSet = streaming.activeChunks.get(layerKey) ?? /* @__PURE__ */ new Set();
37563
- streaming.activeChunks.set(layerKey, activeSet);
37564
- const { tilemap } = cache;
37565
- for (const [chunkIdx, entry] of cache.byChunk) {
37566
- const { specs, bounds } = entry;
37567
- const visible = frustumPlanes === null || frustum.intersectsBox(frustumPlanes, bounds);
37568
- const wasActive = activeSet.has(chunkIdx);
37569
- if (visible && !wasActive) {
37570
- const spawned = [];
37571
- for (const spec of specs) {
37572
- const e = spawnDerivedRenderEntities(
37573
- world,
37574
- tilemap,
37575
- w.layerEntity,
37576
- cache.layerOrder,
37577
- spec,
37578
- spec.packedTile,
37579
- cache.sortScope
37580
- );
37581
- spawned.push(e);
37582
- }
37583
- streaming.chunkEntities.set(`${layerKey}:${chunkIdx}`, spawned);
37584
- activeSet.add(chunkIdx);
37585
- } else if (!visible && wasActive) {
37586
- const key = `${layerKey}:${chunkIdx}`;
37587
- const entities = streaming.chunkEntities.get(key);
37588
- if (entities !== void 0) {
37589
- for (const e of entities) world.despawn(e);
37590
- streaming.chunkEntities.delete(key);
37591
- }
37592
- activeSet.delete(chunkIdx);
37593
- }
37594
- }
37595
- }
37596
- }
37597
37312
 
37598
37313
  // src/assembly/analytic-fog-registration.ts
37599
37314
  function registerAnalyticFogPostProcess(renderSystem, source, candidate) {
@@ -40087,6 +39802,14 @@ function createRendererRecovery(deps) {
40087
39802
  device,
40088
39803
  adaptMipmapShaderModuleFactory2(internals.pack.createShaderModule),
40089
39804
  (world, pod) => {
39805
+ if ("resolveAsset" in world)
39806
+ return err(
39807
+ new AssetError({
39808
+ code: "asset-not-found",
39809
+ expected: "source-owned environment asset allocation",
39810
+ hint: "publish the environment asset from its source owner before GPU preparation"
39811
+ })
39812
+ );
40090
39813
  const handle = world.allocSharedRef(
40091
39814
  "EquirectAsset",
40092
39815
  pod
@@ -40583,974 +40306,6 @@ function collectRequiredFullscreenPostProcesses(features) {
40583
40306
  return Object.freeze([...entries.values()]);
40584
40307
  }
40585
40308
 
40586
- // src/targets/contracts.ts
40587
- var FORMAT_BYTES = {
40588
- rgba16float: 8,
40589
- rgba8unorm: 4,
40590
- "rgba8unorm-srgb": 4
40591
- };
40592
- function mipFactor(mipLevels) {
40593
- return mipLevels === "full" ? 4 / 3 : 1;
40594
- }
40595
- function estimatedBytes(descriptor) {
40596
- const layers = descriptor.shape === "cube" ? 6 : 1;
40597
- const samples = descriptor.sampleCount;
40598
- const depthBytes = descriptor.depth === void 0 ? 0 : 4;
40599
- return Math.ceil(
40600
- descriptor.width * descriptor.height * FORMAT_BYTES[descriptor.format] * layers * samples * mipFactor(descriptor.mipLevels) + descriptor.width * descriptor.height * depthBytes * layers * samples * mipFactor(descriptor.mipLevels)
40601
- );
40602
- }
40603
- function invalid4(field, value, expected) {
40604
- return {
40605
- ok: false,
40606
- error: new RenderTargetDescriptorInvalidError({ field, value, expected })
40607
- };
40608
- }
40609
- function admitRenderTargetDescriptor(descriptor, limits) {
40610
- if (!Number.isInteger(descriptor.width) || descriptor.width < 1) {
40611
- return invalid4("width", descriptor.width, "an integer >= 1");
40612
- }
40613
- if (!Number.isInteger(descriptor.height) || descriptor.height < 1) {
40614
- return invalid4("height", descriptor.height, "an integer >= 1");
40615
- }
40616
- if (descriptor.width > limits.maxTextureDimension2D || descriptor.height > limits.maxTextureDimension2D) {
40617
- return invalid4(
40618
- "extent",
40619
- { width: descriptor.width, height: descriptor.height },
40620
- `width and height <= ${limits.maxTextureDimension2D}`
40621
- );
40622
- }
40623
- if (descriptor.shape === "cube" && descriptor.width !== descriptor.height) {
40624
- return invalid4("shape", descriptor.shape, "cube width === height");
40625
- }
40626
- if (!limits.renderableFormats.includes(descriptor.format)) {
40627
- return {
40628
- ok: false,
40629
- error: new RenderTargetCapabilityMissingError({
40630
- operation: "create",
40631
- requested: descriptor.format,
40632
- capability: "renderableFormats",
40633
- actual: limits.renderableFormats.join(", ")
40634
- })
40635
- };
40636
- }
40637
- if (!limits.sampleCounts.includes(descriptor.sampleCount)) {
40638
- return {
40639
- ok: false,
40640
- error: new RenderTargetCapabilityMissingError({
40641
- operation: "create",
40642
- requested: String(descriptor.sampleCount),
40643
- capability: "sampleCounts",
40644
- actual: limits.sampleCounts.join(", ")
40645
- })
40646
- };
40647
- }
40648
- if (descriptor.depth !== void 0 && !limits.depthFormats.includes(descriptor.depth)) {
40649
- return {
40650
- ok: false,
40651
- error: new RenderTargetCapabilityMissingError({
40652
- operation: "create",
40653
- requested: descriptor.depth,
40654
- capability: "depthFormats",
40655
- actual: limits.depthFormats.join(", ")
40656
- })
40657
- };
40658
- }
40659
- const bytes2 = estimatedBytes(descriptor);
40660
- if (bytes2 > limits.maxBytesPerTarget) {
40661
- return invalid4("bytes", bytes2, `estimated allocation <= ${limits.maxBytesPerTarget}`);
40662
- }
40663
- return { ok: true, value: descriptor };
40664
- }
40665
-
40666
- // src/targets/owner.ts
40667
- function frozenDescriptor(descriptor) {
40668
- return Object.freeze({ ...descriptor });
40669
- }
40670
- function invalid5(operation, reason2, state, generation) {
40671
- return {
40672
- ok: false,
40673
- error: new RenderTargetStateInvalidError({ operation, reason: reason2, state, generation })
40674
- };
40675
- }
40676
- function token() {
40677
- return Object.freeze({});
40678
- }
40679
- function createRenderTargetOwner(options) {
40680
- const targets = /* @__PURE__ */ new WeakMap();
40681
- const requireTarget = (target5, operation) => {
40682
- const state = targets.get(target5);
40683
- if (state === void 0) return invalid5(operation, "foreign-renderer", "destroyed", 0);
40684
- if (state.rendererId !== options.rendererId) {
40685
- return invalid5(operation, "foreign-renderer", state.state, state.generation);
40686
- }
40687
- if (state.state === "destroyed") {
40688
- return invalid5(operation, "destroyed", state.state, state.generation);
40689
- }
40690
- return { ok: true, value: state };
40691
- };
40692
- return {
40693
- create(descriptor) {
40694
- const target5 = token();
40695
- targets.set(target5, {
40696
- target: target5,
40697
- rendererId: options.rendererId,
40698
- state: "uninitialized",
40699
- generation: 0,
40700
- descriptor: frozenDescriptor(descriptor),
40701
- candidate: void 0,
40702
- retiredGenerations: /* @__PURE__ */ new Set()
40703
- });
40704
- return { ok: true, value: target5 };
40705
- },
40706
- stage(target5, descriptor) {
40707
- const found = requireTarget(target5, "resize");
40708
- if (!found.ok) return found;
40709
- const state = found.value;
40710
- if (state.state === "rebuilding") {
40711
- return invalid5("resize", "generation-mismatch", state.state, state.generation);
40712
- }
40713
- const candidate = Object.freeze({
40714
- generation: state.state === "uninitialized" ? options.initialGeneration : state.generation,
40715
- descriptor: frozenDescriptor(descriptor ?? state.descriptor)
40716
- });
40717
- state.candidate = candidate;
40718
- state.state = "candidate";
40719
- return { ok: true, value: candidate };
40720
- },
40721
- promote(target5, generation) {
40722
- const found = requireTarget(target5, "resize");
40723
- if (!found.ok) return found;
40724
- const state = found.value;
40725
- if (state.candidate?.generation !== generation) {
40726
- return invalid5("resize", "generation-mismatch", state.state, state.generation);
40727
- }
40728
- state.descriptor = state.candidate.descriptor;
40729
- state.generation = generation;
40730
- state.candidate = void 0;
40731
- state.state = "active";
40732
- return { ok: true, value: void 0 };
40733
- },
40734
- rejectCandidate(target5, generation, stage) {
40735
- const found = requireTarget(target5, "resize");
40736
- if (!found.ok) return found;
40737
- const state = found.value;
40738
- if (state.candidate?.generation !== generation) {
40739
- return invalid5("resize", "generation-mismatch", state.state, state.generation);
40740
- }
40741
- state.candidate = void 0;
40742
- state.state = state.generation === 0 ? "uninitialized" : "active";
40743
- return {
40744
- ok: false,
40745
- error: new RenderTargetOperationFailedError({
40746
- operation: "resize",
40747
- stage,
40748
- generation,
40749
- cause: new Error(`candidate ${generation} failed during ${stage}`),
40750
- recovery: state.generation === 0 ? "retry" : "retain-last-known-good"
40751
- })
40752
- };
40753
- },
40754
- beginRecovery(target5, generation) {
40755
- const found = requireTarget(target5, "resize");
40756
- if (!found.ok) return found;
40757
- const state = found.value;
40758
- if (state.state !== "active" || generation <= state.generation) {
40759
- return invalid5("resize", "generation-mismatch", state.state, state.generation);
40760
- }
40761
- state.generation = generation;
40762
- state.candidate = void 0;
40763
- state.state = "rebuilding";
40764
- return { ok: true, value: void 0 };
40765
- },
40766
- finishRecovery(target5) {
40767
- const found = requireTarget(target5, "resize");
40768
- if (!found.ok) return found;
40769
- const state = found.value;
40770
- if (state.state !== "rebuilding") {
40771
- return invalid5("resize", "generation-mismatch", state.state, state.generation);
40772
- }
40773
- state.state = "uninitialized";
40774
- return { ok: true, value: void 0 };
40775
- },
40776
- retire(target5, generation) {
40777
- const found = requireTarget(target5, "destroy");
40778
- if (!found.ok) return found;
40779
- found.value.retiredGenerations.add(generation);
40780
- return { ok: true, value: void 0 };
40781
- },
40782
- destroy(target5) {
40783
- const state = targets.get(target5);
40784
- if (state === void 0) return invalid5("destroy", "foreign-renderer", "destroyed", 0);
40785
- if (state.rendererId !== options.rendererId) {
40786
- return invalid5("destroy", "foreign-renderer", state.state, state.generation);
40787
- }
40788
- if (state.state === "destroyed") return { ok: true, value: void 0 };
40789
- state.candidate = void 0;
40790
- state.state = "destroyed";
40791
- return { ok: true, value: void 0 };
40792
- },
40793
- inspect(target5) {
40794
- const found = requireTarget(target5, "inspect");
40795
- if (!found.ok) return found;
40796
- const state = found.value;
40797
- return {
40798
- ok: true,
40799
- value: Object.freeze({
40800
- token: state.target,
40801
- state: state.state,
40802
- generation: state.generation,
40803
- descriptor: state.descriptor,
40804
- ...state.candidate === void 0 ? {} : { candidate: state.candidate }
40805
- })
40806
- };
40807
- }
40808
- };
40809
- }
40810
-
40811
- // src/targets/readback.ts
40812
- function invalidTicket(ticket, reason2) {
40813
- return {
40814
- ok: false,
40815
- error: new RenderTargetStateInvalidError({
40816
- operation: "readback",
40817
- reason: reason2,
40818
- state: reason2 === "destroyed" ? "destroyed" : "active",
40819
- generation: ticket.deviceGeneration
40820
- })
40821
- };
40822
- }
40823
- function bindRenderTargetReadbackTicket(ticket, receipt) {
40824
- if (ticket.consumed) return invalidTicket(ticket, "destroyed");
40825
- if (ticket.frameId !== void 0) {
40826
- return invalidTicket(ticket, "generation-mismatch");
40827
- }
40828
- ticket.frameId = receipt.frameId;
40829
- ticket.deviceGeneration = receipt.deviceGeneration;
40830
- return { ok: true, value: void 0 };
40831
- }
40832
- function createRenderTargetReadbackTicket(target5, input) {
40833
- if (input.frameId !== void 0 && (!Number.isInteger(input.frameId) || input.frameId < 0) || !Number.isInteger(input.deviceGeneration) || input.deviceGeneration < 0 || !Number.isInteger(input.mipLevel) || input.mipLevel < 0 || !Number.isInteger(input.width) || input.width < 1 || !Number.isInteger(input.height) || input.height < 1 || !Number.isInteger(input.bytesPerPixel) || input.bytesPerPixel < 1) {
40834
- return {
40835
- ok: false,
40836
- error: new RenderTargetOperationFailedError({
40837
- operation: "readback",
40838
- stage: "copy",
40839
- generation: input.deviceGeneration,
40840
- cause: new Error("readback dimensions and identity must be non-negative integers"),
40841
- recovery: "retry"
40842
- })
40843
- };
40844
- }
40845
- const unalignedRowBytes = input.width * input.bytesPerPixel;
40846
- const bytesPerRow = Math.ceil(unalignedRowBytes / 256) * 256;
40847
- return {
40848
- ok: true,
40849
- value: {
40850
- target: target5,
40851
- frameId: input.frameId,
40852
- deviceGeneration: input.deviceGeneration,
40853
- mipLevel: input.mipLevel,
40854
- ...input.face === void 0 ? {} : { face: input.face },
40855
- width: input.width,
40856
- height: input.height,
40857
- bytesPerRow,
40858
- byteLength: bytesPerRow * input.height,
40859
- consumed: false
40860
- }
40861
- };
40862
- }
40863
- function completeRenderTargetReadback(ticket, receipt, bytes2) {
40864
- if (ticket.consumed) return invalidTicket(ticket, "destroyed");
40865
- if (ticket.frameId === void 0 || receipt.frameId !== ticket.frameId || receipt.deviceGeneration !== ticket.deviceGeneration) {
40866
- return invalidTicket(ticket, "generation-mismatch");
40867
- }
40868
- if (bytes2.byteLength !== ticket.byteLength) {
40869
- return {
40870
- ok: false,
40871
- error: new RenderTargetOperationFailedError({
40872
- operation: "readback",
40873
- stage: "copy",
40874
- generation: ticket.deviceGeneration,
40875
- cause: new Error(`expected ${ticket.byteLength} bytes, received ${bytes2.byteLength}`),
40876
- recovery: "retry"
40877
- })
40878
- };
40879
- }
40880
- ticket.consumed = true;
40881
- return {
40882
- ok: true,
40883
- value: {
40884
- bytes: bytes2,
40885
- frameId: ticket.frameId,
40886
- deviceGeneration: ticket.deviceGeneration,
40887
- mipLevel: ticket.mipLevel,
40888
- ...ticket.face === void 0 ? {} : { face: ticket.face }
40889
- }
40890
- };
40891
- }
40892
-
40893
- // src/assembly/render-target-host.ts
40894
- var DEFAULT_LIMITS = {
40895
- maxTextureDimension2D: 8192,
40896
- maxBytesPerTarget: 256 * 1024 * 1024,
40897
- renderableFormats: ["rgba16float", "rgba8unorm", "rgba8unorm-srgb"],
40898
- sampleCounts: [1, 4],
40899
- depthFormats: ["depth24plus-stencil8", "depth32float"]
40900
- };
40901
- function opaqueTicket() {
40902
- return Object.freeze({});
40903
- }
40904
- function bytesPerPixel(format) {
40905
- return format === "rgba16float" ? 8 : 4;
40906
- }
40907
- function mipCount(descriptor) {
40908
- return descriptor.mipLevels === 1 ? 1 : Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
40909
- }
40910
- function makePhysical(device, descriptor, generation) {
40911
- const layers = descriptor.shape === "cube" ? 6 : 1;
40912
- const usage = GPU_TEXTURE_USAGE_RENDER_ATTACHMENT | (descriptor.sampled ? GPU_TEXTURE_USAGE_TEXTURE_BINDING : 0) | (descriptor.readback ? GPU_TEXTURE_USAGE_COPY_SRC : 0);
40913
- const created = device.createTexture({
40914
- label: `render-target.${generation}`,
40915
- size: { width: descriptor.width, height: descriptor.height, depthOrArrayLayers: layers },
40916
- format: descriptor.format,
40917
- mipLevelCount: mipCount(descriptor),
40918
- // WebGPU forbids multisampled array textures. The cube is always the
40919
- // single-sample resolve destination; MSAA capture uses one depth=1 color
40920
- // texture per face below.
40921
- sampleCount: 1,
40922
- dimension: "2d",
40923
- usage,
40924
- viewFormats: void 0,
40925
- textureBindingViewDimension: descriptor.shape === "cube" ? "cube" : void 0
40926
- });
40927
- if (!created.ok)
40928
- return {
40929
- ok: false,
40930
- error: new RenderTargetOperationFailedError({
40931
- operation: "create",
40932
- stage: "allocation",
40933
- generation,
40934
- cause: created.error,
40935
- recovery: "retry"
40936
- })
40937
- };
40938
- const texture = created.value;
40939
- const view = device.createTextureView(texture, {
40940
- dimension: descriptor.shape,
40941
- baseMipLevel: 0,
40942
- mipLevelCount: mipCount(descriptor),
40943
- baseArrayLayer: 0,
40944
- arrayLayerCount: layers
40945
- });
40946
- if (!view.ok)
40947
- return {
40948
- ok: false,
40949
- error: new RenderTargetOperationFailedError({
40950
- operation: "create",
40951
- stage: "allocation",
40952
- generation,
40953
- cause: view.error,
40954
- recovery: "retry"
40955
- })
40956
- };
40957
- const mipViews = [];
40958
- for (let mip = 0; mip < mipCount(descriptor); mip += 1) {
40959
- const mipView = device.createTextureView(texture, {
40960
- dimension: descriptor.shape,
40961
- baseMipLevel: mip,
40962
- mipLevelCount: 1,
40963
- baseArrayLayer: 0,
40964
- arrayLayerCount: layers
40965
- });
40966
- if (!mipView.ok)
40967
- return {
40968
- ok: false,
40969
- error: new RenderTargetOperationFailedError({
40970
- operation: "create",
40971
- stage: "allocation",
40972
- generation,
40973
- cause: mipView.error,
40974
- recovery: "retry"
40975
- })
40976
- };
40977
- mipViews.push(mipView.value);
40978
- }
40979
- const resolveFaceViews = [];
40980
- for (let face = 0; face < layers; face += 1) {
40981
- const faceView = device.createTextureView(texture, {
40982
- dimension: "2d",
40983
- baseMipLevel: 0,
40984
- mipLevelCount: 1,
40985
- baseArrayLayer: face,
40986
- arrayLayerCount: 1
40987
- });
40988
- if (!faceView.ok)
40989
- return {
40990
- ok: false,
40991
- error: new RenderTargetOperationFailedError({
40992
- operation: "create",
40993
- stage: "allocation",
40994
- generation,
40995
- cause: faceView.error,
40996
- recovery: "retry"
40997
- })
40998
- };
40999
- resolveFaceViews.push(faceView.value);
41000
- }
41001
- const colorTextures = [];
41002
- const faceViews = [];
41003
- const depthTextures = [];
41004
- const depthViews = [];
41005
- if (descriptor.shape === "cube") {
41006
- for (let face = 0; face < layers; face += 1) {
41007
- const depth = device.createTexture({
41008
- label: `render-target.${generation}.depth.${face}`,
41009
- size: {
41010
- width: descriptor.width,
41011
- height: descriptor.height,
41012
- depthOrArrayLayers: descriptor.sampleCount === 4 ? 1 : layers
41013
- },
41014
- mipLevelCount: 1,
41015
- sampleCount: descriptor.sampleCount,
41016
- dimension: "2d",
41017
- format: "depth24plus-stencil8",
41018
- usage: GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
41019
- viewFormats: void 0,
41020
- textureBindingViewDimension: void 0
41021
- });
41022
- if (!depth.ok)
41023
- return {
41024
- ok: false,
41025
- error: new RenderTargetOperationFailedError({
41026
- operation: "create",
41027
- stage: "allocation",
41028
- generation,
41029
- cause: depth.error,
41030
- recovery: "retry"
41031
- })
41032
- };
41033
- const depthView = device.createTextureView(depth.value, {
41034
- dimension: "2d",
41035
- baseArrayLayer: descriptor.sampleCount === 4 ? 0 : face,
41036
- arrayLayerCount: 1
41037
- });
41038
- if (!depthView.ok)
41039
- return {
41040
- ok: false,
41041
- error: new RenderTargetOperationFailedError({
41042
- operation: "create",
41043
- stage: "allocation",
41044
- generation,
41045
- cause: depthView.error,
41046
- recovery: "retry"
41047
- })
41048
- };
41049
- depthTextures.push(depth.value);
41050
- depthViews.push(depthView.value);
41051
- }
41052
- }
41053
- if (descriptor.sampleCount === 4) {
41054
- for (let face = 0; face < layers; face += 1) {
41055
- const msaa = device.createTexture({
41056
- label: `render-target.${generation}.msaa.${face}`,
41057
- size: { width: descriptor.width, height: descriptor.height, depthOrArrayLayers: 1 },
41058
- format: descriptor.format,
41059
- mipLevelCount: 1,
41060
- sampleCount: 4,
41061
- dimension: "2d",
41062
- usage: GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
41063
- viewFormats: void 0,
41064
- textureBindingViewDimension: void 0
41065
- });
41066
- if (!msaa.ok)
41067
- return {
41068
- ok: false,
41069
- error: new RenderTargetOperationFailedError({
41070
- operation: "create",
41071
- stage: "allocation",
41072
- generation,
41073
- cause: msaa.error,
41074
- recovery: "retry"
41075
- })
41076
- };
41077
- const msaaView = device.createTextureView(msaa.value, {
41078
- dimension: "2d",
41079
- baseMipLevel: 0,
41080
- mipLevelCount: 1,
41081
- baseArrayLayer: 0,
41082
- arrayLayerCount: 1
41083
- });
41084
- if (!msaaView.ok)
41085
- return {
41086
- ok: false,
41087
- error: new RenderTargetOperationFailedError({
41088
- operation: "create",
41089
- stage: "allocation",
41090
- generation,
41091
- cause: msaaView.error,
41092
- recovery: "retry"
41093
- })
41094
- };
41095
- colorTextures.push(msaa.value);
41096
- faceViews.push(msaaView.value);
41097
- }
41098
- } else {
41099
- for (let face = 0; face < layers; face += 1) {
41100
- colorTextures.push(texture);
41101
- faceViews.push(resolveFaceViews[face] ?? view.value);
41102
- }
41103
- }
41104
- return {
41105
- ok: true,
41106
- value: {
41107
- generation,
41108
- descriptor,
41109
- texture,
41110
- view: view.value,
41111
- mipViews,
41112
- colorTextures,
41113
- faceViews,
41114
- depthTextures,
41115
- depthViews,
41116
- ...descriptor.sampleCount === 4 ? { resolveTexture: texture } : {},
41117
- resolveView: view.value,
41118
- resolveFaceViews
41119
- }
41120
- };
41121
- }
41122
- function destroyPhysical(device, physical) {
41123
- if (device === void 0 || physical === void 0) return;
41124
- const textures = /* @__PURE__ */ new Set();
41125
- textures.add(physical.texture);
41126
- if (physical.resolveTexture !== void 0) textures.add(physical.resolveTexture);
41127
- for (const texture of physical.colorTextures) textures.add(texture);
41128
- for (const texture of physical.depthTextures) textures.add(texture);
41129
- for (const texture of textures) device.destroyTexture(texture);
41130
- }
41131
- function createRenderTargetHost(options = {}) {
41132
- let disposed = false;
41133
- const limits = options.limits ?? DEFAULT_LIMITS;
41134
- const owner = createRenderTargetOwner({
41135
- rendererId: options.rendererId ?? /* @__PURE__ */ Symbol("renderer"),
41136
- initialGeneration: options.initialGeneration ?? 0
41137
- });
41138
- const targets = /* @__PURE__ */ new Set();
41139
- const staged = /* @__PURE__ */ new Set();
41140
- const activePhysical = /* @__PURE__ */ new WeakMap();
41141
- const candidatePhysical = /* @__PURE__ */ new WeakMap();
41142
- const sources = /* @__PURE__ */ new WeakMap();
41143
- const readbacks = /* @__PURE__ */ new WeakMap();
41144
- const readbackRecords = /* @__PURE__ */ new Set();
41145
- const currentGeneration = () => options.getGeneration?.() ?? options.initialGeneration ?? 0;
41146
- const stagePhysical = (target5, descriptor) => {
41147
- const stagedTarget = owner.stage(target5, descriptor);
41148
- if (!stagedTarget.ok) return stagedTarget;
41149
- const device = options.getDevice?.();
41150
- if (device === void 0) {
41151
- staged.add(target5);
41152
- return { ok: true, value: void 0 };
41153
- }
41154
- const physical = makePhysical(
41155
- device,
41156
- stagedTarget.value.descriptor,
41157
- stagedTarget.value.generation
41158
- );
41159
- if (!physical.ok) {
41160
- owner.rejectCandidate(target5, stagedTarget.value.generation, "allocation");
41161
- return physical;
41162
- }
41163
- candidatePhysical.set(target5, physical.value);
41164
- staged.add(target5);
41165
- return { ok: true, value: void 0 };
41166
- };
41167
- return Object.freeze({
41168
- owner: "renderer",
41169
- createRenderTarget(descriptor) {
41170
- if (disposed) {
41171
- return {
41172
- ok: false,
41173
- error: new RenderTargetStateInvalidError({
41174
- operation: "inspect",
41175
- reason: "destroyed",
41176
- state: "destroyed",
41177
- generation: currentGeneration()
41178
- })
41179
- };
41180
- }
41181
- const admitted = admitRenderTargetDescriptor(descriptor, limits);
41182
- if (!admitted.ok) return admitted;
41183
- const created = owner.create(admitted.value);
41184
- if (created.ok) targets.add(created.value);
41185
- return created;
41186
- },
41187
- resizeRenderTarget(target5, descriptor) {
41188
- const admitted = admitRenderTargetDescriptor(descriptor, limits);
41189
- if (!admitted.ok) return admitted;
41190
- return stagePhysical(target5, admitted.value);
41191
- },
41192
- createRenderTargetTextureSource(target5, sourceOptions) {
41193
- const inspected = owner.inspect(target5);
41194
- if (!inspected.ok) return inspected;
41195
- if (!inspected.value.descriptor.sampled) {
41196
- return {
41197
- ok: false,
41198
- error: new RenderTargetCapabilityMissingError({
41199
- operation: "source",
41200
- requested: "sampled=true",
41201
- capability: "sampled",
41202
- actual: "false"
41203
- })
41204
- };
41205
- }
41206
- if (sourceOptions.dimension !== inspected.value.descriptor.shape) {
41207
- return {
41208
- ok: false,
41209
- error: new RenderTargetDescriptorInvalidError({
41210
- field: "dimension",
41211
- value: sourceOptions.dimension,
41212
- expected: `dimension matches ${inspected.value.descriptor.shape}`
41213
- })
41214
- };
41215
- }
41216
- if (!Number.isInteger(sourceOptions.mipLevel) || sourceOptions.mipLevel < 0 || inspected.value.descriptor.mipLevels === 1 && sourceOptions.mipLevel !== 0) {
41217
- return {
41218
- ok: false,
41219
- error: new RenderTargetDescriptorInvalidError({
41220
- field: "mipLevel",
41221
- value: sourceOptions.mipLevel,
41222
- expected: "an admitted mip level for the target"
41223
- })
41224
- };
41225
- }
41226
- const binding = createRenderTargetMaterialSource(target5, inspected.value.descriptor, {
41227
- ...sourceOptions,
41228
- generation: inspected.value.generation
41229
- });
41230
- if (!binding.ok) return binding;
41231
- sources.set(binding.value.source, binding.value);
41232
- return { ok: true, value: binding.value.source };
41233
- },
41234
- resolveRenderTargetTextureSource(source) {
41235
- const binding = sources.get(source) ?? resolveRenderTargetMaterialSource(source);
41236
- if (binding === void 0) return void 0;
41237
- const physical = activePhysical.get(binding.target);
41238
- if (physical === void 0) return binding;
41239
- const view = physical.mipViews[binding.view.mipLevel] ?? (binding.shape === "cube" ? physical.view : physical.resolveView);
41240
- if (binding.generation !== physical.generation) return binding;
41241
- return { ...binding, textureView: view };
41242
- },
41243
- requestTargetReadback(target5, request) {
41244
- const inspected = owner.inspect(target5);
41245
- if (!inspected.ok) return inspected;
41246
- if (!inspected.value.descriptor.readback) {
41247
- return {
41248
- ok: false,
41249
- error: new RenderTargetCapabilityMissingError({
41250
- operation: "readback",
41251
- requested: "readback=true",
41252
- capability: "readback",
41253
- actual: "false"
41254
- })
41255
- };
41256
- }
41257
- if (!Number.isInteger(request.mipLevel) || request.mipLevel < 0) {
41258
- return {
41259
- ok: false,
41260
- error: new RenderTargetDescriptorInvalidError({
41261
- field: "mipLevel",
41262
- value: request.mipLevel,
41263
- expected: "a non-negative integer"
41264
- })
41265
- };
41266
- }
41267
- const mipCount2 = inspected.value.descriptor.mipLevels === 1 ? 1 : Math.floor(
41268
- Math.log2(
41269
- Math.max(inspected.value.descriptor.width, inspected.value.descriptor.height)
41270
- )
41271
- ) + 1;
41272
- if (request.mipLevel >= mipCount2) {
41273
- return {
41274
- ok: false,
41275
- error: new RenderTargetDescriptorInvalidError({
41276
- field: "mipLevel",
41277
- value: request.mipLevel,
41278
- expected: `mipLevel < ${mipCount2}`
41279
- })
41280
- };
41281
- }
41282
- if (request.face !== void 0 && (!Number.isInteger(request.face) || request.face < 0 || request.face > 5 || inspected.value.descriptor.shape !== "cube")) {
41283
- return {
41284
- ok: false,
41285
- error: new RenderTargetDescriptorInvalidError({
41286
- field: "face",
41287
- value: request.face,
41288
- expected: inspected.value.descriptor.shape === "cube" ? "an integer in [0, 5]" : "omitted for a 2d target"
41289
- })
41290
- };
41291
- }
41292
- const ticket = opaqueTicket();
41293
- const extent = resolveRenderTargetMipExtent(inspected.value.descriptor, request.mipLevel);
41294
- const buffer = options.getDevice?.()?.createBuffer({
41295
- label: `render-target-readback.${request.mipLevel}.${request.face ?? 0}`,
41296
- size: Math.ceil(extent.width * bytesPerPixel(inspected.value.descriptor.format) / 256) * 256 * extent.height,
41297
- usage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ,
41298
- mappedAtCreation: false
41299
- });
41300
- if (buffer !== void 0 && !buffer.ok) {
41301
- return {
41302
- ok: false,
41303
- error: new RenderTargetOperationFailedError({
41304
- operation: "readback",
41305
- stage: "allocation",
41306
- generation: inspected.value.generation,
41307
- cause: buffer.error,
41308
- recovery: "retry"
41309
- })
41310
- };
41311
- }
41312
- const internalTicket = createRenderTargetReadbackTicket(target5, {
41313
- deviceGeneration: inspected.value.generation,
41314
- mipLevel: request.mipLevel,
41315
- ...request.face === void 0 ? {} : { face: request.face },
41316
- width: extent.width,
41317
- height: extent.height,
41318
- bytesPerPixel: bytesPerPixel(inspected.value.descriptor.format)
41319
- });
41320
- if (!internalTicket.ok) return internalTicket;
41321
- const record = {
41322
- target: target5,
41323
- request,
41324
- ticket: internalTicket.value,
41325
- ...buffer === void 0 ? {} : { buffer: buffer.value },
41326
- encoded: false
41327
- };
41328
- readbacks.set(ticket, record);
41329
- readbackRecords.add(record);
41330
- return { ok: true, value: ticket };
41331
- },
41332
- async observeTargetReadbacks(receipt, tickets) {
41333
- const results = [];
41334
- for (const publicTicket of tickets) {
41335
- const record = readbacks.get(publicTicket);
41336
- if (record === void 0) {
41337
- return {
41338
- ok: false,
41339
- error: new RenderTargetStateInvalidError({
41340
- operation: "readback",
41341
- reason: "foreign-renderer",
41342
- state: "destroyed",
41343
- generation: receipt.deviceGeneration
41344
- })
41345
- };
41346
- }
41347
- const inspected = owner.inspect(record.target);
41348
- if (!inspected.ok) return inspected;
41349
- if (inspected.value.state !== "active") {
41350
- return {
41351
- ok: false,
41352
- error: new RenderTargetStateInvalidError({
41353
- operation: "readback",
41354
- reason: "uninitialized",
41355
- state: inspected.value.state,
41356
- generation: inspected.value.generation
41357
- })
41358
- };
41359
- }
41360
- if (inspected.value.generation !== receipt.deviceGeneration) {
41361
- return {
41362
- ok: false,
41363
- error: new RenderTargetStateInvalidError({
41364
- operation: "readback",
41365
- reason: "generation-mismatch",
41366
- state: inspected.value.state,
41367
- generation: inspected.value.generation
41368
- })
41369
- };
41370
- }
41371
- const bound = bindRenderTargetReadbackTicket(record.ticket, receipt);
41372
- if (!bound.ok) return bound;
41373
- let bytes2 = new Uint8Array(record.ticket.byteLength);
41374
- if (record.buffer !== void 0 && typeof record.buffer.mapAsync === "function") {
41375
- const mapped = await record.buffer.mapAsync(1);
41376
- if (!mapped.ok) {
41377
- return {
41378
- ok: false,
41379
- error: new RenderTargetOperationFailedError({
41380
- operation: "readback",
41381
- stage: "copy",
41382
- generation: receipt.deviceGeneration,
41383
- cause: mapped.error,
41384
- recovery: "retry"
41385
- })
41386
- };
41387
- }
41388
- const range = mapped.value.getMappedRange();
41389
- if (!range.ok) {
41390
- return {
41391
- ok: false,
41392
- error: new RenderTargetOperationFailedError({
41393
- operation: "readback",
41394
- stage: "copy",
41395
- generation: receipt.deviceGeneration,
41396
- cause: range.error,
41397
- recovery: "retry"
41398
- })
41399
- };
41400
- }
41401
- bytes2 = new Uint8Array(range.value.slice(0));
41402
- mapped.value.unmap();
41403
- }
41404
- const completed = completeRenderTargetReadback(record.ticket, receipt, bytes2);
41405
- if (!completed.ok) return completed;
41406
- results.push({
41407
- ticket: publicTicket,
41408
- bytes: completed.value.bytes,
41409
- frameId: completed.value.frameId,
41410
- deviceGeneration: completed.value.deviceGeneration,
41411
- mipLevel: completed.value.mipLevel,
41412
- ...completed.value.face === void 0 ? {} : { face: completed.value.face },
41413
- bytesPerRow: record.ticket.bytesPerRow,
41414
- byteLength: record.ticket.byteLength
41415
- });
41416
- }
41417
- return { ok: true, value: Object.freeze(results) };
41418
- },
41419
- destroyRenderTarget(target5) {
41420
- const destroyed = owner.destroy(target5);
41421
- if (destroyed.ok) {
41422
- destroyPhysical(options.getDevice?.(), activePhysical.get(target5));
41423
- destroyPhysical(options.getDevice?.(), candidatePhysical.get(target5));
41424
- activePhysical.delete(target5);
41425
- candidatePhysical.delete(target5);
41426
- for (const record of readbackRecords) {
41427
- if (record.target !== target5) continue;
41428
- if (record.buffer !== void 0) options.getDevice?.()?.destroyBuffer(record.buffer);
41429
- readbacks.delete(record.ticket);
41430
- readbackRecords.delete(record);
41431
- }
41432
- targets.delete(target5);
41433
- }
41434
- return destroyed;
41435
- },
41436
- beginFrame() {
41437
- if (disposed) return;
41438
- for (const target5 of targets) {
41439
- const inspected = owner.inspect(target5);
41440
- if (!inspected.ok || inspected.value.state === "active" || inspected.value.state === "candidate") {
41441
- continue;
41442
- }
41443
- stagePhysical(target5);
41444
- }
41445
- },
41446
- onFrameSubmitted(completed = Promise.resolve({ ok: true, value: void 0 })) {
41447
- if (disposed) return;
41448
- const submittedTargets = [...staged];
41449
- staged.clear();
41450
- void completed.then((result) => {
41451
- for (const target5 of submittedTargets) {
41452
- const candidate = owner.inspect(target5);
41453
- if (!candidate.ok || candidate.value.candidate === void 0) continue;
41454
- if (!result.ok) {
41455
- owner.rejectCandidate(target5, candidate.value.candidate.generation, "submit");
41456
- destroyPhysical(options.getDevice?.(), candidatePhysical.get(target5));
41457
- candidatePhysical.delete(target5);
41458
- continue;
41459
- }
41460
- if (options.canPromoteTarget?.(target5) === false) {
41461
- staged.add(target5);
41462
- continue;
41463
- }
41464
- const generation = candidate.value.candidate.generation;
41465
- const physical = candidatePhysical.get(target5);
41466
- if (physical === void 0) {
41467
- owner.rejectCandidate(target5, generation, "submit");
41468
- continue;
41469
- }
41470
- const promoted = owner.promote(target5, generation);
41471
- if (!promoted.ok) {
41472
- destroyPhysical(options.getDevice?.(), physical);
41473
- candidatePhysical.delete(target5);
41474
- continue;
41475
- }
41476
- const previous = activePhysical.get(target5);
41477
- activePhysical.set(target5, physical);
41478
- candidatePhysical.delete(target5);
41479
- destroyPhysical(options.getDevice?.(), previous);
41480
- }
41481
- });
41482
- },
41483
- getPhysicalTarget(target5) {
41484
- return candidatePhysical.get(target5) ?? activePhysical.get(target5);
41485
- },
41486
- encodePendingReadbacks(encoder, faces) {
41487
- for (const record of readbackRecords) {
41488
- if (record.encoded || record.buffer === void 0) continue;
41489
- if (faces !== void 0 && record.ticket.face !== void 0 && !faces.includes(record.ticket.face)) {
41490
- continue;
41491
- }
41492
- const candidate = candidatePhysical.get(record.target);
41493
- const physical = faces !== void 0 && candidate !== void 0 && record.ticket.face !== void 0 && faces.includes(record.ticket.face) ? candidate : activePhysical.get(record.target);
41494
- if (physical === void 0) continue;
41495
- const source = physical.resolveTexture ?? physical.texture;
41496
- encoder.copyTextureToBuffer(
41497
- {
41498
- texture: source,
41499
- mipLevel: record.ticket.mipLevel,
41500
- origin: { x: 0, y: 0, z: record.ticket.face ?? 0 }
41501
- },
41502
- {
41503
- buffer: record.buffer,
41504
- bytesPerRow: record.ticket.bytesPerRow,
41505
- rowsPerImage: record.ticket.height
41506
- },
41507
- [record.ticket.width, record.ticket.height, 1]
41508
- );
41509
- record.encoded = true;
41510
- }
41511
- },
41512
- recover() {
41513
- if (disposed) return;
41514
- const generation = currentGeneration();
41515
- for (const target5 of targets) {
41516
- const inspected = owner.inspect(target5);
41517
- if (!inspected.ok || inspected.value.state !== "active") continue;
41518
- destroyPhysical(options.getDevice?.(), activePhysical.get(target5));
41519
- destroyPhysical(options.getDevice?.(), candidatePhysical.get(target5));
41520
- activePhysical.delete(target5);
41521
- candidatePhysical.delete(target5);
41522
- for (const record of readbackRecords) {
41523
- if (record.target !== target5) continue;
41524
- if (record.buffer !== void 0) options.getDevice?.()?.destroyBuffer(record.buffer);
41525
- readbacks.delete(record.ticket);
41526
- readbackRecords.delete(record);
41527
- }
41528
- const begun = owner.beginRecovery(target5, generation);
41529
- if (begun.ok) owner.finishRecovery(target5);
41530
- }
41531
- },
41532
- dispose() {
41533
- disposed = true;
41534
- for (const target5 of [...targets]) {
41535
- destroyPhysical(options.getDevice?.(), activePhysical.get(target5));
41536
- destroyPhysical(options.getDevice?.(), candidatePhysical.get(target5));
41537
- for (const record of readbackRecords) {
41538
- if (record.target !== target5) continue;
41539
- if (record.buffer !== void 0) options.getDevice?.()?.destroyBuffer(record.buffer);
41540
- readbacks.delete(record.ticket);
41541
- readbackRecords.delete(record);
41542
- }
41543
- activePhysical.delete(target5);
41544
- candidatePhysical.delete(target5);
41545
- owner.destroy(target5);
41546
- }
41547
- targets.clear();
41548
- staged.clear();
41549
- readbackRecords.clear();
41550
- }
41551
- });
41552
- }
41553
-
41554
40309
  // src/assembly/renderer-feature-inspection.ts
41555
40310
  function projectRendererFeatureInspection(featureHost) {
41556
40311
  const featureDiagnostics = featureHost?.diagnostics() ?? Object.freeze([]);
@@ -41967,6 +40722,7 @@ function createSkinPaletteAllocator(device, maxBindingSize, useStorageBuffer = t
41967
40722
  if (allocation === void 0) pendingDirty.set(identity, dirty);
41968
40723
  }
41969
40724
  function releasePersistentSlice(identity) {
40725
+ frameSeenPersistent.delete(identity);
41970
40726
  const allocation = persistent.get(identity);
41971
40727
  persistent.delete(identity);
41972
40728
  pendingDirty.delete(identity);
@@ -44249,11 +43005,11 @@ async function buildReadyWebGPU(rhiDevice, rendererScope, getShader, gpuStore, a
44249
43005
  }
44250
43006
  try {
44251
43007
  getOrBuildPipeline(spec, pipelineDeviceProvider, pipelineCache, modules);
44252
- } catch (err57) {
44253
- if (err57 instanceof PipelineSpecError) throw err57;
43008
+ } catch (err58) {
43009
+ if (err58 instanceof PipelineSpecError) throw err58;
44254
43010
  throw new PipelineSpecError({
44255
43011
  code: "pipeline-build-failed",
44256
- detail: { cause: err57 },
43012
+ detail: { cause: err58 },
44257
43013
  hint: `Boot-time SPEC_CONST pre-warm failed for shader '${spec.shader.id}'; inspect gpuMessage on the cause`
44258
43014
  });
44259
43015
  }
@@ -44407,11 +43163,11 @@ async function buildReadyWebGPU(rhiDevice, rendererScope, getShader, gpuStore, a
44407
43163
  pipelineCache,
44408
43164
  modules
44409
43165
  );
44410
- } catch (err57) {
44411
- if (err57 instanceof PipelineSpecError) throw err57;
43166
+ } catch (err58) {
43167
+ if (err58 instanceof PipelineSpecError) throw err58;
44412
43168
  throw new PipelineSpecError({
44413
43169
  code: "pipeline-build-failed",
44414
- detail: { cause: err57 },
43170
+ detail: { cause: err58 },
44415
43171
  hint: "createRenderPipeline (fxaa fullscreen) failed; inspect gpuMessage"
44416
43172
  });
44417
43173
  }
@@ -44666,11 +43422,11 @@ async function buildReadyWebGPU(rhiDevice, rendererScope, getShader, gpuStore, a
44666
43422
  bloomDownsamplePipelineHandle,
44667
43423
  () => void 0
44668
43424
  );
44669
- } catch (err57) {
44670
- if (err57 instanceof PipelineSpecError) throw err57;
43425
+ } catch (err58) {
43426
+ if (err58 instanceof PipelineSpecError) throw err58;
44671
43427
  throw new PipelineSpecError({
44672
43428
  code: "pipeline-build-failed",
44673
- detail: { cause: err57 },
43429
+ detail: { cause: err58 },
44674
43430
  hint: "createRenderPipeline (bloom-downsample fullscreen) failed; inspect gpuMessage"
44675
43431
  });
44676
43432
  }
@@ -44776,11 +43532,11 @@ async function buildReadyWebGPU(rhiDevice, rendererScope, getShader, gpuStore, a
44776
43532
  bloomUpsamplePipelineHandle,
44777
43533
  () => void 0
44778
43534
  );
44779
- } catch (err57) {
44780
- if (err57 instanceof PipelineSpecError) throw err57;
43535
+ } catch (err58) {
43536
+ if (err58 instanceof PipelineSpecError) throw err58;
44781
43537
  throw new PipelineSpecError({
44782
43538
  code: "pipeline-build-failed",
44783
- detail: { cause: err57 },
43539
+ detail: { cause: err58 },
44784
43540
  hint: "createRenderPipeline (bloom-upsample fullscreen) failed; inspect gpuMessage"
44785
43541
  });
44786
43542
  }
@@ -44881,11 +43637,11 @@ async function buildReadyWebGPU(rhiDevice, rendererScope, getShader, gpuStore, a
44881
43637
  bloomCompositePipelineHandle,
44882
43638
  () => void 0
44883
43639
  );
44884
- } catch (err57) {
44885
- if (err57 instanceof PipelineSpecError) throw err57;
43640
+ } catch (err58) {
43641
+ if (err58 instanceof PipelineSpecError) throw err58;
44886
43642
  throw new PipelineSpecError({
44887
43643
  code: "pipeline-build-failed",
44888
- detail: { cause: err57 },
43644
+ detail: { cause: err58 },
44889
43645
  hint: "createRenderPipeline (bloom-composite fullscreen) failed; inspect gpuMessage"
44890
43646
  });
44891
43647
  }
@@ -45183,11 +43939,11 @@ async function buildReadyWebGPU(rhiDevice, rendererScope, getShader, gpuStore, a
45183
43939
  pipelineCache,
45184
43940
  { ...baseModules, fragmentEntryPoint: "fs_ssao_calc" }
45185
43941
  );
45186
- } catch (err57) {
45187
- if (err57 instanceof PipelineSpecError) throw err57;
43942
+ } catch (err58) {
43943
+ if (err58 instanceof PipelineSpecError) throw err58;
45188
43944
  throw new PipelineSpecError({
45189
43945
  code: "pipeline-build-failed",
45190
- detail: { cause: err57 },
43946
+ detail: { cause: err58 },
45191
43947
  hint: "createRenderPipeline (ssao-calc fullscreen) failed; inspect gpuMessage"
45192
43948
  });
45193
43949
  }
@@ -45218,11 +43974,11 @@ async function buildReadyWebGPU(rhiDevice, rendererScope, getShader, gpuStore, a
45218
43974
  pipelineCache,
45219
43975
  { ...baseModules, fragmentEntryPoint: "fs_ssao_blur" }
45220
43976
  );
45221
- } catch (err57) {
45222
- if (err57 instanceof PipelineSpecError) throw err57;
43977
+ } catch (err58) {
43978
+ if (err58 instanceof PipelineSpecError) throw err58;
45223
43979
  throw new PipelineSpecError({
45224
43980
  code: "pipeline-build-failed",
45225
- detail: { cause: err57 },
43981
+ detail: { cause: err58 },
45226
43982
  hint: "createRenderPipeline (ssao-blur fullscreen) failed; inspect gpuMessage"
45227
43983
  });
45228
43984
  }
@@ -45621,6 +44377,28 @@ function createRendererObservationCaptureOwner(fireError) {
45621
44377
  };
45622
44378
  return owner;
45623
44379
  }
44380
+ var PARTICLE_MESH_DEFAULTS = {
44381
+ position: [0, 0, 0],
44382
+ normal: [0, 0, 1],
44383
+ uv: [0, 0],
44384
+ tangent: [1, 0, 0, 1],
44385
+ uv1: [0, 0],
44386
+ color: [1, 1, 1, 1]
44387
+ };
44388
+ var PARTICLE_MESH_GEOMETRY = deriveVertexLayoutProjection(
44389
+ Object.fromEntries(Object.keys(PARTICLE_MESH_DEFAULTS).map((key) => [key, new Float32Array()]))
44390
+ );
44391
+ var PARTICLE_MESH_VERTEX_BUFFER = {
44392
+ arrayStride: PARTICLE_MESH_GEOMETRY.arrayStride,
44393
+ stepMode: "vertex",
44394
+ attributes: PARTICLE_MESH_GEOMETRY.attributes.map(({ key, shaderLocation, offset: offset2, format }) => ({
44395
+ shaderLocation: key === "color" ? 14 : key === "uv1" ? 15 : shaderLocation,
44396
+ offset: offset2,
44397
+ format
44398
+ }))
44399
+ };
44400
+
44401
+ // src/assembly/webgpu-vertex-layouts.ts
45624
44402
  var FLOAT32_COMPONENT_COUNT = {
45625
44403
  float32x2: 2,
45626
44404
  float32x3: 3,
@@ -45687,13 +44465,6 @@ var MESH_GEOMETRY_MATERIAL_INSTANCE_SPEC = {
45687
44465
  };
45688
44466
  var PREPARED_INSTANCE_VERTEX_ATTRS = buildMeshAttributeMapForUvSets(2);
45689
44467
  var PREPARED_MATERIAL_INSTANCE_VERTEX_ATTRS = SKIN_VERTEX_ATTRIBUTE_MAP;
45690
- function canonicalMeshVertexBufferLayout() {
45691
- const [buffer] = toGpuVertexBufferLayouts(deriveVertexBufferLayout(DEFAULT_VERTEX_ATTRIBUTE_MAP));
45692
- if (buffer === void 0) {
45693
- throw new Error("The canonical mesh vertex layout must contain one vertex buffer");
45694
- }
45695
- return { ...buffer, stepMode: "vertex" };
45696
- }
45697
44468
  var POSITION_SIZE_COLOR_INSTANCE_VERTEX_BUFFERS = [
45698
44469
  defineFeatureVertexBuffer(POSITION_SIZE_COLOR_INSTANCE_SPEC)
45699
44470
  ];
@@ -45704,7 +44475,7 @@ var TOPOLOGY_SEGMENT_INSTANCE_VERTEX_BUFFERS = [
45704
44475
  defineFeatureVertexBuffer(TOPOLOGY_SEGMENT_INSTANCE_SPEC)
45705
44476
  ];
45706
44477
  var MESH_GEOMETRY_MATERIAL_INSTANCE_VERTEX_BUFFERS = [
45707
- canonicalMeshVertexBufferLayout(),
44478
+ PARTICLE_MESH_VERTEX_BUFFER,
45708
44479
  defineFeatureVertexBuffer(MESH_GEOMETRY_MATERIAL_INSTANCE_SPEC)
45709
44480
  ];
45710
44481
  var PREPARED_MATERIAL_VERTEX_LAYOUTS = /* @__PURE__ */ new Set([
@@ -45796,12 +44567,13 @@ function resolveWebGPUVertexBufferLayouts(options) {
45796
44567
  }
45797
44568
 
45798
44569
  // src/assembly/webgpu-renderer.ts
45799
- var nextDerivedSystemId = 0;
45800
44570
  async function tryCreateWebGPURenderer2(canvas, options, pack, bundler) {
45801
44571
  return tryCreateWebGPURenderer(canvas, options, pack, bundler, makeWebGPURenderer);
45802
44572
  }
45803
44573
  async function makeWebGPURenderer(internals) {
44574
+ let publicationTargets;
45804
44575
  let disposed = false;
44576
+ const publicationReceiver = internals.options?.publicationSource === void 0 ? void 0 : new RenderPublicationReceiver(internals.options.publicationSource);
45805
44577
  const observeTiming = observeGpuPassTimingDisabled;
45806
44578
  const frameContinuations = /* @__PURE__ */ new Set();
45807
44579
  let recoveryAttempt = 0;
@@ -46015,11 +44787,10 @@ async function makeWebGPURenderer(internals) {
46015
44787
  const getShader = () => {
46016
44788
  const state = candidateShaderState ?? activeShaderState;
46017
44789
  if (state.shaderInstance === null) {
46018
- const bundler = internals.bundler;
46019
- const explicitUrl = bundler?.shaderManifestUrl;
46020
- state.shaderInstance = new ShaderCatalog({
44790
+ const activeCatalog = activeShaderState.shaderInstance;
44791
+ state.shaderInstance = state === candidateShaderState && activeCatalog !== null ? activeCatalog.forkForDevice(getShaderModuleAdapter()) : new ShaderCatalog({
46021
44792
  device: getShaderModuleAdapter(),
46022
- manifestUrl: bundler !== void 0 && "shaderManifestUrl" in bundler ? explicitUrl : "/shaders/manifest.json"
44793
+ manifestUrl: internals.bundler !== void 0 && "shaderManifestUrl" in internals.bundler ? internals.bundler.shaderManifestUrl : "/shaders/manifest.json"
46023
44794
  });
46024
44795
  }
46025
44796
  return state.shaderInstance;
@@ -46096,7 +44867,8 @@ async function makeWebGPURenderer(internals) {
46096
44867
  gpuStore.configureGpuDevice(
46097
44868
  internals.device,
46098
44869
  packShaderFactory,
46099
- (world, pod) => {
44870
+ (world, pod, source) => {
44871
+ if ("resolveAsset" in world) return ok(source);
46100
44872
  const handle = world.allocSharedRef("EquirectAsset", pod);
46101
44873
  return ok(handle);
46102
44874
  },
@@ -47316,7 +46088,6 @@ async function makeWebGPURenderer(internals) {
47316
46088
  currentGeneration: () => activeDeviceScope.generation,
47317
46089
  renderSystem
47318
46090
  });
47319
- const derivedSystemNames = /* @__PURE__ */ new Map();
47320
46091
  const transformReleases = /* @__PURE__ */ new Map();
47321
46092
  const attachmentOwner = {};
47322
46093
  let frameId = 0;
@@ -47352,6 +46123,13 @@ async function makeWebGPURenderer(internals) {
47352
46123
  renderSystem.setSurfaceDynamicInput(frame);
47353
46124
  },
47354
46125
  attach(world) {
46126
+ if (publicationReceiver !== void 0)
46127
+ return err(
46128
+ new RenderPublicationError({
46129
+ reason: "identity",
46130
+ subject: "publication Renderer has no World attachment"
46131
+ })
46132
+ );
47355
46133
  const attached = this.attachScene(world);
47356
46134
  if (!attached.ok) {
47357
46135
  return err(new RendererContractFailureError("attach", attached.error.hint));
@@ -47368,12 +46146,12 @@ async function makeWebGPURenderer(internals) {
47368
46146
  requestTargetReadback: (target5, request) => renderTargetHost.requestTargetReadback(target5, request),
47369
46147
  destroyRenderTarget: (target5) => renderTargetHost.destroyRenderTarget(target5),
47370
46148
  setProfile(profile) {
47371
- const invalid6 = validateRenderProfile(profile);
47372
- if (invalid6 !== void 0) {
46149
+ const invalid4 = validateRenderProfile(profile);
46150
+ if (invalid4 !== void 0) {
47373
46151
  return err(
47374
46152
  new RendererOperationError("frame-input-invalid", {
47375
46153
  operation: "set-profile",
47376
- cause: new RendererContractFailureError("draw", invalid6)
46154
+ cause: new RendererContractFailureError("draw", invalid4)
47377
46155
  })
47378
46156
  );
47379
46157
  }
@@ -47562,23 +46340,7 @@ async function makeWebGPURenderer(internals) {
47562
46340
  }
47563
46341
  if (attachedWorlds.has(world)) return ok(void 0);
47564
46342
  try {
47565
- const releaseTransforms = registerPropagateTransforms(world);
47566
- const derivedSystemName = `renderDerived:${++nextDerivedSystemId}`;
47567
- const derived = world.addSystem(Update, {
47568
- name: derivedSystemName,
47569
- queries: [],
47570
- fn: (world2) => {
47571
- tilemapChunkExtractSystem(world2, (guid) => assets.lookup(guid));
47572
- const glyphResult = glyphTextLayoutSystem(world2, gpuStore);
47573
- if (!glyphResult.ok) throw glyphResult.error;
47574
- }
47575
- });
47576
- if (!derived.ok) {
47577
- releaseTransforms();
47578
- throw new Error(`failed to register ${derivedSystemName}: ${derived.error.code}`);
47579
- }
47580
- transformReleases.set(world, releaseTransforms);
47581
- derivedSystemNames.set(world, derivedSystemName);
46343
+ transformReleases.set(world, registerRenderSourceSystems(world, assets, gpuStore));
47582
46344
  attachedWorlds.add(world);
47583
46345
  return ok(void 0);
47584
46346
  } catch (cause) {
@@ -47609,11 +46371,6 @@ async function makeWebGPURenderer(internals) {
47609
46371
  }
47610
46372
  }
47611
46373
  renderSystem.detachScene(world);
47612
- const derivedSystemName = derivedSystemNames.get(world);
47613
- if (derivedSystemName !== void 0) {
47614
- world.removeSystem(Update, derivedSystemName);
47615
- derivedSystemNames.delete(world);
47616
- }
47617
46374
  transformReleases.get(world)?.();
47618
46375
  transformReleases.delete(world);
47619
46376
  },
@@ -47797,8 +46554,26 @@ async function makeWebGPURenderer(internals) {
47797
46554
  },
47798
46555
  draw(worldsOrRequest, options) {
47799
46556
  const isFrameRequest = !Array.isArray(worldsOrRequest);
47800
- const frameRequest = isFrameRequest ? worldsOrRequest : void 0;
47801
- const worlds = frameRequest !== void 0 ? frameRequest.leases.map((lease) => attachedLeases.get(lease)).filter((world) => world !== void 0) : worldsOrRequest;
46557
+ const publicationRequest = isFrameRequest && "publication" in worldsOrRequest ? worldsOrRequest : void 0;
46558
+ const frameRequest = isFrameRequest && publicationRequest === void 0 ? worldsOrRequest : void 0;
46559
+ let publication;
46560
+ if (publicationRequest !== void 0) {
46561
+ if (publicationReceiver === void 0)
46562
+ return err(
46563
+ new RenderPublicationError({
46564
+ reason: "identity",
46565
+ subject: "RendererOptions.publicationSource"
46566
+ })
46567
+ );
46568
+ } else if (publicationReceiver !== void 0) {
46569
+ return err(
46570
+ new RenderPublicationError({
46571
+ reason: "identity",
46572
+ subject: "a publication-bound renderer cannot consume local World leases"
46573
+ })
46574
+ );
46575
+ }
46576
+ const worlds = frameRequest !== void 0 ? frameRequest.leases.map((lease) => attachedLeases.get(lease)).filter((world) => world !== void 0) : publicationRequest === void 0 ? worldsOrRequest : [];
47802
46577
  const readLeases = frameRequest !== void 0 ? frameRequest.leases : worlds.map((world) => leasesByWorld.get(world)).every((lease) => lease !== void 0) ? worlds.map((world) => leasesByWorld.get(world)) : void 0;
47803
46578
  const physicsFrameError = derivedPhysicsFrameError(worlds);
47804
46579
  if (physicsFrameError !== void 0) return err(physicsFrameError);
@@ -47833,7 +46608,12 @@ async function makeWebGPURenderer(internals) {
47833
46608
  ...motionBlurDrawOptions(frameRequest),
47834
46609
  ...frameRequest.profileFrame === void 0 ? {} : { profileFrame: frameRequest.profileFrame },
47835
46610
  ...frameRequest.geometryLane === void 0 ? {} : { geometryLane: frameRequest.geometryLane }
47836
- } : options ?? { cameraOwner: 0, resourceOwner: 0 };
46611
+ } : publicationRequest === void 0 ? options ?? { cameraOwner: 0, resourceOwner: 0 } : {
46612
+ cameraOwner: 0,
46613
+ resourceOwner: 0,
46614
+ sampleTimeSeconds: publicationRequest.publication.sampleTimeSeconds,
46615
+ temporalReset: publicationRequest.publication.temporalReset
46616
+ };
47837
46617
  if (disposed) {
47838
46618
  const e = new RhiError({
47839
46619
  code: "rhi-not-available",
@@ -47881,7 +46661,7 @@ async function makeWebGPURenderer(internals) {
47881
46661
  internals.errorRegistry.fire(e);
47882
46662
  return err(e);
47883
46663
  }
47884
- const worldCount = Array.isArray(worlds) ? worlds.length : 0;
46664
+ const worldCount = publicationRequest === void 0 ? Array.isArray(worlds) ? worlds.length : 0 : 1;
47885
46665
  if (worldCount === 0 && internals.device.caps.backendKind === "null") {
47886
46666
  return ok(void 0);
47887
46667
  }
@@ -47897,8 +46677,20 @@ async function makeWebGPURenderer(internals) {
47897
46677
  internals.errorRegistry
47898
46678
  );
47899
46679
  if (!contextConfigured.ok) return contextConfigured;
47900
- renderTargetHost.beginFrame();
47901
46680
  try {
46681
+ if (publicationRequest !== void 0 && publicationReceiver !== void 0) {
46682
+ const accepted = publicationReceiver.accept(publicationRequest.publication);
46683
+ if (!accepted.ok) return accepted;
46684
+ publicationTargets ??= new RenderPublicationTargetReceiver(renderTargetHost);
46685
+ publication = {
46686
+ ...publicationTargets.apply(accepted.value),
46687
+ ...publicationRequest.onFeatureSourceSubmitted === void 0 ? {} : {
46688
+ onFeatureSourceSubmitted: publicationRequest.onFeatureSourceSubmitted
46689
+ }
46690
+ };
46691
+ installPublicationPrograms(assets, publicationRequest.publication.programs);
46692
+ }
46693
+ renderTargetHost.beginFrame();
47902
46694
  const timingHost = internals;
47903
46695
  const timingRequested = isFrameRequest && (frameRequest?.profileFrame !== void 0 || internals.options?.captureGpuTimings === true);
47904
46696
  let volumeTimingCapture;
@@ -47917,7 +46709,13 @@ async function makeWebGPURenderer(internals) {
47917
46709
  graphGeneration: 0
47918
46710
  };
47919
46711
  }
47920
- const submitted = renderSystem.draw(worlds, drawOptions, readLeases, volumeTimingCapture);
46712
+ const submitted = renderSystem.draw(
46713
+ worlds,
46714
+ drawOptions,
46715
+ readLeases,
46716
+ volumeTimingCapture,
46717
+ publication
46718
+ );
47921
46719
  timingHost.observationFrameId = void 0;
47922
46720
  timingHost.observationCaptureDomains = void 0;
47923
46721
  timingHost.gpuPassTimingFrameIdentity = void 0;
@@ -48097,6 +46895,8 @@ async function makeWebGPURenderer(internals) {
48097
46895
  });
48098
46896
  internals.errorRegistry.fire(e);
48099
46897
  return err(e);
46898
+ } finally {
46899
+ publicationReceiver?.releaseVideoFrames();
48100
46900
  }
48101
46901
  },
48102
46902
  async observe(receipt, request) {
@@ -48301,6 +47101,7 @@ async function makeWebGPURenderer(internals) {
48301
47101
  disposed = true;
48302
47102
  for (const world of attachedWorlds) dynamicGeometryHost.invalidateDynamicGeometryWorld(world);
48303
47103
  dynamicGeometry.dispose();
47104
+ publicationReceiver?.dispose();
48304
47105
  for (const continuation of frameContinuations) {
48305
47106
  continuation.terminate({ code: "disposed" });
48306
47107
  }
@@ -48311,11 +47112,6 @@ async function makeWebGPURenderer(internals) {
48311
47112
  }
48312
47113
  for (const world of attachedWorlds) {
48313
47114
  try {
48314
- const derivedSystemName = derivedSystemNames.get(world);
48315
- if (derivedSystemName !== void 0) {
48316
- world.removeSystem(Update, derivedSystemName);
48317
- derivedSystemNames.delete(world);
48318
- }
48319
47115
  transformReleases.get(world)?.();
48320
47116
  transformReleases.delete(world);
48321
47117
  } catch (cause) {