[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

@ -37,56 +37,32 @@ SpirvShaderTranslator::Features::Features(bool all)
full_draw_index_uint32(all), full_draw_index_uint32(all),
image_view_format_swizzle(all), image_view_format_swizzle(all),
signed_zero_inf_nan_preserve_float32(all), signed_zero_inf_nan_preserve_float32(all),
denorm_flush_to_zero_float32(all) {} denorm_flush_to_zero_float32(all),
rounding_mode_rte_float32(all) {}
SpirvShaderTranslator::Features::Features( SpirvShaderTranslator::Features::Features(
const ui::vulkan::VulkanProvider& provider) const ui::vulkan::VulkanProvider::DeviceInfo& device_info)
: max_storage_buffer_range( : max_storage_buffer_range(device_info.maxStorageBufferRange),
provider.device_properties().limits.maxStorageBufferRange), clip_distance(device_info.shaderClipDistance),
clip_distance(provider.device_features().shaderClipDistance), cull_distance(device_info.shaderCullDistance),
cull_distance(provider.device_features().shaderCullDistance), demote_to_helper_invocation(device_info.shaderDemoteToHelperInvocation),
demote_to_helper_invocation(
provider.device_extensions().ext_shader_demote_to_helper_invocation &&
provider.device_shader_demote_to_helper_invocation_features()
.shaderDemoteToHelperInvocation),
fragment_shader_sample_interlock( fragment_shader_sample_interlock(
provider.device_extensions().ext_fragment_shader_interlock && device_info.fragmentShaderSampleInterlock),
provider.device_fragment_shader_interlock_features() full_draw_index_uint32(device_info.fullDrawIndexUint32),
.fragmentShaderSampleInterlock), image_view_format_swizzle(device_info.imageViewFormatSwizzle),
full_draw_index_uint32(provider.device_features().fullDrawIndexUint32) { signed_zero_inf_nan_preserve_float32(
uint32_t device_version = provider.device_properties().apiVersion; device_info.shaderSignedZeroInfNanPreserveFloat32),
const ui::vulkan::VulkanProvider::DeviceExtensions& device_extensions = denorm_flush_to_zero_float32(device_info.shaderDenormFlushToZeroFloat32),
provider.device_extensions(); rounding_mode_rte_float32(device_info.shaderRoundingModeRTEFloat32) {
if (device_version >= VK_MAKE_VERSION(1, 2, 0)) { if (device_info.apiVersion >= VK_MAKE_API_VERSION(0, 1, 2, 0)) {
spirv_version = spv::Spv_1_5; spirv_version = spv::Spv_1_5;
} else if (device_extensions.khr_spirv_1_4) { } else if (device_info.ext_1_2_VK_KHR_spirv_1_4) {
spirv_version = spv::Spv_1_4; spirv_version = spv::Spv_1_4;
} else if (device_version >= VK_MAKE_VERSION(1, 1, 0)) { } else if (device_info.apiVersion >= VK_MAKE_API_VERSION(0, 1, 1, 0)) {
spirv_version = spv::Spv_1_3; spirv_version = spv::Spv_1_3;
} else { } else {
spirv_version = spv::Spv_1_0; spirv_version = spv::Spv_1_0;
} }
const VkPhysicalDevicePortabilitySubsetFeaturesKHR*
device_portability_subset_features =
provider.device_portability_subset_features();
if (device_portability_subset_features) {
image_view_format_swizzle =
bool(device_portability_subset_features->imageViewFormatSwizzle);
} else {
image_view_format_swizzle = true;
}
if (spirv_version >= spv::Spv_1_4 ||
device_extensions.khr_shader_float_controls) {
const VkPhysicalDeviceFloatControlsPropertiesKHR&
float_controls_properties = provider.device_float_controls_properties();
signed_zero_inf_nan_preserve_float32 =
bool(float_controls_properties.shaderSignedZeroInfNanPreserveFloat32);
denorm_flush_to_zero_float32 =
bool(float_controls_properties.shaderDenormFlushToZeroFloat32);
} else {
signed_zero_inf_nan_preserve_float32 = false;
denorm_flush_to_zero_float32 = false;
}
} }
uint64_t SpirvShaderTranslator::GetDefaultVertexShaderModification( uint64_t SpirvShaderTranslator::GetDefaultVertexShaderModification(
@ -168,7 +144,8 @@ void SpirvShaderTranslator::StartTranslation() {
: spv::CapabilityShader); : spv::CapabilityShader);
if (features_.spirv_version < spv::Spv_1_4) { if (features_.spirv_version < spv::Spv_1_4) {
if (features_.signed_zero_inf_nan_preserve_float32 || if (features_.signed_zero_inf_nan_preserve_float32 ||
features_.denorm_flush_to_zero_float32) { features_.denorm_flush_to_zero_float32 ||
features_.rounding_mode_rte_float32) {
builder_->addExtension("SPV_KHR_float_controls"); builder_->addExtension("SPV_KHR_float_controls");
} }
} }
@ -724,6 +701,11 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
builder_->addExecutionMode(function_main_, builder_->addExecutionMode(function_main_,
spv::ExecutionModeSignedZeroInfNanPreserve, 32); spv::ExecutionModeSignedZeroInfNanPreserve, 32);
} }
if (features_.rounding_mode_rte_float32) {
builder_->addCapability(spv::CapabilityRoundingModeRTE);
builder_->addExecutionMode(function_main_,
spv::ExecutionModeRoundingModeRTE, 32);
}
spv::Instruction* entry_point = spv::Instruction* entry_point =
builder_->addEntryPoint(execution_model, function_main_, "main"); builder_->addEntryPoint(execution_model, function_main_, "main");
for (spv::Id interface_id : main_interface_) { for (spv::Id interface_id : main_interface_) {

View File

@ -320,7 +320,8 @@ class SpirvShaderTranslator : public ShaderTranslator {
static constexpr uint32_t kSpirvMagicToolId = 26; static constexpr uint32_t kSpirvMagicToolId = 26;
struct Features { struct Features {
explicit Features(const ui::vulkan::VulkanProvider& provider); explicit Features(
const ui::vulkan::VulkanProvider::DeviceInfo& device_info);
explicit Features(bool all = false); explicit Features(bool all = false);
unsigned int spirv_version; unsigned int spirv_version;
uint32_t max_storage_buffer_range; uint32_t max_storage_buffer_range;
@ -332,6 +333,7 @@ class SpirvShaderTranslator : public ShaderTranslator {
bool image_view_format_swizzle; bool image_view_format_swizzle;
bool signed_zero_inf_nan_preserve_float32; bool signed_zero_inf_nan_preserve_float32;
bool denorm_flush_to_zero_float32; bool denorm_flush_to_zero_float32;
bool rounding_mode_rte_float32;
}; };
SpirvShaderTranslator(const Features& features, SpirvShaderTranslator(const Features& features,

View File

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

View File

@ -59,7 +59,7 @@ bool VulkanPipelineCache::Initialize() {
RenderTargetCache::Path::kPixelShaderInterlock; RenderTargetCache::Path::kPixelShaderInterlock;
shader_translator_ = std::make_unique<SpirvShaderTranslator>( shader_translator_ = std::make_unique<SpirvShaderTranslator>(
SpirvShaderTranslator::Features(provider), SpirvShaderTranslator::Features(provider.device_info()),
render_target_cache_.msaa_2x_attachments_supported(), render_target_cache_.msaa_2x_attachments_supported(),
render_target_cache_.msaa_2x_no_attachments_supported(), render_target_cache_.msaa_2x_no_attachments_supported(),
edram_fragment_shader_interlock); edram_fragment_shader_interlock);
@ -471,13 +471,9 @@ void VulkanPipelineCache::WritePipelineRenderTargetDescription(
render_target_out.dst_alpha_blend_factor = render_target_out.dst_alpha_blend_factor =
kBlendFactorMap[uint32_t(blend_control.alpha_destblend)]; kBlendFactorMap[uint32_t(blend_control.alpha_destblend)];
render_target_out.alpha_blend_op = blend_control.alpha_comb_fcn; render_target_out.alpha_blend_op = blend_control.alpha_comb_fcn;
const ui::vulkan::VulkanProvider& provider = if (!command_processor_.GetVulkanProvider()
command_processor_.GetVulkanProvider(); .device_info()
const VkPhysicalDevicePortabilitySubsetFeaturesKHR* .constantAlphaColorBlendFactors) {
device_portability_subset_features =
provider.device_portability_subset_features();
if (device_portability_subset_features &&
!device_portability_subset_features->constantAlphaColorBlendFactors) {
if (blend_control.color_srcblend == xenos::BlendFactor::kConstantAlpha) { if (blend_control.color_srcblend == xenos::BlendFactor::kConstantAlpha) {
render_target_out.src_color_blend_factor = render_target_out.src_color_blend_factor =
PipelineBlendFactor::kConstantColor; PipelineBlendFactor::kConstantColor;
@ -516,12 +512,8 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
PipelineDescription& description_out) const { PipelineDescription& description_out) const {
description_out.Reset(); description_out.Reset();
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider().device_info();
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
const VkPhysicalDevicePortabilitySubsetFeaturesKHR*
device_portability_subset_features =
provider.device_portability_subset_features();
const RegisterFile& regs = register_file_; const RegisterFile& regs = register_file_;
auto pa_su_sc_mode_cntl = regs.Get<reg::PA_SU_SC_MODE_CNTL>(); auto pa_su_sc_mode_cntl = regs.Get<reg::PA_SU_SC_MODE_CNTL>();
@ -556,8 +548,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
break; break;
case xenos::PrimitiveType::kTriangleFan: case xenos::PrimitiveType::kTriangleFan:
// The check should be performed at primitive processing time. // The check should be performed at primitive processing time.
assert_true(!device_portability_subset_features || assert_true(device_info.triangleFans);
device_portability_subset_features->triangleFans);
primitive_topology = PipelinePrimitiveTopology::kTriangleFan; primitive_topology = PipelinePrimitiveTopology::kTriangleFan;
break; break;
case xenos::PrimitiveType::kTriangleStrip: case xenos::PrimitiveType::kTriangleStrip:
@ -581,8 +572,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
primitive_processing_result.host_primitive_reset_enabled; primitive_processing_result.host_primitive_reset_enabled;
description_out.depth_clamp_enable = description_out.depth_clamp_enable =
device_features.depthClamp && device_info.depthClamp && regs.Get<reg::PA_CL_CLIP_CNTL>().clip_disable;
regs.Get<reg::PA_CL_CLIP_CNTL>().clip_disable;
// TODO(Triang3l): Tessellation. // TODO(Triang3l): Tessellation.
bool primitive_polygonal = draw_util::IsPrimitivePolygonal(regs); bool primitive_polygonal = draw_util::IsPrimitivePolygonal(regs);
@ -597,7 +587,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
bool cull_back = pa_su_sc_mode_cntl.cull_back; bool cull_back = pa_su_sc_mode_cntl.cull_back;
description_out.cull_front = cull_front; description_out.cull_front = cull_front;
description_out.cull_back = cull_back; description_out.cull_back = cull_back;
if (device_features.fillModeNonSolid) { if (device_info.fillModeNonSolid) {
xenos::PolygonType polygon_type = xenos::PolygonType::kTriangles; xenos::PolygonType polygon_type = xenos::PolygonType::kTriangles;
if (!cull_front) { if (!cull_front) {
polygon_type = polygon_type =
@ -614,9 +604,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
case xenos::PolygonType::kPoints: case xenos::PolygonType::kPoints:
// When points are not supported, use lines instead, preserving // When points are not supported, use lines instead, preserving
// debug-like purpose. // debug-like purpose.
description_out.polygon_mode = description_out.polygon_mode = device_info.pointPolygons
(!device_portability_subset_features ||
device_portability_subset_features->pointPolygons)
? PipelinePolygonMode::kPoint ? PipelinePolygonMode::kPoint
: PipelinePolygonMode::kLine; : PipelinePolygonMode::kLine;
break; break;
@ -683,7 +671,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
// Color blending and write masks (filled only for the attachments present // Color blending and write masks (filled only for the attachments present
// in the render pass object). // in the render pass object).
uint32_t render_pass_color_rts = render_pass_key.depth_and_color_used >> 1; uint32_t render_pass_color_rts = render_pass_key.depth_and_color_used >> 1;
if (device_features.independentBlend) { if (device_info.independentBlend) {
uint32_t render_pass_color_rts_remaining = render_pass_color_rts; uint32_t render_pass_color_rts_remaining = render_pass_color_rts;
uint32_t color_rt_index; uint32_t color_rt_index;
while (xe::bit_scan_forward(render_pass_color_rts_remaining, while (xe::bit_scan_forward(render_pass_color_rts_remaining,
@ -779,63 +767,35 @@ bool VulkanPipelineCache::ArePipelineRequirementsMet(
return false; return false;
} }
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider().device_info();
const VkPhysicalDevicePortabilitySubsetFeaturesKHR* if (!device_info.geometryShader &&
device_portability_subset_features =
provider.device_portability_subset_features();
if (device_portability_subset_features) {
if (description.primitive_topology ==
PipelinePrimitiveTopology::kTriangleFan &&
!device_portability_subset_features->triangleFans) {
return false;
}
if (description.polygon_mode == PipelinePolygonMode::kPoint &&
!device_portability_subset_features->pointPolygons) {
return false;
}
if (!device_portability_subset_features->constantAlphaColorBlendFactors) {
uint32_t color_rts_remaining =
description.render_pass_key.depth_and_color_used >> 1;
uint32_t color_rt_index;
while (xe::bit_scan_forward(color_rts_remaining, &color_rt_index)) {
color_rts_remaining &= ~(uint32_t(1) << color_rt_index);
const PipelineRenderTarget& color_rt =
description.render_targets[color_rt_index];
if (color_rt.src_color_blend_factor ==
PipelineBlendFactor::kConstantAlpha ||
color_rt.src_color_blend_factor ==
PipelineBlendFactor::kOneMinusConstantAlpha ||
color_rt.dst_color_blend_factor ==
PipelineBlendFactor::kConstantAlpha ||
color_rt.dst_color_blend_factor ==
PipelineBlendFactor::kOneMinusConstantAlpha) {
return false;
}
}
}
}
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
if (!device_features.geometryShader &&
description.geometry_shader != PipelineGeometryShader::kNone) { description.geometry_shader != PipelineGeometryShader::kNone) {
return false; return false;
} }
if (!device_features.depthClamp && description.depth_clamp_enable) { if (!device_info.triangleFans &&
description.primitive_topology ==
PipelinePrimitiveTopology::kTriangleFan) {
return false; return false;
} }
if (!device_features.fillModeNonSolid && if (!device_info.depthClamp && description.depth_clamp_enable) {
return false;
}
if (!device_info.pointPolygons &&
description.polygon_mode == PipelinePolygonMode::kPoint) {
return false;
}
if (!device_info.fillModeNonSolid &&
description.polygon_mode != PipelinePolygonMode::kFill) { description.polygon_mode != PipelinePolygonMode::kFill) {
return false; return false;
} }
if (!device_features.independentBlend) { if (!device_info.independentBlend) {
uint32_t color_rts_remaining = uint32_t color_rts_remaining =
description.render_pass_key.depth_and_color_used >> 1; description.render_pass_key.depth_and_color_used >> 1;
uint32_t first_color_rt_index; uint32_t first_color_rt_index;
@ -865,6 +825,27 @@ bool VulkanPipelineCache::ArePipelineRequirementsMet(
} }
} }
if (!device_info.constantAlphaColorBlendFactors) {
uint32_t color_rts_remaining =
description.render_pass_key.depth_and_color_used >> 1;
uint32_t color_rt_index;
while (xe::bit_scan_forward(color_rts_remaining, &color_rt_index)) {
color_rts_remaining &= ~(uint32_t(1) << color_rt_index);
const PipelineRenderTarget& color_rt =
description.render_targets[color_rt_index];
if (color_rt.src_color_blend_factor ==
PipelineBlendFactor::kConstantAlpha ||
color_rt.src_color_blend_factor ==
PipelineBlendFactor::kOneMinusConstantAlpha ||
color_rt.dst_color_blend_factor ==
PipelineBlendFactor::kConstantAlpha ||
color_rt.dst_color_blend_factor ==
PipelineBlendFactor::kOneMinusConstantAlpha) {
return false;
}
}
}
return true; return true;
} }
@ -1913,7 +1894,8 @@ bool VulkanPipelineCache::EnsurePipelineCreated(
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider& provider =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider();
const VkPhysicalDeviceFeatures& device_features = provider.device_features(); const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
provider.device_info();
bool edram_fragment_shader_interlock = bool edram_fragment_shader_interlock =
render_target_cache_.GetPath() == render_target_cache_.GetPath() ==
@ -2222,7 +2204,7 @@ bool VulkanPipelineCache::EnsurePipelineCreated(
} }
color_blend_attachment.colorWriteMask = color_blend_attachment.colorWriteMask =
VkColorComponentFlags(color_rt.color_write_mask); VkColorComponentFlags(color_rt.color_write_mask);
if (!device_features.independentBlend) { if (!device_info.independentBlend) {
// For non-independent blend, the pAttachments element for the first // For non-independent blend, the pAttachments element for the first
// actually used color will be replicated into all. // actually used color will be replicated into all.
break; break;
@ -2231,7 +2213,7 @@ bool VulkanPipelineCache::EnsurePipelineCreated(
} }
color_blend_state.attachmentCount = 32 - xe::lzcnt(color_rts_used); color_blend_state.attachmentCount = 32 - xe::lzcnt(color_rts_used);
color_blend_state.pAttachments = color_blend_attachments; color_blend_state.pAttachments = color_blend_attachments;
if (color_rts_used && !device_features.independentBlend) { if (color_rts_used && !device_info.independentBlend) {
// "If the independent blending feature is not enabled, all elements of // "If the independent blending feature is not enabled, all elements of
// pAttachments must be identical." // pAttachments must be identical."
uint32_t first_color_rt_index; uint32_t first_color_rt_index;

View File

@ -27,18 +27,12 @@ namespace vulkan {
VulkanPrimitiveProcessor::~VulkanPrimitiveProcessor() { Shutdown(true); } VulkanPrimitiveProcessor::~VulkanPrimitiveProcessor() { Shutdown(true); }
bool VulkanPrimitiveProcessor::Initialize() { bool VulkanPrimitiveProcessor::Initialize() {
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider().device_info();
const VkPhysicalDeviceFeatures& device_features = provider.device_features(); if (!InitializeCommon(device_info.fullDrawIndexUint32,
const VkPhysicalDevicePortabilitySubsetFeaturesKHR* device_info.triangleFans, false,
device_portability_subset_features = device_info.geometryShader, device_info.geometryShader,
provider.device_portability_subset_features(); device_info.geometryShader)) {
if (!InitializeCommon(device_features.fullDrawIndexUint32,
!device_portability_subset_features ||
device_portability_subset_features->triangleFans,
false, device_features.geometryShader,
device_features.geometryShader,
device_features.geometryShader)) {
Shutdown(); Shutdown();
return false; return false;
} }

View File

@ -213,8 +213,8 @@ bool VulkanRenderTargetCache::Initialize(uint32_t shared_memory_binding_count) {
VkPhysicalDevice physical_device = provider.physical_device(); VkPhysicalDevice physical_device = provider.physical_device();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn(); const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device(); VkDevice device = provider.device();
const VkPhysicalDeviceLimits& device_limits = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
provider.device_properties().limits; provider.device_info();
if (cvars::render_target_path_vulkan == "fsi") { if (cvars::render_target_path_vulkan == "fsi") {
path_ = Path::kPixelShaderInterlock; path_ = Path::kPixelShaderInterlock;
@ -226,11 +226,6 @@ bool VulkanRenderTargetCache::Initialize(uint32_t shared_memory_binding_count) {
// OpenGL ES 3.1. Thus, it's fine to demand a wide range of other optional // OpenGL ES 3.1. Thus, it's fine to demand a wide range of other optional
// features for the fragment shader interlock backend to work. // features for the fragment shader interlock backend to work.
if (path_ == Path::kPixelShaderInterlock) { if (path_ == Path::kPixelShaderInterlock) {
const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT&
device_fragment_shader_interlock_features =
provider.device_fragment_shader_interlock_features();
const VkPhysicalDeviceFeatures& device_features =
provider.device_features();
// Interlocking between fragments with common sample coverage is enough, but // Interlocking between fragments with common sample coverage is enough, but
// interlocking more is acceptable too (fragmentShaderShadingRateInterlock // interlocking more is acceptable too (fragmentShaderShadingRateInterlock
// would be okay too, but it's unlikely that an implementation would // would be okay too, but it's unlikely that an implementation would
@ -248,16 +243,13 @@ bool VulkanRenderTargetCache::Initialize(uint32_t shared_memory_binding_count) {
// between, for instance, the ability to vfetch and memexport in fragment // between, for instance, the ability to vfetch and memexport in fragment
// shaders, and the usage of fragment shader interlock, prefer the former // shaders, and the usage of fragment shader interlock, prefer the former
// for simplicity. // for simplicity.
if (!provider.device_extensions().ext_fragment_shader_interlock || if (!(device_info.fragmentShaderSampleInterlock ||
!(device_fragment_shader_interlock_features device_info.fragmentShaderPixelInterlock) ||
.fragmentShaderSampleInterlock || !device_info.fragmentStoresAndAtomics ||
device_fragment_shader_interlock_features !device_info.sampleRateShading ||
.fragmentShaderPixelInterlock) || !device_info.standardSampleLocations ||
!device_features.fragmentStoresAndAtomics ||
!device_features.sampleRateShading ||
!device_limits.standardSampleLocations ||
shared_memory_binding_count >= shared_memory_binding_count >=
device_limits.maxDescriptorSetStorageBuffers) { device_info.maxPerStageDescriptorStorageBuffers) {
path_ = Path::kHostRenderTargets; path_ = Path::kHostRenderTargets;
} }
} }
@ -279,18 +271,17 @@ bool VulkanRenderTargetCache::Initialize(uint32_t shared_memory_binding_count) {
if (cvars::native_2x_msaa) { if (cvars::native_2x_msaa) {
// Multisampled integer sampled images are optional in Vulkan and in Xenia. // Multisampled integer sampled images are optional in Vulkan and in Xenia.
msaa_2x_attachments_supported_ = msaa_2x_attachments_supported_ =
(device_limits.framebufferColorSampleCounts & (device_info.framebufferColorSampleCounts &
device_limits.framebufferDepthSampleCounts & device_info.framebufferDepthSampleCounts &
device_limits.framebufferStencilSampleCounts & device_info.framebufferStencilSampleCounts &
device_limits.sampledImageColorSampleCounts & device_info.sampledImageColorSampleCounts &
device_limits.sampledImageDepthSampleCounts & device_info.sampledImageDepthSampleCounts &
device_limits.sampledImageStencilSampleCounts & device_info.sampledImageStencilSampleCounts & VK_SAMPLE_COUNT_2_BIT) &&
VK_SAMPLE_COUNT_2_BIT) && (device_info.sampledImageIntegerSampleCounts &
(device_limits.sampledImageIntegerSampleCounts &
(VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT)) != (VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT)) !=
VK_SAMPLE_COUNT_4_BIT; VK_SAMPLE_COUNT_4_BIT;
msaa_2x_no_attachments_supported_ = msaa_2x_no_attachments_supported_ =
(device_limits.framebufferNoAttachmentsSampleCounts & (device_info.framebufferNoAttachmentsSampleCounts &
VK_SAMPLE_COUNT_2_BIT) != 0; VK_SAMPLE_COUNT_2_BIT) != 0;
} else { } else {
msaa_2x_attachments_supported_ = false; msaa_2x_attachments_supported_ = false;
@ -847,10 +838,10 @@ bool VulkanRenderTargetCache::Initialize(uint32_t shared_memory_binding_count) {
fsi_framebuffer_create_info.pAttachments = nullptr; fsi_framebuffer_create_info.pAttachments = nullptr;
fsi_framebuffer_create_info.width = std::min( fsi_framebuffer_create_info.width = std::min(
xenos::kTexture2DCubeMaxWidthHeight * draw_resolution_scale_x(), xenos::kTexture2DCubeMaxWidthHeight * draw_resolution_scale_x(),
device_limits.maxFramebufferWidth); device_info.maxFramebufferWidth);
fsi_framebuffer_create_info.height = std::min( fsi_framebuffer_create_info.height = std::min(
xenos::kTexture2DCubeMaxWidthHeight * draw_resolution_scale_y(), xenos::kTexture2DCubeMaxWidthHeight * draw_resolution_scale_y(),
device_limits.maxFramebufferHeight); device_info.maxFramebufferHeight);
fsi_framebuffer_create_info.layers = 1; fsi_framebuffer_create_info.layers = 1;
if (dfn.vkCreateFramebuffer(device, &fsi_framebuffer_create_info, nullptr, if (dfn.vkCreateFramebuffer(device, &fsi_framebuffer_create_info, nullptr,
&fsi_framebuffer_.framebuffer) != VK_SUCCESS) { &fsi_framebuffer_.framebuffer) != VK_SUCCESS) {
@ -1680,17 +1671,17 @@ VulkanRenderTargetCache::VulkanRenderTarget::~VulkanRenderTarget() {
} }
uint32_t VulkanRenderTargetCache::GetMaxRenderTargetWidth() const { uint32_t VulkanRenderTargetCache::GetMaxRenderTargetWidth() const {
const VkPhysicalDeviceLimits& device_limits = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
command_processor_.GetVulkanProvider().device_properties().limits; command_processor_.GetVulkanProvider().device_info();
return std::min(device_limits.maxFramebufferWidth, return std::min(device_info.maxFramebufferWidth,
device_limits.maxImageDimension2D); device_info.maxImageDimension2D);
} }
uint32_t VulkanRenderTargetCache::GetMaxRenderTargetHeight() const { uint32_t VulkanRenderTargetCache::GetMaxRenderTargetHeight() const {
const VkPhysicalDeviceLimits& device_limits = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
command_processor_.GetVulkanProvider().device_properties().limits; command_processor_.GetVulkanProvider().device_info();
return std::min(device_limits.maxFramebufferHeight, return std::min(device_info.maxFramebufferHeight,
device_limits.maxImageDimension2D); device_info.maxImageDimension2D);
} }
RenderTargetCache::RenderTarget* VulkanRenderTargetCache::CreateRenderTarget( RenderTargetCache::RenderTarget* VulkanRenderTargetCache::CreateRenderTarget(
@ -2084,8 +2075,8 @@ VulkanRenderTargetCache::GetHostRenderTargetsFramebuffer(
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn(); const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device(); VkDevice device = provider.device();
const VkPhysicalDeviceLimits& device_limits = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
provider.device_properties().limits; provider.device_info();
VkRenderPass render_pass = GetHostRenderTargetsRenderPass(render_pass_key); VkRenderPass render_pass = GetHostRenderTargetsRenderPass(render_pass_key);
if (render_pass == VK_NULL_HANDLE) { if (render_pass == VK_NULL_HANDLE) {
@ -2134,9 +2125,9 @@ VulkanRenderTargetCache::GetHostRenderTargetsFramebuffer(
// there's no limit imposed by the sizes of the attachments that have been // there's no limit imposed by the sizes of the attachments that have been
// created successfully. // created successfully.
host_extent.width = std::min(host_extent.width * draw_resolution_scale_x(), host_extent.width = std::min(host_extent.width * draw_resolution_scale_x(),
device_limits.maxFramebufferWidth); device_info.maxFramebufferWidth);
host_extent.height = std::min(host_extent.height * draw_resolution_scale_y(), host_extent.height = std::min(host_extent.height * draw_resolution_scale_y(),
device_limits.maxFramebufferHeight); device_info.maxFramebufferHeight);
framebuffer_create_info.width = host_extent.width; framebuffer_create_info.width = host_extent.width;
framebuffer_create_info.height = host_extent.height; framebuffer_create_info.height = host_extent.height;
framebuffer_create_info.layers = 1; framebuffer_create_info.layers = 1;
@ -2161,7 +2152,8 @@ VkShaderModule VulkanRenderTargetCache::GetTransferShader(
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider& provider =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider();
const VkPhysicalDeviceFeatures& device_features = provider.device_features(); const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
provider.device_info();
std::vector<spv::Id> id_vector_temp; std::vector<spv::Id> id_vector_temp;
std::vector<unsigned int> uint_vector_temp; std::vector<unsigned int> uint_vector_temp;
@ -2249,7 +2241,7 @@ VkShaderModule VulkanRenderTargetCache::GetTransferShader(
// Outputs. // Outputs.
bool shader_uses_stencil_reference_output = bool shader_uses_stencil_reference_output =
mode.output == TransferOutput::kDepth && mode.output == TransferOutput::kDepth &&
provider.device_extensions().ext_shader_stencil_export; provider.device_info().ext_VK_EXT_shader_stencil_export;
bool dest_color_is_uint = false; bool dest_color_is_uint = false;
uint32_t dest_color_component_count = 0; uint32_t dest_color_component_count = 0;
spv::Id type_fragment_data_component = spv::NoResult; spv::Id type_fragment_data_component = spv::NoResult;
@ -2485,7 +2477,7 @@ VkShaderModule VulkanRenderTargetCache::GetTransferShader(
spv::Id input_sample_id = spv::NoResult; spv::Id input_sample_id = spv::NoResult;
spv::Id spec_const_sample_id = spv::NoResult; spv::Id spec_const_sample_id = spv::NoResult;
if (key.dest_msaa_samples != xenos::MsaaSamples::k1X) { if (key.dest_msaa_samples != xenos::MsaaSamples::k1X) {
if (device_features.sampleRateShading) { if (device_info.sampleRateShading) {
// One draw for all samples. // One draw for all samples.
builder.addCapability(spv::CapabilitySampleRateShading); builder.addCapability(spv::CapabilitySampleRateShading);
input_sample_id = builder.createVariable( input_sample_id = builder.createVariable(
@ -2579,7 +2571,7 @@ VkShaderModule VulkanRenderTargetCache::GetTransferShader(
// Load the destination sample index. // Load the destination sample index.
spv::Id dest_sample_id = spv::NoResult; spv::Id dest_sample_id = spv::NoResult;
if (key.dest_msaa_samples != xenos::MsaaSamples::k1X) { if (key.dest_msaa_samples != xenos::MsaaSamples::k1X) {
if (device_features.sampleRateShading) { if (device_info.sampleRateShading) {
assert_true(input_sample_id != spv::NoResult); assert_true(input_sample_id != spv::NoResult);
dest_sample_id = builder.createUnaryOp( dest_sample_id = builder.createUnaryOp(
spv::OpBitcast, type_uint, spv::OpBitcast, type_uint,
@ -4242,12 +4234,13 @@ VkPipeline const* VulkanRenderTargetCache::GetTransferPipelines(
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn(); const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device(); VkDevice device = provider.device();
const VkPhysicalDeviceFeatures& device_features = provider.device_features(); const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
provider.device_info();
uint32_t dest_sample_count = uint32_t(1) uint32_t dest_sample_count = uint32_t(1)
<< uint32_t(key.shader_key.dest_msaa_samples); << uint32_t(key.shader_key.dest_msaa_samples);
bool dest_is_masked_sample = bool dest_is_masked_sample =
dest_sample_count > 1 && !device_features.sampleRateShading; dest_sample_count > 1 && !device_info.sampleRateShading;
VkPipelineShaderStageCreateInfo shader_stages[2]; VkPipelineShaderStageCreateInfo shader_stages[2];
shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
@ -4339,7 +4332,7 @@ VkPipeline const* VulkanRenderTargetCache::GetTransferPipelines(
? VK_SAMPLE_COUNT_4_BIT ? VK_SAMPLE_COUNT_4_BIT
: VkSampleCountFlagBits(dest_sample_count); : VkSampleCountFlagBits(dest_sample_count);
if (dest_sample_count > 1) { if (dest_sample_count > 1) {
if (device_features.sampleRateShading) { if (device_info.sampleRateShading) {
multisample_state.sampleShadingEnable = VK_TRUE; multisample_state.sampleShadingEnable = VK_TRUE;
multisample_state.minSampleShading = 1.0f; multisample_state.minSampleShading = 1.0f;
if (dest_sample_count == 2 && !msaa_2x_attachments_supported_) { if (dest_sample_count == 2 && !msaa_2x_attachments_supported_) {
@ -4370,7 +4363,7 @@ VkPipeline const* VulkanRenderTargetCache::GetTransferPipelines(
: VK_COMPARE_OP_ALWAYS; : VK_COMPARE_OP_ALWAYS;
} }
if ((mode.output == TransferOutput::kDepth && if ((mode.output == TransferOutput::kDepth &&
provider.device_extensions().ext_shader_stencil_export) || provider.device_info().ext_VK_EXT_shader_stencil_export) ||
mode.output == TransferOutput::kStencilBit) { mode.output == TransferOutput::kStencilBit) {
depth_stencil_state.stencilTestEnable = VK_TRUE; depth_stencil_state.stencilTestEnable = VK_TRUE;
depth_stencil_state.front.failOp = VK_STENCIL_OP_KEEP; depth_stencil_state.front.failOp = VK_STENCIL_OP_KEEP;
@ -4398,7 +4391,7 @@ VkPipeline const* VulkanRenderTargetCache::GetTransferPipelines(
32 - xe::lzcnt(key.render_pass_key.depth_and_color_used >> 1); 32 - xe::lzcnt(key.render_pass_key.depth_and_color_used >> 1);
color_blend_state.pAttachments = color_blend_attachments; color_blend_state.pAttachments = color_blend_attachments;
if (mode.output == TransferOutput::kColor) { if (mode.output == TransferOutput::kColor) {
if (device_features.independentBlend) { if (device_info.independentBlend) {
// State the intention more explicitly. // State the intention more explicitly.
color_blend_attachments[key.shader_key.dest_color_rt_index] color_blend_attachments[key.shader_key.dest_color_rt_index]
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
@ -4505,13 +4498,8 @@ void VulkanRenderTargetCache::PerformTransfersAndResolveClears(
const Transfer::Rectangle* resolve_clear_rectangle) { const Transfer::Rectangle* resolve_clear_rectangle) {
assert_true(GetPath() == Path::kHostRenderTargets); assert_true(GetPath() == Path::kHostRenderTargets);
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider().device_info();
const VkPhysicalDeviceLimits& device_limits =
provider.device_properties().limits;
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
bool shader_stencil_export =
provider.device_extensions().ext_shader_stencil_export;
uint64_t current_submission = command_processor_.GetCurrentSubmission(); uint64_t current_submission = command_processor_.GetCurrentSubmission();
DeferredCommandBuffer& command_buffer = DeferredCommandBuffer& command_buffer =
command_processor_.deferred_command_buffer(); command_processor_.deferred_command_buffer();
@ -4826,7 +4814,7 @@ void VulkanRenderTargetCache::PerformTransfersAndResolveClears(
// Gather shader keys and sort to reduce pipeline state and binding // Gather shader keys and sort to reduce pipeline state and binding
// switches. Also gather stencil rectangles to clear if needed. // switches. Also gather stencil rectangles to clear if needed.
bool need_stencil_bit_draws = bool need_stencil_bit_draws =
dest_rt_key.is_depth && !shader_stencil_export; dest_rt_key.is_depth && !device_info.ext_VK_EXT_shader_stencil_export;
current_transfer_invocations_.clear(); current_transfer_invocations_.clear();
current_transfer_invocations_.reserve( current_transfer_invocations_.reserve(
current_transfers.size() << uint32_t(need_stencil_bit_draws)); current_transfers.size() << uint32_t(need_stencil_bit_draws));
@ -5018,10 +5006,10 @@ void VulkanRenderTargetCache::PerformTransfersAndResolveClears(
transfer_viewport.y = 0.0f; transfer_viewport.y = 0.0f;
transfer_viewport.width = transfer_viewport.width =
float(std::min(xe::next_pow2(transfer_framebuffer->host_extent.width), float(std::min(xe::next_pow2(transfer_framebuffer->host_extent.width),
device_limits.maxViewportDimensions[0])); device_info.maxViewportDimensions[0]));
transfer_viewport.height = float( transfer_viewport.height = float(
std::min(xe::next_pow2(transfer_framebuffer->host_extent.height), std::min(xe::next_pow2(transfer_framebuffer->host_extent.height),
device_limits.maxViewportDimensions[1])); device_info.maxViewportDimensions[1]));
transfer_viewport.minDepth = 0.0f; transfer_viewport.minDepth = 0.0f;
transfer_viewport.maxDepth = 1.0f; transfer_viewport.maxDepth = 1.0f;
command_processor_.SetViewport(transfer_viewport); command_processor_.SetViewport(transfer_viewport);
@ -5072,7 +5060,7 @@ void VulkanRenderTargetCache::PerformTransfersAndResolveClears(
kTransferPipelineLayoutInfos[size_t( kTransferPipelineLayoutInfos[size_t(
transfer_pipeline_layout_index)]; transfer_pipeline_layout_index)];
uint32_t transfer_sample_pipeline_count = uint32_t transfer_sample_pipeline_count =
device_features.sampleRateShading device_info.sampleRateShading
? 1 ? 1
: uint32_t(1) << uint32_t(dest_rt_key.msaa_samples); : uint32_t(1) << uint32_t(dest_rt_key.msaa_samples);
bool transfer_is_stencil_bit = bool transfer_is_stencil_bit =

View File

@ -51,7 +51,8 @@ bool VulkanSharedMemory::Initialize() {
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn(); const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device(); VkDevice device = provider.device();
const VkPhysicalDeviceFeatures& device_features = provider.device_features(); const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
provider.device_info();
const VkBufferCreateFlags sparse_flags = const VkBufferCreateFlags sparse_flags =
VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_BINDING_BIT |
@ -69,16 +70,14 @@ bool VulkanSharedMemory::Initialize() {
buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
buffer_create_info.queueFamilyIndexCount = 0; buffer_create_info.queueFamilyIndexCount = 0;
buffer_create_info.pQueueFamilyIndices = nullptr; buffer_create_info.pQueueFamilyIndices = nullptr;
if (cvars::vulkan_sparse_shared_memory && if (cvars::vulkan_sparse_shared_memory && device_info.sparseResidencyBuffer) {
provider.IsSparseBindingSupported() &&
device_features.sparseResidencyBuffer) {
if (dfn.vkCreateBuffer(device, &buffer_create_info, nullptr, &buffer_) == if (dfn.vkCreateBuffer(device, &buffer_create_info, nullptr, &buffer_) ==
VK_SUCCESS) { VK_SUCCESS) {
VkMemoryRequirements buffer_memory_requirements; VkMemoryRequirements buffer_memory_requirements;
dfn.vkGetBufferMemoryRequirements(device, buffer_, dfn.vkGetBufferMemoryRequirements(device, buffer_,
&buffer_memory_requirements); &buffer_memory_requirements);
if (xe::bit_scan_forward(buffer_memory_requirements.memoryTypeBits & if (xe::bit_scan_forward(buffer_memory_requirements.memoryTypeBits &
provider.memory_types_device_local(), device_info.memory_types_device_local,
&buffer_memory_type_)) { &buffer_memory_type_)) {
uint32_t allocation_size_log2; uint32_t allocation_size_log2;
xe::bit_scan_forward( xe::bit_scan_forward(
@ -131,7 +130,7 @@ bool VulkanSharedMemory::Initialize() {
dfn.vkGetBufferMemoryRequirements(device, buffer_, dfn.vkGetBufferMemoryRequirements(device, buffer_,
&buffer_memory_requirements); &buffer_memory_requirements);
if (!xe::bit_scan_forward(buffer_memory_requirements.memoryTypeBits & if (!xe::bit_scan_forward(buffer_memory_requirements.memoryTypeBits &
provider.memory_types_device_local(), device_info.memory_types_device_local,
&buffer_memory_type_)) { &buffer_memory_type_)) {
XELOGE( XELOGE(
"Shared memory: Failed to get a device-local Vulkan memory type for " "Shared memory: Failed to get a device-local Vulkan memory type for "
@ -147,15 +146,15 @@ bool VulkanSharedMemory::Initialize() {
buffer_memory_allocate_info.allocationSize = buffer_memory_allocate_info.allocationSize =
buffer_memory_requirements.size; buffer_memory_requirements.size;
buffer_memory_allocate_info.memoryTypeIndex = buffer_memory_type_; buffer_memory_allocate_info.memoryTypeIndex = buffer_memory_type_;
VkMemoryDedicatedAllocateInfoKHR buffer_memory_dedicated_allocate_info; VkMemoryDedicatedAllocateInfo buffer_memory_dedicated_allocate_info;
if (provider.device_extensions().khr_dedicated_allocation) { if (provider.device_info().ext_1_1_VK_KHR_dedicated_allocation) {
buffer_memory_allocate_info_last->pNext = buffer_memory_allocate_info_last->pNext =
&buffer_memory_dedicated_allocate_info; &buffer_memory_dedicated_allocate_info;
buffer_memory_allocate_info_last = buffer_memory_allocate_info_last =
reinterpret_cast<VkMemoryAllocateInfo*>( reinterpret_cast<VkMemoryAllocateInfo*>(
&buffer_memory_dedicated_allocate_info); &buffer_memory_dedicated_allocate_info);
buffer_memory_dedicated_allocate_info.sType = buffer_memory_dedicated_allocate_info.sType =
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
buffer_memory_dedicated_allocate_info.pNext = nullptr; buffer_memory_dedicated_allocate_info.pNext = nullptr;
buffer_memory_dedicated_allocate_info.image = VK_NULL_HANDLE; buffer_memory_dedicated_allocate_info.image = VK_NULL_HANDLE;
buffer_memory_dedicated_allocate_info.buffer = buffer_; buffer_memory_dedicated_allocate_info.buffer = buffer_;
@ -366,7 +365,7 @@ bool VulkanSharedMemory::AllocateSparseHostGpuMemoryRange(
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
if (provider.device_features().tessellationShader) { if (provider.device_info().tessellationShader) {
bind_wait_stage_mask |= bind_wait_stage_mask |=
VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
} }

View File

@ -144,17 +144,17 @@ const VulkanTextureCache::HostFormatPair
xenos::XE_GPU_TEXTURE_SWIZZLE_RGGG, xenos::XE_GPU_TEXTURE_SWIZZLE_RGGG,
true}, true},
// k_Cr_Y1_Cb_Y0_REP // k_Cr_Y1_Cb_Y0_REP
// VK_FORMAT_G8B8G8R8_422_UNORM_KHR (added in // VK_FORMAT_G8B8G8R8_422_UNORM (added in
// VK_KHR_sampler_ycbcr_conversion and promoted to Vulkan 1.1) is // VK_KHR_sampler_ycbcr_conversion and promoted to Vulkan 1.1) is
// optional. // optional.
{{kLoadShaderIndex32bpb, VK_FORMAT_G8B8G8R8_422_UNORM_KHR, true}, {{kLoadShaderIndex32bpb, VK_FORMAT_G8B8G8R8_422_UNORM, true},
{kLoadShaderIndexGBGR8ToRGB8, VK_FORMAT_R8G8B8A8_SNORM}, {kLoadShaderIndexGBGR8ToRGB8, VK_FORMAT_R8G8B8A8_SNORM},
xenos::XE_GPU_TEXTURE_SWIZZLE_RGBB}, xenos::XE_GPU_TEXTURE_SWIZZLE_RGBB},
// k_Y1_Cr_Y0_Cb_REP // k_Y1_Cr_Y0_Cb_REP
// VK_FORMAT_B8G8R8G8_422_UNORM_KHR (added in // VK_FORMAT_B8G8R8G8_422_UNORM (added in
// VK_KHR_sampler_ycbcr_conversion and promoted to Vulkan 1.1) is // VK_KHR_sampler_ycbcr_conversion and promoted to Vulkan 1.1) is
// optional. // optional.
{{kLoadShaderIndex32bpb, VK_FORMAT_B8G8R8G8_422_UNORM_KHR, true}, {{kLoadShaderIndex32bpb, VK_FORMAT_B8G8R8G8_422_UNORM, true},
{kLoadShaderIndexBGRG8ToRGB8, VK_FORMAT_R8G8B8A8_SNORM}, {kLoadShaderIndexBGRG8ToRGB8, VK_FORMAT_R8G8B8A8_SNORM},
xenos::XE_GPU_TEXTURE_SWIZZLE_RGBB}, xenos::XE_GPU_TEXTURE_SWIZZLE_RGBB},
// k_16_16_EDRAM // k_16_16_EDRAM
@ -778,15 +778,15 @@ VkSampler VulkanTextureCache::UseSampler(SamplerParameters parameters,
// kClampToEdge // kClampToEdge
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
// kMirrorClampToEdge // kMirrorClampToEdge
VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE,
// kClampToHalfway // kClampToHalfway
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
// kMirrorClampToHalfway // kMirrorClampToHalfway
VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE,
// kClampToBorder // kClampToBorder
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
// kMirrorClampToBorder // kMirrorClampToBorder
VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE,
}; };
sampler_create_info.addressModeU = sampler_create_info.addressModeU =
kAddressModeMap[uint32_t(parameters.clamp_x)]; kAddressModeMap[uint32_t(parameters.clamp_x)];
@ -938,19 +938,17 @@ uint32_t VulkanTextureCache::GetHostFormatSwizzle(TextureKey key) const {
uint32_t VulkanTextureCache::GetMaxHostTextureWidthHeight( uint32_t VulkanTextureCache::GetMaxHostTextureWidthHeight(
xenos::DataDimension dimension) const { xenos::DataDimension dimension) const {
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider().device_info();
const VkPhysicalDeviceLimits& device_limits =
provider.device_properties().limits;
switch (dimension) { switch (dimension) {
case xenos::DataDimension::k1D: case xenos::DataDimension::k1D:
case xenos::DataDimension::k2DOrStacked: case xenos::DataDimension::k2DOrStacked:
// 1D and 2D are emulated as 2D arrays. // 1D and 2D are emulated as 2D arrays.
return device_limits.maxImageDimension2D; return device_info.maxImageDimension2D;
case xenos::DataDimension::k3D: case xenos::DataDimension::k3D:
return device_limits.maxImageDimension3D; return device_info.maxImageDimension3D;
case xenos::DataDimension::kCube: case xenos::DataDimension::kCube:
return device_limits.maxImageDimensionCube; return device_info.maxImageDimensionCube;
default: default:
assert_unhandled_case(dimension); assert_unhandled_case(dimension);
return 0; return 0;
@ -959,17 +957,15 @@ uint32_t VulkanTextureCache::GetMaxHostTextureWidthHeight(
uint32_t VulkanTextureCache::GetMaxHostTextureDepthOrArraySize( uint32_t VulkanTextureCache::GetMaxHostTextureDepthOrArraySize(
xenos::DataDimension dimension) const { xenos::DataDimension dimension) const {
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider().device_info();
const VkPhysicalDeviceLimits& device_limits =
provider.device_properties().limits;
switch (dimension) { switch (dimension) {
case xenos::DataDimension::k1D: case xenos::DataDimension::k1D:
case xenos::DataDimension::k2DOrStacked: case xenos::DataDimension::k2DOrStacked:
// 1D and 2D are emulated as 2D arrays. // 1D and 2D are emulated as 2D arrays.
return device_limits.maxImageArrayLayers; return device_info.maxImageArrayLayers;
case xenos::DataDimension::k3D: case xenos::DataDimension::k3D:
return device_limits.maxImageDimension3D; return device_info.maxImageDimension3D;
case xenos::DataDimension::kCube: case xenos::DataDimension::kCube:
// Not requesting the imageCubeArray feature, and the Xenos doesn't // Not requesting the imageCubeArray feature, and the Xenos doesn't
// support cube map arrays. // support cube map arrays.
@ -1049,14 +1045,14 @@ std::unique_ptr<TextureCache::Texture> VulkanTextureCache::CreateTexture(
image_create_info.queueFamilyIndexCount = 0; image_create_info.queueFamilyIndexCount = 0;
image_create_info.pQueueFamilyIndices = nullptr; image_create_info.pQueueFamilyIndices = nullptr;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageFormatListCreateInfoKHR image_format_list_create_info; VkImageFormatListCreateInfo image_format_list_create_info;
if (formats[1] != VK_FORMAT_UNDEFINED && if (formats[1] != VK_FORMAT_UNDEFINED &&
provider.device_extensions().khr_image_format_list) { provider.device_info().ext_1_2_VK_KHR_image_format_list) {
image_create_info_last->pNext = &image_format_list_create_info; image_create_info_last->pNext = &image_format_list_create_info;
image_create_info_last = image_create_info_last =
reinterpret_cast<VkImageCreateInfo*>(&image_format_list_create_info); reinterpret_cast<VkImageCreateInfo*>(&image_format_list_create_info);
image_format_list_create_info.sType = image_format_list_create_info.sType =
VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR; VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO;
image_format_list_create_info.pNext = nullptr; image_format_list_create_info.pNext = nullptr;
image_format_list_create_info.viewFormatCount = 2; image_format_list_create_info.viewFormatCount = 2;
image_format_list_create_info.pViewFormats = formats; image_format_list_create_info.pViewFormats = formats;
@ -1635,11 +1631,7 @@ VkImageView VulkanTextureCache::VulkanTexture::GetView(bool is_signed,
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider& provider =
vulkan_texture_cache.command_processor_.GetVulkanProvider(); vulkan_texture_cache.command_processor_.GetVulkanProvider();
const VkPhysicalDevicePortabilitySubsetFeaturesKHR* if (!provider.device_info().imageViewFormatSwizzle) {
device_portability_subset_features =
provider.device_portability_subset_features();
if (device_portability_subset_features &&
!device_portability_subset_features->imageViewFormatSwizzle) {
host_swizzle = xenos::XE_GPU_TEXTURE_SWIZZLE_RGBA; host_swizzle = xenos::XE_GPU_TEXTURE_SWIZZLE_RGBA;
} }
view_key.host_swizzle = host_swizzle; view_key.host_swizzle = host_swizzle;
@ -1716,9 +1708,8 @@ bool VulkanTextureCache::Initialize() {
VkPhysicalDevice physical_device = provider.physical_device(); VkPhysicalDevice physical_device = provider.physical_device();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn(); const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device(); VkDevice device = provider.device();
const VkPhysicalDevicePortabilitySubsetFeaturesKHR* const ui::vulkan::VulkanProvider::DeviceInfo& device_info =
device_portability_subset_features = provider.device_info();
provider.device_portability_subset_features();
// Vulkan Memory Allocator. // Vulkan Memory Allocator.
@ -2476,15 +2467,15 @@ bool VulkanTextureCache::Initialize() {
null_image_memory_requirements_2d_array_cube_.size; null_image_memory_requirements_2d_array_cube_.size;
null_image_memory_allocate_info.memoryTypeIndex = null_image_memory_allocate_info.memoryTypeIndex =
null_image_memory_type_2d_array_cube_; null_image_memory_type_2d_array_cube_;
VkMemoryDedicatedAllocateInfoKHR null_image_memory_dedicated_allocate_info; VkMemoryDedicatedAllocateInfo null_image_memory_dedicated_allocate_info;
if (provider.device_extensions().khr_dedicated_allocation) { if (device_info.ext_1_1_VK_KHR_dedicated_allocation) {
null_image_memory_allocate_info_last->pNext = null_image_memory_allocate_info_last->pNext =
&null_image_memory_dedicated_allocate_info; &null_image_memory_dedicated_allocate_info;
null_image_memory_allocate_info_last = null_image_memory_allocate_info_last =
reinterpret_cast<VkMemoryAllocateInfo*>( reinterpret_cast<VkMemoryAllocateInfo*>(
&null_image_memory_dedicated_allocate_info); &null_image_memory_dedicated_allocate_info);
null_image_memory_dedicated_allocate_info.sType = null_image_memory_dedicated_allocate_info.sType =
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
null_image_memory_dedicated_allocate_info.pNext = nullptr; null_image_memory_dedicated_allocate_info.pNext = nullptr;
null_image_memory_dedicated_allocate_info.image = null_image_memory_dedicated_allocate_info.image =
null_image_2d_array_cube_; null_image_2d_array_cube_;
@ -2538,9 +2529,7 @@ bool VulkanTextureCache::Initialize() {
// constant components instead of the real texels. The image will be cleared // constant components instead of the real texels. The image will be cleared
// to (0, 0, 0, 0) anyway. // to (0, 0, 0, 0) anyway.
VkComponentSwizzle null_image_view_swizzle = VkComponentSwizzle null_image_view_swizzle =
(!device_portability_subset_features || device_info.imageViewFormatSwizzle ? VK_COMPONENT_SWIZZLE_ZERO
device_portability_subset_features->imageViewFormatSwizzle)
? VK_COMPONENT_SWIZZLE_ZERO
: VK_COMPONENT_SWIZZLE_IDENTITY; : VK_COMPONENT_SWIZZLE_IDENTITY;
null_image_view_create_info.components.r = null_image_view_swizzle; null_image_view_create_info.components.r = null_image_view_swizzle;
null_image_view_create_info.components.g = null_image_view_swizzle; null_image_view_create_info.components.g = null_image_view_swizzle;
@ -2574,10 +2563,6 @@ bool VulkanTextureCache::Initialize() {
// Samplers. // Samplers.
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
const VkPhysicalDeviceLimits& device_limits =
provider.device_properties().limits;
// Some MoltenVK devices have a maximum of 2048, 1024, or even 96 samplers, // Some MoltenVK devices have a maximum of 2048, 1024, or even 96 samplers,
// below Vulkan's minimum requirement of 4000. // below Vulkan's minimum requirement of 4000.
// Assuming that the current VulkanTextureCache is the only one on this // Assuming that the current VulkanTextureCache is the only one on this
@ -2585,15 +2570,14 @@ bool VulkanTextureCache::Initialize() {
// allocation slots exclusively. // allocation slots exclusively.
// Also leaving a few slots for use by things like overlay applications. // Also leaving a few slots for use by things like overlay applications.
sampler_max_count_ = sampler_max_count_ =
device_limits.maxSamplerAllocationCount - device_info.maxSamplerAllocationCount -
uint32_t(ui::vulkan::VulkanProvider::HostSampler::kCount) - 16; uint32_t(ui::vulkan::VulkanProvider::HostSampler::kCount) - 16;
if (device_features.samplerAnisotropy) { if (device_info.samplerAnisotropy) {
max_anisotropy_ = xenos::AnisoFilter( max_anisotropy_ = xenos::AnisoFilter(
uint32_t(xenos::AnisoFilter::kMax_1_1) + uint32_t(xenos::AnisoFilter::kMax_1_1) +
(31 - (31 - xe::lzcnt(uint32_t(std::min(
xe::lzcnt(uint32_t(std::min( 16.0f, std::max(1.0f, device_info.maxSamplerAnisotropy))))));
16.0f, std::max(1.0f, device_limits.maxSamplerAnisotropy))))));
} else { } else {
max_anisotropy_ = xenos::AnisoFilter::kDisabled; max_anisotropy_ = xenos::AnisoFilter::kDisabled;
} }
@ -2656,10 +2640,12 @@ xenos::ClampMode VulkanTextureCache::NormalizeClampMode(
if (clamp_mode == xenos::ClampMode::kMirrorClampToEdge || if (clamp_mode == xenos::ClampMode::kMirrorClampToEdge ||
clamp_mode == xenos::ClampMode::kMirrorClampToHalfway || clamp_mode == xenos::ClampMode::kMirrorClampToHalfway ||
clamp_mode == xenos::ClampMode::kMirrorClampToBorder) { clamp_mode == xenos::ClampMode::kMirrorClampToBorder) {
// TODO(Triang3l): VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR if // No equivalents for anything other than kMirrorClampToEdge in Vulkan.
// VK_KHR_sampler_mirror_clamp_to_edge (or Vulkan 1.2) and the return command_processor_.GetVulkanProvider()
// samplerMirrorClampToEdge feature are supported. .device_info()
return xenos::ClampMode::kMirroredRepeat; .samplerMirrorClampToEdge
? xenos::ClampMode::kMirrorClampToEdge
: xenos::ClampMode::kMirroredRepeat;
} }
return clamp_mode; return clamp_mode;
} }

View File

@ -866,9 +866,6 @@ bool VulkanImmediateDrawer::CreateTextureResource(
size_t& pending_upload_index_out) { size_t& pending_upload_index_out) {
const VulkanProvider::DeviceFunctions& dfn = provider_.dfn(); const VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device(); VkDevice device = provider_.device();
const VkPhysicalDevicePortabilitySubsetFeaturesKHR*
device_portability_subset_features =
provider_.device_portability_subset_features();
// Create the image and the descriptor. // Create the image and the descriptor.
@ -913,8 +910,7 @@ bool VulkanImmediateDrawer::CreateTextureResource(
// data == nullptr is a special case for (1, 1, 1, 1), though the image will // data == nullptr is a special case for (1, 1, 1, 1), though the image will
// be cleared to (1, 1, 1, 1) anyway, just a micro-optimization. // be cleared to (1, 1, 1, 1) anyway, just a micro-optimization.
VkComponentSwizzle swizzle = VkComponentSwizzle swizzle =
(data || (device_portability_subset_features && (data || !provider_.device_info().imageViewFormatSwizzle)
!device_portability_subset_features->imageViewFormatSwizzle))
? VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_IDENTITY
: VK_COMPONENT_SWIZZLE_ONE; : VK_COMPONENT_SWIZZLE_ONE;
image_view_create_info.components.r = swizzle; image_view_create_info.components.r = swizzle;

View File

@ -27,8 +27,7 @@ VmaAllocator CreateVmaAllocator(const VulkanProvider& provider,
const VulkanProvider::DeviceFunctions& dfn = provider.dfn(); const VulkanProvider::DeviceFunctions& dfn = provider.dfn();
const VulkanProvider::InstanceExtensions& instance_extensions = const VulkanProvider::InstanceExtensions& instance_extensions =
provider.instance_extensions(); provider.instance_extensions();
const VulkanProvider::DeviceExtensions& device_extensions = const VulkanProvider::DeviceInfo& device_info = provider.device_info();
provider.device_extensions();
VmaVulkanFunctions vma_vulkan_functions = {}; VmaVulkanFunctions vma_vulkan_functions = {};
VmaAllocatorCreateInfo allocator_create_info = {}; VmaAllocatorCreateInfo allocator_create_info = {};
@ -58,31 +57,33 @@ VmaAllocator CreateVmaAllocator(const VulkanProvider& provider,
vma_vulkan_functions.vkCreateImage = dfn.vkCreateImage; vma_vulkan_functions.vkCreateImage = dfn.vkCreateImage;
vma_vulkan_functions.vkDestroyImage = dfn.vkDestroyImage; vma_vulkan_functions.vkDestroyImage = dfn.vkDestroyImage;
vma_vulkan_functions.vkCmdCopyBuffer = dfn.vkCmdCopyBuffer; vma_vulkan_functions.vkCmdCopyBuffer = dfn.vkCmdCopyBuffer;
if (device_extensions.khr_get_memory_requirements2) { if (device_info.ext_1_1_VK_KHR_get_memory_requirements2) {
vma_vulkan_functions.vkGetBufferMemoryRequirements2KHR = vma_vulkan_functions.vkGetBufferMemoryRequirements2KHR =
dfn.vkGetBufferMemoryRequirements2KHR; dfn.vkGetBufferMemoryRequirements2;
vma_vulkan_functions.vkGetImageMemoryRequirements2KHR = vma_vulkan_functions.vkGetImageMemoryRequirements2KHR =
dfn.vkGetImageMemoryRequirements2KHR; dfn.vkGetImageMemoryRequirements2;
if (device_extensions.khr_dedicated_allocation) { if (device_info.ext_1_1_VK_KHR_dedicated_allocation) {
allocator_create_info.flags |= allocator_create_info.flags |=
VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
} }
} }
if (device_extensions.khr_bind_memory2) { if (device_info.ext_1_1_VK_KHR_bind_memory2) {
vma_vulkan_functions.vkBindBufferMemory2KHR = dfn.vkBindBufferMemory2KHR; vma_vulkan_functions.vkBindBufferMemory2KHR = dfn.vkBindBufferMemory2;
vma_vulkan_functions.vkBindImageMemory2KHR = dfn.vkBindImageMemory2KHR; vma_vulkan_functions.vkBindImageMemory2KHR = dfn.vkBindImageMemory2;
allocator_create_info.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT; allocator_create_info.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
} }
if (instance_extensions.khr_get_physical_device_properties2) { if (instance_extensions.khr_get_physical_device_properties2) {
vma_vulkan_functions.vkGetPhysicalDeviceMemoryProperties2KHR = vma_vulkan_functions.vkGetPhysicalDeviceMemoryProperties2KHR =
ifn.vkGetPhysicalDeviceMemoryProperties2KHR; ifn.vkGetPhysicalDeviceMemoryProperties2;
if (device_extensions.ext_memory_budget) { if (device_info.ext_VK_EXT_memory_budget) {
allocator_create_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; allocator_create_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
} }
} }
if (device_extensions.khr_maintenance4) { if (device_info.ext_1_3_VK_KHR_maintenance4) {
vma_vulkan_functions.vkGetDeviceBufferMemoryRequirements =
dfn.vkGetDeviceBufferMemoryRequirements;
vma_vulkan_functions.vkGetDeviceImageMemoryRequirements = vma_vulkan_functions.vkGetDeviceImageMemoryRequirements =
dfn.vkGetDeviceImageMemoryRequirementsKHR; dfn.vkGetDeviceImageMemoryRequirements;
} }
if (externally_synchronized) { if (externally_synchronized) {
@ -93,8 +94,7 @@ VmaAllocator CreateVmaAllocator(const VulkanProvider& provider,
allocator_create_info.device = provider.device(); allocator_create_info.device = provider.device();
allocator_create_info.pVulkanFunctions = &vma_vulkan_functions; allocator_create_info.pVulkanFunctions = &vma_vulkan_functions;
allocator_create_info.instance = provider.instance(); allocator_create_info.instance = provider.instance();
allocator_create_info.vulkanApiVersion = allocator_create_info.vulkanApiVersion = device_info.apiVersion;
provider.device_properties().apiVersion;
VmaAllocator allocator; VmaAllocator allocator;
if (vmaCreateAllocator(&allocator_create_info, &allocator) != VK_SUCCESS) { if (vmaCreateAllocator(&allocator_create_info, &allocator) != VK_SUCCESS) {
XELOGE("Failed to create a Vulkan Memory Allocator instance"); XELOGE("Failed to create a Vulkan Memory Allocator instance");

View File

@ -208,7 +208,7 @@ VulkanPresenter::~VulkanPresenter() {
} }
Surface::TypeFlags VulkanPresenter::GetSupportedSurfaceTypes() const { Surface::TypeFlags VulkanPresenter::GetSupportedSurfaceTypes() const {
if (!provider_.device_extensions().khr_swapchain) { if (!provider_.device_info().ext_VK_KHR_swapchain) {
return 0; return 0;
} }
return GetSurfaceTypesSupportedByInstance(provider_.instance_extensions()); return GetSurfaceTypesSupportedByInstance(provider_.instance_extensions());

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,160 @@ namespace vulkan {
class VulkanProvider : public GraphicsProvider { class VulkanProvider : public GraphicsProvider {
public: public:
struct DeviceInfo {
// "ext_1_X"-prefixed extension fields are set to true not only if the
// extension itself is actually exposed, but also if it was promoted to the
// device's API version. Therefore, merely the field being set to true
// doesn't imply that all the required features in the extension are
// supported - actual properties and features must be checked rather than
// the extension itself where they matter.
// Vulkan 1.0.
uint32_t memory_types_device_local;
uint32_t memory_types_host_visible;
uint32_t memory_types_host_coherent;
uint32_t memory_types_host_cached;
uint32_t apiVersion;
uint32_t maxImageDimension2D;
uint32_t maxImageDimension3D;
uint32_t maxImageDimensionCube;
uint32_t maxImageArrayLayers;
uint32_t maxStorageBufferRange;
uint32_t maxSamplerAllocationCount;
uint32_t maxPerStageDescriptorSamplers;
uint32_t maxPerStageDescriptorStorageBuffers;
uint32_t maxPerStageDescriptorSampledImages;
uint32_t maxPerStageResources;
uint32_t maxVertexOutputComponents;
uint32_t maxTessellationEvaluationOutputComponents;
uint32_t maxGeometryInputComponents;
uint32_t maxGeometryOutputComponents;
uint32_t maxGeometryTotalOutputComponents;
uint32_t maxFragmentInputComponents;
uint32_t maxFragmentCombinedOutputResources;
float maxSamplerAnisotropy;
uint32_t maxViewportDimensions[2];
float viewportBoundsRange[2];
VkDeviceSize minUniformBufferOffsetAlignment;
VkDeviceSize minStorageBufferOffsetAlignment;
uint32_t maxFramebufferWidth;
uint32_t maxFramebufferHeight;
VkSampleCountFlags framebufferColorSampleCounts;
VkSampleCountFlags framebufferDepthSampleCounts;
VkSampleCountFlags framebufferStencilSampleCounts;
VkSampleCountFlags framebufferNoAttachmentsSampleCounts;
VkSampleCountFlags sampledImageColorSampleCounts;
VkSampleCountFlags sampledImageIntegerSampleCounts;
VkSampleCountFlags sampledImageDepthSampleCounts;
VkSampleCountFlags sampledImageStencilSampleCounts;
VkSampleCountFlags standardSampleLocations;
VkDeviceSize optimalBufferCopyOffsetAlignment;
VkDeviceSize optimalBufferCopyRowPitchAlignment;
VkDeviceSize nonCoherentAtomSize;
bool fullDrawIndexUint32;
bool independentBlend;
bool geometryShader;
bool tessellationShader;
bool sampleRateShading;
bool depthClamp;
bool fillModeNonSolid;
bool samplerAnisotropy;
bool vertexPipelineStoresAndAtomics;
bool fragmentStoresAndAtomics;
bool shaderClipDistance;
bool shaderCullDistance;
bool sparseBinding;
bool sparseResidencyBuffer;
// VK_KHR_swapchain (#2).
bool ext_VK_KHR_swapchain;
// VK_KHR_sampler_mirror_clamp_to_edge (#15, Vulkan 1.2).
bool ext_1_2_VK_KHR_sampler_mirror_clamp_to_edge;
bool samplerMirrorClampToEdge;
// VK_KHR_dedicated_allocation (#128, Vulkan 1.1).
bool ext_1_1_VK_KHR_dedicated_allocation;
// VK_EXT_shader_stencil_export (#141).
bool ext_VK_EXT_shader_stencil_export;
// VK_KHR_get_memory_requirements2 (#147, Vulkan 1.1).
bool ext_1_1_VK_KHR_get_memory_requirements2;
// VK_KHR_image_format_list (#148, Vulkan 1.2).
bool ext_1_2_VK_KHR_image_format_list;
// VK_KHR_sampler_ycbcr_conversion (#157, Vulkan 1.1).
bool ext_1_1_VK_KHR_sampler_ycbcr_conversion;
// VK_KHR_bind_memory2 (#158, Vulkan 1.1).
bool ext_1_1_VK_KHR_bind_memory2;
// VK_KHR_portability_subset (#164).
bool ext_VK_KHR_portability_subset;
bool constantAlphaColorBlendFactors;
bool imageViewFormatReinterpretation;
bool imageViewFormatSwizzle;
bool pointPolygons;
bool separateStencilMaskRef;
bool shaderSampleRateInterpolationFunctions;
bool triangleFans;
// VK_KHR_shader_float_controls (#198, Vulkan 1.2).
bool ext_1_2_VK_KHR_shader_float_controls;
bool shaderSignedZeroInfNanPreserveFloat32;
bool shaderDenormFlushToZeroFloat32;
bool shaderRoundingModeRTEFloat32;
// VK_KHR_spirv_1_4 (#237, Vulkan 1.2).
bool ext_1_2_VK_KHR_spirv_1_4;
// VK_EXT_memory_budget (#238).
bool ext_VK_EXT_memory_budget;
// VK_EXT_fragment_shader_interlock (#252).
bool ext_VK_EXT_fragment_shader_interlock;
bool fragmentShaderSampleInterlock;
bool fragmentShaderPixelInterlock;
// VK_EXT_shader_demote_to_helper_invocation (#277, Vulkan 1.3).
bool ext_1_3_VK_EXT_shader_demote_to_helper_invocation;
bool shaderDemoteToHelperInvocation;
// VK_KHR_maintenance4 (#414, Vulkan 1.3).
bool ext_1_3_VK_KHR_maintenance4;
// VK_EXT_non_seamless_cube_map (#423).
bool ext_VK_EXT_non_seamless_cube_map;
bool nonSeamlessCubeMap;
};
~VulkanProvider(); ~VulkanProvider();
static std::unique_ptr<VulkanProvider> Create(bool is_surface_required); static std::unique_ptr<VulkanProvider> Create(bool is_surface_required);
@ -106,7 +260,7 @@ class VulkanProvider : public GraphicsProvider {
struct InstanceFunctions { struct InstanceFunctions {
#define XE_UI_VULKAN_FUNCTION(name) PFN_##name name; #define XE_UI_VULKAN_FUNCTION(name) PFN_##name name;
#define XE_UI_VULKAN_FUNCTION_PROMOTED(extension_name, core_name) \ #define XE_UI_VULKAN_FUNCTION_PROMOTED(extension_name, core_name) \
PFN_##extension_name extension_name; PFN_##core_name core_name;
#include "xenia/ui/vulkan/functions/instance_1_0.inc" #include "xenia/ui/vulkan/functions/instance_1_0.inc"
#include "xenia/ui/vulkan/functions/instance_ext_debug_utils.inc" #include "xenia/ui/vulkan/functions/instance_ext_debug_utils.inc"
#include "xenia/ui/vulkan/functions/instance_khr_get_physical_device_properties2.inc" #include "xenia/ui/vulkan/functions/instance_khr_get_physical_device_properties2.inc"
@ -124,61 +278,9 @@ class VulkanProvider : public GraphicsProvider {
const InstanceFunctions& ifn() const { return ifn_; } const InstanceFunctions& ifn() const { return ifn_; }
VkPhysicalDevice physical_device() const { return physical_device_; } VkPhysicalDevice physical_device() const { return physical_device_; }
const VkPhysicalDeviceProperties& device_properties() const {
return device_properties_; const DeviceInfo& device_info() const { return device_info_; }
}
const VkPhysicalDeviceFeatures& device_features() const {
return device_features_;
}
struct DeviceExtensions {
bool ext_fragment_shader_interlock;
bool ext_memory_budget;
// Core since 1.3.0.
bool ext_shader_demote_to_helper_invocation;
bool ext_shader_stencil_export;
// Core since 1.1.0.
bool khr_bind_memory2;
// Core since 1.1.0.
bool khr_dedicated_allocation;
// Core since 1.1.0.
bool khr_get_memory_requirements2;
// Core since 1.2.0.
bool khr_image_format_list;
// Core since 1.3.0.
bool khr_maintenance4;
// Requires the VK_KHR_get_physical_device_properties2 instance extension.
bool khr_portability_subset;
// Core since 1.1.0.
bool khr_sampler_ycbcr_conversion;
// Core since 1.2.0.
bool khr_shader_float_controls;
// Core since 1.2.0.
bool khr_spirv_1_4;
bool khr_swapchain;
};
const DeviceExtensions& device_extensions() const {
return device_extensions_;
}
// Returns nullptr if the device is fully compliant with Vulkan 1.0.
const VkPhysicalDevicePortabilitySubsetFeaturesKHR*
device_portability_subset_features() const {
if (!device_extensions_.khr_portability_subset) {
return nullptr;
}
return &device_portability_subset_features_;
}
uint32_t memory_types_device_local() const {
return memory_types_device_local_;
}
uint32_t memory_types_host_visible() const {
return memory_types_host_visible_;
}
uint32_t memory_types_host_coherent() const {
return memory_types_host_coherent_;
}
uint32_t memory_types_host_cached() const {
return memory_types_host_cached_;
}
struct QueueFamily { struct QueueFamily {
uint32_t queue_first_index = 0; uint32_t queue_first_index = 0;
uint32_t queue_count = 0; uint32_t queue_count = 0;
@ -196,18 +298,6 @@ class VulkanProvider : public GraphicsProvider {
uint32_t queue_family_sparse_binding() const { uint32_t queue_family_sparse_binding() const {
return queue_family_sparse_binding_; return queue_family_sparse_binding_;
} }
const VkPhysicalDeviceFloatControlsPropertiesKHR&
device_float_controls_properties() const {
return device_float_controls_properties_;
}
const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT&
device_fragment_shader_interlock_features() const {
return device_fragment_shader_interlock_features_;
}
const VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT&
device_shader_demote_to_helper_invocation_features() const {
return device_shader_demote_to_helper_invocation_features_;
}
struct Queue { struct Queue {
VkQueue queue = VK_NULL_HANDLE; VkQueue queue = VK_NULL_HANDLE;
@ -235,7 +325,7 @@ class VulkanProvider : public GraphicsProvider {
struct DeviceFunctions { struct DeviceFunctions {
#define XE_UI_VULKAN_FUNCTION(name) PFN_##name name; #define XE_UI_VULKAN_FUNCTION(name) PFN_##name name;
#define XE_UI_VULKAN_FUNCTION_PROMOTED(extension_name, core_name) \ #define XE_UI_VULKAN_FUNCTION_PROMOTED(extension_name, core_name) \
PFN_##extension_name extension_name; PFN_##core_name core_name;
#include "xenia/ui/vulkan/functions/device_1_0.inc" #include "xenia/ui/vulkan/functions/device_1_0.inc"
#include "xenia/ui/vulkan/functions/device_khr_bind_memory2.inc" #include "xenia/ui/vulkan/functions/device_khr_bind_memory2.inc"
#include "xenia/ui/vulkan/functions/device_khr_get_memory_requirements2.inc" #include "xenia/ui/vulkan/functions/device_khr_get_memory_requirements2.inc"
@ -261,10 +351,6 @@ class VulkanProvider : public GraphicsProvider {
ifn_.vkSetDebugUtilsObjectNameEXT(device_, &name_info); ifn_.vkSetDebugUtilsObjectNameEXT(device_, &name_info);
} }
bool IsSparseBindingSupported() const {
return queue_family_sparse_binding_ != UINT32_MAX;
}
// Samplers that may be useful for host needs. Only these samplers should be // Samplers that may be useful for host needs. Only these samplers should be
// used in host, non-emulation contexts, because the total number of samplers // used in host, non-emulation contexts, because the total number of samplers
// is heavily limited (4000) on Nvidia GPUs - the rest of samplers are // is heavily limited (4000) on Nvidia GPUs - the rest of samplers are
@ -298,6 +384,12 @@ class VulkanProvider : public GraphicsProvider {
const VkDebugUtilsMessengerCallbackDataEXT* callback_data, const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
void* user_data); void* user_data);
// For the current `physical_device_`, sets up the members obtained from the
// physical device info, and tries to create a device and get the needed
// queues.
// The call is successful if `device_` is not VK_NULL_HANDLE as a result.
void TryCreateDevice();
bool is_surface_required_; bool is_surface_required_;
RenderdocApi renderdoc_api_; RenderdocApi renderdoc_api_;
@ -313,30 +405,21 @@ class VulkanProvider : public GraphicsProvider {
InstanceExtensions instance_extensions_; InstanceExtensions instance_extensions_;
VkInstance instance_ = VK_NULL_HANDLE; VkInstance instance_ = VK_NULL_HANDLE;
InstanceFunctions ifn_; InstanceFunctions ifn_;
VkDebugUtilsMessengerEXT debug_messenger_ = VK_NULL_HANDLE; VkDebugUtilsMessengerEXT debug_messenger_ = VK_NULL_HANDLE;
bool debug_names_used_ = false; bool debug_names_used_ = false;
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; VkPhysicalDevice physical_device_ = VK_NULL_HANDLE;
VkPhysicalDeviceProperties device_properties_;
VkPhysicalDeviceFeatures device_features_; DeviceInfo device_info_ = {};
DeviceExtensions device_extensions_;
VkPhysicalDevicePortabilitySubsetFeaturesKHR
device_portability_subset_features_;
uint32_t memory_types_device_local_;
uint32_t memory_types_host_visible_;
uint32_t memory_types_host_coherent_;
uint32_t memory_types_host_cached_;
std::vector<QueueFamily> queue_families_; std::vector<QueueFamily> queue_families_;
uint32_t queue_family_graphics_compute_; uint32_t queue_family_graphics_compute_;
uint32_t queue_family_sparse_binding_; uint32_t queue_family_sparse_binding_;
VkPhysicalDeviceFloatControlsPropertiesKHR device_float_controls_properties_;
VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT
device_fragment_shader_interlock_features_;
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT
device_shader_demote_to_helper_invocation_features_;
VkDevice device_ = VK_NULL_HANDLE; VkDevice device_ = VK_NULL_HANDLE;
DeviceFunctions dfn_ = {}; DeviceFunctions dfn_ = {};
// Queues contain a mutex, can't use std::vector. // Queues contain a mutex, can't use std::vector.
std::unique_ptr<Queue[]> queues_; std::unique_ptr<Queue[]> queues_;

View File

@ -138,13 +138,13 @@ VulkanUploadBufferPool::CreatePageImplementation() {
memory_allocate_info.pNext = nullptr; memory_allocate_info.pNext = nullptr;
memory_allocate_info.allocationSize = allocation_size_; memory_allocate_info.allocationSize = allocation_size_;
memory_allocate_info.memoryTypeIndex = memory_type_; memory_allocate_info.memoryTypeIndex = memory_type_;
VkMemoryDedicatedAllocateInfoKHR memory_dedicated_allocate_info; VkMemoryDedicatedAllocateInfo memory_dedicated_allocate_info;
if (provider_.device_extensions().khr_dedicated_allocation) { if (provider_.device_info().ext_1_1_VK_KHR_dedicated_allocation) {
memory_allocate_info_last->pNext = &memory_dedicated_allocate_info; memory_allocate_info_last->pNext = &memory_dedicated_allocate_info;
memory_allocate_info_last = reinterpret_cast<VkMemoryAllocateInfo*>( memory_allocate_info_last = reinterpret_cast<VkMemoryAllocateInfo*>(
&memory_dedicated_allocate_info); &memory_dedicated_allocate_info);
memory_dedicated_allocate_info.sType = memory_dedicated_allocate_info.sType =
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
memory_dedicated_allocate_info.pNext = nullptr; memory_dedicated_allocate_info.pNext = nullptr;
memory_dedicated_allocate_info.image = VK_NULL_HANDLE; memory_dedicated_allocate_info.image = VK_NULL_HANDLE;
memory_dedicated_allocate_info.buffer = buffer; memory_dedicated_allocate_info.buffer = buffer;

View File

@ -27,8 +27,8 @@ void FlushMappedMemoryRange(const VulkanProvider& provider,
assert_false(size != VK_WHOLE_SIZE && memory_size == VK_WHOLE_SIZE); assert_false(size != VK_WHOLE_SIZE && memory_size == VK_WHOLE_SIZE);
assert_true(memory_size == VK_WHOLE_SIZE || offset <= memory_size); assert_true(memory_size == VK_WHOLE_SIZE || offset <= memory_size);
assert_true(memory_size == VK_WHOLE_SIZE || size <= memory_size - offset); assert_true(memory_size == VK_WHOLE_SIZE || size <= memory_size - offset);
if (!size || if (!size || (provider.device_info().memory_types_host_coherent &
(provider.memory_types_host_coherent() & (uint32_t(1) << memory_type))) { (uint32_t(1) << memory_type))) {
return; return;
} }
VkMappedMemoryRange range; VkMappedMemoryRange range;
@ -38,7 +38,7 @@ void FlushMappedMemoryRange(const VulkanProvider& provider,
range.offset = offset; range.offset = offset;
range.size = size; range.size = size;
VkDeviceSize non_coherent_atom_size = VkDeviceSize non_coherent_atom_size =
provider.device_properties().limits.nonCoherentAtomSize; provider.device_info().nonCoherentAtomSize;
// On some Android implementations, nonCoherentAtomSize is 0, not 1. // On some Android implementations, nonCoherentAtomSize is 0, not 1.
if (non_coherent_atom_size > 1) { if (non_coherent_atom_size > 1) {
range.offset = offset / non_coherent_atom_size * non_coherent_atom_size; range.offset = offset / non_coherent_atom_size * non_coherent_atom_size;
@ -89,13 +89,13 @@ bool CreateDedicatedAllocationBuffer(
memory_allocate_info.pNext = nullptr; memory_allocate_info.pNext = nullptr;
memory_allocate_info.allocationSize = memory_requirements.size; memory_allocate_info.allocationSize = memory_requirements.size;
memory_allocate_info.memoryTypeIndex = memory_type; memory_allocate_info.memoryTypeIndex = memory_type;
VkMemoryDedicatedAllocateInfoKHR memory_dedicated_allocate_info; VkMemoryDedicatedAllocateInfo memory_dedicated_allocate_info;
if (provider.device_extensions().khr_dedicated_allocation) { if (provider.device_info().ext_1_1_VK_KHR_dedicated_allocation) {
memory_allocate_info_last->pNext = &memory_dedicated_allocate_info; memory_allocate_info_last->pNext = &memory_dedicated_allocate_info;
memory_allocate_info_last = reinterpret_cast<VkMemoryAllocateInfo*>( memory_allocate_info_last = reinterpret_cast<VkMemoryAllocateInfo*>(
&memory_dedicated_allocate_info); &memory_dedicated_allocate_info);
memory_dedicated_allocate_info.sType = memory_dedicated_allocate_info.sType =
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
memory_dedicated_allocate_info.pNext = nullptr; memory_dedicated_allocate_info.pNext = nullptr;
memory_dedicated_allocate_info.image = VK_NULL_HANDLE; memory_dedicated_allocate_info.image = VK_NULL_HANDLE;
memory_dedicated_allocate_info.buffer = buffer; memory_dedicated_allocate_info.buffer = buffer;
@ -154,13 +154,13 @@ bool CreateDedicatedAllocationImage(const VulkanProvider& provider,
memory_allocate_info.pNext = nullptr; memory_allocate_info.pNext = nullptr;
memory_allocate_info.allocationSize = memory_requirements.size; memory_allocate_info.allocationSize = memory_requirements.size;
memory_allocate_info.memoryTypeIndex = memory_type; memory_allocate_info.memoryTypeIndex = memory_type;
VkMemoryDedicatedAllocateInfoKHR memory_dedicated_allocate_info; VkMemoryDedicatedAllocateInfo memory_dedicated_allocate_info;
if (provider.device_extensions().khr_dedicated_allocation) { if (provider.device_info().ext_1_1_VK_KHR_dedicated_allocation) {
memory_allocate_info_last->pNext = &memory_dedicated_allocate_info; memory_allocate_info_last->pNext = &memory_dedicated_allocate_info;
memory_allocate_info_last = reinterpret_cast<VkMemoryAllocateInfo*>( memory_allocate_info_last = reinterpret_cast<VkMemoryAllocateInfo*>(
&memory_dedicated_allocate_info); &memory_dedicated_allocate_info);
memory_dedicated_allocate_info.sType = memory_dedicated_allocate_info.sType =
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
memory_dedicated_allocate_info.pNext = nullptr; memory_dedicated_allocate_info.pNext = nullptr;
memory_dedicated_allocate_info.image = image; memory_dedicated_allocate_info.image = image;
memory_dedicated_allocate_info.buffer = VK_NULL_HANDLE; memory_dedicated_allocate_info.buffer = VK_NULL_HANDLE;

View File

@ -50,7 +50,7 @@ enum class MemoryPurpose {
inline VkDeviceSize GetMappableMemorySize(const VulkanProvider& provider, inline VkDeviceSize GetMappableMemorySize(const VulkanProvider& provider,
VkDeviceSize size) { VkDeviceSize size) {
VkDeviceSize non_coherent_atom_size = VkDeviceSize non_coherent_atom_size =
provider.device_properties().limits.nonCoherentAtomSize; provider.device_info().nonCoherentAtomSize;
// On some Android implementations, nonCoherentAtomSize is 0, not 1. // On some Android implementations, nonCoherentAtomSize is 0, not 1.
if (non_coherent_atom_size > 1) { if (non_coherent_atom_size > 1) {
size = xe::round_up(size, non_coherent_atom_size, false); size = xe::round_up(size, non_coherent_atom_size, false);
@ -61,8 +61,8 @@ inline VkDeviceSize GetMappableMemorySize(const VulkanProvider& provider,
inline uint32_t ChooseHostMemoryType(const VulkanProvider& provider, inline uint32_t ChooseHostMemoryType(const VulkanProvider& provider,
uint32_t supported_types, uint32_t supported_types,
bool is_readback) { bool is_readback) {
supported_types &= provider.memory_types_host_visible(); supported_types &= provider.device_info().memory_types_host_visible;
uint32_t host_cached = provider.memory_types_host_cached(); uint32_t host_cached = provider.device_info().memory_types_host_cached;
uint32_t memory_type; uint32_t memory_type;
// For upload, uncached is preferred so writes do not pollute the CPU cache. // For upload, uncached is preferred so writes do not pollute the CPU cache.
// For readback, cached is preferred so multiple CPU reads are fast. // For readback, cached is preferred so multiple CPU reads are fast.
@ -107,12 +107,12 @@ void FlushMappedMemoryRange(const VulkanProvider& provider,
VkDeviceSize size = VK_WHOLE_SIZE); VkDeviceSize size = VK_WHOLE_SIZE);
inline VkExtent2D GetMax2DFramebufferExtent(const VulkanProvider& provider) { inline VkExtent2D GetMax2DFramebufferExtent(const VulkanProvider& provider) {
const VkPhysicalDeviceLimits& limits = provider.device_properties().limits; const VulkanProvider::DeviceInfo& device_info = provider.device_info();
VkExtent2D max_extent; VkExtent2D max_extent;
max_extent.width = max_extent.width = std::min(device_info.maxFramebufferWidth,
std::min(limits.maxFramebufferWidth, limits.maxImageDimension2D); device_info.maxImageDimension2D);
max_extent.height = max_extent.height = std::min(device_info.maxFramebufferHeight,
std::min(limits.maxFramebufferHeight, limits.maxImageDimension2D); device_info.maxImageDimension2D);
return max_extent; return max_extent;
} }