diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 397dec3d5f0..b1c96b109f3 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -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); } - 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); } // 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; } - if (scene_state.used_lightmap) { + if (scene_state.used_lightmap || scene_state.lightmaps_used > 0) { 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; } - if (using_separate_specular) { + if (using_separate_specular || global_surface_data.sss_used) { 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(); } - if (scene_state.used_screen_texture) { + if (scene_state.used_screen_texture || global_surface_data.screen_texture_used) { RENDER_TIMESTAMP("Copy Screen Texture"); - // Copy screen texture to backbuffer so we can read from it - _render_buffers_copy_screen_texture(p_render_data); + _render_buffers_ensure_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"); - // Copy depth texture to backbuffer so we can read from it - _render_buffers_copy_depth_texture(p_render_data); + _render_buffers_ensure_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) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING; + global_surface_data.sss_used = true; } if (p_material->shader_data->uses_screen_texture) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; + global_surface_data.screen_texture_used = true; } if (p_material->shader_data->uses_depth_texture) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; + global_surface_data.depth_texture_used = true; } if (p_material->shader_data->uses_normal_texture) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE; + global_surface_data.normal_texture_used = true; } if (ginstance->data->cast_double_sided_shadows) { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 40ef82e7a90..a8d0a7b2cfd 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -629,6 +629,14 @@ private: void _update_dirty_geometry_instances(); 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 */ struct RenderList { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index f6157437ee7..c441dbb113e 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -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); } - 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_screen_texture || global_surface_data.screen_texture_used) { + _render_buffers_ensure_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) { - // Copy depth texture to backbuffer so we can read from it - _render_buffers_copy_depth_texture(p_render_data); + if (scene_state.used_depth_texture || global_surface_data.depth_texture_used) { + _render_buffers_ensure_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) { @@ -1893,9 +1901,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); if (p_render_list == RENDER_LIST_OPAQUE) { - scene_state.used_sss = false; scene_state.used_screen_texture = false; - scene_state.used_normal_texture = false; scene_state.used_depth_texture = 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; } - if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) { - scene_state.used_sss = true; - } if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) { 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) { 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) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; + global_surface_data.screen_texture_used = true; } if (p_material->shader_data->uses_depth_texture) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; + global_surface_data.depth_texture_used = true; } if (p_material->shader_data->uses_normal_texture) { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 9eba80c747d..643ca4559f3 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -282,9 +282,7 @@ private: RID lightmap_capture_buffer; bool used_screen_texture = false; - bool used_normal_texture = false; bool used_depth_texture = false; - bool used_sss = false; bool used_lightmap = false; struct ShadowPass { @@ -659,6 +657,12 @@ public: void _update_dirty_geometry_instances(); 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 void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 4d7e87534a7..477c50844b5 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -319,6 +319,32 @@ void RendererSceneRenderRD::_process_compositor_effects(RS::CompositorEffectCall } } +void RendererSceneRenderRD::_render_buffers_ensure_screen_texture(const RenderDataRD *p_render_data) { + Ref 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) { Ref rb = p_render_data->render_buffers; 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 reuse_blur_texture = !rb->has_upscaled_texture() || internal_size_matches; if (reuse_blur_texture) { - rb->allocate_blur_textures(); texture_name = RB_TEX_BLUR_0; } 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; } @@ -377,6 +399,23 @@ void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderData RD::get_singleton()->draw_command_end_label(); } +void RendererSceneRenderRD::_render_buffers_ensure_depth_texture(const RenderDataRD *p_render_data) { + Ref 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) { Ref rb = p_render_data->render_buffers; 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"); - // 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(); Size2i size = rb->get_internal_size(); for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 3794a257580..95e500679b5 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -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 _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 _render_buffers_ensure_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_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);