From 5efcd64b2320d76107587ba84191fa20c06594f0 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Fri, 7 Mar 2025 22:01:24 -0800 Subject: [PATCH] Reduce per-frame memory allocations from the heap in the Mobile renderer. --- .../forward_mobile/render_forward_mobile.cpp | 41 ++++++------------- .../forward_mobile/render_forward_mobile.h | 1 - .../renderer_rd/renderer_canvas_render_rd.cpp | 3 +- .../storage_rd/particles_storage.cpp | 6 ++- servers/rendering/rendering_device.cpp | 13 ++---- servers/rendering/rendering_device.h | 3 +- 6 files changed, 24 insertions(+), 43 deletions(-) diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index a4b241c26a..b1a48b2d73 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -35,6 +35,7 @@ #include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h" #include "servers/rendering/renderer_rd/storage_rd/particles_storage.h" #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" +#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h" #include "servers/rendering/rendering_device.h" #include "servers/rendering/rendering_server_default.h" @@ -404,7 +405,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ // default render buffer and scene state uniform set // loaded into set 1 - Vector uniforms; + thread_local LocalVector uniforms; + uniforms.clear(); { RD::Uniform u; @@ -481,9 +483,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ /* we have limited ability to keep textures like this so we're moving this to a set we change before drawing geometry and just pushing the needed texture in */ { - RD::Uniform u; - u.binding = 6; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + Vector textures; + textures.resize(scene_state.max_lightmaps * 2); RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); for (uint32_t i = 0; i < scene_state.max_lightmaps * 2; i++) { @@ -503,14 +504,14 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ if (texture.is_valid()) { RID rd_texture = texture_storage->texture_get_rd_texture(texture); - u.append_id(rd_texture); + textures.write[i] = rd_texture; continue; } } - u.append_id(default_tex); + textures.write[i] = default_tex; } - + RD::Uniform u(RD::UNIFORM_TYPE_TEXTURE, 6, textures); uniforms.push_back(u); } @@ -630,15 +631,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ p_samplers.append_uniforms(uniforms, 13); - if (p_index >= (int)render_pass_uniform_sets.size()) { - render_pass_uniform_sets.resize(p_index + 1); - } - - if (render_pass_uniform_sets[p_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[p_index])) { - RD::get_singleton()->free(render_pass_uniform_sets[p_index]); - } - render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET, true); - return render_pass_uniform_sets[p_index]; + return UniformSetCacheRD::get_singleton()->get_cache_vec(scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET, uniforms); } void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray &p_lightmaps, const Transform3D &p_cam_transform) { @@ -1703,16 +1696,15 @@ void RenderForwardMobile::base_uniforms_changed() { void RenderForwardMobile::_update_render_base_uniform_set() { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); - // We must always recreate the uniform set every frame if we're using linear pools (since we requested it on creation). - // This pays off as long as we often get inside the if() block (i.e. the settings end up changing often). - if (RD::get_singleton()->uniform_sets_have_linear_pools() || render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version())) { + if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version())) { if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); } lightmap_texture_array_version = light_storage->lightmap_array_get_version(); - Vector uniforms; + thread_local LocalVector uniforms; + uniforms.clear(); { RD::Uniform u; @@ -1806,7 +1798,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() { uniforms.push_back(u); } - render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET, true); + render_base_uniform_set = UniformSetCacheRD::get_singleton()->get_cache_vec(scene_shader.default_shader_rd, SCENE_UNIFORM_SET, uniforms); } } @@ -3271,13 +3263,6 @@ RenderForwardMobile::RenderForwardMobile() { RenderForwardMobile::~RenderForwardMobile() { RSG::light_storage->directional_shadow_atlas_set_size(0); - //clear base uniform set if still valid - for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) { - if (render_pass_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[i])) { - RD::get_singleton()->free(render_pass_uniform_sets[i]); - } - } - { for (const RID &rid : scene_state.uniform_buffers) { RD::get_singleton()->free(rid); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index b72f903ba6..b495c316ad 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -173,7 +173,6 @@ private: void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray &p_lightmaps, const Transform3D &p_cam_transform); RID render_base_uniform_set; - LocalVector render_pass_uniform_sets; /* Light map */ diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 13e20eb6c8..cc6a630dbf 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -379,7 +379,8 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); //re create canvas state - Vector uniforms; + thread_local LocalVector uniforms; + uniforms.clear(); { RD::Uniform u; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 6924f11e34..0c449f4ebd 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -765,7 +765,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta MaterialStorage *material_storage = MaterialStorage::get_singleton(); if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) { - Vector uniforms; + thread_local LocalVector uniforms; + uniforms.clear(); { RD::Uniform u; @@ -1071,7 +1072,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta RD::get_singleton()->free(p_particles->collision_textures_uniform_set); } - Vector uniforms; + thread_local LocalVector uniforms; + uniforms.clear(); { RD::Uniform u; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 65fd680c44..171d8526d0 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -3416,15 +3416,10 @@ void RenderingDevice::_uniform_set_update_shared(UniformSet *p_uniform_set) { } } -template RID RenderingDevice::uniform_set_create(const LocalVector &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool); - -template RID RenderingDevice::uniform_set_create(const Vector &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool); - -template -RID RenderingDevice::uniform_set_create(const Collection &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool) { +RID RenderingDevice::uniform_set_create(const VectorView &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(p_uniforms.is_empty(), RID()); + ERR_FAIL_COND_V(p_uniforms.size() == 0, RID()); Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_NULL_V(shader, RID()); @@ -8208,12 +8203,12 @@ RID RenderingDevice::_shader_create_from_spirv(const Ref &p_spirv } RID RenderingDevice::_uniform_set_create(const TypedArray &p_uniforms, RID p_shader, uint32_t p_shader_set) { - Vector uniforms; + LocalVector uniforms; uniforms.resize(p_uniforms.size()); for (int i = 0; i < p_uniforms.size(); i++) { Ref uniform = p_uniforms[i]; ERR_FAIL_COND_V(uniform.is_null(), RID()); - uniforms.write[i] = uniform->base; + uniforms[i] = uniform->base; } return uniform_set_create(uniforms, p_shader, p_shader_set); } diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 2fead08e18..47e8b2d94b 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1067,8 +1067,7 @@ public: * If you plan on keeping the return value around for more than one frame (e.g. Sets that are created once and reused forever) you MUST set it to false. * @return Baked descriptor set. */ - template - RID uniform_set_create(const Collection &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool = false); + RID uniform_set_create(const VectorView &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool = false); bool uniform_set_is_valid(RID p_uniform_set); void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata);