@aura3d/rendering 3.0.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1764) hide show
  1. package/dist/BlendModes.d.ts +34 -0
  2. package/dist/BlendModes.d.ts.map +1 -0
  3. package/dist/BlendModes.js +42 -0
  4. package/dist/BlendModes.js.map +1 -0
  5. package/dist/DepthPass.d.ts +18 -0
  6. package/dist/DepthPass.d.ts.map +1 -1
  7. package/dist/DepthPass.js +103 -20
  8. package/dist/DepthPass.js.map +1 -1
  9. package/dist/EnvironmentBackgroundPass.d.ts +7 -0
  10. package/dist/EnvironmentBackgroundPass.d.ts.map +1 -1
  11. package/dist/EnvironmentBackgroundPass.js +39 -14
  12. package/dist/EnvironmentBackgroundPass.js.map +1 -1
  13. package/dist/EnvironmentMapResources.d.ts +1 -1
  14. package/dist/EnvironmentMapResources.d.ts.map +1 -1
  15. package/dist/EnvironmentMapResources.js +19 -8
  16. package/dist/EnvironmentMapResources.js.map +1 -1
  17. package/dist/EnvironmentPlatform.d.ts +6 -0
  18. package/dist/EnvironmentPlatform.d.ts.map +1 -1
  19. package/dist/EnvironmentPlatform.js +3 -1
  20. package/dist/EnvironmentPlatform.js.map +1 -1
  21. package/dist/EnvironmentPreset.d.ts +7 -0
  22. package/dist/EnvironmentPreset.d.ts.map +1 -1
  23. package/dist/EnvironmentPreset.js +11 -11
  24. package/dist/EnvironmentPreset.js.map +1 -1
  25. package/dist/EnvironmentPresetPack.d.ts +16 -0
  26. package/dist/EnvironmentPresetPack.d.ts.map +1 -1
  27. package/dist/EnvironmentPresetPack.js +28 -0
  28. package/dist/EnvironmentPresetPack.js.map +1 -1
  29. package/dist/ExternalParityRenderPreset.d.ts +15 -1
  30. package/dist/ExternalParityRenderPreset.d.ts.map +1 -1
  31. package/dist/ExternalParityRenderPreset.js +52 -7
  32. package/dist/ExternalParityRenderPreset.js.map +1 -1
  33. package/dist/ForwardPass.d.ts +240 -50
  34. package/dist/ForwardPass.d.ts.map +1 -1
  35. package/dist/ForwardPass.js +845 -866
  36. package/dist/ForwardPass.js.map +1 -1
  37. package/dist/Geometry.d.ts +44 -1
  38. package/dist/Geometry.d.ts.map +1 -1
  39. package/dist/Geometry.js +174 -24
  40. package/dist/Geometry.js.map +1 -1
  41. package/dist/InstancedPBRMaterial.d.ts +5 -0
  42. package/dist/InstancedPBRMaterial.d.ts.map +1 -1
  43. package/dist/InstancedPBRMaterial.js +7 -0
  44. package/dist/InstancedPBRMaterial.js.map +1 -1
  45. package/dist/LightCollector.d.ts +8 -0
  46. package/dist/LightCollector.d.ts.map +1 -1
  47. package/dist/LightCollector.js +1 -1
  48. package/dist/LightCollector.js.map +1 -1
  49. package/dist/LightUniforms.d.ts +78 -0
  50. package/dist/LightUniforms.d.ts.map +1 -1
  51. package/dist/LightUniforms.js +100 -0
  52. package/dist/LightUniforms.js.map +1 -1
  53. package/dist/Material.d.ts +15 -0
  54. package/dist/Material.d.ts.map +1 -1
  55. package/dist/Material.js +19 -2
  56. package/dist/Material.js.map +1 -1
  57. package/dist/MaterialBinding.d.ts +10 -0
  58. package/dist/MaterialBinding.d.ts.map +1 -1
  59. package/dist/MaterialBinding.js +91 -1
  60. package/dist/MaterialBinding.js.map +1 -1
  61. package/dist/MaterialPresets.d.ts +60 -0
  62. package/dist/MaterialPresets.d.ts.map +1 -1
  63. package/dist/MaterialPresets.js +212 -0
  64. package/dist/MaterialPresets.js.map +1 -1
  65. package/dist/NormalMappedPBRMaterial.d.ts +5 -0
  66. package/dist/NormalMappedPBRMaterial.d.ts.map +1 -1
  67. package/dist/NormalMappedPBRMaterial.js +7 -0
  68. package/dist/NormalMappedPBRMaterial.js.map +1 -1
  69. package/dist/OceanSurface.d.ts +8 -0
  70. package/dist/OceanSurface.d.ts.map +1 -1
  71. package/dist/OceanSurface.js +10 -79
  72. package/dist/OceanSurface.js.map +1 -1
  73. package/dist/PBRLightingDefaults.d.ts +8 -0
  74. package/dist/PBRLightingDefaults.d.ts.map +1 -1
  75. package/dist/PBRLightingDefaults.js +8 -0
  76. package/dist/PBRLightingDefaults.js.map +1 -1
  77. package/dist/PBRMaterial.d.ts +5 -0
  78. package/dist/PBRMaterial.d.ts.map +1 -1
  79. package/dist/PBRMaterial.js +7 -0
  80. package/dist/PBRMaterial.js.map +1 -1
  81. package/dist/PostProcessPass.d.ts +6 -490
  82. package/dist/PostProcessPass.d.ts.map +1 -1
  83. package/dist/PostProcessPass.js +6 -2016
  84. package/dist/PostProcessPass.js.map +1 -1
  85. package/dist/ProceduralMaterialTextures.d.ts +28 -0
  86. package/dist/ProceduralMaterialTextures.d.ts.map +1 -0
  87. package/dist/ProceduralMaterialTextures.js +217 -0
  88. package/dist/ProceduralMaterialTextures.js.map +1 -0
  89. package/dist/ReflectionProbe.d.ts.map +1 -1
  90. package/dist/ReflectionProbe.js +4 -1
  91. package/dist/ReflectionProbe.js.map +1 -1
  92. package/dist/RenderBackend.d.ts +2 -0
  93. package/dist/RenderBackend.d.ts.map +1 -1
  94. package/dist/RenderBackend.js +3 -0
  95. package/dist/RenderBackend.js.map +1 -1
  96. package/dist/RenderDevice.d.ts +92 -5
  97. package/dist/RenderDevice.d.ts.map +1 -1
  98. package/dist/RenderDevice.js +166 -9
  99. package/dist/RenderDevice.js.map +1 -1
  100. package/dist/RenderGraph.d.ts.map +1 -1
  101. package/dist/RenderGraph.js +17 -0
  102. package/dist/RenderGraph.js.map +1 -1
  103. package/dist/RenderPass.d.ts +7 -0
  104. package/dist/RenderPass.d.ts.map +1 -1
  105. package/dist/RenderPass.js.map +1 -1
  106. package/dist/RenderPipeline.d.ts +5 -0
  107. package/dist/RenderPipeline.d.ts.map +1 -1
  108. package/dist/RenderPipeline.js +6 -0
  109. package/dist/RenderPipeline.js.map +1 -1
  110. package/dist/Renderer.d.ts +261 -66
  111. package/dist/Renderer.d.ts.map +1 -1
  112. package/dist/Renderer.js +889 -1254
  113. package/dist/Renderer.js.map +1 -1
  114. package/dist/RendererPostprocessPlan.d.ts +4 -0
  115. package/dist/RendererPostprocessPlan.d.ts.map +1 -1
  116. package/dist/RendererPostprocessPlan.js +16 -2
  117. package/dist/RendererPostprocessPlan.js.map +1 -1
  118. package/dist/RendererTiming.d.ts +27 -0
  119. package/dist/RendererTiming.d.ts.map +1 -1
  120. package/dist/RendererTiming.js +179 -12
  121. package/dist/RendererTiming.js.map +1 -1
  122. package/dist/ResolutionGovernor.d.ts +56 -0
  123. package/dist/ResolutionGovernor.d.ts.map +1 -0
  124. package/dist/ResolutionGovernor.js +87 -0
  125. package/dist/ResolutionGovernor.js.map +1 -0
  126. package/dist/Sampler.d.ts +34 -1
  127. package/dist/Sampler.d.ts.map +1 -1
  128. package/dist/Sampler.js +55 -2
  129. package/dist/Sampler.js.map +1 -1
  130. package/dist/ShaderLibrary.d.ts.map +1 -1
  131. package/dist/ShaderLibrary.js +15 -10
  132. package/dist/ShaderLibrary.js.map +1 -1
  133. package/dist/ShaderLibraryCore.d.ts.map +1 -1
  134. package/dist/ShaderLibraryCore.js +3 -2
  135. package/dist/ShaderLibraryCore.js.map +1 -1
  136. package/dist/ShaderModule.d.ts +7 -1
  137. package/dist/ShaderModule.d.ts.map +1 -1
  138. package/dist/ShaderModule.js +20 -5
  139. package/dist/ShaderModule.js.map +1 -1
  140. package/dist/ShadowPass.d.ts.map +1 -1
  141. package/dist/ShadowPass.js +14 -7
  142. package/dist/ShadowPass.js.map +1 -1
  143. package/dist/SkinnedLitMaterial.d.ts +5 -0
  144. package/dist/SkinnedLitMaterial.d.ts.map +1 -1
  145. package/dist/SkinnedLitMaterial.js +13 -0
  146. package/dist/SkinnedLitMaterial.js.map +1 -1
  147. package/dist/SkinningBounds.d.ts +18 -0
  148. package/dist/SkinningBounds.d.ts.map +1 -1
  149. package/dist/SkinningBounds.js +78 -0
  150. package/dist/SkinningBounds.js.map +1 -1
  151. package/dist/SkinningPaletteTextureCache.d.ts +117 -0
  152. package/dist/SkinningPaletteTextureCache.d.ts.map +1 -0
  153. package/dist/SkinningPaletteTextureCache.js +205 -0
  154. package/dist/SkinningPaletteTextureCache.js.map +1 -0
  155. package/dist/SkinningUniforms.d.ts +56 -0
  156. package/dist/SkinningUniforms.d.ts.map +1 -0
  157. package/dist/SkinningUniforms.js +262 -0
  158. package/dist/SkinningUniforms.js.map +1 -0
  159. package/dist/TemporalHistory.d.ts +33 -0
  160. package/dist/TemporalHistory.d.ts.map +1 -1
  161. package/dist/TemporalHistory.js +84 -1
  162. package/dist/TemporalHistory.js.map +1 -1
  163. package/dist/TerrainHeightfield.d.ts +12 -0
  164. package/dist/TerrainHeightfield.d.ts.map +1 -1
  165. package/dist/TerrainHeightfield.js +29 -6
  166. package/dist/TerrainHeightfield.js.map +1 -1
  167. package/dist/TerrainTiles.d.ts +40 -10
  168. package/dist/TerrainTiles.d.ts.map +1 -1
  169. package/dist/TerrainTiles.js +18 -57
  170. package/dist/TerrainTiles.js.map +1 -1
  171. package/dist/Texture.d.ts +47 -2
  172. package/dist/Texture.d.ts.map +1 -1
  173. package/dist/Texture.js +119 -3
  174. package/dist/Texture.js.map +1 -1
  175. package/dist/TexturedPBRMaterial.d.ts +24 -0
  176. package/dist/TexturedPBRMaterial.d.ts.map +1 -1
  177. package/dist/TexturedPBRMaterial.js +72 -20
  178. package/dist/TexturedPBRMaterial.js.map +1 -1
  179. package/dist/TransmissionRenderTarget.d.ts +33 -0
  180. package/dist/TransmissionRenderTarget.d.ts.map +1 -0
  181. package/dist/TransmissionRenderTarget.js +61 -0
  182. package/dist/TransmissionRenderTarget.js.map +1 -0
  183. package/dist/VegetationScatter.js +1 -1
  184. package/dist/VegetationScatter.js.map +1 -1
  185. package/dist/VolumetricFog.d.ts +42 -0
  186. package/dist/VolumetricFog.d.ts.map +1 -1
  187. package/dist/VolumetricFog.js +52 -1
  188. package/dist/VolumetricFog.js.map +1 -1
  189. package/dist/WaterSurface.d.ts +5 -0
  190. package/dist/WaterSurface.d.ts.map +1 -1
  191. package/dist/WaterSurface.js +5 -0
  192. package/dist/WaterSurface.js.map +1 -1
  193. package/dist/WebGL2Device.d.ts +153 -207
  194. package/dist/WebGL2Device.d.ts.map +1 -1
  195. package/dist/WebGL2Device.js +822 -3706
  196. package/dist/WebGL2Device.js.map +1 -1
  197. package/dist/WebGL2StateCache.d.ts +15 -1
  198. package/dist/WebGL2StateCache.d.ts.map +1 -1
  199. package/dist/WebGL2StateCache.js +31 -2
  200. package/dist/WebGL2StateCache.js.map +1 -1
  201. package/dist/WebGPUDevice.d.ts +0 -4
  202. package/dist/WebGPUDevice.d.ts.map +1 -1
  203. package/dist/WebGPUDevice.js +31 -605
  204. package/dist/WebGPUDevice.js.map +1 -1
  205. package/dist/WebGPUSkinningLimits.d.ts +10 -1
  206. package/dist/WebGPUSkinningLimits.d.ts.map +1 -1
  207. package/dist/WebGPUSkinningLimits.js +15 -1
  208. package/dist/WebGPUSkinningLimits.js.map +1 -1
  209. package/dist/advanced-runtime/index.d.ts +6 -2
  210. package/dist/advanced-runtime/index.d.ts.map +1 -1
  211. package/dist/advanced-runtime/index.js +0 -1
  212. package/dist/advanced-runtime/index.js.map +1 -1
  213. package/dist/animation/AnimationRenderPreset.d.ts +1 -1
  214. package/dist/animation/AnimationRenderPreset.d.ts.map +1 -1
  215. package/dist/animation/AnimationRenderPreset.js +1 -1
  216. package/dist/animation/AnimationRenderPreset.js.map +1 -1
  217. package/dist/animation/applyAnimationRenderPreset.d.ts +1 -1
  218. package/dist/animation/applyAnimationRenderPreset.d.ts.map +1 -1
  219. package/dist/animation/index.d.ts +2 -1
  220. package/dist/animation/index.d.ts.map +1 -1
  221. package/dist/animation/index.js +1 -1
  222. package/dist/animation/index.js.map +1 -1
  223. package/dist/atmosphere/CloudLayer.d.ts +24 -0
  224. package/dist/atmosphere/CloudLayer.d.ts.map +1 -0
  225. package/dist/atmosphere/CloudLayer.js +30 -0
  226. package/dist/atmosphere/CloudLayer.js.map +1 -0
  227. package/dist/atmosphere/FogVolumes.d.ts +30 -0
  228. package/dist/atmosphere/FogVolumes.d.ts.map +1 -0
  229. package/dist/atmosphere/FogVolumes.js +96 -0
  230. package/dist/atmosphere/FogVolumes.js.map +1 -0
  231. package/dist/atmosphere/GradientSky.d.ts +40 -0
  232. package/dist/atmosphere/GradientSky.d.ts.map +1 -0
  233. package/dist/atmosphere/GradientSky.js +75 -0
  234. package/dist/atmosphere/GradientSky.js.map +1 -0
  235. package/dist/atmosphere/HeightFog.d.ts +154 -0
  236. package/dist/atmosphere/HeightFog.d.ts.map +1 -0
  237. package/dist/atmosphere/HeightFog.js +379 -0
  238. package/dist/atmosphere/HeightFog.js.map +1 -0
  239. package/dist/atmosphere/PreethamSky.d.ts +38 -0
  240. package/dist/atmosphere/PreethamSky.d.ts.map +1 -0
  241. package/dist/atmosphere/PreethamSky.js +150 -0
  242. package/dist/atmosphere/PreethamSky.js.map +1 -0
  243. package/dist/atmosphere/SkyBackgroundPass.d.ts +63 -0
  244. package/dist/atmosphere/SkyBackgroundPass.d.ts.map +1 -0
  245. package/dist/atmosphere/SkyBackgroundPass.js +233 -0
  246. package/dist/atmosphere/SkyBackgroundPass.js.map +1 -0
  247. package/dist/atmosphere/SkyCaptureAdapter.d.ts +45 -0
  248. package/dist/atmosphere/SkyCaptureAdapter.d.ts.map +1 -0
  249. package/dist/atmosphere/SkyCaptureAdapter.js +65 -0
  250. package/dist/atmosphere/SkyCaptureAdapter.js.map +1 -0
  251. package/dist/atmosphere/SkyEval.d.ts +56 -0
  252. package/dist/atmosphere/SkyEval.d.ts.map +1 -0
  253. package/dist/atmosphere/SkyEval.js +99 -0
  254. package/dist/atmosphere/SkyEval.js.map +1 -0
  255. package/dist/atmosphere/StarField.d.ts +26 -0
  256. package/dist/atmosphere/StarField.d.ts.map +1 -0
  257. package/dist/atmosphere/StarField.js +31 -0
  258. package/dist/atmosphere/StarField.js.map +1 -0
  259. package/dist/atmosphere/VolumetricFogPass.d.ts +69 -0
  260. package/dist/atmosphere/VolumetricFogPass.d.ts.map +1 -0
  261. package/dist/atmosphere/VolumetricFogPass.js +265 -0
  262. package/dist/atmosphere/VolumetricFogPass.js.map +1 -0
  263. package/dist/atmosphere/fogChunks.d.ts +8 -0
  264. package/dist/atmosphere/fogChunks.d.ts.map +1 -0
  265. package/dist/atmosphere/fogChunks.js +39 -0
  266. package/dist/atmosphere/fogChunks.js.map +1 -0
  267. package/dist/atmosphere/fogUniformStore.d.ts +20 -0
  268. package/dist/atmosphere/fogUniformStore.d.ts.map +1 -0
  269. package/dist/atmosphere/fogUniformStore.js +45 -0
  270. package/dist/atmosphere/fogUniformStore.js.map +1 -0
  271. package/dist/atmosphere/shaders/fog.glsl.d.ts +10 -0
  272. package/dist/atmosphere/shaders/fog.glsl.d.ts.map +1 -0
  273. package/dist/atmosphere/shaders/fog.glsl.js +161 -0
  274. package/dist/atmosphere/shaders/fog.glsl.js.map +1 -0
  275. package/dist/atmosphere/shaders/volumetric-apply.glsl.d.ts +3 -0
  276. package/dist/atmosphere/shaders/volumetric-apply.glsl.d.ts.map +1 -0
  277. package/dist/atmosphere/shaders/volumetric-apply.glsl.js +61 -0
  278. package/dist/atmosphere/shaders/volumetric-apply.glsl.js.map +1 -0
  279. package/dist/atmosphere/shaders/volumetric-inject.glsl.d.ts +4 -0
  280. package/dist/atmosphere/shaders/volumetric-inject.glsl.d.ts.map +1 -0
  281. package/dist/atmosphere/shaders/volumetric-inject.glsl.js +129 -0
  282. package/dist/atmosphere/shaders/volumetric-inject.glsl.js.map +1 -0
  283. package/dist/atmosphere/shaders/volumetric-integrate.glsl.d.ts +3 -0
  284. package/dist/atmosphere/shaders/volumetric-integrate.glsl.d.ts.map +1 -0
  285. package/dist/atmosphere/shaders/volumetric-integrate.glsl.js +55 -0
  286. package/dist/atmosphere/shaders/volumetric-integrate.glsl.js.map +1 -0
  287. package/dist/atmosphere/shaders/wetness.glsl.d.ts +34 -0
  288. package/dist/atmosphere/shaders/wetness.glsl.d.ts.map +1 -0
  289. package/dist/atmosphere/shaders/wetness.glsl.js +101 -0
  290. package/dist/atmosphere/shaders/wetness.glsl.js.map +1 -0
  291. package/dist/atmosphere/sky.glsl.d.ts +8 -0
  292. package/dist/atmosphere/sky.glsl.d.ts.map +1 -0
  293. package/dist/atmosphere/sky.glsl.js +249 -0
  294. package/dist/atmosphere/sky.glsl.js.map +1 -0
  295. package/dist/batching/BatchedGeometryPool.d.ts +72 -0
  296. package/dist/batching/BatchedGeometryPool.d.ts.map +1 -0
  297. package/dist/batching/BatchedGeometryPool.js +138 -0
  298. package/dist/batching/BatchedGeometryPool.js.map +1 -0
  299. package/dist/batching/ContentKeys.d.ts +29 -0
  300. package/dist/batching/ContentKeys.d.ts.map +1 -0
  301. package/dist/batching/ContentKeys.js +220 -0
  302. package/dist/batching/ContentKeys.js.map +1 -0
  303. package/dist/batching/DrawDataTexture.d.ts +51 -0
  304. package/dist/batching/DrawDataTexture.d.ts.map +1 -0
  305. package/dist/batching/DrawDataTexture.js +99 -0
  306. package/dist/batching/DrawDataTexture.js.map +1 -0
  307. package/dist/batching/MultiDrawBatch.d.ts +64 -0
  308. package/dist/batching/MultiDrawBatch.d.ts.map +1 -0
  309. package/dist/batching/MultiDrawBatch.js +103 -0
  310. package/dist/batching/MultiDrawBatch.js.map +1 -0
  311. package/dist/batching/StaticMergePlanner.d.ts +80 -0
  312. package/dist/batching/StaticMergePlanner.d.ts.map +1 -0
  313. package/dist/batching/StaticMergePlanner.js +323 -0
  314. package/dist/batching/StaticMergePlanner.js.map +1 -0
  315. package/dist/batching/index.d.ts +8 -0
  316. package/dist/batching/index.d.ts.map +1 -0
  317. package/dist/batching/index.js +8 -0
  318. package/dist/batching/index.js.map +1 -0
  319. package/dist/batching/shaders/drawId.glsl.d.ts +29 -0
  320. package/dist/batching/shaders/drawId.glsl.d.ts.map +1 -0
  321. package/dist/batching/shaders/drawId.glsl.js +93 -0
  322. package/dist/batching/shaders/drawId.glsl.js.map +1 -0
  323. package/dist/batching/shaders/instanceEmissive.glsl.d.ts +16 -0
  324. package/dist/batching/shaders/instanceEmissive.glsl.d.ts.map +1 -0
  325. package/dist/batching/shaders/instanceEmissive.glsl.js +63 -0
  326. package/dist/batching/shaders/instanceEmissive.glsl.js.map +1 -0
  327. package/dist/cinematic/BloomPass.d.ts +5 -9
  328. package/dist/cinematic/BloomPass.d.ts.map +1 -1
  329. package/dist/cinematic/BloomPass.js +5 -17
  330. package/dist/cinematic/BloomPass.js.map +1 -1
  331. package/dist/cinematic/DepthHazePass.d.ts +5 -11
  332. package/dist/cinematic/DepthHazePass.d.ts.map +1 -1
  333. package/dist/cinematic/DepthHazePass.js +5 -19
  334. package/dist/cinematic/DepthHazePass.js.map +1 -1
  335. package/dist/cinematic/FilmGrainPass.d.ts +5 -8
  336. package/dist/cinematic/FilmGrainPass.d.ts.map +1 -1
  337. package/dist/cinematic/FilmGrainPass.js +5 -16
  338. package/dist/cinematic/FilmGrainPass.js.map +1 -1
  339. package/dist/cinematic/VignettePass.d.ts +5 -9
  340. package/dist/cinematic/VignettePass.d.ts.map +1 -1
  341. package/dist/cinematic/VignettePass.js +5 -16
  342. package/dist/cinematic/VignettePass.js.map +1 -1
  343. package/dist/cinematic/index.d.ts +2 -1
  344. package/dist/cinematic/index.d.ts.map +1 -1
  345. package/dist/cinematic/index.js +1 -1
  346. package/dist/cinematic/index.js.map +1 -1
  347. package/dist/contracts/atmosphere.d.ts +30 -0
  348. package/dist/contracts/atmosphere.d.ts.map +1 -0
  349. package/dist/contracts/atmosphere.js +42 -0
  350. package/dist/contracts/atmosphere.js.map +1 -0
  351. package/dist/contracts/blend.d.ts +28 -0
  352. package/dist/contracts/blend.d.ts.map +1 -0
  353. package/dist/contracts/blend.js +73 -0
  354. package/dist/contracts/blend.js.map +1 -0
  355. package/dist/contracts/core.d.ts +47 -0
  356. package/dist/contracts/core.d.ts.map +1 -0
  357. package/dist/contracts/core.js +70 -0
  358. package/dist/contracts/core.js.map +1 -0
  359. package/dist/contracts/deform.d.ts +38 -0
  360. package/dist/contracts/deform.d.ts.map +1 -0
  361. package/dist/contracts/deform.js +14 -0
  362. package/dist/contracts/deform.js.map +1 -0
  363. package/dist/contracts/device.d.ts +71 -0
  364. package/dist/contracts/device.d.ts.map +1 -0
  365. package/dist/contracts/device.js +97 -0
  366. package/dist/contracts/device.js.map +1 -0
  367. package/dist/contracts/environment.d.ts +55 -0
  368. package/dist/contracts/environment.d.ts.map +1 -0
  369. package/dist/contracts/environment.js +115 -0
  370. package/dist/contracts/environment.js.map +1 -0
  371. package/dist/contracts/flags.state.d.ts +15 -0
  372. package/dist/contracts/flags.state.d.ts.map +1 -0
  373. package/dist/contracts/flags.state.js +45 -0
  374. package/dist/contracts/flags.state.js.map +1 -0
  375. package/dist/contracts/frameGraph.d.ts +78 -0
  376. package/dist/contracts/frameGraph.d.ts.map +1 -0
  377. package/dist/contracts/frameGraph.js +32 -0
  378. package/dist/contracts/frameGraph.js.map +1 -0
  379. package/dist/contracts/frameUniforms.d.ts +43 -0
  380. package/dist/contracts/frameUniforms.d.ts.map +1 -0
  381. package/dist/contracts/frameUniforms.js +35 -0
  382. package/dist/contracts/frameUniforms.js.map +1 -0
  383. package/dist/contracts/geometry.d.ts +33 -0
  384. package/dist/contracts/geometry.d.ts.map +1 -0
  385. package/dist/contracts/geometry.js +59 -0
  386. package/dist/contracts/geometry.js.map +1 -0
  387. package/dist/contracts/index.d.ts +27 -0
  388. package/dist/contracts/index.d.ts.map +1 -0
  389. package/dist/contracts/index.js +27 -0
  390. package/dist/contracts/index.js.map +1 -0
  391. package/dist/contracts/materialLobes.d.ts +41 -0
  392. package/dist/contracts/materialLobes.d.ts.map +1 -0
  393. package/dist/contracts/materialLobes.js +14 -0
  394. package/dist/contracts/materialLobes.js.map +1 -0
  395. package/dist/contracts/output.d.ts +35 -0
  396. package/dist/contracts/output.d.ts.map +1 -0
  397. package/dist/contracts/output.js +18 -0
  398. package/dist/contracts/output.js.map +1 -0
  399. package/dist/contracts/particles.d.ts +41 -0
  400. package/dist/contracts/particles.d.ts.map +1 -0
  401. package/dist/contracts/particles.js +15 -0
  402. package/dist/contracts/particles.js.map +1 -0
  403. package/dist/contracts/post.d.ts +71 -0
  404. package/dist/contracts/post.d.ts.map +1 -0
  405. package/dist/contracts/post.js +28 -0
  406. package/dist/contracts/post.js.map +1 -0
  407. package/dist/contracts/program.d.ts +158 -0
  408. package/dist/contracts/program.d.ts.map +1 -0
  409. package/dist/contracts/program.js +128 -0
  410. package/dist/contracts/program.js.map +1 -0
  411. package/dist/contracts/quality.d.ts +93 -0
  412. package/dist/contracts/quality.d.ts.map +1 -0
  413. package/dist/contracts/quality.js +149 -0
  414. package/dist/contracts/quality.js.map +1 -0
  415. package/dist/contracts/renderItem.d.ts +58 -0
  416. package/dist/contracts/renderItem.d.ts.map +1 -0
  417. package/dist/contracts/renderItem.js +8 -0
  418. package/dist/contracts/renderItem.js.map +1 -0
  419. package/dist/contracts/renderSource.d.ts +63 -0
  420. package/dist/contracts/renderSource.d.ts.map +1 -0
  421. package/dist/contracts/renderSource.js +7 -0
  422. package/dist/contracts/renderSource.js.map +1 -0
  423. package/dist/contracts/rendererFactory.d.ts +42 -0
  424. package/dist/contracts/rendererFactory.d.ts.map +1 -0
  425. package/dist/contracts/rendererFactory.js +32 -0
  426. package/dist/contracts/rendererFactory.js.map +1 -0
  427. package/dist/contracts/sampling.d.ts +23 -0
  428. package/dist/contracts/sampling.d.ts.map +1 -0
  429. package/dist/contracts/sampling.js +17 -0
  430. package/dist/contracts/sampling.js.map +1 -0
  431. package/dist/contracts/shadows.d.ts +53 -0
  432. package/dist/contracts/shadows.d.ts.map +1 -0
  433. package/dist/contracts/shadows.js +66 -0
  434. package/dist/contracts/shadows.js.map +1 -0
  435. package/dist/contracts/testing/ChunkHarness.d.ts +18 -0
  436. package/dist/contracts/testing/ChunkHarness.d.ts.map +1 -0
  437. package/dist/contracts/testing/ChunkHarness.js +68 -0
  438. package/dist/contracts/testing/ChunkHarness.js.map +1 -0
  439. package/dist/contracts/textureFormats.d.ts +18 -0
  440. package/dist/contracts/textureFormats.d.ts.map +1 -0
  441. package/dist/contracts/textureFormats.js +13 -0
  442. package/dist/contracts/textureFormats.js.map +1 -0
  443. package/dist/contracts/velocity.d.ts +37 -0
  444. package/dist/contracts/velocity.d.ts.map +1 -0
  445. package/dist/contracts/velocity.js +22 -0
  446. package/dist/contracts/velocity.js.map +1 -0
  447. package/dist/environment/EnvUniforms.d.ts +42 -0
  448. package/dist/environment/EnvUniforms.d.ts.map +1 -0
  449. package/dist/environment/EnvUniforms.js +54 -0
  450. package/dist/environment/EnvUniforms.js.map +1 -0
  451. package/dist/environment/EnvironmentCache.d.ts +83 -0
  452. package/dist/environment/EnvironmentCache.d.ts.map +1 -0
  453. package/dist/environment/EnvironmentCache.js +205 -0
  454. package/dist/environment/EnvironmentCache.js.map +1 -0
  455. package/dist/environment/EnvironmentProbeFactory.d.ts +41 -0
  456. package/dist/environment/EnvironmentProbeFactory.d.ts.map +1 -0
  457. package/dist/environment/EnvironmentProbeFactory.js +52 -0
  458. package/dist/environment/EnvironmentProbeFactory.js.map +1 -0
  459. package/dist/environment/GPUPMREMGenerator.d.ts +44 -0
  460. package/dist/environment/GPUPMREMGenerator.d.ts.map +1 -0
  461. package/dist/environment/GPUPMREMGenerator.js +98 -0
  462. package/dist/environment/GPUPMREMGenerator.js.map +1 -0
  463. package/dist/environment/HdrEquirect.d.ts +28 -0
  464. package/dist/environment/HdrEquirect.d.ts.map +1 -0
  465. package/dist/environment/HdrEquirect.js +205 -0
  466. package/dist/environment/HdrEquirect.js.map +1 -0
  467. package/dist/environment/LightingSamplerBudget.d.ts +20 -0
  468. package/dist/environment/LightingSamplerBudget.d.ts.map +1 -0
  469. package/dist/environment/LightingSamplerBudget.js +94 -0
  470. package/dist/environment/LightingSamplerBudget.js.map +1 -0
  471. package/dist/environment/Prd02BackgroundShaderLibrary.d.ts +10 -0
  472. package/dist/environment/Prd02BackgroundShaderLibrary.d.ts.map +1 -0
  473. package/dist/environment/Prd02BackgroundShaderLibrary.js +100 -0
  474. package/dist/environment/Prd02BackgroundShaderLibrary.js.map +1 -0
  475. package/dist/environment/Rgb9e5Cube.d.ts +25 -0
  476. package/dist/environment/Rgb9e5Cube.d.ts.map +1 -0
  477. package/dist/environment/Rgb9e5Cube.js +103 -0
  478. package/dist/environment/Rgb9e5Cube.js.map +1 -0
  479. package/dist/environment/RoomEnvironmentScene.d.ts +57 -0
  480. package/dist/environment/RoomEnvironmentScene.d.ts.map +1 -0
  481. package/dist/environment/RoomEnvironmentScene.js +165 -0
  482. package/dist/environment/RoomEnvironmentScene.js.map +1 -0
  483. package/dist/environment/SphericalHarmonics.d.ts +32 -0
  484. package/dist/environment/SphericalHarmonics.d.ts.map +1 -0
  485. package/dist/environment/SphericalHarmonics.js +155 -0
  486. package/dist/environment/SphericalHarmonics.js.map +1 -0
  487. package/dist/environment/probeBuild.d.ts +97 -0
  488. package/dist/environment/probeBuild.d.ts.map +1 -0
  489. package/dist/environment/probeBuild.js +406 -0
  490. package/dist/environment/probeBuild.js.map +1 -0
  491. package/dist/environment/workers/cpuPrefilter.d.ts +58 -0
  492. package/dist/environment/workers/cpuPrefilter.d.ts.map +1 -0
  493. package/dist/environment/workers/cpuPrefilter.js +288 -0
  494. package/dist/environment/workers/cpuPrefilter.js.map +1 -0
  495. package/dist/forward/Deform.d.ts +56 -0
  496. package/dist/forward/Deform.d.ts.map +1 -0
  497. package/dist/forward/Deform.js +517 -0
  498. package/dist/forward/Deform.js.map +1 -0
  499. package/dist/forward/DrawSubmit.d.ts +32 -0
  500. package/dist/forward/DrawSubmit.d.ts.map +1 -0
  501. package/dist/forward/DrawSubmit.js +75 -0
  502. package/dist/forward/DrawSubmit.js.map +1 -0
  503. package/dist/forward/Lighting.d.ts +35 -0
  504. package/dist/forward/Lighting.d.ts.map +1 -0
  505. package/dist/forward/Lighting.js +477 -0
  506. package/dist/forward/Lighting.js.map +1 -0
  507. package/dist/forward/Transmission.d.ts +62 -0
  508. package/dist/forward/Transmission.d.ts.map +1 -0
  509. package/dist/forward/Transmission.js +299 -0
  510. package/dist/forward/Transmission.js.map +1 -0
  511. package/dist/forward/Velocity.d.ts +47 -0
  512. package/dist/forward/Velocity.d.ts.map +1 -0
  513. package/dist/forward/Velocity.js +153 -0
  514. package/dist/forward/Velocity.js.map +1 -0
  515. package/dist/forward/transmissionTargetStore.d.ts +21 -0
  516. package/dist/forward/transmissionTargetStore.d.ts.map +1 -0
  517. package/dist/forward/transmissionTargetStore.js +8 -0
  518. package/dist/forward/transmissionTargetStore.js.map +1 -0
  519. package/dist/geometry/Primitives.d.ts +28 -0
  520. package/dist/geometry/Primitives.d.ts.map +1 -0
  521. package/dist/geometry/Primitives.js +110 -0
  522. package/dist/geometry/Primitives.js.map +1 -0
  523. package/dist/index.d.ts +140 -58
  524. package/dist/index.d.ts.map +1 -1
  525. package/dist/index.js +102 -52
  526. package/dist/index.js.map +1 -1
  527. package/dist/lanes/index.d.ts +17 -0
  528. package/dist/lanes/index.d.ts.map +1 -0
  529. package/dist/lanes/index.js +17 -0
  530. package/dist/lanes/index.js.map +1 -0
  531. package/dist/lanes/prd01.d.ts +6 -0
  532. package/dist/lanes/prd01.d.ts.map +1 -0
  533. package/dist/lanes/prd01.js +19 -0
  534. package/dist/lanes/prd01.js.map +1 -0
  535. package/dist/lanes/prd02.d.ts +62 -0
  536. package/dist/lanes/prd02.d.ts.map +1 -0
  537. package/dist/lanes/prd02.js +117 -0
  538. package/dist/lanes/prd02.js.map +1 -0
  539. package/dist/lanes/prd03.d.ts +19 -0
  540. package/dist/lanes/prd03.d.ts.map +1 -0
  541. package/dist/lanes/prd03.js +55 -0
  542. package/dist/lanes/prd03.js.map +1 -0
  543. package/dist/lanes/prd04.d.ts +22 -0
  544. package/dist/lanes/prd04.d.ts.map +1 -0
  545. package/dist/lanes/prd04.js +35 -0
  546. package/dist/lanes/prd04.js.map +1 -0
  547. package/dist/lanes/prd05.d.ts +4 -0
  548. package/dist/lanes/prd05.d.ts.map +1 -0
  549. package/dist/lanes/prd05.js +31 -0
  550. package/dist/lanes/prd05.js.map +1 -0
  551. package/dist/lanes/prd06.d.ts +33 -0
  552. package/dist/lanes/prd06.d.ts.map +1 -0
  553. package/dist/lanes/prd06.js +217 -0
  554. package/dist/lanes/prd06.js.map +1 -0
  555. package/dist/lanes/prd07.d.ts +49 -0
  556. package/dist/lanes/prd07.d.ts.map +1 -0
  557. package/dist/lanes/prd07.js +112 -0
  558. package/dist/lanes/prd07.js.map +1 -0
  559. package/dist/lanes/prd08.d.ts +2 -0
  560. package/dist/lanes/prd08.d.ts.map +1 -0
  561. package/dist/lanes/prd08.js +17 -0
  562. package/dist/lanes/prd08.js.map +1 -0
  563. package/dist/lanes/prd09.d.ts +6 -0
  564. package/dist/lanes/prd09.d.ts.map +1 -0
  565. package/dist/lanes/prd09.js +6 -0
  566. package/dist/lanes/prd09.js.map +1 -0
  567. package/dist/lanes/prd10.d.ts +2 -0
  568. package/dist/lanes/prd10.d.ts.map +1 -0
  569. package/dist/lanes/prd10.js +10 -0
  570. package/dist/lanes/prd10.js.map +1 -0
  571. package/dist/lanes/prd11.d.ts +61 -0
  572. package/dist/lanes/prd11.d.ts.map +1 -0
  573. package/dist/lanes/prd11.js +244 -0
  574. package/dist/lanes/prd11.js.map +1 -0
  575. package/dist/lanes/prd12.d.ts +6 -0
  576. package/dist/lanes/prd12.d.ts.map +1 -0
  577. package/dist/lanes/prd12.js +6 -0
  578. package/dist/lanes/prd12.js.map +1 -0
  579. package/dist/lanes/prd13.d.ts +6 -0
  580. package/dist/lanes/prd13.d.ts.map +1 -0
  581. package/dist/lanes/prd13.js +6 -0
  582. package/dist/lanes/prd13.js.map +1 -0
  583. package/dist/lanes/prd14.d.ts +6 -0
  584. package/dist/lanes/prd14.d.ts.map +1 -0
  585. package/dist/lanes/prd14.js +6 -0
  586. package/dist/lanes/prd14.js.map +1 -0
  587. package/dist/lanes/prd15.d.ts +6 -0
  588. package/dist/lanes/prd15.d.ts.map +1 -0
  589. package/dist/lanes/prd15.js +6 -0
  590. package/dist/lanes/prd15.js.map +1 -0
  591. package/dist/materials/PhysicalFeatures.d.ts +71 -0
  592. package/dist/materials/PhysicalFeatures.d.ts.map +1 -0
  593. package/dist/materials/PhysicalFeatures.js +255 -0
  594. package/dist/materials/PhysicalFeatures.js.map +1 -0
  595. package/dist/materials/PhysicalMaterial.d.ts +85 -0
  596. package/dist/materials/PhysicalMaterial.d.ts.map +1 -1
  597. package/dist/materials/PhysicalMaterial.js +21 -0
  598. package/dist/materials/PhysicalMaterial.js.map +1 -1
  599. package/dist/materials/features.d.ts +47 -0
  600. package/dist/materials/features.d.ts.map +1 -0
  601. package/dist/materials/features.js +282 -0
  602. package/dist/materials/features.js.map +1 -0
  603. package/dist/materials/lobes.d.ts +3 -0
  604. package/dist/materials/lobes.d.ts.map +1 -0
  605. package/dist/materials/lobes.js +225 -0
  606. package/dist/materials/lobes.js.map +1 -0
  607. package/dist/output/HdrTarget.d.ts +27 -0
  608. package/dist/output/HdrTarget.d.ts.map +1 -0
  609. package/dist/output/HdrTarget.js +48 -0
  610. package/dist/output/HdrTarget.js.map +1 -0
  611. package/dist/output/OutputPass.d.ts +28 -0
  612. package/dist/output/OutputPass.d.ts.map +1 -0
  613. package/dist/output/OutputPass.js +142 -0
  614. package/dist/output/OutputPass.js.map +1 -0
  615. package/dist/output/ToneMappingOperators.glsl.d.ts +22 -0
  616. package/dist/output/ToneMappingOperators.glsl.d.ts.map +1 -0
  617. package/dist/output/ToneMappingOperators.glsl.js +217 -0
  618. package/dist/output/ToneMappingOperators.glsl.js.map +1 -0
  619. package/dist/passes/ContactShadowPass.d.ts +57 -0
  620. package/dist/passes/ContactShadowPass.d.ts.map +1 -0
  621. package/dist/passes/ContactShadowPass.js +151 -0
  622. package/dist/passes/ContactShadowPass.js.map +1 -0
  623. package/dist/passes/Prd02ContactShadowsContributor.d.ts +16 -0
  624. package/dist/passes/Prd02ContactShadowsContributor.d.ts.map +1 -0
  625. package/dist/passes/Prd02ContactShadowsContributor.js +133 -0
  626. package/dist/passes/Prd02ContactShadowsContributor.js.map +1 -0
  627. package/dist/passes/Prd02SubFlags.d.ts +22 -0
  628. package/dist/passes/Prd02SubFlags.d.ts.map +1 -0
  629. package/dist/passes/Prd02SubFlags.js +32 -0
  630. package/dist/passes/Prd02SubFlags.js.map +1 -0
  631. package/dist/performance/BVH.d.ts +46 -0
  632. package/dist/performance/BVH.d.ts.map +1 -1
  633. package/dist/performance/BVH.js +212 -0
  634. package/dist/performance/BVH.js.map +1 -1
  635. package/dist/performance/Batcher.d.ts +11 -0
  636. package/dist/performance/Batcher.d.ts.map +1 -1
  637. package/dist/performance/Batcher.js +10 -0
  638. package/dist/performance/Batcher.js.map +1 -1
  639. package/dist/performance/FrustumCuller.d.ts +29 -0
  640. package/dist/performance/FrustumCuller.d.ts.map +1 -1
  641. package/dist/performance/FrustumCuller.js +78 -1
  642. package/dist/performance/FrustumCuller.js.map +1 -1
  643. package/dist/performance/LOD.d.ts +6 -0
  644. package/dist/performance/LOD.d.ts.map +1 -1
  645. package/dist/performance/LOD.js +12 -0
  646. package/dist/performance/LOD.js.map +1 -1
  647. package/dist/performance/RenderItemSorting.d.ts +2 -0
  648. package/dist/performance/RenderItemSorting.d.ts.map +1 -1
  649. package/dist/performance/RenderItemSorting.js +5 -1
  650. package/dist/performance/RenderItemSorting.js.map +1 -1
  651. package/dist/post/CubeLut.d.ts +15 -0
  652. package/dist/post/CubeLut.d.ts.map +1 -0
  653. package/dist/post/CubeLut.js +86 -0
  654. package/dist/post/CubeLut.js.map +1 -0
  655. package/dist/post/DisplayLutCache.d.ts +31 -0
  656. package/dist/post/DisplayLutCache.d.ts.map +1 -0
  657. package/dist/post/DisplayLutCache.js +44 -0
  658. package/dist/post/DisplayLutCache.js.map +1 -0
  659. package/dist/post/PostAntiAlias.d.ts +49 -0
  660. package/dist/post/PostAntiAlias.d.ts.map +1 -0
  661. package/dist/post/PostAntiAlias.js +75 -0
  662. package/dist/post/PostAntiAlias.js.map +1 -0
  663. package/dist/post/PostGraph.d.ts +206 -0
  664. package/dist/post/PostGraph.d.ts.map +1 -0
  665. package/dist/post/PostGraph.js +234 -0
  666. package/dist/post/PostGraph.js.map +1 -0
  667. package/dist/post/PostQualityTiers.d.ts +95 -0
  668. package/dist/post/PostQualityTiers.d.ts.map +1 -0
  669. package/dist/post/PostQualityTiers.js +62 -0
  670. package/dist/post/PostQualityTiers.js.map +1 -0
  671. package/dist/post/PostResources.d.ts +49 -0
  672. package/dist/post/PostResources.d.ts.map +1 -0
  673. package/dist/post/PostResources.js +119 -0
  674. package/dist/post/PostResources.js.map +1 -0
  675. package/dist/post/PostTimer.d.ts +37 -0
  676. package/dist/post/PostTimer.d.ts.map +1 -0
  677. package/dist/post/PostTimer.js +88 -0
  678. package/dist/post/PostTimer.js.map +1 -0
  679. package/dist/post/ScreenFeelPass.d.ts +83 -0
  680. package/dist/post/ScreenFeelPass.d.ts.map +1 -0
  681. package/dist/post/ScreenFeelPass.js +197 -0
  682. package/dist/post/ScreenFeelPass.js.map +1 -0
  683. package/dist/post/ToneOperators.d.ts +42 -0
  684. package/dist/post/ToneOperators.d.ts.map +1 -0
  685. package/dist/post/ToneOperators.js +179 -0
  686. package/dist/post/ToneOperators.js.map +1 -0
  687. package/dist/post/chunks/indirectFraction.glsl.d.ts +50 -0
  688. package/dist/post/chunks/indirectFraction.glsl.d.ts.map +1 -0
  689. package/dist/post/chunks/indirectFraction.glsl.js +82 -0
  690. package/dist/post/chunks/indirectFraction.glsl.js.map +1 -0
  691. package/dist/post/chunks/velocity.glsl.d.ts +35 -0
  692. package/dist/post/chunks/velocity.glsl.d.ts.map +1 -0
  693. package/dist/post/chunks/velocity.glsl.js +86 -0
  694. package/dist/post/chunks/velocity.glsl.js.map +1 -0
  695. package/dist/post/shaders/bloom.glsl.d.ts +21 -0
  696. package/dist/post/shaders/bloom.glsl.d.ts.map +1 -0
  697. package/dist/post/shaders/bloom.glsl.js +120 -0
  698. package/dist/post/shaders/bloom.glsl.js.map +1 -0
  699. package/dist/post/shaders/bloom.wgsl.d.ts +10 -0
  700. package/dist/post/shaders/bloom.wgsl.d.ts.map +1 -0
  701. package/dist/post/shaders/bloom.wgsl.js +121 -0
  702. package/dist/post/shaders/bloom.wgsl.js.map +1 -0
  703. package/dist/post/shaders/common.glsl.d.ts +11 -0
  704. package/dist/post/shaders/common.glsl.d.ts.map +1 -0
  705. package/dist/post/shaders/common.glsl.js +34 -0
  706. package/dist/post/shaders/common.glsl.js.map +1 -0
  707. package/dist/post/shaders/common.wgsl.d.ts +25 -0
  708. package/dist/post/shaders/common.wgsl.d.ts.map +1 -0
  709. package/dist/post/shaders/common.wgsl.js +48 -0
  710. package/dist/post/shaders/common.wgsl.js.map +1 -0
  711. package/dist/post/shaders/composite.glsl.d.ts +25 -0
  712. package/dist/post/shaders/composite.glsl.d.ts.map +1 -0
  713. package/dist/post/shaders/composite.glsl.js +96 -0
  714. package/dist/post/shaders/composite.glsl.js.map +1 -0
  715. package/dist/post/shaders/composite.wgsl.d.ts +10 -0
  716. package/dist/post/shaders/composite.wgsl.d.ts.map +1 -0
  717. package/dist/post/shaders/composite.wgsl.js +92 -0
  718. package/dist/post/shaders/composite.wgsl.js.map +1 -0
  719. package/dist/post/shaders/depthDownsample.glsl.d.ts +20 -0
  720. package/dist/post/shaders/depthDownsample.glsl.d.ts.map +1 -0
  721. package/dist/post/shaders/depthDownsample.glsl.js +78 -0
  722. package/dist/post/shaders/depthDownsample.glsl.js.map +1 -0
  723. package/dist/post/shaders/depthDownsample.wgsl.d.ts +17 -0
  724. package/dist/post/shaders/depthDownsample.wgsl.d.ts.map +1 -0
  725. package/dist/post/shaders/depthDownsample.wgsl.js +87 -0
  726. package/dist/post/shaders/depthDownsample.wgsl.js.map +1 -0
  727. package/dist/post/shaders/displayGrade.glsl.d.ts +18 -0
  728. package/dist/post/shaders/displayGrade.glsl.d.ts.map +1 -0
  729. package/dist/post/shaders/displayGrade.glsl.js +80 -0
  730. package/dist/post/shaders/displayGrade.glsl.js.map +1 -0
  731. package/dist/post/shaders/displayGrade.wgsl.d.ts +9 -0
  732. package/dist/post/shaders/displayGrade.wgsl.d.ts.map +1 -0
  733. package/dist/post/shaders/displayGrade.wgsl.js +75 -0
  734. package/dist/post/shaders/displayGrade.wgsl.js.map +1 -0
  735. package/dist/post/shaders/dof.glsl.d.ts +25 -0
  736. package/dist/post/shaders/dof.glsl.d.ts.map +1 -0
  737. package/dist/post/shaders/dof.glsl.js +129 -0
  738. package/dist/post/shaders/dof.glsl.js.map +1 -0
  739. package/dist/post/shaders/dof.wgsl.d.ts +11 -0
  740. package/dist/post/shaders/dof.wgsl.d.ts.map +1 -0
  741. package/dist/post/shaders/dof.wgsl.js +119 -0
  742. package/dist/post/shaders/dof.wgsl.js.map +1 -0
  743. package/dist/post/shaders/exposure.glsl.d.ts +43 -0
  744. package/dist/post/shaders/exposure.glsl.d.ts.map +1 -0
  745. package/dist/post/shaders/exposure.glsl.js +115 -0
  746. package/dist/post/shaders/exposure.glsl.js.map +1 -0
  747. package/dist/post/shaders/exposure.wgsl.d.ts +16 -0
  748. package/dist/post/shaders/exposure.wgsl.d.ts.map +1 -0
  749. package/dist/post/shaders/exposure.wgsl.js +97 -0
  750. package/dist/post/shaders/exposure.wgsl.js.map +1 -0
  751. package/dist/post/shaders/finalize.glsl.d.ts +17 -0
  752. package/dist/post/shaders/finalize.glsl.d.ts.map +1 -0
  753. package/dist/post/shaders/finalize.glsl.js +120 -0
  754. package/dist/post/shaders/finalize.glsl.js.map +1 -0
  755. package/dist/post/shaders/finalize.wgsl.d.ts +13 -0
  756. package/dist/post/shaders/finalize.wgsl.d.ts.map +1 -0
  757. package/dist/post/shaders/finalize.wgsl.js +124 -0
  758. package/dist/post/shaders/finalize.wgsl.js.map +1 -0
  759. package/dist/post/shaders/fxaa.glsl.d.ts +26 -0
  760. package/dist/post/shaders/fxaa.glsl.d.ts.map +1 -0
  761. package/dist/post/shaders/fxaa.glsl.js +246 -0
  762. package/dist/post/shaders/fxaa.glsl.js.map +1 -0
  763. package/dist/post/shaders/fxaa.wgsl.d.ts +17 -0
  764. package/dist/post/shaders/fxaa.wgsl.d.ts.map +1 -0
  765. package/dist/post/shaders/fxaa.wgsl.js +268 -0
  766. package/dist/post/shaders/fxaa.wgsl.js.map +1 -0
  767. package/dist/post/shaders/godrays.glsl.d.ts +16 -0
  768. package/dist/post/shaders/godrays.glsl.d.ts.map +1 -0
  769. package/dist/post/shaders/godrays.glsl.js +70 -0
  770. package/dist/post/shaders/godrays.glsl.js.map +1 -0
  771. package/dist/post/shaders/godrays.wgsl.d.ts +8 -0
  772. package/dist/post/shaders/godrays.wgsl.d.ts.map +1 -0
  773. package/dist/post/shaders/godrays.wgsl.js +60 -0
  774. package/dist/post/shaders/godrays.wgsl.js.map +1 -0
  775. package/dist/post/shaders/gtao.glsl.d.ts +29 -0
  776. package/dist/post/shaders/gtao.glsl.d.ts.map +1 -0
  777. package/dist/post/shaders/gtao.glsl.js +190 -0
  778. package/dist/post/shaders/gtao.glsl.js.map +1 -0
  779. package/dist/post/shaders/gtao.wgsl.d.ts +13 -0
  780. package/dist/post/shaders/gtao.wgsl.d.ts.map +1 -0
  781. package/dist/post/shaders/gtao.wgsl.js +163 -0
  782. package/dist/post/shaders/gtao.wgsl.js.map +1 -0
  783. package/dist/post/shaders/gtaoDenoise.glsl.d.ts +22 -0
  784. package/dist/post/shaders/gtaoDenoise.glsl.d.ts.map +1 -0
  785. package/dist/post/shaders/gtaoDenoise.glsl.js +121 -0
  786. package/dist/post/shaders/gtaoDenoise.glsl.js.map +1 -0
  787. package/dist/post/shaders/gtaoDenoise.wgsl.d.ts +11 -0
  788. package/dist/post/shaders/gtaoDenoise.wgsl.d.ts.map +1 -0
  789. package/dist/post/shaders/gtaoDenoise.wgsl.js +117 -0
  790. package/dist/post/shaders/gtaoDenoise.wgsl.js.map +1 -0
  791. package/dist/post/shaders/motionBlur.glsl.d.ts +21 -0
  792. package/dist/post/shaders/motionBlur.glsl.d.ts.map +1 -0
  793. package/dist/post/shaders/motionBlur.glsl.js +110 -0
  794. package/dist/post/shaders/motionBlur.glsl.js.map +1 -0
  795. package/dist/post/shaders/motionBlur.wgsl.d.ts +10 -0
  796. package/dist/post/shaders/motionBlur.wgsl.d.ts.map +1 -0
  797. package/dist/post/shaders/motionBlur.wgsl.js +102 -0
  798. package/dist/post/shaders/motionBlur.wgsl.js.map +1 -0
  799. package/dist/post/shaders/smaa.glsl.d.ts +28 -0
  800. package/dist/post/shaders/smaa.glsl.d.ts.map +1 -0
  801. package/dist/post/shaders/smaa.glsl.js +354 -0
  802. package/dist/post/shaders/smaa.glsl.js.map +1 -0
  803. package/dist/post/shaders/smaa.wgsl.d.ts +20 -0
  804. package/dist/post/shaders/smaa.wgsl.d.ts.map +1 -0
  805. package/dist/post/shaders/smaa.wgsl.js +375 -0
  806. package/dist/post/shaders/smaa.wgsl.js.map +1 -0
  807. package/dist/post/shaders/taa.glsl.d.ts +23 -0
  808. package/dist/post/shaders/taa.glsl.d.ts.map +1 -0
  809. package/dist/post/shaders/taa.glsl.js +169 -0
  810. package/dist/post/shaders/taa.glsl.js.map +1 -0
  811. package/dist/post/shaders/taa.wgsl.d.ts +10 -0
  812. package/dist/post/shaders/taa.wgsl.d.ts.map +1 -0
  813. package/dist/post/shaders/taa.wgsl.js +185 -0
  814. package/dist/post/shaders/taa.wgsl.js.map +1 -0
  815. package/dist/post/shaders/velocityDilate.glsl.d.ts +16 -0
  816. package/dist/post/shaders/velocityDilate.glsl.d.ts.map +1 -0
  817. package/dist/post/shaders/velocityDilate.glsl.js +45 -0
  818. package/dist/post/shaders/velocityDilate.glsl.js.map +1 -0
  819. package/dist/post/shaders/velocityDilate.wgsl.d.ts +8 -0
  820. package/dist/post/shaders/velocityDilate.wgsl.d.ts.map +1 -0
  821. package/dist/post/shaders/velocityDilate.wgsl.js +30 -0
  822. package/dist/post/shaders/velocityDilate.wgsl.js.map +1 -0
  823. package/dist/post/smaa/textures.d.ts +17 -0
  824. package/dist/post/smaa/textures.d.ts.map +1 -0
  825. package/dist/post/smaa/textures.js +17 -0
  826. package/dist/post/smaa/textures.js.map +1 -0
  827. package/dist/post/v2Entry.d.ts +25 -0
  828. package/dist/post/v2Entry.d.ts.map +1 -0
  829. package/dist/post/v2Entry.js +28 -0
  830. package/dist/post/v2Entry.js.map +1 -0
  831. package/dist/post/v2Stages.d.ts +156 -0
  832. package/dist/post/v2Stages.d.ts.map +1 -0
  833. package/dist/post/v2Stages.js +1189 -0
  834. package/dist/post/v2Stages.js.map +1 -0
  835. package/dist/postprocess/EffectComposer.d.ts +6 -109
  836. package/dist/postprocess/EffectComposer.d.ts.map +1 -1
  837. package/dist/postprocess/EffectComposer.js +6 -246
  838. package/dist/postprocess/EffectComposer.js.map +1 -1
  839. package/dist/postprocess/NativeBloomPyramid.d.ts +34 -0
  840. package/dist/postprocess/NativeBloomPyramid.d.ts.map +1 -1
  841. package/dist/postprocess/NativeBloomPyramid.js +57 -0
  842. package/dist/postprocess/NativeBloomPyramid.js.map +1 -1
  843. package/dist/postprocess/SSAOPass.d.ts +5 -5
  844. package/dist/postprocess/SSAOPass.d.ts.map +1 -1
  845. package/dist/postprocess/SSAOPass.js +5 -17
  846. package/dist/postprocess/SSAOPass.js.map +1 -1
  847. package/dist/probes/IrradianceVolume.d.ts +45 -0
  848. package/dist/probes/IrradianceVolume.d.ts.map +1 -0
  849. package/dist/probes/IrradianceVolume.js +230 -0
  850. package/dist/probes/IrradianceVolume.js.map +1 -0
  851. package/dist/probes/LtcLuts.d.ts +30 -0
  852. package/dist/probes/LtcLuts.d.ts.map +1 -0
  853. package/dist/probes/LtcLuts.js +120 -0
  854. package/dist/probes/LtcLuts.js.map +1 -0
  855. package/dist/probes/Prd02ProbesContributor.d.ts +53 -0
  856. package/dist/probes/Prd02ProbesContributor.d.ts.map +1 -0
  857. package/dist/probes/Prd02ProbesContributor.js +241 -0
  858. package/dist/probes/Prd02ProbesContributor.js.map +1 -0
  859. package/dist/probes/ProbeBoxProjection.d.ts +53 -0
  860. package/dist/probes/ProbeBoxProjection.d.ts.map +1 -0
  861. package/dist/probes/ProbeBoxProjection.js +99 -0
  862. package/dist/probes/ProbeBoxProjection.js.map +1 -0
  863. package/dist/probes/ReflectionProbeSystem.d.ts +64 -0
  864. package/dist/probes/ReflectionProbeSystem.d.ts.map +1 -0
  865. package/dist/probes/ReflectionProbeSystem.js +157 -0
  866. package/dist/probes/ReflectionProbeSystem.js.map +1 -0
  867. package/dist/production-runtime/PBRHDRPipeline.d.ts.map +1 -1
  868. package/dist/production-runtime/PBRHDRPipeline.js +23 -9
  869. package/dist/production-runtime/PBRHDRPipeline.js.map +1 -1
  870. package/dist/production-runtime/ProductionRendererTypes.d.ts +16 -6
  871. package/dist/production-runtime/ProductionRendererTypes.d.ts.map +1 -1
  872. package/dist/production-runtime/ProductionRendererTypes.js.map +1 -1
  873. package/dist/production-runtime/ProductionWebGPURenderer.d.ts +4 -4
  874. package/dist/production-runtime/ProductionWebGPURenderer.d.ts.map +1 -1
  875. package/dist/production-runtime/ProductionWebGPURenderer.js +10 -45
  876. package/dist/production-runtime/ProductionWebGPURenderer.js.map +1 -1
  877. package/dist/production-runtime/backendSelection.d.ts +26 -0
  878. package/dist/production-runtime/backendSelection.d.ts.map +1 -0
  879. package/dist/production-runtime/backendSelection.js +46 -0
  880. package/dist/production-runtime/backendSelection.js.map +1 -0
  881. package/dist/production-runtime/backends/WebGL2RendererBackend.d.ts +1 -1
  882. package/dist/production-runtime/backends/WebGL2RendererBackend.d.ts.map +1 -1
  883. package/dist/production-runtime/backends/WebGL2RendererBackend.js +8 -4
  884. package/dist/production-runtime/backends/WebGL2RendererBackend.js.map +1 -1
  885. package/dist/production-runtime/backends/WebGPURendererBackend.d.ts +2 -19
  886. package/dist/production-runtime/backends/WebGPURendererBackend.d.ts.map +1 -1
  887. package/dist/production-runtime/backends/WebGPURendererBackend.js +2 -18
  888. package/dist/production-runtime/backends/WebGPURendererBackend.js.map +1 -1
  889. package/dist/production-runtime/backends/webgl2/WebGL2Buffer.d.ts +2 -10
  890. package/dist/production-runtime/backends/webgl2/WebGL2Buffer.d.ts.map +1 -1
  891. package/dist/production-runtime/backends/webgl2/WebGL2Buffer.js +2 -7
  892. package/dist/production-runtime/backends/webgl2/WebGL2Buffer.js.map +1 -1
  893. package/dist/production-runtime/backends/webgl2/WebGL2Capabilities.d.ts +2 -10
  894. package/dist/production-runtime/backends/webgl2/WebGL2Capabilities.d.ts.map +1 -1
  895. package/dist/production-runtime/backends/webgl2/WebGL2Capabilities.js +2 -7
  896. package/dist/production-runtime/backends/webgl2/WebGL2Capabilities.js.map +1 -1
  897. package/dist/production-runtime/backends/webgl2/WebGL2RenderTarget.d.ts +2 -10
  898. package/dist/production-runtime/backends/webgl2/WebGL2RenderTarget.d.ts.map +1 -1
  899. package/dist/production-runtime/backends/webgl2/WebGL2RenderTarget.js +2 -7
  900. package/dist/production-runtime/backends/webgl2/WebGL2RenderTarget.js.map +1 -1
  901. package/dist/production-runtime/backends/webgl2/WebGL2Shader.d.ts +2 -10
  902. package/dist/production-runtime/backends/webgl2/WebGL2Shader.d.ts.map +1 -1
  903. package/dist/production-runtime/backends/webgl2/WebGL2Shader.js +2 -7
  904. package/dist/production-runtime/backends/webgl2/WebGL2Shader.js.map +1 -1
  905. package/dist/production-runtime/backends/webgl2/WebGL2StateCache.d.ts +1 -0
  906. package/dist/production-runtime/backends/webgl2/WebGL2StateCache.d.ts.map +1 -1
  907. package/dist/production-runtime/backends/webgl2/WebGL2StateCache.js +1 -0
  908. package/dist/production-runtime/backends/webgl2/WebGL2StateCache.js.map +1 -1
  909. package/dist/production-runtime/backends/webgl2/WebGL2Texture.d.ts +2 -10
  910. package/dist/production-runtime/backends/webgl2/WebGL2Texture.d.ts.map +1 -1
  911. package/dist/production-runtime/backends/webgl2/WebGL2Texture.js +2 -7
  912. package/dist/production-runtime/backends/webgl2/WebGL2Texture.js.map +1 -1
  913. package/dist/production-runtime/backends/webgpu/WebGPUBuffer.d.ts +2 -10
  914. package/dist/production-runtime/backends/webgpu/WebGPUBuffer.d.ts.map +1 -1
  915. package/dist/production-runtime/backends/webgpu/WebGPUBuffer.js +2 -7
  916. package/dist/production-runtime/backends/webgpu/WebGPUBuffer.js.map +1 -1
  917. package/dist/production-runtime/backends/webgpu/WebGPUCapabilities.d.ts +2 -10
  918. package/dist/production-runtime/backends/webgpu/WebGPUCapabilities.d.ts.map +1 -1
  919. package/dist/production-runtime/backends/webgpu/WebGPUCapabilities.js +2 -7
  920. package/dist/production-runtime/backends/webgpu/WebGPUCapabilities.js.map +1 -1
  921. package/dist/production-runtime/backends/webgpu/WebGPURenderTarget.d.ts +2 -10
  922. package/dist/production-runtime/backends/webgpu/WebGPURenderTarget.d.ts.map +1 -1
  923. package/dist/production-runtime/backends/webgpu/WebGPURenderTarget.js +2 -7
  924. package/dist/production-runtime/backends/webgpu/WebGPURenderTarget.js.map +1 -1
  925. package/dist/production-runtime/backends/webgpu/WebGPUShader.d.ts +2 -10
  926. package/dist/production-runtime/backends/webgpu/WebGPUShader.d.ts.map +1 -1
  927. package/dist/production-runtime/backends/webgpu/WebGPUShader.js +2 -7
  928. package/dist/production-runtime/backends/webgpu/WebGPUShader.js.map +1 -1
  929. package/dist/production-runtime/backends/webgpu/WebGPUTexture.d.ts +2 -10
  930. package/dist/production-runtime/backends/webgpu/WebGPUTexture.d.ts.map +1 -1
  931. package/dist/production-runtime/backends/webgpu/WebGPUTexture.js +2 -7
  932. package/dist/production-runtime/backends/webgpu/WebGPUTexture.js.map +1 -1
  933. package/dist/production-runtime/index.d.ts +6 -6
  934. package/dist/production-runtime/index.d.ts.map +1 -1
  935. package/dist/production-runtime/index.js +9 -3
  936. package/dist/production-runtime/index.js.map +1 -1
  937. package/dist/production-runtime/materials/GLTFMaterialAdapter.d.ts +12 -13
  938. package/dist/production-runtime/materials/GLTFMaterialAdapter.d.ts.map +1 -1
  939. package/dist/production-runtime/materials/GLTFMaterialAdapter.js +10 -4
  940. package/dist/production-runtime/materials/GLTFMaterialAdapter.js.map +1 -1
  941. package/dist/production-runtime/materials/GLTFPBRMaterialAdapter.d.ts +9 -2
  942. package/dist/production-runtime/materials/GLTFPBRMaterialAdapter.d.ts.map +1 -1
  943. package/dist/production-runtime/materials/GLTFPBRMaterialAdapter.js +7 -1
  944. package/dist/production-runtime/materials/GLTFPBRMaterialAdapter.js.map +1 -1
  945. package/dist/production-runtime/materials/MaterialCompiler.d.ts +10 -8
  946. package/dist/production-runtime/materials/MaterialCompiler.d.ts.map +1 -1
  947. package/dist/production-runtime/materials/MaterialCompiler.js +9 -4
  948. package/dist/production-runtime/materials/MaterialCompiler.js.map +1 -1
  949. package/dist/production-runtime/materials/PBRShaderFeatures.d.ts.map +1 -1
  950. package/dist/production-runtime/materials/PBRShaderFeatures.js +30 -1
  951. package/dist/production-runtime/materials/PBRShaderFeatures.js.map +1 -1
  952. package/dist/production-runtime/renderProofs.d.ts +54 -0
  953. package/dist/production-runtime/renderProofs.d.ts.map +1 -0
  954. package/dist/production-runtime/renderProofs.js +245 -0
  955. package/dist/production-runtime/renderProofs.js.map +1 -0
  956. package/dist/program/DFGLut.d.ts +23 -0
  957. package/dist/program/DFGLut.d.ts.map +1 -0
  958. package/dist/program/DFGLut.js +58 -0
  959. package/dist/program/DFGLut.js.map +1 -0
  960. package/dist/program/DFGLutData.d.ts +35 -0
  961. package/dist/program/DFGLutData.d.ts.map +1 -0
  962. package/dist/program/DFGLutData.js +52 -0
  963. package/dist/program/DFGLutData.js.map +1 -0
  964. package/dist/program/FeatureSelect.d.ts +35 -0
  965. package/dist/program/FeatureSelect.d.ts.map +1 -0
  966. package/dist/program/FeatureSelect.js +88 -0
  967. package/dist/program/FeatureSelect.js.map +1 -0
  968. package/dist/program/MaterialFeatures.d.ts +66 -0
  969. package/dist/program/MaterialFeatures.d.ts.map +1 -0
  970. package/dist/program/MaterialFeatures.js +242 -0
  971. package/dist/program/MaterialFeatures.js.map +1 -0
  972. package/dist/program/ProgramCache.d.ts +83 -0
  973. package/dist/program/ProgramCache.d.ts.map +1 -0
  974. package/dist/program/ProgramCache.js +194 -0
  975. package/dist/program/ProgramCache.js.map +1 -0
  976. package/dist/program/ProgramFeatures.d.ts +21 -0
  977. package/dist/program/ProgramFeatures.d.ts.map +1 -0
  978. package/dist/program/ProgramFeatures.js +95 -0
  979. package/dist/program/ProgramFeatures.js.map +1 -0
  980. package/dist/program/ProgramGenerator.d.ts +60 -0
  981. package/dist/program/ProgramGenerator.d.ts.map +1 -0
  982. package/dist/program/ProgramGenerator.js +760 -0
  983. package/dist/program/ProgramGenerator.js.map +1 -0
  984. package/dist/program/ProgramKey.d.ts +10 -0
  985. package/dist/program/ProgramKey.d.ts.map +1 -0
  986. package/dist/program/ProgramKey.js +13 -0
  987. package/dist/program/ProgramKey.js.map +1 -0
  988. package/dist/program/ProgramWarmup.d.ts +37 -0
  989. package/dist/program/ProgramWarmup.d.ts.map +1 -0
  990. package/dist/program/ProgramWarmup.js +68 -0
  991. package/dist/program/ProgramWarmup.js.map +1 -0
  992. package/dist/program/UniformLayout.d.ts +40 -0
  993. package/dist/program/UniformLayout.d.ts.map +1 -0
  994. package/dist/program/UniformLayout.js +105 -0
  995. package/dist/program/UniformLayout.js.map +1 -0
  996. package/dist/program/chunks/alpha.glsl.d.ts +7 -0
  997. package/dist/program/chunks/alpha.glsl.d.ts.map +1 -0
  998. package/dist/program/chunks/alpha.glsl.js +17 -0
  999. package/dist/program/chunks/alpha.glsl.js.map +1 -0
  1000. package/dist/program/chunks/brdf.glsl.d.ts +12 -0
  1001. package/dist/program/chunks/brdf.glsl.d.ts.map +1 -0
  1002. package/dist/program/chunks/brdf.glsl.js +144 -0
  1003. package/dist/program/chunks/brdf.glsl.js.map +1 -0
  1004. package/dist/program/chunks/colorspace.glsl.d.ts +8 -0
  1005. package/dist/program/chunks/colorspace.glsl.d.ts.map +1 -0
  1006. package/dist/program/chunks/colorspace.glsl.js +16 -0
  1007. package/dist/program/chunks/colorspace.glsl.js.map +1 -0
  1008. package/dist/program/chunks/common.glsl.d.ts +7 -0
  1009. package/dist/program/chunks/common.glsl.d.ts.map +1 -0
  1010. package/dist/program/chunks/common.glsl.js +25 -0
  1011. package/dist/program/chunks/common.glsl.js.map +1 -0
  1012. package/dist/program/chunks/depth.glsl.d.ts +9 -0
  1013. package/dist/program/chunks/depth.glsl.d.ts.map +1 -0
  1014. package/dist/program/chunks/depth.glsl.js +18 -0
  1015. package/dist/program/chunks/depth.glsl.js.map +1 -0
  1016. package/dist/program/chunks/drawId.wgsl.d.ts +9 -0
  1017. package/dist/program/chunks/drawId.wgsl.d.ts.map +1 -0
  1018. package/dist/program/chunks/drawId.wgsl.js +29 -0
  1019. package/dist/program/chunks/drawId.wgsl.js.map +1 -0
  1020. package/dist/program/chunks/fog_default.glsl.d.ts +8 -0
  1021. package/dist/program/chunks/fog_default.glsl.d.ts.map +1 -0
  1022. package/dist/program/chunks/fog_default.glsl.js +31 -0
  1023. package/dist/program/chunks/fog_default.glsl.js.map +1 -0
  1024. package/dist/program/chunks/indirect_default.glsl.d.ts +29 -0
  1025. package/dist/program/chunks/indirect_default.glsl.d.ts.map +1 -0
  1026. package/dist/program/chunks/indirect_default.glsl.js +113 -0
  1027. package/dist/program/chunks/indirect_default.glsl.js.map +1 -0
  1028. package/dist/program/chunks/instanceEmissive.wgsl.d.ts +10 -0
  1029. package/dist/program/chunks/instanceEmissive.wgsl.d.ts.map +1 -0
  1030. package/dist/program/chunks/instanceEmissive.wgsl.js +21 -0
  1031. package/dist/program/chunks/instanceEmissive.wgsl.js.map +1 -0
  1032. package/dist/program/chunks/instancing.glsl.d.ts +8 -0
  1033. package/dist/program/chunks/instancing.glsl.d.ts.map +1 -0
  1034. package/dist/program/chunks/instancing.glsl.js +25 -0
  1035. package/dist/program/chunks/instancing.glsl.js.map +1 -0
  1036. package/dist/program/chunks/lights_legacy.glsl.d.ts +15 -0
  1037. package/dist/program/chunks/lights_legacy.glsl.d.ts.map +1 -0
  1038. package/dist/program/chunks/lights_legacy.glsl.js +95 -0
  1039. package/dist/program/chunks/lights_legacy.glsl.js.map +1 -0
  1040. package/dist/program/chunks/manifest.d.ts +42 -0
  1041. package/dist/program/chunks/manifest.d.ts.map +1 -0
  1042. package/dist/program/chunks/manifest.js +48 -0
  1043. package/dist/program/chunks/manifest.js.map +1 -0
  1044. package/dist/program/chunks/normal.glsl.d.ts +8 -0
  1045. package/dist/program/chunks/normal.glsl.d.ts.map +1 -0
  1046. package/dist/program/chunks/normal.glsl.js +34 -0
  1047. package/dist/program/chunks/normal.glsl.js.map +1 -0
  1048. package/dist/program/chunks/shadow_forward.glsl.d.ts +23 -0
  1049. package/dist/program/chunks/shadow_forward.glsl.d.ts.map +1 -0
  1050. package/dist/program/chunks/shadow_forward.glsl.js +73 -0
  1051. package/dist/program/chunks/shadow_forward.glsl.js.map +1 -0
  1052. package/dist/quality/DeviceClasses.d.ts +31 -0
  1053. package/dist/quality/DeviceClasses.d.ts.map +1 -0
  1054. package/dist/quality/DeviceClasses.js +83 -0
  1055. package/dist/quality/DeviceClasses.js.map +1 -0
  1056. package/dist/quality/DeviceProbe.d.ts +42 -0
  1057. package/dist/quality/DeviceProbe.d.ts.map +1 -0
  1058. package/dist/quality/DeviceProbe.js +83 -0
  1059. package/dist/quality/DeviceProbe.js.map +1 -0
  1060. package/dist/quality/FrameStats.d.ts +62 -0
  1061. package/dist/quality/FrameStats.d.ts.map +1 -0
  1062. package/dist/quality/FrameStats.js +220 -0
  1063. package/dist/quality/FrameStats.js.map +1 -0
  1064. package/dist/quality/PostprocessGuard.d.ts +49 -0
  1065. package/dist/quality/PostprocessGuard.d.ts.map +1 -0
  1066. package/dist/quality/PostprocessGuard.js +92 -0
  1067. package/dist/quality/PostprocessGuard.js.map +1 -0
  1068. package/dist/quality/QualityController.d.ts +93 -0
  1069. package/dist/quality/QualityController.d.ts.map +1 -0
  1070. package/dist/quality/QualityController.js +248 -0
  1071. package/dist/quality/QualityController.js.map +1 -0
  1072. package/dist/quality/QualityGovernor.d.ts +78 -0
  1073. package/dist/quality/QualityGovernor.d.ts.map +1 -0
  1074. package/dist/quality/QualityGovernor.js +170 -0
  1075. package/dist/quality/QualityGovernor.js.map +1 -0
  1076. package/dist/quality/QualityTier.d.ts +17 -0
  1077. package/dist/quality/QualityTier.d.ts.map +1 -0
  1078. package/dist/quality/QualityTier.js +23 -0
  1079. package/dist/quality/QualityTier.js.map +1 -0
  1080. package/dist/quality/RenderScaleController.d.ts +35 -0
  1081. package/dist/quality/RenderScaleController.d.ts.map +1 -0
  1082. package/dist/quality/RenderScaleController.js +57 -0
  1083. package/dist/quality/RenderScaleController.js.map +1 -0
  1084. package/dist/quality/RetentionPolicy.d.ts +11 -0
  1085. package/dist/quality/RetentionPolicy.d.ts.map +1 -0
  1086. package/dist/quality/RetentionPolicy.js +12 -0
  1087. package/dist/quality/RetentionPolicy.js.map +1 -0
  1088. package/dist/quality/TierResolver.d.ts +52 -0
  1089. package/dist/quality/TierResolver.d.ts.map +1 -0
  1090. package/dist/quality/TierResolver.js +155 -0
  1091. package/dist/quality/TierResolver.js.map +1 -0
  1092. package/dist/quality/liveTier.d.ts +23 -0
  1093. package/dist/quality/liveTier.d.ts.map +1 -0
  1094. package/dist/quality/liveTier.js +16 -0
  1095. package/dist/quality/liveTier.js.map +1 -0
  1096. package/dist/reference/BloomPass.d.ts +10 -0
  1097. package/dist/reference/BloomPass.d.ts.map +1 -0
  1098. package/dist/reference/BloomPass.js +18 -0
  1099. package/dist/reference/BloomPass.js.map +1 -0
  1100. package/dist/reference/DepthHazePass.d.ts +12 -0
  1101. package/dist/reference/DepthHazePass.d.ts.map +1 -0
  1102. package/dist/reference/DepthHazePass.js +20 -0
  1103. package/dist/reference/DepthHazePass.js.map +1 -0
  1104. package/dist/reference/EffectComposer.d.ts +110 -0
  1105. package/dist/reference/EffectComposer.d.ts.map +1 -0
  1106. package/dist/reference/EffectComposer.js +247 -0
  1107. package/dist/reference/EffectComposer.js.map +1 -0
  1108. package/dist/reference/FilmGrainPass.d.ts +9 -0
  1109. package/dist/reference/FilmGrainPass.d.ts.map +1 -0
  1110. package/dist/reference/FilmGrainPass.js +17 -0
  1111. package/dist/reference/FilmGrainPass.js.map +1 -0
  1112. package/dist/reference/PostProcessPass.d.ts +511 -0
  1113. package/dist/reference/PostProcessPass.d.ts.map +1 -0
  1114. package/dist/reference/PostProcessPass.js +2020 -0
  1115. package/dist/reference/PostProcessPass.js.map +1 -0
  1116. package/dist/reference/SSAOPass.d.ts +6 -0
  1117. package/dist/reference/SSAOPass.d.ts.map +1 -0
  1118. package/dist/reference/SSAOPass.js +18 -0
  1119. package/dist/reference/SSAOPass.js.map +1 -0
  1120. package/dist/reference/VignettePass.d.ts +10 -0
  1121. package/dist/reference/VignettePass.d.ts.map +1 -0
  1122. package/dist/reference/VignettePass.js +17 -0
  1123. package/dist/reference/VignettePass.js.map +1 -0
  1124. package/dist/reference/index.d.ts +15 -0
  1125. package/dist/reference/index.d.ts.map +1 -0
  1126. package/dist/reference/index.js +15 -0
  1127. package/dist/reference/index.js.map +1 -0
  1128. package/dist/renderer/Background.d.ts +49 -0
  1129. package/dist/renderer/Background.d.ts.map +1 -0
  1130. package/dist/renderer/Background.js +259 -0
  1131. package/dist/renderer/Background.js.map +1 -0
  1132. package/dist/renderer/CullingBatching.d.ts +55 -0
  1133. package/dist/renderer/CullingBatching.d.ts.map +1 -0
  1134. package/dist/renderer/CullingBatching.js +362 -0
  1135. package/dist/renderer/CullingBatching.js.map +1 -0
  1136. package/dist/renderer/DeviceLifecycle.d.ts +29 -0
  1137. package/dist/renderer/DeviceLifecycle.d.ts.map +1 -0
  1138. package/dist/renderer/DeviceLifecycle.js +48 -0
  1139. package/dist/renderer/DeviceLifecycle.js.map +1 -0
  1140. package/dist/renderer/FrameGraph.d.ts +96 -0
  1141. package/dist/renderer/FrameGraph.d.ts.map +1 -0
  1142. package/dist/renderer/FrameGraph.js +301 -0
  1143. package/dist/renderer/FrameGraph.js.map +1 -0
  1144. package/dist/renderer/InterleavedTransparentPass.d.ts +31 -0
  1145. package/dist/renderer/InterleavedTransparentPass.d.ts.map +1 -0
  1146. package/dist/renderer/InterleavedTransparentPass.js +65 -0
  1147. package/dist/renderer/InterleavedTransparentPass.js.map +1 -0
  1148. package/dist/renderer/PixelRatio.d.ts +64 -0
  1149. package/dist/renderer/PixelRatio.d.ts.map +1 -0
  1150. package/dist/renderer/PixelRatio.js +81 -0
  1151. package/dist/renderer/PixelRatio.js.map +1 -0
  1152. package/dist/renderer/PostprocessExecution.d.ts +82 -0
  1153. package/dist/renderer/PostprocessExecution.d.ts.map +1 -0
  1154. package/dist/renderer/PostprocessExecution.js +741 -0
  1155. package/dist/renderer/PostprocessExecution.js.map +1 -0
  1156. package/dist/renderer/Prd06ShaderWarmup.d.ts +32 -0
  1157. package/dist/renderer/Prd06ShaderWarmup.d.ts.map +1 -0
  1158. package/dist/renderer/Prd06ShaderWarmup.js +45 -0
  1159. package/dist/renderer/Prd06ShaderWarmup.js.map +1 -0
  1160. package/dist/renderer/RenderShared.d.ts +11 -0
  1161. package/dist/renderer/RenderShared.d.ts.map +1 -0
  1162. package/dist/renderer/RenderShared.js +47 -0
  1163. package/dist/renderer/RenderShared.js.map +1 -0
  1164. package/dist/renderer/RendererFactory.d.ts +3 -0
  1165. package/dist/renderer/RendererFactory.d.ts.map +1 -0
  1166. package/dist/renderer/RendererFactory.js +19 -0
  1167. package/dist/renderer/RendererFactory.js.map +1 -0
  1168. package/dist/renderer/RendererHost.d.ts +25 -0
  1169. package/dist/renderer/RendererHost.d.ts.map +1 -0
  1170. package/dist/renderer/RendererHost.js +4 -0
  1171. package/dist/renderer/RendererHost.js.map +1 -0
  1172. package/dist/renderer/SceneDepthCopyPass.d.ts +50 -0
  1173. package/dist/renderer/SceneDepthCopyPass.d.ts.map +1 -0
  1174. package/dist/renderer/SceneDepthCopyPass.js +124 -0
  1175. package/dist/renderer/SceneDepthCopyPass.js.map +1 -0
  1176. package/dist/renderer/ShadowOrchestration.d.ts +32 -0
  1177. package/dist/renderer/ShadowOrchestration.d.ts.map +1 -0
  1178. package/dist/renderer/ShadowOrchestration.js +491 -0
  1179. package/dist/renderer/ShadowOrchestration.js.map +1 -0
  1180. package/dist/renderer/SkinnedBounds.d.ts +6 -0
  1181. package/dist/renderer/SkinnedBounds.d.ts.map +1 -0
  1182. package/dist/renderer/SkinnedBounds.js +74 -0
  1183. package/dist/renderer/SkinnedBounds.js.map +1 -0
  1184. package/dist/renderer/coreOutputPostRoute.d.ts +40 -0
  1185. package/dist/renderer/coreOutputPostRoute.d.ts.map +1 -0
  1186. package/dist/renderer/coreOutputPostRoute.js +46 -0
  1187. package/dist/renderer/coreOutputPostRoute.js.map +1 -0
  1188. package/dist/renderer/postSkipped.d.ts +12 -0
  1189. package/dist/renderer/postSkipped.d.ts.map +1 -0
  1190. package/dist/renderer/postSkipped.js +54 -0
  1191. package/dist/renderer/postSkipped.js.map +1 -0
  1192. package/dist/renderer/qrSubFlags.d.ts +45 -0
  1193. package/dist/renderer/qrSubFlags.d.ts.map +1 -0
  1194. package/dist/renderer/qrSubFlags.js +130 -0
  1195. package/dist/renderer/qrSubFlags.js.map +1 -0
  1196. package/dist/resources/InstanceBuffer.d.ts +34 -0
  1197. package/dist/resources/InstanceBuffer.d.ts.map +1 -0
  1198. package/dist/resources/InstanceBuffer.js +96 -0
  1199. package/dist/resources/InstanceBuffer.js.map +1 -0
  1200. package/dist/resources/MorphTargetTexture.d.ts +53 -0
  1201. package/dist/resources/MorphTargetTexture.d.ts.map +1 -0
  1202. package/dist/resources/MorphTargetTexture.js +135 -0
  1203. package/dist/resources/MorphTargetTexture.js.map +1 -0
  1204. package/dist/resources/RenderTargetPool.d.ts +47 -0
  1205. package/dist/resources/RenderTargetPool.d.ts.map +1 -0
  1206. package/dist/resources/RenderTargetPool.js +113 -0
  1207. package/dist/resources/RenderTargetPool.js.map +1 -0
  1208. package/dist/resources/ResourceRegistry.d.ts +48 -0
  1209. package/dist/resources/ResourceRegistry.d.ts.map +1 -0
  1210. package/dist/resources/ResourceRegistry.js +95 -0
  1211. package/dist/resources/ResourceRegistry.js.map +1 -0
  1212. package/dist/resources/UniformBlock.d.ts +90 -0
  1213. package/dist/resources/UniformBlock.d.ts.map +1 -0
  1214. package/dist/resources/UniformBlock.js +184 -0
  1215. package/dist/resources/UniformBlock.js.map +1 -0
  1216. package/dist/shaders/camera-fade.glsl.d.ts +26 -0
  1217. package/dist/shaders/camera-fade.glsl.d.ts.map +1 -0
  1218. package/dist/shaders/camera-fade.glsl.js +109 -0
  1219. package/dist/shaders/camera-fade.glsl.js.map +1 -0
  1220. package/dist/shaders/chunks/contact_shadow.glsl.d.ts +12 -0
  1221. package/dist/shaders/chunks/contact_shadow.glsl.d.ts.map +1 -0
  1222. package/dist/shaders/chunks/contact_shadow.glsl.js +53 -0
  1223. package/dist/shaders/chunks/contact_shadow.glsl.js.map +1 -0
  1224. package/dist/shaders/chunks/lighting_ibl.glsl.d.ts +29 -0
  1225. package/dist/shaders/chunks/lighting_ibl.glsl.d.ts.map +1 -0
  1226. package/dist/shaders/chunks/lighting_ibl.glsl.js +122 -0
  1227. package/dist/shaders/chunks/lighting_ibl.glsl.js.map +1 -0
  1228. package/dist/shaders/chunks/lighting_mirrors.d.ts +18 -0
  1229. package/dist/shaders/chunks/lighting_mirrors.d.ts.map +1 -0
  1230. package/dist/shaders/chunks/lighting_mirrors.js +35 -0
  1231. package/dist/shaders/chunks/lighting_mirrors.js.map +1 -0
  1232. package/dist/shaders/chunks/lighting_punctual.glsl.d.ts +17 -0
  1233. package/dist/shaders/chunks/lighting_punctual.glsl.d.ts.map +1 -0
  1234. package/dist/shaders/chunks/lighting_punctual.glsl.js +197 -0
  1235. package/dist/shaders/chunks/lighting_punctual.glsl.js.map +1 -0
  1236. package/dist/shaders/chunks/sh9.glsl.d.ts +9 -0
  1237. package/dist/shaders/chunks/sh9.glsl.d.ts.map +1 -0
  1238. package/dist/shaders/chunks/sh9.glsl.js +41 -0
  1239. package/dist/shaders/chunks/sh9.glsl.js.map +1 -0
  1240. package/dist/shaders/chunks/shadow_caster.glsl.d.ts +10 -0
  1241. package/dist/shaders/chunks/shadow_caster.glsl.d.ts.map +1 -0
  1242. package/dist/shaders/chunks/shadow_caster.glsl.js +32 -0
  1243. package/dist/shaders/chunks/shadow_caster.glsl.js.map +1 -0
  1244. package/dist/shaders/chunks/shadow_receive.glsl.d.ts +13 -0
  1245. package/dist/shaders/chunks/shadow_receive.glsl.d.ts.map +1 -0
  1246. package/dist/shaders/chunks/shadow_receive.glsl.js +136 -0
  1247. package/dist/shaders/chunks/shadow_receive.glsl.js.map +1 -0
  1248. package/dist/shaders/debug-view.glsl.d.ts +18 -0
  1249. package/dist/shaders/debug-view.glsl.d.ts.map +1 -0
  1250. package/dist/shaders/debug-view.glsl.js +153 -0
  1251. package/dist/shaders/debug-view.glsl.js.map +1 -0
  1252. package/dist/shaders/deform/deform.glsl.d.ts +17 -0
  1253. package/dist/shaders/deform/deform.glsl.d.ts.map +1 -0
  1254. package/dist/shaders/deform/deform.glsl.js +99 -0
  1255. package/dist/shaders/deform/deform.glsl.js.map +1 -0
  1256. package/dist/shaders/deform/deform.wgsl.d.ts +15 -0
  1257. package/dist/shaders/deform/deform.wgsl.d.ts.map +1 -0
  1258. package/dist/shaders/deform/deform.wgsl.js +89 -0
  1259. package/dist/shaders/deform/deform.wgsl.js.map +1 -0
  1260. package/dist/shaders/deform/depthFeature.d.ts +22 -0
  1261. package/dist/shaders/deform/depthFeature.d.ts.map +1 -0
  1262. package/dist/shaders/deform/depthFeature.js +44 -0
  1263. package/dist/shaders/deform/depthFeature.js.map +1 -0
  1264. package/dist/shaders/deform/forwardFeature.d.ts +114 -0
  1265. package/dist/shaders/deform/forwardFeature.d.ts.map +1 -0
  1266. package/dist/shaders/deform/forwardFeature.js +300 -0
  1267. package/dist/shaders/deform/forwardFeature.js.map +1 -0
  1268. package/dist/shaders/deform/morph.glsl.d.ts +14 -0
  1269. package/dist/shaders/deform/morph.glsl.d.ts.map +1 -0
  1270. package/dist/shaders/deform/morph.glsl.js +45 -0
  1271. package/dist/shaders/deform/morph.glsl.js.map +1 -0
  1272. package/dist/shaders/deform/morph.wgsl.d.ts +21 -0
  1273. package/dist/shaders/deform/morph.wgsl.d.ts.map +1 -0
  1274. package/dist/shaders/deform/morph.wgsl.js +73 -0
  1275. package/dist/shaders/deform/morph.wgsl.js.map +1 -0
  1276. package/dist/shaders/deform/skinning.glsl.d.ts +8 -0
  1277. package/dist/shaders/deform/skinning.glsl.d.ts.map +1 -0
  1278. package/dist/shaders/deform/skinning.glsl.js +37 -0
  1279. package/dist/shaders/deform/skinning.glsl.js.map +1 -0
  1280. package/dist/shaders/deform/skinning.wgsl.d.ts +26 -0
  1281. package/dist/shaders/deform/skinning.wgsl.d.ts.map +1 -0
  1282. package/dist/shaders/deform/skinning.wgsl.js +58 -0
  1283. package/dist/shaders/deform/skinning.wgsl.js.map +1 -0
  1284. package/dist/shaders/deform/twins.d.ts +8 -0
  1285. package/dist/shaders/deform/twins.d.ts.map +1 -0
  1286. package/dist/shaders/deform/twins.js +20 -0
  1287. package/dist/shaders/deform/twins.js.map +1 -0
  1288. package/dist/shaders/lod-dither.glsl.d.ts +12 -0
  1289. package/dist/shaders/lod-dither.glsl.d.ts.map +1 -0
  1290. package/dist/shaders/lod-dither.glsl.js +101 -0
  1291. package/dist/shaders/lod-dither.glsl.js.map +1 -0
  1292. package/dist/shaders/physical/alpha_a2c.glsl.d.ts +19 -0
  1293. package/dist/shaders/physical/alpha_a2c.glsl.d.ts.map +1 -0
  1294. package/dist/shaders/physical/alpha_a2c.glsl.js +29 -0
  1295. package/dist/shaders/physical/alpha_a2c.glsl.js.map +1 -0
  1296. package/dist/shaders/physical/anisotropy.glsl.d.ts +23 -0
  1297. package/dist/shaders/physical/anisotropy.glsl.d.ts.map +1 -0
  1298. package/dist/shaders/physical/anisotropy.glsl.js +116 -0
  1299. package/dist/shaders/physical/anisotropy.glsl.js.map +1 -0
  1300. package/dist/shaders/physical/bsdf_lobes_common.glsl.d.ts +25 -0
  1301. package/dist/shaders/physical/bsdf_lobes_common.glsl.d.ts.map +1 -0
  1302. package/dist/shaders/physical/bsdf_lobes_common.glsl.js +95 -0
  1303. package/dist/shaders/physical/bsdf_lobes_common.glsl.js.map +1 -0
  1304. package/dist/shaders/physical/clearcoat.glsl.d.ts +23 -0
  1305. package/dist/shaders/physical/clearcoat.glsl.d.ts.map +1 -0
  1306. package/dist/shaders/physical/clearcoat.glsl.js +70 -0
  1307. package/dist/shaders/physical/clearcoat.glsl.js.map +1 -0
  1308. package/dist/shaders/physical/debug_view.glsl.d.ts +19 -0
  1309. package/dist/shaders/physical/debug_view.glsl.d.ts.map +1 -0
  1310. package/dist/shaders/physical/debug_view.glsl.js +76 -0
  1311. package/dist/shaders/physical/debug_view.glsl.js.map +1 -0
  1312. package/dist/shaders/physical/dispersion.glsl.d.ts +18 -0
  1313. package/dist/shaders/physical/dispersion.glsl.d.ts.map +1 -0
  1314. package/dist/shaders/physical/dispersion.glsl.js +67 -0
  1315. package/dist/shaders/physical/dispersion.glsl.js.map +1 -0
  1316. package/dist/shaders/physical/emissive_strength.glsl.d.ts +18 -0
  1317. package/dist/shaders/physical/emissive_strength.glsl.d.ts.map +1 -0
  1318. package/dist/shaders/physical/emissive_strength.glsl.js +20 -0
  1319. package/dist/shaders/physical/emissive_strength.glsl.js.map +1 -0
  1320. package/dist/shaders/physical/index.d.ts +27 -0
  1321. package/dist/shaders/physical/index.d.ts.map +1 -0
  1322. package/dist/shaders/physical/index.js +69 -0
  1323. package/dist/shaders/physical/index.js.map +1 -0
  1324. package/dist/shaders/physical/iridescence.glsl.d.ts +25 -0
  1325. package/dist/shaders/physical/iridescence.glsl.d.ts.map +1 -0
  1326. package/dist/shaders/physical/iridescence.glsl.js +186 -0
  1327. package/dist/shaders/physical/iridescence.glsl.js.map +1 -0
  1328. package/dist/shaders/physical/lobe_calls.glsl.d.ts +83 -0
  1329. package/dist/shaders/physical/lobe_calls.glsl.d.ts.map +1 -0
  1330. package/dist/shaders/physical/lobe_calls.glsl.js +397 -0
  1331. package/dist/shaders/physical/lobe_calls.glsl.js.map +1 -0
  1332. package/dist/shaders/physical/sheen.glsl.d.ts +24 -0
  1333. package/dist/shaders/physical/sheen.glsl.d.ts.map +1 -0
  1334. package/dist/shaders/physical/sheen.glsl.js +108 -0
  1335. package/dist/shaders/physical/sheen.glsl.js.map +1 -0
  1336. package/dist/shaders/physical/specular_ior.glsl.d.ts +20 -0
  1337. package/dist/shaders/physical/specular_ior.glsl.d.ts.map +1 -0
  1338. package/dist/shaders/physical/specular_ior.glsl.js +64 -0
  1339. package/dist/shaders/physical/specular_ior.glsl.js.map +1 -0
  1340. package/dist/shaders/physical/tangent_frame.glsl.d.ts +27 -0
  1341. package/dist/shaders/physical/tangent_frame.glsl.d.ts.map +1 -0
  1342. package/dist/shaders/physical/tangent_frame.glsl.js +71 -0
  1343. package/dist/shaders/physical/tangent_frame.glsl.js.map +1 -0
  1344. package/dist/shaders/physical/transmission.glsl.d.ts +25 -0
  1345. package/dist/shaders/physical/transmission.glsl.d.ts.map +1 -0
  1346. package/dist/shaders/physical/transmission.glsl.js +204 -0
  1347. package/dist/shaders/physical/transmission.glsl.js.map +1 -0
  1348. package/dist/shaders/physical/transmission_copy.glsl.d.ts +15 -0
  1349. package/dist/shaders/physical/transmission_copy.glsl.d.ts.map +1 -0
  1350. package/dist/shaders/physical/transmission_copy.glsl.js +33 -0
  1351. package/dist/shaders/physical/transmission_copy.glsl.js.map +1 -0
  1352. package/dist/shaders/physical/unlit.glsl.d.ts +17 -0
  1353. package/dist/shaders/physical/unlit.glsl.d.ts.map +1 -0
  1354. package/dist/shaders/physical/unlit.glsl.js +19 -0
  1355. package/dist/shaders/physical/unlit.glsl.js.map +1 -0
  1356. package/dist/shaders/physical/uv_transform.glsl.d.ts +18 -0
  1357. package/dist/shaders/physical/uv_transform.glsl.d.ts.map +1 -0
  1358. package/dist/shaders/physical/uv_transform.glsl.js +30 -0
  1359. package/dist/shaders/physical/uv_transform.glsl.js.map +1 -0
  1360. package/dist/shaders/physical/volume.glsl.d.ts +19 -0
  1361. package/dist/shaders/physical/volume.glsl.d.ts.map +1 -0
  1362. package/dist/shaders/physical/volume.glsl.js +47 -0
  1363. package/dist/shaders/physical/volume.glsl.js.map +1 -0
  1364. package/dist/shaders/physical-wgsl/alpha_a2c.wgsl.d.ts +8 -0
  1365. package/dist/shaders/physical-wgsl/alpha_a2c.wgsl.d.ts.map +1 -0
  1366. package/dist/shaders/physical-wgsl/alpha_a2c.wgsl.js +26 -0
  1367. package/dist/shaders/physical-wgsl/alpha_a2c.wgsl.js.map +1 -0
  1368. package/dist/shaders/physical-wgsl/anisotropy.wgsl.d.ts +10 -0
  1369. package/dist/shaders/physical-wgsl/anisotropy.wgsl.d.ts.map +1 -0
  1370. package/dist/shaders/physical-wgsl/anisotropy.wgsl.js +97 -0
  1371. package/dist/shaders/physical-wgsl/anisotropy.wgsl.js.map +1 -0
  1372. package/dist/shaders/physical-wgsl/bsdf_lobes_common.wgsl.d.ts +11 -0
  1373. package/dist/shaders/physical-wgsl/bsdf_lobes_common.wgsl.d.ts.map +1 -0
  1374. package/dist/shaders/physical-wgsl/bsdf_lobes_common.wgsl.js +76 -0
  1375. package/dist/shaders/physical-wgsl/bsdf_lobes_common.wgsl.js.map +1 -0
  1376. package/dist/shaders/physical-wgsl/clearcoat.wgsl.d.ts +9 -0
  1377. package/dist/shaders/physical-wgsl/clearcoat.wgsl.d.ts.map +1 -0
  1378. package/dist/shaders/physical-wgsl/clearcoat.wgsl.js +56 -0
  1379. package/dist/shaders/physical-wgsl/clearcoat.wgsl.js.map +1 -0
  1380. package/dist/shaders/physical-wgsl/debug_view.wgsl.d.ts +10 -0
  1381. package/dist/shaders/physical-wgsl/debug_view.wgsl.d.ts.map +1 -0
  1382. package/dist/shaders/physical-wgsl/debug_view.wgsl.js +71 -0
  1383. package/dist/shaders/physical-wgsl/debug_view.wgsl.js.map +1 -0
  1384. package/dist/shaders/physical-wgsl/dispersion.wgsl.d.ts +10 -0
  1385. package/dist/shaders/physical-wgsl/dispersion.wgsl.d.ts.map +1 -0
  1386. package/dist/shaders/physical-wgsl/dispersion.wgsl.js +51 -0
  1387. package/dist/shaders/physical-wgsl/dispersion.wgsl.js.map +1 -0
  1388. package/dist/shaders/physical-wgsl/emissive_strength.wgsl.d.ts +9 -0
  1389. package/dist/shaders/physical-wgsl/emissive_strength.wgsl.d.ts.map +1 -0
  1390. package/dist/shaders/physical-wgsl/emissive_strength.wgsl.js +15 -0
  1391. package/dist/shaders/physical-wgsl/emissive_strength.wgsl.js.map +1 -0
  1392. package/dist/shaders/physical-wgsl/index.d.ts +35 -0
  1393. package/dist/shaders/physical-wgsl/index.d.ts.map +1 -0
  1394. package/dist/shaders/physical-wgsl/index.js +51 -0
  1395. package/dist/shaders/physical-wgsl/index.js.map +1 -0
  1396. package/dist/shaders/physical-wgsl/iridescence.wgsl.d.ts +9 -0
  1397. package/dist/shaders/physical-wgsl/iridescence.wgsl.d.ts.map +1 -0
  1398. package/dist/shaders/physical-wgsl/iridescence.wgsl.js +162 -0
  1399. package/dist/shaders/physical-wgsl/iridescence.wgsl.js.map +1 -0
  1400. package/dist/shaders/physical-wgsl/sheen.wgsl.d.ts +9 -0
  1401. package/dist/shaders/physical-wgsl/sheen.wgsl.d.ts.map +1 -0
  1402. package/dist/shaders/physical-wgsl/sheen.wgsl.js +85 -0
  1403. package/dist/shaders/physical-wgsl/sheen.wgsl.js.map +1 -0
  1404. package/dist/shaders/physical-wgsl/specular_ior.wgsl.d.ts +10 -0
  1405. package/dist/shaders/physical-wgsl/specular_ior.wgsl.d.ts.map +1 -0
  1406. package/dist/shaders/physical-wgsl/specular_ior.wgsl.js +47 -0
  1407. package/dist/shaders/physical-wgsl/specular_ior.wgsl.js.map +1 -0
  1408. package/dist/shaders/physical-wgsl/tangent_frame.wgsl.d.ts +11 -0
  1409. package/dist/shaders/physical-wgsl/tangent_frame.wgsl.d.ts.map +1 -0
  1410. package/dist/shaders/physical-wgsl/tangent_frame.wgsl.js +57 -0
  1411. package/dist/shaders/physical-wgsl/tangent_frame.wgsl.js.map +1 -0
  1412. package/dist/shaders/physical-wgsl/transmission.wgsl.d.ts +14 -0
  1413. package/dist/shaders/physical-wgsl/transmission.wgsl.d.ts.map +1 -0
  1414. package/dist/shaders/physical-wgsl/transmission.wgsl.js +159 -0
  1415. package/dist/shaders/physical-wgsl/transmission.wgsl.js.map +1 -0
  1416. package/dist/shaders/physical-wgsl/unlit.wgsl.d.ts +8 -0
  1417. package/dist/shaders/physical-wgsl/unlit.wgsl.d.ts.map +1 -0
  1418. package/dist/shaders/physical-wgsl/unlit.wgsl.js +13 -0
  1419. package/dist/shaders/physical-wgsl/unlit.wgsl.js.map +1 -0
  1420. package/dist/shaders/physical-wgsl/uv_transform.wgsl.d.ts +10 -0
  1421. package/dist/shaders/physical-wgsl/uv_transform.wgsl.d.ts.map +1 -0
  1422. package/dist/shaders/physical-wgsl/uv_transform.wgsl.js +24 -0
  1423. package/dist/shaders/physical-wgsl/uv_transform.wgsl.js.map +1 -0
  1424. package/dist/shaders/physical-wgsl/volume.wgsl.d.ts +10 -0
  1425. package/dist/shaders/physical-wgsl/volume.wgsl.d.ts.map +1 -0
  1426. package/dist/shaders/physical-wgsl/volume.wgsl.js +35 -0
  1427. package/dist/shaders/physical-wgsl/volume.wgsl.js.map +1 -0
  1428. package/dist/shadows/DirectionalCascadeFitter.d.ts +97 -0
  1429. package/dist/shadows/DirectionalCascadeFitter.d.ts.map +1 -0
  1430. package/dist/shadows/DirectionalCascadeFitter.js +372 -0
  1431. package/dist/shadows/DirectionalCascadeFitter.js.map +1 -0
  1432. package/dist/shadows/Prd02DepthShaderLibrary.d.ts +77 -0
  1433. package/dist/shadows/Prd02DepthShaderLibrary.d.ts.map +1 -0
  1434. package/dist/shadows/Prd02DepthShaderLibrary.js +381 -0
  1435. package/dist/shadows/Prd02DepthShaderLibrary.js.map +1 -0
  1436. package/dist/shadows/Prd02ReceiveShadowContributor.d.ts +20 -0
  1437. package/dist/shadows/Prd02ReceiveShadowContributor.d.ts.map +1 -0
  1438. package/dist/shadows/Prd02ReceiveShadowContributor.js +20 -0
  1439. package/dist/shadows/Prd02ReceiveShadowContributor.js.map +1 -0
  1440. package/dist/shadows/Prd02ShadowBridge.d.ts +111 -0
  1441. package/dist/shadows/Prd02ShadowBridge.d.ts.map +1 -0
  1442. package/dist/shadows/Prd02ShadowBridge.js +267 -0
  1443. package/dist/shadows/Prd02ShadowBridge.js.map +1 -0
  1444. package/dist/shadows/Prd02ShadowFilter.d.ts +29 -0
  1445. package/dist/shadows/Prd02ShadowFilter.d.ts.map +1 -0
  1446. package/dist/shadows/Prd02ShadowFilter.js +35 -0
  1447. package/dist/shadows/Prd02ShadowFilter.js.map +1 -0
  1448. package/dist/shadows/Prd02ShadowsContributor.d.ts +44 -0
  1449. package/dist/shadows/Prd02ShadowsContributor.d.ts.map +1 -0
  1450. package/dist/shadows/Prd02ShadowsContributor.js +197 -0
  1451. package/dist/shadows/Prd02ShadowsContributor.js.map +1 -0
  1452. package/dist/shadows/ShadowAtlas.d.ts +59 -0
  1453. package/dist/shadows/ShadowAtlas.d.ts.map +1 -0
  1454. package/dist/shadows/ShadowAtlas.js +137 -0
  1455. package/dist/shadows/ShadowAtlas.js.map +1 -0
  1456. package/dist/shadows/ShadowDebugViews.d.ts +5 -0
  1457. package/dist/shadows/ShadowDebugViews.d.ts.map +1 -1
  1458. package/dist/shadows/ShadowDebugViews.js +15 -10
  1459. package/dist/shadows/ShadowDebugViews.js.map +1 -1
  1460. package/dist/shadows/ShadowFrameBinding.d.ts +18 -0
  1461. package/dist/shadows/ShadowFrameBinding.d.ts.map +1 -0
  1462. package/dist/shadows/ShadowFrameBinding.js +52 -0
  1463. package/dist/shadows/ShadowFrameBinding.js.map +1 -0
  1464. package/dist/shadows/ShadowSystem.d.ts +125 -0
  1465. package/dist/shadows/ShadowSystem.d.ts.map +1 -0
  1466. package/dist/shadows/ShadowSystem.js +293 -0
  1467. package/dist/shadows/ShadowSystem.js.map +1 -0
  1468. package/dist/textures/TextureBudget.d.ts +42 -0
  1469. package/dist/textures/TextureBudget.d.ts.map +1 -0
  1470. package/dist/textures/TextureBudget.js +180 -0
  1471. package/dist/textures/TextureBudget.js.map +1 -0
  1472. package/dist/vfx/BeamPass.d.ts +42 -0
  1473. package/dist/vfx/BeamPass.d.ts.map +1 -0
  1474. package/dist/vfx/BeamPass.js +249 -0
  1475. package/dist/vfx/BeamPass.js.map +1 -0
  1476. package/dist/vfx/BlendFallback.d.ts +19 -0
  1477. package/dist/vfx/BlendFallback.d.ts.map +1 -0
  1478. package/dist/vfx/BlendFallback.js +73 -0
  1479. package/dist/vfx/BlendFallback.js.map +1 -0
  1480. package/dist/vfx/DecalBatch.d.ts +120 -0
  1481. package/dist/vfx/DecalBatch.d.ts.map +1 -0
  1482. package/dist/vfx/DecalBatch.js +234 -0
  1483. package/dist/vfx/DecalBatch.js.map +1 -0
  1484. package/dist/vfx/DecalPass.d.ts +63 -0
  1485. package/dist/vfx/DecalPass.d.ts.map +1 -0
  1486. package/dist/vfx/DecalPass.js +159 -0
  1487. package/dist/vfx/DecalPass.js.map +1 -0
  1488. package/dist/vfx/LowResParticles.d.ts +31 -0
  1489. package/dist/vfx/LowResParticles.d.ts.map +1 -0
  1490. package/dist/vfx/LowResParticles.js +151 -0
  1491. package/dist/vfx/LowResParticles.js.map +1 -0
  1492. package/dist/vfx/MeshParticleBatch.d.ts +49 -0
  1493. package/dist/vfx/MeshParticleBatch.d.ts.map +1 -0
  1494. package/dist/vfx/MeshParticleBatch.js +184 -0
  1495. package/dist/vfx/MeshParticleBatch.js.map +1 -0
  1496. package/dist/vfx/MeshParticlePass.d.ts +28 -0
  1497. package/dist/vfx/MeshParticlePass.d.ts.map +1 -0
  1498. package/dist/vfx/MeshParticlePass.js +150 -0
  1499. package/dist/vfx/MeshParticlePass.js.map +1 -0
  1500. package/dist/vfx/ParticleBatchPass.d.ts +61 -0
  1501. package/dist/vfx/ParticleBatchPass.d.ts.map +1 -0
  1502. package/dist/vfx/ParticleBatchPass.js +320 -0
  1503. package/dist/vfx/ParticleBatchPass.js.map +1 -0
  1504. package/dist/vfx/ParticleGpuSim.d.ts +85 -0
  1505. package/dist/vfx/ParticleGpuSim.d.ts.map +1 -0
  1506. package/dist/vfx/ParticleGpuSim.js +301 -0
  1507. package/dist/vfx/ParticleGpuSim.js.map +1 -0
  1508. package/dist/vfx/ParticleInstanceLayout.d.ts +38 -0
  1509. package/dist/vfx/ParticleInstanceLayout.d.ts.map +1 -0
  1510. package/dist/vfx/ParticleInstanceLayout.js +105 -0
  1511. package/dist/vfx/ParticleInstanceLayout.js.map +1 -0
  1512. package/dist/vfx/ParticleSort.d.ts +21 -0
  1513. package/dist/vfx/ParticleSort.d.ts.map +1 -0
  1514. package/dist/vfx/ParticleSort.js +80 -0
  1515. package/dist/vfx/ParticleSort.js.map +1 -0
  1516. package/dist/vfx/ProceduralVolumeEmitter.d.ts +90 -0
  1517. package/dist/vfx/ProceduralVolumeEmitter.d.ts.map +1 -0
  1518. package/dist/vfx/ProceduralVolumeEmitter.js +155 -0
  1519. package/dist/vfx/ProceduralVolumeEmitter.js.map +1 -0
  1520. package/dist/vfx/RibbonBatch.d.ts +71 -0
  1521. package/dist/vfx/RibbonBatch.d.ts.map +1 -0
  1522. package/dist/vfx/RibbonBatch.js +234 -0
  1523. package/dist/vfx/RibbonBatch.js.map +1 -0
  1524. package/dist/vfx/RibbonPass.d.ts +21 -0
  1525. package/dist/vfx/RibbonPass.d.ts.map +1 -0
  1526. package/dist/vfx/RibbonPass.js +108 -0
  1527. package/dist/vfx/RibbonPass.js.map +1 -0
  1528. package/dist/vfx/SceneDepthAdapter.d.ts +28 -0
  1529. package/dist/vfx/SceneDepthAdapter.d.ts.map +1 -0
  1530. package/dist/vfx/SceneDepthAdapter.js +70 -0
  1531. package/dist/vfx/SceneDepthAdapter.js.map +1 -0
  1532. package/dist/vfx/VfxAtlas.d.ts +68 -0
  1533. package/dist/vfx/VfxAtlas.d.ts.map +1 -0
  1534. package/dist/vfx/VfxAtlas.js +106 -0
  1535. package/dist/vfx/VfxAtlas.js.map +1 -0
  1536. package/dist/vfx/contributors.d.ts +73 -0
  1537. package/dist/vfx/contributors.d.ts.map +1 -0
  1538. package/dist/vfx/contributors.js +615 -0
  1539. package/dist/vfx/contributors.js.map +1 -0
  1540. package/dist/vfx/decalLighting.d.ts +8 -0
  1541. package/dist/vfx/decalLighting.d.ts.map +1 -0
  1542. package/dist/vfx/decalLighting.js +53 -0
  1543. package/dist/vfx/decalLighting.js.map +1 -0
  1544. package/dist/vfx/depthSampler.d.ts +3 -0
  1545. package/dist/vfx/depthSampler.d.ts.map +1 -0
  1546. package/dist/vfx/depthSampler.js +10 -0
  1547. package/dist/vfx/depthSampler.js.map +1 -0
  1548. package/dist/vfx/prd07FeaturePars.d.ts +12 -0
  1549. package/dist/vfx/prd07FeaturePars.d.ts.map +1 -0
  1550. package/dist/vfx/prd07FeaturePars.js +54 -0
  1551. package/dist/vfx/prd07FeaturePars.js.map +1 -0
  1552. package/dist/vfx/shaders/beam.glsl.d.ts +11 -0
  1553. package/dist/vfx/shaders/beam.glsl.d.ts.map +1 -0
  1554. package/dist/vfx/shaders/beam.glsl.js +89 -0
  1555. package/dist/vfx/shaders/beam.glsl.js.map +1 -0
  1556. package/dist/vfx/shaders/decal.glsl.d.ts +14 -0
  1557. package/dist/vfx/shaders/decal.glsl.d.ts.map +1 -0
  1558. package/dist/vfx/shaders/decal.glsl.js +157 -0
  1559. package/dist/vfx/shaders/decal.glsl.js.map +1 -0
  1560. package/dist/vfx/shaders/gpu-sim.glsl.d.ts +5 -0
  1561. package/dist/vfx/shaders/gpu-sim.glsl.d.ts.map +1 -0
  1562. package/dist/vfx/shaders/gpu-sim.glsl.js +177 -0
  1563. package/dist/vfx/shaders/gpu-sim.glsl.js.map +1 -0
  1564. package/dist/vfx/shaders/lowresComposite.glsl.d.ts +9 -0
  1565. package/dist/vfx/shaders/lowresComposite.glsl.d.ts.map +1 -0
  1566. package/dist/vfx/shaders/lowresComposite.glsl.js +64 -0
  1567. package/dist/vfx/shaders/lowresComposite.glsl.js.map +1 -0
  1568. package/dist/vfx/shaders/mesh-particle.glsl.d.ts +4 -0
  1569. package/dist/vfx/shaders/mesh-particle.glsl.d.ts.map +1 -0
  1570. package/dist/vfx/shaders/mesh-particle.glsl.js +55 -0
  1571. package/dist/vfx/shaders/mesh-particle.glsl.js.map +1 -0
  1572. package/dist/vfx/shaders/particle.glsl.d.ts +24 -0
  1573. package/dist/vfx/shaders/particle.glsl.d.ts.map +1 -0
  1574. package/dist/vfx/shaders/particle.glsl.js +215 -0
  1575. package/dist/vfx/shaders/particle.glsl.js.map +1 -0
  1576. package/dist/vfx/shaders/ribbon.glsl.d.ts +9 -0
  1577. package/dist/vfx/shaders/ribbon.glsl.d.ts.map +1 -0
  1578. package/dist/vfx/shaders/ribbon.glsl.js +60 -0
  1579. package/dist/vfx/shaders/ribbon.glsl.js.map +1 -0
  1580. package/dist/vfx/shaders/volume.glsl.d.ts +5 -0
  1581. package/dist/vfx/shaders/volume.glsl.d.ts.map +1 -0
  1582. package/dist/vfx/shaders/volume.glsl.js +52 -0
  1583. package/dist/vfx/shaders/volume.glsl.js.map +1 -0
  1584. package/dist/webgl2/ContextLifecycle.d.ts +43 -0
  1585. package/dist/webgl2/ContextLifecycle.d.ts.map +1 -0
  1586. package/dist/webgl2/ContextLifecycle.js +189 -0
  1587. package/dist/webgl2/ContextLifecycle.js.map +1 -0
  1588. package/dist/webgl2/Counters.d.ts +58 -0
  1589. package/dist/webgl2/Counters.d.ts.map +1 -0
  1590. package/dist/webgl2/Counters.js +207 -0
  1591. package/dist/webgl2/Counters.js.map +1 -0
  1592. package/dist/webgl2/DeviceHost.d.ts +41 -0
  1593. package/dist/webgl2/DeviceHost.d.ts.map +1 -0
  1594. package/dist/webgl2/DeviceHost.js +3 -0
  1595. package/dist/webgl2/DeviceHost.js.map +1 -0
  1596. package/dist/webgl2/LegacyPost.d.ts +279 -0
  1597. package/dist/webgl2/LegacyPost.d.ts.map +1 -0
  1598. package/dist/webgl2/LegacyPost.js +2477 -0
  1599. package/dist/webgl2/LegacyPost.js.map +1 -0
  1600. package/dist/webgl2/MultiDraw.d.ts +96 -0
  1601. package/dist/webgl2/MultiDraw.d.ts.map +1 -0
  1602. package/dist/webgl2/MultiDraw.js +716 -0
  1603. package/dist/webgl2/MultiDraw.js.map +1 -0
  1604. package/dist/webgl2/Probe.d.ts +27 -0
  1605. package/dist/webgl2/Probe.d.ts.map +1 -0
  1606. package/dist/webgl2/Probe.js +303 -0
  1607. package/dist/webgl2/Probe.js.map +1 -0
  1608. package/dist/webgl2/Samplers.d.ts +20 -0
  1609. package/dist/webgl2/Samplers.d.ts.map +1 -0
  1610. package/dist/webgl2/Samplers.js +179 -0
  1611. package/dist/webgl2/Samplers.js.map +1 -0
  1612. package/dist/webgl2/TextureFormats.d.ts +48 -0
  1613. package/dist/webgl2/TextureFormats.d.ts.map +1 -0
  1614. package/dist/webgl2/TextureFormats.js +185 -0
  1615. package/dist/webgl2/TextureFormats.js.map +1 -0
  1616. package/dist/webgl2/TextureUpload.d.ts +38 -0
  1617. package/dist/webgl2/TextureUpload.d.ts.map +1 -0
  1618. package/dist/webgl2/TextureUpload.js +346 -0
  1619. package/dist/webgl2/TextureUpload.js.map +1 -0
  1620. package/dist/webgpu/WebGPUBuffer.d.ts +1 -0
  1621. package/dist/webgpu/WebGPUBuffer.d.ts.map +1 -1
  1622. package/dist/webgpu/WebGPUCompute.d.ts +1 -0
  1623. package/dist/webgpu/WebGPUCompute.d.ts.map +1 -1
  1624. package/dist/webgpu/WebGPUCompute.js +1 -0
  1625. package/dist/webgpu/WebGPUCompute.js.map +1 -1
  1626. package/dist/webgpu/WebGPUPipelineCache.d.ts +4 -0
  1627. package/dist/webgpu/WebGPUPipelineCache.d.ts.map +1 -1
  1628. package/dist/webgpu/WebGPUPipelineCache.js +4 -0
  1629. package/dist/webgpu/WebGPUPipelineCache.js.map +1 -1
  1630. package/dist/webgpu/WebGPUPostShaders.d.ts.map +1 -1
  1631. package/dist/webgpu/WebGPUPostShaders.js +33 -2
  1632. package/dist/webgpu/WebGPUPostShaders.js.map +1 -1
  1633. package/dist/webgpu/WebGPUTexture.d.ts +1 -0
  1634. package/dist/webgpu/WebGPUTexture.d.ts.map +1 -1
  1635. package/dist/webgpu/WebGPUTexture.js.map +1 -1
  1636. package/dist/world/chunks.d.ts +15 -0
  1637. package/dist/world/chunks.d.ts.map +1 -0
  1638. package/dist/world/chunks.js +56 -0
  1639. package/dist/world/chunks.js.map +1 -0
  1640. package/dist/world/index.d.ts +38 -0
  1641. package/dist/world/index.d.ts.map +1 -0
  1642. package/dist/world/index.js +39 -0
  1643. package/dist/world/index.js.map +1 -0
  1644. package/dist/world/shared/shaders/worldLightFallback.d.ts +12 -0
  1645. package/dist/world/shared/shaders/worldLightFallback.d.ts.map +1 -0
  1646. package/dist/world/shared/shaders/worldLightFallback.js +82 -0
  1647. package/dist/world/shared/shaders/worldLightFallback.js.map +1 -0
  1648. package/dist/world/space/PlanetMaterial.d.ts +24 -0
  1649. package/dist/world/space/PlanetMaterial.d.ts.map +1 -0
  1650. package/dist/world/space/PlanetMaterial.js +82 -0
  1651. package/dist/world/space/PlanetMaterial.js.map +1 -0
  1652. package/dist/world/space/SpaceSkyBake.d.ts +46 -0
  1653. package/dist/world/space/SpaceSkyBake.d.ts.map +1 -0
  1654. package/dist/world/space/SpaceSkyBake.js +145 -0
  1655. package/dist/world/space/SpaceSkyBake.js.map +1 -0
  1656. package/dist/world/space/shaders/planet.d.ts +8 -0
  1657. package/dist/world/space/shaders/planet.d.ts.map +1 -0
  1658. package/dist/world/space/shaders/planet.js +55 -0
  1659. package/dist/world/space/shaders/planet.js.map +1 -0
  1660. package/dist/world/space/shaders/spaceBake.d.ts +9 -0
  1661. package/dist/world/space/shaders/spaceBake.d.ts.map +1 -0
  1662. package/dist/world/space/shaders/spaceBake.js +102 -0
  1663. package/dist/world/space/shaders/spaceBake.js.map +1 -0
  1664. package/dist/world/terrain/SplatBake.d.ts +76 -0
  1665. package/dist/world/terrain/SplatBake.d.ts.map +1 -0
  1666. package/dist/world/terrain/SplatBake.js +308 -0
  1667. package/dist/world/terrain/SplatBake.js.map +1 -0
  1668. package/dist/world/terrain/TerrainCdlod.d.ts +67 -0
  1669. package/dist/world/terrain/TerrainCdlod.d.ts.map +1 -0
  1670. package/dist/world/terrain/TerrainCdlod.js +115 -0
  1671. package/dist/world/terrain/TerrainCdlod.js.map +1 -0
  1672. package/dist/world/terrain/TerrainHeightTexture.d.ts +44 -0
  1673. package/dist/world/terrain/TerrainHeightTexture.d.ts.map +1 -0
  1674. package/dist/world/terrain/TerrainHeightTexture.js +173 -0
  1675. package/dist/world/terrain/TerrainHeightTexture.js.map +1 -0
  1676. package/dist/world/terrain/TerrainPatchGeometry.d.ts +18 -0
  1677. package/dist/world/terrain/TerrainPatchGeometry.d.ts.map +1 -0
  1678. package/dist/world/terrain/TerrainPatchGeometry.js +40 -0
  1679. package/dist/world/terrain/TerrainPatchGeometry.js.map +1 -0
  1680. package/dist/world/terrain/shaders/terrain.vert.glsl.d.ts +19 -0
  1681. package/dist/world/terrain/shaders/terrain.vert.glsl.d.ts.map +1 -0
  1682. package/dist/world/terrain/shaders/terrain.vert.glsl.js +162 -0
  1683. package/dist/world/terrain/shaders/terrain.vert.glsl.js.map +1 -0
  1684. package/dist/world/terrain/shaders/terrainCdlod.d.ts +23 -0
  1685. package/dist/world/terrain/shaders/terrainCdlod.d.ts.map +1 -0
  1686. package/dist/world/terrain/shaders/terrainCdlod.js +110 -0
  1687. package/dist/world/terrain/shaders/terrainCdlod.js.map +1 -0
  1688. package/dist/world/terrain/shaders/terrainSplat.d.ts +26 -0
  1689. package/dist/world/terrain/shaders/terrainSplat.d.ts.map +1 -0
  1690. package/dist/world/terrain/shaders/terrainSplat.js +181 -0
  1691. package/dist/world/terrain/shaders/terrainSplat.js.map +1 -0
  1692. package/dist/world/vegetation/FoliageMaterial.d.ts +14 -0
  1693. package/dist/world/vegetation/FoliageMaterial.d.ts.map +1 -0
  1694. package/dist/world/vegetation/FoliageMaterial.js +107 -0
  1695. package/dist/world/vegetation/FoliageMaterial.js.map +1 -0
  1696. package/dist/world/vegetation/GrassField.d.ts +43 -0
  1697. package/dist/world/vegetation/GrassField.d.ts.map +1 -0
  1698. package/dist/world/vegetation/GrassField.js +68 -0
  1699. package/dist/world/vegetation/GrassField.js.map +1 -0
  1700. package/dist/world/vegetation/ImpostorMaterial.d.ts +20 -0
  1701. package/dist/world/vegetation/ImpostorMaterial.d.ts.map +1 -0
  1702. package/dist/world/vegetation/ImpostorMaterial.js +80 -0
  1703. package/dist/world/vegetation/ImpostorMaterial.js.map +1 -0
  1704. package/dist/world/vegetation/InstanceChunkGrid.d.ts +67 -0
  1705. package/dist/world/vegetation/InstanceChunkGrid.d.ts.map +1 -0
  1706. package/dist/world/vegetation/InstanceChunkGrid.js +150 -0
  1707. package/dist/world/vegetation/InstanceChunkGrid.js.map +1 -0
  1708. package/dist/world/vegetation/WindCpu.d.ts +19 -0
  1709. package/dist/world/vegetation/WindCpu.d.ts.map +1 -0
  1710. package/dist/world/vegetation/WindCpu.js +43 -0
  1711. package/dist/world/vegetation/WindCpu.js.map +1 -0
  1712. package/dist/world/vegetation/WindField.d.ts +42 -0
  1713. package/dist/world/vegetation/WindField.d.ts.map +1 -0
  1714. package/dist/world/vegetation/WindField.js +154 -0
  1715. package/dist/world/vegetation/WindField.js.map +1 -0
  1716. package/dist/world/vegetation/shaders/foliage.d.ts +8 -0
  1717. package/dist/world/vegetation/shaders/foliage.d.ts.map +1 -0
  1718. package/dist/world/vegetation/shaders/foliage.js +104 -0
  1719. package/dist/world/vegetation/shaders/foliage.js.map +1 -0
  1720. package/dist/world/vegetation/shaders/grass.d.ts +10 -0
  1721. package/dist/world/vegetation/shaders/grass.d.ts.map +1 -0
  1722. package/dist/world/vegetation/shaders/grass.js +79 -0
  1723. package/dist/world/vegetation/shaders/grass.js.map +1 -0
  1724. package/dist/world/vegetation/shaders/impostor.d.ts +9 -0
  1725. package/dist/world/vegetation/shaders/impostor.d.ts.map +1 -0
  1726. package/dist/world/vegetation/shaders/impostor.js +97 -0
  1727. package/dist/world/vegetation/shaders/impostor.js.map +1 -0
  1728. package/dist/world/vegetation/shaders/wind.d.ts +9 -0
  1729. package/dist/world/vegetation/shaders/wind.d.ts.map +1 -0
  1730. package/dist/world/vegetation/shaders/wind.js +103 -0
  1731. package/dist/world/vegetation/shaders/wind.js.map +1 -0
  1732. package/dist/world/water/GerstnerWaves.d.ts +65 -0
  1733. package/dist/world/water/GerstnerWaves.d.ts.map +1 -0
  1734. package/dist/world/water/GerstnerWaves.js +182 -0
  1735. package/dist/world/water/GerstnerWaves.js.map +1 -0
  1736. package/dist/world/water/ReflectionViewPass.d.ts +46 -0
  1737. package/dist/world/water/ReflectionViewPass.d.ts.map +1 -0
  1738. package/dist/world/water/ReflectionViewPass.js +85 -0
  1739. package/dist/world/water/ReflectionViewPass.js.map +1 -0
  1740. package/dist/world/water/SceneCopyFallback.d.ts +21 -0
  1741. package/dist/world/water/SceneCopyFallback.d.ts.map +1 -0
  1742. package/dist/world/water/SceneCopyFallback.js +150 -0
  1743. package/dist/world/water/SceneCopyFallback.js.map +1 -0
  1744. package/dist/world/water/UnderwaterState.d.ts +25 -0
  1745. package/dist/world/water/UnderwaterState.d.ts.map +1 -0
  1746. package/dist/world/water/UnderwaterState.js +134 -0
  1747. package/dist/world/water/UnderwaterState.js.map +1 -0
  1748. package/dist/world/water/WaterMaterial.d.ts +23 -0
  1749. package/dist/world/water/WaterMaterial.d.ts.map +1 -0
  1750. package/dist/world/water/WaterMaterial.js +129 -0
  1751. package/dist/world/water/WaterMaterial.js.map +1 -0
  1752. package/dist/world/water/shaders/caustics.d.ts +13 -0
  1753. package/dist/world/water/shaders/caustics.d.ts.map +1 -0
  1754. package/dist/world/water/shaders/caustics.js +103 -0
  1755. package/dist/world/water/shaders/caustics.js.map +1 -0
  1756. package/dist/world/water/shaders/gerstner.d.ts +9 -0
  1757. package/dist/world/water/shaders/gerstner.d.ts.map +1 -0
  1758. package/dist/world/water/shaders/gerstner.js +100 -0
  1759. package/dist/world/water/shaders/gerstner.js.map +1 -0
  1760. package/dist/world/water/shaders/water.d.ts +12 -0
  1761. package/dist/world/water/shaders/water.d.ts.map +1 -0
  1762. package/dist/world/water/shaders/water.js +112 -0
  1763. package/dist/world/water/shaders/water.js.map +1 -0
  1764. package/package.json +32 -11
@@ -7,8 +7,50 @@ import {} from "./VertexFormat.js";
7
7
  import { WebGL2StateCache } from "./WebGL2StateCache.js";
8
8
  import { BLOOM_BRIGHT_LUT_HEIGHT, BLOOM_BRIGHT_LUT_WIDTH, BLOOM_COMPOSITE_LUT_SIZE, OUTLINE_BLEND_LUT_WIDTH, OUTLINE_LIMB_RADIX, createOutlineBlendLut, createOutlineGradientBound, createBloomBrightThresholdLut, createBloomCompositeLut } from "./postprocess/NativeLdrEffectLuts.js";
9
9
  import { normalizeBloomQualityPreset, resolveBloomPyramidBlurRadii, resolveBloomPyramidPlan, resolveBloomPyramidResponseGain, } from "./postprocess/NativeBloomPyramid.js";
10
- const WEBGL_CUBE_FACES = ["px", "nx", "py", "ny", "pz", "nz"];
11
- class WebGL2Buffer {
10
+ import { WebGL2Counters } from "./webgl2/Counters.js";
11
+ import { createWebGL2DeviceProbe } from "./webgl2/Probe.js";
12
+ import { WebGL2ContextLifecycle } from "./webgl2/ContextLifecycle.js";
13
+ import { WebGL2TextureRegistry } from "./webgl2/TextureUpload.js";
14
+ import { WebGL2SamplerRegistry } from "./webgl2/Samplers.js";
15
+ import { WebGL2DrawCallBinder } from "./webgl2/MultiDraw.js";
16
+ import { AURA_FRAME_BINDING, AURA_LIGHTS_BINDING } from "./resources/UniformBlock.js";
17
+ import { WebGL2ReadbackProbe } from "./webgl2/Probe.js";
18
+ import { WebGL2LegacyPostPipeline } from "./webgl2/LegacyPost.js";
19
+ import { cubeFaceTarget, rgba8TextureInternalFormat, textureUploadFormat, resolveRenderTargetFormat, resolveCompressedTextureFormat, magFilter, minFilter, addressMode } from "./webgl2/TextureFormats.js";
20
+ export const WEBGL_CUBE_FACES = ["px", "nx", "py", "ny", "pz", "nz"];
21
+ /**
22
+ * #621 (01-RTARRAY): immutable storage (`texStorage2D/3D`) only accepts SIZED
23
+ * internal formats. `resolveRenderTargetFormat("rgba8")` returns unsized
24
+ * `gl.RGBA`, which is valid for the `texImage2D` 2d path but makes
25
+ * texStorage raise INVALID_ENUM and allocate nothing, so cube/array colour
26
+ * framebuffers come out incomplete (GPU run 38143556299: "array: WebGL render
27
+ * target framebuffer status is invalid"). Float formats are already sized.
28
+ */
29
+ export function renderTargetStorageFormat(gl, internalFormat) {
30
+ return internalFormat === gl.RGBA ? gl.RGBA8 : internalFormat;
31
+ }
32
+ /**
33
+ * Attachment-0 color format of a single-attachment 2d target: an explicit
34
+ * `colorAttachments[0].format` wins over the legacy `format` field.
35
+ */
36
+ export function renderTargetColorFormat(descriptor) {
37
+ return descriptor.colorAttachments?.[0]?.format ?? descriptor.format ?? "rgba8";
38
+ }
39
+ /**
40
+ * MAX_TEXTURE_SIZE of the canvas's WebGL2 context (4096 when unavailable).
41
+ * Lives in the device owner file so callers never touch getContext
42
+ * themselves (single-renderer gate). Moved from the engine's deleted
43
+ * safe-basic webglRuntime in Live Fix E6.
44
+ */
45
+ export function webGL2MaxTextureSize(canvas) {
46
+ return Number(canvas.getContext("webgl2")?.getParameter(WebGL2RenderingContext.MAX_TEXTURE_SIZE) ?? 4096);
47
+ }
48
+ /** C-08 named uniform-block → binding-point assignment applied post-link (T0-02). */
49
+ const NAMED_UNIFORM_BLOCK_BINDINGS = [
50
+ ["AuraFrame", AURA_FRAME_BINDING],
51
+ ["AuraLights", AURA_LIGHTS_BINDING]
52
+ ];
53
+ export class WebGL2Buffer {
12
54
  id;
13
55
  usage;
14
56
  byteLength;
@@ -16,6 +58,8 @@ class WebGL2Buffer {
16
58
  handle;
17
59
  gl;
18
60
  disposed = false;
61
+ /** PRD-01 Phase 6 (CONTRACTS §6.1): device-side cleanup hook — VAO eviction. */
62
+ onDispose;
19
63
  constructor(id, usage, byteLength, target, handle, gl) {
20
64
  this.id = id;
21
65
  this.usage = usage;
@@ -26,12 +70,14 @@ class WebGL2Buffer {
26
70
  }
27
71
  dispose() {
28
72
  if (!this.disposed) {
29
- this.gl.deleteBuffer(this.handle);
30
73
  this.disposed = true;
74
+ // Evict VAOs referencing this buffer before the GL object goes away.
75
+ this.onDispose?.();
76
+ this.gl.deleteBuffer(this.handle);
31
77
  }
32
78
  }
33
79
  }
34
- class WebGL2ShaderProgram {
80
+ export class WebGL2ShaderProgram {
35
81
  id;
36
82
  label;
37
83
  marker;
@@ -54,7 +100,7 @@ class WebGL2ShaderProgram {
54
100
  }
55
101
  }
56
102
  }
57
- class WebGL2RenderTarget {
103
+ export class WebGL2RenderTarget {
58
104
  id;
59
105
  width;
60
106
  height;
@@ -71,7 +117,14 @@ class WebGL2RenderTarget {
71
117
  gl;
72
118
  disposed = false;
73
119
  needsResolve = false;
74
- constructor(id, width, height, label, colorTexture, depthTexture, framebuffer, colorHandle, depthHandle, depthTextureHandle, sampleCount, drawFramebuffer, multisampleColorHandle, gl) {
120
+ dimension;
121
+ layers;
122
+ colorTextures;
123
+ layerTargets;
124
+ extraColorHandles;
125
+ layerFramebuffers;
126
+ layerChild;
127
+ constructor(id, width, height, label, colorTexture, depthTexture, framebuffer, colorHandle, depthHandle, depthTextureHandle, sampleCount, drawFramebuffer, multisampleColorHandle, gl, options = {}) {
75
128
  this.id = id;
76
129
  this.width = width;
77
130
  this.height = height;
@@ -86,13 +139,31 @@ class WebGL2RenderTarget {
86
139
  this.drawFramebuffer = drawFramebuffer;
87
140
  this.multisampleColorHandle = multisampleColorHandle;
88
141
  this.gl = gl;
142
+ this.dimension = options.dimension ?? "2d";
143
+ this.layers = options.layers;
144
+ this.colorTextures = options.colorTextures;
145
+ this.layerTargets = options.layerTargets;
146
+ this.extraColorHandles = options.extraColorHandles ?? [];
147
+ this.layerFramebuffers = options.layerFramebuffers ?? [];
148
+ this.layerChild = options.layerChild === true;
89
149
  }
90
150
  dispose() {
91
151
  if (!this.disposed) {
152
+ if (this.layerChild) {
153
+ this.disposed = true;
154
+ return;
155
+ }
156
+ for (const framebuffer of this.layerFramebuffers) {
157
+ if (framebuffer !== this.framebuffer)
158
+ this.gl.deleteFramebuffer(framebuffer);
159
+ }
92
160
  this.gl.deleteFramebuffer(this.framebuffer);
93
161
  if (this.drawFramebuffer !== this.framebuffer)
94
162
  this.gl.deleteFramebuffer(this.drawFramebuffer);
95
163
  this.gl.deleteTexture(this.colorHandle);
164
+ for (const handle of this.extraColorHandles) {
165
+ this.gl.deleteTexture(handle);
166
+ }
96
167
  if (this.depthHandle)
97
168
  this.gl.deleteRenderbuffer(this.depthHandle);
98
169
  if (this.multisampleColorHandle)
@@ -100,7 +171,14 @@ class WebGL2RenderTarget {
100
171
  if (this.depthTextureHandle)
101
172
  this.gl.deleteTexture(this.depthTextureHandle);
102
173
  this.colorTexture.dispose();
174
+ for (const texture of this.colorTextures ?? []) {
175
+ if (texture !== this.colorTexture)
176
+ texture.dispose();
177
+ }
103
178
  this.depthTexture?.dispose();
179
+ for (const child of this.layerTargets ?? []) {
180
+ child.disposed = true;
181
+ }
104
182
  this.disposed = true;
105
183
  }
106
184
  }
@@ -109,76 +187,13 @@ export class WebGL2Device {
109
187
  errorCheckMode;
110
188
  kind = "webgl2";
111
189
  info;
112
- disposed = false;
113
- contextLost = false;
114
190
  gl;
115
191
  nextId = 1;
116
- drawCalls = 0;
117
- nativeTemporalPasses = 0;
118
- nativeTemporalBindings = 0;
119
192
  buffers = new Set();
193
+ disposedBufferCount = 0;
120
194
  shaders = new Set();
121
195
  renderTargets = new Set();
122
- activeRenderTarget = null;
123
- textures = new Map();
124
- textureUploadModes = new Map();
125
- fallbackTexture = null;
126
- fallbackCubeTexture = null;
127
- samplerObjectCache = new Map();
128
- presentationProgram = null;
129
- ldrPostprocessProgram = null;
130
- bloomBrightExtractProgram = null;
131
- bloomBlurProgram = null;
132
- bloomCompositeProgram = null;
133
- bloomDownsampleProgram = null;
134
- bloomAccumulateProgram = null;
135
- bloomPyramidResources = null;
136
- outlineProgram = null;
137
- ssaoProgram = null;
138
- ssrProgram = null;
139
- depthOfFieldProgram = null;
140
- motionBlurProgram = null;
141
- motionBlurVelocityTexture = null;
142
- motionBlurVelocitySize = null;
143
- taaProgram = null;
144
- taaPresentationProgram = null;
145
- taaHistoryTexture = null;
146
- taaHistorySize = null;
147
- bloomPingPongResources = null;
148
- bloomBrightLutTexture = null;
149
- bloomBrightLutThreshold = null;
150
- bloomCompositeLutTexture = null;
151
- bloomCompositeLutIntensity = null;
152
- bloomCompositeLutShoulder = null;
153
- lastBloomDiagnostics = null;
154
- outlineBlendLutTexture = null;
155
- outlineBlendLutKey = null;
156
- depthReadbackProgram = null;
157
- uniformLocationCache = new WeakMap();
158
- textureSamplerParameterCache = new WeakMap();
159
196
  stateCache = new WebGL2StateCache({ label: "webgl2-device-state-cache" });
160
- textureUnitBindings = new Map();
161
- vertexArrayCache = new Map();
162
- vertexFormatIds = new WeakMap();
163
- presentationVertexArray = null;
164
- activeTextureUnitIndex = -1;
165
- shaderProgramCreateCount = 0;
166
- uniformLocationLookupCount = 0;
167
- bufferUpdateCount = 0;
168
- textureBindCount = 0;
169
- samplerParameterUploadCount = 0;
170
- samplerAnisotropyUploadCount = 0;
171
- vertexArrayCreateCount = 0;
172
- nativeInstancedSubmissions = 0;
173
- nextVertexFormatId = 1;
174
- releasedTextureHandles = 0;
175
- nativeEnvironmentBindings = 0;
176
- nativeShadowMapBindings = 0;
177
- shadowRenderTargetsAllocated = 0;
178
- lastError = null;
179
- frameActive = false;
180
- viewportWidth = 0;
181
- viewportHeight = 0;
182
197
  maxVertexAttributes;
183
198
  anisotropicFilteringExtension;
184
199
  maxTextureAnisotropy;
@@ -190,16 +205,15 @@ export class WebGL2Device {
190
205
  * why the parity table listed context-loss recovery as a gap while the listeners existed — the
191
206
  * device layer was never the gap, the absence of a public signal was.
192
207
  */
193
- deviceLostListeners = new Set();
194
- deviceRestoredListeners = new Set();
195
- contextLostListener;
196
- contextRestoredListener;
197
- canvas;
208
+ host;
209
+ /** C-28: device capability probe, filled from extension detection in the ctor. */
210
+ probe;
198
211
  static create(options) {
199
212
  const gl = options.canvas.getContext("webgl2", {
200
213
  antialias: options.antialias ?? true,
201
214
  alpha: options.alpha ?? false,
202
- preserveDrawingBuffer: options.preserveDrawingBuffer ?? false
215
+ preserveDrawingBuffer: options.preserveDrawingBuffer ?? false,
216
+ ...(options.powerPreference !== undefined ? { powerPreference: options.powerPreference } : {})
203
217
  });
204
218
  if (!gl) {
205
219
  throw new RenderDeviceError("WebGL2 is not available for the provided canvas", "WEBGL2_UNAVAILABLE");
@@ -256,39 +270,34 @@ export class WebGL2Device {
256
270
  ...(gl.getExtension("EXT_color_buffer_float") ? ["hdr-render-targets", "float-readback"] : [])
257
271
  ]
258
272
  };
259
- this.canvas = canvas;
260
- if ("addEventListener" in canvas) {
261
- this.contextLostListener = ((event) => {
262
- event.preventDefault();
263
- this.contextLost = true;
264
- this.lastError = "CONTEXT_LOST";
265
- this.frameActive = false;
266
- // WS-2.6: notify subscribers. Errors in a listener must not prevent the others from running,
267
- // nor leave the device in a half-notified state during an already-degraded condition.
268
- for (const listener of [...this.deviceLostListeners]) {
269
- try {
270
- listener();
271
- }
272
- catch {
273
- // A listener that throws is the listener's problem; the device stays consistent.
274
- }
275
- }
276
- });
277
- this.contextRestoredListener = (() => {
278
- this.contextLost = false;
279
- this.lastError = null;
280
- for (const listener of [...this.deviceRestoredListeners]) {
281
- try {
282
- listener();
283
- }
284
- catch {
285
- // As above.
286
- }
287
- }
288
- });
289
- canvas.addEventListener("webglcontextlost", this.contextLostListener);
290
- canvas.addEventListener("webglcontextrestored", this.contextRestoredListener);
291
- }
273
+ const host = {
274
+ gl,
275
+ stateCache: this.stateCache,
276
+ counters: new WebGL2Counters(),
277
+ buffers: this.buffers,
278
+ shaders: this.shaders,
279
+ renderTargets: this.renderTargets,
280
+ activeRenderTarget: null,
281
+ disposed: false,
282
+ contextLost: false,
283
+ errorCheckMode: this.errorCheckMode,
284
+ anisotropicFilteringExtension: this.anisotropicFilteringExtension,
285
+ maxTextureAnisotropy: this.maxTextureAnisotropy,
286
+ maxVertexAttributes: this.maxVertexAttributes,
287
+ resolveMultisampleTarget: (target) => this.resolveMultisampleTarget(target),
288
+ device: this
289
+ };
290
+ host.lifecycle = new WebGL2ContextLifecycle(host, canvas);
291
+ host.textureRegistry = new WebGL2TextureRegistry(host);
292
+ host.samplers = new WebGL2SamplerRegistry(host);
293
+ host.drawBinder = new WebGL2DrawCallBinder(host);
294
+ // #94 (Q-01-1): the C-29 restore hook (`renderer/DeviceLifecycle.ts`)
295
+ // calls `host.invalidateGpuObjects?.()` before the registry rebuild.
296
+ host.invalidateGpuObjects = () => this.invalidateGpuObjects();
297
+ host.probe = new WebGL2ReadbackProbe(host);
298
+ host.post = new WebGL2LegacyPostPipeline(host);
299
+ this.host = host;
300
+ this.probe = createWebGL2DeviceProbe(gl);
292
301
  }
293
302
  /**
294
303
  * Subscribe to WebGL context loss. Returns an unsubscribe function.
@@ -297,21 +306,190 @@ export class WebGL2Device {
297
306
  * memory pressure, on driver reset, or when a tab is backgrounded too long. What a caller can do is
298
307
  * be told, so it can recreate resources rather than render nothing.
299
308
  */
309
+ get disposed() {
310
+ return this.host.disposed;
311
+ }
312
+ set disposed(value) {
313
+ this.host.disposed = value;
314
+ }
315
+ get contextLost() {
316
+ return this.host.contextLost;
317
+ }
318
+ set contextLost(value) {
319
+ this.host.contextLost = value;
320
+ }
300
321
  onDeviceLost(listener) {
301
- this.deviceLostListeners.add(listener);
302
- return () => this.deviceLostListeners.delete(listener);
322
+ return this.host.lifecycle.onDeviceLost(listener);
303
323
  }
304
- /** Subscribe to context restoration. Returns an unsubscribe function. */
305
324
  onDeviceRestored(listener) {
306
- this.deviceRestoredListeners.add(listener);
307
- return () => this.deviceRestoredListeners.delete(listener);
325
+ return this.host.lifecycle.onDeviceRestored(listener);
308
326
  }
309
- /** True while the WebGL context is lost. Polling alternative to {@link onDeviceLost}. */
310
327
  isDeviceLost() {
311
- return this.contextLost;
328
+ return this.host.lifecycle.isDeviceLost();
329
+ }
330
+ beginFrame(width, height) {
331
+ this.host.lifecycle.beginFrame(width, height);
332
+ }
333
+ clear(color) {
334
+ this.host.lifecycle.clear(color);
335
+ }
336
+ clearRenderTarget(color, attachment) {
337
+ this.host.lifecycle.clearRenderTarget(color, attachment);
338
+ }
339
+ endFrame() {
340
+ this.host.lifecycle.endFrame();
341
+ }
342
+ draw(command) {
343
+ this.host.drawBinder.draw(command);
344
+ }
345
+ readPixels(x, y, width, height, attachment) {
346
+ return this.host.probe.readPixels(x, y, width, height, attachment);
347
+ }
348
+ readFloatPixels(x, y, width, height) {
349
+ return this.host.probe.readFloatPixels(x, y, width, height);
350
+ }
351
+ readDepthPixels(x, y, width, height) {
352
+ return this.host.probe.readDepthPixels(x, y, width, height);
353
+ }
354
+ writeRenderTargetPixels(target, pixels) {
355
+ this.host.probe.writeRenderTargetPixels(target, pixels);
356
+ }
357
+ presentRenderTarget(source) {
358
+ this.host.post.presentRenderTarget(source);
359
+ }
360
+ presentLdrPostprocess(source, options) {
361
+ this.host.post.presentLdrPostprocess(source, options);
362
+ }
363
+ executeReflectionSurfaceSsr(source, normalMask, output, options) {
364
+ this.host.post.executeReflectionSurfaceSsr(source, normalMask, output, options);
365
+ }
366
+ getBloomDiagnostics() {
367
+ return this.host.post.getBloomDiagnostics();
368
+ }
369
+ /** C-28: partial counters from existing diagnostics and the wrapped counter fields. */
370
+ counters() {
371
+ const diagnostics = this.getDiagnostics();
372
+ return {
373
+ drawCalls: this.host.counters.drawCalls,
374
+ bufferCreates: diagnostics.buffers,
375
+ textureUploads: diagnostics.textures ?? 0,
376
+ readbacks: this.host.counters.readbacks,
377
+ renderTargetsCreated: diagnostics.renderTargets ?? 0,
378
+ programCompiles: this.host.counters.programCompiles,
379
+ liveBuffers: diagnostics.buffers,
380
+ liveVertexArrays: this.host.drawBinder.vertexArrayCache.size,
381
+ textureBytes: diagnostics.textureBytes ?? 0,
382
+ renderTargetBytes: 0
383
+ };
384
+ }
385
+ resetFrameCounters() {
386
+ this.host.counters.drawCalls = 0;
387
+ this.host.counters.readbacks = 0;
388
+ }
389
+ /**
390
+ * PRD-01 §6.4 / 01-S7: with `KHR_parallel_shader_compile`, compile and
391
+ * link are issued without querying status, and the promise resolves once
392
+ * `COMPLETION_STATUS_KHR` reports done (polled per animation frame), so
393
+ * the caller's frame is not blocked. Without the extension this is the
394
+ * synchronous `createShaderProgram` wrapped in a resolved promise.
395
+ */
396
+ compileAsync(sources) {
397
+ const ext = this.parallelShaderCompileExtension();
398
+ if (!ext)
399
+ return Promise.resolve(this.createShaderProgram(sources));
400
+ this.host.lifecycle.assertAlive();
401
+ this.assertShaderMarker(sources);
402
+ const vertexShader = this.issueShaderCompile(this.gl.VERTEX_SHADER, sources.vertex, sources.label);
403
+ const fragmentShader = this.issueShaderCompile(this.gl.FRAGMENT_SHADER, sources.fragment, sources.label);
404
+ const program = this.gl.createProgram();
405
+ if (!program) {
406
+ throw new RenderDeviceError("Failed to allocate WebGL shader program", "WEBGL_ALLOCATION_FAILED");
407
+ }
408
+ this.host.counters.shaderProgramCreateCount += 1;
409
+ this.gl.attachShader(program, vertexShader);
410
+ this.gl.attachShader(program, fragmentShader);
411
+ this.gl.linkProgram(program);
412
+ this.host.counters.programCompiles += 1;
413
+ this.parallelCompilesPending += 1;
414
+ return new Promise((resolve, reject) => {
415
+ const poll = () => {
416
+ if (this.host.disposed || this.host.contextLost) {
417
+ this.parallelCompilesPending -= 1;
418
+ reject(new RenderDeviceError("Device lost during parallel shader compile", "DEVICE_LOST", { label: sources.label }));
419
+ return;
420
+ }
421
+ if (this.gl.getProgramParameter(program, ext.COMPLETION_STATUS_KHR) !== true) {
422
+ scheduleParallelCompilePoll(poll);
423
+ return;
424
+ }
425
+ this.parallelCompilesPending -= 1;
426
+ try {
427
+ for (const [shader, type] of [[vertexShader, "vertex"], [fragmentShader, "fragment"]]) {
428
+ if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
429
+ const log = this.gl.getShaderInfoLog(shader) ?? "Unknown shader compile error";
430
+ this.gl.deleteShader(vertexShader);
431
+ this.gl.deleteShader(fragmentShader);
432
+ this.gl.deleteProgram(program);
433
+ throw new RenderDeviceError("WebGL shader compile failed", "SHADER_COMPILE_FAILED", { label: sources.label, log, stage: type });
434
+ }
435
+ }
436
+ this.gl.deleteShader(vertexShader);
437
+ this.gl.deleteShader(fragmentShader);
438
+ resolve(this.finalizeLinkedProgram(program, sources));
439
+ }
440
+ catch (error) {
441
+ reject(error);
442
+ }
443
+ };
444
+ scheduleParallelCompilePoll(poll);
445
+ });
446
+ }
447
+ /** Programs issued through `compileAsync`'s parallel path that have not completed yet. */
448
+ parallelCompilesPending = 0;
449
+ parallelCompileExt;
450
+ parallelShaderCompileExtension() {
451
+ if (this.parallelCompileExt === undefined) {
452
+ this.parallelCompileExt = this.gl.getExtension("KHR_parallel_shader_compile") ?? null;
453
+ }
454
+ return this.parallelCompileExt;
455
+ }
456
+ issueShaderCompile(type, source, label) {
457
+ const shader = this.gl.createShader(type);
458
+ if (!shader) {
459
+ throw new RenderDeviceError("Failed to allocate WebGL shader", "WEBGL_ALLOCATION_FAILED", { label });
460
+ }
461
+ this.gl.shaderSource(shader, source);
462
+ this.gl.compileShader(shader);
463
+ return shader;
464
+ }
465
+ assertShaderMarker(sources) {
466
+ if (!sources.vertex.includes(sources.marker) || !sources.fragment.includes(sources.marker)) {
467
+ throw new RenderDeviceError("Shader source marker is missing from compiled sources", "SHADER_MARKER_MISSING", {
468
+ label: sources.label,
469
+ marker: sources.marker
470
+ });
471
+ }
472
+ }
473
+ multiDrawElementsInstanced(draws) {
474
+ this.host.drawBinder.multiDrawElementsInstanced(draws);
475
+ }
476
+ /**
477
+ * #94 (Q-01-1, C-28/C-29): forget every GL object name and uploaded value
478
+ * cached against the lost context — VAOs, uniform locations, last-value
479
+ * uniform snapshots, the GL state shadow and texture-unit bindings — so
480
+ * they recreate lazily on the next draw after `webglcontextrestored`.
481
+ * `counters().liveVertexArrays` reads 0 afterwards. Buffers, textures and
482
+ * programs are recreated by the C-29 ResourceRegistry rebuild that runs
483
+ * right after this in the restore hook.
484
+ */
485
+ invalidateGpuObjects() {
486
+ this.host.drawBinder.invalidateGpuObjects();
487
+ this.host.stateCache.invalidate();
488
+ this.host.samplers.activeTextureUnitIndex = -1;
489
+ this.host.samplers.textureUnitBindings.clear();
312
490
  }
313
491
  createBuffer(usage, byteLength, initialData) {
314
- this.assertAlive();
492
+ this.host.lifecycle.assertAlive();
315
493
  if (byteLength <= 0 || !Number.isInteger(byteLength)) {
316
494
  throw new RenderDeviceError("Buffer byteLength must be a positive integer", "INVALID_BUFFER_SIZE", { byteLength });
317
495
  }
@@ -319,8 +497,12 @@ export class WebGL2Device {
319
497
  if (!handle) {
320
498
  throw new RenderDeviceError("Failed to allocate WebGL buffer", "WEBGL_ALLOCATION_FAILED");
321
499
  }
322
- const target = usage === "index" ? this.gl.ELEMENT_ARRAY_BUFFER : this.gl.ARRAY_BUFFER;
323
- this.bindNoVertexArray();
500
+ const target = usage === "index"
501
+ ? this.gl.ELEMENT_ARRAY_BUFFER
502
+ : usage === "uniform"
503
+ ? this.gl.UNIFORM_BUFFER
504
+ : this.gl.ARRAY_BUFFER;
505
+ this.host.drawBinder.bindNoVertexArray();
324
506
  this.stateCache.bindBuffer(target, handle, () => this.gl.bindBuffer(target, handle));
325
507
  this.gl.bufferData(target, byteLength, this.gl.DYNAMIC_DRAW);
326
508
  if (initialData) {
@@ -333,12 +515,20 @@ export class WebGL2Device {
333
515
  this.gl.bufferSubData(target, 0, initialData);
334
516
  }
335
517
  const buffer = new WebGL2Buffer(this.nextId++, usage, byteLength, target, handle, this.gl);
518
+ buffer.onDispose = () => {
519
+ // §6.1 declared leak fix: cached VAOs key on buffer ids; a dead buffer's
520
+ // entries must die with it, and the live-buffer set drops the corpse
521
+ // (`disposedBuffers` stays meaningful via the monotonic counter).
522
+ this.host.drawBinder.evictVertexArraysForBuffer(buffer.id);
523
+ this.buffers.delete(buffer);
524
+ this.disposedBufferCount += 1;
525
+ };
336
526
  this.buffers.add(buffer);
337
527
  return buffer;
338
528
  }
339
529
  updateBuffer(buffer, byteOffset, data) {
340
- this.assertAlive();
341
- const webglBuffer = this.requireBuffer(buffer);
530
+ this.host.lifecycle.assertAlive();
531
+ const webglBuffer = this.host.drawBinder.requireBuffer(buffer);
342
532
  if (byteOffset < 0 || byteOffset + data.byteLength > webglBuffer.byteLength) {
343
533
  throw new RenderDeviceError("Buffer update range is out of bounds", "BUFFER_RANGE_OUT_OF_BOUNDS", {
344
534
  byteOffset,
@@ -346,14 +536,22 @@ export class WebGL2Device {
346
536
  byteLength: webglBuffer.byteLength
347
537
  });
348
538
  }
349
- this.bindNoVertexArray();
539
+ this.host.drawBinder.bindNoVertexArray();
350
540
  this.stateCache.bindBuffer(webglBuffer.target, webglBuffer.handle, () => this.gl.bindBuffer(webglBuffer.target, webglBuffer.handle));
351
541
  this.gl.bufferSubData(webglBuffer.target, byteOffset, data);
352
- this.bufferUpdateCount += 1;
542
+ this.host.counters.bufferUpdateCount += 1;
543
+ }
544
+ bindUniformBuffer(buffer, binding) {
545
+ this.host.lifecycle.assertAlive();
546
+ const webglBuffer = this.host.drawBinder.requireBuffer(buffer);
547
+ if (webglBuffer.target !== this.gl.UNIFORM_BUFFER) {
548
+ throw new RenderDeviceError("Buffer was not created with usage 'uniform'", "INVALID_BUFFER_USAGE", { bufferId: buffer.id });
549
+ }
550
+ this.gl.bindBufferBase(this.gl.UNIFORM_BUFFER, binding, webglBuffer.handle);
353
551
  }
354
552
  readBuffer(buffer, byteOffset = 0, byteLength = buffer.byteLength - byteOffset) {
355
- this.assertAlive();
356
- const webglBuffer = this.requireBuffer(buffer);
553
+ this.host.lifecycle.assertAlive();
554
+ const webglBuffer = this.host.drawBinder.requireBuffer(buffer);
357
555
  if (byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > webglBuffer.byteLength) {
358
556
  throw new RenderDeviceError("Buffer read range is out of bounds", "BUFFER_RANGE_OUT_OF_BOUNDS", {
359
557
  byteOffset,
@@ -362,42 +560,59 @@ export class WebGL2Device {
362
560
  });
363
561
  }
364
562
  const output = new Uint8Array(byteLength);
365
- this.bindNoVertexArray();
563
+ this.host.drawBinder.bindNoVertexArray();
366
564
  this.stateCache.bindBuffer(webglBuffer.target, webglBuffer.handle, () => this.gl.bindBuffer(webglBuffer.target, webglBuffer.handle));
367
565
  this.gl.getBufferSubData(webglBuffer.target, byteOffset, output);
368
566
  return output;
369
567
  }
370
568
  createShaderProgram(sources) {
371
- this.assertAlive();
372
- if (!sources.vertex.includes(sources.marker) || !sources.fragment.includes(sources.marker)) {
373
- throw new RenderDeviceError("Shader source marker is missing from compiled sources", "SHADER_MARKER_MISSING", {
374
- label: sources.label,
375
- marker: sources.marker
376
- });
377
- }
569
+ this.host.lifecycle.assertAlive();
570
+ this.assertShaderMarker(sources);
378
571
  const vertexShader = this.compileShader(this.gl.VERTEX_SHADER, sources.vertex, sources.label);
379
572
  const fragmentShader = this.compileShader(this.gl.FRAGMENT_SHADER, sources.fragment, sources.label);
380
573
  const program = this.gl.createProgram();
381
574
  if (!program) {
382
575
  throw new RenderDeviceError("Failed to allocate WebGL shader program", "WEBGL_ALLOCATION_FAILED");
383
576
  }
384
- this.shaderProgramCreateCount += 1;
577
+ this.host.counters.shaderProgramCreateCount += 1;
385
578
  this.gl.attachShader(program, vertexShader);
386
579
  this.gl.attachShader(program, fragmentShader);
387
580
  this.gl.linkProgram(program);
581
+ this.host.counters.programCompiles += 1;
388
582
  this.gl.deleteShader(vertexShader);
389
583
  this.gl.deleteShader(fragmentShader);
584
+ return this.finalizeLinkedProgram(program, sources);
585
+ }
586
+ /** LINK_STATUS check, named-block bindings and reflection for a linked program. */
587
+ finalizeLinkedProgram(program, sources) {
390
588
  if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
391
589
  const log = this.gl.getProgramInfoLog(program) ?? "Unknown shader link error";
392
590
  this.gl.deleteProgram(program);
393
591
  throw new RenderDeviceError("WebGL shader link failed", "SHADER_LINK_FAILED", { label: sources.label, log });
394
592
  }
593
+ // T0-02/C-08: generated blocks declare `layout(std140)` with no baked
594
+ // `binding=`; the named-block → binding-point assignment is fixed here so
595
+ // every linked program gets AuraFrame→0 and AuraLights→1 regardless of
596
+ // declaration order. Programs that do not declare a block are skipped.
597
+ for (const [blockName, binding] of NAMED_UNIFORM_BLOCK_BINDINGS) {
598
+ const index = this.gl.getUniformBlockIndex(program, blockName);
599
+ if (index !== this.gl.INVALID_INDEX) {
600
+ this.gl.uniformBlockBinding(program, index, binding);
601
+ }
602
+ }
395
603
  const shader = new WebGL2ShaderProgram(this.nextId++, sources.label, sources.marker, this.reflectProgram(program), program, this.gl);
396
604
  this.shaders.add(shader);
397
605
  return shader;
398
606
  }
399
607
  createRenderTarget(descriptor) {
400
- this.assertAlive();
608
+ this.host.lifecycle.assertAlive();
609
+ if ((descriptor.dimension !== undefined && descriptor.dimension !== "2d") ||
610
+ descriptor.layers !== undefined ||
611
+ descriptor.depthOnly === true ||
612
+ descriptor.depthCompare === true ||
613
+ (descriptor.colorAttachments?.length ?? 0) > 1) {
614
+ return this.createFeatureRenderTarget(descriptor);
615
+ }
401
616
  if (!Number.isInteger(descriptor.width) ||
402
617
  descriptor.width <= 0 ||
403
618
  !Number.isInteger(descriptor.height) ||
@@ -462,8 +677,15 @@ export class WebGL2Device {
462
677
  this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
463
678
  this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
464
679
  this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
465
- const format = descriptor.format ?? "rgba8";
466
- const textureFormat = this.resolveRenderTargetFormat(format);
680
+ // A single `colorAttachments` entry is the attachment-0 format (CONTRACTS
681
+ // §3.4) and wins over the legacy `format` field. Before this, the 2d path
682
+ // ignored it, so `createHdrTarget` ({ format: "rgba8", colorAttachments:
683
+ // [{ format: "rgba16f" }] }) without coverage allocated an RGBA8 "HDR"
684
+ // scene target: linear radiance clamped at 1.0 and 8-bit dark banding
685
+ // before tone mapping (GPU run 38190015020: device ACES of 4.0 = 226 vs
686
+ // three 250; tonemap-ramp dark swatches ΔE2000 13-30).
687
+ const format = renderTargetColorFormat(descriptor);
688
+ const textureFormat = resolveRenderTargetFormat(this.gl, format);
467
689
  this.gl.texImage2D(this.gl.TEXTURE_2D, 0, textureFormat.internalFormat, descriptor.width, descriptor.height, 0, this.gl.RGBA, textureFormat.type, null);
468
690
  this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
469
691
  this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, colorHandle, 0);
@@ -524,587 +746,373 @@ export class WebGL2Device {
524
746
  // Cascaded maps use the established renderer-csm-cascade-* labels.
525
747
  // Count their actual allocation too, including the first shadow frame.
526
748
  if (/shadow|(?:^|-)csm(?:-|$)/i.test(descriptor.label ?? ""))
527
- this.shadowRenderTargetsAllocated += 1;
528
- this.textures.set(target.colorTexture, colorHandle);
529
- this.textureUploadModes.set(target.colorTexture, "rgba8");
749
+ this.host.counters.shadowRenderTargetsAllocated += 1;
750
+ this.host.textureRegistry.textures.set(target.colorTexture, colorHandle);
751
+ this.host.textureRegistry.textureUploadModes.set(target.colorTexture, "rgba8");
530
752
  if (depthTexture && depthTextureHandle) {
531
- this.textures.set(depthTexture, depthTextureHandle);
532
- this.textureUploadModes.set(depthTexture, "depth-render-target");
753
+ this.host.textureRegistry.textures.set(depthTexture, depthTextureHandle);
754
+ this.host.textureRegistry.textureUploadModes.set(depthTexture, "depth-render-target");
533
755
  }
534
756
  return target;
535
757
  }
536
- setRenderTarget(target) {
537
- this.assertAlive();
538
- if (this.activeRenderTarget && this.activeRenderTarget !== target) {
539
- this.resolveMultisampleTarget(this.activeRenderTarget);
540
- }
541
- if (target === null) {
542
- this.activeRenderTarget = null;
543
- this.stateCache.bindFramebuffer(this.gl.FRAMEBUFFER, null, () => this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null));
544
- this.stateCache.viewport(0, 0, this.viewportWidth || this.gl.drawingBufferWidth, this.viewportHeight || this.gl.drawingBufferHeight, () => this.gl.viewport(0, 0, this.viewportWidth || this.gl.drawingBufferWidth, this.viewportHeight || this.gl.drawingBufferHeight));
545
- return;
546
- }
547
- if (!(target instanceof WebGL2RenderTarget) || !this.renderTargets.has(target) || target.disposed) {
548
- throw new RenderDeviceError("Render target is not a live WebGL2 resource owned by this device", "INVALID_RESOURCE", {
549
- targetId: target.id
758
+ /**
759
+ * PR 0a render-target fields (CONTRACTS §3.4): `dimension`/`layers` (cube +
760
+ * 2d-array layered targets rendered through `layerTargets`), `depthOnly`
761
+ * (no color attachment), `depthCompare` (comparison-sampler depth texture)
762
+ * and `colorAttachments` (MRT, per-layer `drawBuffers` state).
763
+ */
764
+ createFeatureRenderTarget(descriptor) {
765
+ const gl = this.gl;
766
+ if (!Number.isInteger(descriptor.width) ||
767
+ descriptor.width <= 0 ||
768
+ !Number.isInteger(descriptor.height) ||
769
+ descriptor.height <= 0) {
770
+ throw new RenderDeviceError("Render target dimensions must be positive integers", "INVALID_RENDER_TARGET_SIZE", {
771
+ width: descriptor.width,
772
+ height: descriptor.height,
773
+ label: descriptor.label
550
774
  });
551
775
  }
552
- this.activeRenderTarget = target;
553
- this.stateCache.bindFramebuffer(this.gl.FRAMEBUFFER, target.drawFramebuffer, () => this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, target.drawFramebuffer));
554
- this.stateCache.viewport(0, 0, target.width, target.height, () => this.gl.viewport(0, 0, target.width, target.height));
555
- }
556
- resolveMultisampleTarget(target) {
557
- if (target.sampleCount <= 1 || !target.needsResolve)
558
- return;
559
- const previousFramebuffer = this.gl.getParameter(this.gl.FRAMEBUFFER_BINDING);
560
- this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER, target.drawFramebuffer);
561
- this.gl.bindFramebuffer(this.gl.DRAW_FRAMEBUFFER, target.framebuffer);
562
- let mask = this.gl.COLOR_BUFFER_BIT;
563
- if (target.depthTextureHandle)
564
- mask |= this.gl.DEPTH_BUFFER_BIT;
565
- this.gl.blitFramebuffer(0, 0, target.width, target.height, 0, 0, target.width, target.height, mask, this.gl.NEAREST);
566
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, previousFramebuffer);
567
- target.needsResolve = false;
568
- this.stateCache.invalidate();
569
- }
570
- writeRenderTargetPixels(target, pixels) {
571
- this.assertAlive();
572
- if (!(target instanceof WebGL2RenderTarget) || !this.renderTargets.has(target) || target.disposed) {
573
- throw new RenderDeviceError("Render target is not a live WebGL2 resource owned by this device", "INVALID_RESOURCE", {
574
- targetId: target.id
776
+ const dimension = descriptor.dimension ?? "2d";
777
+ if (descriptor.layers !== undefined && (!Number.isInteger(descriptor.layers) || descriptor.layers < 1)) {
778
+ throw new RenderDeviceError("Render target layer count must be a positive integer", "INVALID_RENDER_TARGET_SIZE", {
779
+ layers: descriptor.layers,
780
+ label: descriptor.label
575
781
  });
576
782
  }
577
- if (target.colorTexture.format !== "rgba8") {
578
- throw new RenderDeviceError("Byte pixel uploads are only supported for rgba8 WebGL2 render targets", "INVALID_PIXEL_UPLOAD_FORMAT", {
579
- targetId: target.id,
580
- format: target.colorTexture.format
783
+ if (descriptor.layers !== undefined && dimension !== "2d-array") {
784
+ throw new RenderDeviceError("Render target `layers` only applies to dimension \"2d-array\"", "INVALID_RENDER_TARGET_SIZE", {
785
+ dimension,
786
+ layers: descriptor.layers,
787
+ label: descriptor.label
581
788
  });
582
789
  }
583
- if (pixels.length !== target.width * target.height * 4) {
584
- throw new RenderDeviceError("Render-target pixel upload must contain width * height * 4 bytes", "INVALID_PIXEL_UPLOAD_SIZE", {
585
- targetId: target.id,
586
- byteLength: pixels.length,
587
- expectedByteLength: target.width * target.height * 4
790
+ const layerCount = dimension === "cube" ? 6 : dimension === "2d-array" ? descriptor.layers ?? 1 : 1;
791
+ const depthOnly = descriptor.depthOnly === true;
792
+ if (depthOnly && (descriptor.colorAttachments?.length ?? 0) > 0) {
793
+ throw new RenderDeviceError("Render target cannot combine `depthOnly` with `colorAttachments`", "INVALID_RENDER_TARGET_SIZE", {
794
+ label: descriptor.label
588
795
  });
589
796
  }
590
- const textureUnit0 = this.captureTextureUnit0();
591
- try {
592
- this.gl.bindTexture(this.gl.TEXTURE_2D, target.colorHandle);
593
- this.gl.texSubImage2D(this.gl.TEXTURE_2D, 0, 0, 0, target.width, target.height, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pixels);
594
- target.needsResolve = false;
595
- }
596
- finally {
597
- this.restoreTextureUnit0(textureUnit0);
598
- }
599
- this.lastError = this.readError();
600
- if (this.lastError) {
601
- throw new RenderDeviceError("WebGL2 render-target pixel upload failed", "WEBGL_PIXEL_UPLOAD_FAILED", {
602
- targetId: target.id,
603
- error: this.lastError
797
+ if (depthOnly && descriptor.depth === false) {
798
+ throw new RenderDeviceError("Render target cannot combine `depthOnly` with `depth: false`", "INVALID_RENDER_TARGET_SIZE", {
799
+ label: descriptor.label
604
800
  });
605
801
  }
606
- }
607
- presentRenderTarget(source) {
608
- this.assertAlive();
609
- if (!(source instanceof WebGL2RenderTarget) || !this.renderTargets.has(source) || source.disposed) {
610
- throw new RenderDeviceError("Render target is not a live WebGL2 resource owned by this device", "INVALID_RESOURCE", {
611
- targetId: source.id
802
+ const sampleCount = descriptor.sampleCount ?? 1;
803
+ const colorAttachmentCount = depthOnly ? 0 : Math.max(1, descriptor.colorAttachments?.length ?? 1);
804
+ if (sampleCount > 1 && (depthOnly || descriptor.depthCompare === true || (descriptor.colorAttachments?.length ?? 0) > 1 || layerCount > 1)) {
805
+ throw new RenderDeviceError("Multisample render targets do not support layered, depth-only, compare or MRT descriptors", "INVALID_RENDER_TARGET_SAMPLE_COUNT", {
806
+ sampleCount,
807
+ label: descriptor.label
612
808
  });
613
809
  }
614
- this.resolveMultisampleTarget(source);
615
- const outputWidth = this.viewportWidth || this.gl.drawingBufferWidth;
616
- const outputHeight = this.viewportHeight || this.gl.drawingBufferHeight;
617
- this.drawRenderTargetToBackbuffer(source, outputWidth, outputHeight);
618
- this.activeRenderTarget = null;
619
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);
620
- this.lastError = this.readError();
621
- if (this.lastError) {
622
- throw new RenderDeviceError(`WebGL2 render-target presentation failed: ${this.lastError}`, "WEBGL_PRESENT_FAILED", {
623
- targetId: source.id,
624
- error: this.lastError
810
+ const maxSamples = Number(gl.getParameter(gl.MAX_SAMPLES) ?? 1);
811
+ if (!Number.isInteger(sampleCount) || sampleCount < 1 || sampleCount > maxSamples) {
812
+ throw new RenderDeviceError("WebGL2 render-target sampleCount must be an integer supported by MAX_SAMPLES.", "INVALID_RENDER_TARGET_SAMPLE_COUNT", {
813
+ sampleCount,
814
+ maxSamples,
815
+ label: descriptor.label
625
816
  });
626
817
  }
627
- }
628
- /** Executes the same native SSR kernel used by postprocessing into an owned target. */
629
- executeReflectionSurfaceSsr(source, normalMask, output, options) {
630
- this.assertAlive();
631
- for (const target of [source, normalMask, output]) {
632
- if (!(target instanceof WebGL2RenderTarget) || !this.renderTargets.has(target) || target.disposed) {
633
- throw new RenderDeviceError("SSR inputs must be live targets owned by this device", "INVALID_RESOURCE");
818
+ const label = descriptor.label ?? "render-target";
819
+ const textureTarget = dimension === "cube" ? gl.TEXTURE_CUBE_MAP : dimension === "2d-array" ? gl.TEXTURE_2D_ARRAY : gl.TEXTURE_2D;
820
+ const depthMode = depthOnly || descriptor.depth === "texture" || (layerCount > 1 && descriptor.depth !== false) ? "texture" : descriptor.depth === false ? "none" : "renderbuffer";
821
+ const depthCompare = descriptor.depthCompare === true;
822
+ const colorFormats = depthOnly
823
+ ? []
824
+ : colorAttachmentCount === 1 && !descriptor.colorAttachments
825
+ ? [descriptor.format ?? "rgba8"]
826
+ : (descriptor.colorAttachments ?? [{ format: descriptor.format ?? "rgba8" }]).map((attachment) => attachment.format);
827
+ const colorHandles = [];
828
+ const colorTextures = [];
829
+ let depthTextureHandle = null;
830
+ const layerFramebuffers = [];
831
+ const cleanup = () => {
832
+ for (const handle of colorHandles)
833
+ gl.deleteTexture(handle);
834
+ if (depthTextureHandle)
835
+ gl.deleteTexture(depthTextureHandle);
836
+ for (const framebuffer of layerFramebuffers)
837
+ gl.deleteFramebuffer(framebuffer);
838
+ };
839
+ const previousActiveTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
840
+ gl.activeTexture(gl.TEXTURE0);
841
+ const previousTexture = gl.getParameter(gl.TEXTURE_BINDING_2D);
842
+ const previousCubeTexture = gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP);
843
+ const previousArrayTexture = gl.getParameter(gl.TEXTURE_BINDING_2D_ARRAY);
844
+ const previousFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
845
+ for (let attachment = 0; attachment < colorFormats.length; attachment += 1) {
846
+ const format = colorFormats[attachment];
847
+ const textureFormat = resolveRenderTargetFormat(gl, format);
848
+ const handle = gl.createTexture();
849
+ if (!handle) {
850
+ cleanup();
851
+ throw new RenderDeviceError("Failed to allocate WebGL render target", "WEBGL_ALLOCATION_FAILED", { label });
852
+ }
853
+ colorHandles.push(handle);
854
+ colorTextures.push(new Texture({ width: descriptor.width, height: descriptor.height, format, label: colorAttachmentCount > 1 ? `${label}-color-${attachment}` : descriptor.label ?? "render-target-color", dimension, layers: dimension === "2d" ? undefined : layerCount, renderAttachment: true }));
855
+ gl.bindTexture(textureTarget, handle);
856
+ gl.texParameteri(textureTarget, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
857
+ gl.texParameteri(textureTarget, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
858
+ gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
859
+ gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
860
+ if (dimension === "2d") {
861
+ gl.texImage2D(textureTarget, 0, textureFormat.internalFormat, descriptor.width, descriptor.height, 0, gl.RGBA, textureFormat.type, null);
862
+ }
863
+ else if (dimension === "cube") {
864
+ gl.texStorage2D(textureTarget, 1, renderTargetStorageFormat(gl, textureFormat.internalFormat), descriptor.width, descriptor.height);
865
+ }
866
+ else {
867
+ gl.texStorage3D(textureTarget, 1, renderTargetStorageFormat(gl, textureFormat.internalFormat), descriptor.width, descriptor.height, layerCount);
634
868
  }
635
869
  }
636
- const color = source, normals = normalMask, destination = output;
637
- if (!color.depthTextureHandle || color === destination || normals === destination
638
- || color.width !== normals.width || color.height !== normals.height) {
639
- throw new RenderDeviceError("SSR requires sampleable scene depth, matching normal-mask input, and a separate output", "INVALID_RESOURCE");
640
- }
641
- this.resolveMultisampleTarget(color);
642
- this.resolveMultisampleTarget(normals);
643
- const state = this.prepareFullscreenPresentation(destination.framebuffer, destination.width, destination.height);
644
- try {
645
- this.drawSsrKernel(color.colorHandle, color.depthTextureHandle, destination.width, destination.height, { ...options, normalMask: normals.colorHandle }, this.ensurePresentationVertexArray(), { near: 0.1, far: 1000 });
646
- }
647
- finally {
648
- this.restoreFullscreenPresentationState(state, destination.width, destination.height);
649
- }
650
- }
651
- presentLdrPostprocess(source, options) {
652
- this.assertAlive();
653
- if (!(source instanceof WebGL2RenderTarget) || !this.renderTargets.has(source) || source.disposed) {
654
- throw new RenderDeviceError("Render target is not a live WebGL2 resource owned by this device", "INVALID_RESOURCE", {
655
- targetId: source.id
656
- });
657
- }
658
- this.resolveMultisampleTarget(source);
659
- const tonePass = options.passes.find((pass) => pass.name === "tone-mapping");
660
- const bloomPass = options.passes.find((pass) => pass.name === "bloom");
661
- const depthOfFieldPass = options.passes.find((pass) => pass.name === "depth-of-field");
662
- const motionBlurPass = options.passes.find((pass) => pass.name === "motion-blur");
663
- const ssaoPass = options.passes.find((pass) => pass.name === "ssao");
664
- const ssrPass = options.passes.find((pass) => pass.name === "ssr");
665
- const taaPass = options.passes.find((pass) => pass.name === "taa");
666
- const outlinePass = options.passes.find((pass) => pass.name === "outline");
667
- if (source.colorTexture.format !== "rgba8" && !tonePass) {
668
- throw new RenderDeviceError("WebGL2 HDR postprocess presentation requires a tone-mapping pass before LDR output.", "WEBGL_LDR_POSTPROCESS_FORMAT_UNSUPPORTED", {
669
- targetId: source.id,
670
- format: source.colorTexture.format
671
- });
672
- }
673
- if (source.colorTexture.format !== "rgba8" && (depthOfFieldPass || motionBlurPass || ssaoPass || ssrPass || taaPass || outlinePass) && !tonePass) {
674
- throw new RenderDeviceError("WebGL2 byte-kernel postprocess requires rgba8 input or a preceding tone-mapping pass.", "WEBGL_LDR_POSTPROCESS_FORMAT_UNSUPPORTED", {
675
- targetId: source.id,
676
- format: source.colorTexture.format,
677
- pass: depthOfFieldPass ? "depth-of-field" : motionBlurPass ? "motion-blur" : ssaoPass ? "ssao" : ssrPass ? "ssr" : taaPass ? "taa" : "outline"
678
- });
679
- }
680
- if ((depthOfFieldPass || ssaoPass || ssrPass) && !source.depthTextureHandle) {
681
- throw new RenderDeviceError("WebGL2 native depth postprocess requires a renderer-owned sampleable depth texture.", "WEBGL_LDR_POSTPROCESS_DEPTH_REQUIRED", {
682
- targetId: source.id,
683
- pass: depthOfFieldPass ? "depth-of-field" : ssaoPass ? "ssao" : "ssr"
684
- });
685
- }
686
- // Raw GL depth is nonlinear (0.1/1000 defaults park the play area past
687
- // 0.97), which blinded every depth-gated native pass. SSR and DOF compare
688
- // linearized depth; SSAO keeps its legacy response (documented partial).
689
- const depthRange = normalizeLdrDepthRange(options.depthRange);
690
- const outputTarget = options.outputTarget;
691
- if (outputTarget && (!(outputTarget instanceof WebGL2RenderTarget) || !this.renderTargets.has(outputTarget) || outputTarget.disposed)) {
692
- throw new RenderDeviceError("Output render target is not a live WebGL2 resource owned by this device", "INVALID_RESOURCE", {
693
- targetId: outputTarget.id
694
- });
695
- }
696
- if (outputTarget && outputTarget.colorTexture.format !== "rgba8") {
697
- throw new RenderDeviceError("WebGL2 LDR postprocess output target must be rgba8.", "WEBGL_LDR_POSTPROCESS_OUTPUT_FORMAT_UNSUPPORTED", {
698
- targetId: outputTarget.id,
699
- format: outputTarget.colorTexture.format
700
- });
701
- }
702
- if (outputTarget && (outputTarget.width !== source.width || outputTarget.height !== source.height)) {
703
- throw new RenderDeviceError("WebGL2 LDR postprocess source and output dimensions must match.", "WEBGL_LDR_POSTPROCESS_SIZE_MISMATCH", {
704
- sourceWidth: source.width,
705
- sourceHeight: source.height,
706
- targetWidth: outputTarget.width,
707
- targetHeight: outputTarget.height
870
+ let depthTexture;
871
+ if (depthMode === "texture") {
872
+ depthTextureHandle = gl.createTexture();
873
+ if (!depthTextureHandle) {
874
+ cleanup();
875
+ throw new RenderDeviceError("Failed to allocate WebGL render target", "WEBGL_ALLOCATION_FAILED", { label });
876
+ }
877
+ depthTexture = new Texture({
878
+ width: descriptor.width,
879
+ height: descriptor.height,
880
+ format: "depth24",
881
+ label: `${label}-depth`,
882
+ dimension,
883
+ layers: dimension === "2d" ? undefined : layerCount,
884
+ renderAttachment: true
708
885
  });
886
+ gl.bindTexture(textureTarget, depthTextureHandle);
887
+ gl.texParameteri(textureTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
888
+ gl.texParameteri(textureTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
889
+ gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
890
+ gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
891
+ if (depthCompare) {
892
+ gl.texParameteri(textureTarget, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
893
+ gl.texParameteri(textureTarget, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL);
894
+ }
895
+ if (dimension === "2d-array") {
896
+ gl.texImage3D(textureTarget, 0, gl.DEPTH_COMPONENT24, descriptor.width, descriptor.height, layerCount, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
897
+ }
898
+ else if (dimension === "cube") {
899
+ gl.texStorage2D(textureTarget, 1, gl.DEPTH_COMPONENT24, descriptor.width, descriptor.height);
900
+ }
901
+ else {
902
+ gl.texImage2D(textureTarget, 0, gl.DEPTH_COMPONENT24, descriptor.width, descriptor.height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
903
+ }
709
904
  }
710
- const webglOutputTarget = outputTarget;
711
- const colorPass = options.passes.find((pass) => pass.name === "color-grade");
712
- const fxaaPass = options.passes.find((pass) => pass.name === "fxaa");
713
- const bloomOptions = bloomPass ? normalizeNativeBloomOptions(bloomPass.options) : undefined;
714
- const depthOfFieldOptions = depthOfFieldPass ? normalizeNativeDepthOfFieldOptions(depthOfFieldPass.options) : undefined;
715
- const motionBlurOptions = motionBlurPass
716
- ? normalizeNativeMotionBlurOptions(motionBlurPass.options, source.width, source.height)
717
- : undefined;
718
- const ssaoOptions = ssaoPass ? normalizeNativeSsaoOptions(ssaoPass.options) : undefined;
719
- const ssrOptions = ssrPass ? normalizeNativeSsrOptions(ssrPass.options) : undefined;
720
- const taaOptions = taaPass ? normalizeNativeTaaOptions(taaPass.options, source.width, source.height) : undefined;
721
- const outlineOptions = outlinePass ? normalizeNativeOutlineOptions(outlinePass.options) : undefined;
722
- const program = this.ensureLdrPostprocessProgram();
723
- const vertexArray = this.ensurePresentationVertexArray();
724
- const sourceIsHdr = source.colorTexture.format !== "rgba8";
725
- const bloomResources = bloomOptions || depthOfFieldOptions || motionBlurOptions || ssaoOptions || ssrOptions || taaOptions || outlineOptions
726
- ? this.ensureBloomPingPongResources(source.width, source.height, sourceIsHdr && Boolean(bloomOptions))
727
- : undefined;
728
- if (bloomOptions && !sourceIsHdr) {
729
- this.ensureBloomLutTextures(bloomOptions);
730
- }
731
- if (outlineOptions) {
732
- this.ensureOutlineBlendLutTexture(outlineOptions);
733
- }
734
- if (motionBlurOptions?.velocity) {
735
- this.ensureMotionBlurVelocityTexture(source.width, source.height, motionBlurOptions.velocity);
736
- }
737
- if (taaOptions?.history) {
738
- this.ensureTaaHistoryTexture(source.width, source.height, taaOptions.history);
739
- }
740
- const outputWidth = webglOutputTarget?.width ?? (this.viewportWidth || this.gl.drawingBufferWidth);
741
- const outputHeight = webglOutputTarget?.height ?? (this.viewportHeight || this.gl.drawingBufferHeight);
742
- const previousState = this.prepareFullscreenPresentation(webglOutputTarget?.framebuffer ?? null, outputWidth, outputHeight);
743
- try {
744
- let ldrSourceHandle = source.colorHandle;
745
- let temporarySourceIndex = -1;
746
- if (bloomOptions && bloomResources) {
747
- if (bloomOptions.quality === "performance") {
748
- ldrSourceHandle = this.executeNativeBloomPasses(ldrSourceHandle, bloomResources, bloomOptions, vertexArray, sourceIsHdr);
749
- temporarySourceIndex = 1;
750
- this.recordBloomDiagnostics(bloomOptions, source.width, source.height, sourceIsHdr, 1);
751
- }
752
- else {
753
- const plan = resolveBloomPyramidPlan(source.width, source.height, bloomOptions.quality, sourceIsHdr);
754
- const pyramid = this.ensureBloomPyramidResources(plan, sourceIsHdr);
755
- const pyramidResult = this.executeNativeBloomPyramidPasses(ldrSourceHandle, source.width, source.height, pyramid, {
756
- textureA: bloomResources.textures[0],
757
- framebufferA: bloomResources.framebuffers[0],
758
- textureB: bloomResources.textures[1],
759
- framebufferB: bloomResources.framebuffers[1]
760
- }, bloomOptions, vertexArray, sourceIsHdr);
761
- // The pyramid sum lands in ping-pong texture A; composite it with the
762
- // source through the proven single-scale composite program.
763
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, bloomResources.framebuffers[1]);
764
- this.gl.viewport(0, 0, source.width, source.height);
765
- const pyramidComposite = this.ensureBloomCompositeProgram();
766
- this.gl.useProgram(pyramidComposite);
767
- this.gl.bindVertexArray(vertexArray);
768
- this.bindFullscreenTexture(0, ldrSourceHandle);
769
- this.bindFullscreenTexture(1, pyramidResult);
770
- if (this.bloomCompositeLutTexture)
771
- this.bindFullscreenTexture(2, this.bloomCompositeLutTexture);
772
- this.gl.uniform1i(this.gl.getUniformLocation(pyramidComposite, "u_source"), 0);
773
- this.gl.uniform1i(this.gl.getUniformLocation(pyramidComposite, "u_blurred"), 1);
774
- this.gl.uniform1i(this.gl.getUniformLocation(pyramidComposite, "u_compositeLut"), 2);
775
- this.gl.uniform1i(this.gl.getUniformLocation(pyramidComposite, "u_hdr"), sourceIsHdr ? 1 : 0);
776
- this.gl.uniform1f(this.gl.getUniformLocation(pyramidComposite, "u_intensity"), bloomOptions.intensity * resolveBloomPyramidResponseGain(plan));
777
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
778
- ldrSourceHandle = bloomResources.textures[1];
779
- // The composited result lives in texture B, so subsequent passes
780
- // must write texture A (index 0) to avoid sampling a bound target.
781
- temporarySourceIndex = 0;
782
- this.recordBloomDiagnostics(bloomOptions, source.width, source.height, sourceIsHdr, plan.mipCount);
783
- }
905
+ let depthRenderbufferHandle = null;
906
+ if (depthMode === "renderbuffer") {
907
+ depthRenderbufferHandle = gl.createRenderbuffer();
908
+ if (!depthRenderbufferHandle) {
909
+ cleanup();
910
+ throw new RenderDeviceError("Failed to allocate WebGL render target", "WEBGL_ALLOCATION_FAILED", { label });
784
911
  }
785
- if ((depthOfFieldOptions || motionBlurOptions || ssaoOptions || ssrOptions || taaOptions || outlineOptions) && bloomResources) {
786
- if (tonePass || colorPass) {
787
- const baseTargetIndex = 0;
788
- this.drawNativeLdrStage(ldrSourceHandle, bloomResources.framebuffers[baseTargetIndex], source.width, source.height, program, vertexArray, tonePass, colorPass, undefined, options.toneMappingDefaults);
789
- ldrSourceHandle = bloomResources.textures[baseTargetIndex];
790
- temporarySourceIndex = baseTargetIndex;
912
+ const previousRenderbuffer = gl.getParameter(gl.RENDERBUFFER_BINDING);
913
+ gl.bindRenderbuffer(gl.RENDERBUFFER, depthRenderbufferHandle);
914
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, descriptor.width, descriptor.height);
915
+ gl.bindRenderbuffer(gl.RENDERBUFFER, previousRenderbuffer);
916
+ }
917
+ const drawBuffers = depthOnly
918
+ ? [gl.NONE]
919
+ : colorFormats.map((_, attachment) => gl.COLOR_ATTACHMENT0 + attachment);
920
+ const attachLayer = (framebuffer, layer) => {
921
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
922
+ if (depthOnly) {
923
+ gl.drawBuffers([gl.NONE]);
924
+ gl.readBuffer(gl.NONE);
925
+ }
926
+ else if (drawBuffers.length > 1) {
927
+ gl.drawBuffers(drawBuffers);
928
+ }
929
+ for (let attachment = 0; attachment < colorHandles.length; attachment += 1) {
930
+ if (dimension === "cube") {
931
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + attachment, gl.TEXTURE_CUBE_MAP_POSITIVE_X + layer, colorHandles[attachment], 0);
791
932
  }
792
- if (depthOfFieldOptions && source.depthTextureHandle) {
793
- const depthOfFieldTargetIndex = temporarySourceIndex === 0 ? 1 : 0;
794
- ldrSourceHandle = this.executeNativeDepthOfFieldPass(ldrSourceHandle, source.depthTextureHandle, bloomResources, depthOfFieldOptions, vertexArray, depthOfFieldTargetIndex, depthRange);
795
- temporarySourceIndex = depthOfFieldTargetIndex;
933
+ else if (dimension === "2d-array") {
934
+ gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + attachment, colorHandles[attachment], 0, layer);
796
935
  }
797
- if (motionBlurOptions) {
798
- const motionBlurTargetIndex = temporarySourceIndex === 0 ? 1 : 0;
799
- ldrSourceHandle = this.executeNativeMotionBlurPass(ldrSourceHandle, bloomResources, motionBlurOptions, vertexArray, motionBlurTargetIndex);
800
- temporarySourceIndex = motionBlurTargetIndex;
936
+ else {
937
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + attachment, gl.TEXTURE_2D, colorHandles[attachment], 0);
801
938
  }
802
- if (ssaoOptions && source.depthTextureHandle) {
803
- const ssaoTargetIndex = temporarySourceIndex === 0 ? 1 : 0;
804
- ldrSourceHandle = this.executeNativeSsaoPass(ldrSourceHandle, source.depthTextureHandle, bloomResources, ssaoOptions, vertexArray, ssaoTargetIndex);
805
- temporarySourceIndex = ssaoTargetIndex;
939
+ }
940
+ if (depthTextureHandle) {
941
+ if (dimension === "cube") {
942
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + layer, depthTextureHandle, 0);
806
943
  }
807
- if (ssrOptions && source.depthTextureHandle) {
808
- const ssrTargetIndex = temporarySourceIndex === 0 ? 1 : 0;
809
- ldrSourceHandle = this.executeNativeSsrPass(ldrSourceHandle, source.depthTextureHandle, bloomResources, ssrOptions, vertexArray, ssrTargetIndex, depthRange);
810
- temporarySourceIndex = ssrTargetIndex;
944
+ else if (dimension === "2d-array") {
945
+ gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, depthTextureHandle, 0, layer);
811
946
  }
812
- if (taaOptions) {
813
- const taaTargetIndex = temporarySourceIndex === 0 ? 1 : 0;
814
- ldrSourceHandle = this.executeNativeTaaPass(ldrSourceHandle, bloomResources, taaOptions, vertexArray, taaTargetIndex);
815
- temporarySourceIndex = taaTargetIndex;
947
+ else {
948
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTextureHandle, 0);
816
949
  }
817
950
  }
818
- if (outlineOptions && bloomResources) {
819
- const outlineTargetIndex = temporarySourceIndex === 0 ? 1 : 0;
820
- ldrSourceHandle = this.executeNativeOutlinePasses(ldrSourceHandle, bloomResources, outlineOptions, vertexArray, outlineTargetIndex);
821
- temporarySourceIndex = outlineTargetIndex;
951
+ if (depthRenderbufferHandle) {
952
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthRenderbufferHandle);
953
+ }
954
+ return gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
955
+ };
956
+ for (let layer = 0; layer < layerCount; layer += 1) {
957
+ const framebuffer = gl.createFramebuffer();
958
+ if (!framebuffer) {
959
+ cleanup();
960
+ throw new RenderDeviceError("Failed to allocate WebGL render target", "WEBGL_ALLOCATION_FAILED", { label });
961
+ }
962
+ layerFramebuffers.push(framebuffer);
963
+ if (!attachLayer(framebuffer, layer)) {
964
+ const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
965
+ cleanup();
966
+ if (depthRenderbufferHandle)
967
+ gl.deleteRenderbuffer(depthRenderbufferHandle);
968
+ gl.bindFramebuffer(gl.FRAMEBUFFER, previousFramebuffer);
969
+ gl.bindTexture(gl.TEXTURE_2D, previousTexture);
970
+ if (previousCubeTexture !== null)
971
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, previousCubeTexture);
972
+ if (previousArrayTexture !== null)
973
+ gl.bindTexture(gl.TEXTURE_2D_ARRAY, previousArrayTexture);
974
+ gl.activeTexture(previousActiveTexture);
975
+ this.stateCache.invalidate();
976
+ throw new RenderDeviceError("WebGL render target framebuffer status is invalid", "FRAMEBUFFER_INVALID", { status, layer, label });
822
977
  }
823
- this.drawNativeLdrStage(ldrSourceHandle, webglOutputTarget?.framebuffer ?? null, outputWidth, outputHeight, program, vertexArray, depthOfFieldOptions || motionBlurOptions || ssaoOptions || ssrOptions || taaOptions || outlineOptions ? undefined : tonePass, depthOfFieldOptions || motionBlurOptions || ssaoOptions || ssrOptions || taaOptions || outlineOptions ? undefined : colorPass, fxaaPass, options.toneMappingDefaults);
824
- this.gl.flush();
825
- }
826
- finally {
827
- this.restoreFullscreenPresentationState(previousState, outputWidth, outputHeight);
828
- }
829
- this.lastError = this.readError();
830
- if (this.lastError) {
831
- throw new RenderDeviceError(`WebGL2 LDR postprocess presentation failed: ${this.lastError}`, "WEBGL_LDR_POSTPROCESS_FAILED", {
832
- targetId: source.id,
833
- error: this.lastError
834
- });
835
- }
836
- this.setRenderTarget(webglOutputTarget ?? null);
837
- }
838
- readPixels(x, y, width, height) {
839
- this.assertAlive();
840
- if (![x, y, width, height].every(Number.isInteger) || x < 0 || y < 0 || width <= 0 || height <= 0) {
841
- throw new RenderDeviceError("Readback rectangle must be positive and in bounds", "INVALID_READBACK_RECT", { x, y, width, height });
842
- }
843
- const boundsWidth = this.activeRenderTarget?.width ?? this.gl.drawingBufferWidth;
844
- const boundsHeight = this.activeRenderTarget?.height ?? this.gl.drawingBufferHeight;
845
- if (x + width > boundsWidth || y + height > boundsHeight) {
846
- throw new RenderDeviceError("Readback rectangle exceeds framebuffer bounds", "READBACK_OUT_OF_BOUNDS", {
847
- x,
848
- y,
849
- width,
850
- height,
851
- boundsWidth,
852
- boundsHeight
853
- });
854
- }
855
- const readTarget = this.activeRenderTarget;
856
- if (readTarget) {
857
- this.resolveMultisampleTarget(readTarget);
858
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, readTarget.framebuffer);
859
- }
860
- const pixels = new Uint8Array(width * height * 4);
861
- this.gl.readPixels(x, y, width, height, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pixels);
862
- if (readTarget && readTarget.sampleCount > 1) {
863
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, readTarget.drawFramebuffer);
864
- this.stateCache.invalidate();
865
978
  }
866
- return pixels;
867
- }
868
- readFloatPixels(x, y, width, height) {
869
- this.assertAlive();
870
- if (![x, y, width, height].every(Number.isInteger) || x < 0 || y < 0 || width <= 0 || height <= 0) {
871
- throw new RenderDeviceError("Float readback rectangle must be positive and in bounds", "INVALID_READBACK_RECT", { x, y, width, height });
979
+ gl.bindFramebuffer(gl.FRAMEBUFFER, previousFramebuffer);
980
+ gl.bindTexture(gl.TEXTURE_2D, previousTexture);
981
+ if (previousCubeTexture !== null)
982
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, previousCubeTexture);
983
+ if (previousArrayTexture !== null)
984
+ gl.bindTexture(gl.TEXTURE_2D_ARRAY, previousArrayTexture);
985
+ gl.activeTexture(previousActiveTexture);
986
+ this.stateCache.invalidate();
987
+ const colorTexture = colorTextures[0] ?? new Texture({ width: descriptor.width, height: descriptor.height, format: "rgba8", label: `${label}-colorless`, dimension, renderAttachment: true });
988
+ let parentColorHandle = colorHandles[0];
989
+ if (!parentColorHandle) {
990
+ // Depth-only targets keep a placeholder Texture in `colorTexture`; give it a
991
+ // real (never-attached, never-registered) GL handle so dispose stays sound.
992
+ parentColorHandle = gl.createTexture();
993
+ if (!parentColorHandle) {
994
+ cleanup();
995
+ if (depthRenderbufferHandle)
996
+ gl.deleteRenderbuffer(depthRenderbufferHandle);
997
+ throw new RenderDeviceError("Failed to allocate WebGL render target", "WEBGL_ALLOCATION_FAILED", { label });
998
+ }
872
999
  }
873
- const boundsWidth = this.activeRenderTarget?.width ?? this.gl.drawingBufferWidth;
874
- const boundsHeight = this.activeRenderTarget?.height ?? this.gl.drawingBufferHeight;
875
- if (x + width > boundsWidth || y + height > boundsHeight) {
876
- throw new RenderDeviceError("Float readback rectangle exceeds framebuffer bounds", "READBACK_OUT_OF_BOUNDS", {
877
- x,
878
- y,
879
- width,
880
- height,
881
- boundsWidth,
882
- boundsHeight
883
- });
1000
+ const target = new WebGL2RenderTarget(this.nextId++, descriptor.width, descriptor.height, label, colorTexture, depthTexture, layerFramebuffers[0], parentColorHandle, depthRenderbufferHandle, depthTextureHandle, 1, layerFramebuffers[0], null, gl, {
1001
+ dimension,
1002
+ layers: layerCount > 1 ? layerCount : undefined,
1003
+ colorTextures: colorTextures.length > 1 ? colorTextures : undefined,
1004
+ extraColorHandles: colorHandles.slice(1),
1005
+ layerFramebuffers,
1006
+ layerChild: false
1007
+ });
1008
+ if (layerCount > 1) {
1009
+ const children = layerFramebuffers.map((framebuffer, layer) => new WebGL2RenderTarget(this.nextId++, descriptor.width, descriptor.height, `${label}-layer-${layer}`, colorTexture, depthTexture, framebuffer, colorHandles[0], null, depthTextureHandle, 1, framebuffer, null, gl, { dimension, layers: 1, colorTextures: target.colorTextures, layerChild: true }));
1010
+ // layerTargets shares parent GL resources; children only mark dispose.
1011
+ target.layerTargets = children;
1012
+ for (const child of children) {
1013
+ this.renderTargets.add(child);
1014
+ }
884
1015
  }
885
- const readTarget = this.activeRenderTarget;
886
- if (readTarget) {
887
- this.resolveMultisampleTarget(readTarget);
888
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, readTarget.framebuffer);
1016
+ this.renderTargets.add(target);
1017
+ if (/shadow|(?:^|-)csm(?:-|$)/i.test(label))
1018
+ this.host.counters.shadowRenderTargetsAllocated += 1;
1019
+ for (let attachment = 0; attachment < colorHandles.length; attachment += 1) {
1020
+ this.host.textureRegistry.textures.set(colorTextures[attachment], colorHandles[attachment]);
1021
+ this.host.textureRegistry.textureUploadModes.set(colorTextures[attachment], colorFormats[attachment]);
889
1022
  }
890
- const pixels = new Float32Array(width * height * 4);
891
- this.gl.readPixels(x, y, width, height, this.gl.RGBA, this.gl.FLOAT, pixels);
892
- if (readTarget && readTarget.sampleCount > 1) {
893
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, readTarget.drawFramebuffer);
894
- this.stateCache.invalidate();
1023
+ if (depthTexture && depthTextureHandle) {
1024
+ this.host.textureRegistry.textures.set(depthTexture, depthTextureHandle);
1025
+ this.host.textureRegistry.textureUploadModes.set(depthTexture, "depth-render-target");
895
1026
  }
896
- return pixels;
1027
+ return target;
897
1028
  }
898
- readDepthPixels(x, y, width, height) {
899
- this.assertAlive();
900
- if (![x, y, width, height].every(Number.isInteger) || x < 0 || y < 0 || width <= 0 || height <= 0) {
901
- throw new RenderDeviceError("Depth readback rectangle must be positive and in bounds", "INVALID_READBACK_RECT", { x, y, width, height });
1029
+ setRenderTarget(target) {
1030
+ this.host.lifecycle.assertAlive();
1031
+ if (this.host.activeRenderTarget && this.host.activeRenderTarget !== target) {
1032
+ this.resolveMultisampleTarget(this.host.activeRenderTarget);
902
1033
  }
903
- const target = this.activeRenderTarget;
904
- if (!target?.depthTextureHandle) {
905
- throw new RenderDeviceError("Depth readback requires an active WebGL2 render target with a sampleable depth texture.", "DEPTH_READBACK_UNAVAILABLE", {
906
- renderTarget: target?.label ?? null
907
- });
1034
+ if (target === null) {
1035
+ this.host.activeRenderTarget = null;
1036
+ this.stateCache.bindFramebuffer(this.gl.FRAMEBUFFER, null, () => this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null));
1037
+ this.stateCache.viewport(0, 0, this.host.lifecycle.viewportWidth || this.gl.drawingBufferWidth, this.host.lifecycle.viewportHeight || this.gl.drawingBufferHeight, () => this.gl.viewport(0, 0, this.host.lifecycle.viewportWidth || this.gl.drawingBufferWidth, this.host.lifecycle.viewportHeight || this.gl.drawingBufferHeight));
1038
+ return;
908
1039
  }
909
- if (x + width > target.width || y + height > target.height) {
910
- throw new RenderDeviceError("Depth readback rectangle exceeds framebuffer bounds", "READBACK_OUT_OF_BOUNDS", {
911
- x,
912
- y,
913
- width,
914
- height,
915
- boundsWidth: target.width,
916
- boundsHeight: target.height
1040
+ if (!(target instanceof WebGL2RenderTarget) || !this.renderTargets.has(target) || target.disposed) {
1041
+ throw new RenderDeviceError("Render target is not a live WebGL2 resource owned by this device", "INVALID_RESOURCE", {
1042
+ targetId: target.id
917
1043
  });
918
1044
  }
919
- this.resolveMultisampleTarget(target);
920
- const encoded = this.copyDepthTextureToBytes(target, x, y, width, height);
921
- const pixels = new Float32Array(width * height);
922
- for (let index = 0; index < pixels.length; index += 1) {
923
- const byteIndex = index * 4;
924
- const r = encoded[byteIndex] ?? 255;
925
- const g = encoded[byteIndex + 1] ?? 255;
926
- const b = encoded[byteIndex + 2] ?? 255;
927
- pixels[index] = Math.max(0, Math.min(1, r / 255 + g / 65025 + b / 16581375));
928
- }
929
- return pixels;
930
- }
931
- beginFrame(width, height) {
932
- this.assertAlive();
933
- if (this.frameActive) {
934
- throw new RenderDeviceError("Frame is already active", "FRAME_ALREADY_ACTIVE");
935
- }
936
- if (width <= 0 || height <= 0) {
937
- throw new RenderDeviceError("Frame dimensions must be positive", "INVALID_FRAME_SIZE", { width, height });
938
- }
939
- this.frameActive = true;
940
- this.drawCalls = 0;
941
- this.nativeEnvironmentBindings = 0;
942
- this.nativeShadowMapBindings = 0;
943
- this.activeTextureUnitIndex = -1;
944
- this.textureUnitBindings.clear();
945
- this.stateCache.invalidate();
946
- this.viewportWidth = width;
947
- this.viewportHeight = height;
948
- this.stateCache.bindFramebuffer(this.gl.FRAMEBUFFER, this.activeRenderTarget?.framebuffer ?? null, () => this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.activeRenderTarget?.framebuffer ?? null));
949
- this.stateCache.viewport(0, 0, width, height, () => this.gl.viewport(0, 0, width, height));
950
- this.stateCache.setEnabled(this.gl.DEPTH_TEST, true, () => this.gl.enable(this.gl.DEPTH_TEST));
951
- this.stateCache.depthFunc(this.gl.LEQUAL, () => this.gl.depthFunc(this.gl.LEQUAL));
952
- }
953
- clear(color) {
954
- this.assertFrame();
955
- this.gl.clearColor(color[0], color[1], color[2], color[3]);
956
- this.stateCache.depthMask(true, () => this.gl.depthMask(true));
957
- this.gl.clearDepth(1);
958
- this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
959
- if (this.activeRenderTarget?.sampleCount && this.activeRenderTarget.sampleCount > 1)
960
- this.activeRenderTarget.needsResolve = true;
961
- }
962
- clearRenderTarget(color) {
963
- this.assertFrame();
964
- this.gl.clearColor(color[0], color[1], color[2], color[3]);
965
- this.stateCache.depthMask(true, () => this.gl.depthMask(true));
966
- this.gl.clearDepth(1);
967
- this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
968
- if (this.activeRenderTarget?.sampleCount && this.activeRenderTarget.sampleCount > 1)
969
- this.activeRenderTarget.needsResolve = true;
1045
+ this.host.activeRenderTarget = target;
1046
+ this.stateCache.bindFramebuffer(this.gl.FRAMEBUFFER, target.drawFramebuffer, () => this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, target.drawFramebuffer));
1047
+ this.stateCache.viewport(0, 0, target.width, target.height, () => this.gl.viewport(0, 0, target.width, target.height));
970
1048
  }
971
- draw(command) {
972
- this.assertFrame();
973
- const vertexBuffer = this.requireBuffer(command.vertexBuffer);
974
- this.applyRenderState(command.renderState);
975
- let shader;
976
- if (command.shader) {
977
- const activeShader = this.requireShader(command.shader);
978
- shader = activeShader;
979
- this.stateCache.useProgram(activeShader.handle, () => this.gl.useProgram(activeShader.handle));
980
- if (command.uniforms) {
981
- this.uploadUniforms(activeShader, command.uniforms);
982
- if (this.errorCheckMode === "strict") {
983
- const uniformError = this.readError();
984
- if (uniformError) {
985
- throw new RenderDeviceError(`WebGL2 uniform upload failed for draw ${command.label ?? "unnamed"}: ${uniformError}`, "WEBGL_DRAW_FAILED", {
986
- label: command.label,
987
- stage: "uniforms",
988
- error: uniformError
989
- });
990
- }
991
- }
992
- }
993
- }
994
- if (shader && command.vertexFormat) {
995
- this.bindVertexArrayForCommand(command, shader, vertexBuffer);
996
- if (this.errorCheckMode === "strict") {
997
- const vertexFormatError = this.readError();
998
- if (vertexFormatError) {
999
- throw new RenderDeviceError(`WebGL2 vertex format binding failed for draw ${command.label ?? "unnamed"}: ${vertexFormatError}`, "WEBGL_DRAW_FAILED", {
1000
- label: command.label,
1001
- stage: "vertex-format",
1002
- error: vertexFormatError
1003
- });
1004
- }
1005
- }
1006
- }
1007
- else {
1008
- this.bindNoVertexArray();
1009
- this.stateCache.bindBuffer(this.gl.ARRAY_BUFFER, vertexBuffer.handle, () => this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexBuffer.handle));
1010
- }
1011
- if (command.indexBuffer) {
1012
- const indexBuffer = this.requireBuffer(command.indexBuffer);
1013
- if (!shader || !command.vertexFormat) {
1014
- this.stateCache.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, indexBuffer.handle, () => this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, indexBuffer.handle));
1015
- }
1016
- const type = command.indexType === "uint32" ? this.gl.UNSIGNED_INT : this.gl.UNSIGNED_SHORT;
1017
- const indexByteSize = command.indexType === "uint32" ? 4 : 2;
1018
- const indexOffset = (command.firstIndex ?? 0) * indexByteSize;
1019
- if ((command.instanceCount ?? 1) > 1) {
1020
- this.gl.drawElementsInstanced(this.primitive(command.topology), command.indexCount ?? 0, type, indexOffset, command.instanceCount ?? 1);
1021
- this.nativeInstancedSubmissions += 1;
1022
- }
1023
- else {
1024
- this.gl.drawElements(this.primitive(command.topology), command.indexCount ?? 0, type, indexOffset);
1025
- }
1026
- }
1027
- else {
1028
- if ((command.instanceCount ?? 1) > 1) {
1029
- this.gl.drawArraysInstanced(this.primitive(command.topology), command.firstVertex ?? 0, command.vertexCount, command.instanceCount ?? 1);
1030
- this.nativeInstancedSubmissions += 1;
1031
- }
1032
- else {
1033
- this.gl.drawArrays(this.primitive(command.topology), command.firstVertex ?? 0, command.vertexCount);
1034
- }
1035
- }
1036
- this.drawCalls += 1;
1037
- if (this.activeRenderTarget?.sampleCount && this.activeRenderTarget.sampleCount > 1)
1038
- this.activeRenderTarget.needsResolve = true;
1039
- if (this.errorCheckMode === "strict") {
1040
- const drawError = this.readError();
1041
- if (drawError) {
1042
- throw new RenderDeviceError(`WebGL2 draw failed for ${command.label ?? "unnamed"}: ${drawError}`, "WEBGL_DRAW_FAILED", {
1043
- label: command.label,
1044
- stage: "draw",
1045
- error: drawError
1046
- });
1047
- }
1048
- }
1049
- }
1050
- endFrame() {
1051
- this.assertFrame();
1052
- this.frameActive = false;
1053
- this.lastError = this.readError();
1049
+ resolveMultisampleTarget(target) {
1050
+ if (target.sampleCount <= 1 || !target.needsResolve)
1051
+ return;
1052
+ const previousFramebuffer = this.gl.getParameter(this.gl.FRAMEBUFFER_BINDING);
1053
+ this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER, target.drawFramebuffer);
1054
+ this.gl.bindFramebuffer(this.gl.DRAW_FRAMEBUFFER, target.framebuffer);
1055
+ let mask = this.gl.COLOR_BUFFER_BIT;
1056
+ if (target.depthTextureHandle)
1057
+ mask |= this.gl.DEPTH_BUFFER_BIT;
1058
+ this.gl.blitFramebuffer(0, 0, target.width, target.height, 0, 0, target.width, target.height, mask, this.gl.NEAREST);
1059
+ this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, previousFramebuffer);
1060
+ target.needsResolve = false;
1061
+ this.stateCache.invalidate();
1054
1062
  }
1055
1063
  captureState() {
1056
1064
  const viewport = this.gl.getParameter(this.gl.VIEWPORT);
1057
1065
  return new Map([
1058
1066
  ["backend", this.kind],
1059
- ["disposed", this.disposed],
1060
- ["contextLost", this.contextLost],
1061
- ["frameActive", this.frameActive],
1067
+ ["disposed", this.host.disposed],
1068
+ ["contextLost", this.host.contextLost],
1069
+ ["frameActive", this.host.lifecycle.frameActive],
1062
1070
  ["depthTest", this.gl.isEnabled(this.gl.DEPTH_TEST)],
1063
1071
  ["blend", this.gl.isEnabled(this.gl.BLEND)],
1064
1072
  ["cullFace", this.gl.isEnabled(this.gl.CULL_FACE)],
1065
1073
  ["program", this.gl.getParameter(this.gl.CURRENT_PROGRAM) ? "bound" : null],
1066
1074
  ["arrayBuffer", this.gl.getParameter(this.gl.ARRAY_BUFFER_BINDING) ? "bound" : null],
1067
1075
  ["elementArrayBuffer", this.gl.getParameter(this.gl.ELEMENT_ARRAY_BUFFER_BINDING) ? "bound" : null],
1068
- ["viewportWidth", this.viewportWidth],
1069
- ["viewportHeight", this.viewportHeight],
1076
+ ["viewportWidth", this.host.lifecycle.viewportWidth],
1077
+ ["viewportHeight", this.host.lifecycle.viewportHeight],
1070
1078
  ["actualViewportWidth", viewport[2] ?? 0],
1071
1079
  ["actualViewportHeight", viewport[3] ?? 0],
1072
- ["renderTarget", this.activeRenderTarget?.label ?? null],
1073
- ["drawCalls", this.drawCalls],
1074
- ["nativeTemporalPasses", this.nativeTemporalPasses],
1075
- ["nativeTemporalBindings", this.nativeTemporalBindings],
1076
- ["shaderProgramCreates", this.shaderProgramCreateCount],
1077
- ["uniformLocationLookups", this.uniformLocationLookupCount],
1078
- ["bufferUpdates", this.bufferUpdateCount],
1079
- ["textureBinds", this.textureBindCount],
1080
- ["samplerParameterUploads", this.samplerParameterUploadCount],
1081
- ["vertexArrayCreates", this.vertexArrayCreateCount],
1082
- ["samplerObjects", this.samplerObjectCache.size],
1083
- ["samplerAnisotropyUploads", this.samplerAnisotropyUploadCount],
1080
+ ["renderTarget", this.host.activeRenderTarget?.label ?? null],
1081
+ ["drawCalls", this.host.counters.drawCalls],
1082
+ ["nativeTemporalPasses", this.host.counters.nativeTemporalPasses],
1083
+ ["nativeTemporalBindings", this.host.counters.nativeTemporalBindings],
1084
+ ["shaderProgramCreates", this.host.counters.shaderProgramCreateCount],
1085
+ ["uniformLocationLookups", this.host.counters.uniformLocationLookupCount],
1086
+ ["bufferUpdates", this.host.counters.bufferUpdateCount],
1087
+ ["textureBinds", this.host.counters.textureBindCount],
1088
+ ["samplerParameterUploads", this.host.counters.samplerParameterUploadCount],
1089
+ ["vertexArrayCreates", this.host.counters.vertexArrayCreateCount],
1090
+ ["samplerObjects", this.host.samplers.samplerObjectCache.size],
1091
+ ["samplerAnisotropyUploads", this.host.counters.samplerAnisotropyUploadCount],
1084
1092
  ["maxTextureAnisotropy", this.maxTextureAnisotropy],
1085
- ["nativeEnvironmentBindings", this.nativeEnvironmentBindings],
1086
- ["nativeShadowMapBindings", this.nativeShadowMapBindings],
1087
- ["nativeInstancedSubmissions", this.nativeInstancedSubmissions],
1093
+ ["nativeEnvironmentBindings", this.host.counters.nativeEnvironmentBindings],
1094
+ ["nativeShadowMapBindings", this.host.counters.nativeShadowMapBindings],
1095
+ ["nativeInstancedSubmissions", this.host.counters.nativeInstancedSubmissions],
1088
1096
  ["stateCacheIssued", this.stateCache.stats().issued],
1089
1097
  ["stateCacheSkipped", this.stateCache.stats().skipped]
1090
1098
  ]);
1091
1099
  }
1092
1100
  getDiagnostics() {
1093
- this.releaseDisposedTextureHandles();
1101
+ this.host.textureRegistry.releaseDisposedTextureHandles();
1094
1102
  const liveRenderTargets = [...this.renderTargets].filter((target) => !target.disposed);
1095
1103
  const liveTextures = new Set([
1096
1104
  ...liveRenderTargets.map((target) => target.colorTexture),
1097
- ...[...this.textures.keys()].filter((texture) => !texture.disposed)
1105
+ ...[...this.host.textureRegistry.textures.keys()].filter((texture) => !texture.disposed)
1098
1106
  ]);
1099
1107
  const liveTextureList = [...liveTextures];
1100
1108
  const compressedTextures = liveTextureList.filter((texture) => isCompressedTextureFormat(texture.format));
1101
- const fallbackTextures = liveTextureList.filter((texture) => this.textureUploadModes.get(texture) === "fallback");
1109
+ const fallbackTextures = liveTextureList.filter((texture) => this.host.textureRegistry.textureUploadModes.get(texture) === "fallback");
1102
1110
  const stateCacheStats = this.stateCache.stats();
1103
1111
  const bufferBytes = [...this.buffers].filter((buffer) => !buffer.disposed).reduce((total, buffer) => total + buffer.byteLength, 0);
1104
1112
  const textureBytes = liveTextureList.reduce((total, texture) => total + texture.byteLength, 0);
1105
- const gpuTargetEntries = this.describeGpuTargetInventory(liveRenderTargets);
1113
+ const gpuTargetEntries = this.host.post.describeGpuTargetInventory(liveRenderTargets);
1106
1114
  return {
1107
- drawCalls: this.drawCalls,
1115
+ drawCalls: this.host.counters.drawCalls,
1108
1116
  buffers: [...this.buffers].filter((buffer) => !buffer.disposed).length,
1109
1117
  shaders: [...this.shaders].filter((shader) => !shader.disposed).length,
1110
1118
  renderTargets: liveRenderTargets.length,
@@ -1117,14 +1125,14 @@ export class WebGL2Device {
1117
1125
  compressedTextureBytes: compressedTextures.reduce((total, texture) => total + texture.byteLength, 0),
1118
1126
  textureFallbacks: fallbackTextures.length,
1119
1127
  textureFallbackBytes: fallbackTextures.reduce((total, texture) => total + texture.fallbackByteLength, 0),
1120
- nativeEnvironmentBindings: this.nativeEnvironmentBindings,
1121
- nativeShadowMapBindings: this.nativeShadowMapBindings,
1122
- shadowRenderTargetsAllocated: this.shadowRenderTargetsAllocated,
1123
- nativeInstancedSubmissions: this.nativeInstancedSubmissions,
1124
- bloom: this.lastBloomDiagnostics,
1125
- nativeTemporalPasses: this.nativeTemporalPasses,
1126
- nativeTemporalBindings: this.nativeTemporalBindings,
1127
- samplerAnisotropyUploads: this.samplerAnisotropyUploadCount,
1128
+ nativeEnvironmentBindings: this.host.counters.nativeEnvironmentBindings,
1129
+ nativeShadowMapBindings: this.host.counters.nativeShadowMapBindings,
1130
+ shadowRenderTargetsAllocated: this.host.counters.shadowRenderTargetsAllocated,
1131
+ nativeInstancedSubmissions: this.host.counters.nativeInstancedSubmissions,
1132
+ bloom: this.host.post.lastBloomDiagnostics,
1133
+ nativeTemporalPasses: this.host.counters.nativeTemporalPasses,
1134
+ nativeTemporalBindings: this.host.counters.nativeTemporalBindings,
1135
+ samplerAnisotropyUploads: this.host.counters.samplerAnisotropyUploadCount,
1128
1136
  maxTextureAnisotropy: this.maxTextureAnisotropy,
1129
1137
  stateCacheIssued: stateCacheStats.issued,
1130
1138
  stateCacheSkipped: stateCacheStats.skipped,
@@ -1133,23 +1141,25 @@ export class WebGL2Device {
1133
1141
  stateCacheBufferBinds: stateCacheStats.byOperation.bindBuffer?.issued ?? 0,
1134
1142
  stateCacheVertexArrayBinds: stateCacheStats.byOperation.bindVertexArray?.issued ?? 0,
1135
1143
  stateCacheSamplerBinds: stateCacheStats.byOperation.bindSampler?.issued ?? 0,
1136
- disposedBuffers: [...this.buffers].filter((buffer) => buffer.disposed).length,
1144
+ disposedBuffers: this.disposedBufferCount + [...this.buffers].filter((buffer) => buffer.disposed).length,
1137
1145
  disposedShaders: [...this.shaders].filter((shader) => shader.disposed).length,
1138
1146
  disposedRenderTargets: [...this.renderTargets].filter((target) => target.disposed).length,
1139
- disposedTextures: [...this.renderTargets].filter((target) => target.colorTexture.disposed).length + this.releasedTextureHandles,
1147
+ disposedTextures: [...this.renderTargets].filter((target) => target.colorTexture.disposed).length + this.host.counters.releasedTextureHandles,
1140
1148
  ...spreadGpuTargetInventory(gpuTargetEntries),
1141
- lastError: this.lastError,
1142
- contextLost: this.contextLost
1149
+ programCompileCount: this.host.counters.programCompiles,
1150
+ readPixelsCalls: this.host.counters.readbacks,
1151
+ lastError: this.host.lifecycle.lastError,
1152
+ contextLost: this.host.contextLost
1143
1153
  };
1144
1154
  }
1145
1155
  dispose() {
1146
- if (this.canvas && "removeEventListener" in this.canvas) {
1147
- this.deviceLostListeners.clear();
1148
- this.deviceRestoredListeners.clear();
1149
- if (this.contextLostListener)
1150
- this.canvas.removeEventListener("webglcontextlost", this.contextLostListener);
1151
- if (this.contextRestoredListener)
1152
- this.canvas.removeEventListener("webglcontextrestored", this.contextRestoredListener);
1156
+ if (this.host.lifecycle.canvas && "removeEventListener" in this.host.lifecycle.canvas) {
1157
+ this.host.lifecycle.deviceLostListeners.clear();
1158
+ this.host.lifecycle.deviceRestoredListeners.clear();
1159
+ if (this.host.lifecycle.contextLostListener)
1160
+ this.host.lifecycle.canvas.removeEventListener("webglcontextlost", this.host.lifecycle.contextLostListener);
1161
+ if (this.host.lifecycle.contextRestoredListener)
1162
+ this.host.lifecycle.canvas.removeEventListener("webglcontextrestored", this.host.lifecycle.contextRestoredListener);
1153
1163
  }
1154
1164
  for (const buffer of this.buffers) {
1155
1165
  buffer.dispose();
@@ -1160,2867 +1170,160 @@ export class WebGL2Device {
1160
1170
  for (const target of this.renderTargets) {
1161
1171
  target.dispose();
1162
1172
  }
1163
- for (const entry of this.vertexArrayCache.values()) {
1173
+ for (const entry of this.host.drawBinder.vertexArrayCache.values()) {
1164
1174
  this.gl.deleteVertexArray(entry.handle);
1165
1175
  }
1166
- this.vertexArrayCache.clear();
1167
- for (const sampler of this.samplerObjectCache.values()) {
1176
+ this.host.drawBinder.vertexArrayCache.clear();
1177
+ for (const sampler of this.host.samplers.samplerObjectCache.values()) {
1168
1178
  this.gl.deleteSampler(sampler);
1169
1179
  }
1170
- this.samplerObjectCache.clear();
1171
- for (const texture of this.textures.values()) {
1180
+ this.host.samplers.samplerObjectCache.clear();
1181
+ for (const texture of this.host.textureRegistry.textures.values()) {
1172
1182
  this.gl.deleteTexture(texture);
1173
1183
  }
1174
- this.textureUploadModes.clear();
1175
- if (this.fallbackTexture) {
1176
- this.gl.deleteTexture(this.fallbackTexture);
1177
- this.fallbackTexture = null;
1178
- }
1179
- if (this.fallbackCubeTexture) {
1180
- this.gl.deleteTexture(this.fallbackCubeTexture);
1181
- this.fallbackCubeTexture = null;
1182
- }
1183
- if (this.presentationProgram) {
1184
- this.gl.deleteProgram(this.presentationProgram);
1185
- this.presentationProgram = null;
1186
- }
1187
- if (this.ldrPostprocessProgram) {
1188
- this.gl.deleteProgram(this.ldrPostprocessProgram);
1189
- this.ldrPostprocessProgram = null;
1190
- }
1191
- if (this.bloomBrightExtractProgram) {
1192
- this.gl.deleteProgram(this.bloomBrightExtractProgram);
1193
- this.bloomBrightExtractProgram = null;
1194
- }
1195
- if (this.bloomBlurProgram) {
1196
- this.gl.deleteProgram(this.bloomBlurProgram);
1197
- this.bloomBlurProgram = null;
1198
- }
1199
- if (this.bloomCompositeProgram) {
1200
- this.gl.deleteProgram(this.bloomCompositeProgram);
1201
- this.bloomCompositeProgram = null;
1202
- }
1203
- if (this.bloomDownsampleProgram) {
1204
- this.gl.deleteProgram(this.bloomDownsampleProgram);
1205
- this.bloomDownsampleProgram = null;
1206
- }
1207
- if (this.bloomAccumulateProgram) {
1208
- this.gl.deleteProgram(this.bloomAccumulateProgram);
1209
- this.bloomAccumulateProgram = null;
1210
- }
1211
- if (this.outlineProgram) {
1212
- this.gl.deleteProgram(this.outlineProgram);
1213
- this.outlineProgram = null;
1214
- }
1215
- if (this.ssaoProgram) {
1216
- this.gl.deleteProgram(this.ssaoProgram);
1217
- this.ssaoProgram = null;
1218
- }
1219
- if (this.ssrProgram) {
1220
- this.gl.deleteProgram(this.ssrProgram);
1221
- this.ssrProgram = null;
1222
- }
1223
- if (this.depthOfFieldProgram) {
1224
- this.gl.deleteProgram(this.depthOfFieldProgram);
1225
- this.depthOfFieldProgram = null;
1226
- }
1227
- if (this.motionBlurProgram) {
1228
- this.gl.deleteProgram(this.motionBlurProgram);
1229
- this.motionBlurProgram = null;
1230
- }
1231
- if (this.motionBlurVelocityTexture) {
1232
- this.gl.deleteTexture(this.motionBlurVelocityTexture);
1233
- this.motionBlurVelocityTexture = null;
1234
- this.motionBlurVelocitySize = null;
1235
- }
1236
- if (this.taaProgram) {
1237
- this.gl.deleteProgram(this.taaProgram);
1238
- this.taaProgram = null;
1239
- }
1240
- if (this.taaPresentationProgram) {
1241
- this.gl.deleteProgram(this.taaPresentationProgram);
1242
- this.taaPresentationProgram = null;
1243
- }
1244
- if (this.taaHistoryTexture) {
1245
- this.gl.deleteTexture(this.taaHistoryTexture);
1246
- this.taaHistoryTexture = null;
1247
- this.taaHistorySize = null;
1248
- }
1249
- this.disposeBloomPingPongResources();
1250
- this.disposeBloomPyramidResources();
1251
- if (this.bloomBrightLutTexture) {
1252
- this.gl.deleteTexture(this.bloomBrightLutTexture);
1253
- this.bloomBrightLutTexture = null;
1254
- this.bloomBrightLutThreshold = null;
1255
- }
1256
- if (this.bloomCompositeLutTexture) {
1257
- this.gl.deleteTexture(this.bloomCompositeLutTexture);
1258
- this.bloomCompositeLutTexture = null;
1259
- this.bloomCompositeLutIntensity = null;
1260
- this.bloomCompositeLutShoulder = null;
1261
- }
1262
- if (this.outlineBlendLutTexture) {
1263
- this.gl.deleteTexture(this.outlineBlendLutTexture);
1264
- this.outlineBlendLutTexture = null;
1265
- this.outlineBlendLutKey = null;
1266
- }
1267
- if (this.presentationVertexArray) {
1268
- this.gl.deleteVertexArray(this.presentationVertexArray);
1269
- this.presentationVertexArray = null;
1270
- }
1271
- if (this.depthReadbackProgram) {
1272
- this.gl.deleteProgram(this.depthReadbackProgram);
1273
- this.depthReadbackProgram = null;
1274
- }
1275
- this.textures.clear();
1276
- this.disposed = true;
1277
- }
1278
- copyDepthTextureToBytes(source, x, y, width, height) {
1279
- const colorHandle = this.gl.createTexture();
1280
- const framebuffer = this.gl.createFramebuffer();
1281
- if (!colorHandle || !framebuffer) {
1282
- if (colorHandle)
1283
- this.gl.deleteTexture(colorHandle);
1284
- if (framebuffer)
1285
- this.gl.deleteFramebuffer(framebuffer);
1286
- throw new RenderDeviceError("Failed to allocate WebGL2 depth readback target", "WEBGL_ALLOCATION_FAILED", {
1287
- renderTarget: source.label
1288
- });
1289
- }
1290
- const previousFramebuffer = this.gl.getParameter(this.gl.FRAMEBUFFER_BINDING);
1291
- const previousProgram = this.gl.getParameter(this.gl.CURRENT_PROGRAM);
1292
- const textureUnit0 = this.captureTextureUnit0();
1293
- const viewport = this.gl.getParameter(this.gl.VIEWPORT);
1294
- const depthTestEnabled = this.gl.isEnabled(this.gl.DEPTH_TEST);
1295
- const depthMask = this.gl.getParameter(this.gl.DEPTH_WRITEMASK);
1296
- const cullFaceEnabled = this.gl.isEnabled(this.gl.CULL_FACE);
1297
- const blendEnabled = this.gl.isEnabled(this.gl.BLEND);
1298
- const pixels = new Uint8Array(width * height * 4);
1299
- try {
1300
- this.gl.activeTexture(this.gl.TEXTURE0);
1301
- this.gl.bindTexture(this.gl.TEXTURE_2D, colorHandle);
1302
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
1303
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
1304
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
1305
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
1306
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA8, width, height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, null);
1307
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
1308
- this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, colorHandle, 0);
1309
- const status = this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);
1310
- if (status !== this.gl.FRAMEBUFFER_COMPLETE) {
1311
- throw new RenderDeviceError("WebGL2 depth readback framebuffer status is invalid", "FRAMEBUFFER_INVALID", {
1312
- renderTarget: source.label,
1313
- status
1314
- });
1315
- }
1316
- this.gl.viewport(0, 0, width, height);
1317
- this.gl.disable(this.gl.DEPTH_TEST);
1318
- this.gl.disable(this.gl.CULL_FACE);
1319
- this.gl.disable(this.gl.BLEND);
1320
- this.gl.depthMask(false);
1321
- this.gl.useProgram(this.ensureDepthReadbackProgram());
1322
- this.gl.activeTexture(this.gl.TEXTURE0);
1323
- this.gl.bindTexture(this.gl.TEXTURE_2D, source.depthTextureHandle);
1324
- this.gl.bindSampler(0, null);
1325
- this.gl.uniform1i(this.gl.getUniformLocation(this.ensureDepthReadbackProgram(), "u_depth"), 0);
1326
- this.gl.uniform4f(this.gl.getUniformLocation(this.ensureDepthReadbackProgram(), "u_sourceRect"), x / source.width, y / source.height, width / source.width, height / source.height);
1327
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1328
- this.gl.readPixels(0, 0, width, height, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pixels);
1329
- const error = this.readError();
1330
- if (error) {
1331
- throw new RenderDeviceError("WebGL2 depth texture readback failed", "WEBGL_DEPTH_READBACK_FAILED", {
1332
- renderTarget: source.label,
1333
- error
1334
- });
1335
- }
1336
- return pixels;
1337
- }
1338
- finally {
1339
- this.restoreTextureUnit0(textureUnit0);
1340
- this.gl.useProgram(previousProgram);
1341
- if (depthTestEnabled)
1342
- this.gl.enable(this.gl.DEPTH_TEST);
1343
- else
1344
- this.gl.disable(this.gl.DEPTH_TEST);
1345
- if (cullFaceEnabled)
1346
- this.gl.enable(this.gl.CULL_FACE);
1347
- else
1348
- this.gl.disable(this.gl.CULL_FACE);
1349
- if (blendEnabled)
1350
- this.gl.enable(this.gl.BLEND);
1351
- else
1352
- this.gl.disable(this.gl.BLEND);
1353
- this.gl.depthMask(depthMask);
1354
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, previousFramebuffer);
1355
- this.gl.viewport(viewport[0] ?? 0, viewport[1] ?? 0, viewport[2] ?? this.viewportWidth, viewport[3] ?? this.viewportHeight);
1356
- this.gl.deleteTexture(colorHandle);
1357
- this.gl.deleteFramebuffer(framebuffer);
1358
- this.stateCache.invalidate();
1359
- }
1360
- }
1361
- drawRenderTargetToBackbuffer(source, outputWidth, outputHeight) {
1362
- const program = this.ensurePresentationProgram();
1363
- const vertexArray = this.ensurePresentationVertexArray();
1364
- const previousState = this.prepareFullscreenPresentation(null, outputWidth, outputHeight);
1365
- this.gl.useProgram(program);
1366
- this.gl.bindVertexArray(vertexArray);
1367
- this.gl.activeTexture(this.gl.TEXTURE0);
1368
- this.gl.bindTexture(this.gl.TEXTURE_2D, source.colorHandle);
1369
- this.gl.bindSampler(0, null);
1370
- try {
1371
- const uniformLocation = this.gl.getUniformLocation(program, "u_source");
1372
- this.gl.uniform1i(uniformLocation, 0);
1373
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1374
- this.gl.flush();
1375
- }
1376
- finally {
1377
- this.restoreFullscreenPresentationState(previousState, outputWidth, outputHeight);
1378
- }
1379
- }
1380
- ensureBloomPingPongResources(width, height, hdr = false) {
1381
- const current = this.bloomPingPongResources;
1382
- if (current && current.width === width && current.height === height && current.hdr === hdr) {
1383
- return current;
1384
- }
1385
- this.disposeBloomPingPongResources();
1386
- this.disposeBloomPyramidResources();
1387
- const textureUnit0 = this.captureTextureUnit0();
1388
- const previousFramebuffer = this.gl.getParameter(this.gl.FRAMEBUFFER_BINDING);
1389
- const textures = [];
1390
- const framebuffers = [];
1391
- try {
1392
- for (let index = 0; index < 2; index += 1) {
1393
- const texture = this.gl.createTexture();
1394
- const framebuffer = this.gl.createFramebuffer();
1395
- if (!texture || !framebuffer) {
1396
- if (texture)
1397
- this.gl.deleteTexture(texture);
1398
- if (framebuffer)
1399
- this.gl.deleteFramebuffer(framebuffer);
1400
- throw new RenderDeviceError("Failed to allocate WebGL2 bloom ping-pong resources", "WEBGL_ALLOCATION_FAILED", {
1401
- width,
1402
- height,
1403
- index
1404
- });
1405
- }
1406
- textures.push(texture);
1407
- framebuffers.push(framebuffer);
1408
- this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
1409
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
1410
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
1411
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
1412
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
1413
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, hdr ? this.gl.RGBA16F : this.gl.RGBA8, width, height, 0, this.gl.RGBA, hdr ? this.gl.HALF_FLOAT : this.gl.UNSIGNED_BYTE, null);
1414
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
1415
- this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, texture, 0);
1416
- const status = this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);
1417
- if (status !== this.gl.FRAMEBUFFER_COMPLETE) {
1418
- throw new RenderDeviceError("WebGL2 bloom ping-pong framebuffer status is invalid", "FRAMEBUFFER_INVALID", {
1419
- width,
1420
- height,
1421
- index,
1422
- status
1423
- });
1424
- }
1425
- }
1426
- const resources = {
1427
- width,
1428
- height,
1429
- hdr,
1430
- textures: [textures[0], textures[1]],
1431
- framebuffers: [framebuffers[0], framebuffers[1]]
1432
- };
1433
- this.bloomPingPongResources = resources;
1434
- return resources;
1435
- }
1436
- catch (error) {
1437
- for (const texture of textures)
1438
- this.gl.deleteTexture(texture);
1439
- for (const framebuffer of framebuffers)
1440
- this.gl.deleteFramebuffer(framebuffer);
1441
- throw error;
1442
- }
1443
- finally {
1444
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, previousFramebuffer);
1445
- this.restoreTextureUnit0(textureUnit0);
1446
- this.stateCache.invalidate();
1447
- }
1448
- }
1449
- ensureBloomLutTextures(options) {
1450
- const updateBright = this.bloomBrightLutThreshold !== options.threshold;
1451
- const updateComposite = this.bloomCompositeLutIntensity !== options.intensity ||
1452
- this.bloomCompositeLutShoulder !== options.shoulder;
1453
- if (this.bloomBrightLutTexture && this.bloomCompositeLutTexture && !updateBright && !updateComposite) {
1454
- return;
1455
- }
1456
- const textureUnit0 = this.captureTextureUnit0();
1457
- try {
1458
- if (!this.bloomBrightLutTexture) {
1459
- this.bloomBrightLutTexture = this.createNativeBloomDataTexture();
1460
- }
1461
- if (updateBright) {
1462
- const pixels = createBloomBrightThresholdLut(options.threshold);
1463
- this.gl.bindTexture(this.gl.TEXTURE_2D, this.bloomBrightLutTexture);
1464
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA8, BLOOM_BRIGHT_LUT_WIDTH, BLOOM_BRIGHT_LUT_HEIGHT, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pixels);
1465
- this.bloomBrightLutThreshold = options.threshold;
1466
- }
1467
- if (!this.bloomCompositeLutTexture) {
1468
- this.bloomCompositeLutTexture = this.createNativeBloomDataTexture();
1469
- }
1470
- if (updateComposite) {
1471
- const pixels = createBloomCompositeLut(options.intensity, { shoulder: options.shoulder });
1472
- this.gl.bindTexture(this.gl.TEXTURE_2D, this.bloomCompositeLutTexture);
1473
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA8, BLOOM_COMPOSITE_LUT_SIZE, BLOOM_COMPOSITE_LUT_SIZE, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pixels);
1474
- this.bloomCompositeLutIntensity = options.intensity;
1475
- this.bloomCompositeLutShoulder = options.shoulder;
1476
- }
1477
- }
1478
- finally {
1479
- this.restoreTextureUnit0(textureUnit0);
1480
- this.stateCache.invalidate();
1481
- }
1482
- }
1483
- createNativeBloomDataTexture() {
1484
- const texture = this.gl.createTexture();
1485
- if (!texture) {
1486
- throw new RenderDeviceError("Failed to allocate WebGL2 bloom lookup texture", "WEBGL_ALLOCATION_FAILED");
1487
- }
1488
- this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
1489
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
1490
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
1491
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
1492
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
1493
- return texture;
1494
- }
1495
- ensureOutlineBlendLutTexture(options) {
1496
- const combinedAlpha = options.opacity * (options.color[3] / 255);
1497
- const key = `${options.color.join(",")}|${combinedAlpha}`;
1498
- if (this.outlineBlendLutTexture && this.outlineBlendLutKey === key)
1499
- return;
1500
- const textureUnit0 = this.captureTextureUnit0();
1501
- try {
1502
- if (!this.outlineBlendLutTexture) {
1503
- this.outlineBlendLutTexture = this.createNativeBloomDataTexture();
1504
- }
1505
- this.gl.bindTexture(this.gl.TEXTURE_2D, this.outlineBlendLutTexture);
1506
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA8, OUTLINE_BLEND_LUT_WIDTH, 1, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, createOutlineBlendLut(options.color, combinedAlpha));
1507
- this.outlineBlendLutKey = key;
1508
- }
1509
- finally {
1510
- this.restoreTextureUnit0(textureUnit0);
1511
- this.stateCache.invalidate();
1512
- }
1513
- }
1514
- ensureMotionBlurVelocityTexture(width, height, velocity) {
1515
- const textureUnit0 = this.captureTextureUnit0();
1516
- try {
1517
- if (!this.motionBlurVelocityTexture) {
1518
- this.motionBlurVelocityTexture = this.createNativeBloomDataTexture();
1519
- }
1520
- this.motionBlurVelocitySize = { width, height };
1521
- this.gl.bindTexture(this.gl.TEXTURE_2D, this.motionBlurVelocityTexture);
1522
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RG32F, width, height, 0, this.gl.RG, this.gl.FLOAT, velocity);
1523
- }
1524
- finally {
1525
- this.restoreTextureUnit0(textureUnit0);
1526
- this.stateCache.invalidate();
1527
- }
1528
- }
1529
- ensureTaaHistoryTexture(width, height, history) {
1530
- const textureUnit0 = this.captureTextureUnit0();
1531
- try {
1532
- if (!this.taaHistoryTexture) {
1533
- this.taaHistoryTexture = this.createNativeBloomDataTexture();
1534
- }
1535
- this.taaHistorySize = { width, height };
1536
- this.gl.bindTexture(this.gl.TEXTURE_2D, this.taaHistoryTexture);
1537
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA8, width, height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, history);
1538
- }
1539
- finally {
1540
- this.restoreTextureUnit0(textureUnit0);
1541
- this.stateCache.invalidate();
1542
- }
1543
- }
1544
- drawNativeLdrStage(sourceTexture, framebuffer, width, height, program, vertexArray, tonePass, colorPass, fxaaPass, toneMappingDefaults) {
1545
- const toneOptions = { ...(toneMappingDefaults ?? {}), ...(tonePass?.options ?? {}) };
1546
- const colorOptions = colorPass?.options ?? {};
1547
- const fxaaOptions = fxaaPass?.options ?? {};
1548
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
1549
- this.gl.viewport(0, 0, width, height);
1550
- this.gl.useProgram(program);
1551
- this.gl.bindVertexArray(vertexArray);
1552
- this.bindFullscreenTexture(0, sourceTexture);
1553
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_source"), 0);
1554
- this.gl.uniform2f(this.gl.getUniformLocation(program, "u_texelSize"), 1 / width, 1 / height);
1555
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_hasToneMapping"), tonePass ? 1 : 0);
1556
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_toneOperator"), toneMappingOperatorId(stringOption(toneOptions, "operator", "reinhard")));
1557
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_inputColorSpace"), colorSpaceId(stringOption(toneOptions, "inputColorSpace", "linear")));
1558
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_outputColorSpace"), colorSpaceId(stringOption(toneOptions, "outputColorSpace", "linear")));
1559
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_exposure"), numberOption(toneOptions, "exposure", 1));
1560
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_whitePoint"), Math.max(0.0001, numberOption(toneOptions, "whitePoint", 1)));
1561
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_gamma"), Math.max(0.0001, numberOption(toneOptions, "gamma", 2.2)));
1562
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_hasColorGrade"), colorPass ? 1 : 0);
1563
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_contrast"), numberOption(colorOptions, "contrast", 1));
1564
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_temperature"), numberOption(colorOptions, "temperature", 0));
1565
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_tint"), numberOption(colorOptions, "tint", 0));
1566
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_saturation"), numberOption(colorOptions, "saturation", 1));
1567
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_vibrance"), numberOption(colorOptions, "vibrance", 0));
1568
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_vignette"), numberOption(colorOptions, "vignette", 0));
1569
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_sharpening"), numberOption(colorOptions, "sharpening", 0));
1570
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_hasFxaa"), fxaaPass ? 1 : 0);
1571
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_edgeThreshold"), numberOption(fxaaOptions, "edgeThreshold", 0.125));
1572
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_subpixelBlend"), numberOption(fxaaOptions, "subpixelBlend", 0.75));
1573
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1574
- }
1575
- executeNativeBloomPasses(sourceTexture, resources, options, vertexArray, hdr) {
1576
- const brightLut = this.bloomBrightLutTexture;
1577
- const compositeLut = this.bloomCompositeLutTexture;
1578
- if (!hdr && (!brightLut || !compositeLut)) {
1579
- throw new RenderDeviceError("WebGL2 bloom lookup textures were not initialized", "WEBGL_ALLOCATION_FAILED");
1580
- }
1581
- const [textureA, textureB] = resources.textures;
1582
- const [framebufferA, framebufferB] = resources.framebuffers;
1583
- const brightProgram = this.ensureBloomBrightExtractProgram();
1584
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebufferA);
1585
- this.gl.viewport(0, 0, resources.width, resources.height);
1586
- this.gl.useProgram(brightProgram);
1587
- this.gl.bindVertexArray(vertexArray);
1588
- this.bindFullscreenTexture(0, sourceTexture);
1589
- if (brightLut)
1590
- this.bindFullscreenTexture(1, brightLut);
1591
- this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_source"), 0);
1592
- this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_brightLut"), 1);
1593
- this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_hdr"), hdr ? 1 : 0);
1594
- this.gl.uniform1f(this.gl.getUniformLocation(brightProgram, "u_threshold"), options.threshold);
1595
- this.gl.uniform1f(this.gl.getUniformLocation(brightProgram, "u_softKnee"), options.softKnee);
1596
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1597
- const blurProgram = this.ensureBloomBlurProgram();
1598
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebufferB);
1599
- this.gl.useProgram(blurProgram);
1600
- this.bindFullscreenTexture(0, textureA);
1601
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_source"), 0);
1602
- this.gl.uniform2i(this.gl.getUniformLocation(blurProgram, "u_size"), resources.width, resources.height);
1603
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_radius"), options.radius);
1604
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_horizontal"), 1);
1605
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_hdr"), hdr ? 1 : 0);
1606
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1607
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebufferA);
1608
- this.bindFullscreenTexture(0, textureB);
1609
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_horizontal"), 0);
1610
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1611
- const compositeProgram = this.ensureBloomCompositeProgram();
1612
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebufferB);
1613
- this.gl.useProgram(compositeProgram);
1614
- this.bindFullscreenTexture(0, sourceTexture);
1615
- this.bindFullscreenTexture(1, textureA);
1616
- if (compositeLut)
1617
- this.bindFullscreenTexture(2, compositeLut);
1618
- this.gl.uniform1i(this.gl.getUniformLocation(compositeProgram, "u_source"), 0);
1619
- this.gl.uniform1i(this.gl.getUniformLocation(compositeProgram, "u_blurred"), 1);
1620
- this.gl.uniform1i(this.gl.getUniformLocation(compositeProgram, "u_compositeLut"), 2);
1621
- this.gl.uniform1i(this.gl.getUniformLocation(compositeProgram, "u_hdr"), hdr ? 1 : 0);
1622
- this.gl.uniform1f(this.gl.getUniformLocation(compositeProgram, "u_intensity"), options.intensity);
1623
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1624
- return textureB;
1625
- }
1626
- /**
1627
- * Balanced/cinematic bloom: bright-extract once, then a half-resolution mip
1628
- * chain where every level is downsampled, separably blurred, and accumulated
1629
- * with its energy-preserving weight. Returns a full-resolution bloom texture
1630
- * holding the weighted sum, ready for the existing composite program.
1631
- */
1632
- executeNativeBloomPyramidPasses(sourceTexture, sourceWidth, sourceHeight, resources, fullResStaging, options, vertexArray, hdr) {
1633
- const plan = resources.plan;
1634
- const mipCount = plan.mips.length;
1635
- const blurRadii = resolveBloomPyramidBlurRadii(plan, options.radius);
1636
- const downsampleProgram = this.ensureBloomDownsampleProgram();
1637
- const brightProgram = this.ensureBloomBrightExtractProgram();
1638
- const blurProgram = this.ensureBloomBlurProgram();
1639
- const accumulateProgram = this.ensureBloomAccumulateProgram();
1640
- const brightLut = this.bloomBrightLutTexture;
1641
- const mipTexture = (level, slot) => resources.textures[level * 2 + slot];
1642
- const mipFramebuffer = (level, slot) => resources.framebuffers[level * 2 + slot];
1643
- const mipSize = (level) => plan.mips[level];
1644
- // Every level settles in slot 0 after the vertical blur.
1645
- const blurredSlot = (_level) => 0;
1646
- const drawDownsample = (fromTexture, fromWidth, fromHeight, toFramebuffer, toWidth, toHeight) => {
1647
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, toFramebuffer);
1648
- this.gl.viewport(0, 0, toWidth, toHeight);
1649
- this.gl.useProgram(downsampleProgram);
1650
- this.gl.bindVertexArray(vertexArray);
1651
- this.bindFullscreenTexture(0, fromTexture);
1652
- this.gl.uniform1i(this.gl.getUniformLocation(downsampleProgram, "u_source"), 0);
1653
- this.gl.uniform2f(this.gl.getUniformLocation(downsampleProgram, "u_texelSize"), 1 / fromWidth, 1 / fromHeight);
1654
- this.gl.uniform2f(this.gl.getUniformLocation(downsampleProgram, "u_targetSize"), toWidth, toHeight);
1655
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1656
- };
1657
- const drawBrightExtract = (fromTexture, toFramebuffer, size) => {
1658
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, toFramebuffer);
1659
- this.gl.viewport(0, 0, size.width, size.height);
1660
- this.gl.useProgram(brightProgram);
1661
- this.gl.bindVertexArray(vertexArray);
1662
- this.bindFullscreenTexture(0, fromTexture);
1663
- if (brightLut)
1664
- this.bindFullscreenTexture(1, brightLut);
1665
- this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_source"), 0);
1666
- this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_brightLut"), 1);
1667
- this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_hdr"), hdr ? 1 : 0);
1668
- this.gl.uniform1f(this.gl.getUniformLocation(brightProgram, "u_threshold"), options.threshold);
1669
- this.gl.uniform1f(this.gl.getUniformLocation(brightProgram, "u_softKnee"), options.softKnee);
1670
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1671
- };
1672
- const drawSeparableBlur = (readTexture, tmpTexture, tmpFramebuffer, outFramebuffer, size, radius) => {
1673
- // Horizontal into the temp target, vertical back into the output target.
1674
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, tmpFramebuffer);
1675
- this.gl.viewport(0, 0, size.width, size.height);
1676
- this.gl.useProgram(blurProgram);
1677
- this.gl.bindVertexArray(vertexArray);
1678
- this.bindFullscreenTexture(0, readTexture);
1679
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_source"), 0);
1680
- this.gl.uniform2i(this.gl.getUniformLocation(blurProgram, "u_size"), size.width, size.height);
1681
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_radius"), radius);
1682
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_horizontal"), 1);
1683
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_hdr"), hdr ? 1 : 0);
1684
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1685
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, outFramebuffer);
1686
- this.bindFullscreenTexture(0, tmpTexture);
1687
- this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_horizontal"), 0);
1688
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1689
- };
1690
- // Extract highlights at the source resolution before the first downsample.
1691
- // Downsampling the complete scene first averaged narrow emissive sources
1692
- // below the authored threshold, so balanced/cinematic bloom could execute
1693
- // all native passes yet remain pixel-identical to disabled output.
1694
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, fullResStaging.framebufferA);
1695
- this.gl.viewport(0, 0, sourceWidth, sourceHeight);
1696
- this.gl.useProgram(brightProgram);
1697
- this.gl.bindVertexArray(vertexArray);
1698
- this.bindFullscreenTexture(0, sourceTexture);
1699
- if (brightLut)
1700
- this.bindFullscreenTexture(1, brightLut);
1701
- this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_source"), 0);
1702
- this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_brightLut"), 1);
1703
- this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_hdr"), hdr ? 1 : 0);
1704
- this.gl.uniform1f(this.gl.getUniformLocation(brightProgram, "u_threshold"), options.threshold);
1705
- this.gl.uniform1f(this.gl.getUniformLocation(brightProgram, "u_softKnee"), options.softKnee);
1706
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1707
- // Level 0 downsamples the extracted highlight field, then blurs H into
1708
- // slot 1 and V back into slot 0. The result therefore settles in slot 0.
1709
- const level0 = mipSize(0);
1710
- drawDownsample(fullResStaging.textureA, sourceWidth, sourceHeight, mipFramebuffer(0, 0), level0.width, level0.height);
1711
- drawSeparableBlur(mipTexture(0, 0), mipTexture(0, 1), mipFramebuffer(0, 1), mipFramebuffer(0, 0), level0, blurRadii[0]);
1712
- for (let level = 1; level < mipCount; level += 1) {
1713
- const size = mipSize(level);
1714
- const previous = mipSize(level - 1);
1715
- drawDownsample(mipTexture(level - 1, blurredSlot(level - 1)), previous.width, previous.height, mipFramebuffer(level, 0), size.width, size.height);
1716
- // H into slot 1, V back into slot 0: blurred result settles in slot 0.
1717
- drawSeparableBlur(mipTexture(level, 0), mipTexture(level, 1), mipFramebuffer(level, 1), mipFramebuffer(level, 0), size, blurRadii[level]);
1718
- }
1719
- // Accumulate smallest-to-largest, ping-ponging between the two
1720
- // accumulators (a pass must never sample its own bound target).
1721
- const weights = plan.weights;
1722
- let readAccumulator = { texture: resources.accumulatorTextureA, framebuffer: resources.accumulatorFramebufferA };
1723
- let writeAccumulator = { texture: resources.accumulatorTextureB, framebuffer: resources.accumulatorFramebufferB };
1724
- // Clear both accumulators; the seed reads the cleared sibling, never the
1725
- // bound target (feedback loop).
1726
- for (const acc of [readAccumulator, writeAccumulator]) {
1727
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, acc.framebuffer);
1728
- this.gl.viewport(0, 0, level0.width, level0.height);
1729
- this.gl.clearColor(0, 0, 0, 0);
1730
- this.gl.clear(this.gl.COLOR_BUFFER_BIT);
1731
- }
1732
- // Seed: smallest mip onto the cleared sibling accumulator.
1733
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, writeAccumulator.framebuffer);
1734
- this.gl.viewport(0, 0, level0.width, level0.height);
1735
- this.gl.useProgram(accumulateProgram);
1736
- this.gl.bindVertexArray(vertexArray);
1737
- this.bindFullscreenTexture(0, readAccumulator.texture);
1738
- this.bindFullscreenTexture(1, mipTexture(mipCount - 1, blurredSlot(mipCount - 1)));
1739
- this.gl.uniform1i(this.gl.getUniformLocation(accumulateProgram, "u_base"), 0);
1740
- this.gl.uniform1i(this.gl.getUniformLocation(accumulateProgram, "u_bloom"), 1);
1741
- this.gl.uniform1f(this.gl.getUniformLocation(accumulateProgram, "u_weight"), weights[mipCount - 1]);
1742
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1743
- for (let level = mipCount - 2; level >= 0; level -= 1) {
1744
- const nextRead = writeAccumulator;
1745
- const nextWrite = readAccumulator;
1746
- readAccumulator = nextRead;
1747
- writeAccumulator = nextWrite;
1748
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, writeAccumulator.framebuffer);
1749
- this.gl.viewport(0, 0, level0.width, level0.height);
1750
- this.gl.useProgram(accumulateProgram);
1751
- this.gl.bindVertexArray(vertexArray);
1752
- this.bindFullscreenTexture(0, readAccumulator.texture);
1753
- this.bindFullscreenTexture(1, mipTexture(level, blurredSlot(level)));
1754
- this.gl.uniform1i(this.gl.getUniformLocation(accumulateProgram, "u_base"), 0);
1755
- this.gl.uniform1i(this.gl.getUniformLocation(accumulateProgram, "u_bloom"), 1);
1756
- this.gl.uniform1f(this.gl.getUniformLocation(accumulateProgram, "u_weight"), weights[level]);
1757
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1758
- }
1759
- // Upsample the weighted sum onto full-resolution staging target A, using
1760
- // the cleared staging target B as the zero base (never sample A while
1761
- // rendering into it).
1762
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, fullResStaging.framebufferB);
1763
- this.gl.viewport(0, 0, sourceWidth, sourceHeight);
1764
- this.gl.clearColor(0, 0, 0, 0);
1765
- this.gl.clear(this.gl.COLOR_BUFFER_BIT);
1766
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, fullResStaging.framebufferA);
1767
- this.gl.viewport(0, 0, sourceWidth, sourceHeight);
1768
- this.gl.useProgram(accumulateProgram);
1769
- this.gl.bindVertexArray(vertexArray);
1770
- this.bindFullscreenTexture(0, fullResStaging.textureB);
1771
- this.bindFullscreenTexture(1, writeAccumulator.texture);
1772
- this.gl.uniform1i(this.gl.getUniformLocation(accumulateProgram, "u_base"), 0);
1773
- this.gl.uniform1i(this.gl.getUniformLocation(accumulateProgram, "u_bloom"), 1);
1774
- this.gl.uniform1f(this.gl.getUniformLocation(accumulateProgram, "u_weight"), 1);
1775
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1776
- return fullResStaging.textureA;
1777
- }
1778
- executeNativeOutlinePasses(sourceTexture, resources, options, vertexArray, targetIndex) {
1779
- const blendLut = this.outlineBlendLutTexture;
1780
- if (!blendLut) {
1781
- throw new RenderDeviceError("WebGL2 outline lookup texture was not initialized", "WEBGL_ALLOCATION_FAILED");
1782
- }
1783
- const program = this.ensureOutlineProgram();
1784
- const targetTexture = resources.textures[targetIndex];
1785
- const targetFramebuffer = resources.framebuffers[targetIndex];
1786
- const bound = createOutlineGradientBound(options.threshold);
1787
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, targetFramebuffer);
1788
- this.gl.viewport(0, 0, resources.width, resources.height);
1789
- this.gl.useProgram(program);
1790
- this.gl.bindVertexArray(vertexArray);
1791
- this.bindFullscreenTexture(0, sourceTexture);
1792
- this.bindFullscreenTexture(1, blendLut);
1793
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_source"), 0);
1794
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_blendLut"), 1);
1795
- this.gl.uniform2i(this.gl.getUniformLocation(program, "u_size"), resources.width, resources.height);
1796
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_width"), options.width);
1797
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_boundHigh"), bound.highWord);
1798
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_boundLow"), bound.lowWord);
1799
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1800
- return targetTexture;
1801
- }
1802
- executeNativeSsaoPass(sourceTexture, depthTexture, resources, options, vertexArray, targetIndex) {
1803
- const program = this.ensureSsaoProgram();
1804
- const targetTexture = resources.textures[targetIndex];
1805
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, resources.framebuffers[targetIndex]);
1806
- this.gl.viewport(0, 0, resources.width, resources.height);
1807
- this.gl.useProgram(program);
1808
- this.gl.bindVertexArray(vertexArray);
1809
- this.bindFullscreenTexture(0, sourceTexture);
1810
- this.bindFullscreenTexture(1, depthTexture);
1811
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_source"), 0);
1812
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_depth"), 1);
1813
- this.gl.uniform2i(this.gl.getUniformLocation(program, "u_size"), resources.width, resources.height);
1814
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_radius"), options.radius);
1815
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_intensity"), options.intensity);
1816
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_bias"), options.bias);
1817
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1818
- return targetTexture;
1819
- }
1820
- executeNativeSsrPass(sourceTexture, depthTexture, resources, options, vertexArray, targetIndex, depthRange) {
1821
- const targetTexture = resources.textures[targetIndex];
1822
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, resources.framebuffers[targetIndex]);
1823
- this.drawSsrKernel(sourceTexture, depthTexture, resources.width, resources.height, options, vertexArray, depthRange);
1824
- return targetTexture;
1825
- }
1826
- drawSsrKernel(sourceTexture, depthTexture, width, height, options, vertexArray, depthRange) {
1827
- const program = this.ensureSsrProgram();
1828
- this.gl.viewport(0, 0, width, height);
1829
- this.gl.useProgram(program);
1830
- this.gl.bindVertexArray(vertexArray);
1831
- this.bindFullscreenTexture(0, sourceTexture);
1832
- this.bindFullscreenTexture(1, depthTexture);
1833
- this.bindFullscreenTexture(2, options.normalMask ?? sourceTexture);
1834
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_source"), 0);
1835
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_depth"), 1);
1836
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_normalMask"), 2);
1837
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_hasNormalMask"), options.normalMask ? 1 : 0);
1838
- this.gl.uniform2i(this.gl.getUniformLocation(program, "u_size"), width, height);
1839
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_intensity"), options.intensity);
1840
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_maxDistance"), options.maxDistance);
1841
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_maxSteps"), options.maxSteps ?? 32);
1842
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_thickness"), options.thickness ?? 0.2);
1843
- if (options.projection && options.inverseProjection) {
1844
- this.gl.uniformMatrix4fv(this.gl.getUniformLocation(program, "u_projection"), false, options.projection);
1845
- this.gl.uniformMatrix4fv(this.gl.getUniformLocation(program, "u_inverseProjection"), false, options.inverseProjection);
1846
- }
1847
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_depthNear"), depthRange.near);
1848
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_depthFar"), depthRange.far);
1849
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1850
- }
1851
- executeNativeDepthOfFieldPass(sourceTexture, depthTexture, resources, options, vertexArray, targetIndex, depthRange) {
1852
- const program = this.ensureDepthOfFieldProgram();
1853
- const targetTexture = resources.textures[targetIndex];
1854
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, resources.framebuffers[targetIndex]);
1855
- this.gl.viewport(0, 0, resources.width, resources.height);
1856
- this.gl.useProgram(program);
1857
- this.gl.bindVertexArray(vertexArray);
1858
- this.bindFullscreenTexture(0, sourceTexture);
1859
- this.bindFullscreenTexture(1, depthTexture);
1860
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_source"), 0);
1861
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_depth"), 1);
1862
- this.gl.uniform2i(this.gl.getUniformLocation(program, "u_size"), resources.width, resources.height);
1863
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_focusDepth"), options.focusDepth);
1864
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_focusRange"), options.focusRange);
1865
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_maxRadius"), options.maxRadius);
1866
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_depthNear"), depthRange.near);
1867
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_depthFar"), depthRange.far);
1868
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1869
- return targetTexture;
1870
- }
1871
- executeNativeMotionBlurPass(sourceTexture, resources, options, vertexArray, targetIndex) {
1872
- const velocityTexture = options.temporal ? this.requireTemporalTarget(options.temporal.velocity, resources.width, resources.height).colorHandle : this.motionBlurVelocityTexture;
1873
- if (!velocityTexture) {
1874
- throw new RenderDeviceError("WebGL2 motion-blur velocity texture was not initialized", "WEBGL_ALLOCATION_FAILED");
1875
- }
1876
- const program = this.ensureMotionBlurProgram();
1877
- const targetTexture = resources.textures[targetIndex];
1878
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, resources.framebuffers[targetIndex]);
1879
- this.gl.viewport(0, 0, resources.width, resources.height);
1880
- this.gl.useProgram(program);
1881
- this.gl.bindVertexArray(vertexArray);
1882
- this.bindFullscreenTexture(0, sourceTexture);
1883
- this.bindFullscreenTexture(1, velocityTexture);
1884
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_source"), 0);
1885
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_velocity"), 1);
1886
- this.gl.uniform2i(this.gl.getUniformLocation(program, "u_size"), resources.width, resources.height);
1887
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_samples"), options.samples);
1888
- this.gl.uniform1f(this.gl.getUniformLocation(program, "u_scale"), options.scale);
1889
- this.gl.uniform1i(this.gl.getUniformLocation(program, "u_velocityUv"), options.temporal ? 1 : 0);
1890
- if (options.temporal) {
1891
- this.nativeTemporalPasses++;
1892
- this.nativeTemporalBindings++;
1893
- }
1894
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1895
- return targetTexture;
1184
+ this.host.textureRegistry.textureUploadModes.clear();
1185
+ if (this.host.textureRegistry.fallbackTexture) {
1186
+ this.gl.deleteTexture(this.host.textureRegistry.fallbackTexture);
1187
+ this.host.textureRegistry.fallbackTexture = null;
1188
+ }
1189
+ if (this.host.textureRegistry.fallbackCubeTexture) {
1190
+ this.gl.deleteTexture(this.host.textureRegistry.fallbackCubeTexture);
1191
+ this.host.textureRegistry.fallbackCubeTexture = null;
1192
+ }
1193
+ if (this.host.post.presentationProgram) {
1194
+ this.gl.deleteProgram(this.host.post.presentationProgram);
1195
+ this.host.post.presentationProgram = null;
1196
+ }
1197
+ if (this.host.post.ldrPostprocessProgram) {
1198
+ this.gl.deleteProgram(this.host.post.ldrPostprocessProgram);
1199
+ this.host.post.ldrPostprocessProgram = null;
1200
+ }
1201
+ if (this.host.post.bloomBrightExtractProgram) {
1202
+ this.gl.deleteProgram(this.host.post.bloomBrightExtractProgram);
1203
+ this.host.post.bloomBrightExtractProgram = null;
1204
+ }
1205
+ if (this.host.post.bloomBlurProgram) {
1206
+ this.gl.deleteProgram(this.host.post.bloomBlurProgram);
1207
+ this.host.post.bloomBlurProgram = null;
1208
+ }
1209
+ if (this.host.post.bloomCompositeProgram) {
1210
+ this.gl.deleteProgram(this.host.post.bloomCompositeProgram);
1211
+ this.host.post.bloomCompositeProgram = null;
1212
+ }
1213
+ if (this.host.post.bloomDownsampleProgram) {
1214
+ this.gl.deleteProgram(this.host.post.bloomDownsampleProgram);
1215
+ this.host.post.bloomDownsampleProgram = null;
1216
+ }
1217
+ if (this.host.post.bloomAccumulateProgram) {
1218
+ this.gl.deleteProgram(this.host.post.bloomAccumulateProgram);
1219
+ this.host.post.bloomAccumulateProgram = null;
1220
+ }
1221
+ if (this.host.post.outlineProgram) {
1222
+ this.gl.deleteProgram(this.host.post.outlineProgram);
1223
+ this.host.post.outlineProgram = null;
1224
+ }
1225
+ if (this.host.post.ssaoProgram) {
1226
+ this.gl.deleteProgram(this.host.post.ssaoProgram);
1227
+ this.host.post.ssaoProgram = null;
1228
+ }
1229
+ if (this.host.post.ssrProgram) {
1230
+ this.gl.deleteProgram(this.host.post.ssrProgram);
1231
+ this.host.post.ssrProgram = null;
1232
+ }
1233
+ if (this.host.post.depthOfFieldProgram) {
1234
+ this.gl.deleteProgram(this.host.post.depthOfFieldProgram);
1235
+ this.host.post.depthOfFieldProgram = null;
1236
+ }
1237
+ if (this.host.post.motionBlurProgram) {
1238
+ this.gl.deleteProgram(this.host.post.motionBlurProgram);
1239
+ this.host.post.motionBlurProgram = null;
1240
+ }
1241
+ if (this.host.post.motionBlurVelocityTexture) {
1242
+ this.gl.deleteTexture(this.host.post.motionBlurVelocityTexture);
1243
+ this.host.post.motionBlurVelocityTexture = null;
1244
+ this.host.post.motionBlurVelocitySize = null;
1245
+ }
1246
+ if (this.host.post.taaProgram) {
1247
+ this.gl.deleteProgram(this.host.post.taaProgram);
1248
+ this.host.post.taaProgram = null;
1249
+ }
1250
+ if (this.host.post.taaPresentationProgram) {
1251
+ this.gl.deleteProgram(this.host.post.taaPresentationProgram);
1252
+ this.host.post.taaPresentationProgram = null;
1253
+ }
1254
+ if (this.host.post.taaHistoryTexture) {
1255
+ this.gl.deleteTexture(this.host.post.taaHistoryTexture);
1256
+ this.host.post.taaHistoryTexture = null;
1257
+ this.host.post.taaHistorySize = null;
1258
+ }
1259
+ this.host.post.disposeBloomPingPongResources();
1260
+ this.host.post.disposeBloomPyramidResources();
1261
+ if (this.host.post.bloomBrightLutTexture) {
1262
+ this.gl.deleteTexture(this.host.post.bloomBrightLutTexture);
1263
+ this.host.post.bloomBrightLutTexture = null;
1264
+ this.host.post.bloomBrightLutThreshold = null;
1265
+ }
1266
+ if (this.host.post.bloomCompositeLutTexture) {
1267
+ this.gl.deleteTexture(this.host.post.bloomCompositeLutTexture);
1268
+ this.host.post.bloomCompositeLutTexture = null;
1269
+ this.host.post.bloomCompositeLutIntensity = null;
1270
+ this.host.post.bloomCompositeLutShoulder = null;
1271
+ }
1272
+ if (this.host.post.outlineBlendLutTexture) {
1273
+ this.gl.deleteTexture(this.host.post.outlineBlendLutTexture);
1274
+ this.host.post.outlineBlendLutTexture = null;
1275
+ this.host.post.outlineBlendLutKey = null;
1276
+ }
1277
+ if (this.host.post.presentationVertexArray) {
1278
+ this.gl.deleteVertexArray(this.host.post.presentationVertexArray);
1279
+ this.host.post.presentationVertexArray = null;
1280
+ }
1281
+ if (this.host.probe.depthReadbackProgram) {
1282
+ this.gl.deleteProgram(this.host.probe.depthReadbackProgram);
1283
+ this.host.probe.depthReadbackProgram = null;
1284
+ }
1285
+ this.host.textureRegistry.textures.clear();
1286
+ this.host.disposed = true;
1896
1287
  }
1897
- executeNativeTaaPass(sourceTexture, resources, options, vertexArray, targetIndex) {
1898
- const temporal = options.temporal;
1899
- const historyTarget = temporal ? this.requireTemporalTarget(temporal.history, resources.width, resources.height) : undefined;
1900
- const historyTexture = historyTarget?.colorHandle ?? this.taaHistoryTexture;
1901
- if (!historyTexture) {
1902
- throw new RenderDeviceError("WebGL2 TAA history texture was not initialized", "WEBGL_ALLOCATION_FAILED");
1903
- }
1904
- const accumulationProgram = this.ensureTaaProgram();
1905
- const targetTexture = resources.textures[targetIndex];
1906
- this.gl.viewport(0, 0, resources.width, resources.height);
1907
- this.gl.useProgram(accumulationProgram);
1908
- this.gl.bindVertexArray(vertexArray);
1909
- this.bindFullscreenTexture(0, sourceTexture);
1910
- this.bindFullscreenTexture(1, historyTexture);
1911
- this.gl.uniform1i(this.gl.getUniformLocation(accumulationProgram, "u_source"), 0);
1912
- this.gl.uniform1i(this.gl.getUniformLocation(accumulationProgram, "u_history"), 1);
1913
- this.gl.uniform1f(this.gl.getUniformLocation(accumulationProgram, "u_blend"), temporal && !temporal.historyValid ? 0 : temporalAccumulationWeight(options.blend, temporal?.historyFrames));
1914
- this.gl.uniform1i(this.gl.getUniformLocation(accumulationProgram, "u_temporal"), temporal ? 1 : 0);
1915
- if (temporal) {
1916
- const velocity = this.requireTemporalTarget(temporal.velocity, resources.width, resources.height);
1917
- const destination = this.requireTemporalTarget(temporal.historyOutput, resources.width, resources.height);
1918
- if (destination === historyTarget || destination === velocity || historyTarget === velocity)
1919
- throw new RenderDeviceError("Temporal targets must not alias", "TEMPORAL_TARGET_ALIAS");
1920
- this.bindFullscreenTexture(2, velocity.colorHandle);
1921
- this.gl.uniform1i(this.gl.getUniformLocation(accumulationProgram, "u_velocity"), 2);
1922
- // Resolve exactly once into the next history target. Presentation reads
1923
- // this immutable result through a separate program, so display tuning
1924
- // cannot alter the accumulated history shader or its stored bytes.
1925
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, destination.framebuffer);
1926
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1927
- const presentationProgram = this.ensureTaaPresentationProgram();
1928
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, resources.framebuffers[targetIndex]);
1929
- this.gl.useProgram(presentationProgram);
1930
- this.bindFullscreenTexture(0, sourceTexture);
1931
- this.bindFullscreenTexture(1, destination.colorHandle);
1932
- this.gl.uniform1i(this.gl.getUniformLocation(presentationProgram, "u_source"), 0);
1933
- this.gl.uniform1i(this.gl.getUniformLocation(presentationProgram, "u_accumulated"), 1);
1934
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1935
- this.nativeTemporalPasses++;
1936
- this.nativeTemporalBindings += 3;
1288
+ compileShader(type, source, label) {
1289
+ const shader = this.gl.createShader(type);
1290
+ if (!shader) {
1291
+ throw new RenderDeviceError("Failed to allocate WebGL shader", "WEBGL_ALLOCATION_FAILED", { label });
1937
1292
  }
1938
- else {
1939
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, resources.framebuffers[targetIndex]);
1940
- this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1293
+ this.gl.shaderSource(shader, source);
1294
+ this.gl.compileShader(shader);
1295
+ if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
1296
+ const log = this.gl.getShaderInfoLog(shader) ?? "Unknown shader compile error";
1297
+ this.gl.deleteShader(shader);
1298
+ throw new RenderDeviceError("WebGL shader compile failed", "SHADER_COMPILE_FAILED", { label, log });
1941
1299
  }
1942
- return targetTexture;
1943
- }
1944
- requireTemporalTarget(target, width, height) {
1945
- if (!(target instanceof WebGL2RenderTarget) || !this.renderTargets.has(target) || target.disposed || target.width !== width || target.height !== height || target.colorTexture.format !== "rgba16f")
1946
- throw new RenderDeviceError("Temporal input must be a live same-device same-size RGBA16F target", "TEMPORAL_TARGET_INVALID");
1947
- return target;
1948
- }
1949
- bindFullscreenTexture(unit, texture) {
1950
- this.gl.activeTexture(this.gl.TEXTURE0 + unit);
1951
- this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
1952
- this.gl.bindSampler(unit, null);
1953
- }
1954
- disposeBloomPingPongResources() {
1955
- if (!this.bloomPingPongResources)
1956
- return;
1957
- for (const texture of this.bloomPingPongResources.textures)
1958
- this.gl.deleteTexture(texture);
1959
- for (const framebuffer of this.bloomPingPongResources.framebuffers)
1960
- this.gl.deleteFramebuffer(framebuffer);
1961
- this.bloomPingPongResources = null;
1962
- }
1963
- /**
1964
- * Diagnostics for the most recent native bloom execution (muse3jsparity-PRD
1965
- * A1). Null when no native bloom pass has run yet on this device.
1966
- */
1967
- getBloomDiagnostics() {
1968
- return this.lastBloomDiagnostics;
1969
- }
1970
- recordBloomDiagnostics(options, sourceWidth, sourceHeight, hdr, mipCount) {
1971
- const plan = resolveBloomPyramidPlan(sourceWidth, sourceHeight, options.quality, hdr);
1972
- const pingPongBytes = sourceWidth * sourceHeight * 4 * (hdr ? 2 : 1) * 2;
1973
- const bytesPerChannel = plan.halfFloat ? 2 : 1;
1974
- const level0 = plan.mips[0];
1975
- const accumulatorBytes = level0.width * level0.height * 4 * bytesPerChannel;
1976
- this.lastBloomDiagnostics = {
1977
- quality: options.quality,
1978
- mipCount,
1979
- targetCount: options.quality === "performance" ? 2 : plan.mips.length * 2 + 1,
1980
- targetBytes: (options.quality === "performance" ? pingPongBytes : plan.targetBytes + accumulatorBytes + pingPongBytes),
1981
- compositeGain: options.intensity * resolveBloomPyramidResponseGain(plan),
1982
- threshold: options.threshold,
1983
- intensity: options.intensity,
1984
- softKnee: options.softKnee,
1985
- shoulder: options.shoulder,
1986
- halfFloat: hdr || plan.halfFloat,
1987
- };
1300
+ return shader;
1988
1301
  }
1989
- /**
1990
- * PART U: every live GPU allocation with bytes + lane owner — registry
1991
- * render targets (B1 shadow maps arrive labeled, B4 captures arrive as
1992
- * `-mirror-target`/`-scene-color-target`) plus the raw-handle residents the
1993
- * registry set cannot see: the A1 bloom pyramid (two targets per mip plus
1994
- * two level-0 accumulators), the legacy bloom ping-pong pair, the A1/A3
1995
- * lookup textures, and the motion-blur/taa history textures. The
1996
- * depth-readback scratch pair is intentionally absent: it is allocated and
1997
- * deleted inside one synchronous call, so it is never live at a diagnostics
1998
- * boundary. A5 volumetric light, C4 decals, and the G1 SDF atlas own no GPU
1999
- * target (forward uniforms + CPU kernel, CPU geometry, CPU atlas data), so
2000
- * no entry is emitted for them; a target appearing under their owner would
2001
- * be the signal that the lane grew one.
2002
- */
2003
- describeGpuTargetInventory(liveRenderTargets) {
2004
- const entries = liveRenderTargets.map((target) => ({
2005
- label: target.label,
2006
- kind: "render-target",
2007
- bytes: target.colorTexture.byteLength + (target.depthTexture?.byteLength ?? 0),
2008
- owner: resolveGpuTargetOwner(target.label)
2009
- }));
2010
- const pyramid = this.bloomPyramidResources;
2011
- if (pyramid) {
2012
- const bytesPerPixel = pyramid.hdr ? 8 : 4;
2013
- pyramid.plan.mips.forEach((mip, index) => {
2014
- for (const side of ["a", "b"]) {
2015
- entries.push({
2016
- label: `bloom-pyramid-mip${index}${side}`,
2017
- kind: "pyramid-mip",
2018
- bytes: mip.width * mip.height * bytesPerPixel,
2019
- owner: "a1-bloom"
2020
- });
2021
- }
2022
- });
2023
- const level0 = pyramid.plan.mips[0];
2024
- if (level0) {
2025
- for (const side of ["a", "b"]) {
2026
- entries.push({
2027
- label: `bloom-pyramid-accumulator-${side}`,
2028
- kind: "pyramid-accumulator",
2029
- bytes: level0.width * level0.height * bytesPerPixel,
2030
- owner: "a1-bloom"
2031
- });
2032
- }
2033
- }
2034
- }
2035
- const pingPong = this.bloomPingPongResources;
2036
- if (pingPong) {
2037
- const bytesPerPixel = pingPong.hdr ? 8 : 4;
2038
- for (const side of ["a", "b"]) {
2039
- entries.push({
2040
- label: `bloom-ping-pong-${side}`,
2041
- kind: "ping-pong",
2042
- bytes: pingPong.width * pingPong.height * bytesPerPixel,
2043
- owner: "a1-bloom"
2044
- });
1302
+ reflectProgram(program) {
1303
+ const attributes = new Map();
1304
+ const uniforms = new Set();
1305
+ const attributeDetails = new Map();
1306
+ const uniformDetails = new Map();
1307
+ const activeAttributes = this.gl.getProgramParameter(program, this.gl.ACTIVE_ATTRIBUTES);
1308
+ const activeUniforms = this.gl.getProgramParameter(program, this.gl.ACTIVE_UNIFORMS);
1309
+ for (let i = 0; i < activeAttributes; i += 1) {
1310
+ const info = this.gl.getActiveAttrib(program, i);
1311
+ if (info) {
1312
+ const location = this.gl.getAttribLocation(program, info.name);
1313
+ attributes.set(info.name, location);
1314
+ attributeDetails.set(info.name, { name: info.name, type: String(info.type), location, source: "vertex", line: 0 });
2045
1315
  }
2046
1316
  }
2047
- if (this.bloomBrightLutTexture) {
2048
- entries.push({
2049
- label: "bloom-bright-lut",
2050
- kind: "lut",
2051
- bytes: BLOOM_BRIGHT_LUT_WIDTH * BLOOM_BRIGHT_LUT_HEIGHT * 4,
2052
- owner: "a1-bloom"
2053
- });
2054
- }
2055
- if (this.bloomCompositeLutTexture) {
2056
- entries.push({
2057
- label: "bloom-composite-lut",
2058
- kind: "lut",
2059
- bytes: BLOOM_COMPOSITE_LUT_SIZE * BLOOM_COMPOSITE_LUT_SIZE * 4,
2060
- owner: "a1-bloom"
2061
- });
2062
- }
2063
- if (this.outlineBlendLutTexture) {
2064
- entries.push({ label: "outline-blend-lut", kind: "lut", bytes: OUTLINE_BLEND_LUT_WIDTH * 4, owner: "post" });
2065
- }
2066
- if (this.motionBlurVelocityTexture && this.motionBlurVelocitySize) {
2067
- entries.push({
2068
- label: "motion-blur-velocity",
2069
- kind: "history",
2070
- bytes: this.motionBlurVelocitySize.width * this.motionBlurVelocitySize.height * 8,
2071
- owner: "post"
2072
- });
2073
- }
2074
- if (this.taaHistoryTexture && this.taaHistorySize) {
2075
- entries.push({
2076
- label: "taa-history",
2077
- kind: "history",
2078
- bytes: this.taaHistorySize.width * this.taaHistorySize.height * 4,
2079
- owner: "post"
2080
- });
2081
- }
2082
- return entries;
2083
- }
2084
- disposeBloomPyramidResources() {
2085
- if (!this.bloomPyramidResources)
2086
- return;
2087
- for (const texture of this.bloomPyramidResources.textures)
2088
- this.gl.deleteTexture(texture);
2089
- for (const framebuffer of this.bloomPyramidResources.framebuffers)
2090
- this.gl.deleteFramebuffer(framebuffer);
2091
- this.gl.deleteTexture(this.bloomPyramidResources.accumulatorTextureA);
2092
- this.gl.deleteFramebuffer(this.bloomPyramidResources.accumulatorFramebufferA);
2093
- this.gl.deleteTexture(this.bloomPyramidResources.accumulatorTextureB);
2094
- this.gl.deleteFramebuffer(this.bloomPyramidResources.accumulatorFramebufferB);
2095
- this.bloomPyramidResources = null;
2096
- }
2097
- /**
2098
- * Mip-chain targets for the balanced/cinematic bloom pyramid. Each level is a
2099
- * single texture+framebuffer at the planned size with linear filtering so the
2100
- * downsample and accumulate passes can sample across levels. Half-float backs
2101
- * the chain when the source is HDR or the cinematic preset requests it.
2102
- */
2103
- ensureBloomPyramidResources(plan, hdr) {
2104
- const current = this.bloomPyramidResources;
2105
- if (current && current.plan.quality === plan.quality && current.hdr === (hdr || plan.halfFloat) &&
2106
- current.plan.mips.length === plan.mips.length &&
2107
- current.plan.mips.every((mip, index) => mip.width === plan.mips[index].width && mip.height === plan.mips[index].height)) {
2108
- return current;
2109
- }
2110
- this.disposeBloomPyramidResources();
2111
- const textureUnit0 = this.captureTextureUnit0();
2112
- const previousFramebuffer = this.gl.getParameter(this.gl.FRAMEBUFFER_BINDING);
2113
- const textures = [];
2114
- const framebuffers = [];
2115
- const useHalfFloat = hdr || plan.halfFloat;
2116
- const allocateTarget = (width, height, label) => {
2117
- const texture = this.gl.createTexture();
2118
- const framebuffer = this.gl.createFramebuffer();
2119
- if (!texture || !framebuffer) {
2120
- if (texture)
2121
- this.gl.deleteTexture(texture);
2122
- if (framebuffer)
2123
- this.gl.deleteFramebuffer(framebuffer);
2124
- throw new RenderDeviceError(`Failed to allocate WebGL2 bloom pyramid ${label}`, "WEBGL_ALLOCATION_FAILED", { width, height });
2125
- }
2126
- textures.push(texture);
2127
- framebuffers.push(framebuffer);
2128
- this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
2129
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
2130
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
2131
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
2132
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
2133
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, useHalfFloat ? this.gl.RGBA16F : this.gl.RGBA8, width, height, 0, this.gl.RGBA, useHalfFloat ? this.gl.HALF_FLOAT : this.gl.UNSIGNED_BYTE, null);
2134
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
2135
- this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, texture, 0);
2136
- const status = this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);
2137
- if (status !== this.gl.FRAMEBUFFER_COMPLETE) {
2138
- throw new RenderDeviceError("WebGL2 bloom pyramid framebuffer status is invalid", "FRAMEBUFFER_INVALID", { width, height, status });
2139
- }
2140
- return { texture, framebuffer };
2141
- };
2142
- try {
2143
- // Two ping-pong targets per mip (separable blur needs distinct read/write
2144
- // targets at the same size), plus two level-0-sized accumulators: the
2145
- // weighted sum ping-pongs between them so no pass ever samples the
2146
- // texture of its own bound framebuffer (feedback loop).
2147
- for (const mip of plan.mips) {
2148
- allocateTarget(mip.width, mip.height, "mip");
2149
- allocateTarget(mip.width, mip.height, "mip");
1317
+ for (let i = 0; i < activeUniforms; i += 1) {
1318
+ const info = this.gl.getActiveUniform(program, i);
1319
+ if (info) {
1320
+ const name = info.name.replace(/\[0\]$/, "");
1321
+ uniforms.add(name);
1322
+ uniformDetails.set(name, { name, type: String(info.type), arraySize: info.size > 1 ? info.size : null, source: "fragment", line: 0 });
2150
1323
  }
2151
- const level0 = plan.mips[0];
2152
- const accumulatorA = allocateTarget(level0.width, level0.height, "accumulator-a");
2153
- const accumulatorB = allocateTarget(level0.width, level0.height, "accumulator-b");
2154
- const finalResources = {
2155
- plan,
2156
- hdr: useHalfFloat,
2157
- textures,
2158
- framebuffers,
2159
- accumulatorTextureA: accumulatorA.texture,
2160
- accumulatorFramebufferA: accumulatorA.framebuffer,
2161
- accumulatorTextureB: accumulatorB.texture,
2162
- accumulatorFramebufferB: accumulatorB.framebuffer
2163
- };
2164
- this.bloomPyramidResources = finalResources;
2165
- return finalResources;
2166
- }
2167
- catch (error) {
2168
- for (const texture of textures)
2169
- this.gl.deleteTexture(texture);
2170
- for (const framebuffer of framebuffers)
2171
- this.gl.deleteFramebuffer(framebuffer);
2172
- throw error;
2173
1324
  }
2174
- finally {
2175
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, previousFramebuffer);
2176
- this.restoreTextureUnit0(textureUnit0);
2177
- this.stateCache.invalidate();
2178
- }
2179
- }
2180
- captureTextureUnit0() {
2181
- const activeTexture = this.gl.getParameter(this.gl.ACTIVE_TEXTURE);
2182
- this.gl.activeTexture(this.gl.TEXTURE0);
2183
- return {
2184
- activeTexture,
2185
- texture2d: this.gl.getParameter(this.gl.TEXTURE_BINDING_2D),
2186
- sampler: this.gl.getParameter(this.gl.SAMPLER_BINDING)
2187
- };
2188
- }
2189
- restoreTextureUnit0(snapshot) {
2190
- this.gl.activeTexture(this.gl.TEXTURE0);
2191
- this.gl.bindTexture(this.gl.TEXTURE_2D, snapshot.texture2d);
2192
- this.gl.bindSampler(0, snapshot.sampler);
2193
- this.gl.activeTexture(snapshot.activeTexture);
2194
- }
2195
- captureTextureUnitBinding(unit) {
2196
- this.gl.activeTexture(this.gl.TEXTURE0 + unit);
2197
- return {
2198
- texture2d: this.gl.getParameter(this.gl.TEXTURE_BINDING_2D),
2199
- sampler: this.gl.getParameter(this.gl.SAMPLER_BINDING)
2200
- };
2201
- }
2202
- restoreTextureUnitBinding(unit, snapshot) {
2203
- this.gl.activeTexture(this.gl.TEXTURE0 + unit);
2204
- this.gl.bindTexture(this.gl.TEXTURE_2D, snapshot.texture2d);
2205
- this.gl.bindSampler(unit, snapshot.sampler);
2206
- }
2207
- prepareFullscreenPresentation(framebuffer, outputWidth, outputHeight) {
2208
- const textureUnit0 = this.captureTextureUnit0();
2209
- const textureUnit1 = this.captureTextureUnitBinding(1);
2210
- const textureUnit2 = this.captureTextureUnitBinding(2);
2211
- this.gl.activeTexture(textureUnit0.activeTexture);
2212
- const snapshot = {
2213
- framebuffer: this.gl.getParameter(this.gl.FRAMEBUFFER_BINDING),
2214
- program: this.gl.getParameter(this.gl.CURRENT_PROGRAM),
2215
- textureUnit0,
2216
- textureUnit1,
2217
- textureUnit2,
2218
- vertexArray: this.gl.getParameter(this.gl.VERTEX_ARRAY_BINDING),
2219
- viewport: this.gl.getParameter(this.gl.VIEWPORT),
2220
- colorMask: this.gl.getParameter(this.gl.COLOR_WRITEMASK),
2221
- depthTestEnabled: this.gl.isEnabled(this.gl.DEPTH_TEST),
2222
- cullFaceEnabled: this.gl.isEnabled(this.gl.CULL_FACE),
2223
- blendEnabled: this.gl.isEnabled(this.gl.BLEND),
2224
- scissorTestEnabled: this.gl.isEnabled(this.gl.SCISSOR_TEST),
2225
- stencilTestEnabled: this.gl.isEnabled(this.gl.STENCIL_TEST),
2226
- polygonOffsetFillEnabled: this.gl.isEnabled(this.gl.POLYGON_OFFSET_FILL),
2227
- depthMask: this.gl.getParameter(this.gl.DEPTH_WRITEMASK)
2228
- };
2229
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
2230
- this.gl.viewport(0, 0, outputWidth, outputHeight);
2231
- this.gl.colorMask(true, true, true, true);
2232
- this.gl.disable(this.gl.SCISSOR_TEST);
2233
- this.gl.disable(this.gl.STENCIL_TEST);
2234
- this.gl.disable(this.gl.POLYGON_OFFSET_FILL);
2235
- this.gl.disable(this.gl.DEPTH_TEST);
2236
- this.gl.disable(this.gl.CULL_FACE);
2237
- this.gl.disable(this.gl.BLEND);
2238
- this.gl.depthMask(false);
2239
- return snapshot;
2240
- }
2241
- restoreFullscreenPresentationState(snapshot, fallbackWidth, fallbackHeight) {
2242
- this.gl.bindVertexArray(snapshot.vertexArray);
2243
- this.restoreTextureUnitBinding(2, snapshot.textureUnit2);
2244
- this.restoreTextureUnitBinding(1, snapshot.textureUnit1);
2245
- this.restoreTextureUnit0(snapshot.textureUnit0);
2246
- this.gl.useProgram(snapshot.program);
2247
- if (snapshot.depthTestEnabled)
2248
- this.gl.enable(this.gl.DEPTH_TEST);
2249
- else
2250
- this.gl.disable(this.gl.DEPTH_TEST);
2251
- if (snapshot.cullFaceEnabled)
2252
- this.gl.enable(this.gl.CULL_FACE);
2253
- else
2254
- this.gl.disable(this.gl.CULL_FACE);
2255
- if (snapshot.blendEnabled)
2256
- this.gl.enable(this.gl.BLEND);
2257
- else
2258
- this.gl.disable(this.gl.BLEND);
2259
- if (snapshot.scissorTestEnabled)
2260
- this.gl.enable(this.gl.SCISSOR_TEST);
2261
- else
2262
- this.gl.disable(this.gl.SCISSOR_TEST);
2263
- if (snapshot.stencilTestEnabled)
2264
- this.gl.enable(this.gl.STENCIL_TEST);
2265
- else
2266
- this.gl.disable(this.gl.STENCIL_TEST);
2267
- if (snapshot.polygonOffsetFillEnabled)
2268
- this.gl.enable(this.gl.POLYGON_OFFSET_FILL);
2269
- else
2270
- this.gl.disable(this.gl.POLYGON_OFFSET_FILL);
2271
- this.gl.colorMask(snapshot.colorMask[0] ?? true, snapshot.colorMask[1] ?? true, snapshot.colorMask[2] ?? true, snapshot.colorMask[3] ?? true);
2272
- this.gl.depthMask(snapshot.depthMask);
2273
- this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, snapshot.framebuffer);
2274
- this.gl.viewport(snapshot.viewport[0] ?? 0, snapshot.viewport[1] ?? 0, snapshot.viewport[2] ?? fallbackWidth, snapshot.viewport[3] ?? fallbackHeight);
2275
- this.stateCache.invalidate();
2276
- }
2277
- ensurePresentationVertexArray() {
2278
- if (this.presentationVertexArray)
2279
- return this.presentationVertexArray;
2280
- const vertexArray = this.gl.createVertexArray();
2281
- if (!vertexArray) {
2282
- throw new RenderDeviceError("Failed to allocate WebGL presentation vertex array", "WEBGL_ALLOCATION_FAILED");
2283
- }
2284
- this.presentationVertexArray = vertexArray;
2285
- return vertexArray;
2286
- }
2287
- ensureDepthReadbackProgram() {
2288
- if (this.depthReadbackProgram) {
2289
- return this.depthReadbackProgram;
2290
- }
2291
- const vertex = this.compileShader(this.gl.VERTEX_SHADER, `#version 300 es
2292
- precision highp float;
2293
- out vec2 v_uv;
2294
- void main() {
2295
- vec2 position = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
2296
- v_uv = position;
2297
- gl_Position = vec4(position * 2.0 - 1.0, 0.0, 1.0);
2298
- }
2299
- `, "webgl2-depth-readback");
2300
- const fragment = this.compileShader(this.gl.FRAGMENT_SHADER, `#version 300 es
2301
- precision highp float;
2302
- uniform sampler2D u_depth;
2303
- uniform vec4 u_sourceRect;
2304
- in vec2 v_uv;
2305
- out vec4 outColor;
2306
- vec3 packDepth24(float value) {
2307
- value = clamp(value, 0.0, 1.0);
2308
- vec3 encoded = fract(value * vec3(1.0, 255.0, 65025.0));
2309
- encoded -= encoded.yzz * vec3(1.0 / 255.0, 1.0 / 255.0, 0.0);
2310
- return encoded;
2311
- }
2312
- void main() {
2313
- vec2 uv = u_sourceRect.xy + v_uv * u_sourceRect.zw;
2314
- outColor = vec4(packDepth24(texture(u_depth, uv).r), 1.0);
2315
- }
2316
- `, "webgl2-depth-readback");
2317
- const program = this.gl.createProgram();
2318
- if (!program) {
2319
- this.gl.deleteShader(vertex);
2320
- this.gl.deleteShader(fragment);
2321
- throw new RenderDeviceError("Failed to allocate WebGL2 depth readback shader", "WEBGL_ALLOCATION_FAILED");
2322
- }
2323
- this.gl.attachShader(program, vertex);
2324
- this.gl.attachShader(program, fragment);
2325
- this.gl.linkProgram(program);
2326
- this.gl.deleteShader(vertex);
2327
- this.gl.deleteShader(fragment);
2328
- if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
2329
- const log = this.gl.getProgramInfoLog(program) ?? "Unknown depth readback shader link error";
2330
- this.gl.deleteProgram(program);
2331
- throw new RenderDeviceError("WebGL2 depth readback shader link failed", "SHADER_LINK_FAILED", { log });
2332
- }
2333
- this.depthReadbackProgram = program;
2334
- return program;
1325
+ return { attributes, uniforms, attributeDetails, uniformDetails };
2335
1326
  }
2336
- ensurePresentationProgram() {
2337
- if (this.presentationProgram) {
2338
- return this.presentationProgram;
2339
- }
2340
- const vertex = this.compileShader(this.gl.VERTEX_SHADER, `#version 300 es
2341
- precision highp float;
2342
- out vec2 v_uv;
2343
- void main() {
2344
- vec2 position = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
2345
- v_uv = position;
2346
- gl_Position = vec4(position * 2.0 - 1.0, 0.0, 1.0);
2347
- }
2348
- `, "webgl2-present-render-target");
2349
- const fragment = this.compileShader(this.gl.FRAGMENT_SHADER, `#version 300 es
2350
- precision highp float;
2351
- uniform sampler2D u_source;
2352
- in vec2 v_uv;
2353
- out vec4 outColor;
2354
- void main() {
2355
- outColor = texture(u_source, v_uv);
2356
- }
2357
- `, "webgl2-present-render-target");
2358
- const program = this.gl.createProgram();
2359
- if (!program) {
2360
- this.gl.deleteShader(vertex);
2361
- this.gl.deleteShader(fragment);
2362
- throw new RenderDeviceError("Failed to allocate WebGL presentation shader", "WEBGL_ALLOCATION_FAILED");
2363
- }
2364
- this.gl.attachShader(program, vertex);
2365
- this.gl.attachShader(program, fragment);
2366
- this.gl.linkProgram(program);
2367
- this.gl.deleteShader(vertex);
2368
- this.gl.deleteShader(fragment);
2369
- if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
2370
- const log = this.gl.getProgramInfoLog(program) ?? "Unknown presentation shader link error";
2371
- this.gl.deleteProgram(program);
2372
- throw new RenderDeviceError("WebGL presentation shader link failed", "SHADER_LINK_FAILED", { log });
2373
- }
2374
- this.presentationProgram = program;
2375
- return program;
2376
- }
2377
- ensureBloomBrightExtractProgram() {
2378
- if (this.bloomBrightExtractProgram) {
2379
- return this.bloomBrightExtractProgram;
2380
- }
2381
- this.bloomBrightExtractProgram = this.createFullscreenProgram(`#version 300 es
2382
- precision highp float;
2383
- precision highp int;
2384
- uniform sampler2D u_source;
2385
- uniform sampler2D u_brightLut;
2386
- uniform int u_hdr;
2387
- uniform float u_threshold;
2388
- uniform float u_softKnee;
2389
- out vec4 outColor;
2390
-
2391
- uvec4 byteTexel(sampler2D source, ivec2 coordinate) {
2392
- return uvec4(texelFetch(source, coordinate, 0) * 255.0 + 0.5);
2393
- }
2394
-
2395
- void main() {
2396
- ivec2 pixel = ivec2(gl_FragCoord.xy);
2397
- if (u_hdr == 1) {
2398
- vec4 source = texelFetch(u_source, pixel, 0);
2399
- float luma = dot(source.rgb, vec3(0.2126, 0.7152, 0.0722));
2400
- float kneeLow = max(u_threshold - u_softKnee, 0.0);
2401
- float kneeHigh = min(u_threshold + u_softKnee, 1.0);
2402
- float weight = u_softKnee <= 0.0
2403
- ? (luma >= u_threshold ? 1.0 : 0.0)
2404
- : smoothstep(kneeLow, kneeHigh, luma);
2405
- outColor = source * weight;
2406
- return;
2407
- }
2408
- uvec4 source = byteTexel(u_source, pixel);
2409
- uint colorIndex = (source.r << 16u) | (source.g << 8u) | source.b;
2410
- uint byteIndex = colorIndex >> 3u;
2411
- uint texelIndex = byteIndex >> 2u;
2412
- ivec2 lutCoordinate = ivec2(
2413
- int(texelIndex % ${BLOOM_BRIGHT_LUT_WIDTH}u),
2414
- int(texelIndex / ${BLOOM_BRIGHT_LUT_WIDTH}u)
2415
- );
2416
- uvec4 packed = byteTexel(u_brightLut, lutCoordinate);
2417
- uint component = byteIndex & 3u;
2418
- uint packedByte = component == 0u
2419
- ? packed.r
2420
- : component == 1u
2421
- ? packed.g
2422
- : component == 2u
2423
- ? packed.b
2424
- : packed.a;
2425
- bool bright = ((packedByte >> (colorIndex & 7u)) & 1u) == 1u;
2426
- outColor = bright ? vec4(source) / 255.0 : vec4(0.0);
2427
- }
2428
- `, "webgl2-bloom-bright-extract");
2429
- return this.bloomBrightExtractProgram;
2430
- }
2431
- ensureBloomBlurProgram() {
2432
- if (this.bloomBlurProgram) {
2433
- return this.bloomBlurProgram;
2434
- }
2435
- this.bloomBlurProgram = this.createFullscreenProgram(`#version 300 es
2436
- precision highp float;
2437
- precision highp int;
2438
- uniform sampler2D u_source;
2439
- uniform ivec2 u_size;
2440
- uniform int u_radius;
2441
- uniform int u_horizontal;
2442
- uniform int u_hdr;
2443
- out vec4 outColor;
2444
-
2445
- vec4 sourcePixel(ivec2 coordinate) {
2446
- return texelFetch(u_source, clamp(coordinate, ivec2(0), u_size - ivec2(1)), 0);
2447
- }
2448
-
2449
- void main() {
2450
- ivec2 pixel = ivec2(gl_FragCoord.xy);
2451
- float sigma = max(float(u_radius) / 3.0, 0.5);
2452
- float coefficient = 0.39894 / sigma;
2453
- vec4 sum = sourcePixel(pixel) * coefficient;
2454
- float weightSum = coefficient;
2455
- for (int offset = 1; offset <= 16; offset += 1) {
2456
- if (offset > u_radius) continue;
2457
- float distance = float(offset);
2458
- float weight = coefficient * exp(-0.5 * distance * distance / (sigma * sigma));
2459
- ivec2 delta = u_horizontal == 1 ? ivec2(offset, 0) : ivec2(0, offset);
2460
- sum += (sourcePixel(pixel + delta) + sourcePixel(pixel - delta)) * weight;
2461
- weightSum += 2.0 * weight;
2462
- }
2463
- outColor = sum / max(weightSum, 0.000001);
2464
- }
2465
- `, "webgl2-bloom-blur");
2466
- return this.bloomBlurProgram;
2467
- }
2468
- ensureBloomCompositeProgram() {
2469
- if (this.bloomCompositeProgram) {
2470
- return this.bloomCompositeProgram;
2471
- }
2472
- this.bloomCompositeProgram = this.createFullscreenProgram(`#version 300 es
2473
- precision highp float;
2474
- precision highp int;
2475
- uniform sampler2D u_source;
2476
- uniform sampler2D u_blurred;
2477
- uniform sampler2D u_compositeLut;
2478
- uniform int u_hdr;
2479
- uniform float u_intensity;
2480
- out vec4 outColor;
2481
-
2482
- uvec4 byteTexel(sampler2D source, ivec2 coordinate) {
2483
- return uvec4(texelFetch(source, coordinate, 0) * 255.0 + 0.5);
2484
- }
2485
-
2486
- float compositeChannel(uint source, uint blurred) {
2487
- return texelFetch(u_compositeLut, ivec2(int(source), int(blurred)), 0).r;
2488
- }
2489
-
2490
- void main() {
2491
- ivec2 pixel = ivec2(gl_FragCoord.xy);
2492
- if (u_hdr == 1) {
2493
- vec4 source = texelFetch(u_source, pixel, 0);
2494
- vec3 blurred = texelFetch(u_blurred, pixel, 0).rgb;
2495
- outColor = vec4(source.rgb + blurred * u_intensity, source.a);
2496
- return;
2497
- }
2498
- uvec4 source = byteTexel(u_source, pixel);
2499
- uvec4 blurred = byteTexel(u_blurred, pixel);
2500
- outColor = vec4(
2501
- compositeChannel(source.r, blurred.r),
2502
- compositeChannel(source.g, blurred.g),
2503
- compositeChannel(source.b, blurred.b),
2504
- float(source.a) / 255.0
2505
- );
2506
- }
2507
- `, "webgl2-bloom-composite");
2508
- return this.bloomCompositeProgram;
2509
- }
2510
- ensureBloomDownsampleProgram() {
2511
- if (this.bloomDownsampleProgram)
2512
- return this.bloomDownsampleProgram;
2513
- this.bloomDownsampleProgram = this.createFullscreenProgram(`#version 300 es
2514
- precision highp float;
2515
- uniform sampler2D u_source;
2516
- uniform vec2 u_texelSize;
2517
- uniform vec2 u_targetSize;
2518
- out vec4 outColor;
2519
- void main() {
2520
- // gl_FragCoord is expressed in destination pixels. Normalize by the
2521
- // destination size so every downsample covers the complete source image;
2522
- // multiplying by source texel size cropped a half-size target to the
2523
- // lower-left quarter of the preceding level.
2524
- vec2 uv = gl_FragCoord.xy / u_targetSize;
2525
- vec2 e = u_texelSize * 0.5;
2526
- vec4 sum = texture(u_source, uv - e) + texture(u_source, uv + vec2(e.x, -e.y))
2527
- + texture(u_source, uv + vec2(-e.x, e.y)) + texture(u_source, uv + e);
2528
- outColor = sum * 0.25;
2529
- }
2530
- `, "webgl2-bloom-downsample");
2531
- return this.bloomDownsampleProgram;
2532
- }
2533
- ensureBloomAccumulateProgram() {
2534
- if (this.bloomAccumulateProgram)
2535
- return this.bloomAccumulateProgram;
2536
- this.bloomAccumulateProgram = this.createFullscreenProgram(`#version 300 es
2537
- precision highp float;
2538
- uniform sampler2D u_base;
2539
- uniform sampler2D u_bloom;
2540
- uniform float u_weight;
2541
- out vec4 outColor;
2542
- void main() {
2543
- ivec2 pixel = ivec2(gl_FragCoord.xy);
2544
- vec4 base = texelFetch(u_base, pixel, 0);
2545
- vec2 uv = (vec2(pixel) + 0.5) / vec2(textureSize(u_base, 0));
2546
- vec3 bloom = texture(u_bloom, uv).rgb;
2547
- outColor = vec4(base.rgb + bloom * u_weight, base.a);
2548
- }
2549
- `, "webgl2-bloom-accumulate");
2550
- return this.bloomAccumulateProgram;
2551
- }
2552
- ensureOutlineProgram() {
2553
- if (this.outlineProgram)
2554
- return this.outlineProgram;
2555
- this.outlineProgram = this.createFullscreenProgram(`#version 300 es
2556
- precision highp float;
2557
- precision highp int;
2558
- uniform sampler2D u_source;
2559
- uniform sampler2D u_blendLut;
2560
- uniform ivec2 u_size;
2561
- uniform int u_width;
2562
- uniform float u_boundHigh;
2563
- uniform float u_boundLow;
2564
- out vec4 outColor;
2565
-
2566
- uvec4 sourceByte(ivec2 coordinate) {
2567
- ivec2 bounded = clamp(coordinate, ivec2(0), u_size - ivec2(1));
2568
- return uvec4(texelFetch(u_source, bounded, 0) * 255.0 + 0.5);
2569
- }
2570
-
2571
- uint lumaNumerator(ivec2 coordinate) {
2572
- uvec3 source = sourceByte(coordinate).rgb;
2573
- return 2126u * source.r + 7152u * source.g + 722u * source.b;
2574
- }
2575
-
2576
- uvec2 squareWords(int signedValue) {
2577
- uint value = uint(abs(signedValue));
2578
- uint high = value >> 12u;
2579
- uint low = value & 4095u;
2580
- uint middle = 2u * high * low;
2581
- uint lowWord = low * low + (middle & 4095u) * 4096u;
2582
- uint highWord = high * high + (middle >> 12u);
2583
- highWord += lowWord / ${OUTLINE_LIMB_RADIX}u;
2584
- lowWord %= ${OUTLINE_LIMB_RADIX}u;
2585
- return uvec2(highWord, lowWord);
2586
- }
2587
-
2588
- bool edgeAt(ivec2 pixel) {
2589
- int nw = int(lumaNumerator(pixel + ivec2(-1, -1)));
2590
- int n = int(lumaNumerator(pixel + ivec2(0, -1)));
2591
- int ne = int(lumaNumerator(pixel + ivec2(1, -1)));
2592
- int w = int(lumaNumerator(pixel + ivec2(-1, 0)));
2593
- int e = int(lumaNumerator(pixel + ivec2(1, 0)));
2594
- int sw = int(lumaNumerator(pixel + ivec2(-1, 1)));
2595
- int s = int(lumaNumerator(pixel + ivec2(0, 1)));
2596
- int se = int(lumaNumerator(pixel + ivec2(1, 1)));
2597
- int gx = -nw - 2 * w - sw + ne + 2 * e + se;
2598
- int gy = -nw - 2 * n - ne + sw + 2 * s + se;
2599
- uvec2 x = squareWords(gx);
2600
- uvec2 y = squareWords(gy);
2601
- uint low = x.y + y.y;
2602
- uint high = x.x + y.x;
2603
- if (low >= ${OUTLINE_LIMB_RADIX}u) {
2604
- low -= ${OUTLINE_LIMB_RADIX}u;
2605
- high += 1u;
2606
- }
2607
- uint boundHigh = uint(u_boundHigh);
2608
- uint boundLow = uint(u_boundLow);
2609
- return high != boundHigh ? high > boundHigh : low >= boundLow;
2610
- }
2611
-
2612
- void main() {
2613
- ivec2 pixel = ivec2(gl_FragCoord.xy);
2614
- bool outlined = false;
2615
- for (int offsetY = -6; offsetY <= 6 && !outlined; offsetY += 1) {
2616
- for (int offsetX = -6; offsetX <= 6; offsetX += 1) {
2617
- if (abs(offsetX) > u_width || abs(offsetY) > u_width) continue;
2618
- if (offsetX * offsetX + offsetY * offsetY > u_width * u_width) continue;
2619
- ivec2 candidate = clamp(pixel + ivec2(offsetX, offsetY), ivec2(0), u_size - ivec2(1));
2620
- if (edgeAt(candidate)) {
2621
- outlined = true;
2622
- break;
2623
- }
2624
- }
2625
- }
2626
- uvec4 source = sourceByte(pixel);
2627
- if (!outlined) {
2628
- outColor = vec4(source) / 255.0;
2629
- return;
2630
- }
2631
- outColor = vec4(
2632
- texelFetch(u_blendLut, ivec2(int(source.r), 0), 0).r,
2633
- texelFetch(u_blendLut, ivec2(int(source.g), 0), 0).g,
2634
- texelFetch(u_blendLut, ivec2(int(source.b), 0), 0).b,
2635
- float(source.a) / 255.0
2636
- );
2637
- }
2638
- `, "webgl2-outline");
2639
- return this.outlineProgram;
2640
- }
2641
- ensureSsaoProgram() {
2642
- if (this.ssaoProgram)
2643
- return this.ssaoProgram;
2644
- this.ssaoProgram = this.createFullscreenProgram(`#version 300 es
2645
- precision highp float;
2646
- precision highp int;
2647
- uniform sampler2D u_source;
2648
- uniform sampler2D u_depth;
2649
- uniform ivec2 u_size;
2650
- uniform int u_radius;
2651
- uniform float u_intensity;
2652
- uniform float u_bias;
2653
- out vec4 outColor;
2654
-
2655
- float depthAt(ivec2 coordinate) {
2656
- return texelFetch(u_depth, clamp(coordinate, ivec2(0), u_size - ivec2(1)), 0).r;
2657
- }
2658
-
2659
- void main() {
2660
- ivec2 pixel = ivec2(gl_FragCoord.xy);
2661
- float centerDepth = depthAt(pixel);
2662
- float occlusion = 0.0;
2663
- float samples = 0.0;
2664
- for (int stepY = -1; stepY <= 1; stepY += 1) {
2665
- for (int stepX = -1; stepX <= 1; stepX += 1) {
2666
- if (stepX == 0 && stepY == 0) continue;
2667
- float sampleDepth = depthAt(pixel + ivec2(stepX * u_radius, stepY * u_radius));
2668
- occlusion += clamp(
2669
- (centerDepth - sampleDepth - u_bias) / (0.14 + float(u_radius) * 0.04),
2670
- 0.0,
2671
- 1.0
2672
- );
2673
- samples += 1.0;
2674
- }
2675
- }
2676
- float factor = max(0.18, 1.0 - (occlusion / max(1.0, samples)) * u_intensity * 0.72);
2677
- vec4 source = texelFetch(u_source, pixel, 0);
2678
- outColor = vec4(source.rgb * factor, source.a);
2679
- }
2680
- `, "webgl2-ssao");
2681
- return this.ssaoProgram;
2682
- }
2683
- ensureSsrProgram() {
2684
- if (this.ssrProgram)
2685
- return this.ssrProgram;
2686
- this.ssrProgram = this.createFullscreenProgram(`#version 300 es
2687
- precision highp float;
2688
- precision highp int;
2689
- uniform sampler2D u_source;
2690
- uniform sampler2D u_depth;
2691
- uniform sampler2D u_normalMask;
2692
- uniform ivec2 u_size;
2693
- uniform float u_intensity;
2694
- uniform float u_maxDistance;
2695
- uniform int u_maxSteps;
2696
- uniform float u_thickness;
2697
- uniform int u_hasNormalMask;
2698
- uniform mat4 u_projection;
2699
- uniform mat4 u_inverseProjection;
2700
- out vec4 outColor;
2701
- vec3 positionAtDepth(vec2 uv, float depth) {
2702
- vec4 p = u_inverseProjection * vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
2703
- return p.xyz / p.w;
2704
- }
2705
- vec3 positionAt(vec2 uv) {
2706
- return positionAtDepth(uv, texture(u_depth, uv).r);
2707
- }
2708
- vec3 viewDirection(vec2 uv) {
2709
- return normalize(positionAtDepth(uv, 0.999) - positionAtDepth(uv, 0.0));
2710
- }
2711
- vec2 projectPosition(vec3 p) {
2712
- vec4 clip = u_projection * vec4(p, 1.0);
2713
- return clip.xy / clip.w * 0.5 + 0.5;
2714
- }
2715
- float depthDifference(vec3 p, vec2 uv) {
2716
- return dot(p - positionAt(uv), viewDirection(uv));
2717
- }
2718
- void main() {
2719
- vec2 uv = gl_FragCoord.xy / vec2(u_size);
2720
- vec4 base = texture(u_source, uv);
2721
- outColor = base;
2722
- vec3 origin = positionAt(uv);
2723
- vec4 normalMask = texture(u_normalMask, uv);
2724
- vec3 normal = u_hasNormalMask == 1 ? normalize(normalMask.xyz * 2.0 - 1.0) : normalize(cross(dFdx(origin), dFdy(origin)));
2725
- float roughness = u_hasNormalMask == 1 ? normalMask.a : 0.25;
2726
- if (texture(u_depth, uv).r >= 0.999999 || (u_hasNormalMask == 1 && normalMask.a == 0.0) || roughness >= 1.0) return;
2727
- vec3 ray = normalize(reflect(viewDirection(uv), normal));
2728
- float stepSize = u_maxDistance / float(u_maxSteps);
2729
- vec3 start = origin + normal * u_thickness;
2730
- float previous = 0.0;
2731
- for (int i = 1; i <= 64; ++i) {
2732
- if (i > u_maxSteps) break;
2733
- float distanceAlong = float(i) * stepSize;
2734
- vec3 candidate = start + ray * distanceAlong;
2735
- vec4 candidateClip = u_projection * vec4(candidate, 1.0);
2736
- if (candidateClip.w <= 0.0 || abs(candidateClip.z) >= candidateClip.w) break;
2737
- vec2 hitUV = projectPosition(candidate);
2738
- if (any(lessThanEqual(hitUV, vec2(0.0))) || any(greaterThanEqual(hitUV, vec2(1.0)))) break;
2739
- float difference = depthDifference(candidate, hitUV);
2740
- if (difference >= 0.0 && previous < 0.0) {
2741
- float lo = distanceAlong - stepSize, hi = distanceAlong;
2742
- for (int j = 0; j < 5; ++j) {
2743
- float mid = (lo + hi) * 0.5;
2744
- vec3 point = start + ray * mid;
2745
- if (depthDifference(point, projectPosition(point)) >= 0.0) hi = mid; else lo = mid;
2746
- }
2747
- candidate = start + ray * hi;
2748
- hitUV = projectPosition(candidate);
2749
- difference = depthDifference(candidate, hitUV);
2750
- if (difference > u_thickness || texture(u_depth, hitUV).r >= 0.999999) break;
2751
- float edge = smoothstep(0.0, 0.08, min(min(hitUV.x, hitUV.y), min(1.0 - hitUV.x, 1.0 - hitUV.y)));
2752
- float response = clamp(u_intensity * edge * (1.0 - roughness) * (1.0 - hi / u_maxDistance), 0.0, 1.0);
2753
- outColor = vec4(mix(base.rgb, texture(u_source, hitUV).rgb, response), base.a);
2754
- break;
2755
- }
2756
- previous = difference;
2757
- }
2758
- }
2759
- `, "webgl2-ssr");
2760
- return this.ssrProgram;
2761
- }
2762
- ensureDepthOfFieldProgram() {
2763
- if (this.depthOfFieldProgram)
2764
- return this.depthOfFieldProgram;
2765
- this.depthOfFieldProgram = this.createFullscreenProgram(`#version 300 es
2766
- precision highp float;
2767
- precision highp int;
2768
- uniform sampler2D u_source;
2769
- uniform sampler2D u_depth;
2770
- uniform ivec2 u_size;
2771
- uniform float u_focusDepth;
2772
- uniform float u_focusRange;
2773
- uniform int u_maxRadius;
2774
- uniform float u_depthNear;
2775
- uniform float u_depthFar;
2776
- out vec4 outColor;
2777
-
2778
- // Same linearization contract as the SSR program, except focus is authored
2779
- // directly as a linear-distance fraction (0 = near plane, 1 = far plane):
2780
- // buffer-unit focus values are unusable once depth is linearized, because the
2781
- // projection curve parks the whole play area inside a sliver of buffer units.
2782
- // The CPU byte kernel keeps buffer-unit semantics; the divergence is
2783
- // documented at normalizeLdrDepthRange.
2784
- float a3dDofLinearDepth(float depth) {
2785
- float viewZ = u_depthNear * u_depthFar / max(u_depthFar - depth * (u_depthFar - u_depthNear), 0.0001);
2786
- return clamp((viewZ - u_depthNear) / max(u_depthFar - u_depthNear, 0.0001), 0.0, 1.0);
2787
- }
2788
-
2789
- void main() {
2790
- ivec2 pixel = ivec2(gl_FragCoord.xy);
2791
- vec4 source = texelFetch(u_source, pixel, 0);
2792
- float linearDepth = a3dDofLinearDepth(texelFetch(u_depth, pixel, 0).r);
2793
- float normalizedBlur = max(0.0, abs(linearDepth - u_focusDepth) - u_focusRange)
2794
- / max(u_focusRange, 0.001) * float(u_maxRadius);
2795
- int radius = min(u_maxRadius, int(round(normalizedBlur)));
2796
- if (radius == 0) {
2797
- outColor = source;
2798
- return;
2799
- }
2800
- vec3 sum = vec3(0.0);
2801
- float samples = 0.0;
2802
- for (int offsetY = -8; offsetY <= 8; offsetY += 1) {
2803
- for (int offsetX = -8; offsetX <= 8; offsetX += 1) {
2804
- if (abs(offsetX) > radius || abs(offsetY) > radius) continue;
2805
- if (offsetX * offsetX + offsetY * offsetY > radius * radius) continue;
2806
- ivec2 samplePixel = clamp(pixel + ivec2(offsetX, offsetY), ivec2(0), u_size - ivec2(1));
2807
- sum += texelFetch(u_source, samplePixel, 0).rgb;
2808
- samples += 1.0;
2809
- }
2810
- }
2811
- outColor = vec4(sum / max(1.0, samples), source.a);
2812
- }
2813
- `, "webgl2-depth-of-field");
2814
- return this.depthOfFieldProgram;
2815
- }
2816
- ensureMotionBlurProgram() {
2817
- if (this.motionBlurProgram)
2818
- return this.motionBlurProgram;
2819
- this.motionBlurProgram = this.createFullscreenProgram(`#version 300 es
2820
- precision highp float;
2821
- precision highp int;
2822
- uniform sampler2D u_source;
2823
- uniform sampler2D u_velocity;
2824
- uniform bool u_velocityUv;
2825
- uniform ivec2 u_size;
2826
- uniform int u_samples;
2827
- uniform float u_scale;
2828
- out vec4 outColor;
2829
-
2830
- void main() {
2831
- ivec2 pixel = ivec2(gl_FragCoord.xy);
2832
- vec4 source = texelFetch(u_source, pixel, 0);
2833
- vec2 velocity = texelFetch(u_velocity, pixel, 0).rg * u_scale;
2834
- if (u_velocityUv) velocity *= vec2(u_size);
2835
- velocity = clamp(velocity, vec2(-64.0), vec2(64.0));
2836
- if (length(velocity) < 0.01) {
2837
- outColor = source;
2838
- return;
2839
- }
2840
- vec3 sum = vec3(0.0);
2841
- for (int sampleIndex = 0; sampleIndex < 16; sampleIndex += 1) {
2842
- if (sampleIndex >= u_samples) continue;
2843
- float t = float(sampleIndex) / float(u_samples - 1) - 0.5;
2844
- ivec2 samplePixel = ivec2(floor(vec2(pixel) - velocity * t + vec2(0.5)));
2845
- samplePixel = clamp(samplePixel, ivec2(0), u_size - ivec2(1));
2846
- sum += texelFetch(u_source, samplePixel, 0).rgb;
2847
- }
2848
- outColor = vec4(sum / float(u_samples), source.a);
2849
- }
2850
- `, "webgl2-motion-blur");
2851
- return this.motionBlurProgram;
2852
- }
2853
- ensureTaaProgram() {
2854
- if (this.taaProgram)
2855
- return this.taaProgram;
2856
- this.taaProgram = this.createFullscreenProgram(`#version 300 es
2857
- precision highp float;
2858
- uniform sampler2D u_source;
2859
- uniform sampler2D u_history;
2860
- uniform sampler2D u_velocity;
2861
- uniform float u_blend;
2862
- uniform bool u_temporal;
2863
- out vec4 outColor;
2864
- vec4 cubicWeights(float f) {
2865
- float f2=f*f, f3=f2*f;
2866
- return vec4(-0.5*f+f2-0.5*f3,1.0-2.5*f2+1.5*f3,0.5*f+2.0*f2-1.5*f3,-0.5*f2+0.5*f3);
2867
- }
2868
- vec4 historyAt(vec2 uv) {
2869
- ivec2 size=textureSize(u_history,0);
2870
- vec2 position=uv*vec2(size)-0.5;
2871
- ivec2 base=ivec2(floor(position));
2872
- vec4 wx=cubicWeights(fract(position.x)), wy=cubicWeights(fract(position.y));
2873
- vec4 result=vec4(0.0);
2874
- // Repeated bilinear history reconstruction diffuses a moving edge every
2875
- // frame. Cubic reconstruction preserves it; the resolve's current-neighbor
2876
- // clipping below bounds ringing before accumulation.
2877
- for(int y=0;y<4;y++) for(int x=0;x<4;x++) {
2878
- result+=texelFetch(u_history,clamp(base+ivec2(x-1,y-1),ivec2(0),size-1),0)*wx[x]*wy[y];
2879
- }
2880
- return result;
2881
- }
2882
-
2883
- void main() {
2884
- ivec2 pixel = ivec2(gl_FragCoord.xy);
2885
- ivec2 size = textureSize(u_source, 0);
2886
- vec2 outputUV=(vec2(pixel)+0.5)/vec2(size);
2887
- // Raster jitter supplies quadrature samples inside the output pixel.
2888
- // Keep that sample on its pixel's accumulation grid; undoing the jitter
2889
- // spatially filters it and defeats temporal coverage integration.
2890
- vec2 sourceUV=outputUV;
2891
- ivec2 sourcePixel=clamp(ivec2(floor(sourceUV*vec2(size))),ivec2(0),size-1);
2892
- // Reconstruct current color on the stable output grid before accumulation.
2893
- vec4 source = texelFetch(u_source, pixel, 0);
2894
- vec4 motion = u_temporal ? texelFetch(u_velocity, sourcePixel, 0) : vec4(0.0);
2895
- // A currently uncovered sample may still carry integrated foreground
2896
- // coverage in history. Track nearby foreground motion for that coverage,
2897
- // but retain this pixel's own current/previous depth tags: copying RGBA
2898
- // wholesale falsely labels background color as a foreground surface.
2899
- if (u_temporal) {
2900
- float nearestDepth=motion.b;
2901
- for(int y=-1;y<=1;y++) for(int x=-1;x<=1;x++) {
2902
- vec4 candidate=texelFetch(u_velocity,clamp(pixel+ivec2(x,y),ivec2(0),size-1),0);
2903
- if(candidate.b<nearestDepth) {nearestDepth=candidate.b;motion.xy=candidate.xy;}
2904
- }
2905
- }
2906
- vec2 previousUV = outputUV-motion.xy;
2907
- vec4 history = u_temporal ? historyAt(previousUV) : texture(u_history, previousUV);
2908
- float weight = u_blend;
2909
- if (u_temporal) {
2910
- // Reprojected history incurs reconstruction error as the footprint moves
2911
- // across the pixel grid. Reduce its confidence with displacement instead
2912
- // of repeatedly giving a softened moving edge the stationary .9 weight.
2913
- // Physical motion itself remains fully represented in previousUV.
2914
- weight /= 1.0 + length(motion.xy * vec2(size));
2915
- // Depth is categorical at a silhouette: bilinear alpha interpolation creates
2916
- // nonexistent surfaces and rejects valid history on every jittered edge.
2917
- // Test surface presence in the central history footprint. RGB remains
2918
- // an integrated coverage value reconstructed from the wider cubic kernel.
2919
- ivec2 previousBase=ivec2(floor(previousUV*vec2(size)-vec2(0.5)));
2920
- float depthError=1.0;
2921
- for(int y=0;y<2;y++) for(int x=0;x<2;x++) {
2922
- float previousDepth=texelFetch(u_history,clamp(previousBase+ivec2(x,y),ivec2(0),size-1),0).a;
2923
- depthError=min(depthError,abs(previousDepth-motion.a));
2924
- }
2925
- if (any(lessThan(previousUV,vec2(0.0))) || any(greaterThanEqual(previousUV,vec2(1.0))) || depthError>0.002) weight=0.0;
2926
- vec3 lo=source.rgb, hi=source.rgb;
2927
- for(int y=-1;y<=1;y++) for(int x=-1;x<=1;x++) { vec3 tap=texelFetch(u_source,clamp(pixel+ivec2(x,y),ivec2(0),size-1),0).rgb; lo=min(lo,tap); hi=max(hi,tap); }
2928
- history.rgb=clamp(history.rgb,lo,hi);
2929
- }
2930
- vec3 resolved=mix(source.rgb,history.rgb,weight);
2931
- outColor=vec4(resolved,u_temporal?motion.b:source.a);
2932
- }
2933
- `, "webgl2-taa-accumulation");
2934
- return this.taaProgram;
2935
- }
2936
- ensureTaaPresentationProgram() {
2937
- if (this.taaPresentationProgram)
2938
- return this.taaPresentationProgram;
2939
- this.taaPresentationProgram = this.createFullscreenProgram(`#version 300 es
2940
- precision highp float;
2941
- uniform sampler2D u_source;
2942
- uniform sampler2D u_accumulated;
2943
- out vec4 outColor;
2944
- void main() {
2945
- ivec2 pixel=ivec2(gl_FragCoord.xy);
2946
- ivec2 size=textureSize(u_source,0);
2947
- vec4 source=texelFetch(u_source,pixel,0);
2948
- vec3 accumulated=texelFetch(u_accumulated,pixel,0).rgb;
2949
- // Retained native pixels isolate the remaining spatial excess to the
2950
- // horizontally moving silhouette. Apply a bounded three-tap unsharp resolve
2951
- // to presentation only; accumulated history remains immutable.
2952
- vec3 center=mix(source.rgb,accumulated,0.90);
2953
- ivec2 leftPixel=clamp(pixel+ivec2(-1,0),ivec2(0),size-1);
2954
- ivec2 rightPixel=clamp(pixel+ivec2(1,0),ivec2(0),size-1);
2955
- vec3 left=mix(texelFetch(u_source,leftPixel,0).rgb,texelFetch(u_accumulated,leftPixel,0).rgb,0.90);
2956
- vec3 right=mix(texelFetch(u_source,rightPixel,0).rgb,texelFetch(u_accumulated,rightPixel,0).rgb,0.90);
2957
- outColor=vec4(clamp(center*1.04-(left+right)*0.02,0.0,1.0),source.a);
2958
- }
2959
- `, "webgl2-taa-presentation");
2960
- return this.taaPresentationProgram;
2961
- }
2962
- createFullscreenProgram(fragmentSource, label) {
2963
- const vertex = this.compileShader(this.gl.VERTEX_SHADER, `#version 300 es
2964
- precision highp float;
2965
- void main() {
2966
- vec2 position = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
2967
- gl_Position = vec4(position * 2.0 - 1.0, 0.0, 1.0);
2968
- }
2969
- `, label);
2970
- const fragment = this.compileShader(this.gl.FRAGMENT_SHADER, fragmentSource, label);
2971
- const program = this.gl.createProgram();
2972
- if (!program) {
2973
- this.gl.deleteShader(vertex);
2974
- this.gl.deleteShader(fragment);
2975
- throw new RenderDeviceError("Failed to allocate WebGL2 fullscreen shader program", "WEBGL_ALLOCATION_FAILED", { label });
2976
- }
2977
- this.gl.attachShader(program, vertex);
2978
- this.gl.attachShader(program, fragment);
2979
- this.gl.linkProgram(program);
2980
- this.gl.deleteShader(vertex);
2981
- this.gl.deleteShader(fragment);
2982
- if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
2983
- const log = this.gl.getProgramInfoLog(program) ?? "Unknown fullscreen shader link error";
2984
- this.gl.deleteProgram(program);
2985
- throw new RenderDeviceError("WebGL2 fullscreen shader link failed", "SHADER_LINK_FAILED", { label, log });
2986
- }
2987
- return program;
2988
- }
2989
- ensureLdrPostprocessProgram() {
2990
- if (this.ldrPostprocessProgram) {
2991
- return this.ldrPostprocessProgram;
2992
- }
2993
- const vertex = this.compileShader(this.gl.VERTEX_SHADER, `#version 300 es
2994
- precision highp float;
2995
- out vec2 v_uv;
2996
- void main() {
2997
- vec2 position = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
2998
- v_uv = position;
2999
- gl_Position = vec4(position * 2.0 - 1.0, 0.0, 1.0);
3000
- }
3001
- `, "webgl2-ldr-postprocess");
3002
- const fragment = this.compileShader(this.gl.FRAGMENT_SHADER, `#version 300 es
3003
- precision highp float;
3004
- uniform sampler2D u_source;
3005
- uniform vec2 u_texelSize;
3006
- uniform int u_hasToneMapping;
3007
- uniform int u_toneOperator;
3008
- uniform int u_inputColorSpace;
3009
- uniform int u_outputColorSpace;
3010
- uniform float u_exposure;
3011
- uniform float u_whitePoint;
3012
- uniform float u_gamma;
3013
- uniform int u_hasColorGrade;
3014
- uniform float u_contrast;
3015
- uniform float u_temperature;
3016
- uniform float u_tint;
3017
- uniform float u_saturation;
3018
- uniform float u_vibrance;
3019
- uniform float u_vignette;
3020
- uniform float u_sharpening;
3021
- uniform int u_hasFxaa;
3022
- uniform float u_edgeThreshold;
3023
- uniform float u_subpixelBlend;
3024
- in vec2 v_uv;
3025
- out vec4 outColor;
3026
-
3027
- float srgbToLinear(float value) {
3028
- return value <= 0.04045 ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4);
3029
- }
3030
-
3031
- float linearToSrgb(float value) {
3032
- return value <= 0.0031308 ? value * 12.92 : 1.055 * pow(value, 1.0 / 2.4) - 0.055;
3033
- }
3034
-
3035
- vec3 decodeColor(vec3 color) {
3036
- return u_inputColorSpace == 1 ? vec3(srgbToLinear(color.r), srgbToLinear(color.g), srgbToLinear(color.b)) : color;
3037
- }
3038
-
3039
- vec3 encodeColor(vec3 color) {
3040
- vec3 linear = clamp(color, 0.0, 1.0);
3041
- return u_outputColorSpace == 1 ? vec3(linearToSrgb(linear.r), linearToSrgb(linear.g), linearToSrgb(linear.b)) : linear;
3042
- }
3043
-
3044
- vec3 acesRrtAndOdtFit(vec3 value) {
3045
- vec3 numerator = value * (value + 0.0245786) - 0.000090537;
3046
- vec3 denominator = value * (0.983729 * value + 0.4329510) + 0.238081;
3047
- return numerator / denominator;
3048
- }
3049
-
3050
- vec3 acesFilmic(vec3 color) {
3051
- // Match current Three.js ACESFilmicToneMapping. ACES is a coupled RGB
3052
- // transform; a scalar approximation shifts hue and washes saturated colors.
3053
- const mat3 acesInput = mat3(
3054
- vec3(0.59719, 0.07600, 0.02840),
3055
- vec3(0.35458, 0.90834, 0.13383),
3056
- vec3(0.04823, 0.01566, 0.83777)
3057
- );
3058
- const mat3 acesOutput = mat3(
3059
- vec3(1.60475, -0.10208, -0.00327),
3060
- vec3(-0.53108, 1.10813, -0.07276),
3061
- vec3(-0.07367, -0.00605, 1.07602)
3062
- );
3063
- vec3 acesColor = acesInput * (color / 0.6);
3064
- acesColor = acesRrtAndOdtFit(acesColor);
3065
- return clamp(acesOutput * acesColor, 0.0, 1.0);
3066
- }
3067
-
3068
- float filmic(float value) {
3069
- float x = max(0.0, value);
3070
- float toe = max(0.0, x - 0.004);
3071
- float curve = (toe * (6.2 * toe + 0.5)) / (toe * (6.2 * toe + 1.7) + 0.06);
3072
- return min(curve, x * 1.08);
3073
- }
3074
-
3075
- float uncharted2(float value) {
3076
- float a = 0.15;
3077
- float b = 0.5;
3078
- float c = 0.1;
3079
- float d = 0.2;
3080
- float e = 0.02;
3081
- float f = 0.3;
3082
- float w = 11.2;
3083
- float x = value * 2.0;
3084
- float curve = ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
3085
- float wx = w;
3086
- float white = ((wx * (a * wx + c * b) + d * e) / (wx * (a * wx + b) + d * f)) - e / f;
3087
- return clamp(curve / white, 0.0, 1.0);
3088
- }
3089
-
3090
- float agx(float value) {
3091
- float x = max(0.0, value);
3092
- float encoded = log2(1.0 + x) / log2(17.0);
3093
- return clamp(encoded * encoded * (3.0 - 2.0 * encoded), 0.0, 1.0);
3094
- }
3095
-
3096
- float neutral(float value) {
3097
- float x = max(0.0, value);
3098
- return min(1.0, (x * (1.0 + x / 7.5)) / (1.0 + x));
3099
- }
3100
-
3101
- float toneMapChannel(float value) {
3102
- float exposed = max(0.0, value * u_exposure) / max(0.0001, u_whitePoint);
3103
- if (u_toneOperator == 0) return min(1.0, exposed);
3104
- if (u_toneOperator == 1) return exposed / (1.0 + exposed);
3105
- if (u_toneOperator == 2) return exposed;
3106
- if (u_toneOperator == 3) return filmic(exposed);
3107
- if (u_toneOperator == 4) return uncharted2(exposed);
3108
- if (u_toneOperator == 5) return agx(exposed);
3109
- return neutral(exposed);
3110
- }
3111
-
3112
- vec3 applyToneMapping(vec3 color) {
3113
- if (u_hasToneMapping == 0) return color;
3114
- vec3 decoded = decodeColor(color);
3115
- vec3 mapped = u_toneOperator == 2
3116
- ? acesFilmic(max(vec3(0.0), decoded * u_exposure) / max(0.0001, u_whitePoint))
3117
- : vec3(toneMapChannel(decoded.r), toneMapChannel(decoded.g), toneMapChannel(decoded.b));
3118
- return encodeColor(mapped);
3119
- }
3120
-
3121
- vec3 applyColorGrade(vec3 color, vec2 uv) {
3122
- if (u_hasColorGrade == 0) return color;
3123
- float contrastOffset = 0.5 - 0.5 * u_contrast;
3124
- float redShift = u_temperature * 0.08 - u_tint * 0.02;
3125
- float greenShift = u_tint * 0.06;
3126
- float blueShift = -u_temperature * 0.08 - u_tint * 0.02;
3127
- float luma = dot(color, vec3(0.2126, 0.7152, 0.0722));
3128
- vec3 graded = color * u_contrast + vec3(contrastOffset + redShift, contrastOffset + greenShift, contrastOffset + blueShift);
3129
- float distanceFromLuma = min(1.0, abs(graded.r - luma) + abs(graded.g - luma) + abs(graded.b - luma));
3130
- float vibranceBoost = u_vibrance == 0.0 ? 0.0 : u_vibrance * (1.0 - distanceFromLuma);
3131
- float saturation = u_saturation + vibranceBoost;
3132
- graded = vec3(luma) + (graded - vec3(luma)) * saturation;
3133
- vec2 centered = uv * 2.0 - 1.0;
3134
- float vignette = 1.0 - u_vignette * clamp((length(centered) - 0.28) / 1.12, 0.0, 1.0);
3135
- return clamp(graded * vignette, 0.0, 1.0);
3136
- }
3137
-
3138
- vec3 baseColorAt(vec2 uv) {
3139
- vec2 clampedUv = clamp(uv, vec2(0.0), vec2(1.0));
3140
- vec3 color = texture(u_source, clampedUv).rgb;
3141
- return applyColorGrade(applyToneMapping(color), clampedUv);
3142
- }
3143
-
3144
- vec3 finalColorAt(vec2 uv) {
3145
- vec3 center = baseColorAt(uv);
3146
- if (u_hasColorGrade == 0 || u_sharpening <= 0.0) return center;
3147
- vec3 blur = (
3148
- baseColorAt(uv + vec2(-u_texelSize.x, 0.0)) +
3149
- baseColorAt(uv + vec2(u_texelSize.x, 0.0)) +
3150
- baseColorAt(uv + vec2(0.0, -u_texelSize.y)) +
3151
- baseColorAt(uv + vec2(0.0, u_texelSize.y))
3152
- ) * 0.25;
3153
- return clamp(center + (center - blur) * u_sharpening, 0.0, 1.0);
3154
- }
3155
-
3156
- float luma(vec3 color) {
3157
- return dot(color, vec3(0.2126, 0.7152, 0.0722));
3158
- }
3159
-
3160
- void main() {
3161
- vec3 center = finalColorAt(v_uv);
3162
- float alpha = texture(u_source, clamp(v_uv, vec2(0.0), vec2(1.0))).a;
3163
- if (u_hasFxaa == 0) {
3164
- outColor = vec4(center, alpha);
3165
- return;
3166
- }
3167
- vec3 north = finalColorAt(v_uv + vec2(0.0, -u_texelSize.y));
3168
- vec3 south = finalColorAt(v_uv + vec2(0.0, u_texelSize.y));
3169
- vec3 west = finalColorAt(v_uv + vec2(-u_texelSize.x, 0.0));
3170
- vec3 east = finalColorAt(v_uv + vec2(u_texelSize.x, 0.0));
3171
- float centerLuma = luma(center);
3172
- float minLuma = min(centerLuma, min(min(luma(north), luma(south)), min(luma(west), luma(east))));
3173
- float maxLuma = max(centerLuma, max(max(luma(north), luma(south)), max(luma(west), luma(east))));
3174
- if (maxLuma - minLuma < u_edgeThreshold) {
3175
- outColor = vec4(center, alpha);
3176
- return;
3177
- }
3178
- vec3 average = (north + south + west + east) * 0.25;
3179
- outColor = vec4(mix(center, average, clamp(u_subpixelBlend, 0.0, 1.0)), alpha);
3180
- }
3181
- `, "webgl2-ldr-postprocess");
3182
- const program = this.gl.createProgram();
3183
- if (!program) {
3184
- this.gl.deleteShader(vertex);
3185
- this.gl.deleteShader(fragment);
3186
- throw new RenderDeviceError("Failed to allocate WebGL2 LDR postprocess shader", "WEBGL_ALLOCATION_FAILED");
3187
- }
3188
- this.gl.attachShader(program, vertex);
3189
- this.gl.attachShader(program, fragment);
3190
- this.gl.linkProgram(program);
3191
- this.gl.deleteShader(vertex);
3192
- this.gl.deleteShader(fragment);
3193
- if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
3194
- const log = this.gl.getProgramInfoLog(program) ?? "Unknown LDR postprocess shader link error";
3195
- this.gl.deleteProgram(program);
3196
- throw new RenderDeviceError("WebGL2 LDR postprocess shader link failed", "SHADER_LINK_FAILED", { log });
3197
- }
3198
- this.ldrPostprocessProgram = program;
3199
- return program;
3200
- }
3201
- compileShader(type, source, label) {
3202
- const shader = this.gl.createShader(type);
3203
- if (!shader) {
3204
- throw new RenderDeviceError("Failed to allocate WebGL shader", "WEBGL_ALLOCATION_FAILED", { label });
3205
- }
3206
- this.gl.shaderSource(shader, source);
3207
- this.gl.compileShader(shader);
3208
- if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
3209
- const log = this.gl.getShaderInfoLog(shader) ?? "Unknown shader compile error";
3210
- this.gl.deleteShader(shader);
3211
- throw new RenderDeviceError("WebGL shader compile failed", "SHADER_COMPILE_FAILED", { label, log });
3212
- }
3213
- return shader;
3214
- }
3215
- reflectProgram(program) {
3216
- const attributes = new Map();
3217
- const uniforms = new Set();
3218
- const attributeDetails = new Map();
3219
- const uniformDetails = new Map();
3220
- const activeAttributes = this.gl.getProgramParameter(program, this.gl.ACTIVE_ATTRIBUTES);
3221
- const activeUniforms = this.gl.getProgramParameter(program, this.gl.ACTIVE_UNIFORMS);
3222
- for (let i = 0; i < activeAttributes; i += 1) {
3223
- const info = this.gl.getActiveAttrib(program, i);
3224
- if (info) {
3225
- const location = this.gl.getAttribLocation(program, info.name);
3226
- attributes.set(info.name, location);
3227
- attributeDetails.set(info.name, { name: info.name, type: String(info.type), location, source: "vertex", line: 0 });
3228
- }
3229
- }
3230
- for (let i = 0; i < activeUniforms; i += 1) {
3231
- const info = this.gl.getActiveUniform(program, i);
3232
- if (info) {
3233
- const name = info.name.replace(/\[0\]$/, "");
3234
- uniforms.add(name);
3235
- uniformDetails.set(name, { name, type: String(info.type), arraySize: info.size > 1 ? info.size : null, source: "fragment", line: 0 });
3236
- }
3237
- }
3238
- return { attributes, uniforms, attributeDetails, uniformDetails };
3239
- }
3240
- uploadUniforms(shader, uniforms) {
3241
- let textureUnit = 0;
3242
- for (const [name, value] of uniforms) {
3243
- if (!shader.reflection.uniforms.has(name)) {
3244
- continue;
3245
- }
3246
- const location = this.getUniformLocation(shader, name);
3247
- if (location === null) {
3248
- throw new RenderDeviceError("Material tried to bind a missing shader uniform", "MISSING_UNIFORM", { name });
3249
- }
3250
- if (isTextureBinding(value)) {
3251
- this.uploadTextureUniform(location, value, textureUnit);
3252
- textureUnit += 1;
3253
- }
3254
- else if (typeof value === "number") {
3255
- this.gl.uniform1f(location, value);
3256
- }
3257
- else if (Array.isArray(value) || ArrayBuffer.isView(value)) {
3258
- const length = value.length;
3259
- const floatData = value;
3260
- if (length === 16 || (length > 16 && length % 16 === 0 && /(?:Matrix|Matrices)$/.test(name))) {
3261
- this.gl.uniformMatrix4fv(location, false, floatData);
3262
- }
3263
- else if (length > 16 && length % 4 === 0) {
3264
- this.gl.uniform4fv(location, floatData);
3265
- }
3266
- else if (length === 4) {
3267
- this.gl.uniform4fv(location, floatData);
3268
- }
3269
- else if (length === 3) {
3270
- this.gl.uniform3fv(location, floatData);
3271
- }
3272
- else if (length === 2) {
3273
- this.gl.uniform2fv(location, floatData);
3274
- }
3275
- else {
3276
- throw new RenderDeviceError("Unsupported uniform array length", "UNSUPPORTED_UNIFORM", { name, length });
3277
- }
3278
- }
3279
- else {
3280
- throw new RenderDeviceError("Unsupported uniform value", "UNSUPPORTED_UNIFORM", { name, valueType: typeof value });
3281
- }
3282
- if (this.errorCheckMode === "strict") {
3283
- const uniformError = this.readError();
3284
- if (uniformError) {
3285
- throw new RenderDeviceError(`WebGL2 uniform upload failed for ${name}: ${uniformError}`, "WEBGL_DRAW_FAILED", {
3286
- name,
3287
- stage: "uniform",
3288
- error: uniformError
3289
- });
3290
- }
3291
- }
3292
- }
3293
- }
3294
- getUniformLocation(shader, name) {
3295
- let cache = this.uniformLocationCache.get(shader);
3296
- if (!cache) {
3297
- cache = new Map();
3298
- this.uniformLocationCache.set(shader, cache);
3299
- }
3300
- if (!cache.has(name)) {
3301
- this.uniformLocationLookupCount += 1;
3302
- cache.set(name, this.gl.getUniformLocation(shader.handle, name) ?? this.gl.getUniformLocation(shader.handle, `${name}[0]`));
3303
- }
3304
- return cache.get(name) ?? null;
3305
- }
3306
- uploadTextureUniform(location, binding, textureUnit) {
3307
- const validation = binding.validate();
3308
- if (!validation.ok) {
3309
- throw new RenderDeviceError("Texture binding validation failed", "INVALID_TEXTURE_BINDING", {
3310
- diagnostics: validation.diagnostics,
3311
- name: binding.name
3312
- });
3313
- }
3314
- this.activateTextureUnit(textureUnit);
3315
- const dimension = binding.texture?.dimension ?? (binding.name.toLowerCase().includes("cubemap") || binding.name.toLowerCase().includes("cube") ? "cube" : "2d");
3316
- const target = dimension === "cube" ? this.gl.TEXTURE_CUBE_MAP : this.gl.TEXTURE_2D;
3317
- const handle = binding.texture ? this.getTextureHandle(binding.texture) : dimension === "cube" ? this.getFallbackCubeTextureHandle() : this.getFallbackTextureHandle();
3318
- if (binding.texture) {
3319
- const lowerName = binding.name.toLowerCase();
3320
- if (lowerName.includes("environment"))
3321
- this.nativeEnvironmentBindings += 1;
3322
- if (lowerName.includes("shadow"))
3323
- this.nativeShadowMapBindings += 1;
3324
- }
3325
- this.bindTextureForUnit(textureUnit, target, handle);
3326
- const samplerHandle = this.getSamplerHandle(binding.sampler, target);
3327
- this.stateCache.bindSampler(textureUnit, samplerHandle, () => this.gl.bindSampler(textureUnit, samplerHandle));
3328
- this.gl.uniform1i(location, textureUnit);
3329
- }
3330
- activateTextureUnit(textureUnit) {
3331
- if (this.activeTextureUnitIndex === textureUnit)
3332
- return;
3333
- this.stateCache.activeTexture(textureUnit, () => this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit));
3334
- this.activeTextureUnitIndex = textureUnit;
3335
- }
3336
- bindTextureForUnit(textureUnit, target, handle) {
3337
- const key = `${textureUnit}:${target}`;
3338
- if (this.textureUnitBindings.get(key) === handle)
3339
- return;
3340
- this.stateCache.bindTexture(target, handle, () => this.gl.bindTexture(target, handle));
3341
- this.textureUnitBindings.set(key, handle);
3342
- this.textureBindCount += 1;
3343
- }
3344
- setTextureParameterIfNeeded(handle, target, parameter, value) {
3345
- let parameters = this.textureSamplerParameterCache.get(handle);
3346
- if (!parameters) {
3347
- parameters = new Map();
3348
- this.textureSamplerParameterCache.set(handle, parameters);
3349
- }
3350
- if (parameters.get(parameter) === value)
3351
- return;
3352
- this.gl.texParameteri(target, parameter, value);
3353
- parameters.set(parameter, value);
3354
- this.samplerParameterUploadCount += 1;
3355
- }
3356
- applySamplerAnisotropy(maxAnisotropy, target = this.gl.TEXTURE_2D) {
3357
- if (maxAnisotropy <= 1)
3358
- return;
3359
- if (!this.anisotropicFilteringExtension)
3360
- return;
3361
- this.gl.texParameterf(target, this.anisotropicFilteringExtension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(Math.max(1, maxAnisotropy), this.maxTextureAnisotropy));
3362
- this.samplerAnisotropyUploadCount += 1;
3363
- }
3364
- getSamplerHandle(sampler, target) {
3365
- const key = this.samplerKey(sampler, target);
3366
- const cached = this.samplerObjectCache.get(key);
3367
- if (cached)
3368
- return cached;
3369
- const handle = this.gl.createSampler();
3370
- if (!handle) {
3371
- throw new RenderDeviceError("Failed to allocate WebGL sampler", "WEBGL_ALLOCATION_FAILED");
3372
- }
3373
- this.gl.samplerParameteri(handle, this.gl.TEXTURE_MIN_FILTER, this.minFilter(sampler.minFilter));
3374
- this.gl.samplerParameteri(handle, this.gl.TEXTURE_MAG_FILTER, this.magFilter(sampler.magFilter));
3375
- this.gl.samplerParameteri(handle, this.gl.TEXTURE_WRAP_S, this.addressMode(sampler.addressU));
3376
- this.gl.samplerParameteri(handle, this.gl.TEXTURE_WRAP_T, this.addressMode(sampler.addressV));
3377
- this.samplerParameterUploadCount += 4;
3378
- if (target === this.gl.TEXTURE_CUBE_MAP) {
3379
- this.gl.samplerParameteri(handle, this.gl.TEXTURE_WRAP_R, this.addressMode(sampler.addressV));
3380
- this.samplerParameterUploadCount += 1;
3381
- }
3382
- if (sampler.maxAnisotropy > 1 && this.anisotropicFilteringExtension) {
3383
- this.gl.samplerParameterf(handle, this.anisotropicFilteringExtension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(Math.max(1, sampler.maxAnisotropy), this.maxTextureAnisotropy));
3384
- this.samplerAnisotropyUploadCount += 1;
3385
- }
3386
- this.samplerObjectCache.set(key, handle);
3387
- return handle;
3388
- }
3389
- samplerKey(sampler, target) {
3390
- return [
3391
- sampler.minFilter,
3392
- sampler.magFilter,
3393
- sampler.addressU,
3394
- sampler.addressV,
3395
- sampler.maxAnisotropy,
3396
- target === this.gl.TEXTURE_CUBE_MAP ? "cube" : "2d"
3397
- ].join("|");
3398
- }
3399
- getFallbackTextureHandle() {
3400
- if (this.fallbackTexture) {
3401
- return this.fallbackTexture;
3402
- }
3403
- const handle = this.gl.createTexture();
3404
- if (!handle) {
3405
- throw new RenderDeviceError("Failed to allocate WebGL fallback texture", "WEBGL_ALLOCATION_FAILED");
3406
- }
3407
- this.stateCache.invalidate();
3408
- this.gl.bindTexture(this.gl.TEXTURE_2D, handle);
3409
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
3410
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
3411
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
3412
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
3413
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, 1, 1, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 255, 255]));
3414
- this.fallbackTexture = handle;
3415
- return handle;
3416
- }
3417
- getFallbackCubeTextureHandle() {
3418
- if (this.fallbackCubeTexture) {
3419
- return this.fallbackCubeTexture;
3420
- }
3421
- const handle = this.gl.createTexture();
3422
- if (!handle) {
3423
- throw new RenderDeviceError("Failed to allocate WebGL fallback cube texture", "WEBGL_ALLOCATION_FAILED");
3424
- }
3425
- this.stateCache.invalidate();
3426
- this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, handle);
3427
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
3428
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
3429
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
3430
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
3431
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_R, this.gl.CLAMP_TO_EDGE);
3432
- const pixel = new Uint8Array([255, 255, 255, 255]);
3433
- for (const face of WEBGL_CUBE_FACES) {
3434
- this.gl.texImage2D(this.cubeFaceTarget(face), 0, this.gl.RGBA, 1, 1, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pixel);
3435
- }
3436
- this.fallbackCubeTexture = handle;
3437
- return handle;
3438
- }
3439
- getTextureHandle(texture) {
3440
- this.releaseDisposedTextureHandles();
3441
- if (texture.disposed) {
3442
- throw new RenderDeviceError("Texture is disposed", "DISPOSED_RESOURCE", { label: texture.label });
3443
- }
3444
- const cached = this.textures.get(texture);
3445
- if (cached) {
3446
- return cached;
3447
- }
3448
- const handle = this.gl.createTexture();
3449
- if (!handle) {
3450
- throw new RenderDeviceError("Failed to allocate WebGL texture", "WEBGL_ALLOCATION_FAILED", { label: texture.label });
3451
- }
3452
- this.stateCache.invalidate();
3453
- this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false);
3454
- this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
3455
- this.gl.pixelStorei(this.gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, this.gl.NONE);
3456
- if (texture.dimension === "cube") {
3457
- this.uploadCubeTexture(texture, handle);
3458
- this.textureUploadModes.set(texture, "cube");
3459
- this.textures.set(texture, handle);
3460
- return handle;
3461
- }
3462
- this.gl.bindTexture(this.gl.TEXTURE_2D, handle);
3463
- if (isCompressedTextureFormat(texture.format)) {
3464
- const compressed = this.resolveCompressedTextureFormat(texture.format);
3465
- if (compressed) {
3466
- const uploadLevels = completeUploadLevels(texture.textureLevels);
3467
- for (const [levelIndex, level] of uploadLevels.entries()) {
3468
- this.gl.compressedTexImage2D(this.gl.TEXTURE_2D, levelIndex, compressed.internalFormat, level.width, level.height, 0, level.data);
3469
- }
3470
- const compressedUploadError = this.readError();
3471
- if (!compressedUploadError) {
3472
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_BASE_LEVEL, 0);
3473
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAX_LEVEL, uploadLevels.length - 1);
3474
- this.textureUploadModes.set(texture, "compressed");
3475
- this.textures.set(texture, handle);
3476
- return handle;
3477
- }
3478
- }
3479
- const fallbackLevels = completeUploadLevels(texture.fallbackTextureLevels);
3480
- if (fallbackLevels.length === 0) {
3481
- this.gl.deleteTexture(handle);
3482
- throw new RenderDeviceError("Compressed texture format is not supported and no RGBA8 fallback data was provided", "COMPRESSED_TEXTURE_UNSUPPORTED", {
3483
- label: texture.label,
3484
- format: texture.format
3485
- });
3486
- }
3487
- this.uploadRgba8FallbackTexture(texture, fallbackLevels);
3488
- this.textureUploadModes.set(texture, "fallback");
3489
- this.textures.set(texture, handle);
3490
- return handle;
3491
- }
3492
- if (texture.format === "depth24") {
3493
- throw new RenderDeviceError("Depth textures cannot be uploaded to WebGL2 color samplers", "UNSUPPORTED_TEXTURE_FORMAT", {
3494
- label: texture.label,
3495
- format: texture.format
3496
- });
3497
- }
3498
- if (texture.source) {
3499
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.rgba8TextureInternalFormat(texture), this.gl.RGBA, this.gl.UNSIGNED_BYTE, texture.source);
3500
- this.gl.generateMipmap(this.gl.TEXTURE_2D);
3501
- }
3502
- else if (texture.mipLevels.length > 0) {
3503
- const uploadFormat = this.textureUploadFormat(texture);
3504
- const uploadLevels = completeUploadLevels(texture.textureLevels);
3505
- for (const [levelIndex, level] of uploadLevels.entries()) {
3506
- this.gl.texImage2D(this.gl.TEXTURE_2D, levelIndex, uploadFormat.internalFormat, level.width, level.height, 0, uploadFormat.format, uploadFormat.type, texturePixelUploadData(level.data, texture.format));
3507
- }
3508
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_BASE_LEVEL, 0);
3509
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAX_LEVEL, uploadLevels.length - 1);
3510
- }
3511
- else {
3512
- const uploadFormat = this.textureUploadFormat(texture);
3513
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, uploadFormat.internalFormat, texture.width, texture.height, 0, uploadFormat.format, uploadFormat.type, texture.data ? texturePixelUploadData(texture.data, texture.format) : null);
3514
- // Float colour formats are not guaranteed mipmap-filterable in WebGL2:
3515
- // RGBA32F/RGBA16F are only linear-filterable with OES_texture_float_linear, and
3516
- // generateMipmap on a non-filterable format raises INVALID_OPERATION. Data
3517
- // textures such as joint palettes are point-sampled with texelFetch and never
3518
- // need mips, so skip generation and pin the level range instead.
3519
- if (isFloatColorTextureFormat(texture.format)) {
3520
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_BASE_LEVEL, 0);
3521
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAX_LEVEL, 0);
3522
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
3523
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
3524
- }
3525
- else {
3526
- this.gl.generateMipmap(this.gl.TEXTURE_2D);
3527
- }
3528
- }
3529
- this.textureUploadModes.set(texture, texture.format);
3530
- this.textures.set(texture, handle);
3531
- return handle;
3532
- }
3533
- uploadCubeTexture(texture, handle) {
3534
- this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, handle);
3535
- const uploadFormat = this.textureUploadFormat(texture);
3536
- for (const face of texture.cubeFaces) {
3537
- const uploadLevels = completeUploadLevels(face.mipLevels);
3538
- for (const [levelIndex, level] of uploadLevels.entries()) {
3539
- this.gl.texImage2D(this.cubeFaceTarget(face.face), levelIndex, uploadFormat.internalFormat, level.width, level.height, 0, uploadFormat.format, uploadFormat.type, texturePixelUploadData(level.data, texture.format));
3540
- }
3541
- }
3542
- const firstFaceLevels = completeUploadLevels(texture.cubeFaces[0]?.mipLevels ?? []);
3543
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_BASE_LEVEL, 0);
3544
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_MAX_LEVEL, Math.max(0, firstFaceLevels.length - 1));
3545
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
3546
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
3547
- this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_R, this.gl.CLAMP_TO_EDGE);
3548
- }
3549
- uploadRgba8FallbackTexture(texture, fallbackLevels) {
3550
- const internalFormat = this.rgba8TextureInternalFormat(texture);
3551
- for (const [levelIndex, level] of fallbackLevels.entries()) {
3552
- this.gl.texImage2D(this.gl.TEXTURE_2D, levelIndex, internalFormat, level.width, level.height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, texturePixelUploadData(level.data, "rgba8"));
3553
- }
3554
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_BASE_LEVEL, 0);
3555
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAX_LEVEL, fallbackLevels.length - 1);
3556
- }
3557
- cubeFaceTarget(face) {
3558
- switch (face) {
3559
- case "px": return this.gl.TEXTURE_CUBE_MAP_POSITIVE_X;
3560
- case "nx": return this.gl.TEXTURE_CUBE_MAP_NEGATIVE_X;
3561
- case "py": return this.gl.TEXTURE_CUBE_MAP_POSITIVE_Y;
3562
- case "ny": return this.gl.TEXTURE_CUBE_MAP_NEGATIVE_Y;
3563
- case "pz": return this.gl.TEXTURE_CUBE_MAP_POSITIVE_Z;
3564
- case "nz": return this.gl.TEXTURE_CUBE_MAP_NEGATIVE_Z;
3565
- }
3566
- }
3567
- rgba8TextureInternalFormat(texture) {
3568
- return texture.colorSpace === "srgb" ? this.gl.SRGB8_ALPHA8 : this.gl.RGBA;
3569
- }
3570
- textureUploadFormat(texture) {
3571
- if (texture.format === "rgba8") {
3572
- return { internalFormat: this.rgba8TextureInternalFormat(texture), format: this.gl.RGBA, type: this.gl.UNSIGNED_BYTE };
3573
- }
3574
- if (texture.colorSpace === "srgb") {
3575
- throw new RenderDeviceError("Floating-point texture uploads must use linear colorSpace", "UNSUPPORTED_TEXTURE_FORMAT", {
3576
- label: texture.label,
3577
- format: texture.format,
3578
- colorSpace: texture.colorSpace
3579
- });
3580
- }
3581
- if (texture.format === "rgba16f") {
3582
- return { internalFormat: this.gl.RGBA16F, format: this.gl.RGBA, type: this.gl.HALF_FLOAT };
3583
- }
3584
- if (texture.format === "rgba32f") {
3585
- return { internalFormat: this.gl.RGBA32F, format: this.gl.RGBA, type: this.gl.FLOAT };
3586
- }
3587
- throw new RenderDeviceError("Unsupported texture upload format", "UNSUPPORTED_TEXTURE_FORMAT", {
3588
- label: texture.label,
3589
- format: texture.format
3590
- });
3591
- }
3592
- resolveRenderTargetFormat(format) {
3593
- if (format === "rgba8") {
3594
- return { internalFormat: this.gl.RGBA, type: this.gl.UNSIGNED_BYTE };
3595
- }
3596
- if (!this.gl.getExtension("EXT_color_buffer_float")) {
3597
- throw new RenderDeviceError("Floating-point color render targets require EXT_color_buffer_float", "HDR_RENDER_TARGET_UNSUPPORTED", { format });
3598
- }
3599
- if (format === "rgba16f") {
3600
- return { internalFormat: this.gl.RGBA16F, type: this.gl.HALF_FLOAT };
3601
- }
3602
- return { internalFormat: this.gl.RGBA32F, type: this.gl.FLOAT };
3603
- }
3604
- releaseDisposedTextureHandles() {
3605
- for (const [texture, handle] of [...this.textures]) {
3606
- if (texture.disposed) {
3607
- this.gl.deleteTexture(handle);
3608
- this.textures.delete(texture);
3609
- this.textureUploadModes.delete(texture);
3610
- this.releasedTextureHandles += 1;
3611
- }
3612
- }
3613
- }
3614
- resolveCompressedTextureFormat(format) {
3615
- switch (format) {
3616
- case "bc1-rgba-unorm": {
3617
- const extension = this.gl.getExtension("WEBGL_compressed_texture_s3tc");
3618
- return extension ? { internalFormat: extension.COMPRESSED_RGBA_S3TC_DXT1_EXT } : null;
3619
- }
3620
- case "bc3-rgba-unorm": {
3621
- const extension = this.gl.getExtension("WEBGL_compressed_texture_s3tc");
3622
- return extension ? { internalFormat: extension.COMPRESSED_RGBA_S3TC_DXT5_EXT } : null;
3623
- }
3624
- case "etc2-rgba8unorm":
3625
- return { internalFormat: 0x9278 };
3626
- case "astc-4x4-rgba-unorm": {
3627
- const extension = this.gl.getExtension("WEBGL_compressed_texture_astc");
3628
- return extension ? { internalFormat: extension.COMPRESSED_RGBA_ASTC_4x4_KHR } : null;
3629
- }
3630
- }
3631
- }
3632
- magFilter(filter) {
3633
- return filter === "nearest" ? this.gl.NEAREST : this.gl.LINEAR;
3634
- }
3635
- minFilter(filter) {
3636
- switch (filter) {
3637
- case "nearest":
3638
- return this.gl.NEAREST;
3639
- case "linear":
3640
- return this.gl.LINEAR;
3641
- case "nearest-mipmap-nearest":
3642
- return this.gl.NEAREST_MIPMAP_NEAREST;
3643
- case "linear-mipmap-nearest":
3644
- return this.gl.LINEAR_MIPMAP_NEAREST;
3645
- case "nearest-mipmap-linear":
3646
- return this.gl.NEAREST_MIPMAP_LINEAR;
3647
- case "linear-mipmap-linear":
3648
- return this.gl.LINEAR_MIPMAP_LINEAR;
3649
- }
3650
- }
3651
- addressMode(mode) {
3652
- if (mode === "repeat")
3653
- return this.gl.REPEAT;
3654
- if (mode === "mirror-repeat")
3655
- return this.gl.MIRRORED_REPEAT;
3656
- return this.gl.CLAMP_TO_EDGE;
3657
- }
3658
- bindVertexFormat(shader, format) {
3659
- const boundLocations = new Set();
3660
- for (const attribute of format.attributes) {
3661
- const location = this.resolveAttributeLocation(shader, attribute);
3662
- if (location < 0) {
3663
- continue;
3664
- }
3665
- if (attribute.type !== "float32") {
3666
- throw new RenderDeviceError("Unsupported vertex attribute type", "UNSUPPORTED_VERTEX_ATTRIBUTE", {
3667
- attribute: attribute.shaderName,
3668
- type: attribute.type
3669
- });
3670
- }
3671
- boundLocations.add(location);
3672
- this.gl.enableVertexAttribArray(location);
3673
- this.gl.vertexAttribDivisor(location, 0);
3674
- this.gl.vertexAttribPointer(location, attribute.components, this.gl.FLOAT, attribute.normalized, format.stride, attribute.offset);
3675
- }
3676
- return boundLocations;
3677
- }
3678
- bindVertexArrayForCommand(command, shader, vertexBuffer) {
3679
- const indexBuffer = command.indexBuffer ? this.requireBuffer(command.indexBuffer) : undefined;
3680
- const key = this.vertexArrayCacheKey(command, shader, vertexBuffer, indexBuffer);
3681
- const cached = this.vertexArrayCache.get(key);
3682
- if (cached) {
3683
- this.stateCache.bindVertexArray(cached.handle, () => this.gl.bindVertexArray(cached.handle));
3684
- return cached;
3685
- }
3686
- const handle = this.gl.createVertexArray();
3687
- if (!handle) {
3688
- throw new RenderDeviceError("Failed to allocate WebGL vertex array", "WEBGL_ALLOCATION_FAILED");
3689
- }
3690
- this.vertexArrayCreateCount += 1;
3691
- this.stateCache.bindVertexArray(handle, () => this.gl.bindVertexArray(handle));
3692
- this.stateCache.bindBuffer(this.gl.ARRAY_BUFFER, vertexBuffer.handle, () => this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexBuffer.handle));
3693
- const boundLocations = this.bindVertexFormat(shader, command.vertexFormat);
3694
- if (command.instanceAttributes && command.instanceAttributes.length > 0) {
3695
- this.bindInstanceAttributes(shader, command.instanceAttributes, boundLocations);
3696
- }
3697
- if (indexBuffer) {
3698
- this.stateCache.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, indexBuffer.handle, () => this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, indexBuffer.handle));
3699
- }
3700
- this.disableUnboundVertexAttributes(boundLocations);
3701
- this.applyDefaultAttributes(shader, boundLocations);
3702
- const entry = { key, handle, boundLocations };
3703
- this.vertexArrayCache.set(key, entry);
3704
- return entry;
3705
- }
3706
- bindNoVertexArray() {
3707
- this.stateCache.bindVertexArray(null, () => this.gl.bindVertexArray(null));
3708
- }
3709
- vertexArrayCacheKey(command, shader, vertexBuffer, indexBuffer) {
3710
- const instanceKey = (command.instanceAttributes ?? []).map((attribute) => {
3711
- const buffer = this.requireBuffer(attribute.buffer);
3712
- return `${attribute.shaderName}:${buffer.id}:${attribute.components}:${attribute.offset}:${attribute.stride}:${attribute.normalized === true ? 1 : 0}:${attribute.divisor ?? 1}`;
3713
- }).join(",");
3714
- return [
3715
- shader.id,
3716
- vertexBuffer.id,
3717
- this.vertexFormatId(command.vertexFormat),
3718
- indexBuffer?.id ?? 0,
3719
- instanceKey
3720
- ].join("|");
3721
- }
3722
- vertexFormatId(format) {
3723
- const existing = this.vertexFormatIds.get(format);
3724
- if (existing !== undefined)
3725
- return existing;
3726
- const next = this.nextVertexFormatId;
3727
- this.nextVertexFormatId += 1;
3728
- this.vertexFormatIds.set(format, next);
3729
- return next;
3730
- }
3731
- bindInstanceAttributes(shader, attributes, boundLocations) {
3732
- for (const attribute of attributes) {
3733
- const location = shader.reflection.attributes.get(attribute.shaderName);
3734
- if (location === undefined || location < 0) {
3735
- continue;
3736
- }
3737
- if (![1, 2, 3, 4].includes(attribute.components)) {
3738
- throw new RenderDeviceError("Instance vertex attribute components must be 1, 2, 3, or 4", "INVALID_DRAW_COMMAND", {
3739
- attribute: attribute.shaderName,
3740
- components: attribute.components
3741
- });
3742
- }
3743
- if (!Number.isInteger(attribute.offset) || attribute.offset < 0 || attribute.offset % 4 !== 0) {
3744
- throw new RenderDeviceError("Instance vertex attribute offset must be non-negative and 4-byte aligned", "INVALID_DRAW_COMMAND", {
3745
- attribute: attribute.shaderName,
3746
- offset: attribute.offset
3747
- });
3748
- }
3749
- if (!Number.isInteger(attribute.stride) || attribute.stride <= 0 || attribute.stride % 4 !== 0) {
3750
- throw new RenderDeviceError("Instance vertex attribute stride must be positive and 4-byte aligned", "INVALID_DRAW_COMMAND", {
3751
- attribute: attribute.shaderName,
3752
- stride: attribute.stride
3753
- });
3754
- }
3755
- if (attribute.offset + attribute.components * 4 > attribute.stride) {
3756
- throw new RenderDeviceError("Instance vertex attribute range must fit inside its stride", "INVALID_DRAW_COMMAND", {
3757
- attribute: attribute.shaderName,
3758
- offset: attribute.offset,
3759
- components: attribute.components,
3760
- stride: attribute.stride
3761
- });
3762
- }
3763
- const buffer = this.requireBuffer(attribute.buffer);
3764
- boundLocations.add(location);
3765
- this.stateCache.bindBuffer(this.gl.ARRAY_BUFFER, buffer.handle, () => this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer.handle));
3766
- this.gl.enableVertexAttribArray(location);
3767
- this.gl.vertexAttribPointer(location, attribute.components, this.gl.FLOAT, attribute.normalized ?? false, attribute.stride, attribute.offset);
3768
- this.gl.vertexAttribDivisor(location, attribute.divisor ?? 1);
3769
- }
3770
- }
3771
- resolveAttributeLocation(shader, attribute) {
3772
- const reflected = shader.reflection.attributes.get(attribute.shaderName);
3773
- if (reflected !== undefined) {
3774
- return reflected;
3775
- }
3776
- return shader.reflection.attributes.get(attribute.semantic) ?? -1;
3777
- }
3778
- applyDefaultAttributes(shader, boundLocations) {
3779
- const colorLocation = shader.reflection.attributes.get("a_color") ?? shader.reflection.attributes.get("color");
3780
- if (colorLocation !== undefined && colorLocation >= 0 && !boundLocations.has(colorLocation)) {
3781
- this.gl.disableVertexAttribArray(colorLocation);
3782
- this.gl.vertexAttribDivisor(colorLocation, 0);
3783
- this.gl.vertexAttrib4f(colorLocation, 1, 1, 1, 1);
3784
- }
3785
- const tangentLocation = shader.reflection.attributes.get("a_tangent") ?? shader.reflection.attributes.get("tangent");
3786
- if (tangentLocation !== undefined && tangentLocation >= 0 && !boundLocations.has(tangentLocation)) {
3787
- this.gl.disableVertexAttribArray(tangentLocation);
3788
- this.gl.vertexAttribDivisor(tangentLocation, 0);
3789
- this.gl.vertexAttrib4f(tangentLocation, 1, 0, 0, 1);
3790
- }
3791
- const uv1Location = shader.reflection.attributes.get("a_uv1") ?? shader.reflection.attributes.get("uv1");
3792
- if (uv1Location !== undefined && uv1Location >= 0 && !boundLocations.has(uv1Location)) {
3793
- this.gl.disableVertexAttribArray(uv1Location);
3794
- this.gl.vertexAttribDivisor(uv1Location, 0);
3795
- this.gl.vertexAttrib2f(uv1Location, 0, 0);
3796
- }
3797
- const instanceColorLocation = shader.reflection.attributes.get("a_instanceColor") ?? shader.reflection.attributes.get("instanceColor");
3798
- if (instanceColorLocation !== undefined && instanceColorLocation >= 0 && !boundLocations.has(instanceColorLocation)) {
3799
- this.gl.disableVertexAttribArray(instanceColorLocation);
3800
- this.gl.vertexAttribDivisor(instanceColorLocation, 0);
3801
- this.gl.vertexAttrib4f(instanceColorLocation, 1, 1, 1, 1);
3802
- }
3803
- }
3804
- disableUnboundVertexAttributes(boundLocations) {
3805
- for (let location = 0; location < this.maxVertexAttributes; location += 1) {
3806
- if (!boundLocations.has(location)) {
3807
- this.gl.disableVertexAttribArray(location);
3808
- this.gl.vertexAttribDivisor(location, 0);
3809
- }
3810
- }
3811
- }
3812
- primitive(topology) {
3813
- if (topology === "lines")
3814
- return this.gl.LINES;
3815
- if (topology === "points")
3816
- return this.gl.POINTS;
3817
- return this.gl.TRIANGLES;
3818
- }
3819
- applyRenderState(state) {
3820
- const renderState = state ?? {
3821
- depthTest: true,
3822
- depthWrite: true,
3823
- cullMode: "back",
3824
- blend: false,
3825
- depthCompare: "less-equal",
3826
- colorWrite: [true, true, true, true],
3827
- scissor: null,
3828
- polygonOffset: null,
3829
- stencil: null
3830
- };
3831
- this.stateCache.setEnabled(this.gl.DEPTH_TEST, renderState.depthTest, () => {
3832
- if (renderState.depthTest)
3833
- this.gl.enable(this.gl.DEPTH_TEST);
3834
- else
3835
- this.gl.disable(this.gl.DEPTH_TEST);
3836
- });
3837
- this.stateCache.depthMask(renderState.depthWrite, () => this.gl.depthMask(renderState.depthWrite));
3838
- this.stateCache.depthFunc(renderState.depthCompare === "always" ? this.gl.ALWAYS : this.gl.LEQUAL, () => this.gl.depthFunc(renderState.depthCompare === "always" ? this.gl.ALWAYS : this.gl.LEQUAL));
3839
- const colorWrite = renderState.colorWrite ?? [true, true, true, true];
3840
- this.stateCache.colorMask(colorWrite[0], colorWrite[1], colorWrite[2], colorWrite[3], () => this.gl.colorMask(colorWrite[0], colorWrite[1], colorWrite[2], colorWrite[3]));
3841
- if (renderState.scissor) {
3842
- this.stateCache.setEnabled(this.gl.SCISSOR_TEST, true, () => this.gl.enable(this.gl.SCISSOR_TEST));
3843
- this.stateCache.scissor(renderState.scissor.x, renderState.scissor.y, renderState.scissor.width, renderState.scissor.height, () => {
3844
- this.gl.scissor(renderState.scissor.x, renderState.scissor.y, renderState.scissor.width, renderState.scissor.height);
3845
- });
3846
- }
3847
- else {
3848
- this.stateCache.setEnabled(this.gl.SCISSOR_TEST, false, () => this.gl.disable(this.gl.SCISSOR_TEST));
3849
- }
3850
- if (renderState.polygonOffset) {
3851
- this.stateCache.setEnabled(this.gl.POLYGON_OFFSET_FILL, true, () => this.gl.enable(this.gl.POLYGON_OFFSET_FILL));
3852
- this.stateCache.polygonOffset(renderState.polygonOffset.factor, renderState.polygonOffset.units, () => this.gl.polygonOffset(renderState.polygonOffset.factor, renderState.polygonOffset.units));
3853
- }
3854
- else {
3855
- this.stateCache.setEnabled(this.gl.POLYGON_OFFSET_FILL, false, () => this.gl.disable(this.gl.POLYGON_OFFSET_FILL));
3856
- }
3857
- if (renderState.stencil) {
3858
- const stencil = renderState.stencil;
3859
- const compare = this.stencilCompare(stencil.compare ?? "always");
3860
- const reference = stencil.reference ?? 0;
3861
- const readMask = stencil.readMask ?? 0xff;
3862
- const writeMask = stencil.writeMask ?? 0xff;
3863
- const fail = this.stencilOperation(stencil.fail ?? "keep");
3864
- const depthFail = this.stencilOperation(stencil.depthFail ?? "keep");
3865
- const depthPass = this.stencilOperation(stencil.depthPass ?? "keep");
3866
- this.stateCache.setEnabled(this.gl.STENCIL_TEST, true, () => this.gl.enable(this.gl.STENCIL_TEST));
3867
- this.stateCache.stencilFunc(compare, reference, readMask, () => this.gl.stencilFunc(compare, reference, readMask));
3868
- this.stateCache.stencilMask(writeMask, () => this.gl.stencilMask(writeMask));
3869
- this.stateCache.stencilOp(fail, depthFail, depthPass, () => this.gl.stencilOp(fail, depthFail, depthPass));
3870
- }
3871
- else {
3872
- this.stateCache.setEnabled(this.gl.STENCIL_TEST, false, () => this.gl.disable(this.gl.STENCIL_TEST));
3873
- }
3874
- if (renderState.cullMode === "none") {
3875
- this.stateCache.setEnabled(this.gl.CULL_FACE, false, () => this.gl.disable(this.gl.CULL_FACE));
3876
- }
3877
- else {
3878
- this.stateCache.setEnabled(this.gl.CULL_FACE, true, () => this.gl.enable(this.gl.CULL_FACE));
3879
- this.stateCache.cullFace(renderState.cullMode === "front" ? this.gl.FRONT : this.gl.BACK, () => this.gl.cullFace(renderState.cullMode === "front" ? this.gl.FRONT : this.gl.BACK));
3880
- }
3881
- if (renderState.blend) {
3882
- this.stateCache.setEnabled(this.gl.BLEND, true, () => this.gl.enable(this.gl.BLEND));
3883
- this.stateCache.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA, () => this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA));
3884
- }
3885
- else {
3886
- this.stateCache.setEnabled(this.gl.BLEND, false, () => this.gl.disable(this.gl.BLEND));
3887
- }
3888
- }
3889
- requireBuffer(buffer) {
3890
- if (!(buffer instanceof WebGL2Buffer) || !this.buffers.has(buffer) || buffer.disposed) {
3891
- throw new RenderDeviceError("Buffer is not a live WebGL2 resource owned by this device", "INVALID_RESOURCE", {
3892
- bufferId: buffer.id
3893
- });
3894
- }
3895
- return buffer;
3896
- }
3897
- stencilCompare(compare) {
3898
- switch (compare) {
3899
- case "never": return this.gl.NEVER;
3900
- case "less": return this.gl.LESS;
3901
- case "less-equal": return this.gl.LEQUAL;
3902
- case "greater": return this.gl.GREATER;
3903
- case "greater-equal": return this.gl.GEQUAL;
3904
- case "equal": return this.gl.EQUAL;
3905
- case "not-equal": return this.gl.NOTEQUAL;
3906
- case "always": return this.gl.ALWAYS;
3907
- }
3908
- }
3909
- stencilOperation(operation) {
3910
- switch (operation) {
3911
- case "keep": return this.gl.KEEP;
3912
- case "zero": return this.gl.ZERO;
3913
- case "replace": return this.gl.REPLACE;
3914
- case "increment": return this.gl.INCR;
3915
- case "decrement": return this.gl.DECR;
3916
- case "invert": return this.gl.INVERT;
3917
- case "increment-wrap": return this.gl.INCR_WRAP;
3918
- case "decrement-wrap": return this.gl.DECR_WRAP;
3919
- }
3920
- }
3921
- requireShader(shader) {
3922
- if (!(shader instanceof WebGL2ShaderProgram) || !this.shaders.has(shader) || shader.disposed) {
3923
- throw new RenderDeviceError("Shader is not a live WebGL2 resource owned by this device", "INVALID_RESOURCE", {
3924
- shaderId: shader.id
3925
- });
3926
- }
3927
- return shader;
3928
- }
3929
- assertAlive() {
3930
- if (this.disposed) {
3931
- throw new RenderDeviceError("Render device is disposed", "DISPOSED_DEVICE");
3932
- }
3933
- if (this.contextLost) {
3934
- throw new RenderDeviceError("Render context is lost", "CONTEXT_LOST");
3935
- }
3936
- }
3937
- assertFrame() {
3938
- this.assertAlive();
3939
- if (!this.frameActive) {
3940
- throw new RenderDeviceError("No active frame", "NO_ACTIVE_FRAME");
3941
- }
3942
- }
3943
- readError() {
3944
- const error = this.gl.getError();
3945
- return error === this.gl.NO_ERROR ? null : `0x${error.toString(16)}`;
3946
- }
3947
- }
3948
- function numberOption(options, key, fallback) {
3949
- const value = options[key];
3950
- return typeof value === "number" && Number.isFinite(value) ? value : fallback;
3951
- }
3952
- function normalizeNativeBloomOptions(options) {
3953
- const threshold = bloomNumberOption(options, "threshold", 0.75);
3954
- const intensity = bloomNumberOption(options, "intensity", 0.35);
3955
- const radius = bloomNumberOption(options, "radius", 1);
3956
- if (threshold < 0 || threshold > 1) {
3957
- throw new RenderDeviceError("Bloom threshold must be finite and in [0, 1].", "INVALID_POSTPROCESS_OPTIONS", { threshold });
3958
- }
3959
- if (intensity < 0) {
3960
- throw new RenderDeviceError("Bloom intensity must be finite and non-negative.", "INVALID_POSTPROCESS_OPTIONS", { intensity });
3961
- }
3962
- if (!Number.isInteger(radius) || radius < 0 || radius > 16) {
3963
- throw new RenderDeviceError("Bloom radius must be an integer in [0, 16].", "INVALID_POSTPROCESS_OPTIONS", { radius });
3964
- }
3965
- const softKnee = bloomNumberOption(options, "softKnee", 0);
3966
- if (!(softKnee >= 0) || softKnee > 0.5) {
3967
- throw new RenderDeviceError("Bloom softKnee must be finite and in [0, 0.5].", "INVALID_POSTPROCESS_OPTIONS", { softKnee });
3968
- }
3969
- const shoulder = bloomNumberOption(options, "shoulder", 0);
3970
- if (!(shoulder >= 0) || shoulder > 1) {
3971
- throw new RenderDeviceError("Bloom shoulder must be finite and in [0, 1].", "INVALID_POSTPROCESS_OPTIONS", { shoulder });
3972
- }
3973
- let quality;
3974
- try {
3975
- quality = normalizeBloomQualityPreset(options.quality);
3976
- }
3977
- catch {
3978
- throw new RenderDeviceError("Bloom quality must be one of performance|balanced|cinematic.", "INVALID_POSTPROCESS_OPTIONS", { quality: options.quality });
3979
- }
3980
- return { threshold, intensity, radius, quality, softKnee, shoulder };
3981
- }
3982
- function normalizeNativeOutlineOptions(options) {
3983
- const width = outlineNumberOption(options, "width", 1);
3984
- const threshold = outlineNumberOption(options, "threshold", 0.22);
3985
- const opacity = outlineNumberOption(options, "opacity", 0.85);
3986
- const value = options.color;
3987
- const sourceColor = value === undefined ? [255, 188, 64, 255] : value;
3988
- if (!Array.isArray(sourceColor)
3989
- || (sourceColor.length !== 3 && sourceColor.length !== 4)
3990
- || sourceColor.some((channel) => typeof channel !== "number" || !Number.isFinite(channel) || channel < 0 || channel > 255)) {
3991
- throw new RenderDeviceError("Outline color must contain three or four finite channels in [0, 255].", "INVALID_POSTPROCESS_OPTIONS", { color: value });
3992
- }
3993
- if (!Number.isInteger(width) || width < 1 || width > 6) {
3994
- throw new RenderDeviceError("Outline width must be an integer in [1, 6].", "INVALID_POSTPROCESS_OPTIONS", { width });
3995
- }
3996
- if (threshold < 0 || threshold > 4) {
3997
- throw new RenderDeviceError("Outline threshold must be finite and in [0, 4].", "INVALID_POSTPROCESS_OPTIONS", { threshold });
3998
- }
3999
- if (opacity < 0 || opacity > 1) {
4000
- throw new RenderDeviceError("Outline opacity must be finite and in [0, 1].", "INVALID_POSTPROCESS_OPTIONS", { opacity });
4001
- }
4002
- const color = [
4003
- sourceColor[0],
4004
- sourceColor[1],
4005
- sourceColor[2],
4006
- (sourceColor[3] ?? 255)
4007
- ];
4008
- return { width, threshold, opacity, color };
4009
- }
4010
- function normalizeNativeSsaoOptions(options) {
4011
- const radius = ssaoNumberOption(options, "radius", 2);
4012
- const intensity = ssaoNumberOption(options, "intensity", 0.38);
4013
- const bias = ssaoNumberOption(options, "bias", 0.015);
4014
- if (!Number.isInteger(radius) || radius < 1 || radius > 8) {
4015
- throw new RenderDeviceError("SSAO radius must be an integer in [1, 8].", "INVALID_POSTPROCESS_OPTIONS", { radius });
4016
- }
4017
- if (intensity < 0 || intensity > 2) {
4018
- throw new RenderDeviceError("SSAO intensity must be finite and in [0, 2].", "INVALID_POSTPROCESS_OPTIONS", { intensity });
4019
- }
4020
- if (bias < 0 || bias > 0.25) {
4021
- throw new RenderDeviceError("SSAO bias must be finite and in [0, 0.25].", "INVALID_POSTPROCESS_OPTIONS", { bias });
4022
- }
4023
- return { radius, intensity, bias };
4024
1327
  }
4025
1328
  /**
4026
1329
  * Camera depth range for linearizing sampleable GL depth in the native
@@ -4031,199 +1334,12 @@ function normalizeNativeSsaoOptions(options) {
4031
1334
  * keep fixture-unit depth semantics (deterministic reference); the native
4032
1335
  * programs document their GL-depth contract in-shader.
4033
1336
  */
4034
- function normalizeLdrDepthRange(range) {
4035
- const near = range && Number.isFinite(range.near) && range.near > 0 ? range.near : 0.1;
4036
- const far = range && Number.isFinite(range.far) && range.far > near ? range.far : 1000;
4037
- return { near, far };
4038
- }
4039
- function normalizeNativeSsrOptions(options) {
4040
- const intensity = ssrNumberOption(options, "intensity", 0.32);
4041
- const maxDistance = ssrNumberOption(options, "maxDistance", 16);
4042
- if (intensity < 0 || intensity > 2) {
4043
- throw new RenderDeviceError("SSR intensity must be finite and in [0, 2].", "INVALID_POSTPROCESS_OPTIONS", { intensity });
4044
- }
4045
- if (!Number.isInteger(maxDistance) || maxDistance < 1 || maxDistance > 64) {
4046
- throw new RenderDeviceError("SSR maxDistance must be an integer in [1, 64].", "INVALID_POSTPROCESS_OPTIONS", { maxDistance });
4047
- }
4048
- const projection = options["projection"];
4049
- if (!(projection instanceof Float32Array))
4050
- throw new RenderDeviceError("Native SSR requires the actual frame projection or view-projection matrix.", "INVALID_POSTPROCESS_OPTIONS");
4051
- const inverseProjection = invertSsrProjection(projection);
4052
- return { intensity, maxDistance, projection, inverseProjection };
4053
- }
4054
- function normalizeNativeDepthOfFieldOptions(options) {
4055
- const focusDepth = depthOfFieldNumberOption(options, "focusDepth", 0.5);
4056
- const focusRange = depthOfFieldNumberOption(options, "focusRange", 0.12);
4057
- const maxRadius = depthOfFieldNumberOption(options, "maxRadius", 2);
4058
- if (focusDepth < 0 || focusDepth > 1) {
4059
- throw new RenderDeviceError("Depth-of-field focusDepth must be finite and in [0, 1].", "INVALID_POSTPROCESS_OPTIONS", { focusDepth });
4060
- }
4061
- if (focusRange < 0.001 || focusRange > 1) {
4062
- throw new RenderDeviceError("Depth-of-field focusRange must be finite and in [0.001, 1].", "INVALID_POSTPROCESS_OPTIONS", { focusRange });
4063
- }
4064
- if (!Number.isInteger(maxRadius) || maxRadius < 0 || maxRadius > 8) {
4065
- throw new RenderDeviceError("Depth-of-field maxRadius must be an integer in [0, 8].", "INVALID_POSTPROCESS_OPTIONS", { maxRadius });
4066
- }
4067
- return { focusDepth, focusRange, maxRadius };
4068
- }
4069
- function normalizeNativeMotionBlurOptions(options, width, height) {
4070
- const samples = motionBlurNumberOption(options, "samples", 5);
4071
- const scale = motionBlurNumberOption(options, "scale", 1);
4072
- if (options.temporal) {
4073
- if (!Number.isInteger(samples) || samples < 2 || samples > 16 || scale < 0 || scale > 8)
4074
- throw new RenderDeviceError("Invalid motion blur samples/scale", "INVALID_POSTPROCESS_OPTIONS");
4075
- return { samples, scale, temporal: options.temporal };
4076
- }
4077
- const value = options.velocity;
4078
- if (!(value instanceof Float32Array) && !Array.isArray(value)) {
4079
- throw new RenderDeviceError("Motion blur requires a velocity Float32Array or number array.", "WEBGL_LDR_POSTPROCESS_VELOCITY_REQUIRED");
4080
- }
4081
- const velocity = value instanceof Float32Array ? value : new Float32Array(value);
4082
- if (velocity.length !== width * height * 2) {
4083
- throw new RenderDeviceError("Motion blur velocity must contain width * height * 2 float samples.", "INVALID_POSTPROCESS_OPTIONS", {
4084
- expectedLength: width * height * 2,
4085
- actualLength: velocity.length
4086
- });
4087
- }
4088
- if (!Number.isInteger(samples) || samples < 2 || samples > 16) {
4089
- throw new RenderDeviceError("Motion blur samples must be an integer in [2, 16].", "INVALID_POSTPROCESS_OPTIONS", { samples });
4090
- }
4091
- if (scale < 0 || scale > 8) {
4092
- throw new RenderDeviceError("Motion blur scale must be finite and in [0, 8].", "INVALID_POSTPROCESS_OPTIONS", { scale });
4093
- }
4094
- return { samples, scale, velocity };
4095
- }
4096
- function normalizeNativeTaaOptions(options, width, height) {
4097
- const blend = taaNumberOption(options, "blend", 0.18);
4098
- if (options.temporal) {
4099
- if (blend < 0 || blend > .95)
4100
- throw new RenderDeviceError("Invalid TAA blend", "INVALID_POSTPROCESS_OPTIONS");
4101
- return { blend, temporal: options.temporal };
4102
- }
4103
- const history = options.history;
4104
- if (!(history instanceof Uint8Array)) {
4105
- throw new RenderDeviceError("TAA requires a Uint8Array history buffer.", "WEBGL_LDR_POSTPROCESS_HISTORY_REQUIRED");
4106
- }
4107
- if (history.byteLength !== width * height * 4) {
4108
- throw new RenderDeviceError("TAA history must contain width * height * 4 RGBA bytes.", "INVALID_POSTPROCESS_OPTIONS", {
4109
- expectedLength: width * height * 4,
4110
- actualLength: history.byteLength
4111
- });
4112
- }
4113
- if (blend < 0 || blend > 0.95) {
4114
- throw new RenderDeviceError("TAA blend must be finite and in [0, 0.95].", "INVALID_POSTPROCESS_OPTIONS", { blend });
4115
- }
4116
- return { blend, history };
4117
- }
4118
- function bloomNumberOption(options, key, fallback) {
4119
- const value = options[key];
4120
- if (value === undefined)
4121
- return fallback;
4122
- if (typeof value !== "number" || !Number.isFinite(value)) {
4123
- throw new RenderDeviceError(`Bloom ${key} must be a finite number.`, "INVALID_POSTPROCESS_OPTIONS", { key, value });
4124
- }
4125
- return value;
4126
- }
4127
- function outlineNumberOption(options, key, fallback) {
4128
- const value = options[key];
4129
- if (value === undefined)
4130
- return fallback;
4131
- if (typeof value !== "number" || !Number.isFinite(value)) {
4132
- throw new RenderDeviceError(`Outline ${key} must be a finite number.`, "INVALID_POSTPROCESS_OPTIONS", { key, value });
4133
- }
4134
- return value;
4135
- }
4136
- function ssaoNumberOption(options, key, fallback) {
4137
- const value = options[key];
4138
- if (value === undefined)
4139
- return fallback;
4140
- if (typeof value !== "number" || !Number.isFinite(value)) {
4141
- throw new RenderDeviceError(`SSAO ${key} must be a finite number.`, "INVALID_POSTPROCESS_OPTIONS", { key, value });
4142
- }
4143
- return value;
4144
- }
4145
- function ssrNumberOption(options, key, fallback) {
4146
- const value = options[key];
4147
- if (value === undefined)
4148
- return fallback;
4149
- if (typeof value !== "number" || !Number.isFinite(value)) {
4150
- throw new RenderDeviceError(`SSR ${key} must be a finite number.`, "INVALID_POSTPROCESS_OPTIONS", { key, value });
4151
- }
4152
- return value;
4153
- }
4154
- function depthOfFieldNumberOption(options, key, fallback) {
4155
- const value = options[key];
4156
- if (value === undefined)
4157
- return fallback;
4158
- if (typeof value !== "number" || !Number.isFinite(value)) {
4159
- throw new RenderDeviceError(`Depth-of-field ${key} must be a finite number.`, "INVALID_POSTPROCESS_OPTIONS", { key, value });
4160
- }
4161
- return value;
4162
- }
4163
- function motionBlurNumberOption(options, key, fallback) {
4164
- const value = options[key];
4165
- if (value === undefined)
4166
- return fallback;
4167
- if (typeof value !== "number" || !Number.isFinite(value)) {
4168
- throw new RenderDeviceError(`Motion blur ${key} must be a finite number.`, "INVALID_POSTPROCESS_OPTIONS", { key, value });
4169
- }
4170
- return value;
4171
- }
4172
- function taaNumberOption(options, key, fallback) {
4173
- const value = options[key];
4174
- if (value === undefined)
4175
- return fallback;
4176
- if (typeof value !== "number" || !Number.isFinite(value)) {
4177
- throw new RenderDeviceError(`TAA ${key} must be a finite number.`, "INVALID_POSTPROCESS_OPTIONS", { key, value });
4178
- }
4179
- return value;
4180
- }
4181
- function stringOption(options, key, fallback) {
4182
- const value = options[key];
4183
- return typeof value === "string" ? value : fallback;
4184
- }
4185
- function colorSpaceId(value) {
4186
- return value === "srgb" ? 1 : 0;
4187
- }
4188
- function toneMappingOperatorId(value) {
4189
- if (value === "linear")
4190
- return 0;
4191
- if (value === "reinhard")
4192
- return 1;
4193
- if (value === "aces")
4194
- return 2;
4195
- if (value === "filmic")
4196
- return 3;
4197
- if (value === "uncharted2")
4198
- return 4;
4199
- if (value === "agx")
4200
- return 5;
4201
- return 6;
4202
- }
4203
- function completeUploadLevels(levels) {
4204
- const uploadLevels = [];
4205
- for (const level of levels) {
4206
- if (uploadLevels.length === 0) {
4207
- uploadLevels.push(level);
4208
- continue;
4209
- }
4210
- const previous = uploadLevels[uploadLevels.length - 1];
4211
- const expectedWidth = Math.max(1, Math.floor(previous.width / 2));
4212
- const expectedHeight = Math.max(1, Math.floor(previous.height / 2));
4213
- if (level.width !== expectedWidth || level.height !== expectedHeight) {
4214
- break;
4215
- }
4216
- uploadLevels.push(level);
4217
- }
4218
- return uploadLevels;
4219
- }
4220
- function texturePixelUploadData(data, format) {
4221
- if (format === "rgba16f" && data instanceof Uint16Array)
4222
- return data;
4223
- if (format === "rgba32f" && data instanceof Float32Array)
4224
- return data;
4225
- if (format === "rgba8" && (data instanceof Uint8Array || data instanceof Uint8ClampedArray))
4226
- return data;
4227
- throw new RenderDeviceError("Texture pixel data type does not match texture format", "UNSUPPORTED_TEXTURE_FORMAT", { format });
1337
+ /** Next animation frame when available (browser), else a macrotask. */
1338
+ function scheduleParallelCompilePoll(poll) {
1339
+ const raf = globalThis.requestAnimationFrame;
1340
+ if (typeof raf === "function")
1341
+ raf(poll);
1342
+ else
1343
+ setTimeout(poll, 0);
4228
1344
  }
4229
1345
  //# sourceMappingURL=WebGL2Device.js.map