ParticlePreSortCS.hlsl 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // RUN: %dxc -E main -T cs_6_0 %s | FileCheck %s
  2. // CHECK: groupId
  3. // CHECK: flattenedThreadIdInGroup
  4. // CHECK: FAbs
  5. // CHECK: FMax
  6. // CHECK: Saturate
  7. // CHECK: barrier
  8. // CHECK: addrspace(3)
  9. // CHECK: barrier
  10. //
  11. // Copyright (c) Microsoft. All rights reserved.
  12. // This code is licensed under the MIT License (MIT).
  13. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
  14. // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
  15. // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
  16. // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  17. //
  18. // Developed by Minigraph
  19. //
  20. // Author: James Stanard
  21. //
  22. #include "ParticleUtility.hlsli"
  23. StructuredBuffer<ParticleVertex> g_VertexBuffer : register( t0 );
  24. ByteAddressBuffer g_VertexCount : register(t1);
  25. RWStructuredBuffer<uint> g_SortBuffer : register(u0);
  26. //RWByteAddressBuffer g_VisibleCount : register(u1);
  27. groupshared uint gs_SortKeys[2048];
  28. void FillSortKey( uint GroupStart, uint Offset, uint VertexCount )
  29. {
  30. if (GroupStart + Offset >= VertexCount)
  31. {
  32. gs_SortKeys[Offset] = 0; // Z = 0 will sort to the end of the list (back to front)
  33. return;
  34. }
  35. uint VertexIdx = GroupStart + Offset;
  36. ParticleVertex Sprite = g_VertexBuffer[VertexIdx];
  37. // Frustum cull before adding this particle to list of visible particles (for rendering)
  38. float4 HPos = mul( gViewProj, float4(Sprite.Position, 1) );
  39. float Height = Sprite.Size * gVertCotangent;
  40. float Width = Height * gAspectRatio;
  41. float3 Extent = abs(HPos.xyz) - float3(Width, Height, 0);
  42. // Frustum cull rather than sorting and rendering every particle
  43. if (max(max(0.0, Extent.x), max(Extent.y, Extent.z)) <= HPos.w)
  44. {
  45. // Encode depth as 14 bits because we only need [0, 1] at half precision.
  46. // This gives us 18-bit indices--up to 256k particles.
  47. float Depth = saturate(HPos.w * gRcpFarZ);
  48. gs_SortKeys[Offset] = f32tof16(Depth) << 18 | VertexIdx;
  49. // We should keep track of how many visible particles there are, but it probably would require a separate
  50. // shader pass so that we don't end up sorting non-visible particles.
  51. //g_VisibleCount.InterlockedAdd(0, 1);
  52. }
  53. else
  54. {
  55. // Until we can remove non-visible particles, we need to provide the actual index of the off-screen
  56. // particle. It will get culled again by the rasterizer.
  57. gs_SortKeys[Offset] = VertexIdx;
  58. }
  59. }
  60. [RootSignature(Particle_RootSig)]
  61. [numthreads(1024, 1, 1)]
  62. void main( uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex )
  63. {
  64. uint VisibleParticles = g_VertexCount.Load(4);
  65. uint GroupStart = Gid.x * 2048;
  66. if (GroupStart > VisibleParticles)
  67. {
  68. g_SortBuffer[GroupStart + GI] = 0;
  69. g_SortBuffer[GroupStart + GI + 1024] = 0;
  70. return;
  71. }
  72. FillSortKey(GroupStart, GI, VisibleParticles);
  73. FillSortKey(GroupStart, GI + 1024, VisibleParticles);
  74. GroupMemoryBarrierWithGroupSync();
  75. for (uint k = 2; k <= 2048; k <<= 1)
  76. {
  77. for (uint j = k >> 1; j > 0; j >>= 1)
  78. {
  79. uint Index1 = InsertZeroBit(GI, j);
  80. uint Index2 = Index1 | j;
  81. uint A = gs_SortKeys[Index1];
  82. uint B = gs_SortKeys[Index2];
  83. if ((A > B) != (((GroupStart + Index1) & k) == 0))
  84. {
  85. gs_SortKeys[Index1] = B;
  86. gs_SortKeys[Index2] = A;
  87. }
  88. GroupMemoryBarrierWithGroupSync();
  89. }
  90. }
  91. g_SortBuffer[GroupStart + GI] = gs_SortKeys[GI];
  92. g_SortBuffer[GroupStart + GI + 1024] = gs_SortKeys[GI + 1024];
  93. }