super-three 0.172.0 → 0.173.1

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 (180) hide show
  1. package/LICENSE +1 -1
  2. package/build/three.cjs +439 -380
  3. package/build/three.core.js +413 -41
  4. package/build/three.core.min.js +2 -2
  5. package/build/three.module.js +28 -344
  6. package/build/three.module.min.js +2 -2
  7. package/build/three.tsl.js +11 -3
  8. package/build/three.tsl.min.js +2 -2
  9. package/build/three.webgpu.js +7550 -1798
  10. package/build/three.webgpu.min.js +2 -2
  11. package/build/three.webgpu.nodes.js +7551 -1798
  12. package/build/three.webgpu.nodes.min.js +2 -2
  13. package/examples/jsm/animation/CCDIKSolver.js +6 -5
  14. package/examples/jsm/capabilities/WebGPU.js +1 -1
  15. package/examples/jsm/controls/ArcballControls.js +23 -21
  16. package/examples/jsm/exporters/GLTFExporter.js +26 -25
  17. package/examples/jsm/geometries/TextGeometry.js +1 -12
  18. package/examples/jsm/interactive/InteractiveGroup.js +108 -51
  19. package/examples/jsm/libs/demuxer_mp4.js +109 -0
  20. package/examples/jsm/loaders/GCodeLoader.js +3 -1
  21. package/examples/jsm/loaders/GLTFLoader.js +0 -2
  22. package/examples/jsm/loaders/TDSLoader.js +0 -1
  23. package/examples/jsm/materials/MeshGouraudMaterial.js +2 -0
  24. package/examples/jsm/misc/GPUComputationRenderer.js +6 -7
  25. package/examples/jsm/misc/ProgressiveLightMap.js +4 -3
  26. package/examples/jsm/misc/ProgressiveLightMapGPU.js +4 -3
  27. package/examples/jsm/misc/Volume.js +7 -5
  28. package/examples/jsm/misc/VolumeSlice.js +5 -3
  29. package/examples/jsm/objects/WaterMesh.js +25 -20
  30. package/examples/jsm/physics/JoltPhysics.js +7 -7
  31. package/examples/jsm/physics/RapierPhysics.js +4 -4
  32. package/examples/jsm/postprocessing/EffectComposer.js +23 -2
  33. package/examples/jsm/postprocessing/OutputPass.js +2 -0
  34. package/examples/jsm/postprocessing/Pass.js +6 -1
  35. package/examples/jsm/shaders/OutputShader.js +5 -1
  36. package/examples/jsm/transpiler/GLSLDecoder.js +2 -2
  37. package/examples/jsm/transpiler/TSLEncoder.js +2 -0
  38. package/package.json +1 -1
  39. package/src/Three.Core.js +2 -0
  40. package/src/Three.TSL.js +9 -1
  41. package/src/cameras/ArrayCamera.js +1 -0
  42. package/src/constants.js +6 -1
  43. package/src/core/BufferAttribute.js +4 -0
  44. package/src/core/EventDispatcher.js +8 -6
  45. package/src/extras/ImageUtils.js +1 -11
  46. package/src/loaders/nodes/NodeObjectLoader.js +1 -1
  47. package/src/materials/nodes/MeshBasicNodeMaterial.js +1 -1
  48. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +1 -1
  49. package/src/materials/nodes/NodeMaterial.js +5 -5
  50. package/src/materials/nodes/NodeMaterials.js +0 -1
  51. package/src/materials/nodes/PointsNodeMaterial.js +109 -7
  52. package/src/materials/nodes/SpriteNodeMaterial.js +1 -1
  53. package/src/materials/nodes/VolumeNodeMaterial.js +3 -3
  54. package/src/materials/nodes/manager/NodeMaterialObserver.js +8 -0
  55. package/src/nodes/Nodes.js +4 -0
  56. package/src/nodes/TSL.js +4 -0
  57. package/src/nodes/accessors/Arrays.js +30 -8
  58. package/src/nodes/accessors/BatchNode.js +3 -3
  59. package/src/nodes/accessors/BufferAttributeNode.js +1 -1
  60. package/src/nodes/accessors/Camera.js +64 -3
  61. package/src/nodes/accessors/InstanceNode.js +1 -1
  62. package/src/nodes/accessors/MaterialNode.js +9 -9
  63. package/src/nodes/accessors/ModelViewProjectionNode.js +1 -1
  64. package/src/nodes/accessors/Normal.js +6 -2
  65. package/src/nodes/accessors/Object3DNode.js +0 -1
  66. package/src/nodes/accessors/Position.js +6 -6
  67. package/src/nodes/accessors/ReferenceBaseNode.js +2 -4
  68. package/src/nodes/accessors/ReferenceNode.js +2 -3
  69. package/src/nodes/accessors/StorageBufferNode.js +42 -5
  70. package/src/nodes/accessors/Tangent.js +2 -2
  71. package/src/nodes/accessors/Texture3DNode.js +1 -1
  72. package/src/nodes/accessors/TextureNode.js +12 -5
  73. package/src/nodes/accessors/UniformArrayNode.js +9 -3
  74. package/src/nodes/accessors/VelocityNode.js +0 -2
  75. package/src/nodes/code/ScriptableNode.js +3 -3
  76. package/src/nodes/core/ArrayNode.js +125 -0
  77. package/src/nodes/core/ConstNode.js +8 -0
  78. package/src/nodes/core/Node.js +14 -1
  79. package/src/nodes/core/NodeBuilder.js +229 -19
  80. package/src/nodes/core/NodeUtils.js +11 -1
  81. package/src/nodes/core/NodeVar.js +17 -1
  82. package/src/nodes/core/OutputStructNode.js +19 -9
  83. package/src/nodes/core/StackNode.js +20 -1
  84. package/src/nodes/core/StructNode.js +121 -0
  85. package/src/nodes/core/StructType.js +13 -0
  86. package/src/nodes/core/StructTypeNode.js +82 -21
  87. package/src/nodes/core/TempNode.js +1 -1
  88. package/src/nodes/core/VarNode.js +94 -7
  89. package/src/nodes/core/VaryingNode.js +19 -3
  90. package/src/nodes/display/BlendModes.js +88 -1
  91. package/src/nodes/display/BumpMapNode.js +6 -6
  92. package/src/nodes/display/NormalMapNode.js +6 -6
  93. package/src/nodes/display/PassNode.js +3 -1
  94. package/src/nodes/display/ScreenNode.js +9 -0
  95. package/src/nodes/fog/Fog.js +17 -0
  96. package/src/nodes/gpgpu/AtomicFunctionNode.js +20 -4
  97. package/src/nodes/gpgpu/ComputeBuiltinNode.js +8 -0
  98. package/src/nodes/gpgpu/WorkgroupInfoNode.js +1 -1
  99. package/src/nodes/lighting/ShadowNode.js +1 -1
  100. package/src/nodes/math/ConditionalNode.js +8 -1
  101. package/src/nodes/math/MathNode.js +14 -1
  102. package/src/nodes/math/OperatorNode.js +96 -18
  103. package/src/nodes/pmrem/PMREMUtils.js +1 -1
  104. package/src/nodes/shapes/Shapes.js +33 -0
  105. package/src/nodes/tsl/TSLBase.js +1 -0
  106. package/src/nodes/tsl/TSLCore.js +22 -2
  107. package/src/nodes/utils/ArrayElementNode.js +1 -1
  108. package/src/nodes/utils/LoopNode.js +8 -1
  109. package/src/nodes/utils/MemberNode.js +68 -0
  110. package/src/nodes/utils/StorageArrayElementNode.js +14 -0
  111. package/src/nodes/utils/Timer.js +21 -0
  112. package/src/objects/BatchedMesh.js +1 -1
  113. package/src/objects/Line.js +6 -6
  114. package/src/renderers/WebGLRenderer.js +7 -0
  115. package/src/renderers/common/Animation.js +23 -1
  116. package/src/renderers/common/Backend.js +58 -15
  117. package/src/renderers/common/Background.js +14 -0
  118. package/src/renderers/common/Binding.js +1 -1
  119. package/src/renderers/common/BufferUtils.js +1 -1
  120. package/src/renderers/common/BundleGroup.js +1 -1
  121. package/src/renderers/common/ChainMap.js +9 -7
  122. package/src/renderers/common/ClippingContext.js +1 -1
  123. package/src/renderers/common/Color4.js +7 -3
  124. package/src/renderers/common/Geometries.js +2 -23
  125. package/src/renderers/common/Info.js +1 -45
  126. package/src/renderers/common/Lighting.js +8 -6
  127. package/src/renderers/common/Pipelines.js +3 -3
  128. package/src/renderers/common/PostProcessing.js +24 -8
  129. package/src/renderers/common/QuadMesh.js +1 -1
  130. package/src/renderers/common/RenderBundles.js +9 -3
  131. package/src/renderers/common/RenderContext.js +37 -3
  132. package/src/renderers/common/RenderContexts.js +30 -17
  133. package/src/renderers/common/RenderList.js +2 -2
  134. package/src/renderers/common/RenderLists.js +9 -3
  135. package/src/renderers/common/RenderObject.js +76 -17
  136. package/src/renderers/common/RenderObjects.js +9 -7
  137. package/src/renderers/common/Renderer.js +86 -67
  138. package/src/renderers/common/SampledTexture.js +0 -1
  139. package/src/renderers/common/StorageBufferAttribute.js +1 -1
  140. package/src/renderers/common/StorageInstancedBufferAttribute.js +1 -1
  141. package/src/renderers/common/StorageTexture.js +1 -1
  142. package/src/renderers/common/Textures.js +14 -7
  143. package/src/renderers/common/TimestampQueryPool.js +39 -0
  144. package/src/renderers/common/Uniform.js +37 -1
  145. package/src/renderers/common/UniformsGroup.js +2 -0
  146. package/src/renderers/common/XRManager.js +1193 -0
  147. package/src/renderers/common/XRRenderTarget.js +74 -0
  148. package/src/renderers/common/extras/PMREMGenerator.js +53 -8
  149. package/src/renderers/common/nodes/NodeBuilderState.js +4 -4
  150. package/src/renderers/common/nodes/NodeLibrary.js +5 -5
  151. package/src/renderers/common/nodes/NodeSampledTexture.js +0 -1
  152. package/src/renderers/common/nodes/NodeUniform.js +54 -2
  153. package/src/renderers/common/nodes/Nodes.js +25 -18
  154. package/src/renderers/webgl/WebGLBackground.js +4 -0
  155. package/src/renderers/webgl-fallback/WebGLBackend.js +295 -110
  156. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +347 -17
  157. package/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +57 -0
  158. package/src/renderers/webgl-fallback/utils/WebGLCapabilities.js +28 -0
  159. package/src/renderers/webgl-fallback/utils/WebGLExtensions.js +45 -0
  160. package/src/renderers/webgl-fallback/utils/WebGLState.js +323 -11
  161. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +167 -21
  162. package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +359 -0
  163. package/src/renderers/webgl-fallback/utils/WebGLUtils.js +43 -0
  164. package/src/renderers/webgpu/WebGPUBackend.js +132 -149
  165. package/src/renderers/webgpu/WebGPURenderer.Nodes.js +6 -4
  166. package/src/renderers/webgpu/WebGPURenderer.js +5 -4
  167. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +615 -41
  168. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +85 -6
  169. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +85 -0
  170. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +102 -3
  171. package/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +98 -1
  172. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +257 -9
  173. package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +274 -0
  174. package/src/renderers/webgpu/utils/WebGPUUtils.js +86 -4
  175. package/src/renderers/webxr/WebXRManager.js +13 -2
  176. package/src/textures/VideoFrameTexture.js +35 -0
  177. package/examples/jsm/geometries/InstancedPointsGeometry.js +0 -176
  178. package/examples/jsm/objects/InstancedPoints.js +0 -19
  179. package/src/materials/nodes/InstancedPointsNodeMaterial.js +0 -209
  180. package/src/nodes/accessors/InstancedPointsMaterialNode.js +0 -37
@@ -2,19 +2,53 @@ import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Near
2
2
 
3
3
  let initialized = false, wrappingToGL, filterToGL, compareToGL;
4
4
 
5
+ /**
6
+ * A WebGL 2 backend utility module for managing textures.
7
+ *
8
+ * @private
9
+ */
5
10
  class WebGLTextureUtils {
6
11
 
12
+ /**
13
+ * Constructs a new utility object.
14
+ *
15
+ * @param {WebGLBackend} backend - The WebGL 2 backend.
16
+ */
7
17
  constructor( backend ) {
8
18
 
19
+ /**
20
+ * A reference to the WebGL 2 backend.
21
+ *
22
+ * @type {WebGLBackend}
23
+ */
9
24
  this.backend = backend;
10
25
 
26
+ /**
27
+ * A reference to the rendering context.
28
+ *
29
+ * @type {WebGL2RenderingContext}
30
+ */
11
31
  this.gl = backend.gl;
32
+
33
+ /**
34
+ * A reference to a backend module holding extension-related
35
+ * utility functions.
36
+ *
37
+ * @type {WebGLExtensions}
38
+ */
12
39
  this.extensions = backend.extensions;
40
+
41
+ /**
42
+ * A dictionary for managing default textures. The key
43
+ * is the binding point (target), the value the WEbGL texture object.
44
+ *
45
+ * @type {Object<GLenum,WebGLTexture>}
46
+ */
13
47
  this.defaultTextures = {};
14
48
 
15
49
  if ( initialized === false ) {
16
50
 
17
- this._init( this.gl );
51
+ this._init();
18
52
 
19
53
  initialized = true;
20
54
 
@@ -22,7 +56,14 @@ class WebGLTextureUtils {
22
56
 
23
57
  }
24
58
 
25
- _init( gl ) {
59
+ /**
60
+ * Inits the state of the utility.
61
+ *
62
+ * @private
63
+ */
64
+ _init() {
65
+
66
+ const gl = this.gl;
26
67
 
27
68
  // Store only WebGL constants here.
28
69
 
@@ -55,20 +96,12 @@ class WebGLTextureUtils {
55
96
 
56
97
  }
57
98
 
58
- filterFallback( f ) {
59
-
60
- const { gl } = this;
61
-
62
- if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
63
-
64
- return gl.NEAREST;
65
-
66
- }
67
-
68
- return gl.LINEAR;
69
-
70
- }
71
-
99
+ /**
100
+ * Returns the native texture type for the given texture.
101
+ *
102
+ * @param {Texture} texture - The texture.
103
+ * @return {GLenum} The native texture type.
104
+ */
72
105
  getGLTextureType( texture ) {
73
106
 
74
107
  const { gl } = this;
@@ -98,6 +131,16 @@ class WebGLTextureUtils {
98
131
 
99
132
  }
100
133
 
134
+ /**
135
+ * Returns the native texture type for the given texture.
136
+ *
137
+ * @param {String?} internalFormatName - The internal format name. When `null`, the internal format is derived from the subsequent parameters.
138
+ * @param {GLenum} glFormat - The WebGL format.
139
+ * @param {GLenum} glType - The WebGL type.
140
+ * @param {String} colorSpace - The texture's color space.
141
+ * @param {Boolean} [forceLinearTransfer=false] - Whether to force a linear transfer or not.
142
+ * @return {GLenum} The internal format.
143
+ */
101
144
  getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) {
102
145
 
103
146
  const { gl, extensions } = this;
@@ -218,7 +261,8 @@ class WebGLTextureUtils {
218
261
 
219
262
  if ( glFormat === gl.DEPTH_COMPONENT ) {
220
263
 
221
- if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.DEPTH24_STENCIL8;
264
+ if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.DEPTH_COMPONENT16;
265
+ if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.DEPTH_COMPONENT24;
222
266
  if ( glType === gl.FLOAT ) internalFormat = gl.DEPTH_COMPONENT32F;
223
267
 
224
268
  }
@@ -241,6 +285,12 @@ class WebGLTextureUtils {
241
285
 
242
286
  }
243
287
 
288
+ /**
289
+ * Sets the texture parameters for the given texture.
290
+ *
291
+ * @param {GLenum} textureType - The texture type.
292
+ * @param {Texture} texture - The texture.
293
+ */
244
294
  setTextureParameters( textureType, texture ) {
245
295
 
246
296
  const { gl, extensions, backend } = this;
@@ -294,6 +344,12 @@ class WebGLTextureUtils {
294
344
 
295
345
  }
296
346
 
347
+ /**
348
+ * Creates a default texture for the given texture that can be used
349
+ * as a placeholder until the actual texture is ready for usage.
350
+ *
351
+ * @param {Texture} texture - The texture to create a default texture for.
352
+ */
297
353
  createDefaultTexture( texture ) {
298
354
 
299
355
  const { gl, backend, defaultTextures } = this;
@@ -325,6 +381,13 @@ class WebGLTextureUtils {
325
381
 
326
382
  }
327
383
 
384
+ /**
385
+ * Defines a texture on the GPU for the given texture object.
386
+ *
387
+ * @param {Texture} texture - The texture.
388
+ * @param {Object} [options={}] - Optional configuration parameter.
389
+ * @return {undefined}
390
+ */
328
391
  createTexture( texture, options ) {
329
392
 
330
393
  const { gl, backend } = this;
@@ -365,6 +428,12 @@ class WebGLTextureUtils {
365
428
 
366
429
  }
367
430
 
431
+ /**
432
+ * Uploads texture buffer data to the GPU memory.
433
+ *
434
+ * @param {WebGLBuffer} buffer - The buffer data.
435
+ * @param {Texture} texture - The texture,
436
+ */
368
437
  copyBufferToTexture( buffer, texture ) {
369
438
 
370
439
  const { gl, backend } = this;
@@ -400,6 +469,12 @@ class WebGLTextureUtils {
400
469
 
401
470
  }
402
471
 
472
+ /**
473
+ * Uploads the updated texture data to the GPU.
474
+ *
475
+ * @param {Texture} texture - The texture.
476
+ * @param {Object} [options={}] - Optional configuration parameter.
477
+ */
403
478
  updateTexture( texture, options ) {
404
479
 
405
480
  const { gl } = this;
@@ -520,6 +595,11 @@ class WebGLTextureUtils {
520
595
 
521
596
  }
522
597
 
598
+ /**
599
+ * Generates mipmaps for the given texture.
600
+ *
601
+ * @param {Texture} texture - The texture.
602
+ */
523
603
  generateMipmaps( texture ) {
524
604
 
525
605
  const { gl, backend } = this;
@@ -530,6 +610,11 @@ class WebGLTextureUtils {
530
610
 
531
611
  }
532
612
 
613
+ /**
614
+ * Deallocates the render buffers of the given render target.
615
+ *
616
+ * @param {RenderTarget} renderTarget - The render target.
617
+ */
533
618
  deallocateRenderBuffers( renderTarget ) {
534
619
 
535
620
  const { gl, backend } = this;
@@ -590,6 +675,11 @@ class WebGLTextureUtils {
590
675
 
591
676
  }
592
677
 
678
+ /**
679
+ * Destroys the GPU data for the given texture object.
680
+ *
681
+ * @param {Texture} texture - The texture.
682
+ */
593
683
  destroyTexture( texture ) {
594
684
 
595
685
  const { gl, backend } = this;
@@ -602,6 +692,15 @@ class WebGLTextureUtils {
602
692
 
603
693
  }
604
694
 
695
+ /**
696
+ * Copies data of the given source texture to the given destination texture.
697
+ *
698
+ * @param {Texture} srcTexture - The source texture.
699
+ * @param {Texture} dstTexture - The destination texture.
700
+ * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy.
701
+ * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy.
702
+ * @param {Number} [level=0] - The mip level to copy.
703
+ */
605
704
  copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {
606
705
 
607
706
  const { gl, backend } = this;
@@ -720,6 +819,13 @@ class WebGLTextureUtils {
720
819
 
721
820
  }
722
821
 
822
+ /**
823
+ * Copies the current bound framebuffer to the given texture.
824
+ *
825
+ * @param {Texture} texture - The destination texture.
826
+ * @param {RenderContext} renderContext - The render context.
827
+ * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy.
828
+ */
723
829
  copyFramebufferToTexture( texture, renderContext, rectangle ) {
724
830
 
725
831
  const { gl } = this;
@@ -807,13 +913,20 @@ class WebGLTextureUtils {
807
913
 
808
914
  }
809
915
 
810
- // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
811
- setupRenderBufferStorage( renderbuffer, renderContext ) {
916
+ /**
917
+ * SetupS storage for internal depth/stencil buffers and bind to correct framebuffer.
918
+ *
919
+ * @param {WebGLRenderbuffer} renderbuffer - The render buffer.
920
+ * @param {RenderContext} renderContext - The render context.
921
+ * @param {Number} samples - The MSAA sample count.
922
+ * @param {Boolean} [useMultisampledRTT=false] - Whether to use WEBGL_multisampled_render_to_texture or not.
923
+ */
924
+ setupRenderBufferStorage( renderbuffer, renderContext, samples, useMultisampledRTT = false ) {
812
925
 
813
926
  const { gl } = this;
814
927
  const renderTarget = renderContext.renderTarget;
815
928
 
816
- const { samples, depthTexture, depthBuffer, stencilBuffer, width, height } = renderTarget;
929
+ const { depthTexture, depthBuffer, stencilBuffer, width, height } = renderTarget;
817
930
 
818
931
  gl.bindRenderbuffer( gl.RENDERBUFFER, renderbuffer );
819
932
 
@@ -821,7 +934,13 @@ class WebGLTextureUtils {
821
934
 
822
935
  let glInternalFormat = gl.DEPTH_COMPONENT24;
823
936
 
824
- if ( samples > 0 ) {
937
+ if ( useMultisampledRTT === true ) {
938
+
939
+ const multisampledRTTExt = this.extensions.get( 'WEBGL_multisampled_render_to_texture' );
940
+
941
+ multisampledRTTExt.renderbufferStorageMultisampleEXT( gl.RENDERBUFFER, renderTarget.samples, glInternalFormat, width, height );
942
+
943
+ } else if ( samples > 0 ) {
825
944
 
826
945
  if ( depthTexture && depthTexture.isDepthTexture ) {
827
946
 
@@ -862,6 +981,18 @@ class WebGLTextureUtils {
862
981
 
863
982
  }
864
983
 
984
+ /**
985
+ * Returns texture data as a typed array.
986
+ *
987
+ * @async
988
+ * @param {Texture} texture - The texture to copy.
989
+ * @param {Number} x - The x coordinate of the copy origin.
990
+ * @param {Number} y - The y coordinate of the copy origin.
991
+ * @param {Number} width - The width of the copy.
992
+ * @param {Number} height - The height of the copy.
993
+ * @param {Number} faceIndex - The face index.
994
+ * @return {Promise<TypedArray>} A Promise that resolves with a typed array when the copy operation has finished.
995
+ */
865
996
  async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) {
866
997
 
867
998
  const { backend, gl } = this;
@@ -903,6 +1034,13 @@ class WebGLTextureUtils {
903
1034
 
904
1035
  }
905
1036
 
1037
+ /**
1038
+ * Returns the corresponding typed array type for the given WebGL data type.
1039
+ *
1040
+ * @private
1041
+ * @param {GLenum} glType - The WebGL data type.
1042
+ * @return {TypedArray.constructor} The typed array type.
1043
+ */
906
1044
  _getTypedArrayType( glType ) {
907
1045
 
908
1046
  const { gl } = this;
@@ -922,6 +1060,14 @@ class WebGLTextureUtils {
922
1060
 
923
1061
  }
924
1062
 
1063
+ /**
1064
+ * Returns the bytes-per-texel value for the given WebGL data type and texture format.
1065
+ *
1066
+ * @private
1067
+ * @param {GLenum} glType - The WebGL data type.
1068
+ * @param {GLenum} glFormat - The WebGL texture format.
1069
+ * @return {Number} The bytes-per-texel.
1070
+ */
925
1071
  _getBytesPerTexel( glType, glFormat ) {
926
1072
 
927
1073
  const { gl } = this;
@@ -0,0 +1,359 @@
1
+ import { warnOnce } from '../../../utils.js';
2
+ import TimestampQueryPool from '../../common/TimestampQueryPool.js';
3
+
4
+ /**
5
+ * Manages a pool of WebGL timestamp queries for performance measurement.
6
+ * Handles creation, execution, and resolution of timer queries using WebGL extensions.
7
+ * @extends TimestampQueryPool
8
+ */
9
+ class WebGLTimestampQueryPool extends TimestampQueryPool {
10
+
11
+ /**
12
+ * Creates a new WebGL timestamp query pool.
13
+ * @param {WebGLRenderingContext|WebGL2RenderingContext} gl - The WebGL context.
14
+ * @param {string} type - The type identifier for this query pool.
15
+ * @param {number} [maxQueries=2048] - Maximum number of queries this pool can hold.
16
+ */
17
+ constructor( gl, type, maxQueries = 2048 ) {
18
+
19
+ super( maxQueries );
20
+
21
+ this.gl = gl;
22
+ this.type = type;
23
+
24
+ // Check for timer query extensions
25
+ this.ext = gl.getExtension( 'EXT_disjoint_timer_query_webgl2' ) ||
26
+ gl.getExtension( 'EXT_disjoint_timer_query' );
27
+
28
+ if ( ! this.ext ) {
29
+
30
+ console.warn( 'EXT_disjoint_timer_query not supported; timestamps will be disabled.' );
31
+ this.trackTimestamp = false;
32
+ return;
33
+
34
+ }
35
+
36
+ // Create query objects
37
+ this.queries = [];
38
+ for ( let i = 0; i < this.maxQueries; i ++ ) {
39
+
40
+ this.queries.push( gl.createQuery() );
41
+
42
+ }
43
+
44
+ this.activeQuery = null;
45
+ this.queryStates = new Map(); // Track state of each query: 'inactive', 'started', 'ended'
46
+
47
+ }
48
+
49
+ /**
50
+ * Allocates a pair of queries for a given render context.
51
+ * @param {Object} renderContext - The render context to allocate queries for.
52
+ * @returns {?number} The base offset for the allocated queries, or null if allocation failed.
53
+ */
54
+ allocateQueriesForContext( renderContext ) {
55
+
56
+ if ( ! this.trackTimestamp ) return null;
57
+
58
+ // Check if we have enough space for a new query pair
59
+ if ( this.currentQueryIndex + 2 > this.maxQueries ) {
60
+
61
+ warnOnce( `WebGPUTimestampQueryPool [${ this.type }]: Maximum number of queries exceeded, when using trackTimestamp it is necessary to resolves the queries via renderer.resolveTimestampsAsync( THREE.TimestampQuery.${ this.type.toUpperCase() } ).` );
62
+ return null;
63
+
64
+ }
65
+
66
+ const baseOffset = this.currentQueryIndex;
67
+ this.currentQueryIndex += 2;
68
+
69
+ // Initialize query states
70
+ this.queryStates.set( baseOffset, 'inactive' );
71
+ this.queryOffsets.set( renderContext.id, baseOffset );
72
+
73
+ return baseOffset;
74
+
75
+ }
76
+
77
+ /**
78
+ * Begins a timestamp query for the specified render context.
79
+ * @param {Object} renderContext - The render context to begin timing for.
80
+ */
81
+ beginQuery( renderContext ) {
82
+
83
+ if ( ! this.trackTimestamp || this.isDisposed ) {
84
+
85
+ return;
86
+
87
+ }
88
+
89
+ const baseOffset = this.queryOffsets.get( renderContext.id );
90
+ if ( baseOffset == null ) {
91
+
92
+ return;
93
+
94
+ }
95
+
96
+ // Don't start a new query if there's an active one
97
+ if ( this.activeQuery !== null ) {
98
+
99
+ return;
100
+
101
+ }
102
+
103
+ const query = this.queries[ baseOffset ];
104
+ if ( ! query ) {
105
+
106
+ return;
107
+
108
+ }
109
+
110
+ try {
111
+
112
+ // Only begin if query is inactive
113
+ if ( this.queryStates.get( baseOffset ) === 'inactive' ) {
114
+
115
+ this.gl.beginQuery( this.ext.TIME_ELAPSED_EXT, query );
116
+ this.activeQuery = baseOffset;
117
+ this.queryStates.set( baseOffset, 'started' );
118
+
119
+ }
120
+
121
+ } catch ( error ) {
122
+
123
+ console.error( 'Error in beginQuery:', error );
124
+ this.activeQuery = null;
125
+ this.queryStates.set( baseOffset, 'inactive' );
126
+
127
+ }
128
+
129
+ }
130
+
131
+ /**
132
+ * Ends the active timestamp query for the specified render context.
133
+ * @param {Object} renderContext - The render context to end timing for.
134
+ * @param {string} renderContext.id - Unique identifier for the render context.
135
+ */
136
+ endQuery( renderContext ) {
137
+
138
+ if ( ! this.trackTimestamp || this.isDisposed ) {
139
+
140
+ return;
141
+
142
+ }
143
+
144
+ const baseOffset = this.queryOffsets.get( renderContext.id );
145
+ if ( baseOffset == null ) {
146
+
147
+ return;
148
+
149
+ }
150
+
151
+ // Only end if this is the active query
152
+ if ( this.activeQuery !== baseOffset ) {
153
+
154
+ return;
155
+
156
+ }
157
+
158
+ try {
159
+
160
+ this.gl.endQuery( this.ext.TIME_ELAPSED_EXT );
161
+ this.queryStates.set( baseOffset, 'ended' );
162
+ this.activeQuery = null;
163
+
164
+ } catch ( error ) {
165
+
166
+ console.error( 'Error in endQuery:', error );
167
+ // Reset state on error
168
+ this.queryStates.set( baseOffset, 'inactive' );
169
+ this.activeQuery = null;
170
+
171
+ }
172
+
173
+ }
174
+
175
+ /**
176
+ * Asynchronously resolves all completed queries and returns the total duration.
177
+ * @returns {Promise<number>} The total duration in milliseconds, or the last valid value if resolution fails.
178
+ */
179
+ async resolveQueriesAsync() {
180
+
181
+ if ( ! this.trackTimestamp || this.pendingResolve ) {
182
+
183
+ return this.lastValue;
184
+
185
+ }
186
+
187
+ this.pendingResolve = true;
188
+
189
+ try {
190
+
191
+ // Wait for all ended queries to complete
192
+ const resolvePromises = [];
193
+
194
+ for ( const [ baseOffset, state ] of this.queryStates ) {
195
+
196
+ if ( state === 'ended' ) {
197
+
198
+ const query = this.queries[ baseOffset ];
199
+ resolvePromises.push( this.resolveQuery( query ) );
200
+
201
+ }
202
+
203
+ }
204
+
205
+ if ( resolvePromises.length === 0 ) {
206
+
207
+ return this.lastValue;
208
+
209
+ }
210
+
211
+ const results = await Promise.all( resolvePromises );
212
+ const totalDuration = results.reduce( ( acc, val ) => acc + val, 0 );
213
+
214
+ // Store the last valid result
215
+ this.lastValue = totalDuration;
216
+
217
+ // Reset states
218
+ this.currentQueryIndex = 0;
219
+ this.queryOffsets.clear();
220
+ this.queryStates.clear();
221
+ this.activeQuery = null;
222
+
223
+ return totalDuration;
224
+
225
+ } catch ( error ) {
226
+
227
+ console.error( 'Error resolving queries:', error );
228
+ return this.lastValue;
229
+
230
+ } finally {
231
+
232
+ this.pendingResolve = false;
233
+
234
+ }
235
+
236
+ }
237
+
238
+ /**
239
+ * Resolves a single query, checking for completion and disjoint operation.
240
+ * @private
241
+ * @param {WebGLQuery} query - The query object to resolve.
242
+ * @returns {Promise<number>} The elapsed time in milliseconds.
243
+ */
244
+ async resolveQuery( query ) {
245
+
246
+ return new Promise( ( resolve ) => {
247
+
248
+ if ( this.isDisposed ) {
249
+
250
+ resolve( this.lastValue );
251
+ return;
252
+
253
+ }
254
+
255
+ let timeoutId;
256
+ let isResolved = false;
257
+
258
+ const cleanup = () => {
259
+
260
+ if ( timeoutId ) {
261
+
262
+ clearTimeout( timeoutId );
263
+ timeoutId = null;
264
+
265
+ }
266
+
267
+ };
268
+
269
+ const finalizeResolution = ( value ) => {
270
+
271
+ if ( ! isResolved ) {
272
+
273
+ isResolved = true;
274
+ cleanup();
275
+ resolve( value );
276
+
277
+ }
278
+
279
+ };
280
+
281
+ const checkQuery = () => {
282
+
283
+ if ( this.isDisposed ) {
284
+
285
+ finalizeResolution( this.lastValue );
286
+ return;
287
+
288
+ }
289
+
290
+ try {
291
+
292
+ // Check if the GPU timer was disjoint (i.e., timing was unreliable)
293
+ const disjoint = this.gl.getParameter( this.ext.GPU_DISJOINT_EXT );
294
+ if ( disjoint ) {
295
+
296
+ finalizeResolution( this.lastValue );
297
+ return;
298
+
299
+ }
300
+
301
+ const available = this.gl.getQueryParameter( query, this.gl.QUERY_RESULT_AVAILABLE );
302
+ if ( ! available ) {
303
+
304
+ timeoutId = setTimeout( checkQuery, 1 );
305
+ return;
306
+
307
+ }
308
+
309
+ const elapsed = this.gl.getQueryParameter( query, this.gl.QUERY_RESULT );
310
+ resolve( Number( elapsed ) / 1e6 ); // Convert nanoseconds to milliseconds
311
+
312
+ } catch ( error ) {
313
+
314
+ console.error( 'Error checking query:', error );
315
+ resolve( this.lastValue );
316
+
317
+ }
318
+
319
+ };
320
+
321
+ checkQuery();
322
+
323
+ } );
324
+
325
+ }
326
+
327
+ /**
328
+ * Releases all resources held by this query pool.
329
+ * This includes deleting all query objects and clearing internal state.
330
+ */
331
+ dispose() {
332
+
333
+ if ( this.isDisposed ) {
334
+
335
+ return;
336
+
337
+ }
338
+
339
+ this.isDisposed = true;
340
+
341
+ if ( ! this.trackTimestamp ) return;
342
+
343
+ for ( const query of this.queries ) {
344
+
345
+ this.gl.deleteQuery( query );
346
+
347
+ }
348
+
349
+ this.queries = [];
350
+ this.queryStates.clear();
351
+ this.queryOffsets.clear();
352
+ this.lastValue = 0;
353
+ this.activeQuery = null;
354
+
355
+ }
356
+
357
+ }
358
+
359
+ export default WebGLTimestampQueryPool;