vulkan/screenshot-layer: Correct queueFamilyIndex source

From the Vulkan documentation, the queueFamilyIndex value will be
created with VkDeviceQueueCreateInfo. So let's avoid counting the
index value and just refer to the already-created value.

This will resolve crashes on some GPUs for various workloads.

v2: Needed to use GetDeviceQueue() in order to map the queueFamilyIndex
values. These values can be different when obtaining the queue used
for presentation, so we need to ensure we update the mapped
queueFamilyIndex value for the associated queue_data struct.

Signed-off-by: Casey Bowman <casey.g.bowman@intel.com>
Reviewed-by: Felix DeGrood <felix.j.degrood@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33487>
This commit is contained in:
Casey Bowman 2025-02-10 22:11:59 -08:00 committed by Marge Bot
parent 67d03033e4
commit 111faf2158

View file

@ -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, &copyDone);
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),