3#include "InspectorGuiHelper.h"
6#include "Services/Variables.h"
8#include "Renderer/Renderer.h"
9#include "Renderer/RenderPipelineManager.h"
10#include "Renderer/RenderTexture.h"
11#include "Renderer/RenderList.h"
12#include "Renderer/RenderTarget.h"
13#include "Renderer/RenderBuffer.h"
14#include "Renderer/RenderMaterialInstance.h"
16#include "Renderer/Tasks/GenerateListTask.h"
17#include "Renderer/Tasks/ProcessTask.h"
18#include "Renderer/Tasks/PostProcessTask.h"
19#include "Renderer/Tasks/FilterListTask.h"
20#include "Renderer/Tasks/RenderListTask.h"
22#include "Resources/TextureManager.h"
24#include "Foundation/Reflection/TypeDatabase.h"
32 void binaryNumber(uint32_t number)
34 ImGui::Text(
"0b_%u%u%u%u_%u%u%u%u_%u%u%u%u_%u%u%u%u_%u%u%u%u_%u%u%u%u_%u%u%u%u_%u%u%u%u",
35 (number & (1 << 31)) ? 1 : 0,
36 (number & (1 << 30)) ? 1 : 0,
37 (number & (1 << 29)) ? 1 : 0,
38 (number & (1 << 28)) ? 1 : 0,
39 (number & (1 << 27)) ? 1 : 0,
40 (number & (1 << 26)) ? 1 : 0,
41 (number & (1 << 25)) ? 1 : 0,
42 (number & (1 << 24)) ? 1 : 0,
43 (number & (1 << 23)) ? 1 : 0,
44 (number & (1 << 22)) ? 1 : 0,
45 (number & (1 << 21)) ? 1 : 0,
46 (number & (1 << 20)) ? 1 : 0,
47 (number & (1 << 19)) ? 1 : 0,
48 (number & (1 << 18)) ? 1 : 0,
49 (number & (1 << 17)) ? 1 : 0,
50 (number & (1 << 16)) ? 1 : 0,
51 (number & (1 << 15)) ? 1 : 0,
52 (number & (1 << 14)) ? 1 : 0,
53 (number & (1 << 13)) ? 1 : 0,
54 (number & (1 << 12)) ? 1 : 0,
55 (number & (1 << 11)) ? 1 : 0,
56 (number & (1 << 10)) ? 1 : 0,
57 (number & (1 << 9)) ? 1 : 0,
58 (number & (1 << 8)) ? 1 : 0,
59 (number & (1 << 7)) ? 1 : 0,
60 (number & (1 << 6)) ? 1 : 0,
61 (number & (1 << 5)) ? 1 : 0,
62 (number & (1 << 4)) ? 1 : 0,
63 (number & (1 << 3)) ? 1 : 0,
64 (number & (1 << 2)) ? 1 : 0,
65 (number & (1 << 1)) ? 1 : 0,
66 (number & (1 << 0)) ? 1 : 0);
71 std::string header =
"Item " + std::to_string(ix);
72 if ((item.
stateChanges & StateChangeFlags::ChangeAll) == StateChangeFlags::ChangeAll) {
75 if ((item.
stateChanges & StateChangeFlags::ChangeTransform) != 0) {
78 if ((item.
stateChanges & StateChangeFlags::ChangeMesh) != 0) {
81 if ((item.
stateChanges & StateChangeFlags::ChangeMaterialInstance) != 0) {
84 if ((item.
stateChanges & StateChangeFlags::ChangeMaterialVariant) != 0) {
87 if ((item.
stateChanges & StateChangeFlags::ChangeRasterizerState) != 0) {
90 if ((item.
stateChanges & StateChangeFlags::ChangeBlendState) != 0) {
93 if ((item.
stateChanges & StateChangeFlags::ChangeDepthStencilState) != 0) {
96 if ((item.
stateChanges & StateChangeFlags::ChangeLayer) != 0) {
99 if ((item.
stateChanges & StateChangeFlags::ChangeViewport) != 0) {
103 if (item.materialInstance && item.materialInstance->
material) {
104 header.append(
" mat=");
105 header.append(item.materialInstance->
material->definition.name);
106 RenderMaterialInstance * renderMaterialInstance = renderer->getRenderResources().getRenderMaterialInstance(item.materialInstance);
107 if (!renderMaterialInstance) {
108 header.append(
"(no render material)");
112 if (renderMaterialInstance->loadedBindings.empty()) {
113 header.append(
"no bindings");
116 for (
auto & binding : renderMaterialInstance->loadedBindings) {
117 if (binding.enginePermutation) {
118 header.append(binding.enginePermutation->getName());
121 header.append(
"<no engine perm>");
124 if (binding.binding) {
125 if (binding.binding->renderEffect) {
126 header.append(
"has renderEffect");
129 header.append(
"<no renderEffect>");
133 header.append(
"<no binding>");
140 ImGui::Text(
"%s", header.c_str());
145 if (batch.empty())
return;
147 if (ImGui::TreeNode(name.c_str(),
"%s (%zu items)", name.c_str(), batch.size())) {
148 for (
size_t i = 0; i < batch.size(); i++) {
149 showRenderItem(context, renderer, batch[i], i);
154 void showRenderList(
Context* context,
Renderer* renderer,
const RenderItems& items,
const std::string& name)
156 if (items.empty())
return;
158 if (ImGui::TreeNode(name.c_str(),
"%s (%zu items)", name.c_str(), items.size())) {
159 for (
size_t i = 0; i < items.size(); i++) {
160 showRenderItem(context, renderer, items[i], i);
168 ImGui::Text(
"Width"); ImGui::SameLine(250.f); ImGui::Text(
"%u", renderTarget->width);
169 ImGui::Text(
"Height"); ImGui::SameLine(250.f); ImGui::Text(
"%u", renderTarget->height);
170 ImGui::Text(
"Subresource index"); ImGui::SameLine(250.f); ImGui::Text(
"%u", renderTarget->subresourceIndex);
171 ImGui::Text(
"Depth layer index"); ImGui::SameLine(250.f); ImGui::Text(
"%u", renderTarget->depthLayerIndex);
172 ImGui::Text(
"Level views"); ImGui::SameLine(250.f); ImGui::Text(
"%zu", renderTarget->mipLevelViews.size());
174 auto size = ImVec2(128, 128);
175 float aspectRatio = 1;
176 if (renderTarget->width > 0 && renderTarget->height > 0) {
177 aspectRatio =
static_cast<float>(renderTarget->width) /
static_cast<float>(renderTarget->height);
180 if (aspectRatio < 1) {
181 size.x *= aspectRatio;
183 size.y /= aspectRatio;
188 for (
size_t i = 0; i < renderTarget->textures.size(); i++) {
189 if (i != 0) ImGui::SameLine(100 + i*150.f);
190 ImGui::Text(
" Tex %zu", i);
192 for (
size_t i = 0; i < renderTarget->textures.size(); i++) {
193 if (i != 0) ImGui::SameLine(100 + i*150.f);
194 ImGui::Image(ImTextureID(renderTarget->textures[i]->textureHandle.handle), size);
197 if (renderTarget->depth) {
198 ImGui::Text(
" Depth");
199 ImGui::Image(ImTextureID(renderTarget->depth->textureHandle.
handle), size);
207 constexpr char const * fmtTitle[] = {
209 "%s [TaskResource@0x%p]",
210 "%s [RenderTarget@0x%p]",
211 "%s [RenderList@0x%p]",
212 "%s [RenderBuffer@0x%p]",
213 "%s [RenderTexture@0x%p]",
217 ImGui::PushID(resource);
218 if (ImGui::TreeNode(
"RenderResource", fmtTitle[
static_cast<int>(resource->type)], std::string(resource->resource->getName()).c_str(), resource->resource)) {
219 switch (resource->type)
221 case RenderResourceType::RenderTarget:
223 showRenderTarget(context, renderer, resource->renderTarget);
226 case RenderResourceType::RenderList:
228 auto renderList = resource->renderList;
229 showRenderList(context, renderer, renderList->batch,
"All items");
230 showRenderList(context, renderer, renderList->buckets[
size_t(BucketType::Backdrop)],
"Backdrop bucket");
231 showRenderList(context, renderer, renderList->buckets[
size_t(BucketType::SolidOrderedBack)],
"Solid ordered back bucket");
232 showRenderList(context, renderer, renderList->buckets[
size_t(BucketType::Solid)],
"Solid bucket");
233 showRenderList(context, renderer, renderList->buckets[
size_t(BucketType::SolidOrderedFront)],
"Solid ordered front bucket");
234 showRenderList(context, renderer, renderList->buckets[
size_t(BucketType::Transparent)],
"Transparent bucket");
235 showRenderList(context, renderer, renderList->buckets[
size_t(BucketType::Annotation)],
"Annotation bucket");
236 showRenderList(context, renderer, renderList->buckets[
size_t(BucketType::Overlay)],
"Overlay bucket");
237 showRenderList(context, renderer, renderList->buckets[
size_t(BucketType::Custom)],
"Custombucket");
240 case RenderResourceType::RenderTexture:
242 showRenderTexture(context, renderer, resource->renderTexure);
245 case RenderResourceType::RenderBuffer:
246 case RenderResourceType::TaskResource:
259 if (task ==
nullptr)
return;
261 ImGui::Text(
"list obj buffer %u of %u, size=%zukb",
262 task->listObjectBuffer.fill,
263 task->listObjectBuffer.cpuCapacity,
264 ((
size_t(task->listObjectBuffer.stride) * task->listObjectBuffer.gpuCapacity) + 1023) / 1024);
269 if (task ==
nullptr)
return;
275 if (task ==
nullptr)
return;
281 if (task ==
nullptr)
return;
283 ImGui::Text(
"BucketMask");
284 ImGui::SameLine(250.f);
285 ImGui::Text(
"%s%s%s%s%s%s%s%s",
286 hasBucket(task->bucketMask, BucketType::Backdrop) ?
"BucketBackdrop " :
"",
287 hasBucket(task->bucketMask, BucketType::SolidOrderedBack) ?
"SolidOrderedBack " :
"",
288 hasBucket(task->bucketMask, BucketType::Solid) ?
"Solid " :
"",
289 hasBucket(task->bucketMask, BucketType::SolidOrderedFront) ?
"SolidOrderedFront " :
"",
290 hasBucket(task->bucketMask, BucketType::Transparent) ?
"Transparent " :
"",
291 hasBucket(task->bucketMask, BucketType::Annotation) ?
"Annotation " :
"",
292 hasBucket(task->bucketMask, BucketType::Overlay) ?
"Overlay " :
"",
293 hasBucket(task->bucketMask, BucketType::Custom) ?
"Custom " :
"");
295 ImGui::Text(
"Wireframe");
296 ImGui::SameLine(250.f);
297 ImGui::Text(
"%s", task->wireframe ?
"yes" :
"no");
299 ImGui::Text(
"RenderMask");
300 ImGui::SameLine(250.f);
301 ImGui::Text(
"%s%s%s%s",
302 ((task->renderMask & RenderLayers::Default) != RenderLayers::None) ?
"Default " :
"",
303 ((task->renderMask & RenderLayers::Ocean) != RenderLayers::None) ?
"Ocean " :
"",
304 ((task->renderMask & RenderLayers::Annotations) != RenderLayers::None) ?
"Annotations " :
"",
305 ((task->renderMask & RenderLayers::Sky) != RenderLayers::None) ?
"Sky " :
"");
307 ImGui::Text(
"Permutation");
308 ImGui::SameLine(250.f);
315 if (task ==
nullptr)
return;
318 ImGui::TextUnformatted(
"Object buffer mode:");
320 switch (task->objectBufferMode) {
321 case RenderListTask::ObjectBufferMode::Single:
322 ImGui::TextUnformatted(
"Single");
324 case RenderListTask::ObjectBufferMode::Batched:
325 ImGui::TextUnformatted(
"Batched");
327 case RenderListTask::ObjectBufferMode::List:
328 ImGui::TextUnformatted(
"List");
333 ImGui::TextUnformatted(
"Permutation index:");
335 ImGui::Text(
"%s (%zu)", renderer->
getEnginePermutations().get(task->permutationIndex)->getName().c_str(), task->permutationIndex);
338 ImGui::TextUnformatted(
"Bucket mask:");
340 binaryNumber(uint32_t(task->bucketMask));
343 ImGui::TextUnformatted(
"State change mask:");
345 binaryNumber(uint32_t(task->stateChangeMask));
348 ImGui::TextUnformatted(
"Lighting layers:");
350 binaryNumber(uint32_t(task->lightingMask));
353 ImGui::TextUnformatted(
"Blend mode:");
355 ImGui::Text(
"%u", uint32_t(task->blendMode));
358 ImGui::TextUnformatted(
"Depth mode:");
360 ImGui::Text(
"%u", uint32_t(task->depthMode));
363 ImGui::TextUnformatted(
"Depth func:");
365 ImGui::Text(
"%u", uint32_t(task->depthFunc));
368 ImGui::TextUnformatted(
"Clear color:");
370 ImGui::TextUnformatted(task->colorClear ?
"yes" :
"no");
373 ImGui::TextUnformatted(
"Clear depth:");
375 ImGui::TextUnformatted(task->depthClear ?
"yes" :
"no");
378 ImGui::TextUnformatted(
"Depth write:");
380 ImGui::TextUnformatted(task->depthWrite ?
"yes" :
"no");
383 ImGui::TextUnformatted(
"Discard color:");
385 ImGui::TextUnformatted(task->discardColor ?
"yes" :
"no");
388 ImGui::TextUnformatted(
"Discard depth:");
390 ImGui::TextUnformatted(task->discardDepth ?
"yes" :
"no");
393 ImGui::TextUnformatted(
"Default viewport size:");
395 ImGui::Text(
"[%d x %d]", task->defaultViewportSize.x, task->defaultViewportSize.y);
398 ImGui::TextUnformatted(
"Viewport from target:");
400 ImGui::TextUnformatted(task->viewportFromTarget ?
"yes" :
"no");
403 ImGui::TextUnformatted(
"Temporal offsets:");
405 ImGui::TextUnformatted(task->temporalOffsets ?
"yes" :
"no");
412 std::string
id = std::to_string(
reinterpret_cast<size_t>(task));
413 std::string name = task->name.empty() ?
"<unnamed>" : task->name;
415 if (task->flags & RenderTaskFlags::Persistent) {
416 name +=
" [persistent]";
419 if (ImGui::TreeNode(
id.c_str(),
"%s", name.c_str())) {
421 if (!task->input.resources.empty()) {
422 if (ImGui::TreeNode(
"Inputs")) {
423 for (
const auto & resource : task->input.resources) {
424 showResource(context, renderer, &resource);
430 if (!task->output.resources.empty()) {
431 if (ImGui::TreeNode(
"Outputs")) {
432 for (
const auto & resource : task->output.resources) {
433 showResource(context, renderer, &resource);
439 if (!task->dependencies.empty()) {
440 if (ImGui::TreeNode(
"Dependencies")) {
441 for (
auto & dependency : task->dependencies) {
442 ImGui::Text(
"%s", dependency.c_str());
448 if (!task->options.empty()) {
449 if (ImGui::TreeNode(
"Options")) {
450 for (
auto & option : task->options) {
451 ImGui::Text(
"%s=%s", option.first.c_str(), option.second.c_str());
457 showTaskInner(context, renderer,
dynamic_cast<const GenerateListTask*
>(task));
458 showTaskInner(context, renderer,
dynamic_cast<const ProcessTask*
>(task));
459 showTaskInner(context, renderer,
dynamic_cast<const PostProcessTask*
>(task));
460 showTaskInner(context, renderer,
dynamic_cast<const FilterListTask*
>(task));
461 showTaskInner(context, renderer,
dynamic_cast<const RenderListTask*
>(task));
469 std::vector<const PipelineInstance *> instances;
470 instances.reserve(renderer->getPipelineManager()->getPipelineInstances().size());
471 for (
auto & it : renderer->getPipelineManager()->getPipelineInstances()) {
472 instances.push_back(it.second.get());
477 if (ImGui::TreeNode(
"Global resources")) {
479 r.type = RenderResourceType::RenderList;
481 r.renderList =
const_cast<RenderList*
>(renderer->getPipelineManager()->getMainRenderList());
482 showResource(context, renderer, &r);
486 if (ImGui::TreeNode(
"Global tasks")) {
487 showTask(context, renderer, renderer->getPipelineManager()->getGenerateListTask());
491 if (ImGui::TreeNode(
"Pipeline instance sequence")) {
493 for (
const auto instance : instances) {
494 std::string name =
"Unknown";
495 if (!instance->name.empty()) {
496 name = instance->name;
500 if (instance->definitionKey != 0) {
501 def = &renderer->getPipelineManager()->definitionByKey(context, instance->definitionKey);
502 name +=
", def=" + def->name;
505 ImGui::PushID(instance);
506 if (ImGui::TreeNode(
"Instance",
"%d: %s",
id++, name.c_str())) {
508 if (!instance->pipeline.updateResources.resources.empty()) {
509 if (ImGui::TreeNode(
"Update resources")) {
510 for (
const auto & resource : instance->pipeline.updateResources.resources) {
511 showResource(context, renderer, &resource);
516 if (!instance->pipeline.resources.resources.empty()) {
517 if (ImGui::TreeNode(
"Resources")) {
518 for (
const auto & resource : instance->pipeline.resources.resources) {
519 showResource(context, renderer, &resource);
524 if (!instance->pipeline.tasks.empty()) {
525 if (ImGui::TreeNode(
"Tasks")) {
526 for (
const auto * task : instance->pipeline.tasks) {
527 showTask(context, renderer, task);
542void Cogs::Core::pipelineInspector(
class Context * context,
bool * show)
546 ImGui::SetNextWindowSize(ImVec2(600, 300), ImGuiCond_FirstUseEver);
547 ImGui::Begin(
"Pipeline", show, 0);
549 const char* tabs[2] = {
"Pipeline Structure",
"Settings" };
552 ImGuiStyle & style = ImGui::GetStyle();
553 ImVec2 itemSpacing = style.ItemSpacing;
554 ImVec4 color = style.Colors[ImGuiCol_Button];
555 ImVec4 colorActive = style.Colors[ImGuiCol_ButtonActive];
556 ImVec4 colorHover = style.Colors[ImGuiCol_ButtonHovered];
558 style.ItemSpacing.x = 1;
559 style.ItemSpacing.y = 0;
561 for (
int i = 0; i < static_cast<int>(
sizeof(tabs) /
sizeof(
const char*)); i++) {
562 if (i != 0) ImGui::SameLine();
565 style.Colors[ImGuiCol_Button] = colorActive;
566 style.Colors[ImGuiCol_ButtonActive] = colorActive;
567 style.Colors[ImGuiCol_ButtonHovered] = colorActive;
569 if (ImGui::Button(tabs[i])) tab = i;
571 style.Colors[ImGuiCol_Button] = color;
572 style.Colors[ImGuiCol_ButtonActive] = colorActive;
573 style.Colors[ImGuiCol_ButtonHovered] = colorHover;
577 style.ItemSpacing = itemSpacing;
585 showTasks(context, renderer);
596void Cogs::Core::permutationInspector(
class Context * context,
bool * show)
600 ImGui::Begin(
"Permutations", show);
605 ImGui::PushID(permutation);
606 if (ImGui::TreeNode(permutation->getName().c_str())) {
607 auto & properties = permutation->constantBuffers.
variables;
608 if (!properties.empty()) {
609 if (ImGui::TreeNode(
"Properties")) {
610 for (
auto & prop : properties) {
611 if (prop.type == MaterialDataType::Float) {
613 if (ImGui::SliderFloat(prop.name.c_str(), &value, 0.0f, 2.0f)) {
614 permutation->constantBuffers.
buffers[prop.buffer].setValue(prop.descriptor.offset, value);
616 }
else if (prop.type == MaterialDataType::Float4) {
618 if (ImGui::DragFloat4(prop.name.c_str(), glm::value_ptr(value), 0.01f, 0.0f, 2.0f)) {
619 permutation->constantBuffers.
buffers[prop.buffer].setValue(prop.descriptor.offset, value);
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class IRenderer * renderer
Renderer.
virtual EnginePermutations & getEnginePermutations()=0
Get the reference to the EnginePermutations structure.
EnginePermutations & getEnginePermutations() override
Get the reference to the EnginePermutations structure.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
Contains reflection support.
std::vector< MaterialPropertyBuffer > buffers
Constant buffer instances.
std::vector< MaterialProperty > variables
Individual variables from all buffer instances.
Material * material
Material resource this MaterialInstance is created from.
StateChangeFlags stateChanges
Encodes what state changed from previous item, updated by FilterListTask.
handle_type handle
Internal resource handle.