Browse Source

Merge pull request #83649 from BastiaanOlij/no_2d_stereo

Skip 2D rendering if stereo enabled and fix couple of MSAA issues
Rémi Verschelde 1 year ago
parent
commit
4cc8f0f36d

+ 1 - 1
servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp

@@ -264,7 +264,7 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe
 			RID render_target = render_buffers->get_render_target();
 			ERR_FAIL_COND_V(render_target.is_null(), RID());
 			RID target_buffer;
-			if (texture_storage->render_target_get_msaa(render_target) == RS::VIEWPORT_MSAA_DISABLED) {
+			if (view_count > 1 || texture_storage->render_target_get_msaa(render_target) == RS::VIEWPORT_MSAA_DISABLED) {
 				target_buffer = texture_storage->render_target_get_rd_texture(render_target);
 			} else {
 				target_buffer = texture_storage->render_target_get_rd_texture_msaa(render_target);

+ 15 - 1
servers/rendering/renderer_rd/renderer_scene_render_rd.cpp

@@ -365,6 +365,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
 	RID color_texture = use_upscaled_texture ? rb->get_upscaled_texture() : rb->get_internal_texture();
 	Size2i color_size = use_upscaled_texture ? target_size : rb->get_internal_size();
 
+	bool dest_is_msaa_2d = rb->get_view_count() == 1 && texture_storage->render_target_get_msaa(render_target) != RS::VIEWPORT_MSAA_DISABLED;
+
 	if (can_use_effects && RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes)) {
 		RENDER_TIMESTAMP("Depth of Field");
 		RD::get_singleton()->draw_command_begin_label("DOF");
@@ -581,7 +583,12 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
 			// If we do a bilinear upscale we just render into our render target and our shader will upscale automatically.
 			// Target size in this case is lying as we never get our real target size communicated.
 			// Bit nasty but...
-			dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target);
+
+			if (dest_is_msaa_2d) {
+				dest_fb = FramebufferCacheRD::get_singleton()->get_cache(texture_storage->render_target_get_rd_texture_msaa(render_target));
+			} else {
+				dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target);
+			}
 		}
 
 		tone_mapper->tonemapper(color_texture, dest_fb, tonemap);
@@ -599,6 +606,13 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
 			fsr->fsr_upscale(rb, source_texture, dest_texture);
 		}
 
+		if (dest_is_msaa_2d) {
+			// We can't upscale directly into our MSAA buffer so we need to do a copy
+			RID source_texture = texture_storage->render_target_get_rd_texture(render_target);
+			RID dest_fb = FramebufferCacheRD::get_singleton()->get_cache(texture_storage->render_target_get_rd_texture_msaa(render_target));
+			copy_effects->copy_to_fb_rect(source_texture, dest_fb, Rect2i(Point2i(), rb->get_target_size()));
+		}
+
 		RD::get_singleton()->draw_command_end_label();
 	}
 

+ 36 - 24
servers/rendering/renderer_viewport.cpp

@@ -116,19 +116,30 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
 		if (p_viewport->size.width == 0 || p_viewport->size.height == 0) {
 			p_viewport->render_buffers.unref();
 		} else {
+			const float EPSILON = 0.0001;
 			float scaling_3d_scale = p_viewport->scaling_3d_scale;
 			RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode;
+			bool upscaler_available = p_viewport->fsr_enabled;
+
+			if ((!upscaler_available || scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_BILINEAR || scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && scaling_3d_scale >= (1.0 - EPSILON) && scaling_3d_scale <= (1.0 + EPSILON)) {
+				// No 3D scaling on bilinear or FSR? Ignore scaling mode, this just introduces overhead.
+				// - Mobile can't perform optimal path
+				// - FSR does an extra pass (or 2 extra passes if 2D-MSAA is enabled)
+				// Scaling = 1.0 on FSR2 has benefits
+				scaling_3d_scale = 1.0;
+				scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
+			}
+
 			bool scaling_3d_is_fsr = (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) || (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR2);
 			bool use_taa = p_viewport->use_taa;
 
-			if (scaling_3d_is_fsr && (scaling_3d_scale > 1.0)) {
+			if (scaling_3d_is_fsr && (scaling_3d_scale >= (1.0 + EPSILON))) {
 				// FSR is not designed for downsampling.
 				// Fall back to bilinear scaling.
 				WARN_PRINT_ONCE("FSR 3D resolution scaling is not designed for downsampling. Falling back to bilinear 3D resolution scaling.");
 				scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
 			}
 
-			bool upscaler_available = p_viewport->fsr_enabled;
 			if (scaling_3d_is_fsr && !upscaler_available) {
 				// FSR is not actually available.
 				// Fall back to bilinear scaling.
@@ -143,8 +154,8 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
 				use_taa = false;
 			}
 
-			int width;
-			int height;
+			int target_width;
+			int target_height;
 			int render_width;
 			int render_height;
 
@@ -152,40 +163,40 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
 				case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR:
 					// Clamp 3D rendering resolution to reasonable values supported on most hardware.
 					// This prevents freezing the engine or outright crashing on lower-end GPUs.
-					width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384);
-					height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384);
-					render_width = width;
-					render_height = height;
+					target_width = p_viewport->size.width;
+					target_height = p_viewport->size.height;
+					render_width = CLAMP(target_width * scaling_3d_scale, 1, 16384);
+					render_height = CLAMP(target_height * scaling_3d_scale, 1, 16384);
 					break;
 				case RS::VIEWPORT_SCALING_3D_MODE_FSR:
 				case RS::VIEWPORT_SCALING_3D_MODE_FSR2:
-					width = p_viewport->size.width;
-					height = p_viewport->size.height;
-					render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling)
-					render_height = MAX(height * scaling_3d_scale, 1.0);
+					target_width = p_viewport->size.width;
+					target_height = p_viewport->size.height;
+					render_width = MAX(target_width * scaling_3d_scale, 1.0); // target_width / (target_width * scaling)
+					render_height = MAX(target_height * scaling_3d_scale, 1.0);
 					break;
 				case RS::VIEWPORT_SCALING_3D_MODE_OFF:
-					width = p_viewport->size.width;
-					height = p_viewport->size.height;
-					render_width = width;
-					render_height = height;
+					target_width = p_viewport->size.width;
+					target_height = p_viewport->size.height;
+					render_width = target_width;
+					render_height = target_height;
 					break;
 				default:
 					// This is an unknown mode.
 					WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode));
 					scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
 					scaling_3d_scale = 1.0;
-					width = p_viewport->size.width;
-					height = p_viewport->size.height;
-					render_width = width;
-					render_height = height;
+					target_width = p_viewport->size.width;
+					target_height = p_viewport->size.height;
+					render_width = target_width;
+					render_height = target_height;
 					break;
 			}
 
 			uint32_t jitter_phase_count = 0;
 			if (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR2) {
 				// Implementation has been copied from ffxFsr2GetJitterPhaseCount.
-				jitter_phase_count = uint32_t(8.0f * pow(float(width) / render_width, 2.0f));
+				jitter_phase_count = uint32_t(8.0f * pow(float(target_width) / render_width, 2.0f));
 			} else if (use_taa) {
 				// Default jitter count for TAA.
 				jitter_phase_count = 16;
@@ -201,7 +212,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
 			RenderSceneBuffersConfiguration rb_config;
 			rb_config.set_render_target(p_viewport->render_target);
 			rb_config.set_internal_size(Size2i(render_width, render_height));
-			rb_config.set_target_size(Size2(width, height));
+			rb_config.set_target_size(Size2(target_width, target_height));
 			rb_config.set_view_count(p_viewport->view_count);
 			rb_config.set_scaling_3d_mode(scaling_3d_mode);
 			rb_config.set_msaa_3d(p_viewport->msaa_3d);
@@ -259,6 +270,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
 
 	/* Camera should always be BEFORE any other 3D */
 
+	bool can_draw_2d = !p_viewport->disable_2d && p_viewport->view_count == 1; // Stereo rendering does not support 2D, no depth data
 	bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front
 	int scenario_canvas_max_layer = 0;
 	bool force_clear_render_target = false;
@@ -272,7 +284,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
 	if (RSG::scene->is_scenario(p_viewport->scenario)) {
 		RID environment = RSG::scene->scenario_get_environment(p_viewport->scenario);
 		if (RSG::scene->is_environment(environment)) {
-			if (!p_viewport->disable_2d && !viewport_is_environment_disabled(p_viewport)) {
+			if (can_draw_2d && !viewport_is_environment_disabled(p_viewport)) {
 				scenario_draw_canvas_bg = RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS;
 				scenario_canvas_max_layer = RSG::scene->environment_get_canvas_max_layer(environment);
 			} else if (RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS) {
@@ -307,7 +319,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
 		_draw_3d(p_viewport);
 	}
 
-	if (!p_viewport->disable_2d) {
+	if (can_draw_2d) {
 		RBMap<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map;
 
 		Rect2 clip_rect(0, 0, p_viewport->size.x, p_viewport->size.y);