MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SamplerForge.cpp
Go to the documentation of this file.
1#include "SamplerForge.hpp"
2
6#include "TextureLoom.hpp"
7
9
11
12bool SamplerForge::initialize(const std::shared_ptr<Core::VulkanBackend>& backend)
13{
14 if (s_initialized) {
16 "SamplerForge already initialized (static flag)");
17 return true;
18 }
19
20 if (!backend) {
22 "Cannot initialize SamplerForge with null backend");
23 return false;
24 }
25
26 if (m_backend) {
28 "SamplerForge already initialized");
29 return true;
30 }
31
32 m_backend = backend;
33
34 s_initialized = true;
35
37 "SamplerForge initialized");
38
39 return true;
40}
41
43{
44 if (!s_initialized) {
45 return;
46 }
47
48 if (!m_backend) {
49 return;
50 }
51
53 "Shutting down SamplerForge...");
54
55 auto device = m_backend->get_context().get_device();
56 for (auto& [hash, sampler] : m_sampler_cache) {
57 if (sampler) {
58 device.destroySampler(sampler);
59 }
60 }
61 m_sampler_cache.clear();
62
63 m_backend = nullptr;
64
65 s_initialized = false;
66
68 "SamplerForge shutdown complete");
69}
70
72{
73 if (!is_initialized()) {
75 "SamplerForge not initialized");
76 return nullptr;
77 }
78
79 size_t hash = hash_config(config);
80
81 auto it = m_sampler_cache.find(hash);
82 if (it != m_sampler_cache.end()) {
83 return it->second;
84 }
85
86 vk::Sampler sampler = create_sampler(config);
87 if (sampler) {
88 m_sampler_cache[hash] = sampler;
90 "Created and cached sampler (hash: {}, total: {})",
91 hash, m_sampler_cache.size());
92 }
93
94 return sampler;
95}
96
98{
99 SamplerConfig config;
105 config.max_anisotropy = 1.0F;
106 return get_or_create(config);
107}
108
120
121vk::Sampler SamplerForge::get_anisotropic(float max_anisotropy)
122{
123 SamplerConfig config;
129 config.max_anisotropy = std::clamp(max_anisotropy, 1.0F, 16.0F);
130 return get_or_create(config);
131}
132
133void SamplerForge::destroy_sampler(vk::Sampler sampler)
134{
135 if (!is_initialized() || !sampler) {
136 return;
137 }
138
139 for (auto it = m_sampler_cache.begin(); it != m_sampler_cache.end(); ++it) {
140 if (it->second == sampler) {
141 auto device = m_backend->get_context().get_device();
142 device.destroySampler(sampler);
143 m_sampler_cache.erase(it);
145 "Destroyed sampler (remaining: {})", m_sampler_cache.size());
146 return;
147 }
148 }
149}
150
152{
153 auto device = m_backend->get_context().get_device();
154 auto physical_device = m_backend->get_context().get_physical_device();
155
156 vk::SamplerCreateInfo sampler_info {};
157 sampler_info.magFilter = to_vk_filter(config.mag_filter);
158 sampler_info.minFilter = to_vk_filter(config.min_filter);
159
160 sampler_info.addressModeU = to_vk_address_mode(config.address_mode_u);
161 sampler_info.addressModeV = to_vk_address_mode(config.address_mode_v);
162 sampler_info.addressModeW = to_vk_address_mode(config.address_mode_w);
163
164 if (config.max_anisotropy > 1.0F) {
165 auto properties = physical_device.getProperties();
166 sampler_info.anisotropyEnable = VK_TRUE;
167 sampler_info.maxAnisotropy = std::min(
168 config.max_anisotropy,
169 properties.limits.maxSamplerAnisotropy);
170 } else {
171 sampler_info.anisotropyEnable = VK_FALSE;
172 sampler_info.maxAnisotropy = 1.0F;
173 }
174
175 sampler_info.borderColor = vk::BorderColor::eIntOpaqueBlack;
176
177 sampler_info.unnormalizedCoordinates = VK_FALSE;
178
179 sampler_info.compareEnable = VK_FALSE;
180 sampler_info.compareOp = vk::CompareOp::eAlways;
181
182 if (config.enable_mipmaps) {
183 sampler_info.mipmapMode = (config.min_filter == FilterMode::LINEAR)
184 ? vk::SamplerMipmapMode::eLinear
185 : vk::SamplerMipmapMode::eNearest;
186 sampler_info.minLod = 0.0F;
187 sampler_info.maxLod = VK_LOD_CLAMP_NONE;
188 sampler_info.mipLodBias = 0.0F;
189 } else {
190 sampler_info.mipmapMode = vk::SamplerMipmapMode::eNearest;
191 sampler_info.minLod = 0.0F;
192 sampler_info.maxLod = 0.0F;
193 sampler_info.mipLodBias = 0.0F;
194 }
195
196 try {
197 vk::Sampler sampler = device.createSampler(sampler_info);
199 "Created sampler: mag={}, min={}, aniso={}",
200 vk::to_string(sampler_info.magFilter),
201 vk::to_string(sampler_info.minFilter),
202 sampler_info.maxAnisotropy);
203 return sampler;
204 } catch (const vk::SystemError& e) {
206 "Failed to create sampler: {}", e.what());
207 return nullptr;
208 }
209}
210
212{
213 size_t hash = 0;
214 hash ^= std::hash<int> {}(static_cast<int>(config.mag_filter)) << 0;
215 hash ^= std::hash<int> {}(static_cast<int>(config.min_filter)) << 4;
216 hash ^= std::hash<int> {}(static_cast<int>(config.address_mode_u)) << 8;
217 hash ^= std::hash<int> {}(static_cast<int>(config.address_mode_v)) << 12;
218 hash ^= std::hash<int> {}(static_cast<int>(config.address_mode_w)) << 16;
219 hash ^= std::hash<float> {}(config.max_anisotropy) << 20;
220 hash ^= std::hash<bool> {}(config.enable_mipmaps) << 24;
221 return hash;
222}
223
225{
226 switch (mode) {
228 return vk::Filter::eNearest;
230 return vk::Filter::eLinear;
232 return vk::Filter::eCubicEXT;
233 default:
234 return vk::Filter::eLinear;
235 }
236}
237
239{
240 switch (mode) {
242 return vk::SamplerAddressMode::eRepeat;
244 return vk::SamplerAddressMode::eMirroredRepeat;
246 return vk::SamplerAddressMode::eClampToEdge;
248 return vk::SamplerAddressMode::eClampToBorder;
249 default:
250 return vk::SamplerAddressMode::eRepeat;
251 }
252}
253
254} // namespace MayaFlux::Portal::Graphics
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
bool is_initialized() const
Check if factory is initialized.
static vk::Filter to_vk_filter(FilterMode mode)
std::unordered_map< size_t, vk::Sampler > m_sampler_cache
static vk::SamplerAddressMode to_vk_address_mode(AddressMode mode)
vk::Sampler get_default_linear()
Get a default linear sampler.
static size_t hash_config(const SamplerConfig &config)
vk::Sampler get_default_nearest()
Get a default nearest sampler.
void shutdown()
Shutdown and cleanup all samplers.
void destroy_sampler(vk::Sampler sampler)
Destroy a specific sampler.
vk::Sampler get_or_create(const SamplerConfig &config)
Get or create a sampler with the given configuration.
vk::Sampler get_anisotropic(float max_anisotropy=16.0F)
Get an anisotropic sampler (high quality)
bool initialize(const std::shared_ptr< Core::VulkanBackend > &backend)
Initialize with backend reference.
vk::Sampler create_sampler(const SamplerConfig &config)
std::shared_ptr< Core::VulkanBackend > m_backend
@ ImageProcessing
Image processing tasks (filters, transformations)
@ Portal
High-level user-facing API layer.
AddressMode
Texture addressing mode (wrapping)
@ CLAMP_TO_BORDER
Clamp to border color.
FilterMode
Texture filtering mode.
@ LINEAR
Bilinear filtering (smooth)
@ NEAREST
Nearest neighbor (pixelated)
@ CUBIC
Bicubic filtering (high quality, slower)