From 6c52ba9625edda92570c8c46b0e14d0a432aed03 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Fri, 19 Dec 2025 11:00:53 +1100 Subject: [PATCH] OpenGL: Split the ubos for motion vectors into separate uniforms --- drivers/gles3/rasterizer_scene_gles3.cpp | 70 +++++++++++++++--------- drivers/gles3/rasterizer_scene_gles3.h | 10 +++- drivers/gles3/shaders/scene.glsl | 32 ++++++----- 3 files changed, 72 insertions(+), 40 deletions(-) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index aa1b732b88f..5628ff54665 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1477,6 +1477,19 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const } } +void RasterizerSceneGLES3::_update_scene_ubo(GLuint &p_ubo_buffer, GLuint p_index, uint32_t p_size, const void *p_source_data, String p_name) { + if (p_ubo_buffer == 0) { + glGenBuffers(1, &p_ubo_buffer); + glBindBufferBase(GL_UNIFORM_BUFFER, p_index, p_ubo_buffer); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, p_ubo_buffer, p_size, p_source_data, GL_STREAM_DRAW, p_name); + } else { + glBindBufferBase(GL_UNIFORM_BUFFER, p_index, p_ubo_buffer); + glBufferData(GL_UNIFORM_BUFFER, p_size, p_source_data, GL_STREAM_DRAW); + } + + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + // Needs to be called after _setup_lights so that directional_light_count is accurate. void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows, float p_shadow_bias) { Projection correction; @@ -1619,29 +1632,19 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da scene_state.data.IBL_exposure_normalization = 1.0; } - if (scene_state.ubo_buffer == 0) { - glGenBuffers(1, &scene_state.ubo_buffer); - glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.ubo_buffer, sizeof(SceneState::UBO) * 2, &scene_state.data, GL_STREAM_DRAW, "Scene state UBO"); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - } else { - glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer); - glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO) * 2, &scene_state.data, GL_STREAM_DRAW); + _update_scene_ubo(scene_state.ubo_buffer, SCENE_DATA_UNIFORM_LOCATION, sizeof(SceneState::UBO), &scene_state.data, "Scene state UBO"); + if (p_render_data->view_count > 1) { + _update_scene_ubo(scene_state.multiview_buffer, SCENE_MULTIVIEW_UNIFORM_LOCATION, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_data, "Multiview UBO"); } - glBindBuffer(GL_UNIFORM_BUFFER, 0); + if (scene_state.prev_data_state != 0) { + void *source_data = scene_state.prev_data_state == 1 ? &scene_state.data : &scene_state.prev_data; + _update_scene_ubo(scene_state.prev_ubo_buffer, SCENE_PREV_DATA_UNIFORM_LOCATION, sizeof(SceneState::UBO), source_data, "Previous scene state UBO"); - if (p_render_data->view_count > 1) { - if (scene_state.multiview_buffer == 0) { - glGenBuffers(1, &scene_state.multiview_buffer); - glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.multiview_buffer, sizeof(SceneState::MultiviewUBO) * 2, &scene_state.multiview_data, GL_STREAM_DRAW, "Multiview UBO"); - } else { - glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer); - glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO) * 2, &scene_state.multiview_data, GL_STREAM_DRAW); + if (p_render_data->view_count > 1) { + source_data = scene_state.prev_data_state == 1 ? &scene_state.multiview_data : &scene_state.prev_multiview_data; + _update_scene_ubo(scene_state.prev_multiview_buffer, SCENE_PREV_MULTIVIEW_UNIFORM_LOCATION, sizeof(SceneState::MultiviewUBO), source_data, "Previous multiview UBO"); } - - glBindBuffer(GL_UNIFORM_BUFFER, 0); } } @@ -2408,6 +2411,17 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ scene_state.data.emissive_exposure_normalization = -1.0; // Use default exposure normalization. + bool enough_vertex_attribs_for_motion_blue = GLES3::Config::get_singleton()->max_vertex_attribs >= 22; + if (rt && rt->overridden.velocity_fbo != 0 && enough_vertex_attribs_for_motion_blue) { + // First frame we render motion vectors? Use our current data! + if (scene_state.prev_data_state == 0) { + scene_state.prev_data_state = 1; + } + } else { + // Not using motion vectors? We don't need to load our data. + scene_state.prev_data_state = 0; + } + bool flip_y = !is_reflection_probe; if (rt && rt->overridden.color.is_valid()) { @@ -2520,19 +2534,13 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ scene_state.reset_gl_state(); GLuint motion_vectors_fbo = rt ? rt->overridden.velocity_fbo : 0; - if (motion_vectors_fbo != 0 && GLES3::Config::get_singleton()->max_vertex_attribs >= 22) { + if (motion_vectors_fbo != 0 && enough_vertex_attribs_for_motion_blue) { RENDER_TIMESTAMP("Motion Vectors Pass"); glBindFramebuffer(GL_FRAMEBUFFER, motion_vectors_fbo); Size2i motion_vectors_target_size = rt->velocity_target_size; glViewport(0, 0, motion_vectors_target_size.x, motion_vectors_target_size.y); - if (!scene_state.is_prev_data_stored) { - scene_state.prev_data = scene_state.data; - scene_state.prev_multiview_data = scene_state.multiview_data; - scene_state.is_prev_data_stored = true; - } - scene_state.enable_gl_depth_test(true); scene_state.enable_gl_depth_draw(true); scene_state.enable_gl_blend(false); @@ -2553,8 +2561,10 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant, use_wireframe); _render_list_template(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size()); + // Copy our current scene data to our previous scene data for use in the next frame. scene_state.prev_data = scene_state.data; scene_state.prev_multiview_data = scene_state.multiview_data; + scene_state.prev_data_state = 2; } GLuint fbo = 0; @@ -4602,10 +4612,18 @@ RasterizerSceneGLES3::~RasterizerSceneGLES3() { GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.ubo_buffer); } + if (scene_state.prev_ubo_buffer != 0) { + GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.prev_ubo_buffer); + } + if (scene_state.multiview_buffer != 0) { GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.multiview_buffer); } + if (scene_state.prev_multiview_buffer != 0) { + GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.prev_multiview_buffer); + } + if (scene_state.tonemap_buffer != 0) { GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.tonemap_buffer); } diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 49e4a22b5fd..3ca8fcf346b 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -79,6 +79,8 @@ enum SceneUniformLocation { SCENE_POSITIONAL_SHADOW_UNIFORM_LOCATION, SCENE_DIRECTIONAL_SHADOW_UNIFORM_LOCATION, SCENE_EMPTY2, // Unused, put here to avoid conflicts with SKY_MULTIVIEW_UNIFORM_LOCATION. + SCENE_PREV_DATA_UNIFORM_LOCATION, + SCENE_PREV_MULTIVIEW_UNIFORM_LOCATION, }; enum SkyUniformLocation { @@ -94,6 +96,8 @@ enum SkyUniformLocation { SKY_EMPTY6, // Unused, put here to avoid conflicts with SCENE_POSITIONAL_SHADOW_UNIFORM_LOCATION. SKY_EMPTY7, // Unused, put here to avoid conflicts with SCENE_DIRECTIONAL_SHADOW_UNIFORM_LOCATION. SKY_MULTIVIEW_UNIFORM_LOCATION, + SKY_EMPTY8, // Unused, put here to avoid conflicts with SCENE_PREV_DATA_UNIFORM_LOCATION. + SKY_EMPTY9, // Unused, put here to avoid conflicts with SCENE_PREV_MULTIVIEW_UNIFORM_LOCATION. }; struct RenderDataGLES3 { @@ -463,12 +467,14 @@ private: UBO data; UBO prev_data; GLuint ubo_buffer = 0; + GLuint prev_ubo_buffer = 0; MultiviewUBO multiview_data; MultiviewUBO prev_multiview_data; GLuint multiview_buffer = 0; + GLuint prev_multiview_buffer = 0; GLuint tonemap_buffer = 0; - bool is_prev_data_stored = false; + int prev_data_state = 0; // 0 = Motion vectors not used, 1 = use data (first frame only), 2 = use previous data bool used_depth_prepass = false; @@ -717,6 +723,8 @@ private: RenderList render_list[RENDER_LIST_MAX]; + void _update_scene_ubo(GLuint &p_ubo_buffer, GLuint p_index, uint32_t p_size, const void *p_source_data, String p_name = ""); + void _setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count, uint32_t &r_directional_shadow_count); void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows, float p_shadow_bias = 0.0); void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false); diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index d46da35d026..dedf4df7c46 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -198,7 +198,7 @@ struct SceneData { float fog_aerial_perspective; float time; - mat3 radiance_inverse_xform; + mat3x4 radiance_inverse_xform; uint directional_light_count; float z_far; @@ -224,12 +224,16 @@ struct SceneData { bool pancake_shadows; }; +// The containing data block is for historic reasons. layout(std140) uniform SceneDataBlock { // ubo:2 SceneData data; - SceneData prev_data; } scene_data_block; +#ifdef RENDER_MOTION_VECTORS +layout(std140) uniform SceneData prev_scene_data; // ubo:12 +#endif + #ifndef RENDER_MOTION_VECTORS #ifdef USE_ADDITIVE_LIGHTING @@ -456,10 +460,14 @@ struct MultiviewData { layout(std140) uniform MultiviewDataBlock { // ubo:8 MultiviewData data; - MultiviewData prev_data; } multiview_data_block; -#endif + +#ifdef RENDER_MOTION_VECTORS +layout(std140) uniform MultiviewData prev_multiview_data; // ubo:13 +#endif // RENDER_MOTION_VECTORS + +#endif // USE_MULTIVIEW uniform highp mat4 world_transform; uniform highp vec3 compressed_aabb_position; @@ -901,7 +909,7 @@ void main() { compressed_aabb_position, prev_world_transform, model_flags, - scene_data_block.prev_data, + prev_scene_data.data, #ifdef USE_INSTANCING input_instance_xform0, input_instance_xform1, input_instance_xform2, input_instance_color_custom_data, @@ -919,9 +927,9 @@ void main() { uv2_attrib, #endif #ifdef USE_MULTIVIEW - multiview_data_block.prev_data.projection_matrix_view[ViewIndex], - multiview_data_block.prev_data.inv_projection_matrix_view[ViewIndex], - multiview_data_block.prev_data.eye_offset[ViewIndex].xyz, + prev_multiview_data.projection_matrix_view[ViewIndex], + prev_multiview_data.inv_projection_matrix_view[ViewIndex], + prev_multiview_data.eye_offset[ViewIndex].xyz, #endif uv_scale, prev_clip_position); @@ -1146,7 +1154,7 @@ struct SceneData { float fog_aerial_perspective; float time; - mat3 radiance_inverse_xform; + mat3x4 radiance_inverse_xform; uint directional_light_count; float z_far; @@ -1174,7 +1182,6 @@ struct SceneData { layout(std140) uniform SceneDataBlock { // ubo:2 SceneData data; - SceneData prev_data; } scene_data_block; @@ -1187,7 +1194,6 @@ struct MultiviewData { layout(std140) uniform MultiviewDataBlock { // ubo:8 MultiviewData data; - MultiviewData prev_data; } multiview_data_block; #endif @@ -2205,7 +2211,7 @@ void main() { #endif ref_vec = mix(ref_vec, normal, roughness * roughness); float horizon = min(1.0 + dot(ref_vec, normal), 1.0); - ref_vec = scene_data_block.data.radiance_inverse_xform * ref_vec; + ref_vec = mat3(scene_data_block.data.radiance_inverse_xform) * ref_vec; specular_light = textureLod(radiance_map, ref_vec, sqrt(roughness) * RADIANCE_MAX_LOD).rgb; specular_light = srgb_to_linear(specular_light); specular_light *= horizon * horizon; @@ -2250,7 +2256,7 @@ void main() { #ifdef USE_RADIANCE_MAP if (scene_data_block.data.use_ambient_cubemap) { - vec3 ambient_dir = scene_data_block.data.radiance_inverse_xform * normal; + vec3 ambient_dir = mat3(scene_data_block.data.radiance_inverse_xform) * normal; vec3 cubemap_ambient = textureLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).rgb; cubemap_ambient = srgb_to_linear(cubemap_ambient); ambient_light = mix(ambient_light, cubemap_ambient * scene_data_block.data.ambient_light_color_energy.a, scene_data_block.data.ambient_color_sky_mix);