Files
face_sdk/vulkan/framework/rendering/postprocessing_renderpass.h
T

327 lines
11 KiB
C++

/* Copyright (c) 2020-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 "core/sampled_image.h"
#include "postprocessing_pass.h"
#include "render_pipeline.h"
#include "subpass.h"
namespace vkb
{
/**
* @brief An utility struct for hashing pairs.
*/
struct PairHasher
{
template <typename TPair>
size_t operator()(const TPair &pair) const
{
std::hash<decltype(pair.first)> hash1{};
std::hash<decltype(pair.second)> hash2{};
return hash1(pair.first) * 43 + pair.second;
}
};
/**
* @brief Maps in-shader binding names to indices into a RenderTarget's attachments.
*/
using AttachmentMap = std::unordered_map<std::string, uint32_t>;
/**
* @brief Maps in-shader binding names to the core::SampledImage to bind.
*/
using SampledMap = std::unordered_map<std::string, core::SampledImage>;
/**
* @brief Maps in-shader binding names to the core::ImageView to bind for storage images.
*/
using StorageImageMap = std::unordered_map<std::string, const core::ImageView *>;
/**
* @brief A list of indices into a RenderTarget's attachments.
*/
using AttachmentList = std::vector<uint32_t>;
/**
* @brief A set of indices into a RenderTarget's attachments.
*/
using AttachmentSet = std::unordered_set<uint32_t>;
class PostProcessingRenderPass;
/**
* @brief A single step of a vkb::PostProcessingRenderPass.
*/
class PostProcessingSubpass : public vkb::rendering::SubpassC
{
public:
PostProcessingSubpass(PostProcessingRenderPass *parent, RenderContext &render_context, ShaderSource &&triangle_vs,
ShaderSource &&fs, ShaderVariant &&fs_variant = {});
PostProcessingSubpass(const PostProcessingSubpass &to_copy) = delete;
PostProcessingSubpass &operator=(const PostProcessingSubpass &to_copy) = delete;
PostProcessingSubpass(PostProcessingSubpass &&to_move);
PostProcessingSubpass &operator=(PostProcessingSubpass &&to_move) = delete;
~PostProcessingSubpass() = default;
/**
* @brief Maps the names of input attachments in the shader to indices into the render target's images.
* These are given as `subpassInput`s to the subpass, at set 0; they are bound automatically according to their name.
*/
inline const AttachmentMap &get_input_attachments() const
{
return input_attachments;
}
/**
* @brief Maps the names of samplers in the shader to vkb::core::SampledImage.
* These are given as samplers to the subpass, at set 0; they are bound automatically according to their name.
* @remarks PostProcessingPipeline::get_sampler() is used as the default sampler if none is specified.
* The RenderTarget for the current PostProcessingSubpass is used if none is specified for attachment images.
*/
inline const SampledMap &get_sampled_images() const
{
return sampled_images;
}
/**
* @brief Maps the names of storage images in the shader to vkb::core::ImageView.
* These are given as image2D[Array] to the subpass, at set 0; they are bound automatically according to their name.
*/
inline const StorageImageMap &get_storage_images() const
{
return storage_images;
}
/**
* @brief Returns the shader variant used for this postprocess' fragment shader.
*/
inline ShaderVariant &get_fs_variant()
{
return fs_variant;
}
/**
* @brief Sets the shader variant that will be used for this postprocess' fragment shader.
*/
inline PostProcessingSubpass &set_fs_variant(ShaderVariant &&new_variant)
{
fs_variant = std::move(new_variant);
return *this;
}
/**
* @brief Changes the debug name of this Subpass.
*/
inline PostProcessingSubpass &set_debug_name(const std::string &name)
{
Subpass::set_debug_name(name);
return *this;
}
/**
* @brief Changes (or adds) the input attachment at name for this step.
*/
PostProcessingSubpass &bind_input_attachment(const std::string &name, uint32_t new_input_attachment);
/**
* @brief Changes (or adds) the sampled image at name for this step.
* @remarks If no RenderTarget is specifically set for the core::SampledImage,
* it will default to sample in the RenderTarget currently bound for drawing in the parent PostProcessingRenderpass.
*/
PostProcessingSubpass &bind_sampled_image(const std::string &name, core::SampledImage &&new_image);
/**
* @brief Changes (or adds) the storage image at name for this step.
*/
PostProcessingSubpass &bind_storage_image(const std::string &name, const core::ImageView &new_image);
/**
* @brief Removes the sampled image at name for this step.
*/
void unbind_sampled_image(const std::string &name);
/**
* @brief Set the constants that are pushed before each fullscreen draw.
*/
PostProcessingSubpass &set_push_constants(const std::vector<uint8_t> &data);
/**
* @brief Set the constants that are pushed before each fullscreen draw.
*/
template <typename T>
inline PostProcessingSubpass &set_push_constants(const T &data)
{
push_constants_data.reserve(sizeof(data));
auto data_ptr = reinterpret_cast<const uint8_t *>(&data);
push_constants_data.assign(data_ptr, data_ptr + sizeof(data));
return *this;
}
/**
* @brief A functor used to draw the primitives for a post-processing step.
* @see default_draw_func()
*/
using DrawFunc = std::function<void(vkb::core::CommandBufferC &command_buffer, RenderTarget &render_target)>;
/**
* @brief Sets the function used to draw this postprocessing step.
* @see default_draw_func()
*/
PostProcessingSubpass &set_draw_func(DrawFunc &&new_func);
/**
* @brief The default function used to draw a step; it draws 1 instance with 3 vertices.
*/
static void default_draw_func(vkb::core::CommandBufferC &command_buffer, vkb::RenderTarget &render_target);
private:
PostProcessingRenderPass *parent;
ShaderVariant fs_variant{};
AttachmentMap input_attachments{};
SampledMap sampled_images{};
StorageImageMap storage_images{};
std::vector<uint8_t> push_constants_data{};
DrawFunc draw_func{&PostProcessingSubpass::default_draw_func};
void prepare() override;
void draw(vkb::core::CommandBufferC &command_buffer) override;
};
/**
* @brief A collection of vkb::PostProcessingSubpass that are run as a single renderpass.
*/
class PostProcessingRenderPass : public PostProcessingPass<PostProcessingRenderPass>
{
public:
friend class PostProcessingSubpass;
PostProcessingRenderPass(PostProcessingPipeline *parent, std::unique_ptr<core::Sampler> &&default_sampler = nullptr);
PostProcessingRenderPass(const PostProcessingRenderPass &to_copy) = delete;
PostProcessingRenderPass &operator=(const PostProcessingRenderPass &to_copy) = delete;
PostProcessingRenderPass(PostProcessingRenderPass &&to_move) = default;
PostProcessingRenderPass &operator=(PostProcessingRenderPass &&to_move) = default;
void draw(vkb::core::CommandBufferC &command_buffer, RenderTarget &default_render_target) override;
/**
* @brief Gets the step at the given index.
*/
inline PostProcessingSubpass &get_subpass(size_t index)
{
assert(index < pipeline.get_subpasses().size());
return *dynamic_cast<PostProcessingSubpass *>(pipeline.get_subpasses()[index].get());
}
/**
* @brief Constructs a new PostProcessingSubpass and adds it to the tail of the pipeline.
* @remarks `this`, the render context and the vertex shader source are passed automatically before `args`.
* @returns The inserted step.
*/
template <typename... ConstructorArgs>
PostProcessingSubpass &add_subpass(ConstructorArgs &&...args)
{
ShaderSource vs_copy = get_triangle_vs();
auto new_subpass = std::make_unique<PostProcessingSubpass>(this, get_render_context(), std::move(vs_copy), std::forward<ConstructorArgs>(args)...);
auto &new_subpass_ref = *new_subpass;
pipeline.add_subpass(std::move(new_subpass));
return new_subpass_ref;
}
/**
* @brief Set the uniform data to be bound at set 0, binding 0.
*/
template <typename T>
inline PostProcessingRenderPass &set_uniform_data(const T &data)
{
uniform_data.reserve(sizeof(data));
auto data_ptr = reinterpret_cast<const uint8_t *>(&data);
uniform_data.assign(data_ptr, data_ptr + sizeof(data));
return *this;
}
/**
* @copydoc set_uniform_data(const T&)
*/
inline PostProcessingRenderPass &set_uniform_data(const std::vector<uint8_t> &data)
{
uniform_data = data;
return *this;
}
private:
// An attachment sampled from a rendertarget
using SampledAttachmentSet = std::unordered_set<std::pair<RenderTarget *, uint32_t>, PairHasher>;
/**
* @brief Transition input, sampled and output attachments as appropriate.
* @remarks If a RenderTarget is not explicitly set for this pass, fallback_render_target is used.
*/
void transition_attachments(const AttachmentSet &input_attachments,
const SampledAttachmentSet &sampled_attachments,
const AttachmentSet &output_attachments,
vkb::core::CommandBufferC &command_buffer,
RenderTarget &fallback_render_target);
/**
* @brief Select appropriate load/store operations for each buffer of render_target,
* according to the subpass inputs/sampled inputs/subpass outputs of all steps
* in the pipeline.
* @remarks If a RenderTarget is not explicitly set for this pass, fallback_render_target is used.
*/
void update_load_stores(const AttachmentSet &input_attachments,
const SampledAttachmentSet &sampled_attachments,
const AttachmentSet &output_attachments,
const RenderTarget &fallback_render_target);
/**
* @brief Transition images and prepare load/stores before draw()ing.
*/
void prepare_draw(vkb::core::CommandBufferC &command_buffer, RenderTarget &fallback_render_target);
BarrierInfo get_src_barrier_info() const override;
BarrierInfo get_dst_barrier_info() const override;
RenderPipeline pipeline{};
std::unique_ptr<core::Sampler> default_sampler{};
std::unique_ptr<core::Sampler> default_sampler_nearest{};
RenderTarget *draw_render_target{nullptr};
std::vector<LoadStoreInfo> load_stores{};
bool load_stores_dirty{true};
std::vector<uint8_t> uniform_data{};
std::shared_ptr<BufferAllocationC> uniform_buffer_alloc{};
};
} // namespace vkb