17 uint64_t hash = 14695981039346656037ULL;
18 const auto mix = [&hash](uint64_t
value) {
19 hash = (hash ^
value) * 1099511628211ULL;
26 mix(
static_cast<uint64_t
>(key.format));
27 mix(
static_cast<uint64_t
>(key.kind));
29 return static_cast<size_t>(hash);
38 "TextureLoom already initialized (static flag)");
44 "Cannot initialize TextureLoom with null backend");
50 "TextureLoom already initialized");
59 "TextureLoom initialized");
74 "Shutting down TextureLoom...");
77 if (texture && texture->is_initialized()) {
89 "TextureLoom shutdown complete");
102 "TextureLoom not initialized");
107 auto image = std::make_shared<Core::VKImage>(
116 if (!
image->is_initialized()) {
118 "Failed to initialize VKImage");
128 vk::ImageLayout::eUndefined,
129 vk::ImageLayout::eShaderReadOnlyOptimal,
130 mip_levels, 1, vk::ImageAspectFlagBits::eColor);
131 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
136 "Created 2D texture: {}x{}, format: {}, mips: {}",
137 width,
height, vk::to_string(vk_format), mip_levels);
147 "TextureLoom not initialized");
152 auto image = std::make_shared<Core::VKImage>(
161 if (!
image->is_initialized()) {
163 "Failed to initialize VKImage");
169 "Created 2D texture (uninitialized): {}x{}, format: {}, mips: {}",
170 width,
height, vk::to_string(vk_format), mip_levels);
180 "TextureLoom not initialized");
185 auto image = std::make_shared<Core::VKImage>(
193 if (!
image->is_initialized()) {
195 "Failed to initialize 3D VKImage");
205 vk::ImageLayout::eUndefined,
206 vk::ImageLayout::eShaderReadOnlyOptimal,
207 1, 1, vk::ImageAspectFlagBits::eColor);
208 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
213 "Created 3D texture: {}x{}x{}, format: {}",
223 "TextureLoom not initialized");
228 auto image = std::make_shared<Core::VKImage>(
236 if (!
image->is_initialized()) {
238 "Failed to initialize cubemap VKImage");
244 size_t total_size = face_size * 6;
249 vk::ImageLayout::eUndefined,
250 vk::ImageLayout::eShaderReadOnlyOptimal,
251 1, 6, vk::ImageAspectFlagBits::eColor);
252 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
257 "Created cubemap: {}x{}, format: {}",
size,
size, vk::to_string(vk_format));
267 "TextureLoom not initialized");
273 "create_2d_array: layers must be > 0");
278 auto image = std::make_shared<Core::VKImage>(
287 if (!
image->is_initialized()) {
289 "create_2d_array: failed to initialize VKImage ({}x{} layers={})",
300 vk::ImageLayout::eUndefined,
301 vk::ImageLayout::eShaderReadOnlyOptimal,
302 1, layers, vk::ImageAspectFlagBits::eColor);
303 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
308 "Created 2D array texture: {}x{} layers={} format={}",
318 "TextureLoom not initialized");
323 auto image = std::make_shared<Core::VKImage>(
331 if (!
image->is_initialized()) {
333 "Failed to initialize render target VKImage");
339 vk::ImageLayout::eUndefined,
340 vk::ImageLayout::eColorAttachmentOptimal,
341 1, 1, vk::ImageAspectFlagBits::eColor);
342 image->set_current_layout(vk::ImageLayout::eColorAttachmentOptimal);
346 "Created render target: {}x{}, format: {}",
352 uint32_t
width, uint32_t
height,
bool with_stencil)
356 "TextureLoom not initialized");
360 vk::Format vk_format = with_stencil
361 ? vk::Format::eD24UnormS8Uint
362 : vk::Format::eD32Sfloat;
364 auto image = std::make_shared<Core::VKImage>(
372 if (!
image->is_initialized()) {
374 "Failed to initialize depth buffer VKImage");
378 vk::ImageAspectFlags aspect = with_stencil
379 ? (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil)
380 : vk::ImageAspectFlagBits::eDepth;
384 vk::ImageLayout::eUndefined,
385 vk::ImageLayout::eDepthStencilAttachmentOptimal,
387 image->set_current_layout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
391 "Created depth buffer: {}x{}, format: {}, stencil: {}",
392 width,
height, vk::to_string(vk_format), with_stencil);
401 "TextureLoom not initialized");
406 auto image = std::make_shared<Core::VKImage>(
414 if (!
image->is_initialized()) {
416 "Failed to initialize storage image VKImage");
422 vk::ImageLayout::eUndefined,
423 vk::ImageLayout::eGeneral,
424 1, 1, vk::ImageAspectFlagBits::eColor);
425 image->set_current_layout(vk::ImageLayout::eGeneral);
429 "Created storage image: {}x{}, format: {}",
444 if (entry.
image && entry.
key == key && entry.
image->is_initialized()
454 std::shared_ptr<Core::VKImage>
image;
483 std::span<const uint8_t>
pixels,
484 const std::shared_ptr<Buffers::VKBuffer>& staging)
492 if (
pixels.size() != required) {
494 "Cached image upload has {} bytes, expected {}",
pixels.size(), required);
498 if (staging && (staging->get_size() < required || !staging->get_mapped_ptr())) {
500 "Cached image staging buffer is unavailable or too small");
546 "Image cache holds {} bytes, exceeding its {}-byte warning threshold",
563 "TextureLoom not initialized");
573 if (access->byte_count != expected) {
574 error<std::invalid_argument>(
577 std::source_location::current(),
578 "create_2d: byte count mismatch — {} bytes supplied, "
579 "{}x{} format {} requires {}",
591 const std::shared_ptr<Core::VKImage>&
image,
const void* data,
size_t size)
595 "Invalid parameters for upload_data");
603 const std::shared_ptr<Core::VKImage>&
image,
606 const std::shared_ptr<Buffers::VKBuffer>& staging,
611 "Invalid parameters for upload_data_streaming");
619 const std::shared_ptr<Core::VKImage>&
image,
622 const std::shared_ptr<Buffers::VKBuffer>& staging,
624 vk::ImageLayout restore_layout,
625 vk::PipelineStageFlags restore_stage)
629 "download_data(staging): invalid parameters");
634 image, data,
size, staging, deferred, restore_layout, restore_stage);
638 const std::shared_ptr<Core::VKImage>&
image,
639 const std::shared_ptr<Buffers::VKBuffer>& staging,
640 vk::ImageLayout restore_layout,
641 vk::PipelineStageFlags restore_stage)
645 "download_image: TextureLoom is not initialised");
652 "download_image: image is not readable as a single-layer 2D base level");
660 if (!result || result->byte_size() != byte_count) {
662 "download_image: format {} has no typed pixel storage matching its size",
static_cast<int>(*
format));
666 download_data(
image, result->data(), byte_count, staging,
false, restore_layout, restore_stage);
668 if (!result->is_consistent()) {
670 "download_image: downloaded pixels do not match format {}",
static_cast<int>(*
format));
678 const std::shared_ptr<Core::VKImage>&
image,
679 vk::ImageLayout old_layout,
680 vk::ImageLayout new_layout,
682 uint32_t array_layers,
683 vk::ImageAspectFlags aspect_mask)
687 "Invalid parameters for transition_vk_image_layout");
695 mip_levels, array_layers, aspect_mask);
697 image->set_current_layout(new_layout);
707 std::optional<std::pair<vk::Offset3D, vk::Offset3D>> region_offsets(
710 const int32_t left = region.offset.x;
711 const int32_t top = region.offset.y;
713 if (left < 0 || top < 0
714 ||
static_cast<uint32_t
>(left) >=
image.get_width()
715 ||
static_cast<uint32_t
>(top) >=
image.get_height()) {
719 const auto x =
static_cast<uint32_t
>(left);
720 const auto y =
static_cast<uint32_t
>(top);
721 const uint32_t
width = region.extent.width != 0 ? region.extent.width :
image.get_width() - x;
722 const uint32_t
height = region.extent.height != 0 ? region.extent.height :
image.get_height() - y;
729 vk::Offset3D { left, top, 0 },
730 vk::Offset3D {
static_cast<int32_t
>(x +
width),
static_cast<int32_t
>(y +
height), 1 }
737 const std::shared_ptr<Core::VKImage>&
image,
741 const std::shared_ptr<Buffers::VKBuffer>& staging,
746 "Invalid parameters for upload_layer");
754 const std::shared_ptr<Core::VKImage>&
src,
755 const std::shared_ptr<Core::VKImage>&
dst,
763 src->get_format(),
dst->get_format(), to_blit_filter(filter));
767 const std::shared_ptr<Core::VKImage>&
src,
768 const std::shared_ptr<Core::VKImage>&
dst,
774 "Invalid parameters for blit_layer");
780 "blit_layer: layer {} of {} or layer {} of {} does not exist",
785 constexpr auto color = vk::ImageAspectFlagBits::eColor;
788 "blit_layer: only color images can be blitted");
792 const auto src_offsets = region_offsets(blit.
src, *
src);
793 auto dst_offsets = region_offsets(blit.
dst, *
dst);
794 if (!src_offsets || !dst_offsets) {
796 "blit_layer: a rectangle lies outside its image");
802 "blit_layer: cubic filtering is not available, using linear");
806 std::swap(dst_offsets->first.x, dst_offsets->second.x);
809 std::swap(dst_offsets->first.y, dst_offsets->second.y);
812 const vk::ImageBlit region {
814 { src_offsets->first, src_offsets->second },
816 { dst_offsets->first, dst_offsets->second }
830 "TextureLoom not initialized");
872 hash ^= std::hash<int> {}(
static_cast<int>(config.
mag_filter)) << 0;
873 hash ^= std::hash<int> {}(
static_cast<int>(config.
min_filter)) << 4;
874 hash ^= std::hash<int> {}(
static_cast<int>(config.
address_mode_u)) << 8;
875 hash ^= std::hash<int> {}(
static_cast<int>(config.
address_mode_v)) << 12;
876 hash ^= std::hash<int> {}(
static_cast<int>(config.
address_mode_w)) << 16;
889 case ImageFormat::R8:
890 return vk::Format::eR8Unorm;
891 case ImageFormat::RG8:
892 return vk::Format::eR8G8Unorm;
893 case ImageFormat::RGB8:
894 return vk::Format::eR8G8B8Unorm;
895 case ImageFormat::RGBA8:
896 return vk::Format::eR8G8B8A8Unorm;
897 case ImageFormat::RGBA8_SRGB:
898 return vk::Format::eR8G8B8A8Srgb;
899 case ImageFormat::BGRA8:
900 return vk::Format::eB8G8R8A8Unorm;
901 case ImageFormat::BGRA8_SRGB:
902 return vk::Format::eB8G8R8A8Srgb;
903 case ImageFormat::R16:
904 return vk::Format::eR16Unorm;
905 case ImageFormat::RG16:
906 return vk::Format::eR16G16Unorm;
907 case ImageFormat::RGBA16:
908 return vk::Format::eR16G16B16A16Unorm;
909 case ImageFormat::R16F:
910 return vk::Format::eR16Sfloat;
911 case ImageFormat::RG16F:
912 return vk::Format::eR16G16Sfloat;
913 case ImageFormat::RGBA16F:
914 return vk::Format::eR16G16B16A16Sfloat;
915 case ImageFormat::R32F:
916 return vk::Format::eR32Sfloat;
917 case ImageFormat::RG32F:
918 return vk::Format::eR32G32Sfloat;
919 case ImageFormat::RGBA32F:
920 return vk::Format::eR32G32B32A32Sfloat;
921 case ImageFormat::DEPTH16:
922 return vk::Format::eD16Unorm;
923 case ImageFormat::DEPTH24:
924 return vk::Format::eX8D24UnormPack32;
925 case ImageFormat::DEPTH32F:
926 return vk::Format::eD32Sfloat;
927 case ImageFormat::DEPTH24_STENCIL8:
928 return vk::Format::eD24UnormS8Uint;
930 return vk::Format::eR8G8B8A8Unorm;
937 case ImageFormat::R8:
939 case ImageFormat::RG8:
941 case ImageFormat::RGB8:
943 case ImageFormat::RGBA8:
944 case ImageFormat::RGBA8_SRGB:
945 case ImageFormat::BGRA8:
946 case ImageFormat::BGRA8_SRGB:
948 case ImageFormat::R16:
950 case ImageFormat::RG16:
952 case ImageFormat::RGBA16:
954 case ImageFormat::R16F:
956 case ImageFormat::RG16F:
958 case ImageFormat::RGBA16F:
960 case ImageFormat::R32F:
962 case ImageFormat::RG32F:
964 case ImageFormat::RGBA32F:
966 case ImageFormat::DEPTH16:
968 case ImageFormat::DEPTH24:
969 case ImageFormat::DEPTH32F:
970 case ImageFormat::DEPTH24_STENCIL8:
979 case vk::Format::eR8Unorm:
980 return ImageFormat::R8;
981 case vk::Format::eR8G8Unorm:
982 return ImageFormat::RG8;
983 case vk::Format::eR8G8B8Unorm:
984 return ImageFormat::RGB8;
985 case vk::Format::eR8G8B8A8Unorm:
986 return ImageFormat::RGBA8;
987 case vk::Format::eR8G8B8A8Srgb:
988 return ImageFormat::RGBA8_SRGB;
989 case vk::Format::eB8G8R8A8Unorm:
990 return ImageFormat::BGRA8;
991 case vk::Format::eB8G8R8A8Srgb:
992 return ImageFormat::BGRA8_SRGB;
994 case vk::Format::eR16Unorm:
995 return ImageFormat::R16;
996 case vk::Format::eR16G16Unorm:
997 return ImageFormat::RG16;
998 case vk::Format::eR16G16B16A16Unorm:
999 return ImageFormat::RGBA16;
1001 case vk::Format::eR16Sfloat:
1002 return ImageFormat::R16F;
1003 case vk::Format::eR16G16Sfloat:
1004 return ImageFormat::RG16F;
1005 case vk::Format::eR16G16B16A16Sfloat:
1006 return ImageFormat::RGBA16F;
1008 case vk::Format::eR32Sfloat:
1009 return ImageFormat::R32F;
1010 case vk::Format::eR32G32Sfloat:
1011 return ImageFormat::RG32F;
1012 case vk::Format::eR32G32B32A32Sfloat:
1013 return ImageFormat::RGBA32F;
1015 case vk::Format::eD16Unorm:
1016 return ImageFormat::DEPTH16;
1017 case vk::Format::eX8D24UnormPack32:
1018 return ImageFormat::DEPTH24;
1019 case vk::Format::eD32Sfloat:
1020 return ImageFormat::DEPTH32F;
1021 case vk::Format::eD24UnormS8Uint:
1022 return ImageFormat::DEPTH24_STENCIL8;
1025 return std::nullopt;
1030 const std::shared_ptr<Core::VKImage>&
image,
1031 vk::ImageUsageFlagBits required_usage)
1034 return std::nullopt;
1038 ||
image->get_depth() != 1 ||
image->get_array_layers() != 1) {
1039 return std::nullopt;
1042 if (!
static_cast<bool>(
image->get_usage_flags() & required_usage)) {
1043 return std::nullopt;
1046 const auto aspects =
image->get_aspect_flags();
1047 if (
static_cast<bool>(aspects & vk::ImageAspectFlagBits::eDepth)
1048 &&
static_cast<bool>(aspects & vk::ImageAspectFlagBits::eStencil)) {
1049 return std::nullopt;
1054 return std::nullopt;
1058 if (byte_count == 0 || byte_count >
image->get_size_bytes()) {
1059 return std::nullopt;
1066 const std::shared_ptr<Core::VKImage>&
image)
1072 const std::shared_ptr<Core::VKImage>&
image)
1086 case ImageFormat::R8:
1087 case ImageFormat::R16:
1088 case ImageFormat::R16F:
1089 case ImageFormat::R32F:
1092 case ImageFormat::RG8:
1093 case ImageFormat::RG16:
1094 case ImageFormat::RG16F:
1095 case ImageFormat::RG32F:
1098 case ImageFormat::RGB8:
1101 case ImageFormat::RGBA8:
1102 case ImageFormat::RGBA8_SRGB:
1103 case ImageFormat::BGRA8:
1104 case ImageFormat::BGRA8_SRGB:
1105 case ImageFormat::RGBA16:
1106 case ImageFormat::RGBA16F:
1107 case ImageFormat::RGBA32F:
1110 case ImageFormat::DEPTH16:
1111 case ImageFormat::DEPTH24:
1112 case ImageFormat::DEPTH32F:
1115 case ImageFormat::DEPTH24_STENCIL8:
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
const std::vector< float > * pixels
void cleanup_image(const std::shared_ptr< VKImage > &image)
Cleanup a VKImage (destroy view, image, and free memory)
bool blit_image(const std::shared_ptr< VKImage > &src, const std::shared_ptr< VKImage > &dst, const vk::ImageBlit ®ion, vk::Filter filter, bool deferred=false)
Blit a region of one image into a region of another.
void download_image_data(std::shared_ptr< VKImage > image, void *data, size_t size, const std::shared_ptr< Buffers::VKBuffer > &staging=nullptr, bool deferred=false, vk::ImageLayout restore_layout=vk::ImageLayout::eShaderReadOnlyOptimal, vk::PipelineStageFlags restore_stage=vk::PipelineStageFlagBits::eFragmentShader)
Download image data to a host pointer.
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.
bool supports_blit(vk::Format src_format, vk::Format dst_format, vk::Filter filter=vk::Filter::eNearest) const
Whether a blit between two formats is supported with a filter.
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.
bool upload_image_layer(const std::shared_ptr< VKImage > &image, uint32_t layer, const void *data, size_t size, const std::shared_ptr< Buffers::VKBuffer > &staging=nullptr, bool deferred=false)
Upload pixel data into one layer of an array image.
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.
Lightweight Vulkan image wrapper for MayaFlux processing pipeline.
std::optional< ImageKey > m_last_key
std::unordered_map< ImageKey, Entry, ImageKeyHash > m_entries
std::shared_ptr< Core::VKImage > acquire(TextureLoom &loom, const ImageKey &key)
void download_data(const std::shared_ptr< Core::VKImage > &image, void *data, size_t size, const std::shared_ptr< Buffers::VKBuffer > &staging, bool deferred=false, vk::ImageLayout restore_layout=vk::ImageLayout::eShaderReadOnlyOptimal, vk::PipelineStageFlags restore_stage=vk::PipelineStageFlagBits::eFragmentShader)
Download pixel data from a VKImage, reusing a caller-supplied persistent staging buffer.
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.
std::shared_ptr< Core::VKImage > refresh_cached_image(ImageCacheEntry &entry, const ImageKey &key, std::span< const uint8_t > pixels, const std::shared_ptr< Buffers::VKBuffer > &staging={})
Refresh a sampled image in an owner-held cache entry.
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.
std::optional< Kakshya::ImageData > download_image(const std::shared_ptr< Core::VKImage > &image, const std::shared_ptr< Buffers::VKBuffer > &staging=nullptr, vk::ImageLayout restore_layout=vk::ImageLayout::eShaderReadOnlyOptimal, vk::PipelineStageFlags restore_stage=vk::PipelineStageFlagBits::eFragmentShader)
Download the base level of an image as typed pixels.
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.
static std::optional< ImageFormat > readable_format(const std::shared_ptr< Core::VKImage > &image)
ImageFormat of an image that can be read back as one flat block.
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.
std::shared_ptr< Core::VKImage > create_2d_uninitialized(uint32_t width, uint32_t height, ImageFormat format=ImageFormat::RGBA8, uint32_t mip_levels=1)
Allocate a 2D texture without uploading data or transitioning its layout - left VK_IMAGE_LAYOUT_UNDEF...
bool blit_layer(const std::shared_ptr< Core::VKImage > &src, const std::shared_ptr< Core::VKImage > &dst, const LayerBlit &blit={}, bool deferred=false)
Copy a layer of one image into a layer of another, scaling to fit.
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.
bool upload_layer(const std::shared_ptr< Core::VKImage > &image, uint32_t layer, const void *data, size_t size, const std::shared_ptr< Buffers::VKBuffer > &staging=nullptr, bool deferred=false)
Upload pixels into one layer of an array image.
std::shared_ptr< Core::VKImage > create_2d_array(uint32_t width, uint32_t height, uint32_t layers, ImageFormat format=ImageFormat::RGBA8, const void *data=nullptr)
Create a 2D texture array.
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 > writable_format(const std::shared_ptr< Core::VKImage > &image)
ImageFormat of an image that can be written as one flat block.
std::shared_ptr< Core::VKImage > acquire_cached_image(ImageCacheEntry &entry, const ImageKey &key)
Reuse a matching image in an owner-held entry or create it once.
static std::optional< ImageFormat > from_vulkan_format(vk::Format vk_format)
Convert Vulkan format to Portal ImageFormat.
bool can_blit(const std::shared_ptr< Core::VKImage > &src, const std::shared_ptr< Core::VKImage > &dst, FilterMode filter=FilterMode::LINEAR) const
Whether the device can blit between two images with a filter.
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)
static std::optional< ImageFormat > transfer_format(const std::shared_ptr< Core::VKImage > &image, vk::ImageUsageFlagBits required_usage)
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.
Portal-level texture creation and management.
@ ImageProcessing
Image processing tasks (filters, transformations)
@ Portal
High-level user-facing API layer.
ImageFormat
User-friendly image format enum.
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.
FilterMode
Texture filtering mode.
@ NEAREST
Nearest neighbor (pixelated)
@ CUBIC
Bicubic filtering (high quality, slower)
static std::optional< ImageData > allocate(uint32_t width, uint32_t height, uint32_t channels, ImageFormat format)
Allocate zeroed pixel storage of the variant format calls for.
std::shared_ptr< Core::VKImage > image
Image retained by the producing owner.
size_t operator()(const ImageKey &key) const noexcept
Immutable properties that determine whether an image can be reused.
One layer to layer copy that scales and converts format.
AddressMode address_mode_v
AddressMode address_mode_w
AddressMode address_mode_u