BVB Source Codes

CRYENGINE Show ParticleProfiler.cpp Source code

Return Download CRYENGINE: download ParticleProfiler.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include <CryEntitySystem/IEntity.h>
  5. #include <CryEntitySystem/IEntitySystem.h>
  6. #include "ParticleProfiler.h"
  7. #include "ParticleComponentRuntime.h"
  8. #include "ParticleEmitter.h"
  9.  
  10. CRY_PFX2_DBG
  11.  
  12. namespace pfx2
  13. {
  14.  
  15. const cstr gDefaultEntityName = "- no entity -";
  16. const Vec2 gDisplayPosition = Vec2(0.05f, 0.05f);
  17. const Vec2 gDisplayBarSize = Vec2(0.45f, 0.025f);
  18. const uint gDisplayMaxNumComponents = 8;
  19. const float gDisplayFontSize = 1.2f;
  20. const float gDisplayLineGap = 0.0175f;
  21. const ColorB gBudgetOk = ColorB(16, 92, 198);
  22. const ColorB gBudgetOver = ColorB(255, 0, 0);
  23. const float gBudgetBarSize = 0.015f;
  24. const float gBudgetLineWidth = 1.5f;
  25.  
  26. struct SStatDisplay
  27. {
  28.         EProfileStat m_stat;
  29.         const char*  m_statName;
  30.         uint         m_budget;
  31. };
  32.  
  33. const SStatDisplay statisticsOutput[] =
  34. {
  35.         { EPS_Jobs,                "Jobs",                  0 },
  36.         { EPS_RendereredParticles, "Rendered",              0 },
  37.         { EPS_ActiveParticles,     "Active",                0 },
  38.         { EPS_AllocatedParticles,  "Alloc",                 0 },
  39.         { EPS_NewBornTime,         "New Borns (ns)",        0 },
  40.         { EPS_UpdateTime,          "Update (ns)",           0 },
  41.         { EPS_ComputeVerticesTime, "Compute Vertices (ns)", 0 },
  42.         { EPS_TotalTiming,         "Total Timing (ns)",     0 },
  43. };
  44.  
  45. class CParticleProfiler::CCSVFileOutput
  46. {
  47. public:
  48.         CCSVFileOutput(cstr fileName)
  49.         {
  50.                 m_file = fxopen(fileName, "w");
  51.         }
  52.         ~CCSVFileOutput()
  53.         {
  54.                 fclose(m_file);
  55.         }
  56.  
  57.         operator bool() const { return m_file != nullptr; }
  58.  
  59.         void WriteHeader()
  60.         {
  61.                 Column("Entity");
  62.                 Column("Effect");
  63.                 Column("Component");
  64.                 for (const auto& stat : statisticsOutput)
  65.                         Column(stat.m_statName);
  66.                 NewLine();
  67.         }
  68.  
  69.         void WriteStatistics(CParticleComponentRuntime* pRuntime, const SStatistics& statistics)
  70.         {
  71.                 CParticleComponent* pComponent = pRuntime->GetComponent();
  72.                 CParticleEmitter* pEmitter = pRuntime->GetEmitter();
  73.                 CParticleEffect* pEffect = pEmitter->GetCEffect();
  74.                 IEntity* pEntity = gEnv->pEntitySystem->GetEntity(pEmitter->GetEntityId());
  75.                 cstr effectName = pEffect->GetFullName();
  76.                 cstr componentName = pComponent->GetName();
  77.                 cstr entityName = pEntity ? pEntity->GetName() : gDefaultEntityName;
  78.  
  79.                 Column(entityName);
  80.                 Column(effectName);
  81.                 Column(componentName);
  82.                 for (const auto& stat : statisticsOutput)
  83.                         Column(string().Format("%d", statistics.m_values[stat.m_stat]));
  84.                 NewLine();
  85.         }
  86.  
  87. private:
  88.         void Column(cstr text)
  89.         {
  90.                 fprintf(m_file, "%s, ", text);
  91.         }
  92.         void NewLine()
  93.         {
  94.                 fprintf(m_file, "\n");
  95.         }
  96.  
  97.         FILE* m_file;
  98. };
  99.  
  100. class CParticleProfiler::CStatisticsDisplay
  101. {
  102. public:
  103.         CStatisticsDisplay()
  104.         {
  105.                 m_pRender = gEnv->pRenderer;
  106.                 m_pRenderAux = m_pRender->GetIRenderAuxGeom();
  107.                 m_prevFlags = m_pRenderAux->GetRenderFlags();
  108.                 m_screenSize = Vec2(float(m_pRender->GetWidth()), float(m_pRender->GetHeight()));
  109.                 SAuxGeomRenderFlags curFlags = m_prevFlags;
  110.                 curFlags.SetMode2D3DFlag(e_Mode2D);
  111.                 curFlags.SetDepthTestFlag(e_DepthTestOff);
  112.                 curFlags.SetDepthWriteFlag(e_DepthWriteOff);
  113.                 m_pRenderAux->SetRenderFlags(curFlags);
  114.         }
  115.         ~CStatisticsDisplay()
  116.         {
  117.                 m_pRenderAux->SetRenderFlags(m_prevFlags);
  118.         }
  119.  
  120.         void DrawBudgetBar(Vec2 pos, uint maxValue, uint budget)
  121.         {
  122.                 AABB box;
  123.                 box.min.x = pos.x;
  124.                 box.min.y = pos.y;
  125.                 box.max.x = pos.x + gDisplayBarSize.x;
  126.                 box.max.y = pos.y + gDisplayBarSize.y;
  127.                 box.min.z = box.max.z = 0.0f;
  128.  
  129.                 const Vec3 boxVertices[] =
  130.                 {
  131.                         Vec3(box.min.x, box.min.y, 0.0f), Vec3(box.max.x, box.min.y, 0.0f),
  132.                         Vec3(box.max.x, box.min.y, 0.0f), Vec3(box.max.x, box.max.y, 0.0f),
  133.                         Vec3(box.max.x, box.max.y, 0.0f), Vec3(box.min.x, box.max.y, 0.0f),
  134.                         Vec3(box.min.x, box.max.y, 0.0f), Vec3(box.min.x, box.min.y, 0.0f),
  135.                 };
  136.                 m_pRenderAux->DrawLines(boxVertices, 8, ColorB(0, 0, 0));
  137.  
  138.                 const ColorB color = (maxValue <= budget) ? gBudgetOk : gBudgetOver;
  139.                 const float linePos = pos.x + gDisplayBarSize.x * (budget / float(maxValue));
  140.                 const Vec3 lineVertices[] =
  141.                 {
  142.                         Vec3(linePos, pos.y - gBudgetBarSize, 0.0f),
  143.                         Vec3(linePos, pos.y + gDisplayBarSize.y + gBudgetBarSize, 0.0f),
  144.                 };
  145.                 m_pRenderAux->DrawLines(lineVertices, 2, color, gBudgetLineWidth);
  146.         }
  147.  
  148.         void DrawBar(Vec2 pos, Vec2 size, uint maxValue, uint startValue, uint endValue, ColorB color)
  149.         {
  150.                 AABB box;
  151.                 box.min.x = pos.x + size.x * (startValue / float(maxValue));
  152.                 box.min.y = pos.y;
  153.                 box.max.x = pos.x + size.x * (endValue / float(maxValue));
  154.                 box.max.y = pos.y + size.y;
  155.                 box.min.z = box.max.z = 0.0f;
  156.  
  157.                 m_pRenderAux->DrawAABB(box, true, color, eBBD_Faceted);
  158.         }
  159.  
  160.         void DrawBar(Vec2 pos, uint maxValue, uint startValue, uint endValue, ColorB color)
  161.         {
  162.                 DrawBar(pos, gDisplayBarSize, maxValue, startValue, endValue, color);
  163.         }
  164.  
  165.         void DrawBar(Vec2 pos, uint maxValue, uint curValue, ColorB color)
  166.         {
  167.                 DrawBar(pos, gDisplayBarSize, maxValue, 0, curValue, color);
  168.         }
  169.  
  170.         void DrawText(Vec2 pos, ColorF color, cstr text, ...)
  171.         {
  172.                 va_list args;
  173.                 va_start(args, text);
  174.                 m_pRenderAux->Draw2dLabel(
  175.                         pos.x * m_screenSize.x, pos.y * m_screenSize.y,
  176.                         gDisplayFontSize, color, false,
  177.                         text, args);
  178.                 va_end(args);
  179.         }
  180.  
  181. private:
  182.         IRenderer* m_pRender;
  183.         IRenderAuxGeom* m_pRenderAux;
  184.         SAuxGeomRenderFlags m_prevFlags;
  185.         Vec2 m_screenSize;
  186. };
  187.  
  188. SStatistics::SStatistics()
  189. {
  190.         memset(m_values, 0, sizeof(m_values));
  191. }
  192.  
  193. CParticleProfiler::CParticleProfiler()
  194.         : m_entries(gEnv->pJobManager->GetNumWorkerThreads() + 1)
  195. {
  196. }
  197.  
  198. void CParticleProfiler::Display()
  199. {
  200.         CRY_PROFILE_FUNCTION(PROFILE_PARTICLE);
  201.  
  202.         CVars* pCVars = static_cast<C3DEngine*>(gEnv->p3DEngine)->GetCVars();
  203.         const int anyProfilerFlags = 1 | AlphaBits('f');
  204.         if (pCVars->e_ParticlesProfiler & anyProfilerFlags)
  205.         {
  206.                 SortEntries();
  207.  
  208.                 if (!m_entries[0].empty())
  209.                 {
  210. #ifndef _RELEASE
  211.                         if (pCVars->e_ParticlesProfiler & AlphaBit('f'))
  212.                                 SaveToFile();
  213. #endif
  214.                         if (pCVars->e_ParticlesProfiler & 1)
  215.                                 DrawStats();
  216.                 }
  217.         }
  218.         for (auto& entries : m_entries)
  219.                 entries.clear();
  220. }
  221.  
  222. void CParticleProfiler::SaveToFile()
  223. {
  224.         CVars* pCVars = static_cast<C3DEngine*>(gEnv->p3DEngine)->GetCVars();
  225.         string genName;
  226.         string folderName = pCVars->e_ParticlesProfilerOutputFolder->GetString();
  227.         string fileName = pCVars->e_ParticlesProfilerOutputName->GetString();
  228.         if (folderName.empty() || fileName.empty())
  229.                 return;
  230.         if (folderName[folderName.size() - 1] != '\\' || folderName[folderName.size() - 1] != '/')
  231.                 folderName += '/';
  232.         static int fileIndex = 0;
  233.         do
  234.         {
  235.                 genName.Format("%s%s%06d.csv", folderName.c_str(), fileName.c_str(), fileIndex);
  236.                 ++fileIndex;
  237.         } while (gEnv->pCryPak->IsFileExist(genName));
  238.  
  239.         CCSVFileOutput output(genName.c_str());
  240.         if (output)
  241.                 WriteEntries(output);
  242. }
  243.  
  244. void CParticleProfiler::SortEntries()
  245. {
  246.         auto& finalElements = m_entries[0];
  247.         for (uint i = 1; i < m_entries.size(); ++i)
  248.                 finalElements.insert(finalElements.end(), m_entries[i].begin(), m_entries[i].end());
  249.        
  250.         auto predicate = [](const SEntry& entry0, const SEntry& entry1)
  251.         {
  252.                 const CParticleEmitter* pEmitter0 = entry0.m_pRuntime->GetEmitter();
  253.                 const CParticleEmitter* pEmitter1 = entry1.m_pRuntime->GetEmitter();
  254.                 if (pEmitter0->GetEmitterId() != pEmitter1->GetEmitterId())
  255.                         return pEmitter0->GetEmitterId() < pEmitter1->GetEmitterId();
  256.  
  257.                 const CParticleComponent* pComponent0 = entry0.m_pRuntime->GetComponent();
  258.                 const CParticleComponent* pComponent1 = entry1.m_pRuntime->GetComponent();
  259.                 return pComponent0->GetComponentId() < pComponent1->GetComponentId();
  260.         };
  261.         std::sort(finalElements.begin(), finalElements.end(), predicate);
  262. }
  263.  
  264. void CParticleProfiler::WriteEntries(CCSVFileOutput& output) const
  265. {
  266.         const auto& finalElements = m_entries[0];
  267.  
  268.         output.WriteHeader();
  269.  
  270.         const CParticleEmitter* pEmitter = nullptr;
  271.         SStatistics runtimeStats;
  272.         CParticleComponentRuntime* pCurrentRuntime = finalElements.front().m_pRuntime;
  273.  
  274.         for (const SEntry& entry : finalElements)
  275.         {
  276.                 if (entry.m_pRuntime != pCurrentRuntime)
  277.                 {
  278.                         output.WriteStatistics(entry.m_pRuntime, runtimeStats);
  279.                         runtimeStats = SStatistics();
  280.                         pCurrentRuntime = entry.m_pRuntime;
  281.                 }
  282.                 runtimeStats.m_values[entry.m_type] += entry.m_value;
  283.         }
  284.         output.WriteStatistics(pCurrentRuntime, runtimeStats);
  285. }
  286.  
  287. void CParticleProfiler::DrawStats()
  288. {
  289.         CVars* pCVars = static_cast<C3DEngine*>(gEnv->p3DEngine)->GetCVars();
  290.         const uint countsBudget = pCVars->e_ParticlesProfilerCountBudget;
  291.         const uint timingBudget = pCVars->e_ParticlesProfilerTimingBudget;
  292.  
  293.         const SStatDisplay statisticsDisplay[] =
  294.         {
  295.                 { EPS_ActiveParticles,     "Active",            countsBudget },
  296.                 { EPS_RendereredParticles, "Rendered",          countsBudget },
  297.                 { EPS_TotalTiming,         "Total Timing (ns)", timingBudget },
  298.         };
  299.  
  300.         CStatisticsDisplay output;
  301.         Vec2 statPos = gDisplayPosition;
  302.         DrawStatsCounts(output, statPos, countsBudget);
  303.         statPos.y += gDisplayBarSize.y + gDisplayLineGap * 4;
  304.         for (const auto& stat : statisticsDisplay)
  305.         {
  306.                 DrawStats(output, statPos, stat.m_stat, stat.m_budget, stat.m_statName);
  307.                 statPos.y += gDisplayBarSize.y + gDisplayLineGap * (gDisplayMaxNumComponents + 3);
  308.         }
  309. }
  310.  
  311. void CParticleProfiler::DrawStatsCounts(CStatisticsDisplay& output, Vec2 pos, uint budget)
  312. {
  313.         uint numRendererd = 0;
  314.         uint numActive = 0;
  315.         uint numAllocated = 0;
  316.         for (const SEntry& entry : m_entries[0])
  317.         {
  318.                 switch (entry.m_type)
  319.                 {
  320.                 case EPS_RendereredParticles:
  321.                         numRendererd += entry.m_value;
  322.                         break;
  323.                 case EPS_ActiveParticles:
  324.                         numActive += entry.m_value;
  325.                         break;
  326.                 case EPS_AllocatedParticles:
  327.                         numAllocated += entry.m_value;
  328.                         break;
  329.                 }
  330.         }
  331.  
  332.         const uint maxValue = max(budget, numAllocated);
  333.         const Vec2 barSize = Vec2(gDisplayBarSize.x, gDisplayBarSize.y / 3.0f);
  334.         Vec2 barPos = pos;
  335.         Vec2 textPos = Vec2(pos.x, pos.y + gDisplayBarSize.y);
  336.  
  337.         output.DrawBar(barPos, barSize, maxValue, 0, numAllocated, ColorB(255, 0, 0));
  338.         barPos.y += barSize.y;
  339.         output.DrawBar(barPos, barSize, maxValue, 0, numActive, ColorB(255, 255, 0));
  340.         barPos.y += barSize.y;
  341.         output.DrawBar(barPos, barSize, maxValue, 0, numRendererd, ColorB(0, 255, 0));
  342.  
  343.         output.DrawText(textPos, ColorF(0.0f, 1.0f, 0.0f), "Rendered (%d)", numRendererd);
  344.         textPos.y += gDisplayLineGap;
  345.         output.DrawText(textPos, ColorF(1.0f, 1.0f, 0.0f), "Active (%d)", numActive);
  346.         textPos.y += gDisplayLineGap;
  347.         output.DrawText(textPos, ColorF(1.0f, 0.0f, 0.0f), "Allocated (%d)", numAllocated);
  348.  
  349.         output.DrawBudgetBar(pos, maxValue, budget);
  350. }
  351.  
  352. void CParticleProfiler::DrawStats(CStatisticsDisplay& output, Vec2 pos, EProfileStat stat, uint budget, cstr statName)
  353. {
  354.         struct SStatEntry
  355.         {
  356.                 SStatEntry()
  357.                         : pRuntime(nullptr)
  358.                         , value(0) {}
  359.                 CParticleComponentRuntime* pRuntime;
  360.                 uint value;
  361.         };
  362.  
  363.         const CParticleComponentRuntime* pRuntime = nullptr;
  364.         SStatEntry statEntry;
  365.         std::vector<SStatEntry> statEntries;
  366.         uint statTotal = 0;
  367.  
  368.         for (const SEntry& entry : m_entries[0])
  369.         {
  370.                 if (entry.m_type != stat)
  371.                         continue;
  372.  
  373.                 if (entry.m_pRuntime != pRuntime)
  374.                 {
  375.                         pRuntime = entry.m_pRuntime;
  376.                         if (pRuntime && statEntry.value != 0.0f)
  377.                                 statEntries.push_back(statEntry);
  378.                         statEntry = SStatEntry();
  379.                         statEntry.pRuntime = entry.m_pRuntime;
  380.                         pRuntime = entry.m_pRuntime;
  381.                 }
  382.  
  383.                 uint value = 0;
  384.                 value += entry.m_value;
  385.                 statEntry.value += value;
  386.                 statTotal += value;
  387.         }
  388.         if (pRuntime && statEntry.value != 0.0f)
  389.                 statEntries.push_back(statEntry);
  390.  
  391.         std::sort(statEntries.begin(), statEntries.end(), [](const SStatEntry& v0, const SStatEntry& v1)
  392.         {
  393.                 return v0.value > v1.value;
  394.         });
  395.  
  396.         const Vec2 barPosition = Vec2(pos.x, pos.y + gDisplayLineGap);
  397.         const uint maxValue = max(statTotal, budget);
  398.         Vec2 textPos = pos;
  399.         uint lastStat = 0;
  400.  
  401.         output.DrawText(textPos, ColorF(1.0f, 1.0f, 1.0f), "%s Total (%d)", statName, statTotal);
  402.         textPos.y += gDisplayLineGap + gDisplayBarSize.y;
  403.  
  404.         uint statCount = min(uint(statEntries.size()), gDisplayMaxNumComponents);
  405.         for (uint i = 0; i < statCount; ++i)
  406.         {
  407.                 CParticleComponentRuntime* pRuntime = statEntries[i].pRuntime;
  408.                 CParticleComponent* pComponent = pRuntime->GetComponent();
  409.                 CParticleEmitter* pEmitter = pRuntime->GetEmitter();
  410.                 IEntity* pEntity = gEnv->pEntitySystem->GetEntity(pEmitter->GetEntityId());
  411.  
  412.                 const ColorF color = pEmitter->GetProfilerColor();
  413.                 const uint value = statEntries[i].value;
  414.  
  415.                 output.DrawBar(barPosition, maxValue, lastStat, lastStat + value, ColorB(color));
  416.  
  417.                 const cstr format = "\"%s\" : %s : %s (%d)";
  418.                 const cstr componentName = pComponent->GetName();
  419.                 const cstr effectName = pComponent->GetEffect()->GetFullName();
  420.                 const cstr entityName = pEntity ? pEntity->GetName() : gDefaultEntityName;
  421.                 output.DrawText(textPos, color, format, entityName, effectName, componentName, value);
  422.                 textPos.y += gDisplayLineGap;
  423.  
  424.                 lastStat += value;
  425.         }
  426.         if ((statTotal - lastStat) != 0)
  427.         {
  428.                 output.DrawBar(barPosition, maxValue, lastStat, statTotal, ColorB(92, 92, 92));
  429.                 output.DrawText(textPos, ColorF(0.35f, 0.35f, 0.35f), "other (%d)", statTotal - lastStat);
  430.         }
  431.  
  432.         output.DrawBudgetBar(barPosition, maxValue, budget);
  433. }
  434.  
  435. }
  436.  
downloadParticleProfiler.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top