diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index c8a11427b9a6..84542b755c87 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 a3762e828e34..7fc9992c3d9b 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 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender { 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 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender { 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 b6c7a0c5a580..4c70c43244fa 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -428,6 +428,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender { 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 @@ class RasterizerSceneGLES3 : public RendererSceneRender { 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 996c2050424d..bacf607c6682 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 ca347ed070c0..086f5f79361f 100644 --- a/drivers/gles3/storage/particles_storage.h +++ b/drivers/gles3/storage/particles_storage.h @@ -145,6 +145,9 @@ class ParticlesStorage : public RendererParticlesStorage { 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 7637d4e7da26..dd3491f62ced 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);