[译]Vulkan教程(07)物理设备和队列家族
[译]Vulkan教程(07)物理设备和队列家族
Selecting a physical device 选择一个物理设备
After initializing the Vulkan library through a VkInstance
we need to look for and select a graphics card in the system that supports the features we need. In fact we can select any number of graphics cards and use them simultaneously, but in this tutorial we'll stick to the first graphics card that suits our needs.
通过VkInstance
初始化了Vulkan库之后,我们需要在系统中查找和选择一个支持我们需要的特性的图形卡。实际上我们可以选择任意多个图形卡,同步地使用它们,但是本教程中我们只使用第一个满足我们需要的图形卡。
We'll add a function pickPhysicalDevice
and add a call to it in the initVulkan
function.
我们添加一个函数pickPhysicalDevice
,在initVulkan
函数中调用它。
void initVulkan() {
createInstance();
setupDebugCallback();
pickPhysicalDevice();
} void pickPhysicalDevice() { }
The graphics card that we'll end up selecting will be stored in a VkPhysicalDevice
handle that is added as a new class member. This object will be implicitly destroyed when the VkInstance
is destroyed, so we won't need to do anything new in the cleanup
function.
我们添加一个VkPhysicalDevice
成员,用于保存我们将选择的图形卡。这个对象会在VkInstance
被销毁时隐式地销毁,所以我们不需要在cleanup
函数中做什么。
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
Listing the graphics cards is very similar to listing extensions and starts with querying just the number.
列举图形卡,与列举扩展很相似,开始要查询数量。
uint32_t deviceCount = ;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
If there are 0 devices with Vulkan support then there is no point going further.
如果支持Vulkan的设备数量为0,那么就没有必要继续了。
if (deviceCount == ) {
throw std::runtime_error("failed to find GPUs with Vulkan support!");
}
Otherwise we can now allocate an array to hold all of the VkPhysicalDevice
handles.
如果有,我们就申请一个数组来记录所有的VkPhysicalDevice
句柄。
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
Now we need to evaluate each of them and check if they are suitable for the operations we want to perform, because not all graphics cards are created equal. For that we'll introduce a new function:
现在我们需要评估它们,检查它们是不是适合我们需要施展的操作,因为不是所有的图形卡都一样。为此我们引入一个新的函数:
bool isDeviceSuitable(VkPhysicalDevice device) {
return true;
}
And we'll check if any of the physical devices meet the requirements that we'll add to that function.
我们将检查设备是否符合我们在此函数中设定的要求。
for (const auto& device : devices) {
if (isDeviceSuitable(device)) {
physicalDevice = device;
break;
}
} if (physicalDevice == VK_NULL_HANDLE) {
throw std::runtime_error("failed to find a suitable GPU!");
}
The next section will introduce the first requirements that we'll check for in the isDeviceSuitable
function. As we'll start using more Vulkan features in the later chapters we will also extend this function to include more checks.
下一节将引入第一个要求,我们将在isDeviceSuitable
函数中检查它。随着我们将使用更多的Vulkan特性,我们还会逐步扩展这个函数,加入更多的检查。
Base device suitability checks 基础的设备适用性检查
To evaluate the suitability of a device we can start by querying for some details. Basic device properties like the name, type and supported Vulkan version can be queried using vkGetPhysicalDeviceProperties
.
为了估计设备的适用性,我们可以从查询某些细节开始。基础的设备属性(例如名字、类型和支持的Vulkan版本)可以用vkGetPhysicalDeviceProperties
查询。
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
The support for optional features like texture compression, 64 bit floats and multi viewport rendering (useful for VR) can be queried using vkGetPhysicalDeviceFeatures
:
对于可选特性(例如纹理压缩、64位浮点数和多视口渲染(用于VR))的支持,可以用vkGetPhysicalDeviceFeatures
查询。
VkPhysicalDeviceFeatures deviceFeatures;
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
There are more details that can be queried from devices that we'll discuss later concerning device memory and queue families (see the next section).
关于设备内存和队列家族(见下一节)方面,设备还有更多细节可供查询,我们将在以后讨论之。
As an example, let's say we consider our application only usable for dedicated graphics cards that support geometry shaders. Then the isDeviceSuitable
function would look like this:
举个例子,假设我们的app只使用支持几何shader的专用图形卡。那么isDeviceSuitable
函数应该是这样:
bool isDeviceSuitable(VkPhysicalDevice device) {
VkPhysicalDeviceProperties deviceProperties;
VkPhysicalDeviceFeatures deviceFeatures;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
vkGetPhysicalDeviceFeatures(device, &deviceFeatures); return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
deviceFeatures.geometryShader;
}
Instead of just checking if a device is suitable or not and going with the first one, you could also give each device a score and pick the highest one. That way you could favor a dedicated graphics card by giving it a higher score, but fall back to an integrated GPU if that's the only available one. You could implement something like that as follows:
你可以检查一个设备适用与否,然后总选第一个合适的,你更可以给每个设备一个评分,选择最高分的。那样你就可以通过最高分来找到最专业的图形卡,而若只有1个适用的,你也可以选到那个。你可以实现一些这样的东西:
#include <map> ... void pickPhysicalDevice() {
... // Use an ordered map to automatically sort candidates by increasing score
std::multimap<int, VkPhysicalDevice> candidates; for (const auto& device : devices) {
int score = rateDeviceSuitability(device);
candidates.insert(std::make_pair(score, device));
} // Check if the best candidate is suitable at all
if (candidates.rbegin()->first > ) {
physicalDevice = candidates.rbegin()->second;
} else {
throw std::runtime_error("failed to find a suitable GPU!");
}
} int rateDeviceSuitability(VkPhysicalDevice device) {
... int score = ; // Discrete GPUs have a significant performance advantage
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
score += ;
} // Maximum possible size of textures affects graphics quality
score += deviceProperties.limits.maxImageDimension2D; // Application can't function without geometry shaders
if (!deviceFeatures.geometryShader) {
return ;
} return score;
}
You don't need to implement all that for this tutorial, but it's to give you an idea of how you could design your device selection process. Of course you can also just display the names of the choices and allow the user to select.
在本教程中你不需要实现所有这些,但这些可以给你一点启示(关于如何设计你的设备选择流程)。当然你可以只显示选项名字,让用户来选择。
Because we're just starting out, Vulkan support is the only thing we need and therefore we'll settle for just any GPU:
因为我们是刚刚开始,Vulkan支持是我们唯一需要的,因此我们对任何GPU都能行:
bool isDeviceSuitable(VkPhysicalDevice device) {
return true;
}
In the next section we'll discuss the first real required feature to check for.
下一节我们将讨论要检查的第一个特性。
Queue families 队列家族
It has been briefly touched upon before that almost every operation in Vulkan, anything from drawing to uploading textures, requires commands to be submitted to a queue. There are different types of queues that originate from different queue families and each family of queues allows only a subset of commands. For example, there could be a queue family that only allows processing of compute commands or one that only allows memory transfer related commands.
之前简要提到过,Vulkan中的任何操作,从绘画到上传纹理,都需要将命令提交到一个队列。有多种类型的queue,它们起源于不同的队列家族,每个家族里的队列都只能做某一些特定的命令。例如,可能有一个队列家族,它只能处理计算命令,或者只能执行内存转移相关的命令。
We need to check which queue families are supported by the device and which one of these supports the commands that we want to use. For that purpose we'll add a new function findQueueFamilies
that looks for all the queue families we need. Right now we'll only look for a queue that supports graphics commands, but we may extend this function to look for more at a later point in time.
我们需要检查,设备支持哪些队列家族,其中哪个支持我们想使用的命令。为此,我们添加新函数findQueueFamilies
,它查询我们需要的所有的队列家族。现在我们将只查找支持图形命令的队列,但是我们可能以后扩展这个函数,以查询更多东西。
This function will return the indices of the queue families that satisfy certain desired properties. The best way to do that is using a structure where we use std::optional
to track if an index was found:
这个函数会返回满足给定属性的队列家族的索引。最好的方式是用一个struct(我们用std::optional
)来追踪一个索引是否被找到了:
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily; bool isComplete() {
return graphicsFamily.has_value();
}
};
Note that this also requires including <optional>
. We can now begin implementing findQueueFamilies
:
注意这需要include一下<optional>
。现在我们可以开始实现findQueueFamilies
了:
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
QueueFamilyIndices indices; ... return indices;
}
The process of retrieving the list of queue families is exactly what you expect and uses vkGetPhysicalDeviceQueueFamilyProperties
:
如你所料,检索家族列表的过程,就是要用vkGetPhysicalDeviceQueueFamilyProperties
:
uint32_t queueFamilyCount = ;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
The VkQueueFamilyProperties
struct contains some details about the queue family, including the type of operations that are supported and the number of queues that can be created based on that family. We need to find at least one queue family that supports VK_QUEUE_GRAPHICS_BIT
.
结构体VkQueueFamilyProperties
包含队列家族的一些细节,包括支持的操作类型,可以创建的队列数量。我们需要找到至少一个支持VK_QUEUE_GRAPHICS_BIT
的队列家族。
int i = ;
for (const auto& queueFamily : queueFamilies) {
if (queueFamily.queueCount > && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
indices.graphicsFamily = i;
} if (indices.isComplete()) {
break;
} i++;
}
Now that we have this fancy queue family lookup function, we can use it as a check in the isDeviceSuitable
function to ensure that the device can process the commands we want to use:
现在我们有了查询队列家族的函数,我们可以在isDeviceSuitable
函数中用它做个判断,确保设备能处理我们想用的命令:
bool isDeviceSuitable(VkPhysicalDevice device) {
QueueFamilyIndices indices = findQueueFamilies(device); return indices.isComplete();
}
Great, that's all we need for now to find the right physical device! The next step is to create a logical device to interface with it.
好极了,这就是我们目前需要的用以找到正确的物理设备的所有东西!下一步是创建逻辑设备,然后与之交互。
C++ code C++代码
- Previous上一章
- Next下一章
[译]Vulkan教程(07)物理设备和队列家族的更多相关文章
- [译]Vulkan教程(08)逻辑设备和队列
[译]Vulkan教程(08)逻辑设备和队列 Introduction 入门 After selecting a physical device to use we need to set up a ...
- [译]Vulkan教程(23)暂存buffer
[译]Vulkan教程(23)暂存buffer Staging buffer 暂存buffer Introduction 入门 The vertex buffer we have right now ...
- [译]Vulkan教程(09)窗口表面
[译]Vulkan教程(09)窗口表面 Since Vulkan is a platform agnostic API, it can not interface directly with the ...
- [译]Vulkan教程(27)Image
[译]Vulkan教程(27)Image Images Introduction 入门 The geometry has been colored using per-vertex colors so ...
- [译]Vulkan教程(22)创建顶点buffer
[译]Vulkan教程(22)创建顶点buffer Vertex buffer creation 创建顶点buffer Introduction 入门 Buffers in Vulkan are re ...
- [译]Vulkan教程(10)交换链
[译]Vulkan教程(10)交换链 Vulkan does not have the concept of a "default framebuffer", hence it r ...
- [译]Vulkan教程(02)概况
[译]Vulkan教程(02)概况 这是我翻译(https://vulkan-tutorial.com)上的Vulkan教程的第2篇. This chapter will start off with ...
- [译]Vulkan教程(33)多重采样
[译]Vulkan教程(33)多重采样 Multisampling 多重采样 Introduction 入门 Our program can now load multiple levels of d ...
- [译]Vulkan教程(19)渲染和呈现
[译]Vulkan教程(19)渲染和呈现 Rendering and presentation 渲染和呈现 Setup 设置 This is the chapter where everything ...
随机推荐
- 【算法】273-每周一练 之 数据结构与算法(Tree)
这是第六周的练习题,最近加班比较多. 下面是之前分享的链接: [算法]200-每周一练 之 数据结构与算法(Stack) [算法]213-每周一练 之 数据结构与算法(LinkedList) [算法] ...
- 【Redis】270- 你需要知道的那些 redis 数据结构
本文出自「掘金社区」,欢迎戳「阅读原文」链接和作者进行技术交流 ?? 作者简介 世宇,一个喜欢吉他.MDD 摄影.自走棋的工程师,属于饿了么上海物流研发部.目前负责的是网格商圈.代理商基础产线,平时喜 ...
- JS基础-事件队列
为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. JavaSc ...
- 安装Django、Nginx和uWSGI
安装Django.Nginx和uWSGI 1.确定已经安装了2.7版本的Python: 2.安装python-devel yum install python-devel 3.安装uwsgi pip ...
- vue bus.js 使用方法
1 ,新建bus.js 内容如下 2,bus.$emit 绑定数据 bus.$emit('tags', this.tagsList); 第一个参数为定义的变量,第二个为集合数据 3, 监听数据 bus ...
- 《Java基础知识》Java final关键字:阻止继承和多态
在 Java 中,声明类.变量和方法时,可使用关键字 final 来修饰.final 所修饰的数据具有“终态”的特征,表示“最终的”意思.具体规定如下: final 修饰的类不能被继承. final ...
- 3. abp依赖注入的分析.md
abp依赖注入的原理剖析 请先移步参考 [Abp vNext 源码分析] - 3. 依赖注入与拦截器 本文此篇文章的补充和完善. abp的依赖注入最后是通过IConventionalRegister接 ...
- Yii2 框架跑脚本时内存泄漏问题分析
现象 在跑 edu_ocr_img 表的归档时,每跑几万个数据,都会报一次内存耗尽 PHP Fatal error: Allowed memory size of 134217728 bytesex ...
- web端百度地图API实现实时轨迹动态展现
最近在工作中遇到了一个百度地图api中的难题,恐怕有的程序员可能也遇到过.就是实时定位并显示轨迹,网上大部分都是通过创建polyline对象贴到地图上.当然,百度地图的画线就是这样实现的,但是好多人会 ...
- Android DSelectorBryant 单选滚动选择器
单选滚动选择器.diy丰富.有阻尼效果.简单美观.触摸or点击模式 (Rolling Selector, Diy Rich, Damping Effect, Simple and Beautiful, ...