Browse Source

Add support for pipeline VRS

Panagiotis Christopoulos Charitos 4 years ago
parent
commit
611a2d5830

+ 3 - 0
AnKi/Gr/CommandBuffer.h

@@ -304,6 +304,9 @@ public:
 
 
 	/// End renderpass.
 	/// End renderpass.
 	void endRenderPass();
 	void endRenderPass();
+
+	/// Set VRS rate of the following drawcalls. By default it's 1x1.
+	void setVrsRate(VrsRate rate);
 	/// @}
 	/// @}
 
 
 	/// @name Jobs
 	/// @name Jobs

+ 4 - 1
AnKi/Gr/Common.h

@@ -156,12 +156,15 @@ public:
 	/// 64 bit atomics.
 	/// 64 bit atomics.
 	Bool m_64bitAtomics = false;
 	Bool m_64bitAtomics = false;
 
 
+	/// VRS.
+	Bool m_vrs = false;
+
 	/// Supports min/max texture filtering.
 	/// Supports min/max texture filtering.
 	Bool m_samplingFilterMinMax = false;
 	Bool m_samplingFilterMinMax = false;
 };
 };
 ANKI_END_PACKED_STRUCT
 ANKI_END_PACKED_STRUCT
 static_assert(sizeof(GpuDeviceCapabilities)
 static_assert(sizeof(GpuDeviceCapabilities)
-				  == sizeof(PtrSize) * 4 + sizeof(U32) * 5 + sizeof(U8) * 3 + sizeof(Bool) * 3,
+				  == sizeof(PtrSize) * 4 + sizeof(U32) * 5 + sizeof(U8) * 3 + sizeof(Bool) * 4,
 			  "Should be packed");
 			  "Should be packed");
 
 
 /// Bindless related info.
 /// Bindless related info.

+ 1 - 0
AnKi/Gr/ConfigDefs.h

@@ -12,6 +12,7 @@ ANKI_CONFIG_OPTION(gr_maxBindlessImages, 32, 8, 1024)
 ANKI_CONFIG_OPTION(gr_rayTracing, 0, 0, 1, "Try enabling ray tracing")
 ANKI_CONFIG_OPTION(gr_rayTracing, 0, 0, 1, "Try enabling ray tracing")
 ANKI_CONFIG_OPTION(gr_64bitAtomics, 1, 0, 1)
 ANKI_CONFIG_OPTION(gr_64bitAtomics, 1, 0, 1)
 ANKI_CONFIG_OPTION(gr_samplerFilterMinMax, 1, 0, 1)
 ANKI_CONFIG_OPTION(gr_samplerFilterMinMax, 1, 0, 1)
+ANKI_CONFIG_OPTION(gr_vrs, 0, 0, 1)
 
 
 // Vulkan
 // Vulkan
 ANKI_CONFIG_OPTION(gr_diskShaderCacheMaxSize, 128_MB, 1_MB, 1_GB)
 ANKI_CONFIG_OPTION(gr_diskShaderCacheMaxSize, 128_MB, 1_MB, 1_GB)

+ 16 - 0
AnKi/Gr/Enums.h

@@ -543,6 +543,22 @@ enum class AccelerationStructureUsageBit : U8
 	ALL_WRITE = BUILD
 	ALL_WRITE = BUILD
 };
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(AccelerationStructureUsageBit)
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(AccelerationStructureUsageBit)
+
+/// VRS rates.
+enum class VrsRate : U8
+{
+	_1x1, ///< Disable VRS. Always supported.
+	_2x1, ///< Always supported.
+	_1x2,
+	_2x2, ///< Always supported.
+	_4x2,
+	_2x4,
+	_4x4,
+
+	COUNT,
+	FIRST = 0
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VrsRate)
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 6 - 0
AnKi/Gr/Vulkan/CommandBuffer.cpp

@@ -257,6 +257,12 @@ void CommandBuffer::endRenderPass()
 	self.endRenderPass();
 	self.endRenderPass();
 }
 }
 
 
+void CommandBuffer::setVrsRate(VrsRate rate)
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setVrsRateInternal(rate);
+}
+
 void CommandBuffer::drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex,
 void CommandBuffer::drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex,
 								 U32 baseVertex, U32 baseInstance)
 								 U32 baseVertex, U32 baseInstance)
 {
 {

+ 2 - 0
AnKi/Gr/Vulkan/CommandBufferImpl.h

@@ -293,6 +293,8 @@ public:
 
 
 	void endRenderPass();
 	void endRenderPass();
 
 
+	void setVrsRateInternal(VrsRate rate);
+
 	void drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance);
 	void drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance);
 
 
 	void drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex,
 	void drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex,

+ 14 - 0
AnKi/Gr/Vulkan/CommandBufferImpl.inl.h

@@ -950,4 +950,18 @@ inline void CommandBufferImpl::setLineWidth(F32 width)
 #endif
 #endif
 }
 }
 
 
+inline void CommandBufferImpl::setVrsRateInternal(VrsRate rate)
+{
+	ANKI_ASSERT(getGrManagerImpl().getDeviceCapabilities().m_vrs);
+	ANKI_ASSERT(rate < VrsRate::COUNT);
+
+	commandCommon();
+
+	const VkExtent2D extend = convertVrsShadingRate(rate);
+	Array<VkFragmentShadingRateCombinerOpKHR, 2> combiner;
+	combiner[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // Keep pipeline rating over primitive
+	combiner[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // Keep pipeline rating over attachment
+	vkCmdSetFragmentShadingRateKHR(m_handle, &extend, &combiner[0]);
+}
+
 } // end namespace anki
 } // end namespace anki

+ 34 - 0
AnKi/Gr/Vulkan/Common.h

@@ -81,6 +81,7 @@ enum class VulkanExtensions : U32
 	KHR_SHADER_FLOAT_CONTROLS = 1 << 20,
 	KHR_SHADER_FLOAT_CONTROLS = 1 << 20,
 	EXT_SAMPLER_FILTER_MIN_MAX = 1 << 21,
 	EXT_SAMPLER_FILTER_MIN_MAX = 1 << 21,
 	KHR_CREATE_RENDERPASS_2 = 1 << 22,
 	KHR_CREATE_RENDERPASS_2 = 1 << 22,
+	KHR_FRAGMENT_SHADING_RATE = 1 << 23,
 };
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VulkanExtensions)
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VulkanExtensions)
 
 
@@ -341,6 +342,39 @@ ANKI_USE_RESULT inline VkAccelerationStructureTypeKHR convertAccelerationStructu
 }
 }
 
 
 ANKI_USE_RESULT const char* vkResultToString(VkResult res);
 ANKI_USE_RESULT const char* vkResultToString(VkResult res);
+
+ANKI_USE_RESULT inline VkExtent2D convertVrsShadingRate(VrsRate rate)
+{
+	VkExtent2D out = {};
+	switch(rate)
+	{
+	case VrsRate::_1x1:
+		out = {1, 1};
+		break;
+	case VrsRate::_2x1:
+		out = {2, 1};
+		break;
+	case VrsRate::_1x2:
+		out = {1, 2};
+		break;
+	case VrsRate::_2x2:
+		out = {2, 2};
+		break;
+	case VrsRate::_4x2:
+		out = {4, 2};
+		break;
+	case VrsRate::_2x4:
+		out = {2, 4};
+		break;
+	case VrsRate::_4x4:
+		out = {4, 4};
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
+
+	return out;
+}
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 38 - 0
AnKi/Gr/Vulkan/GrManagerImpl.cpp

@@ -724,6 +724,11 @@ Error GrManagerImpl::initDevice(const GrManagerInitInfo& init)
 				m_extensions |= VulkanExtensions::KHR_CREATE_RENDERPASS_2;
 				m_extensions |= VulkanExtensions::KHR_CREATE_RENDERPASS_2;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
 			}
+			else if(extensionName == VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME && init.m_config->getBool("gr_vrs"))
+			{
+				m_extensions |= VulkanExtensions::KHR_FRAGMENT_SHADING_RATE;
+				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
+			}
 		}
 		}
 
 
 		ANKI_VK_LOGI("Will enable the following device extensions:");
 		ANKI_VK_LOGI("Will enable the following device extensions:");
@@ -961,6 +966,39 @@ Error GrManagerImpl::initDevice(const GrManagerInitInfo& init)
 		ci.pNext = &m_atomicInt64Features;
 		ci.pNext = &m_atomicInt64Features;
 	}
 	}
 
 
+	// VRS
+	if(!(m_extensions & VulkanExtensions::KHR_FRAGMENT_SHADING_RATE))
+	{
+		ANKI_VK_LOGI(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME " is not supported or disabled");
+		m_capabilities.m_vrs = false;
+	}
+	else
+	{
+		m_capabilities.m_vrs = true;
+
+		m_fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
+
+		VkPhysicalDeviceFeatures2 features = {};
+		features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+		features.pNext = &m_fragmentShadingRateFeatures;
+		vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
+
+		// Some checks
+		if(!m_fragmentShadingRateFeatures.attachmentFragmentShadingRate
+		   || !m_fragmentShadingRateFeatures.pipelineFragmentShadingRate)
+		{
+			ANKI_VK_LOGE(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME
+						 " doesn't support attachment and/or pipeline rates");
+			return Error::FUNCTION_FAILED;
+		}
+
+		// Disable some things
+		m_fragmentShadingRateFeatures.primitiveFragmentShadingRate = false;
+
+		m_fragmentShadingRateFeatures.pNext = const_cast<void*>(ci.pNext);
+		ci.pNext = &m_fragmentShadingRateFeatures;
+	}
+
 	ANKI_VK_CHECK(vkCreateDevice(m_physicalDevice, &ci, nullptr, &m_device));
 	ANKI_VK_CHECK(vkCreateDevice(m_physicalDevice, &ci, nullptr, &m_device));
 
 
 	// Get debug marker
 	// Get debug marker

+ 1 - 0
AnKi/Gr/Vulkan/GrManagerImpl.h

@@ -257,6 +257,7 @@ private:
 	VkPhysicalDeviceTimelineSemaphoreFeaturesKHR m_timelineSemaphoreFeatures = {};
 	VkPhysicalDeviceTimelineSemaphoreFeaturesKHR m_timelineSemaphoreFeatures = {};
 	VkPhysicalDeviceShaderFloat16Int8FeaturesKHR m_float16Int8Features = {};
 	VkPhysicalDeviceShaderFloat16Int8FeaturesKHR m_float16Int8Features = {};
 	VkPhysicalDeviceShaderAtomicInt64FeaturesKHR m_atomicInt64Features = {};
 	VkPhysicalDeviceShaderAtomicInt64FeaturesKHR m_atomicInt64Features = {};
+	VkPhysicalDeviceFragmentShadingRateFeaturesKHR m_fragmentShadingRateFeatures = {};
 
 
 	PFN_vkDebugMarkerSetObjectNameEXT m_pfnDebugMarkerSetObjectNameEXT = nullptr;
 	PFN_vkDebugMarkerSetObjectNameEXT m_pfnDebugMarkerSetObjectNameEXT = nullptr;
 	PFN_vkCmdDebugMarkerBeginEXT m_pfnCmdDebugMarkerBeginEXT = nullptr;
 	PFN_vkCmdDebugMarkerBeginEXT m_pfnCmdDebugMarkerBeginEXT = nullptr;

+ 2 - 2
AnKi/Gr/Vulkan/Pipeline.cpp

@@ -376,10 +376,10 @@ const VkGraphicsPipelineCreateInfo& PipelineStateTracker::updatePipelineCreateIn
 	dynCi.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
 	dynCi.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
 
 
 	// Almost all state is dynamic. Depth bias is static
 	// Almost all state is dynamic. Depth bias is static
-	static const Array<VkDynamicState, 8> DYN = {
+	static const Array<VkDynamicState, 9> DYN = {
 		{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_BLEND_CONSTANTS,
 		{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_BLEND_CONSTANTS,
 		 VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
 		 VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
-		 VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_LINE_WIDTH}};
+		 VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_LINE_WIDTH, VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR}};
 
 
 	dynCi.dynamicStateCount = DYN.getSize();
 	dynCi.dynamicStateCount = DYN.getSize();
 	dynCi.pDynamicStates = &DYN[0];
 	dynCi.pDynamicStates = &DYN[0];