1#include "InspectorGuiRenderer.h"
4#include "imgui_internal.h"
9#include "Renderer/IRenderer.h"
11#include "Editor/IEditor.h"
13#include "InspectorGuiHelper.h"
14#include "EntityInspector.h"
15#include "Inspectors.h"
16#include "Platform/Instrumentation.h"
17#include "Services/QualityService.h"
19#ifdef COGS_USE_MICROPROFILE
20#include <microprofileui.h>
23void Cogs::Core::InspectorGuiRenderer::initialize(Context * , IRenderer* renderer)
25 imguiRenderer = renderer->getGuiRenderer();
26 imguiContext = imguiRenderer->createGuiContext();
28#ifdef COGS_USE_MICROPROFILE
31 auto & profiler = *MicroProfileGet();
32 profiler.nDisplay = MP_DRAW_DETAILED;
33 profiler.nAllGroupsWanted = 1;
37void Cogs::Core::InspectorGuiRenderer::registerInspector(
const std::string& name, Inspector inspector)
39 inspectors.emplace_back(RegisteredInspector{ name, inspector,
false });
42void Cogs::Core::InspectorGuiRenderer::beginRender(Context* context, IRenderer* renderer)
44 RenderInstrumentationScope(renderer->getDevice()->getImmediateContext(), SCOPE_RENDERING,
"GuiRenderer::beginRender");
46 imguiRenderer->frame(imguiContext, *context->getDefaultView());
47 imguiRenderer->style();
50void Cogs::Core::InspectorGuiRenderer::renderTimes(Context * context)
52 QualityService* quality = context->qualityService.get();
58 size_t timesCount = quality->TIMES_COUNT;
60 ImU32 CpuTimeColor = IM_COL32(255, 50, 50, 255);
61 ImU32 PreRenderColor = IM_COL32(0, 128, 0, 255);
62 ImU32 PresentColor = IM_COL32(255, 255, 50, 255);
63 ImU32 IdleColor = IM_COL32(0, 127, 255, 255);
65 float dt =
static_cast<float>(delta_timer.elapsedSeconds());
66 delta_timer = Timer::startNew();
68 if(delta_akk > delta_update){
69 cogsTime = quality->getMetric(MetricType::Frame)*1000.0f;
70 idleTime = quality->getMetric(MetricType::Idle)*1000.0f;
71 frameTime = cogsTime+idleTime;
72 preRenderTime = quality->getMetric(MetricType::PreRender)*1000.0f;
73 presentTime = quality->getMetric(MetricType::Present)*1000.0f;
74 cpuTime = cogsTime-presentTime;
75 cogsFPS = 1000.0f/cogsTime;
76 frameFPS = 1000.0f/frameTime;
77 cpuFps = 1000.0f/cpuTime;
81 frameMax = std::max(frameMax, frameTime);
82 frameMin = std::min(frameMin, frameTime);
84 cogsMax = std::max(cogsMax, cogsTime);
85 cogsMin = std::min(cogsMin, cogsTime);
87 static std::vector<float> scales = { 10.0f, 16.67f, 33.33f, 100.0f };
89 float scale = scales.front();
90 for (
auto & s : scales) {
91 if (frameMax < scale) {
93 }
else if (frameMax > scale && frameMax < s) {
102 ImGui::Text(
"Frame: %.3fms Max: %.3fms (%.2f FPS)", frameTime, frameMax, frameFPS);
103 ImGui::Text(
"Cogs: %.3fms Max: %.3fms (%.2f FPS)", cogsTime, cogsMax, cogsFPS);
104 ImGui::TextColored(ImColor(PreRenderColor),
"PreRender: %.3fms", preRenderTime);
106 ImGui::TextColored(ImColor(CpuTimeColor),
"CPU: %.3fms (%.2f FPS)", cpuTime, cpuFps);
107 ImGui::TextColored(ImColor(PresentColor),
"Present: %.3fms", presentTime);
109 ImGui::TextColored(ImColor(IdleColor),
"Idle: %.3fms", idleTime);
112 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos();
113 ImVec2 canvas_sz = ImGui::GetContentRegionAvail();
114 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
115 canvas_sz.y = 140.0f;
116 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
118 ImGui::PushClipRect(canvas_p0, canvas_p1,
true);
120 ImDrawList *draw_list = ImGui::GetWindowDrawList();
121 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
123 ImGui::InvisibleButton(
"canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
126 for(
size_t i=0; i<timesCount; i++){
127 size_t idx = (quality->times_idx+quality->TIMES_COUNT-i)%quality->TIMES_COUNT;
128 float x0 = (
float)i/timesCount;
129 float x1 = (float)(i+1)/timesCount;
130 float y0 = quality->times[idx][(size_t)MetricType::Frame]/scale;
131 ImVec2 pos0(canvas_p0.x+x0*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y0));
132 ImVec2 pos1(canvas_p0.x+x1*canvas_sz.x, canvas_p1.y);
133 draw_list->AddRectFilled(pos0, pos1, CpuTimeColor);
136 for(
size_t i=0; i<timesCount; i++){
137 size_t idx = (quality->times_idx+quality->TIMES_COUNT-i)%quality->TIMES_COUNT;
138 float x0 = (
float)i/timesCount;
139 float x1 = (float)(i+1)/timesCount;
140 float y0 = quality->times[idx][(size_t)MetricType::PreRender]/scale;
142 ImVec2 pos0(canvas_p0.x+x0*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y0));
143 ImVec2 pos1(canvas_p0.x+x1*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y1));
144 draw_list->AddRectFilled(pos0, pos1, PreRenderColor);
147 for(
size_t i=0; i<timesCount; i++){
148 size_t idx = (quality->times_idx+quality->TIMES_COUNT-i)%quality->TIMES_COUNT;
149 float x0 = (
float)i/timesCount;
150 float x1 = (float)(i+1)/timesCount;
151 float y0 = quality->times[idx][(size_t)MetricType::Frame]/scale;
152 float y1 = (quality->times[idx][(size_t)MetricType::Frame]-quality->times[idx][(
size_t)MetricType::Present])/scale;
153 ImVec2 pos0(canvas_p0.x+x0*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y0));
154 ImVec2 pos1(canvas_p0.x+x1*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y1));
155 draw_list->AddRectFilled(pos0, pos1, PresentColor);
158 for(
size_t i=0; i<timesCount; i++){
159 size_t idx = (quality->times_idx+quality->TIMES_COUNT-i)%quality->TIMES_COUNT;
160 float x0 = (
float)i/timesCount;
161 float x1 = (float)(i+1)/timesCount;
162 float y0 = (quality->times[idx][(size_t)MetricType::Frame]+quality->times[idx][(
size_t)MetricType::Idle])/scale;
163 float y1 = quality->times[idx][(size_t)MetricType::Frame]/scale;
164 ImVec2 pos0(canvas_p0.x+x0*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y0));
165 ImVec2 pos1(canvas_p0.x+x1*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y1));
166 draw_list->AddRectFilled(pos0, pos1, IdleColor);
168 if (ImGui::IsItemHovered()) {
169 ImGui::SetNextWindowBgAlpha(0.7f);
170 ImGui::BeginTooltip();
171 ImVec2 cpos =ImGui::GetMousePos();
172 ImVec2 rpos = cpos - canvas_p0;
173 ImVec2 npos = rpos / canvas_sz;
174 int i = (int)(npos.x * timesCount);
176 i = std::min(i, (
int)timesCount-1);
177 size_t idx = (quality->times_idx+quality->TIMES_COUNT-i)%quality->TIMES_COUNT;
178 ImGui::Text(
"(%d, %.3fms)", i, (1.0f-npos.y)*scale);
179 ImGui::Text(
"%.3fms", quality->times[idx][(
size_t)MetricType::Frame]*1000);
181 ImGui::TextColored(ImColor(PreRenderColor),
"%.3fms", quality->times[idx][(
size_t)MetricType::PreRender]*1000);
183 ImGui::TextColored(ImColor(CpuTimeColor),
"%.3fms", (quality->times[idx][(
size_t)MetricType::Frame]-
184 quality->times[idx][(
size_t)MetricType::Present])*1000);
185 ImGui::TextColored(ImColor(PresentColor),
"%.3fms", quality->times[idx][(
size_t)MetricType::Present]*1000);
187 ImGui::TextColored(ImColor(IdleColor),
"%.3fms", quality->times[idx][(
size_t)MetricType::Idle]*1000);
191 ImGui::PopClipRect();
195 if(ImGui::TreeNode(
"Upload Statistics")){
198 ImU32 BufferUploadColor = IM_COL32(0, 128, 0, 255);
199 ImU32 TextureUploadColor = IM_COL32(255, 255, 50, 255);
201 ImGui::TextColored(ImColor(BufferUploadColor),
"Buffer Upload: %zu", quality->bufferUploadSize[(quality->times_idx+timesCount-1)%timesCount]);
203 ImGui::TextColored(ImColor(TextureUploadColor),
"Texture Upload: %zu", quality->textureUploadSize[(quality->times_idx+timesCount-1)%timesCount]);
205 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos();
206 ImVec2 canvas_sz = ImGui::GetContentRegionAvail();
207 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
208 canvas_sz.y = 140.0f;
209 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
210 ImGui::PushClipRect(canvas_p0, canvas_p1,
true);
212 ImDrawList *draw_list = ImGui::GetWindowDrawList();
213 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
215 ImGui::InvisibleButton(
"canvas2", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
217 float upload_scale = 1.0f/(1024.0f*1024.0f*64.0f);
220 for(
size_t i=0; i<timesCount; i++){
221 size_t idx = (quality->times_idx+quality->TIMES_COUNT-i)%quality->TIMES_COUNT;
222 float x0 = (
float)i/timesCount;
223 float x1 = (float)(i+1)/timesCount;
224 float y0 = quality->bufferUploadSize[idx]*upload_scale;
226 ImVec2 pos0(canvas_p0.x+x0*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y0));
227 ImVec2 pos1(canvas_p0.x+x1*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y1));
228 draw_list->AddRectFilled(pos0, pos1, BufferUploadColor);
231 for(
size_t i=0; i<timesCount; i++){
232 size_t idx = (quality->times_idx+quality->TIMES_COUNT-i)%quality->TIMES_COUNT;
233 float x0 = (
float)i/timesCount;
234 float x1 = (float)(i+1)/timesCount;
235 float y0 = (quality->bufferUploadSize[idx]+quality->textureUploadSize[idx])*upload_scale;
236 float y1 = quality->bufferUploadSize[idx]*upload_scale;
237 ImVec2 pos0(canvas_p0.x+x0*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y0));
238 ImVec2 pos1(canvas_p0.x+x1*canvas_sz.x, canvas_p0.y+canvas_sz.y*(1.0f-y1));
239 draw_list->AddRectFilled(pos0, pos1, TextureUploadColor);
242 if (ImGui::IsItemHovered()) {
243 ImGui::SetNextWindowBgAlpha(0.7f);
244 ImGui::BeginTooltip();
245 ImVec2 cpos =ImGui::GetMousePos();
246 ImVec2 rpos = cpos - canvas_p0;
247 ImVec2 npos = rpos / canvas_sz;
248 int i = (int)(npos.x * timesCount);
250 i = std::min(i, (
int)timesCount-1);
251 size_t idx = (quality->times_idx+quality->TIMES_COUNT-i)%quality->TIMES_COUNT;
252 ImGui::TextColored(ImColor(BufferUploadColor),
"%zu", quality->bufferUploadSize[idx]);
253 ImGui::TextColored(ImColor(TextureUploadColor),
"%zu", quality->textureUploadSize[idx]);
257 ImGui::PopClipRect();
262 ImVec2 buttonSize(96, 24);
264 if (ImGui::Button(
"Reset", buttonSize)) {
271 bool vSync = context->variables->get(
"renderer.vSync",
false);
272 if(ImGui::Checkbox(
"vSync", &vSync)){
273 context->variables->set(
"renderer.vSync", vSync);
276 ImGui::Text(
"Scale Y %.3f", scale);
278void Cogs::Core::InspectorGuiRenderer::render(Context * context, IRenderer * renderer)
280 if (context->engine->getEditor() && context->engine->getEditor()->isActive()) {
281 context->engine->getEditor()->show();
284 if (!context->variables->get(
"gui.enabled",
false))
return;
286 context->engine->triggerUpdate();
288 RenderInstrumentationScope(renderer->getDevice()->getImmediateContext(), SCOPE_RENDERING,
"GuiRenderer::render");
293 } variableMapping[] = {
294 {
"gui.aboutCogs", showAboutCogs },
295 {
"gui.renderingStatsInspector", showRenderingStatsInspector },
296 {
"gui.textureInspector", showTextureInspector },
297 {
"gui.shadowMapInspector", showShadowMapInspector },
298 {
"gui.entityInspector", showEntityInspector },
299 {
"gui.fontInspector", showFontInspector },
300 {
"gui.variableInspector", showVariableInspector },
301 {
"gui.inputInspector", showInputInspector },
302 {
"gui.modelInspector", showModelInspector },
303 {
"gui.meshInspector", showMeshInspector },
304 {
"gui.materialInspector", showMaterialInspector },
305 {
"gui.materialInstanceInspector", showMaterialInstanceInspector },
306 {
"gui.resourceInspector", showResourceInspector },
307 {
"gui.scriptInspector", showScriptInspector },
308 {
"gui.scriptConsole", showScriptConsole },
309 {
"gui.profiler", showProfiler },
310 {
"gui.pipelineInspector", showPipelineInspector },
311 {
"gui.permutationInspector", showPermutationInspector },
312 {
"gui.assetInspector", showAssetInspector },
313 {
"gui.assetQueueInspector", showAssetQueueInspector },
314 {
"gui.boundsInspector", showBoundsInspector },
315 {
"gui.bufferInspector", showBufferInspector },
316 {
"gui.engineInspector", showEngineInspector },
317 {
"gui.exampleGui", showExampleGui },
318 {
"gui.gammaDebugger", showGammaDebugger },
321 for (
const VariableMap variableMap : variableMapping) {
322 if (Variable* var = context->variables->getIfExists(variableMap.name); var !=
nullptr && !var->isEmpty()) {
323 variableMap.toggle = var->getBool();
328 if(ImGui::Begin(
"Engine", &show, ImGuiWindowFlags_MenuBar)){
330 if (ImGui::BeginMenuBar()) {
331 if (ImGui::BeginMenu(
"View")) {
337 {
"Asset Queue", showAssetQueueInspector },
338 {
"Assets", showAssetInspector },
339 {
"Buffers", showBufferInspector },
340 {
"Console", showScriptConsole },
341 {
"Entities", showEntityInspector },
342 {
"Fonts", showFontInspector },
343 {
"Inputs", showInputInspector },
344 {
"Materials", showMaterialInspector },
345 {
"Material Instances", showMaterialInstanceInspector },
346 {
"Meshes", showMeshInspector},
347 {
"Models", showModelInspector},
348 {
"Render Pipeline", showPipelineInspector },
349 {
"Permutations", showPermutationInspector },
350 {
"Resources", showResourceInspector },
351 {
"Textures", showTextureInspector },
352 {
"Variables", showVariableInspector },
353 {
"ImGui Examples", showExampleGui},
356 for (
size_t i = 0; i < glm::countof(buttons); ++i) {
357 if (!buttons[i].title)
continue;
358 if (ImGui::MenuItem(buttons[i].title)) {
359 buttons[i].toggle = !buttons[i].toggle;
364 if (ImGui::BeginMenu(
"Debuggers")) {
370 {
"Bounds", showBoundsInspector },
371 {
"Engine Statistics", showEngineInspector },
372 {
"Task Manager Statistics", showTaskManagerInspector },
373 {
"GammaDebugger", showGammaDebugger },
374 {
"Performance", showRenderingStatsInspector },
375 {
"Profiler", showProfiler },
376 {
"Shadow maps", showShadowMapInspector },
379 for (
size_t i = 0; i < glm::countof(buttons); ++i) {
380 if (!buttons[i].title)
continue;
381 if (ImGui::MenuItem(buttons[i].title)) {
382 buttons[i].toggle = !buttons[i].toggle;
387 if (inspectors.size() && ImGui::BeginMenu(
"Extensions")) {
388 for (
auto & inspector : inspectors) {
389 if (ImGui::MenuItem(inspector.name.c_str())) {
390 inspector.show = !inspector.show;
395 if (ImGui::BeginMenu(
"Help")) {
401 {
"About", showAboutCogs },
404 for (
size_t i = 0; i < glm::countof(buttons); ++i) {
405 if (!buttons[i].title)
continue;
406 if (ImGui::MenuItem(buttons[i].title)) {
407 buttons[i].toggle = !buttons[i].toggle;
415 renderTimes(context);
421 const char* pipeline;
422 } visualizationModes[] = {
423 {
"No visualizer",
"" },
424 {
"Show normals",
"Pipelines/DebugView/ShowNormals.pipeline" },
425 {
"Show draw calls",
"Pipelines/DebugView/ShowDrawCalls.pipeline" },
426 {
"Show object IDs",
"Pipelines/DebugView/ShowObjectIDs.pipeline" },
427 {
"Show triangle size",
"Pipelines/DebugView/ShowTriangleSizes.pipeline" },
428 {
"Show shadow cascades",
"Pipelines/DebugView/ShowShadowCascades.pipeline" }
430 if (ImGui::BeginCombo(
"##combo", visualizationModes[visualizationMode].name)) {
431 for (
size_t i = 0; i < IM_ARRAYSIZE(visualizationModes); i++) {
432 bool selected = i == visualizationMode;
433 if (ImGui::Selectable(visualizationModes[i].name, selected)) {
434 visualizationMode =
static_cast<uint8_t
>(i);
435 context->variables->set(
"renderer.pipeline.override", visualizationModes[i].pipeline);
438 ImGui::SetItemDefaultFocus();
445 if (visualizationMode != 0) {
446 float edge = std::pow(context->variables->get(
"debugView.edge", 0.5f), 2.2f);
447 if (ImGui::SliderFloat(
"Wireframe", &edge, 0.f, 1.f,
"%.3f")) {
448 context->variables->set(
"debugView.edge", std::pow(edge, 1.f / 2.2f));
450 float outline = std::pow(context->variables->get(
"debugView.outline", 1.0f), 2.2f);
451 if (ImGui::SliderFloat(
"Outline", &outline, 0.f, 1.f,
"%.3f")) {
452 context->variables->set(
"debugView.outline", std::pow(outline, 1.f / 2.2f));
457 if (visualizationMode == 4) {
458 float lo = context->variables->get(
"debugView.triangleSize.lo", 10.f);
459 float hi = context->variables->get(
"debugView.triangleSize.hi", 100.f);
461 if (ImGui::SliderFloat(
"Yellow size", &lo, 1.f, 100.f,
"%.1f")) {
464 if (ImGui::SliderFloat(
"Green size", &hi, 1.f, 100.f,
"%.1f")) {
465 lo = std::max(1.f, std::min(lo, hi - 1.f));
468 hi = std::max(lo + 1.f, hi);
470 context->variables->set(
"debugView.triangleSize.lo", lo);
471 context->variables->set(
"debugView.triangleSize.hi", hi);
477 QualityService* quality = context->qualityService.get();
478 float qualitySetting = context->variables->get(
"quality.setting", 100.f);
479 if (ImGui::SliderFloat(
"##Quality", &qualitySetting, 0.f, 200.f,
"quality %.0f%%")) {
480 context->variables->set(
"quality.setting", qualitySetting);
482 ImGui::Text(
"Current quality: %.2f, AssetSystem: %.2f",
483 quality->currentQuality,
484 quality->assetSystemToleranceScale);
485 ImGui::Text(
"PoTreeSystem: %.2f/%.2f, 3DTilesSystem: %.2f/%.2f",
486 quality->potreeSystemToleranceScale,
487 quality->potreeSystemChunkCountScale,
488 quality->ogc3DTilesSystemCacheControl,
489 quality->ogc3DTilesSystemToleranceScale);
498 {
"Entities", showEntityInspector },
499 {
"Variables", showVariableInspector },
501 ImVec2 buttonSize(96, 24);
503 for (
size_t i = 0; i < glm::countof(buttons); ++i) {
504 if (!buttons[i].title)
continue;
506 if (i % 2 != 0) ImGui::SameLine();
508 if (ImGui::Button(buttons[i].title, buttonSize)) {
509 buttons[i].toggle = !buttons[i].toggle;
515 for (VariableMap variableMap : variableMapping) {
516 if (Variable* var = context->variables->getIfExists(variableMap.name); var !=
nullptr && !var->isEmpty()) {
517 var->setBool(variableMap.toggle);
521 for (
auto & inspector : inspectors) {
522 inspector.inspector(context, &inspector.show);
525 aboutCogs(context, &showAboutCogs);
526 textureInspector(context, &showTextureInspector);
527 shadowMapInspector(context, &showShadowMapInspector);
528 entityInspector(context, &showEntityInspector);
529 variableInspector(context, &showVariableInspector);
530 modelInspector(context, &showModelInspector);
531 meshInspector(context, &showMeshInspector);
532 materialInspector(context, &showMaterialInspector);
533 materialInstanceInspector(context, &showMaterialInstanceInspector);
534 fontInspector(context, &showFontInspector);
535 inputInspector(context, &showInputInspector);
536 resourceStoreInspector(context, &showResourceInspector);
537 scriptInspector(context, &showScriptInspector);
538 scriptConsole(context, &showScriptConsole);
539 profileInspector(context, &showProfiler);
540 renderingStatsInspector(context, &showRenderingStatsInspector);
541 pipelineInspector(context, &showPipelineInspector);
542 permutationInspector(context, &showPermutationInspector);
543 assetInspector(context, &showAssetInspector);
544 assetQueueInspector(context, &showAssetQueueInspector);
545 boundsInspector(context, &showBoundsInspector);
546 bufferInspector(context, &showBufferInspector);
547 engineInspector(context, &showEngineInspector);
548 gammaDebugger(context, &showGammaDebugger);
549 taskManagerInspector(context, &showTaskManagerInspector);
552 ImGui::ShowDemoWindow(&showExampleGui);
556 context->variables->set(
"gui.enabled",
false);
560void Cogs::Core::InspectorGuiRenderer::endRender(Context * , IRenderer * renderer)
562 RenderInstrumentationScope(renderer->getDevice()->getImmediateContext(), SCOPE_RENDERING,
"GuiRenderer::endRender");
564 imguiRenderer->render();
567void Cogs::Core::InspectorGuiRenderer::cleanup(Context * , IRenderer * )
570 imguiRenderer->deleteGuiContext(imguiContext);
571 imguiContext =
nullptr;