diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index ce7fde3f1..4b6334316 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -2594,6 +2594,14 @@ string ToStrHelper::Get(const VkClearAttachment &el) el.colorAttachment, ToStr::Get(el.clearValue).c_str()); } +template <> +string ToStrHelper::Get(const VkQueueFamilyProperties &el) +{ + return StringFormat::Fmt( + "%s x %u, %u bits, %s", ToStr::Get((VkQueueFlagBits)el.queueFlags).c_str(), el.queueCount, + el.timestampValidBits, ToStr::Get(el.minImageTransferGranularity).c_str()); +} + template <> string ToStrHelper::Get(const VkExtent2D &el) { diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index b84bea516..8a6991bc6 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -44,7 +44,7 @@ struct VkInitParams : public RDCInitParams void Set(const VkInstanceCreateInfo *pCreateInfo, ResourceId inst); - static const uint32_t VK_SERIALISE_VERSION = 0x0000004; + static const uint32_t VK_SERIALISE_VERSION = 0x0000005; // version number internal to vulkan stream uint32_t SerialiseVersion; @@ -273,7 +273,16 @@ private: m_QueueFamilyIdx; // the family index that we've selected in CreateDevice for our queue VkQueue m_Queue; // the queue used for our own command buffer work + // the physical devices vector m_PhysicalDevices; + + // the single queue family supported for each physical device + vector > m_SupportedQueueFamilies; + + // the supported queue family for the created device + uint32_t m_SupportedQueueFamily; + + // the queue families (an array of count for each) for the created device vector m_QueueFamilies; vector m_MemIdxMaps; diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index fbfedafbd..d1064cc0d 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -470,17 +470,32 @@ bool WrappedVulkan::Serialise_vkEnumeratePhysicalDevices(Serialiser *localSerial VkPhysicalDeviceProperties physProps; VkPhysicalDeviceMemoryProperties memProps; VkPhysicalDeviceFeatures physFeatures; + VkQueueFamilyProperties queueProps[16]; if(m_State >= WRITING) { ObjDisp(instance)->GetPhysicalDeviceProperties(Unwrap(*pPhysicalDevices), &physProps); ObjDisp(instance)->GetPhysicalDeviceMemoryProperties(Unwrap(*pPhysicalDevices), &memProps); ObjDisp(instance)->GetPhysicalDeviceFeatures(Unwrap(*pPhysicalDevices), &physFeatures); + + uint32_t queueCount = 0; + ObjDisp(instance)->GetPhysicalDeviceQueueFamilyProperties(Unwrap(*pPhysicalDevices), + &queueCount, NULL); + + if(queueCount < 16) + { + RDCWARN("More than 16 queues"); + queueCount = 16; + } + + ObjDisp(instance)->GetPhysicalDeviceQueueFamilyProperties(Unwrap(*pPhysicalDevices), + &queueCount, queueProps); } localSerialiser->Serialise("physProps", physProps); localSerialiser->Serialise("memProps", memProps); localSerialiser->Serialise("physFeatures", physFeatures); + localSerialiser->SerialisePODArray<16>("queueProps", queueProps); VkPhysicalDevice pd = VK_NULL_HANDLE; @@ -580,6 +595,7 @@ VkResult WrappedVulkan::vkEnumeratePhysicalDevices(VkInstance instance, RDCASSERTEQUAL(vkr, VK_SUCCESS); m_PhysicalDevices.resize(count); + m_SupportedQueueFamilies.resize(count); for(uint32_t i = 0; i < count; i++) { @@ -632,6 +648,89 @@ VkResult WrappedVulkan::vkEnumeratePhysicalDevices(VkInstance instance, } } } + + // find the queue with the most bits set and only report that one + + { + uint32_t count = 0; + ObjDisp(m_PhysicalDevices[i]) + ->GetPhysicalDeviceQueueFamilyProperties(Unwrap(m_PhysicalDevices[i]), &count, NULL); + + VkQueueFamilyProperties *props = new VkQueueFamilyProperties[count]; + ObjDisp(m_PhysicalDevices[i]) + ->GetPhysicalDeviceQueueFamilyProperties(Unwrap(m_PhysicalDevices[i]), &count, props); + + uint32_t best = 0; + + // don't need to explicitly check for transfer, because graphics bit + // implies it. We do have to check for compute bit, because there might + // be a graphics only queue - it just means we have to keep looking + // to find the grpahics & compute queue family which is guaranteed. + for(uint32_t q = 1; q < count; q++) + { + // compare current against the known best + VkQueueFamilyProperties ¤tProps = props[q]; + VkQueueFamilyProperties &bestProps = props[best]; + + const bool currentGraphics = (currentProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0; + const bool currentCompute = (currentProps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0; + const bool currentSparse = (currentProps.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0; + + const bool bestGraphics = (bestProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0; + const bool bestCompute = (bestProps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0; + const bool bestSparse = (bestProps.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0; + + // if one has graphics bit set, but the other doesn't + if(currentGraphics != bestGraphics) + { + // if current has graphics but best doesn't, we have a new best + if(currentGraphics) + best = q; + continue; + } + + if(currentCompute != bestCompute) + { + // if current has compute but best doesn't, we have a new best + if(currentCompute) + best = q; + continue; + } + + // if we've gotten here, both best and current have graphics and compute. Check + // to see if the current is somehow better than best (in the case of a tie, we + // keep the lower index of queue). + + if(currentSparse != bestSparse) + { + if(currentSparse) + best = q; + continue; + } + + if(currentProps.timestampValidBits != bestProps.timestampValidBits) + { + if(currentProps.timestampValidBits > bestProps.timestampValidBits) + best = q; + continue; + } + + if(currentProps.minImageTransferGranularity.width < + bestProps.minImageTransferGranularity.width || + currentProps.minImageTransferGranularity.height < + bestProps.minImageTransferGranularity.height || + currentProps.minImageTransferGranularity.depth < + bestProps.minImageTransferGranularity.depth) + { + best = q; + continue; + } + } + + m_SupportedQueueFamilies[i] = std::make_pair(best, props[best]); + + SAFE_DELETE_ARRAY(props); + } } if(pPhysicalDeviceCount) @@ -653,6 +752,7 @@ bool WrappedVulkan::Serialise_vkCreateDevice(Serialiser *localSerialiser, SERIALISE_ELEMENT(ResourceId, physId, GetResID(physicalDevice)); SERIALISE_ELEMENT(VkDeviceCreateInfo, serCreateInfo, *pCreateInfo); SERIALISE_ELEMENT(ResourceId, devId, GetResID(*pDevice)); + SERIALISE_ELEMENT(uint32_t, queueFamily, m_SupportedQueueFamily); if(m_State == READING) { @@ -660,6 +760,8 @@ bool WrappedVulkan::Serialise_vkCreateDevice(Serialiser *localSerialiser, // in the serialised VkDeviceCreateInfo don't double-free VkDeviceCreateInfo createInfo = serCreateInfo; + m_SupportedQueueFamily = queueFamily; + std::vector Extensions; for(uint32_t i = 0; i < createInfo.enabledExtensionCount; i++) { @@ -1002,6 +1104,11 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice, m_QueueFamilies[family][q] = VK_NULL_HANDLE; } + // find the matching physical device + for(size_t i = 0; i < m_PhysicalDevices.size(); i++) + if(m_PhysicalDevices[i] == physicalDevice) + m_SupportedQueueFamily = m_SupportedQueueFamilies[i].first; + VkLayerDeviceCreateInfo *layerCreateInfo = (VkLayerDeviceCreateInfo *)pCreateInfo->pNext; // step through the chain of pNext until we get to the link info diff --git a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp index 050d31370..11272afb3 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp @@ -87,9 +87,18 @@ void WrappedVulkan::vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevic void WrappedVulkan::vkGetPhysicalDeviceQueueFamilyProperties( VkPhysicalDevice physicalDevice, uint32_t *pCount, VkQueueFamilyProperties *pQueueFamilyProperties) { - ObjDisp(physicalDevice) - ->GetPhysicalDeviceQueueFamilyProperties(Unwrap(physicalDevice), pCount, - pQueueFamilyProperties); + // pretend to only have one queue, the one with graphics capability + if(pCount) + *pCount = 1; + + if(pQueueFamilyProperties) + { + // find the matching physical device + for(size_t i = 0; i < m_PhysicalDevices.size(); i++) + if(m_PhysicalDevices[i] == physicalDevice) + *pQueueFamilyProperties = m_SupportedQueueFamilies[i].second; + return; + } } void WrappedVulkan::vkGetPhysicalDeviceMemoryProperties( diff --git a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp index 743a67e67..01eef4f1a 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp @@ -29,7 +29,7 @@ bool WrappedVulkan::Serialise_vkGetDeviceQueue(Serialiser *localSerialiser, VkDe VkQueue *pQueue) { SERIALISE_ELEMENT(ResourceId, devId, GetResID(device)); - SERIALISE_ELEMENT(uint32_t, familyIdx, queueFamilyIndex); + SERIALISE_ELEMENT(uint32_t, familyIdx, m_SupportedQueueFamily); SERIALISE_ELEMENT(uint32_t, idx, queueIndex); SERIALISE_ELEMENT(ResourceId, queueId, GetResID(*pQueue));