1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-05 12:10:55 +00:00

Detect possible usage of SSS and screen textures at load time to allocate needed resources at load time.

This allows us to avoid a class of pipeline compilation stutters and
stutters from allocating screen textures.
This commit is contained in:
clayjohn
2025-04-08 23:52:45 -07:00
parent 87f897ae0a
commit bf47c42b21
6 changed files with 106 additions and 37 deletions

View File

@@ -1904,16 +1904,25 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags); color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags);
} }
if (using_sss || using_separate_specular || scene_state.used_lightmap || using_voxelgi) { // Ensure this is allocated so we don't get a stutter the first time an object with SSS appears on screen.
if (global_surface_data.sss_used) {
rb_data->ensure_specular();
}
if (global_surface_data.normal_texture_used) {
rb_data->ensure_normal_roughness_texture();
}
if (using_sss || using_separate_specular || scene_state.used_lightmap || using_voxelgi || global_surface_data.sss_used) {
scene_shader.enable_advanced_shader_group(p_render_data->scene_data->view_count > 1); scene_shader.enable_advanced_shader_group(p_render_data->scene_data->view_count > 1);
} }
// Update the global pipeline requirements with all the features found to be in use in this scene. // Update the global pipeline requirements with all the features found to be in use in this scene.
if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS) { if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || global_surface_data.normal_texture_used) {
global_pipeline_data_required.use_normal_and_roughness = true; global_pipeline_data_required.use_normal_and_roughness = true;
} }
if (scene_state.used_lightmap) { if (scene_state.used_lightmap || scene_state.lightmaps_used > 0) {
global_pipeline_data_required.use_lightmaps = true; global_pipeline_data_required.use_lightmaps = true;
} }
@@ -1921,7 +1930,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
global_pipeline_data_required.use_voxelgi = true; global_pipeline_data_required.use_voxelgi = true;
} }
if (using_separate_specular) { if (using_separate_specular || global_surface_data.sss_used) {
global_pipeline_data_required.use_separate_specular = true; global_pipeline_data_required.use_separate_specular = true;
} }
@@ -2292,18 +2301,26 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
rb->ensure_upscaled(); rb->ensure_upscaled();
} }
if (scene_state.used_screen_texture) { if (scene_state.used_screen_texture || global_surface_data.screen_texture_used) {
RENDER_TIMESTAMP("Copy Screen Texture"); RENDER_TIMESTAMP("Copy Screen Texture");
// Copy screen texture to backbuffer so we can read from it _render_buffers_ensure_screen_texture(p_render_data);
_render_buffers_copy_screen_texture(p_render_data);
if (scene_state.used_screen_texture) {
// Copy screen texture to backbuffer so we can read from it
_render_buffers_copy_screen_texture(p_render_data);
}
} }
if (scene_state.used_depth_texture) { if (scene_state.used_depth_texture || global_surface_data.depth_texture_used) {
RENDER_TIMESTAMP("Copy Depth Texture"); RENDER_TIMESTAMP("Copy Depth Texture");
// Copy depth texture to backbuffer so we can read from it _render_buffers_ensure_depth_texture(p_render_data);
_render_buffers_copy_depth_texture(p_render_data);
if (scene_state.used_depth_texture) {
// Copy depth texture to backbuffer so we can read from it
_render_buffers_copy_depth_texture(p_render_data);
}
} }
{ {
@@ -3937,18 +3954,22 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
if (p_material->shader_data->uses_sss) { if (p_material->shader_data->uses_sss) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING; flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING;
global_surface_data.sss_used = true;
} }
if (p_material->shader_data->uses_screen_texture) { if (p_material->shader_data->uses_screen_texture) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE;
global_surface_data.screen_texture_used = true;
} }
if (p_material->shader_data->uses_depth_texture) { if (p_material->shader_data->uses_depth_texture) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE;
global_surface_data.depth_texture_used = true;
} }
if (p_material->shader_data->uses_normal_texture) { if (p_material->shader_data->uses_normal_texture) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE; flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE;
global_surface_data.normal_texture_used = true;
} }
if (ginstance->data->cast_double_sided_shadows) { if (ginstance->data->cast_double_sided_shadows) {

View File

@@ -629,6 +629,14 @@ private:
void _update_dirty_geometry_instances(); void _update_dirty_geometry_instances();
void _update_dirty_geometry_pipelines(); void _update_dirty_geometry_pipelines();
// Global data about the scene that can be used to pre-allocate resources without relying on culling.
struct GlobalSurfaceData {
bool screen_texture_used = false;
bool normal_texture_used = false;
bool depth_texture_used = false;
bool sss_used = false;
} global_surface_data;
/* Render List */ /* Render List */
struct RenderList { struct RenderList {

View File

@@ -1180,14 +1180,22 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data);
} }
if (scene_state.used_screen_texture) { if (scene_state.used_screen_texture || global_surface_data.screen_texture_used) {
// Copy screen texture to backbuffer so we can read from it _render_buffers_ensure_screen_texture(p_render_data);
_render_buffers_copy_screen_texture(p_render_data);
if (scene_state.used_screen_texture) {
// Copy screen texture to backbuffer so we can read from it
_render_buffers_copy_screen_texture(p_render_data);
}
} }
if (scene_state.used_depth_texture) { if (scene_state.used_depth_texture || global_surface_data.depth_texture_used) {
// Copy depth texture to backbuffer so we can read from it _render_buffers_ensure_depth_texture(p_render_data);
_render_buffers_copy_depth_texture(p_render_data);
if (scene_state.used_depth_texture) {
// Copy depth texture to backbuffer so we can read from it
_render_buffers_copy_depth_texture(p_render_data);
}
} }
if (render_list[RENDER_LIST_ALPHA].element_info.size() > 0) { if (render_list[RENDER_LIST_ALPHA].element_info.size() > 0) {
@@ -1893,9 +1901,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
if (p_render_list == RENDER_LIST_OPAQUE) { if (p_render_list == RENDER_LIST_OPAQUE) {
scene_state.used_sss = false;
scene_state.used_screen_texture = false; scene_state.used_screen_texture = false;
scene_state.used_normal_texture = false;
scene_state.used_depth_texture = false; scene_state.used_depth_texture = false;
scene_state.used_lightmap = false; scene_state.used_lightmap = false;
} }
@@ -2049,15 +2055,9 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
scene_state.used_lightmap = true; scene_state.used_lightmap = true;
} }
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) {
scene_state.used_sss = true;
}
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) { if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) {
scene_state.used_screen_texture = true; scene_state.used_screen_texture = true;
} }
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) {
scene_state.used_normal_texture = true;
}
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) { if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) {
scene_state.used_depth_texture = true; scene_state.used_depth_texture = true;
} }
@@ -2542,10 +2542,12 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
if (p_material->shader_data->uses_screen_texture) { if (p_material->shader_data->uses_screen_texture) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE;
global_surface_data.screen_texture_used = true;
} }
if (p_material->shader_data->uses_depth_texture) { if (p_material->shader_data->uses_depth_texture) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE;
global_surface_data.depth_texture_used = true;
} }
if (p_material->shader_data->uses_normal_texture) { if (p_material->shader_data->uses_normal_texture) {

View File

@@ -282,9 +282,7 @@ private:
RID lightmap_capture_buffer; RID lightmap_capture_buffer;
bool used_screen_texture = false; bool used_screen_texture = false;
bool used_normal_texture = false;
bool used_depth_texture = false; bool used_depth_texture = false;
bool used_sss = false;
bool used_lightmap = false; bool used_lightmap = false;
struct ShadowPass { struct ShadowPass {
@@ -659,6 +657,12 @@ public:
void _update_dirty_geometry_instances(); void _update_dirty_geometry_instances();
void _update_dirty_geometry_pipelines(); void _update_dirty_geometry_pipelines();
// Global data about the scene that can be used to pre-allocate resources without relying on culling.
struct GlobalSurfaceData {
bool screen_texture_used = false;
bool depth_texture_used = false;
} global_surface_data;
virtual RenderGeometryInstance *geometry_instance_create(RID p_base) override; virtual RenderGeometryInstance *geometry_instance_create(RID p_base) override;
virtual void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override; virtual void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override;

View File

@@ -319,6 +319,32 @@ void RendererSceneRenderRD::_process_compositor_effects(RS::CompositorEffectCall
} }
} }
void RendererSceneRenderRD::_render_buffers_ensure_screen_texture(const RenderDataRD *p_render_data) {
Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
ERR_FAIL_COND(rb.is_null());
if (!rb->has_internal_texture()) {
// We're likely rendering reflection probes where we can't use our backbuffers.
return;
}
bool can_use_storage = _render_buffers_can_be_storage();
Size2i size = rb->get_internal_size();
// When upscaling, the blur texture needs to be at the target size for post-processing to work. We prefer to use a
// dedicated backbuffer copy texture instead if the blur texture is not an option so shader effects work correctly.
Size2i target_size = rb->get_target_size();
bool internal_size_matches = (size.width == target_size.width) && (size.height == target_size.height);
bool reuse_blur_texture = !rb->has_upscaled_texture() || internal_size_matches;
if (reuse_blur_texture) {
rb->allocate_blur_textures();
} else {
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
usage_bits |= can_use_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
rb->create_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_COLOR, rb->get_base_data_format(), usage_bits);
}
}
void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) { void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) {
Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers; Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
ERR_FAIL_COND(rb.is_null()); ERR_FAIL_COND(rb.is_null());
@@ -340,12 +366,8 @@ void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderData
bool internal_size_matches = (size.width == target_size.width) && (size.height == target_size.height); bool internal_size_matches = (size.width == target_size.width) && (size.height == target_size.height);
bool reuse_blur_texture = !rb->has_upscaled_texture() || internal_size_matches; bool reuse_blur_texture = !rb->has_upscaled_texture() || internal_size_matches;
if (reuse_blur_texture) { if (reuse_blur_texture) {
rb->allocate_blur_textures();
texture_name = RB_TEX_BLUR_0; texture_name = RB_TEX_BLUR_0;
} else { } else {
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
usage_bits |= can_use_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
rb->create_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_COLOR, rb->get_base_data_format(), usage_bits);
texture_name = RB_TEX_BACK_COLOR; texture_name = RB_TEX_BACK_COLOR;
} }
@@ -377,6 +399,23 @@ void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderData
RD::get_singleton()->draw_command_end_label(); RD::get_singleton()->draw_command_end_label();
} }
void RendererSceneRenderRD::_render_buffers_ensure_depth_texture(const RenderDataRD *p_render_data) {
Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
ERR_FAIL_COND(rb.is_null());
if (!rb->has_depth_texture()) {
// We're likely rendering reflection probes where we can't use our backbuffers.
return;
}
// Note, this only creates our back depth texture if we haven't already created it.
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; // Set this as color attachment because we're copying data into it, it's not actually used as a depth buffer
rb->create_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH, RD::DATA_FORMAT_R32_SFLOAT, usage_bits, RD::TEXTURE_SAMPLES_1);
}
void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataRD *p_render_data) { void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataRD *p_render_data) {
Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers; Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
ERR_FAIL_COND(rb.is_null()); ERR_FAIL_COND(rb.is_null());
@@ -388,13 +427,6 @@ void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataR
RD::get_singleton()->draw_command_begin_label("Copy depth texture"); RD::get_singleton()->draw_command_begin_label("Copy depth texture");
// note, this only creates our back depth texture if we haven't already created it.
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; // set this as color attachment because we're copying data into it, it's not actually used as a depth buffer
rb->create_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH, RD::DATA_FORMAT_R32_SFLOAT, usage_bits, RD::TEXTURE_SAMPLES_1);
bool can_use_storage = _render_buffers_can_be_storage(); bool can_use_storage = _render_buffers_can_be_storage();
Size2i size = rb->get_internal_size(); Size2i size = rb->get_internal_size();
for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) { for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) {

View File

@@ -102,7 +102,9 @@ protected:
bool _compositor_effects_has_flag(const RenderDataRD *p_render_data, RS::CompositorEffectFlags p_flag, RS::CompositorEffectCallbackType p_callback_type = RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_ANY); bool _compositor_effects_has_flag(const RenderDataRD *p_render_data, RS::CompositorEffectFlags p_flag, RS::CompositorEffectCallbackType p_callback_type = RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_ANY);
bool _has_compositor_effect(RS::CompositorEffectCallbackType p_callback_type, const RenderDataRD *p_render_data); bool _has_compositor_effect(RS::CompositorEffectCallbackType p_callback_type, const RenderDataRD *p_render_data);
void _process_compositor_effects(RS::CompositorEffectCallbackType p_callback_type, const RenderDataRD *p_render_data); void _process_compositor_effects(RS::CompositorEffectCallbackType p_callback_type, const RenderDataRD *p_render_data);
void _render_buffers_ensure_screen_texture(const RenderDataRD *p_render_data);
void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data); void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data);
void _render_buffers_ensure_depth_texture(const RenderDataRD *p_render_data);
void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data); void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data);
void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data); void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
void _post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data); void _post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data);