MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
TextureLoom.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <vulkan/vulkan.hpp>
4
5#include "GraphicsUtils.hpp"
6
8
9namespace MayaFlux::Core {
10class VulkanBackend;
11class BackendResourceManager;
12}
13
14namespace MayaFlux::Buffers {
15class VKBuffer;
16}
17
19
20/** @brief Immutable properties that determine whether an image can be reused. */
21struct ImageKey {
22 enum class Kind : uint8_t {
26 };
27
28 uint32_t width {};
29 uint32_t height {};
30 uint32_t layers { 1 };
31 uint32_t mip_levels { 1 };
34
35 [[nodiscard]] bool operator==(const ImageKey&) const = default;
36};
37
38/** @brief Hash image allocation properties for keyed reuse. */
39struct MAYAFLUX_API ImageKeyHash {
40 [[nodiscard]] size_t operator()(const ImageKey& key) const noexcept;
41};
42
43/** @brief Image retained by the producing owner. */
46 std::shared_ptr<Core::VKImage> image;
47};
48
49/**
50 * @brief One layer to layer copy that scales and converts format.
51 *
52 * Whole images by default, stretched to fit. Rectangles are in pixels and a zero
53 * extent runs to the image edge. A smaller @c dst rectangle letterboxes, a smaller
54 * @c src rectangle crops, and the flips mirror the destination.
55 */
56struct LayerBlit {
57 uint32_t src_layer {};
58 uint32_t dst_layer {};
59 vk::Rect2D src {};
60 vk::Rect2D dst {};
62 bool flip_x {};
63 bool flip_y {};
64};
65
66/**
67 * @class TextureLoom
68 * @brief Portal-level texture creation and management
69 *
70 * TextureLoom is the primary Portal::Graphics class for creating and
71 * managing GPU textures. It bridges between user-friendly Portal API and
72 * backend VKImage resources via BufferService registry.
73 *
74 * Key Responsibilities:
75 * - Create textures (2D, 3D, cubemaps, render targets)
76 * - Load textures from files (delegates to IO namespace)
77 * - Manage sampler objects (filtering, addressing)
78 * - Track texture lifecycle for cleanup
79 * - Provide convenient format conversions
80 *
81 * Design Philosophy:
82 * - Manages creation, NOT rendering (that's Pipeline/RenderPass)
83 * - Returns VKImage directly (no wrapping yet)
84 * - Simple, focused API (file loading deferred to IO)
85 * - Integrates with BufferService for backend independence
86 *
87 * Usage:
88 * auto& mgr = Portal::Graphics::TextureLoom::instance();
89 *
90 * // Create basic texture
91 * auto texture = mgr.create_2d(512, 512, ImageFormat::RGBA8);
92 *
93 * // Create with data
94 * std::vector<uint8_t> pixels = {...};
95 * auto texture = mgr.create_2d(512, 512, ImageFormat::RGBA8, pixels.data());
96 *
97 * // Create render target
98 * auto target = mgr.create_render_target(1920, 1080);
99 *
100 * // Get sampler
101 * SamplerConfig config;
102 * config.mag_filter = FilterMode::LINEAR;
103 * auto sampler = mgr.get_or_create_sampler(config);
104 */
105class MAYAFLUX_API TextureLoom {
106public:
108 {
109 static TextureLoom manager;
110 return manager;
111 }
112
113 // Non-copyable, movable
114 TextureLoom(const TextureLoom&) = delete;
116 TextureLoom(TextureLoom&&) noexcept = default;
117 TextureLoom& operator=(TextureLoom&&) noexcept = default;
118
119 /**
120 * @brief Initialize texture manager
121 * @param backend Shared pointer to VulkanBackend
122 * @return True if initialization succeeded
123 *
124 * Queries BufferService from BackendRegistry.
125 * Must be called before creating any textures.
126 */
127 bool initialize(const std::shared_ptr<Core::VulkanBackend>& backend);
128
129 /**
130 * @brief Shutdown and cleanup all textures
131 *
132 * Destroys all managed textures and samplers.
133 * Safe to call multiple times.
134 */
135 void shutdown();
136
137 /**
138 * @brief Check if manager is initialized
139 */
140 [[nodiscard]] bool is_initialized() const { return m_backend != nullptr; }
141
142 //==========================================================================
143 // Texture Creation
144 //==========================================================================
145
146 /**
147 * @brief Create a 2D texture
148 * @param width Width in pixels
149 * @param height Height in pixels
150 * @param format Image format
151 * @param data Optional initial pixel data (nullptr = empty)
152 * @param mip_levels Number of mipmap levels (1 = no mipmaps)
153 * @return Initialized VKImage ready for use
154 *
155 * Creates device-local texture optimized for shader sampling.
156 * If data provided, uploads immediately and transitions to shader read layout.
157 */
158 std::shared_ptr<Core::VKImage> create_2d(
159 uint32_t width,
160 uint32_t height,
161 ImageFormat format = ImageFormat::RGBA8,
162 const void* data = nullptr,
163 uint32_t mip_levels = 1);
164
165 /**
166 * @brief Allocate a 2D texture without uploading data or transitioning
167 * its layout - left VK_IMAGE_LAYOUT_UNDEFINED.
168 *
169 * Every create_2d*() overload above performs (and blocks on) an initial
170 * layout transition or upload of its own, even when called with no
171 * data - create_2d(w, h, format, nullptr) still does a blocking
172 * transition to eShaderReadOnlyOptimal before returning. Use this
173 * instead when the caller is about to record its own upload right
174 * after (e.g. upload_data(image, data, size, staging, true) with
175 * deferred=true), so the whole undefined -> transfer-dst -> copy ->
176 * shader-read sequence is recorded once into a deferred command batch instead of
177 * paying for a separate blocking queue.waitIdle() first.
178 *
179 * @param width Width in pixels.
180 * @param height Height in pixels.
181 * @param format Image format (default RGBA8).
182 * @param mip_levels Number of mipmap levels (1 = no mipmaps).
183 * @return VKImage with device memory allocated, still in
184 * VK_IMAGE_LAYOUT_UNDEFINED, or nullptr on failure.
185 * The caller owns transitioning it before use.
186 */
187 [[nodiscard]] std::shared_ptr<Core::VKImage> create_2d_uninitialized(
188 uint32_t width,
189 uint32_t height,
190 ImageFormat format = ImageFormat::RGBA8,
191 uint32_t mip_levels = 1);
192
193 /**
194 * @brief Create a 3D texture (volumetric)
195 * @param width Width in pixels
196 * @param height Height in pixels
197 * @param depth Depth in pixels
198 * @param format Image format
199 * @param data Optional initial pixel data
200 * @return Initialized VKImage
201 */
202 std::shared_ptr<Core::VKImage> create_3d(
203 uint32_t width,
204 uint32_t height,
205 uint32_t depth,
206 ImageFormat format = ImageFormat::RGBA8,
207 const void* data = nullptr);
208
209 /**
210 * @brief Create a cubemap texture
211 * @param size Cubemap face size in pixels (square)
212 * @param format Image format
213 * @param data Optional face data (6 faces in order: +X,-X,+Y,-Y,+Z,-Z)
214 * @return Initialized VKImage configured as cubemap
215 */
216 std::shared_ptr<Core::VKImage> create_cubemap(
217 uint32_t size,
218 ImageFormat format = ImageFormat::RGBA8,
219 const void* data = nullptr);
220
221 /**
222 * @brief Create a 2D texture array.
223 *
224 * All layers share the same width, height, and format. The image view
225 * type is VK_IMAGE_VIEW_TYPE_2D_ARRAY, making it bindable as
226 * sampler2DArray in GLSL.
227 *
228 * @param width Width in pixels per layer.
229 * @param height Height in pixels per layer.
230 * @param layers Number of array layers. Must be > 0.
231 * @param format Image format (default RGBA8).
232 * @param data Optional pixel data for all layers concatenated in order
233 * (layer 0 first). Must be exactly
234 * width * height * bpp(format) * layers bytes when non-null.
235 * Pass nullptr to allocate without uploading; the image is
236 * transitioned to eShaderReadOnlyOptimal.
237 * @return Initialised VKImage with array_layers == layers, or nullptr on failure.
238 */
239 std::shared_ptr<Core::VKImage> create_2d_array(
240 uint32_t width,
241 uint32_t height,
242 uint32_t layers,
243 ImageFormat format = ImageFormat::RGBA8,
244 const void* data = nullptr);
245
246 /**
247 * @brief Create a render target (color attachment)
248 * @param width Width in pixels
249 * @param height Height in pixels
250 * @param format Image format (default RGBA8)
251 * @return Initialized VKImage configured for rendering
252 *
253 * Creates image suitable for use as framebuffer color attachment.
254 * Can also be sampled in shaders after rendering.
255 */
256 std::shared_ptr<Core::VKImage> create_render_target(
257 uint32_t width,
258 uint32_t height,
259 ImageFormat format = ImageFormat::RGBA8);
260
261 /**
262 * @brief Create a depth buffer
263 * @param width Width in pixels
264 * @param height Height in pixels
265 * @param with_stencil Whether to include stencil component
266 * @return Initialized VKImage configured as depth/stencil attachment
267 */
268 std::shared_ptr<Core::VKImage> create_depth_buffer(
269 uint32_t width,
270 uint32_t height,
271 bool with_stencil = false);
272
273 /**
274 * @brief Create a storage image (compute shader read/write)
275 * @param width Width in pixels
276 * @param height Height in pixels
277 * @param format Image format
278 * @return Initialized VKImage configured for compute storage
279 */
280 std::shared_ptr<Core::VKImage> create_storage_image(
281 uint32_t width,
282 uint32_t height,
283 ImageFormat format = ImageFormat::RGBA8);
284
285 /**
286 * @brief Reuse a matching image in an owner-held entry or create it once.
287 * @param entry Cache entry retained by the image producer.
288 * @param key Immutable image allocation properties.
289 * @return Matching image, or nullptr on failure.
290 */
291 [[nodiscard]] std::shared_ptr<Core::VKImage> acquire_cached_image(
292 ImageCacheEntry& entry, const ImageKey& key);
293
294 /**
295 * @brief Refresh a sampled image in an owner-held cache entry.
296 * @param entry Cache entry retained by the image producer.
297 * @param key Sampled image allocation properties.
298 * @param pixels Complete pixel bytes for every layer.
299 * @param staging Optional caller staging buffer. Without one, upload_data
300 * uses its existing transient staging path.
301 * @return Refreshed image, or nullptr when validation or creation fails.
302 */
303 [[nodiscard]] std::shared_ptr<Core::VKImage> refresh_cached_image(
304 ImageCacheEntry& entry,
305 const ImageKey& key,
306 std::span<const uint8_t> pixels,
307 const std::shared_ptr<Buffers::VKBuffer>& staging = {});
308
309 /**
310 * @brief Create a 2D texture from a DataVariant in one shot.
311 * @param variant Source data. Conversion and validation delegated to
312 * Kakshya::as_texture_access(): vec3 is promoted to vec4
313 * with W=0 (warned); complex<double> and mat4 are rejected.
314 * @param width Texture width in texels.
315 * @param height Texture height in texels.
316 * @param format Target image format (default: RGBA32F).
317 * @return Initialised VKImage in shader-read layout, or nullptr on failure.
318 *
319 * Validates byte count against width * height * bpp(format) before upload.
320 * Throws std::invalid_argument on mismatch.
321 */
322 [[nodiscard]] std::shared_ptr<Core::VKImage> create_2d(
323 const Kakshya::DataVariant& variant,
324 uint32_t width,
325 uint32_t height,
326 ImageFormat format = ImageFormat::RGBA32F);
327
328 //==========================================================================
329 // Data Upload/Download
330 //==========================================================================
331
332 /**
333 * @brief Upload pixel data to an existing texture
334 * @param image Target image
335 * @param data Pixel data pointer
336 * @param size Data size in bytes
337 *
338 * Handles staging buffer, layout transitions, and cleanup.
339 * Blocks until upload completes.
340 */
341 void upload_data(
342 const std::shared_ptr<Core::VKImage>& image,
343 const void* data,
344 size_t size);
345
346 /**
347 * @brief Upload pixel data reusing a caller-supplied persistent staging buffer.
348 * Identical to upload_data() but skips the per-call VkBuffer allocation,
349 * eliminating the Vulkan object churn that causes VK_ERROR_DEVICE_LOST
350 * under sustained per-frame texture updates (e.g. video playback).
351 * @param image Target VKImage (must already be initialised).
352 * @param data Pixel data pointer (at least @p size bytes).
353 * @param size Byte count — must match the image footprint.
354 * @param staging Host-visible staging VKBuffer from create_streaming_staging().
355 * @param deferred. If true, record_deferred_commands will be used by the backend.
356 */
357 void upload_data(
358 const std::shared_ptr<Core::VKImage>& image,
359 const void* data,
360 size_t size,
361 const std::shared_ptr<Buffers::VKBuffer>& staging, bool deferred = false);
362
363 /**
364 * @brief Download pixel data from a VKImage, reusing a caller-supplied
365 * persistent staging buffer.
366 *
367 * When @p staging is null, falls through to the per-call blocking path.
368 * When @p staging is supplied, submits under a fence (fenced, not waitIdle)
369 * so other GPU work proceeds concurrently during the wait.
370 * When @p deferred is true, records commands for deferred submission;
371 * the caller is responsible for flushing. Ignored when staging is null.
372 *
373 * The staging buffer must be host-visible and at least @p size bytes.
374 * Allocate once with Buffers::create_image_staging_buffer(size).
375 *
376 * @param image Source VKImage. Must be initialised.
377 * @param data Destination host pointer, at least @p size bytes.
378 * @param size Byte count to read.
379 * @param staging Persistent staging buffer, or nullptr for per-call path.
380 * @param deferred When true and staging is supplied, records for deferred
381 * submission rather than immediate fenced execution.
382 * @param restore_layout Layout the image is left in. The default matches the
383 * layout the download previously always restored.
384 * @param restore_stage Pipeline stage that consumes the image after restore.
385 */
386 void download_data(
387 const std::shared_ptr<Core::VKImage>& image,
388 void* data,
389 size_t size,
390 const std::shared_ptr<Buffers::VKBuffer>& staging,
391 bool deferred = false,
392 vk::ImageLayout restore_layout = vk::ImageLayout::eShaderReadOnlyOptimal,
393 vk::PipelineStageFlags restore_stage = vk::PipelineStageFlagBits::eFragmentShader);
394
395 /**
396 * @brief Download the base level of an image as typed pixels.
397 *
398 * Blocking. The element type of the returned storage follows the format:
399 * one byte per channel gives uint8, two gives uint16, four gives float.
400 *
401 * @param image Source image. Must satisfy readable_format().
402 * @param staging Persistent host-visible staging buffer of at least
403 * the base level's byte size, or nullptr for a per-call one.
404 * @param restore_layout Layout the image is left in.
405 * @param restore_stage Pipeline stage that consumes the image after restore.
406 * @return The pixels with width, height, channels and format set, or
407 * nullopt, with an error logged, if the image is not readable or
408 * the loom is not initialised.
409 */
410 [[nodiscard]] std::optional<Kakshya::ImageData> download_image(
411 const std::shared_ptr<Core::VKImage>& image,
412 const std::shared_ptr<Buffers::VKBuffer>& staging = nullptr,
413 vk::ImageLayout restore_layout = vk::ImageLayout::eShaderReadOnlyOptimal,
414 vk::PipelineStageFlags restore_stage = vk::PipelineStageFlagBits::eFragmentShader);
415
416 /**
417 * @brief Transition a VKImage to a new Vulkan layout via an immediate submission.
418 * @param image Image to transition. Must be initialised.
419 * @param old_layout Current layout of the image.
420 * @param new_layout Target layout.
421 * @param mip_levels Number of mip levels covered by the transition.
422 * @param array_layers Number of array layers covered by the transition.
423 * @param aspect_mask Image aspect flags (colour, depth, stencil).
424 *
425 * Delegates to BackendResourceManager and updates the image's tracked layout.
426 * Use before binding an image to a compute shader descriptor or before
427 * upload/download operations that require a specific layout.
428 */
429 void transition_layout(
430 const std::shared_ptr<Core::VKImage>& image,
431 vk::ImageLayout old_layout,
432 vk::ImageLayout new_layout,
433 uint32_t mip_levels = 1,
434 uint32_t array_layers = 1,
435 vk::ImageAspectFlags aspect_mask = vk::ImageAspectFlagBits::eColor);
436
437 /**
438 * @brief Upload pixels into one layer of an array image.
439 *
440 * The other layers keep their contents. @p size must be one layer's byte count.
441 *
442 * @param image Array image.
443 * @param layer Layer index.
444 * @param data Pixels of one layer.
445 * @param size Byte count of one layer.
446 * @param staging Persistent staging buffer, or nullptr for a per-call one.
447 * @param deferred Record for deferred submission (requires @p staging).
448 * @return True if the upload was recorded or executed.
449 */
450 bool upload_layer(
451 const std::shared_ptr<Core::VKImage>& image,
452 uint32_t layer,
453 const void* data,
454 size_t size,
455 const std::shared_ptr<Buffers::VKBuffer>& staging = nullptr,
456 bool deferred = false);
457
458 /**
459 * @brief Copy a layer of one image into a layer of another, scaling to fit.
460 *
461 * Works between any two color images, so it writes GPU images into an array
462 * layer without a host read, and also converts between supported formats. A
463 * cubic filter is not available and falls back to linear.
464 *
465 * @param src Source image, distinct from @p dst.
466 * @param dst Destination image.
467 * @param blit Layers, rectangles, filter and flips.
468 * @param deferred Record for deferred submission.
469 * @return True if the blit was recorded or executed.
470 */
471 bool blit_layer(
472 const std::shared_ptr<Core::VKImage>& src,
473 const std::shared_ptr<Core::VKImage>& dst,
474 const LayerBlit& blit = {},
475 bool deferred = false);
476
477 /**
478 * @brief Whether the device can blit between two images with a filter.
479 */
480 [[nodiscard]] bool can_blit(
481 const std::shared_ptr<Core::VKImage>& src,
482 const std::shared_ptr<Core::VKImage>& dst,
483 FilterMode filter = FilterMode::LINEAR) const;
484
485 //==========================================================================
486 // Sampler Management
487 //==========================================================================
488
489 /**
490 * @brief Get or create a sampler with the given configuration
491 * @param config Sampler configuration
492 * @return Vulkan sampler handle (cached)
493 *
494 * Samplers are cached - identical configs return same sampler.
495 * Managed by TextureLoom, destroyed on shutdown.
496 */
497 vk::Sampler get_or_create_sampler(const SamplerConfig& config);
498
499 /**
500 * @brief Get a default linear sampler (for convenience)
501 */
502 vk::Sampler get_default_sampler();
503
504 /**
505 * @brief Get a default nearest sampler (for pixel-perfect sampling)
506 */
507 vk::Sampler get_nearest_sampler();
508
509 //==========================================================================
510 // Utilities
511 //==========================================================================
512
513 /**
514 * @brief Convert Portal ImageFormat to Vulkan format
515 */
516 static vk::Format to_vulkan_format(ImageFormat format);
517
518 /**
519 * @brief Get bytes per pixel for a format
520 */
521 static size_t get_bytes_per_pixel(ImageFormat format);
522
523 /**
524 * @brief Convert Vulkan format to Portal ImageFormat.
525 *
526 * Reverse twin of to_vulkan_format. Returns std::nullopt for Vulkan
527 * formats with no ImageFormat equivalent rather than guessing.
528 */
529 static std::optional<ImageFormat> from_vulkan_format(vk::Format vk_format);
530
531 /**
532 * @brief ImageFormat of an image that can be read back as one flat block.
533 *
534 * Requires an initialised 2D image of one layer and depth 1 with a
535 * transfer-source usage, a format with an ImageFormat mapping that is not
536 * combined depth-stencil, and a nonzero base level that fits the image's
537 * allocation. The base level's byte count is
538 * calculate_image_size(width, height, 1, format).
539 *
540 * Checks structure only: it says nothing about the image's current layout
541 * or whether anything has been written to it.
542 *
543 * @return The format, or nullopt when any requirement is not met.
544 */
545 [[nodiscard]] static std::optional<ImageFormat> readable_format(
546 const std::shared_ptr<Core::VKImage>& image);
547
548 /**
549 * @brief ImageFormat of an image that can be written as one flat block.
550 *
551 * The mirror of readable_format() with transfer-destination usage in
552 * place of transfer-source: an initialised single-layer 2D image of depth 1,
553 * a mapped format that is not combined depth-stencil, and a nonzero base
554 * level that fits the image's allocation.
555 *
556 * @return The format, or nullopt when any requirement is not met.
557 */
558 [[nodiscard]] static std::optional<ImageFormat> writable_format(
559 const std::shared_ptr<Core::VKImage>& image);
560
561 /**
562 * @brief Calculate image data size
563 */
564 static size_t calculate_image_size(
565 uint32_t width,
566 uint32_t height,
567 uint32_t depth,
568 ImageFormat format);
569
570 /**
571 * @brief Get the number of color channels for a given format
572 */
573 static uint32_t get_channel_count(ImageFormat format);
574
575private:
576 static std::optional<ImageFormat> transfer_format(
577 const std::shared_ptr<Core::VKImage>& image,
578 vk::ImageUsageFlagBits required_usage);
579
580 TextureLoom() = default;
581 ~TextureLoom() { shutdown(); }
582
583 std::shared_ptr<Core::VulkanBackend> m_backend;
584 Core::BackendResourceManager* m_resource_manager = nullptr;
585
586 // Managed textures (for cleanup)
587 std::vector<std::shared_ptr<Core::VKImage>> m_textures;
588
589 // Sampler cache (config hash -> sampler)
590 std::unordered_map<size_t, vk::Sampler> m_sampler_cache;
591
592 // Helper: create sampler from config
593 vk::Sampler create_sampler(const SamplerConfig& config);
594
595 // Helper: hash sampler config for caching
596 static size_t hash_sampler_config(const SamplerConfig& config);
597
598 static bool s_initialized;
599};
600
601/**
602 * @brief Cache images keyed by immutable allocation properties.
603 *
604 * The byte budget is a warning threshold. Entries remain cached after the
605 * threshold is exceeded because TextureLoom retains created images until
606 * shutdown and eviction would recreate them on a later request.
607 */
608class MAYAFLUX_API ImageCacheSet {
609public:
610 explicit ImageCacheSet(size_t byte_budget)
611 : m_byte_budget(byte_budget)
612 {
613 }
614
615 ImageCacheSet(const ImageCacheSet&) = delete;
617 ImageCacheSet(ImageCacheSet&&) noexcept = default;
618 ImageCacheSet& operator=(ImageCacheSet&&) noexcept = default;
619 ~ImageCacheSet() = default;
620
621 [[nodiscard]] std::shared_ptr<Core::VKImage> acquire(
622 TextureLoom& loom, const ImageKey& key);
623
624private:
628
629 std::unordered_map<ImageKey, Entry, ImageKeyHash> m_entries;
631 size_t m_cached_bytes {};
632 bool m_budget_warned {};
633 std::optional<ImageKey> m_last_key;
634 Entry* m_last_entry {};
635};
636
637/**
638 * @brief Get the global texture manager instance
639 * @return Reference to singleton texture manager
640 *
641 * Must call initialize() before first use.
642 * Thread-safe after initialization.
643 */
644inline MAYAFLUX_API TextureLoom& get_texture_manager()
645{
646 return TextureLoom::instance();
647}
648
649} // namespace MayaFlux::Portal::Graphics
IO::ImageData image
Definition Decoder.cpp:47
const std::vector< float > * pixels
Definition Decoder.cpp:48
bool format
bool size
uint32_t * dst
const uint32_t * src
uint32_t width
uint32_t height
uint32_t depth
Manages Vulkan resources (buffers, images, samplers) for the graphics backend.
ImageCacheSet & operator=(const ImageCacheSet &)=delete
ImageCacheSet(const ImageCacheSet &)=delete
ImageCacheSet(ImageCacheSet &&) noexcept=default
std::unordered_map< ImageKey, Entry, ImageKeyHash > m_entries
Cache images keyed by immutable allocation properties.
TextureLoom(const TextureLoom &)=delete
std::shared_ptr< Core::VulkanBackend > m_backend
TextureLoom(TextureLoom &&) noexcept=default
TextureLoom & operator=(const TextureLoom &)=delete
std::vector< std::shared_ptr< Core::VKImage > > m_textures
std::unordered_map< size_t, vk::Sampler > m_sampler_cache
Portal-level texture creation and management.
void initialize()
Definition main.cpp:10
ImageFormat
User-friendly image format enum.
Definition ImageData.hpp:12
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:70
MAYAFLUX_API TextureLoom & get_texture_manager()
Get the global texture manager instance.
FilterMode
Texture filtering mode.
@ LINEAR
Bilinear filtering (smooth)
std::shared_ptr< Kriya::SamplingPipeline > create_sampler(const std::string &filepath, uint32_t num_samples, bool truncate, uint32_t channel, uint64_t max_dur_ms)
Construct a built SamplingPipeline from an audio file.
Definition Rigs.cpp:20
std::shared_ptr< Core::VKImage > image
Image retained by the producing owner.
Hash image allocation properties for keyed reuse.
bool operator==(const ImageKey &) const =default
Immutable properties that determine whether an image can be reused.
One layer to layer copy that scales and converts format.