Vulkan API и C - запрос свойств физического устройства вызывает segfault - PullRequest
0 голосов
/ 23 января 2020

Это основная функция вызывающего абонента

void createVulkanContext()
{
  queueFamilyCount = 0;

  populatePhysicalDevice(&instance, &physicalDevice);
  physicalDeviceTest(&physicalDevice); // This one works fine

  populateQueueFamilies(physicalDevice, &queueFamilyIndicesList, &queueFamilyCount, surface);
  physicalDeviceTest(&physicalDevice); // This one causes segfault
}

, и это функция запроса

void physicalDeviceTest(VkPhysicalDevice* gPhysicalDevice)
{

  printf("%p\n", gPhysicalDevice);

  VkPhysicalDeviceProperties pdProp;
  vkGetPhysicalDeviceProperties(*gPhysicalDevice, &pdProp);

  printf("%u\n", pdProp.deviceID);
  printf("%s\n", pdProp.deviceName);
  printf("%u\n", pdProp.apiVersion);
  printf("%u\n", pdProp.driverVersion);
  printf("%u\n", pdProp.vendorID);
}

, которая печатает это

0x55555555a1e8
26958
Unknown AMD GPU
4198513
8388708
4098
0x55555555a1e8

Это gdb backtrace результат

Thread 1 "VulkanApp1090" received signal SIGSEGV, Segmentation fault.
0x00007ffff7f63467 in vkGetPhysicalDeviceProperties () from /usr/lib/libvulkan.so.1
(gdb) backtrace
#0  0x00007ffff7f63467 in vkGetPhysicalDeviceProperties () from /usr/lib/libvulkan.so.1
#1  0x0000555555555602 in physicalDeviceTest (gPhysicalDevice=0x55555555a1e8 <physicalDevice>)

Насколько я знаю, этого не должно происходить, потому что функция populateQueueFamilies(physicalDevice, &queueFamilyIndicesList ...) на самом деле не меняет physicalDevice переменную, которая передается по значению.


Full код

typedef struct QueueFamilyIndices
{
  int graphicsFamilySupportQueueIndex;
  int computeFamilySupportQueueIndex;
  int transferFamilySupportQueueIndex;
  int sparsebindingFamilySupportQueueIndex;
  int protectedFamilySupportQueueIndex;
  int presentFamilySupportQueueIndex;

} QueueFamilyIndices;


VkInstance instance;

VkPhysicalDevice physicalDevice;
VkDevice         logicalDevice;

QueueFamilyIndices* queueFamilyIndicesList;
QueueFamilyIndices  selectedQueueFamilyIndex;
uint32_t            queueFamilyCount;

VkQueue      graphicsQueue;
VkSurfaceKHR surface;


void populateQueueFamilyQueueIndices(VkQueueFamilyProperties gQueueFamilyProperties,
                                     uint32_t                gQueueFamilyIndex,
                                     QueueFamilyIndices*     gQueueFamilyIndices)
{
  gQueueFamilyIndices->graphicsFamilySupportQueueIndex      = -1;
  gQueueFamilyIndices->computeFamilySupportQueueIndex       = -1;
  gQueueFamilyIndices->transferFamilySupportQueueIndex      = -1;
  gQueueFamilyIndices->sparsebindingFamilySupportQueueIndex = -1;
  gQueueFamilyIndices->protectedFamilySupportQueueIndex     = -1;

  if (gQueueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT)
    {
      gQueueFamilyIndices->graphicsFamilySupportQueueIndex = gQueueFamilyIndex;
    }
  if (gQueueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT)
    {
      gQueueFamilyIndices->computeFamilySupportQueueIndex = gQueueFamilyIndex;
    }
  if (gQueueFamilyProperties.queueFlags & VK_QUEUE_TRANSFER_BIT)
    {
      gQueueFamilyIndices->transferFamilySupportQueueIndex = gQueueFamilyIndex;
    }
  if (gQueueFamilyProperties.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)
    {
      gQueueFamilyIndices->sparsebindingFamilySupportQueueIndex = gQueueFamilyIndex;
    }
  if (gQueueFamilyProperties.queueFlags & VK_QUEUE_PROTECTED_BIT)
    {
      gQueueFamilyIndices->protectedFamilySupportQueueIndex = gQueueFamilyIndex;
    }
}


void populateQueueFamilies(VkPhysicalDevice     gPhysicalDevice,
                           QueueFamilyIndices** gQueueFamilyIndicesList,
                           uint32_t*            gQueueFamilyCount,
                           VkSurfaceKHR         surface)
{

  uint32_t queueFamilyCount;
  vkGetPhysicalDeviceQueueFamilyProperties(gPhysicalDevice, &queueFamilyCount, VK_NULL_HANDLE);

  VkQueueFamilyProperties queueFamilies[queueFamilyCount];
  vkGetPhysicalDeviceQueueFamilyProperties(gPhysicalDevice, &queueFamilyCount, queueFamilies);

  VkBool32 presentFamilySupported;

  *gQueueFamilyIndicesList = malloc(sizeof(QueueFamilyIndices*) * queueFamilyCount);

  for (uint32_t i = 0; i < queueFamilyCount; ++i)
    {
      QueueFamilyIndices gQueueFamilyIndices;

      populateQueueFamilyQueueIndices(queueFamilies[i], i, &gQueueFamilyIndices);

      presentFamilySupported = false;

      vkGetPhysicalDeviceSurfaceSupportKHR(gPhysicalDevice, i, surface, &presentFamilySupported);
      gQueueFamilyIndices.presentFamilySupportQueueIndex = presentFamilySupported ? i : -1;

      gQueueFamilyIndicesList[i]  = malloc(sizeof(QueueFamilyIndices));
      *gQueueFamilyIndicesList[i] = gQueueFamilyIndices;
    }

  *gQueueFamilyCount = queueFamilyCount;
}

void physicalDeviceTest(VkPhysicalDevice* gPhysicalDevice)
{

  printf("%p\n", gPhysicalDevice);

  VkPhysicalDeviceProperties pdProp;
  vkGetPhysicalDeviceProperties(*gPhysicalDevice, &pdProp);

  printf("%u\n", pdProp.deviceID);
  printf("%s\n", pdProp.deviceName);
  printf("%u\n", pdProp.apiVersion);
  printf("%u\n", pdProp.driverVersion);
  printf("%u\n", pdProp.vendorID);
}

void createVulkanContext()
{
  queueFamilyCount = 0;

  populatePhysicalDevice(&instance, &physicalDevice);
  physicalDeviceTest(&physicalDevice); // This one works fine

  populateQueueFamilies(physicalDevice, &queueFamilyIndicesList, &queueFamilyCount, surface);
  physicalDeviceTest(&physicalDevice); // This one causes segfault
}

Диагностика немного больше заставляет меня думать

      gQueueFamilyIndicesList[i]  = malloc(sizeof(QueueFamilyIndices));
      *gQueueFamilyIndicesList[i] = gQueueFamilyIndices;

, потому что их комментирование исправляет ошибку.


TL; DR

Та же функция (physicalDeviceTest), вызываемая снова, вызывает segfault

void createVulkanContext()
{
  queueFamilyCount = 0;

  populatePhysicalDevice(&instance, &physicalDevice);
  physicalDeviceTest(&physicalDevice); // This one works fine

  populateQueueFamilies(physicalDevice, &queueFamilyIndicesList, &queueFamilyCount, surface);
  physicalDeviceTest(&physicalDevice); // This one causes segfault
}

, вероятно, из-за этих вызовов

      gQueueFamilyIndicesList[i]  = malloc(sizeof(QueueFamilyIndices));
      *gQueueFamilyIndicesList[i] = gQueueFamilyIndices;

в функции populateQueueFamilies, хотя я ' Я не уверен, почему или как.

1 Ответ

0 голосов
/ 23 января 2020

Разобрался.

*gQueueFamilyIndicesList = malloc(sizeof(QueueFamilyIndices) * queueFamilyCount);

теперь правильно распределяет память и указывает на первый блок памяти в списке.

Разыменование и приравнивание как это

(*gQueueFamilyIndicesList)[i] = gQueueFamilyIndices;

теперь работает так, как я ожидал.

Скобки вокруг gQueueFamilyIndicesList важны, поскольку оператор [] имеет приоритет над *.

*gQueueFamilyIndicesList[i] = *(*(gQueueFamilyIndicesList + i))

и

(*gQueueFamilyIndicesList)[i] = *((*gQueueFamilyIndicesList) + i)

...