23 "TextureLoom already initialized (static flag)");
29 "Cannot initialize TextureLoom with null backend");
35 "TextureLoom already initialized");
44 "TextureLoom initialized");
59 "Shutting down TextureLoom...");
62 if (texture && texture->is_initialized()) {
74 "TextureLoom shutdown complete");
82 uint32_t
width, uint32_t height,
83 ImageFormat format,
const void* data, uint32_t mip_levels)
87 "TextureLoom not initialized");
92 auto image = std::make_shared<Core::VKImage>(
93 width, height, 1, vk_format,
101 if (!
image->is_initialized()) {
103 "Failed to initialize VKImage");
113 vk::ImageLayout::eUndefined,
114 vk::ImageLayout::eShaderReadOnlyOptimal,
115 mip_levels, 1, vk::ImageAspectFlagBits::eColor);
116 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
121 "Created 2D texture: {}x{}, format: {}, mips: {}",
122 width, height, vk::to_string(vk_format), mip_levels);
127 uint32_t
width, uint32_t height, uint32_t depth,
132 "TextureLoom not initialized");
137 auto image = std::make_shared<Core::VKImage>(
138 width, height, depth, vk_format,
145 if (!
image->is_initialized()) {
147 "Failed to initialize 3D VKImage");
157 vk::ImageLayout::eUndefined,
158 vk::ImageLayout::eShaderReadOnlyOptimal,
159 1, 1, vk::ImageAspectFlagBits::eColor);
160 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
165 "Created 3D texture: {}x{}x{}, format: {}",
166 width, height, depth, vk::to_string(vk_format));
171 uint32_t size,
ImageFormat format,
const void* data)
175 "TextureLoom not initialized");
180 auto image = std::make_shared<Core::VKImage>(
181 size, size, 1, vk_format,
188 if (!
image->is_initialized()) {
190 "Failed to initialize cubemap VKImage");
196 size_t total_size = face_size * 6;
201 vk::ImageLayout::eUndefined,
202 vk::ImageLayout::eShaderReadOnlyOptimal,
203 1, 6, vk::ImageAspectFlagBits::eColor);
204 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
209 "Created cubemap: {}x{}, format: {}", size, size, vk::to_string(vk_format));
218 "TextureLoom not initialized");
223 auto image = std::make_shared<Core::VKImage>(
224 width, height, 1, vk_format,
231 if (!
image->is_initialized()) {
233 "Failed to initialize render target VKImage");
239 vk::ImageLayout::eUndefined,
240 vk::ImageLayout::eColorAttachmentOptimal,
241 1, 1, vk::ImageAspectFlagBits::eColor);
242 image->set_current_layout(vk::ImageLayout::eColorAttachmentOptimal);
246 "Created render target: {}x{}, format: {}",
247 width, height, vk::to_string(vk_format));
252 uint32_t
width, uint32_t height,
bool with_stencil)
256 "TextureLoom not initialized");
260 vk::Format vk_format = with_stencil
261 ? vk::Format::eD24UnormS8Uint
262 : vk::Format::eD32Sfloat;
264 auto image = std::make_shared<Core::VKImage>(
265 width, height, 1, vk_format,
272 if (!
image->is_initialized()) {
274 "Failed to initialize depth buffer VKImage");
278 vk::ImageAspectFlags aspect = with_stencil
279 ? (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil)
280 : vk::ImageAspectFlagBits::eDepth;
284 vk::ImageLayout::eUndefined,
285 vk::ImageLayout::eDepthStencilAttachmentOptimal,
287 image->set_current_layout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
291 "Created depth buffer: {}x{}, format: {}, stencil: {}",
292 width, height, vk::to_string(vk_format), with_stencil);
301 "TextureLoom not initialized");
306 auto image = std::make_shared<Core::VKImage>(
307 width, height, 1, vk_format,
314 if (!
image->is_initialized()) {
316 "Failed to initialize storage image VKImage");
322 vk::ImageLayout::eUndefined,
323 vk::ImageLayout::eGeneral,
324 1, 1, vk::ImageAspectFlagBits::eColor);
325 image->set_current_layout(vk::ImageLayout::eGeneral);
329 "Created storage image: {}x{}, format: {}",
330 width, height, vk::to_string(vk_format));
342 "TextureLoom not initialized");
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);
370 const std::shared_ptr<Core::VKImage>&
image,
const void* data,
size_t size)
374 "Invalid parameters for upload_data");
382 const std::shared_ptr<Core::VKImage>&
image,
385 const std::shared_ptr<Buffers::VKBuffer>& staging,
390 "Invalid parameters for upload_data_streaming");
398 const std::shared_ptr<Core::VKImage>&
image,
void* data,
size_t size)
402 "Invalid parameters for download_data");
410 const std::shared_ptr<Core::VKImage>&
image,
void* data,
size_t size)
414 "Invalid parameters for download_data_async");
420 if (!buffer_service || !buffer_service->execute_fenced
421 || !buffer_service->wait_fenced || !buffer_service->release_fenced
422 || !buffer_service->initialize_buffer || !buffer_service->destroy_buffer
423 || !buffer_service->invalidate_range) {
425 "download_data_async: BufferService unavailable or incomplete");
429 auto staging = std::make_shared<Buffers::VKBuffer>(
434 buffer_service->initialize_buffer(std::static_pointer_cast<void>(staging));
436 auto handle = buffer_service->execute_fenced([&](
void* cmd_ptr) {
437 vk::CommandBuffer
cmd(
static_cast<VkCommandBuffer
>(cmd_ptr));
439 vk::ImageMemoryBarrier barrier {};
440 barrier.oldLayout =
image->get_current_layout();
441 barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
442 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
443 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
444 barrier.image =
image->get_image();
445 barrier.subresourceRange.aspectMask =
image->get_aspect_flags();
446 barrier.subresourceRange.baseMipLevel = 0;
447 barrier.subresourceRange.levelCount =
image->get_mip_levels();
448 barrier.subresourceRange.baseArrayLayer = 0;
449 barrier.subresourceRange.layerCount =
image->get_array_layers();
450 barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead;
451 barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
454 vk::PipelineStageFlagBits::eFragmentShader,
455 vk::PipelineStageFlagBits::eTransfer,
456 vk::DependencyFlags {}, {}, {}, barrier);
458 vk::BufferImageCopy region {};
459 region.bufferOffset = 0;
460 region.bufferRowLength = 0;
461 region.bufferImageHeight = 0;
462 region.imageSubresource.aspectMask =
image->get_aspect_flags();
463 region.imageSubresource.mipLevel = 0;
464 region.imageSubresource.baseArrayLayer = 0;
465 region.imageSubresource.layerCount =
image->get_array_layers();
466 region.imageOffset = vk::Offset3D { 0, 0, 0 };
467 region.imageExtent = vk::Extent3D {
473 cmd.copyImageToBuffer(
475 vk::ImageLayout::eTransferSrcOptimal,
476 staging->get_buffer(),
479 barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
480 barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
481 barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
482 barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;
485 vk::PipelineStageFlagBits::eTransfer,
486 vk::PipelineStageFlagBits::eFragmentShader,
487 vk::DependencyFlags {}, {}, {}, barrier);
492 "download_data_async: execute_fenced returned null handle");
493 buffer_service->destroy_buffer(std::static_pointer_cast<void>(staging));
497 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
499 buffer_service->wait_fenced(handle);
501 auto& resources = staging->get_buffer_resources();
502 buffer_service->invalidate_range(resources.memory, 0, 0);
504 void* mapped = staging->get_mapped_ptr();
506 std::memcpy(data, mapped, size);
509 "download_data_async: staging buffer has no mapped pointer");
512 buffer_service->release_fenced(handle);
513 buffer_service->destroy_buffer(std::static_pointer_cast<void>(staging));
516 "download_data_async: completed {} byte download for {}x{}",
517 size,
image->get_width(),
image->get_height());
521 const std::shared_ptr<Core::VKImage>&
image,
522 vk::ImageLayout old_layout,
523 vk::ImageLayout new_layout,
525 uint32_t array_layers,
526 vk::ImageAspectFlags aspect_mask)
530 "Invalid parameters for transition_vk_image_layout");
538 mip_levels, array_layers, aspect_mask);
540 image->set_current_layout(new_layout);
551 "TextureLoom not initialized");
593 hash ^= std::hash<int> {}(
static_cast<int>(config.
mag_filter)) << 0;
594 hash ^= std::hash<int> {}(
static_cast<int>(config.
min_filter)) << 4;
595 hash ^= std::hash<int> {}(
static_cast<int>(config.
address_mode_u)) << 8;
596 hash ^= std::hash<int> {}(
static_cast<int>(config.
address_mode_v)) << 12;
597 hash ^= std::hash<int> {}(
static_cast<int>(config.
address_mode_w)) << 16;
611 return vk::Format::eR8Unorm;
613 return vk::Format::eR8G8Unorm;
615 return vk::Format::eR8G8B8Unorm;
617 return vk::Format::eR8G8B8A8Unorm;
620 return vk::Format::eB8G8R8A8Unorm;
622 return vk::Format::eB8G8R8A8Srgb;
623 return vk::Format::eR8G8B8A8Srgb;
625 return vk::Format::eR16Unorm;
627 return vk::Format::eR16G16Unorm;
629 return vk::Format::eR16G16B16A16Unorm;
631 return vk::Format::eR16Sfloat;
633 return vk::Format::eR16G16Sfloat;
635 return vk::Format::eR16G16B16A16Sfloat;
637 return vk::Format::eR32Sfloat;
639 return vk::Format::eR32G32Sfloat;
641 return vk::Format::eR32G32B32A32Sfloat;
643 return vk::Format::eD16Unorm;
645 return vk::Format::eX8D24UnormPack32;
647 return vk::Format::eD32Sfloat;
649 return vk::Format::eD24UnormS8Uint;
651 return vk::Format::eR8G8B8A8Unorm;
700 case vk::Format::eR8Unorm:
702 case vk::Format::eR8G8Unorm:
704 case vk::Format::eR8G8B8Unorm:
706 case vk::Format::eR8G8B8A8Unorm:
708 case vk::Format::eR8G8B8A8Srgb:
710 case vk::Format::eB8G8R8A8Unorm:
713 case vk::Format::eR16Unorm:
715 case vk::Format::eR16G16Unorm:
717 case vk::Format::eR16G16B16A16Unorm:
720 case vk::Format::eR16Sfloat:
722 case vk::Format::eR16G16Sfloat:
724 case vk::Format::eR16G16B16A16Sfloat:
727 case vk::Format::eR32Sfloat:
729 case vk::Format::eR32G32Sfloat:
731 case vk::Format::eR32G32B32A32Sfloat:
734 case vk::Format::eD16Unorm:
736 case vk::Format::eX8D24UnormPack32:
738 case vk::Format::eD32Sfloat:
740 case vk::Format::eD24UnormS8Uint:
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
@ STAGING
Host-visible staging buffer (CPU-writable, eTransferSrc|Dst)
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(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
static bool s_initialized
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.
@ 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.
@ CLAMP_TO_EDGE
Clamp to edge color.
@ NEAREST
Nearest neighbor (pixelated)
ImageFormat
User-friendly image format enum.
@ DEPTH24_STENCIL8
24-bit depth + 8-bit stencil
@ RGB8
Three channel 8-bit.
@ DEPTH32F
32-bit float depth
@ 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.
@ RGBA8
Four channel 8-bit.
@ RG32F
Two channel 32-bit float.
@ R32F
Single channel 32-bit float.
@ R8
Single channel 8-bit.
@ RG16F
Two channel 16-bit float.
@ RGBA8_SRGB
Four channel 8-bit sRGB.
@ BGRA8_SRGB
8-bit BGRA sRGB
AddressMode address_mode_v
AddressMode address_mode_w
AddressMode address_mode_u
Backend buffer management service interface.