MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GpuResourceManager.hpp
Go to the documentation of this file.
1#pragma once
2
5
6namespace MayaFlux::Yantra {
7
10
12
13/**
14 * @class GpuResourceManager
15 * @brief Encapsulates all Vulkan resource lifecycle behind Portal facades.
16 *
17 * Manages a keyed set of pipelines, each with its own storage buffers,
18 * pipeline, shader, and descriptor sets. There is no distinct single-
19 * pipeline mode: a caller using exactly one shader simply uses one key
20 * throughout. PIMPL hides vk:: types from the header entirely.
21 */
22class MAYAFLUX_API GpuResourceManager {
23public:
26
31
32 /**
33 * @brief Create (or confirm existing) pipeline for the given key.
34 *
35 * Create-if-absent: if a unit already exists and is ready for this
36 * key, returns true immediately without recreating anything. Call
37 * release(key) first to force recreation with a different config.
38 */
39 bool initialise(const std::string& key,
40 const GpuComputeConfig& config,
41 const std::vector<GpuBufferBinding>& bindings);
42
43 void ensure_buffer(const std::string& key, size_t index, size_t required_bytes,
44 Portal::Graphics::BufferUsageHint usage_hint = Portal::Graphics::BufferUsageHint::COMPUTE_STORAGE);
45 void upload(const std::string& key, size_t index, const float* data, size_t byte_size);
46 void upload_raw(const std::string& key, size_t index, const uint8_t* data, size_t byte_size);
47 void download(const std::string& key, size_t index, float* dest, size_t byte_size);
48 void bind_descriptor(const std::string& key, size_t index, const GpuBufferBinding& spec);
49
50 /**
51 * @brief Bind every non-image buffer binding in one Vulkan call.
52 *
53 * Equivalent to calling bind_descriptor or bind_shared_descriptor once
54 * per non-image entry in bindings (routed the same way, by whether a
55 * shared slot exists at that (set, binding)), except every entry is
56 * submitted through a single vkUpdateDescriptorSets call. Image entries
57 * are skipped, matching bind_all_descriptors' existing split between
58 * buffer descriptors here and image descriptors bound separately per
59 * staged image.
60 */
61 void bind_descriptors_batch(const std::string& key, const std::vector<GpuBufferBinding>& bindings);
62
63 void ensure_shared_buffer(uint32_t set, size_t binding_index, size_t element_count,
65 Portal::Graphics::BufferUsageHint usage_hint = Portal::Graphics::BufferUsageHint::COMPUTE_STORAGE);
66
67 /**
68 * @brief Non-owning view of the shared buffer at (set, binding_index).
69 *
70 * The manager keeps ownership. A null handle is returned when no such
71 * buffer exists, and the view is invalidated if ensure_shared_buffer later
72 * grows the slot.
73 */
74 [[nodiscard]] Portal::Graphics::GpuBufferHandle shared_buffer_handle(uint32_t set, size_t binding_index) const;
75 void bind_shared_descriptor(const std::string& key, uint32_t set, size_t binding_index, const GpuBufferBinding& spec);
76 void download_shared(uint32_t set, size_t binding_index, void* dest, size_t byte_size);
77 void upload_shared_raw(uint32_t set, size_t binding_index, const uint8_t* data, size_t byte_size);
78
79 [[nodiscard]] Portal::Graphics::HazardResource make_shared_buffer_hazard(
80 const GpuBufferBinding& spec) const;
81
82 /**
83 * @brief Bind a storage image descriptor at the given slot index.
84 * @param key Pipeline unit to bind into.
85 * @param index Slot index matching the binding declaration.
86 * @param image VKImage to bind. Must be initialised and in eGeneral layout.
87 * @param spec Binding declaration. element_type must be IMAGE_STORAGE.
88 */
89 void bind_image_storage(const std::string& key, size_t index,
90 const std::shared_ptr<Core::VKImage>& image,
91 const GpuBufferBinding& spec);
92
93 /**
94 * @brief Bind a combined image+sampler descriptor at the given slot index.
95 * @param key Pipeline unit to bind into.
96 * @param index Slot index matching the binding declaration.
97 * @param image VKImage to bind. Must be in eShaderReadOnlyOptimal layout.
98 * @param sampler Vulkan sampler handle from SamplerForge.
99 * @param spec Binding declaration. element_type must be IMAGE_SAMPLED.
100 */
101 void bind_image_sampled(const std::string& key, size_t index,
102 const std::shared_ptr<Core::VKImage>& image,
103 vk::Sampler sampler,
104 const GpuBufferBinding& spec);
105
106 /**
107 * @brief One image slot for bind_images_batch: a storage image entry
108 * leaves sampler null.
109 */
110 struct ImageBind {
111 size_t index;
112 std::shared_ptr<Core::VKImage> image;
113 vk::Sampler sampler;
115 };
116
117 /**
118 * @brief Bind every image in one Vulkan call.
119 *
120 * Equivalent to calling bind_image_storage or bind_image_sampled once
121 * per entry (routed by spec.element_type), except every entry is
122 * submitted through a single vkUpdateDescriptorSets call. Also records
123 * each image in the pipeline unit's image_slots, same as the per-call
124 * methods.
125 */
126 void bind_images_batch(const std::string& key, const std::vector<ImageBind>& images);
127
128 /**
129 * @brief Transition a VKImage layout via an immediate command submission.
130 *
131 * Not tied to any pipeline unit; operates on the image directly.
132 * @param image Image to transition.
133 * @param old_layout Source layout.
134 * @param new_layout Target layout.
135 */
136 void transition_image(const std::shared_ptr<Core::VKImage>& image,
137 vk::ImageLayout old_layout,
138 vk::ImageLayout new_layout);
139
140 void dispatch(const std::string& key,
141 const std::array<uint32_t, 3>& groups,
142 const std::vector<GpuBufferBinding>& bindings,
143 const uint8_t* push_constant_data,
144 size_t push_constant_size);
145
146 void dispatch_batched(const std::string& key,
147 const std::array<uint32_t, 3>& groups,
148 const std::vector<GpuBufferBinding>& bindings,
149 size_t push_constant_size,
150 const ExecutionContext& ctx);
151
152 void dispatch_batched_indirect(const std::string& key,
153 uint32_t indirect_set, size_t indirect_binding,
154 const std::array<uint32_t, 3>& groups,
155 const std::vector<GpuBufferBinding>& bindings,
156 size_t push_constant_size,
157 const ExecutionContext& ctx);
158
159 /**
160 * @brief Submit a compute dispatch without blocking.
161 *
162 * Records the same command sequence as dispatch() but submits via
163 * ShaderFoundry::submit_async instead of submit_and_wait. Returns a
164 * FenceID immediately. Readback must be deferred until
165 * ShaderFoundry::is_fence_signaled returns true for the returned ID.
166 *
167 * @param key Pipeline unit to dispatch.
168 * @param groups Workgroup counts {x, y, z}.
169 * @param bindings Binding declarations; output barriers inserted.
170 * @param push_constant_data Pointer to push constant bytes, or nullptr.
171 * @param push_constant_size Byte count of push constant data.
172 * @return FenceID to poll with ShaderFoundry::is_fence_signaled.
173 * Returns INVALID_FENCE if not ready or submission fails.
174 */
175 [[nodiscard]] Portal::Graphics::FenceID dispatch_async(const std::string& key,
176 const std::array<uint32_t, 3>& groups,
177 const std::vector<GpuBufferBinding>& bindings,
178 const uint8_t* push_constant_data,
179 size_t push_constant_size);
180
181 /**
182 * @brief Record a dispatch for each requested key into one command
183 * buffer via ComputePress::record_sequence, submitted once.
184 *
185 * Each key must already be initialise()'d. Vectors are parallel,
186 * indexed by position, one entry per key in the same order as keys.
187 * indirect_per_key is either empty or parallel too; a stage whose entry
188 * has a buffer dispatches with the counts stored there instead of its
189 * fixed groups.
190 */
191 void dispatch_sequence(
192 const std::vector<std::string>& keys,
193 const std::vector<std::array<uint32_t, 3>>& groups_per_key,
194 const std::vector<std::vector<uint8_t>>& push_constants_per_key,
195 const std::vector<std::vector<Portal::Graphics::HazardResource>>& hazards_per_key,
196 const std::vector<Portal::Graphics::IndirectDispatch>& indirect_per_key = {});
197
198 /**
199 * @brief Non-blocking counterpart of dispatch_sequence.
200 *
201 * Records the identical command buffer and submits it via
202 * ShaderFoundry::submit_async instead of submit_and_wait. Barriers owed to
203 * each stage's hazards are recorded as in dispatch_sequence, including the
204 * one after the final stage, so a caller that does not await the fence
205 * still gets the trailing dependency for anything submitted later.
206 *
207 * Like dispatch_sequence, and unlike dispatch_async, no shader-write to
208 * host-read barrier is recorded. Host reads after the fence has signaled
209 * rely on the fence's own visibility guarantee and on the buffers being
210 * host coherent.
211 *
212 * @return FenceID to poll with ShaderFoundry::is_fence_signaled and to
213 * release once signaled.
214 */
215 [[nodiscard]] Portal::Graphics::FenceID dispatch_sequence_async(
216 const std::vector<std::string>& keys,
217 const std::vector<std::array<uint32_t, 3>>& groups_per_key,
218 const std::vector<std::vector<uint8_t>>& push_constants_per_key,
219 const std::vector<std::vector<Portal::Graphics::HazardResource>>& hazards_per_key,
220 const std::vector<Portal::Graphics::IndirectDispatch>& indirect_per_key = {});
221
222 /**
223 * @brief Destroy the pipeline, shader, descriptor sets, and buffers
224 * for a single key, without affecting any other key.
225 */
226 void release(const std::string& key);
227
228 /**
229 * @brief Destroy every key currently held. Called from the destructor.
230 */
231 void cleanup();
232
233 [[nodiscard]] bool is_ready(const std::string& key) const;
234 [[nodiscard]] size_t buffer_allocated_bytes(const std::string& key, size_t index) const;
235
236private:
238 Portal::Graphics::ShaderID shader_id { Portal::Graphics::INVALID_SHADER };
239 Portal::Graphics::ComputePipelineID pipeline_id { Portal::Graphics::INVALID_COMPUTE_PIPELINE };
240 std::vector<Portal::Graphics::DescriptorSetID> descriptor_set_ids;
241
242 std::unique_ptr<GpuResourceManagerImpl> impl;
243
244 struct BufferSlot {
245 size_t allocated_bytes {};
246 };
247 std::vector<BufferSlot> buffer_slots;
248 std::vector<std::shared_ptr<Core::VKImage>> image_slots;
249
250 bool ready {};
251 };
252
253 /**
254 * @brief Record one command buffer holding a dispatch per key, with the
255 * barriers each stage's hazards owe the next.
256 *
257 * Shared by dispatch_sequence and dispatch_sequence_async, which differ
258 * only in how they submit the returned buffer.
259 */
260 [[nodiscard]] Portal::Graphics::CommandBufferID record_sequence_commands(
261 const std::vector<std::string>& keys,
262 const std::vector<std::array<uint32_t, 3>>& groups_per_key,
263 const std::vector<std::vector<uint8_t>>& push_constants_per_key,
264 const std::vector<std::vector<Portal::Graphics::HazardResource>>& hazards_per_key,
265 const std::vector<Portal::Graphics::IndirectDispatch>& indirect_per_key);
266
267 struct SharedBuffers;
268 std::unique_ptr<SharedBuffers> m_shared;
269
270 [[nodiscard]] PipelineUnit& unit_for(const std::string& key);
271 [[nodiscard]] const PipelineUnit* find_unit(const std::string& key) const;
272
273 std::unordered_map<std::string, std::unique_ptr<PipelineUnit>> m_units;
274}; // class GpuResourceManager
275
276} // namespace MayaFlux::Yantra
IO::ImageData image
Definition Decoder.cpp:47
uint32_t index
Definition VKDevice.cpp:122
GpuResourceManager & operator=(GpuResourceManager &&)=delete
std::unique_ptr< SharedBuffers > m_shared
GpuResourceManager(GpuResourceManager &&)=delete
GpuResourceManager & operator=(const GpuResourceManager &)=delete
std::unordered_map< std::string, std::unique_ptr< PipelineUnit > > m_units
GpuResourceManager(const GpuResourceManager &)=delete
Encapsulates all Vulkan resource lifecycle behind Portal facades.
BufferUsageHint
Semantic usage hint for buffer allocation and memory properties.
ElementType
Element type the shader expects in this binding.
Declares a single storage buffer or image binding a compute shader expects.
Non-owning view of a GPU storage buffer produced by a compute path.
Plain-data description of the compute shader to dispatch.
One resource this stage's dispatch reads/writes that a later stage in the sequence depends on,...
Context information controlling how a compute operation executes.
One image slot for bind_images_batch: a storage image entry leaves sampler null.
std::vector< Portal::Graphics::DescriptorSetID > descriptor_set_ids
std::unique_ptr< GpuResourceManagerImpl > impl
std::vector< std::shared_ptr< Core::VKImage > > image_slots