From 5bd6176312f39fd2778b3e052ff94df1f890cdee Mon Sep 17 00:00:00 2001 From: Hugo Nedelec Date: Wed, 28 Jun 2023 15:01:47 +0200 Subject: [PATCH 1/3] PopcornFX Plugin v2.17.0 --- Download_SDK_Desktop.bat | 2 +- Download_SDK_Mobile.bat | 2 +- PopcornFX.uplugin | 4 +- README.md | 2 +- .../PopcornFXDependencyModuleLevelEditor.cpp | 2 +- .../Private/HUD/PopcornFXHUDProfiler.cpp | 228 ++++++++++++++---- .../Private/Internal/ParticleScene.cpp | 34 ++- .../Private/Internal/ParticleScene.h | 4 +- .../PopcornFX/Private/PopcornFXSettings.cpp | 4 + .../Private/Render/BatchDrawer_Ribbon_CPU.cpp | 12 +- .../Private/Render/BatchDrawer_Ribbon_CPU.h | 1 + .../PopcornFX/Private/Render/MaterialDesc.cpp | 32 +-- .../World/PopcornFXEmitterComponent.cpp | 55 +++-- Source/PopcornFX/Public/PopcornFXSettings.h | 16 ++ .../Public/PopcornFXVersionGenerated.h | 4 +- 15 files changed, 283 insertions(+), 119 deletions(-) diff --git a/Download_SDK_Desktop.bat b/Download_SDK_Desktop.bat index 2ee1441..baf151b 100644 --- a/Download_SDK_Desktop.bat +++ b/Download_SDK_Desktop.bat @@ -6,7 +6,7 @@ setlocal bitsadmin /reset bitsadmin /create third_party_download_desktop -bitsadmin /addfile third_party_download_desktop https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.16.5_Win64_Linux64_Mac64.7z "%~dp0\_PopcornFX_Runtime_SDK_Desktop.7z" +bitsadmin /addfile third_party_download_desktop https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.0_Win64_Linux64_Mac64.7z "%~dp0\_PopcornFX_Runtime_SDK_Desktop.7z" bitsadmin /setpriority third_party_download_desktop "FOREGROUND" bitsadmin /resume third_party_download_desktop diff --git a/Download_SDK_Mobile.bat b/Download_SDK_Mobile.bat index 5bc36f4..1b67a07 100644 --- a/Download_SDK_Mobile.bat +++ b/Download_SDK_Mobile.bat @@ -6,7 +6,7 @@ setlocal bitsadmin /reset bitsadmin /create third_party_download_mobile -bitsadmin /addfile third_party_download_mobile https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.16.5_iOS_Android.7z "%~dp0\_PopcornFX_Runtime_SDK_Mobile.7z" +bitsadmin /addfile third_party_download_mobile https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.0_iOS_Android.7z "%~dp0\_PopcornFX_Runtime_SDK_Mobile.7z" bitsadmin /setpriority third_party_download_mobile "FOREGROUND" bitsadmin /resume third_party_download_mobile diff --git a/PopcornFX.uplugin b/PopcornFX.uplugin index 1f7848f..57adc74 100644 --- a/PopcornFX.uplugin +++ b/PopcornFX.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, - "Version": 21605, - "VersionName": "2.16.5", + "Version": 21700, + "VersionName": "2.17.0", "FriendlyName": "PopcornFX", "Description": "PopcornFX Realtime Particle Solution integration into Unreal Engine", "Category": "PopcornFX", diff --git a/README.md b/README.md index 9b32fcd..406bc1b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Unreal Engine PopcornFX Plugin Integrates the **PopcornFX Runtime SDK** into **Unreal Engine 4** and **Unreal Engine 5** as a Plugin. -* **Version:** `v2.16.5` +* **Version:** `v2.17.0` * **Unreal Engine:** `4.27`, `5.0`, `5.1` and `5.2` * **Supported platforms:** `Windows`, `MacOS`, `Linux`, `iOS`, `Android`, `PS4`, `PS5`, `XboxOne`, `Xbox Series`, `Switch` diff --git a/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModuleLevelEditor.cpp b/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModuleLevelEditor.cpp index 33a7d64..fd55b40 100644 --- a/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModuleLevelEditor.cpp +++ b/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModuleLevelEditor.cpp @@ -119,7 +119,7 @@ void FPopcornFXDependencyModuleLevelEditor::FillPopcornFXMenu(FMenuBuilder &menu menuBuilder.AddMenuEntry( LOCTEXT("WikiTitle", "Plugin Wiki"), - LOCTEXT("WikiTooltip", "Opens the PopcornFX UE4 plugin wiki"), + LOCTEXT("WikiTooltip", "Opens the PopcornFX UE plugin wiki"), #if (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1) FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.BrowseDocumentation"), #else diff --git a/Source/PopcornFX/Private/HUD/PopcornFXHUDProfiler.cpp b/Source/PopcornFX/Private/HUD/PopcornFXHUDProfiler.cpp index 2f266b5..b680957 100644 --- a/Source/PopcornFX/Private/HUD/PopcornFXHUDProfiler.cpp +++ b/Source/PopcornFX/Private/HUD/PopcornFXHUDProfiler.cpp @@ -97,7 +97,7 @@ void APopcornFXHUDProfiler::DrawBar(float minX, float maxX, float yPos, float cu { const float clampedCursor = FMath::Clamp(cursor, 0.0f, 1.0f); const float sizeX = (maxX - minX) * clampedCursor; - FLinearColor color(clampedCursor, 1.f - clampedCursor, 0.f, 0.6f); + FLinearColor color(clampedCursor, 1.f - clampedCursor, 0.f, 0.8f); { FCanvasTileItem tile(FVector2D(minX, yPos), FVector2D(sizeX, thickness), color); tile.BlendMode = SE_BLEND_AlphaBlend; @@ -128,7 +128,7 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p // Grab all medium collections from the world PopcornFX::TArray allSceneTimings; - double totalUpdateTime = 0.0; + double wallUpdateTimeCPU = 0.0; u32 totalParticleCount_CPU = 0; u32 totalParticleCount_GPU = 0; u32 totalInstanceCount = 0; @@ -140,7 +140,7 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p if (sceneComp->ParticleScene() == null) continue; allSceneTimings.Merge(sceneComp->ParticleScene()->EffectTimings()); - totalUpdateTime += sceneComp->ParticleScene()->MediumCollectionUpdateTime(); + wallUpdateTimeCPU += sceneComp->ParticleScene()->MediumCollectionUpdateTime(); totalParticleCount_CPU += sceneComp->ParticleScene()->MediumCollectionParticleCount_CPU(); totalParticleCount_GPU += sceneComp->ParticleScene()->MediumCollectionParticleCount_GPU(); totalInstanceCount += sceneComp->ParticleScene()->MediumCollectionInstanceCount(); @@ -169,10 +169,19 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p const u32 frameCount = settings->HUD_UpdateTimeFrameCount; const EPopcornFXEffectsProfilerSortMode::Type sortMode = settings->EffectsProfilerSortMode; + // Sum flat times: double totalTime = 0.0; + double totalTimeCPU = 0.0; + double totalTimeGPU = 0.0; for (u32 iTiming = 0; iTiming < allSceneTimings.Count(); ++iTiming) + { totalTime += allSceneTimings[iTiming].TotalTime() / frameCount; - const float timeNormalizer = totalUpdateTime / totalTime; + totalTimeCPU += allSceneTimings[iTiming].TotalTimeCPU() / frameCount; + totalTimeGPU += allSceneTimings[iTiming].TotalTimeGPU() / frameCount; // Note: not this frame's gpu time, 2-4 frames delay + } + // Always display gpu flat time, we won't extract hardware specs here. + // This normalizes effect flat time against CPU wall time (time between mediumCollection->Update() and mediumCollection->UpdateFence()) + const float timeNormalizerCPU = wallUpdateTimeCPU / totalTimeCPU; switch (sortMode) { @@ -191,31 +200,41 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p Canvas->SetDrawColor(255, 255, 255, 255); - UFont *font = GEngine->GetSmallFont(); - FFontRenderInfo fri = Canvas->CreateFontRenderInfo(true, true); - FFontRenderInfo friNoShadow = Canvas->CreateFontRenderInfo(true, false); + const UFont *font = GEngine->GetSmallFont(); + const FFontRenderInfo fri = Canvas->CreateFontRenderInfo(true, true); + const FFontRenderInfo friNoShadow = Canvas->CreateFontRenderInfo(true, false); - FString title = TEXT("PopcornFX Effects Profiler"); - float titleWidth; - float lineHeight; + const FString title = TEXT("PopcornFX Effects Profiler"); + float titleWidth; + float lineHeight; Canvas->StrLen(font, title, titleWidth, lineHeight); float yPos = Canvas->SizeY * screenRatio; - float maxyPos = Canvas->SizeY * (1.f - screenRatio); float xPos = yPos; + const float maxyPos = Canvas->SizeY * (1.f - screenRatio); Canvas->DrawText(font, title, xPos, yPos, 1.f, 1.f, fri); yPos += lineHeight; + const bool hasGPU = totalTimeGPU > 0.0f; + const float relTimexPos = xPos + 0; - const float timexPos = relTimexPos + 60; - const float pCountCPUxPos = timexPos + 60; + const float relTimeCPUxPos = relTimexPos + 60; + const float relTimeGPUxPos = relTimeCPUxPos + 60; + const float timexPos = (hasGPU ? relTimeGPUxPos : relTimexPos) + 60; + const float timeCPUxPos = timexPos + 60; + const float timeGPUxPos = timeCPUxPos + 60; + const float pCountCPUxPos = (hasGPU ? timeGPUxPos : timexPos) + 60; const float pCountGPUxPos = pCountCPUxPos + 70; - const float iCountxPos = pCountGPUxPos + 70; + const float iCountxPos = (hasGPU ? pCountGPUxPos : pCountCPUxPos) + 70; const float effectPathxPos = iCountxPos + 60; + const float TimeLimitPerEffectSeconds = settings->TimeLimitPerEffect * 0.001f; const float CPUTimeLimitPerEffectSeconds = settings->CPUTimeLimitPerEffect * 0.001f; + const float GPUTimeLimitPerEffectSeconds = settings->GPUTimeLimitPerEffect * 0.001f; + const float TimeLimitTotalSeconds = settings->TimeLimitTotal * 0.001f; const float CPUTimeLimitTotalSeconds = settings->CPUTimeLimitTotal * 0.001f; + const float GPUTimeLimitTotalSeconds = settings->GPUTimeLimitTotal * 0.001f; const u32 CPUParticleCountLimitPerEffect = settings->CPUParticleCountLimitPerEffect; const u32 GPUParticleCountLimitPerEffect = settings->GPUParticleCountLimitPerEffect; @@ -223,48 +242,86 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p const u32 CPUParticleCountLimitTotal = settings->CPUParticleCountLimitTotal; const u32 GPUParticleCountLimitTotal = settings->GPUParticleCountLimitTotal; + // Draw summary + Canvas->DrawText(font, FString::Printf(TEXT("Timings are averaged over %d frames"), frameCount), relTimexPos, yPos, 1.f, 1.f, fri); yPos += lineHeight; - Canvas->DrawText(font, FString::Printf(TEXT("Total:")), relTimexPos, yPos, 1.f, 1.f, fri); Canvas->DrawText(font, FString::Printf(TEXT("Total time")), timexPos, yPos, 1.f, 1.f, fri); Canvas->DrawText(font, FString::Printf(TEXT("CPU count")), pCountCPUxPos, yPos, 1.f, 1.f, fri); - Canvas->DrawText(font, FString::Printf(TEXT("GPU count")), pCountGPUxPos, yPos, 1.f, 1.f, fri); Canvas->DrawText(font, FString::Printf(TEXT("Instances")), iCountxPos, yPos, 1.f, 1.f, fri); + if (hasGPU) + { + Canvas->DrawText(font, FString::Printf(TEXT("Total CPU")), timeCPUxPos, yPos, 1.f, 1.f, fri); + Canvas->DrawText(font, FString::Printf(TEXT("Total GPU")), timeGPUxPos, yPos, 1.f, 1.f, fri); + Canvas->DrawText(font, FString::Printf(TEXT("GPU count")), pCountGPUxPos, yPos, 1.f, 1.f, fri); + } yPos += lineHeight; - const PopcornFX::Units::SValueAndNamedUnit readableTotalTime = PopcornFX::Units::AutoscaleTime(totalUpdateTime, 0.5f); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTime.m_Value, ANSI_TO_TCHAR(readableTotalTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); - Canvas->DrawText(font, FString::Printf(TEXT("%d"), totalParticleCount_CPU), pCountCPUxPos, yPos, 1.f, 1.f, fri); - Canvas->DrawText(font, FString::Printf(TEXT("%d"), totalParticleCount_GPU), pCountGPUxPos, yPos, 1.f, 1.f, fri); - Canvas->DrawText(font, FString::Printf(TEXT("%d"), totalInstanceCount), iCountxPos, yPos, 1.f, 1.f, fri); - DrawBar(timexPos, pCountCPUxPos - 1, yPos, totalUpdateTime / CPUTimeLimitTotalSeconds, lineHeight); - DrawBar(pCountCPUxPos, pCountGPUxPos - 1, yPos, (float)totalParticleCount_CPU / (float)CPUParticleCountLimitTotal, lineHeight); - DrawBar(pCountGPUxPos, iCountxPos - 1, yPos, (float)totalParticleCount_GPU / (float)GPUParticleCountLimitTotal, lineHeight); + // Timings + { + const PopcornFX::Units::SValueAndNamedUnit readableTotalTime = PopcornFX::Units::AutoscaleTime(wallUpdateTimeCPU, 0.5f); + const PopcornFX::Units::SValueAndNamedUnit readableTotalTimeCPU = PopcornFX::Units::AutoscaleTime(wallUpdateTimeCPU, 0.5f); + //const PopcornFX::Units::SValueAndNamedUnit readableTotalTimeGPU = PopcornFX::Units::AutoscaleTime(totalUpdateTimeGPU, 0.5f); + DrawBar(timexPos, timeCPUxPos - 1, yPos, wallUpdateTimeCPU / TimeLimitTotalSeconds, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTime.m_Value, ANSI_TO_TCHAR(readableTotalTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); + if (hasGPU) + { + DrawBar(timeCPUxPos, timeGPUxPos - 1, yPos, wallUpdateTimeCPU / CPUTimeLimitTotalSeconds, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTimeCPU.m_Value, ANSI_TO_TCHAR(readableTotalTimeCPU.m_UnitName)), timeCPUxPos, yPos, 1.f, 1.f, friNoShadow); + //DrawBar(timeGPUxPos, pCountCPUxPos - 1, yPos, totalUpdateTimeGPU / GPUTimeLimitTotalSeconds, lineHeight); + //Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTimeGPU.m_Value, ANSI_TO_TCHAR(readableTotalTimeGPU.m_UnitName)), timeGPUxPos, yPos, 1.f, 1.f, friNoShadow); + } + } + // Counts + { + DrawBar(pCountCPUxPos, pCountGPUxPos - 1, yPos, (float)totalParticleCount_CPU / (float)CPUParticleCountLimitTotal, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%d"), totalParticleCount_CPU), pCountCPUxPos, yPos, 1.f, 1.f, fri); + if (hasGPU) + { + DrawBar(pCountGPUxPos, iCountxPos - 1, yPos, (float)totalParticleCount_GPU / (float)GPUParticleCountLimitTotal, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%d"), totalParticleCount_GPU), pCountGPUxPos, yPos, 1.f, 1.f, fri); + } + + Canvas->DrawText(font, FString::Printf(TEXT("%d"), totalInstanceCount), iCountxPos, yPos, 1.f, 1.f, fri); + } yPos += lineHeight; if (totalTime > 0.0f && !allSceneTimings.Empty()) { - Canvas->DrawText(font, TEXT("%CPU"), relTimexPos, yPos, 1.f, 1.f, fri); + Canvas->DrawText(font, TEXT("%"), relTimexPos, yPos, 1.f, 1.f, fri); + if (hasGPU) + { + Canvas->DrawText(font, TEXT("%CPU"), relTimeCPUxPos, yPos, 1.f, 1.f, fri); + Canvas->DrawText(font, TEXT("%GPU"), relTimeGPUxPos, yPos, 1.f, 1.f, fri); + Canvas->DrawText(font, TEXT("Est. CPU"), timeCPUxPos, yPos, 1.f, 1.f, fri); + Canvas->DrawText(font, TEXT("Est. GPU"), timeGPUxPos, yPos, 1.f, 1.f, fri); + Canvas->DrawText(font, TEXT("GPU count"), pCountGPUxPos, yPos, 1.f, 1.f, fri); + } Canvas->DrawText(font, TEXT("Est. time"), timexPos, yPos, 1.f, 1.f, fri); Canvas->DrawText(font, TEXT("CPU count"), pCountCPUxPos, yPos, 1.f, 1.f, fri); - Canvas->DrawText(font, TEXT("GPU count"), pCountGPUxPos, yPos, 1.f, 1.f, fri); Canvas->DrawText(font, TEXT("Instances"), iCountxPos, yPos, 1.f, 1.f, fri); Canvas->DrawText(font, TEXT("Effect path"), effectPathxPos, yPos, 1.f, 1.f, fri); yPos += lineHeight; const float maxDrawyPos = maxyPos - lineHeight * 2; // 2 last total lines double displayedTotalTime = 0.0f; + double displayedTotalTimeCPU = 0.0f; + double displayedTotalTimeGPU = 0.0f; u32 displayedTotalPCount_CPU = 0; u32 displayedTotalPCount_GPU = 0; u32 displayedTotalICount = 0; for (u32 iTiming = 0; iTiming < allSceneTimings.Count(); ++iTiming) { const float effectTime = allSceneTimings[iTiming].TotalTime() / frameCount; + const float effectTimeCPU = allSceneTimings[iTiming].TotalTimeCPU() / frameCount; + const float effectTimeGPU = allSceneTimings[iTiming].TotalTimeGPU() / frameCount; const u32 effectCPUPCount = allSceneTimings[iTiming].TotalParticleCount_CPU() / frameCount; const u32 effectGPUPCount = allSceneTimings[iTiming].TotalParticleCount_GPU() / frameCount; const u32 effectInstanceCount = allSceneTimings[iTiming].TotalInstanceCount()/* / frameCount */; // Not averaged const float effectTimeRelative = (effectTime / totalTime) * 100.0f; + const float effectTimeRelativeCPU = totalTimeCPU > 0.0 ? (effectTimeCPU / totalTimeCPU) * 100.0f : 0.0f; + const float effectTimeRelativeGPU = totalTimeGPU > 0.0 ? (effectTimeGPU / totalTimeGPU) * 100.0f : 0.0f; if (effectTimeRelative < hideBelowPerc) { @@ -272,29 +329,61 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p continue; break; // We know all following will be lower } - DrawBar(relTimexPos, timexPos - 1, yPos, effectTimeRelative / 100.0f, lineHeight); - - Canvas->DrawText(font, FString::Printf(TEXT("%.1f"), effectTimeRelative), relTimexPos, yPos, 1.f, 1.f, friNoShadow); - displayedTotalTime += effectTime; + displayedTotalTimeCPU += effectTimeCPU; + displayedTotalTimeGPU += effectTimeGPU; displayedTotalPCount_CPU += effectCPUPCount; displayedTotalPCount_GPU += effectGPUPCount; displayedTotalICount += effectInstanceCount; - const PopcornFX::Units::SValueAndNamedUnit readableTime = PopcornFX::Units::AutoscaleTime(effectTime * timeNormalizer, 0.5f); - const PopcornFX::Units::SValueAndNamedUnit readableTimeFlat = PopcornFX::Units::AutoscaleTime(effectTime, 0.5f); - - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTime.m_Value, ANSI_TO_TCHAR(readableTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); - DrawBar(timexPos, pCountCPUxPos - 1, yPos, (float)(effectTime * timeNormalizer) / (float)CPUTimeLimitPerEffectSeconds, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%d"), effectCPUPCount), pCountCPUxPos, yPos, 1.f, 1.f, friNoShadow); - DrawBar(pCountCPUxPos, pCountGPUxPos - 1, yPos, (float)effectCPUPCount / (float)CPUParticleCountLimitPerEffect, lineHeight); + // Relative time + { + DrawBar(relTimexPos, relTimeCPUxPos - 1, yPos, effectTimeRelative / 100.0f, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f"), effectTimeRelative), relTimexPos, yPos, 1.f, 1.f, friNoShadow); + if (hasGPU) + { + DrawBar(relTimeCPUxPos, relTimeGPUxPos - 1, yPos, effectTimeRelativeCPU / 100.0f, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f"), effectTimeRelativeCPU), relTimeCPUxPos, yPos, 1.f, 1.f, friNoShadow); + DrawBar(relTimeGPUxPos, timexPos - 1, yPos, effectTimeRelativeGPU / 100.0f, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f"), effectTimeRelativeGPU), relTimeGPUxPos, yPos, 1.f, 1.f, friNoShadow); + } + } - Canvas->DrawText(font, FString::Printf(TEXT("%d"), effectGPUPCount), pCountGPUxPos, yPos, 1.f, 1.f, friNoShadow); - DrawBar(pCountGPUxPos, iCountxPos - 1, yPos, (float)effectGPUPCount / (float)GPUParticleCountLimitPerEffect, lineHeight); + // Timings + { + const float timeTotalCPU = effectTimeCPU * timeNormalizerCPU; + const float timeTotalGPU = effectTimeGPU; + const float timeTotal = timeTotalCPU + timeTotalGPU; + const PopcornFX::Units::SValueAndNamedUnit readableTime = PopcornFX::Units::AutoscaleTime(timeTotal, 0.5f); + const PopcornFX::Units::SValueAndNamedUnit readableTimeCPU = PopcornFX::Units::AutoscaleTime(timeTotalCPU, 0.5f); + const PopcornFX::Units::SValueAndNamedUnit readableTimeGPU = PopcornFX::Units::AutoscaleTime(timeTotalGPU, 0.5f); + + DrawBar(timexPos, timeCPUxPos - 1, yPos, timeTotal / TimeLimitPerEffectSeconds, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTime.m_Value, ANSI_TO_TCHAR(readableTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); + if (hasGPU) + { + DrawBar(timeCPUxPos, timeGPUxPos - 1, yPos, timeTotalCPU / CPUTimeLimitPerEffectSeconds, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTimeCPU.m_Value, ANSI_TO_TCHAR(readableTimeCPU.m_UnitName)), timeCPUxPos, yPos, 1.f, 1.f, friNoShadow); + DrawBar(timeGPUxPos, pCountCPUxPos - 1, yPos, timeTotalGPU / GPUTimeLimitPerEffectSeconds, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTimeGPU.m_Value, ANSI_TO_TCHAR(readableTimeGPU.m_UnitName)), timeGPUxPos, yPos, 1.f, 1.f, friNoShadow); + } + } - Canvas->DrawText(font, FString::Printf(TEXT("%d"), effectInstanceCount), iCountxPos, yPos, 1.f, 1.f, friNoShadow); + // Counts + { + DrawBar(pCountCPUxPos, pCountGPUxPos - 1, yPos, (float)effectCPUPCount / (float)CPUParticleCountLimitPerEffect, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%d"), effectCPUPCount), pCountCPUxPos, yPos, 1.f, 1.f, friNoShadow); + if (hasGPU) + { + DrawBar(pCountGPUxPos, iCountxPos - 1, yPos, (float)effectGPUPCount / (float)GPUParticleCountLimitPerEffect, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%d"), effectGPUPCount), pCountGPUxPos, yPos, 1.f, 1.f, friNoShadow); + } + + Canvas->DrawText(font, FString::Printf(TEXT("%d"), effectInstanceCount), iCountxPos, yPos, 1.f, 1.f, friNoShadow); + } - Canvas->DrawText(font, FString::Printf(TEXT("%s"), ANSI_TO_TCHAR(allSceneTimings[iTiming].m_EffectPath.Data())), effectPathxPos, yPos, 1.f, 1.f, friNoShadow); + // Effect path + Canvas->DrawText(font, FString::Printf(TEXT("%s"), ANSI_TO_TCHAR(allSceneTimings[iTiming].m_EffectPath.Data())), effectPathxPos, yPos, 1.f, 1.f, fri); yPos += lineHeight; if (yPos > maxDrawyPos) @@ -303,21 +392,54 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p yPos += lineHeight / 2; - const float displayedEffectsPercentage = 100.0f * (displayedTotalTime / totalTime); + const float displayedEffectsPercentage = totalTime > 0.0 ? 100.0f * (displayedTotalTime / totalTime) : 0.0f; + const float displayedEffectsPercentageCPU = totalTimeCPU > 0.0 ? 100.0f * (displayedTotalTimeCPU / totalTimeCPU) : 0.0f; + const float displayedEffectsPercentageGPU = totalTimeGPU > 0.0 ? 100.0f * (displayedTotalTimeGPU / totalTimeGPU) : 0.0f; - DrawBar(relTimexPos, timexPos - 1, yPos, displayedEffectsPercentage / 100.0f, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%5.1f"), displayedEffectsPercentage), relTimexPos, yPos, 1.f, 1.f, friNoShadow); + // Relative time + { + DrawBar(relTimexPos, relTimeCPUxPos - 1, yPos, displayedEffectsPercentage / 100.0f, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%5.1f"), displayedEffectsPercentage), relTimexPos, yPos, 1.f, 1.f, friNoShadow); + if (hasGPU) + { + DrawBar(relTimeCPUxPos, relTimeGPUxPos - 1, yPos, displayedEffectsPercentageCPU / 100.0f, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%5.1f"), displayedEffectsPercentageCPU), relTimeCPUxPos, yPos, 1.f, 1.f, friNoShadow); + DrawBar(relTimeGPUxPos, timexPos - 1, yPos, displayedEffectsPercentageGPU / 100.0f, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%5.1f"), displayedEffectsPercentageGPU), relTimeGPUxPos, yPos, 1.f, 1.f, friNoShadow); + } + } - const PopcornFX::Units::SValueAndNamedUnit readableTotalDisplayedTime = PopcornFX::Units::AutoscaleTime(displayedTotalTime * timeNormalizer, 0.5f); - const PopcornFX::Units::SValueAndNamedUnit readableTotalDisplayedTimeFlat = PopcornFX::Units::AutoscaleTime(displayedTotalTime, 0.5f); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTime.m_Value, ANSI_TO_TCHAR(readableTotalDisplayedTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); - DrawBar(timexPos, pCountCPUxPos - 1, yPos, (float)(displayedTotalTime * timeNormalizer) / (float)CPUTimeLimitTotalSeconds, lineHeight); + // Timings + { + const float timeTotalCPU = displayedTotalTimeCPU * timeNormalizerCPU; + const float timeTotalGPU = displayedTotalTimeGPU; + const float timeTotal = timeTotalCPU + timeTotalGPU; + const PopcornFX::Units::SValueAndNamedUnit readableTotalDisplayedTime = PopcornFX::Units::AutoscaleTime(timeTotal, 0.5f); + const PopcornFX::Units::SValueAndNamedUnit readableTotalDisplayedTimeCPU = PopcornFX::Units::AutoscaleTime(timeTotalCPU, 0.5f); + const PopcornFX::Units::SValueAndNamedUnit readableTotalDisplayedTimeGPU = PopcornFX::Units::AutoscaleTime(timeTotalGPU, 0.5f); + DrawBar(timexPos, timeCPUxPos - 1, yPos, timeTotal / TimeLimitTotalSeconds, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTime.m_Value, ANSI_TO_TCHAR(readableTotalDisplayedTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); + if (hasGPU) + { + DrawBar(timeCPUxPos, timeGPUxPos - 1, yPos, timeTotalCPU / CPUTimeLimitTotalSeconds, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTimeCPU.m_Value, ANSI_TO_TCHAR(readableTotalDisplayedTimeCPU.m_UnitName)), timeCPUxPos, yPos, 1.f, 1.f, friNoShadow); + DrawBar(timeGPUxPos, pCountCPUxPos - 1, yPos, timeTotalGPU / GPUTimeLimitTotalSeconds, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTimeGPU.m_Value, ANSI_TO_TCHAR(readableTotalDisplayedTimeGPU.m_UnitName)), timeGPUxPos, yPos, 1.f, 1.f, friNoShadow); + } + } - Canvas->DrawText(font, FString::Printf(TEXT("%d"), displayedTotalPCount_CPU), pCountCPUxPos, yPos, 1.f, 1.f, friNoShadow); - DrawBar(pCountCPUxPos, pCountGPUxPos - 1, yPos, (float)displayedTotalPCount_CPU / (float)CPUParticleCountLimitTotal, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%d"), displayedTotalPCount_GPU), pCountGPUxPos, yPos, 1.f, 1.f, friNoShadow); - DrawBar(pCountGPUxPos, iCountxPos - 1, yPos, (float)displayedTotalPCount_GPU / (float)GPUParticleCountLimitTotal, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%d"), displayedTotalICount), iCountxPos, yPos, 1.f, 1.f, friNoShadow); + // Counts + { + DrawBar(pCountCPUxPos, pCountGPUxPos - 1, yPos, (float)displayedTotalPCount_CPU / (float)CPUParticleCountLimitTotal, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%d"), displayedTotalPCount_CPU), pCountCPUxPos, yPos, 1.f, 1.f, friNoShadow); + if (hasGPU) + { + DrawBar(pCountGPUxPos, iCountxPos - 1, yPos, (float)displayedTotalPCount_GPU / (float)GPUParticleCountLimitTotal, lineHeight); + Canvas->DrawText(font, FString::Printf(TEXT("%d"), displayedTotalPCount_GPU), pCountGPUxPos, yPos, 1.f, 1.f, friNoShadow); + } + + Canvas->DrawText(font, FString::Printf(TEXT("%d"), displayedTotalICount), iCountxPos, yPos, 1.f, 1.f, friNoShadow); + } Canvas->DrawText(font, TEXT("Effects timings displayed here"), effectPathxPos, yPos, 1.f, 1.f, fri); } diff --git a/Source/PopcornFX/Private/Internal/ParticleScene.cpp b/Source/PopcornFX/Private/Internal/ParticleScene.cpp index 25f0761..a5eb1ab 100644 --- a/Source/PopcornFX/Private/Internal/ParticleScene.cpp +++ b/Source/PopcornFX/Private/Internal/ParticleScene.cpp @@ -579,9 +579,8 @@ void CParticleScene::StartUpdate(float dt) #if (PK_PARTICLES_HAS_STATS != 0) if (FPopcornFXPlugin::Get().EffectsProfilerActive()) { - for (u32 iMedium = 0; iMedium < m_ParticleMediumCollection->Mediums().Count(); iMedium++) + for (const PopcornFX::PParticleMedium &medium : m_ParticleMediumCollection->_ActiveMediums_NoLock()) { - const PopcornFX::CParticleMedium *medium = m_ParticleMediumCollection->Mediums()[iMedium].Get(); const PopcornFX::CMediumStats *mediumStats = medium->Stats(); const PopcornFX::CParticleEffect *effect = medium->Descriptor()->ParentEffect(); @@ -2338,9 +2337,12 @@ namespace struct SFetchD3D12Context { - bool volatile m_Finished = false; - struct ID3D12Device * volatile m_Device = null; - struct ID3D12CommandQueue * volatile m_CopyCommandQueue = null; + bool volatile m_Finished = false; + struct ID3D12Device * volatile m_Device = null; +#if (PK_PARTICLES_HAS_STATS != 0) + struct ID3D12CommandQueue * volatile m_DirectCommandQueue = null; +#endif // (PK_PARTICLES_HAS_STATS != 0) + struct ID3D12CommandQueue * volatile m_CopyCommandQueue = null; void Fetch() { @@ -2352,6 +2354,14 @@ namespace #if 0 m_CopyCommandQueue = dynamicRHI->GetAdapter().GetDevice(0)->GetD3DCommandQueue(ED3D12CommandQueueType::Copy); #endif + +#if (PK_PARTICLES_HAS_STATS != 0) +# if (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1) + m_DirectCommandQueue = GetID3D12DynamicRHI()->RHIGetCommandQueue(); +# else + m_DirectCommandQueue = dynamicRHI->RHIGetD3DCommandQueue(); // Returns the direct command queue +# endif // (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1) +#endif // (PK_PARTICLES_HAS_STATS != 0) if (!PK_VERIFY(m_Device != null)) { m_Finished = true; @@ -2458,8 +2468,20 @@ bool CParticleScene::D3D12_InitIFN() return false; } + // Get info from command queue + const D3D12_COMMAND_LIST_TYPE queueType = D3D12_COMMAND_LIST_TYPE_DIRECT; // We're currently submitting in the gfx queue (_D3D12_ExecuteTasksArray) + u64 queueTimestampFrequency = 0; +#if (PK_PARTICLES_HAS_STATS != 0) + fetch->m_DirectCommandQueue->GetTimestampFrequency(&queueTimestampFrequency); +#endif // (PK_PARTICLES_HAS_STATS != 0) + m_D3D12_Device = fetch->m_Device; - PopcornFX::SD3D12Context context(m_D3D12_Device, fetch->m_CopyCommandQueue, &D3D12SerializeRootSignature, PopcornFX::CParticleUpdateManager_D3D12::CbEnqueueTask(this, &CParticleScene::D3D12_EnqueueTask)); + const PopcornFX::SD3D12Context context( m_D3D12_Device, // Device used by runtime to allocate resources + fetch->m_CopyCommandQueue, // Copy command queue used by runtime by resource handlers + &D3D12SerializeRootSignature, // Required to link internal kernels + PopcornFX::CParticleUpdateManager_D3D12::CbEnqueueTask(this, &CParticleScene::D3D12_EnqueueTask), // Enqueue cb + queueType, + queueTimestampFrequency); // Queue frequency, used to collect GPU timings (disabled in retail). delete fetch; if (!PK_VERIFY(updateManager_D3D12->BindContext(context))) diff --git a/Source/PopcornFX/Private/Internal/ParticleScene.h b/Source/PopcornFX/Private/Internal/ParticleScene.h index dacfdf7..f2eabf5 100644 --- a/Source/PopcornFX/Private/Internal/ParticleScene.h +++ b/Source/PopcornFX/Private/Internal/ParticleScene.h @@ -149,7 +149,9 @@ class CParticleScene : public PopcornFX::IParticleScene u32 m_TotalParticleCount_GPU = 0; u32 m_InstanceCount = 0; - float TotalTime() const { return m_TotalStatsReport.m_PipelineStages[PopcornFX::SEvolveStatsReport::PipelineStage_Total].m_Time; } + float TotalTime() const { return TotalTimeCPU() + TotalTimeGPU(); } + float TotalTimeCPU() const { return m_TotalStatsReport.m_PipelineStages[PopcornFX::SEvolveStatsReport::PipelineStage_Total].m_Time; } + float TotalTimeGPU() const { return m_TotalStatsReport.m_PipelineStages[PopcornFX::SEvolveStatsReport::PipelineStage_Total + PopcornFX::SEvolveStatsReport::__MaxPipelineStages].m_Time; } u32 TotalParticleCount_CPU() const { return m_TotalParticleCount_CPU; } u32 TotalParticleCount_GPU() const { return m_TotalParticleCount_GPU; } u32 TotalParticleCount() const { return m_TotalParticleCount_CPU + m_TotalParticleCount_GPU; } diff --git a/Source/PopcornFX/Private/PopcornFXSettings.cpp b/Source/PopcornFX/Private/PopcornFXSettings.cpp index 6ee0859..03dcd1b 100644 --- a/Source/PopcornFX/Private/PopcornFXSettings.cpp +++ b/Source/PopcornFX/Private/PopcornFXSettings.cpp @@ -40,8 +40,12 @@ UPopcornFXSettings::UPopcornFXSettings(const FObjectInitializer& PCIP) , PackMountPoint("/Game/") , GlobalScale(100.0f) , EnableAsserts(true) +, TimeLimitPerEffect(2.0f) , CPUTimeLimitPerEffect(2.0f) +, GPUTimeLimitPerEffect(1.0f) +, TimeLimitTotal(3.0f) , CPUTimeLimitTotal(3.0f) +, GPUTimeLimitTotal(2.0f) , CPUParticleCountLimitPerEffect(3000) , GPUParticleCountLimitPerEffect(10000) , CPUParticleCountLimitTotal(30000) diff --git a/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.cpp b/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.cpp index 76b52cd..4bb5893 100644 --- a/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.cpp +++ b/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.cpp @@ -77,6 +77,8 @@ CBatchDrawer_Ribbon_CPUBB::~CBatchDrawer_Ribbon_CPUBB() PK_ASSERT(!m_Tangents.Valid()); PK_ASSERT(!m_Texcoords.Valid()); PK_ASSERT(!m_AtlasIDs.Valid()); + PK_ASSERT(!m_UVRemaps.Valid()); + PK_ASSERT(!m_UVFactors.Valid()); PK_ASSERT(!m_SimData.Valid()); @@ -86,6 +88,7 @@ CBatchDrawer_Ribbon_CPUBB::~CBatchDrawer_Ribbon_CPUBB() PK_ASSERT(!m_ViewDependents[iView].m_Positions.Valid()); PK_ASSERT(!m_ViewDependents[iView].m_Normals.Valid()); PK_ASSERT(!m_ViewDependents[iView].m_Tangents.Valid()); + PK_ASSERT(!m_ViewDependents[iView].m_UVFactors.Valid()); } } @@ -99,6 +102,7 @@ bool CBatchDrawer_Ribbon_CPUBB::Setup(const PopcornFX::CRendererDataBase *render m_NeedsBTN = renderer->m_RendererCache->m_Flags.m_HasNormal; m_SecondUVSet = renderer->m_RendererCache->m_Flags.m_HasAtlasBlending && renderer->m_RendererCache->m_Flags.m_HasUV; m_RibbonCorrectDeformation = renderer->m_RendererCache->m_Flags.m_HasRibbonCorrectDeformation; + m_FlipUVs = renderer->m_RendererCache->m_Flags.m_RotateTexture; return true; } @@ -396,6 +400,8 @@ void CBatchDrawer_Ribbon_CPUBB::_ClearBuffers() m_Tangents.UnmapAndClear(); m_Texcoords.UnmapAndClear(); m_AtlasIDs.UnmapAndClear(); + m_UVRemaps.UnmapAndClear(); + m_UVFactors.UnmapAndClear(); m_SimData.UnmapAndClear(); @@ -578,6 +584,7 @@ bool CBatchDrawer_Ribbon_CPUBB::MapBuffers(PopcornFX::SRenderContext &ctx, const dstView.m_Exec_PNT.m_UVFactors4 = uvFactors; } } + m_BBJobs_Ribbon.m_Exec_Texcoords.m_ForUVFactor = hasUVFactors; return true; } @@ -649,6 +656,7 @@ void CBatchDrawer_Ribbon_CPUBB::_IssueDrawCall_Ribbon(const SUERenderContext &re const bool fullViewIndependent = viewDep == null; const bool viewIndependentIndices = (fullViewIndependent && m_Indices.Valid()) || (!fullViewIndependent && !viewDep->m_Indices.Valid()); const bool viewIndependentPNT = (fullViewIndependent && m_Positions.Valid()) || (!fullViewIndependent && !viewDep->m_Positions.Valid()); + const bool viewIndependentUVFactors = (fullViewIndependent && m_UVFactors.Valid()) || (!fullViewIndependent && !viewDep->m_UVFactors.Valid()); // This should never happen if (!viewIndependentIndices && (viewDep == null || !viewDep->m_Indices.Valid())) @@ -678,6 +686,8 @@ void CBatchDrawer_Ribbon_CPUBB::_IssueDrawCall_Ribbon(const SUERenderContext &re vertexFactory->m_Normals.Setup(viewIndependentPNT ? m_Normals : viewDep->m_Normals); vertexFactory->m_Tangents.Setup(viewIndependentPNT ? m_Tangents : viewDep->m_Tangents); + vertexFactory->m_UVFactors.Setup(viewIndependentUVFactors ? m_UVFactors : viewDep->m_UVFactors); + vertexFactory->m_UVScalesAndOffsets.Setup(m_UVRemaps); FPopcornFXUniforms vsUniforms; FPopcornFXBillboardVSUniforms vsUniformsbillboard; @@ -696,7 +706,7 @@ void CBatchDrawer_Ribbon_CPUBB::_IssueDrawCall_Ribbon(const SUERenderContext &re vsUniformsbillboard.InDynamicParameter3sOffset = m_AdditionalStreamOffsets[StreamOffset_DynParam3s].OffsetForShaderConstant(); commonUniformsBillboard.HasSecondUVSet = m_SecondUVSet; - commonUniformsBillboard.FlipUVs = false; + commonUniformsBillboard.FlipUVs = m_FlipUVs; commonUniformsBillboard.NeedsBTN = m_NeedsBTN; commonUniformsBillboard.CorrectRibbonDeformation = m_RibbonCorrectDeformation; diff --git a/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.h b/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.h index 15eb5c5..71298ea 100644 --- a/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.h +++ b/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.h @@ -87,6 +87,7 @@ class CBatchDrawer_Ribbon_CPUBB : public PopcornFX::CRendererBatchJobs_Ribbon_CP bool m_SecondUVSet = false; bool m_NeedsBTN = false; bool m_RibbonCorrectDeformation = false; + bool m_FlipUVs = false; // View independent buffers CPooledIndexBuffer m_Indices; diff --git a/Source/PopcornFX/Private/Render/MaterialDesc.cpp b/Source/PopcornFX/Private/Render/MaterialDesc.cpp index ebdefe1..ad02b63 100644 --- a/Source/PopcornFX/Private/Render/MaterialDesc.cpp +++ b/Source/PopcornFX/Private/Render/MaterialDesc.cpp @@ -212,31 +212,21 @@ void CRendererCache::UpdateThread_BuildBillboardingFlags(const PopcornFX::PRende if (renderer->m_RendererType == PopcornFX::Renderer_Billboard) { - const PopcornFX::SRendererFeaturePropertyValue *flipUVs = renderer->m_Declaration.FindProperty(PopcornFX::BasicRendererProperties::SID_FlipUVs()); - - if (flipUVs != null && flipUVs->ValueB()) + if (renderer->m_Declaration.IsFeatureEnabled(PopcornFX::BasicRendererProperties::SID_FlipUVs())) { - m_Flags.m_FlipU = true; + m_Flags.m_FlipU = false; m_Flags.m_FlipV = true; } } else if (renderer->m_RendererType == PopcornFX::Renderer_Ribbon) { - const PopcornFX::SRendererFeaturePropertyValue *textureUVs = renderer->m_Declaration.FindProperty(PopcornFX::BasicRendererProperties::SID_TextureUVs()); - - if (textureUVs != null && textureUVs->ValueB()) + if (renderer->m_Declaration.IsFeatureEnabled(PopcornFX::BasicRendererProperties::SID_TextureUVs())) { - const PopcornFX::SRendererFeaturePropertyValue *flipU = renderer->m_Declaration.FindProperty(PopcornFX::BasicRendererProperties::SID_TextureUVs_FlipU()); - const PopcornFX::SRendererFeaturePropertyValue *flipV = renderer->m_Declaration.FindProperty(PopcornFX::BasicRendererProperties::SID_TextureUVs_FlipV()); - const PopcornFX::SRendererFeaturePropertyValue *rotateTexture = renderer->m_Declaration.FindProperty(PopcornFX::BasicRendererProperties::SID_TextureUVs_RotateTexture()); - - m_Flags.m_FlipU = flipU != null ? flipU->ValueB() : false; - m_Flags.m_FlipV = flipV != null ? flipV->ValueB() : false; - m_Flags.m_RotateTexture = rotateTexture != null ? rotateTexture->ValueB() : false; + m_Flags.m_FlipU = renderer->m_Declaration.GetPropertyValue_B(PopcornFX::BasicRendererProperties::SID_TextureUVs_FlipU(), false); + m_Flags.m_FlipV = renderer->m_Declaration.GetPropertyValue_B(PopcornFX::BasicRendererProperties::SID_TextureUVs_FlipV(), false); + m_Flags.m_RotateTexture = renderer->m_Declaration.GetPropertyValue_B(PopcornFX::BasicRendererProperties::SID_TextureUVs_RotateTexture(), false); } - - const PopcornFX::SRendererFeaturePropertyValue *correctDeformation = renderer->m_Declaration.FindProperty(PopcornFX::BasicRendererProperties::SID_CorrectDeformation()); - m_Flags.m_HasRibbonCorrectDeformation = correctDeformation != null ? correctDeformation->ValueB() : false; + m_Flags.m_HasRibbonCorrectDeformation = renderer->m_Declaration.IsFeatureEnabled(PopcornFX::BasicRendererProperties::SID_CorrectDeformation()); } else if (renderer->m_RendererType == PopcornFX::Renderer_Mesh) { @@ -412,13 +402,7 @@ bool CMaterialDesc_GameThread::GameThread_Setup() return false; } else - { - const PopcornFX::SRendererFeaturePropertyValue *lightsTranslucent = m_Renderer->m_Declaration.FindProperty(PopcornFX::BasicRendererProperties::SID_LightTranslucent()); - m_LightsTranslucent = lightsTranslucent != null ? lightsTranslucent->ValueB() : false; - - const PopcornFX::SRendererFeaturePropertyValue *castShadows = m_Renderer->m_Declaration.FindProperty(PopcornFX::BasicRendererProperties::SID_LegacyLit_CastShadows()); - m_CastShadows = castShadows != null ? castShadows->ValueB() : false; - } + m_LightsTranslucent = m_Renderer->m_Declaration.IsFeatureEnabled(PopcornFX::BasicRendererProperties::SID_LightTranslucent()); } else { diff --git a/Source/PopcornFX/Private/World/PopcornFXEmitterComponent.cpp b/Source/PopcornFX/Private/World/PopcornFXEmitterComponent.cpp index 9bb593f..8b4f931 100644 --- a/Source/PopcornFX/Private/World/PopcornFXEmitterComponent.cpp +++ b/Source/PopcornFX/Private/World/PopcornFXEmitterComponent.cpp @@ -128,8 +128,6 @@ UPopcornFXEmitterComponent::UPopcornFXEmitterComponent(const FObjectInitializer& AttributeList = CreateDefaultSubobject("AttributeList"); - //UE_LOG(LogPopcornFXEmitterComponent, Log, TEXT("EMITTERCOMP ctor attrlist %p"), AttributeList); - AttributeList->SetFlags(RF_Transactional); AttributeList->CheckEmitter(this); @@ -149,16 +147,6 @@ UPopcornFXEmitterComponent::~UPopcornFXEmitterComponent() UE_LOG(LogPopcornFXEmitterComponent, Log, TEXT("UPopcornFXEmitterComponent::dtor '%p'"), this); #endif // HEAVY_DEBUG -#if 0 -#if defined(PK_DEBUG) - if (m_CurrentScene != null) - m_CurrentScene->RegisterDestroyedEmitter(this); -#endif // defined(PK_DEBUG) -#endif // 0 - - // Last-minute terminate call. we need to unregister from the owner scene. - TerminateEmitter(); - check(m_EffectInstancePtr == null); check(m_Started == false); check(!SelfSceneIsRegistered()); @@ -206,8 +194,6 @@ bool UPopcornFXEmitterComponent::ResolveScene(bool warnIFN) SpawnPreviewSceneIFN(world); #endif // WITH_EDITOR } - //if (!found) - // UE_LOG(LogPopcornFXEmitterComponent, Warning, TEXT("Emitter '%s': scene '%s' not found"), *GetFullName(), *(SceneName.ToString())); } m_CurrentScene = Scene != null ? Scene->ParticleScene() : null; @@ -298,11 +284,8 @@ void UPopcornFXEmitterComponent::PostEditChangeProperty(FPropertyChangedEvent& p } } - if (AttributeList != null) - { - PK_VERIFY(AttributeList->Prepare(Effect)); // make sure everything is up to date, always + if (IsValid(AttributeList)) AttributeList->CheckEmitter(this); - } } //---------------------------------------------------------------------------- @@ -531,7 +514,11 @@ bool UPopcornFXEmitterComponent::SetEffect(UPopcornFXEffect *effect, bool startE bool UPopcornFXEmitterComponent::StartEmitter() { - if (m_Destroyed || IsPendingKill() || m_DiedThisFrame) +#if (ENGINE_MAJOR_VERSION == 5) + if (m_Destroyed || m_DiedThisFrame || !IsValid(this)) +#else + if (m_Destroyed || m_DiedThisFrame || IsPendingKill()) +#endif // (ENGINE_MAJOR_VERSION == 5) { UE_LOG(LogPopcornFXEmitterComponent, Warning, TEXT("Could not StartEmitter '%s' of effect '%s': emitter was destroyed"), *GetFullName(), *Effect->GetPathName()); return false; @@ -646,10 +633,11 @@ bool UPopcornFXEmitterComponent::StartEmitter() UPopcornFXAttributeList *attributeList = GetAttributeList(); PK_ASSERT(attributeList != null); - if (attributeList != null) + if (IsValid(attributeList)) + { attributeList->RefreshAttributes(this); - if (attributeList != null) attributeList->RefreshAttributeSamplers(this, true); + } AActor *owner = GetOwner(); bool isVisible = IsVisible(); @@ -726,7 +714,11 @@ void UPopcornFXEmitterComponent::OnComponentDestroyed(bool bDestroyingHierarchy) void UPopcornFXEmitterComponent::RestartEmitter(bool killParticles) { - if (m_Destroyed || IsPendingKill() || m_DiedThisFrame) +#if (ENGINE_MAJOR_VERSION == 5) + if (m_Destroyed || m_DiedThisFrame || !IsValid(this)) +#else + if (m_Destroyed || m_DiedThisFrame || IsPendingKill()) +#endif // (ENGINE_MAJOR_VERSION == 5) { UE_LOG(LogPopcornFXEmitterComponent, Warning, TEXT("Could not RestartEmitter '%s' of effect '%s': emitter was destroyed"), *GetFullName(), *Effect->GetPathName()); return; @@ -790,7 +782,11 @@ void UPopcornFXEmitterComponent::StopEmitter(bool killParticles) bool UPopcornFXEmitterComponent::ToggleEmitter(bool startEmitter, bool killParticles) { - if (m_Destroyed || IsPendingKill() || m_DiedThisFrame) +#if (ENGINE_MAJOR_VERSION == 5) + if (m_Destroyed || m_DiedThisFrame || !IsValid(this)) +#else + if (m_Destroyed || m_DiedThisFrame || IsPendingKill()) +#endif // (ENGINE_MAJOR_VERSION == 5) { UE_LOG(LogPopcornFXEmitterComponent, Warning, TEXT("Could not ToggleEmitter '%s' of effect '%s': emitter was destroyed"), *GetFullName(), *Effect->GetPathName()); return false; @@ -868,6 +864,12 @@ void UPopcornFXEmitterComponent::TerminateEmitter(bool killParticles) CheckForDead(); // can call OnEmissionStops + // Force unregister + if (SelfSceneIsRegistered()) + SelfSceneUnregister(); + if (SelfSceneIsPreInitRegistered()) + SelfPreInitSceneUnregister(); + PK_ASSERT(!SelfSceneIsRegistered()); PK_ASSERT(!SelfSceneIsPreInitRegistered()); PK_ASSERT(m_EffectInstancePtr == null); @@ -1347,7 +1349,7 @@ void UPopcornFXEmitterComponent::OnRegister() // Sometimes UE reflection breaks connection with the underlying AttributeList member, not sure why. // Returning here instead of crashing below, and UE properly re-registers the component later on.. // Ugly but does the trick (there is probably wrong done plugin side that causes this issue) - if (AttributeList == null) + if (!IsValid(AttributeList)) return; // Avoids Prepare call on the attribute list before the PostEditChangeProperty is called @@ -1619,10 +1621,11 @@ void UPopcornFXEmitterComponent::CheckForDead() { m_DiedThisFrame = false; + // Instance died: unregister from the scene if (SelfSceneIsRegistered()) - { SelfSceneUnregister(); - } + if (SelfSceneIsPreInitRegistered()) + SelfPreInitSceneUnregister(); // if effect dies, need to unregister all events listeners UnregisterAllEventsListeners(); diff --git a/Source/PopcornFX/Public/PopcornFXSettings.h b/Source/PopcornFX/Public/PopcornFXSettings.h index 83eb13b..c49169e 100644 --- a/Source/PopcornFX/Public/PopcornFXSettings.h +++ b/Source/PopcornFX/Public/PopcornFXSettings.h @@ -259,14 +259,30 @@ class UPopcornFXSettings : public UObject UPROPERTY(Config, EditAnywhere, Category="PopcornFX Materials") FPopcornFXDefaultMaterialsSettings DefaultMaterials; + /** Time limit per effect in miliseconds (does not affect simulated effects yet) */ + UPROPERTY(Config, EditAnywhere, Category="PopcornFX Budget") + float TimeLimitPerEffect; + /** CPU time limit per effect in miliseconds (does not affect simulated effects yet) */ UPROPERTY(Config, EditAnywhere, Category="PopcornFX Budget") float CPUTimeLimitPerEffect; + /** GPU time limit per effect in miliseconds (does not affect simulated effects yet) */ + UPROPERTY(Config, EditAnywhere, Category="PopcornFX Budget") + float GPUTimeLimitPerEffect; + + /** Time limit in miliseconds (does not affect simulated effects yet) */ + UPROPERTY(Config, EditAnywhere, Category="PopcornFX Budget") + float TimeLimitTotal; + /** CPU time limit in miliseconds (does not affect simulated effects yet) */ UPROPERTY(Config, EditAnywhere, Category="PopcornFX Budget") float CPUTimeLimitTotal; + /** GPU time limit in miliseconds (does not affect simulated effects yet) */ + UPROPERTY(Config, EditAnywhere, Category="PopcornFX Budget") + float GPUTimeLimitTotal; + /** CPU particle count limit per effect (does not affect simulated effects yet) */ UPROPERTY(Config, EditAnywhere, Category="PopcornFX Budget") uint32 CPUParticleCountLimitPerEffect; diff --git a/Source/PopcornFX/Public/PopcornFXVersionGenerated.h b/Source/PopcornFX/Public/PopcornFXVersionGenerated.h index 58a7fcc..a4a1d44 100644 --- a/Source/PopcornFX/Public/PopcornFXVersionGenerated.h +++ b/Source/PopcornFX/Public/PopcornFXVersionGenerated.h @@ -6,6 +6,6 @@ #pragma once #define POPCORNFX_PLUGIN_VERSION_MAJOR 2 -#define POPCORNFX_PLUGIN_VERSION_MINOR 16 -#define POPCORNFX_PLUGIN_VERSION_PATCH 5 +#define POPCORNFX_PLUGIN_VERSION_MINOR 17 +#define POPCORNFX_PLUGIN_VERSION_PATCH 0 #define POPCORNFX_PLUGIN_VERSION_TAG "" From 153bcef7332174993460544a9743042ea7913019 Mon Sep 17 00:00:00 2001 From: Hugo Nedelec Date: Thu, 6 Jul 2023 17:08:50 +0200 Subject: [PATCH 2/3] PopcornFX Plugin v2.17.1 --- Download_SDK_Desktop.bat | 2 +- Download_SDK_Mobile.bat | 2 +- PopcornFX.uplugin | 4 ++-- README.md | 2 +- Source/PopcornFX/Private/Assets/PopcornFXMesh.cpp | 2 ++ Source/PopcornFX/Public/PopcornFXVersionGenerated.h | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Download_SDK_Desktop.bat b/Download_SDK_Desktop.bat index baf151b..6fb80fc 100644 --- a/Download_SDK_Desktop.bat +++ b/Download_SDK_Desktop.bat @@ -6,7 +6,7 @@ setlocal bitsadmin /reset bitsadmin /create third_party_download_desktop -bitsadmin /addfile third_party_download_desktop https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.0_Win64_Linux64_Mac64.7z "%~dp0\_PopcornFX_Runtime_SDK_Desktop.7z" +bitsadmin /addfile third_party_download_desktop https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.1_Win64_Linux64_Mac64.7z "%~dp0\_PopcornFX_Runtime_SDK_Desktop.7z" bitsadmin /setpriority third_party_download_desktop "FOREGROUND" bitsadmin /resume third_party_download_desktop diff --git a/Download_SDK_Mobile.bat b/Download_SDK_Mobile.bat index 1b67a07..abdf75e 100644 --- a/Download_SDK_Mobile.bat +++ b/Download_SDK_Mobile.bat @@ -6,7 +6,7 @@ setlocal bitsadmin /reset bitsadmin /create third_party_download_mobile -bitsadmin /addfile third_party_download_mobile https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.0_iOS_Android.7z "%~dp0\_PopcornFX_Runtime_SDK_Mobile.7z" +bitsadmin /addfile third_party_download_mobile https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.1_iOS_Android.7z "%~dp0\_PopcornFX_Runtime_SDK_Mobile.7z" bitsadmin /setpriority third_party_download_mobile "FOREGROUND" bitsadmin /resume third_party_download_mobile diff --git a/PopcornFX.uplugin b/PopcornFX.uplugin index 57adc74..ae96bb5 100644 --- a/PopcornFX.uplugin +++ b/PopcornFX.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, - "Version": 21700, - "VersionName": "2.17.0", + "Version": 21701, + "VersionName": "2.17.1", "FriendlyName": "PopcornFX", "Description": "PopcornFX Realtime Particle Solution integration into Unreal Engine", "Category": "PopcornFX", diff --git a/README.md b/README.md index 406bc1b..f914e35 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Unreal Engine PopcornFX Plugin Integrates the **PopcornFX Runtime SDK** into **Unreal Engine 4** and **Unreal Engine 5** as a Plugin. -* **Version:** `v2.17.0` +* **Version:** `v2.17.1` * **Unreal Engine:** `4.27`, `5.0`, `5.1` and `5.2` * **Supported platforms:** `Windows`, `MacOS`, `Linux`, `iOS`, `Android`, `PS4`, `PS5`, `XboxOne`, `Xbox Series`, `Switch` diff --git a/Source/PopcornFX/Private/Assets/PopcornFXMesh.cpp b/Source/PopcornFX/Private/Assets/PopcornFXMesh.cpp index cd0f481..113d35c 100644 --- a/Source/PopcornFX/Private/Assets/PopcornFXMesh.cpp +++ b/Source/PopcornFX/Private/Assets/PopcornFXMesh.cpp @@ -933,6 +933,8 @@ void UPopcornFXMesh::WriteMesh() if (m_ResourceMesh != null) { PopcornFX::SMeshWriteSettings writeSettings; + writeSettings.m_Tangents = PopcornFX::SVStreamCode::Type_F32; + const PopcornFX::CString pkPath = PkPath(); // char* -> CString bool success = false; diff --git a/Source/PopcornFX/Public/PopcornFXVersionGenerated.h b/Source/PopcornFX/Public/PopcornFXVersionGenerated.h index a4a1d44..92a1869 100644 --- a/Source/PopcornFX/Public/PopcornFXVersionGenerated.h +++ b/Source/PopcornFX/Public/PopcornFXVersionGenerated.h @@ -7,5 +7,5 @@ #define POPCORNFX_PLUGIN_VERSION_MAJOR 2 #define POPCORNFX_PLUGIN_VERSION_MINOR 17 -#define POPCORNFX_PLUGIN_VERSION_PATCH 0 +#define POPCORNFX_PLUGIN_VERSION_PATCH 1 #define POPCORNFX_PLUGIN_VERSION_TAG "" From b29e14448ed6c4e278dfdf9d3f107c41fa44a713 Mon Sep 17 00:00:00 2001 From: Hugo Nedelec Date: Thu, 13 Jul 2023 17:04:48 +0200 Subject: [PATCH 3/3] PopcornFX Plugin v2.17.2 --- Download_SDK_Desktop.bat | 2 +- Download_SDK_Mobile.bat | 2 +- PopcornFX.uplugin | 4 ++-- README.md | 2 +- Source/PopcornFX/Public/PopcornFXVersionGenerated.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Download_SDK_Desktop.bat b/Download_SDK_Desktop.bat index 6fb80fc..d38fde3 100644 --- a/Download_SDK_Desktop.bat +++ b/Download_SDK_Desktop.bat @@ -6,7 +6,7 @@ setlocal bitsadmin /reset bitsadmin /create third_party_download_desktop -bitsadmin /addfile third_party_download_desktop https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.1_Win64_Linux64_Mac64.7z "%~dp0\_PopcornFX_Runtime_SDK_Desktop.7z" +bitsadmin /addfile third_party_download_desktop https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.2_Win64_Linux64_Mac64.7z "%~dp0\_PopcornFX_Runtime_SDK_Desktop.7z" bitsadmin /setpriority third_party_download_desktop "FOREGROUND" bitsadmin /resume third_party_download_desktop diff --git a/Download_SDK_Mobile.bat b/Download_SDK_Mobile.bat index abdf75e..9e81fe8 100644 --- a/Download_SDK_Mobile.bat +++ b/Download_SDK_Mobile.bat @@ -6,7 +6,7 @@ setlocal bitsadmin /reset bitsadmin /create third_party_download_mobile -bitsadmin /addfile third_party_download_mobile https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.1_iOS_Android.7z "%~dp0\_PopcornFX_Runtime_SDK_Mobile.7z" +bitsadmin /addfile third_party_download_mobile https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.17.2_iOS_Android.7z "%~dp0\_PopcornFX_Runtime_SDK_Mobile.7z" bitsadmin /setpriority third_party_download_mobile "FOREGROUND" bitsadmin /resume third_party_download_mobile diff --git a/PopcornFX.uplugin b/PopcornFX.uplugin index ae96bb5..a55e61d 100644 --- a/PopcornFX.uplugin +++ b/PopcornFX.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, - "Version": 21701, - "VersionName": "2.17.1", + "Version": 21702, + "VersionName": "2.17.2", "FriendlyName": "PopcornFX", "Description": "PopcornFX Realtime Particle Solution integration into Unreal Engine", "Category": "PopcornFX", diff --git a/README.md b/README.md index f914e35..4722513 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Unreal Engine PopcornFX Plugin Integrates the **PopcornFX Runtime SDK** into **Unreal Engine 4** and **Unreal Engine 5** as a Plugin. -* **Version:** `v2.17.1` +* **Version:** `v2.17.2` * **Unreal Engine:** `4.27`, `5.0`, `5.1` and `5.2` * **Supported platforms:** `Windows`, `MacOS`, `Linux`, `iOS`, `Android`, `PS4`, `PS5`, `XboxOne`, `Xbox Series`, `Switch` diff --git a/Source/PopcornFX/Public/PopcornFXVersionGenerated.h b/Source/PopcornFX/Public/PopcornFXVersionGenerated.h index 92a1869..58a0231 100644 --- a/Source/PopcornFX/Public/PopcornFXVersionGenerated.h +++ b/Source/PopcornFX/Public/PopcornFXVersionGenerated.h @@ -7,5 +7,5 @@ #define POPCORNFX_PLUGIN_VERSION_MAJOR 2 #define POPCORNFX_PLUGIN_VERSION_MINOR 17 -#define POPCORNFX_PLUGIN_VERSION_PATCH 1 +#define POPCORNFX_PLUGIN_VERSION_PATCH 2 #define POPCORNFX_PLUGIN_VERSION_TAG ""