327 lines
11 KiB
C++
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
|