Bläddra i källkod

Fix VRS issues

Bastiaan Olij 2 år sedan
förälder
incheckning
616ba8745f

+ 7 - 1
drivers/vulkan/rendering_device_vulkan.cpp

@@ -3826,7 +3826,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
 			vrs_reference.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
 			vrs_reference.aspectMask = VK_IMAGE_ASPECT_NONE;
 
-			Size2i texel_size = context->get_vrs_capabilities().max_texel_size;
+			Size2i texel_size = context->get_vrs_capabilities().texel_size;
 
 			VkFragmentShadingRateAttachmentInfoKHR &vrs_attachment_info = vrs_attachment_info_array[i];
 			vrs_attachment_info.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
@@ -9724,6 +9724,12 @@ uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const {
 			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
 			return subgroup_capabilities.supported_operations_flags_rd();
 		}
+		case LIMIT_VRS_TEXEL_WIDTH: {
+			return context->get_vrs_capabilities().texel_size.x;
+		}
+		case LIMIT_VRS_TEXEL_HEIGHT: {
+			return context->get_vrs_capabilities().texel_size.y;
+		}
 		default:
 			ERR_FAIL_V(0);
 	}

+ 7 - 0
drivers/vulkan/vulkan_context.cpp

@@ -625,6 +625,9 @@ Error VulkanContext::_check_capabilities() {
 	vrs_capabilities.pipeline_vrs_supported = false;
 	vrs_capabilities.primitive_vrs_supported = false;
 	vrs_capabilities.attachment_vrs_supported = false;
+	vrs_capabilities.min_texel_size = Size2i();
+	vrs_capabilities.max_texel_size = Size2i();
+	vrs_capabilities.texel_size = Size2i();
 	multiview_capabilities.is_supported = false;
 	multiview_capabilities.geometry_shader_is_supported = false;
 	multiview_capabilities.tessellation_shader_is_supported = false;
@@ -788,6 +791,10 @@ Error VulkanContext::_check_capabilities() {
 				vrs_capabilities.max_texel_size.x = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width;
 				vrs_capabilities.max_texel_size.y = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.height;
 
+				// We'll attempt to default to a texel size of 16x16
+				vrs_capabilities.texel_size.x = CLAMP(16, vrs_capabilities.min_texel_size.x, vrs_capabilities.max_texel_size.x);
+				vrs_capabilities.texel_size.y = CLAMP(16, vrs_capabilities.min_texel_size.y, vrs_capabilities.max_texel_size.y);
+
 				print_verbose(String("  Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")"));
 			}
 

+ 2 - 0
drivers/vulkan/vulkan_context.h

@@ -76,6 +76,8 @@ public:
 
 		Size2i min_texel_size;
 		Size2i max_texel_size;
+
+		Size2i texel_size; // The texel size we'll use
 	};
 
 	struct ShaderCapabilities {

+ 7 - 10
servers/rendering/renderer_rd/effects/vrs.cpp

@@ -92,18 +92,15 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi
 }
 
 Size2i VRS::get_vrs_texture_size(const Size2i p_base_size) const {
-	// TODO we should find some way to store this properly, we're assuming 16x16 as this seems to be the standard but in our vrs_capacities we
-	// obtain a minimum and maximum size, and we should choose something within this range and then make sure that is consistently set when creating
-	// our frame buffer. Also it is important that we make the resulting size we calculate down below available to the end user so they know the size
-	// of the VRS buffer to supply.
-	Size2i texel_size = Size2i(16, 16);
-
-	int width = p_base_size.x / texel_size.x;
-	if (p_base_size.x % texel_size.x != 0) {
+	int32_t texel_width = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_WIDTH);
+	int32_t texel_height = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_HEIGHT);
+
+	int width = p_base_size.x / texel_width;
+	if (p_base_size.x % texel_width != 0) {
 		width++;
 	}
-	int height = p_base_size.y / texel_size.y;
-	if (p_base_size.y % texel_size.y != 0) {
+	int height = p_base_size.y / texel_height;
+	if (p_base_size.y % texel_height != 0) {
 		height++;
 	}
 	return Size2i(width, height);

+ 11 - 3
servers/rendering/renderer_rd/shaders/effects/vrs.glsl

@@ -63,10 +63,18 @@ void main() {
 
 #ifdef MULTIVIEW
 	vec4 color = textureLod(source_color, uv, 0.0);
+	frag_color = uint(color.r * 255.0);
 #else /* MULTIVIEW */
 	vec4 color = textureLod(source_color, uv, 0.0);
-#endif /* MULTIVIEW */
 
-	// See if we can change the sampler to one that returns int...
-	frag_color = uint(color.r * 256.0);
+	// for user supplied VRS map we do a color mapping
+	color.r *= 3.0;
+	frag_color = int(color.r) << 2;
+
+	color.g *= 3.0;
+	frag_color += int(color.g);
+
+	// note 1x4, 4x1, 1x8, 8x1, 2x8 and 8x2 are not supported
+	// 4x8, 8x4 and 8x8 are only available on some GPUs
+#endif /* MULTIVIEW */
 }

+ 2 - 0
servers/rendering/rendering_device.h

@@ -1257,6 +1257,8 @@ public:
 		LIMIT_SUBGROUP_SIZE,
 		LIMIT_SUBGROUP_IN_SHADERS, // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc.
 		LIMIT_SUBGROUP_OPERATIONS,
+		LIMIT_VRS_TEXEL_WIDTH,
+		LIMIT_VRS_TEXEL_HEIGHT,
 	};
 
 	virtual uint64_t limit_get(Limit p_limit) const = 0;

+ 5 - 2
servers/xr/xr_interface.cpp

@@ -167,11 +167,12 @@ RID XRInterface::get_vrs_texture() {
 	// Default logic will return a standard VRS image based on our target size and default projections.
 	// Note that this only gets called if VRS is supported on the hardware.
 
-	Size2 texel_size = Size2(16.0, 16.0); // For now we assume we always use 16x16 texels, seems to be the standard.
+	int32_t texel_width = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_WIDTH);
+	int32_t texel_height = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_HEIGHT);
 	int view_count = get_view_count();
 	Size2 target_size = get_render_target_size();
 	real_t aspect = target_size.x / target_size.y; // is this y/x ?
-	Size2 vrs_size = Size2(round(0.5 + target_size.x / texel_size.x), round(0.5 + target_size.y / texel_size.y));
+	Size2 vrs_size = Size2(round(0.5 + target_size.x / texel_width), round(0.5 + target_size.y / texel_height));
 	real_t radius = vrs_size.length() * 0.5;
 	Size2 vrs_sizei = vrs_size;
 
@@ -179,6 +180,8 @@ RID XRInterface::get_vrs_texture() {
 		const uint8_t densities[] = {
 			0, // 1x1
 			1, // 1x2
+			// 2, // 1x4 - not supported
+			// 3, // 1x8 - not supported
 			// 4, // 2x1
 			5, // 2x2
 			6, // 2x4