Merge pull request #103794 from clayjohn/mobile-allocations

Significantly reduce per-frame memory allocations from the heap in the Mobile renderer
This commit is contained in:
Thaddeus Crews
2025-03-09 09:05:08 -05:00
6 changed files with 24 additions and 43 deletions

View File

@ -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<RD::Uniform> uniforms;
thread_local LocalVector<RD::Uniform> 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<RID> 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<RID> &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<RD::Uniform> uniforms;
thread_local LocalVector<RD::Uniform> 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);

View File

@ -173,7 +173,6 @@ private:
void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
RID render_base_uniform_set;
LocalVector<RID> render_pass_uniform_sets;
/* Light map */

View File

@ -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<RD::Uniform> uniforms;
thread_local LocalVector<RD::Uniform> uniforms;
uniforms.clear();
{
RD::Uniform u;

View File

@ -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<RD::Uniform> uniforms;
thread_local LocalVector<RD::Uniform> 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<RD::Uniform> uniforms;
thread_local LocalVector<RD::Uniform> uniforms;
uniforms.clear();
{
RD::Uniform u;

View File

@ -3416,15 +3416,10 @@ void RenderingDevice::_uniform_set_update_shared(UniformSet *p_uniform_set) {
}
}
template RID RenderingDevice::uniform_set_create(const LocalVector<RD::Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool);
template RID RenderingDevice::uniform_set_create(const Vector<RD::Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool);
template <typename Collection>
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<RD::Uniform> &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<RDShaderSPIRV> &p_spirv
}
RID RenderingDevice::_uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {
Vector<Uniform> uniforms;
LocalVector<Uniform> uniforms;
uniforms.resize(p_uniforms.size());
for (int i = 0; i < p_uniforms.size(); i++) {
Ref<RDUniform> 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);
}

View File

@ -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 <typename Collection>
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<Uniform> &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);