Procházet zdrojové kódy

Merge pull request #105175 from clayjohn/RD-pipeline-sss-roughness

Detect more pipeline settings at load time to avoid pipeline stutters
Thaddeus Crews před 3 měsíci
rodič
revize
06c71fbf40

+ 31 - 10
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp

@@ -1902,16 +1902,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;
 	}
 	}
 
 
@@ -1919,7 +1928,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;
 	}
 	}
 
 
@@ -2290,18 +2299,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_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");
 		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);
+		}
 	}
 	}
 
 
 	{
 	{
@@ -3935,18 +3952,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) {

+ 8 - 0
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h

@@ -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 {

+ 16 - 14
servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp

@@ -1174,14 +1174,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) {
-				// 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) {
 			if (render_list[RENDER_LIST_ALPHA].element_info.size() > 0) {
@@ -1887,9 +1895,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;
 	}
 	}
@@ -2043,15 +2049,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;
 				}
 				}
@@ -2536,10 +2536,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) {

+ 6 - 2
servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h

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

+ 41 - 9
servers/rendering/renderer_rd/renderer_scene_render_rd.cpp

@@ -315,6 +315,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());
@@ -336,12 +362,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;
 	}
 	}
 
 
@@ -373,7 +395,7 @@ 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_copy_depth_texture(const RenderDataRD *p_render_data) {
+void RendererSceneRenderRD::_render_buffers_ensure_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());
 
 
@@ -382,14 +404,24 @@ void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataR
 		return;
 		return;
 	}
 	}
 
 
-	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.
+	// Note, this only creates our back depth texture if we haven't already created it.
 	uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
 	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_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
+	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);
 	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<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;
+	}
+
+	RD::get_singleton()->draw_command_begin_label("Copy depth texture");
 
 
 	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();

+ 2 - 0
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 _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);