среда, 23 марта 2016 г.

Vulkan API, Framebuffers

Ну и предлагаю вам почитать превод последней части главы "Render Pass" спецификации, в которой рассказывается об еще одном фундаментальном понятии Вулкана - Framebuffers, они же буферы кадра или фреймбуферы. 


Render pass-ы работают в связке с фреймбуферами, которые представляют коллекцию аттачментов, используемых инстансом render pass-а.
Чтоб создать фрэймбуфер необходимо вызвать функцию::
VkResult vkCreateFramebuffer(
VkDevice device,
const VkFramebufferCreateInfo * pCreateInfo,
const VkAllocationCallbacks * pAllocator,
VkFramebuffer * pFramebuffer);

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

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

The VkFramebufferCreateInfo structure is defined as:
typedef struct VkFramebufferCreateInfo {
VkStructureType sType;
const void * pNext;
VkFramebufferCreateFlags flags;
VkRenderPass renderPass;
uint32_t attachmentCount;
const VkImageView * pAttachments;
uint32_t width;
uint32_t height;
uint32_t layers;
} VkFramebufferCreateInfo;
• sType =  VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO.
• pNext = NULL.
• flags - зарезервирован, должен быть 0.
• renderPass - render pass, который определяет с каким из render pass-ов будет совместим фреймбуфер.
• attachmentCount - количество аттачментов.
• pAttachments - массив хэндлов VkImageView, каждый из которых будет использован соответствующим аттачментом инстанса render pass-а.
• width, height и layers - определяют размерность фреймбуфера.

• Любой из элементов pAttachments, используемый renderPass-ом как color или resolve аттачмент должен быть создан с использованием бита VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
• Любой из элементов pAttachments, использованный renderPass-ом как depth/stencil аттачмент должен быть создан с флагом VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
• Любой из элементов pAttachments, используемый renderPass-ом как входной аттачмент, должен быть создан с флагом VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
• Любой из элементов pAttachments должен быть создан со значением VkFormat совпадающим с VkFormat указанным в соответствующем VkAttachmentDescription в renderPass
• Любой из элементов pAttachments должен быть создан со значением samples совпадающим со значением указанным в соответствующих VkAttachmentDescription в renderPass
• Любой из элементов pAttachments должен иметь размерность как минимум такого же размера как и размерность соответствующего фрэймбуфера
• Любой из элементов pAttachments должен представлять один mip-уровень
• Любой из элементов pAttachments должен быть создан с единичным “swizzle”
• width должен быть не более VkPhysicalDeviceLimits:: maxFramebufferWidth
• height должен быть не более VkPhysicalDeviceLimits:: maxFramebufferHeight
• layers должен быть не более VkPhysicalDeviceLimits:: maxFramebufferLayers

Ресурсы изображения, использующиеся как аттачменты, не могут быть использованны другим способом на протяжении работы инстанса render pass-а.

Заметка:
Это означает что render pass знает обо всех использованиях всех аттачментов, таким образом, имплементация может принимать правильные решения о том, когда и как выполнять смену внутренней структуры аттачмента, перекрывать выполнение subpass-ов и прочее.

Допустимо чтоб subpass не использовал color или depth/stencil аттачменты, вместо чего использовать возможности шейдеров, такие как “image stores” и атомарные операции, осуществляющие вывод. В этом случае subpass продожает использовать размерности фрэймбуфера чтоб определить размеры выводимой области и количество растеризируемых сэмплов (rasterizationSamples) из каждого
VkPipelineMultisampleStateCreateInfo, однако, если VkPhysicalDeviceFeatures:: variableMultisampleRate равен VK_FALSE, то все конвейеры, используемые без аттачментов, должны иметь одинаковое значение VkPipelineMultisampleStateCreateInfo:: rasterizationSamples

Чтоб уничтожить фреймбуфер необходимо вызвать:
void vkDestroyFramebuffer(
VkDevice device,
VkFramebuffer framebuffer,
const VkAllocationCallbacks * pAllocator);
• device - устройство, уничтожающее фреймбуфер.
• framebuffer - указатель на уничтожаемый фрэймбуфер, должен быть получен из device.
• pAllocator - контролирует выделение памяти хостом.
• Все отправленные команды, ссылающиеся на framebuffer должны быть завершены.

Render Pass Commands

Приложение записывает команды для инстанса render pass-а для одного subpass-а в один момент времени, начиная с инстанса render pass-а, проходя через все его subpass-ы и записывая команды для каждого из его subpass-ов, и затем завершая инстанс render pass-а.

Чтоб начать инстанс render pass-а необходимо вызвать:
void vkCmdBeginRenderPass(
VkCommandBuffer commandBuffer,
const VkRenderPassBeginInfo * pRenderPassBegin,
VkSubpassContents contents);

• commandBuffer - буфер команд, в который будут записываться команды.
• pRenderPassBegin - указатель на структуру VkRenderPassBeginInfo, в которой указывается инстанс render pass-а и используемый им фреймбуфер.
• contents - указывает как будут представлены команды в первом subpass-е и может иметь такие значения::
typedef enum VkSubpassContents {
VK_SUBPASS_CONTENTS_INLINE = 0,
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1,
} VkSubpassContents;

Если contents равен VK_SUBPASS_CONTENTS_INLINE, то содержимое subpass-а будет вписано в первичный буфер команд, а вторичный буфер команд не должен вызываться внутри subpass-а. Если contents равен VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, то содержимое будет записано во вторичный буфер команд, который будет вызван из первичного буфера команд, и vkCmdExecuteCommands единственная валидная команда в буфере команд пока не будет вызван vkCmdNextSubpass или vkCmdEndRenderPass.
• Эта команда должна быть вызвана вне инстанса render pass-а
• commandBuffer - должен быть первичным VkCommandBuffer
• Если любой из initialLayout или finalLayout элементов структуры VkAttachmentDescription или структуры VkAttachmentReference указан при создании render pass-а в поле renderPass из pRenderPassBegin равен VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, то соответствующие аттачменты фреймбуфера, указанные в поле framebuffer в pRenderPassBegin должны быть созданы с битом VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
• Если любой из initialLayout или finalLayout  полей структуры VkAttachmentDescription в VkAttachmentReference указанных при создании render pass-а в поле renderPass в pRenderPassBegin равен VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL или VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, то соответствующие
аттачменты фреймбуфера указанные в поле framebuffer в
pRenderPassBegin должны быть созданны с битом VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
• Если любой из initialLayout или finalLayout  полей структуры VkAttachmentDescription в VkAttachmentReference указанных при создании render pass-а в поле renderPass в pRenderPassBegin равен VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, то соответствующий аттачмент фрэймбуфера, указанный в поле framebuffer в pRenderPassBegin должен создаваться с битом VK_IMAGE_USAGE_SAMPLED_BIT или VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT.
• Если любой из initialLayout или finalLayout  полей структуры VkAttachmentDescription в VkAttachmentReference указанных при создании render pass-а в поле renderPass в pRenderPassBegin равен VK_IMAGE_LAYOUT_TRANSFER_SRC_BIT то соответствующий аттачмент фрэймбуфера, указанный в поле framebuffer в pRenderPassBegin должен создаваться с битом VK_IMAGE_USAGE_TRANSFER_SRC_BIT.
• Если любой из initialLayout или finalLayout  полей структуры VkAttachmentDescription в VkAttachmentReference указанных при создании render pass-а в поле renderPass в pRenderPassBegin равен  VK_IMAGE_LAYOUT_TRANSFER_DST_BIT, то соответствующий аттачмент фрэймбуфера, указанный в поле framebuffer в pRenderPassBegin должен создаваться с битом VK_IMAGE_USAGE_TRANSFER_DST_BIT.

После начала инстанса render pass-а, буфер команд готов к записи команд для первого subpass-а этого render pass-а.
Структура VkRenderPassBeginInfo определена как:
typedef struct VkRenderPassBeginInfo {
VkStructureType sType;
const void * pNext;
VkRenderPass renderPass;
VkFramebuffer framebuffer;
VkRect2D renderArea;
uint32_t clearValueCount;
const VkClearValue * pClearValues;
} VkRenderPassBeginInfo;
• sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
• pNext = NULL
• renderPass хэндл render pass-а, чей инстанс стартует
• framebuffer - фреймбуфер, содержащий аттачменты render pass-а.
• renderArea - область вывода, куда будет осуществляться рендеринг инстанса render pass-а.
• clearValueCount - количество элементов в pClearValues .
• pClearValues - массив структур VkClearValue, содержащих цвет очистки для каждого из аттачментов, если аттачмент использует loadOp со значением  VK_ATTACHMENT_LOAD_OP_CLEAR. Индексы массива соответствующи номерам аттачментов, с элементами соответствующими неочищенным неиспользованным аттачментам.

renderArea - область рендеринга, на которую влияет инстанс render pass-а. Все операции с аттачментом (load, store, resolve) ограничены этой областью на всех аттачментах. Область рендеринга расширяется на все слои фрэймбуфера. Приложение должно убедиться (используя scissor, если необходимо) что весь рендеринг происходит внутри области рендеринга, в противном случае, пиксели вне этой области будут не определены и шейдер может применяться для фрагментов за пределами области рендеринга. Область рендеринга должна быть в пределах размерности фреймбуфера.

Заметка:
Если область рендеринга меньше размера фреймбуфера, то может снизиться производительность, если эта область не соответствует области детализации render pass-а.

Детализация области рендеринга может быть получена через вызов:
void vkGetRenderAreaGranularity(
VkDevice device,
VkRenderPass renderPass,
VkExtent2D * pGranularity);
• device - устройство владеющее render pass-ом.
• renderPass - хэндл render pass-а.
• pGranularity - указатель на структуру VkExtent2D, куда вернется детализация.

Оптимальный размер renderArea можно определить следуя следующим условиям:
• offset.x в renderArea кратный полю width из VkExtent2D (горизонтальная детализация).
• offset.y в renderArea кратный полю height из VkExtent2D (вертикальная детализация).
• offset.width и offset.height в renderArea кратны соответствующим детализациям или
offset.x + offset.width и offset.y + offset.height равны размерностям фреймбуфера из VkRenderPassBeginInfo.

После записи команд для subpass-а, приложение переходит следующему subpass-у инстанса render pass-а через вызов:
void vkCmdNextSubpass(
VkCommandBuffer commandBuffer,
VkSubpassContents contents);

• commandBuffer - буфер команд для записи.
• contents - указывает как команды из следующего subpass-а будут вставлены в этот буфер команд, так же как и соответствующем параметре vkCmdBeginRenderPass.

• commandBuffer - должен быть в состоянии записи.
• VkCommandPool, создающий commandBuffer, должен поддерживать графические операции
• Это команда должна вызываться только внутри инстанса render pass-а
• commandBuffer - должен быть первичным VkCommandBuffer
• Индекс текущего subpass-а должен быть на единицу меньше количества subpass-ов в render pass-е

Индекс subpass-а в render pass-е начинается с нуля, когда вызывается vkCmdBeginRenderPass, и увеличивается при каждом вызове vkCmdNextSubpass.

Перемещение к следующему subpass-у автоматически выполняет все операции “multisample resolve” в конце subpass-а. Это трактуется как запись в аттачмент цвета с целью синхронизации, то есть это аналогично выполнению на стадии конвейера  VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT и запись синхронизируется с VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT. Синхронизация между рендерингом внутри subpass-а и разрешающими операциями в конце subpass-а происходит автоматически, без необходимости явного указания зависимостей или барьеров. Однако, если resolve аттачмент еще используется и в других subpass-ах, то нужно явное указание зависимостей.

После перехода к следующему subpass-у, приложение может начинать записывать команды для этого subpass-а.
После записи команд для последнего subpass-а приложение должно вызвать команду завершения инстанса render pass-а:
void vkCmdEndRenderPass(
VkCommandBuffer commandBuffer);

• commandBuffer - буфер команд, завершающий инстанс render pass-а.

• commandBuffer - должен быть в состоянии записи
• VkCommandPool, создавший этот commandBuffer, должен поддерживать графические операции
• Команда должна вызываться только внутри инстанса render pass-а
• commandBuffer - должен быть первичным VkCommandBuffer
• Текущий номер subpass-а должен быть равен количеству subpass-ов в render pass-е минус один

Завершение инстанса render pass-а выполняет все “multisample resolve operations” на финальном subpass-е.

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

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