понедельник, 21 марта 2016 г.

Vulkan API, Render Pass

Render Pass

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


Сразу оговорюсь - в тексте я буду использовать англоязычные термины, так как они более понятны людям, работавшим с другими графическими API, в частности - аттачменты (attachment) вместо “вложение, приложение, прикрепление”, алиасы (alias) вместо “псевдонимов”, местами заменяя соответствующий глагол на “ссылаться” или “разделять”, в зависимости от контекста. Термины render pass и subpass оставил как есть, так как в отношении объекта и состояния термин “проход рендера” плохо употребим и под этим в графических API обычно подразумевается совсем иное. То же касается и “под-прохода”, так что решил оставить их как есть (альтернатива использовать рендер пасс и сабпасс, но я еще не определился как лучше).
Так же в тексте вместо термина layout используется термин “структура”, в контексте описания назначения/usage изображения, в котором по сути определяется его внутренняя структура, пригодная для хранения или использования цвета, глубины или оптимизированная для передачи в рамках subpass-ов.


Render pass представляет из себя коллекцию вложений(аттачментов), subpass-ов, и зависимостей между ними. А так же описывают как аттачменты используются внутри subpass-ов. Если render pass используется внутри буфера команд, то мы говорим об инстансе render pass-а.

Дескрипторы аттачментов (attachment description) описывают свойства аттачментов, включающие их формат, количество сэмплов и как их содержимое трактуется в начале и конце каждого из инстансов render pass-а.

Subpass - представляет из себя фазу рендеринга, которая осуществляет чтение/запись набора аттачментов в render pass-е. Команды ренеринга записываются в отдельный subpass инстанса render pass-а.

Дескриптор subpass-а описывает набор аттачментов, используемых subpass-ом. Какждый subpass может читать из некоторых аттачментов (входных аттачментов), осуществлять запись в color attachments, depth/stencil attachments и выполнять разрешающие операции к другим resolve attachment-ам. Дескрипторы могут так же включать набор “законсервированных” аттачментов, которые не будут использоваться subpass-ом, но чьё содержимое будет передано через subpass.

Subpass использует аттачменты только если это color, depth/stencil, resolve или входные аттачменты для этого subpass-а и не использует “законсервированные” аттачменты. Первое использование аттачмента происходит в subpass-е с наименьшим номером, последнее использование - в subpass-е с наибольшим номером.

Все subpass-ы render pass-а  рендерят в том же разрешении. Фрагмент(x,y,layer) о одном subpass-е может читать только содержимое аттачментов записанное предыдущим subpass-ом в той же позиции (x,y,layer).

Заметка:
Предоставление render pass-у описания полного набора subpass-ов предоставляет реализации Вулкана возможность оптимизировать хранение и передачу данных аттачментов между subpass-ами. На практике это означает что subpass-ы с зависимостями в рамках одного фрэймбуфера могут быть объединены в один “tiled rendering pass”, хранящий данные аттачмента на чипе на протяжении работы инстанса render pass-а. Однако, вполне нормально когда у render pass-а только один subpass.

Subpass dependencies - если пара subpass-ов работает с перекрывающимися областями аттачмента то для них необходимо добавить subpass dependencies, Если зависимость не указана, реализация Вулкана может менять порядок или перекрывать части выполнения subpass-ов (к примеру - определенные шейдерные стадии). Зависимости (dependencies) ограничивают степень перекрытия или изменения порядка выполнения subpass-ов, определяется через маски стадий конвейера и типы доступа к памяти. Каждая из зависимостей действует как зависимость выполнения и как зависимость памяти (execution и memory dependency). Зависимости необходимы когда два subpass-а работают с одним аттачментом с перекрывающимися диапазонами, подобными объектам VkDeviceMemory, и как минимум один из subpass-ов осуществляет запись в этот диапазон.

Subpass dependency chain - цепочка зависимостей subpass-а в render pass-е, где начальный subpass каждой из зависимостей (после первой) равен конечному subpass-у предыдущей зависимости.

Self-Dependency - Зависимость subpass-а от самого себя, то есть когда srcSubpass равен dstSubpass. Self-dependency не выполняется автоматически во время работы инстанса render pass-а, но они могут быть выполнены явно через vkCmdPipelineBarrier во время работы subpass-а.

Render Pass Creation

Для того чтоб создать render pass необходимо вызывать команду:
VkResult vkCreateRenderPass(
VkDevice device,
const VkRenderPassCreateInfo * pCreateInfo,
const VkAllocationCallbacks * pAllocator,
VkRenderPass * pRenderPass);
• device - логическое устрйоство, создающее render pass.
• pCreateInfo - указатель на структуру VkRenderPassCreateInfo, описывающую параметры render pass-а.
• pAllocator - контролирует выделение памяти хостом.
• pRenderPass - указатель на хэндл VkRenderPass, куда будет возвращен созданный объект render pass.

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

Структура VkRenderPassCreateInfo определена как:
typedef struct VkRenderPassCreateInfo {
VkStructureType sType;
const void * pNext;
VkRenderPassCreateFlags flags;
uint32_t attachmentCount;
const VkAttachmentDescription * pAttachments;
uint32_t subpassCount;
const VkSubpassDescription * pSubpasses;
uint32_t dependencyCount;
const VkSubpassDependency * pDependencies;
} VkRenderPassCreateInfo;

• sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO.
• pNext = NULL.
• flags - зарезервирован, равен 0.
• attachmentCount - количество аттачментов в render pass-е, или 0.
• pAttachments - указатель на массив структур VkAttachmentDescription, описывающий свойства аттачментов, или NULL, если attachmentCount = 0.
• subpassCount - количество subpass-овсоздаваемых для этого render pass-а. Render pass должен иметь хотя бы один subpass.
• pSubpasses указатель на массив структур VkSubpassDescription, описывающий свойства subpass-ов.
• dependencyCount - количество зависимостей между парами subpass-ов, или 0.
• pDependencies - указатель на массив структур VkSubpassDependency, описывающих зависимости между парами subpass-ов, или NULL, если dependencyCount = 0.
• Если два subpass-а работают с аттачментами с перекрывающимися областями одного и того же объекта VkDeviceMemory, и как минимум один из subpass-в пишет в эту область VkDeviceMemory, то между ними должна быть добавлена subpass dependency (явно или через промежуточный subpass).
• Если любой из аттачментов из pInputAttachments, pColorAttachments, pResolveAttachments, pDepthStencilAttachment или аттачменты из pPreserveAttachments в любом из элементов pSubpasses связан с диапазоном объекта VkDeviceMemory, который перекрывается с любым из аттачментов в любом из subpass-ов (включая тот же subpass), то в структуре VkAttachmentDescription, описывающей их, должен быть включен флаг VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT в flags.
• Значение элементов pPreserveAttachments для любого из элементов pSubpasses не должно быть VK_ATTACHMENT_UNUSED

Структура VkAttachmentDescription определяется как:
typedef struct VkAttachmentDescription {
VkAttachmentDescriptionFlags flags;
VkFormat format;
VkSampleCountFlagBits samples;
VkAttachmentLoadOp loadOp;
VkAttachmentStoreOp storeOp;
VkAttachmentLoadOp stencilLoadOp;
VkAttachmentStoreOp stencilStoreOp;
VkImageLayout initialLayout;
VkImageLayout finalLayout;
} VkAttachmentDescription;

• format - значение типа VkFormat, определяющее формат изображения, которы йбудет использован для аттачмента.
• samples - количество сэмплов изображения, определенное в VkSampleCountFlagBits.
• loadOp - определяет как содержимое компонент цвета и глубины в аттачменте трактуется в начале subpass-а, где оно впервые используется:
typedef enum VkAttachmentLoadOp {
VK_ATTACHMENT_LOAD_OP_LOAD = 0,
VK_ATTACHMENT_LOAD_OP_CLEAR = 1,
VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2,
} VkAttachmentLoadOp;
– VK_ATTACHMENT_LOAD_OP_LOAD - означает что содержимое внутри выводимой области будет сохранено.
– VK_ATTACHMENT_LOAD_OP_CLEAR - означает что содержимое внутри выводимой области будет очищено (залито значением), которое указывается в начале инстанса render pass-а.
– VK_ATTACHMENT_LOAD_OP_DONT_CARE - означает что содержимое внутри выводимой области не нужно сохранять, содержимое аттачмента в этой области будет неопределенным
• storeOp - указывает как содержимое компонент цвета и глубины аттачмента трактуется в в конце subpass-а, где оно в последний раз используется:
typedef enum VkAttachmentStoreOp {
VK_ATTACHMENT_STORE_OP_STORE = 0,
VK_ATTACHMENT_STORE_OP_DONT_CARE = 1,
} VkAttachmentStoreOp;
– VK_ATTACHMENT_STORE_OP_STORE  - означает что содержимое внутри выводимой области будет записано в память и будет доступно для чтения после завершения инстанса render pass-а, как только запись будет синхронизирована с VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT (для color attachments) или VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT (для depth/stencil attachments).
– VK_ATTACHMENT_STORE_OP_DONT_CARE - щзначает что содержимое внутри выводимой области не потребуется после рендеринга и может быть отброшено . Содержимое аттачмента будет не определено внутри области рендеринга.
• stencilLoadOp - указывает как будет трактоваться содержимое stencil-компонент аттачмента в начале subpass-а при первом использовании, и должно быть одним из допустимых для loadOp значений.
• stencilStoreOp - указывает как будет трактоваться содержимое stencil-компонент аттачмента в конце последнего subpass-а где это он используется и он должен быть одним из допустимых для storeOp значений.
• initialLayout  - начальная структура изображения аттачмента в начале инстанса render pass-а.
• finalLayout - конечная структура изображения аттачмента, в которую перейдет изображение в конце инстанса render pass-а. При необходимости, в течении инстанса render pass-а, аттачмент может использовать разную структуру для каждого из subpass-в.
• flags - битовая маска из VkAttachmentDescriptionFlagBits, описывающая дополнительные свойства аттачмента:
typedef enum VkAttachmentDescriptionFlagBits {
VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001,
} VkAttachmentDescriptionFlagBits;

Если аттачмент использует цветовой формат, то используются loadOp и storeOp, а stencilLoadOp и stencilStoreOp игнорируются. Если формат имеет компоненты глубины и трафарета, то loadOp и storeOp применяются только к данным глубины, а stencilLoadOp и stencilStoreOp определяют как будут храниться компоненты трафарета.

Пока используется инстанс renderpass-а, input/color аттачменты с цветовыми форматами имеющими размер компоненты 8, 16, или 32 бита должны быть представлены в формате аттачмента через. Аттачменты с форматом цвета с плавающей или фиксированной точкой или глубиной могут быть представлены с точностью большей чем формат аттачмента но должны быт представлены в том же диапазоне. Когда такие компоненты загружаются через loadOp, они будут сконвертированны в формат, требуемый реализацией Вулкана, используемый render pass-ом. Такие форматы должны быть сконвертированны из формата render pass-а в формат аттачментов, прежде чем они будут сохранены или разрешены в конце инстанса render pass-а через storeOp. КОнвертация осуществляется как описано в главе “Numeric Representation and Computation and Fixed-Point Data Conversions”.

Если flags включает бит VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, то аттачмент трактуется как разделяющий физическую память с другим аттачментом в этом же render pass-е. Эта информация ограничивает возможности имплементации менять порядок некоторых операций (таких как смена структуры и loadOp), чтоб изменение порядка не повлияло на другие использования этой же физической памяти в других аттачментах. Ниже это будет описано более детально.

Если render pass использует несколько аттачментов, ссылающихся на одну и ту же область физической памяти, то каждый из таких аттачментов должен включать бит VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT в поле flags структуры VkAttachmentDescription. Аттачменыт могут ссылаться на одну и ту же память несколькими способами:
• Несколько аттачментов были присвоены одному и тому же image view в процессе создания фреймбуфера.
• Аттачменты используют различные image view, которые соответствуют тем же ресурсам изображения.
• Аттачменты используют представления (views) отдельных ресурсов изображения которые закреплены за перекрывающимися диапазонами памяти.

Render passe-ы должны включать зависимости subpass-ов (явно или через цепочку зависимостей subpass-а) между любыми двумя subpass-ами, которые работают с тем же аттачментом или алиасом аттачмента и эти зависимости должны включать зависимости выполнения и зависимости памяти для каждого использования алиаса,  если хотя бы один из subpass-ов пишет в один из этих алиасов. Эти зависимости не должны включать бит VK_DEPENDENCY_BY_REGION_BIT если алиасы это представления отдельных ресурсов изображения, перекрывающихся в памяти.

Если несколько аттачментов разделяют одну память то их нельзя использовать в рамках одного subpass-а. Данный индекс аттачмента не должен использоваться несколько раз в одном subpass-е, с одним исключением: два аттачмента subpass-а могут использовать тот же индекс аттачмента, если как минимум один из них это входной аттачмент а другой используется как resolve или preserve аттачмент. Другими словами, одно и то же представление (view)  может быть использовано одновременно как входной color или depth/stencil аттачмент, но не может быть использовано ни как несколько color или depth/stencil аттачментов, ни как resolve или preserve аттачментов. Этот сценарий детально описан ниже.

Если набор аттачментов ссылается друг на друга, тогда все,кромое первого, использованного в render pass-е, дожны использовать initialLayout как  VK_IMAGE_LAYOUT_UNDEFINED, так как боле раннее использование других алиасов делает их содержимое неопределенным. Как только алиас был использован и другой алиас был использован после него, первый алиас не должен более использоваться в последующих subpass-ах. Однако, приложение может присвоить тот же image view нескольким индексам аттачментов определяемых через алиасы, что позволяет этот image view использовать несколько раз, даже если другие алиасы использется между ними. 
Если у аттачмента установлен бит  VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, то объявление дополнительных алиасов не потребует дополнительных расходов, и использование этих дополнительных алиасов  может позволить боле эффективно очищать аттачменты при множественном использовании через VK_ATTACHMENT_LOAD_OP_CLEAR.

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

Структура VkSubpassDescription определяется как:
typedef struct VkSubpassDescription {
VkSubpassDescriptionFlags flags;
VkPipelineBindPoint pipelineBindPoint;
uint32_t inputAttachmentCount;
const VkAttachmentReference * pInputAttachments;
uint32_t colorAttachmentCount;
const VkAttachmentReference * pColorAttachments;
const VkAttachmentReference * pResolveAttachments;
const VkAttachmentReference * pDepthStencilAttachment;
uint32_t preserveAttachmentCount;
const uint32_t * pPreserveAttachments;
} VkSubpassDescription;

• flags  - зарезервирован, должен быть равен 0
• pipelineBindPoint - значение типа VkPipelineBindPoint, указывающее на то графический это или вычислительный subpass. Сейчас поддерживаются только графические subpass-ы, потому значение должно быть  VK_PIPELINE_BIND_POINT_GRAPHICS
• inputAttachmentCount - количество входных аттачментов.
• pInputAttachments массив структур VkAttachmentReference (определение ниже) в котором перечислены аттачменты render pass-а, которые можно прочесть в шейдере в процессе subpass-а, и какая структура изображения аттачмента будет использоваться в этом subpass-е. Каждый индекс аттачмента в этом массиве соответствует “input attachment unit number” в шейдере, то есть, если шейдер объявляет входную переменную как layout(input_attachment_index=X, set=Y, binding=Z) то это используется аттачмент из pInputAttachments [X]. Входной аттачмент так же должен быть закреплен за конвейером через набор дескрипторов, с “input attachment descriptor” записанным в позицию (set=Y, binding=Z).
• colorAttachmentCount - количество аттачментов в pColorAttachments, должно быть не более VkPhysicalDeviceLimits:: maxColorAttachments.
• pColorAttachments - массив структур VkAttachmentReference, определяющий какие из аттачментов render pass-а будут использоваться в качестве color attachments в subpass-е, и какая структура изображений этого аттачмента будет использована в subpass-е. Каждый элемент массива соответствует выходной позиции фрагментного шейдера, то есть, если шейдер объявляет выходную переменную как layout(location=X) то это используется аттачмент из pColorAttachments [X].
• pResolveAttachments - NULL или указатель но массив структур  VkAttachmentReference. Если pResolveAttachments не NULL, то каждый его элемент соответствует элементу pColorAttachments по тому же индексу. В конце каждого subpass-а, его аттачменты цвета разрешаются в соответствующие resolve attachments, кроме случая когда индекс resolve аттачмента равен VK_ATTACHMENT_UNUSED или
pResolveAttachments равен NULL. Если первое использование аттачмента в render pass-е это было как resolve аттачмент, то loadOp для эффективности игнорируется, так как разрешающая операция гарантированно перезаписывает все пиксели в выводимой области.
• pDepthStencilAttachment - указатель на структуру VkAttachmentReference, определяющую какой из аттачментов будет использован для данных глубины/трафарета и их структуры в этом subpass-е. Установка индекса аттачмента в VK_ATTACHMENT_UNUSED или если оставить этот указатель пустым, то это укажет на то, что в этом subpass-е depth/stencil аттачмент не будет использоваться.
• preserveAttachmentCount - количество законсервированных аттачментов.
• pPreserveAttachments - массив индексов аттачментов render pass-а, указывающих какие из аттачментов не будут использоваться subpass-ом, но чьё содержимое должно сохраниться после выполнения этого subpass-а.

Содержимое аттачмента внутри области рендеринга может стать неопределенным вначале subpass-а S если все последующие условия выполняются:
• Аттачмент используется как color, depth/stencil или resolve в любом из subpass-ов.
• Существует такой subpass S1, использующий аттачмент (или хранящий его в законсервированном виде) и существует зависимость subpass-а S1 от S.
• Аттачмент не используется или не законсервирован в subpass-е S.

Как только содержимое аттачмента станет неопределенным в subpass-е S, оно станет неопределенным для subpass-ов в цепочке зависимостей subpass-ов, начиная с  subpass-а S, пока в него вновь не будет осуществлена запись. Однако, он останется валидным для subpass-ов в других цепочках зависимостей subpass-ов, начиная с subpass-а S1 если эти subpass-ы использовали или хранили аттачмент.

• Если аттачмент первый раз используется этим render pass-ом как входной аттачмент, и аттачмент более не используется как как color или depth/stencil аттачмент в этом же subpass-е, тогда loadOp не должно быть VK_ATTACHMENT_LOAD_OP_CLEAR
• Для каждого не пустого элемента pResolveAttachments, для каждого из resolve аттачмента, не имеющего значения VK_ATTACHMENT_UNUSED, соответствующий color аттачмент так же не должен иметь значение VK_ATTACHMENT_UNUSED.
• Если pResolveAttachments не NULL, то количество сэмплов каждого из элементов  pColorAttachments должно быть любым кроме VK_SAMPLE_COUNT_1_BIT.
• Любой из элементов pResolveAttachments должен иметь количество сэмплов VK_SAMPLE_COUNT_1_BIT
• Любой из элементов pResolveAttachments должен иметь такой же VkFormat как и соответствующий color аттачмент.
• Все аттачменты в pColorAttachments и pDepthStencilAttachment, если они не  VK_ATTACHMENT_UNUSED, должны иметь одинаковое количество сэмплов.
• Если любой из входных аттачментов является VK_ATTACHMENT_UNUSED, то ни один из фрагментных шейдеров не должен иметь дступа к этому входному аттачменту.
• Ни один из элементов pPreserveAttachments не должен быть VK_ATTACHMENT_UNUSED
• Ни один из элементов pPreserveAttachments не должен так же быть элементом любого другого дескриптора subpass-а.
• Если какой-либо аттачмент используется и как входной аттачмент и как аттачмент color или depth/stencil, то все они должны иметь одинаковую структуру.

Структура VkAttachmentReference определяется как:
typedef struct VkAttachmentReference {
uint32_t attachment;
VkImageLayout layout;
} VkAttachmentReference;

• attachment - индекс аттачмента render pass-а, соответствующий индексу элемента из массива  pAttachments структуры VkRenderPassCreateInfo. Если любой из color или depth/stencil аттачментов VK_ATTACHMENT_UNUSED, то запись в эти аттачменты не производится.
• layout - значение VkImageLayout, указывающее структуру аттачмента в subpass-е. Имплементация автоматически выполняет конвертацию структуры в нужную между subpass-ами, чтоб каждый из subpass-ов мож использовать нужную структуру.
Допустимые значения для layout:
typedef enum VkImageLayout {
VK_IMAGE_LAYOUT_UNDEFINED = 0,
VK_IMAGE_LAYOUT_GENERAL = 1,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7,
VK_IMAGE_LAYOUT_PREINITIALIZED = 8,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,
} VkImageLayout;

Подробно об их значениях можно почитать в главе спецификации “Image Layouts”

Структура VkSubpassDependency определена как:
typedef struct VkSubpassDependency {
uint32_t srcSubpass;
uint32_t dstSubpass;
VkPipelineStageFlags srcStageMask;
VkPipelineStageFlags dstStageMask;
VkAccessFlags srcAccessMask;
VkAccessFlags dstAccessMask;
VkDependencyFlags dependencyFlags;
} VkSubpassDependency;

• srcSubpass и dstSubpass это индексы subpass-ов производителя и потребителя соответственно. srcSubpass и dstSubpass могут так же иметь специальное значение - VK_SUBPASS_EXTERNAL. Индекс исходного subpass-а всегда должен быть нже чем у конечного subpass-а (кроме внешних subpass-ов и self-dependencies), таким образом, порядок дескрипторов subpass-ов это так же правильный порядок выполнения, для избежания циклов в графе зависимостей.
• Значения srcSubpass и dstSubpass не должны быть оба равны VK_SUBPASS_EXTERNAL
• srcStageMask , dstStageMask , srcAccessMask , dstAccessMask и dependencyFlags - описыают зависимости выполнения и зависимости памяти между subpass-ами. dependencyFlags  может включать биты из VkDependencyFlagBits:
typedef enum VkDependencyFlagBits {
VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,
} VkDependencyFlagBits;
• Если dependencyFlags содержит бит VK_DEPENDENCY_BY_REGION_BIT, то зависимость будет по-регионной, как это было описано в главе “Execution And Memory Dependencies”.

Каждая зависимость определяет зависимость выполнения и памяти между двумя наборами команд, где второй набор команд зависит от первого. Если srcSubpass не равен dstSubpass, то первым набором команд будут:
• Все команды в subpass-е указанные в srcSubpass, если srcSubpass не VK_SUBPASS_EXTERNAL.
• Все команды пред инстансом render pass-а, если srcSubpass VK_SUBPASS_EXTERNAL.

Если соответствующий второй набор команд:
• Все команды в subpass-е указанные в dstSubpass, если dstSubpass не VK_SUBPASS_EXTERNAL.
• Все команды после инстанса render pass-а, если dstSubpass это VK_SUBPASS_EXTERNAL.

Если srcSubpass равен dstSubpass то первый набор состоит из команд в subpass-е перед вызовом vkCmdPipelineBarrier, а второй набор команд состоит из последующих команд subpass-а.

Параметры зависимости srcStageMask , dstStageMask , srcAccessMask , dstAccessMask и dependencyFlags интерпретируются так же как и другие зависимости.

Автоматический перевод структуры изображения между subpass-ами так же взаимодействует с subpass dependencies. Если два subpass-а связаны зависимостью и оба subpass-а используют один и тот же аттачмент с разной структурой, то смена структуры произойдет после того как доступ к памяти через srcAccessMask будет завершен на всех стадиях конвейера, включенных в srcStageMask в исходном subpass-е, и до того, как произойдет доступ к памяти через dstAccessMask в клюбой из стадий конвейера из dstStageMask в конечном subpass-е.

Автоматический перевод структуры из initialLayout в первую используемую структуру  (если они отличаются) выполняется по следующим правилам:
• Если аттачмент не включяет бит VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, и не указана зависимость subpass-а от VK_SUBPASS_EXTERNAL к первому subpass-у, который использует этот аттачмент, тогда это тоже самое что и зависимость, где  srcStageMask = srcAccessMask = 0, а dstStageMask и dstAccessMask включают все соответствующие биты (все графические стадии конвейера и все типы доступа, использующие ресурсы изображения), где перевод выполняется как часть зависимости. Другими словами, задачи до инстанса render pass-а могут пересекаться и они завершаются до начала subpass-а.
• Если аттачмент не включает бит VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT и есть зависимость subpass-а от VK_SUBPASS_EXTERNAL к первому subpass-у использующему аттачмент, тогда перевод осуществляется как часть зависимости в соответствии ее маскам стадий и доступа. Это не должно пересекаться с задачами, пришедшими до инстанса render pass-а, включенными в исходной маске, но они могут пересекаться с задачами в предыдущих subpass-ах.
• Если аттачмент включает бит VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, то перевод осуществляется в соответствии со всеми зависимостями subpass-а, где dstSubpass равен индексу первого subpass-а, в котором используется аттачмент. Тоесть это происходит после того как все доступы к памяти указанных а маске исходных стадий и масках со всех исходных subpass-ов были завершены и до того, как начнется объединение всех конечных стадий, тогда новая структура будет видима объединению всех конечных типов доступа. Если не было никаких входящих зависимостей subpass-а, то этот вариант будет первым правилом.

Подобные правила будут применены для прехода к finalLayout, используя зависимости с dstSubpass равным VK_SUBPASS_EXTERNAL.
Если для аттачмента указана операция VK_ATTACHMENT_LOAD_OP_CLEAR, то он будет очищен в начале первого subpass-а в котором он будет использован.

Заметка:
Реализация Вулкана может выполнить операцию очистки на много раньше, если это не повлияет на работу инстанса render pass-а. К примеру, имплементация может решить очистить все аттачменты в момент старта инстанса render pass-а. Если у аттачмента установлен флаг  VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, то очистка должна происходить в начале subpass-а где аттачмент будет впервые использован, в порядке обеспечивающем сохранность работы инстанса render pass-а.

При первом использовании аттачмента нельзя указывать структуру VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL или VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, если для аттачмента указана loadOp как VK_ATTACHMENT_LOAD_OP_CLEAR. Если subpass использует один и тот же аттачмент как входной и как color или depth/stencil аттачмент, то в обоих случаях будет наблюдаться результат очистки.

Аналогично, если у аттачмента указано значение storeOp как  VK_ATTACHMENT_STORE_OP_STORE, то он будет сохранен в конце последнего subpass-а в котором он использовался.

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

Если аттачмент не используется ни одним из subpass-ов, то loadOp и storeOp игнорируются и содержимое памяти аттачмента не модифицируется в процессе выполнения инстанса render pass-а. В общих случаях render pass будет состоять из простых линейных зависимостей, где subpass N зависит от subpass N-1 для всех N, и работа барьеров памяти и смены структуры достаточна простая, это этих простейших случаев. Но для более сложных графов существуют более сложные правила, регулирующие когда между subpass-ами должны быть зависимости.

Как уже говорилось ранее, render pass-ы должны включать зависимости subpass-ов, которые (явно или через цепочку зависимостей subpass-ов) разделяют работу любых двух subpass-ов, использующих один и тот же аттачмент или алиас, если как минимум один из этих subpass-ов осуществляет запись в аттачмент. Если между этими subpass-ами изменяется структура изображения, то имплементация использует stageMasks и accessMasks указанные в зависимостях subpass-а, как маски, которые контролируют когда должно произойти преобразование структуры. Если изменения структуры аттачмента не будет, или имплементация посчитает что структуры идентичны, то эту зависимость можно считать простым барьером выполнения/памяти.

Если два subpass-а используют один и тот же аттачмент с разной структурой, но оба используют его только для чтения(т.е. входные аттачменты или depth/stencil аттачмент в режиме только для чтения), то приложению не нужно заботиться о зависимостях между этими subpass-ами.

Если имплементация Вулкана решит что две структуры отличаются, то она может решить вставить между ними зависимость, между subpass-ом выбранным имплементацией соответствующей маской стадии конвейера и маской дсоутпа, основываясь на том, используется ли аттачмент как входной или depth/stencil аттачмент, и может вставить соответствующую конвертацию структуры вместе с барьером выполнения/памяти. Если имплементация решает что две структуры идентичны и нет необходимости вставлять барьер, то эти subpass-ы могут выполняться одновременно. Маска стадии конвейера и маска доступа выбирается как описано ниже:
• для входных аттачментов , stage mask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, access mask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT.
• для depth/stencil аттачментов, stage mask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, access mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
Где srcStageMask и srcAccessMask берутся основываясь на использовании в исходном subpass-е а dstStageMask и dstAccessMask берутся основываясь на ипользовании в конечном subpass-е. Если subpass использует один и тот же аттачмент и как входной аттачмент и как color или depth/stencil аттачмент, то чтение из входного аттачмента не когерентно автоматически с записью в color или depth/stencil аттачмент. Для того чтоб достичь хорошо предсказуемых результатов должно удовлетворятся одно из двух условий:

Первое, если компоненты цвета или depth/stencil-компоненты читаются во входном аттачменте то это исключает запись в компоненты color или depth/stencil аттачмента, то есть нет петли обратной связи, и чтение и запись работают нормально, чтение получает результаты из предыдущего subpassа-а  или из памяти. Эта опция требует чтоб используемый subpass-ом графический конвейер отключал запись в компоненты цвета, используемые в качестве входных данных, через установку маски colorWriteMask, а так же отключал запись в компоненты глубины/трафарета, использующиеся в качестве входных данных, через установку depthWriteEnable и stencilTestEnable соответственно.

Второе, если входной аттачмент читает компоненты записанные color или depth/stencilаттачментом, то есть есть петля обратной связи и конвейер должен использовать барьер между тем как аттачмент был записан и в последующем будет прочтен в фрагментном шейдере. Этот барьер конвейера должен следовать следующим правилам self-dependency, где должны быть включены следующие флаги:
• dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
• dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, and
• srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT (для аттачментов цвета) или srcAccessMask
= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT (для аттачментов глубины/трафарета).
• srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT (для аттачментов цвета) или
srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT (для аттачментов глубины/трафарета).
• dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT.
Барьер конвеёера необходим каждый раз когда фрагмент читает фрагмент из позиции (x,y,layer,sample), если в эту позицию была произведена запись с момента последнего барьера, или с момента начала subpass-а, если там с момента старта subpass-а не было барьеров.

Аттачмент используемый и как входной аттачмент и как color аттачмент должен иметь структуру VK_IMAGE_LAYOUT_GENERAL. Структура аттачмента, использующегося и как входной аттачмент и как depth/stencil аттачмент должна быть либо VK_IMAGE_LAYOUT_GENERAL либо  VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL.
С момента в VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL станет доступен только для чтения, эта ситуация перестанет быть случаем с обратной связью.

Чтоб уничтожить render pass вызовите:
void vkDestroyRenderPass(
VkDevice device,
VkRenderPass renderPass,
const VkAllocationCallbacks * pAllocator);

• device - логическое устройство, которое уничтожит render pass.
• renderPass - хэндл уничтожаемого render pass-а.
• pAllocator - контролирует выделение памяти хостом.
• Все отправленные команды, ссылающиеся на renderPass должны быть завершены.

Render Pass Compatibility

Фрэймбуфер и графический конвейер создаются на основе указанного объекта render pass-а. Они должны использоваться только с этим объектом render pass-а, или с одним из совместимых с ним.

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

Два массива аттачментов совместимы, если все соответствующие пары аттачментов совместимы. Если размеры массивов отличаются, то недостающие аттачменты в меньшем массиве трактуются как VK_ATTACHMENT_UNUSED.

Две render pass-а, содержащие только один subpass совместимы, если их соответствующие аттачменты совместимы (color, input, resolve и depth/stencil аттачменты).

Если два render pass-а содержат более одного subpass-а, то они совместимы, если они идентичны, без учета:
• Начальной и конечной структуры в дескрипторах аттачмента;
• Операций load и store в дескрипторах аттачмента;
• Структуры изображения в массиве аттачментов

Фреймбуфер совместим с render pass-ом если он был создан тем же render pass-ом или совместимым с ним.

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

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