ATOM-13791 Editor: ImGui profiling tools doesn't work correctly due to disabled RenderPipelines

- Added pause/resume button to ImGui Profiler to pause/resume profiling
- Added showing pass execution timeline
- Change TimestampResult to include both begin tick and duration tick. Update some function names of TimestampResult.
- Update some functions names in Pass.
- Stop showing accumulated time for ParentPass.
- Fixed a crash issue with ImGuiManager which doesn't have default font.
This commit is contained in:
qingtao
2021-04-14 22:48:46 -07:00
parent 70c2d5ee40
commit fa7f61cf0d
13 changed files with 291 additions and 124 deletions
+1
View File
@@ -18,3 +18,4 @@ _savebackup/
#Output folder for test results when running Automated Tests
TestResults/**
*.swatches
/imgui.ini
@@ -186,7 +186,7 @@ namespace AZ
{
for (const RPI::Pass* pass : passes)
{
m_timestampEntries.push_back({ pass->GetName(), pass->GetTimestampResult().GetTimestampInNanoseconds() });
m_timestampEntries.push_back({pass->GetName(), pass->GetLatestTimestampResult().GetDurationInNanoseconds()});
}
}
@@ -223,7 +223,7 @@ namespace AZ
{
for (const RPI::Pass* pass : passes)
{
m_pipelineStatisticsEntries.push_back({ pass->GetName(), pass->GetPipelineStatisticsResult() });
m_pipelineStatisticsEntries.push_back({pass->GetName(), pass->GetLatestPipelineStatisticsResult()});
}
}
@@ -11,6 +11,7 @@
*/
#pragma once
#include <Atom/RHI.Reflect/AttachmentEnums.h>
#include <Atom/RHI.Reflect/QueryPoolDescriptor.h>
#include <AtomCore/std/containers/array_view.h>
@@ -43,15 +44,19 @@ namespace AZ
{
public:
TimestampResult() = default;
TimestampResult(uint64_t timestampInTicks);
TimestampResult(uint64_t timestampQueryResultLow, uint64_t timestampQueryResultHigh);
TimestampResult(AZStd::array_view<TimestampResult>&& timestampResultArray);
TimestampResult(uint64_t beginTick, uint64_t endTick, RHI::HardwareQueueClass hardwareQueueClass);
uint64_t GetTimestampInNanoseconds() const;
uint64_t GetTimestampInTicks() const;
uint64_t GetDurationInNanoseconds() const;
uint64_t GetDurationInTicks() const;
uint64_t GetTimestampBeginInTicks() const;
void Add(const TimestampResult& extent);
private:
uint64_t m_timestampInTicks = 0u;
// the timestamp of begin and duration in ticks.
uint64_t m_begin = 0;
uint64_t m_duration = 0;
RHI::HardwareQueueClass m_hardwareQueueClass = RHI::HardwareQueueClass::Graphics;
};
//! The structure that is used to read back the results form the PipelineStatistics queries
@@ -122,7 +122,6 @@ namespace AZ
private:
// RPI::Pass overrides...
TimestampResult GetTimestampResultInternal() const override;
PipelineStatisticsResult GetPipelineStatisticsResultInternal() const override;
// --- Hierarchy related functions ---
@@ -211,11 +211,11 @@ namespace AZ
//! Prints the pass
virtual void DebugPrint() const;
//! Return the Timestamp result of this pass
TimestampResult GetTimestampResult() const;
//! Return the latest Timestamp result of this pass
TimestampResult GetLatestTimestampResult() const;
//! Return the PipelineStatistic result of this pass
PipelineStatisticsResult GetPipelineStatisticsResult() const;
//! Return the latest PipelineStatistic result of this pass
PipelineStatisticsResult GetLatestPipelineStatisticsResult() const;
//! Enables/Disables Timestamp queries for this pass
virtual void SetTimestampQueryEnabled(bool enable);
@@ -21,41 +21,39 @@ namespace AZ
namespace RPI
{
// --- TimestampResult ---
TimestampResult::TimestampResult(uint64_t timestampInTicks)
TimestampResult::TimestampResult(uint64_t beginTick, uint64_t endTick, RHI::HardwareQueueClass hardwareQueueClass)
{
m_timestampInTicks = timestampInTicks;
AZ_Assert(endTick >= beginTick, "TimestampResult: bad inputs");
m_begin = beginTick;
m_duration = endTick - beginTick;
m_hardwareQueueClass = hardwareQueueClass;
}
TimestampResult::TimestampResult(uint64_t timestampQueryResultLow, uint64_t timestampQueryResultHigh)
{
const uint64_t low = AZStd::min(timestampQueryResultLow, timestampQueryResultHigh);
const uint64_t high = AZStd::max(timestampQueryResultLow, timestampQueryResultHigh);
m_timestampInTicks = high - low;
}
TimestampResult::TimestampResult(AZStd::array_view<TimestampResult>&& timestampResultArray)
{
// Loop through all the child passes, and accumulate all the timestampTicks
for (const TimestampResult& timestampResult : timestampResultArray)
{
m_timestampInTicks += timestampResult.m_timestampInTicks;
}
}
uint64_t TimestampResult::GetTimestampInNanoseconds() const
uint64_t TimestampResult::GetDurationInNanoseconds() const
{
const RHI::Ptr<RHI::Device> device = RHI::GetRHIDevice();
const AZStd::chrono::microseconds timeInMicroseconds = device->GpuTimestampToMicroseconds(m_timestampInTicks, RHI::HardwareQueueClass::Graphics);
const AZStd::chrono::microseconds timeInMicroseconds = device->GpuTimestampToMicroseconds(m_duration, m_hardwareQueueClass);
const auto timeInNanoseconds = AZStd::chrono::nanoseconds(timeInMicroseconds);
return static_cast<uint64_t>(timeInNanoseconds.count());
}
uint64_t TimestampResult::GetTimestampInTicks() const
uint64_t TimestampResult::GetDurationInTicks() const
{
return m_timestampInTicks;
return m_duration;
}
uint64_t TimestampResult::GetTimestampBeginInTicks() const
{
return m_begin;
}
void TimestampResult::Add(const TimestampResult& extent)
{
uint64_t end1 = m_begin + m_duration;
uint64_t end2 = extent.m_begin + extent.m_duration;
m_begin = m_begin < extent.m_begin ? m_begin : extent.m_begin;
m_duration = (end1 > end2 ? end1 : end2) - m_begin;
}
// --- PipelineStatisticsResult ---
@@ -393,19 +393,6 @@ namespace AZ
}
}
TimestampResult ParentPass::GetTimestampResultInternal() const
{
AZStd::vector<TimestampResult> timestampResultArray;
timestampResultArray.reserve(m_children.size());
// Calculate the Timestamp result by summing all of its child's TimestampResults
for (const Ptr<Pass>& childPass : m_children)
{
timestampResultArray.emplace_back(childPass->GetTimestampResult());
}
return TimestampResult(timestampResultArray);
}
PipelineStatisticsResult ParentPass::GetPipelineStatisticsResultInternal() const
{
AZStd::vector<PipelineStatisticsResult> pipelineStatisticsResultArray;
@@ -414,7 +401,7 @@ namespace AZ
// Calculate the PipelineStatistics result by summing all of its child's PipelineStatistics
for (const Ptr<Pass>& childPass : m_children)
{
pipelineStatisticsResultArray.emplace_back(childPass->GetPipelineStatisticsResult());
pipelineStatisticsResultArray.emplace_back(childPass->GetLatestPipelineStatisticsResult());
}
return PipelineStatisticsResult(pipelineStatisticsResultArray);
}
@@ -1273,24 +1273,14 @@ namespace AZ
}
}
TimestampResult Pass::GetTimestampResult() const
TimestampResult Pass::GetLatestTimestampResult() const
{
if (IsEnabled() && IsTimestampQueryEnabled())
{
return GetTimestampResultInternal();
}
return TimestampResult();
return GetTimestampResultInternal();
}
PipelineStatisticsResult Pass::GetPipelineStatisticsResult() const
PipelineStatisticsResult Pass::GetLatestPipelineStatisticsResult() const
{
if (IsEnabled() && IsPipelineStatisticsQueryEnabled())
{
return GetPipelineStatisticsResultInternal();
}
return PipelineStatisticsResult();
return GetPipelineStatisticsResultInternal();
}
TimestampResult Pass::GetTimestampResultInternal() const
@@ -539,7 +539,7 @@ namespace AZ
const uint32_t TimestampResultQueryCount = 2u;
uint64_t timestampResult[TimestampResultQueryCount] = {0};
query->GetLatestResult(&timestampResult, sizeof(uint64_t) * TimestampResultQueryCount);
m_timestampResult = TimestampResult(timestampResult[0], timestampResult[1]);
m_timestampResult = TimestampResult(timestampResult[0], timestampResult[1], RHI::HardwareQueueClass::Graphics);
});
ExecuteOnPipelineStatisticsQuery([this](RHI::Ptr<Query> query)
@@ -109,8 +109,8 @@ namespace MaterialEditor
AZ::RHI::Ptr<AZ::RPI::ParentPass> rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass();
if (rootPass)
{
AZ::RPI::TimestampResult timestampResult = rootPass->GetTimestampResult();
double gpuFrameTimeMs = aznumeric_cast<double>(timestampResult.GetTimestampInNanoseconds()) / 1000000;
AZ::RPI::TimestampResult timestampResult = rootPass->GetLatestTimestampResult();
double gpuFrameTimeMs = aznumeric_cast<double>(timestampResult.GetDurationInNanoseconds()) / 1000000;
m_gpuFrameTimeMs.PushSample(gpuFrameTimeMs);
}
}
@@ -93,7 +93,9 @@ namespace AZ
ImGuiPipelineStatisticsView();
//! Draw the PipelineStatistics window.
void DrawPipelineStatisticsWindow(bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<AZ::Name, PassEntry>& m_timestampEntryDatabase);
void DrawPipelineStatisticsWindow(bool& draw, const PassEntry* rootPassEntry,
AZStd::unordered_map<AZ::Name, PassEntry>& m_timestampEntryDatabase,
AZ::RHI::Ptr<AZ::RPI::ParentPass> rootPass);
//! Total number of columns (Attribute columns + PassName column).
static const uint32_t HeaderAttributeCount = PassEntry::PipelineStatisticsAttributeCount + 1u;
@@ -139,6 +141,9 @@ namespace AZ
// ImGui filter used to filter passes by the user's input.
ImGuiTextFilter m_passFilter;
// Pause and showing the pipeline statistics result when it's paused.
bool m_paused = false;
};
class ImGuiTimestampView
@@ -180,9 +185,19 @@ namespace AZ
Count
};
// Timestamp refresh type .
enum class RefreshType : int32_t
{
Realtime = 0,
OncePerSecond,
Count
};
public:
//! Draw the Timestamp window.
void DrawTimestampWindow(bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& m_timestampEntryDatabase);
void DrawTimestampWindow(bool& draw, const PassEntry* rootPassEntry,
AZStd::unordered_map<Name, PassEntry>& m_timestampEntryDatabase,
AZ::RHI::Ptr<AZ::RPI::ParentPass> rootPass);
private:
// Draw option for the hierarchical view of the passes.
@@ -223,6 +238,20 @@ namespace AZ
// ImGui filter used to filter passes.
ImGuiTextFilter m_passFilter;
// Pause and showing the timestamp result when it's paused.
bool m_paused = false;
// Hide non-parent passes which has 0 execution time.
bool m_hideZeroPasses = false;
// Show pass execution timeline
bool m_showTimeline = false;
// Controls how often the timestamp data is refreshed
RefreshType m_refreshType = RefreshType::OncePerSecond;
AZStd::sys_time_t m_lastUpdateTimeMicroSecond;
};
class ImGuiGpuProfiler
@@ -105,9 +105,9 @@ namespace AZ
// [GFX TODO][ATOM-4001] Cache the timestamp and PipelineStatistics results.
// Get the query results from the passes.
m_timestampResult = pass->GetTimestampResult();
m_timestampResult = pass->GetLatestTimestampResult();
const RPI::PipelineStatisticsResult rps = pass->GetPipelineStatisticsResult();
const RPI::PipelineStatisticsResult rps = pass->GetLatestPipelineStatisticsResult();
m_pipelineStatistics = { rps.m_vertexCount, rps.m_primitiveCount, rps.m_vertexShaderInvocationCount,
rps.m_rasterizedPrimitiveCount, rps.m_renderedPrimitiveCount, rps.m_pixelShaderInvocationCount, rps.m_computeShaderInvocationCount };
@@ -153,7 +153,9 @@ namespace AZ
}
inline void ImGuiPipelineStatisticsView::DrawPipelineStatisticsWindow(bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& passEntryDatabase)
inline void ImGuiPipelineStatisticsView::DrawPipelineStatisticsWindow(bool& draw,
const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& passEntryDatabase,
AZ::RHI::Ptr<RPI::ParentPass> rootPass)
{
// Early out if nothing is supposed to be drawn
if (!draw)
@@ -188,12 +190,6 @@ namespace AZ
continue;
}
// Filter out disabled passes for the PipelineStatistics window if necessary.
if (!m_showDisabledPasses && !passEntry.IsPipelineStatisticsEnabled())
{
continue;
}
// Filter out parent passes if necessary.
if (!m_showParentPasses && passEntry.m_isParent)
{
@@ -230,6 +226,13 @@ namespace AZ
// Start drawing the PipelineStatistics window.
if (ImGui::Begin("PipelineStatistics Window", &draw, ImGuiWindowFlags_NoResize))
{
// Pause/unpause the profiling
if (ImGui::Button(m_paused ? "Resume" : "Pause"))
{
m_paused = !m_paused;
rootPass->SetPipelineStatisticsQueryEnabled(!m_paused);
}
ImGui::Columns(2, "HeaderColumns");
// Draw the statistics of the RootPass.
@@ -426,23 +429,16 @@ namespace AZ
}
AZStd::string label;
if (passEntry->IsPipelineStatisticsEnabled())
if (rootEntry && m_showAttributeContribution)
{
if (rootEntry && m_showAttributeContribution)
{
label = AZStd::string::format("%llu (%u%%)",
static_cast<AZ::u64>(passEntry->m_pipelineStatistics[attributeIdx]),
static_cast<uint32_t>(normalized * 100.0f));
}
else
{
label = AZStd::string::format("%llu",
static_cast<AZ::u64>(passEntry->m_pipelineStatistics[attributeIdx]));
}
label = AZStd::string::format("%llu (%u%%)",
static_cast<AZ::u64>(passEntry->m_pipelineStatistics[attributeIdx]),
static_cast<uint32_t>(normalized * 100.0f));
}
else
{
label = "-";
label = AZStd::string::format("%llu",
static_cast<AZ::u64>(passEntry->m_pipelineStatistics[attributeIdx]));
}
if (rootEntry)
@@ -523,7 +519,9 @@ namespace AZ
// --- ImGuiTimestampView ---
inline void ImGuiTimestampView::DrawTimestampWindow(bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& timestampEntryDatabase)
inline void ImGuiTimestampView::DrawTimestampWindow(
bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& timestampEntryDatabase,
AZ::RHI::Ptr<RPI::ParentPass> rootPass)
{
// Early out if nothing is supposed to be drawn
if (!draw)
@@ -534,10 +532,28 @@ namespace AZ
// Clear the references from the previous frame.
m_passEntryReferences.clear();
// pass entry grid based on its timestamp
AZStd::vector<PassEntry*> sortedPassEntries;
AZStd::vector<AZStd::vector<PassEntry*>> sortedPassGrid;
// Set the child of the parent, only if it passes the filter.
for (auto& passEntryIt : timestampEntryDatabase)
{
PassEntry* passEntry = &passEntryIt.second;
// Collect all pass entries with non-zero durations
if (passEntry->m_timestampResult.GetDurationInTicks() > 0)
{
sortedPassEntries.push_back(passEntry);
}
// Skip the pass if the pass' timestamp duration is 0
if (m_hideZeroPasses && (!passEntry->m_isParent) && passEntry->m_timestampResult.GetDurationInTicks() == 0)
{
continue;
}
// Only add pass if it pass the filter.
if (m_passFilter.PassFilter(passEntry->m_name.GetCStr()))
{
if (passEntry->m_parent && !passEntry->m_linked)
@@ -545,19 +561,94 @@ namespace AZ
passEntry->m_parent->LinkChild(passEntry);
}
AZ_Assert(m_passEntryReferences.size() < TimestampEntryCount, "Too many PassEntry references. Increase the size of the array.");
AZ_Assert(
m_passEntryReferences.size() < TimestampEntryCount,
"Too many PassEntry references. Increase the size of the array.");
m_passEntryReferences.push_back(passEntry);
}
}
// Sort the pass entries based on their starting time and duration
AZStd::sort(sortedPassEntries.begin(), sortedPassEntries.end(), [](const PassEntry* passEntry1, const PassEntry* passEntry2) {
if (passEntry1->m_timestampResult.GetTimestampBeginInTicks() == passEntry2->m_timestampResult.GetTimestampBeginInTicks())
{
return passEntry1->m_timestampResult.GetDurationInTicks() < passEntry2->m_timestampResult.GetDurationInTicks();
}
return passEntry1->m_timestampResult.GetTimestampBeginInTicks() < passEntry2->m_timestampResult.GetTimestampBeginInTicks();
});
// calculate the total GPU duration.
RPI::TimestampResult gpuTimestamp;
if (sortedPassEntries.size() > 0)
{
gpuTimestamp = sortedPassEntries.front()->m_timestampResult;
gpuTimestamp.Add(sortedPassEntries.back()->m_timestampResult);
}
// Add a pass to the pass grid which none of the pass's timestamp range won't overlap each other.
// Search each row until the pass can be added to the end of row without overlap the previous one.
for (auto& passEntry : sortedPassEntries)
{
auto row = sortedPassGrid.begin();
for (; row != sortedPassGrid.end(); row++)
{
if (row->empty())
{
break;
}
auto last = (*row).back();
if (passEntry->m_timestampResult.GetTimestampBeginInTicks() >=
last->m_timestampResult.GetTimestampBeginInTicks() + last->m_timestampResult.GetDurationInTicks())
{
row->push_back(passEntry);
break;
}
}
if (row == sortedPassGrid.end())
{
sortedPassGrid.push_back();
sortedPassGrid.back().push_back(passEntry);
}
}
// Refresh timestamp query
bool needEnable = false;
if (!m_paused)
{
if (m_refreshType == RefreshType::OncePerSecond)
{
auto now = AZStd::GetTimeNowMicroSecond();
if (m_lastUpdateTimeMicroSecond == 0 || now - m_lastUpdateTimeMicroSecond > 1000000)
{
needEnable = true;
m_lastUpdateTimeMicroSecond = now;
}
}
else if (m_refreshType == RefreshType::Realtime)
{
needEnable = true;
}
}
if (rootPass->IsTimestampQueryEnabled() != needEnable)
{
rootPass->SetTimestampQueryEnabled(needEnable);
}
const ImVec2 windowSize(680.0f, 620.0f);
ImGui::SetNextWindowSize(windowSize, ImGuiCond_Always);
if (ImGui::Begin("Timestamp View", &draw, ImGuiWindowFlags_NoResize))
{
// Draw the header.
{
// Pause/unpause the profiling
if (ImGui::Button(m_paused? "Resume":"Pause"))
{
m_paused = !m_paused;
}
// Draw the frame time (GPU).
const AZStd::string formattedTimestamp = FormatTimestampLabel(rootPassEntry->m_interpolatedTimestampInNanoseconds);
const AZStd::string formattedTimestamp = FormatTimestampLabel(gpuTimestamp.GetDurationInNanoseconds());
const AZStd::string headerFrameTime = AZStd::string::format("Total frame duration (GPU): %s", formattedTimestamp.c_str());
ImGui::Text(headerFrameTime.c_str());
@@ -566,6 +657,17 @@ namespace AZ
ImGui::SameLine();
ImGui::RadioButton("Flat", reinterpret_cast<int32_t*>(&m_viewType), static_cast<int32_t>(ProfilerViewType::Flat));
// Draw the refresh option
ImGui::RadioButton("Realtime", reinterpret_cast<int32_t*>(&m_refreshType), static_cast<int32_t>(RefreshType::Realtime));
ImGui::SameLine();
ImGui::RadioButton("Once Per Second", reinterpret_cast<int32_t*>(&m_refreshType), static_cast<int32_t>(RefreshType::OncePerSecond));
// Show/hide non-parent passes which have zero execution time
ImGui::Checkbox("Hide Zero Cost Passes", &m_hideZeroPasses);
// Show/hide the timeline bar of all the passes which has non-zero execution time
ImGui::Checkbox("Show Timeline", &m_showTimeline);
// Draw advanced options.
const ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_None;
GpuProfilerImGuiHelper::TreeNode("Advanced options", flags, [this](bool unrolled)
@@ -587,6 +689,56 @@ namespace AZ
ImGui::Separator();
// Draw the pass entry grid
if (!sortedPassEntries.empty() && m_showTimeline)
{
const float passBarHeight = 20.f;
const float passBarSpace = 3.f;
float areaWidth = ImGui::GetContentRegionAvail().x - 20.f;
if (ImGui::BeginChild("Timeline", ImVec2(areaWidth, (passBarHeight + passBarSpace) * sortedPassGrid.size()), false))
{
// start tick and end tick for the area
uint64_t areaStartTick = sortedPassEntries.front()->m_timestampResult.GetTimestampBeginInTicks();
uint64_t areaEndTick = sortedPassEntries.back()->m_timestampResult.GetTimestampBeginInTicks() +
sortedPassEntries.back()->m_timestampResult.GetDurationInTicks();
uint64_t areaDurationInTicks = areaEndTick - areaStartTick;
float rowStartY = 0.f;
for (auto& row : sortedPassGrid)
{
// row start y
for (auto passEntry : row)
{
// button start and end
float buttonStartX = (passEntry->m_timestampResult.GetTimestampBeginInTicks() - areaStartTick) * areaWidth /
areaDurationInTicks;
float buttonWidth = passEntry->m_timestampResult.GetDurationInTicks() * areaWidth / areaDurationInTicks;
ImGui::SetCursorPosX(buttonStartX);
ImGui::SetCursorPosY(rowStartY);
// Adds a button and the hover colors.
ImGui::Button(passEntry->m_name.GetCStr(), ImVec2(buttonWidth, passBarHeight));
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Name: %s", passEntry->m_name.GetCStr());
ImGui::Text("Path: %s", passEntry->m_path.GetCStr());
ImGui::Text("Duration in ticks: %u", passEntry->m_timestampResult.GetDurationInTicks());
ImGui::Text("Duration in microsecond: %.3f us", passEntry->m_timestampResult.GetDurationInNanoseconds()/1000.f);
ImGui::EndTooltip();
}
}
rowStartY += passBarHeight + passBarSpace;
}
}
ImGui::EndChild();
ImGui::Separator();
}
// Draw the timestamp view.
{
static const AZStd::array<const char*, static_cast<int32_t>(TimestampMetricUnit::Count)> MetricUnitText =
@@ -713,20 +865,18 @@ namespace AZ
const auto drawWorkloadBar = [this](const AZStd::string& entryTime, const PassEntry* entry)
{
ImGui::NextColumn();
ImGui::Text(entryTime.c_str());
ImGui::NextColumn();
// Only draw the workload bar when the entry is enabled.
if (entry->IsTimestampEnabled())
if (entry->m_isParent)
{
DrawFrameWorkloadBar(NormalizeFrameWorkload(entry->m_interpolatedTimestampInNanoseconds));
ImGui::NextColumn();
ImGui::NextColumn();
}
else
{
ImGui::ProgressBar(0.0f, ImVec2(-1.0f, 0.0f), "Disabled");
ImGui::Text(entryTime.c_str());
ImGui::NextColumn();
DrawFrameWorkloadBar(NormalizeFrameWorkload(entry->m_interpolatedTimestampInNanoseconds));
ImGui::NextColumn();
}
ImGui::NextColumn();
};
static const auto createHoverMarker = [](const char* text)
@@ -800,23 +950,17 @@ namespace AZ
// Draw the flat view.
for (const PassEntry* entry : m_passEntryReferences)
{
if (entry->m_isParent)
{
continue;
}
const AZStd::string entryTime = FormatTimestampLabel(entry->m_interpolatedTimestampInNanoseconds);
ImGui::Text(entry->m_name.GetCStr());
ImGui::NextColumn();
ImGui::Text(entryTime.c_str());
ImGui::NextColumn();
// Only draw the workload bar if the entry is enabled.
if (entry->IsTimestampEnabled())
{
DrawFrameWorkloadBar(NormalizeFrameWorkload(entry->m_interpolatedTimestampInNanoseconds));
}
else
{
ImGui::ProgressBar(0.0f, ImVec2(-1.0f, 0.0f), "Disabled");
}
DrawFrameWorkloadBar(NormalizeFrameWorkload(entry->m_interpolatedTimestampInNanoseconds));
ImGui::NextColumn();
}
}
@@ -890,23 +1034,33 @@ namespace AZ
// Update the PassEntry database.
const PassEntry* rootPassEntryRef = CreatePassEntries(rootPass);
bool wasDraw = draw;
GpuProfilerImGuiHelper::Begin("Gpu Profiler", &draw, ImGuiWindowFlags_NoResize, [this, &rootPass]()
{
ImGui::Checkbox("Enable TimestampView", &m_drawTimestampView);
if (ImGui::Checkbox("Enable TimestampView", &m_drawTimestampView))
{
rootPass->SetTimestampQueryEnabled(m_drawTimestampView);
}
ImGui::Spacing();
ImGui::Checkbox("Enable PipelineStatisticsView", &m_drawPipelineStatisticsView);
if(ImGui::Checkbox("Enable PipelineStatisticsView", &m_drawPipelineStatisticsView))
{
rootPass->SetPipelineStatisticsQueryEnabled(m_drawPipelineStatisticsView);
}
});
// Draw the PipelineStatistics window.
m_timestampView.DrawTimestampWindow(m_drawTimestampView, rootPassEntryRef, m_passEntryDatabase);
m_timestampView.DrawTimestampWindow(m_drawTimestampView, rootPassEntryRef, m_passEntryDatabase, rootPass);
// Draw the PipelineStatistics window.
m_pipelineStatisticsView.DrawPipelineStatisticsWindow(m_drawPipelineStatisticsView, rootPassEntryRef, m_passEntryDatabase);
m_pipelineStatisticsView.DrawPipelineStatisticsWindow(m_drawPipelineStatisticsView, rootPassEntryRef, m_passEntryDatabase, rootPass);
// [GFX TODO][ATOM-13792] Optimization: ImGui GpuProfiler Pass hierarchy traversal.
// Enable/Disable the Timestamp and PipelineStatistics on the RootPass
rootPass->SetTimestampQueryEnabled(draw && m_drawTimestampView);
rootPass->SetPipelineStatisticsQueryEnabled(draw && m_drawPipelineStatisticsView);
//closing window
if (wasDraw && !draw)
{
rootPass->SetTimestampQueryEnabled(false);
rootPass->SetPipelineStatisticsQueryEnabled(false);
}
}
inline void ImGuiGpuProfiler::InterpolatePassEntries(AZStd::unordered_map<Name, PassEntry>& passEntryDatabase, float weight) const
@@ -918,7 +1072,7 @@ namespace AZ
{
// Interpolate the timestamps.
const double interpolated = Lerp(static_cast<double>(oldEntryIt->second.m_interpolatedTimestampInNanoseconds),
static_cast<double>(entry.second.m_timestampResult.GetTimestampInNanoseconds()),
static_cast<double>(entry.second.m_timestampResult.GetDurationInNanoseconds()),
static_cast<double>(weight));
entry.second.m_interpolatedTimestampInNanoseconds = static_cast<uint64_t>(interpolated);
}
+4
View File
@@ -222,6 +222,10 @@ void ImGuiManager::Initialize()
io.DisplaySize.x = 1920;
io.DisplaySize.y = 1080;
// Create a default font
io.Fonts->AddFontDefault();
io.Fonts->Build();
// Broadcast ImGui Ready to Listeners
ImGuiUpdateListenerBus::Broadcast(&IImGuiUpdateListener::OnImGuiInitialize);
m_currentControllerIndex = -1;