From ea4be9afa6207cf0c2f5b66dbba5b826ba5e8d5c Mon Sep 17 00:00:00 2001 From: clayjohn Date: Thu, 30 May 2024 12:30:53 -0700 Subject: [PATCH] Add more validation to UBO size and alignment in Compatibility renderer --- doc/classes/ProjectSettings.xml | 2 ++ drivers/gles3/rasterizer_canvas_gles3.h | 6 ++++++ drivers/gles3/rasterizer_scene_gles3.h | 2 ++ drivers/gles3/storage/material_storage.cpp | 9 +++++---- drivers/gles3/storage/particles_storage.h | 3 +++ servers/rendering_server.cpp | 2 +- 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index c8a11427b9a..84542b755c8 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2634,6 +2634,8 @@ [b]Note:[/b] This setting is only effective when using the Forward+ rendering method, not Mobile and Compatibility. + The maximum number of uniforms that can be used by the global shader uniform buffer. Each item takes up one slot. In other words, a single uniform float and a uniform vec4 will take the same amount of space in the buffer. + [b]Note:[/b] When using the Compatibility backend, most mobile devices (and all web exports) will be limited to a maximum size of 1024 due to hardware constraints. Max number of omnilights and spotlights renderable per object. At the default value of 8, this means that each surface can be affected by up to 8 omnilights and 8 spotlights. This is further limited by hardware support and [member rendering/limits/opengl/max_renderable_lights]. Setting this low will slightly reduce memory usage, may decrease shader compile times, and may result in faster rendering on low-end, mobile, or web devices. diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index a3762e828e3..7fc9992c3d9 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -157,6 +157,8 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender { float atlas_rect[4]; }; + static_assert(sizeof(LightUniform) % 16 == 0, "2D light UBO size must be a multiple of 16 bytes"); + public: enum { BASE_UNIFORM_LOCATION = 0, @@ -186,6 +188,8 @@ public: uint32_t pad2; }; + static_assert(sizeof(StateBuffer) % 16 == 0, "2D state UBO size must be a multiple of 16 bytes"); + struct PolygonBuffers { GLuint vertex_buffer = 0; GLuint vertex_array = 0; @@ -230,6 +234,8 @@ public: uint32_t lights[4]; }; + static_assert(sizeof(InstanceData) == 128, "2D instance data struct size must be 128 bytes"); + struct Data { GLuint canvas_quad_vertices; GLuint canvas_quad_array; diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index b6c7a0c5a58..4c70c43244f 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -428,6 +428,7 @@ private: bool pancake_shadows; }; static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes"); + static_assert(sizeof(UBO) < 16384, "Scene UBO size must be 16384 bytes or smaller"); struct MultiviewUBO { float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; @@ -435,6 +436,7 @@ private: float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4]; }; static_assert(sizeof(MultiviewUBO) % 16 == 0, "Multiview UBO size must be a multiple of 16 bytes"); + static_assert(sizeof(MultiviewUBO) < 16384, "MultiviewUBO size must be 16384 bytes or smaller"); struct TonemapUBO { float exposure = 1.0; diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 996c2050424..bacf607c668 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -1055,6 +1055,7 @@ void MaterialData::update_parameters_internal(const HashMap ubo_data.resize(p_ubo_size); if (ubo_data.size()) { + ERR_FAIL_COND(p_ubo_size > uint32_t(Config::get_singleton()->max_uniform_buffer_size)); memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear } } @@ -1108,10 +1109,10 @@ MaterialStorage::MaterialStorage() { static_assert(sizeof(GlobalShaderUniforms::Value) == 16); - global_shader_uniforms.buffer_size = MAX(4096, (int)GLOBAL_GET("rendering/limits/global_shader_variables/buffer_size")); - if (global_shader_uniforms.buffer_size > uint32_t(Config::get_singleton()->max_uniform_buffer_size)) { - global_shader_uniforms.buffer_size = uint32_t(Config::get_singleton()->max_uniform_buffer_size); - WARN_PRINT("Project setting \"rendering/limits/global_shader_variables/buffer_size\" exceeds maximum uniform buffer size of: " + itos(Config::get_singleton()->max_uniform_buffer_size)); + global_shader_uniforms.buffer_size = MAX(16, (int)GLOBAL_GET("rendering/limits/global_shader_variables/buffer_size")); + if (global_shader_uniforms.buffer_size * sizeof(GlobalShaderUniforms::Value) > uint32_t(Config::get_singleton()->max_uniform_buffer_size)) { + global_shader_uniforms.buffer_size = uint32_t(Config::get_singleton()->max_uniform_buffer_size) / sizeof(GlobalShaderUniforms::Value); + WARN_PRINT("Project setting \"rendering/limits/global_shader_variables/buffer_size\" exceeds maximum uniform buffer size of: " + itos(Config::get_singleton()->max_uniform_buffer_size / sizeof(GlobalShaderUniforms::Value)) + ". Falling back on maximum buffer size."); } global_shader_uniforms.buffer_values = memnew_arr(GlobalShaderUniforms::Value, global_shader_uniforms.buffer_size); diff --git a/drivers/gles3/storage/particles_storage.h b/drivers/gles3/storage/particles_storage.h index ca347ed070c..086f5f79361 100644 --- a/drivers/gles3/storage/particles_storage.h +++ b/drivers/gles3/storage/particles_storage.h @@ -145,6 +145,9 @@ private: Collider colliders[MAX_COLLIDERS]; }; + static_assert(sizeof(ParticlesFrameParams) % 16 == 0, "ParticlesFrameParams size must be a multiple of 16 bytes"); + static_assert(sizeof(ParticlesFrameParams) < 16384, "ParticlesFrameParams must be 16384 bytes or smaller"); + struct Particles { RS::ParticlesMode mode = RS::PARTICLES_MODE_3D; bool inactive = true; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 7637d4e7da2..dd3491f62ce 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3610,7 +3610,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"), 0.05); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"), 0.01); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/global_shader_variables/buffer_size", PROPERTY_HINT_RANGE, "1,1048576,1"), 65536); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/global_shader_variables/buffer_size", PROPERTY_HINT_RANGE, "16,1048576,1"), 65536); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/probe_capture/update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001"), 15); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/primitive_meshes/texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.2);