1

背景:
我一直在关注编写一个需要非常基本但快速的图形(仅绘制线条和正方形)的应用程序,如果我要使用 Rust,我可能会使用 GLFW 或 Vulkano 之类的库。

我想了解 Vulkan API 的一个具体的,而且我想非常实用的细节。我知道 GPU 可能是一个相当复杂的话题,但我想强调一下,我没有任何低级图形或 Vulkan 的背景,所以我理解如果我的问题无法回答,或者我的问题甚至没有感觉。我会尽力使用正确的术语。我不得不承认,我不是最擅长浏览和查看大量我不太理解但仍然掌握整体概念的源代码,这就是为什么我希望我能在这里找到我的答案。我试过查看 Vulkan 和 Mesa 驱动程序的源代码,但没有结果。

原始问题:
我想了解 API 调用如何传播到 GPU 驱动程序。

我四处搜寻,但找不到我要寻找的细节。我发现的最接近的帖子是这两个:
https ://softwareengineering.stackexchange.com/questions/279069/how-does-a-program-talk-to-a-graphics-card
https://superuser.com/问题/461022/cpu 和 gpu-interact-in-displaying-computer-graphics 如何

他们都提到了类似于“为了让 GPU 做某事,你必须通过支持的 API 进行调用”。我知道这一点,但两者都没有深入研究如何进行 API 调用的细节。希望下图能说明我的问题。

MyVulkanProgram.c with "#include <vulkan/vulkan.h>"
|
| (Makes call via Vulkan API)
v
This is the part I don't understand!
|
v
Driver (Mesa, for example) takes the request sent via the Vulkan API.
|
| (Driver asks GPU to perform task)
v
GPU does task

我不在乎 GPU 做什么或如何做某事。它是如何通过 Vulkan 的 API 调用调用的,以及它是如何在系统中传播的。理想情况下,我正在寻找的是代码片段或链接到 Vulkan 源代码中实际请求发送到驱动程序的位置。

还是我全都搞错了?Vulkan 是否比我意识到的更多地成为驱动程序的一部分?驱动程序是否包含与我的“MyVulkanProgram.c”相同的 Vulkan 标头,并且驱动程序与 libvulkan.so 等库文件链接在一起?是不是更像下图?

MyVulkanProgram.c with "#include <vulkan/vulkan.h>"
|
| (Makes call via Vulkan API)
v
Driver (Mesa, for example, which includes the vulkan headers and is linked with the Vulkan shared object-files) takes the request sent via the Vulkan API.
|
| (Driver asks GPU to perform task)
v
GPU does task

可能是一个基本问题,可能不是,但我仍然感到困惑。非常感谢任何答案!

更新后的问题:
在阅读了@krOoze 的答案(来自 krOoze 的答案)并给出了上述文档中的“Vulkan loader”概述图之后,我可以更准确地表达我的问题。

通过 Vulkan API 进行调用的应用程序如何通过 Vulkan 加载程序到达 ICD?

4

1 回答 1

1

您正在寻找Vulkan-Loader/LoaderAndLayerInterface.md文档。

该应用程序与加载器(有时称为 Vulkan RT 或 Vulkan 运行时)交互。那是vulkan-1.dll(或so)。

Loader 也有vulkan-1.lib,这是经典的 dll shim。这是加载核心版本和 WSI 命令的地方,但您可以跳过lib并直接从dllusing手动完成所有操作vkGetInstanceProcAddr

然后你有 ICD(可安装的客户端驱动程序)。这些类似于nvoglv64.dll,您可以在您的 PC 上拥有更多它们(例如 Intel iGPU + NV)。该名称是任意的且特定于供应商。Loader 通过配置文件找到它们。

现在,当您调用某个命令获得的命令时vkGetInstanceProcAddress(如果您使用*.lib唯一的,这就是所有内容),您会进入加载程序蹦床,它调用一系列层,然后调用相关的 ICD(或所有它们)。然后调用堆栈被展开,所以它会朝着另一个方向前进,直到返回到应用程序。加载器互斥并将输入和输出合并到 ICD。

使用 获得的命令vkGetDeviceProcAddress更加精简,因为它们不需要互斥或合并,并且可以在没有加载器太多干预的情况下传递给 ICD。

代码也在同一个 repo 中:trampoline.cloader.c。这很简单;每层只调用它下面的层。从蹦床开始,到终结层结束,终结层又称为 ICD 层。

于 2021-05-26T13:39:39.787 回答