ParticleLargeBinCullingCS.hlsl 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // RUN: %dxc -E main -T cs_6_0 %s | FileCheck %s
  2. // CHECK: threadId
  3. // CHECK: bufferLoad
  4. // CHECK: FAbs
  5. // CHECK: FMax
  6. // CHECK: Log
  7. // CHECK: Saturate
  8. // CHECK: UMin
  9. // CHECK: bufferUpdateCounter
  10. // CHECK: bufferStore
  11. // CHECK: AtomicAdd
  12. //
  13. // Copyright (c) Microsoft. All rights reserved.
  14. // This code is licensed under the MIT License (MIT).
  15. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
  16. // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
  17. // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
  18. // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  19. //
  20. // Developed by Minigraph
  21. //
  22. // Author(s): James Stanard
  23. // Julia Careaga
  24. //
  25. #include "ParticleUtility.hlsli"
  26. #define MAX_PARTICLES_PER_LARGE_BIN (16 * MAX_PARTICLES_PER_BIN)
  27. StructuredBuffer<ParticleVertex> g_VertexBuffer : register(t0);
  28. ByteAddressBuffer g_VertexCount : register(t1);
  29. RWStructuredBuffer<uint> g_LargeBinParticles : register(u0);
  30. RWStructuredBuffer<uint> g_LargeBinCounters : register(u1);
  31. RWStructuredBuffer<ParticleScreenData> g_VisibleParticles : register( u2 );
  32. cbuffer CB : register(b0)
  33. {
  34. uint2 LogTilesPerLargeBin;
  35. };
  36. [RootSignature(Particle_RootSig)]
  37. [numthreads(64, 1, 1)]
  38. void main( uint3 DTid : SV_DispatchThreadID )
  39. {
  40. uint VertexIdx = DTid.x;
  41. if (VertexIdx >= g_VertexCount.Load(4))
  42. return;
  43. //
  44. // Transform and cull the sprite
  45. //
  46. ParticleVertex Sprite = g_VertexBuffer[VertexIdx];
  47. // Frustum cull before adding this particle to list of visible particles (for rendering)
  48. float4 HPos = mul( gViewProj, float4(Sprite.Position, 1) );
  49. float Height = Sprite.Size * gVertCotangent;
  50. float Width = Height * gAspectRatio;
  51. float3 Extent = abs(HPos.xyz) - float3(Width, Height, 0);
  52. // Technically, we should check for HPos.z > 0 because this is D3D. But there is only a tiny
  53. // window of space between the eye and the near plane where this could be true.
  54. if (max(max(0.0, Extent.x), max(Extent.y, Extent.z)) > HPos.w)
  55. return;
  56. //
  57. // Generate tile-relevant draw data
  58. //
  59. ParticleScreenData Particle;
  60. float RcpW = 1.0 / HPos.w;
  61. // Compute texture LOD for this sprite
  62. float ScreenSize = Height * RcpW * gBufferDim.y;
  63. float TextureLevel = (float)firstbithigh(MaxTextureSize) - log2(ScreenSize);
  64. Particle.Corner = float2(HPos.x - Width, -HPos.y - Height) * RcpW * 0.5 + 0.5;
  65. Particle.RcpSize = HPos.w / float2(Width, Height);
  66. Particle.Depth = saturate(HPos.w * gRcpFarZ);
  67. Particle.Color = Sprite.Color;
  68. Particle.TextureIndex = (float)Sprite.TextureID;
  69. Particle.TextureLevel = TextureLevel;
  70. float2 TopLeft = max(Particle.Corner * gBufferDim, 0.0);
  71. float2 BottomRight = max(TopLeft + gBufferDim / Particle.RcpSize, 0.0);
  72. uint2 EdgeTile = uint2(gTilesPerRow, gTilesPerCol) - 1;
  73. uint2 MinTile = uint2(TopLeft) / TILE_SIZE;
  74. uint2 MaxTile = min(EdgeTile, uint2(BottomRight) / TILE_SIZE);
  75. Particle.Bounds = MinTile.x | MinTile.y << 8 | MaxTile.x << 16 | MaxTile.y << 24;
  76. uint GlobalIdx = g_VisibleParticles.IncrementCounter();
  77. g_VisibleParticles[GlobalIdx] = Particle;
  78. //
  79. // Insert the particle into all large bins it occupies
  80. //
  81. uint LargeBinsPerRow = (gBinsPerRow + 3) / 4;
  82. uint2 MinLargeBin = MinTile >> LogTilesPerLargeBin;
  83. uint2 MaxLargeBin = MaxTile >> LogTilesPerLargeBin;
  84. uint SortKey = f32tof16(Particle.Depth) << 18 | GlobalIdx;
  85. for (uint y = MinLargeBin.y; y <= MaxLargeBin.y; y++)
  86. {
  87. for (uint x = MinLargeBin.x; x <= MaxLargeBin.x; x++)
  88. {
  89. uint LargeBinIndex = y * LargeBinsPerRow + x;
  90. uint AllocIdx;
  91. InterlockedAdd(g_LargeBinCounters[LargeBinIndex], 1, AllocIdx);
  92. AllocIdx = min(AllocIdx, MAX_PARTICLES_PER_LARGE_BIN - 1);
  93. g_LargeBinParticles[LargeBinIndex * MAX_PARTICLES_PER_LARGE_BIN + AllocIdx] = SortKey;
  94. }
  95. }
  96. }