Dynamic Rendering
The source for this sample can be found in the Khronos Vulkan samples github repository. |
Overview
This sample demonstrates how to use the VK_KHR_dynamic_rendering
extension, which eliminates the need to create render passes and improves flexibility while developing render pipelines.
This extension changes how rendering resources are managed. Rather than using render pass objects, this extension allows the developer to directly reference rendering attachments prior to the start of rendering.
Below is a comparison of the common Vulkan render pass construction and dynamic rendering.
Vulkan 1.0 | Dynamic Rendering |
---|---|
Rendering begins with |
Rendering begins with |
Rendering struct is |
Rendering struct is |
Attachments are referenced by |
Attachments are referenced by |
|
|
Graphics pipeline creation references a |
Graphics pipeline creation references a |
More detail is provided in the sections that follow.
Rendering Attachments
Previously, developers had to create render passes and framebuffers, which would be referenced in VkRenderPassBeginInfo
.
This is illustrated in the non-dynamic version of the command buffer construction sample code:
VkRenderPassBeginInfo render_pass_begin_info = vkb::initializers::render_pass_begin_info();
render_pass_begin_info.renderPass = render_pass;
render_pass_begin_info.framebuffer = framebuffers[i];
render_pass_begin_info.renderArea.extent.width = width;
render_pass_begin_info.renderArea.extent.height = height;
render_pass_begin_info.clearValueCount = 3;
render_pass_begin_info.pClearValues = clear_values.data();
vkCmdBeginRenderPass(draw_cmd_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
draw_scene();
vkCmdEndRenderPass(draw_cmd_buffer);
However, with dynamic rendering, the render pass and framebuffer structs are replaced by VkRenderingAttachmentInfoKHR
, which contains information about color, depth, and stencil attachments, and VkRenderingInfoKHR
, which references the attachments.
These structs are used at the start of rendering with the new command vkCmdBeginRenderingKHR
, as shown in the dynamic version of the command buffer construction sample code:
VkRenderingAttachmentInfoKHR color_attachment_info = vkb::initializers::rendering_attachment_info();
color_attachment_info.imageView = swapchain_buffers[i].view; // color_attachment.image_view;
...
VkRenderingAttachmentInfoKHR depth_attachment_info = vkb::initializers::rendering_attachment_info();
depth_attachment_info.imageView = depth_stencil.view;
...
auto render_area = VkRect2D{VkOffset2D{}, VkExtent2D{width, height}};
auto render_info = vkb::initializers::rendering_info(render_area, 1, &color_attachment_info);
render_info.layerCount = 1;
render_info.pDepthAttachment = &depth_attachment_info;
render_info.pStencilAttachment = &depth_attachment_info;
vkCmdBeginRenderingKHR(draw_cmd_buffer, &render_info);
draw_scene();
vkCmdEndRenderingKHR(draw_cmd_buffer);
Pipelines
Dynamic rendering changes how graphics pipelines are created.
Whereas before, the VkGraphicsPipelineCreateInfo
struct was required to reference a non-null pointer to a VkRenderPass
object, the dynamic rendering information is instead contained in a VkPipelineRenderingCreateInfoKHR
struct referenced by pNext
of the graphics pipeline create info:
// Provide information for dynamic rendering
VkPipelineRenderingCreateInfoKHR pipeline_create{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR};
pipeline_create.pNext = VK_NULL_HANDLE;
pipeline_create.colorAttachmentCount = 1;
pipeline_create.pColorAttachmentFormats = &color_rendering_format;
pipeline_create.depthAttachmentFormat = depth_format;
pipeline_create.stencilAttachmentFormat = depth_format;
// Use the pNext to point to the rendering create struct
VkGraphicsPipelineCreateInfo graphics_create{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
graphics_create.pNext = &pipeline_create; // reference the new dynamic structure
graphics_create.renderPass = VK_NULL_HANDLE; // previously required non-null
During graphics pipeline construction, the VkPipelineRenderingCreateInfoKHR
structure does not contain pointers to the actual attachment images (as the pointers aren’t required until VkRenderingAttachmentInfoKHR
);
instead, only the number and format of the attachments are required.
Enabling the Extension
The dynamic rendering api is provided in Vulkan 1.2.197 and the appropriate headers / SDK is required.
In addition, since dynamic rendering is provided as an extension and may have varying levels of support, the developer must query availability for each device used.
The device extension is provided by VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME
, and additional features are provided by the VkPhysicalDeviceDynamicRenderingFeaturesKHR
struct:
typedef struct VkPhysicalDeviceDynamicRenderingFeaturesKHR {
VkStructureType sType;
void* pNext;
VkBool32 dynamicRendering;
} VkPhysicalDeviceDynamicRenderingFeaturesKHR;
In addition to enabling the extension, developers may need to dynamically query the function pointers for vkCmdBeginRenderingKHR
and vkCmdEndRenderingKHR
if the preprocessor macro VK_NO_PROTOTYPES
is enabled.
This can be achieved through vkGetInstanceProcAddr
:
VkInstance instance = get_device().get_gpu().get_instance().get_handle();
assert(!!instance);
vkCmdBeginRenderingKHR = (PFN_vkCmdBeginRenderingKHR) vkGetInstanceProcAddr(instance, "vkCmdBeginRenderingKHR");
vkCmdEndRenderingKHR = (PFN_vkCmdEndRenderingKHR) vkGetInstanceProcAddr(instance, "vkCmdEndRenderingKHR");
if (!vkCmdBeginRenderingKHR || !vkCmdEndRenderingKHR)
{
throw std::runtime_error("Unable to dynamically load vkCmdBeginRenderingKHR and vkCmdEndRenderingKHR");
}