Vulkan vkCreateInstance - 访问位置0x0000000000000000时出现访问冲突写入错误

4

我正在尝试使用Vulkan编写一个基本程序,但是我一直遇到运行时错误。

Exception thrown at 0x00007FFDC27A8DBE (vulkan-1.dll) in VulkanTest.exe: 0xC0000005: Access violation writing location 0x0000000000000000.

这似乎是一个相对常见的问题,由于未能初始化vkCreateInstance函数的参数而导致。我尝试过所有我发现的针对其他人提出的解决方案,甚至初始化了我相当确定不需要的东西,但我仍然无法解决问题。该程序使用MSVC编译器用C语言编写。

#include "stdio.h"
#include "SDL.h"
#include "vulkan\vulkan.h"
#include "System.h"

int main(int argc, char *argv[])
{
    //Initialize SDL
    if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    {
        printf("Error");
    }
    printf("Success");

    //Initialize Vulkan
    VkInstance VulkanInstance;

    VkApplicationInfo VulkanApplicationInfo;
    VulkanApplicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
    VulkanApplicationInfo.pNext = 0;
    VulkanApplicationInfo.pApplicationName = "VulkanTest";
    VulkanApplicationInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
    VulkanApplicationInfo.pEngineName = "VulkanTest";
    VulkanApplicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
    VulkanApplicationInfo.apiVersion = VK_API_VERSION_1_0;


    VkInstanceCreateInfo VulkanCreateInfo = {0,0,0,0,0,0,0,0};
    VulkanCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    VulkanCreateInfo.pNext = 0;
    VulkanCreateInfo.pApplicationInfo = &VulkanApplicationInfo;
    VulkanCreateInfo.enabledLayerCount = 1;
    VulkanCreateInfo.ppEnabledLayerNames = "VK_LAYER_KHRONOS_validation";
    vkEnumerateInstanceExtensionProperties(0, VulkanCreateInfo.enabledExtensionCount,             
    VulkanCreateInfo.ppEnabledExtensionNames);

    //Create Vulkan Instance
    if(vkCreateInstance(&VulkanCreateInfo, 0, &VulkanInstance) != VK_SUCCESS)
    {
        printf("Vulkan instance was not created");
    }

    //Create SDL Window
    SDL_Window* window;
    window = SDL_CreateWindow("VulkanTest", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 0, 0, SDL_WINDOW_VULKAN || SDL_WINDOW_FULLSCREEN_DESKTOP);

    SDL_Delay(10000);
    return 0;
}

那是一个空指针。你是否忘记初始化某些东西了?通过调试器逐步查找该指针应该表示什么。 - tadman
请标记您正在使用的语言。不要在C问题上贴上C++标签。 (Simplified Chinese) - tadman
这是一个C++库。我认为它可能与此相关。哪个空指针?我相信有几个。 - FeeeshMeister
这是C代码。请使用问题的可见部分进行标记。请注意:正在查看标签并尝试回答C++问题的人将寻找C++代码。 - tadman
ppEnabledLayerNames = "VK_LAYER_KHRONOS_validation"。这是如何工作的?看起来像是类型错误。一个是char*,另一个是char** - krOoze
vkEnumerateInstanceExtensionProperties(0,VulkanCreateInfo.enabledExtensionCount, VulkanCreateInfo.ppEnabledExtensionNames); 这也不应该编译。你传递了 uint32_t,但参数是 uint32_t* - krOoze
1个回答

2
你确定是调用 vkCreateInstance() 导致崩溃的吗?我没有尝试调试你展示的代码(那是你的工作),但仅查看代码所做的调用,应该是调用 vkEnumerateInstanceExtensionProperties() 导致崩溃(如果它甚至能编译通过!)。 vkEnumerateInstanceExtensionProperties() 的第二个参数期望一个 uint32_t* 指针,但是你传递了一个已初始化为 0 的 uint32_t 值(VulkanCreateInfo.enabledExtensionCount),因此会使 pPropertyCount 参数成为 NULL 指针(如果它甚至能编译通过)。
你在第三个参数中传递了 VulkanCreateInfo.ppEnabledExtensionNames(如果它甚至能编译通过),而且 ppEnabledExtensionNames 已初始化为 NULL。根据 vkEnumerateInstanceExtensionProperties() 的文档:

如果 pProperties 为 NULL,则返回可用扩展属性数目的 pPropertyCount。否则,pPropertyCount 必须指向由用户设置的 pProperties 数组中元素数量,并在返回时覆盖变量,以包含实际写入 pProperties 的结构数量。

由于 pPropertCount 为 NULL,vkEnumerateInstanceExtensionProperties() 没有地方可以将属性计数写入!这肯定会导致试图写入地址 0x0000000000000000 的访问冲突。
文档明确指出:

pPropertyCount 必须 是一个指向 uint32_t 值的有效指针

此外,你对 vkEnumerateInstanceExtensionProperties() 的调用逻辑上也是错误的,因为第三个参数期望一个指向 VkExtensionProperties 结构体数组的指针,但是 VulkanCreateInfo.ppEnabledExtensionNames 实际上是一个指向 const char* UTF-8 字符串数组的指针。
换句话说,你不应该使用 vkEnumerateInstanceExtensionProperties() 来初始化调用 vkCreateInstance() 的条件。你完全误用了 vkEnumerateInstanceExtensionProperties()。你可能想要使用 SDL_Vulkan_GetInstanceExtensions(),例如:
uint32_t ExtensionCount = 0;
if (!SDL_Vulkan_GetInstanceExtensions(NULL, &ExtensionCount, NULL))
{
    ...
}

const char **ExtensionNames = (const char **) SDL_malloc(sizeof(const char *) * ExtensionCount);
if (!ExtensionNames)
{
    ...
}

if (!SDL_Vulkan_GetInstanceExtensions(NULL, &ExtensionCount, ExtensionNames))
{
    SDL_free(ExtensionNames);
    ...
}

VulkanCreateInfo.enabledExtensionCount = ExtensionCount;
VulkanCreateInfo.ppEnabledExtensionNames = ExtensionNames;

if (vkCreateInstance(&VulkanCreateInfo, 0, &VulkanInstance) != VK_SUCCESS)
{
    ...
}

SDL_free(ExtensionNames);
...

我正在使用那个教程的部分内容,但是使用的是SDL2而不是GLFW。事实证明,SDL2提供了一个类似的获取扩展的函数。我会尝试使用它。 - FeeeshMeister

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接