Cogs.Core
MeshInspector.cpp
1#include "Inspectors.h"
2
3#include "InspectorGuiHelper.h"
4#include "Context.h"
5
6#include "Resources/MeshManager.h"
7#include "Resources/BufferManager.h"
8
9#include "MemoryContext.h"
10
11#include "imgui.h"
12
13namespace {
14 using namespace Cogs::Core;
15
16 // Helper item with mesh + calculated size used for sorting the view
17 struct MeshInspectorItem
18 {
19 Mesh* mesh;
20 size_t byteSize;
21 };
22
23}
24
25
26void Cogs::Core::meshInspector(Context * context, bool * show)
27{
28 if (*show) {
29 ImGui::SetNextWindowSize(ImVec2(600, 1000), ImGuiCond_Once);
30
31 // Get all mesh resources.
32 // Note that we get our own copy here, since new mesh resources can be created at any time.
33 const std::vector<ResourceBase*> meshResources = context->meshManager->getAllocatedResources();
34
35 // Calculate byte size of all meshes and populate a new array with this info.
36 size_t totalByteSize = 0;
37 size_t totalStreamCount = 0;
38 std::vector<MeshInspectorItem> meshes;
39 meshes.reserve(meshResources.size());
40 for (ResourceBase* resource : meshResources) {
41 if (resource->getSlot() == 0xFFFFFFFF) continue;
42 assert(resource->getType() == ResourceTypes::Mesh);
43 Mesh* mesh = reinterpret_cast<Mesh*>(resource);
44
45 size_t byteSizeMesh = 0;
46 for (const DataStream& stream : mesh->streams) {
47 byteSizeMesh += stream.size();
48 }
49 totalByteSize += byteSizeMesh;
50 totalStreamCount += mesh->streams.size();
51 meshes.push_back({ .mesh = mesh, .byteSize = byteSizeMesh });
52 }
53
54 // Sort meshes the way the user wants
55 const char* sortings[] = {
56 "Unsorted",
57 "Sort by size",
58 "Sort by usage and size"
59 };
60 static int sorting = 0;
61 switch (sorting) {
62 case 0:
63 break;
64
65 case 1:
66 std::sort(meshes.begin(), meshes.end(),
67 [](const MeshInspectorItem& a, const MeshInspectorItem& b)
68 {
69 return b.byteSize < a.byteSize;
70 });
71 break;
72
73 case 2:
74 std::sort(meshes.begin(), meshes.end(),
75 [](const MeshInspectorItem& a, const MeshInspectorItem& b)
76 {
77 if (a.mesh->referenceCount() == b.mesh->referenceCount()) return b.byteSize < a.byteSize;
78 return b.mesh->referenceCount() < a.mesh->referenceCount();
79 });
80 break;
81
82 default:
83 assert(false);
84 }
85
86 // Begin window header.
87 std::string windowHeader;
88 windowHeader.reserve(50);
89 windowHeader.append("Meshes [");
90 windowHeader.append(std::to_string(meshes.size()));
91 windowHeader.append(" meshes, ");
92 windowHeader.append(std::to_string(totalStreamCount));
93 windowHeader.append(" streams, ");
94 appendBytesize(windowHeader, totalByteSize);
95 windowHeader.append("]");
96
97 guiBegin(windowHeader, show);
98
99 // Combo box to specify sorting
100 ImGui::Combo("##sorting", &sorting, sortings, IM_ARRAYSIZE(sortings), 10);
101
102 // List of meshes
103 unsigned line = 0;
104 std::string header;
105 header.reserve(100);
106 for (const MeshInspectorItem& item : meshes) {
107 header.clear();
108 header.append(std::to_string(line++));
109 header.append(": ");
110 if (std::string_view name = item.mesh->getName(); !name.empty()) {
111 header.append(name);
112 }
113 else {
114 header.append("Mesh");
115 }
116
117 header.append(" [");
118 appendBytesize(header, item.byteSize);
119 header.append(", ");
120 header.append(std::to_string(item.mesh->referenceCount()));
121 header.append(" refs]");
122 showMesh(context, item.mesh, header);
123 }
124
125 guiEnd();
126 }
127}
128
129void Cogs::Core::bufferInspector(Context * context, bool * show)
130{
131 if (*show) {
132 ImGui::SetNextWindowSize(ImVec2(600, 1000), ImGuiCond_Once);
133
134 std::vector<ResourceBase*> buffers = context->bufferManager->getAllocatedResources();
135
136 guiBegin("Buffers", show);
137
138 size_t mem = 0;
139
140 for (ResourceBase* b : buffers) {
141 BufferResource* buffer = static_cast<BufferResource*>(b);
142 mem += buffer->size();
143 }
144
145 ImGui::Text("Count: %zu Mem: %zu bytes", buffers.size(), mem);
146
147 int id = 0;
148 for (ResourceBase* b : buffers) {
149 BufferResource* buffer = static_cast<BufferResource*>(b);
150 std::string header;
151
152 ++id;
153 std::string_view name = buffer->getName();
154
155 if (name.empty()) {
156 header = "Buffer " + std::to_string(id);
157 }
158 else {
159 header = std::string(name);
160 }
161 header += " (" + std::to_string(buffer->size()) + " bytes)";
162
163 ImGui::PushID(buffer);
164
165 if (ImGui::TreeNode(header.c_str())) {
166 bool isVB = buffer->isVertexBuffer();
167 bool isIB = buffer->isIndexBuffer();
168
169 bool isResident = buffer->isResident();
170 bool hasChanged = buffer->hasChanged();
171
172 ImGui::Checkbox("Vertex Buffer", &isVB);
173 ImGui::Checkbox("Index Buffer", &isIB);
174 ImGui::Checkbox("Resident", &isResident);
175 ImGui::Checkbox("Changed", &hasChanged);
176
177 ImGui::Text("Size: %zu", buffer->size());
178
179 ImGui::TreePop();
180 }
181
182 ImGui::PopID();
183 }
184
185 guiEnd();
186 }
187}
188
189void Cogs::Core::engineInspector(Context * context, bool * show)
190{
191 if (*show) {
192 ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Once);
193
194 std::string title = "Engine Statistics";
195 guiBegin(title, show);
196
197 auto & memory = *context->memory;
198
199 if (ImGui::CollapsingHeader("Memory Allocation")) {
200 ImGui::Columns(5, "Stats");
201
202 ImGui::Text("Type"); ImGui::NextColumn();
203 ImGui::Text("Count"); ImGui::NextColumn();
204 ImGui::Text("Bytes"); ImGui::NextColumn();
205 ImGui::Text("Peak Count"); ImGui::NextColumn();
206 ImGui::Text("Peak Bytes"); ImGui::Separator(); ImGui::NextColumn();
207
208 struct AllocatorStats
209 {
210 const char * name;
211 Memory::Allocator * allocator;
212 } allocators[] = {
213 { "Base", memory.baseAllocator },
214 { "Resources", memory.resourceAllocator },
215 { "Components", memory.componentAllocator },
216 { "Strings", memory.getStringsAllocator()},
217 };
218
219 for (auto & a : allocators) {
220 ImGui::Text("%s", a.name); ImGui::NextColumn();
221 ImGui::Text("%zu", getAllocationCount(a.allocator)); ImGui::NextColumn();
222 ImGui::Text("%zu", getAllocatedBytes(a.allocator)); ImGui::NextColumn();
223 ImGui::Text("%zu", getPeakCount(a.allocator)); ImGui::NextColumn();
224 ImGui::Text("%zu", getPeakBytes(a.allocator)); ImGui::NextColumn();
225 }
226 }
227
228 guiEnd();
229 }
230}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
std::unique_ptr< struct MemoryContext > memory
Memory and allocation info.
Definition: Context.h:171
Base allocator implementation.
Definition: Allocator.h:30
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
Buffer resource.
Definition: Buffer.h:50
bool isVertexBuffer() const
Gets if the buffer data is usable as a vertex data.
Definition: Buffer.h:98
size_t size() const
Size of the buffer in bytes.
Definition: Buffer.h:62
bool isIndexBuffer() const
Gets if the buffer data is usable as index buffer data.
Definition: Buffer.h:101
Contains a stream of data used by Mesh resources.
Definition: Mesh.h:80
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
Base class for engine resources.
Definition: ResourceBase.h:107
StringView getName() const
Get the name of the resource.
Definition: ResourceBase.h:307