2

vkEnumerateDeviceExtensionProperties 的手册页中

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

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

这是一个示例,说明为什么拥有这样的功能“更好”:

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

我的问题是:我这样做是否依赖于不受支持的功能,或者这是否以某种方式在文档中的其他地方宣传?

4

2 回答 2

2

最新规格

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

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

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

于 2016-06-06T18:21:10.673 回答
0

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

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

如果在第二步中,您得到 VkResult::VK_INCOMPLETE 结果,那么您传递的数组太短而无法取回所有对象。注意 VK_INCOMPLETE 不是错误,它是部分成功(2.6.2 Return Codes ...“所有成功的完成代码都是非负值。”)

你的问题 :

我这样做是否依赖于不受支持的功能,或者这是否以某种方式在文档中的其他地方进行了宣传?

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

我的回答:是的,您通过“猜测”数组大小做出了错误的设计决定。

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

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

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

一个可能的解决方案是编写 sweet wrap 函数:

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

祝你好运!

于 2016-06-07T16:40:27.473 回答