init
This commit is contained in:
@@ -0,0 +1,488 @@
|
||||
/* Copyright (c) 2019-2025, Arm Limited and Contributors
|
||||
* Copyright (c) 2024-2025, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* 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 "buffer_pool.h"
|
||||
#include "rendering/hpp_pipeline_state.h"
|
||||
#include "rendering/hpp_render_target.h"
|
||||
#include "rendering/pipeline_state.h"
|
||||
#include "rendering/render_frame.h"
|
||||
#include "scene_graph/components/light.h"
|
||||
#include "scene_graph/node.h"
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
class RenderContext;
|
||||
class RenderTarget;
|
||||
class ShaderSource;
|
||||
|
||||
namespace core
|
||||
{
|
||||
template <vkb::BindingType bindingType>
|
||||
class CommandBuffer;
|
||||
}
|
||||
|
||||
namespace rendering
|
||||
{
|
||||
class HPPRenderContext;
|
||||
|
||||
struct alignas(16) Light
|
||||
{
|
||||
glm::vec4 position; // position.w represents type of light
|
||||
glm::vec4 color; // color.w represents light intensity
|
||||
glm::vec4 direction; // direction.w represents range
|
||||
glm::vec2 info; // (only used for spot lights) info.x represents light inner cone angle, info.y represents light outer cone angle
|
||||
};
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
struct LightingState
|
||||
{
|
||||
std::vector<Light> directional_lights;
|
||||
std::vector<Light> point_lights;
|
||||
std::vector<Light> spot_lights;
|
||||
BufferAllocation<bindingType> light_buffer;
|
||||
};
|
||||
|
||||
using LightingStateC = LightingState<vkb::BindingType::C>;
|
||||
using LightingStateCpp = LightingState<vkb::BindingType::Cpp>;
|
||||
|
||||
/**
|
||||
* @brief Calculates the vulkan style projection matrix
|
||||
* @param proj The projection matrix
|
||||
* @return The vulkan style projection matrix
|
||||
*/
|
||||
glm::mat4 vulkan_style_projection(const glm::mat4 &proj);
|
||||
|
||||
inline const std::vector<std::string> light_type_definitions = {
|
||||
"DIRECTIONAL_LIGHT " + std::to_string(static_cast<float>(sg::LightType::Directional)),
|
||||
"POINT_LIGHT " + std::to_string(static_cast<float>(sg::LightType::Point)),
|
||||
"SPOT_LIGHT " + std::to_string(static_cast<float>(sg::LightType::Spot))};
|
||||
|
||||
/**
|
||||
* @brief This class defines an interface for subpasses
|
||||
* where they need to implement the draw function.
|
||||
* It is used to construct a RenderPipeline
|
||||
*/
|
||||
template <vkb::BindingType bindingType>
|
||||
class Subpass
|
||||
{
|
||||
using ResolveModeFlagBitsType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::ResolveModeFlagBits, VkResolveModeFlagBits>::type;
|
||||
using SampleCountflagBitsType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::SampleCountFlagBits, VkSampleCountFlagBits>::type;
|
||||
|
||||
using DepthStencilStateType =
|
||||
typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPDepthStencilState, vkb::DepthStencilState>::type;
|
||||
using RenderContextType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPRenderContext, vkb::RenderContext>::type;
|
||||
using RenderTargetType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPRenderTarget, vkb::RenderTarget>::type;
|
||||
|
||||
public:
|
||||
Subpass(RenderContextType &render_context, ShaderSource &&vertex_shader, ShaderSource &&fragment_shader);
|
||||
|
||||
Subpass(const Subpass &) = delete;
|
||||
Subpass(Subpass &&) = default;
|
||||
virtual ~Subpass() = default;
|
||||
Subpass &operator=(const Subpass &) = delete;
|
||||
Subpass &operator=(Subpass &&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Draw virtual function
|
||||
* @param command_buffer Command buffer to use to record draw commands
|
||||
*/
|
||||
virtual void draw(vkb::core::CommandBuffer<bindingType> &command_buffer) = 0;
|
||||
|
||||
/**
|
||||
* @brief Prepares the shaders and shader variants for a subpass
|
||||
*/
|
||||
virtual void prepare() = 0;
|
||||
|
||||
/**
|
||||
* @brief Prepares the lighting state to have its lights
|
||||
*
|
||||
* @tparam A light structure that has 'directional_lights', 'point_lights' and 'spot_light' array fields defined.
|
||||
* @param scene_lights All of the light components from the scene graph
|
||||
* @param max_lights_per_type The maximum amount of lights allowed for any given type of light.
|
||||
*/
|
||||
template <typename T>
|
||||
void allocate_lights(const std::vector<sg::Light *> &scene_lights,
|
||||
size_t max_lights_per_type);
|
||||
|
||||
const std::vector<uint32_t> &get_color_resolve_attachments() const;
|
||||
const std::string &get_debug_name() const;
|
||||
const uint32_t &get_depth_stencil_resolve_attachment() const;
|
||||
ResolveModeFlagBitsType get_depth_stencil_resolve_mode() const;
|
||||
DepthStencilStateType &get_depth_stencil_state();
|
||||
const bool &get_disable_depth_stencil_attachment() const;
|
||||
const ShaderSource &get_fragment_shader() const;
|
||||
const std::vector<uint32_t> &get_input_attachments() const;
|
||||
LightingState<bindingType> &get_lighting_state();
|
||||
const std::vector<uint32_t> &get_output_attachments() const;
|
||||
RenderContextType &get_render_context();
|
||||
std::unordered_map<std::string, ShaderResourceMode> const &get_resource_mode_map() const;
|
||||
SampleCountflagBitsType get_sample_count() const;
|
||||
const ShaderSource &get_vertex_shader() const;
|
||||
void set_color_resolve_attachments(std::vector<uint32_t> const &color_resolve);
|
||||
void set_debug_name(const std::string &name);
|
||||
void set_disable_depth_stencil_attachment(bool disable_depth_stencil);
|
||||
void set_depth_stencil_resolve_attachment(uint32_t depth_stencil_resolve);
|
||||
void set_depth_stencil_resolve_mode(ResolveModeFlagBitsType mode);
|
||||
void set_input_attachments(std::vector<uint32_t> const &input);
|
||||
void set_output_attachments(std::vector<uint32_t> const &output);
|
||||
void set_sample_count(SampleCountflagBitsType sample_count);
|
||||
|
||||
/**
|
||||
* @brief Updates the render target attachments with the ones stored in this subpass
|
||||
* This function is called by the RenderPipeline before beginning the render
|
||||
* pass and before proceeding with a new subpass.
|
||||
*/
|
||||
void update_render_target_attachments(RenderTargetType &render_target);
|
||||
|
||||
private:
|
||||
/// Default to no color resolve attachments
|
||||
std::vector<uint32_t> color_resolve_attachments = {};
|
||||
|
||||
std::string debug_name{};
|
||||
|
||||
/**
|
||||
* @brief When creating the renderpass, if not None, the resolve
|
||||
* of the multisampled depth attachment will be enabled,
|
||||
* with this mode, to depth_stencil_resolve_attachment
|
||||
*/
|
||||
vk::ResolveModeFlagBits depth_stencil_resolve_mode{vk::ResolveModeFlagBits::eNone};
|
||||
|
||||
vkb::rendering::HPPDepthStencilState depth_stencil_state{};
|
||||
|
||||
/**
|
||||
* @brief When creating the renderpass, pDepthStencilAttachment will
|
||||
* be set to nullptr, which disables depth testing
|
||||
*/
|
||||
bool disable_depth_stencil_attachment{false};
|
||||
|
||||
/// Default to no depth stencil resolve attachment
|
||||
uint32_t depth_stencil_resolve_attachment{VK_ATTACHMENT_UNUSED};
|
||||
|
||||
/// The structure containing all the requested render-ready lights for the scene
|
||||
LightingStateCpp lighting_state{};
|
||||
|
||||
ShaderSource fragment_shader;
|
||||
|
||||
/// Default to no input attachments
|
||||
std::vector<uint32_t> input_attachments = {};
|
||||
|
||||
/// Default to swapchain output attachment
|
||||
std::vector<uint32_t> output_attachments = {0};
|
||||
|
||||
vkb::rendering::HPPRenderContext &render_context;
|
||||
|
||||
// A map of shader resource names and the mode of constant data
|
||||
std::unordered_map<std::string, ShaderResourceMode> resource_mode_map;
|
||||
|
||||
vk::SampleCountFlagBits sample_count{vk::SampleCountFlagBits::e1};
|
||||
ShaderSource vertex_shader;
|
||||
};
|
||||
|
||||
using SubpassC = Subpass<vkb::BindingType::C>;
|
||||
using SubpassCpp = Subpass<vkb::BindingType::Cpp>;
|
||||
} // namespace rendering
|
||||
} // namespace vkb
|
||||
|
||||
#include "rendering/hpp_render_context.h"
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace rendering
|
||||
{
|
||||
inline glm::mat4 vulkan_style_projection(const glm::mat4 &proj)
|
||||
{
|
||||
// Flip Y in clipspace. X = -1, Y = -1 is topLeft in Vulkan.
|
||||
glm::mat4 mat = proj;
|
||||
mat[1][1] *= -1;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline Subpass<bindingType>::Subpass(RenderContextType &render_context, ShaderSource &&vertex_source, ShaderSource &&fragment_source) :
|
||||
render_context{reinterpret_cast<vkb::rendering::HPPRenderContext &>(render_context)},
|
||||
vertex_shader{std::move(vertex_source)},
|
||||
fragment_shader{std::move(fragment_source)}
|
||||
{
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline const std::vector<uint32_t> &Subpass<bindingType>::get_input_attachments() const
|
||||
{
|
||||
return input_attachments;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline LightingState<bindingType> &Subpass<bindingType>::get_lighting_state()
|
||||
{
|
||||
if constexpr (bindingType == vkb::BindingType::Cpp)
|
||||
{
|
||||
return lighting_state;
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<LightingState<bindingType> &>(lighting_state);
|
||||
}
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline const std::vector<uint32_t> &Subpass<bindingType>::get_output_attachments() const
|
||||
{
|
||||
return output_attachments;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline typename vkb::rendering::Subpass<bindingType>::RenderContextType &Subpass<bindingType>::get_render_context()
|
||||
{
|
||||
if constexpr (bindingType == vkb::BindingType::Cpp)
|
||||
{
|
||||
return render_context;
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<vkb::RenderContext &>(render_context);
|
||||
}
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
std::unordered_map<std::string, ShaderResourceMode> const &Subpass<bindingType>::get_resource_mode_map() const
|
||||
{
|
||||
return resource_mode_map;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline typename Subpass<bindingType>::SampleCountflagBitsType Subpass<bindingType>::get_sample_count() const
|
||||
{
|
||||
if constexpr (bindingType == vkb::BindingType::Cpp)
|
||||
{
|
||||
return sample_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<VkSampleCountFlagBits>(sample_count);
|
||||
}
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline const ShaderSource &Subpass<bindingType>::get_vertex_shader() const
|
||||
{
|
||||
return vertex_shader;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
template <typename T>
|
||||
void Subpass<bindingType>::allocate_lights(const std::vector<sg::Light *> &scene_lights,
|
||||
size_t max_lights_per_type)
|
||||
{
|
||||
lighting_state.directional_lights.clear();
|
||||
lighting_state.point_lights.clear();
|
||||
lighting_state.spot_lights.clear();
|
||||
|
||||
for (auto &scene_light : scene_lights)
|
||||
{
|
||||
const auto &properties = scene_light->get_properties();
|
||||
auto &transform = scene_light->get_node()->get_transform();
|
||||
|
||||
Light light{{transform.get_translation(), static_cast<float>(scene_light->get_light_type())},
|
||||
{properties.color, properties.intensity},
|
||||
{transform.get_rotation() * properties.direction, properties.range},
|
||||
{properties.inner_cone_angle, properties.outer_cone_angle}};
|
||||
|
||||
switch (scene_light->get_light_type())
|
||||
{
|
||||
case sg::LightType::Directional:
|
||||
{
|
||||
if (lighting_state.directional_lights.size() < max_lights_per_type)
|
||||
{
|
||||
lighting_state.directional_lights.push_back(light);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGE("Subpass::allocate_lights: exceeding max_lights_per_type of {} for directional lights", max_lights_per_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sg::LightType::Point:
|
||||
{
|
||||
if (lighting_state.point_lights.size() < max_lights_per_type)
|
||||
{
|
||||
lighting_state.point_lights.push_back(light);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGE("Subpass::allocate_lights: exceeding max_lights_per_type of {} for point lights", max_lights_per_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sg::LightType::Spot:
|
||||
{
|
||||
if (lighting_state.spot_lights.size() < max_lights_per_type)
|
||||
{
|
||||
lighting_state.spot_lights.push_back(light);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGE("Subpass::allocate_lights: exceeding max_lights_per_type of {} for spot lights", max_lights_per_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOGE("Subpass::allocate_lights: encountered unknown light type {}", to_string(scene_light->get_light_type()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
T light_info;
|
||||
|
||||
std::copy(lighting_state.directional_lights.begin(), lighting_state.directional_lights.end(), light_info.directional_lights);
|
||||
std::copy(lighting_state.point_lights.begin(), lighting_state.point_lights.end(), light_info.point_lights);
|
||||
std::copy(lighting_state.spot_lights.begin(), lighting_state.spot_lights.end(), light_info.spot_lights);
|
||||
|
||||
auto &render_frame = render_context.get_active_frame();
|
||||
lighting_state.light_buffer = render_frame.allocate_buffer(vk::BufferUsageFlagBits::eUniformBuffer, sizeof(T));
|
||||
lighting_state.light_buffer.update(light_info);
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline const std::vector<uint32_t> &Subpass<bindingType>::get_color_resolve_attachments() const
|
||||
{
|
||||
return color_resolve_attachments;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline const std::string &Subpass<bindingType>::get_debug_name() const
|
||||
{
|
||||
return debug_name;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline const uint32_t &Subpass<bindingType>::get_depth_stencil_resolve_attachment() const
|
||||
{
|
||||
return depth_stencil_resolve_attachment;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline typename Subpass<bindingType>::ResolveModeFlagBitsType Subpass<bindingType>::get_depth_stencil_resolve_mode() const
|
||||
{
|
||||
if constexpr (bindingType == vkb::BindingType::Cpp)
|
||||
{
|
||||
return depth_stencil_resolve_mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<VkResolveModeFlagBits>(depth_stencil_resolve_mode);
|
||||
}
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline typename Subpass<bindingType>::DepthStencilStateType &Subpass<bindingType>::get_depth_stencil_state()
|
||||
{
|
||||
if constexpr (bindingType == vkb::BindingType::Cpp)
|
||||
{
|
||||
return depth_stencil_state;
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<vkb::DepthStencilState &>(depth_stencil_state);
|
||||
}
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline const bool &Subpass<bindingType>::get_disable_depth_stencil_attachment() const
|
||||
{
|
||||
return disable_depth_stencil_attachment;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline const ShaderSource &Subpass<bindingType>::get_fragment_shader() const
|
||||
{
|
||||
return fragment_shader;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline void Subpass<bindingType>::set_color_resolve_attachments(std::vector<uint32_t> const &color_resolve)
|
||||
{
|
||||
color_resolve_attachments = color_resolve;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline void Subpass<bindingType>::set_depth_stencil_resolve_attachment(uint32_t depth_stencil_resolve)
|
||||
{
|
||||
depth_stencil_resolve_attachment = depth_stencil_resolve;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline void Subpass<bindingType>::set_debug_name(const std::string &name)
|
||||
{
|
||||
debug_name = name;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline void Subpass<bindingType>::set_disable_depth_stencil_attachment(bool disable_depth_stencil)
|
||||
{
|
||||
disable_depth_stencil_attachment = disable_depth_stencil;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline void Subpass<bindingType>::set_depth_stencil_resolve_mode(ResolveModeFlagBitsType mode)
|
||||
{
|
||||
if constexpr (bindingType == vkb::BindingType::Cpp)
|
||||
{
|
||||
depth_stencil_resolve_mode = mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
depth_stencil_resolve_mode = static_cast<vk::ResolveModeFlagBits>(mode);
|
||||
}
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline void Subpass<bindingType>::set_input_attachments(std::vector<uint32_t> const &input)
|
||||
{
|
||||
input_attachments = input;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline void Subpass<bindingType>::set_output_attachments(std::vector<uint32_t> const &output)
|
||||
{
|
||||
output_attachments = output;
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline void Subpass<bindingType>::set_sample_count(SampleCountflagBitsType sample_count_)
|
||||
{
|
||||
if constexpr (bindingType == vkb::BindingType::Cpp)
|
||||
{
|
||||
sample_count = sample_count_;
|
||||
}
|
||||
else
|
||||
{
|
||||
sample_count = static_cast<vk::SampleCountFlagBits>(sample_count_);
|
||||
}
|
||||
}
|
||||
|
||||
template <vkb::BindingType bindingType>
|
||||
inline void Subpass<bindingType>::update_render_target_attachments(RenderTargetType &render_target)
|
||||
{
|
||||
render_target.set_input_attachments(input_attachments);
|
||||
render_target.set_output_attachments(output_attachments);
|
||||
}
|
||||
} // namespace rendering
|
||||
} // namespace vkb
|
||||
Reference in New Issue
Block a user