MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
TextureLoom.cpp
Go to the documentation of this file.
1#include "TextureLoom.hpp"
2
6
8
12
14
16
18
19bool TextureLoom::initialize(const std::shared_ptr<Core::VulkanBackend>& backend)
20{
21 if (s_initialized) {
23 "TextureLoom already initialized (static flag)");
24 return true;
25 }
26
27 if (!backend) {
29 "Cannot initialize TextureLoom with null backend");
30 return false;
31 }
32
33 if (m_backend) {
35 "TextureLoom already initialized");
36 return true;
37 }
38
39 m_backend = backend;
40 m_resource_manager = &m_backend->get_resource_manager();
41 s_initialized = true;
42
44 "TextureLoom initialized");
45 return true;
46}
47
49{
50 if (!s_initialized) {
51 return;
52 }
53
54 if (!m_backend) {
55 return;
56 }
57
59 "Shutting down TextureLoom...");
60
61 for (auto& texture : m_textures) {
62 if (texture && texture->is_initialized()) {
64 }
65 }
66 m_textures.clear();
67 m_sampler_cache.clear();
68 m_resource_manager = nullptr;
69 m_backend = nullptr;
70
71 s_initialized = false;
72
74 "TextureLoom shutdown complete");
75}
76
77//==============================================================================
78// Texture Creation
79//==============================================================================
80
81std::shared_ptr<Core::VKImage> TextureLoom::create_2d(
82 uint32_t width, uint32_t height,
83 ImageFormat format, const void* data, uint32_t mip_levels)
84{
85 if (!is_initialized()) {
87 "TextureLoom not initialized");
88 return nullptr;
89 }
90
91 auto vk_format = to_vulkan_format(format);
92 auto image = std::make_shared<Core::VKImage>(
93 width, height, 1, vk_format,
96 mip_levels, 1,
98
100
101 if (!image->is_initialized()) {
103 "Failed to initialize VKImage");
104 return nullptr;
105 }
106
107 if (data) {
108 size_t data_size = calculate_image_size(width, height, 1, format);
109 upload_data(image, data, data_size);
110 } else {
112 image->get_image(),
113 vk::ImageLayout::eUndefined,
114 vk::ImageLayout::eShaderReadOnlyOptimal,
115 mip_levels, 1, vk::ImageAspectFlagBits::eColor);
116 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
117 }
118
119 m_textures.push_back(image);
121 "Created 2D texture: {}x{}, format: {}, mips: {}",
122 width, height, vk::to_string(vk_format), mip_levels);
123 return image;
124}
125
126std::shared_ptr<Core::VKImage> TextureLoom::create_3d(
127 uint32_t width, uint32_t height, uint32_t depth,
128 ImageFormat format, const void* data)
129{
130 if (!is_initialized()) {
132 "TextureLoom not initialized");
133 return nullptr;
134 }
135
136 auto vk_format = to_vulkan_format(format);
137 auto image = std::make_shared<Core::VKImage>(
138 width, height, depth, vk_format,
142
144
145 if (!image->is_initialized()) {
147 "Failed to initialize 3D VKImage");
148 return nullptr;
149 }
150
151 if (data) {
152 size_t data_size = calculate_image_size(width, height, depth, format);
153 upload_data(image, data, data_size);
154 } else {
156 image->get_image(),
157 vk::ImageLayout::eUndefined,
158 vk::ImageLayout::eShaderReadOnlyOptimal,
159 1, 1, vk::ImageAspectFlagBits::eColor);
160 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
161 }
162
163 m_textures.push_back(image);
165 "Created 3D texture: {}x{}x{}, format: {}",
166 width, height, depth, vk::to_string(vk_format));
167 return image;
168}
169
170std::shared_ptr<Core::VKImage> TextureLoom::create_cubemap(
171 uint32_t size, ImageFormat format, const void* data)
172{
173 if (!is_initialized()) {
175 "TextureLoom not initialized");
176 return nullptr;
177 }
178
179 auto vk_format = to_vulkan_format(format);
180 auto image = std::make_shared<Core::VKImage>(
181 size, size, 1, vk_format,
185
187
188 if (!image->is_initialized()) {
190 "Failed to initialize cubemap VKImage");
191 return nullptr;
192 }
193
194 if (data) {
195 size_t face_size = calculate_image_size(size, size, 1, format);
196 size_t total_size = face_size * 6;
197 upload_data(image, data, total_size);
198 } else {
200 image->get_image(),
201 vk::ImageLayout::eUndefined,
202 vk::ImageLayout::eShaderReadOnlyOptimal,
203 1, 6, vk::ImageAspectFlagBits::eColor);
204 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
205 }
206
207 m_textures.push_back(image);
209 "Created cubemap: {}x{}, format: {}", size, size, vk::to_string(vk_format));
210 return image;
211}
212
213std::shared_ptr<Core::VKImage> TextureLoom::create_render_target(
214 uint32_t width, uint32_t height, ImageFormat format)
215{
216 if (!is_initialized()) {
218 "TextureLoom not initialized");
219 return nullptr;
220 }
221
222 auto vk_format = to_vulkan_format(format);
223 auto image = std::make_shared<Core::VKImage>(
224 width, height, 1, vk_format,
228
230
231 if (!image->is_initialized()) {
233 "Failed to initialize render target VKImage");
234 return nullptr;
235 }
236
238 image->get_image(),
239 vk::ImageLayout::eUndefined,
240 vk::ImageLayout::eColorAttachmentOptimal,
241 1, 1, vk::ImageAspectFlagBits::eColor);
242 image->set_current_layout(vk::ImageLayout::eColorAttachmentOptimal);
243
244 m_textures.push_back(image);
246 "Created render target: {}x{}, format: {}",
247 width, height, vk::to_string(vk_format));
248 return image;
249}
250
251std::shared_ptr<Core::VKImage> TextureLoom::create_depth_buffer(
252 uint32_t width, uint32_t height, bool with_stencil)
253{
254 if (!is_initialized()) {
256 "TextureLoom not initialized");
257 return nullptr;
258 }
259
260 vk::Format vk_format = with_stencil
261 ? vk::Format::eD24UnormS8Uint
262 : vk::Format::eD32Sfloat;
263
264 auto image = std::make_shared<Core::VKImage>(
265 width, height, 1, vk_format,
269
271
272 if (!image->is_initialized()) {
274 "Failed to initialize depth buffer VKImage");
275 return nullptr;
276 }
277
278 vk::ImageAspectFlags aspect = with_stencil
279 ? (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil)
280 : vk::ImageAspectFlagBits::eDepth;
281
283 image->get_image(),
284 vk::ImageLayout::eUndefined,
285 vk::ImageLayout::eDepthStencilAttachmentOptimal,
286 1, 1, aspect);
287 image->set_current_layout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
288
289 m_textures.push_back(image);
291 "Created depth buffer: {}x{}, format: {}, stencil: {}",
292 width, height, vk::to_string(vk_format), with_stencil);
293 return image;
294}
295
296std::shared_ptr<Core::VKImage> TextureLoom::create_storage_image(
297 uint32_t width, uint32_t height, ImageFormat format)
298{
299 if (!is_initialized()) {
301 "TextureLoom not initialized");
302 return nullptr;
303 }
304
305 auto vk_format = to_vulkan_format(format);
306 auto image = std::make_shared<Core::VKImage>(
307 width, height, 1, vk_format,
311
313
314 if (!image->is_initialized()) {
316 "Failed to initialize storage image VKImage");
317 return nullptr;
318 }
319
321 image->get_image(),
322 vk::ImageLayout::eUndefined,
323 vk::ImageLayout::eGeneral,
324 1, 1, vk::ImageAspectFlagBits::eColor);
325 image->set_current_layout(vk::ImageLayout::eGeneral);
326
327 m_textures.push_back(image);
329 "Created storage image: {}x{}, format: {}",
330 width, height, vk::to_string(vk_format));
331 return image;
332}
333
334std::shared_ptr<Core::VKImage> TextureLoom::create_2d(
335 const Kakshya::DataVariant& variant,
336 uint32_t width,
337 uint32_t height,
338 ImageFormat format)
339{
340 if (!is_initialized()) {
342 "TextureLoom not initialized");
343 return nullptr;
344 }
345
346 const auto access = Kakshya::as_texture_access(variant);
347 if (!access) {
348 return nullptr;
349 }
350
351 const size_t expected = calculate_image_size(width, height, 1, format);
352 if (access->byte_count != expected) {
353 error<std::invalid_argument>(
356 std::source_location::current(),
357 "create_2d: byte count mismatch — {} bytes supplied, "
358 "{}x{} format {} requires {}",
359 access->byte_count, width, height, static_cast<int>(format), expected);
360 }
361
362 return create_2d(width, height, format, access->data_ptr, 1);
363}
364
365//==============================================================================
366// Data Upload/Download
367//==============================================================================
368
370 const std::shared_ptr<Core::VKImage>& image, const void* data, size_t size)
371{
372 if (!is_initialized() || !image || !data) {
374 "Invalid parameters for upload_data");
375 return;
376 }
377
379}
380
382 const std::shared_ptr<Core::VKImage>& image,
383 const void* data,
384 size_t size,
385 const std::shared_ptr<Buffers::VKBuffer>& staging)
386{
387 if (!is_initialized() || !image || !data || !staging) {
389 "Invalid parameters for upload_data_streaming");
390 return;
391 }
392
394}
395
397 const std::shared_ptr<Core::VKImage>& image, void* data, size_t size)
398{
399 if (!is_initialized() || !image || !data) {
401 "Invalid parameters for download_data");
402 return;
403 }
404
406}
407
409 const std::shared_ptr<Core::VKImage>& image, void* data, size_t size)
410{
411 if (!is_initialized() || !image || !data) {
413 "Invalid parameters for download_data_async");
414 return;
415 }
416
417 auto buffer_service = Registry::BackendRegistry::instance()
419 if (!buffer_service || !buffer_service->execute_fenced
420 || !buffer_service->wait_fenced || !buffer_service->release_fenced
421 || !buffer_service->initialize_buffer || !buffer_service->destroy_buffer
422 || !buffer_service->invalidate_range) {
424 "download_data_async: BufferService unavailable or incomplete");
425 return;
426 }
427
428 auto staging = std::make_shared<Buffers::VKBuffer>(
429 size,
432
433 buffer_service->initialize_buffer(std::static_pointer_cast<void>(staging));
434
435 auto handle = buffer_service->execute_fenced([&](void* cmd_ptr) {
436 vk::CommandBuffer cmd(static_cast<VkCommandBuffer>(cmd_ptr));
437
438 vk::ImageMemoryBarrier barrier {};
439 barrier.oldLayout = image->get_current_layout();
440 barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
441 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
442 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
443 barrier.image = image->get_image();
444 barrier.subresourceRange.aspectMask = image->get_aspect_flags();
445 barrier.subresourceRange.baseMipLevel = 0;
446 barrier.subresourceRange.levelCount = image->get_mip_levels();
447 barrier.subresourceRange.baseArrayLayer = 0;
448 barrier.subresourceRange.layerCount = image->get_array_layers();
449 barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead;
450 barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
451
452 cmd.pipelineBarrier(
453 vk::PipelineStageFlagBits::eFragmentShader,
454 vk::PipelineStageFlagBits::eTransfer,
455 vk::DependencyFlags {}, {}, {}, barrier);
456
457 vk::BufferImageCopy region {};
458 region.bufferOffset = 0;
459 region.bufferRowLength = 0;
460 region.bufferImageHeight = 0;
461 region.imageSubresource.aspectMask = image->get_aspect_flags();
462 region.imageSubresource.mipLevel = 0;
463 region.imageSubresource.baseArrayLayer = 0;
464 region.imageSubresource.layerCount = image->get_array_layers();
465 region.imageOffset = vk::Offset3D { 0, 0, 0 };
466 region.imageExtent = vk::Extent3D {
467 image->get_width(),
468 image->get_height(),
469 image->get_depth()
470 };
471
472 cmd.copyImageToBuffer(
473 image->get_image(),
474 vk::ImageLayout::eTransferSrcOptimal,
475 staging->get_buffer(),
476 1, &region);
477
478 barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
479 barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
480 barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
481 barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;
482
483 cmd.pipelineBarrier(
484 vk::PipelineStageFlagBits::eTransfer,
485 vk::PipelineStageFlagBits::eFragmentShader,
486 vk::DependencyFlags {}, {}, {}, barrier);
487 });
488
489 if (!handle) {
491 "download_data_async: execute_fenced returned null handle");
492 buffer_service->destroy_buffer(std::static_pointer_cast<void>(staging));
493 return;
494 }
495
496 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
497
498 buffer_service->wait_fenced(handle);
499
500 auto& resources = staging->get_buffer_resources();
501 buffer_service->invalidate_range(resources.memory, 0, 0);
502
503 void* mapped = staging->get_mapped_ptr();
504 if (mapped) {
505 std::memcpy(data, mapped, size);
506 } else {
508 "download_data_async: staging buffer has no mapped pointer");
509 }
510
511 buffer_service->release_fenced(handle);
512 buffer_service->destroy_buffer(std::static_pointer_cast<void>(staging));
513
515 "download_data_async: completed {} byte download for {}x{}",
516 size, image->get_width(), image->get_height());
517}
518
520 const std::shared_ptr<Core::VKImage>& image,
521 vk::ImageLayout old_layout,
522 vk::ImageLayout new_layout,
523 uint32_t mip_levels,
524 uint32_t array_layers,
525 vk::ImageAspectFlags aspect_mask)
526{
527 if (!is_initialized() || !image) {
529 "Invalid parameters for transition_vk_image_layout");
530 return;
531 }
532
534 image->get_image(),
535 old_layout,
536 new_layout,
537 mip_levels, array_layers, aspect_mask);
538
539 image->set_current_layout(new_layout);
540}
541
542//==============================================================================
543// Sampler Management
544//==============================================================================
545
547{
548 if (!is_initialized()) {
550 "TextureLoom not initialized");
551 return nullptr;
552 }
553
554 size_t hash = hash_sampler_config(config);
555 auto it = m_sampler_cache.find(hash);
556 if (it != m_sampler_cache.end()) {
557 return it->second;
558 }
559
560 vk::Sampler sampler = create_sampler(config);
561 m_sampler_cache[hash] = sampler;
562 return sampler;
563}
564
566{
567 SamplerConfig config;
568 return get_or_create_sampler(config);
569}
570
580
582{
584 static_cast<vk::Filter>(config.mag_filter),
585 static_cast<vk::SamplerAddressMode>(config.address_mode_u),
586 config.max_anisotropy);
587}
588
590{
591 size_t hash = 0;
592 hash ^= std::hash<int> {}(static_cast<int>(config.mag_filter)) << 0;
593 hash ^= std::hash<int> {}(static_cast<int>(config.min_filter)) << 4;
594 hash ^= std::hash<int> {}(static_cast<int>(config.address_mode_u)) << 8;
595 hash ^= std::hash<int> {}(static_cast<int>(config.address_mode_v)) << 12;
596 hash ^= std::hash<int> {}(static_cast<int>(config.address_mode_w)) << 16;
597 hash ^= std::hash<float> {}(config.max_anisotropy) << 20;
598 hash ^= std::hash<bool> {}(config.enable_mipmaps) << 24;
599 return hash;
600}
601
602//==============================================================================
603// Utilities
604//==============================================================================
605
607{
608 switch (format) {
609 case ImageFormat::R8:
610 return vk::Format::eR8Unorm;
611 case ImageFormat::RG8:
612 return vk::Format::eR8G8Unorm;
614 return vk::Format::eR8G8B8Unorm;
616 return vk::Format::eR8G8B8A8Unorm;
619 return vk::Format::eB8G8R8A8Unorm;
621 return vk::Format::eB8G8R8A8Srgb;
622 return vk::Format::eR8G8B8A8Srgb;
623 case ImageFormat::R16:
624 return vk::Format::eR16Unorm;
626 return vk::Format::eR16G16Unorm;
628 return vk::Format::eR16G16B16A16Unorm;
630 return vk::Format::eR16Sfloat;
632 return vk::Format::eR16G16Sfloat;
634 return vk::Format::eR16G16B16A16Sfloat;
636 return vk::Format::eR32Sfloat;
638 return vk::Format::eR32G32Sfloat;
640 return vk::Format::eR32G32B32A32Sfloat;
642 return vk::Format::eD16Unorm;
644 return vk::Format::eX8D24UnormPack32;
646 return vk::Format::eD32Sfloat;
648 return vk::Format::eD24UnormS8Uint;
649 default:
650 return vk::Format::eR8G8B8A8Unorm;
651 }
652}
653
655{
656 switch (format) {
657 case ImageFormat::R8:
658 return 1;
659 case ImageFormat::RG8:
660 return 2;
662 return 3;
667 return 4;
668 case ImageFormat::R16:
669 return 2;
671 return 4;
673 return 8;
675 return 2;
677 return 4;
679 return 8;
681 return 4;
683 return 8;
685 return 16;
687 return 2;
691 default:
692 return 4;
693 }
694}
695
696std::optional<ImageFormat> TextureLoom::from_vulkan_format(vk::Format vk_format)
697{
698 switch (vk_format) {
699 case vk::Format::eR8Unorm:
700 return ImageFormat::R8;
701 case vk::Format::eR8G8Unorm:
702 return ImageFormat::RG8;
703 case vk::Format::eR8G8B8Unorm:
704 return ImageFormat::RGB8;
705 case vk::Format::eR8G8B8A8Unorm:
706 return ImageFormat::RGBA8;
707 case vk::Format::eR8G8B8A8Srgb:
709 case vk::Format::eB8G8R8A8Unorm:
710 return ImageFormat::BGRA8;
711
712 case vk::Format::eR16Unorm:
713 return ImageFormat::R16;
714 case vk::Format::eR16G16Unorm:
715 return ImageFormat::RG16;
716 case vk::Format::eR16G16B16A16Unorm:
717 return ImageFormat::RGBA16;
718
719 case vk::Format::eR16Sfloat:
720 return ImageFormat::R16F;
721 case vk::Format::eR16G16Sfloat:
722 return ImageFormat::RG16F;
723 case vk::Format::eR16G16B16A16Sfloat:
725
726 case vk::Format::eR32Sfloat:
727 return ImageFormat::R32F;
728 case vk::Format::eR32G32Sfloat:
729 return ImageFormat::RG32F;
730 case vk::Format::eR32G32B32A32Sfloat:
732
733 case vk::Format::eD16Unorm:
735 case vk::Format::eX8D24UnormPack32:
737 case vk::Format::eD32Sfloat:
739 case vk::Format::eD24UnormS8Uint:
741
742 default:
743 return std::nullopt;
744 }
745}
746
748 uint32_t width, uint32_t height, uint32_t depth, ImageFormat format)
749{
750 return static_cast<size_t>(width) * height * depth * get_bytes_per_pixel(format);
751}
752
754{
755 switch (format) {
756 case ImageFormat::R8:
757 case ImageFormat::R16:
760 return 1;
761
762 case ImageFormat::RG8:
766 return 2;
767
769 return 3;
770
777 return 4;
778
782 return 1;
783
785 return 2;
786
787 default:
788 return 0;
789 }
790}
791
792} // namespace MayaFlux::Portal::Graphics
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
vk::CommandBuffer cmd
IO::ImageData image
uint32_t width
Range size
@ STAGING
Host-visible staging buffer (CPU-writable)
void cleanup_image(const std::shared_ptr< VKImage > &image)
Cleanup a VKImage (destroy view, image, and free memory)
void initialize_image(const std::shared_ptr< VKImage > &image)
Initialize a VKImage (allocate VkImage, memory, and create image view)
vk::Sampler create_sampler(vk::Filter filter=vk::Filter::eLinear, vk::SamplerAddressMode address_mode=vk::SamplerAddressMode::eRepeat, float max_anisotropy=0.0F)
Create sampler.
void download_image_data(std::shared_ptr< VKImage > image, void *data, size_t size, vk::ImageLayout restore_layout=vk::ImageLayout::eShaderReadOnlyOptimal, vk::PipelineStageFlags restore_stage=vk::PipelineStageFlagBits::eFragmentShader)
Download data from an image into a caller-supplied buffer.
void transition_image_layout(vk::Image image, vk::ImageLayout old_layout, vk::ImageLayout new_layout, uint32_t mip_levels=1, uint32_t array_layers=1, vk::ImageAspectFlags aspect_flags=vk::ImageAspectFlagBits::eColor)
Transition image layout using a pipeline barrier.
void upload_image_data_with_staging(std::shared_ptr< VKImage > image, const void *data, size_t size, const std::shared_ptr< Buffers::VKBuffer > &staging)
Upload image data using a caller-supplied persistent staging buffer.
void upload_image_data(std::shared_ptr< VKImage > image, const void *data, size_t size)
Upload data to an image (creates staging buffer internally)
@ RENDER_TARGET
Color attachment for rendering.
@ STORAGE
Storage image (compute shader read/write)
@ TEXTURE_2D
Sampled texture (shader read)
@ DEPTH_STENCIL
Depth/stencil attachment.
std::shared_ptr< Core::VKImage > create_render_target(uint32_t width, uint32_t height, ImageFormat format=ImageFormat::RGBA8)
Create a render target (color attachment)
std::shared_ptr< Core::VKImage > create_depth_buffer(uint32_t width, uint32_t height, bool with_stencil=false)
Create a depth buffer.
static size_t get_bytes_per_pixel(ImageFormat format)
Get bytes per pixel for a format.
static uint32_t get_channel_count(ImageFormat format)
Get the number of color channels for a given format.
vk::Sampler get_nearest_sampler()
Get a default nearest sampler (for pixel-perfect sampling)
static size_t calculate_image_size(uint32_t width, uint32_t height, uint32_t depth, ImageFormat format)
Calculate image data size.
static vk::Format to_vulkan_format(ImageFormat format)
Convert Portal ImageFormat to Vulkan format.
std::shared_ptr< Core::VKImage > create_storage_image(uint32_t width, uint32_t height, ImageFormat format=ImageFormat::RGBA8)
Create a storage image (compute shader read/write)
void upload_data(const std::shared_ptr< Core::VKImage > &image, const void *data, size_t size)
Upload pixel data to an existing texture.
bool initialize(const std::shared_ptr< Core::VulkanBackend > &backend)
Initialize texture manager.
vk::Sampler get_or_create_sampler(const SamplerConfig &config)
Get or create a sampler with the given configuration.
void transition_layout(const std::shared_ptr< Core::VKImage > &image, vk::ImageLayout old_layout, vk::ImageLayout new_layout, uint32_t mip_levels=1, uint32_t array_layers=1, vk::ImageAspectFlags aspect_mask=vk::ImageAspectFlagBits::eColor)
Transition a VKImage to a new Vulkan layout via an immediate submission.
void download_data(const std::shared_ptr< Core::VKImage > &image, void *data, size_t size)
Download pixel data from a texture.
std::shared_ptr< Core::VulkanBackend > m_backend
std::shared_ptr< Core::VKImage > create_3d(uint32_t width, uint32_t height, uint32_t depth, ImageFormat format=ImageFormat::RGBA8, const void *data=nullptr)
Create a 3D texture (volumetric)
vk::Sampler create_sampler(const SamplerConfig &config)
void shutdown()
Shutdown and cleanup all textures.
static std::optional< ImageFormat > from_vulkan_format(vk::Format vk_format)
Convert Vulkan format to Portal ImageFormat.
void download_data_async(const std::shared_ptr< Core::VKImage > &image, void *data, size_t size)
Download pixel data from a texture without blocking the graphics queue.
Core::BackendResourceManager * m_resource_manager
std::shared_ptr< Core::VKImage > create_2d(uint32_t width, uint32_t height, ImageFormat format=ImageFormat::RGBA8, const void *data=nullptr, uint32_t mip_levels=1)
Create a 2D texture.
static size_t hash_sampler_config(const SamplerConfig &config)
std::vector< std::shared_ptr< Core::VKImage > > m_textures
std::shared_ptr< Core::VKImage > create_cubemap(uint32_t size, ImageFormat format=ImageFormat::RGBA8, const void *data=nullptr)
Create a cubemap texture.
vk::Sampler get_default_sampler()
Get a default linear sampler (for convenience)
std::unordered_map< size_t, vk::Sampler > m_sampler_cache
bool is_initialized() const
Check if manager is initialized.
Interface * get_service()
Query for a backend service.
static BackendRegistry & instance()
Get the global registry instance.
@ ImageProcessing
Image processing tasks (filters, transformations)
@ Portal
High-level user-facing API layer.
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:76
@ VOLUMETRIC_3D
3D volumetric data
@ IMAGE_COLOR
2D RGB/RGBA image
@ IMAGE_2D
2D image (grayscale or single channel)
std::optional< TextureAccess > as_texture_access(const DataVariant &variant)
Extract a TextureAccess from a DataVariant.
@ NEAREST
Nearest neighbor (pixelated)
ImageFormat
User-friendly image format enum.
@ DEPTH24_STENCIL8
24-bit depth + 8-bit stencil
@ RG16
Two channel 16-bit unsigned integer.
@ BGRA8
8-bit BGRA unsigned normalized
@ RGBA16
Four channel 16-bit unsigned integer.
@ RGBA32F
Four channel 32-bit float.
@ R16F
Single channel 16-bit float.
@ R16
Single channel 16-bit unsigned integer.
@ RGBA16F
Four channel 16-bit float.
@ RG32F
Two channel 32-bit float.
@ R32F
Single channel 32-bit float.
@ RG16F
Two channel 16-bit float.
@ RGBA8_SRGB
Four channel 8-bit sRGB.
Backend buffer management service interface.