MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ComputePress.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "ShaderFoundry.hpp"
4
6
7using ComputePipelineID = uint64_t;
8
10
11//==========================================================================
12// Multi-Pipeline Sequencing
13//==========================================================================
14
15/**
16 * @struct HazardResource
17 * @brief One resource this stage's dispatch reads/writes that a later
18 * stage in the sequence depends on, paired with its binding
19 * metadata for barrier construction.
20 *
21 * ComputePress owns no resource registry (that lives in callers like
22 * Yantra::GpuResourceManager), so the raw handle must travel with the
23 * binding description rather than being looked up by index.
24 */
26 GpuBufferBinding binding; ///< Direction/element_type describing this resource.
27 vk::Image image; ///< Valid when binding.element_type is IMAGE_STORAGE/IMAGE_SAMPLED.
28 vk::Buffer buffer; ///< Valid when binding.element_type is anything else.
29};
30
31/**
32 * @struct IndirectDispatch
33 * @brief Optional GPU-resident source of a stage's workgroup counts.
34 *
35 * The buffer holds three consecutive uint32 values {x, y, z} at offset, and
36 * must have been created with indirect usage. A null buffer means the stage
37 * dispatches its fixed counts.
38 *
39 * The counts are expected to be written by an earlier compute stage of the
40 * same sequence, or by the host before submission. Any offset may be used, so
41 * one buffer can hold the counts of several stages.
42 */
44 vk::Buffer buffer {};
45 vk::DeviceSize offset { 0 };
46};
47
48/**
49 * @struct ComputeStage
50 * @brief One pipeline dispatch within a ComputePress::record_sequence call.
51 *
52 * Bundles everything needed to bind a pipeline, push constants, dispatch,
53 * and determine the barrier owed to the next stage in the sequence.
54 * Pipeline and descriptor sets must already exist (created via
55 * create_pipeline / allocate_pipeline_descriptors) — this struct only
56 * describes how to use them within a recorded sequence, it does not
57 * own their lifetime.
58 */
60 ComputePipelineID pipeline_id; ///< Pipeline to bind for this stage.
61 std::vector<DescriptorSetID> descriptor_set_ids; ///< Descriptor sets to bind.
62 std::array<uint32_t, 3> groups; ///< Workgroup dispatch counts {x, y, z}.
63 std::vector<uint8_t> push_constant_data; ///< Raw push constant bytes for this stage.
64
65 /**
66 * @brief Resources this stage reads or writes that a subsequent
67 * stage in the same sequence depends on.
68 *
69 * Drives the compute-to-compute barrier inserted immediately after
70 * this stage's dispatch, before the next stage binds its pipeline.
71 * Only entries whose binding.direction is INPUT_OUTPUT trigger a
72 * barrier; include a resource here if a later stage must observe
73 * this stage's writes to it. Leave empty if nothing downstream
74 * depends on this stage's output within the sequence.
75 */
76 std::vector<HazardResource> hazard_resources;
77
78 /**
79 * @brief When set, the stage dispatches with counts read from this buffer
80 * and groups is ignored.
81 *
82 * record_sequence orders the read after earlier shader writes to the
83 * buffer, so the stage that produces the counts needs no hazard entry for
84 * it.
85 */
87};
88
89/**
90 * @class ComputePress
91 * @brief Compute-specific pipeline and dispatch orchestration
92 *
93 * Responsibilities:
94 * - Create compute pipelines
95 * - Bind compute pipelines
96 * - Dispatch compute workgroups (direct + indirect)
97 * - Compute-specific optimizations
98 *
99 * Uses ShaderFoundry for:
100 * - Shaders, descriptors, commands, sync, barriers
101 */
102class MAYAFLUX_API ComputePress {
103public:
105 {
106 static ComputePress press;
107 return press;
108 }
109
110 ComputePress(const ComputePress&) = delete;
112 ComputePress(ComputePress&&) noexcept = delete;
113 ComputePress& operator=(ComputePress&&) noexcept = delete;
114
115 bool initialize();
116 void stop();
117 void shutdown();
118
119 /**
120 * @brief Check if ComputePress is initialized
121 */
122 [[nodiscard]] bool is_initialized() const { return m_shader_foundry != nullptr; }
123
124 //==========================================================================
125 // Pipeline Creation (COMPUTE-SPECIFIC)
126 //==========================================================================
127
128 /**
129 * @brief Create compute pipeline
130 */
131 ComputePipelineID create_pipeline(
132 ShaderID shader_id,
133 const std::vector<std::vector<DescriptorBindingInfo>>& descriptor_sets = {},
134 size_t push_constant_size = 0);
135
136 /**
137 * @brief Create pipeline with auto-reflection
138 */
139 ComputePipelineID create_pipeline_auto(
140 ShaderID shader_id,
141 size_t push_constant_size = 0);
142
143 void destroy_pipeline(ComputePipelineID pipeline_id);
144
145 //==========================================================================
146 // Pipeline Binding (COMPUTE-SPECIFIC)
147 //==========================================================================
148
149 /**
150 * @brief Bind pipeline to active command buffer
151 */
152 void bind_pipeline(CommandBufferID cmd_id, ComputePipelineID pipeline_id);
153
154 /**
155 * @brief Bind descriptor sets to active command buffer
156 */
157 void bind_descriptor_sets(
158 CommandBufferID cmd_id,
159 ComputePipelineID pipeline_id,
160 const std::vector<DescriptorSetID>& descriptor_set_ids);
161
162 /**
163 * @brief Push constants to active command buffer
164 */
165 void push_constants(
166 CommandBufferID cmd_id,
167 ComputePipelineID pipeline_id,
168 const void* data,
169 size_t size);
170
171 /**
172 * @brief Push part of the push constant block, starting at a byte offset
173 * @param offset Byte offset into the block
174 *
175 * The range [offset, offset + size) must lie inside the push constant size
176 * the pipeline was created with; otherwise nothing is recorded.
177 */
178 void push_constants(
179 CommandBufferID cmd_id,
180 ComputePipelineID pipeline_id,
181 const void* data,
182 size_t size,
183 uint32_t offset);
184
185 //==========================================================================
186 // Dispatch (COMPUTE-SPECIFIC)
187 //==========================================================================
188
189 /**
190 * @brief Dispatch compute workgroups
191 */
192 void dispatch(CommandBufferID cmd_id, uint32_t x, uint32_t y, uint32_t z);
193
194 /**
195 * @brief Dispatch compute workgroups indirectly
196 */
197 void dispatch_indirect(
198 CommandBufferID cmd_id,
199 vk::Buffer indirect_buffer,
200 vk::DeviceSize offset = 0);
201
202 //==========================================================================
203 // Convenience Wrappers
204 //==========================================================================
205
206 /**
207 * @brief All-in-one: allocate descriptors for pipeline
208 */
209 std::vector<DescriptorSetID> allocate_pipeline_descriptors(ComputePipelineID pipeline_id);
210
211 /**
212 * @brief All-in-one: bind pipeline + descriptors + push constants
213 */
214 void bind_all(
215 CommandBufferID cmd_id,
216 ComputePipelineID pipeline_id,
217 const std::vector<DescriptorSetID>& descriptor_set_ids,
218 const void* push_constants_data = nullptr,
219 size_t push_constant_size = 0);
220
221 /**
222 * @brief Record multiple pipeline dispatches into one already-open
223 * command buffer, inserting a barrier between each consecutive
224 * stage for that stage's hazard_bindings.
225 *
226 * Vulkan permits binding different pipelines sequentially within a
227 * single command buffer recording — this is not a render-pass-style
228 * batching mechanism, only direct multi-pipeline recording plus the
229 * hazard barriers each transition needs. Does not submit; caller owns
230 * the command buffer's lifetime via ShaderFoundry (begin_commands /
231 * submit_and_wait or submit_async), the same as any other recorded
232 * sequence of commands.
233 *
234 * Image bindings receive an eGeneral -> eGeneral shader write/read
235 * hazard barrier via ShaderFoundry::image_barrier. Non-image bindings
236 * receive a buffer_barrier with the same access/stage masks. Both use
237 * compute-to-compute pipeline stages throughout, since this method is
238 * for chaining compute stages only.
239 *
240 * @param cmd_id Command buffer to record into. Must already be active
241 * (begun via ShaderFoundry::begin_commands).
242 * @param stages Ordered list of pipeline dispatches to record.
243 */
244 void record_sequence(CommandBufferID cmd_id, const std::vector<ComputeStage>& stages);
245
246private:
247 ComputePress() = default;
248 ~ComputePress() { shutdown(); }
249 void cleanup_pipelines();
250
253 std::shared_ptr<Core::VKComputePipeline> pipeline;
254 std::vector<vk::DescriptorSetLayout> layouts;
255 vk::PipelineLayout layout;
256 size_t push_constant_size {};
257 };
258
259 std::shared_ptr<Core::VKDescriptorManager> m_descriptor_manager;
260 std::unordered_map<ComputePipelineID, PipelineState> m_pipelines;
261 std::atomic<uint64_t> m_next_pipeline_id { 1 };
262 ShaderFoundry* m_shader_foundry = nullptr;
263
264 static bool s_initialized;
265};
266
267inline MAYAFLUX_API ComputePress& get_compute_press()
268{
269 return ComputePress::instance();
270}
271
272} // namespace MayaFlux::Portal::Graphics
uint64_t offset
Definition Composite.cpp:10
bool size
ComputePress & operator=(const ComputePress &)=delete
ComputePress(ComputePress &&) noexcept=delete
std::unordered_map< ComputePipelineID, PipelineState > m_pipelines
ComputePress(const ComputePress &)=delete
std::shared_ptr< Core::VKDescriptorManager > m_descriptor_manager
Compute-specific pipeline and dispatch orchestration.
Portal-level shader compilation and caching.
void initialize()
Definition main.cpp:10
constexpr ComputePipelineID INVALID_COMPUTE_PIPELINE
MAYAFLUX_API ComputePress & get_compute_press()
std::vector< vk::DescriptorSetLayout > layouts
std::shared_ptr< Core::VKComputePipeline > pipeline
ComputePipelineID pipeline_id
Pipeline to bind for this stage.
std::vector< uint8_t > push_constant_data
Raw push constant bytes for this stage.
IndirectDispatch indirect
When set, the stage dispatches with counts read from this buffer and groups is ignored.
std::array< uint32_t, 3 > groups
Workgroup dispatch counts {x, y, z}.
std::vector< DescriptorSetID > descriptor_set_ids
Descriptor sets to bind.
std::vector< HazardResource > hazard_resources
Resources this stage reads or writes that a subsequent stage in the same sequence depends on.
One pipeline dispatch within a ComputePress::record_sequence call.
Declares a single storage buffer or image binding a compute shader expects.
vk::Buffer buffer
Valid when binding.element_type is anything else.
vk::Image image
Valid when binding.element_type is IMAGE_STORAGE/IMAGE_SAMPLED.
GpuBufferBinding binding
Direction/element_type describing this resource.
One resource this stage's dispatch reads/writes that a later stage in the sequence depends on,...
Optional GPU-resident source of a stage's workgroup counts.