diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 77e8b9d4f6..0d97fe2ddb 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -126,12 +126,12 @@ static VkAttachmentLoadOp GetLoadOpForTexture(GSTextureVK* tex) // clang-format off switch (tex->GetState()) { - case GSTextureVK::State::Cleared: tex->SetState(GSTexture::State::Dirty); return VK_ATTACHMENT_LOAD_OP_CLEAR; - case GSTextureVK::State::Invalidated: tex->SetState(GSTexture::State::Dirty); return VK_ATTACHMENT_LOAD_OP_DONT_CARE; - case GSTextureVK::State::Dirty: return VK_ATTACHMENT_LOAD_OP_LOAD; - default: return VK_ATTACHMENT_LOAD_OP_LOAD; + case GSTextureVK::State::Cleared: tex->SetState(GSTexture::State::Dirty); return VK_ATTACHMENT_LOAD_OP_CLEAR; + case GSTextureVK::State::Invalidated: tex->SetState(GSTexture::State::Dirty); return VK_ATTACHMENT_LOAD_OP_DONT_CARE; + case GSTextureVK::State::Dirty: return VK_ATTACHMENT_LOAD_OP_LOAD; } // clang-format on + return VK_ATTACHMENT_LOAD_OP_LOAD; } static constexpr VkClearValue s_present_clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; @@ -162,26 +162,18 @@ VkInstance GSDeviceVK::CreateVulkanInstance(const WindowInfo& wi, OptionalExtens if (!SelectInstanceExtensions(&enabled_extensions, wi, oe, enable_debug_utils)) return VK_NULL_HANDLE; - VkApplicationInfo app_info = {}; - app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app_info.pNext = nullptr; + uint32_t version = VK_MAKE_VERSION(BuildVersion::GitTagHi, BuildVersion::GitTagMid, BuildVersion::GitTagLo); + VkApplicationInfo app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO}; app_info.pApplicationName = "PCSX2"; - app_info.applicationVersion = VK_MAKE_VERSION( - BuildVersion::GitTagHi, BuildVersion::GitTagMid, BuildVersion::GitTagLo); + app_info.applicationVersion = version; app_info.pEngineName = "PCSX2"; - app_info.engineVersion = VK_MAKE_VERSION( - BuildVersion::GitTagHi, BuildVersion::GitTagMid, BuildVersion::GitTagLo); + app_info.engineVersion = version; app_info.apiVersion = VK_API_VERSION_1_1; - VkInstanceCreateInfo instance_create_info = {}; - instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instance_create_info.pNext = nullptr; - instance_create_info.flags = 0; + VkInstanceCreateInfo instance_create_info = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; instance_create_info.pApplicationInfo = &app_info; instance_create_info.enabledExtensionCount = static_cast(enabled_extensions.size()); instance_create_info.ppEnabledExtensionNames = enabled_extensions.data(); - instance_create_info.enabledLayerCount = 0; - instance_create_info.ppEnabledLayerNames = nullptr; // Enable debug layer on debug builds if (enable_validation_layer) @@ -224,10 +216,10 @@ bool GSDeviceVK::SelectInstanceExtensions(ExtensionList* extension_list, const W pxAssert(res == VK_SUCCESS); auto SupportsExtension = [&available_extension_list, extension_list](const char* name, bool required) { - if (std::find_if(available_extension_list.begin(), available_extension_list.end(), - [name](const VkExtensionProperties& properties) { return !strcmp(name, properties.extensionName); }) != - available_extension_list.end()) + for (const VkExtensionProperties& properties : available_extension_list) { + if (0 != strcmp(name, properties.extensionName)) + continue; DevCon.WriteLn("VK: Enabling extension: %s", name); extension_list->push_back(name); return true; @@ -319,8 +311,7 @@ GSDeviceVK::GPUList GSDeviceVK::EnumerateGPUs(VkInstance instance) vkGetPhysicalDeviceProperties(device, &props); // Skip GPUs which don't support Vulkan 1.1, since we won't be able to create a device with them anyway. - if (VK_API_VERSION_VARIANT(props.apiVersion) == 0 && VK_API_VERSION_MAJOR(props.apiVersion) <= 1 && - VK_API_VERSION_MINOR(props.apiVersion) < 1) + if (props.apiVersion < VK_API_VERSION_1_1) { Console.Warning(fmt::format("VK: Ignoring GPU '{}' because it only claims support for Vulkan {}.{}.{}", props.deviceName, VK_API_VERSION_MAJOR(props.apiVersion), VK_API_VERSION_MINOR(props.apiVersion), @@ -365,8 +356,7 @@ GSDeviceVK::GPUList GSDeviceVK::EnumerateGPUs(VkInstance instance) ai.max_upscale_multiplier = GSGetMaxUpscaleMultiplier(ai.max_texture_size); // handle duplicate adapter names - if (std::any_of( - gpus.begin(), gpus.end(), [&ai](const auto& other) { return (ai.name == other.second.name); })) + if (std::any_of(gpus.begin(), gpus.end(), [&ai](const auto& other) { return (ai.name == other.second.name); })) { std::string original_adapter_name = std::move(ai.name); @@ -375,8 +365,7 @@ GSDeviceVK::GPUList GSDeviceVK::EnumerateGPUs(VkInstance instance) { ai.name = fmt::format("{} ({})", original_adapter_name, current_extra); current_extra++; - } while (std::any_of( - gpus.begin(), gpus.end(), [&ai](const auto& other) { return (ai.name == other.second.name); })); + } while (std::any_of(gpus.begin(), gpus.end(), [&ai](const auto& other) { return (ai.name == other.second.name); })); } gpus.emplace_back(device, std::move(ai)); @@ -438,10 +427,10 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab pxAssert(res == VK_SUCCESS); auto SupportsExtension = [&available_extension_list, extension_list](const char* name, bool required) { - if (std::find_if(available_extension_list.begin(), available_extension_list.end(), - [name](const VkExtensionProperties& properties) { return !strcmp(name, properties.extensionName); }) != - available_extension_list.end()) + for (const VkExtensionProperties& properties : available_extension_list) { + if (0 != strcmp(name, properties.extensionName)) + continue; if (std::none_of(extension_list->begin(), extension_list->end(), [name](const char* existing_name) { return (std::strcmp(existing_name, name) == 0); })) { @@ -491,7 +480,7 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab const bool khr_swapchain_maintenance1 = SupportsExtension(VK_KHR_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false); // vk_swapchain_maintenance1_is_khr will be set if we havn't enabled VK_EXT_surface_maintenance1 // This will happen if either the VK_EXT_surface_maintenance1 was unsupported, or we instead found the KHR version. - // As the EXT version depends on the surface maintenance1 extension, we need to check that aswell. + // As the EXT version depends on the surface maintenance1 extension, we need to check that as well. m_optional_extensions.vk_swapchain_maintenance1 = khr_swapchain_maintenance1 ? khr_swapchain_maintenance1 : (!m_optional_extensions.vk_swapchain_maintenance1_is_khr && SupportsExtension(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false)); @@ -610,28 +599,18 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer return false; } - VkDeviceCreateInfo device_info = {}; - device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_info.pNext = nullptr; - device_info.flags = 0; - device_info.queueCreateInfoCount = 0; + VkDeviceCreateInfo device_info = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; static constexpr float queue_priorities[] = {1.0f, 0.0f}; // Low priority for the spin queue std::array queue_infos; - VkDeviceQueueCreateInfo& graphics_queue_info = queue_infos[device_info.queueCreateInfoCount++]; - graphics_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - graphics_queue_info.pNext = nullptr; - graphics_queue_info.flags = 0; + VkDeviceQueueCreateInfo& graphics_queue_info = queue_infos[device_info.queueCreateInfoCount++] = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; graphics_queue_info.queueFamilyIndex = m_graphics_queue_family_index; graphics_queue_info.queueCount = 1; graphics_queue_info.pQueuePriorities = queue_priorities; if (surface != VK_NULL_HANDLE && m_graphics_queue_family_index != m_present_queue_family_index) { - VkDeviceQueueCreateInfo& present_queue_info = queue_infos[device_info.queueCreateInfoCount++]; - present_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - present_queue_info.pNext = nullptr; - present_queue_info.flags = 0; + VkDeviceQueueCreateInfo& present_queue_info = queue_infos[device_info.queueCreateInfoCount++] = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; present_queue_info.queueFamilyIndex = m_present_queue_family_index; present_queue_info.queueCount = 1; present_queue_info.pQueuePriorities = queue_priorities; @@ -649,10 +628,7 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer } else if (m_spin_queue_family_index != queue_family_count) { - VkDeviceQueueCreateInfo& spin_queue_info = queue_infos[device_info.queueCreateInfoCount++]; - spin_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - spin_queue_info.pNext = nullptr; - spin_queue_info.flags = 0; + VkDeviceQueueCreateInfo& spin_queue_info = queue_infos[device_info.queueCreateInfoCount++] = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; spin_queue_info.queueFamilyIndex = m_spin_queue_family_index; spin_queue_info.queueCount = 1; spin_queue_info.pQueuePriorities = queue_priorities + 1; @@ -681,22 +657,15 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer device_info.ppEnabledLayerNames = layer_names; } - VkPhysicalDeviceSynchronization2Features sync2_features = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES}; + VkPhysicalDeviceSynchronization2Features sync2_features = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES}; // provoking vertex - VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT}; - VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT}; - VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT}; - VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT}; + VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT}; + VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT}; + VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT}; + VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT}; // VK_EXT_swapchain_maintenance1 types/enums are aliases of VK_KHR_swapchain_maintenance1 types/enums. - VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR}; - VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock_ext_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT}; + VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR}; + VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock_ext_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT}; if (m_optional_extensions.vk_khr_synchronization2) { @@ -757,9 +726,9 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer m_spin_queue_is_graphics_queue = m_spin_queue_family_index == m_graphics_queue_family_index && spin_queue_index == 0; - m_gpu_timing_supported = (m_device_properties.limits.timestampComputeAndGraphics != 0 && - queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0 && - m_device_properties.limits.timestampPeriod > 0); + m_gpu_timing_supported = m_device_properties.limits.timestampComputeAndGraphics != 0 && + queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0 && + m_device_properties.limits.timestampPeriod > 0; DevCon.WriteLn("GPU timing is %s (TS=%u TS valid bits=%u, TS period=%f)", m_gpu_timing_supported ? "supported" : "not supported", static_cast(m_device_properties.limits.timestampComputeAndGraphics), @@ -801,21 +770,14 @@ bool GSDeviceVK::ProcessDeviceExtensions() { // advanced feature checks VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; - VkPhysicalDeviceSynchronization2Features sync2_features = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES}; - VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT}; - VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT}; - VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT}; + VkPhysicalDeviceSynchronization2Features sync2_features = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES}; + VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT}; + VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT}; + VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT}; // VK_EXT_swapchain_maintenance1 types/enums are aliases of VK_KHR_swapchain_maintenance1 types/enums. - VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR, nullptr, VK_TRUE}; - VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT}; - VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock_ext_feature = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT }; + VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR}; + VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT}; + VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock_ext_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT}; // add in optional feature structs if (m_optional_extensions.vk_khr_synchronization2) @@ -837,12 +799,10 @@ bool GSDeviceVK::ProcessDeviceExtensions() vkGetPhysicalDeviceFeatures2(m_physical_device, &features2); // confirm we actually support it - m_optional_extensions.vk_khr_synchronization2 &= (sync2_features.synchronization2 == VK_TRUE); - m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE); - m_optional_extensions.vk_ext_rasterization_order_attachment_access &= - (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE); - m_optional_extensions.vk_ext_attachment_feedback_loop_layout &= - (attachment_feedback_loop_feature.attachmentFeedbackLoopLayout == VK_TRUE); + m_optional_extensions.vk_khr_synchronization2 &= !!sync2_features.synchronization2; + m_optional_extensions.vk_ext_provoking_vertex &= !!provoking_vertex_features.provokingVertexLast; + m_optional_extensions.vk_ext_rasterization_order_attachment_access &= !!rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess; + m_optional_extensions.vk_ext_attachment_feedback_loop_layout &= !!attachment_feedback_loop_feature.attachmentFeedbackLoopLayout; VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; @@ -852,8 +812,7 @@ bool GSDeviceVK::ProcessDeviceExtensions() Vulkan::AddPointerToChain(&properties2, &m_device_driver_properties); } - VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor_properties = { - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR}; + VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor_properties = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR}; Vulkan::AddPointerToChain(&properties2, &push_descriptor_properties); // query @@ -907,11 +866,8 @@ bool GSDeviceVK::ProcessDeviceExtensions() m_optional_extensions.vk_ext_calibrated_timestamps = false; } - m_optional_extensions.vk_swapchain_maintenance1 &= - (swapchain_maintenance1_feature.swapchainMaintenance1 == VK_TRUE); - - m_optional_extensions.vk_ext_fragment_shader_interlock &= - (fragment_shader_interlock_ext_feature.fragmentShaderPixelInterlock == VK_TRUE); + m_optional_extensions.vk_swapchain_maintenance1 &= !!swapchain_maintenance1_feature.swapchainMaintenance1; + m_optional_extensions.vk_ext_fragment_shader_interlock &= !!fragment_shader_interlock_ext_feature.fragmentShaderPixelInterlock; Console.WriteLn("VK_%s_swapchain_maintenance1 is %s", m_optional_extensions.vk_swapchain_maintenance1_is_khr ? "KHR" : "EXT", @@ -1009,8 +965,8 @@ bool GSDeviceVK::CreateCommandBuffers() { resources.needs_fence_wait = false; - VkCommandPoolCreateInfo pool_info = { - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, 0, m_graphics_queue_family_index}; + VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; + pool_info.queueFamilyIndex = m_graphics_queue_family_index; res = vkCreateCommandPool(m_device, &pool_info, nullptr, &resources.command_pool); if (res != VK_SUCCESS) { @@ -1019,9 +975,10 @@ bool GSDeviceVK::CreateCommandBuffers() } Vulkan::SetObjectName(m_device, resources.command_pool, "Frame Command Pool %u", frame_index); - VkCommandBufferAllocateInfo buffer_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, - resources.command_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, - static_cast(resources.command_buffers.size())}; + VkCommandBufferAllocateInfo buffer_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO}; + buffer_info.commandPool = resources.command_pool; + buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + buffer_info.commandBufferCount = static_cast(resources.command_buffers.size()); res = vkAllocateCommandBuffers(m_device, &buffer_info, resources.command_buffers.data()); if (res != VK_SUCCESS) @@ -1035,7 +992,8 @@ bool GSDeviceVK::CreateCommandBuffers() (i == 0) ? "Init" : ""); } - VkFenceCreateInfo fence_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT}; + VkFenceCreateInfo fence_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; res = vkCreateFence(m_device, &fence_info, nullptr, &resources.fence); if (res != VK_SUCCESS) @@ -1058,10 +1016,11 @@ bool GSDeviceVK::CreateGlobalDescriptorPool() {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3}, }; - VkDescriptorPoolCreateInfo pool_create_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, nullptr, - VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, - 1024, // TODO: tweak this - static_cast(std::size(pool_sizes)), pool_sizes}; + VkDescriptorPoolCreateInfo pool_create_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; + pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + pool_create_info.maxSets = 1024; // TODO: tweak this + pool_create_info.poolSizeCount = std::size(pool_sizes); + pool_create_info.pPoolSizes = pool_sizes; VkResult res = vkCreateDescriptorPool(m_device, &pool_create_info, nullptr, &m_global_descriptor_pool); if (res != VK_SUCCESS) @@ -1073,8 +1032,9 @@ bool GSDeviceVK::CreateGlobalDescriptorPool() if (m_gpu_timing_supported) { - const VkQueryPoolCreateInfo query_create_info = { - VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, nullptr, 0, VK_QUERY_TYPE_TIMESTAMP, NUM_COMMAND_BUFFERS * 4, 0}; + VkQueryPoolCreateInfo query_create_info = {VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO}; + query_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; + query_create_info.queryCount = NUM_COMMAND_BUFFERS * 4; res = vkCreateQueryPool(m_device, &query_create_info, nullptr, &m_timestamp_query_pool); if (res != VK_SUCCESS) { @@ -1086,9 +1046,11 @@ bool GSDeviceVK::CreateGlobalDescriptorPool() if (m_gpu_pipeline_statistics_supported) { - const VkQueryPoolCreateInfo query_create_info = { - VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, nullptr, 0, VK_QUERY_TYPE_PIPELINE_STATISTICS, NUM_COMMAND_BUFFERS, - VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT }; + VkQueryPoolCreateInfo query_create_info = {VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO}; + query_create_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS; + query_create_info.queryCount = NUM_COMMAND_BUFFERS; + query_create_info.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT + | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT; res = vkCreateQueryPool(m_device, &query_create_info, nullptr, &m_pipeline_statistics_query_pool); if (res != VK_SUCCESS) { @@ -1101,10 +1063,11 @@ bool GSDeviceVK::CreateGlobalDescriptorPool() return true; } -VkRenderPass GSDeviceVK::GetRenderPass(VkFormat color_format, VkFormat depth_format, VkAttachmentLoadOp color_load_op, - VkAttachmentStoreOp color_store_op, VkAttachmentLoadOp depth_load_op, VkAttachmentStoreOp depth_store_op, - VkAttachmentLoadOp stencil_load_op, VkAttachmentStoreOp stencil_store_op, bool color_feedback_loop, - bool depth_sampling) +VkRenderPass GSDeviceVK::GetRenderPass(VkFormat color_format, VkFormat depth_format, + VkAttachmentLoadOp color_load_op, VkAttachmentStoreOp color_store_op, + VkAttachmentLoadOp depth_load_op, VkAttachmentStoreOp depth_store_op, + VkAttachmentLoadOp stencil_load_op, VkAttachmentStoreOp stencil_store_op, + bool color_feedback_loop, bool depth_sampling) { RenderPassCacheKey key = {}; key.color_format = color_format; @@ -1161,8 +1124,8 @@ VkCommandBuffer GSDeviceVK::GetCurrentInitCommandBuffer() if (res.init_buffer_used) return buf; - VkCommandBufferBeginInfo bi{ - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr}; + VkCommandBufferBeginInfo bi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkBeginCommandBuffer(buf, &bi); res.init_buffer_used = true; return buf; @@ -1170,8 +1133,10 @@ VkCommandBuffer GSDeviceVK::GetCurrentInitCommandBuffer() VkDescriptorSet GSDeviceVK::AllocatePersistentDescriptorSet(VkDescriptorSetLayout set_layout) { - VkDescriptorSetAllocateInfo allocate_info = { - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, nullptr, m_global_descriptor_pool, 1, &set_layout}; + VkDescriptorSetAllocateInfo allocate_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocate_info.descriptorPool = m_global_descriptor_pool; + allocate_info.descriptorSetCount = 1; + allocate_info.pSetLayouts = &set_layout; VkDescriptorSet descriptor_set; VkResult res = vkAllocateDescriptorSets(m_device, &allocate_info, &descriptor_set); @@ -1326,7 +1291,7 @@ void GSDeviceVK::ScanForCommandBufferCompletion() continue; if (vkGetFenceStatus(m_device, resources.fence) != VK_SUCCESS) continue; - SpinCommandCompleted(&resources - &m_spin_resources[0]); + SpinCommandCompleted(static_cast(&resources - &m_spin_resources[0])); } } @@ -1478,9 +1443,12 @@ void GSDeviceVK::SubmitCommandBuffer(VKSwapChain* present_swap_chain) if (present_swap_chain) { - const VkPresentInfoKHR present_info = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, nullptr, 1, - present_swap_chain->GetRenderingFinishedSemaphorePtr(), 1, present_swap_chain->GetSwapChainPtr(), - present_swap_chain->GetCurrentImageIndexPtr(), nullptr}; + VkPresentInfoKHR present_info = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = present_swap_chain->GetRenderingFinishedSemaphorePtr(); + present_info.swapchainCount = 1; + present_info.pSwapchains = present_swap_chain->GetSwapChainPtr(); + present_info.pImageIndices = present_swap_chain->GetCurrentImageIndexPtr(); present_swap_chain->ResetImageAcquireResult(); @@ -1678,13 +1646,14 @@ bool GSDeviceVK::EnableDebugUtils() return false; } - VkDebugUtilsMessengerCreateInfoEXT messenger_info = {VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - nullptr, 0, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, - DebugMessengerCallback, nullptr}; + VkDebugUtilsMessengerCreateInfoEXT messenger_info = {VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; + messenger_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + messenger_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + messenger_info.pfnUserCallback = DebugMessengerCallback; const VkResult res = vkCreateDebugUtilsMessengerEXT(m_instance, &messenger_info, nullptr, &m_debug_messenger_callback); @@ -1714,19 +1683,22 @@ VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key) VkAttachmentReference* depth_reference_ptr = nullptr; std::array input_reference; u32 num_subpass_inputs = 0; - std::array subpass_dependency; + std::array subpass_dependencies; u32 num_subpass_dependencies = 0; std::array attachments; u32 num_attachments = 0; if (key.color_format != VK_FORMAT_UNDEFINED) { - const VkImageLayout layout = - key.color_feedback_loop ? (UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : - VK_IMAGE_LAYOUT_GENERAL) : - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[num_attachments] = {0, static_cast(key.color_format), VK_SAMPLE_COUNT_1_BIT, - static_cast(key.color_load_op), static_cast(key.color_store_op), - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, layout, layout}; + const VkImageLayout layout = key.color_feedback_loop ? GetFeedbackLoopLayout() : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentDescription& attachment = attachments[num_attachments] = {}; + attachment.format = static_cast(key.color_format); + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = static_cast(key.color_load_op); + attachment.storeOp = static_cast(key.color_store_op); + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = layout; + attachment.finalLayout = layout; color_reference.attachment = num_attachments; color_reference.layout = layout; color_reference_ptr = &color_reference; @@ -1743,15 +1715,14 @@ VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key) if (!m_features.framebuffer_fetch) { // don't need the framebuffer-local dependency when we have rasterization order attachment access - subpass_dependency[num_subpass_dependencies].srcSubpass = 0; - subpass_dependency[num_subpass_dependencies].dstSubpass = 0; - subpass_dependency[num_subpass_dependencies].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - subpass_dependency[num_subpass_dependencies].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - subpass_dependency[num_subpass_dependencies].srcAccessMask = - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - subpass_dependency[num_subpass_dependencies].dstAccessMask = static_cast(GetFeedbackLoopInputAccessFlags()); - subpass_dependency[num_subpass_dependencies].dependencyFlags = GetFeedbackBarrierDependencyFlags(); - num_subpass_dependencies++; + VkSubpassDependency& subpass_dependency = subpass_dependencies[num_subpass_dependencies++]; + subpass_dependency.srcSubpass = 0; + subpass_dependency.dstSubpass = 0; + subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + subpass_dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + subpass_dependency.dstAccessMask = static_cast(GetFeedbackLoopInputAccessFlags()); + subpass_dependency.dependencyFlags = GetFeedbackBarrierDependencyFlags(); } } @@ -1765,10 +1736,15 @@ VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key) VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL) : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments[num_attachments] = {0, static_cast(key.depth_format), VK_SAMPLE_COUNT_1_BIT, - static_cast(key.depth_load_op), static_cast(key.depth_store_op), - static_cast(key.stencil_load_op), - static_cast(key.stencil_store_op), layout, layout}; + VkAttachmentDescription& attachment = attachments[num_attachments] = {}; + attachment.format = static_cast(key.depth_format); + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = static_cast(key.depth_load_op); + attachment.storeOp = static_cast(key.depth_store_op); + attachment.stencilLoadOp = static_cast(key.stencil_load_op); + attachment.stencilStoreOp = static_cast(key.stencil_store_op); + attachment.initialLayout = layout; + attachment.finalLayout = layout; depth_reference.attachment = num_attachments; depth_reference.layout = layout; depth_reference_ptr = &depth_reference; @@ -1785,31 +1761,37 @@ VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key) if (!m_features.framebuffer_fetch) { // don't need the framebuffer-local dependency when we have rasterization order attachment access - subpass_dependency[num_subpass_dependencies].srcSubpass = 0; - subpass_dependency[num_subpass_dependencies].dstSubpass = 0; - subpass_dependency[num_subpass_dependencies].srcStageMask = - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - subpass_dependency[num_subpass_dependencies].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - subpass_dependency[num_subpass_dependencies].srcAccessMask = - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - subpass_dependency[num_subpass_dependencies].dstAccessMask = static_cast(GetFeedbackLoopInputAccessFlags()); - subpass_dependency[num_subpass_dependencies].dependencyFlags = GetFeedbackBarrierDependencyFlags(); - num_subpass_dependencies++; + VkSubpassDependency& subpass_dependency = subpass_dependencies[num_subpass_dependencies++]; + subpass_dependency.srcSubpass = 0; + subpass_dependency.dstSubpass = 0; + subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + subpass_dependency.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + subpass_dependency.dstAccessMask = static_cast(GetFeedbackLoopInputAccessFlags()); + subpass_dependency.dependencyFlags = GetFeedbackBarrierDependencyFlags(); } } num_attachments++; } - const VkSubpassDescriptionFlags subpass_flags = - (key.color_feedback_loop && m_features.framebuffer_fetch) ? - VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT : - 0; - const VkSubpassDescription subpass = {subpass_flags, VK_PIPELINE_BIND_POINT_GRAPHICS, num_subpass_inputs, - num_subpass_inputs ? input_reference.data() : nullptr, color_reference_ptr ? 1u : 0u, - color_reference_ptr ? color_reference_ptr : nullptr, nullptr, depth_reference_ptr, 0, nullptr}; - const VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0u, num_attachments, - attachments.data(), 1u, &subpass, num_subpass_dependencies, num_subpass_dependencies ? subpass_dependency.data() : nullptr}; + VkSubpassDescription subpass = {}; + if (key.color_feedback_loop && m_features.framebuffer_fetch) + subpass.flags |= VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = num_subpass_inputs; + subpass.pInputAttachments = num_subpass_inputs ? input_reference.data() : nullptr; + subpass.colorAttachmentCount = color_reference_ptr ? 1 : 0; + subpass.pColorAttachments = color_reference_ptr; + subpass.pDepthStencilAttachment = depth_reference_ptr; + + VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; + pass_info.attachmentCount = num_attachments; + pass_info.pAttachments = attachments.data(); + pass_info.subpassCount = 1; + pass_info.pSubpasses = &subpass; + pass_info.dependencyCount = num_subpass_dependencies; + pass_info.pDependencies = num_subpass_dependencies ? subpass_dependencies.data() : nullptr; VkRenderPass pass; const VkResult res = vkCreateRenderPass(m_device, &pass_info, nullptr, &pass); @@ -1903,8 +1885,7 @@ bool GSDeviceVK::InitSpinResources() VkBufferCreateInfo buf_create = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; buf_create.size = 4; buf_create.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - if ((res = vmaCreateBuffer(m_allocator, &buf_create, &buf_vma_create, &m_spin_buffer, &m_spin_buffer_allocation, - nullptr)) != VK_SUCCESS) + if ((res = vmaCreateBuffer(m_allocator, &buf_create, &buf_vma_create, &m_spin_buffer, &m_spin_buffer_allocation, nullptr)) != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vmaCreateBuffer failed: "); return false; @@ -2104,16 +2085,12 @@ void GSDeviceVK::SubmitSpinCommand(u32 index, u32 cycles) const u32 timestamp_base = (index + NUM_COMMAND_BUFFERS) * 2; vkCmdResetQueryPool(resources.command_buffer, m_timestamp_query_pool, timestamp_base, 2); - vkCmdWriteTimestamp( - resources.command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool, timestamp_base); - vkCmdPushConstants( - resources.command_buffer, m_spin_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(u32), &cycles); + vkCmdWriteTimestamp(resources.command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool, timestamp_base); + vkCmdPushConstants(resources.command_buffer, m_spin_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(u32), &cycles); vkCmdBindPipeline(resources.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, m_spin_pipeline); - vkCmdBindDescriptorSets(resources.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, m_spin_pipeline_layout, 0, 1, - &m_spin_descriptor_set, 0, nullptr); + vkCmdBindDescriptorSets(resources.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, m_spin_pipeline_layout, 0, 1, &m_spin_descriptor_set, 0, nullptr); vkCmdDispatch(resources.command_buffer, 1, 1, 1); - vkCmdWriteTimestamp( - resources.command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, m_timestamp_query_pool, timestamp_base + 1); + vkCmdWriteTimestamp(resources.command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, m_timestamp_query_pool, timestamp_base + 1); if ((res = vkEndCommandBuffer(resources.command_buffer)) != VK_SUCCESS) LOG_VULKAN_ERROR(res, "vkEndCommandBuffer failed: "); @@ -2191,9 +2168,13 @@ bool GSDeviceVK::AllocatePreinitializedGPUBuffer(u32 size, VkBuffer* gpu_buffer, // Try to place the fixed index buffer in GPU local memory. // Use the staging buffer to copy into it. - const VkBufferCreateInfo cpu_bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, size, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_SHARING_MODE_EXCLUSIVE}; - const VmaAllocationCreateInfo cpu_aci = {VMA_ALLOCATION_CREATE_MAPPED_BIT, VMA_MEMORY_USAGE_CPU_ONLY, 0, 0}; + VkBufferCreateInfo cpu_bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + cpu_bci.size = size; + cpu_bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + cpu_bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VmaAllocationCreateInfo cpu_aci = {}; + cpu_aci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + cpu_aci.usage = VMA_MEMORY_USAGE_CPU_ONLY; VkBuffer cpu_buffer; VmaAllocation cpu_allocation; VmaAllocationInfo cpu_ai; @@ -2204,9 +2185,13 @@ bool GSDeviceVK::AllocatePreinitializedGPUBuffer(u32 size, VkBuffer* gpu_buffer, return false; } - const VkBufferCreateInfo gpu_bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, size, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE}; - const VmaAllocationCreateInfo gpu_aci = {0, VMA_MEMORY_USAGE_GPU_ONLY, 0, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT}; + VkBufferCreateInfo gpu_bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + gpu_bci.size = size; + gpu_bci.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + gpu_bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VmaAllocationCreateInfo gpu_aci = {}; + gpu_aci.usage = VMA_MEMORY_USAGE_GPU_ONLY; + gpu_aci.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; VmaAllocationInfo ai; res = vmaCreateBuffer(m_allocator, &gpu_bci, &gpu_aci, gpu_buffer, gpu_allocation, &ai); if (res != VK_SUCCESS) @@ -2423,7 +2408,7 @@ bool GSDeviceVK::UpdateWindow() VkPresentModeKHR present_mode; if (!VKSwapChain::SelectPresentMode(surface, &m_vsync_mode, &present_mode) || !(m_swap_chain = VKSwapChain::Create(m_window_info, surface, present_mode, - Pcsx2Config::GSOptions::TriStateToOptionalBoolean(GSConfig.ExclusiveFullscreenControl)))) + Pcsx2Config::GSOptions::TriStateToOptionalBoolean(GSConfig.ExclusiveFullscreenControl)))) { Console.Error("VK: Failed to create swap chain"); VKSwapChain::DestroyVulkanSurface(m_instance, &m_window_info, surface); @@ -2442,7 +2427,7 @@ void GSDeviceVK::ResizeWindow(u32 new_window_width, u32 new_window_height, float m_resize_requested = false; if (!m_swap_chain || (m_swap_chain->GetWidth() == new_window_width && - m_swap_chain->GetHeight() == new_window_height)) + m_swap_chain->GetHeight() == new_window_height)) { // skip unnecessary resizes m_window_info.surface_scale = new_window_scale; @@ -2483,16 +2468,17 @@ std::string GSDeviceVK::GetDriverInfo() const const VkPhysicalDeviceDriverProperties& props = m_device_driver_properties; ret = StringUtil::StdStringFromFormat( "Driver %u.%u.%u\nVulkan %u.%u.%u\nConformance Version %u.%u.%u.%u\n%s\n%s\n%s", - VK_VERSION_MAJOR(driver_version), VK_VERSION_MINOR(driver_version), VK_VERSION_PATCH(driver_version), + VK_VERSION_MAJOR(driver_version), VK_VERSION_MINOR(driver_version), VK_VERSION_PATCH(driver_version), VK_API_VERSION_MAJOR(api_version), VK_API_VERSION_MINOR(api_version), VK_API_VERSION_PATCH(api_version), props.conformanceVersion.major, props.conformanceVersion.minor, props.conformanceVersion.subminor, props.conformanceVersion.patch, props.driverInfo, props.driverName, m_device_properties.deviceName); } else { - ret = StringUtil::StdStringFromFormat("Driver %u.%u.%u\nVulkan %u.%u.%u\n%s", VK_VERSION_MAJOR(driver_version), - VK_VERSION_MINOR(driver_version), VK_VERSION_PATCH(driver_version), VK_API_VERSION_MAJOR(api_version), - VK_API_VERSION_MINOR(api_version), VK_API_VERSION_PATCH(api_version), m_device_properties.deviceName); + ret = StringUtil::StdStringFromFormat("Driver %u.%u.%u\nVulkan %u.%u.%u\n%s", + VK_VERSION_MAJOR(driver_version), VK_VERSION_MINOR(driver_version), VK_VERSION_PATCH(driver_version), + VK_API_VERSION_MAJOR(api_version), VK_API_VERSION_MINOR(api_version), VK_API_VERSION_PATCH(api_version), + m_device_properties.deviceName); } return ret; @@ -2608,18 +2594,16 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip) if (fb == VK_NULL_HANDLE) return GSDevice::PresentResult::FrameSkipped; - const VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, - GetRenderPass(swap_chain_texture->GetVkFormat(), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_STORE_OP_STORE), - fb, - {{0, 0}, {static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight())}}, - 1u, &s_present_clear_color}; + VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + rp.renderPass = GetRenderPass(swap_chain_texture->GetVkFormat(), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); + rp.framebuffer = fb; + rp.renderArea = {{0, 0}, {static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight())}}; + rp.clearValueCount = 1; + rp.pClearValues = &s_present_clear_color; vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE); - const VkViewport vp{0.0f, 0.0f, static_cast(swap_chain_texture->GetWidth()), - static_cast(swap_chain_texture->GetHeight()), 0.0f, 1.0f}; - const VkRect2D scissor{ - {0, 0}, {static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight())}}; + const VkViewport vp{0.0f, 0.0f, static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight()), 0.0f, 1.0f}; + const VkRect2D scissor{{0, 0}, {static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight())}}; vkCmdSetViewport(GetCurrentCommandBuffer(), 0, 1, &vp); vkCmdSetScissor(GetCurrentCommandBuffer(), 0, 1, &scissor); m_is_presenting = true; @@ -2673,12 +2657,11 @@ void GSDeviceVK::PushDebugGroup(const char* fmt, ...) const std::array color = Palette( ++s_debug_scope_depth, {0.5f, 0.5f, 0.5f}, {0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 0.5f}, {0.8f, 0.90f, 0.30f}); - const VkDebugUtilsLabelEXT label = { - VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, - nullptr, - buf.c_str(), - {color[0], color[1], color[2], 1.0f}, - }; + VkDebugUtilsLabelEXT label = {VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT}; + label.pLabelName = buf.c_str(); + for (uint32_t i = 0; i < 3; i++) + label.color[i] = color[i]; + label.color[3] = 1.0f; vkCmdBeginDebugUtilsLabelEXT(GetCurrentCommandBuffer(), &label); #endif } @@ -2717,9 +2700,11 @@ void GSDeviceVK::InsertDebugMessage(DebugMessageCategory category, const char* f {0.0f, 0.2f, 0.0f} // Performance }; - const VkDebugUtilsLabelEXT label = {VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, nullptr, buf.c_str(), - {colors[static_cast(category)][0], colors[static_cast(category)][1], - colors[static_cast(category)][2], 1.0f}}; + VkDebugUtilsLabelEXT label = {VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT}; + label.pLabelName = buf.c_str(); + for (uint32_t i = 0; i < 3; i++) + label.color[i] = colors[static_cast(category)][i]; + label.color[3] = 1.0f; vkCmdInsertDebugUtilsLabelEXT(GetCurrentCommandBuffer(), &label); #endif } @@ -2847,7 +2832,7 @@ bool GSDeviceVK::CreateDeviceAndSwapChain() VkPresentModeKHR present_mode; if (!VKSwapChain::SelectPresentMode(surface, &m_vsync_mode, &present_mode) || !(m_swap_chain = VKSwapChain::Create(m_window_info, surface, present_mode, - Pcsx2Config::GSOptions::TriStateToOptionalBoolean(GSConfig.ExclusiveFullscreenControl)))) + Pcsx2Config::GSOptions::TriStateToOptionalBoolean(GSConfig.ExclusiveFullscreenControl)))) { ERROR_LOG("Failed to create swap chain"); return false; @@ -2873,8 +2858,7 @@ bool GSDeviceVK::CheckFeatures() //const bool isAMD = (vendorID == 0x1002 || vendorID == 0x1022); //const bool isNVIDIA = (vendorID == 0x10DE); - m_features.framebuffer_fetch = - m_optional_extensions.vk_ext_rasterization_order_attachment_access && !GSConfig.DisableFramebufferFetch; + m_features.framebuffer_fetch = m_optional_extensions.vk_ext_rasterization_order_attachment_access && !GSConfig.DisableFramebufferFetch; m_features.texture_barrier = GSConfig.OverrideTextureBarriers != 0; m_features.multidraw_fb_copy = false; m_features.broken_point_sampler = false; @@ -2910,7 +2894,7 @@ bool GSDeviceVK::CheckFeatures() // whether we can do point/line expand depends on the range of the device const float f_upscale = static_cast(GSConfig.UpscaleMultiplier); m_features.point_expand = (m_device_features.largePoints && limits.pointSizeRange[0] <= f_upscale && - limits.pointSizeRange[1] >= f_upscale); + limits.pointSizeRange[1] >= f_upscale); m_features.line_expand = (m_device_features.wideLines && limits.lineWidthRange[0] <= f_upscale && limits.lineWidthRange[1] >= f_upscale); @@ -2958,8 +2942,7 @@ bool GSDeviceVK::CheckFeatures() if (!m_features.texture_barrier && !m_features.stencil_buffer) { Host::AddKeyedOSDMessage("GSDeviceVK_NoTextureBarrierOrStencilBuffer", - TRANSLATE_STR("GS", - "Stencil buffers and texture barriers are both unavailable, this will break some graphical effects."), + TRANSLATE_STR("GS", "Stencil buffers and texture barriers are both unavailable, this will break some graphical effects."), Host::OSD_WARNING_DURATION); } @@ -3031,23 +3014,24 @@ void GSDeviceVK::Draw(const GSHWDrawConfig& config) VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const { - static constexpr std::array(GSTexture::Format::Last) + 1> s_format_mapping = {{ - VK_FORMAT_UNDEFINED, // Invalid - VK_FORMAT_R8G8B8A8_UNORM, // Color + static constexpr VkFormat s_format_mapping[] = { + VK_FORMAT_UNDEFINED, // Invalid + VK_FORMAT_R8G8B8A8_UNORM, // Color VK_FORMAT_A2B10G10R10_UNORM_PACK32, // ColorHQ - VK_FORMAT_R16G16B16A16_SFLOAT, // ColorHDR - VK_FORMAT_R16G16B16A16_UNORM, // ColorClip - VK_FORMAT_D32_SFLOAT_S8_UINT, // DepthStencil - VK_FORMAT_R32_SFLOAT, // DepthColor - VK_FORMAT_R8_UNORM, // UNorm8 - VK_FORMAT_R16_UINT, // UInt16 - VK_FORMAT_R32_UINT, // UInt32 - VK_FORMAT_R32_SFLOAT, // PrimID - VK_FORMAT_BC1_RGBA_UNORM_BLOCK, // BC1 - VK_FORMAT_BC2_UNORM_BLOCK, // BC2 - VK_FORMAT_BC3_UNORM_BLOCK, // BC3 - VK_FORMAT_BC7_UNORM_BLOCK, // BC7 - }}; + VK_FORMAT_R16G16B16A16_SFLOAT, // ColorHDR + VK_FORMAT_R16G16B16A16_UNORM, // ColorClip + VK_FORMAT_D32_SFLOAT_S8_UINT, // DepthStencil + VK_FORMAT_R32_SFLOAT, // DepthColor + VK_FORMAT_R8_UNORM, // UNorm8 + VK_FORMAT_R16_UINT, // UInt16 + VK_FORMAT_R32_UINT, // UInt32 + VK_FORMAT_R32_SFLOAT, // PrimID + VK_FORMAT_BC1_RGBA_UNORM_BLOCK, // BC1 + VK_FORMAT_BC2_UNORM_BLOCK, // BC2 + VK_FORMAT_BC3_UNORM_BLOCK, // BC3 + VK_FORMAT_BC7_UNORM_BLOCK, // BC7 + }; + static_assert(std::size(s_format_mapping) == static_cast(GSTexture::Format::Last) + 1); return (format != GSTexture::Format::DepthStencil || m_features.stencil_buffer) ? s_format_mapping[static_cast(format)] : @@ -3420,8 +3404,13 @@ void GSDeviceVK::BlitRect(GSTexture* sTex, const GSVector4i& sRect, u32 sLevel, pxAssert(sTexVK->IsDepthStencil() == dTexVK->IsDepthStencil()); const VkImageAspectFlags aspect = sTexVK->IsDepthStencil() ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - const VkImageBlit ib{{aspect, sLevel, 0u, 1u}, {{sRect.left, sRect.top, 0}, {sRect.right, sRect.bottom, 1}}, - {aspect, dLevel, 0u, 1u}, {{dRect.left, dRect.top, 0}, {dRect.right, dRect.bottom, 1}}}; + VkImageBlit ib = {}; + ib.srcSubresource = {aspect, sLevel, 0u, 1u}; + ib.dstSubresource = {aspect, dLevel, 0u, 1u}; + ib.srcOffsets[0] = {sRect.left, sRect.top, 0}; + ib.dstOffsets[0] = {dRect.left, dRect.top, 0}; + ib.srcOffsets[1] = {sRect.right, sRect.bottom, 1}; + ib.dstOffsets[1] = {dRect.right, dRect.bottom, 1}; vkCmdBlitImage(GetCurrentCommandBuffer(), sTexVK->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dTexVK->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &ib, @@ -3904,26 +3893,16 @@ VkSampler GSDeviceVK::GetSampler(GSHWDrawConfig::SamplerSelector ss) // See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSamplerCreateInfo.html#_description // for the reasoning behind 0.25f here. - const VkSamplerCreateInfo ci = { - VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, nullptr, 0, - ss.IsMagFilterLinear() ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, // min - ss.IsMinFilterLinear() ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, // mag - ss.IsMipFilterLinear() ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST, // mip - static_cast( - ss.tau ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE), // u - static_cast( - ss.tav ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE), // v - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // w - 0.0f, // lod bias - VK_FALSE, // anisotropy enable - 1.0f, // anisotropy - VK_FALSE, // compare enable - VK_COMPARE_OP_ALWAYS, // compare op - 0.0f, // min lod - (ss.lodclamp || !ss.UseMipmapFiltering()) ? 0.25f : VK_LOD_CLAMP_NONE, // max lod - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // border - VK_FALSE // unnormalized coordinates - }; + VkSamplerCreateInfo ci = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + ci.magFilter = ss.IsMagFilterLinear() ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + ci.minFilter = ss.IsMinFilterLinear() ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + ci.mipmapMode = ss.IsMipFilterLinear() ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; + ci.addressModeU = ss.tau ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + ci.addressModeV = ss.tav ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + ci.maxAnisotropy = 1.0f; + ci.compareOp = VK_COMPARE_OP_ALWAYS; + ci.maxLod = (ss.lodclamp || !ss.UseMipmapFiltering()) ? 0.25f : VK_LOD_CLAMP_NONE; VkSampler sampler = VK_NULL_HANDLE; VkResult res = vkCreateSampler(m_device, &ci, nullptr, &sampler); if (res != VK_SUCCESS) @@ -4136,7 +4115,7 @@ bool GSDeviceVK::CreatePipelineLayouts() dslb.AddBinding(TFX_TEXTURE_PALETTE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT); dslb.AddBinding(TFX_TEXTURE_RT, (m_features.texture_barrier && !UseFeedbackLoopLayout()) ? VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT : - VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT); dslb.AddBinding(TFX_TEXTURE_PRIMID, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT); dslb.AddBinding(TFX_TEXTURE_DEPTH, @@ -4165,10 +4144,10 @@ bool GSDeviceVK::CreateRenderPasses() dest = GetRenderPass( \ (rt), (depth), ((rt) != VK_FORMAT_UNDEFINED) ? (opa) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, /* color load */ \ ((rt) != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : \ - VK_ATTACHMENT_STORE_OP_DONT_CARE, /* color store */ \ + VK_ATTACHMENT_STORE_OP_DONT_CARE, /* color store */ \ ((depth) != VK_FORMAT_UNDEFINED) ? (opb) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, /* depth load */ \ ((depth) != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : \ - VK_ATTACHMENT_STORE_OP_DONT_CARE, /* depth store */ \ + VK_ATTACHMENT_STORE_OP_DONT_CARE, /* depth store */ \ ((depth) != VK_FORMAT_UNDEFINED) ? (opc) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, /* stencil load */ \ VK_ATTACHMENT_STORE_OP_DONT_CARE, /* stencil store */ \ (fbl), /* feedback loop */ \ @@ -4376,8 +4355,7 @@ bool GSDeviceVK::CompileConvertPipelines() m_primid_image_setup_render_passes[ds][clear] = GetRenderPass(LookupNativeFormat(GSTexture::Format::PrimID), ds ? LookupNativeFormat(GSTexture::Format::DepthStencil) : VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE, - ds ? (clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD) : - VK_ATTACHMENT_LOAD_OP_DONT_CARE, + ds ? (clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, ds ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE); } } @@ -5224,14 +5202,14 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p) else if (pbs.enable) { // clang-format off - static constexpr std::array vk_blend_factors = { { - VK_BLEND_FACTOR_SRC_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_FACTOR_DST_COLOR, VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, - VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - VK_BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, VK_BLEND_FACTOR_SRC1_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, + static constexpr std::array vk_blend_factors = {{ + VK_BLEND_FACTOR_SRC_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_FACTOR_DST_COLOR, VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, + VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, VK_BLEND_FACTOR_SRC1_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO }}; static constexpr std::array vk_blend_ops = {{ - VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT + VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT }}; // clang-format on @@ -6185,16 +6163,16 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1}; BeginClearRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(), - pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR, - pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), + pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR, + pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), draw_rt->GetRect(), cvs, cv_count); draw_rt->SetState(GSTexture::State::Dirty); } else { BeginRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(), - pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD, - pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), + pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD, + pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), draw_rt->GetRect()); } @@ -6453,9 +6431,10 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne) { const VkClearAttachment ca = {VK_IMAGE_ASPECT_STENCIL_BIT, 0u, {.depthStencil = {0.0f, 1u}}}; - const VkClearRect rc = {{{config.drawarea.left, config.drawarea.top}, - {static_cast(config.drawarea.width()), static_cast(config.drawarea.height())}}, - 0u, 1u}; + VkClearRect rc = {}; + rc.rect.offset = {config.drawarea.left, config.drawarea.top}; + rc.rect.extent = {static_cast(config.drawarea.width()), static_cast(config.drawarea.height())}; + rc.layerCount = 1; vkCmdClearAttachments(m_current_command_buffer, 1, &ca, 1, &rc); } @@ -6553,16 +6532,16 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1}; BeginClearRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(), - pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR, - pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), + pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR, + pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), draw_rt->GetRect(), cvs, cv_count); draw_rt->SetState(GSTexture::State::Dirty); } else { BeginRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(), - pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD, - pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), + pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD, + pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), draw_rt->GetRect()); } diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp index 6af56425de..5aefadc9a9 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp @@ -14,10 +14,11 @@ VkFramebuffer GSTextureVK::CreateNullFramebuffer(u32 w, u32 h) { const VkRenderPass rp = GSDeviceVK::GetInstance()->GetRenderPass( - VK_FORMAT_UNDEFINED, - VK_FORMAT_UNDEFINED, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, false, false); + VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + false, false); if (!rp) return VK_NULL_HANDLE; @@ -29,29 +30,31 @@ VkFramebuffer GSTextureVK::CreateNullFramebuffer(u32 w, u32 h) return fbb.Create(GSDeviceVK::GetInstance()->GetDevice()); } -static constexpr const VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; +static constexpr const VkComponentMapping s_identity_swizzle { + VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, +}; static VkImageLayout GetVkImageLayout(GSTextureVK::Layout layout) { static constexpr VkImageLayout s_vk_layout_mapping[] = { - VK_IMAGE_LAYOUT_UNDEFINED, // Undefined - VK_IMAGE_LAYOUT_PREINITIALIZED, // Preinitialized + VK_IMAGE_LAYOUT_UNDEFINED, // Undefined + VK_IMAGE_LAYOUT_PREINITIALIZED, // Preinitialized VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // ColorAttachment VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // DepthStencilAttachment VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // ShaderReadOnly VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // ClearDst VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // CopySrc VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // CopyDst - VK_IMAGE_LAYOUT_GENERAL, // CopySelf + VK_IMAGE_LAYOUT_GENERAL, // CopySelf VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // BlitSrc VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // BlitDst - VK_IMAGE_LAYOUT_GENERAL, // BlitSelf - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // PresentSrc - VK_IMAGE_LAYOUT_GENERAL, // FeedbackLoop - VK_IMAGE_LAYOUT_GENERAL, // ReadWriteImage - VK_IMAGE_LAYOUT_GENERAL, // ComputeReadWriteImage - VK_IMAGE_LAYOUT_GENERAL, // General + VK_IMAGE_LAYOUT_GENERAL, // BlitSelf + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // PresentSrc + VK_IMAGE_LAYOUT_GENERAL, // FeedbackLoop + VK_IMAGE_LAYOUT_GENERAL, // ReadWriteImage + VK_IMAGE_LAYOUT_GENERAL, // ComputeReadWriteImage + VK_IMAGE_LAYOUT_GENERAL, // General }; static_assert(std::size(s_vk_layout_mapping) == static_cast(GSTextureVK::Layout::Count)); if (layout == GSTextureVK::Layout::FeedbackLoop) @@ -62,11 +65,13 @@ static VkImageLayout GetVkImageLayout(GSTextureVK::Layout layout) static VkPipelineStageFlags2 GetPipelineStageFlags(GSTextureVK::Layout layout, bool color) { + static constexpr VkPipelineStageFlags2 VK_PIPELINE_STAGE_2_FRAGMENT_TESTS_BITS = + VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT; static constexpr VkPipelineStageFlags2 s_vk_stage_mapping[] = { VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, // Undefined VK_PIPELINE_STAGE_2_HOST_BIT, // Preinitialized VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, // ColorAttachment - VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, // DepthStencilAttachment + VK_PIPELINE_STAGE_2_FRAGMENT_TESTS_BITS, // DepthStencilAttachment VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, // ShaderReadOnly VK_PIPELINE_STAGE_2_CLEAR_BIT, // ClearDst VK_PIPELINE_STAGE_2_COPY_BIT, // CopySrc @@ -88,7 +93,7 @@ static VkPipelineStageFlags2 GetPipelineStageFlags(GSTextureVK::Layout layout, b if (color) flags |= VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; else - flags |= VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT; + flags |= VK_PIPELINE_STAGE_2_FRAGMENT_TESTS_BITS; return flags; } else @@ -99,25 +104,27 @@ static VkPipelineStageFlags2 GetPipelineStageFlags(GSTextureVK::Layout layout, b static VkAccessFlags2 GetAccessFlags(GSTextureVK::Layout layout, bool color) { +#define VK_ACCESS_2_READ_WRITE_BITS(x) VK_ACCESS_2_##x##_READ_BIT | VK_ACCESS_2_##x##_WRITE_BIT static constexpr VkPipelineStageFlags2 s_vk_access_mapping[] = { VK_ACCESS_2_NONE, // Undefined VK_ACCESS_2_HOST_WRITE_BIT, // Preinitialized - VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, // ColorAttachment - VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // DepthStencilAttachment + VK_ACCESS_2_READ_WRITE_BITS(COLOR_ATTACHMENT), // ColorAttachment + VK_ACCESS_2_READ_WRITE_BITS(DEPTH_STENCIL_ATTACHMENT), // DepthStencilAttachment VK_ACCESS_2_SHADER_READ_BIT, // ShaderReadOnly VK_ACCESS_2_TRANSFER_WRITE_BIT, // ClearDst VK_ACCESS_2_TRANSFER_READ_BIT, // CopySrc VK_ACCESS_2_TRANSFER_WRITE_BIT, // CopyDst - VK_ACCESS_2_TRANSFER_READ_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT, // CopySelf + VK_ACCESS_2_READ_WRITE_BITS(TRANSFER), // CopySelf VK_ACCESS_2_TRANSFER_READ_BIT, // BlitSrc VK_ACCESS_2_TRANSFER_WRITE_BIT, // BlitDst - VK_ACCESS_2_TRANSFER_READ_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT, // BlitSelf + VK_ACCESS_2_READ_WRITE_BITS(TRANSFER), // BlitSelf VK_ACCESS_2_NONE, // PresentSrc VK_ACCESS_2_NONE, // FeedbackLoop (overridden) - VK_ACCESS_2_SHADER_STORAGE_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, // ReadWriteImage - VK_ACCESS_2_SHADER_STORAGE_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, // ComputeReadWriteImage + VK_ACCESS_2_READ_WRITE_BITS(SHADER_STORAGE), // ReadWriteImage + VK_ACCESS_2_READ_WRITE_BITS(SHADER_STORAGE), // ComputeReadWriteImage VK_ACCESS_2_NONE, // General }; +#undef VK_ACCESS_2_READ_WRITE_BITS static_assert(std::size(s_vk_access_mapping) == static_cast(GSTextureVK::Layout::Count)); if (layout == GSTextureVK::Layout::FeedbackLoop) @@ -161,18 +168,25 @@ std::unique_ptr GSTextureVK::Create(Usage usage, Format format, int const VkFormat vk_format = GSDeviceVK::GetInstance()->LookupNativeFormat(format); - VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, nullptr, 0, VK_IMAGE_TYPE_2D, vk_format, - {static_cast(width), static_cast(height), 1}, static_cast(levels), 1, VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_TILING_OPTIMAL}; + VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + ici.imageType = VK_IMAGE_TYPE_2D; + ici.format = vk_format; + ici.extent = {static_cast(width), static_cast(height), 1}; + ici.mipLevels = levels; + ici.arrayLayers = 1; + ici.samples = VK_SAMPLE_COUNT_1_BIT; + ici.tiling = VK_IMAGE_TILING_OPTIMAL; VmaAllocationCreateInfo aci = {}; aci.usage = VMA_MEMORY_USAGE_GPU_ONLY; aci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT; aci.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - VkImageViewCreateInfo vci = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr, 0, VK_NULL_HANDLE, - VK_IMAGE_VIEW_TYPE_2D, vk_format, s_identity_swizzle, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, static_cast(levels), 0, 1}}; + VkImageViewCreateInfo vci = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + vci.viewType = VK_IMAGE_VIEW_TYPE_2D; + vci.format = vk_format; + vci.components = s_identity_swizzle; + vci.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, static_cast(levels), 0, 1}; ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; @@ -250,12 +264,14 @@ std::unique_ptr GSTextureVK::Adopt( VkImage image, Usage usage, Format format, int width, int height, int levels, VkFormat vk_format) { // Only need to create the image view, this is mainly for swap chains. - const VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr, 0, image, - VK_IMAGE_VIEW_TYPE_2D, vk_format, s_identity_swizzle, - {IsDepthStencil(usage) ? - static_cast(VK_IMAGE_ASPECT_DEPTH_BIT) : - static_cast(VK_IMAGE_ASPECT_COLOR_BIT), - 0u, static_cast(levels), 0u, 1u}}; + VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + view_info.image = image; + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_info.format = vk_format; + view_info.components = s_identity_swizzle; + view_info.subresourceRange.aspectMask = IsDepthStencil(usage) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + view_info.subresourceRange.levelCount = levels; + view_info.subresourceRange.layerCount = 1; // Memory is managed by the owner of the image. VkImageView view = VK_NULL_HANDLE; @@ -355,8 +371,10 @@ void GSTextureVK::CopyTextureDataForUpload(void* dst, const void* src, u32 pitch VkBuffer GSTextureVK::AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 height) const { const u32 size = upload_pitch * height; - const VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, static_cast(size), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, nullptr}; + VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bci.size = size; + bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; // Don't worry about setting the coherent bit for this upload, the main reason we had // that set in StreamBuffer was for MoltenVK, which would upload the whole buffer on @@ -393,9 +411,15 @@ void GSTextureVK::UpdateFromBuffer(VkCommandBuffer cmdbuf, int level, u32 x, u32 else if (old_layout != Layout::CopyDst) TransitionSubresourcesToLayout(cmdbuf, level, 1, old_layout, Layout::CopyDst); - const VkBufferImageCopy bic = {static_cast(buffer_offset), row_length, buffer_height, - {VK_IMAGE_ASPECT_COLOR_BIT, static_cast(level), 0u, 1u}, {static_cast(x), static_cast(y), 0}, - {width, height, 1u}}; + VkBufferImageCopy bic = {}; + bic.bufferOffset = buffer_offset; + bic.bufferRowLength = row_length; + bic.bufferImageHeight = buffer_height; + bic.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + bic.imageSubresource.mipLevel = level; + bic.imageSubresource.layerCount = 1; + bic.imageOffset = {static_cast(x), static_cast(y), 0}; + bic.imageExtent = {width, height, 1}; vkCmdCopyBufferToImage(cmdbuf, buffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bic); @@ -581,12 +605,13 @@ void GSTextureVK::GenerateMipmap() TransitionSubresourcesToLayout(cmdbuf, src_level, 1, m_layout, Layout::BlitSrc); TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, m_layout, Layout::BlitDst); - const VkImageBlit blit = { - {VK_IMAGE_ASPECT_COLOR_BIT, static_cast(src_level), 0u, 1u}, // srcSubresource - {{0, 0, 0}, {src_width, src_height, 1}}, // srcOffsets - {VK_IMAGE_ASPECT_COLOR_BIT, static_cast(dst_level), 0u, 1u}, // dstSubresource - {{0, 0, 0}, {dst_width, dst_height, 1}} // dstOffsets - }; + VkImageBlit blit; + blit.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, static_cast(src_level), 0u, 1u}; + blit.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, static_cast(dst_level), 0u, 1u}; + blit.srcOffsets[0] = {0, 0, 0}; + blit.dstOffsets[0] = {0, 0, 0}; + blit.srcOffsets[1] = {src_width, src_height, 1}; + blit.dstOffsets[1] = {dst_width, dst_height, 1}; vkCmdBlitImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); @@ -700,12 +725,12 @@ void GSTextureVK::TransitionSubresourcesToLayout( pxAssert(new_layout != Layout::Preinitialized); VkImageMemoryBarrier2 barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; - barrier.srcStageMask = GetPipelineStageFlags(old_layout, !IsDepthStencil()); - barrier.dstStageMask = GetPipelineStageFlags(new_layout, !IsDepthStencil()); + barrier.srcStageMask = GetPipelineStageFlags(old_layout, !IsDepthStencil()); + barrier.dstStageMask = GetPipelineStageFlags(new_layout, !IsDepthStencil()); barrier.srcAccessMask = GetAccessFlags(old_layout, !IsDepthStencil()); barrier.dstAccessMask = GetAccessFlags(new_layout, !IsDepthStencil()); - barrier.oldLayout = GetVkImageLayout(old_layout); - barrier.newLayout = GetVkImageLayout(new_layout); + barrier.oldLayout = GetVkImageLayout(old_layout); + barrier.newLayout = GetVkImageLayout(new_layout); barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = m_image; @@ -745,8 +770,10 @@ VkFramebuffer GSTextureVK::GetLinkedFramebuffer(GSTextureVK* depth_texture, bool const VkRenderPass rp = GSDeviceVK::GetInstance()->GetRenderPass( !IsDepthStencil() ? m_vk_format : VK_FORMAT_UNDEFINED, !IsDepthStencil() ? (depth_texture ? depth_texture->m_vk_format : VK_FORMAT_UNDEFINED) : m_vk_format, - VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, feedback_loop_color, feedback_loop_depth); + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + feedback_loop_color, feedback_loop_depth); if (!rp) return VK_NULL_HANDLE; @@ -784,8 +811,10 @@ std::unique_ptr GSDownloadTextureVK::Create(u32 width, u32 const u32 buffer_size = GetBufferSize(width, height, format, GSDeviceVK::GetInstance()->GetBufferCopyRowPitchAlignment()); - const VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0u, buffer_size, - VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 0u, nullptr}; + VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bci.size = buffer_size; + bci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VmaAllocationCreateInfo aci = {}; aci.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;