Merge pull request #114175 from BastiaanOlij/opengl_split_motion_vector_ubos

OpenGL: Split the ubos for motion vectors into separate uniforms
This commit is contained in:
Rémi Verschelde
2025-12-19 11:53:26 +01:00
3 changed files with 72 additions and 40 deletions

View File

@@ -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. // 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) { 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; Projection correction;
@@ -1619,29 +1632,19 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
scene_state.data.IBL_exposure_normalization = 1.0; scene_state.data.IBL_exposure_normalization = 1.0;
} }
if (scene_state.ubo_buffer == 0) { _update_scene_ubo(scene_state.ubo_buffer, SCENE_DATA_UNIFORM_LOCATION, sizeof(SceneState::UBO), &scene_state.data, "Scene state UBO");
glGenBuffers(1, &scene_state.ubo_buffer); if (p_render_data->view_count > 1) {
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer); _update_scene_ubo(scene_state.multiview_buffer, SCENE_MULTIVIEW_UNIFORM_LOCATION, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_data, "Multiview UBO");
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);
} }
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 (p_render_data->view_count > 1) {
if (scene_state.multiview_buffer == 0) { source_data = scene_state.prev_data_state == 1 ? &scene_state.multiview_data : &scene_state.prev_multiview_data;
glGenBuffers(1, &scene_state.multiview_buffer); _update_scene_ubo(scene_state.prev_multiview_buffer, SCENE_PREV_MULTIVIEW_UNIFORM_LOCATION, sizeof(SceneState::MultiviewUBO), source_data, "Previous multiview UBO");
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);
} }
glBindBuffer(GL_UNIFORM_BUFFER, 0);
} }
} }
@@ -2408,6 +2411,17 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
scene_state.data.emissive_exposure_normalization = -1.0; // Use default exposure normalization. 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; bool flip_y = !is_reflection_probe;
if (rt && rt->overridden.color.is_valid()) { if (rt && rt->overridden.color.is_valid()) {
@@ -2520,19 +2534,13 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
scene_state.reset_gl_state(); scene_state.reset_gl_state();
GLuint motion_vectors_fbo = rt ? rt->overridden.velocity_fbo : 0; 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"); RENDER_TIMESTAMP("Motion Vectors Pass");
glBindFramebuffer(GL_FRAMEBUFFER, motion_vectors_fbo); glBindFramebuffer(GL_FRAMEBUFFER, motion_vectors_fbo);
Size2i motion_vectors_target_size = rt->velocity_target_size; Size2i motion_vectors_target_size = rt->velocity_target_size;
glViewport(0, 0, motion_vectors_target_size.x, motion_vectors_target_size.y); 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_test(true);
scene_state.enable_gl_depth_draw(true); scene_state.enable_gl_depth_draw(true);
scene_state.enable_gl_blend(false); scene_state.enable_gl_blend(false);
@@ -2553,8 +2561,10 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &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); 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<PASS_MODE_MOTION_VECTORS>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size()); _render_list_template<PASS_MODE_MOTION_VECTORS>(&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_data = scene_state.data;
scene_state.prev_multiview_data = scene_state.multiview_data; scene_state.prev_multiview_data = scene_state.multiview_data;
scene_state.prev_data_state = 2;
} }
GLuint fbo = 0; GLuint fbo = 0;
@@ -4602,10 +4612,18 @@ RasterizerSceneGLES3::~RasterizerSceneGLES3() {
GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.ubo_buffer); 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) { if (scene_state.multiview_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.multiview_buffer); 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) { if (scene_state.tonemap_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.tonemap_buffer); GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.tonemap_buffer);
} }

View File

@@ -79,6 +79,8 @@ enum SceneUniformLocation {
SCENE_POSITIONAL_SHADOW_UNIFORM_LOCATION, SCENE_POSITIONAL_SHADOW_UNIFORM_LOCATION,
SCENE_DIRECTIONAL_SHADOW_UNIFORM_LOCATION, SCENE_DIRECTIONAL_SHADOW_UNIFORM_LOCATION,
SCENE_EMPTY2, // Unused, put here to avoid conflicts with SKY_MULTIVIEW_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 { enum SkyUniformLocation {
@@ -94,6 +96,8 @@ enum SkyUniformLocation {
SKY_EMPTY6, // Unused, put here to avoid conflicts with SCENE_POSITIONAL_SHADOW_UNIFORM_LOCATION. 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_EMPTY7, // Unused, put here to avoid conflicts with SCENE_DIRECTIONAL_SHADOW_UNIFORM_LOCATION.
SKY_MULTIVIEW_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 { struct RenderDataGLES3 {
@@ -463,12 +467,14 @@ private:
UBO data; UBO data;
UBO prev_data; UBO prev_data;
GLuint ubo_buffer = 0; GLuint ubo_buffer = 0;
GLuint prev_ubo_buffer = 0;
MultiviewUBO multiview_data; MultiviewUBO multiview_data;
MultiviewUBO prev_multiview_data; MultiviewUBO prev_multiview_data;
GLuint multiview_buffer = 0; GLuint multiview_buffer = 0;
GLuint prev_multiview_buffer = 0;
GLuint tonemap_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; bool used_depth_prepass = false;
@@ -717,6 +723,8 @@ private:
RenderList render_list[RENDER_LIST_MAX]; 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_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 _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); void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false);

View File

@@ -198,7 +198,7 @@ struct SceneData {
float fog_aerial_perspective; float fog_aerial_perspective;
float time; float time;
mat3 radiance_inverse_xform; mat3x4 radiance_inverse_xform;
uint directional_light_count; uint directional_light_count;
float z_far; float z_far;
@@ -224,12 +224,16 @@ struct SceneData {
bool pancake_shadows; bool pancake_shadows;
}; };
// The containing data block is for historic reasons.
layout(std140) uniform SceneDataBlock { // ubo:2 layout(std140) uniform SceneDataBlock { // ubo:2
SceneData data; SceneData data;
SceneData prev_data;
} }
scene_data_block; scene_data_block;
#ifdef RENDER_MOTION_VECTORS
layout(std140) uniform SceneData prev_scene_data; // ubo:12
#endif
#ifndef RENDER_MOTION_VECTORS #ifndef RENDER_MOTION_VECTORS
#ifdef USE_ADDITIVE_LIGHTING #ifdef USE_ADDITIVE_LIGHTING
@@ -456,10 +460,14 @@ struct MultiviewData {
layout(std140) uniform MultiviewDataBlock { // ubo:8 layout(std140) uniform MultiviewDataBlock { // ubo:8
MultiviewData data; MultiviewData data;
MultiviewData prev_data;
} }
multiview_data_block; 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 mat4 world_transform;
uniform highp vec3 compressed_aabb_position; uniform highp vec3 compressed_aabb_position;
@@ -901,7 +909,7 @@ void main() {
compressed_aabb_position, compressed_aabb_position,
prev_world_transform, prev_world_transform,
model_flags, model_flags,
scene_data_block.prev_data, prev_scene_data.data,
#ifdef USE_INSTANCING #ifdef USE_INSTANCING
input_instance_xform0, input_instance_xform1, input_instance_xform2, input_instance_xform0, input_instance_xform1, input_instance_xform2,
input_instance_color_custom_data, input_instance_color_custom_data,
@@ -919,9 +927,9 @@ void main() {
uv2_attrib, uv2_attrib,
#endif #endif
#ifdef USE_MULTIVIEW #ifdef USE_MULTIVIEW
multiview_data_block.prev_data.projection_matrix_view[ViewIndex], prev_multiview_data.projection_matrix_view[ViewIndex],
multiview_data_block.prev_data.inv_projection_matrix_view[ViewIndex], prev_multiview_data.inv_projection_matrix_view[ViewIndex],
multiview_data_block.prev_data.eye_offset[ViewIndex].xyz, prev_multiview_data.eye_offset[ViewIndex].xyz,
#endif #endif
uv_scale, uv_scale,
prev_clip_position); prev_clip_position);
@@ -1146,7 +1154,7 @@ struct SceneData {
float fog_aerial_perspective; float fog_aerial_perspective;
float time; float time;
mat3 radiance_inverse_xform; mat3x4 radiance_inverse_xform;
uint directional_light_count; uint directional_light_count;
float z_far; float z_far;
@@ -1174,7 +1182,6 @@ struct SceneData {
layout(std140) uniform SceneDataBlock { // ubo:2 layout(std140) uniform SceneDataBlock { // ubo:2
SceneData data; SceneData data;
SceneData prev_data;
} }
scene_data_block; scene_data_block;
@@ -1187,7 +1194,6 @@ struct MultiviewData {
layout(std140) uniform MultiviewDataBlock { // ubo:8 layout(std140) uniform MultiviewDataBlock { // ubo:8
MultiviewData data; MultiviewData data;
MultiviewData prev_data;
} }
multiview_data_block; multiview_data_block;
#endif #endif
@@ -2205,7 +2211,7 @@ void main() {
#endif #endif
ref_vec = mix(ref_vec, normal, roughness * roughness); ref_vec = mix(ref_vec, normal, roughness * roughness);
float horizon = min(1.0 + dot(ref_vec, normal), 1.0); 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 = textureLod(radiance_map, ref_vec, sqrt(roughness) * RADIANCE_MAX_LOD).rgb;
specular_light = srgb_to_linear(specular_light); specular_light = srgb_to_linear(specular_light);
specular_light *= horizon * horizon; specular_light *= horizon * horizon;
@@ -2250,7 +2256,7 @@ void main() {
#ifdef USE_RADIANCE_MAP #ifdef USE_RADIANCE_MAP
if (scene_data_block.data.use_ambient_cubemap) { 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; vec3 cubemap_ambient = textureLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).rgb;
cubemap_ambient = srgb_to_linear(cubemap_ambient); 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); ambient_light = mix(ambient_light, cubemap_ambient * scene_data_block.data.ambient_light_color_energy.a, scene_data_block.data.ambient_color_sky_mix);