| 678 | } |
| 679 | |
| 680 | void DrawEmittersGPU(GPUContext* context, RenderContextBatch& renderContextBatch) |
| 681 | { |
| 682 | PROFILE_GPU_CPU_NAMED("DrawEmittersGPU"); |
| 683 | ScopeReadLock systemScope(Particles::SystemLocker); |
| 684 | |
| 685 | // Count draws and sorting passes needed for resources allocation |
| 686 | uint32 indirectArgsSize = 0; |
| 687 | bool sorting = false; |
| 688 | for (const GPUEmitterDraw& draw : GPUEmitterDraws) |
| 689 | { |
| 690 | indirectArgsSize += draw.IndirectArgsSize; |
| 691 | sorting |= draw.Sorting; |
| 692 | } |
| 693 | |
| 694 | // Prepare pipeline |
| 695 | if (sorting && GPUParticlesSorting == nullptr) |
| 696 | { |
| 697 | // TODO: preload shader if platform supports GPU particles (eg. inside ParticleEmitter::load if it's GPU sim with any sort module) |
| 698 | GPUParticlesSorting = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/GPUParticlesSorting")); |
| 699 | #if COMPILE_WITH_DEV_ENV |
| 700 | if (GPUParticlesSorting) |
| 701 | GPUParticlesSorting.Get()->OnReloading.Bind<OnShaderReloading>(); |
| 702 | #endif |
| 703 | } |
| 704 | if (GPUParticlesSorting == nullptr || !GPUParticlesSorting->IsLoaded()) |
| 705 | { |
| 706 | // Skip sorting until shader is ready |
| 707 | sorting = false; |
| 708 | } |
| 709 | else if (!GPUParticlesSortingCB) |
| 710 | { |
| 711 | const auto shader = GPUParticlesSorting->GetShader(); |
| 712 | const StringAnsiView CS_Sort("CS_Sort"); |
| 713 | GPUParticlesSortingCS[0] = shader->GetCS(CS_Sort, 0); |
| 714 | GPUParticlesSortingCS[1] = shader->GetCS(CS_Sort, 1); |
| 715 | GPUParticlesSortingCS[2] = shader->GetCS(CS_Sort, 2); |
| 716 | GPUParticlesSortingCB = shader->GetCB(0); |
| 717 | ASSERT_LOW_LAYER(GPUParticlesSortingCB); |
| 718 | } |
| 719 | const uint32 indirectArgsCapacity = Math::RoundUpToPowerOf2(indirectArgsSize); |
| 720 | if (GPUIndirectArgsBuffer == nullptr) |
| 721 | GPUIndirectArgsBuffer = GPUDevice::Instance->CreateBuffer(TEXT("ParticleIndirectDrawArgsBuffer")); |
| 722 | if (GPUIndirectArgsBuffer->GetSize() < indirectArgsCapacity) |
| 723 | GPUIndirectArgsBuffer->Init(GPUBufferDescription::Argument(indirectArgsCapacity)); |
| 724 | |
| 725 | // Build indirect arguments |
| 726 | uint32 indirectArgsOffset = 0; |
| 727 | { |
| 728 | PROFILE_GPU_CPU_NAMED("Init Indirect Args"); |
| 729 | |
| 730 | GPUMemoryPass pass(context); |
| 731 | pass.Transition(GPUIndirectArgsBuffer, GPUResourceAccess::CopyWrite); |
| 732 | for (GPUEmitterDraw& draw : GPUEmitterDraws) |
| 733 | pass.Transition(draw.Buffer->GPU.Buffer, GPUResourceAccess::CopyRead); |
| 734 | |
| 735 | // Init default arguments |
| 736 | byte* indirectArgsMemory = (byte*)renderContextBatch.GetMainContext().List->Memory.Allocate(indirectArgsSize, GPU_SHADER_DATA_ALIGNMENT); |
| 737 | for (GPUEmitterDraw& draw : GPUEmitterDraws) |
no test coverage detected