MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VKBuffer.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Buffer.hpp"
4
6
8
10struct BufferService;
11struct ComputeService;
12}
13
14namespace MayaFlux::Core {
15class Window;
16}
17
18namespace MayaFlux::Buffers {
19
20class RenderProcessor;
21struct ShaderConfig;
22
23/**
24 * @struct VKBufferResources
25 * @brief Raw Vulkan handles owned by a VKBuffer instance.
26 *
27 * The index_buffer / index_memory / index_size_bytes fields are populated
28 * by GeometryBindingsProcessor after index data upload and consumed by
29 * RenderProcessor to select the indexed draw path. They are null/zero for
30 * all non-indexed geometry; no separate allocation object is required.
31 * back_buffers are reserved for double-buffered or N-buffered ping-pong state or
32 * other auxiliary buffers owned by a VKBuffer subclass. They are empty when unused.
33 */
35 vk::Buffer buffer;
36 vk::DeviceMemory memory;
37 void* mapped_ptr { nullptr };
38
39 vk::Buffer index_buffer;
40 vk::DeviceMemory index_memory;
41 size_t index_size_bytes { 0 };
42
44 vk::Buffer buffer { VK_NULL_HANDLE };
45 vk::DeviceMemory memory { VK_NULL_HANDLE };
46 void* mapped_ptr { nullptr };
47 };
48 std::vector<GenerationSlot> back_buffers;
49};
50
51using RenderPipelineID = uint64_t;
52using CommandBufferID = uint64_t;
53
54/**
55 * @class VKBuffer
56 * @brief Vulkan-backed buffer wrapper used in processing chains
57 *
58 * VKBuffer is a lightweight, high-level representation of a GPU buffer used by
59 * the MayaFlux processing pipeline. It carries semantic metadata (Kakshya
60 * modalities and dimensions), integrates with the Buffer processing chain and
61 * BufferManager, and exposes Vulkan handles once the backend registers the
62 * buffer. Prior to registration the object contains no GPU resources and can
63 * be manipulated cheaply (like AudioBuffer).
64 *
65 * Responsibilities:
66 * - Store buffer size, usage intent and semantic modality
67 * - Provide inferred data dimensions for processors and pipeline inspection
68 * - Hold Vulkan handles (VkBuffer, VkDeviceMemory) assigned by graphics backend
69 * - Provide convenience helpers for common Vulkan creation flags and memory props
70 * - Integrate with BufferProcessor / BufferProcessingChain for default processing
71 *
72 * Note: Actual allocation, mapping and command-based transfers are performed by
73 * the graphics backend / BufferManager. VKBuffer only stores handles and
74 * metadata and provides helpers for processors to operate on it.
75 */
76class MAYAFLUX_API VKBuffer : public Buffer {
77public:
79
81
82 /**
83 * @brief Context shared with BufferProcessors during pipeline execution
84 *
85 * Processors can use this struct to share data (e.g., push constant staging)
86 * and metadata during processing of this buffer in a chain.
87 */
89 std::vector<Portal::Graphics::PushConstantBindingInfo> push_constant_bindings;
90
91 std::vector<Portal::Graphics::DescriptorBindingInfo> descriptor_buffer_bindings;
92
93 std::unordered_map<std::string, std::any> metadata;
94 };
95
96 /**
97 * @brief Engine-internal per-frame binding state
98 *
99 * Carries descriptor bindings written by engine processors (e.g.
100 * MeshNetworkProcessor SSBOs) that must reach RenderProcessor::execute_shader
101 * without passing through the user-facing PipelineContext. Access is
102 * unrestricted by convention only: engine processors write here, user code
103 * should not.
104 */
106 std::vector<Portal::Graphics::DescriptorBindingInfo> ssbo_bindings;
107 };
108
109 /**
110 * @brief Construct an unregistered VKBuffer
111 *
112 * Creates a VKBuffer object with the requested capacity, usage intent and
113 * semantic modality. No Vulkan resources are created by this constructor —
114 * registration with the BufferManager / backend is required to allocate
115 * VkBuffer and VkDeviceMemory.
116 *
117 * @param size_bytes Buffer capacity in bytes.
118 * @param usage Intended usage pattern (affects Vulkan flags and memory).
119 * @param modality Semantic interpretation of the buffer contents.
120 */
121 VKBuffer(
122 size_t size_bytes,
123 Usage usage,
124 Kakshya::DataModality modality = Kakshya::DataModality::VERTICES_3D);
125
126 VKBuffer() = default;
127
128 /**
129 * @brief Virtual destructor
130 *
131 * VKBuffer does not own Vulkan resources directly; cleanup is handled by
132 * the backend during unregistration. The destructor ensures derived class
133 * cleanup and safe destruction semantics.
134 */
135 ~VKBuffer() override;
136
137 /**
138 * @brief Get the Vulkan device address for this buffer (if applicable)
139 * @return 64-bit device address, or 0 if not BDA-capable or not initialized
140 *
141 * Only buffers created with Usage::UNIFORM_BDA or Usage::STORAGE_BDA and
142 * registered with the backend will return a valid device address. This is
143 * used by processors that need to bind buffers via device address (e.g.,
144 * for ray tracing or bindless access).
145 */
146 [[nodiscard]] uint64_t get_device_address() const;
147
148 /**
149 * @brief Clear buffer contents
150 *
151 * Zeroes the contents in place. Mapped buffers are cleared on the host;
152 * unmapped (device-local) buffers are cleared on the GPU and the call
153 * blocks until the fill completes. Handles and addresses are unchanged.
154 * Requires the buffer to be registered and, when unmapped, to have been
155 * created with transfer destination usage.
156 */
157 void clear() override;
158
159 /**
160 * @brief Read buffer contents as Kakshya DataVariant
161 *
162 * For host-visible buffers this returns a single DataVariant containing the
163 * raw bytes. For device-local buffers this warns and returns empty — a
164 * BufferDownloadProcessor should be used to read GPU-only memory.
165 *
166 * @return Vector of DataVariant objects representing buffer contents.
167 */
168 std::vector<Kakshya::DataVariant> get_data();
169
170 /**
171 * @brief Write data into the buffer
172 *
173 * If the buffer is host-visible and mapped the provided data is copied into
174 * the mapped memory. For device-local buffers, a BufferUploadProcessor must
175 * be present in the processing chain to perform the staging/upload.
176 *
177 * @param data Vector of Kakshya::DataVariant containing the payload to copy.
178 */
179 void set_data(const std::vector<Kakshya::DataVariant>& data);
180
181 /**
182 * @brief Resize buffer and recreate GPU resources if needed
183 * @param new_size New size in bytes
184 * @param preserve_data If true, copy existing data to new buffer
185 *
186 * If buffer is already initialized (has GPU resources), this will:
187 * 1. Create new GPU buffer with new size
188 * 2. Optionally copy old data
189 * 3. Destroy old GPU buffer
190 * 4. Update buffer resources
191 *
192 * If buffer is not initialized, just updates logical size.
193 */
194 void resize(size_t new_size, bool preserve_data = false);
195
196 /**
197 * @brief Get current logical size in bytes
198 * @return Buffer size in bytes.
199 */
200 size_t get_size() const { return m_size_bytes; }
201
202 /**
203 * @brief Run the buffer's default processor (if set and enabled)
204 *
205 * Invokes the attached default BufferProcessor. Processors should be
206 * prepared to handle mapped/unmapped memory according to buffer usage.
207 */
208 void process_default() override;
209
210 /**
211 * @brief Set the buffer's default processor
212 *
213 * Attaches a processor that will be invoked by process_default(). The
214 * previous default processor (if any) is detached first.
215 *
216 * @param processor Shared pointer to a BufferProcessor or nullptr to clear.
217 */
218 void set_default_processor(const std::shared_ptr<BufferProcessor>& processor) override;
219
220 /**
221 * @brief Get the currently attached default processor
222 * @return Shared pointer to the default BufferProcessor or nullptr.
223 */
224 std::shared_ptr<Buffers::BufferProcessor> get_default_processor() const override;
225
226 /**
227 * @brief Access the buffer's processing chain
228 * @return Shared pointer to the BufferProcessingChain used for this buffer.
229 */
230 std::shared_ptr<Buffers::BufferProcessingChain> get_processing_chain() override;
231
232 /**
233 * @brief Replace the buffer's processing chain
234 * @param chain New processing chain to assign.
235 * @param force If true, replaces existing chain even if one is set.
236 */
237 void set_processing_chain(const std::shared_ptr<BufferProcessingChain>& chain, bool force = false) override;
238
239 bool has_data_for_cycle() const override { return m_has_data; }
240 bool needs_removal() const override { return m_needs_removal; }
241 void mark_for_processing(bool has_data) override { m_has_data = has_data; }
242 void mark_for_removal() override { m_needs_removal = true; }
243 void enforce_default_processing(bool should_process) override { m_process_default = should_process; }
244 bool needs_default_processing() override { return m_process_default; }
245
246 /**
247 * @brief Try to acquire processing lock for this buffer
248 * @return True if lock acquired, false if already processing.
249 *
250 * Uses an atomic flag to guard concurrent processing attempts.
251 */
252 inline bool try_acquire_processing() override
253 {
254 bool expected = false;
255 return m_is_processing.compare_exchange_strong(expected, true,
256 std::memory_order_acquire, std::memory_order_relaxed);
257 }
258
259 /**
260 * @brief Release previously acquired processing lock
261 */
262 inline void release_processing() override
263 {
264 m_is_processing.store(false, std::memory_order_release);
265 }
266
267 /**
268 * @brief Query whether the buffer is currently being processed
269 * @return True if a processing operation holds the lock.
270 */
271 inline bool is_processing() const override
272 {
273 return m_is_processing.load(std::memory_order_acquire);
274 }
275
276 /** Get VkBuffer handle (VK_NULL_HANDLE if not registered) */
277 vk::Buffer& get_buffer() { return m_resources.buffer; }
278
279 /* Get logical buffer size as VkDeviceSize */
280 vk::DeviceSize get_size_bytes() const { return m_size_bytes; }
281
282 /** Check whether Vulkan handles are present (buffer registered) */
283 bool is_initialized() const { return m_resources.buffer != VK_NULL_HANDLE; }
284
285 /**
286 * @brief Setup processors with a processing token
287 * @param token ProcessingToken to assign.
288 *
289 * For VKBuffer this is a no-op as processors get the token.
290 * This is meant for derived classes that need to setup default processors
291 */
292 virtual void setup_processors(ProcessingToken token) { }
293
294 /** Get the buffer's semantic modality */
295 Kakshya::DataModality get_modality() const { return m_modality; }
296
297 /** Get the inferred data dimensions for the buffer contents */
298 const std::vector<Kakshya::DataDimension>& get_dimensions() const { return m_dimensions; }
299
300 /**
301 * @brief Update the semantic modality and re-infer dimensions
302 * @param modality New Kakshya::DataModality to apply.
303 */
304 void set_modality(Kakshya::DataModality modality);
305
306 /** Retrieve the declared usage intent */
307 Usage get_usage() const { return m_usage; }
308
309 /** Set VkBuffer handle after backend allocation */
310 void set_buffer(vk::Buffer buffer) { m_resources.buffer = buffer; }
311
312 /** Set device memory handle after backend allocation */
313 void set_memory(vk::DeviceMemory memory) { m_resources.memory = memory; }
314
315 /** Set mapped host pointer (for host-visible allocations) */
316 void set_mapped_ptr(void* ptr) { m_resources.mapped_ptr = ptr; }
317
318 /** Set all buffer resources at once */
319 inline void set_buffer_resources(const VKBufferResources& resources)
320 {
321 m_resources = resources;
322 }
323
324 /**
325 * @brief Store raw index buffer handles produced by the geometry upload path.
326 *
327 * Called by GeometryBindingsProcessor after allocating and uploading index
328 * data. Overwrites any previously stored handles. Pass null handles and
329 * zero size to clear (non-indexed geometry).
330 *
331 * @param buf Allocated vk::Buffer with INDEX usage flags.
332 * @param mem Backing vk::DeviceMemory.
333 * @param size Byte size of the index buffer.
334 */
335 void set_index_resources(vk::Buffer buf, vk::DeviceMemory mem, size_t size)
336 {
337 m_resources.index_buffer = buf;
338 m_resources.index_memory = mem;
339 m_resources.index_size_bytes = size;
340 }
341
342 /** Get all buffer resources at once (read-only) */
343 inline const VKBufferResources& get_buffer_resources() const { return m_resources; }
344
345 /** Get all buffer resources at once (mutable). */
346 inline VKBufferResources& get_buffer_resources() { return m_resources; }
347
348 /**
349 * @brief Return the raw index buffer handle.
350 * @return vk::Buffer; operator bool() returns false when non-indexed.
351 */
352 [[nodiscard]] vk::Buffer get_index_buffer() const { return m_resources.index_buffer; }
353
354 /**
355 * @brief Number of bytes in the index buffer.
356 * @return Byte count; divide by sizeof(uint32_t) for index count.
357 * Zero when non-indexed.
358 */
359 [[nodiscard]] size_t get_index_buffer_size() const { return m_resources.index_size_bytes; }
360
361 /**
362 * @brief True when an index buffer has been associated with this buffer.
363 */
364 [[nodiscard]] bool has_index_buffer() const
365 {
366 return static_cast<bool>(m_resources.index_buffer);
367 }
368
369 /**
370 * @brief Whether this VKBuffer should be host-visible
371 * @return True for staging or uniform buffers, false for device-local types.
372 */
373 bool is_host_visible() const
374 {
375 return m_usage == Usage::STAGING
376 || m_usage == Usage::UNIFORM
377 || m_usage == Usage::UNIFORM_BDA
378 || m_usage == Usage::STORAGE_BDA
379 || m_usage == Usage::HOST_STORAGE;
380 }
381
382 /**
383 * @brief Get appropriate VkBufferUsageFlags for creation based on Usage
384 * @return VkBufferUsageFlags to be used when creating VkBuffer.
385 */
386 vk::BufferUsageFlags get_usage_flags() const;
387
388 /**
389 * @brief Get appropriate VkMemoryPropertyFlags for allocation based on Usage
390 * @return VkMemoryPropertyFlags to request during memory allocation.
391 */
392 vk::MemoryPropertyFlags get_memory_properties() const;
393
394 /** Get mapped host pointer (nullptr if not host-visible or unmapped) */
395 void* get_mapped_ptr() const { return m_resources.mapped_ptr; }
396
397 /** Get device memory handle */
398 void mark_dirty_range(size_t offset, size_t size);
399
400 /** Mark a range as invalid (needs download) */
401 void mark_invalid_range(size_t offset, size_t size);
402
403 /** Retrieve and clear all dirty ranges */
404 std::vector<std::pair<size_t, size_t>> get_and_clear_dirty_ranges();
405
406 /** Retrieve and clear all invalid ranges */
407 std::vector<std::pair<size_t, size_t>> get_and_clear_invalid_ranges();
408
409 /**
410 * @brief Associate this buffer with a window for rendering
411 * @param window Target window for rendering this buffer's content
412 *
413 * When this buffer is processed, its content will be rendered to the associated window.
414 * Currently supports one window per buffer (will be extended to multiple windows).
415 */
416 void set_pipeline_window(RenderPipelineID id, const std::shared_ptr<Core::Window>& window)
417 {
418 m_window_pipelines[id] = window;
419 }
420
421 /** @brief Withdraw one pipeline and request presentation of its former window. */
423 {
424 if (auto window = get_pipeline_window(id))
425 request_presentation_refresh(window);
426 m_window_pipelines.erase(id);
427 m_pipeline_commands.erase(id);
428 }
429
430 /** @brief Queue a composition change independently of buffer processing. */
431 void request_presentation_refresh(const std::shared_ptr<Core::Window>& window)
432 {
433 if (window)
434 m_pending_presentation_refreshes.insert(window);
435 }
436
437 /** @brief Transfer pending composition changes to the owning graphics root. */
438 std::unordered_set<std::shared_ptr<Core::Window>> take_presentation_refreshes()
439 {
440 return std::exchange(m_pending_presentation_refreshes, {});
441 }
442
443 /**
444 * @brief Get the window associated with this buffer
445 * @return Target window, or nullptr if not set
446 */
447 std::shared_ptr<Core::Window> get_pipeline_window(RenderPipelineID id) const
448 {
449 auto it = m_window_pipelines.find(id);
450 if (it != m_window_pipelines.end()) {
451 return it->second;
452 }
453 return nullptr;
454 }
455
456 /**
457 * @brief Check if this buffer has a rendering pipeline configured
458 */
460 {
461 return !m_window_pipelines.empty();
462 }
463
464 /**
465 * @brief Get all render pipelines associated with this buffer
466 * @return Map of RenderPipelineID to associated windows
467 */
468 std::unordered_map<RenderPipelineID, std::shared_ptr<Core::Window>> get_render_pipelines() const
469 {
470 return m_window_pipelines;
471 }
472
473 /**
474 * @brief Store recorded command buffer for a pipeline
475 */
477 CommandBufferID cmd_id)
478 {
479 m_pipeline_commands[pipeline_id] = cmd_id;
480 }
481
482 /**
483 * @brief Get recorded command buffer for a pipeline
484 */
486 {
487 auto it = m_pipeline_commands.find(pipeline_id);
488 return it != m_pipeline_commands.end() ? it->second : 0;
489 }
490
491 /**
492 * @brief Clear all recorded commands (called after presentation)
493 */
495 {
496 m_pipeline_commands.clear();
497 }
498
499 /**
500 * @brief Set vertex layout for this buffer
501 *
502 * Required before using buffer with graphics rendering.
503 * Describes how to interpret buffer data as vertices.
504 *
505 * @param layout VertexLayout describing vertex structure
506 */
507 void set_vertex_layout(const Kakshya::VertexLayout& layout);
508
509 /**
510 * @brief Get vertex layout if set
511 * @return Optional containing layout, or empty if not set
512 */
513 std::optional<Kakshya::VertexLayout> get_vertex_layout() const { return m_vertex_layout; }
514
515 /**
516 * @brief Check if this buffer has vertex layout configured
517 */
518 bool has_vertex_layout() const { return m_vertex_layout.has_value(); }
519
520 /**
521 * @brief Clear vertex layout
522 */
524 {
525 m_vertex_layout.reset();
526 }
527
528 std::shared_ptr<Buffer> clone_to(uint8_t dest_desc) override;
529
530 /**
531 * @brief Create a clone of this buffer with the same data and properties
532 * @param usage Usage enum for the cloned buffer
533 * @return Shared pointer to the cloned VKBuffer
534 *
535 * The cloned buffer will have the same size, modality, dimensions,
536 * processing chain and default processor as the original. Changes to
537 * one buffer after cloning do not affect the other.
538 */
539 std::shared_ptr<VKBuffer> clone_to(Usage usage);
540
541 /** Set whether this buffer is for internal engine usage */
542 void force_internal_usage(bool internal) override { m_internal_usage = internal; }
543
544 /** Check whether this buffer is for internal engine usage */
545 bool is_internal_only() const override { return m_internal_usage; }
546
547 /** Access the pipeline context for custom metadata (non-const) */
548 PipelineContext& get_pipeline_context() { return m_pipeline_context; }
549
550 /** Access the pipeline context for custom metadata (const) */
551 const PipelineContext& get_pipeline_context() const { return m_pipeline_context; }
552
553 [[nodiscard]] EngineContext& get_engine_context() { return m_engine_context; }
554 [[nodiscard]] const EngineContext& get_engine_context() const { return m_engine_context; }
555
556 /**
557 * @brief Mark config as changed (processors will detect and react)
558 * @param is_dirty Whether the config is now dirty (default: true)
559 * NOTE: Child classes override this to call their internal setup_rendering() with the new config, which may have additional side effects.
560 */
561 virtual void mark_render_config_dirty(bool is_dirty = true) { m_render_config_dirty = is_dirty; }
562
563 /**
564 * @brief Check if config has changed since last frame
565 */
566 [[nodiscard]] bool is_render_config_dirty() const { return m_render_config_dirty; }
567
568 /**
569 * @brief Get the current render configuration
570 * @return RenderConfig struct with current settings
571 */
572 RenderConfig get_render_config() const { return m_render_config; }
573
574 /**
575 * @brief Update the render configuration and mark as dirty
576 * @param config New RenderConfig to apply
577 *
578 * This will update the buffer's render configuration and set the dirty flag,
579 * signaling to any RenderProcessor that it needs to reconfigure rendering for this buffer.
580 * NOTE: Child classes override this to call their internal setup_rendering() with the new config, which may have additional side effects.
581 */
582 virtual void set_render_config(const RenderConfig& config)
583 {
584 m_render_config = config;
585 m_render_config_dirty = true;
586 }
587
588 /**
589 * @brief Mark this buffer as requiring depth testing when rendered
590 */
591 void set_needs_depth_attachment(bool needs) { m_needs_depth = needs; }
592
593 /**
594 * @brief Check if this buffer requires depth attachment for rendering
595 */
596 [[nodiscard]] bool needs_depth_attachment() const { return m_needs_depth; }
597
598 /**
599 * @brief Get a RenderProcessor suitable for rendering this buffer
600 * @return Shared pointer to a RenderProcessor, or nullptr if not renderable
601 *
602 * By default returns nullptr. Derived classes that support rendering should
603 * override this to return an appropriate RenderProcessor instance.
604 */
605 virtual std::shared_ptr<RenderProcessor> get_render_processor() const { return m_render_processor; }
606
607 /** @brief Find the attached render processor responsible for a pipeline. */
608 std::shared_ptr<RenderProcessor> get_render_processor(RenderPipelineID id);
609
610 /**
611 * @brief Get additional live render processors attached through the chain.
612 *
613 * The processor returned by get_render_processor() is excluded.
614 */
615 std::vector<std::shared_ptr<RenderProcessor>> get_additional_render_processors();
616
617 inline void set_render_processor(std::shared_ptr<RenderProcessor> rp) { m_render_processor = std::move(rp); }
618
619protected:
620 /**
621 * @brief Called by derived classes to set their context-specific defaults
622 * @param config RenderConfig with default values for this buffer type
623 *
624 * Example (GeometryBuffer calls this in constructor):
625 * RenderConfig defaults;
626 * defaults.vertex_shader = "point.vert.spv";
627 * defaults.fragment_shader = "point.frag.spv";
628 * defaults.topology = PrimitiveTopology::POINT_LIST;
629 * set_default_render_config(defaults);
630 */
632 {
633 m_render_config = config;
634 m_render_config_dirty = false;
635 }
636
637 /**
638 * @brief Configure the internal m_render_processor from a RenderConfig.
639 */
640 void apply_render_config(const RenderConfig& config, const ShaderConfig& shader_config);
641
642 /**
643 * @brief Configure a RenderProcessor, creating one if null.
644 * @param render_processor Existing processor to configure, or nullptr to create one.
645 * @param config RenderConfig with settings to apply
646 */
647 void apply_render_config(
648 std::shared_ptr<RenderProcessor>& render_processor,
649 const RenderConfig& config,
650 const ShaderConfig& shader_config);
651
652 bool m_render_config_dirty {};
654 std::shared_ptr<RenderProcessor> m_render_processor;
655
656private:
658
659 // Buffer parameters
660 size_t m_size_bytes {};
661 Usage m_usage {};
662 bool m_needs_depth {};
663
664 // Semantic metadata
666 std::vector<Kakshya::DataDimension> m_dimensions;
667
668 std::optional<Kakshya::VertexLayout> m_vertex_layout;
669
670 // Buffer interface state
671 bool m_has_data { true };
672 bool m_needs_removal {};
673 bool m_process_default { true };
674 bool m_internal_usage {};
675 std::atomic<bool> m_is_processing;
676 std::shared_ptr<Buffers::BufferProcessor> m_default_processor;
677 std::shared_ptr<Buffers::BufferProcessingChain> m_processing_chain;
681
682 std::unordered_map<RenderPipelineID, std::shared_ptr<Core::Window>> m_window_pipelines;
683 std::unordered_map<RenderPipelineID, CommandBufferID> m_pipeline_commands;
684 std::unordered_set<std::shared_ptr<Core::Window>> m_pending_presentation_refreshes;
685
686 std::vector<std::pair<size_t, size_t>> m_dirty_ranges;
687 std::vector<std::pair<size_t, size_t>> m_invalid_ranges;
688
689 /**
690 * @brief Infer Kakshya::DataDimension entries from a given byte count
691 *
692 * Uses the current modality and provided byte count to populate
693 * m_dimensions so processors and UI code can reason about the buffer's layout.
694 *
695 * @param byte_count Number of bytes of data to infer dimensions from.
696 */
697 void infer_dimensions_from_data(size_t byte_count);
698};
699
700class MAYAFLUX_API VKBufferProcessor : public BufferProcessor {
701protected:
702 Registry::Service::BufferService* m_buffer_service = nullptr;
703 Registry::Service::ComputeService* m_compute_service = nullptr;
704
705 void initialize_buffer_service();
706 void initialize_compute_service();
707 void ensure_initialized(const std::shared_ptr<VKBuffer>& buffer);
708};
709
710/**
711 * @concept GpuImageSource
712 * @brief Satisfied by any VKBuffer subclass that exposes a GPU-resident image.
713 *
714 * Covers all pixel-bearing buffer types via whichever accessor they provide:
715 * - get_texture() TextureBuffer and all its children
716 * - get_gpu_texture() NodeTextureBuffer
717 *
718 * New pixel-bearing buffer types satisfy this concept automatically by
719 * implementing either method with the correct return type. No registration
720 * or base class change required.
721 *
722 * Processors constrained by GpuImageSource use if constexpr to select
723 * the correct accessor at compile time.
724 */
725template <typename T>
726concept GpuImageSource = std::derived_from<T, VKBuffer> && (requires(const T& b) {
727 { b.get_texture() } -> std::convertible_to<std::shared_ptr<Core::VKImage>>; } || requires(const T& b) {
728 { b.get_gpu_texture() } -> std::convertible_to<std::shared_ptr<Core::VKImage>>; });
729
730} // namespace MayaFlux::Buffers
uint64_t offset
Definition Composite.cpp:10
bool size
std::shared_ptr< NetworkGeometryBuffer > buffer
BufferProcessingChain * chain
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23
size_t b
uint16_t usage
const uint8_t * ptr
Central computational transformation interface for continuous buffer processing.
Backend-agnostic interface for sequential data storage and transformation.
Definition Buffer.hpp:37
std::vector< std::pair< size_t, size_t > > m_dirty_ranges
Definition VKBuffer.hpp:686
bool is_render_config_dirty() const
Check if config has changed since last frame.
Definition VKBuffer.hpp:566
void request_presentation_refresh(const std::shared_ptr< Core::Window > &window)
Queue a composition change independently of buffer processing.
Definition VKBuffer.hpp:431
std::unordered_map< RenderPipelineID, std::shared_ptr< Core::Window > > get_render_pipelines() const
Get all render pipelines associated with this buffer.
Definition VKBuffer.hpp:468
size_t get_index_buffer_size() const
Number of bytes in the index buffer.
Definition VKBuffer.hpp:359
void * get_mapped_ptr() const
Get mapped host pointer (nullptr if not host-visible or unmapped)
Definition VKBuffer.hpp:395
CommandBufferID get_pipeline_command(RenderPipelineID pipeline_id) const
Get recorded command buffer for a pipeline.
Definition VKBuffer.hpp:485
ProcessingToken m_processing_token
Definition VKBuffer.hpp:678
void set_pipeline_command(RenderPipelineID pipeline_id, CommandBufferID cmd_id)
Store recorded command buffer for a pipeline.
Definition VKBuffer.hpp:476
PipelineContext m_pipeline_context
Definition VKBuffer.hpp:679
void set_render_processor(std::shared_ptr< RenderProcessor > rp)
Definition VKBuffer.hpp:617
std::unordered_map< RenderPipelineID, std::shared_ptr< Core::Window > > m_window_pipelines
Definition VKBuffer.hpp:682
std::optional< Kakshya::VertexLayout > m_vertex_layout
Definition VKBuffer.hpp:668
std::vector< Kakshya::DataDimension > m_dimensions
Definition VKBuffer.hpp:666
std::shared_ptr< Buffers::BufferProcessingChain > m_processing_chain
Definition VKBuffer.hpp:677
bool is_processing() const override
Query whether the buffer is currently being processed.
Definition VKBuffer.hpp:271
RenderConfig get_render_config() const
Get the current render configuration.
Definition VKBuffer.hpp:572
EngineContext m_engine_context
Definition VKBuffer.hpp:680
bool has_render_pipeline() const
Check if this buffer has a rendering pipeline configured.
Definition VKBuffer.hpp:459
bool needs_depth_attachment() const
Check if this buffer requires depth attachment for rendering.
Definition VKBuffer.hpp:596
bool needs_removal() const override
Checks if the buffer should be removed from processing chains.
Definition VKBuffer.hpp:240
bool has_data_for_cycle() const override
Checks if the buffer has data for the current processing cycle.
Definition VKBuffer.hpp:239
VKBufferResources & get_buffer_resources()
Get all buffer resources at once (mutable).
Definition VKBuffer.hpp:346
virtual std::shared_ptr< RenderProcessor > get_render_processor() const
Get a RenderProcessor suitable for rendering this buffer.
Definition VKBuffer.hpp:605
void clear_pipeline_commands()
Clear all recorded commands (called after presentation)
Definition VKBuffer.hpp:494
vk::Buffer get_index_buffer() const
Return the raw index buffer handle.
Definition VKBuffer.hpp:352
Usage get_usage() const
Retrieve the declared usage intent.
Definition VKBuffer.hpp:307
const EngineContext & get_engine_context() const
Definition VKBuffer.hpp:554
Kakshya::DataModality get_modality() const
Get the buffer's semantic modality.
Definition VKBuffer.hpp:295
const PipelineContext & get_pipeline_context() const
Access the pipeline context for custom metadata (const)
Definition VKBuffer.hpp:551
EngineContext & get_engine_context()
Definition VKBuffer.hpp:553
std::vector< std::pair< size_t, size_t > > m_invalid_ranges
Definition VKBuffer.hpp:687
void set_mapped_ptr(void *ptr)
Set mapped host pointer (for host-visible allocations)
Definition VKBuffer.hpp:316
vk::DeviceSize get_size_bytes() const
Definition VKBuffer.hpp:280
bool has_index_buffer() const
True when an index buffer has been associated with this buffer.
Definition VKBuffer.hpp:364
std::optional< Kakshya::VertexLayout > get_vertex_layout() const
Get vertex layout if set.
Definition VKBuffer.hpp:513
VKBufferResources m_resources
Definition VKBuffer.hpp:657
PipelineContext & get_pipeline_context()
Access the pipeline context for custom metadata (non-const)
Definition VKBuffer.hpp:548
void clear_vertex_layout()
Clear vertex layout.
Definition VKBuffer.hpp:523
void set_memory(vk::DeviceMemory memory)
Set device memory handle after backend allocation.
Definition VKBuffer.hpp:313
void set_needs_depth_attachment(bool needs)
Mark this buffer as requiring depth testing when rendered.
Definition VKBuffer.hpp:591
vk::Buffer & get_buffer()
Get VkBuffer handle (VK_NULL_HANDLE if not registered)
Definition VKBuffer.hpp:277
bool needs_default_processing() override
Checks if the buffer should undergo default processing.
Definition VKBuffer.hpp:244
std::shared_ptr< Buffers::BufferProcessor > m_default_processor
Definition VKBuffer.hpp:676
virtual void setup_processors(ProcessingToken token)
Setup processors with a processing token.
Definition VKBuffer.hpp:292
virtual void mark_render_config_dirty(bool is_dirty=true)
Mark config as changed (processors will detect and react)
Definition VKBuffer.hpp:561
void set_pipeline_window(RenderPipelineID id, const std::shared_ptr< Core::Window > &window)
Associate this buffer with a window for rendering.
Definition VKBuffer.hpp:416
bool is_initialized() const
Check whether Vulkan handles are present (buffer registered)
Definition VKBuffer.hpp:283
void enforce_default_processing(bool should_process) override
Controls whether the buffer should use default processing.
Definition VKBuffer.hpp:243
bool is_internal_only() const override
Check whether this buffer is for internal engine usage.
Definition VKBuffer.hpp:545
void set_buffer(vk::Buffer buffer)
Set VkBuffer handle after backend allocation.
Definition VKBuffer.hpp:310
bool has_vertex_layout() const
Check if this buffer has vertex layout configured.
Definition VKBuffer.hpp:518
const std::vector< Kakshya::DataDimension > & get_dimensions() const
Get the inferred data dimensions for the buffer contents.
Definition VKBuffer.hpp:298
std::shared_ptr< RenderProcessor > m_render_processor
Definition VKBuffer.hpp:654
virtual void set_render_config(const RenderConfig &config)
Update the render configuration and mark as dirty.
Definition VKBuffer.hpp:582
void set_index_resources(vk::Buffer buf, vk::DeviceMemory mem, size_t size)
Store raw index buffer handles produced by the geometry upload path.
Definition VKBuffer.hpp:335
std::atomic< bool > m_is_processing
Definition VKBuffer.hpp:675
void set_default_render_config(const RenderConfig &config)
Called by derived classes to set their context-specific defaults.
Definition VKBuffer.hpp:631
Kakshya::DataModality m_modality
Definition VKBuffer.hpp:665
void remove_pipeline_window(RenderPipelineID id)
Withdraw one pipeline and request presentation of its former window.
Definition VKBuffer.hpp:422
void release_processing() override
Release previously acquired processing lock.
Definition VKBuffer.hpp:262
void set_buffer_resources(const VKBufferResources &resources)
Set all buffer resources at once.
Definition VKBuffer.hpp:319
const VKBufferResources & get_buffer_resources() const
Get all buffer resources at once (read-only)
Definition VKBuffer.hpp:343
void force_internal_usage(bool internal) override
Set whether this buffer is for internal engine usage.
Definition VKBuffer.hpp:542
size_t get_size() const
Get current logical size in bytes.
Definition VKBuffer.hpp:200
void mark_for_removal() override
Marks the buffer for removal from processing chains.
Definition VKBuffer.hpp:242
std::unordered_map< RenderPipelineID, CommandBufferID > m_pipeline_commands
Definition VKBuffer.hpp:683
bool is_host_visible() const
Whether this VKBuffer should be host-visible.
Definition VKBuffer.hpp:373
void mark_for_processing(bool has_data) override
Marks the buffer's data availability for the current processing cycle.
Definition VKBuffer.hpp:241
std::unordered_set< std::shared_ptr< Core::Window > > m_pending_presentation_refreshes
Definition VKBuffer.hpp:684
std::unordered_set< std::shared_ptr< Core::Window > > take_presentation_refreshes()
Transfer pending composition changes to the owning graphics root.
Definition VKBuffer.hpp:438
std::shared_ptr< Core::Window > get_pipeline_window(RenderPipelineID id) const
Get the window associated with this buffer.
Definition VKBuffer.hpp:447
~VKBuffer() override
Virtual destructor.
bool try_acquire_processing() override
Try to acquire processing lock for this buffer.
Definition VKBuffer.hpp:252
Vulkan-backed buffer wrapper used in processing chains.
Definition VKBuffer.hpp:76
Satisfied by any VKBuffer subclass that exposes a GPU-resident image.
Definition VKBuffer.hpp:726
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
uint64_t RenderPipelineID
Definition VKBuffer.hpp:51
uint64_t CommandBufferID
Definition VKBuffer.hpp:52
DataModality
Data modality types for cross-modal analysis.
Definition NDData.hpp:132
BufferUsageHint
Semantic usage hint for buffer allocation and memory properties.
std::vector< GenerationSlot > back_buffers
Definition VKBuffer.hpp:48
Raw Vulkan handles owned by a VKBuffer instance.
Definition VKBuffer.hpp:34
std::vector< Portal::Graphics::DescriptorBindingInfo > ssbo_bindings
Definition VKBuffer.hpp:106
Engine-internal per-frame binding state.
Definition VKBuffer.hpp:105
std::vector< Portal::Graphics::DescriptorBindingInfo > descriptor_buffer_bindings
Definition VKBuffer.hpp:91
std::vector< Portal::Graphics::PushConstantBindingInfo > push_constant_bindings
Definition VKBuffer.hpp:89
std::unordered_map< std::string, std::any > metadata
Definition VKBuffer.hpp:93
Context shared with BufferProcessors during pipeline execution.
Definition VKBuffer.hpp:88
Complete description of vertex data layout in a buffer.
Unified rendering configuration for graphics buffers.
Backend buffer management service interface.
Backend compute shader and pipeline service interface.