diff --git a/src/vulkan/screenshot-layer/screenshot.cpp b/src/vulkan/screenshot-layer/screenshot.cpp index f23eedaac50..71c2bb1bd0f 100644 --- a/src/vulkan/screenshot-layer/screenshot.cpp +++ b/src/vulkan/screenshot-layer/screenshot.cpp @@ -126,15 +126,16 @@ struct device_data { VkPhysicalDeviceProperties properties; struct queue_data *graphic_queue; - struct queue_data **queues; - uint32_t n_queues; + struct queue_data* queue_data_head; + struct queue_data* queue_data_tail; }; /* Mapped from VkQueue */ struct queue_data { struct device_data *device; + struct queue_data *next; VkQueue queue; - VkQueueFlags flags; + uint32_t familyIndex; uint32_t index; }; @@ -296,24 +297,31 @@ static struct device_data *new_device_data(VkDevice device, struct instance_data struct device_data *data = rzalloc(NULL, struct device_data); data->instance = instance; data->device = device; + data->graphic_queue = VK_NULL_HANDLE; + data->queue_data_head = VK_NULL_HANDLE; + data->queue_data_tail = VK_NULL_HANDLE; map_object(HKEY(data->device), data); return data; } static struct queue_data *new_queue_data(VkQueue queue, - const VkQueueFamilyProperties *family_props, struct device_data *device_data, - uint32_t index) + uint32_t index, + uint32_t familyIndex) { struct queue_data *data = rzalloc(device_data, struct queue_data); data->device = device_data; data->queue = queue; - data->flags = family_props->queueFlags; data->index = index; + data->familyIndex = familyIndex; + data->next = VK_NULL_HANDLE; map_object(HKEY(data->queue), data); - - if ((data->flags & VK_QUEUE_GRAPHICS_BIT) != 0) { - device_data->graphic_queue = data; + if (device_data->queue_data_head == VK_NULL_HANDLE) { + device_data->queue_data_head = data; + device_data->queue_data_tail = data; + } else { + device_data->queue_data_tail->next = data; + device_data->queue_data_tail = data; } return data; } @@ -325,48 +333,14 @@ static void destroy_queue(struct queue_data *data) ralloc_free(data); } -static void device_map_queues(struct device_data *data, - const VkDeviceCreateInfo *pCreateInfo) +static void device_destroy_queues(struct device_data *data) { - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) - data->n_queues += pCreateInfo->pQueueCreateInfos[i].queueCount; - data->queues = ralloc_array(data, struct queue_data *, data->n_queues); - - struct instance_data *instance_data = data->instance; - uint32_t n_family_props; - instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device, - &n_family_props, - NULL); - VkQueueFamilyProperties *family_props = - (VkQueueFamilyProperties *)malloc(sizeof(VkQueueFamilyProperties) * n_family_props); - instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device, - &n_family_props, - family_props); - - uint32_t queue_index = 0; - for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) { - for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) { - VkQueue queue; - data->vtable.GetDeviceQueue(data->device, - pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, - j, &queue); - VK_CHECK(data->set_device_loader_data(data->device, queue)); - - data->queues[queue_index] = - new_queue_data(queue, family_props, data, queue_index); - queue_index++; - } + struct queue_data *tmp_queue = VK_NULL_HANDLE; + for (auto it = data->queue_data_head; it != VK_NULL_HANDLE;) { + tmp_queue = it->next; + destroy_queue(it); + it = tmp_queue; } - - free(family_props); - loader_platform_thread_unlock_mutex(&globalLock); -} - -static void device_unmap_queues(struct device_data *data) -{ - for (uint32_t i = 0; i < data->n_queues; i++) - destroy_queue(data->queues[i]); } static void destroy_device_data(struct device_data *data) @@ -600,6 +574,30 @@ static void process_control_socket(struct instance_data *instance_data) } } +static void screenshot_GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) { + struct device_data *device_data = FIND(struct device_data, device); + device_data->vtable.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue); + loader_platform_thread_lock_mutex(&globalLock); + struct queue_data *it = device_data->queue_data_head; + while (it != VK_NULL_HANDLE) { + if (it->queue == *pQueue) { + break; + } + it = it->next; + } + if (it == VK_NULL_HANDLE) { + new_queue_data(*pQueue, device_data, queueIndex, queueFamilyIndex); + } else { + it->familyIndex = queueFamilyIndex; + it->index = queueIndex; + } + loader_platform_thread_unlock_mutex(&globalLock); +} + +static void screenshot_GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) { + if (pQueueInfo) screenshot_GetDeviceQueue(device, pQueueInfo->queueFamilyIndex, pQueueInfo->queueIndex, pQueue); +} + static VkResult screenshot_CreateSwapchainKHR( VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, @@ -692,6 +690,37 @@ static bool get_mem_type_from_properties( return false; } +VkQueue getQueueForScreenshot(struct device_data *device_data, + struct instance_data *instance_data) { + // Find a queue that we can use for taking a screenshot + VkQueue queue = VK_NULL_HANDLE; + VkBool32 presentCapable = VK_FALSE; + uint32_t n_family_props; + instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(device_data->physical_device, + &n_family_props, + NULL); + if (n_family_props > 0) { + VkQueueFamilyProperties *family_props = + (VkQueueFamilyProperties *)malloc(sizeof(VkQueueFamilyProperties) * n_family_props); + instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(device_data->physical_device, + &n_family_props, + family_props); + + // Iterate over all queues for this device, searching for a queue that is graphics capable + for (auto it = device_data->queue_data_head; it != VK_NULL_HANDLE; it = it->next) { + queue = it->queue; + if((family_props[it->familyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { + break; + } else { + // Clear the queue if it's not graphics capable + queue = VK_NULL_HANDLE; + } + } + free(family_props); + } + return queue; +} + // Track allocated resources in writeFile() // and clean them up when they go out of scope. struct WriteFileCleanupData { @@ -863,6 +892,7 @@ static bool write_image( VkImage image, struct device_data* device_data, struct instance_data* instance_data, + struct queue_data* queue_data, struct swapchain_data* swapchain_data) { VkDevice device = device_data->device; @@ -893,8 +923,11 @@ static bool write_image( instance_data->params.region.endY*100, regionEndY); } - queue_data* queue_data = device_data->graphic_queue; - VkQueue queue = queue_data->queue; + VkQueue queue = getQueueForScreenshot(device_data, instance_data); + if (!queue) { + LOG(ERROR, "Unable to find a valid graphics-enabled queue\n"); + return false; + } VkResult err; /* Attempt to set destination format to RGB to make writing to file much faster. @@ -1023,7 +1056,7 @@ static bool write_image( VkCommandPoolCreateInfo cmd_pool_info = {}; cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cmd_pool_info.pNext = NULL; - cmd_pool_info.queueFamilyIndex = queue_data->index; + cmd_pool_info.queueFamilyIndex = queue_data->familyIndex; cmd_pool_info.flags = 0; VK_CHECK(device_data->vtable.CreateCommandPool(device, &cmd_pool_info, NULL, &data.commandPool)); @@ -1110,7 +1143,7 @@ static bool write_image( imageBlitRegion.srcSubresource.mipLevel = 0; imageBlitRegion.srcOffsets[0].x = regionStartX; imageBlitRegion.srcOffsets[0].y = regionStartY; - imageBlitRegion.srcOffsets[0].z = 1; + imageBlitRegion.srcOffsets[0].z = 0; imageBlitRegion.srcOffsets[1].x = regionEndX; imageBlitRegion.srcOffsets[1].y = regionEndY; imageBlitRegion.srcOffsets[1].z = 1; @@ -1216,6 +1249,9 @@ static VkResult screenshot_QueuePresentKHR( VkResult result = VK_SUCCESS; loader_platform_thread_lock_mutex(&globalLock); + VkSemaphoreCreateInfo semaphoreInfo = {}; + VkFenceCreateInfo fenceInfo = {}; + if (pPresentInfo && pPresentInfo->swapchainCount > 0) { VkSwapchainKHR swapchain = pPresentInfo->pSwapchains[0]; @@ -1302,16 +1338,15 @@ static VkResult screenshot_QueuePresentKHR( strcat(full_path, filename); pSemaphoreWaitBeforePresent = pPresentInfo->pWaitSemaphores; semaphoreWaitBeforePresentCount = pPresentInfo->waitSemaphoreCount; - VkSemaphoreCreateInfo semaphoreInfo = {}; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; device_data->vtable.CreateSemaphore(device_data->device, &semaphoreInfo, nullptr, &semaphoreWaitAfterSubmission); - VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; device_data->vtable.CreateFence(device_data->device, &fenceInfo, nullptr, ©Done); if(write_image(full_path, swapchain_data->image, device_data, instance_data, + queue_data, swapchain_data)) { present_info.pWaitSemaphores = &semaphoreWaitAfterSubmission; // Make semaphore here present_info.waitSemaphoreCount = 1; @@ -1406,8 +1441,6 @@ static VkResult screenshot_CreateDevice( get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK); device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData; - - device_map_queues(device_data, pCreateInfo); return result; } @@ -1416,7 +1449,6 @@ static void screenshot_DestroyDevice( const VkAllocationCallbacks* pAllocator) { struct device_data *device_data = FIND(struct device_data, device); - device_unmap_queues(device_data); device_data->vtable.DestroyDevice(device, pAllocator); destroy_device_data(device_data); } @@ -1488,6 +1520,8 @@ static const struct { ADD_HOOK(AcquireNextImageKHR), ADD_HOOK(CreateDevice), + ADD_HOOK(GetDeviceQueue), + ADD_HOOK(GetDeviceQueue2), ADD_HOOK(DestroyDevice), ADD_HOOK(CreateInstance),