[Vulkan] Optional functionality usage improvements

Functional changes:
- Enable only actually used features, as drivers may take more optimal
  paths when certain features are disabled.
- Support VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE.
- Fix the separateStencilMaskRef check doing the opposite.
- Support shaderRoundingModeRTEFloat32.
- Fix vkGetDeviceBufferMemoryRequirements pointer not passed to the Vulkan
  Memory Allocator.

Stylistic changes:
- Move all device extensions, properties and features to one structure,
  especially simplifying portability subset feature checks, and also making
  it easier to request new extension functionality in the future.
- Remove extension suffixes from usage of promoted extensions.
This commit is contained in:
Triang3l
2024-05-04 22:47:14 +03:00
parent f87c6afdeb
commit e9f7a8bd48
16 changed files with 1115 additions and 1027 deletions

View File

@@ -138,7 +138,8 @@ bool VulkanCommandProcessor::SetupContext() {
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device();
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
provider.device_info();
// The unconditional inclusion of the vertex shader stage also covers the case
// of manual index / factor buffer fetch (the system constants and the shared
@@ -147,12 +148,12 @@ bool VulkanCommandProcessor::SetupContext() {
guest_shader_pipeline_stages_ = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
guest_shader_vertex_stages_ = VK_SHADER_STAGE_VERTEX_BIT;
if (device_features.tessellationShader) {
if (device_info.tessellationShader) {
guest_shader_pipeline_stages_ |=
VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
guest_shader_vertex_stages_ |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
}
if (!device_features.vertexPipelineStoresAndAtomics) {
if (!device_info.vertexPipelineStoresAndAtomics) {
// For memory export from vertex shaders converted to compute shaders.
guest_shader_pipeline_stages_ |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
guest_shader_vertex_stages_ |= VK_SHADER_STAGE_COMPUTE_BIT;
@@ -160,14 +161,11 @@ bool VulkanCommandProcessor::SetupContext() {
// 16384 is bigger than any single uniform buffer that Xenia needs, but is the
// minimum maxUniformBufferRange, thus the safe minimum amount.
VkDeviceSize uniform_buffer_alignment = std::max(
provider.device_properties().limits.minUniformBufferOffsetAlignment,
VkDeviceSize(1));
uniform_buffer_pool_ = std::make_unique<ui::vulkan::VulkanUploadBufferPool>(
provider, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
xe::align(std::max(ui::GraphicsUploadBufferPool::kDefaultPageSize,
size_t(16384)),
size_t(uniform_buffer_alignment)));
size_t(device_info.minUniformBufferOffsetAlignment)));
// Descriptor set layouts that don't depend on the setup of other subsystems.
VkShaderStageFlags guest_shader_stages =
@@ -201,10 +199,9 @@ bool VulkanCommandProcessor::SetupContext() {
[SpirvShaderTranslator::kConstantBufferSystem]
.stageFlags =
guest_shader_stages |
(device_features.tessellationShader
? VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT
: 0) |
(device_features.geometryShader ? VK_SHADER_STAGE_GEOMETRY_BIT : 0);
(device_info.tessellationShader ? VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT
: 0) |
(device_info.geometryShader ? VK_SHADER_STAGE_GEOMETRY_BIT : 0);
descriptor_set_layout_bindings_constants
[SpirvShaderTranslator::kConstantBufferFloatVertex]
.stageFlags = guest_shader_vertex_stages_;
@@ -283,7 +280,7 @@ bool VulkanCommandProcessor::SetupContext() {
uint32_t shared_memory_binding_count_log2 =
SpirvShaderTranslator::GetSharedMemoryStorageBufferCountLog2(
provider.device_properties().limits.maxStorageBufferRange);
device_info.maxStorageBufferRange);
uint32_t shared_memory_binding_count = UINT32_C(1)
<< shared_memory_binding_count_log2;
@@ -487,14 +484,14 @@ bool VulkanCommandProcessor::SetupContext() {
&gamma_ramp_host_visible_buffer_memory_requirements);
uint32_t gamma_ramp_host_visible_buffer_memory_types =
gamma_ramp_host_visible_buffer_memory_requirements.memoryTypeBits &
(provider.memory_types_device_local() &
provider.memory_types_host_visible());
(device_info.memory_types_device_local &
device_info.memory_types_host_visible);
VkMemoryAllocateInfo gamma_ramp_host_visible_buffer_memory_allocate_info;
// Prefer a host-uncached (because it's write-only) memory type, but try a
// host-cached host-visible device-local one as well.
if (xe::bit_scan_forward(
gamma_ramp_host_visible_buffer_memory_types &
~provider.memory_types_host_cached(),
~device_info.memory_types_host_cached,
&(gamma_ramp_host_visible_buffer_memory_allocate_info
.memoryTypeIndex)) ||
xe::bit_scan_forward(
@@ -509,16 +506,16 @@ bool VulkanCommandProcessor::SetupContext() {
gamma_ramp_host_visible_buffer_memory_allocate_info.pNext = nullptr;
gamma_ramp_host_visible_buffer_memory_allocate_info.allocationSize =
gamma_ramp_host_visible_buffer_memory_requirements.size;
VkMemoryDedicatedAllocateInfoKHR
VkMemoryDedicatedAllocateInfo
gamma_ramp_host_visible_buffer_memory_dedicated_allocate_info;
if (provider.device_extensions().khr_dedicated_allocation) {
if (device_info.ext_1_1_VK_KHR_dedicated_allocation) {
gamma_ramp_host_visible_buffer_memory_allocate_info_last->pNext =
&gamma_ramp_host_visible_buffer_memory_dedicated_allocate_info;
gamma_ramp_host_visible_buffer_memory_allocate_info_last =
reinterpret_cast<VkMemoryAllocateInfo*>(
&gamma_ramp_host_visible_buffer_memory_dedicated_allocate_info);
gamma_ramp_host_visible_buffer_memory_dedicated_allocate_info.sType =
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
gamma_ramp_host_visible_buffer_memory_dedicated_allocate_info.pNext =
nullptr;
gamma_ramp_host_visible_buffer_memory_dedicated_allocate_info.image =
@@ -2419,10 +2416,8 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
current_guest_graphics_pipeline_layout_ = pipeline_layout;
}
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
const VkPhysicalDeviceLimits& device_limits =
provider.device_properties().limits;
const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
GetVulkanProvider().device_info();
bool host_render_targets_used = render_target_cache_->GetPath() ==
RenderTargetCache::Path::kHostRenderTargets;
@@ -2446,8 +2441,8 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// interlocks case completely - apply the viewport and the scissor offset
// directly to pixel address and to things like ps_param_gen.
draw_util::GetHostViewportInfo(
regs, 1, 1, false, device_limits.maxViewportDimensions[0],
device_limits.maxViewportDimensions[1], true, normalized_depth_control,
regs, 1, 1, false, device_info.maxViewportDimensions[0],
device_info.maxViewportDimensions[1], true, normalized_depth_control,
false, host_render_targets_used,
pixel_shader && pixel_shader->writes_depth(), viewport_info);
@@ -2461,7 +2456,7 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// indirectly in the vertex shader if full 32-bit indices are not supported by
// the host.
bool shader_32bit_index_dma =
!device_features.fullDrawIndexUint32 &&
!device_info.fullDrawIndexUint32 &&
primitive_processing_result.index_buffer_type ==
PrimitiveProcessor::ProcessedIndexBufferType::kGuestDMA &&
vgt_draw_initiator.index_size == xenos::IndexFormat::kInt32 &&
@@ -3315,21 +3310,16 @@ void VulkanCommandProcessor::UpdateDynamicState(
if (normalized_depth_control.stencil_enable) {
Register stencil_ref_mask_front_reg, stencil_ref_mask_back_reg;
if (primitive_polygonal && normalized_depth_control.backface_enable) {
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const VkPhysicalDevicePortabilitySubsetFeaturesKHR*
device_portability_subset_features =
provider.device_portability_subset_features();
if (!device_portability_subset_features ||
device_portability_subset_features->separateStencilMaskRef) {
if (GetVulkanProvider().device_info().separateStencilMaskRef) {
stencil_ref_mask_front_reg = XE_GPU_REG_RB_STENCILREFMASK;
stencil_ref_mask_back_reg = XE_GPU_REG_RB_STENCILREFMASK_BF;
} else {
// Choose the back face values only if drawing only back faces.
stencil_ref_mask_front_reg =
regs.Get<reg::PA_SU_SC_MODE_CNTL>().cull_front
? XE_GPU_REG_RB_STENCILREFMASK_BF
: XE_GPU_REG_RB_STENCILREFMASK;
stencil_ref_mask_back_reg = stencil_ref_mask_front_reg;
} else {
stencil_ref_mask_front_reg = XE_GPU_REG_RB_STENCILREFMASK;
stencil_ref_mask_back_reg = XE_GPU_REG_RB_STENCILREFMASK_BF;
}
} else {
stencil_ref_mask_front_reg = XE_GPU_REG_RB_STENCILREFMASK;
@@ -3681,12 +3671,7 @@ void VulkanCommandProcessor::UpdateSystemConstantValues(
}
// Texture host swizzle in the shader.
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const VkPhysicalDevicePortabilitySubsetFeaturesKHR*
device_portability_subset_features =
provider.device_portability_subset_features();
if (device_portability_subset_features &&
!device_portability_subset_features->imageViewFormatSwizzle) {
if (!GetVulkanProvider().device_info().imageViewFormatSwizzle) {
uint32_t textures_remaining = used_texture_mask;
uint32_t texture_index;
while (xe::bit_scan_forward(textures_remaining, &texture_index)) {
@@ -3968,8 +3953,8 @@ bool VulkanCommandProcessor::UpdateBindings(const VulkanShader* vertex_shader,
kAllConstantBuffersMask) {
current_graphics_descriptor_set_values_up_to_date_ &=
~(UINT32_C(1) << SpirvShaderTranslator::kDescriptorSetConstants);
size_t uniform_buffer_alignment = size_t(
provider.device_properties().limits.minUniformBufferOffsetAlignment);
size_t uniform_buffer_alignment =
size_t(provider.device_info().minUniformBufferOffsetAlignment);
// System constants.
if (!(current_constant_buffers_up_to_date_ &
(UINT32_C(1) << SpirvShaderTranslator::kConstantBufferSystem))) {
@@ -4348,8 +4333,7 @@ uint8_t* VulkanCommandProcessor::WriteTransientUniformBufferBinding(
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
uint8_t* mapping = uniform_buffer_pool_->Request(
frame_current_, size,
size_t(
provider.device_properties().limits.minUniformBufferOffsetAlignment),
size_t(provider.device_info().minUniformBufferOffsetAlignment),
descriptor_buffer_info_out.buffer, descriptor_buffer_info_out.offset);
if (!mapping) {
return nullptr;