diff --git a/core/image.cpp b/core/image.cpp index 4c0a23492be..06b7a78488e 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -34,6 +34,33 @@ #include "print_string.h" #include + +const char* Image::format_names[Image::FORMAT_MAX]={ + "Grayscale", + "Intensity", + "GrayscaleAlpha", + "RGB", + "RGBA", + "Indexed", + "IndexedAlpha", + "YUV422", + "YUV444", + "BC1", + "BC2", + "BC3", + "BC4", + "BC5", + "PVRTC2", + "PVRTC2Alpha", + "PVRTC4", + "PVRTC4Alpha", + "ETC", + "ATC", + "ATCAlphaExp", + "ATCAlphaInterp", + +}; + SavePNGFunc Image::save_png_func = NULL; void Image::_put_pixel(int p_x,int p_y, const BColor& p_color, unsigned char *p_data) { @@ -2355,6 +2382,12 @@ void Image::fix_alpha_edges() { } +String Image::get_format_name(Format p_format) { + + ERR_FAIL_INDEX_V(p_format,FORMAT_MAX,String()); + return format_names[p_format]; +} + Image::Image(const uint8_t* p_png,int p_len) { width=0; diff --git a/core/image.h b/core/image.h index 4461e97144b..a155823af79 100644 --- a/core/image.h +++ b/core/image.h @@ -87,6 +87,7 @@ public: FORMAT_MAX }; + static const char* format_names[FORMAT_MAX]; enum Interpolation { INTERPOLATE_NEAREST, @@ -352,6 +353,8 @@ public: Image get_rect(const Rect2& p_area) const; static void set_compress_bc_func(void (*p_compress_func)(Image *)); + static String get_format_name(Format p_format); + Image(const uint8_t* p_mem_png, int p_len=-1); Image(const char **p_xpm); ~Image(); diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index 9019b4e3c0d..66ae014dbc8 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -2056,8 +2056,8 @@ Error ResourceFormatLoaderXML::rename_dependencies(const String &p_path,const Ma void ResourceFormatSaverXMLInstance::escape(String& p_str) { p_str=p_str.replace("&","&"); - p_str=p_str.replace("<",">"); - p_str=p_str.replace(">","<"); + p_str=p_str.replace("<","<"); + p_str=p_str.replace(">",">"); p_str=p_str.replace("'","'"); p_str=p_str.replace("\"","""); for (char i=1;i<32;i++) { diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index d42f8794410..d72c9f75329 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -31,6 +31,28 @@ #include "io/ip.h" #include "globals.h" +void ScriptDebuggerRemote::_send_video_memory() { + + List usage; + if (resource_usage_func) + resource_usage_func(&usage); + + usage.sort(); + + packet_peer_stream->put_var("message:video_mem"); + packet_peer_stream->put_var(usage.size()*4); + + + for(List::Element *E=usage.front();E;E=E->next()) { + + packet_peer_stream->put_var(E->get().path); + packet_peer_stream->put_var(E->get().type); + packet_peer_stream->put_var(E->get().format); + packet_peer_stream->put_var(E->get().vram); + } + +} + Error ScriptDebuggerRemote::connect_to_host(const String& p_host,uint16_t p_port) { @@ -248,6 +270,9 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) { if (request_scene_tree) request_scene_tree(request_scene_tree_ud); + } else if (command=="request_video_mem") { + + _send_video_memory(); } else if (command=="breakpoint") { bool set = cmd[3]; @@ -531,6 +556,9 @@ void ScriptDebuggerRemote::_poll_events() { if (request_scene_tree) request_scene_tree(request_scene_tree_ud); + } else if (command=="request_video_mem") { + + _send_video_memory(); } else if (command=="breakpoint") { bool set = cmd[3]; @@ -652,6 +680,8 @@ void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) { live_edit_funcs=p_funcs; } +ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func=NULL; + ScriptDebuggerRemote::ScriptDebuggerRemote() { tcp_client = StreamPeerTCP::create_ref(); diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h index c2642782a9c..973fa232122 100644 --- a/core/script_debugger_remote.h +++ b/core/script_debugger_remote.h @@ -34,6 +34,7 @@ #include "io/stream_peer_tcp.h" #include "io/packet_peer.h" #include "list.h" + class ScriptDebuggerRemote : public ScriptDebugger { struct Message { @@ -42,6 +43,8 @@ class ScriptDebuggerRemote : public ScriptDebugger { Array data; }; + + Ref tcp_client; Ref packet_peer_stream; @@ -90,6 +93,7 @@ class ScriptDebuggerRemote : public ScriptDebugger { RequestSceneTreeMessageFunc request_scene_tree; void *request_scene_tree_ud; + void _send_video_memory(); LiveEditFuncs *live_edit_funcs; ErrorHandlerList eh; @@ -98,6 +102,20 @@ class ScriptDebuggerRemote : public ScriptDebugger { public: + struct ResourceUsage { + + String path; + String format; + String type; + RID id; + int vram; + bool operator<(const ResourceUsage& p_img) const { return vram==p_img.vram ? id p_img.vram; } + }; + + typedef void (*ResourceUsageFunc)(List*); + + static ResourceUsageFunc resource_usage_func; + Error connect_to_host(const String& p_host,uint16_t p_port); virtual void debug(ScriptLanguage *p_script,bool p_can_continue=true); virtual void idle_poll(); diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index c36f99d78dd..d84ee5a7589 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -1408,6 +1408,40 @@ GLuint RasterizerGLES2::_texture_get_name(RID p_tex) { return texture->tex_id; }; +void RasterizerGLES2::texture_set_path(RID p_texture,const String& p_path) { + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND(!texture); + + texture->path=p_path; + +} + +String RasterizerGLES2::texture_get_path(RID p_texture) const{ + + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND_V(!texture,String()); + return texture->path; +} +void RasterizerGLES2::texture_debug_usage(List *r_info){ + + List textures; + texture_owner.get_owned_list(&textures); + + for (List::Element *E=textures.front();E;E=E->next()) { + + Texture *t = texture_owner.get(E->get()); + if (!t) + continue; + VS::TextureInfo tinfo; + tinfo.path=t->path; + tinfo.format=t->format; + tinfo.size.x=t->alloc_width; + tinfo.size.y=t->alloc_height; + tinfo.bytes=t->total_data_size; + r_info->push_back(tinfo); + } + +} /* SHADER API */ diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index f759e84b534..507e46ae750 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -115,6 +115,7 @@ class RasterizerGLES2 : public Rasterizer { struct Texture { + String path; uint32_t flags; int width,height; int alloc_width, alloc_height; @@ -1325,6 +1326,10 @@ public: virtual void texture_set_size_override(RID p_texture,int p_width, int p_height); virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const; + virtual void texture_set_path(RID p_texture,const String& p_path); + virtual String texture_get_path(RID p_texture) const; + virtual void texture_debug_usage(List *r_info); + GLuint _texture_get_name(RID p_tex); /* SHADER API */ diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 7b261f7791b..994473f11e9 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -366,6 +366,16 @@ void ImageTexture::set_size_override(const Size2& p_size) { VisualServer::get_singleton()->texture_set_size_override(texture,w,h); } +void ImageTexture::set_path(const String& p_path,bool p_take_over) { + + if (texture.is_valid()) { + VisualServer::get_singleton()->texture_set_path(texture,p_path); + } + + Resource::set_path(p_path,p_take_over); +} + + void ImageTexture::set_storage(Storage p_storage) { storage=p_storage; @@ -944,6 +954,16 @@ float CubeMap::get_lossy_storage_quality() const { return lossy_storage_quality; } +void CubeMap::set_path(const String& p_path,bool p_take_over) { + + if (cubemap.is_valid()) { + VisualServer::get_singleton()->texture_set_path(cubemap,p_path); + } + + Resource::set_path(p_path,p_take_over); +} + + bool CubeMap::_set(const StringName& p_name, const Variant& p_value) { if (p_name=="side/left") { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index ad0e21093d7..1a4f211af10 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -152,7 +152,8 @@ public: void set_size_override(const Size2& p_size); - + virtual void set_path(const String& p_path,bool p_take_over=false); + ImageTexture(); ~ImageTexture(); @@ -320,6 +321,8 @@ public: void set_lossy_storage_quality(float p_lossy_storage_quality); float get_lossy_storage_quality() const; + virtual void set_path(const String& p_path,bool p_take_over=false); + CubeMap(); ~CubeMap(); diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 3634a03dbc6..2af2a79d076 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -35,6 +35,25 @@ #include "physics_2d_server.h" #include "spatial_sound_server.h" #include "spatial_sound_2d_server.h" +#include "script_debugger_remote.h" + +static void _debugger_get_resource_usage(List* r_usage) { + + List tinfo; + VS::get_singleton()->texture_debug_usage(&tinfo); + + for (List::Element *E=tinfo.front();E;E=E->next()) { + + ScriptDebuggerRemote::ResourceUsage usage; + usage.path=E->get().path; + usage.vram=E->get().bytes; + usage.id=E->get().texture; + usage.type="Texture"; + usage.format=itos(E->get().size.width)+"x"+itos(E->get().size.height)+" "+Image::get_format_name(E->get().format); + r_usage->push_back(usage); + } + +} void register_server_types() { @@ -63,6 +82,7 @@ void register_server_types() { ObjectTypeDB::register_virtual_type(); ObjectTypeDB::register_virtual_type(); + ScriptDebuggerRemote::resource_usage_func=_debugger_get_resource_usage; } void unregister_server_types(){ diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 15c757665bd..e22b3c3a6c3 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -190,9 +190,12 @@ public: virtual bool texture_has_alpha(RID p_texture) const=0; virtual void texture_set_size_override(RID p_texture,int p_width, int p_height)=0; - virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const=0; + virtual void texture_set_path(RID p_texture,const String& p_path)=0; + virtual String texture_get_path(RID p_texture) const=0; + virtual void texture_debug_usage(List *r_info)=0; + /* SHADER API */ virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_MATERIAL)=0; diff --git a/servers/visual/rasterizer_dummy.h b/servers/visual/rasterizer_dummy.h index 9249ad62564..f582fbd8ee8 100644 --- a/servers/visual/rasterizer_dummy.h +++ b/servers/visual/rasterizer_dummy.h @@ -415,6 +415,10 @@ public: virtual void texture_set_size_override(RID p_texture,int p_width, int p_height); virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const; + virtual void texture_set_path(RID p_texture,const String& p_path) {} + virtual String texture_get_path(RID p_texture) const { return String(); } + virtual void texture_debug_usage(List *r_info) {} + /* SHADER API */ virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_MATERIAL); diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 01af2d86ad6..a94d4f64c7a 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -112,6 +112,21 @@ void VisualServerRaster::texture_set_reload_hook(RID p_texture,ObjectID p_owner, rasterizer->texture_set_reload_hook(p_texture,p_owner,p_function); } +void VisualServerRaster::texture_set_path(RID p_texture,const String& p_path) { + + rasterizer->texture_set_path(p_texture,p_path); +} + +String VisualServerRaster::texture_get_path(RID p_texture) const{ + + return rasterizer->texture_get_path(p_texture); +} + +void VisualServerRaster::texture_debug_usage(List *r_info){ + + rasterizer->texture_debug_usage(r_info); +} + /* SHADER API */ RID VisualServerRaster::shader_create(ShaderMode p_mode) { diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 3d8331984a8..b6a5ca63084 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -668,6 +668,11 @@ public: virtual bool texture_can_stream(RID p_texture) const; virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const; + virtual void texture_set_path(RID p_texture,const String& p_path); + virtual String texture_get_path(RID p_texture) const; + + virtual void texture_debug_usage(List *r_info); + /* SHADER API */ diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index af88c9bdc93..57d691ae685 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -98,6 +98,15 @@ public: FUNC1RC(bool,texture_can_stream,RID); FUNC3C(texture_set_reload_hook,RID,ObjectID,const StringName&); + FUNC2(texture_set_path,RID,const String&); + FUNC1RC(String,texture_get_path,RID); + + virtual void texture_debug_usage(List *r_info) { + //pass directly, should lock the server anyway + visual_server->texture_debug_usage(r_info); + } + + /* SHADER API */ FUNC1R(RID,shader_create,ShaderMode); diff --git a/servers/visual_server.h b/servers/visual_server.h index ece61ec701c..96c3e15cde5 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -135,6 +135,18 @@ public: virtual bool texture_can_stream(RID p_texture) const=0; virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const=0; + virtual void texture_set_path(RID p_texture,const String& p_path)=0; + virtual String texture_get_path(RID p_texture) const=0; + + struct TextureInfo { + RID texture; + Size2 size; + Image::Format format; + int bytes; + String path; + }; + + virtual void texture_debug_usage(List *r_info)=0; /* SHADER API */ diff --git a/tools/editor/script_editor_debugger.cpp b/tools/editor/script_editor_debugger.cpp index 084e7a6a1f2..8e0e7ddb49c 100644 --- a/tools/editor/script_editor_debugger.cpp +++ b/tools/editor/script_editor_debugger.cpp @@ -169,6 +169,17 @@ void ScriptEditorDebugger::_scene_tree_request() { } +void ScriptEditorDebugger::_video_mem_request() { + + ERR_FAIL_COND(connection.is_null()); + ERR_FAIL_COND(!connection->is_connected()); + + Array msg; + msg.push_back("request_video_mem"); + ppeer->put_var(msg); + +} + Size2 ScriptEditorDebugger::get_minimum_size() const { Size2 ms = Control::get_minimum_size(); @@ -244,6 +255,31 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat le_clear->set_disabled(false); le_set->set_disabled(false); + } else if (p_msg=="message:video_mem") { + + vmem_tree->clear(); + TreeItem* root=vmem_tree->create_item(); + + int total=0; + + for(int i=0;icreate_item(root); + String type=p_data[i+1]; + int bytes=p_data[i+3].operator int(); + it->set_text(0,p_data[i+0]); //path + it->set_text(1,type); //type + it->set_text(2,p_data[i+2]); //type + it->set_text(3,String::humanize_size(bytes)); //type + total+=bytes; + + if (has_icon(type,"EditorIcons")) + it->set_icon(0,get_icon(type,"EditorIcons")); + } + + vmem_total->set_tooltip("Bytes: "+itos(total)); + vmem_total->set_text(String::humanize_size(total)); + } else if (p_msg=="stack_dump") { stack_dump->clear(); @@ -506,6 +542,7 @@ void ScriptEditorDebugger::_notification(int p_what) { le_clear->connect("pressed",this,"_live_edit_clear"); error_list->connect("item_selected",this,"_error_selected"); error_stack->connect("item_selected",this,"_error_stack_selected"); + vmem_refresh->set_icon( get_icon("Reload","EditorIcons")); } break; case NOTIFICATION_PROCESS: { @@ -1136,6 +1173,7 @@ void ScriptEditorDebugger::_bind_methods() { ObjectTypeDB::bind_method(_MD("_performance_draw"),&ScriptEditorDebugger::_performance_draw); ObjectTypeDB::bind_method(_MD("_performance_select"),&ScriptEditorDebugger::_performance_select); ObjectTypeDB::bind_method(_MD("_scene_tree_request"),&ScriptEditorDebugger::_scene_tree_request); + ObjectTypeDB::bind_method(_MD("_video_mem_request"),&ScriptEditorDebugger::_video_mem_request); ObjectTypeDB::bind_method(_MD("_live_edit_set"),&ScriptEditorDebugger::_live_edit_set); ObjectTypeDB::bind_method(_MD("_live_edit_clear"),&ScriptEditorDebugger::_live_edit_clear); @@ -1327,9 +1365,15 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){ Label *vmlb = memnew(Label("List of Video Memory Usage by Resource: ") ); vmlb->set_h_size_flags(SIZE_EXPAND_FILL); vmem_hb->add_child( vmlb ); + vmem_hb->add_child( memnew(Label("Total: ")) ); + vmem_total = memnew( LineEdit ); + vmem_total->set_editable(false); + vmem_total->set_custom_minimum_size(Size2(100,1)); + vmem_hb->add_child(vmem_total); vmem_refresh = memnew( Button ); vmem_hb->add_child(vmem_refresh); vmem_vb->add_child(vmem_hb); + vmem_refresh->connect("pressed",this,"_video_mem_request"); MarginContainer *vmmc = memnew( MarginContainer ); vmmc = memnew( MarginContainer ); @@ -1341,16 +1385,20 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){ vmem_vb->add_child(vmmc); vmem_vb->set_name("Video Mem"); - vmem_tree->set_columns(3); + vmem_tree->set_columns(4); vmem_tree->set_column_titles_visible(true); vmem_tree->set_column_title(0,"Resource Path"); vmem_tree->set_column_expand(0,true); vmem_tree->set_column_expand(1,false); vmem_tree->set_column_title(1,"Type"); - vmem_tree->set_column_min_width(1,150); + vmem_tree->set_column_min_width(1,100); vmem_tree->set_column_expand(2,false); - vmem_tree->set_column_title(2,"Usage"); + vmem_tree->set_column_title(2,"Format"); vmem_tree->set_column_min_width(2,150); + vmem_tree->set_column_expand(3,false); + vmem_tree->set_column_title(3,"Usage"); + vmem_tree->set_column_min_width(3,80); + vmem_tree->set_hide_root(true); tabs->add_child(vmem_vb); diff --git a/tools/editor/script_editor_debugger.h b/tools/editor/script_editor_debugger.h index 04459e39f80..6b66a62dd5a 100644 --- a/tools/editor/script_editor_debugger.h +++ b/tools/editor/script_editor_debugger.h @@ -98,6 +98,7 @@ class ScriptEditorDebugger : public Control { Tree *vmem_tree; Button *vmem_refresh; + LineEdit *vmem_total; Tree *stack_dump; PropertyEditor *inspector; @@ -130,6 +131,7 @@ class ScriptEditorDebugger : public Control { void _scene_tree_request(); void _parse_message(const String& p_msg,const Array& p_data); + void _video_mem_request(); int _get_node_path_cache(const NodePath& p_path);