MayaFlux 0.3.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
7namespace MayaFlux::Core {
8class VulkanBackend;
9class BackendResourceManager;
10}
11
12namespace MayaFlux::Buffers {
13class VKBuffer;
14}
15
17
18/**
19 * @struct SamplerConfig
20 * @brief Sampler configuration
21 */
31
32/**
33 * @class TextureLoom
34 * @brief Portal-level texture creation and management
35 *
36 * TextureLoom is the primary Portal::Graphics class for creating and
37 * managing GPU textures. It bridges between user-friendly Portal API and
38 * backend VKImage resources via BufferService registry.
39 *
40 * Key Responsibilities:
41 * - Create textures (2D, 3D, cubemaps, render targets)
42 * - Load textures from files (delegates to IO namespace)
43 * - Manage sampler objects (filtering, addressing)
44 * - Track texture lifecycle for cleanup
45 * - Provide convenient format conversions
46 *
47 * Design Philosophy:
48 * - Manages creation, NOT rendering (that's Pipeline/RenderPass)
49 * - Returns VKImage directly (no wrapping yet)
50 * - Simple, focused API (file loading deferred to IO)
51 * - Integrates with BufferService for backend independence
52 *
53 * Usage:
54 * auto& mgr = Portal::Graphics::TextureLoom::instance();
55 *
56 * // Create basic texture
57 * auto texture = mgr.create_2d(512, 512, ImageFormat::RGBA8);
58 *
59 * // Create with data
60 * std::vector<uint8_t> pixels = {...};
61 * auto texture = mgr.create_2d(512, 512, ImageFormat::RGBA8, pixels.data());
62 *
63 * // Create render target
64 * auto target = mgr.create_render_target(1920, 1080);
65 *
66 * // Get sampler
67 * SamplerConfig config;
68 * config.mag_filter = FilterMode::LINEAR;
69 * auto sampler = mgr.get_or_create_sampler(config);
70 */
71class MAYAFLUX_API TextureLoom {
72public:
74 {
75 static TextureLoom manager;
76 return manager;
77 }
78
79 // Non-copyable, movable
80 TextureLoom(const TextureLoom&) = delete;
82 TextureLoom(TextureLoom&&) noexcept = default;
83 TextureLoom& operator=(TextureLoom&&) noexcept = default;
84
85 /**
86 * @brief Initialize texture manager
87 * @param backend Shared pointer to VulkanBackend
88 * @return True if initialization succeeded
89 *
90 * Queries BufferService from BackendRegistry.
91 * Must be called before creating any textures.
92 */
93 bool initialize(const std::shared_ptr<Core::VulkanBackend>& backend);
94
95 /**
96 * @brief Shutdown and cleanup all textures
97 *
98 * Destroys all managed textures and samplers.
99 * Safe to call multiple times.
100 */
101 void shutdown();
102
103 /**
104 * @brief Check if manager is initialized
105 */
106 [[nodiscard]] bool is_initialized() const { return m_backend != nullptr; }
107
108 //==========================================================================
109 // Texture Creation
110 //==========================================================================
111
112 /**
113 * @brief Create a 2D texture
114 * @param width Width in pixels
115 * @param height Height in pixels
116 * @param format Image format
117 * @param data Optional initial pixel data (nullptr = empty)
118 * @param mip_levels Number of mipmap levels (1 = no mipmaps)
119 * @return Initialized VKImage ready for use
120 *
121 * Creates device-local texture optimized for shader sampling.
122 * If data provided, uploads immediately and transitions to shader read layout.
123 */
124 std::shared_ptr<Core::VKImage> create_2d(
125 uint32_t width,
126 uint32_t height,
127 ImageFormat format = ImageFormat::RGBA8,
128 const void* data = nullptr,
129 uint32_t mip_levels = 1);
130
131 /**
132 * @brief Create a 3D texture (volumetric)
133 * @param width Width in pixels
134 * @param height Height in pixels
135 * @param depth Depth in pixels
136 * @param format Image format
137 * @param data Optional initial pixel data
138 * @return Initialized VKImage
139 */
140 std::shared_ptr<Core::VKImage> create_3d(
141 uint32_t width,
142 uint32_t height,
143 uint32_t depth,
144 ImageFormat format = ImageFormat::RGBA8,
145 const void* data = nullptr);
146
147 /**
148 * @brief Create a cubemap texture
149 * @param size Cubemap face size in pixels (square)
150 * @param format Image format
151 * @param data Optional face data (6 faces in order: +X,-X,+Y,-Y,+Z,-Z)
152 * @return Initialized VKImage configured as cubemap
153 */
154 std::shared_ptr<Core::VKImage> create_cubemap(
155 uint32_t size,
156 ImageFormat format = ImageFormat::RGBA8,
157 const void* data = nullptr);
158
159 /**
160 * @brief Create a render target (color attachment)
161 * @param width Width in pixels
162 * @param height Height in pixels
163 * @param format Image format (default RGBA8)
164 * @return Initialized VKImage configured for rendering
165 *
166 * Creates image suitable for use as framebuffer color attachment.
167 * Can also be sampled in shaders after rendering.
168 */
169 std::shared_ptr<Core::VKImage> create_render_target(
170 uint32_t width,
171 uint32_t height,
172 ImageFormat format = ImageFormat::RGBA8);
173
174 /**
175 * @brief Create a depth buffer
176 * @param width Width in pixels
177 * @param height Height in pixels
178 * @param with_stencil Whether to include stencil component
179 * @return Initialized VKImage configured as depth/stencil attachment
180 */
181 std::shared_ptr<Core::VKImage> create_depth_buffer(
182 uint32_t width,
183 uint32_t height,
184 bool with_stencil = false);
185
186 /**
187 * @brief Create a storage image (compute shader read/write)
188 * @param width Width in pixels
189 * @param height Height in pixels
190 * @param format Image format
191 * @return Initialized VKImage configured for compute storage
192 */
193 std::shared_ptr<Core::VKImage> create_storage_image(
194 uint32_t width,
195 uint32_t height,
196 ImageFormat format = ImageFormat::RGBA8);
197
198 //==========================================================================
199 // Data Upload/Download
200 //==========================================================================
201
202 /**
203 * @brief Upload pixel data to an existing texture
204 * @param image Target image
205 * @param data Pixel data pointer
206 * @param size Data size in bytes
207 *
208 * Handles staging buffer, layout transitions, and cleanup.
209 * Blocks until upload completes.
210 */
211 void upload_data(
212 const std::shared_ptr<Core::VKImage>& image,
213 const void* data,
214 size_t size);
215
216 /**
217 * @brief Upload pixel data reusing a caller-supplied persistent staging buffer.
218 * Identical to upload_data() but skips the per-call VkBuffer allocation,
219 * eliminating the Vulkan object churn that causes VK_ERROR_DEVICE_LOST
220 * under sustained per-frame texture updates (e.g. video playback).
221 * @param image Target VKImage (must already be initialised).
222 * @param data Pixel data pointer (at least @p size bytes).
223 * @param size Byte count — must match the image footprint.
224 * @param staging Host-visible staging VKBuffer from create_streaming_staging().
225 */
226 void upload_data(
227 const std::shared_ptr<Core::VKImage>& image,
228 const void* data,
229 size_t size,
230 const std::shared_ptr<Buffers::VKBuffer>& staging);
231
232 /**
233 * @brief Download pixel data from a texture
234 * @param image Source image
235 * @param data Destination buffer
236 * @param size Buffer size in bytes
237 *
238 * Handles staging buffer, layout transitions, and cleanup.
239 * Blocks until download completes.
240 */
241 void download_data(
242 const std::shared_ptr<Core::VKImage>& image,
243 void* data,
244 size_t size);
245
246 //==========================================================================
247 // Sampler Management
248 //==========================================================================
249
250 /**
251 * @brief Get or create a sampler with the given configuration
252 * @param config Sampler configuration
253 * @return Vulkan sampler handle (cached)
254 *
255 * Samplers are cached - identical configs return same sampler.
256 * Managed by TextureLoom, destroyed on shutdown.
257 */
258 vk::Sampler get_or_create_sampler(const SamplerConfig& config);
259
260 /**
261 * @brief Get a default linear sampler (for convenience)
262 */
263 vk::Sampler get_default_sampler();
264
265 /**
266 * @brief Get a default nearest sampler (for pixel-perfect sampling)
267 */
268 vk::Sampler get_nearest_sampler();
269
270 //==========================================================================
271 // Utilities
272 //==========================================================================
273
274 /**
275 * @brief Convert Portal ImageFormat to Vulkan format
276 */
277 static vk::Format to_vulkan_format(ImageFormat format);
278
279 /**
280 * @brief Get bytes per pixel for a format
281 */
282 static size_t get_bytes_per_pixel(ImageFormat format);
283
284 /**
285 * @brief Calculate image data size
286 */
287 static size_t calculate_image_size(
288 uint32_t width,
289 uint32_t height,
290 uint32_t depth,
291 ImageFormat format);
292
293private:
294 TextureLoom() = default;
296
297 std::shared_ptr<Core::VulkanBackend> m_backend;
298 Core::BackendResourceManager* m_resource_manager = nullptr;
299
300 // Managed textures (for cleanup)
301 std::vector<std::shared_ptr<Core::VKImage>> m_textures;
302
303 // Sampler cache (config hash -> sampler)
304 std::unordered_map<size_t, vk::Sampler> m_sampler_cache;
305
306 // Helper: create sampler from config
307 vk::Sampler create_sampler(const SamplerConfig& config);
308
309 // Helper: hash sampler config for caching
310 static size_t hash_sampler_config(const SamplerConfig& config);
311
312 static bool s_initialized;
313};
314
315/**
316 * @brief Get the global texture manager instance
317 * @return Reference to singleton texture manager
318 *
319 * Must call initialize() before first use.
320 * Thread-safe after initialization.
321 */
322inline MAYAFLUX_API TextureLoom& get_texture_manager()
323{
324 return TextureLoom::instance();
325}
326
327} // namespace MayaFlux::Portal::Graphics
Manages Vulkan resources (buffers, images, samplers) for the graphics backend.
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:11
MAYAFLUX_API TextureLoom & get_texture_manager()
Get the global texture manager instance.
void shutdown()
Shutdown Portal::Graphics subsystem.
Definition Graphics.cpp:87
AddressMode
Texture addressing mode (wrapping)
FilterMode
Texture filtering mode.
@ LINEAR
Bilinear filtering (smooth)
ImageFormat
User-friendly image format enum.