目录
- Vulkan Logical Device OverView
- 逻辑设备创建
- VkDeviceQueueCreateInfo
- DeviceExtension
- 获取DeviceQueue
- 参考代码
Vulkan Logical Device OverView
在 Vulkan 中,逻辑设备(Logical Device
)是与物理设备(Physical Device
)交互的接口,它抽象了对特定GPU
(物理设备)的访问,使得应用程序能够提交命令并管理资源,而无需与物理硬件打交道
举例来说:物理设备可能包含三种队列:图形,计算和传输。但是逻辑设备创建的时候,可以只关联一个单独的队列(比如图形),这样我们就可以很方便地向队列提交指令缓存了
逻辑设备创建
创建逻辑设备时,需要指定你希望使用的队列族和队列、启用的扩展、以及一些其他特性,我们通过 vkCreateDevice()
函数创建逻辑设备, 函数原型如下:
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(
VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice);
physicalDevice
指定在哪一个物理设备上创建逻辑设备pCreateInfo
创建逻辑设备的配置信息,是关键结构pAllocator
内存分配器。如果为 nullptr表示使用内部默认分配器,否则为自定义分配器pDevice
创建逻辑设备的实例
其中关键的输入参数结构是VkDeviceCreateInfo
,其定义如下:
typedef struct VkDeviceCreateInfo {
VkStructureType sType;
const void* pNext;
VkDeviceCreateFlags flags;
uint32_t queueCreateInfoCount;
const VkDeviceQueueCreateInfo* pQueueCreateInfos;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
const VkPhysicalDeviceFeatures* pEnabledFeatures;
} VkDeviceCreateInfo;
各个参数的含义如下:
sType
是该结构体的类型枚举值, 必须是VkStructureType::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
pNext
要么是 NULL 要么指向其他结构体来扩展该结构体flags
:reseveredqueueCreateInfoCount
指定pQueueCreateInfos
数组元素个数,一般设置为 1pQueueCreateInfos
指定VkDeviceQueueCreateInfo
数组, 用于配置要创建的设备队列信息enabledLayerCount
指定ppEnabledLayerNames
数组元素个数。该成员已被遗弃ppEnabledLayerNames
指定要开启的验证层。该成员已被遗弃enabledExtensionCount
指定ppEnabledExtensionNames
数组中元素个数ppEnabledExtensionNames
指定要开启的扩展。该数组数量必须大于等于enabledExtensionCount
pEnabledFeatures
配置要开启的特性
VkDeviceQueueCreateInfo
VkDeviceQueueCreateInfo
的定义如下:
typedef struct VkDeviceQueueCreateInfo {
VkStructureType sType;
const void* pNext;
VkDeviceQueueCreateFlags flags;
uint32_t queueFamilyIndex;
uint32_t queueCount;
const float* pQueuePriorities;
} VkDeviceQueueCreateInfo;
sType
是该结构体的类型枚举值, 必须是VkStructureType::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
pNext
要么是 NULL 要么指向其他结构体来扩展该结构体flags
配置额外的信息。可设置的值定义在VkDeviceQueueCreateFlagBits
枚举中queueFamilyIndex
指定目标设备队列族的索引queueCount
指定要在queueFamilyIndex
中创建设备队列的数量pQueuePriorities
指向元素数量为 queueCount 的 float 数组。用于配置创建的每一个设备队列的优先级
其中 queueFamilyIndex
必须 是目标物理设备中有效的设备队列族索引,并且queueCount
必须小于等于queueFamilyIndex
索引对应的设备队列族中的队列数量。
其中 pQueuePriorities
配置的优先级的有效等级范围为[0, 1] ,值越大,优先级越高。其中 0.0
是最低的优先级,1.0
是最高的优先级。
在某些设备中,优先级越高意味着将会得到更多的执行机会,具体的队列调由设备自身管理, Vulkan 并不规定调度规则
DeviceExtension
前文创建实例的时候可以设置实例的扩展,在 VkDeviceCreateInfo
我们需要通过 enabledExtensionCount
和 ppEnabledExtensionNames
来指定该逻辑设备要开启的设备扩展
在开启设备扩展之前,我们需要通过 vkEnumerateDeviceExtensionProperties
函数获取目标设备支持的扩展
注意这和之前的获取 Insatance 的拓展并不一致,获取 Instance 拓展的函数是 vkEnumerateInstanceExtensionProperties
VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(
VkPhysicalDevice physicalDevice,
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties);
physicalDevice
创建的物理设备pLayerName
要么为空要么为层的名称,实际如果传入 nullptr,可以遍历出所有层pPropertyCount
要么为空要么为 pProperties 中元素的数量。pProperties
为扩展信息数组,元素个数 必须 大于等于 pPropertyCount 中指定数量
参考代码如下:
std::cout << "===========================================================" << std::endl;
uint32_t extension_property_count = 0;
vkEnumerateDeviceExtensionProperties(physicalDevice,nullptr, &extension_property_count, nullptr);
std::cout << "device extension count:" << extension_property_count << std::endl;
std::vector<VkExtensionProperties> extension_properties(extension_property_count);
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_property_count, extension_properties.data());
std::cout << "enumrate extension_properties:" << std::endl;
for (auto& properties:extension_properties) {
std::cout << "name:" << properties.extensionName << std::endl;
}
一共可以打印出128层,如下:
name:VK_EXT_device_address_binding_report
name:VK_EXT_full_screen_exclusive
// 用于与VK_KHR_surface 和平台相关的,VK_{vender}_{platform}_surface 扩展配合使用。用于窗口化显示渲染结果
name:VK_KHR_swapchain
name:VK_KHR_external_memory
name:VK_KHR_external_memory_win32
name:VK_EXT_external_memory_host
name:VK_KHR_external_semaphore
name:VK_KHR_external_semaphore_win32
name:VK_KHR_external_fence
name:VK_KHR_external_fence_win32
name:VK_KHR_timeline_semaphore
name:VK_KHR_win32_keyed_mutex
name:VK_KHR_get_memory_requirements2
name:VK_KHR_bind_memory2
name:VK_KHR_dedicated_allocation
name:VK_KHR_sampler_mirror_clamp_to_edge
name:VK_KHR_maintenance1
name:VK_KHR_maintenance2
name:VK_KHR_maintenance3
name:VK_KHR_maintenance4
name:VK_KHR_synchronization2
name:VK_KHR_shader_draw_parameters
name:VK_KHR_push_descriptor
name:VK_KHR_descriptor_update_template
name:VK_KHR_multiview
name:VK_KHR_shader_float16_int8
name:VK_KHR_shader_float_controls
name:VK_KHR_16bit_storage
name:VK_KHR_8bit_storage
name:VK_EXT_shader_subgroup_ballot
name:VK_EXT_shader_subgroup_vote
name:VK_KHR_storage_buffer_storage_class
name:VK_KHR_variable_pointers
name:VK_KHR_relaxed_block_layout
name:VK_EXT_sampler_filter_minmax
name:VK_KHR_device_group
name:VK_KHR_sampler_ycbcr_conversion
name:VK_EXT_ycbcr_2plane_444_formats
name:VK_EXT_4444_formats
name:VK_EXT_post_depth_coverage
name:VK_EXT_shader_viewport_index_layer
name:VK_EXT_shader_stencil_export
name:VK_EXT_conservative_rasterization
name:VK_EXT_sample_locations
name:VK_KHR_draw_indirect_count
name:VK_EXT_multi_draw
name:VK_KHR_image_format_list
name:VK_EXT_image_view_min_lod
name:VK_EXT_vertex_attribute_divisor
name:VK_EXT_descriptor_indexing
name:VK_EXT_mutable_descriptor_type
name:VK_EXT_inline_uniform_block
name:VK_KHR_create_renderpass2
name:VK_KHR_dynamic_rendering
name:VK_KHR_swapchain_mutable_format
name:VK_KHR_depth_stencil_resolve
name:VK_KHR_driver_properties
name:VK_KHR_vulkan_memory_model
name:VK_EXT_conditional_rendering
name:VK_EXT_hdr_metadata
name:VK_KHR_fragment_shading_rate
name:VK_EXT_depth_clip_enable
name:VK_EXT_depth_clip_control
name:VK_EXT_scalar_block_layout
name:VK_KHR_imageless_framebuffer
name:VK_KHR_buffer_device_address
name:VK_EXT_buffer_device_address
name:VK_KHR_pipeline_library
name:VK_EXT_host_query_reset
name:VK_KHR_performance_query
name:VK_NV_device_diagnostic_checkpoints
name:VK_KHR_separate_depth_stencil_layouts
name:VK_KHR_shader_clock
name:VK_KHR_spirv_1_4
name:VK_KHR_uniform_buffer_standard_layout
name:VK_EXT_separate_stencil_usage
name:VK_EXT_fragment_shader_interlock
name:VK_EXT_index_type_uint8
name:VK_EXT_primitive_topology_list_restart
name:VK_KHR_shader_subgroup_extended_types
name:VK_EXT_line_rasterization
name:VK_EXT_memory_budget
name:VK_EXT_memory_priority
name:VK_EXT_pageable_device_local_memory
name:VK_EXT_texel_buffer_alignment
name:VK_INTEL_performance_query
name:VK_EXT_subgroup_size_control
name:VK_EXT_shader_demote_to_helper_invocation
name:VK_EXT_pipeline_creation_feedback
name:VK_EXT_pipeline_creation_cache_control
name:VK_KHR_pipeline_executable_properties
name:VK_EXT_graphics_pipeline_library
name:VK_EXT_transform_feedback
name:VK_EXT_provoking_vertex
name:VK_EXT_extended_dynamic_state
name:VK_EXT_extended_dynamic_state2
name:VK_EXT_extended_dynamic_state3
name:VK_EXT_vertex_input_dynamic_state
name:VK_EXT_custom_border_color
name:VK_EXT_robustness2
name:VK_EXT_image_robustness
name:VK_EXT_pipeline_robustness
name:VK_EXT_calibrated_timestamps
name:VK_KHR_shader_integer_dot_product
name:VK_KHR_shader_subgroup_uniform_control_flow
name:VK_KHR_shader_terminate_invocation
name:VK_KHR_workgroup_memory_explicit_layout
name:VK_EXT_shader_atomic_float
name:VK_KHR_copy_commands2
name:VK_KHR_shader_non_semantic_info
name:VK_KHR_zero_initialize_workgroup_memory
name:VK_EXT_shader_atomic_float2
name:VK_EXT_global_priority
name:VK_EXT_global_priority_query
name:VK_KHR_global_priority
name:VK_KHR_format_feature_flags2
name:VK_KHR_video_queue
name:VK_KHR_video_decode_queue
name:VK_KHR_video_decode_h264
name:VK_KHR_video_decode_h265
name:VK_EXT_color_write_enable
name:VK_NV_compute_shader_derivatives
name:VK_EXT_private_data
name:VK_EXT_image_2d_view_of_3d
name:VK_EXT_primitives_generated_query
name:VK_EXT_shader_module_identifier
name:VK_EXT_attachment_feedback_loop_layout
name:VK_KHR_map_memory2
获取DeviceQueue
通过 vkGetDeviceQueue()
函数获取设备队列
VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(
VkDevice device,
uint32_t queueFamilyIndex,
uint32_t queueIndex,
VkQueue* pQueue);
device
目标逻辑设备。queueFamilyIndex
是前面获取的目标设备队列的队列族索引。queueIndex
对应VkDeviceQueueCreateInfo::queueCount
的对应设备队列索引, 用于区分创建的多个队列pQueue
对应VkDeviceQueueCreateInfo::queueCount
创建的第 queueIndex 的设备队列
参考代码
void vulkanBasicDemo::vulkanCreateLogicalDevice() {
float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueCreateInfo = {};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
// device extension
std::vector<const char*> device_extensions;
device_extensions.push_back("VK_KHR_swapchain");
VkDeviceCreateInfo deviceCreateInfo = {};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.queueCreateInfoCount = 1;
deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(device_extensions.size());
deviceCreateInfo.ppEnabledExtensionNames = device_extensions.data();
if (vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device) != VK_SUCCESS) {
throw std::runtime_error("failed to create logical device!");
}
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue);
}