调用 vkEnumerateDeviceExtensionProperties "twice" - 是必需的吗?

Calling vkEnumerateDeviceExtensionProperties "twice" - is it required?

来自man page for vkEnumerateDeviceExtensionProperties

vkEnumerateDeviceExtensionProperties retrieves properties for extensions on a physical device whose handle is given in physicalDevice. To determine the extensions implemented by a layer set pLayerName to point to the layer’s name and any returned extensions are implemented by that layer. Setting pLayerName to NULL will return the available non-layer extensions. pPropertyCount must be set to the size of the VkExtensionProperties array pointed to by pProperties. The pProperties should point to an array of VkExtensionProperties to be filled out or null. If null, vkEnumerateDeviceExtensionProperties will update pPropertyCount with the number of extensions found. The definition of VkExtensionProperties is as follows:

(强调我的)。似乎在当前的实现中(Window SDK v1.0.13),pPropertyCount 随着扩展数量更新的,不管pProperties是否是是否为空。但是,文档似乎没有明确说明在这种情况下会发生什么。

这里有一个例子,说明为什么拥有这样的功能 'nicer':

const uint32_t MaxCount = 1024; // More than you'll ever need
uint32_t ActualCount = MaxCount;
VkLayerProperties layers[MaxCount];
VkResult result = vkEnumerateDeviceLayerProperties(physicalDevice, &ActualCount, layers);
//...

对比

uint32_t ActualCount = 0;
VkLayerProperties* layers;
VkResult result = vkEnumerateDeviceLayerProperties(physicalDevice, &ActualCount, nullptr);
if (ActualCount > 0) 
{
    extensions = alloca(ActualCount * sizeof(VkLayerProperties));
    result = vkEnumerateDeviceLayerProperties(physicalDevice, &ActualCount, layers);
    //...
}

我的问题是:我这样做是依赖于不受支持的功能,还是以某种方式在文档的其他地方做广告?

来自latest spec

For both vkEnumerateInstanceExtensionProperties and vkEnumerateDeviceExtensionProperties, if pProperties is NULL, then the number of extensions properties available is returned in pPropertyCount. Otherwise, pPropertyCount must point to a variable set by the user to the number of elements in the pProperties array, and on return the variable is overwritten with the number of structures actually written to pProperties. If pPropertyCount is less than the number of extension properties available, at most pPropertyCount structures will be written. If pPropertyCount is smaller than the number of extensions available, VK_INCOMPLETE will be returned instead of VK_SUCCESS, to indicate that not all the available properties were returned.

所以你的方法是正确的,尽管它有点浪费内存。返回数组的类似函数也有这样的行为。

另请注意,自 1.0.13 起,设备层已弃用。所有实例层都能够拦截对实例和从实例创建的设备的命令。

大多数 Vulkan 命令在双重调用中中继:

  1. 第一次调用以获取返回结构或句柄的计数;
  2. 第二次调用传递一个适当大小的数组以返回请求 structures/handle。在第二次调用中,count 参数告诉您数组的大小。

如果,在第二步中,您得到 VkResult::VK_INCOMPLETE 结果,那么您传递的数组太短,无法取回所有对象。注意 VK_INCOMPLETE 不是错误,它是部分成功 (2.6.2 Return Codes ... "All successful completion codes are non-negative values. ")

您的问题:

Am I depending on unsupported functionality by doing this, or is this somehow advertised somewhere else in the documentation?

您建议在调用函数之前创建一个大数组,以避免调用 Vulkan 函数两次。

My reply: Yes, and you are doing a bad design decision by "guessing" the array size.

请不要误会我的意思。 我非常同意你的观点,调用同一个函数两次很烦人,但你可以通过用对程序员更友好的行为包装这些排序函数来解决这个问题。

我将使用另一个 Vulkan 函数来进行说明。假设您想避免重复调用 :

VkResult vkEnumeratePhysicalDevices(
VkInstance                                  instance,
uint32_t*                                   pPhysicalDeviceCount,
VkPhysicalDevice*                           pPhysicalDevices);

一个可能的解决方案是编写甜蜜包装函数:

VkResult getPhysicalDevices(VkInstance instance,  std::vector<VkPhysicalDevice>& container){
   uint32_t count = 0;
   VkResult res = vkEnumeratePhysicalDevices(instance, &count, NULL); // get #count
   container.resize(count); //Removes extra entries or allocates more.
   if (res < 0) // something goes wrong here
         return res;       
   res =  vkEnumeratePhysicalDevices(instance, &count, container.data()); // all entries overwritten.
   return res; // possible OK        
}

这是我对 Vulkan 函数的双重调用的两分钱。 这是一个天真的实现,可能不适用于所有情况!请注意,您必须在调用包装函数之前创建矢量。

祝你好运!