4
votes

With Vulkan released, I decided to write (as a hobby) a Vulkan based GUI. However, I'm currently stuck at the very first step - loading Vulkan functions. I'm using Nvidia's C++ Vulkan wrapper which requires, as far as I can see, Vulkan functions to be loaded globally.

I can load local functions successfully, however ::vkCreateInstance fails:

void loadInstanceFunctions() {
    PFN_vkCreateInstance vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(nullptr, "vkCreateInstance"); //works

    ::vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(nullptr, "vkCreateInstance");  //does not work
}

Trying to assign new function pointer globally gives me 2 compile-time errors (compiled using VS2015):

  • expression must be a modifiable lvalue.
  • '=': function as left operand.

There are function prototypes declared in vulkan.h header, for example:

VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
    const VkInstanceCreateInfo*                 pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
    VkInstance*                                 pInstance);

This is what might prevent me from loading functions globally. If I were to define VK_NO_PROTOTYPES, then these prototypes would be skipped and I believe that I could just re-declare them as PFN_vkCreateInstance vkCreateInstance = nullptr; and so on. But is this the correct way?

So, my question - what is the correct way to load Vulkan functions globally?

1
What do you mean by "does not work". Is there a compile-time error, and if so, can you copy/paste the entire compiler output from the error? Or do you mean run-time behavior? - Yakk - Adam Nevraumont
Is there some reason you can't just use the Vulkan SDK to load function pointers? I mean, if you're using NVIDIA's C++ wrapper, then you're clearly not against 3rd party software. And really, working with Vulkan with a validation layer is like working with nitroglycerine without safety equipment. - Nicol Bolas
Quote errors verbatim: don't paraphrase, or copy/paste part of it. Every error and information and warning message generated by the compile, error codes and line numbers and file names and everything. Looking at your code, you have a local variable named vkCreateInstance, then you use scope resolution to access what seems to be a global variable called vkCreateInstance (or at least a global name named vkCreateInstance -- who knows!). I have no idea what it is you are trying to do. Post a minimal reproducible example that generates your error. - Yakk - Adam Nevraumont
@Nicol Bolas, I would like to rely on third party software as less as possible. Also, I learn by doing stuff that seems pointless to others, which is what I might be doing right now. - FrogTheFrog
@Helix for dynamic loading, you can also take a look at Simple Vulkan Extension Loader. - vallentin

1 Answers

7
votes
::vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(nullptr, "vkCreateInstance");  //does not work

You are trying to assign a function pointer to the symbol vkCreateInstance which, by default, is defined as a prototype in vulkan.h.

Defining VK_NO_PROTOTYPES will pre-process out all prototypes:

#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
    const VkInstanceCreateInfo*                 pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
    VkInstance*                                 pInstance);
...
#endif

Once the prototypes are gone you can load vkCreateInstance globally as per the documentation:

#define VK_NO_PROTOTYPES
#include <vulkan/vulkan.h>

#ifdef __cplusplus
extern "C" {
#endif
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *pName);
#ifdef __cplusplus
}
#endif

PFN_vkCreateInstance vkCreateInstance;

int main()
{
        vkCreateInstance = (PFN_vkCreateInstance) vkGetInstanceProcAddr(NULL, "vkCreateInstance");

        return 0;
}