@plastic-software/three 0.180.0 → 0.181.2
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.
- package/build/three.cjs +944 -487
- package/build/three.core.js +506 -327
- package/build/three.core.min.js +1 -1
- package/build/three.module.js +436 -164
- package/build/three.module.min.js +1 -1
- package/build/three.tsl.js +8 -2
- package/build/three.tsl.min.js +1 -1
- package/build/three.webgpu.js +3753 -1177
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +3752 -1176
- package/build/three.webgpu.nodes.min.js +1 -1
- package/examples/fonts/MPLUSRounded1c/MPLUSRounded1c-Regular.typeface.json.zip +0 -0
- package/examples/fonts/MPLUSRounded1c/OFL.txt +91 -0
- package/examples/jsm/animation/CCDIKSolver.js +1 -1
- package/examples/jsm/controls/ArcballControls.js +1 -1
- package/examples/jsm/controls/DragControls.js +1 -1
- package/examples/jsm/controls/FirstPersonControls.js +1 -1
- package/examples/jsm/controls/FlyControls.js +1 -1
- package/examples/jsm/controls/OrbitControls.js +2 -2
- package/examples/jsm/controls/PointerLockControls.js +2 -2
- package/examples/jsm/controls/TrackballControls.js +1 -1
- package/examples/jsm/controls/TransformControls.js +1 -1
- package/examples/jsm/effects/AsciiEffect.js +8 -8
- package/examples/jsm/exporters/DRACOExporter.js +2 -2
- package/examples/jsm/exporters/EXRExporter.js +1 -1
- package/examples/jsm/exporters/GLTFExporter.js +3 -3
- package/examples/jsm/exporters/USDZExporter.js +9 -2
- package/examples/jsm/geometries/DecalGeometry.js +2 -2
- package/examples/jsm/geometries/ParametricGeometry.js +1 -1
- package/examples/jsm/geometries/TeapotGeometry.js +2 -2
- package/examples/jsm/geometries/TextGeometry.js +3 -2
- package/examples/jsm/gpgpu/BitonicSort.js +715 -0
- package/examples/jsm/helpers/ViewHelper.js +43 -5
- package/examples/jsm/inspector/Inspector.js +427 -0
- package/examples/jsm/inspector/RendererInspector.js +415 -0
- package/examples/jsm/inspector/tabs/Console.js +204 -0
- package/examples/jsm/inspector/tabs/Parameters.js +332 -0
- package/examples/jsm/inspector/tabs/Performance.js +268 -0
- package/examples/jsm/inspector/tabs/Viewer.js +166 -0
- package/examples/jsm/inspector/ui/Graph.js +95 -0
- package/examples/jsm/inspector/ui/Item.js +170 -0
- package/examples/jsm/inspector/ui/List.js +75 -0
- package/examples/jsm/inspector/ui/Profiler.js +170 -0
- package/examples/jsm/inspector/ui/Style.js +654 -0
- package/examples/jsm/inspector/ui/Tab.js +46 -0
- package/examples/jsm/inspector/ui/Values.js +423 -0
- package/examples/jsm/inspector/ui/utils.js +56 -0
- package/examples/jsm/interactive/HTMLMesh.js +6 -10
- package/examples/jsm/interactive/InteractiveGroup.js +1 -1
- package/examples/jsm/interactive/SelectionBox.js +30 -0
- package/examples/jsm/lights/RectAreaLightTexturesLib.js +1 -1
- package/examples/jsm/loaders/3MFLoader.js +1 -1
- package/examples/jsm/loaders/ColladaLoader.js +2 -2
- package/examples/jsm/loaders/DDSLoader.js +1 -1
- package/examples/jsm/loaders/DRACOLoader.js +73 -22
- package/examples/jsm/loaders/FBXLoader.js +2 -2
- package/examples/jsm/loaders/FontLoader.js +23 -5
- package/examples/jsm/loaders/GLTFLoader.js +5 -3
- package/examples/jsm/loaders/KTX2Loader.js +28 -21
- package/examples/jsm/loaders/KTXLoader.js +2 -2
- package/examples/jsm/loaders/LDrawLoader.js +1 -1
- package/examples/jsm/loaders/LUT3dlLoader.js +2 -2
- package/examples/jsm/loaders/LUTCubeLoader.js +1 -1
- package/examples/jsm/loaders/LWOLoader.js +2 -2
- package/examples/jsm/loaders/MaterialXLoader.js +22 -5
- package/examples/jsm/loaders/OBJLoader.js +1 -1
- package/examples/jsm/loaders/PDBLoader.js +1 -1
- package/examples/jsm/loaders/SVGLoader.js +2 -2
- package/examples/jsm/loaders/UltraHDRLoader.js +1 -1
- package/examples/jsm/math/ConvexHull.js +1 -1
- package/examples/jsm/math/ImprovedNoise.js +1 -1
- package/examples/jsm/math/SimplexNoise.js +1 -1
- package/examples/jsm/misc/ProgressiveLightMap.js +9 -3
- package/examples/jsm/misc/ProgressiveLightMapGPU.js +7 -1
- package/examples/jsm/misc/TubePainter.js +383 -40
- package/examples/jsm/modifiers/SimplifyModifier.js +1 -1
- package/examples/jsm/objects/ReflectorForSSRPass.js +1 -0
- package/examples/jsm/objects/Sky.js +1 -1
- package/examples/jsm/objects/SkyMesh.js +1 -1
- package/examples/jsm/objects/Water.js +3 -3
- package/examples/jsm/objects/WaterMesh.js +6 -6
- package/examples/jsm/postprocessing/GlitchPass.js +2 -2
- package/examples/jsm/postprocessing/UnrealBloomPass.js +8 -6
- package/examples/jsm/renderers/CSS2DRenderer.js +16 -5
- package/examples/jsm/renderers/CSS3DRenderer.js +7 -6
- package/examples/jsm/renderers/SVGRenderer.js +1 -1
- package/examples/jsm/shaders/ACESFilmicToneMappingShader.js +1 -1
- package/examples/jsm/shaders/AfterimageShader.js +1 -1
- package/examples/jsm/shaders/BleachBypassShader.js +1 -1
- package/examples/jsm/shaders/BokehShader.js +1 -1
- package/examples/jsm/shaders/BokehShader2.js +1 -1
- package/examples/jsm/shaders/DotScreenShader.js +1 -1
- package/examples/jsm/shaders/FocusShader.js +1 -1
- package/examples/jsm/shaders/GTAOShader.js +2 -2
- package/examples/jsm/shaders/GodRaysShader.js +1 -1
- package/examples/jsm/shaders/KaleidoShader.js +1 -1
- package/examples/jsm/shaders/PoissonDenoiseShader.js +2 -2
- package/examples/jsm/shaders/SSRShader.js +1 -1
- package/examples/jsm/shaders/SepiaShader.js +1 -1
- package/examples/jsm/shaders/SubsurfaceScatteringShader.js +1 -1
- package/examples/jsm/shaders/TriangleBlurShader.js +1 -1
- package/examples/jsm/shaders/VignetteShader.js +1 -1
- package/examples/jsm/transpiler/TSLEncoder.js +7 -0
- package/examples/jsm/tsl/display/AfterImageNode.js +26 -24
- package/examples/jsm/tsl/display/AnamorphicNode.js +2 -1
- package/examples/jsm/tsl/display/BloomNode.js +4 -0
- package/examples/jsm/tsl/display/DenoiseNode.js +2 -0
- package/examples/jsm/tsl/display/DepthOfFieldNode.js +7 -0
- package/examples/jsm/tsl/display/GTAONode.js +45 -5
- package/examples/jsm/tsl/display/GaussianBlurNode.js +5 -3
- package/examples/jsm/tsl/display/OutlineNode.js +11 -0
- package/examples/jsm/tsl/display/SSGINode.js +654 -0
- package/examples/jsm/tsl/display/SSRNode.js +2 -0
- package/examples/jsm/tsl/display/SSSNode.js +488 -0
- package/examples/jsm/tsl/display/TRAANode.js +123 -6
- package/examples/jsm/tsl/display/boxBlur.js +1 -0
- package/examples/jsm/tsl/display/hashBlur.js +1 -0
- package/examples/jsm/tsl/lighting/TiledLightsNode.js +21 -1
- package/examples/jsm/webxr/XRControllerModelFactory.js +1 -1
- package/examples/jsm/webxr/XRHandModelFactory.js +2 -6
- package/package.json +5 -10
- package/src/Three.Core.js +3 -2
- package/src/Three.TSL.js +7 -1
- package/src/Three.WebGPU.Nodes.js +2 -0
- package/src/Three.WebGPU.js +2 -0
- package/src/animation/AnimationClip.js +3 -2
- package/src/animation/AnimationMixer.js +3 -3
- package/src/animation/AnimationObjectGroup.js +2 -1
- package/src/animation/KeyframeTrack.js +7 -6
- package/src/animation/PropertyBinding.js +12 -11
- package/src/audio/Audio.js +10 -9
- package/src/audio/PositionalAudio.js +1 -1
- package/src/cameras/OrthographicCamera.js +1 -1
- package/src/cameras/PerspectiveCamera.js +1 -1
- package/src/cameras/StereoCamera.js +2 -2
- package/src/constants.js +1 -1
- package/src/core/BufferGeometry.js +8 -8
- package/src/core/EventDispatcher.js +1 -1
- package/src/core/InterleavedBuffer.js +1 -1
- package/src/core/InterleavedBufferAttribute.js +3 -2
- package/src/core/Object3D.js +3 -2
- package/src/core/Raycaster.js +2 -1
- package/src/core/RenderTarget.js +10 -1
- package/src/extras/Controls.js +5 -4
- package/src/extras/DataUtils.js +2 -1
- package/src/extras/Earcut.js +6 -0
- package/src/extras/ImageUtils.js +2 -2
- package/src/extras/PMREMGenerator.js +268 -55
- package/src/extras/core/Curve.js +2 -1
- package/src/extras/core/Interpolations.js +7 -1
- package/src/extras/core/ShapePath.js +4 -4
- package/src/extras/lib/earcut.js +7 -7
- package/src/geometries/BoxGeometry.js +1 -0
- package/src/geometries/CapsuleGeometry.js +1 -0
- package/src/geometries/CircleGeometry.js +1 -0
- package/src/geometries/ConeGeometry.js +1 -0
- package/src/geometries/CylinderGeometry.js +1 -0
- package/src/geometries/DodecahedronGeometry.js +1 -0
- package/src/geometries/ExtrudeGeometry.js +8 -6
- package/src/geometries/IcosahedronGeometry.js +1 -0
- package/src/geometries/LatheGeometry.js +1 -0
- package/src/geometries/OctahedronGeometry.js +1 -0
- package/src/geometries/PlaneGeometry.js +1 -0
- package/src/geometries/RingGeometry.js +1 -0
- package/src/geometries/ShapeGeometry.js +1 -0
- package/src/geometries/SphereGeometry.js +1 -0
- package/src/geometries/TetrahedronGeometry.js +1 -0
- package/src/geometries/TorusGeometry.js +1 -0
- package/src/geometries/TorusKnotGeometry.js +1 -0
- package/src/geometries/TubeGeometry.js +1 -0
- package/src/helpers/CameraHelper.js +1 -1
- package/src/loaders/AnimationLoader.js +2 -1
- package/src/loaders/AudioLoader.js +2 -1
- package/src/loaders/BufferGeometryLoader.js +2 -2
- package/src/loaders/Cache.js +2 -2
- package/src/loaders/DataTextureLoader.js +1 -1
- package/src/loaders/FileLoader.js +3 -2
- package/src/loaders/ImageBitmapLoader.js +5 -4
- package/src/loaders/ImageLoader.js +1 -1
- package/src/loaders/Loader.js +3 -3
- package/src/loaders/LoadingManager.js +25 -3
- package/src/loaders/MaterialLoader.js +3 -2
- package/src/loaders/ObjectLoader.js +13 -13
- package/src/loaders/TextureLoader.js +1 -1
- package/src/loaders/nodes/NodeLoader.js +3 -2
- package/src/materials/Material.js +4 -3
- package/src/materials/MeshBasicMaterial.js +1 -0
- package/src/materials/MeshDepthMaterial.js +1 -0
- package/src/materials/MeshLambertMaterial.js +2 -1
- package/src/materials/MeshMatcapMaterial.js +22 -0
- package/src/materials/MeshNormalMaterial.js +1 -0
- package/src/materials/MeshPhongMaterial.js +2 -1
- package/src/materials/MeshPhysicalMaterial.js +2 -1
- package/src/materials/MeshStandardMaterial.js +8 -7
- package/src/materials/MeshToonMaterial.js +1 -0
- package/src/materials/PointsMaterial.js +1 -1
- package/src/materials/ShaderMaterial.js +2 -2
- package/src/materials/nodes/Line2NodeMaterial.js +2 -2
- package/src/materials/nodes/MeshSSSNodeMaterial.js +1 -1
- package/src/materials/nodes/NodeMaterial.js +62 -22
- package/src/materials/nodes/manager/NodeMaterialObserver.js +2 -1
- package/src/math/Color.js +6 -5
- package/src/math/ColorManagement.js +2 -2
- package/src/math/Cylindrical.js +1 -1
- package/src/math/Euler.js +2 -1
- package/src/math/MathUtils.js +13 -11
- package/src/math/Matrix2.js +1 -1
- package/src/math/Matrix3.js +2 -2
- package/src/math/Matrix4.js +7 -7
- package/src/math/Plane.js +1 -1
- package/src/math/Quaternion.js +68 -66
- package/src/math/Spherical.js +1 -1
- package/src/nodes/Nodes.js +1 -1
- package/src/nodes/TSL.js +1 -1
- package/src/nodes/accessors/CubeTextureNode.js +3 -2
- package/src/nodes/accessors/InstanceNode.js +22 -4
- package/src/nodes/accessors/Lights.js +10 -0
- package/src/nodes/accessors/Normal.js +5 -4
- package/src/nodes/accessors/Position.js +18 -2
- package/src/nodes/accessors/ReferenceNode.js +2 -1
- package/src/nodes/accessors/SceneNode.js +2 -1
- package/src/nodes/accessors/StorageBufferNode.js +2 -1
- package/src/nodes/accessors/StorageTextureNode.js +22 -0
- package/src/nodes/accessors/Texture3DNode.js +1 -1
- package/src/nodes/accessors/TextureNode.js +61 -27
- package/src/nodes/code/FunctionCallNode.js +5 -4
- package/src/nodes/core/ArrayNode.js +1 -0
- package/src/nodes/core/AttributeNode.js +2 -1
- package/src/nodes/core/ContextNode.js +5 -10
- package/src/nodes/core/IndexNode.js +2 -2
- package/src/nodes/core/InputNode.js +2 -1
- package/src/nodes/core/InspectorNode.js +128 -0
- package/src/nodes/core/{CacheNode.js → IsolateNode.js} +40 -7
- package/src/nodes/core/Node.js +137 -12
- package/src/nodes/core/NodeBuilder.js +135 -21
- package/src/nodes/core/NodeFrame.js +20 -20
- package/src/nodes/core/NodeFunction.js +2 -1
- package/src/nodes/core/NodeParser.js +2 -1
- package/src/nodes/core/NodeUtils.js +17 -90
- package/src/nodes/core/ParameterNode.js +31 -0
- package/src/nodes/core/PropertyNode.js +7 -0
- package/src/nodes/core/StackNode.js +16 -14
- package/src/nodes/core/UniformNode.js +2 -1
- package/src/nodes/core/VarNode.js +70 -12
- package/src/nodes/core/VaryingNode.js +3 -2
- package/src/nodes/display/BlendModes.js +5 -4
- package/src/nodes/display/BumpMapNode.js +1 -1
- package/src/nodes/display/ColorAdjustment.js +1 -1
- package/src/nodes/display/NormalMapNode.js +2 -1
- package/src/nodes/display/PassNode.js +51 -10
- package/src/nodes/display/RenderOutputNode.js +28 -2
- package/src/nodes/display/ScreenNode.js +2 -1
- package/src/nodes/display/ToneMappingNode.js +31 -4
- package/src/nodes/display/ToonOutlinePassNode.js +8 -0
- package/src/nodes/fog/Fog.js +3 -2
- package/src/nodes/functions/BSDF/BRDF_GGX_Multiscatter.js +52 -0
- package/src/nodes/functions/BSDF/DFGApprox.js +60 -19
- package/src/nodes/functions/BasicLightingModel.js +2 -1
- package/src/nodes/functions/PhysicalLightingModel.js +3 -2
- package/src/nodes/functions/VolumetricLightingModel.js +5 -5
- package/src/nodes/geometry/RangeNode.js +40 -4
- package/src/nodes/gpgpu/ComputeBuiltinNode.js +2 -1
- package/src/nodes/gpgpu/ComputeNode.js +17 -5
- package/src/nodes/gpgpu/SubgroupFunctionNode.js +25 -0
- package/src/nodes/gpgpu/WorkgroupInfoNode.js +2 -1
- package/src/nodes/lighting/EnvironmentNode.js +6 -6
- package/src/nodes/lighting/LightsNode.js +2 -3
- package/src/nodes/lighting/PointShadowNode.js +6 -0
- package/src/nodes/lighting/ShadowFilterNode.js +2 -0
- package/src/nodes/lighting/ShadowNode.js +75 -8
- package/src/nodes/math/ConditionalNode.js +6 -5
- package/src/nodes/math/MathNode.js +22 -4
- package/src/nodes/math/OperatorNode.js +3 -2
- package/src/nodes/pmrem/PMREMUtils.js +117 -2
- package/src/nodes/shapes/Shapes.js +1 -1
- package/src/nodes/tsl/TSLBase.js +5 -2
- package/src/nodes/tsl/TSLCore.js +36 -15
- package/src/nodes/utils/DebugNode.js +2 -1
- package/src/nodes/utils/EventNode.js +36 -0
- package/src/nodes/utils/FunctionOverloadingNode.js +37 -19
- package/src/nodes/utils/JoinNode.js +3 -2
- package/src/nodes/utils/LoopNode.js +20 -24
- package/src/nodes/utils/MemberNode.js +2 -1
- package/src/nodes/utils/PostProcessingUtils.js +28 -1
- package/src/nodes/utils/RTTNode.js +12 -2
- package/src/nodes/utils/ReflectorNode.js +10 -3
- package/src/objects/Line.js +2 -1
- package/src/objects/LineSegments.js +2 -1
- package/src/objects/Skeleton.js +3 -2
- package/src/objects/SkinnedMesh.js +3 -1
- package/src/objects/Sprite.js +2 -1
- package/src/renderers/WebGLRenderer.js +49 -33
- package/src/renderers/common/Animation.js +13 -1
- package/src/renderers/common/Backend.js +93 -30
- package/src/renderers/common/Background.js +2 -1
- package/src/renderers/common/Bindings.js +56 -2
- package/src/renderers/common/CanvasTarget.js +341 -0
- package/src/renderers/common/Geometries.js +26 -0
- package/src/renderers/common/Info.js +4 -2
- package/src/renderers/common/InspectorBase.js +146 -0
- package/src/renderers/common/PostProcessing.js +6 -25
- package/src/renderers/common/QuadMesh.js +7 -1
- package/src/renderers/common/RenderList.js +7 -3
- package/src/renderers/common/RenderObject.js +3 -1
- package/src/renderers/common/RenderObjects.js +1 -1
- package/src/renderers/common/Renderer.js +436 -228
- package/src/renderers/common/RendererUtils.js +9 -0
- package/src/renderers/common/SampledTexture.js +8 -0
- package/src/renderers/common/Sampler.js +37 -11
- package/src/renderers/common/StorageTexture.js +9 -1
- package/src/renderers/common/Textures.js +89 -35
- package/src/renderers/common/TimestampQueryPool.js +63 -1
- package/src/renderers/common/UniformsGroup.js +2 -1
- package/src/renderers/common/XRManager.js +7 -3
- package/src/renderers/common/extras/PMREMGenerator.js +160 -65
- package/src/renderers/common/nodes/NodeLibrary.js +4 -2
- package/src/renderers/common/nodes/NodeSampler.js +13 -1
- package/src/renderers/common/nodes/Nodes.js +38 -16
- package/src/renderers/shaders/DFGLUTData.js +64 -0
- package/src/renderers/shaders/ShaderChunk/common.glsl.js +0 -12
- package/src/renderers/shaders/ShaderChunk/envmap_common_pars_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +52 -18
- package/src/renderers/shaders/UniformsLib.js +1 -0
- package/src/renderers/shaders/UniformsUtils.js +25 -4
- package/src/renderers/webgl/WebGLCapabilities.js +2 -1
- package/src/renderers/webgl/WebGLExtensions.js +2 -25
- package/src/renderers/webgl/WebGLInfo.js +3 -1
- package/src/renderers/webgl/WebGLProgram.js +11 -10
- package/src/renderers/webgl/WebGLPrograms.js +2 -1
- package/src/renderers/webgl/WebGLShadowMap.js +2 -1
- package/src/renderers/webgl/WebGLState.js +15 -14
- package/src/renderers/webgl/WebGLTextures.js +18 -14
- package/src/renderers/webgl/WebGLUniformsGroups.js +5 -3
- package/src/renderers/webgl-fallback/WebGLBackend.js +22 -41
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +74 -11
- package/src/renderers/webgl-fallback/utils/WebGLConstants.js +2 -3
- package/src/renderers/webgl-fallback/utils/WebGLState.js +6 -5
- package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +117 -16
- package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +42 -12
- package/src/renderers/webgpu/WebGPUBackend.js +134 -108
- package/src/renderers/webgpu/WebGPURenderer.Nodes.js +2 -1
- package/src/renderers/webgpu/WebGPURenderer.js +3 -2
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +21 -19
- package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +2 -1
- package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +5 -3
- package/src/renderers/webgpu/utils/WebGPUConstants.js +5 -0
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +44 -16
- package/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +6 -8
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +146 -74
- package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +29 -6
- package/src/renderers/webgpu/utils/WebGPUUtils.js +22 -2
- package/src/renderers/webxr/WebXRManager.js +3 -2
- package/src/textures/Source.js +2 -1
- package/src/textures/Texture.js +3 -2
- package/src/textures/VideoTexture.js +2 -0
- package/src/utils.js +67 -3
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
import { Fn, uvec2, If, instancedArray, instanceIndex, invocationLocalIndex, Loop, workgroupArray, workgroupBarrier, workgroupId, uint, select, min, max } from 'three/tsl';
|
|
2
|
+
|
|
3
|
+
const StepType = {
|
|
4
|
+
NONE: 0,
|
|
5
|
+
// Swap all values within the local range of workgroupSize * 2
|
|
6
|
+
SWAP_LOCAL: 1,
|
|
7
|
+
DISPERSE_LOCAL: 2,
|
|
8
|
+
// Swap values within global data buffer.
|
|
9
|
+
FLIP_GLOBAL: 3,
|
|
10
|
+
DISPERSE_GLOBAL: 4,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Returns the indices that will be compared in a bitonic flip operation.
|
|
16
|
+
*
|
|
17
|
+
* @tsl
|
|
18
|
+
* @private
|
|
19
|
+
* @param {Node<uint>} index - The compute thread's invocation id.
|
|
20
|
+
* @param {Node<uint>} blockHeight - The height of the block within which elements are being swapped.
|
|
21
|
+
* @returns {Node<uvec2>} The indices of the elements in the data buffer being compared.
|
|
22
|
+
*/
|
|
23
|
+
export const getBitonicFlipIndices = /*@__PURE__*/ Fn( ( [ index, blockHeight ] ) => {
|
|
24
|
+
|
|
25
|
+
const blockOffset = ( index.mul( 2 ).div( blockHeight ) ).mul( blockHeight );
|
|
26
|
+
const halfHeight = blockHeight.div( 2 );
|
|
27
|
+
const idx = uvec2(
|
|
28
|
+
index.mod( halfHeight ),
|
|
29
|
+
blockHeight.sub( index.mod( halfHeight ) ).sub( 1 )
|
|
30
|
+
);
|
|
31
|
+
idx.x.addAssign( blockOffset );
|
|
32
|
+
idx.y.addAssign( blockOffset );
|
|
33
|
+
|
|
34
|
+
return idx;
|
|
35
|
+
|
|
36
|
+
} ).setLayout( {
|
|
37
|
+
name: 'getBitonicFlipIndices',
|
|
38
|
+
type: 'uvec2',
|
|
39
|
+
inputs: [
|
|
40
|
+
{ name: 'index', type: 'uint' },
|
|
41
|
+
{ name: 'blockHeight', type: 'uint' }
|
|
42
|
+
]
|
|
43
|
+
} );
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Returns the indices that will be compared in a bitonic sort's disperse operation.
|
|
47
|
+
*
|
|
48
|
+
* @tsl
|
|
49
|
+
* @private
|
|
50
|
+
* @param {Node<uint>} index - The compute thread's invocation id.
|
|
51
|
+
* @param {Node<uint>} swapSpan - The maximum span over which elements are being swapped.
|
|
52
|
+
* @returns {Node<uvec2>} The indices of the elements in the data buffer being compared.
|
|
53
|
+
*/
|
|
54
|
+
export const getBitonicDisperseIndices = /*@__PURE__*/ Fn( ( [ index, swapSpan ] ) => {
|
|
55
|
+
|
|
56
|
+
const blockOffset = ( ( index.mul( 2 ) ).div( swapSpan ) ).mul( swapSpan );
|
|
57
|
+
const halfHeight = swapSpan.div( 2 );
|
|
58
|
+
const idx = uvec2(
|
|
59
|
+
index.mod( halfHeight ),
|
|
60
|
+
( index.mod( halfHeight ) ).add( halfHeight )
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
idx.x.addAssign( blockOffset );
|
|
64
|
+
idx.y.addAssign( blockOffset );
|
|
65
|
+
|
|
66
|
+
return idx;
|
|
67
|
+
|
|
68
|
+
} ).setLayout( {
|
|
69
|
+
name: 'getBitonicDisperseIndices',
|
|
70
|
+
type: 'uvec2',
|
|
71
|
+
inputs: [
|
|
72
|
+
{ name: 'index', type: 'uint' },
|
|
73
|
+
{ name: 'blockHeight', type: 'uint' }
|
|
74
|
+
]
|
|
75
|
+
} );
|
|
76
|
+
|
|
77
|
+
export class BitonicSort {
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Constructs a new light probe helper.
|
|
81
|
+
*
|
|
82
|
+
* @param {Renderer} renderer - The current scene's renderer.
|
|
83
|
+
* @param {StorageBufferNode} dataBuffer - The data buffer to sort.
|
|
84
|
+
* @param {Object} [options={}] - Options that modify the bitonic sort.
|
|
85
|
+
*/
|
|
86
|
+
constructor( renderer, dataBuffer, options = {} ) {
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* A reference to the renderer.
|
|
90
|
+
*
|
|
91
|
+
* @type {Renderer}
|
|
92
|
+
*/
|
|
93
|
+
this.renderer = renderer;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* A reference to the StorageBufferNode holding the data that will be sorted .
|
|
97
|
+
*
|
|
98
|
+
* @type {StorageBufferNode}
|
|
99
|
+
*/
|
|
100
|
+
this.dataBuffer = dataBuffer;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The size of the data.
|
|
104
|
+
*
|
|
105
|
+
* @type {StorageBufferNode}
|
|
106
|
+
*/
|
|
107
|
+
this.count = dataBuffer.value.count;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
*
|
|
111
|
+
* The size of each compute dispatch.
|
|
112
|
+
* @type {number}
|
|
113
|
+
*/
|
|
114
|
+
|
|
115
|
+
this.dispatchSize = this.count / 2;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The workgroup size of the compute shaders executed during the sort.
|
|
119
|
+
*
|
|
120
|
+
* @type {StorageBufferNode}
|
|
121
|
+
*/
|
|
122
|
+
this.workgroupSize = options.workgroupSize ? Math.min( this.dispatchSize, options.workgroupSize ) : Math.min( this.dispatchSize, 64 );
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* A node representing a workgroup scoped buffer that holds locally sorted elements.
|
|
126
|
+
*
|
|
127
|
+
* @type {WorkgroupInfoNode}
|
|
128
|
+
*/
|
|
129
|
+
this.localStorage = workgroupArray( dataBuffer.nodeType, this.workgroupSize * 2 );
|
|
130
|
+
|
|
131
|
+
this._tempArray = new Uint32Array( this.count );
|
|
132
|
+
for ( let i = 0; i < this.count; i ++ ) {
|
|
133
|
+
|
|
134
|
+
this._tempArray[ i ] = 0;
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* A node representing a storage buffer used for transferring the result of the global sort back to the original data buffer.
|
|
140
|
+
*
|
|
141
|
+
* @type {StorageBufferNode}
|
|
142
|
+
*/
|
|
143
|
+
this.tempBuffer = instancedArray( this.count, dataBuffer.nodeType ).setName( 'TempStorage' );
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* A node containing the current algorithm type, the current swap span, and the highest swap span.
|
|
147
|
+
*
|
|
148
|
+
* @type {StorageBufferNode}
|
|
149
|
+
*/
|
|
150
|
+
this.infoStorage = instancedArray( new Uint32Array( [ 1, 2, 2 ] ), 'uint' ).setName( 'BitonicSortInfo' );
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The number of distinct swap operations ('flips' and 'disperses') executed in an in-place
|
|
155
|
+
* bitonic sort of the current data buffer.
|
|
156
|
+
*
|
|
157
|
+
* @type {number}
|
|
158
|
+
*/
|
|
159
|
+
this.swapOpCount = this._getSwapOpCount();
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The number of steps (i.e prepping and/or executing a swap) needed to fully execute an in-place bitonic sort of the current data buffer.
|
|
163
|
+
*
|
|
164
|
+
* @type {number}
|
|
165
|
+
*/
|
|
166
|
+
this.stepCount = this._getStepCount();
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* The number of the buffer being read from.
|
|
170
|
+
*
|
|
171
|
+
* @type {string}
|
|
172
|
+
*/
|
|
173
|
+
this.readBufferName = 'Data';
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* An object containing compute shaders that execute a 'flip' swap within a global address space on elements in the data buffer.
|
|
177
|
+
*
|
|
178
|
+
* @type {Object<string, ComputeNode>}
|
|
179
|
+
*/
|
|
180
|
+
this.flipGlobalNodes = {
|
|
181
|
+
'Data': this._getFlipGlobal( this.dataBuffer, this.tempBuffer ),
|
|
182
|
+
'Temp': this._getFlipGlobal( this.tempBuffer, this.dataBuffer )
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* An object containing compute shaders that execute a 'disperse' swap within a global address space on elements in the data buffer.
|
|
187
|
+
*
|
|
188
|
+
* @type {Object<string, ComputeNode>}
|
|
189
|
+
*/
|
|
190
|
+
this.disperseGlobalNodes = {
|
|
191
|
+
'Data': this._getDisperseGlobal( this.dataBuffer, this.tempBuffer ),
|
|
192
|
+
'Temp': this._getDisperseGlobal( this.tempBuffer, this.dataBuffer )
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* A compute shader that executes a sequence of flip and disperse swaps within a local address space on elements in the data buffer.
|
|
197
|
+
*
|
|
198
|
+
* @type {ComputeNode}
|
|
199
|
+
*/
|
|
200
|
+
this.swapLocalFn = this._getSwapLocal();
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* A compute shader that executes a sequence of disperse swaps within a local address space on elements in the data buffer.
|
|
204
|
+
*
|
|
205
|
+
* @type {Object<string, ComputeNode>}
|
|
206
|
+
*/
|
|
207
|
+
this.disperseLocalNodes = {
|
|
208
|
+
'Data': this._getDisperseLocal( this.dataBuffer ),
|
|
209
|
+
'Temp': this._getDisperseLocal( this.tempBuffer ),
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Utility functions
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* A compute shader that sets up the algorithm and the swap span for the next swap operation.
|
|
216
|
+
*
|
|
217
|
+
* @type {ComputeNode}
|
|
218
|
+
*/
|
|
219
|
+
this.setAlgoFn = this._getSetAlgoFn();
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* A compute shader that aligns the result of the global swap operation with the current buffer.
|
|
223
|
+
*
|
|
224
|
+
* @type {ComputeNode}
|
|
225
|
+
*/
|
|
226
|
+
this.alignFn = this._getAlignFn();
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* A compute shader that resets the algorithm and swap span information.
|
|
231
|
+
*
|
|
232
|
+
* @type {ComputeNode}
|
|
233
|
+
*/
|
|
234
|
+
this.resetFn = this._getResetFn();
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* The current compute shader dispatch within the list of dispatches needed to complete the sort.
|
|
239
|
+
*
|
|
240
|
+
* @type {number}
|
|
241
|
+
*/
|
|
242
|
+
this.currentDispatch = 0;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The number of global swap operations that must be executed before the sort
|
|
246
|
+
* can swap in local address space.
|
|
247
|
+
*
|
|
248
|
+
* @type {number}
|
|
249
|
+
*/
|
|
250
|
+
this.globalOpsRemaining = 0;
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* The total number of global operations needed to sort elements within the current swap span.
|
|
254
|
+
*
|
|
255
|
+
* @type {number}
|
|
256
|
+
*/
|
|
257
|
+
this.globalOpsInSpan = 0;
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Get total number of distinct swaps that occur in a bitonic sort.
|
|
264
|
+
*
|
|
265
|
+
* @private
|
|
266
|
+
* @returns {number} - The total number of distinct swaps in a bitonic sort
|
|
267
|
+
*/
|
|
268
|
+
_getSwapOpCount() {
|
|
269
|
+
|
|
270
|
+
const n = Math.log2( this.count );
|
|
271
|
+
return ( n * ( n + 1 ) ) / 2;
|
|
272
|
+
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get the number of steps it takes to execute a complete bitonic sort.
|
|
277
|
+
*
|
|
278
|
+
* @private
|
|
279
|
+
* @returns {number} The number of steps it takes to execute a complete bitonic sort.
|
|
280
|
+
*/
|
|
281
|
+
_getStepCount() {
|
|
282
|
+
|
|
283
|
+
const logElements = Math.log2( this.count );
|
|
284
|
+
const logSwapSpan = Math.log2( this.workgroupSize * 2 );
|
|
285
|
+
|
|
286
|
+
const numGlobalFlips = logElements - logSwapSpan;
|
|
287
|
+
|
|
288
|
+
// Start with 1 for initial sort over all local elements
|
|
289
|
+
let numSteps = 1;
|
|
290
|
+
let numGlobalDisperses = 0;
|
|
291
|
+
|
|
292
|
+
for ( let i = 1; i <= numGlobalFlips; i ++ ) {
|
|
293
|
+
|
|
294
|
+
// Increment by the global flip that starts each global block
|
|
295
|
+
numSteps += 1;
|
|
296
|
+
// Increment by number of global disperses following the global flip
|
|
297
|
+
numSteps += numGlobalDisperses;
|
|
298
|
+
// Increment by local disperse that occurs after all global swaps are finished
|
|
299
|
+
numSteps += 1;
|
|
300
|
+
|
|
301
|
+
// Number of global disperse increases as swapSpan increases by factor of 2
|
|
302
|
+
numGlobalDisperses += 1;
|
|
303
|
+
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return numSteps;
|
|
307
|
+
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Compares and swaps two data points in the data buffer within the global address space.
|
|
312
|
+
* @param {Node<uint>} idxBefore - The index of the first data element in the data buffer.
|
|
313
|
+
* @param {Node<uint>} idxAfter - The index of the second data element in the data buffer.
|
|
314
|
+
* @param {StorageBufferNode} dataBuffer - The buffer of data to read from.
|
|
315
|
+
* @param {StorageBufferNode} tempBuffer - The buffer of data to write to.
|
|
316
|
+
* @private
|
|
317
|
+
*
|
|
318
|
+
*/
|
|
319
|
+
_globalCompareAndSwapTSL( idxBefore, idxAfter, dataBuffer, tempBuffer ) {
|
|
320
|
+
|
|
321
|
+
const data1 = dataBuffer.element( idxBefore );
|
|
322
|
+
const data2 = dataBuffer.element( idxAfter );
|
|
323
|
+
|
|
324
|
+
tempBuffer.element( idxBefore ).assign( min( data1, data2 ) );
|
|
325
|
+
tempBuffer.element( idxAfter ).assign( max( data1, data2 ) );
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Compares and swaps two data points in the data buffer within the local address space.
|
|
331
|
+
*
|
|
332
|
+
* @private
|
|
333
|
+
* @param {Node<uint>} idxBefore - The index of the first data element in the data buffer.
|
|
334
|
+
* @param {Node<uint>} idxAfter - The index of the second data element in the data buffer
|
|
335
|
+
*/
|
|
336
|
+
_localCompareAndSwapTSL( idxBefore, idxAfter ) {
|
|
337
|
+
|
|
338
|
+
const { localStorage } = this;
|
|
339
|
+
|
|
340
|
+
const data1 = localStorage.element( idxBefore ).toVar();
|
|
341
|
+
const data2 = localStorage.element( idxAfter ).toVar();
|
|
342
|
+
|
|
343
|
+
localStorage.element( idxBefore ).assign( min( data1, data2 ) );
|
|
344
|
+
localStorage.element( idxAfter ).assign( max( data1, data2 ) );
|
|
345
|
+
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Create the compute shader that performs a global disperse swap on the data buffer.
|
|
351
|
+
*
|
|
352
|
+
* @private
|
|
353
|
+
* @param {StorageBufferNode} readBuffer - The data buffer to read from.
|
|
354
|
+
* @param {StorageBufferNode} writeBuffer - The data buffer to read from.
|
|
355
|
+
* @returns {ComputeNode} - A compute shader that performs a global disperse swap on the data buffer.
|
|
356
|
+
*/
|
|
357
|
+
_getDisperseGlobal( readBuffer, writeBuffer ) {
|
|
358
|
+
|
|
359
|
+
const { infoStorage } = this;
|
|
360
|
+
|
|
361
|
+
const currentSwapSpan = infoStorage.element( 1 );
|
|
362
|
+
|
|
363
|
+
const fnDef = Fn( () => {
|
|
364
|
+
|
|
365
|
+
const idx = getBitonicDisperseIndices( instanceIndex, currentSwapSpan );
|
|
366
|
+
this._globalCompareAndSwapTSL( idx.x, idx.y, readBuffer, writeBuffer );
|
|
367
|
+
|
|
368
|
+
} )().compute( this.dispatchSize, [ this.workgroupSize ] );
|
|
369
|
+
|
|
370
|
+
return fnDef;
|
|
371
|
+
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Create the compute shader that performs a global flip swap on the data buffer.
|
|
376
|
+
*
|
|
377
|
+
* @private
|
|
378
|
+
* @param {StorageBufferNode} readBuffer - The data buffer to read from.
|
|
379
|
+
* @param {StorageBufferNode} writeBuffer - The data buffer to read from.
|
|
380
|
+
* @returns {ComputeNode} - A compute shader that executes a global flip swap.
|
|
381
|
+
*/
|
|
382
|
+
_getFlipGlobal( readBuffer, writeBuffer ) {
|
|
383
|
+
|
|
384
|
+
const { infoStorage } = this;
|
|
385
|
+
|
|
386
|
+
const currentSwapSpan = infoStorage.element( 1 );
|
|
387
|
+
|
|
388
|
+
const fnDef = Fn( () => {
|
|
389
|
+
|
|
390
|
+
const idx = getBitonicFlipIndices( instanceIndex, currentSwapSpan );
|
|
391
|
+
this._globalCompareAndSwapTSL( idx.x, idx.y, readBuffer, writeBuffer );
|
|
392
|
+
|
|
393
|
+
} )().compute( this.dispatchSize, [ this.workgroupSize ] );
|
|
394
|
+
|
|
395
|
+
return fnDef;
|
|
396
|
+
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Create the compute shader that performs a complete local swap on the data buffer.
|
|
402
|
+
*
|
|
403
|
+
* @private
|
|
404
|
+
* @returns {ComputeNode} - A compute shader that executes a full local swap.
|
|
405
|
+
*/
|
|
406
|
+
_getSwapLocal() {
|
|
407
|
+
|
|
408
|
+
const { localStorage, dataBuffer, workgroupSize } = this;
|
|
409
|
+
|
|
410
|
+
const fnDef = Fn( () => {
|
|
411
|
+
|
|
412
|
+
// Get ids of indices needed to populate workgroup local buffer.
|
|
413
|
+
// Use .toVar() to prevent these values from being recalculated multiple times.
|
|
414
|
+
const localOffset = uint( workgroupSize ).mul( 2 ).mul( workgroupId.x ).toVar();
|
|
415
|
+
|
|
416
|
+
const localID1 = invocationLocalIndex.mul( 2 );
|
|
417
|
+
const localID2 = invocationLocalIndex.mul( 2 ).add( 1 );
|
|
418
|
+
|
|
419
|
+
localStorage.element( localID1 ).assign( dataBuffer.element( localOffset.add( localID1 ) ) );
|
|
420
|
+
localStorage.element( localID2 ).assign( dataBuffer.element( localOffset.add( localID2 ) ) );
|
|
421
|
+
|
|
422
|
+
// Ensure that all local data has been populated
|
|
423
|
+
workgroupBarrier();
|
|
424
|
+
|
|
425
|
+
// Perform a chunk of the sort in a single pass that operates entirely in workgroup local space
|
|
426
|
+
// SWAP_LOCAL will always be first pass, so we start with known block height of 2
|
|
427
|
+
const flipBlockHeight = uint( 2 );
|
|
428
|
+
|
|
429
|
+
Loop( { start: uint( 2 ), end: uint( workgroupSize * 2 ), type: 'uint', condition: '<=', update: '<<= 1' }, () => {
|
|
430
|
+
|
|
431
|
+
// Ensure that last dispatch block executed
|
|
432
|
+
workgroupBarrier();
|
|
433
|
+
|
|
434
|
+
const flipIdx = getBitonicFlipIndices( invocationLocalIndex, flipBlockHeight );
|
|
435
|
+
|
|
436
|
+
this._localCompareAndSwapTSL( flipIdx.x, flipIdx.y );
|
|
437
|
+
|
|
438
|
+
const localBlockHeight = flipBlockHeight.div( 2 );
|
|
439
|
+
|
|
440
|
+
Loop( { start: localBlockHeight, end: uint( 1 ), type: 'uint', condition: '>', update: '>>= 1' }, () => {
|
|
441
|
+
|
|
442
|
+
// Ensure that last dispatch op executed
|
|
443
|
+
workgroupBarrier();
|
|
444
|
+
|
|
445
|
+
const disperseIdx = getBitonicDisperseIndices( invocationLocalIndex, localBlockHeight );
|
|
446
|
+
this._localCompareAndSwapTSL( disperseIdx.x, disperseIdx.y );
|
|
447
|
+
|
|
448
|
+
localBlockHeight.divAssign( 2 );
|
|
449
|
+
|
|
450
|
+
} );
|
|
451
|
+
|
|
452
|
+
// flipBlockHeight *= 2;
|
|
453
|
+
flipBlockHeight.shiftLeftAssign( 1 );
|
|
454
|
+
|
|
455
|
+
} );
|
|
456
|
+
|
|
457
|
+
// Ensure that all invocations have swapped their own regions of data
|
|
458
|
+
workgroupBarrier();
|
|
459
|
+
|
|
460
|
+
dataBuffer.element( localOffset.add( localID1 ) ).assign( localStorage.element( localID1 ) );
|
|
461
|
+
dataBuffer.element( localOffset.add( localID2 ) ).assign( localStorage.element( localID2 ) );
|
|
462
|
+
|
|
463
|
+
} )().compute( this.dispatchSize, [ this.workgroupSize ] );
|
|
464
|
+
|
|
465
|
+
return fnDef;
|
|
466
|
+
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Create the compute shader that performs a local disperse swap on the data buffer.
|
|
471
|
+
*
|
|
472
|
+
* @private
|
|
473
|
+
* @param {StorageBufferNode} readWriteBuffer - The data buffer to read from and write to.
|
|
474
|
+
* @returns {ComputeNode} - A compute shader that executes a local disperse swap.
|
|
475
|
+
*/
|
|
476
|
+
_getDisperseLocal( readWriteBuffer ) {
|
|
477
|
+
|
|
478
|
+
const { localStorage, workgroupSize } = this;
|
|
479
|
+
|
|
480
|
+
const fnDef = Fn( () => {
|
|
481
|
+
|
|
482
|
+
// Get ids of indices needed to populate workgroup local buffer.
|
|
483
|
+
// Use .toVar() to prevent these values from being recalculated multiple times.
|
|
484
|
+
const localOffset = uint( workgroupSize ).mul( 2 ).mul( workgroupId.x ).toVar();
|
|
485
|
+
|
|
486
|
+
const localID1 = invocationLocalIndex.mul( 2 );
|
|
487
|
+
const localID2 = invocationLocalIndex.mul( 2 ).add( 1 );
|
|
488
|
+
|
|
489
|
+
localStorage.element( localID1 ).assign( readWriteBuffer.element( localOffset.add( localID1 ) ) );
|
|
490
|
+
localStorage.element( localID2 ).assign( readWriteBuffer.element( localOffset.add( localID2 ) ) );
|
|
491
|
+
|
|
492
|
+
// Ensure that all local data has been populated
|
|
493
|
+
workgroupBarrier();
|
|
494
|
+
|
|
495
|
+
const localBlockHeight = uint( workgroupSize * 2 );
|
|
496
|
+
|
|
497
|
+
Loop( { start: localBlockHeight, end: uint( 1 ), type: 'uint', condition: '>', update: '>>= 1' }, () => {
|
|
498
|
+
|
|
499
|
+
// Ensure that last dispatch op executed
|
|
500
|
+
workgroupBarrier();
|
|
501
|
+
|
|
502
|
+
const disperseIdx = getBitonicDisperseIndices( invocationLocalIndex, localBlockHeight );
|
|
503
|
+
this._localCompareAndSwapTSL( disperseIdx.x, disperseIdx.y );
|
|
504
|
+
|
|
505
|
+
localBlockHeight.divAssign( 2 );
|
|
506
|
+
|
|
507
|
+
} );
|
|
508
|
+
|
|
509
|
+
// Ensure that all invocations have swapped their own regions of data
|
|
510
|
+
workgroupBarrier();
|
|
511
|
+
|
|
512
|
+
readWriteBuffer.element( localOffset.add( localID1 ) ).assign( localStorage.element( localID1 ) );
|
|
513
|
+
readWriteBuffer.element( localOffset.add( localID2 ) ).assign( localStorage.element( localID2 ) );
|
|
514
|
+
|
|
515
|
+
} )().compute( this.dispatchSize, [ this.workgroupSize ] );
|
|
516
|
+
|
|
517
|
+
return fnDef;
|
|
518
|
+
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Create the compute shader that resets the sort's algorithm information.
|
|
523
|
+
*
|
|
524
|
+
* @private
|
|
525
|
+
* @returns {ComputeNode} - A compute shader that resets the bitonic sort's algorithm information.
|
|
526
|
+
*/
|
|
527
|
+
_getResetFn() {
|
|
528
|
+
|
|
529
|
+
const fnDef = Fn( () => {
|
|
530
|
+
|
|
531
|
+
const { infoStorage } = this;
|
|
532
|
+
|
|
533
|
+
const currentAlgo = infoStorage.element( 0 );
|
|
534
|
+
const currentSwapSpan = infoStorage.element( 1 );
|
|
535
|
+
const maxSwapSpan = infoStorage.element( 2 );
|
|
536
|
+
|
|
537
|
+
currentAlgo.assign( StepType.SWAP_LOCAL );
|
|
538
|
+
currentSwapSpan.assign( 2 );
|
|
539
|
+
maxSwapSpan.assign( 2 );
|
|
540
|
+
|
|
541
|
+
} )().compute( 1 );
|
|
542
|
+
|
|
543
|
+
return fnDef;
|
|
544
|
+
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Create the compute shader that copies the state of the last global swap to the data buffer.
|
|
549
|
+
*
|
|
550
|
+
* @private
|
|
551
|
+
* @returns {ComputeNode} - A compute shader that copies the state of the last global swap to the data buffer.
|
|
552
|
+
*/
|
|
553
|
+
_getAlignFn() {
|
|
554
|
+
|
|
555
|
+
const { dataBuffer, tempBuffer } = this;
|
|
556
|
+
|
|
557
|
+
// TODO: Only do this in certain instances by ping-ponging which buffer gets sorted
|
|
558
|
+
// And only aligning if numDispatches % 2 === 1
|
|
559
|
+
const fnDef = Fn( () => {
|
|
560
|
+
|
|
561
|
+
dataBuffer.element( instanceIndex ).assign( tempBuffer.element( instanceIndex ) );
|
|
562
|
+
|
|
563
|
+
} )().compute( this.count, [ this.workgroupSize ] );
|
|
564
|
+
|
|
565
|
+
return fnDef;
|
|
566
|
+
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Create the compute shader that sets the bitonic sort algorithm's information.
|
|
571
|
+
*
|
|
572
|
+
* @private
|
|
573
|
+
* @returns {ComputeNode} - A compute shader that sets the bitonic sort algorithm's information.
|
|
574
|
+
*/
|
|
575
|
+
_getSetAlgoFn() {
|
|
576
|
+
|
|
577
|
+
const fnDef = Fn( () => {
|
|
578
|
+
|
|
579
|
+
const { infoStorage, workgroupSize } = this;
|
|
580
|
+
|
|
581
|
+
const currentAlgo = infoStorage.element( 0 );
|
|
582
|
+
const currentSwapSpan = infoStorage.element( 1 );
|
|
583
|
+
const maxSwapSpan = infoStorage.element( 2 );
|
|
584
|
+
|
|
585
|
+
If( currentAlgo.equal( StepType.SWAP_LOCAL ), () => {
|
|
586
|
+
|
|
587
|
+
const nextHighestSwapSpan = uint( workgroupSize * 4 );
|
|
588
|
+
|
|
589
|
+
currentAlgo.assign( StepType.FLIP_GLOBAL );
|
|
590
|
+
currentSwapSpan.assign( nextHighestSwapSpan );
|
|
591
|
+
maxSwapSpan.assign( nextHighestSwapSpan );
|
|
592
|
+
|
|
593
|
+
} ).ElseIf( currentAlgo.equal( StepType.DISPERSE_LOCAL ), () => {
|
|
594
|
+
|
|
595
|
+
currentAlgo.assign( StepType.FLIP_GLOBAL );
|
|
596
|
+
|
|
597
|
+
const nextHighestSwapSpan = maxSwapSpan.mul( 2 );
|
|
598
|
+
|
|
599
|
+
currentSwapSpan.assign( nextHighestSwapSpan );
|
|
600
|
+
maxSwapSpan.assign( nextHighestSwapSpan );
|
|
601
|
+
|
|
602
|
+
} ).Else( () => {
|
|
603
|
+
|
|
604
|
+
const nextSwapSpan = currentSwapSpan.div( 2 );
|
|
605
|
+
currentAlgo.assign(
|
|
606
|
+
select(
|
|
607
|
+
nextSwapSpan.lessThanEqual( uint( workgroupSize * 2 ) ),
|
|
608
|
+
StepType.DISPERSE_LOCAL,
|
|
609
|
+
StepType.DISPERSE_GLOBAL
|
|
610
|
+
).uniformFlow()
|
|
611
|
+
);
|
|
612
|
+
currentSwapSpan.assign( nextSwapSpan );
|
|
613
|
+
|
|
614
|
+
} );
|
|
615
|
+
|
|
616
|
+
} )().compute( 1 );
|
|
617
|
+
|
|
618
|
+
return fnDef;
|
|
619
|
+
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Executes a step of the bitonic sort operation.
|
|
624
|
+
*
|
|
625
|
+
* @param {Renderer} renderer - The current scene's renderer.
|
|
626
|
+
*/
|
|
627
|
+
computeStep( renderer ) {
|
|
628
|
+
|
|
629
|
+
// Swap local only runs once
|
|
630
|
+
if ( this.currentDispatch === 0 ) {
|
|
631
|
+
|
|
632
|
+
renderer.compute( this.swapLocalFn );
|
|
633
|
+
|
|
634
|
+
this.globalOpsRemaining = 1;
|
|
635
|
+
this.globalOpsInSpan = 1;
|
|
636
|
+
|
|
637
|
+
} else if ( this.globalOpsRemaining > 0 ) {
|
|
638
|
+
|
|
639
|
+
const swapType = this.globalOpsRemaining === this.globalOpsInSpan ? 'Flip' : 'Disperse';
|
|
640
|
+
|
|
641
|
+
renderer.compute( swapType === 'Flip' ? this.flipGlobalNodes[ this.readBufferName ] : this.disperseGlobalNodes[ this.readBufferName ] );
|
|
642
|
+
|
|
643
|
+
if ( this.readBufferName === 'Data' ) {
|
|
644
|
+
|
|
645
|
+
this.readBufferName = 'Temp';
|
|
646
|
+
|
|
647
|
+
} else {
|
|
648
|
+
|
|
649
|
+
this.readBufferName = 'Data';
|
|
650
|
+
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
this.globalOpsRemaining -= 1;
|
|
654
|
+
|
|
655
|
+
} else {
|
|
656
|
+
|
|
657
|
+
// Then run local disperses when we've finished all global swaps
|
|
658
|
+
renderer.compute( this.disperseLocalNodes[ this.readBufferName ] );
|
|
659
|
+
|
|
660
|
+
const nextSpanGlobalOps = this.globalOpsInSpan + 1;
|
|
661
|
+
this.globalOpsInSpan = nextSpanGlobalOps;
|
|
662
|
+
this.globalOpsRemaining = nextSpanGlobalOps;
|
|
663
|
+
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
this.currentDispatch += 1;
|
|
668
|
+
|
|
669
|
+
if ( this.currentDispatch === this.stepCount ) {
|
|
670
|
+
|
|
671
|
+
// If our last swap addressed only addressed the temp buffer, then re-align it with the data buffer
|
|
672
|
+
// to fulfill the requirement of an in-place sort.
|
|
673
|
+
if ( this.readBufferName === 'Temp' ) {
|
|
674
|
+
|
|
675
|
+
renderer.compute( this.alignFn );
|
|
676
|
+
this.readBufferName = 'Data';
|
|
677
|
+
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// Just reset the algorithm information
|
|
681
|
+
renderer.compute( this.resetFn );
|
|
682
|
+
|
|
683
|
+
this.currentDispatch = 0;
|
|
684
|
+
this.globalOpsRemaining = 0;
|
|
685
|
+
this.globalOpsInSpan = 0;
|
|
686
|
+
|
|
687
|
+
} else {
|
|
688
|
+
|
|
689
|
+
// Otherwise, determine what next swap span is
|
|
690
|
+
renderer.compute( this.setAlgoFn );
|
|
691
|
+
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Executes a complete bitonic sort on the data buffer.
|
|
698
|
+
*
|
|
699
|
+
* @param {Renderer} renderer - The current scene's renderer.
|
|
700
|
+
*/
|
|
701
|
+
compute( renderer ) {
|
|
702
|
+
|
|
703
|
+
this.globalOpsRemaining = 0;
|
|
704
|
+
this.globalOpsInSpan = 0;
|
|
705
|
+
this.currentDispatch = 0;
|
|
706
|
+
|
|
707
|
+
for ( let i = 0; i < this.stepCount; i ++ ) {
|
|
708
|
+
|
|
709
|
+
this.computeStep( renderer );
|
|
710
|
+
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
}
|