我正在使用ash和gpu_allocator来尝试将一些C++代码移植到rust。
我遇到了一个C++代码从未遇到过的验证错误:
"Validation Error: [ VUID-VkMemoryAllocateInfo-flags-03331 ] Object 0: handle = 0x56443b02d140, name = Logical device from NVIDIA GeForce GTX 1070, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xf972dfbf | If VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT is set, bufferDeviceAddress must be enabled. The Vulkan spec states: If VkMemoryAllocateFlagsInfo::flags includes VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, the bufferDeviceAddress feature must be enabled (https://vulkan.lunarg.com/doc/view/1.3.211.0/linux/1.3-extensions/vkspec.html#VUID-VkMemoryAllocateInfo-flags-03331)"', src/vulkan/hardware_interface.rs:709:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
从消息来看,我似乎需要启用一个扩展。
困惑n1,根据医生的说法,这似乎总是应该引起争论:https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_buffer_device_address.html
因为它被移为核心扩展?但也许我没有理解核心的含义,所以我尝试手动启用它。
我有一个扩展名列表,我在创建时将其传递给设备:
const DEVICE_EXTENSIONS : &'static [&str] =
&[
"VK_KHR_swapchain",
"VK_KHR_dynamic_rendering",
"VK_EXT_buffer_device_address",
"VK_EXT_extended_dynamic_state",
"VK_EXT_conservative_rasterization",
];
let extensions : Vec<CString> = DEVICE_EXTENSIONS.iter().map(
|extension_name| CString::new(extension_name.to_string()).unwrap()
).collect();
let raw_extensions : Vec<*const i8> = extensions.iter().map(
|extension| extension.as_ptr()
).collect();
let mut dynamic_rendering =
vk::PhysicalDeviceDynamicRenderingFeaturesKHR {
dynamic_rendering : true as u32,
..Default::default()
};
type PDDRF = vk::PhysicalDeviceDynamicRenderingFeaturesKHR;
let indexing_features =
vk::PhysicalDeviceDescriptorIndexingFeatures
{
p_next : (&mut dynamic_rendering) as *mut PDDRF as *mut c_void,
shader_sampled_image_array_non_uniform_indexing : true as u32,
..Default::default()
};
// The enabledLayerCount and ppEnabledLayerNames parameters are deprecated,
// they should always be 0 and nullptr.
// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkDeviceCreateInfo.html
let create_info =
vk::DeviceCreateInfo {
p_next : &indexing_features as *const _ as *const c_void,
queue_create_info_count : 1,
p_queue_create_infos : &queue_create_info,
enabled_extension_count : requested_device_extensions.len() as u32,
pp_enabled_extension_names : raw_extensions.as_ptr(),
p_enabled_features : &device_features,
..Default::default()
};
我知道这有点复杂,但到目前为止,swapchain扩展似乎加载得很好,所以我不明白为什么设备地址扩展从未启用。
有人提到我应该在扩展的同时启用这个功能:
let buffer_address =
vk::PhysicalDeviceBufferAddressFeaturesEXT
{
buffer_device_address : vk::TRUE,
..Default::default()
};
let dynamic_rendering =
vk::PhysicalDeviceDynamicRenderingFeaturesKHR {
p_next : (&buffer_address) as *const _ as *mut c_void,
dynamic_rendering : true as u32,
..Default::default()
};
type PDDRF = vk::PhysicalDeviceDynamicRenderingFeaturesKHR;
let indexing_features =
vk::PhysicalDeviceDescriptorIndexingFeatures
{
p_next : (&dynamic_rendering) as *const PDDRF as *mut c_void,
shader_sampled_image_array_non_uniform_indexing : true as u32,
..Default::default()
};
// The enabledLayerCount and ppEnabledLayerNames parameters are deprecated,
// they should always be 0 and nullptr.
// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkDeviceCreateInfo.html
let create_info =
vk::DeviceCreateInfo
{
p_next : &indexing_features as *const _ as *const c_void,
queue_create_info_count : 1,
p_queue_create_infos : &queue_create_info,
enabled_extension_count : requested_device_extensions.len() as u32,
pp_enabled_extension_names : raw_extensions.as_ptr(),
p_enabled_features : &device_features,
..Default::default()
};
但即使这样,我仍然会犯同样的错误。
您已经在Khronos Vulkan Discord上提到,您使用了我发布的使用ash的构建器模式和push_next
功能的代码,但我想我明白了为什么您的原始代码会触发验证层。
启用该功能
您正在启用VK_EXT_buffer_device_address
并使用其结构VkPhysicalDeviceBufferDeviceAddressFeaturesEXT
,
但VK_KHR_buffer_device_address
不赞成使用VK_EXT_buffer_device_address
;它被提升为KHR扩展。
这里没有什么价值,VkPhysicalDeviceBufferDeviceAddressFeaturesKHR
是而不是VkPhysicalDeviceBufferDeviceAddressFeaturesEXT
的别名,它是一个不同的结构(…具有相同的布局(
因此它们具有不同的sType
值:
// Provided by VK_EXT_buffer_device_address
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000,
// Provided by VK_VERSION_1_2
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000,
// Provided by VK_KHR_buffer_device_address
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES,
现在,让我们检查验证层的相关代码,它在其中检查vkAllocateMemory
:的VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT
标志
VkBool32 buffer_device_address = false;
// --snip--
const auto *bda_features = LvlFindInChain<VkPhysicalDeviceBufferDeviceAddressFeatures>(device_createinfo_pnext);
if (bda_features) {
capture_replay = bda_features->bufferDeviceAddressCaptureReplay;
buffer_device_address = bda_features->bufferDeviceAddress;
}
它试图在pNext
链中找到一个VkPhysicalDeviceBufferDeviceAddressFeatures
,它是VkPhysicalDeviceBufferDeviceAddressFeaturesKHR
的别名,而不是EXT,这可以从LvlFindInChain
的源代码中看出:
// Find an entry of the given type in the const pNext chain
template <typename T> const T *LvlFindInChain(const void *next) {
// --snip--
if (LvlTypeMap<T>::kSType == current->sType) {
// Map type VkPhysicalDeviceBufferDeviceAddressFeatures to id VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES
template <> struct LvlTypeMap<VkPhysicalDeviceBufferDeviceAddressFeatures> {
static const VkStructureType kSType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
};
也就是说,验证层查找具有sType
==VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES
==1000257000
的结构,
而不是具有VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT
==1000244000
的结构,因此得出结论,bufferDeviceAddress
功能未启用。
您需要使用升级的KHR驱动程序来满足验证层的要求,尽管您的Vulkan驱动程序可能也支持不推荐使用的EXT驱动程序。
gpu分配器
至于为什么使用gpu分配器机箱似乎需要启用缓冲区设备地址,
我建议检查是否意外将gpu_allocator::vulkan::AllocatorCreatorDesc::buffer_device_address
设置为true
这是在调用vkAllocateMemory
:时提示库使用VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT
的原因
let allocation_flags = vk::MemoryAllocateFlags::DEVICE_ADDRESS;
let mut flags_info = vk::MemoryAllocateFlagsInfo::builder().flags(allocation_flags);
// TODO(manon): Test this based on if the device has this feature enabled or not
let alloc_info = if buffer_device_address {
alloc_info.push_next(&mut flags_info)