|
Todo proceso de dibujo en Vulkan debe estar contenido en un objeto
VkRenderPass,
que define el conjunto de pasadas de pipelines necesarias para generar el dibujo.
Estas pasadas se conocen como subpasses. Incluso si solo se realiza una pasada
es necesario crear un objeto VkRenderPass. Para crear el objeto
VkRenderPass se
utiliza la función vkCreateRenderPass().
VkResult vkCreateRenderPass (
VkDevice device,
const VkRenderPassCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkRenderPass* pRenderPass);
|
Para destruir un objeto
VkRenderPass se usa la función vkDestroyRenderPass().
void vkDestroyRenderPass(
VkDevice device,
VkRenderPass renderPass,
const VkAllocationCallbacks* pAllocator);
|
El proceso de renderizado trabaja sobre una estructura de
memoria llamada framebuffer. Cada framebuffer
contiene tres arrays encargados de almacenar la información de los
píxeles. La imagen propiamente dicha corresponde al buffer en el que
se almacena el color (color buffer), pero el
framebuffer contiene dos arrays más dedicados a almacenar la
profundidad de cada píxel (depth buffer) y la información
auxiliar (stencil buffer). La configuración del renderpass se introduce en una
estructura de tipo 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;
|
El campo sType debe tener el valor
VK_STRUCTURE_TYPE_RENDERPASS_CREATE_INFO.
El campo pNext debe dejarse nulo.
El campo flags debe ser cero.
Cada renderpass debe describir un conjunto de ataduras
(attachments) que definen
la forma en la que se va a leer y almacenar los framebuffers.
El campo pAttachments contiene una lista describiendo estas ataduras.
Para ello se utilizan estructuras de tipo VkAttachmentDescription.
El campo attachmentCount indica el tamaño de esta lista.
El campo subpassCount indica el número de subpases que formarán el
renderpass mientras que el campo pSubpasses contiene la lista con las
descripciones de estos subpases. Las descripciones se detallan en estructuras
de tipo VkSubpassDescription.
Cuando un subpass necesita utilizar información generada
por un subpass previo es necesario definir una dependencia.
El campo dependencyCount define el número de dependencias definidas en
el renderpass. El campo pDependencies contiene el
array de dependencias descritas mediante estructuras
VkSubpassDependency.
La estructura VkAttachmentDescription tiene el siguiente
contenido:
typedef struct VkAttachmentDescription {
VkAttachmentDescriptionFlags flags;
VkFormat format;
VkSampleCountFlagBits samples;
VkAttachmentLoadOp loadOp;
VkAttachmentStoreOp storeOp;
VkAttachmentLoadOp stencilLoadOp;
VkAttachmentStoreOp stencilStoreOp;
VkImageLayout initialLayout;
VkImageLayout finalLayout;
} VkAttachmentDescription;
|
El campo flags no se utiliza en estos momentos.
El campo format debe conicidir con el formato utilizado en
las imágenes del SwapChain.
El campo samples define las opciones de multisampleado que
deben coincidir con las asignadas en el pipeline.
El campo loadOp indica la actuación a realizar sobre el
buffer de profundidad al comenzar el renderpass. Los
valores pueden ser VK_ATTACHMENT_LOAD_OP_LOAD (para cargar
como entrada el buffer que se generó como salida en la generación
anterior), VK_ATTACHMENT_LOAD_OP_CLEAR (para limpiar el buffer de
profundidad al comenzar el renderpass) o
VK_ATTACHMENT_LOAD_OP_DONT_CARE (cuando resulte indiferente el valor
inicial del buffer).
El campo storeOp indica la actuación a realizar sobre el
buffer de profundidad al terninar el renderpass. Los valores
aceptados son VK_ATTACHMENT_STORE_OP_STORE (para almacenar los
valores si desean utilizarse en la próxima iteración) o
VK_ATTACHMENT_STORE_OP_DONT_CARE (cuando no sea necesario
almacenarlos).
El campo stencilLoadOp define la actuación a realizar sobre
el stencil buffer al comenzar el renderpass.
Admite los mismos valores que los aceptados por el campo loadOp.
El campo stencilStoreOp define la actuación a realizar
sobre el stencil buffer al terminar el renderpass.
Admite los mismos valores que los aceptados por el campo storeOp.
El campo initialLayout describe la forma en que se va a
tratar inicialmente el color buffer. El tipo de dato VkImageLayout
permite definir muchísimas formas de tratamiento, pero la mayoría de
esos valores tienen sentido en otro ámbito. Si la forma inicial de
la imagen es indiferente porque será totalmente creada a lo largo
del renderizado, el valor a asignar es
VK_IMAGE_LAYOUT_UNDEFINED.
El campo finalLayout describe la forma en que se tratará el
color buffer tras el proceso de renderizado. Para volcar
este color buffer sobre una superficie por medio de la
extensión de presentación se utiliza el valor
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR.
La estructura VkSubpassDescription se utiliza para
describir un subpase y tiene el siguiente
contenido:
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;
|
El campo flags no se utiliza en estos momentos.
El campo
pipelineBindPoint indica el tipo de pipeline que se
asociará al subpass. Típicamente será VK_PIPELINE_BIND_POINT_GRAPHICS
para generar gráficos o VK_PIPELINE_BIND_POINT_COMPUTE para
pipelines de tipo computación aunque también se están añadiendo
extensiones para identificar pipelines de ray tracing.
Los campos de tipo VkAttachmentReference permiten definir
el formato utilizado en el almacenamiento de algunas variables
utilizadas en el fragment shader. Esta estructura tiene un
campo attachment para indicar el índice de la variable y un
campo layout para indicar el formato de tipo
VkImageLayout.
El campo pInputAttachments describe el formato de las
entradas del fragment shader decoradas con un
InputAttachmentIndex. El campo inputAttachmentCount
indica el número de ataduras de entrada incluidas en
pInputAttachments.
El campo pColorAttachments describe el formato de salida
para el color buffer del frambuffer. Se pueden
configurar fragment shaders con varias salidas, que
corresponderán a las diferentes ataduras descritas en este campo. El
campo colorAttachmentCount indica el número de
ataduras que contiene pColorAttachments.
El campo pResolveAttachments describe las ataduras vinculadas a la
operación resolve que se ejecuta en el multisampleado. Si se utiliza
debe tener el mismo tamaño que pColorAttachments.
El campo pDepthStencilAttachment describe las ataduras
asociadas al depth buffer y al stencil buffer.
Normalmente las ataduras no se conservan al pasar de un subpase a
otro. Para preservar algunas ataduras se indican sus índices en el
array pPreserveAttachments. El tamaño de este array se
define en preserveAttachmentCount.
La estructura
VkSubpassDependency define las dependencias entre los subpases
y tiene el siguiente
contenido:
typedef struct VkSubpassDependency {
uint32_t srcSubpass;
uint32_t dstSubpass;
VkPipelineStageFlags srcStageMask;
VkPipelineStageFlags dstStageMask;
VkAccessFlags srcAccessMask;
VkAccessFlags dstAccessMask;
VkDependencyFlags dependencyFlags;
} VkSubpassDependency;
|
El campo srcSubpass es el índice del subpase
origen de la dependencia.
El campo dstSubpass es el índice del subpase de destino de
la dependencia.
El campo srcStageMask indica las etapas del pipeline origen
que tienen la dependencia, es decir, que deben finalizar antes de
que comiencen a ejecutarse las del destino.
El campo dstStageMask indica las etapas del pipeline de
destino que tienen la dependencia, es decir, que no pueden comenzar
hasta que no hayan finalizado las de origen.
El campo srcAccessMask describe el tipo de dependencia
sobre las estapas de origen, por ejemplo, que no se pueda leer o que
no se pueda escribir en determinado resultado del pipeline de
origen.
El campo dstAccessMask describe el tipo de dependencia
sobre las etapas de destino.
El campo dependencyFlags indica la forma en que se produce
la dependencia. Puede ser a nivel de framebuffer, a nivel
de vista o incluso a nivel de dispositivo.
|