Вызов vkEnumerateDeviceExtensionProperties дважды - это обязательно?

На странице vkEnumerateDeviceExtensionProperties,

vkEnumerateDeviceExtensionProperties извлекает свойства для расширений на физическом устройстве, дескриптор которого указан в PhysicalDevice. Чтобы определить расширения, реализованные на уровне, установите pLayerName так, чтобы он указывал на имя уровня, и любые возвращенные расширения будут реализованы этим уровнем. Установка для pLayerName значения NULL вернет доступные расширения, не относящиеся к слою. pPropertyCount должен быть установлен равным размеру массива VkExtensionProperties, на который указывает pProperties. PProperties должен указывать на массив VkExtensionProperties, который нужно заполнить или обнулить. Если значение равно нулю, vkEnumerateDeviceExtensionProperties обновит pPropertyCount, указав количество найденных расширений. Определение VkExtensionProperties выглядит следующим образом:

(курсив мой). Кажется, что в текущей реализации (Window SDK v1.0.13) pPropertyCount обновляется с учетом количества расширений, независимо от того, является ли 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);
//...

vs.

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

У меня вопрос: я зависим от неподдерживаемых функций, делая это, или это каким-то образом рекламируется где-то еще в документации?


person MuertoExcobito    schedule 06.06.2016    source источник
comment
Страницы man / ref плохо обслуживаются банкоматом, прочтите спецификацию напрямую. ; На самом деле вам может потребоваться позвонить четыре и более раз, в маловероятном случае, если вы получите VK_INCOMPLETE. ; Нет ничего плохого и в вашем подходе с одним вызовом, и спецификация достаточно четко об этом говорит.   -  person krOoze    schedule 06.06.2016


Ответы (2)


Из последней спецификации:

Для vkEnumerateInstanceExtensionProperties и vkEnumerateDeviceExtensionProperties, если pProperties имеет значение NULL, то количество доступных свойств расширений возвращается в pPropertyCount. В противном случае pPropertyCount должен указывать на переменную, установленную пользователем для количества элементов в массиве pProperties, и при возврате переменная перезаписывается количеством структур, фактически записанных в pProperties. Если pPropertyCount меньше, чем количество доступных свойств расширения, будет записано не более pPropertyCount структур. Если pPropertyCount меньше количества доступных расширений, вместо VK_SUCCESS будет возвращено VK_INCOMPLETE, чтобы указать, что были возвращены не все доступные свойства.

Итак, ваш подход правильный, хотя он немного расточает память. Аналогичные функции, возвращающие массивы, также ведут себя так.

Также обратите внимание, что с 1.0.13 уровни устройств устарели. Все уровни экземпляра могут перехватывать команды как экземпляру, так и устройствам, созданным из него.

person Quinchilion    schedule 06.06.2016
comment
спасибо - не видел новый язык спецификации. Кроме того, мой подход не является расточительным в отношении памяти - объекты, выделенные стеком, на самом деле не учитываются, если у вас не закончилось пространство стека. - person MuertoExcobito; 06.06.2016
comment
@MuertoExcobito: Стековая память очень важна. Как только виртуальная страница стека зафиксирована, вы не можете освободить ее. Он занимает место навсегда. Поэтому, если вы регулярно не используете тонны пространства стека, вы занимаетесь памятью, которая никогда не будет использоваться. Кроме того, многие компиляторы предоставляют вам только 1 МБ или около того места в стеке. 1024 слоя позволяют только VkLayerProperties иметь размер 1 КБ, прежде чем вы переполнитесь. И sizeof(VkLayerProperties) превышает 500 байт. Так что это не просто расточительно; высока вероятность переполнения. - person Nicol Bolas; 07.06.2016
comment
Справедливо, однако, этот код работает на всех платформах Vulkan без переполнения стека. Возможно, размер массива можно было бы немного уменьшить, поскольку 1024 расширения, вероятно, будут излишними. - person MuertoExcobito; 07.06.2016
comment
@MuertoExcobito OpenGL в настоящее время имеет около 600 расширений. Сделайте себе одолжение и просто динамически распределяйте его (это не значит, что сканирование исключений - это горячий путь). - person Colonel Thirty Two; 07.06.2016
comment
хорошо, хорошо, мне нужно побороть тягу к лени ... но это тяжелая битва. Тем не менее, я чувствую, что если спецификация Vulkan была изменена для проверки того, что свойство будет возвращено, очевидно, что они имели в виду вариант использования, подобный моему. Возможно, было бы лучше просто возвращать расширения по индексу, например, OpenGL. - person MuertoExcobito; 07.06.2016
comment
@MuertoExcobito, если результат когда-либо вернет VK_INCOMPLETE, вам все равно нужно будет выполнить двойной вызов + выделение. X - это все, что кому-либо понадобится. это худшее отношение, которое когда-нибудь в будущем приведет вас к проклятию. - person ratchet freak; 07.06.2016

Большинство команд 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. Это наивная реализация, и она может работать не во всех случаях! Обратите внимание, что вы должны создать вектор ДО вызова функции упаковки.

Удачи!

person Alex Byrth    schedule 07.06.2016
comment
@Jherico - Спасибо за подсказку по параметру stl :: vector ‹›! - person Alex Byrth; 08.06.2016