5#include "InspectorGuiHelper.h"
6#include "Services/Variables.h"
7#include "Services/QualityService.h"
9#include "Rendering/IGraphicsDevice.h"
10#include "Rendering/IContext.h"
11#include "Rendering/Statistics.h"
18 std::string byteString(
size_t bytes)
20 if (bytes < 16 * 1024) {
21 return std::to_string(bytes) +
" B";
24 if (bytes < 16 * 1024) {
25 return std::to_string(bytes) +
" KiB";
28 if (bytes < 16 * 1024) {
29 return std::to_string(bytes) +
" MiB";
32 return std::to_string(bytes) +
" GiB";
36 std::string numberString(T n)
38 if (n == ~T(0)) {
return "n/a"; }
41 return std::to_string(n);
45 return std::to_string(n) +
" k";
49 return std::to_string(n) +
" M";
52 return std::to_string(n) +
" G";
58void Cogs::Core::renderingStatsInspector(
class Context* context,
bool* show)
60 IContext* deviceContext = context->device->getImmediateContext();
62 QualityService* quality = context->qualityService.get();
64 deviceContext->frameStatisticsConfigure(
true);
66 guiBegin(
"Performance statistics", show);
67 if (ImGui::CollapsingHeader(
"Draw calls", ImGuiTreeNodeFlags_::ImGuiTreeNodeFlags_DefaultOpen)) {
68 const Cogs::FrameStatistics& frameStats = context->device->getImmediateContext()->getLastFrameStatistics();
69 const uint32_t* h = frameStats.drawCallHistogram;
71 std::array<std::string,12> labelTexts{
86 std::array<uint32_t, labelTexts.size()-1> values{
97 h[20] + h[21] + h[22] + h[23] +
98 h[24] + h[25] + h[26] + h[27] +
99 h[28] + h[29] + h[30] + h[31]
102 uint32_t drawCalls = 0;
103 uint32_t maxValue = 1;
104 ImVec2 maxTextSize(40, 0);
105 std::array<std::string, values.size()> valueTexts;
106 std::array<ImVec2, values.size()> valueSizes;
107 std::array<ImVec2, labelTexts.size()> labelSizes;
109 for (
size_t i = 0; i < values.size(); i++) {
110 drawCalls += values[i];
111 maxValue = std::max(maxValue, values[i]);
112 valueTexts[i] = numberString(values[i]);
113 valueSizes[i] = ImGui::CalcTextSize(valueTexts[i].c_str());
114 maxTextSize.x = std::max(maxTextSize.x, valueSizes[i].x);
115 maxTextSize.y = std::max(maxTextSize.y, valueSizes[i].y);
117 for (
size_t i = 0; i < labelTexts.size(); i++) {
118 labelSizes[i] = ImGui::CalcTextSize(labelTexts[i].c_str());
119 maxTextSize.x = std::max(maxTextSize.x, labelSizes[i].x);
120 maxTextSize.y = std::max(maxTextSize.y, labelSizes[i].y);
123 const float height = 100.f;
124 const float spacing = 2.f;
125 ImGuiStyle& style = ImGui::GetStyle();
126 const ImU32 textCol = ImColor(style.Colors[ImGuiCol_Text]);
127 const ImU32 graphCol = ImColor(style.Colors[ImGuiCol_PlotLines]);
128 const ImVec2 p = ImGui::GetCursorScreenPos();
129 ImDrawList* draw_list = ImGui::GetWindowDrawList();
132 for (
size_t i = 0; i < values.size(); i++) {
133 float v =
static_cast<float>(values[i]) /
static_cast<float>(maxValue);
134 float x = p.x + i * maxTextSize.x + spacing;
137 draw_list->AddRect(ImVec2(x + spacing,
138 maxTextSize.y + y + (1.f - v) * height),
139 ImVec2(x + maxTextSize.x - spacing,
140 maxTextSize.y + y + height),
146 for (
size_t i = 0; i < valueTexts.size(); i++) {
147 float v =
static_cast<float>(values[i]) /
static_cast<float>(maxValue);
148 float x = p.x + spacing + i * maxTextSize.x + 0.5f * (maxTextSize.x - valueSizes[i].x);
149 float y = p.y + spacing + (1.f - v) * height;
150 draw_list->AddText(ImVec2(x, y), textCol, valueTexts[i].c_str());
154 for (
size_t i = 0; i < labelTexts.size(); i++) {
155 float x = p.x + spacing + std::min(std::max((i - 0.5f) * maxTextSize.x + 0.5f * (maxTextSize.x - labelSizes[i].x),
157 (labelTexts.size()-1) * maxTextSize.x - labelSizes[i].x - spacing);
158 float y = p.y + spacing + maxTextSize.y + height;
159 draw_list->AddText(ImVec2(x, y), textCol, labelTexts[i].c_str());
163 ImVec2 q(values.size() * maxTextSize.x + 2.f * spacing, 2.f * spacing + height + 2.f * maxTextSize.y);
164 draw_list->AddRect(p, ImVec2(p.x + q.x, p.y + q.y), graphCol, 0.0f);
171 ImGui::Text(
"Draw calls submitted");
173 t = numberString(drawCalls);
174 ImGui::TextUnformatted(t.c_str());
178 ImGui::Text(
"Vertices submitted");
180 t = numberString(frameStats.vertices);
181 ImGui::TextUnformatted(t.c_str());
185 ImGui::Text(
"Percentage indexed");
187 ImGui::Text(
"%.1f%%", (100.f * frameStats.indices) / frameStats.vertices);
191 ImGui::Text(
"Average submission size");
193 t = numberString(drawCalls == 0 ? 0 :
static_cast<size_t>(
static_cast<float>(frameStats.vertices) / drawCalls));
194 ImGui::TextUnformatted(t.c_str());
198 ImGui::Text(
"Frame time:");
200 ImGui::Text(
"%.2fms (%.1f FPS)",
201 quality->avgFrameTime,
202 1000.f/ quality->avgFrameTime);
205 float frameTime = std::max(0.f, context->variables->get(
"quality.frameTimeTarget", 0.f));
206 if (ImGui::InputFloat(
"##frametimetarget", &frameTime, 1.f, 10.f,
"%.1f ms")) {
207 context->variables->set(
"quality.frameTimeTarget", std::max(0.f, frameTime));
213 if (ImGui::CollapsingHeader(
"GPU resources", ImGuiTreeNodeFlags_::ImGuiTreeNodeFlags_DefaultOpen)) {
219 ImGui::Text(
"GPU memory consumption");
221 t = byteString(resourceStats.memoryConsumption());
222 ImGui::TextUnformatted(t.c_str());
225 ImGui::Text(
"Limit:");
226 float GPUMBLimit = std::max(0.f, context->variables->get(
"quality.GPUMemTargetMB", 0.f));
227 if (ImGui::InputFloat(
"##gpumemtarget", &GPUMBLimit, 100.f, 250.f,
"%.0f MB")) {
228 context->variables->set(
"quality.GPUMemTargetMB", std::max(0,
int(GPUMBLimit)));
232 static size_t memoryPeak = 0;
233 static size_t bufferMemoryPeak = 0;
234 static size_t textureMemoryPeak = 0;
235 static size_t memoryAverage = resourceStats.memoryConsumption();
236 static size_t bufferMemoryAverage = resourceStats.bufferMemoryConsumption;
237 static size_t textureMemoryAverage = resourceStats.textureMemoryConsumption;
238 static size_t statsReadIteration = 1;
239 if((statsReadIteration + 1) == 0)
241 statsReadIteration = 1;
242 memoryAverage = resourceStats.memoryConsumption();
243 bufferMemoryAverage = resourceStats.bufferMemoryConsumption;
244 textureMemoryAverage = resourceStats.textureMemoryConsumption;
247 double res = 1.0 / statsReadIteration;
248 double termpart =
static_cast<double>(statsReadIteration-1) * res;
249 memoryAverage =
static_cast<size_t>(memoryAverage * termpart +
static_cast<double>(resourceStats.memoryConsumption()) * res);
250 bufferMemoryAverage =
static_cast<size_t>(bufferMemoryAverage * termpart +
static_cast<double>(resourceStats.bufferMemoryConsumption) * res);
251 textureMemoryAverage =
static_cast<size_t>(textureMemoryAverage * termpart +
static_cast<double>(resourceStats.textureMemoryConsumption) * res);
255 ImGui::Text(
"\t- Peak");
257 memoryPeak = std::max(memoryPeak, resourceStats.memoryConsumption());
258 ImGui::TextUnformatted(byteString(memoryPeak).c_str());
261 if(ImGui::Button(
"Reset Peaks##mem")) {
262 statsReadIteration = 1;
263 memoryPeak = resourceStats.memoryConsumption();
264 bufferMemoryPeak = resourceStats.bufferMemoryConsumption;
265 textureMemoryPeak = resourceStats.textureMemoryConsumption;
269 ImGui::Text(
"\t- Average");
271 ImGui::TextUnformatted(byteString(memoryAverage).c_str());
275 ImGui::Text(
"Buffers");
277 ImGui::Text(
"%u (%s)", resourceStats.bufferCount, byteString(resourceStats.bufferMemoryConsumption).c_str());
280 ImGui::Text(
"\t- Peak");
282 bufferMemoryPeak = std::max(bufferMemoryPeak, resourceStats.bufferMemoryConsumption);
283 ImGui::TextUnformatted(byteString(bufferMemoryPeak).c_str());
286 ImGui::Text(
"\t- Average");
288 ImGui::TextUnformatted(byteString(bufferMemoryAverage).c_str());
292 ImGui::Text(
"Textures");
294 ImGui::Text(
"%u (%s)", resourceStats.textureCount, byteString(resourceStats.textureMemoryConsumption).c_str());
297 ImGui::Text(
"\t- Peak");
299 textureMemoryPeak = std::max(textureMemoryPeak, resourceStats.textureMemoryConsumption);
300 ImGui::TextUnformatted(byteString(textureMemoryPeak).c_str());
303 ImGui::Text(
"\t- Average");
305 ImGui::TextUnformatted(byteString(textureMemoryAverage).c_str());
309 ImGui::Text(
"Vertex array objects");
311 t = numberString(resourceStats.vertexArrayObjectCount);
312 ImGui::TextUnformatted(t.c_str());
316 ImGui::Text(
"Input layouts");
318 t = numberString(resourceStats.inputLayoutCount);
319 ImGui::TextUnformatted(t.c_str());
323 ImGui::Text(
"Effects");
325 t = numberString(resourceStats.effectCount);
326 ImGui::TextUnformatted(t.c_str());
330 ImGui::Text(
"Rendertargets");
332 t = numberString(resourceStats.rendertargetsCount);
333 ImGui::TextUnformatted(t.c_str());
337 ImGui::Text(
"Framebuffers");
339 t = numberString(resourceStats.framebufferCount);
340 ImGui::TextUnformatted(t.c_str());
344 ImGui::Text(
"Sampler states");
346 t = numberString(resourceStats.samplerStateCount);
347 ImGui::TextUnformatted(t.c_str());
351 ImGui::Text(
"Blend states");
353 t = numberString(resourceStats.blendStateCount);
354 ImGui::TextUnformatted(t.c_str());
358 ImGui::Text(
"Rasterizer states");
360 t = numberString(resourceStats.rasterizerStateCount);
361 ImGui::TextUnformatted(t.c_str());
365 ImGui::Text(
"Depth-stencil states");
367 t = numberString(resourceStats.depthStencilStateCount);
368 ImGui::TextUnformatted(t.c_str());
378 deviceContext->frameStatisticsConfigure(
false);