一种简单加载vulkan动态库的方法
背景
最近在国产linux环境上适配vulkan应用,一般系统会自带libvulkan.so.1
但是没有libvulkan.so
,而libvulkan.so.1
无法通过find_library找到,如果系统源没有vulkan sdk
或者vulkan loader
,这时就得手工下载代码编译vulkan sdk
或者vulkan loader
,过程中可能还得安装各种依赖,升级cmake,非常繁琐,安装完成后使用下面的方式将vulkan动态库链接到目标应用:
find_package(Vulkan)
if (NOT Vulkan_FOUND)
find_library(Vulkan_LIBRARIES NAMES vulkan REQUIRED)
endif ()
include_directories(${Vulkan_INCLUDE_DIRS})
target_link_libraries (${PROJECT_NAME} ${Vulkan_LIBRARIES})
在麒麟、龙芯、鲲鹏等各种系统上都经历过手工编译vulkan sdk
,为了更快的测试vulkan兼容性以及调试应用,一直在找更简易的方法。
闲暇之余看到了这篇文章 WHAT IS VK_NO_PROTOTYPES,萌生了写一个简易的vulkan动态库加载方法的想法,不用安装vulkan sdk
或者vulkan loader
,直接使用系统上的libvulkan.so.1
(一般都会自带,没有的话执行sudo apt install libvulkan1
安装)。
代码示例
基本原理是初始化时使用 dlopen
、dlsym
加载vulkan动态库中的api函数指针,app直接使用这些api,这里我用了一个开源的动态库加载工具dylib
,它支持多系统平台:
以vkCreateInstance
函数地址的加载过程为例:
//加载vulkan动态库
dylib lib("libvulkan.so.1", false);
//定义函数指针vkCreateInstance, PFN_vkCreateInstance的声明在vulkan_core.h中
PFN_vkCreateInstance vkCreateInstance;
//从动态库中获取函数地址
auto vkCreateInstance = (PFN_vkCreateInstance)lib.get_function<PFN_vkCreateInstance>("vkCreateInstance");
这里有个小tip:vkCreateInstance
在vulkan_core.h
中的声明是被宏VK_NO_PROTOTYPES
括起来的,我们得在cmake中添加该宏定义add_definitions(-DVK_NO_PROTOTYPES)
,不让 vulkan_core.h
中对原生的vk api进行声明,这样我们就可以在load.h
中对原生的vulkan api进行声明了。
附上整个load.h
的源码,在app初始化时调用vk_loader_init()
即可加载vulkan动态库中所有的函数地址:
#include "dylib/dylib.hpp"
#include "vulkan/vulkan_core.h"
#if defined(WIN32) || defined(_WIN32) || defined(_WIN32_) || defined(WIN64) || defined(_WIN64) || defined(_WIN64_)
#define VULKAN_LIB "vulkan-1.dll"
#elif defined(ANDROID) || defined(_ANDROID_)
#define VULKAN_LIB "libvulkan.so"
#else
#define VULKAN_LIB "libvulkan.so.1"
#endif
#define APPLY_PFN_DEF_VK_FUNCTIONS(PFN_DEF) \
PFN_DEF(vkGetInstanceProcAddr) \
PFN_DEF(vkCreateInstance) \
PFN_DEF(vkEnumerateInstanceExtensionProperties) \
PFN_DEF(vkEnumerateInstanceLayerProperties) \
PFN_DEF(vkDestroyInstance) \
PFN_DEF(vkEnumeratePhysicalDevices) \
PFN_DEF(vkGetPhysicalDeviceFeatures) \
PFN_DEF(vkGetPhysicalDeviceFormatProperties) \
PFN_DEF(vkGetPhysicalDeviceImageFormatProperties) \
PFN_DEF(vkGetPhysicalDeviceProperties) \
PFN_DEF(vkGetPhysicalDeviceQueueFamilyProperties) \
PFN_DEF(vkGetPhysicalDeviceMemoryProperties) \
PFN_DEF(vkGetDeviceProcAddr) \
PFN_DEF(vkCreateDevice) \
PFN_DEF(vkDestroySurfaceKHR) \
PFN_DEF(vkGetPhysicalDeviceSurfaceSupportKHR) \
PFN_DEF(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
PFN_DEF(vkGetPhysicalDeviceSurfaceFormatsKHR) \
PFN_DEF(vkGetPhysicalDeviceSurfacePresentModesKHR) \
PFN_DEF(vkCreateSwapchainKHR) \
PFN_DEF(vkDestroySwapchainKHR) \
PFN_DEF(vkGetSwapchainImagesKHR) \
PFN_DEF(vkAcquireNextImageKHR) \
PFN_DEF(vkQueuePresentKHR) \
PFN_DEF(vkDestroyDevice) \
PFN_DEF(vkEnumerateDeviceExtensionProperties) \
PFN_DEF(vkEnumerateDeviceLayerProperties) \
PFN_DEF(vkGetDeviceQueue) \
PFN_DEF(vkQueueSubmit) \
PFN_DEF(vkQueueWaitIdle) \
PFN_DEF(vkDeviceWaitIdle) \
PFN_DEF(vkAllocateMemory) \
PFN_DEF(vkFreeMemory) \
PFN_DEF(vkMapMemory) \
PFN_DEF(vkUnmapMemory) \
PFN_DEF(vkFlushMappedMemoryRanges) \
PFN_DEF(vkInvalidateMappedMemoryRanges) \
PFN_DEF(vkGetDeviceMemoryCommitment) \
PFN_DEF(vkBindBufferMemory) \
PFN_DEF(vkBindImageMemory) \
PFN_DEF(vkGetBufferMemoryRequirements) \
PFN_DEF(vkGetImageMemoryRequirements) \
PFN_DEF(vkGetImageSparseMemoryRequirements) \
PFN_DEF(vkGetPhysicalDeviceSparseImageFormatProperties) \
PFN_DEF(vkQueueBindSparse) \
PFN_DEF(vkCreateFence) \
PFN_DEF(vkDestroyFence) \
PFN_DEF(vkResetFences) \
PFN_DEF(vkGetFenceStatus) \
PFN_DEF(vkWaitForFences) \
PFN_DEF(vkCreateSemaphore) \
PFN_DEF(vkDestroySemaphore) \
PFN_DEF(vkCreateEvent) \
PFN_DEF(vkDestroyEvent) \
PFN_DEF(vkGetEventStatus) \
PFN_DEF(vkSetEvent) \
PFN_DEF(vkResetEvent) \
PFN_DEF(vkCreateQueryPool) \
PFN_DEF(vkDestroyQueryPool) \
PFN_DEF(vkGetQueryPoolResults) \
PFN_DEF(vkCreateBuffer) \
PFN_DEF(vkDestroyBuffer) \
PFN_DEF(vkCreateBufferView) \
PFN_DEF(vkDestroyBufferView) \
PFN_DEF(vkCreateImage) \
PFN_DEF(vkDestroyImage) \
PFN_DEF(vkGetImageSubresourceLayout) \
PFN_DEF(vkCreateImageView) \
PFN_DEF(vkDestroyImageView) \
PFN_DEF(vkCreateShaderModule) \
PFN_DEF(vkDestroyShaderModule) \
PFN_DEF(vkCreatePipelineCache) \
PFN_DEF(vkDestroyPipelineCache) \
PFN_DEF(vkGetPipelineCacheData) \
PFN_DEF(vkMergePipelineCaches) \
PFN_DEF(vkCreateGraphicsPipelines) \
PFN_DEF(vkCreateComputePipelines) \
PFN_DEF(vkDestroyPipeline) \
PFN_DEF(vkCreatePipelineLayout) \
PFN_DEF(vkDestroyPipelineLayout) \
PFN_DEF(vkCreateSampler) \
PFN_DEF(vkDestroySampler) \
PFN_DEF(vkCreateDescriptorSetLayout) \
PFN_DEF(vkDestroyDescriptorSetLayout) \
PFN_DEF(vkCreateDescriptorPool) \
PFN_DEF(vkDestroyDescriptorPool) \
PFN_DEF(vkResetDescriptorPool) \
PFN_DEF(vkAllocateDescriptorSets) \
PFN_DEF(vkFreeDescriptorSets) \
PFN_DEF(vkUpdateDescriptorSets) \
PFN_DEF(vkCreateFramebuffer) \
PFN_DEF(vkDestroyFramebuffer) \
PFN_DEF(vkCreateRenderPass) \
PFN_DEF(vkDestroyRenderPass) \
PFN_DEF(vkGetRenderAreaGranularity) \
PFN_DEF(vkCreateCommandPool) \
PFN_DEF(vkDestroyCommandPool) \
PFN_DEF(vkResetCommandPool) \
PFN_DEF(vkAllocateCommandBuffers) \
PFN_DEF(vkFreeCommandBuffers) \
PFN_DEF(vkBeginCommandBuffer) \
PFN_DEF(vkEndCommandBuffer) \
PFN_DEF(vkResetCommandBuffer) \
PFN_DEF(vkCmdBindPipeline) \
PFN_DEF(vkCmdSetViewport) \
PFN_DEF(vkCmdSetScissor) \
PFN_DEF(vkCmdSetLineWidth) \
PFN_DEF(vkCmdSetDepthBias) \
PFN_DEF(vkCmdSetBlendConstants) \
PFN_DEF(vkCmdSetDepthBounds) \
PFN_DEF(vkCmdSetStencilCompareMask) \
PFN_DEF(vkCmdSetStencilWriteMask) \
PFN_DEF(vkCmdSetStencilReference) \
PFN_DEF(vkCmdBindDescriptorSets) \
PFN_DEF(vkCmdBindIndexBuffer) \
PFN_DEF(vkCmdBindVertexBuffers) \
PFN_DEF(vkCmdDraw) \
PFN_DEF(vkCmdDrawIndexed) \
PFN_DEF(vkCmdDrawIndirect) \
PFN_DEF(vkCmdDrawIndexedIndirect) \
PFN_DEF(vkCmdDispatch) \
PFN_DEF(vkCmdDispatchIndirect) \
PFN_DEF(vkCmdCopyBuffer) \
PFN_DEF(vkCmdCopyImage) \
PFN_DEF(vkCmdBlitImage) \
PFN_DEF(vkCmdCopyBufferToImage) \
PFN_DEF(vkCmdCopyImageToBuffer) \
PFN_DEF(vkCmdUpdateBuffer) \
PFN_DEF(vkCmdFillBuffer) \
PFN_DEF(vkCmdClearColorImage) \
PFN_DEF(vkCmdClearDepthStencilImage) \
PFN_DEF(vkCmdClearAttachments) \
PFN_DEF(vkCmdResolveImage) \
PFN_DEF(vkCmdSetEvent) \
PFN_DEF(vkCmdResetEvent) \
PFN_DEF(vkCmdWaitEvents) \
PFN_DEF(vkCmdPipelineBarrier) \
PFN_DEF(vkCmdBeginQuery) \
PFN_DEF(vkCmdEndQuery) \
PFN_DEF(vkCmdResetQueryPool) \
PFN_DEF(vkCmdWriteTimestamp) \
PFN_DEF(vkCmdCopyQueryPoolResults) \
PFN_DEF(vkCmdPushConstants) \
PFN_DEF(vkCmdBeginRenderPass) \
PFN_DEF(vkCmdNextSubpass) \
PFN_DEF(vkCmdEndRenderPass) \
PFN_DEF(vkCmdExecuteCommands)
#define DEFINE_VK_FUNCTION_MACRO(function) \
PFN_##function function;
#define GET_VK_FUNCTION_PROCADDR(function) \
function = reinterpret_cast<PFN_##function>(lib.get_function<PFN_##function>(#function));
APPLY_PFN_DEF_VK_FUNCTIONS(DEFINE_VK_FUNCTION_MACRO);
void vk_loader_init()
{
static dylib lib(VULKAN_LIB, false);
APPLY_PFN_DEF_VK_FUNCTIONS(GET_VK_FUNCTION_PROCADDR);
}
项目实战
这是整个测试demo的项目地址: