Reputation: 739
Vulkan handles are either opaque pointers to struct
s, or simply unsigned 64-bit integers depending on the value of VK_USE_64_BIT_PTR_DEFINES
:
#if (VK_USE_64_BIT_PTR_DEFINES==1)
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
#else
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
#endif
VK_USE_64_BIT_PTR_DEFINES
is set, when not already define
d, in vulkan_core.h
to the following values depending on the platform (at least on my version of the header):
#ifndef VK_USE_64_BIT_PTR_DEFINES
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define VK_USE_64_BIT_PTR_DEFINES 1
#else
#define VK_USE_64_BIT_PTR_DEFINES 0
#endif
#endif
The documentation for that preprocessor #define
states the following:
The
vulkan_core.h
header allows theVK_USE_64_BIT_PTR_DEFINES
definition to be overridden by the application. This allows the application to select either a 64-bit pointer type or a 64-bit unsigned integer type for non-dispatchable handles in the case where the predefined preprocessor check does not identify the desired configuration.
I interpret this declaration as:
It's okay to force
VK_USE_64_BIT_PTR_DEFINES
's value at build time so that I can use either of the definitions.
But, to the best of my knowledge, changing the definitions on header-side only has... Implications for shared libraries compiled as .dll
/ .so
, obviously including the ones of the LunarG's Vulkan SDK I am using (we're not only changing types, we are also changing function signatures).
On Linux or on Windows with MinGW, VK_USE_64_BIT_PTR_DEFINES
is 1
by default. On Windows using MSVC, it defaults to 0
. So I tried changing it to 1
, which, as expected, generates the following linker error (MRE used for that test below).
main.cpp.obj : error LNK2019: unresolved external symbol _vkCmdBindIndexBuffer@20 referenced in function "void __cdecl foo(void)" (?foo@@YAXXZ)
vk_test.exe : fatal error LNK1120: 1 unresolved externals
Edit - clarification after comment: everything is extern "C"{}
in vulkan_core.h
.
I highly, highly doubt the Vulkan documentation is wrong, so I assume I must be missing something very obvious. I suspect the answer is either:
But I don't really know how to confirm my conjunctures.
CMakeLists.txt
cmake_minimum_required(VERSION 3.23)
project(vk_test LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Vulkan REQUIRED)
add_executable(vk_test main.cpp)
# No effect for GCC / MinGW
# On MSVC on the other hand, the value is set to 0 when not defined by user
# Comment that line to build with MSVC
add_compile_definitions(VK_USE_64_BIT_PTR_DEFINES=1)
target_link_libraries(vk_test PUBLIC ${Vulkan_LIBRARY})
target_include_directories(vk_test SYSTEM PUBLIC ${Vulkan_INCLUDE_DIRS})
main.cpp
:#include <cassert>
#include <vulkan/vulkan_core.h>
void foo()
{
assert(false); // The following call has invalid parameters, so no point letting execution reach that point
vkCmdBindIndexBuffer(VK_NULL_HANDLE, VK_NULL_HANDLE, 0, VkIndexType{});
}
int main()
{
return 0;
}
System:
14.34
(hopefully got their numbering correct)1.3.216.0
.Upvotes: 4
Views: 240
Reputation: 739
Okay, just a little bit more research allowed me to clear things up.
TL;DR: it's not meant to be used like that (so I was partially right in my conjunctures, yay!). Overriding VK_USE_64_BIT_PTR_DEFINES
makes it so you cannot use the "raw" definitions of the lib' you're linking with for, well, the reasons I was worried about in my post.
Instead, you first create a VkInstance
, and then get the function pointers using vkGetInstanceProcAddr
(resp. with a VkDevice
and vkGetDeviceProcAddr
for device functions). All the functions required to get the relevant function pointers are accessible from the lib'.
A simple demo of what you are expected to do when overriding VK_USE_64_BIT_PTR_DEFINES
cmake_minimum_required(VERSION 3.23)
project(vk_test LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Vulkan REQUIRED)
add_executable(vk_test main.cpp)
# No effect for GCC / MinGW
# On MSVC on the other hand, the value is set to 0 when not defined by user
add_compile_definitions(VK_USE_64_BIT_PTR_DEFINES=1)
target_link_libraries(vk_test PUBLIC ${Vulkan_LIBRARY})
target_include_directories(vk_test SYSTEM PUBLIC ${Vulkan_INCLUDE_DIRS})
#include <iostream>
#include <vulkan/vulkan_core.h>
void foo()
{
const VkInstanceCreateInfo instance_info
{
/*.sType = */VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
/*.pNext = */nullptr,
/*.flags = */0,
/*.pApplicationInfo = */nullptr,
/*.enabledLayerCount = */0,
/*.ppEnabledLayerNames = */nullptr,
/*.enabledExtensionCount = */0,
/*.ppEnabledExtensionNames = */nullptr
};
VkInstance instance = VK_NULL_HANDLE;
if(vkCreateInstance(&instance_info, nullptr, &instance) != VK_SUCCESS)
{
std::cout << ":(" << std::endl;
return;
}
const auto f = reinterpret_cast<PFN_vkCmdBindIndexBuffer>(vkGetInstanceProcAddr(instance, "vkCmdBindIndexBuffer"));
std::cout << (f != nullptr) << std::endl; // Prints '1' (hopefully for you too)
vkDestroyInstance(instance, nullptr);
}
int main()
{
foo();
return 0;
}
There is a generated list of all the required calls in vulkan.hpp
, which hopefully can be integrated in your application with less efforts than writing this by hand.
Vulkan-Loader
(VOLK) is a Khronos-developed library for that purpose. It also has a list of the symbols that can be loaded in such a way stored as plain text, which can also be used to generate appropriate code.
Upvotes: 3