调用 vkEnumerateDeviceExtensionProperties "twice" - 是否需要?

Calling vkEnumerateDeviceExtensionProperties "twice" - is it required?

本文关键字:是否 vkEnumerateDeviceExtensionProperties twice 调用      更新时间:2023-10-16

从vkEnumerateDeviceExtensionProperties的手册页,

vkEnumerateDeviceExtensionProperties检索的属性中给定句柄的物理设备上的扩展物理设备。确定图层集实现的扩展pLayerName指向层的名称和任何返回的扩展名由该层实现。将pLayerName设置为NULL将返回可用的非层扩展。pPropertyCount必须设置为pProperties指向的VkExtensionProperties数组的大小。这个pProperties应该指向要填写或为空如果为null,vkEnumerateDeviceExtensionProperties将使用找到的扩展数更新pPropertyCountVkExtensionProperties的定义如下:

(强调矿)。在当前的实现(Window SDK v1.0.13)中,无论pProperties是否为null,pPropertyCount都会随扩展的数量而更新。然而,文档似乎没有明确说明在这种情况下会发生什么。

以下是一个例子,说明为什么拥有这样的功能"更好":

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);
//...
}

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

来自最新规范:

对于vkEnumerateInstanceExtensionProperties和vkEnuerateDeviceExtensionProperties,如果pProperties为NULL,则在pPropertyCount中返回可用的扩展属性数。否则,pPropertyCount必须指向一个变量,该变量由用户设置为pProperties数组中的元素数,,返回时,该变量将被实际写入pProperties的结构数覆盖。如果pPropertyCount小于可用的扩展属性数,则最多将写入pPropertyCount结构。如果pPropertyCount小于可用扩展的数量,则将返回VK_INCOMPLETE而不是VK_SUCCESS,以表明并非所有可用属性都已返回。

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

还要注意的是,自1.0.13以来,设备层已被弃用。所有实例层都能够拦截对实例和从中创建的设备的命令

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

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

如果在第二步中获得VkResult::VK_INCOMPLETE结果,则传递的数组太短,无法取回所有对象。注意VK_INCOMPLETE不是错误,它是部分成功(2.6.2返回代码…"所有成功的完成代码都是非负值。")

您的问题:

我是否依赖于不受支持的功能这个,或者这是在《文档

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

我的回答:是的,你"猜测"是在做一个糟糕的设计决定数组大小。

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

我将使用另一个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函数的双重调用的两美分这是一个幼稚的实现,可能不适用于所有情况请注意,在调用包装函数之前,必须创建向量。

祝你好运!