MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ShaderProcessor.hpp
Go to the documentation of this file.
1#pragma once
2
4
6
7namespace MayaFlux::Buffers {
8
9/**
10 * @struct ShaderBinding
11 * @brief Describes how a VKBuffer binds to a shader descriptor
12 */
14 uint32_t set = 0; ///< Descriptor set index
15 uint32_t binding = 0; ///< Binding point within set
16 vk::DescriptorType type = vk::DescriptorType::eStorageBuffer;
17 uint32_t count = 1; ///< Array count for array descriptors (default 1)
18
19 ShaderBinding() = default;
20
21 /**
22 * @brief Construct with semantic role — preferred public API.
23 */
25 : set(s)
26 , binding(b)
27 , type(to_vk_descriptor_type(role))
28 , count(c)
29 {
30 }
31
32 /**
33 * @brief Construct with explicit Vulkan type — internal / advanced use only.
34 */
35 ShaderBinding(uint32_t s, uint32_t b, vk::DescriptorType t, uint32_t c = 1)
36 : set(s)
37 , binding(b)
38 , type(t)
39 , count(c)
40 {
41 }
42};
43
44/**
45 * @struct ShaderProcessorConfig
46 * @brief Complete configuration for shader processor
47 */
49 std::string shader_path; ///< Path to shader file
51 std::string entry_point = "main";
53
54 std::unordered_map<std::string, ShaderBinding> bindings;
55
57
58 std::vector<Portal::Graphics::PushConstantField> pc_fields; ///< Retained from a ShaderSpec so feeds can resolve a field name to an offset. Empty for file shaders.
59
60 std::unordered_map<uint32_t, uint32_t> specialization_constants;
61
62 ShaderConfig() = default;
63 ShaderConfig(std::string path)
64 : shader_path(std::move(path))
65 {
66 }
68 : shader_id(Portal::Graphics::get_shader_foundry().load_shader(spec))
69 , push_constant_size(spec.push_constant_bytes)
70 , pc_fields(spec.pc_fields)
71 {
72 }
73};
74
75/**
76 * @class ShaderProcessor
77 * @brief Abstract base class for shader-based buffer processing
78 *
79 * ShaderProcessor provides the foundational infrastructure for managing shader resources,
80 * descriptor sets, and buffer bindings. It is designed to be stage-agnostic, serving as
81 * the common parent for specialized processors like ComputeProcessor and RenderProcessor.
82 *
83 * Core Responsibilities:
84 * - **Shader Management:** Loads and manages shader modules via Portal::Graphics::ShaderFoundry.
85 * - **Descriptor Management:** Handles descriptor set allocation, updates, and binding.
86 * - **Buffer Binding:** Maps logical names (e.g., "input", "output") to physical VKBuffers.
87 * - **Constants:** Manages push constants and specialization constants.
88 * - **Hot-Reload:** Supports runtime shader reloading and pipeline invalidation.
89 *
90 * It does NOT define specific pipeline creation or execution logic (e.g., dispatch vs draw),
91 * leaving those details to derived classes (ComputeProcessor, RenderProcessor).
92 *
93 * Quality-of-life features:
94 * - **Data movement hints:** Query buffer usage (input/output/in-place) for automation.
95 * - **Binding introspection:** Validate if required bindings are satisfied.
96 * - **State queries:** Track processing state for chain management.
97 *
98 * Design Philosophy:
99 * - **Inheritance-focused**: Provides the "plumbing" for shader processors without dictating the pipeline type.
100 * - **Buffer-agnostic**: Works with any VKBuffer modality/usage.
101 * - **Flexible binding**: Decouples logical shader parameters from physical buffers.
102 *
103 * Integration:
104 * - Base class for `ComputeProcessor` (Compute Pipelines)
105 * - Base class for `RenderProcessor` (Graphics Pipelines)
106 * - Base class for `NodeBindingsProcessor` (Node-driven parameters)
107 *
108 * Usage (via derived classes):
109 * // Compute example
110 * auto compute = std::make_shared<ComputeProcessor>("shaders/kernel.comp");
111 * compute->bind_buffer("data", buffer);
112 *
113 * // Graphics example
114 * auto render = std::make_shared<RenderProcessor>(config);
115 * render->bind_buffer("vertices", vertex_buffer);
116 */
117class MAYAFLUX_API ShaderProcessor : public VKBufferProcessor {
118public:
119 /**
120 * @brief Get buffer usage characteristics needed for safe data flow
121 *
122 * Returns flags indicating:
123 * - Does compute read from input? (HOST_TO_DEVICE upload needed?)
124 * - Does compute write to output? (DEVICE_TO_HOST readback needed?)
125 *
126 * This lets ComputeProcessingChain auto-determine staging needs.
127 */
128 enum class BufferUsageHint : uint8_t {
129 NONE = 0,
130 INPUT_READ = 1 << 0, ///< Shader reads input
131 OUTPUT_WRITE = 1 << 1, ///< Shader writes output (modifies)
132 BIDIRECTIONAL = INPUT_READ | OUTPUT_WRITE
133 };
134
135 /**
136 * @brief Construct processor with shader path
137 * @param shader_path Path to shader file (e.g., .comp, .vert, .frag, .spv)
138 */
139 explicit ShaderProcessor(const std::string& shader_path);
140
141 /**
142 * @brief Construct processor with full configuration
143 * @param config Complete shader processor configuration
144 */
145 explicit ShaderProcessor(ShaderConfig config);
146
147 ~ShaderProcessor() override;
148
149 //==========================================================================
150 // BufferProcessor Interface
151 //==========================================================================
152
153 void processing_function(const std::shared_ptr<Buffer>& buffer) override;
154 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
155 void on_detach(const std::shared_ptr<Buffer>& buffer) override;
156
157 [[nodiscard]] bool is_compatible_with(const std::shared_ptr<Buffer>& buffer) const override;
158
159 //==========================================================================
160 // Buffer Binding - Multi-buffer Support
161 //==========================================================================
162
163 /**
164 * @brief Bind a VKBuffer to a named shader descriptor
165 * @param descriptor_name Logical name (e.g., "input", "output")
166 * @param buffer VKBuffer to bind
167 *
168 * Registers the buffer for descriptor set binding.
169 * The descriptor_name must match a key in config.bindings.
170 */
171 void bind_buffer(const std::string& descriptor_name, const std::shared_ptr<VKBuffer>& buffer);
172
173 /**
174 * @brief Unbind a buffer from a descriptor
175 * @param descriptor_name Logical name to unbind
176 */
177 void unbind_buffer(const std::string& descriptor_name);
178
179 /**
180 * @brief Get bound buffer for a descriptor name
181 * @param descriptor_name Logical name
182 * @return Bound buffer, or nullptr if not bound
183 */
184 [[nodiscard]] std::shared_ptr<VKBuffer> get_bound_buffer(const std::string& descriptor_name) const;
185
186 /**
187 * @brief Auto-bind buffer based on attachment order
188 * @param buffer Buffer to auto-bind
189 *
190 * First attachment -> "input" or first binding
191 * Second attachment -> "output" or second binding
192 * Useful for simple single-buffer or input/output patterns.
193 */
194 void auto_bind_buffer(const std::shared_ptr<VKBuffer>& buffer);
195
196 /**
197 * @brief Download the buffer currently bound to a named descriptor.
198 * @param descriptor_name Logical name previously bound via bind_buffer.
199 * @param data Destination pointer, at least the bound buffer's size in bytes.
200 * @param size Byte count to copy.
201 * @param staging Optional staging buffer, forwarded to download_from_gpu.
202 * @return True if the name resolved to a bound buffer and the download ran.
203 */
204 bool download_bound(
205 const std::string& descriptor_name,
206 void* data,
207 size_t size,
208 const std::shared_ptr<VKBuffer>& staging = nullptr) const;
209
210 template <typename T>
211 bool download_bound(const std::string& descriptor_name, std::vector<T>& data) const
212 {
213 auto buffer = get_bound_buffer(descriptor_name);
214 if (!buffer) {
215 MF_ERROR(Journal::Component::Buffers, Journal::Context::BufferProcessing,
216 "download_bound: no buffer bound to descriptor '{}'", descriptor_name);
217 return false;
218 }
219 download_from_gpu(buffer, data);
220 return true;
221 }
222
223 //==========================================================================
224 // Feeds
225 //==========================================================================
226
227 /**
228 * @brief What a feed callable returns.
229 *
230 * A double lands in the push constant block. A DataVariant lands in a
231 * storage descriptor. Which one an entry expects is fixed when it is
232 * registered by the name it resolves to.
233 */
234 using FeedValue = std::variant<double, Kakshya::DataVariant>;
235
236 /** @brief A callable pulled once per processing cycle. */
237 using FeedSource = std::function<FeedValue()>;
238
239 /**
240 * @brief Supply a shader input from a callable, resolved by name.
241 * @param name A name already declared on this shader: a descriptor in
242 * config.bindings, or a push constant field from the ShaderSpec
243 * this processor was constructed from.
244 * @param source Callable pulled each cycle. Returns a DataVariant for a
245 * descriptor name, a double for a push constant field.
246 *
247 * Resolution happens once, here. Descriptor names take precedence; a
248 * name matching neither is an error and registers nothing. File-shader
249 * processors have no record of push constant field names, so their
250 * constant feeds must use the explicit overload.
251 */
252 void feed(const std::string& name, FeedSource source);
253
254 /**
255 * @brief Supply a push constant from a callable at an explicit offset.
256 * @param name Logical name, used for removal and error reporting. Need
257 * not match anything on the shader.
258 * @param source Callable returning a double.
259 * @param offset Byte offset in the push constant block.
260 * @param size Byte width written. Four narrows to float, eight keeps
261 * double. Other values are rejected.
262 *
263 * The form hand-written shaders need, since their push constant block
264 * is described nowhere the processor can read.
265 */
266 void feed(const std::string& name, FeedSource source, uint32_t offset, size_t size = sizeof(float));
267
268 /** @brief Remove a feed. Any buffer it created is released. */
269 void remove_feed(const std::string& name);
270
271 /** @brief Whether a feed of this name is registered. */
272 [[nodiscard]] bool has_feed(const std::string& name) const;
273
274 /** @brief Names of every registered feed. */
275 [[nodiscard]] std::vector<std::string> get_feed_names() const;
276
277 //==========================================================================
278 // Shader Management
279 //==========================================================================
280
281 /**
282 * @brief Hot-reload shader from ShaderFoundry
283 * @return True if reload succeeded
284 *
285 * Invalidates cached shader and rebuilds pipeline.
286 * Existing descriptor sets are preserved if compatible.
287 */
288 bool hot_reload_shader();
289
290 /**
291 * @brief Update shader path and reload
292 * @param shader_path New shader path
293 */
294 void set_shader(const std::string& shader_path);
295
296 /**
297 * @brief Get current shader path
298 */
299 [[nodiscard]] const std::string& get_shader_path() const { return m_config.shader_path; }
300
301 //==========================================================================
302 // Push Constants
303 //==========================================================================
304
305 /**
306 * @brief Set push constant size
307 * @param size Size in bytes
308 */
309 void set_push_constant_size(size_t size);
310
311 /**
312 * @brief Set push constant size from type
313 * @tparam T Push constant struct type
314 */
315 template <typename T>
317 {
318 set_push_constant_size(sizeof(T));
319 }
320
321 /**
322 * @brief Update push constant data (type-safe)
323 * @tparam T Push constant struct type
324 * @param data Push constant data
325 *
326 * Data is copied and uploaded during next process() call.
327 */
328 template <typename T>
329 void set_push_constant_data(const T& data);
330
331 /**
332 * @brief Update push constant data (raw bytes)
333 * @param data Pointer to data
334 * @param size Size in bytes
335 */
336 virtual void set_push_constant_data_raw(const void* data, size_t size);
337
338 /**
339 * @brief Get current push constant data
340 */
341 [[nodiscard]] const std::vector<uint8_t>& get_push_constant_data() const { return m_push_constant_data; }
342 [[nodiscard]] std::vector<uint8_t>& get_push_constant_data() { return m_push_constant_data; }
343
344 //==========================================================================
345 // Specialization Constants
346 //==========================================================================
347
348 /**
349 * @brief Set specialization constant
350 * @param constant_id Specialization constant ID
351 * @param value Value to set
352 *
353 * Requires pipeline recreation to take effect.
354 */
355 void set_specialization_constant(uint32_t constant_id, uint32_t value);
356
357 /**
358 * @brief Clear all specialization constants
359 */
360 void clear_specialization_constants();
361
362 //==========================================================================
363 // Configuration
364 //==========================================================================
365
366 /**
367 * @brief Update entire configuration
368 * @param config New configuration
369 *
370 * Triggers pipeline recreation.
371 */
372 void set_config(const ShaderConfig& config);
373
374 /**
375 * @brief Get current configuration
376 */
377 [[nodiscard]] const ShaderConfig& get_config() const { return m_config; }
378
379 /**
380 * @brief Add descriptor binding configuration
381 * @param descriptor_name Logical name
382 * @param binding Shader binding info
383 */
384 void add_binding(const std::string& descriptor_name, const ShaderBinding& binding);
385
386 //==========================================================================
387 // Data movement hints
388 //==========================================================================
389
390 /**
391 * @brief Get buffer usage hint for a descriptor
392 * @param descriptor_name Binding name
393 * @return BufferUsageHint flags
394 */
395 [[nodiscard]] virtual BufferUsageHint get_buffer_usage_hint(const std::string& descriptor_name) const;
396
397 /**
398 * @brief Check if shader modifies a specific buffer in-place
399 * @param descriptor_name Binding name
400 * @return True if shader both reads and writes this buffer
401 */
402 [[nodiscard]] virtual bool is_in_place_operation(const std::string& descriptor_name) const;
403
404 /**
405 * @brief Check if a descriptor binding exists
406 * @param descriptor_name Name of the binding (e.g., "input", "output")
407 * @return True if binding is configured
408 */
409 [[nodiscard]] bool has_binding(const std::string& descriptor_name) const;
410
411 /**
412 * @brief Get all configured descriptor names
413 * @return Vector of binding names
414 *
415 * Useful for introspection: which buffers does this shader expect?
416 */
417 [[nodiscard]] std::vector<std::string> get_binding_names() const;
418
419 /**
420 * @brief Check if all required bindings are satisfied
421 * @return True if all configured bindings have buffers bound
422 */
423 [[nodiscard]] bool are_bindings_complete() const;
424
425 //==========================================================================
426 // State Queries
427 //==========================================================================
428
429 /**
430 * @brief Check if shader is loaded
431 */
432 [[nodiscard]] bool is_shader_loaded() const { return m_shader_id != Portal::Graphics::INVALID_SHADER; }
433
434 /**
435 * @brief Check if descriptors are initialized
436 */
437 [[nodiscard]] bool are_descriptors_ready() const { return !m_descriptor_set_ids.empty(); }
438
439 /**
440 * @brief Get number of bound buffers
441 */
442 [[nodiscard]] size_t get_bound_buffer_count() const { return m_bound_buffers.size(); }
443
444 /**
445 * @brief Get the output buffer after compute dispatch
446 *
447 * Returns the buffer that was last processed (input/output depends on
448 * shader and binding configuration). Used by ComputeProcessingChain
449 * to determine where compute results ended up.
450 *
451 * Typically the buffer passed to processing_function(), but can be
452 * overridden by subclasses if compute modifies different buffers.
453 */
454 [[nodiscard]] virtual std::shared_ptr<VKBuffer> get_output_buffer() const { return m_last_processed_buffer; }
455
456 /**
457 * @brief Submit asynchronously and resolve at the top of a later cycle.
458 * @param deferred True to submit via submit_async, false for submit_and_wait.
459 *
460 * Only meaningful for children that submit their own command buffers.
461 * Children that record without submitting, such as RenderProcessor,
462 * are unaffected. Switching back to synchronous while a submission is
463 * outstanding waits for and releases it first.
464 */
465 void set_deferred_submission(bool deferred);
466
467 /** @brief Whether this processor submits asynchronously. */
468 [[nodiscard]] bool is_deferred_submission() const { return m_deferred_submission; }
469
470 /** @brief True while an asynchronous submission is outstanding. */
471 [[nodiscard]] bool is_dispatch_pending() const
472 {
473 return m_pending_fence != Portal::Graphics::INVALID_FENCE;
474 }
475
476 /**
477 * @brief Resolve an outstanding asynchronous submission.
478 * @param block True to wait for the fence, false to return immediately
479 * when it is not yet signaled.
480 * @return True if a submission was resolved by this call.
481 *
482 * On resolution invokes on_dispatch_complete, then release_fence, which
483 * also frees the associated command buffer. Invoked with block=false at
484 * the top of processing_function and with block=true from cleanup.
485 */
486 bool resolve_pending_dispatch(bool block);
487
488 /**
489 * @brief Check if compute has been executed at least once
490 * @return True if processing_function() has been called
491 */
492 [[nodiscard]] virtual inline bool has_executed() const
493 {
494 return m_last_command_buffer != Portal::Graphics::INVALID_COMMAND_BUFFER;
495 }
496
497protected:
498 /**
499 * @brief Byte width of this processor's push constant block, extended to
500 * cover any fragment staged on the buffer.
501 */
502 [[nodiscard]] size_t resolve_push_constant_size(const std::shared_ptr<VKBuffer>& buffer) const;
503
504 /**
505 * @brief This processor's push constant data with buffer-staged fragments
506 * overlaid at their declared offsets.
507 */
508 [[nodiscard]] std::vector<uint8_t> resolve_push_constants(const std::shared_ptr<VKBuffer>& buffer) const;
509
510 /**
511 * @brief Pull every feed and write its result.
512 *
513 * Called at the top of processing_function, before descriptors are
514 * rebuilt, so a storage feed creating its buffer binds the same cycle.
515 * Callables run on whichever thread drives the chain.
516 */
517 void pump_feeds();
518
519 //==========================================================================
520 // Overridable Hooks for Specialized Processors
521 //==========================================================================
522
523 /**
524 * @brief Called before shader compilation
525 * @param shader_path Path to shader
526 *
527 * Override to modify shader compilation (e.g., add defines, includes).
528 */
529 virtual void on_before_compile(const std::string& shader_path);
530
531 /**
532 * @brief Called after shader is loaded
533 * @param shader Loaded shader module
534 *
535 * Override to extract reflection data or validate shader.
536 */
537 virtual void on_shader_loaded(Portal::Graphics::ShaderID shader_id);
538
539 /**
540 * @brief Called before pipeline creation
541 * @param config Pipeline configuration
542 *
543 * Override to modify pipeline configuration.
544 */
546
547 /**
548 * @brief Called after pipeline is created
549 * @param pipeline Created pipeline
550 *
551 * Override for post-pipeline setup.
552 */
553 virtual void on_pipeline_created(Portal::Graphics::ComputePipelineID pipeline_id);
554
555 /**
556 * @brief Called before descriptor sets are created
557 *
558 * Override to add custom descriptor bindings.
559 */
560 virtual void on_before_descriptors_create();
561
562 /**
563 * @brief Called after descriptor sets are created
564 *
565 * Override for custom descriptor updates.
566 */
567 virtual void on_descriptors_created();
568
569 /**
570 * @brief Called before each process callback
571 * @param cmd Command buffer
572 * @param buffer Currently processing buffer
573 * @return True to proceed with execution, false to skip
574 *
575 * Override to update push constants or dynamic descriptors.
576 */
577 virtual bool on_before_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr<VKBuffer>& buffer);
578
579 /**
580 * @brief Called after each process callback
581 * @param cmd Command buffer
582 * @param buffer Currently processed buffer
583 *
584 * Override for post-dispatch synchronization or state updates.
585 */
586 virtual void on_after_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr<VKBuffer>& buffer);
587
588 /**
589 * @brief Called once when an asynchronous submission is observed complete.
590 * @param buffer Buffer processed by the completed submission.
591 *
592 * The correct place for device-to-host readback under deferred
593 * submission, since on_after_execute runs at record time, before the
594 * GPU has executed anything. Never invoked under synchronous
595 * submission, where submit_and_wait already precedes the return.
596 */
597 virtual void on_dispatch_complete(const std::shared_ptr<VKBuffer>& buffer);
598
599 /**
600 * @brief Submit a recorded command buffer honoring the submission mode.
601 * @param cmd_id Command buffer to submit.
602 * @param buffer Buffer being processed. Retained until resolution when
603 * deferred, so on_dispatch_complete receives the same instance.
604 *
605 * Synchronous submission calls submit_and_wait and returns. Deferred
606 * submission calls submit_async and stores the fence; a failed
607 * submission falls back to leaving nothing pending.
608 */
609 void submit_recorded(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr<VKBuffer>& buffer);
610
611 /**
612 * @brief Resolve logical descriptor set index to actual index
613 * @param set Logical set index from ShaderBinding
614 * @return Resolved set index, or std::nullopt if invalid
615 *
616 * Handles cases where the engine reserves set 0 for global resources.
617 * If m_engine_owns_set_zero is true, logical set 0 maps to no descriptor,
618 * and logical sets are offset by +1 in the actual descriptor sets.
619 */
620 [[nodiscard]] std::optional<uint32_t> resolve_ds_index(uint32_t set) const;
621
622 //==========================================================================
623 // Protected State - Available to Subclasses
624 //==========================================================================
625
627
628 Portal::Graphics::ShaderID m_shader_id = Portal::Graphics::INVALID_SHADER;
629 std::vector<Portal::Graphics::DescriptorSetID> m_descriptor_set_ids;
630 Portal::Graphics::CommandBufferID m_last_command_buffer = Portal::Graphics::INVALID_COMMAND_BUFFER;
631
632 std::unordered_map<std::string, std::shared_ptr<VKBuffer>> m_bound_buffers;
633 std::shared_ptr<VKBuffer> m_last_processed_buffer;
634
635 bool m_deferred_submission {}; ///< False submits synchronously, preserving pre-existing behaviour.
636 Portal::Graphics::FenceID m_pending_fence { Portal::Graphics::INVALID_FENCE }; ///< Outstanding async submission, if any.
637 std::shared_ptr<VKBuffer> m_pending_buffer; ///< Buffer retained for the outstanding submission.
638
639 std::vector<uint8_t> m_push_constant_data;
640
641 bool m_initialized {};
642 bool m_needs_pipeline_rebuild = true;
643 bool m_needs_descriptor_rebuild = true;
644
645 size_t m_auto_bind_index {};
646
647 /**
648 * @brief Whether the engine reserves set=0 for global resources
649 *
650 * Defaults to false. Only RenderProcessor sets this to true in its
651 * constructor. When true, resolve_ds_index() maps logical set=0 to
652 * nullopt (no user descriptor) and offsets all other sets by -1.
653 * Compute subclasses leave this false: their descriptor sets are
654 * numbered from set=0 with no engine reservation.
655 *
656 * A future subclass that needs engine-owned sets must set this
657 * explicitly and be aware of the index offset applied by resolve_ds_index.
658 */
659 bool m_engine_owns_set_zero {};
660
661 virtual void initialize_pipeline(const std::shared_ptr<VKBuffer>& buffer) = 0;
662 virtual void initialize_descriptors(const std::shared_ptr<VKBuffer>& buffer) = 0;
663 virtual void execute_shader(const std::shared_ptr<VKBuffer>& buffer) = 0;
664
665 virtual void update_descriptors(const std::shared_ptr<VKBuffer>& buffer);
666 virtual void cleanup();
667
668private:
669 //==========================================================================
670 // Internal Implementation
671 //==========================================================================
672
673 /**
674 * @struct Feed
675 * @brief One registered callable and where its result is written.
676 */
677 struct Feed {
679 bool is_storage {};
680 uint32_t offset {};
681 size_t size {};
682 std::string descriptor_name;
683 std::shared_ptr<VKBuffer> buffer;
684 bool mismatch_logged {};
685 };
686
687 std::unordered_map<std::string, Feed> m_feeds;
688
689 void initialize_shader();
690};
691
692template <typename T>
694{
695 const auto size = sizeof(T);
696 static_assert(size <= 128, "Push constants typically limited to 128 bytes");
697 if (m_push_constant_data.size() < size) {
699 }
700
701 std::memcpy(m_push_constant_data.data(), &data, size);
702}
703
704} // namespace MayaFlux::Buffers
#define MF_ERROR(comp, ctx,...)
size_t b
std::string name
Definition VKDevice.cpp:143
float value
float offset
virtual void initialize_pipeline(const std::shared_ptr< VKBuffer > &buffer)=0
const std::vector< uint8_t > & get_push_constant_data() const
Get current push constant data.
size_t get_bound_buffer_count() const
Get number of bound buffers.
virtual void execute_shader(const std::shared_ptr< VKBuffer > &buffer)=0
std::unordered_map< std::string, std::shared_ptr< VKBuffer > > m_bound_buffers
std::vector< uint8_t > m_push_constant_data
virtual void initialize_descriptors(const std::shared_ptr< VKBuffer > &buffer)=0
std::shared_ptr< VKBuffer > m_pending_buffer
Buffer retained for the outstanding submission.
std::vector< uint8_t > & get_push_constant_data()
bool is_deferred_submission() const
Whether this processor submits asynchronously.
const std::string & get_shader_path() const
Get current shader path.
void set_push_constant_size()
Set push constant size from type.
const ShaderConfig & get_config() const
Get current configuration.
virtual bool has_executed() const
Check if compute has been executed at least once.
void set_push_constant_data(const T &data)
Update push constant data (type-safe)
bool are_descriptors_ready() const
Check if descriptors are initialized.
std::shared_ptr< VKBuffer > m_last_processed_buffer
std::variant< double, Kakshya::DataVariant > FeedValue
What a feed callable returns.
bool is_shader_loaded() const
Check if shader is loaded.
virtual std::shared_ptr< VKBuffer > get_output_buffer() const
Get the output buffer after compute dispatch.
BufferUsageHint
Get buffer usage characteristics needed for safe data flow.
virtual void on_before_pipeline_create(Portal::Graphics::ComputePipelineID pipeline_id)
Called before pipeline creation.
bool is_dispatch_pending() const
True while an asynchronous submission is outstanding.
std::unordered_map< std::string, Feed > m_feeds
std::function< FeedValue()> FeedSource
A callable pulled once per processing cycle.
bool download_bound(const std::string &descriptor_name, std::vector< T > &data) const
std::vector< Portal::Graphics::DescriptorSetID > m_descriptor_set_ids
Abstract base class for shader-based buffer processing.
void download_from_gpu(const std::shared_ptr< VKBuffer > &source, void *data, size_t size, const std::shared_ptr< VKBuffer > &staging)
Download from GPU buffer to raw data (auto-detects host-visible vs device-local)
constexpr ShaderID INVALID_SHADER
ShaderStage
User-friendly shader stage enum.
DescriptorRole
Semantic descriptor type — maps to Vulkan descriptor types internally.
@ STORAGE
Large arrays or buffers the shader may write (SSBO)
static constexpr DomainSpec Graphics
Domain constant for Graphics domain.
Definition Creator.hpp:318
uint32_t binding
Binding point within set.
ShaderBinding(uint32_t s, uint32_t b, vk::DescriptorType t, uint32_t c=1)
Construct with explicit Vulkan type — internal / advanced use only.
uint32_t set
Descriptor set index.
ShaderBinding(uint32_t s, uint32_t b, Portal::Graphics::DescriptorRole role=Portal::Graphics::DescriptorRole::STORAGE, uint32_t c=1)
Construct with semantic role — preferred public API.
uint32_t count
Array count for array descriptors (default 1)
Describes how a VKBuffer binds to a shader descriptor.
ShaderConfig(const Portal::Graphics::ShaderSpec &spec)
std::string shader_path
Path to shader file.
std::unordered_map< uint32_t, uint32_t > specialization_constants
std::unordered_map< std::string, ShaderBinding > bindings
Portal::Graphics::ShaderStage stage
std::vector< Portal::Graphics::PushConstantField > pc_fields
Retained from a ShaderSpec so feeds can resolve a field name to an offset. Empty for file shaders.
Portal::Graphics::ShaderID shader_id
One registered callable and where its result is written.
Complete declarative description of a generated compute shader.