MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ShaderFoundry.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "ShaderUtils.hpp"
4
5#include "ShaderSpec.hpp"
6
8
9#include <span>
10
11namespace MayaFlux::Core {
12class VulkanBackend;
13class VKShaderModule;
14class VKComputePipeline;
15class VKDescriptorManager;
16}
17
19
20class ComputePress;
21class RenderFlow;
22
23/**
24 * @struct DescriptorBufferWrite
25 * @brief One descriptor set slot to update, for ShaderFoundry::update_descriptor_buffers.
26 *
27 * Same fields as update_descriptor_buffer's parameter list, collected so
28 * several slots, across one or more descriptor sets, can be written with a
29 * single vkUpdateDescriptorSets call instead of one call per slot.
30 */
33 uint32_t binding;
34 vk::DescriptorType type;
35 vk::Buffer buffer;
36 size_t offset;
37 size_t size;
38};
39
40/**
41 * @struct DescriptorImageWrite
42 * @brief One descriptor set slot to update, for ShaderFoundry::update_descriptor_images.
43 *
44 * Covers both update_descriptor_image (combined image sampler) and
45 * update_descriptor_storage_image (storage image) shapes; sampler is
46 * ignored for a storage image write. Collected the same way as
47 * DescriptorBufferWrite, so several image slots can be written with a
48 * single vkUpdateDescriptorSets call instead of one call per slot.
49 */
52 uint32_t binding;
53 vk::DescriptorType type;
54 vk::ImageView image_view;
55 vk::Sampler sampler;
56 vk::ImageLayout layout;
57};
58
59namespace detail {
60 /**
61 * @brief Emit complete SPIR-V assembly text for a generated compute kernel.
62 * @param spec ShaderSpec produced by ShaderSpec::Assemble::build().
63 * @return SPIR-V assembly string suitable for spvTextToBinary.
64 */
65 MAYAFLUX_API std::string emit_spirv_asm(const ShaderSpec& spec);
66
67 /**
68 * Emit a complete GLSL compute shader from spec metadata and a KernelSource body.
69 *
70 * Binding names are used directly as GLSL identifiers. The body text from
71 * KernelSource::parse() is injected verbatim inside main() after uint i and
72 * optional ivec2 coord are declared. Push constant fields are accessible as
73 * pc.<name>. SSBO arrays are accessible as <name>[i].
74 */
75 MAYAFLUX_API std::string emit_glsl_kernel(const ShaderSpec& spec);
76}
77
78/**
79 * @class ShaderFoundry
80 * @brief Portal-level shader compilation and caching
81 *
82 * ShaderFoundry is a thin glue layer that:
83 * - Wraps Core::VKShaderModule for convenient shader creation
84 * - Provides caching to avoid redundant compilation
85 * - Supports hot-reload workflows (watch files, recompile)
86 * - Returns VKShaderModule directly for use in pipelines
87 *
88 * Design Philosophy:
89 * - Manages compilation, NOT execution (that's Pipeline/Compute)
90 * - Returns VKShaderModule directly (no wrapping)
91 * - Simple, focused API aligned with VKShaderModule capabilities
92 * - Integrates with existing Core shader infrastructure
93 *
94 * Consumers:
95 * - VKBufferProcessor subclasses (compute shaders)
96 * - Future Yantra::ComputePipeline (compute shaders)
97 * - Future Yantra::RenderPipeline (graphics shaders)
98 * - Future DataProcessors (image processing shaders)
99 *
100 * Usage:
101 * auto& compiler = Portal::Graphics::ShaderFoundry::instance();
102 *
103 * // Compile from file
104 * auto shader = compiler.compile_from_file("shaders/my_kernel.comp");
105 *
106 * // Compile from string
107 * auto shader = compiler.compile_from_source(glsl_code, ShaderStage::COMPUTE);
108 *
109 * // Use in pipeline
110 * my_buffer_processor->set_shader(shader);
111 * my_compute_pipeline->set_shader(shader);
112 */
113class MAYAFLUX_API ShaderFoundry {
114public:
115 enum class CommandBufferType : uint8_t {
116 GRAPHICS,
117 COMPUTE,
118 TRANSFER
119 };
120
121 enum class CommandBufferLevel : uint8_t {
122 PRIMARY,
123 SECONDARY
124 };
125
126private:
128 vk::DescriptorSet descriptor_set;
129 };
130
132 vk::CommandBuffer cmd;
134 CommandBufferLevel level { CommandBufferLevel::PRIMARY };
136 vk::QueryPool timestamp_pool;
137 std::unordered_map<std::string, uint32_t> timestamp_queries;
138 };
139
140 struct FenceState {
141 vk::Fence fence;
143
145 };
146
148 vk::Semaphore semaphore;
149 };
150
151 struct ShaderState {
152 std::shared_ptr<Core::VKShaderModule> module;
153 std::string filepath;
155 std::string entry_point;
156 };
157
158public:
160 {
161 static ShaderFoundry compiler;
162 return compiler;
163 }
164
165 ShaderFoundry(const ShaderFoundry&) = delete;
167 ShaderFoundry(ShaderFoundry&&) noexcept = delete;
168 ShaderFoundry& operator=(ShaderFoundry&&) noexcept = delete;
169
170 /**
171 * @brief Initialize shader compiler
172 * @param backend Shared pointer to VulkanBackend
173 * @param config Compiler configuration
174 * @return True if initialization succeeded
175 *
176 * Must be called before compiling any shaders.
177 */
178 bool initialize(
179 const std::shared_ptr<Core::VulkanBackend>& backend,
180 const ShaderCompilerConfig& config = {});
181
182 /**
183 * @brief Stop active command recording and free command buffers
184 *
185 * Frees all command buffers back to pool and destroys query pools.
186 * Call this BEFORE destroying pipelines/resources that command buffers reference.
187 * Does NOT destroy the command pool itself - that happens in shutdown().
188 */
189 void stop();
190
191 /**
192 * @brief Shutdown and cleanup all ShaderFoundry resources
193 *
194 * Destroys sync objects, descriptor resources, and shader modules.
195 * Must be called AFTER stop() and AFTER pipeline consumers (RenderFlow/ComputePress) shutdown.
196 */
197 void shutdown();
198
199 /**
200 * @brief Check if compiler is initialized
201 */
202 [[nodiscard]] bool is_initialized() const { return m_backend != nullptr; }
203
204 //==========================================================================
205 // Shader Compilation - Primary API
206 //==========================================================================
207
208 /**
209 * @brief Universal shader loader - auto-detects source type
210 * @param content File path, GLSL source string, or SPIR-V path
211 * @param stage Optional stage override (auto-detected if omitted)
212 * @param entry_point Entry point function name (default: "main")
213 * @return ShaderID, or INVALID_SHADER on failure
214 *
215 * Supports:
216 * - GLSL files: .comp, .vert, .frag, .geom, .tesc, .tese
217 * - SPIR-V files: .spv
218 *
219 * Stage auto-detection:
220 * .comp → COMPUTE
221 * .vert → VERTEX
222 * .frag → FRAGMENT
223 * .geom → GEOMETRY
224 * .tesc → TESS_CONTROL
225 * .tese → TESS_EVALUATION
226 * .mesh → MESH
227 * .task → TASK
228 *
229 * Examples:
230 * load_shader("shaders/kernel.comp"); // File
231 * load_shader("shaders/kernel.spv", COMPUTE); // SPIR-V
232 * load_shader("#version 460\nvoid main(){}", COMPUTE); // Source
233 */
234 ShaderID load_shader(
235 const std::string& content,
236 std::optional<ShaderStage> stage = std::nullopt,
237 const std::string& entry_point = "main");
238
239 /**
240 * @brief Load shader from explicit ShaderSource descriptor
241 * @param source Complete shader source specification
242 * @return ShaderID, or INVALID_SHADER on failure
243 */
244 ShaderID load_shader(const ShaderSource& source);
245
246 /**
247 * @brief Compile and cache a compute shader from a declarative ShaderSpec.
248 *
249 * Emits SPIR-V assembly text from the spec via detail::emit_spirv_asm(),
250 * assembles it via VKShaderModule::create_from_spirv_asm() using
251 * SPIRV-Tools, and caches the result by content hash. No shaderc or
252 * GLSL toolchain is involved.
253 *
254 * Subsequent calls with a spec that produces identical assembly are cache
255 * hits and return the existing ShaderID at no cost.
256 *
257 * The emitted shader is always a compute stage. Entry point is "main".
258 * Binding 0 at set 0 is never emitted; it is engine-reserved.
259 *
260 * @param spec ShaderSpec produced by ShaderSpec::Assemble::build().
261 * @return ShaderID on success, INVALID_SHADER on compilation failure.
262 */
263 ShaderID load_shader(const ShaderSpec& spec);
264
265 /**
266 * @brief Hot-reload shader (returns new ID)
267 */
268 ShaderID reload_shader(const std::string& filepath);
269
270 /**
271 * @brief Destroy shader (cleanup internal state)
272 */
273 void destroy_shader(ShaderID shader_id);
274
275 /**
276 * @brief Compile shader from ShaderSource descriptor
277 * @param shader_source Shader descriptor (path or source + type + stage)
278 * @return Compiled shader module, or nullptr on failure
279 *
280 * Unified interface that dispatches to appropriate compile method.
281 * Useful for abstracted shader loading pipelines.
282 */
283 std::shared_ptr<Core::VKShaderModule> compile(const ShaderSource& shader_source);
284
285 //==========================================================================
286 // Shader Introspection
287 //==========================================================================
288
289 /**
290 * @brief Get reflection info for compiled shader
291 * @param shader_id ID of compiled shader
292 * @return Reflection information
293 *
294 * Extracted during compilation if enabled in config.
295 * Includes descriptor bindings, push constant ranges, workgroup size, etc.
296 */
297 ShaderReflectionInfo get_shader_reflection(ShaderID shader_id);
298
299 /**
300 * @brief Get the descriptor bindings a shader's entry point statically uses
301 * @param shader_id ID of compiled shader
302 * @return Used bindings only, excluding declared but unused resources
303 */
304 std::vector<DescriptorBindingInfo> get_active_descriptor_bindings(ShaderID shader_id);
305
306 /**
307 * @brief Get shader stage for compiled shader
308 * @param shader_id ID of compiled shader
309 * @return Shader stage (COMPUTE, VERTEX, FRAGMENT, etc.)
310 */
311 ShaderStage get_shader_stage(ShaderID shader_id);
312
313 /**
314 * @brief Get entry point name for compiled shader
315 * @param shader_id ID of compiled shader
316 * @return Entry point function name
317 */
318 std::string get_shader_entry_point(ShaderID shader_id);
319
320 //==========================================================================
321 // Hot-Reload Support
322 //==========================================================================
323
324 /**
325 * @brief Invalidate cache for specific shader
326 * @param cache_key File path or cache key
327 *
328 * Forces next compilation to recompile from source.
329 * Useful for hot-reload workflows.
330 */
331 void invalidate_cache(const std::string& cache_key);
332
333 /**
334 * @brief Invalidate entire shader cache
335 *
336 * Forces all subsequent compilations to recompile.
337 * Does NOT destroy existing shader modules (they remain valid).
338 */
339 void clear_cache();
340
341 /**
342 * @brief Hot-reload a shader from file
343 * @param filepath Path to shader file
344 * @return Recompiled shader module, or nullptr on failure
345 *
346 * Convenience method: invalidate_cache() + compile_from_file().
347 * Returns new shader module; consumers must update references.
348 */
349 std::shared_ptr<Core::VKShaderModule> hot_reload(const std::string& filepath);
350
351 //==========================================================================
352 // Configuration
353 //==========================================================================
354
355 /**
356 * @brief Update compiler configuration
357 * @param config New configuration
358 *
359 * Affects future compilations.
360 * Does NOT recompile existing shaders.
361 */
362 void set_config(const ShaderCompilerConfig& config);
363
364 /**
365 * @brief Get current compiler configuration
366 */
367 [[nodiscard]] const ShaderCompilerConfig& get_config() const { return m_config; }
368
369 /**
370 * @brief Add include directory for shader compilation
371 * @param directory Path to directory containing shader includes
372 *
373 * Used for #include resolution in GLSL files.
374 */
375 void add_include_directory(const std::string& directory);
376
377 /**
378 * @brief Add preprocessor define for shader compilation
379 * @param name Macro name
380 * @param value Macro value (optional)
381 *
382 * Example: define("DEBUG", "1") → #define DEBUG 1
383 */
384 void add_define(const std::string& name, const std::string& value = "");
385
386 //==========================================================================
387 // Introspection
388 //==========================================================================
389
390 /**
391 * @brief Check if shader is cached
392 * @param cache_key File path or cache key
393 */
394 [[nodiscard]] bool is_cached(const std::string& cache_key) const;
395
396 /**
397 * @brief Get all cached shader keys
398 */
399 [[nodiscard]] std::vector<std::string> get_cached_keys() const;
400
401 /**
402 * @brief Get number of cached shaders
403 */
404 [[nodiscard]] size_t get_cache_size() const { return m_shader_cache.size(); }
405
406 //==========================================================================
407 // Descriptor Set Management - ShaderFoundry allocates and tracks
408 //==========================================================================
409
410 /**
411 * @brief Allocate descriptor set for a pipeline
412 * @param pipeline_id Which pipeline this is for
413 * @param set_index Which descriptor set (0, 1, 2...)
414 * @return Descriptor set ID
415 */
416 DescriptorSetID allocate_descriptor_set(vk::DescriptorSetLayout layout);
417
418 /**
419 * @brief Update descriptor set with buffer binding
420 * @param descriptor_set_id ID of descriptor set to update
421 * @param binding Binding index within the descriptor set
422 * @param type Descriptor type (e.g., eStorageBuffer, eUniformBuffer)
423 * @param buffer Vulkan buffer to bind
424 * @param offset Offset within the buffer
425 * @param size Size of the buffer region
426 */
427 void update_descriptor_buffer(
428 DescriptorSetID descriptor_set_id,
429 uint32_t binding,
430 vk::DescriptorType type,
431 vk::Buffer buffer,
432 size_t offset,
433 size_t size);
434
435 /**
436 * @brief Update several buffer descriptor slots in one Vulkan call.
437 *
438 * Equivalent to calling update_descriptor_buffer once per entry, except
439 * every entry is submitted through a single vkUpdateDescriptorSets call
440 * instead of one call per entry. Entries may target different descriptor
441 * sets; order among them does not matter since each names a distinct
442 * (descriptor set, binding). An entry naming an unknown descriptor_set_id
443 * is skipped, matching update_descriptor_buffer's behaviour for the same
444 * case. A call with an empty span does nothing.
445 *
446 * @param writes Slots to update.
447 */
448 void update_descriptor_buffers(std::span<const DescriptorBufferWrite> writes);
449
450 /**
451 * @brief Update descriptor set with image binding
452 * @param descriptor_set_id ID of descriptor set to update
453 * @param binding Binding index within the descriptor set
454 * @param image_view Vulkan image view to bind
455 * @param sampler Vulkan sampler to bind
456 * @param layout Image layout (default: eShaderReadOnlyOptimal)
457 * @param array_element Array index for array bindings (default: 0)
458 */
459 void update_descriptor_image(
460 DescriptorSetID descriptor_set_id,
461 uint32_t binding,
462 vk::ImageView image_view,
463 vk::Sampler sampler,
464 vk::ImageLayout layout = vk::ImageLayout::eShaderReadOnlyOptimal,
465 uint32_t array_element = 0);
466
467 /**
468 * @brief Update descriptor set with storage image binding
469 * @param descriptor_set_id ID of descriptor set to update
470 * @param binding Binding index within the descriptor set
471 * @param image_view Vulkan image view to bind
472 * @param layout Image layout (default: eGeneral)
473 */
474 void update_descriptor_storage_image(
475 DescriptorSetID descriptor_set_id,
476 uint32_t binding,
477 vk::ImageView image_view,
478 vk::ImageLayout layout = vk::ImageLayout::eGeneral);
479
480 /**
481 * @brief Update several image descriptor slots in one Vulkan call.
482 *
483 * Equivalent to calling update_descriptor_image or
484 * update_descriptor_storage_image once per entry, except every entry is
485 * submitted through a single vkUpdateDescriptorSets call. An entry
486 * naming an unknown descriptor_set_id is skipped. A call with an empty
487 * span does nothing.
488 *
489 * @param writes Slots to update.
490 */
491 void update_descriptor_images(std::span<const DescriptorImageWrite> writes);
492
493 /**
494 * @brief Get Vulkan descriptor set handle from DescriptorSetID
495 * @param descriptor_set_id Descriptor set ID
496 * @return Vulkan descriptor set handle
497 */
498 vk::DescriptorSet get_descriptor_set(DescriptorSetID descriptor_set_id);
499
500 //==========================================================================
501 // Command Recording - ShaderFoundry manages command buffers
502 //==========================================================================
503
504 /**
505 * @brief Begin recording command buffer
506 * @param type Command buffer type (GRAPHICS, COMPUTE, TRANSFER)
507 * @return Command buffer ID
508 */
509 CommandBufferID begin_commands(CommandBufferType type);
510
511 /**
512 * @brief Begin recording a secondary command buffer for dynamic rendering
513 * @param color_format Format of the color attachment (from swapchain)
514 * @return Command buffer ID
515 *
516 * With dynamic rendering, secondary buffers don't need render pass objects.
517 * They only need to know the attachment formats they'll render to.
518 */
519 CommandBufferID begin_secondary_commands(
520 vk::Format color_format,
521 vk::Format depth_format = vk::Format::eUndefined);
522
523 /**
524 * @brief Get Vulkan command buffer handle from CommandBufferID
525 * @param cmd_id Command buffer ID
526 */
527 vk::CommandBuffer get_command_buffer(CommandBufferID cmd_id);
528
529 /**
530 * @brief End recording command buffer
531 * @param cmd_id Command buffer ID to end
532 * @return True if successful, false if invalid ID or not active
533 */
534 bool end_commands(CommandBufferID cmd_id);
535
536 /**
537 * @brief Free all allocated command buffers
538 */
539 void free_all_command_buffers();
540
541 //==========================================================================
542 // Memory Barriers and Synchronization
543 //==========================================================================
544
545 /**
546 * @brief Submit command buffer and wait for completion
547 * @param cmd_id Command buffer ID to submit
548 */
549 void submit_and_wait(CommandBufferID cmd_id);
550
551 /**
552 * @brief Submit command buffer asynchronously, returning a fence
553 * @param cmd_id Command buffer ID to submit
554 * @return Fence ID to wait on later
555 */
556 FenceID submit_async(CommandBufferID cmd_id);
557
558 /**
559 * @brief Submit command buffer asynchronously, returning a semaphore
560 * @param cmd_id Command buffer ID to submit
561 * @return Semaphore ID to wait on later
562 */
563 SemaphoreID submit_with_signal(CommandBufferID cmd_id);
564
565 /**
566 * @brief Wait for fence to be signaled
567 * @param fence_id Fence ID to wait on
568 */
569 void wait_for_fence(FenceID fence_id);
570
571 /**
572 * @brief Wait for multiple fences to be signaled
573 * @param fence_ids Vector of fence IDs to wait on
574 */
575 void wait_for_fences(const std::vector<FenceID>& fence_ids);
576
577 /**
578 * @brief Destroy the fence and free its associated command buffer.
579 *
580 * Must be called once per FenceID returned by submit_async, after
581 * is_fence_signaled returns true. Failure to call this leaks a VkFence
582 * and a command buffer slot every dispatch cycle.
583 *
584 * Safe to call with INVALID_FENCE.
585 *
586 * @param fence_id FenceID returned by submit_async.
587 */
588 void release_fence(FenceID fence_id);
589
590 /**
591 * @brief Check if fence is signaled
592 * @param fence_id Fence ID to check
593 * @return True if fence is signaled, false otherwise
594 */
595 bool is_fence_signaled(FenceID fence_id);
596
597 /**
598 * @brief Begin command buffer that waits on a semaphore
599 * @param type Command buffer type (GRAPHICS, COMPUTE, TRANSFER)
600 * @param wait_semaphore Semaphore ID to wait on
601 * @param wait_stage Pipeline stage to wait at
602 * @return Command buffer ID
603 */
604 CommandBufferID begin_commands_with_wait(
605 CommandBufferType type,
606 SemaphoreID wait_semaphore,
607 vk::PipelineStageFlags wait_stage);
608
609 /**
610 * @brief Get Vulkan fence handle from FenceID
611 * @param fence_id Fence ID
612 */
613 vk::Semaphore get_semaphore_handle(SemaphoreID semaphore_id);
614
615 /**
616 * @brief Insert buffer memory barrier
617 */
618 void buffer_barrier(
619 CommandBufferID cmd_id,
620 vk::Buffer buffer,
621 vk::AccessFlags src_access,
622 vk::AccessFlags dst_access,
623 vk::PipelineStageFlags src_stage,
624 vk::PipelineStageFlags dst_stage);
625
626 /**
627 * @brief Insert image memory barrier
628 */
629 void image_barrier(
630 CommandBufferID cmd_id,
631 vk::Image image,
632 vk::ImageLayout old_layout,
633 vk::ImageLayout new_layout,
634 vk::AccessFlags src_access,
635 vk::AccessFlags dst_access,
636 vk::PipelineStageFlags src_stage,
637 vk::PipelineStageFlags dst_stage);
638
639 //==========================================================================
640 // Queue Management
641 //==========================================================================
642
643 /**
644 * @brief Set Vulkan queues for command submission
645 */
646 void set_graphics_queue(vk::Queue queue);
647
648 /**
649 * @brief Set Vulkan queues for command submission
650 */
651 void set_compute_queue(vk::Queue queue);
652
653 /**
654 * @brief Set Vulkan queues for command submission
655 */
656 void set_transfer_queue(vk::Queue queue);
657
658 /**
659 * @brief Get Vulkan graphics queue
660 */
661 [[nodiscard]] vk::Queue get_graphics_queue() const;
662
663 /**
664 * @brief Get Vulkan compute queue
665 */
666 [[nodiscard]] vk::Queue get_compute_queue() const;
667
668 /**
669 * @brief Get Vulkan transfer queue
670 */
671 [[nodiscard]] vk::Queue get_transfer_queue() const;
672
673 //==========================================================================
674 // Profiling
675 //==========================================================================
676
677 void begin_timestamp(CommandBufferID cmd_id, const std::string& label = "");
678 void end_timestamp(CommandBufferID cmd_id, const std::string& label = "");
679
681 std::string label;
682 uint64_t duration_ns;
683 bool valid;
684 };
685
686 TimestampResult get_timestamp_result(CommandBufferID cmd_id, const std::string& label);
687
688 //==========================================================================
689 // Utilities
690 //==========================================================================
691
692 /**
693 * @brief Convert Portal ShaderStage to Vulkan ShaderStageFlagBits
694 */
695 static vk::ShaderStageFlagBits to_vulkan_stage(ShaderStage stage);
696
697 /**
698 * @brief Auto-detect shader stage from file extension
699 * @param filepath Path to shader file
700 * @return Detected stage, or nullopt if unknown
701 *
702 * Delegates to VKShaderModule::detect_stage_from_extension().
703 */
704 static std::optional<ShaderStage> detect_stage_from_extension(const std::string& filepath);
705
706 //==========================================================================
707 // Device Access
708 //==========================================================================
709
710 /**
711 * @brief Get logical device handle
712 */
713 [[nodiscard]] vk::Device get_device() const;
714
715 /**
716 * @brief Get physical device handle
717 *
718 * Required by consumers that allocate raw Vulkan buffers directly
719 * (e.g. GpuComputeOperation) and need memory type selection via
720 * vk::PhysicalDevice::getMemoryProperties().
721 */
722 [[nodiscard]] vk::PhysicalDevice get_physical_device() const;
723
724private:
725 /**
726 * @enum DetectedSourceType
727 * @brief Internal enum for source type detection
728 */
729 enum class DetectedSourceType : uint8_t {
730 FILE_GLSL,
731 FILE_SPIRV,
732 SOURCE_STRING,
733 UNKNOWN
734 };
735
736 ShaderFoundry() = default;
737 ~ShaderFoundry() { shutdown(); }
738
739 std::shared_ptr<Core::VulkanBackend> m_backend;
741
742 std::unordered_map<std::string, std::shared_ptr<Core::VKShaderModule>> m_shader_cache;
743 std::unordered_map<ShaderID, ShaderState> m_shaders;
744 std::unordered_map<std::string, ShaderID> m_shader_filepath_cache;
745
746 std::shared_ptr<Core::VKDescriptorManager> m_global_descriptor_manager;
747 std::unordered_map<DescriptorSetID, DescriptorSetState> m_descriptor_sets;
748
749 std::unordered_map<CommandBufferID, CommandBufferState> m_command_buffers;
750
755
756 static constexpr size_t k_finished_timestamp_capacity = 1024;
757 Memory::HistoryBuffer<FinishedTimestamp> m_finished_timestamps { k_finished_timestamp_capacity };
758
759 std::unordered_map<FenceID, FenceState> m_fences;
760 std::unordered_map<SemaphoreID, SemaphoreState> m_semaphores;
761
765
766 std::atomic<uint64_t> m_next_shader_id { 1 };
767 std::atomic<uint64_t> m_next_descriptor_set_id { 1 };
768 std::atomic<uint64_t> m_next_command_id { 1 };
769 std::atomic<uint64_t> m_next_fence_id { 1 };
770 std::atomic<uint64_t> m_next_semaphore_id { 1 };
771
772 DetectedSourceType detect_source_type(const std::string& content) const;
773 std::optional<std::filesystem::path> resolve_shader_path(const std::string& filepath) const;
774 std::string generate_source_cache_key(const std::string& source, ShaderStage stage) const;
775
776 std::shared_ptr<Core::VKShaderModule> create_shader_module();
777
778 TimestampResult resolve_timestamp(const CommandBufferState& state, const std::string& label, bool wait);
779
780 void cleanup_sync_objects();
781 void cleanup_descriptor_resources();
782 void cleanup_shader_modules();
783
784 //==========================================================================
785 // INTERNAL Shader Compilation Methods
786 //==========================================================================
787
788 std::shared_ptr<Core::VKShaderModule> compile_from_file(
789 const std::string& filepath,
790 std::optional<ShaderStage> stage = std::nullopt,
791 const std::string& entry_point = "main");
792
793 std::shared_ptr<Core::VKShaderModule> compile_from_source(
794 const std::string& source,
795 ShaderStage stage,
796 const std::string& entry_point = "main");
797
798 std::shared_ptr<Core::VKShaderModule> compile_from_source_cached(
799 const std::string& source,
800 ShaderStage stage,
801 const std::string& cache_key,
802 const std::string& entry_point = "main");
803
804 std::shared_ptr<Core::VKShaderModule> compile_from_spirv(
805 const std::string& spirv_path,
806 ShaderStage stage,
807 const std::string& entry_point = "main");
808
809 std::shared_ptr<Core::VKShaderModule> compile_from_spirv_asm(
810 const std::string& spirv_asm,
811 ShaderStage stage,
812 const std::string& entry_point = "main");
813
814 std::shared_ptr<Core::VKShaderModule> get_vk_shader_module(ShaderID shader_id);
815
816 friend class ComputePress;
817 friend class RenderFlow;
818
819 static bool s_initialized;
820};
821
822/**
823 * @brief Get the global shader compiler instance
824 * @return Reference to singleton shader compiler
825 *
826 * Must call initialize() before first use.
827 * Thread-safe after initialization.
828 */
829inline MAYAFLUX_API ShaderFoundry& get_shader_foundry()
830{
832}
833
834} // namespace MayaFlux::Portal::Graphics
uint64_t offset
Definition Composite.cpp:10
uint32_t label
Definition Contours.cpp:16
IO::ImageData image
Definition Decoder.cpp:47
bool size
std::shared_ptr< NetworkGeometryBuffer > buffer
glm::vec3 value
vk::PhysicalDeviceType type
Definition VKDevice.cpp:126
std::string name
Definition VKDevice.cpp:123
History buffer for difference equations and recursive relations.
Compute-specific pipeline and dispatch orchestration.
Graphics pipeline orchestration for dynamic rendering.
ShaderFoundry(const ShaderFoundry &)=delete
ShaderFoundry & operator=(const ShaderFoundry &)=delete
size_t get_cache_size() const
Get number of cached shaders.
void set_compute_queue(vk::Queue queue)
Set Vulkan queues for command submission.
DetectedSourceType
Internal enum for source type detection.
std::unordered_map< std::string, ShaderID > m_shader_filepath_cache
std::unordered_map< FenceID, FenceState > m_fences
void set_graphics_queue(vk::Queue queue)
Set Vulkan queues for command submission.
void set_transfer_queue(vk::Queue queue)
Set Vulkan queues for command submission.
ShaderFoundry(ShaderFoundry &&) noexcept=delete
std::unordered_map< std::string, std::shared_ptr< Core::VKShaderModule > > m_shader_cache
std::unordered_map< DescriptorSetID, DescriptorSetState > m_descriptor_sets
std::unordered_map< CommandBufferID, CommandBufferState > m_command_buffers
std::shared_ptr< Core::VKDescriptorManager > m_global_descriptor_manager
bool is_initialized() const
Check if compiler is initialized.
std::shared_ptr< Core::VulkanBackend > m_backend
std::unordered_map< SemaphoreID, SemaphoreState > m_semaphores
const ShaderCompilerConfig & get_config() const
Get current compiler configuration.
std::unordered_map< ShaderID, ShaderState > m_shaders
Portal-level shader compilation and caching.
void initialize()
Definition main.cpp:10
std::string emit_glsl_kernel(const ShaderSpec &spec)
Emit a complete GLSL compute shader from spec metadata and a KernelSource body.
std::string emit_spirv_asm(const ShaderSpec &spec)
Emit complete SPIR-V assembly text for a generated compute kernel.
void stop()
Stop all Portal::Graphics operations.
Definition Graphics.cpp:69
ShaderStage
User-friendly shader stage enum.
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
constexpr CommandBufferID INVALID_COMMAND_BUFFER
@ GRAPHICS
Standard real-time graphics processing domain.
Definition Domain.hpp:55
One descriptor set slot to update, for ShaderFoundry::update_descriptor_buffers.
One descriptor set slot to update, for ShaderFoundry::update_descriptor_images.
Configuration for shader compilation.
std::unordered_map< std::string, uint32_t > timestamp_queries
std::shared_ptr< Core::VKShaderModule > std::string filepath
Extracted reflection information from compiled shader.
Shader source descriptor for compilation.
Complete declarative description of a generated compute shader.