159 lines
6.9 KiB
Plaintext
159 lines
6.9 KiB
Plaintext
////
|
|
Copyright (c) 2021-2023, Holochip
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
////
|
|
= Dynamic Rendering
|
|
|
|
ifdef::site-gen-antora[]
|
|
TIP: The source for this sample can be found in the https://github.com/KhronosGroup/Vulkan-Samples/tree/main/samples/extensions/dynamic_rendering[Khronos Vulkan samples github repository].
|
|
endif::[]
|
|
|
|
|
|
== 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 `vkCmdBeginRenderPass`
|
|
| Rendering begins with `vkCmdBeginRenderingKHR`
|
|
|
|
| Rendering struct is `VkRenderPassBeginInfo`
|
|
| Rendering struct is `VkRenderingInfoKHR`
|
|
|
|
| Attachments are referenced by `VkFramebuffer`
|
|
| Attachments are referenced by `VkRenderingAttachmentInfoKHR`
|
|
|
|
| `VkFramebuffer` objects are heap-allocated and opaque
|
|
| `VkRenderingAttachmentInfoKHR` objects are stack-allocated
|
|
|
|
| Graphics pipeline creation references a `VkRenderPass`
|
|
| Graphics pipeline creation references a `VkPipelineRenderingCreateInfoKHR`
|
|
|
|
|
|
|
|
|
|
|===
|
|
|
|
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:
|
|
|
|
[,C++]
|
|
----
|
|
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:
|
|
|
|
[,C++]
|
|
----
|
|
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:
|
|
|
|
[,C++]
|
|
----
|
|
// 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:
|
|
|
|
[,C++]
|
|
----
|
|
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`:
|
|
|
|
[,C++]
|
|
----
|
|
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");
|
|
}
|
|
----
|