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.
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<RenderSceneBuffers> &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<RenderSceneBuffers> &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<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);
_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_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);
}

View File

@@ -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);

View File

@@ -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);