Toast Engine
Loading...
Searching...
No Matches
voxel_pass.hpp
Go to the documentation of this file.
1
6
7#pragma once
8
9#include "../hiz_pyramid.hpp"
10#include "../render_pass_base.hpp"
12#include "../shader_layout.hpp"
13#include "../vulkan_pipeline.hpp"
14
15#include <array>
16#include <chrono>
17#include <glm/glm.hpp>
18#include <memory>
19#include <optional>
20#include <string_view>
21#include <vector>
22
23namespace renderer {
24class VulkanCore;
25class VoxelGpuStorage;
26
28class VoxelPass : public IRenderPass {
29public:
30 VoxelPass(const VulkanCore& core, vk::Format scene_format, vk::Format depth_format, vk::Extent2D extent);
31
32 [[nodiscard]]
33 auto stage() const -> RenderStage override {
34 return RenderStage::voxel_gbuffer;
35 }
36
38 [[nodiscard]]
39 auto prepare(uint32_t frame_index) -> bool;
40
42 void recordCellCull(vk::CommandBuffer cmd, uint32_t frame_index, vk::Extent2D scene_extent);
43
45 void record(vk::CommandBuffer cmd, uint32_t frame_index, uint32_t image_index) override;
46
48 [[nodiscard]]
49 auto occlusionActive() const -> bool {
50 return m_occlusion_active;
51 }
52
54 void recordOcclusion(vk::CommandBuffer cmd, uint32_t frame_index, vk::Extent2D scene_extent);
55
57 void recordLate(vk::CommandBuffer cmd, uint32_t frame_index);
58
60 [[nodiscard]]
61 auto nearQuadDepthPass() const -> bool {
62 return m_near_voxels > 0.0f && !m_mesh_shading;
63 }
64
66 void recordQuadDepth(vk::CommandBuffer cmd, uint32_t frame_index, bool late);
67
69 void recordLighting(vk::CommandBuffer cmd, uint32_t frame_index, vk::Extent2D viewport);
70
72 void onTargetsRecreated();
73
74 [[nodiscard]]
75 auto name() const -> std::string_view override {
76 return "Voxels";
77 }
78
79 static constexpr uint32_t k_max_instances = 4096;
80
81private:
83 std::chrono::steady_clock::time_point m_last_limit_warning;
84
86 struct PushConstants {
87 uint32_t instance_index = 0;
88 uint32_t bucket = 0;
89 uint32_t mode = 0;
90 uint32_t quad_capacity = 0;
91 };
92
94 static constexpr uint32_t k_draw_volume = 0;
95 static constexpr uint32_t k_draw_cells = 1;
96
98 struct CellCullPush {
99 glm::mat4 view_projection {1.0f};
100 glm::vec4 camera_near {0.0f};
101 uint32_t total_cells = 0;
102 uint32_t instance_count = 0;
103 uint32_t phase = 0;
104 uint32_t quad_capacity = 0;
105 float near_voxels = 0.0f;
106 uint32_t hiz_levels = 0;
107 uint32_t hiz_width = 0;
108 uint32_t hiz_height = 0;
109 };
110
112 struct HizView {
113 glm::mat4 view_projection {1.0f};
114 };
115
117 static constexpr uint32_t k_cell_bucket_count = 17;
118 static constexpr uint32_t k_late_list = k_cell_bucket_count;
119 static constexpr uint32_t k_cell_draw_count = k_cell_bucket_count + 1;
120 static constexpr uint32_t k_near_list = k_cell_draw_count;
121 static constexpr uint32_t k_near_band_count = 4;
122 static constexpr uint32_t k_retest_list = k_near_list + k_near_band_count;
123 static constexpr uint32_t k_late_near_list = k_retest_list + 1;
124 static constexpr uint32_t k_cell_list_count = k_late_near_list + 1;
125 static constexpr uint32_t k_cell_offsets_word = k_cell_draw_count * 4;
126 static constexpr uint32_t k_cell_cursors_word = k_cell_offsets_word + k_cell_list_count;
127 static constexpr uint32_t k_near_dispatch_word = k_cell_cursors_word + k_cell_list_count;
128 static constexpr uint32_t k_retest_dispatch_word = k_near_dispatch_word + 3;
129 static constexpr uint32_t k_late_mesh_dispatch_word = k_retest_dispatch_word + 3;
130 static constexpr uint32_t k_quad_draw_word = k_late_mesh_dispatch_word + 3;
131 static constexpr uint32_t k_late_quad_draw_word = k_quad_draw_word + 4;
132 static constexpr uint32_t k_near_task_word = k_late_quad_draw_word + 4;
133 static constexpr uint32_t k_late_task_word = k_near_task_word + 3;
134 static constexpr uint32_t k_occlusion_stats_word = k_late_task_word + 3;
135 static constexpr uint32_t k_cell_args_words = k_occlusion_stats_word + 2;
136 static constexpr uint32_t k_min_quad_capacity = 65536;
138 static constexpr uint32_t k_max_coarse_dim = 1024;
139 static constexpr uint32_t k_min_cell_capacity = 4096;
140
142 struct CellBuffers {
144 std::optional<vma::raii::Buffer> cells;
146 std::optional<vma::raii::Buffer> classes;
148 std::optional<vma::raii::Buffer> args;
149 uint32_t capacity = 0;
151 std::optional<vma::raii::Buffer> quads;
152 uint32_t quad_capacity = 0;
154 std::optional<vma::raii::Buffer> readback;
156 bool measured = false;
158 std::optional<vma::raii::Buffer> hiz_view;
159 };
160
162 struct LightingPushConstants {
163 glm::mat4 inverse_view_projection {1.0f};
164 glm::vec4 camera_radius {0.0f};
165 glm::vec4 viewport {0.0f};
166 };
167
168 void createCells(const VulkanCore& core);
169 void ensureCellCapacity(uint32_t frame_index, uint32_t cells);
170 void ensureQuadCapacity(uint32_t frame_index, uint32_t quads);
172 void afterCullWrites(vk::CommandBuffer cmd, uint32_t frame_index, sync::BarrierBatch& barriers);
174 void recordNearQuads(vk::CommandBuffer cmd, uint32_t frame_index, bool late, bool depth_only);
176 void recordReadback(vk::CommandBuffer cmd, uint32_t frame_index, sync::BarrierBatch& barriers);
178 void updateOcclusionMode(uint32_t retest_cells, uint32_t listed_cells);
179 void writeCellDescriptors(uint32_t frame_index);
181 void writeHizDescriptors();
182 void recordCellDraws(vk::CommandBuffer cmd, uint32_t frame_index);
183
184 enum class Cull : uint8_t {
185 back,
186 front,
187 };
188
189 enum class Depth : uint8_t {
191 conservative,
193 exact,
194 };
195
196 struct Draw {
197 uint32_t instance = 0;
198 Cull cull = Cull::back;
199 Depth depth = Depth::conservative;
200 };
201
202 void createInstanceBuffers(const VulkanCore& core);
203 void createDescriptors(const VulkanCore& core, const ShaderReflection& reflection);
204 void createLighting(const VulkanCore& core, vk::Format scene_format, vk::Extent2D extent);
205
206 void bindStorage(uint32_t frame_index, const std::shared_ptr<const VoxelGpuStorage>& storage);
207
208 const VulkanCore* m_core = nullptr;
209 ShaderLayout m_shader_layout;
210
212 std::array<std::array<VulkanPipeline, 2>, 2> m_pipelines;
213
214 SceneDescriptorSets m_scene_sets;
215
216 std::vector<vk::raii::DescriptorSet> m_storage_sets;
217
218 std::vector<vma::raii::Buffer> m_instance_buffers;
219
220 std::vector<std::shared_ptr<const VoxelGpuStorage>> m_bound_storage;
221
222 std::vector<Draw> m_draws;
223
224 ShaderLayout m_cell_layout;
225 VulkanPipeline m_cell_pipeline;
226 VulkanPipeline m_mesh_pipeline;
227 VulkanPipeline m_quad_pipeline;
228 VulkanPipeline m_quad_depth_pipeline;
230 VulkanPipeline m_mesh_quad_pipeline;
231 PFN_vkCmdDrawMeshTasksIndirectEXT m_draw_mesh_tasks_indirect = nullptr;
233 bool m_mesh_shading = false;
234 std::vector<vk::raii::DescriptorSet> m_cell_sets;
235 std::vector<CellBuffers> m_cell_buffers;
236
237 bool m_cells_active = false;
238 bool m_occlusion_active = false;
239
240 enum class OcclusionMode : uint8_t {
241 engaged,
243 idle,
244 };
245 OcclusionMode m_occlusion_mode = OcclusionMode::engaged;
247 uint32_t m_occlusion_low_frames = 0;
249 uint32_t m_occlusion_idle_frames = 0;
251 uint64_t m_frame_count = 0;
252 uint64_t m_pyramid_frame = 0;
253 uint32_t m_total_cells = 0;
255 CellCullPush m_cull_push;
256 HiZPyramid m_hiz;
258 float m_near_voxels = 0.0f;
259
260 ShaderLayout m_lighting_layout;
261 VulkanPipeline m_lighting_pipeline;
262 SceneDescriptorSets m_lighting_scene_sets;
263
264 vk::raii::Sampler m_point_sampler = nullptr;
265 std::vector<vk::raii::DescriptorSet> m_gbuffer_sets;
266
268 std::vector<std::array<vk::ImageView, 4>> m_bound_gbuffer;
269};
270
271}
Definition render_pass_base.hpp:19
Immutable scene version and versions from small carves share buffers patched in place.
Definition voxel_gpu_storage.hpp:54
auto nearQuadDepthPass() const -> bool
A depth only scope for recordQuadDepth() precedes each G-buffer scope except on the mesh shader path.
Definition voxel_pass.hpp:61
auto prepare(uint32_t frame_index) -> bool
Definition voxel_pass.cpp:457
void record(vk::CommandBuffer cmd, uint32_t frame_index, uint32_t image_index) override
Inside the voxel G-buffer scope after prepare() for everything the previous pyramid did not hide.
Definition voxel_pass.cpp:880
void onTargetsRecreated()
After the G-buffer and depth targets are recreated since a new view can reuse a destroyed handle valu...
Definition voxel_pass.cpp:985
auto occlusionActive() const -> bool
The renderer then runs recordOcclusion() and a second G-buffer scope for recordLate().
Definition voxel_pass.hpp:49
void recordCellCull(vk::CommandBuffer cmd, uint32_t frame_index, vk::Extent2D scene_extent)
Outside any rendering scope after prepare() and before record().
Definition voxel_pass.cpp:582
void recordLate(vk::CommandBuffer cmd, uint32_t frame_index)
Inside a G-buffer scope that loads the early draws.
Definition voxel_pass.cpp:851
void recordQuadDepth(vk::CommandBuffer cmd, uint32_t frame_index, bool late)
Inside a depth only scope before the G-buffer scope that shades the same quads.
Definition voxel_pass.cpp:844
void recordOcclusion(vk::CommandBuffer cmd, uint32_t frame_index, vk::Extent2D scene_extent)
Outside any rendering scope with depth in depth_sampled.
Definition voxel_pass.cpp:789
void recordLighting(vk::CommandBuffer cmd, uint32_t frame_index, vk::Extent2D viewport)
Writes scene colour indirect and rounded normal while reading the G-buffer and depth.
Definition voxel_pass.cpp:921
Definition vulkan_core.hpp:48