[GPU] Implement ZPD occlusion queries
Implements EVENT_WRITE_ZPD handling across shared CommandProcessor, D3D12, and Vulkan backends. This adds a shared report lifecycle. Reports can span submissions/render passes, split into multiple segments, and asynchronously retire. Reports can also survive same-slot reuse, which is critical for titles that aggressively recycle against a small pool. RTV/FBO use their respective host occlusion queries, whereas ROV/FSI use counter buffers instead, with shader helpers that are called from the translated PS, accumulating surviving MSAA sample coverage into active slots. Regardless of approach, results are copied to small, dedicated readbacks and fed through shared retirement. Fast mode writes speculative values and patches in resolved results later. Strict mode waits for real results with a small retire backstop so it doesn't spin forever when a report gets weird. Fake mode's fundamentals are unchanged, it just now uses XenosZPDReport memory helpers like all the modes do. Also adds optional sample count saturation for instances when attenuation isn't a one-for-one with real hardware, an optional alternate fast behavior that preserves cached zeroes (that can improve flare-heavy titles but might regress occlusion culling), and normalization for upscaling. QueryBatch is still unsupported other than a fake path that's enabled when a range is set via cvar.
This commit is contained in:
committed by
Radosław Gliński
parent
29311ddcdd
commit
fbd620c22b
@@ -5,6 +5,7 @@ XE_UI_VULKAN_FUNCTION(vkAllocateMemory)
|
||||
XE_UI_VULKAN_FUNCTION(vkBeginCommandBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkBindBufferMemory)
|
||||
XE_UI_VULKAN_FUNCTION(vkBindImageMemory)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBeginQuery)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBeginRenderPass)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBindDescriptorSets)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBindIndexBuffer)
|
||||
@@ -16,12 +17,16 @@ XE_UI_VULKAN_FUNCTION(vkCmdClearColorImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdCopyBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdCopyBufferToImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdCopyImageToBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdCopyQueryPoolResults)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDispatch)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDraw)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDrawIndexed)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdEndQuery)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdEndRenderPass)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdFillBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdPipelineBarrier)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdPushConstants)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdResetQueryPool)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetBlendConstants)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetDepthBias)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetScissor)
|
||||
@@ -42,6 +47,7 @@ XE_UI_VULKAN_FUNCTION(vkCreateImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateImageView)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreatePipelineCache)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreatePipelineLayout)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateQueryPool)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateRenderPass)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateSampler)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateSemaphore)
|
||||
@@ -58,6 +64,7 @@ XE_UI_VULKAN_FUNCTION(vkDestroyImageView)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyPipeline)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyPipelineCache)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyPipelineLayout)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyQueryPool)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyRenderPass)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroySampler)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroySemaphore)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
// VK_EXT_host_query_reset functions used in Xenia.
|
||||
// Promoted to Vulkan 1.2 core.
|
||||
XE_UI_VULKAN_FUNCTION_PROMOTED(vkResetQueryPoolEXT, vkResetQueryPool)
|
||||
@@ -175,6 +175,7 @@ std::unique_ptr<VulkanDevice> VulkanDevice::CreateIfSupported(
|
||||
}
|
||||
|
||||
bool ext_1_2_KHR_sampler_mirror_clamp_to_edge = false;
|
||||
bool ext_1_2_EXT_host_query_reset = false;
|
||||
bool ext_1_1_KHR_maintenance1 = false;
|
||||
bool ext_1_2_KHR_shader_float_controls = false;
|
||||
bool ext_EXT_fragment_shader_interlock = false;
|
||||
@@ -195,6 +196,7 @@ std::unique_ptr<VulkanDevice> VulkanDevice::CreateIfSupported(
|
||||
XE_UI_VULKAN_STRUCT_PROMOTED_EXTENSION(KHR_sampler_ycbcr_conversion, 1, 1)
|
||||
// #198. Also must be enabled for VK_KHR_spirv_1_4.
|
||||
XE_UI_VULKAN_LOCAL_PROMOTED_EXTENSION(KHR_shader_float_controls, 1, 2)
|
||||
XE_UI_VULKAN_LOCAL_PROMOTED_EXTENSION(EXT_host_query_reset, 1, 2)
|
||||
// #252.
|
||||
XE_UI_VULKAN_LOCAL_EXTENSION(EXT_fragment_shader_interlock)
|
||||
// #277.
|
||||
@@ -282,6 +284,9 @@ std::unique_ptr<VulkanDevice> VulkanDevice::CreateIfSupported(
|
||||
VulkanFeatures<VkPhysicalDeviceVulkan12Features,
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES>
|
||||
features_1_2;
|
||||
VulkanFeatures<VkPhysicalDeviceHostQueryResetFeatures,
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES>
|
||||
features_EXT_host_query_reset;
|
||||
VulkanFeatures<VkPhysicalDeviceVulkan13Features,
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES>
|
||||
features_1_3;
|
||||
@@ -310,6 +315,9 @@ std::unique_ptr<VulkanDevice> VulkanDevice::CreateIfSupported(
|
||||
if (get_physical_device_properties2_supported) {
|
||||
if (properties.apiVersion >= VK_MAKE_API_VERSION(0, 1, 2, 0)) {
|
||||
features_1_2.Link(supported_features_2, device_create_info);
|
||||
} else if (ext_1_2_EXT_host_query_reset) {
|
||||
features_EXT_host_query_reset.Link(supported_features_2,
|
||||
device_create_info);
|
||||
}
|
||||
if (properties.apiVersion >= VK_MAKE_API_VERSION(0, 1, 3, 0)) {
|
||||
features_1_3.Link(supported_features_2, device_create_info);
|
||||
@@ -631,12 +639,18 @@ std::unique_ptr<VulkanDevice> VulkanDevice::CreateIfSupported(
|
||||
XE_UI_VULKAN_FEATURE_2(features_1_2, samplerMirrorClampToEdge);
|
||||
XE_UI_VULKAN_FEATURE_2(features_1_2, uniformBufferStandardLayout);
|
||||
XE_UI_VULKAN_FEATURE_2(features_1_2, scalarBlockLayout);
|
||||
XE_UI_VULKAN_FEATURE_2(features_1_2, hostQueryReset);
|
||||
}
|
||||
} else {
|
||||
if (ext_1_2_KHR_sampler_mirror_clamp_to_edge) {
|
||||
XE_UI_VULKAN_FEATURE_IMPLIED(samplerMirrorClampToEdge)
|
||||
}
|
||||
if (ext_1_2_EXT_host_query_reset && with_gpu_emulation) {
|
||||
XE_UI_VULKAN_FEATURE_2(features_EXT_host_query_reset, hostQueryReset);
|
||||
}
|
||||
}
|
||||
device->extensions_.ext_1_2_EXT_host_query_reset =
|
||||
ext_1_2_EXT_host_query_reset;
|
||||
|
||||
if (properties.apiVersion >= VK_MAKE_API_VERSION(0, 1, 3, 0)) {
|
||||
if (with_gpu_emulation) {
|
||||
@@ -743,6 +757,9 @@ std::unique_ptr<VulkanDevice> VulkanDevice::CreateIfSupported(
|
||||
if (properties.apiVersion >= VK_MAKE_API_VERSION(0, 1, 1, 0)) {
|
||||
#include "xenia/ui/vulkan/functions/device_1_1_khr_bind_memory2.inc"
|
||||
#include "xenia/ui/vulkan/functions/device_1_1_khr_get_memory_requirements2.inc"
|
||||
}
|
||||
if (properties.apiVersion >= VK_MAKE_API_VERSION(0, 1, 2, 0)) {
|
||||
#include "xenia/ui/vulkan/functions/device_1_2_ext_host_query_reset.inc"
|
||||
}
|
||||
if (properties.apiVersion >= VK_MAKE_API_VERSION(0, 1, 3, 0)) {
|
||||
#include "xenia/ui/vulkan/functions/device_1_3_khr_maintenance4.inc"
|
||||
@@ -763,6 +780,11 @@ std::unique_ptr<VulkanDevice> VulkanDevice::CreateIfSupported(
|
||||
#include "xenia/ui/vulkan/functions/device_1_1_khr_bind_memory2.inc"
|
||||
}
|
||||
}
|
||||
if (properties.apiVersion < VK_MAKE_API_VERSION(0, 1, 2, 0)) {
|
||||
if (device->extensions_.ext_1_2_EXT_host_query_reset) {
|
||||
#include "xenia/ui/vulkan/functions/device_1_2_ext_host_query_reset.inc"
|
||||
}
|
||||
}
|
||||
if (properties.apiVersion < VK_MAKE_API_VERSION(0, 1, 3, 0)) {
|
||||
if (device->extensions_.ext_1_3_KHR_maintenance4) {
|
||||
#include "xenia/ui/vulkan/functions/device_1_3_khr_maintenance4.inc"
|
||||
|
||||
@@ -126,6 +126,10 @@ class VulkanDevice {
|
||||
|
||||
bool scalarBlockLayout = false;
|
||||
|
||||
// VK_EXT_host_query_reset (promoted to 1.2)
|
||||
|
||||
bool hostQueryReset = false;
|
||||
|
||||
// VK_KHR_portability_subset (#164)
|
||||
|
||||
bool constantAlphaColorBlendFactors = false;
|
||||
@@ -181,6 +185,7 @@ class VulkanDevice {
|
||||
bool ext_1_1_KHR_bind_memory2 = false; // #158
|
||||
bool ext_1_2_KHR_spirv_1_4 = false; // #237
|
||||
bool ext_EXT_memory_budget = false; // #238
|
||||
bool ext_1_2_EXT_host_query_reset = false; // promoted to 1.2
|
||||
// Has optional features not implied by this being true.
|
||||
bool ext_1_3_KHR_maintenance4 = false; // #414
|
||||
#if XE_PLATFORM_WIN32
|
||||
@@ -204,6 +209,8 @@ class VulkanDevice {
|
||||
#include "xenia/ui/vulkan/functions/device_1_1_khr_get_memory_requirements2.inc"
|
||||
// VK_KHR_bind_memory2 (#158, promoted to 1.1)
|
||||
#include "xenia/ui/vulkan/functions/device_1_1_khr_bind_memory2.inc"
|
||||
// VK_EXT_host_query_reset (promoted to 1.2)
|
||||
#include "xenia/ui/vulkan/functions/device_1_2_ext_host_query_reset.inc"
|
||||
// VK_KHR_maintenance4 (#414, promoted to 1.3)
|
||||
#include "xenia/ui/vulkan/functions/device_1_3_khr_maintenance4.inc"
|
||||
#undef XE_UI_VULKAN_FUNCTION_PROMOTED
|
||||
|
||||
Reference in New Issue
Block a user