Vulkan 学习(4)---- Vulkan 逻辑设备

Overview

Vulkan 中,逻辑设备(Logical Device)是与物理设备(Physical Device)交互的接口,它抽象了对特定GPU(物理设备)的访问,使得应用程序能够提交命令并管理资源,而无需与物理硬件打交道
举例来说:物理设备可能包含三种队列:图形,计算和传输。但是逻辑设备创建的时候,可以只关联一个单独的队列(比如图形),这样我们就可以很方便地向队列提交指令缓存了
vulkan_program

创建逻辑设备

创建逻辑设备时,需要指定你希望使用的队列族和队列、启用的扩展、以及一些其他特性,我们通过 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:resevered
  • queueCreateInfoCount 指定pQueueCreateInfos数组元素个数,一般设置为 1
  • pQueueCreateInfos 指定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 指向元素数量为 queueCountfloat 数组。用于配置创建的每一个设备队列的优先级

其中 queueFamilyIndex 必须 是目标物理设备中有效的设备队列族索引,并且queueCount必须小于等于queueFamilyIndex 索引对应的设备队列族中的队列数量。
其中 pQueuePriorities 配置的优先级的有效等级范围为[0,1] ,值越大,优先级越高。其中 0.0 是最低的优先级,1.0是最高的优先级。
在某些设备中,优先级越高意味着将会得到更多的执行机会,具体的队列调由设备自身管理, Vulkan 并不规定调度规则

DeviceExtension

前文创建实例的时候可以设置实例的扩展,在 VkDeviceCreateInfo 我们需要通过 enabledExtensionCountppEnabledExtensionNames 来指定该逻辑设备要开启的设备扩展

在开启设备扩展之前,我们需要通过 vkEnumerateDeviceExtensionProperties函数获取目标设备支持的扩展
注意这和之前的获取 Instance 的拓展并不一致,获取 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
获取设备队列

通过 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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值