|
| 1 | +#--- particle-life.hlsl |
| 2 | +#define ROOT_SIGNATURE \ |
| 3 | + "RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)," \ |
| 4 | + "CBV(b0)," \ |
| 5 | + "SRV(t0)," \ |
| 6 | + "SRV(t1)," \ |
| 7 | + "UAV(u0)," \ |
| 8 | + "UAV(u1)" |
| 9 | + |
| 10 | + |
| 11 | +[[vk::binding(0)]] |
| 12 | +cbuffer CONSTANTS : register(b0) { |
| 13 | + uint ParticleTypeMax; |
| 14 | + uint NumParticles; |
| 15 | + float2 WorldSize; |
| 16 | + float Friction; |
| 17 | + float ForceMultipler; |
| 18 | +} |
| 19 | + |
| 20 | +struct Rule { |
| 21 | + float force; |
| 22 | + float min_distance; |
| 23 | + float max_distance; |
| 24 | +}; |
| 25 | + |
| 26 | +struct Particle { |
| 27 | + float2 position; |
| 28 | + float2 velocity; |
| 29 | + uint type; |
| 30 | +}; |
| 31 | + |
| 32 | +struct Vertex { |
| 33 | + float2 position; |
| 34 | + uint color; |
| 35 | +}; |
| 36 | + |
| 37 | +[[vk::binding(1)]] |
| 38 | +StructuredBuffer<Rule> Rules : register(t0); |
| 39 | +[[vk::binding(2)]] |
| 40 | +StructuredBuffer<Particle> OldParticles : register(t1); |
| 41 | +[[vk::binding(3)]] |
| 42 | +RWStructuredBuffer<Particle> NewParticles : register(u0); |
| 43 | +[[vk::binding(4)]] |
| 44 | +RWStructuredBuffer<Vertex> Vertices : register(u1); |
| 45 | + |
| 46 | + |
| 47 | +float3 particle_type_to_color(uint type); |
| 48 | +uint float_to_abgr(float3 rgb); |
| 49 | + |
| 50 | + |
| 51 | +[numthreads(32, 1, 1)] |
| 52 | +void main(uint3 dispatch_thread_id : SV_DispatchThreadID) { |
| 53 | + uint particle_id = dispatch_thread_id.x; |
| 54 | + |
| 55 | + Particle particle = OldParticles[particle_id]; |
| 56 | + |
| 57 | + // Accumulate forces |
| 58 | + float2 force = float2(0,0); |
| 59 | + float hit = 0; |
| 60 | + |
| 61 | + for (uint i = 0; i < NumParticles; ++i) { |
| 62 | + if (i == particle_id) |
| 63 | + continue; |
| 64 | + |
| 65 | + Particle other_particle = OldParticles[i]; |
| 66 | + |
| 67 | + Rule rule = Rules[particle.type * ParticleTypeMax + other_particle.type]; |
| 68 | + |
| 69 | + float2 direction = other_particle.position - particle.position; |
| 70 | + |
| 71 | + // wrapping |
| 72 | + if (direction.x > WorldSize.x * 0.5f) |
| 73 | + direction.x -= WorldSize.x; |
| 74 | + if (direction.x < WorldSize.x * -0.5f) |
| 75 | + direction.x += WorldSize.x; |
| 76 | + if (direction.y > WorldSize.y * 0.5f) |
| 77 | + direction.y -= WorldSize.y; |
| 78 | + if (direction.y < WorldSize.y * -0.5f) |
| 79 | + direction.y += WorldSize.y; |
| 80 | + |
| 81 | + // apply rule |
| 82 | + float distance = length(direction); |
| 83 | + direction = normalize(direction); |
| 84 | + |
| 85 | + if (distance < rule.min_distance) { |
| 86 | + float repulsive_amount = abs(rule.force) * (1.0f - (distance / rule.min_distance)) * -3.0f; |
| 87 | + force += direction * repulsive_amount; |
| 88 | + } |
| 89 | + |
| 90 | + if (distance < rule.max_distance) { |
| 91 | + float attract_amount = rule.force * (1.0f - (distance / rule.max_distance)); |
| 92 | + force += direction * attract_amount; |
| 93 | + hit += 0.01f; |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + float2 velocity = particle.velocity; |
| 98 | + velocity += force * ForceMultipler; |
| 99 | + velocity *= Friction; |
| 100 | + |
| 101 | + particle.position = particle.position + velocity; |
| 102 | + |
| 103 | + if (particle.position.x < 0) |
| 104 | + particle.position.x += WorldSize.x; |
| 105 | + |
| 106 | + if (particle.position.x > WorldSize.x) |
| 107 | + particle.position.x -= WorldSize.x; |
| 108 | + |
| 109 | + if (particle.position.y < 0) |
| 110 | + particle.position.y += WorldSize.y; |
| 111 | + |
| 112 | + if (particle.position.y > WorldSize.y) |
| 113 | + particle.position.y -= WorldSize.y; |
| 114 | + |
| 115 | + |
| 116 | + particle.velocity = velocity; |
| 117 | + |
| 118 | + Vertices[particle_id].position = particle.position; |
| 119 | + |
| 120 | + float3 color = particle_type_to_color(particle.type); |
| 121 | + |
| 122 | + color = lerp(color, color * 0.1f, 1-saturate(hit)); |
| 123 | + |
| 124 | + Vertices[particle_id].color = float_to_abgr(color); |
| 125 | + |
| 126 | + NewParticles[particle_id] = particle; |
| 127 | +} |
| 128 | + |
| 129 | + |
| 130 | + |
| 131 | +// from https://chilliant.com/rgb2hsv.html |
| 132 | +float3 hue2rgb(float H) { |
| 133 | + float R = abs(H * 6 - 3) - 1; |
| 134 | + float G = 2 - abs(H * 6 - 2); |
| 135 | + float B = 2 - abs(H * 6 - 4); |
| 136 | + return saturate(float3(R,G,B)); |
| 137 | +} |
| 138 | + |
| 139 | +float3 particle_type_to_color(uint type) { |
| 140 | + float hue = (float)type / float(ParticleTypeMax); |
| 141 | + return hue2rgb(hue); |
| 142 | +} |
| 143 | + |
| 144 | +uint float_to_abgr(float3 rgb) { |
| 145 | + rgb *= 255.0; |
| 146 | + |
| 147 | + uint r = rgb.x; |
| 148 | + uint g = rgb.y; |
| 149 | + uint b = rgb.z; |
| 150 | + uint a = 255; |
| 151 | + |
| 152 | + return (a << 24) | (b << 16) | (g << 8) | r; |
| 153 | +} |
| 154 | +//--- particle-life.yaml |
| 155 | +--- |
| 156 | +Shaders: |
| 157 | + - Stage: Compute |
| 158 | + Entry: main |
| 159 | + DispatchSize: [32, 1, 1] |
| 160 | +Buffers: |
| 161 | + - Name: CONSTANTS |
| 162 | + Format: Int32 |
| 163 | + Data: [ |
| 164 | + 2, # ParticleTypeMax |
| 165 | + 32, # NumParticles |
| 166 | + 576, # Width |
| 167 | + 432, # Height |
| 168 | + 1063675494, # Friction (0.9f) |
| 169 | + 1028443341, # Force Multiplier (0.05f) |
| 170 | + ] |
| 171 | + - Name: Rules |
| 172 | + Format: Float32 |
| 173 | + Stride: 12 |
| 174 | + Data: [ |
| 175 | + # Values found via PIX capture. |
| 176 | + 0.668609, 36.0982, 126.076, |
| 177 | + 0.777813, 47.3667, 153.301, |
| 178 | + 0.580675, 36.4385, 223.18, |
| 179 | + -0.4252, 49.3721, 268.325, |
| 180 | + ] |
| 181 | + - Name: OldParticles |
| 182 | + Format: Float32 |
| 183 | + Stride: 20 |
| 184 | + Data: [ |
| 185 | + # Values found via PIX capture. |
| 186 | + # Note: 1.40129846E-45f == 0x00000001 |
| 187 | + 0.696739, 142.038651, 0, 0, 0, |
| 188 | + 291.907013, 399.526642, 0, 0, 1.40129846E-45, |
| 189 | + 175.601410, 275.703766, 0, 0, 1.40129846E-45, |
| 190 | + 568.259949, 49.678871, 0, 0, 0, |
| 191 | + 403.012360, 364.514069, 0, 0, 0, |
| 192 | + 543.165344, 129.993225, 0, 0, 1.40129846E-45, |
| 193 | + 72.757988, 416.646820, 0, 0, 0, |
| 194 | + 131.410492, 240.978271, 0, 0, 1.40129846E-45, |
| 195 | + 97.691116, 348.687927, 0, 0, 1.40129846E-45, |
| 196 | + 400.843658, 79.489296, 0, 0, 1.40129846E-45, |
| 197 | + 17.295982, 21.020313, 0, 0, 1.40129846E-45, |
| 198 | + 43.010857, 110.249710, 0, 0, 1.40129846E-45, |
| 199 | + 120.579689, 289.477570, 0, 0, 0, |
| 200 | + 525.788818, 62.932449, 0, 0, 0, |
| 201 | + 174.842529, 259.451721, 0, 0, 1.40129846E-45, |
| 202 | + 149.797974, 192.973465, 0, 0, 0, |
| 203 | + 384.795868, 0.964359, 0, 0, 0, |
| 204 | + 364.804382, 424.608429, 0, 0, 0, |
| 205 | + 197.151855, 327.236420, 0, 0, 0, |
| 206 | + 248.257019, 395.461426, 0, 0, 1.40129846E-45, |
| 207 | + 137.357452, 154.307480, 0, 0, 0, |
| 208 | + 249.463043, 268.753845, 0, 0, 1.40129846E-45, |
| 209 | + 208.790161, 427.462463, 0, 0, 0, |
| 210 | + 326.137054, 65.707703, 0, 0, 1.40129846E-45, |
| 211 | + 104.155403, 329.894623, 0, 0, 1.40129846E-45, |
| 212 | + 551.543274, 30.785648, 0, 0, 0, |
| 213 | + 467.292267, 431.669495, 0, 0, 0, |
| 214 | + 257.305725, 28.127918, 0, 0, 0, |
| 215 | + 52.601646, 55.992886, 0, 0, 0, |
| 216 | + 202.340485, 285.560913, 0, 0, 1.40129846E-45, |
| 217 | + 320.065735, 225.830231, 0, 0, 0, |
| 218 | + 538.903625, 321.111237, 0, 0, 0, |
| 219 | + ] |
| 220 | + - Name: NewParticles |
| 221 | + Format: Float32 |
| 222 | + Stride: 20 |
| 223 | + ZeroInitSize: 640 |
| 224 | + - Name: ExpectedParticles |
| 225 | + Format: Float32 |
| 226 | + Stride: 20 |
| 227 | + Data: [ |
| 228 | + 0.719183, 142.013, 0.0224437, -0.0260402, 0, |
| 229 | + 291.965, 399.553, 0.0578723, 0.0264942, 1.4013e-45, |
| 230 | + 175.561, 275.738, -0.0406105, 0.0342286, 1.4013e-45, |
| 231 | + 568.239, 49.7021, -0.0212302, 0.023205, 0, |
| 232 | + 403.003, 364.533, -0.00957608, 0.0192838, 0, |
| 233 | + 543.176, 129.952, 0.0105071, -0.0414064, 1.4013e-45, |
| 234 | + 72.7691, 416.616, 0.0111061, -0.0304487, 0, |
| 235 | + 131.376, 240.927, -0.034767, -0.0512624, 1.4013e-45, |
| 236 | + 97.6543, 348.763, -0.0368595, 0.0750704, 1.4013e-45, |
| 237 | + 400.861, 79.4692, 0.0170616, -0.0201277, 1.4013e-45, |
| 238 | + 17.3085, 21.0374, 0.0125516, 0.0170663, 1.4013e-45, |
| 239 | + 43.0106, 110.25, -0.000270761, 4.26963e-05, 1.4013e-45, |
| 240 | + 120.643, 289.471, 0.0629655, -0.00696298, 0, |
| 241 | + 525.819, 62.9302, 0.0298929, -0.00222033, 0, |
| 242 | + 174.816, 259.361, -0.0265245, -0.0912027, 1.4013e-45, |
| 243 | + 149.799, 193.026, 0.00128695, 0.0527595, 0, |
| 244 | + 384.789, 0.99188, -0.00676379, 0.0275205, 0, |
| 245 | + 364.793, 424.59, -0.0112163, -0.0181641, 0, |
| 246 | + 197.127, 327.186, -0.025348, -0.0508726, 0, |
| 247 | + 248.25, 395.497, -0.00664204, 0.0360285, 1.4013e-45, |
| 248 | + 137.358, 154.353, 0.000708882, 0.0458239, 0, |
| 249 | + 249.506, 268.737, 0.043196, -0.0167597, 1.4013e-45, |
| 250 | + 208.817, 427.431, 0.0266717, -0.0318986, 0, |
| 251 | + 326.12, 65.6863, -0.0165907, -0.0213587, 1.4013e-45, |
| 252 | + 104.15, 329.865, -0.00585696, -0.0293124, 1.4013e-45, |
| 253 | + 551.528, 30.8113, -0.015763, 0.0257023, 0, |
| 254 | + 467.281, 431.663, -0.0110225, -0.00609188, 0, |
| 255 | + 257.321, 28.1362, 0.0151884, 0.008258, 0, |
| 256 | + 52.5778, 56.0035, -0.0238628, 0.0106606, 0, |
| 257 | + 202.387, 285.595, 0.0461606, 0.0336835, 1.4013e-45, |
| 258 | + 320.047, 225.841, -0.0191667, 0.0108352, 0, |
| 259 | + 538.904, 321.111, 0, 0, 0 |
| 260 | + ] |
| 261 | + - Name: Vertices |
| 262 | + Format: Float32 |
| 263 | + Stride: 12 |
| 264 | + ZeroInitSize: 384 |
| 265 | + - Name: ExpectedVertices |
| 266 | + Format: Float32 |
| 267 | + Stride: 20 |
| 268 | + Data: [ |
| 269 | + 0.719183, 142.013, -1.70142e+38, |
| 270 | + 291.965, 399.553, -2.52875e+38, |
| 271 | + 175.561, 275.738, -2.58213e+38, |
| 272 | + 568.239, 49.7021, -1.70142e+38, |
| 273 | + 403.003, 364.533, -1.70142e+38, |
| 274 | + 543.176, 129.952, -2.24852e+38, |
| 275 | + 72.7691, 416.616, -1.70142e+38, |
| 276 | + 131.376, 240.927, -2.64885e+38, |
| 277 | + 97.6543, 348.763, -2.48872e+38, |
| 278 | + 400.861, 79.4692, -2.31525e+38, |
| 279 | + 17.3085, 21.0374, -2.22184e+38, |
| 280 | + 43.0106, 110.25, -2.43534e+38, |
| 281 | + 120.643, 289.471, -1.70142e+38, |
| 282 | + 525.819, 62.9302, -1.70142e+38, |
| 283 | + 174.816, 259.361, -2.58213e+38, |
| 284 | + 149.799, 193.026, -1.70142e+38, |
| 285 | + 384.789, 0.99188, -1.70142e+38, |
| 286 | + 364.793, 424.59, -1.70142e+38, |
| 287 | + 197.127, 327.186, -1.70142e+38, |
| 288 | + 248.25, 395.497, -2.52875e+38, |
| 289 | + 137.358, 154.353, -1.70142e+38, |
| 290 | + 249.506, 268.737, -2.62216e+38, |
| 291 | + 208.817, 427.431, -1.70142e+38, |
| 292 | + 326.12, 65.6863, -2.43534e+38, |
| 293 | + 104.15, 329.865, -2.52875e+38, |
| 294 | + 551.528, 30.8113, -1.70142e+38, |
| 295 | + 467.281, 431.663, -1.70142e+38, |
| 296 | + 257.321, 28.1362, -1.70142e+38, |
| 297 | + 52.5778, 56.0035, -1.70142e+38, |
| 298 | + 202.387, 285.595, -2.62216e+38, |
| 299 | + 320.047, 225.841, -1.70142e+38, |
| 300 | + 538.904, 321.111, -1.70142e+38 |
| 301 | + ] |
| 302 | +Results: |
| 303 | + - Result: CheckNewParticles |
| 304 | + Rule: BufferFuzzy |
| 305 | + ULPT: 1000 |
| 306 | + Actual: NewParticles |
| 307 | + Expected: ExpectedParticles |
| 308 | + - Result: CheckVertices |
| 309 | + Rule: BufferFuzzy |
| 310 | + ULPT: 1000 |
| 311 | + Actual: Vertices |
| 312 | + Expected: ExpectedVertices |
| 313 | +DescriptorSets: |
| 314 | + - Resources: |
| 315 | + - Name: CONSTANTS |
| 316 | + Kind: ConstantBuffer |
| 317 | + DirectXBinding: |
| 318 | + Register: 0 |
| 319 | + Space: 0 |
| 320 | + VulkanBinding: |
| 321 | + Binding: 0 |
| 322 | + - Name: Rules |
| 323 | + Kind: StructuredBuffer |
| 324 | + DirectXBinding: |
| 325 | + Register: 0 |
| 326 | + Space: 0 |
| 327 | + VulkanBinding: |
| 328 | + Binding: 1 |
| 329 | + - Name: OldParticles |
| 330 | + Kind: StructuredBuffer |
| 331 | + DirectXBinding: |
| 332 | + Register: 1 |
| 333 | + Space: 0 |
| 334 | + VulkanBinding: |
| 335 | + Binding: 2 |
| 336 | + - Name: NewParticles |
| 337 | + Kind: RWStructuredBuffer |
| 338 | + DirectXBinding: |
| 339 | + Register: 0 |
| 340 | + Space: 0 |
| 341 | + VulkanBinding: |
| 342 | + Binding: 3 |
| 343 | + - Name: Vertices |
| 344 | + Kind: RWStructuredBuffer |
| 345 | + DirectXBinding: |
| 346 | + Register: 1 |
| 347 | + Space: 0 |
| 348 | + VulkanBinding: |
| 349 | + Binding: 4 |
| 350 | +... |
| 351 | +#--- end |
| 352 | + |
| 353 | +# UNSUPPORTED: Clang-Vulkan |
| 354 | + |
| 355 | +# CBuffer bindings seem to be broken under metal |
| 356 | +# https://github.com/llvm-beanz/offload-test-suite/issues/55 |
| 357 | +# UNSUPPORTED: Metal |
| 358 | + |
| 359 | +# RUN: split-file %s %t |
| 360 | +# RUN: %if !Vulkan %{ %dxc_target -T cs_6_0 -Fo %t.o %t/particle-life.hlsl %} |
| 361 | +# RUN: %if Vulkan %{ %dxc_target -T cs_6_0 -fspv-target-env=vulkan1.3 -fvk-use-scalar-layout -Fo %t.o %t/particle-life.hlsl %} |
| 362 | +# TODO: Specify -rootsig-define ROOT_SIGNATURE |
| 363 | +# RUN: %offloader %t/particle-life.yaml %t.o |
0 commit comments