Files
Vulkan-Samples/samples/performance/msaa/msaa.h
T
2025-09-04 10:54:47 +08:00

284 lines
10 KiB
C++

/* Copyright (c) 2023-2025, Arm Limited and Contributors
*
* 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.
*/
#pragma once
#include "rendering/postprocessing_pipeline.h"
#include "rendering/render_pipeline.h"
#include "scene_graph/components/perspective_camera.h"
#include "vulkan_sample.h"
/**
* @brief MSAA Sample
*
* This sample shows the benefits of multisample anti-aliasing (MSAA) and how to
* resolve the multisampled attachments with minimum impact on performance.
*
* The UI controls allow the user to choose between different levels of MSAA
* and to select whether or not to resolve the color and depth attachments
* within the render pass.
*
* Resolving within the renderpass is very efficient on mobile since usually
* tilers can resolve the multisampled attachments on writeback to
* main memory. This means on mobile it is possible to get considerable
* quality improvements with relatively little cost.
*
* The alternative to resolving within the renderpass is to have a separate
* color resolve pass (using vkCmdResolveImage), which is much less efficient.
*
* Resolving on writeback was only possible with color attachments, but
* VK_KHR_depth_stencil_resolve (promoted in Vulkan 1.2) makes it possible to
* also resolve the depth attachment within the renderpass.
*
* Without this extension there is no simple alternative to resolve depth
* in a separate pass (vkCmdResolveImage does not support depth).
*
* Usually the depth attachment is transient (it is not needed outside the
* render pass) but some postprocessing effects require it as an input texture.
* Without the extension, if MSAA is enabled in the geometry pass, the
* multisampled depth attachment would be have to be written out to be
* consumed by the postprocessing renderpass.
*
* As with unresolved color, writing out unresolved depth attachments is very
* bandwidth intensive and therefore depth-based postprocessing was
* usually avoided on mobile platforms.
*
* This sample shows how to use the extension to also resolve the depth
* attachment on writeback and use it in a simple postprocessing pass.
*/
class MSAASample : public vkb::VulkanSampleC
{
public:
MSAASample();
virtual ~MSAASample() = default;
virtual bool prepare(const vkb::ApplicationOptions &options) override;
virtual void update(float delta_time) override;
virtual void draw(vkb::core::CommandBufferC &command_buffer, vkb::RenderTarget &render_target) override;
void draw_gui() override;
private:
vkb::sg::PerspectiveCamera *camera{nullptr};
virtual void prepare_render_context() override;
std::unique_ptr<vkb::RenderTarget> create_render_target(vkb::core::Image &&swapchain_image);
/**
* @brief Scene pipeline
* Render and light the scene (optionally using MSAA)
*/
std::unique_ptr<vkb::RenderPipeline> scene_pipeline{};
/**
* @brief Postprocessing pipeline
* Read in the output color and depth attachments from the
* scene subpass and use them to apply a screen-based effect
*/
std::unique_ptr<vkb::PostProcessingPipeline> postprocessing_pipeline{};
/**
* @brief Postprocessing pipeline using multi-sampled depth
* Read in the output color and depth attachments from the
* scene subpass and use them to apply a screen-based effect
*/
std::unique_ptr<vkb::PostProcessingPipeline> ms_depth_postprocessing_pipeline{};
/**
* @brief Update MSAA options and accordingly set the load/store
* attachment operations for the renderpasses
* This will trigger a swapchain recreation
*/
void update_pipelines();
/**
* @brief Update pipelines given that there will be a single
* renderpass for rendering the scene and GUI only
*/
void update_for_scene_only(bool msaa_enabled);
/**
* @brief Update pipelines given that there will be two renderpasses
* The first renderpass will draw the scene and save the output
* color and depth attachments which will be read in by
* a postprocessing renderpass
*/
void update_for_scene_and_postprocessing(bool msaa_enabled);
/**
* @brief If true the postprocessing renderpass is enabled
*/
bool run_postprocessing{false};
/**
* @brief Submits a postprocessing renderpass which binds full screen color
* and depth attachments and uses them to apply a screen-based effect
* It also draws the GUI
*/
void postprocessing(vkb::core::CommandBufferC &command_buffer, vkb::RenderTarget &render_target, VkImageLayout &swapchain_layout, bool msaa_enabled);
/**
* @brief Enables MSAA if set to more than 1 sample per pixel
* (e.g. sample count 4 enables 4X MSAA)
*/
VkSampleCountFlagBits sample_count{VK_SAMPLE_COUNT_1_BIT};
/**
* @brief List of MSAA levels supported by the platform
*/
std::vector<VkSampleCountFlagBits> supported_sample_count_list{};
/**
* @brief Queries the Vulkan device to construct the list of supported
* sample counts
*/
void prepare_supported_sample_count_list();
enum ColorResolve : int
{
OnWriteback = 0,
SeparatePass = 1
};
/**
* @brief Selects how to resolve the color attachment, either on writeback
* (efficient) or in a separate pass (inefficient)
*/
int color_resolve_method{ColorResolve::OnWriteback};
/**
* @brief Sets the multisampled color attachment as the output attachment
* and configures the resolve operation to resolve_attachment
* as well as the load/store operations of color attachments
* Note that MSAA will not have any effect in the postprocessing
* renderpass since it only renders a texture on single full-screen
* triangle and MSAA only works on primitive edges
*/
void use_multisampled_color(std::unique_ptr<vkb::rendering::SubpassC> &subpass,
std::vector<vkb::LoadStoreInfo> &load_store,
uint32_t resolve_attachment);
/**
* @brief Sets the single-sampled output_attachment as the output attachment,
* disables color resolve and updates the load/store operations of
* color attachments
*/
void use_singlesampled_color(std::unique_ptr<vkb::rendering::SubpassC> &subpass,
std::vector<vkb::LoadStoreInfo> &load_store,
uint32_t output_attachment);
/**
* @brief Submits a transfer operation to resolve the multisampled color attachment
* to the given single-sampled resolve attachment
* color_layout is an in-out parameter that holds the last known layout
* of the resolve attachment, and may be used for any further transitions
*/
void resolve_color_separate_pass(vkb::core::CommandBufferC &command_buffer,
const std::vector<vkb::core::ImageView> &views,
uint32_t color_destination,
VkImageLayout &color_layout);
/**
* @brief If true, the platform supports the VK_KHR_depth_stencil_resolve extension
* and therefore can resolve the depth attachment on writeback
*/
bool depth_writeback_resolve_supported{false};
/**
* @brief If true, enable writeback depth resolve
* If false the multisampled depth attachment will be stored
* (only if postprocessing is enabled since the attachment is
* otherwise unused)
*/
bool resolve_depth_on_writeback{true};
/**
* @brief Store the multisampled depth attachment, resolved to a single-sampled
* attachment if depth resolve on writeback is supported
* Update the load/store operations of the depth attachments
*/
void store_multisampled_depth(std::unique_ptr<vkb::rendering::SubpassC> &subpass, std::vector<vkb::LoadStoreInfo> &load_store);
/**
* @brief Disables depth writeback resolve and updates the load/store operations of
* the depth resolve attachment
*/
void disable_depth_writeback_resolve(std::unique_ptr<vkb::rendering::SubpassC> &subpass, std::vector<vkb::LoadStoreInfo> &load_store);
/**
* @brief Selects the depth resolve mode (e.g. min or max sample values)
*/
VkResolveModeFlagBits depth_resolve_mode{VK_RESOLVE_MODE_NONE};
/**
* @brief List of depth resolve modes supported by the platform
*/
std::vector<VkResolveModeFlagBits> supported_depth_resolve_mode_list{};
/**
* @brief Queries the Vulkan device to construct the list of supported
* depth resolve modes
*/
void prepare_depth_resolve_mode_list();
/* Helpers for managing attachments */
uint32_t i_swapchain{0};
uint32_t i_depth{0};
uint32_t i_color_ms{0};
uint32_t i_color_resolve{0};
uint32_t i_depth_resolve{0};
std::vector<uint32_t> color_atts{};
std::vector<uint32_t> depth_atts{};
std::vector<vkb::LoadStoreInfo> scene_load_store{};
/* Helpers for managing GUI input */
bool gui_run_postprocessing{false};
bool last_gui_run_postprocessing{false};
VkSampleCountFlagBits gui_sample_count{VK_SAMPLE_COUNT_1_BIT};
VkSampleCountFlagBits last_gui_sample_count{VK_SAMPLE_COUNT_1_BIT};
int gui_color_resolve_method{ColorResolve::OnWriteback};
int last_gui_color_resolve_method{ColorResolve::OnWriteback};
bool gui_resolve_depth_on_writeback{true};
bool last_gui_resolve_depth_on_writeback{true};
VkResolveModeFlagBits gui_depth_resolve_mode{VK_RESOLVE_MODE_NONE};
VkResolveModeFlagBits last_gui_depth_resolve_mode{VK_RESOLVE_MODE_NONE};
};
std::unique_ptr<vkb::VulkanSampleC> create_msaa();