Skip to content

Commit 33065d8

Browse files
committed
Merge pull request godotengine#103238 from Ryan-000/mesh_support_vram_profiler
Add Meshes to the Video RAM Profiler
2 parents e2766d4 + 4497e2a commit 33065d8

File tree

13 files changed

+176
-8
lines changed

13 files changed

+176
-8
lines changed

drivers/gles3/storage/mesh_storage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ class MeshStorage : public RendererMeshStorage {
319319

320320
virtual void mesh_clear(RID p_mesh) override;
321321
virtual void mesh_surface_remove(RID p_mesh, int p_surface) override;
322+
virtual void mesh_debug_usage(List<RS::MeshInfo> *r_info) override {}
322323

323324
_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
324325
Mesh *mesh = mesh_owner.get_or_null(p_mesh);

drivers/gles3/storage/texture_storage.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,7 @@ void TextureStorage::texture_debug_usage(List<RS::TextureInfo> *r_info) {
14811481
tinfo.width = t->alloc_width;
14821482
tinfo.height = t->alloc_height;
14831483
tinfo.bytes = t->total_data_size;
1484+
tinfo.type = static_cast<RenderingServer::TextureType>(t->type);
14841485

14851486
switch (t->type) {
14861487
case Texture::TYPE_3D:

editor/debugger/script_editor_debugger.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -451,9 +451,19 @@ void ScriptEditorDebugger::_msg_servers_memory_usage(uint64_t p_thread_id, const
451451
it->set_text(3, String::humanize_size(bytes));
452452
total += bytes;
453453

454-
if (has_theme_icon(type, EditorStringName(EditorIcons))) {
455-
it->set_icon(0, get_editor_theme_icon(type));
454+
// If it does not have a theme icon, just go up the inheritance tree until we find one.
455+
if (!has_theme_icon(type, EditorStringName(EditorIcons))) {
456+
StringName base_type = type;
457+
while (base_type != "Resource" || base_type != "") {
458+
base_type = ClassDB::get_parent_class(base_type);
459+
if (has_theme_icon(base_type, EditorStringName(EditorIcons))) {
460+
type = base_type;
461+
break;
462+
}
463+
}
456464
}
465+
466+
it->set_icon(0, get_editor_theme_icon(type));
457467
}
458468

459469
vmem_total->set_tooltip_text(TTR("Bytes:") + " " + itos(total));
@@ -1004,6 +1014,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
10041014
next->set_button_icon(get_editor_theme_icon(SNAME("DebugNext")));
10051015
dobreak->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
10061016
docontinue->set_button_icon(get_editor_theme_icon(SNAME("DebugContinue")));
1017+
vmem_notice_icon->set_texture(get_editor_theme_icon(SNAME("NodeInfo")));
10071018
vmem_refresh->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
10081019
vmem_export->set_button_icon(get_editor_theme_icon(SNAME("Save")));
10091020
search->set_right_icon(get_editor_theme_icon(SNAME("Search")));
@@ -2185,11 +2196,32 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
21852196
{ //vmem inspect
21862197
VBoxContainer *vmem_vb = memnew(VBoxContainer);
21872198
HBoxContainer *vmem_hb = memnew(HBoxContainer);
2188-
Label *vmlb = memnew(Label(TTR("List of Video Memory Usage by Resource:") + " "));
2189-
vmlb->set_theme_type_variation("HeaderSmall");
21902199

2191-
vmlb->set_h_size_flags(SIZE_EXPAND_FILL);
2200+
Label *vmlb = memnew(Label(TTRC("List of Video Memory Usage by Resource:")));
2201+
vmlb->set_theme_type_variation("HeaderSmall");
21922202
vmem_hb->add_child(vmlb);
2203+
2204+
{ // Add notice icon.
2205+
vmem_notice_icon = memnew(TextureRect);
2206+
vmem_notice_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
2207+
vmem_notice_icon->set_h_size_flags(SIZE_SHRINK_CENTER);
2208+
vmem_notice_icon->set_visible(true);
2209+
vmem_notice_icon->set_tooltip_text(TTR(R"(Notice:
2210+
This tool only reports memory allocations tracked by the engine.
2211+
Therefore, total VRAM usage is inaccurate compared to what the Monitors tab or external tools can report.
2212+
Instead, use the monitors tab to obtain more precise VRAM usage.
2213+
2214+
- Buffer Memory (e.g. GPUParticles) is not tracked.
2215+
- Meshes are not tracked in the Compatibility renderer.)"));
2216+
vmem_hb->add_child(vmem_notice_icon);
2217+
}
2218+
2219+
{ // Add some space to move the rest of the controls to the right.
2220+
Control *space = memnew(Control);
2221+
space->set_h_size_flags(SIZE_EXPAND_FILL);
2222+
vmem_hb->add_child(space);
2223+
}
2224+
21932225
vmem_hb->add_child(memnew(Label(TTR("Total:") + " ")));
21942226
vmem_total = memnew(LineEdit);
21952227
vmem_total->set_editable(false);

editor/debugger/script_editor_debugger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class ScriptEditorDebugger : public MarginContainer {
137137
Button *vmem_refresh = nullptr;
138138
Button *vmem_export = nullptr;
139139
LineEdit *vmem_total = nullptr;
140+
TextureRect *vmem_notice_icon = nullptr;
140141

141142
Tree *stack_dump = nullptr;
142143
LineEdit *search = nullptr;

servers/debugger/servers_debugger.cpp

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "core/config/project_settings.h"
3434
#include "core/debugger/engine_debugger.h"
3535
#include "core/debugger/engine_profiler.h"
36+
#include "core/io/resource_loader.h"
3637
#include "core/object/script_language.h"
3738
#include "servers/display_server.h"
3839

@@ -435,7 +436,24 @@ void ServersDebugger::_send_resource_usage() {
435436
info.path = E.path;
436437
info.vram = E.bytes;
437438
info.id = E.texture;
438-
info.type = "Texture";
439+
440+
switch (E.type) {
441+
case RS::TextureType::TEXTURE_TYPE_2D:
442+
info.type = "Texture2D";
443+
break;
444+
case RS::TextureType::TEXTURE_TYPE_3D:
445+
info.type = "Texture3D";
446+
break;
447+
case RS::TextureType::TEXTURE_TYPE_LAYERED:
448+
info.type = "TextureLayered";
449+
break;
450+
}
451+
452+
String possible_type = _get_resource_type_from_path(E.path);
453+
if (!possible_type.is_empty()) {
454+
info.type = possible_type;
455+
}
456+
439457
if (E.depth == 0) {
440458
info.format = itos(E.width) + "x" + itos(E.height) + " " + Image::get_format_name(E.format);
441459
} else {
@@ -444,9 +462,61 @@ void ServersDebugger::_send_resource_usage() {
444462
usage.infos.push_back(info);
445463
}
446464

465+
List<RS::MeshInfo> mesh_info;
466+
RS::get_singleton()->mesh_debug_usage(&mesh_info);
467+
468+
for (const RS::MeshInfo &E : mesh_info) {
469+
ServersDebugger::ResourceInfo info;
470+
info.path = E.path;
471+
// We use 64-bit integers to avoid overflow, if for whatever reason, the sum is bigger than 4GB.
472+
uint64_t vram = E.vertex_buffer_size + E.attribute_buffer_size + E.skin_buffer_size + E.index_buffer_size + E.blend_shape_buffer_size + E.lod_index_buffers_size;
473+
// But can info.vram even hold that, and why is it an int instead of an uint?
474+
info.vram = vram;
475+
476+
// Even though these empty meshes can be indicative of issues somewhere else
477+
// for UX reasons, we don't want to show them.
478+
if (vram == 0 && E.path.is_empty()) {
479+
continue;
480+
}
481+
482+
info.id = E.mesh;
483+
info.type = "Mesh";
484+
String possible_type = _get_resource_type_from_path(E.path);
485+
if (!possible_type.is_empty()) {
486+
info.type = possible_type;
487+
}
488+
489+
info.format = itos(E.vertex_count) + " Vertices";
490+
usage.infos.push_back(info);
491+
}
492+
447493
EngineDebugger::get_singleton()->send_message("servers:memory_usage", usage.serialize());
448494
}
449495

496+
// Done on a best-effort basis.
497+
String ServersDebugger::_get_resource_type_from_path(const String &p_path) {
498+
if (p_path.is_empty()) {
499+
return "";
500+
}
501+
502+
if (!ResourceLoader::exists(p_path)) {
503+
return "";
504+
}
505+
506+
if (ResourceCache::has(p_path)) {
507+
Ref<Resource> resource = ResourceCache::get_ref(p_path);
508+
return resource->get_class();
509+
} else {
510+
// This doesn't work all the time for embedded resources.
511+
String resource_type = ResourceLoader::get_resource_type(p_path);
512+
if (resource_type != "") {
513+
return resource_type;
514+
}
515+
}
516+
517+
return "";
518+
}
519+
450520
ServersDebugger::ServersDebugger() {
451521
singleton = this;
452522

servers/debugger/servers_debugger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class ServersDebugger {
117117
static Error _capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured);
118118

119119
void _send_resource_usage();
120+
String _get_resource_type_from_path(const String &p_path);
120121

121122
ServersDebugger();
122123

servers/rendering/dummy/storage/mesh_storage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class MeshStorage : public RendererMeshStorage {
132132

133133
virtual void mesh_surface_remove(RID p_mesh, int p_surface) override;
134134
virtual void mesh_clear(RID p_mesh) override;
135+
virtual void mesh_debug_usage(List<RS::MeshInfo> *r_info) override {}
135136

136137
/* MESH INSTANCE */
137138

servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
395395

396396
if (new_surface.attribute_data.size()) {
397397
s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.attribute_data.size(), new_surface.attribute_data);
398+
s->attribute_buffer_size = new_surface.attribute_data.size();
398399
}
399400
if (new_surface.skin_data.size()) {
400401
s->skin_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.skin_data.size(), new_surface.skin_data, as_storage_flag);
@@ -411,6 +412,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
411412
bool is_index_16 = new_surface.vertex_count <= 65536 && new_surface.vertex_count > 0;
412413

413414
s->index_buffer = RD::get_singleton()->index_buffer_create(new_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.index_data, false);
415+
s->index_buffer_size = new_surface.index_data.size();
414416
s->index_count = new_surface.index_count;
415417
s->index_array = RD::get_singleton()->index_array_create(s->index_buffer, 0, s->index_count);
416418
if (new_surface.lods.size()) {
@@ -420,6 +422,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
420422
for (int i = 0; i < new_surface.lods.size(); i++) {
421423
uint32_t indices = new_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
422424
s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.lods[i].index_data);
425+
s->lods[i].index_buffer_size = new_surface.lods[i].index_data.size();
423426
s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices);
424427
s->lods[i].edge_length = new_surface.lods[i].edge_length;
425428
s->lods[i].index_count = indices;
@@ -437,6 +440,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
437440

438441
if (mesh->blend_shape_count > 0) {
439442
s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(new_surface.blend_shape_data.size(), new_surface.blend_shape_data);
443+
s->blend_shape_buffer_size = new_surface.blend_shape_data.size();
440444
}
441445

442446
if (use_as_storage) {
@@ -917,6 +921,35 @@ void MeshStorage::mesh_surface_remove(RID p_mesh, int p_surface) {
917921
}
918922
}
919923

924+
void MeshStorage::mesh_debug_usage(List<RS::MeshInfo> *r_info) {
925+
for (const RID &mesh_rid : mesh_owner.get_owned_list()) {
926+
Mesh *mesh = mesh_owner.get_or_null(mesh_rid);
927+
if (!mesh) {
928+
continue;
929+
}
930+
RS::MeshInfo mesh_info;
931+
mesh_info.mesh = mesh_rid;
932+
mesh_info.path = mesh->path;
933+
934+
for (uint32_t surface_index = 0; surface_index < mesh->surface_count; surface_index++) {
935+
MeshStorage::Mesh::Surface *surface = mesh->surfaces[surface_index];
936+
937+
mesh_info.vertex_buffer_size += surface->vertex_buffer_size;
938+
mesh_info.attribute_buffer_size += surface->attribute_buffer_size;
939+
mesh_info.skin_buffer_size += surface->skin_buffer_size;
940+
mesh_info.index_buffer_size += surface->index_buffer_size;
941+
mesh_info.blend_shape_buffer_size += surface->blend_shape_buffer_size;
942+
mesh_info.vertex_count += surface->vertex_count;
943+
944+
for (uint32_t lod_index = 0; lod_index < surface->lod_count; lod_index++) {
945+
mesh_info.lod_index_buffers_size += surface->lods[lod_index].index_buffer_size;
946+
}
947+
}
948+
949+
r_info->push_back(mesh_info);
950+
}
951+
}
952+
920953
bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
921954
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
922955
ERR_FAIL_NULL_V(mesh, false);

servers/rendering/renderer_rd/storage_rd/mesh_storage.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,14 @@ class MeshStorage : public RendererMeshStorage {
7878
RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
7979
uint64_t format = 0;
8080

81+
uint32_t vertex_count = 0;
8182
RID vertex_buffer;
83+
uint32_t vertex_buffer_size = 0;
84+
8285
RID attribute_buffer;
86+
uint32_t attribute_buffer_size = 0;
87+
8388
RID skin_buffer;
84-
uint32_t vertex_count = 0;
85-
uint32_t vertex_buffer_size = 0;
8689
uint32_t skin_buffer_size = 0;
8790

8891
// A different pipeline needs to be allocated
@@ -106,13 +109,15 @@ class MeshStorage : public RendererMeshStorage {
106109
uint32_t version_count = 0;
107110

108111
RID index_buffer;
112+
uint32_t index_buffer_size = 0;
109113
RID index_array;
110114
uint32_t index_count = 0;
111115

112116
struct LOD {
113117
float edge_length = 0.0;
114118
uint32_t index_count = 0;
115119
RID index_buffer;
120+
uint32_t index_buffer_size = 0;
116121
RID index_array;
117122
};
118123

@@ -130,6 +135,7 @@ class MeshStorage : public RendererMeshStorage {
130135
Vector4 uv_scale;
131136

132137
RID blend_shape_buffer;
138+
uint32_t blend_shape_buffer_size = 0;
133139

134140
RID material;
135141

@@ -397,6 +403,8 @@ class MeshStorage : public RendererMeshStorage {
397403
virtual void mesh_clear(RID p_mesh) override;
398404
virtual void mesh_surface_remove(RID p_mesh, int p_surface) override;
399405

406+
virtual void mesh_debug_usage(List<RS::MeshInfo> *r_info) override;
407+
400408
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override;
401409

402410
_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {

servers/rendering/renderer_rd/storage_rd/texture_storage.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,7 @@ void TextureStorage::texture_debug_usage(List<RS::TextureInfo> *r_info) {
16511651
tinfo.width = t->width;
16521652
tinfo.height = t->height;
16531653
tinfo.bytes = Image::get_image_data_size(t->width, t->height, t->format, t->mipmaps > 1);
1654+
tinfo.type = static_cast<RenderingServer::TextureType>(t->type);
16541655

16551656
switch (t->type) {
16561657
case TextureType::TYPE_3D:

0 commit comments

Comments
 (0)