关于Vulkan中的函数加载器

时间:2016-08-15 01:26:00

标签: c++ vulkan

在Vulkan中,我们有两个需要使用dlopen / LoadLibrary加载的全局函数。它们是vkGetInstanceProcAddr和vkGetDeviceProcAddr。

我有一个gpu并安装了vulkan驱动程序。我应该在运行时或链接时更好地加载库吗?我给差异逻辑设备(从相同的gpu创建)到vkGetDeviceProcAddr以查询相同的函数。他们都给我回复了同样的地址。我认为重新加载可能会浪费。

我的问题是这个想法是如何产生的?它是多实现还是多gpus?

我的加载器功能目前如下:

class VulkanDevice
{
public:
    VkDevice m_Device;
    void LoadAllCoreFunctions();
    void LoadExtension(const char *name);
    void LoadExtensions(const char *postfix); // for example: "KHR"

    PFN_vkCreateCommandBuffers vkCreateCommandBuffers;
    // Then a lot of function pointers.....
}

int main() {
    // After creating instance and creating device with vkCreateDevice
    VulkanDevice vkd(device);
    vkd.LoadAllCoreFunctions();
    vkd.vkCreateCommandBuffers(vkd.m_Device, ....);
}

正如你所看到的,如果我有多个设备,那么重新加载会非常浪费...而且函数指针也可能会占用大量内存....

2 个答案:

答案 0 :(得分:4)

"实例函数指针和#34;之间的区别和"设备功能指针"适用于需要更快的函数调用性能的人。

只有vkGetInstanceProcAddr才能使用Vulkan。此函数将检索所有 Vulkan函数的函数指针。这些函数指针将使用存储在您传递的各种Vulkan对象中的调度信息,以确定您正在与之通信的设备。这些指针可以与任何实例,设备或设备相关对象一起使用。

您从vkGetDeviceProcAddr 获得的指示知道他们使用特定设备。他们不需要使用调度逻辑来调用该设备。所以他们会略低一些。缺点是您只能 将它们与特定的VkDevice或设备派生对象一起使用。

对于大多数人来说,调度开销可能不会非常重要。如果你真的关心这些事情,你可以选择避免它。

  

如果我有多个设备,重新加载将非常浪费...而且函数指针也可能使用大量内存....

无论你是否查询指针,这些函数都存在;因此获取它们的指针只会占用用于存储指针的内存。 Vulkan的API包含大约140个函数。每个函数指针8个字节,即1120个字节,仅超过1KB。

至于加载它们的时间......如果加载140个函数指针花费的时间超过几个微秒,我会感到震惊。你在启动时做一次

答案 1 :(得分:4)

  

在Vulkan中,我们有两个需要使用dlopen / LoadLibrary加载的全局函数。它们是vkGetInstanceProcAddr和vkGetDeviceProcAddr。

错误。只有1个}}。 vkGetInstanceProcAddr本身可以从vkGetDeviceProcAddr加载。

  

我应该在运行时或链接时更好地加载库吗?我给差异逻辑设备(从相同的gpu创建)到vkGetDeviceProcAddr以查询相同的函数。他们都给我同样的地址。

vkGetInstanceProcAddr获取的命令的

VkInstance仅限于用于获取命令的vkGetInstanceProcAddr

同样,从instance获得的命令只能用于获取它们的vkGetDeviceProcAddr(类型为VkDevice)。

他们可能,而且往往是相同的,但你不能提前知道,并在每个平台/ PC上以这种方式工作。你可以只加载单个命令,测试它是同一个指针并推断其他指针也是如此 - 但是这样做很少,没有合理的好处。

为方便起见,请在与官方装载机的链接时间进行,除非您有理由不这样做。

  

我认为重新加载可能会浪费。

除非您计划使用数百万个不断连接和断开连接的GPU来制作硬件,否则请不要担心并正确加载命令。这是一个很小的一个(或几个)时间成本,它将在你无疑会做的所有渲染中快速摊销。

也没有“重装”。新指针可以与旧指针和平共存。在C ++中,您可能会创建实例或设备的成员函数...

  

我的问题是这个想法是如何产生的?它是多实现还是多gpus?

是的,有点。

你肯定会看到,如果你有两个GPU(来自不同的供应商),使用不同的驱动程序文件(通常是一些* .dll或其他平台上的等价物),那么必须以某种方式选择指向正确文件的指针。

device解决它,以便它为您提供指向另一个选择并调用右指针的函数的指针。 (“一切都可以通过另一层次的间接解决”,对吧?)。静态加载Khronos / Official / LunargSDK加载器可能会做类似的事情。

vkGetInstanceProcAddr,您只需提供确切的设备,反过来它只会为您提供指向该特定GPU驱动程序的直接函数指针。

实例也可能发生(加载器必须只导出vkGetDeviceProcAddr,其余的可以在其他地方)。虽然通常(如在Loader的情况下)它导出所有实例级甚至间接设备级函数指针以方便使用。

  

正如你所看到的,如果我有多个设备,那么重新加载会非常浪费...而且函数指针也可能会占用大量内存....

如前所述,并没有那么多CPU时间浪费。

如果指针中没有那么少的kB,那么无论如何你可能无法做出可行的基于Vulkan的应用程序。您只能加载实际使用的那些命令,但我没有看到这种类型的过早优化的原因。您是否有一些特殊的硬件,需要这样的绝望措施或进行64K演示?