VkSurfaceKHR 指针的值在没有任何显式赋值的函数调用后发生变化

VkSurfaceKHR pointer's value changes after a function call without any explicit assignments

这是来自 Vulkan 验证层的删节错误消息

Invalid VkSurfaceKHR Object 0x1000000002.
Objects: 1
        [0] 0x1000000002, type: 1000000000, name: NULL

由此函数抛出

populateQueueFamilies(&physicalDevice, &queueFamilyIndicesList, &queueFamilyCount, &surface);

现在这不应该发生,因为

populatePhysicalDevice(&instance, &physicalDevice, &surface);
populateQueueFamilies(&physicalDevice, &queueFamilyIndicesList, &queueFamilyCount, &surface);

它之前的函数也使用了 surface 变量并且没有抛出任何错误!

我很生气一些打印函数,看看变量是否有问题,瞧


  printf("%p\n", surface); // prints - 0x10000000001

  populatePhysicalDevice(&instance, &physicalDevice, &surface);

  printf("%p\n", surface); // prints - 0x10000000002

  populateQueueFamilies(&physicalDevice, &queueFamilyIndicesList, &queueFamilyCount, &surface);

我知道当您将局部变量的地址分配给指针时会发生此类问题。

但我认为这不是这里发生的事情,因为 populateQueueFamilies 中唯一触及 surface var 的函数是这个函数:

void populateSwapchainSupportDetails(SwapchainSupportDetails* gSwapchainSupportDetails,
                                     VkPhysicalDevice*        gPhysicalDevice,
                                     VkSurfaceKHR*            gSurface)
{

  VkSurfaceCapabilitiesKHR lCapabilities;
  uint32_t                 formatCount;
  uint32_t                 presentModeCount;

  vkGetPhysicalDeviceSurfaceCapabilitiesKHR(*gPhysicalDevice, *gSurface, &lCapabilities);

  uint32_t gFormatCount;
  vkGetPhysicalDeviceSurfaceFormatsKHR(*gPhysicalDevice, *gSurface, &gFormatCount, VK_NULL_HANDLE);

  VkSurfaceFormatKHR lFormats[gFormatCount];
  if (gFormatCount != 0)
    {
      vkGetPhysicalDeviceSurfaceFormatsKHR(*gPhysicalDevice, *gSurface, &gFormatCount, lFormats);
    }

  uint32_t gPresentModeCount;

  vkGetPhysicalDeviceSurfacePresentModesKHR(*gPhysicalDevice, *gSurface, &gPresentModeCount, VK_NULL_HANDLE);

  VkPresentModeKHR lPresentModes[gPresentModeCount];
  if (gPresentModeCount != 0)
    {
      vkGetPhysicalDeviceSurfacePresentModesKHR(
          *gPhysicalDevice, *gSurface, &gPresentModeCount, lPresentModes);
    }

  gSwapchainSupportDetails->capabilities     = lCapabilities;
  gSwapchainSupportDetails->formatCount      = gFormatCount;
  gSwapchainSupportDetails->presentModeCount = gPresentModeCount;

  gSwapchainSupportDetails->formats = malloc(sizeof(lFormats));
  memcpy(gSwapchainSupportDetails->formats, lFormats, sizeof(lFormats));

  gSwapchainSupportDetails->formats = malloc(sizeof(lPresentModes));
  memcpy(gSwapchainSupportDetails->formats, lPresentModes, sizeof(lPresentModes));

有一个有效的临时修复:

VkSurfaceKHR surface1 = surface;
VkSurfaceKHR surface2 = surface;

并将每个 surface(number) 传递给不同的函数。

哦,天哪,这是一次有趣的旅程,最终让我完全被震撼了;轻松地说 - 缺乏 天才。

找了一段时间后,尝试调试东西,我最终发现了一个真正 真正 导致各种问题的愚蠢错误。

我是通过 valgrind 得到的。

我运行它使用这个命令

valgrind\
       --leak-check=full\
       --leak-resolution=high\
       --show-leak-kinds=all\
       --xtree-leak=yes\
       --track-origins=yes\
       --show-mismatched-frees=yes\

它给了我很多信息,这里是它们的删节版

Invalid write of size 8
    at <someaddress>: populateQueueFamilies ()
...
...
Invalid write of size 8
    at <someaddress>: populateQueueFamilies ()
...
...
Invalid write of size 8
    at <someaddress>: populateQueueFamilies ()
...
...

无效写入意味着我正在写入无效的内存位置。 一些谷歌搜索告诉我错误消息几乎总是由于 malloc.

的错误使用而发生

这是我的 populateQueueFamilies 函数

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

  uint32_t lQueueFamilyCount;
  vkGetPhysicalDeviceQueueFamilyProperties(*gPhysicalDevice, &lQueueFamilyCount, VK_NULL_HANDLE);

  VkQueueFamilyProperties lQueueFamilies[lQueueFamilyCount];
  vkGetPhysicalDeviceQueueFamilyProperties(*gPhysicalDevice, &lQueueFamilyCount, lQueueFamilies);

  VkBool32 presentFamilySupported;

  (*gQueueFamilyIndicesList) = malloc(sizeof(*lQueueFamilies) * lQueueFamilyCount);

  for (int i = 0; i < lQueueFamilyCount; ++i)
    {
      QueueFamilyIndices gQueueFamilyIndices;

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

      presentFamilySupported = false;
      vkGetPhysicalDeviceSurfaceSupportKHR(*gPhysicalDevice, i, *surface, &presentFamilySupported);

      gQueueFamilyIndices.presentFamilySupportQueueIndex = presentFamilySupported ? i : -1;

      (*gQueueFamilyIndicesList)[i] = gQueueFamilyIndices;
    }

  *gQueueFamilyCount = lQueueFamilyCount;
}

那一行

(*gQueueFamilyIndicesList) = malloc(sizeof(*lQueueFamilies) * lQueueFamilyCount);

在我的脑海里我在想,"yes, I need size to store information from this lQueueFamilies array" 并且我分配了内存来存储来自 *lQueueFamilies 次计数的信息。

但这是错误的!

我需要的是

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

因为我需要 gQueueFamilyIndicesList 来存储来自 VkQueueFamilyProperties 的特定信息,而不是结构本身。

我不知道我是怎么错过的。感谢@krOoze 建议使用 const 和 @solidpixel 建议这可能是内存损坏,确实如此。