пятница, 4 марта 2016 г.

Vulkan API, Command Buffers

Признаться, начинал я переводить эту главу нехотя, во-првых - она очень большая :)
Во-вторых - на этом месте все туториалы делают большой прыжок и минуя эту главу начинают создавать поверхность рендеринга, фреймбуфер и прочее. Был и у меня такой соблазн, темболе что предыдущие главы были достаточно простыми. Однако я себя пересилил и думал правильно сделал. Тут как никогда подходит выражение - "чем дальше в лес тем больше дров", количество понятий, новых терминов, нюансов использования и связей с другими объектами здесь просто зашкаливает. Боюсь к этой статье придется возвращаться еще не раз, так как на этом этапе нужно начинать планировать всю архитектуру вашего приложения, причем в таких деталях, что аж мурашки по коже :) Без этого ваше приложение будет работать, но эффективность его будет на уровне вызовов glBegin/glEnd на фоне дисплейных списков. Вообщем скоро вы сами все поймете :)



Command Buffers


Буферы команд это объекты, используемые для записи команд, которые могут быть впоследствии отправлены в очередь устройства для выполнения. Существует два уровня буферов команд - первичный буфер команд, который может выполнять вторичный буфер команд и который отправляется в очередь. И вторичный буфер команд, который может быть исполнен первичным буфером команд и который на прямую не отправляется в очередь.


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


Существует одно исключение из этоо правила, если первичный буфер команд находится внутри инстанса прохода рендера (render pass), тогда рендер пасс и его сабпассы не нарушаются в результате выполнения вторичного буфера команд.


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


Если не указано иное, и без явной синхронизации, команды, отправленные в очередь через командные буферы, могут выполняться в произвольном порядке по отношению друг к другу, и/или одновременно. Коме того, если эти команды изменяли память, то результаты без барьеров памяти эти результаты не будут видимы другим командам. Это действительно как внутри буфера команд так и между буферами команд, отправленными в данную очередь.


Каждый буфер команд всегда находится в одном из трех состояний:


• Начальное состояние: до вызова vkBeginCommandBuffer или если буфер команд был сброшен с момента последней записанной команды.
• Состояние записи: между вызовом vkBeginCommandBuffer и vkEndCommandBuffer, состояние при котором возможна запись команд.
• Состояние выполнения: после vkEndCommandBuffer, буфер команд находится в состоянии когда запись завершена и команды могут выполняться.


Сброс буфера команд  - эта команда отменяет все записанные ранее команды и переводит буфер в начальное состояние. Сброс происходит после вызова vkResetCommandBuffer или vkResetCommandPool, или как часть vkBeginCommandBuffer (которая так же дополнительно переводит буфер в состояние записи).


Command Pools


Командный пул это объект из которого аллоцируются буферы команд и который позволяет реализации снизить стоимость создания ресурсов при использования множества буферов команд. За синхронизацию командного пула отвечает приложение, это значит, что командный пул не должен использоваться одновременно в нескольких потоках. Это включает запись команд в любой буфер команд полученный из пула, так же как и операции которые выделяют, освобождают и сбрасывают буферы команд или сам пул.


Чтоб создать пул команд необходимо вызвать команду:
VkResult vkCreateCommandPool(
VkDevice device,
const VkCommandPoolCreateInfo * pCreateInfo,
const VkAllocationCallbacks * pAllocator,
VkCommandPool * pCommandPool);


• device - логическое устройство, которое создает командный пул.
• pCreateInfo - содержит информацию, необходимую для создания командного пула.
• pAllocator - контролирует выделение памяти хостом, может быть NULL.
• pCommandPool - указатель на возвращаемый хэндл VkCommandPool.


Коды ошибок:
Success
• VK_SUCCESS
Failure
• VK_ERROR_OUT_OF_HOST_MEMORY
• VK_ERROR_OUT_OF_DEVICE_MEMORY


Структура VkCommandPoolCreateInfo определяется как:
typedef struct VkCommandPoolCreateInfo {
VkStructureType sType;
const void * pNext;
VkCommandPoolCreateFlags flags;
uint32_t queueFamilyIndex;
} VkCommandPoolCreateInfo;


• sType равен VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO.
• pNext - должен быть NULL.
• flags - комбинация битовых флагов, определяющая поведене использования пула и созданных им буферов команд. Возможные значения:
typedef enum VkCommandPoolCreateFlagBits {
   VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001,
   VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002,
} VkCommandPoolCreateFlagBits;


– VK_COMMAND_POOL_CREATE_TRANSIENT_BIT - предполагает, что буфер команд, полученный с пула, будет короткоживущим, что означает что он будет освобожден или сброшен в относительно короткое время. Этот флаг может использоваться реализацией Вулкана чтоб контролировать выделение памяти  внутр пула.
– VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT - указывает что буферы команд, полученные из пула, могут сбрасываться независимо. Если этот флаг установлен, то отдельные буферы команды могут сбрасываться как явно, через вызов vkResetCommandBuffer так и автоматически, при вызове vkBeginCommandBuffer на выполняемом буфере команд. Если этот флаг не задан, то тогда vkResetCommandBuffer и vkBeginCommandBuffer не должны вызываться на командных буферах, полученных из пула и могут быть сброшены только при вызове vkResetCommandPool.
• queueFamilyIndex - индекс семейства очередей. Все буферы команд, созданные из этого командного пула, должны быть отправлены в очереди одного семейства.


Чтоб сбросить командный пул необходимо вызвать команду:
VkResult vkResetCommandPool(
VkDevice device,
VkCommandPool commandPool,
VkCommandPoolResetFlags flags);
• device - хэнд логического устройства. владеющего этим пулом.
• commandPool - хэндл командного пула, который нужно сбросить.
• flags - содержит комбинацию флагов VkCommandPoolResetFlagBits, управляющую поведением сброса.
Заметка: device и commandPool должны быть созданы из одного физического устройства.
Объекты, полученные из пула commandPool, не должны быть в состоянии ожидания выполнения.


Коды ошибок:
Success
• VK_SUCCESS
Failure
• VK_ERROR_OUT_OF_HOST_MEMORY
• VK_ERROR_OUT_OF_DEVICE_MEMORY


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


параметр flags имеет тип VkCommandPoolResetFlags, который может содержать флаги. определенные в структуре VkCommandPoolResetFlagBits:
typedef enum VkCommandPoolResetFlagBits {
   VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001,
} VkCommandPoolResetFlagBits;


Если flags включает  VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT, то сброс командного возвращает все ресурсы обратно в систему.


Удаление командного пула производится командой:
void vkDestroyCommandPool(
VkDevice device,
VkCommandPool commandPool,
const VkAllocationCallbacks * pAllocator);


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


Command Buffer Lifetime


Буфер команд создается командной:


VkResult vkAllocateCommandBuffers(
VkDevice device,
const VkCommandBufferAllocateInfo * pAllocateInfo,
VkCommandBuffer * pCommandBuffers);


• device - логическое устрой, владеющее командным пулом.
• pAllocateInfo - указатель на инстанс структуры VkCommandBufferAllocateInfo, содержащей дополнительную информацию о создании пула.
• pCommandBuffers - указывает на массив, в который будут возвращены создаваемые буферы команд. Размер массива под буферы определяется через pAllocateInfo.commandBufferCount. Все создаваемые буфере переводятся в начальное состояние.


Синхронизация: доступ хоста к pAllocateInfo →commandPool требует синхронизации.


Возвращаемые коды ошибки:
Success
• VK_SUCCESS
Failure
• VK_ERROR_OUT_OF_HOST_MEMORY
• VK_ERROR_OUT_OF_DEVICE_MEMORY


Структура VkCommandBufferAllocateInfo оперделена как:
typedef struct VkCommandBufferAllocateInfo {
VkStructureType sType;
const void * pNext;
VkCommandPool commandPool;
VkCommandBufferLevel level;
uint32_t commandBufferCount;
} VkCommandBufferAllocateInfo;


• sType - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO.
• pNext - должен быть NULL.
• commandPool - хэндл пула из которого мы хотим получить буфер команд.
• level - определяет будет этот буфер первичным или вторичным. Возможные значения:
typedef enum VkCommandBufferLevel {
VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0,
VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1,
} VkCommandBufferLevel;
• commandBufferCount - количество получаемых буферов команд.


Сброс буфера команд производится через:
VkResult vkResetCommandBuffer(
VkCommandBuffer commandBuffer,
VkCommandBufferResetFlags flags);
• flags может содержать флаги, определенные в VkCommandBufferResetFlagBits:
typedef enum VkCommandBufferResetFlagBits {
  VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001,
} VkCommandBufferResetFlagBits;


• commandBuffer - должен быть получен из пула, созданного с параметром: VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT


Если flags включает бит:
VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT,
то при сбросе буфера все ресурсы будут возвращены в соответствующий пул, в иначе, буфер будет продолжать использовать эти ресурсы и может быть вновь использован для записи команд.


Возвращаемые коды ошибок:
Success
• VK_SUCCESS
Failure
• VK_ERROR_OUT_OF_HOST_MEMORY
• VK_ERROR_OUT_OF_DEVICE_MEMORY


Буферы команд освобождаются вызовом:
void vkFreeCommandBuffers(
VkDevice device,
VkCommandPool commandPool,
uint32_t commandBufferCount,
const VkCommandBuffer * pCommandBuffers);
• device - логическое устройство владеющее соответствующим пулом.
• commandPool - хэнд пула из которого был получен буфер.
• commandBufferCount - количество элементов в массиве pCommandBuffers.
• pCommandBuffers - массив освобождаемых буферов команд.


Синхронизация:
• Доступ хоста к commandPool требует синхронизации.
• Доступ хоста к каждому элементу pCommandBuffers требует синхронизации.


Command Buffer Recording


Чтоб начать запись в буфер команд необходимо вызвать функцию:
VkResult vkBeginCommandBuffer(
VkCommandBuffer commandBuffer,
const VkCommandBufferBeginInfo * pBeginInfo);


• commandBuffer - хэнд буфера команд, куда будут помещатсья записываемые состояния.
  • Не должен быть в состоянии выполнения.
  • Если у Пула. из которого был создан буфер, не был установлен флаг VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, то commandBuffer должен находиться в начальном состоянии.
  • если commandBuffer это вторичный буфер, то поле pInheritanceInfo структуры pBeginInfo должно указывать на валидную структуру VkCommandBufferInheritanceInfo.
  • если commandBuffer это вторичный буфер, или же поле occlusionQueryEnable структуры pInheritanceInfo имеет значение VK_FALSE, или не активно свойство precise occlusion queries, то поле queryFlags структуры pInheritanceInfo параметра pBeginInfo не должно содержать флага VK_QUERY_CONTROL_PRECISE_BIT.
• pBeginInfo - указатель на иснтанс структуры VkCommandBufferBeginInfo, содержащий дополнительную информацию о том. как команды будут записываться в буфер.


Возвращаемые коды ошибок:
Success
• VK_SUCCESS
Failure
• VK_ERROR_OUT_OF_HOST_MEMORY
• VK_ERROR_OUT_OF_DEVICE_MEMORY


Структура VkCommandBufferBeginInfo определена как:
typedef struct VkCommandBufferBeginInfo {
VkStructureType sType;
const void * pNext;
VkCommandBufferUsageFlags flags;
const VkCommandBufferInheritanceInfo * pInheritanceInfo;
} VkCommandBufferBeginInfo;
• sType =  VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO.
• pNext - должен быть NULL.
• flags - комбинация флагов VkCommandBufferUsageFlagBits:
 typedef enum VkCommandBufferUsageFlagBits {
   VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001,
   VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002,
   VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004,
 } VkCommandBufferUsageFlagBits;
– VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT -  указывает что каждая запись в буфере будет добавлена в буфер единожды и между этим буфер будет сброшен и перезаписан.
– VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT - предполагается что вторичный буфер команд  будет находиться целиком в проходе рендера: поле renderPass параметра pInheritanceInfo должно ссылаться на валидный хэндл VkRenderPass, поле subpass - валидный индекс внутри renderPass. Если это первичный буфер, то значение этого бита игнорируется. Поле framebuffer параметра pInheritanceInfo должно быть или VK_NULL_HANDLE или валидный VkFramebuffer, совместимый с renderPass, указанным в pInheritanceInfo.
– Setting VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT - позволяет повторно отправлять буфер в очередь или записывать его в первичный буфер команд, пока отложено выполнение.


• pInheritanceInfo - указатель на структуру VkCommandBufferInheritanceInfo, которая используется только в случае когда commandBuffer это вторичный буфер команд, для первичного это поле игнорируется.


Если буфер команд будет вторичным, тогда нужно заполнить структуру VkCommandBufferInheritanceInfo, в которой определены состояния, наследуемые из первичного буфера команд:
typedef struct VkCommandBufferInheritanceInfo {
VkStructureType sType;
const void * pNext;
VkRenderPass renderPass;
uint32_t subpass;
VkFramebuffer framebuffer;
VkBool32 occlusionQueryEnable;
VkQueryControlFlags queryFlags;
VkQueryPipelineStatisticFlags pipelineStatistics;
} VkCommandBufferInheritanceInfo;
• sType =  VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO.
• pNext - должен быть NULL.
• renderPass - объект VkRenderPass, который должен быть совместим используемым, при выполнении VkCommandBuffer, если буфер команд был создан с установленным битом: VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT.
• subpass - индекс прохода в renderPass, который будет рендериться в  VkCommandBuffer, если он был создан с битом:  VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT.
• framebuffer - указывает на объект VkFramebuffer, куда VkCommandBuffer будет осуществлять рендеринг, если он был создан с битом: VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT. Если фреймбуфер не известен, то он может быть VK_NULL_HANDLE.
Заметка: Точное указание framebuffer, для которого будет выполнен вторичный буфер команд, может улучшить производительность выполнения буфера команд.


• occlusionQueryEnable - указывает будет ли выполняться буфер команд пока активен occlusion query в первичном буфере. Если его значение VK_TRUE, тогда этот буфер команд может выполняться будь то occlusion query активно или нет. Если значение VK_FALSE, то первичный буфер команд не должен иметь активного occlusion query.
• queryFlags - определяет флаги, которые могут быть использованы активным occlusion query и первичном буфере команд, когда выполняется этот вторичный буфер команд. Если это значение включает бит VK_QUERY_CONTROL_PRECISE_BIT, тогда активный запрос может вернуть результат как логический или как актуальное количество сэмплов. Если этот бит не установлен, тогда активный запрос не должен использовать бит VK_QUERY_CONTROL_PRECISE_BIT, если это первичный буфер, это значение игнорируется.
• pipelineStatistics - если эта возможность не активна, то  pipelineStatistics должен быть равен 0. Это поле указывает что набор статистических данных пайплайна может быть учтен активным запросом первичного буфера, пока выполняется вторичный буфер команд. Если это значение включает данный бит, то буфер команд может быть выполнен не зависимо от того имеет ли первичный буфер установленный бит или же активен запрос статистики пайплайна. Если из значения исключен данный бит, то запрос не может идти от пула, в котором активен сбор статистики.


Первичный буфер команд считается находящимся в состоянии ожидания выполнения с момента, когда он был отправлен через vkQueueSubmit и до момента пока его выполнение не завершится.
Для вторичного буфера команд состояние ожидания начинается с момента, когда его выполнение было записано в первичный буфер через vkCmdExecuteCommands, и до момента, пока все задачи в очереди первичного буфера не будут завершены. Если после завершения в первичном буфере, вторичный буфер будет записан для исполнения в другой первичный буфер, то первичный буфер не должен быть переотправлен в очередь пока он не будет сброшен через vkResetCommandBuffer. Если VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT не установлен для вторичного буфера, тогда буфер команд нельзя использовать более одного раза в данном первичном буфере.мБолее того, если вторичный буфер, в котором не установлен бит VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, будет записан для выполнения в первичный буфер, с установленным битом VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, первичный буфер, не быть переведен в состояние ожидания более одного раза.


Заметка: некоторые из реализаций Вулкана не использующие бит  VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, позволяют при необходимости “патчить” буфер команд на месте, вместо того, чтоб создавать копию буфера команд.


Если буфер команд в состоянии исполнения, он был создан пулом с установленным битом VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, тогда  vkBeginCommandBuffer автоматически сбрасывает буфер команд так, как если бы была вызвана команда vkResetCommandBuffer с неустановленным битом  VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT, это тогда переводит буфер команд в состояние записи.


Как только началась запись, приложение записывает последовательность команд (vkCmd * ), устанавливающих состояние (рисования, вычисления и другие команды ), в буфер команд. Чтоб завершить запись необходимо вызвать функцию:
VkResult vkEndCommandBuffer(
VkCommandBuffer commandBuffer);
• commandBuffer - буфер для записи, должен быть в состоянии записи, после выполнения команды переводится в состояние исполнения.


vkEndCommandBuffer не должна вызываться непосредственно внутри прохода рендера.
Все запросы, которые были активированы в в процессе записи, должны быть деактивированы.
Если в процессе выполнения функция vkEndCommandBuffer вернула ошибку, то для дальнейшего использования буфер команд должен быть сброшен.
Когда буфер находится в состоянии исполнения, он может быть отправлен в очередь для выполнения.


Возвращаемые коды ошибок:
Success
• VK_SUCCESS
Failure
• VK_ERROR_OUT_OF_HOST_MEMORY
• VK_ERROR_OUT_OF_DEVICE_MEMORY


Command Buffer Submission
Буферы команд оправляются в очередь через вызов:
VkResult vkQueueSubmit(
VkQueue queue,
uint32_t submitCount,
const VkSubmitInfo * pSubmits,
VkFence fence);


• queue - очередь в которую будет отправлен буфер команд.
• submitCount - количество элементов в массиве pSubmits.
• pSubmits - указатель на массив структур VkSubmitInfo, которые описывают отправляемые задачи. Все задачи, описанные в pSubmits, должны быть отправлены в очередь до того как команда вернет управление.
• fence - опциональный параметр, если fence не равно VK_NULL_HANDLE, fence посылает сигнал когда выполнение всех задач в VkSubmitInfo:: pCommandBuffers завершено. Если submitCount равен нулю, а fence  не VK_NULL_HANDLE, тогда fence все равно будет отправлен в очередь и будет сигнализировать о том, что предыдущая задача, отправленная в очередь, была завершена. Начальное значение fence должно быть “ unsignalled”, и fence не должно быть связано ни с одной из команд в очереди, чье выполнение не было завершено.


Следующие действия Хоста быть синхронизированы:
• Обращение к очереди.
• Обращение к pSubmits [].pWaitSemaphores[]
• Обращение к pSubmits [].pSignalSemaphores[]
• Обращение к fence


Возвращаемые коды ошибок:
Success
• VK_SUCCESS
Failure
• VK_ERROR_OUT_OF_HOST_MEMORY
• VK_ERROR_OUT_OF_DEVICE_MEMORY
• VK_ERROR_DEVICE_LOST


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


Заметка: Оптимальный размер отправляемого пакета зависит от платформы, но тем не менее отправка пакета относительно дорогая операция, поэтому приложение должно пытаться по мере возможности минимизировать количество вызовов vkQueueSubmit.


Каждый вызов vkQueueSubmit отправляет 0 или более пакетов задач в очередь для выполнения. Параметр submitCount указывает количество пакетов для отправки. Каждый пакет включает 0 или более семафоров, на которых происходит ожидание, и соответствующих этапов, ожидающих сигнала от семафора для начала выполнения задач, за которыми следуют выполняемые буферы команд. И наконец, 0 или более семафоров, которые сигнализируют о завершении выполнения буфера команд. Каждый пакет это массив инстансов структур VkSubmitInfo, адрес которого передается в pSubmitInfo. Определение VkSubmitInfo следующее:


typedef struct VkSubmitInfo {
VkStructureType sType;
const void * pNext;
uint32_t waitSemaphoreCount;
const VkSemaphore * pWaitSemaphores;
const VkPipelineStageFlags * pWaitDstStageMask;
uint32_t commandBufferCount;
const VkCommandBuffer * pCommandBuffers;
uint32_t signalSemaphoreCount;
const VkSemaphore * pSignalSemaphores;
} VkSubmitInfo;


• sType = VK_STRUCTURE_TYPE_SUBMIT_INFO.
• pNext = NULL.
• waitSemaphoreCount - количество семафоров в пакете.
• pWaitSemaphores - указатель на массив семафоров в пакете, которые ожидают начало выполнения буфера команд в пакете.
• pWaitDstStageMask - указатель на этапы пайплайна, в которых сработают соответствующие семафоры.
• commandBufferCount - содержит количество выполняемых в пакете буферов команд.
• pCommandBuffers - указатель на массив буферов команд, выполняемых в пакете. Буферы команд выполняются в порядке их добавления в pCommandBuffers, но могут завершаться в произвольном порядке.
• signalSemaphoreCount - количество семафоров в pCommandBuffers.
• pSignalSemaphores - указатель на массив семафоров, вызываемых по завершению выполнения буфера команд.


  • Все элементы pSignalSemaphores должны быть в состоянии “unsignalled”
  • Все элементы pCommandBuffers должны быть записаны с флагом VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT или в текущее время не вызываться на устройстве.
  • Все элементы pCommandBuffers должны находиться в состоянии выполнения.
  • Если какой-либо из элементов pCommandBuffers содержит выполнение вторичного буфера команд, тогда этот вторичный буфер должен быть записан с флагом VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT или не должен в данный момент выполняться на этом устройстве.
  • Если какой-либо из элементов pCommandBuffers был создан с флагом VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, то прежде чем он второй раз будет отправлен в очередь, его нужно перезаписать.
  • В буфере не должно быть выполнение вторичных буферов, которые были записаны в другой первичный буфер, после того, как они были добавлены в текущий буфер команд.
  • Все элементы в pCommandBuffers должны быть созданны в одном VkCommandPool, который был создан для того же семейства очередей, что и вызывающая команды очередь.
  • Элементы pCommandBuffers не могут быть созданы с флагом VK_COMMAND_BUFFER_LEVEL_SECONDARY.
  • Все семафоры в pWaitSemaphores должны ссылаться на предшествующий сигнал VkSemaphore, который не будет использоваться для ожидания другим семафором.
  • Если возможность использования геометрического шейдера не активна, то элементы pWaitDstStageMask не должны содержать флага  VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT
  • Если возможность использования шейдера тесселляции не активна, то элементы pWaitDstStageMask не должны содержать флагов VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT  и  VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT


Если передается fence, то он должен быть в состоянии “unsignaled” и он должен быть связан только с одним пакетом, пока выполнение этого пакета не завершится, впоследствии он сбрасывается. Когда выполнение всех буферов команд в pCommandBuffers было завершено, статус fence устанавливается в “signaled”, предоставляя определенную неявную гарантию порядка выполнения буферов.


Queue Forward Progress


Приложение должно гарантировать, что пакеты буферов команд способны завершить выполнение без каких либо последующих действий со стороны приложения на любой из очередей. После любого из вызовов vkQueueSubmit, каждой очереди ожидания на семафоре должен предшествовать сигнал этого семафора, который не может быть задействован для ожидания на другом семафоре.
Буферы команд в пакете могут включать команды vkCmdWaitEvents, которые могут ожидать события, которые не посылаются предыдущими командами в этой очереди, такие события должны отправляться приложением через команды vkSetEvent и vkCmdWaitEvents, на которых ожидание происходит вне инстанса рендер пасса. Реализация Вулкана может иметь ограничения на то, как долго буфер команд будет ожидать, чтоб не мешать ходу работы других клиентов устройства. Если событие не произошло в рамках этих лимитов, результат будет не определен и может включать потерю устройства.


Secondary Command Buffer Execution
Вторичный буфер команд не может быть явно отправлен в очередь, вместо этого, вторичный буфер записывается на выполнение как часть первичного буфера команд через:
void vkCmdExecuteCommands(
VkCommandBuffer commandBuffer,
uint32_t commandBufferCount,
const VkCommandBuffer * pCommandBuffers);


• commandBuffer - хэндл первичного буфера команд (созданный с флагом  VK_COMMAND_BUFFER_LEVEL_PRIMARY), куда будет отправлены эти буферы. Первичный буфер для этого должен находиться в состоянии записи.
• commandBufferCount - количество элементов в массиве pCommandBuffers.
• pCommandBuffers - массив вторичных буферов команд, который будут записаны для выполнения в первичный буфер команд в порядке в каком он перечисленны в массиве.
• Все элементы pCommandBuffers должны быть созданы с флагом VK_COMMAND_BUFFER_LEVEL_SECONDARY
• Ни один из элементов pCommandBuffers не должен быть в состоянии ожидания выполнения в commandBuffer, или дважды появляться в pCommandBuffers, кроме случая когда он был создан с флагом  VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT.
• Н один из элементов pCommandBuffers не должен быть в состоянии ожидания выполнения в любом другом VkCommandBuffer, кроме случая, когда он создан с флагом VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT
• Все элементы pCommandBuffers должны быть в состоянии выполнения
• Если vkCmdExecuteCommands был вызван внутри инстанса рендер пасса, то этот инстанс рендер пасса должен начинаться с содержимого параметра vkCmdBeginRenderPass установленного в VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
• Если vkCmdExecuteCommands был вызван внутри инстанса рендер паса, все элементы pCommandBuffers должны быть записаны с флагом VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
• Если vkCmdExecuteCommands был вызван внутри инстанса рендер паса, все элементы pCommandBuffers должны быть записаны с указанием поля subpass структуры inheritanceInfo, при этом индекс этого subpass должен быть индексом subpass в котором эта команда будет вызываться.
• Если vkCmdExecuteCommands был вызван внутри инстанса рендер паса, все элементы pCommandBuffers должны быть записаны с render pass, который совместим с текущим render pass
• Если vkCmdExecuteCommands вызван внутри инстанса рендер паса, все элементы pCommandBuffers должны быть записаны с полем framebuffer структуры  VkCommandBufferInheritanceInfo не рвной VK_NULL_HANDLE, тогда VkFramebuffer должен быть совместим с VkFramebuffer, используемым в инстансе текущего рендер пасса
• Если функция наследования запросов не включена, то буфер команд не должен иметь активных запросов.
• Если у commandBuffer активен запрос VK_QUERY_TYPE_OCCLUSION, тогда все элементы pCommandBuffers должны быть записаны с параметром VkCommandBufferBeginInfo:: occlusionQueryEnable установленным в VK_TRUE
• Если у commandBuffer активен запрос VK_QUERY_TYPE_OCCLUSION, то все элементы pCommandBuffers должны быть записаны с параметром  VkCommandBufferBeginInfo:: queryFlags со всеми установленными битами устанавливаемыми для запросов.
• Если у commandBuffer активен запрос VK_QUERY_TYPE_PIPELINE_STATISTICS, тогда все элементы pCommandBuffers должны быть записаны с параметром VkCommandBufferBeginInfo:: pipelineStatistics, в котором все биты должны иметь те же значения что и в VkQueryPool, который этот запрос использует.
• Ни один из элементов pCommandBuffers не должен начинаться с запросов, которые активны в commandBuffer


Command Properties
Command Buffer Levels: Первичный
Render Pass Scope: Оба
Supported Queue Types: TRANSFER, GRAPHICS, COMPUTE


Как только команда vkCmdExecuteCommands была вызвана, все предыдущие исполнения вторичных буферов команд, указанных в pCommandBuffers во всех остальных первичных буферах будут аннулированы, если эти вторичные буферы команд не были записаны с флагом  VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT.

Комментариев нет:

Отправить комментарий