This repository was archived by the owner on Mar 11, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPipelinePool.hpp
More file actions
111 lines (93 loc) · 4.45 KB
/
PipelinePool.hpp
File metadata and controls
111 lines (93 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#pragma once
#include <Tkge/Graphics/PipelineFixedState.hpp>
#include <Tkge/Graphics/Shader.hpp>
#include <Tkge/Graphics/Vertex.hpp>
#include <klib/hash_combine.hpp>
#include <kvf/render_device.hpp>
#include <unordered_map>
namespace Tkge::Detail
{
/// \brief Cached storage for Vulkan Graphics Pipelines.
class PipelinePool
{
public:
using FixedState = Graphics::PipelineFixedState;
/// \param renderDevice Pointer to valid RenderDevice.
/// \param framebufferSamples Sample count of target Render Pass' colour attachment.
explicit PipelinePool(gsl::not_null<const kvf::RenderDevice*> renderDevice, vk::SampleCountFlagBits framebufferSamples)
: _renderDevice(renderDevice), _framebufferSamples(framebufferSamples)
{
CreateSetLayouts();
CreatePipelineLayout();
}
[[nodiscard]] vk::PipelineLayout PipelineLayout() const { return *_pipelineLayout; }
[[nodiscard]] std::span<const vk::DescriptorSetLayout> SetLayouts() const { return _setLayouts; }
/// \brief Get the Pipeline identified by the input parameters.
/// \param shader Shader that will be used in draw calls (dynamic Pipeline state).
/// \param state Fixed Pipeline state.
/// \returns Existing Pipeline if already cached, otherwise a newly created one (unless creation fails).
[[nodiscard]] vk::Pipeline GetPipeline(const Graphics::Shader& shader, const FixedState& state)
{
using Graphics::Vertex;
// A single Vertex Buffer is bound during draw (index 0), containing vertices.
static constexpr auto VertexBindings = std::array{
vk::VertexInputBindingDescription{0, sizeof(Vertex)},
};
// Attributes for Vertex Buffer at index 0: list of interleaved vertices (span<Vertex>).
static constexpr auto VertexAttributes = std::array{
vk::VertexInputAttributeDescription{0, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, position)},
vk::VertexInputAttributeDescription{1, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(Vertex, colour)},
vk::VertexInputAttributeDescription{2, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, uv)},
};
const auto key = klib::make_combined_hash(shader.GetHash(), state.colourFormat, state.polygonMode, state.topology);
auto it = _pipelines.find(key);
if (it != _pipelines.end()) { return *it->second; }
const auto pipelineState = kvf::PipelineState{
.vertex_bindings = VertexBindings,
.vertex_attributes = VertexAttributes,
.vertex_shader = shader.VertexModule(),
.fragment_shader = shader.FragmentModule(),
.topology = state.topology,
.polygon_mode = state.polygonMode,
};
const auto pipelineFormat = kvf::PipelineFormat{
.samples = _framebufferSamples,
.color = state.colourFormat,
};
auto ret = _renderDevice->create_pipeline(*_pipelineLayout, pipelineState, pipelineFormat);
if (!ret) { return {}; }
it = _pipelines.insert({key, std::move(ret)}).first;
return *it->second;
}
private:
void CreateSetLayouts()
{
static constexpr auto StageFlags = vk::ShaderStageFlagBits::eAllGraphics;
// set 0: builtin
auto set0 = std::array<vk::DescriptorSetLayoutBinding, 3>{};
// set 0, binding 0: view
set0[0].setBinding(0).setDescriptorCount(1).setDescriptorType(vk::DescriptorType::eUniformBuffer).setStageFlags(StageFlags);
// set 0, binding 1: instances
set0[1].setBinding(1).setDescriptorCount(1).setDescriptorType(vk::DescriptorType::eStorageBuffer).setStageFlags(StageFlags);
// set0, binding 2: texture
set0[2].setBinding(2).setDescriptorCount(1).setDescriptorType(vk::DescriptorType::eCombinedImageSampler).setStageFlags(StageFlags);
// TODO: set 1: user data
auto dslci = std::array<vk::DescriptorSetLayoutCreateInfo, 1>{};
dslci[0].setBindings(set0);
for (const auto& createInfo : dslci) { _setLayoutStorage.push_back(_renderDevice->get_device().createDescriptorSetLayoutUnique(createInfo)); }
for (const auto& setLayout : _setLayoutStorage) { _setLayouts.push_back(*setLayout); }
}
void CreatePipelineLayout()
{
auto plci = vk::PipelineLayoutCreateInfo{};
plci.setSetLayouts(_setLayouts);
_pipelineLayout = _renderDevice->get_device().createPipelineLayoutUnique(plci);
}
gsl::not_null<const kvf::RenderDevice*> _renderDevice;
vk::SampleCountFlagBits _framebufferSamples;
vk::UniquePipelineLayout _pipelineLayout{};
std::vector<vk::UniqueDescriptorSetLayout> _setLayoutStorage{};
std::vector<vk::DescriptorSetLayout> _setLayouts{};
std::unordered_map<std::size_t, vk::UniquePipeline> _pipelines{};
};
} // namespace Tkge::Detail