rotex_vulkan/backend/vulkan/
image.rs1use ash::vk;
2
3use super::command::CommandBuffer;
4use super::device::Device;
5use crate::core::Instance;
6use crate::error::vk_error;
7use crate::{Error, ErrorKind};
8
9pub struct ImageDescriptor {
10 pub format: vk::Format,
11 pub extent: vk::Extent3D,
12 pub usage: vk::ImageUsageFlags,
13 pub properties: vk::MemoryPropertyFlags,
14 pub mip_levels: u32,
15 pub array_layers: u32,
16 pub image_type: vk::ImageType,
17 pub view_type: vk::ImageViewType,
18 pub tiling: vk::ImageTiling,
19 pub samples: vk::SampleCountFlags,
20}
21
22impl ImageDescriptor {
23 pub fn default(
24 format: vk::Format,
25 extent: vk::Extent3D,
26 usage: vk::ImageUsageFlags,
27 properties: vk::MemoryPropertyFlags,
28 ) -> Self {
29 Self {
30 format,
31 extent,
32 usage,
33 properties,
34 mip_levels: 1,
35 array_layers: 1,
36 image_type: vk::ImageType::TYPE_2D,
37 view_type: vk::ImageViewType::TYPE_2D,
38 tiling: vk::ImageTiling::OPTIMAL,
39 samples: vk::SampleCountFlags::TYPE_1,
40 }
41 }
42
43 pub fn with_mip_levels(mut self, levels: u32) -> Self {
44 self.mip_levels = levels;
45 self
46 }
47
48 pub fn with_array_layers(mut self, layers: u32, view_type: vk::ImageViewType) -> Self {
49 self.array_layers = layers;
50 self.view_type = view_type;
51 self
52 }
53}
54
55pub struct RotexImage {
56 image_handle: vk::Image,
57 device_memory: vk::DeviceMemory,
58 image_view: vk::ImageView,
59 current_layout: std::cell::Cell<vk::ImageLayout>,
60 aspect_mask: vk::ImageAspectFlags,
61}
62
63impl RotexImage {
64 pub fn new(instance: &Instance, device: &Device, desc: ImageDescriptor) -> Result<Self, Error> {
65 let image_create_info = vk::ImageCreateInfo::default()
66 .image_type(desc.image_type)
67 .format(desc.format)
68 .extent(desc.extent)
69 .mip_levels(desc.mip_levels)
70 .array_layers(desc.array_layers)
71 .samples(desc.samples)
72 .tiling(desc.tiling)
73 .usage(desc.usage)
74 .sharing_mode(vk::SharingMode::EXCLUSIVE);
75
76 let image_handle = unsafe { device.logical_device().create_image(&image_create_info, None) }
77 .map_err(vk_error)?;
78
79 let mem_requirements = unsafe {
80 device
81 .logical_device()
82 .get_image_memory_requirements(image_handle)
83 };
84
85 let memory_type_index = device.find_memory_type(
86 instance,
87 mem_requirements.memory_type_bits,
88 desc.properties,
89 )?;
90
91 let alloc_info = vk::MemoryAllocateInfo::default()
92 .allocation_size(mem_requirements.size)
93 .memory_type_index(memory_type_index);
94
95 let device_memory = unsafe { device.logical_device().allocate_memory(&alloc_info, None) }
96 .map_err(vk_error)?;
97
98 unsafe {
99 device
100 .logical_device()
101 .bind_image_memory(image_handle, device_memory, 0)
102 }
103 .map_err(vk_error)?;
104
105 let aspect_mask = Self::infer_aspect_mask(desc.format);
106
107 let view_create_info = vk::ImageViewCreateInfo::default()
108 .image(image_handle)
109 .view_type(desc.view_type)
110 .format(desc.format)
111 .subresource_range(vk::ImageSubresourceRange {
112 aspect_mask,
113 base_mip_level: 0,
114 level_count: desc.mip_levels,
115 base_array_layer: 0,
116 layer_count: desc.array_layers,
117 });
118
119 let image_view = unsafe { device.logical_device().create_image_view(&view_create_info, None) }
120 .map_err(vk_error)?;
121
122 Ok(Self {
123 image_handle,
124 device_memory,
125 image_view,
126 current_layout: std::cell::Cell::new(vk::ImageLayout::UNDEFINED),
127 aspect_mask,
128 })
129 }
130
131 fn infer_aspect_mask(format: vk::Format) -> vk::ImageAspectFlags {
132 let is_depth = matches!(
133 format,
134 vk::Format::D32_SFLOAT
135 | vk::Format::D32_SFLOAT_S8_UINT
136 | vk::Format::D24_UNORM_S8_UINT
137 | vk::Format::D16_UNORM
138 | vk::Format::D16_UNORM_S8_UINT
139 );
140
141 let is_stencil = matches!(
142 format,
143 vk::Format::D32_SFLOAT_S8_UINT
144 | vk::Format::D24_UNORM_S8_UINT
145 | vk::Format::D16_UNORM_S8_UINT
146 | vk::Format::S8_UINT
147 );
148
149 if is_depth && is_stencil {
150 vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL
151 } else if is_depth {
152 vk::ImageAspectFlags::DEPTH
153 } else {
154 vk::ImageAspectFlags::COLOR
155 }
156 }
157
158 pub fn transition_layout(
159 &self,
160 device: &Device,
161 command_buffer: &CommandBuffer,
162 new_layout: vk::ImageLayout,
163 ) {
164 let old_layout = self.current_layout.get();
165
166 if old_layout == new_layout {
167 return;
168 }
169
170 command_buffer.transition_image_layout(
171 device,
172 self.image_handle,
173 old_layout,
174 new_layout,
175 self.aspect_mask,
176 );
177
178 self.current_layout.set(new_layout);
179 }
180
181 pub fn handle(&self) -> vk::Image {
182 self.image_handle
183 }
184
185 pub fn view(&self) -> vk::ImageView {
186 self.image_view
187 }
188
189 pub fn destroy(&self, device: &Device) {
190 unsafe {
191 device
192 .logical_device()
193 .destroy_image_view(self.image_view, None);
194 device
195 .logical_device()
196 .destroy_image(self.image_handle, None);
197 device
198 .logical_device()
199 .free_memory(self.device_memory, None);
200 }
201 }
202}
203
204pub struct SamplerDescriptor {
205 pub mag_filter: vk::Filter,
206 pub min_filter: vk::Filter,
207 pub anisotropy_enable: bool,
208 pub max_anisotropy: f32,
209 pub address_mode_u: vk::SamplerAddressMode,
210 pub address_mode_v: vk::SamplerAddressMode,
211 pub address_mode_w: vk::SamplerAddressMode,
212 pub border_color: vk::BorderColor,
213 pub unnormalized_coordinates: bool,
214 pub compare_enable: bool,
215 pub mipmap_mode: vk::SamplerMipmapMode,
216}
217
218impl SamplerDescriptor {
219 pub fn default() -> Self {
220 Self {
221 mag_filter: vk::Filter::NEAREST,
222 min_filter: vk::Filter::NEAREST,
223 anisotropy_enable: false,
224 max_anisotropy: 1.0,
225 address_mode_u: vk::SamplerAddressMode::CLAMP_TO_EDGE,
226 address_mode_v: vk::SamplerAddressMode::CLAMP_TO_EDGE,
227 address_mode_w: vk::SamplerAddressMode::CLAMP_TO_EDGE,
228 border_color: vk::BorderColor::INT_OPAQUE_BLACK,
229 unnormalized_coordinates: false,
230 compare_enable: false,
231 mipmap_mode: vk::SamplerMipmapMode::LINEAR,
232 }
233 }
234
235 pub fn with_address_modes(
236 mut self,
237 u: vk::SamplerAddressMode,
238 v: vk::SamplerAddressMode,
239 w: vk::SamplerAddressMode,
240 ) -> Self {
241 self.address_mode_u = u;
242 self.address_mode_v = v;
243 self.address_mode_w = w;
244 self
245 }
246
247 pub fn with_anisotropy(mut self, enable: bool, max_anisotropy: f32) -> Self {
248 self.anisotropy_enable = enable;
249 self.max_anisotropy = max_anisotropy;
250 self
251 }
252
253 pub fn with_filters(mut self, mag_filter: vk::Filter, min_filter: vk::Filter) -> Self {
254 self.mag_filter = mag_filter;
255 self.min_filter = min_filter;
256 self
257 }
258
259 pub fn with_border_color(mut self, border_color: vk::BorderColor) -> Self {
260 self.border_color = border_color;
261 self
262 }
263
264 pub fn with_unnormalized_coordinates(mut self, unnormalized: bool) -> Self {
265 self.unnormalized_coordinates = unnormalized;
266 self
267 }
268
269 pub fn with_compare_enable(mut self, compare_enable: bool) -> Self {
270 self.compare_enable = compare_enable;
271 self
272 }
273
274 pub fn with_mipmap_mode(mut self, mipmap_mode: vk::SamplerMipmapMode) -> Self {
275 self.mipmap_mode = mipmap_mode;
276 self
277 }
278}
279
280pub struct RotexSampler {
281 handle: vk::Sampler,
282}
283
284impl RotexSampler {
285 pub fn new(device: &Device, descriptor: SamplerDescriptor) -> Result<Self, Error> {
286 let create_info = vk::SamplerCreateInfo::default()
287 .mag_filter(descriptor.mag_filter)
288 .min_filter(descriptor.min_filter)
289 .address_mode_u(descriptor.address_mode_u)
290 .address_mode_v(descriptor.address_mode_v)
291 .address_mode_w(descriptor.address_mode_w)
292 .anisotropy_enable(descriptor.anisotropy_enable)
293 .max_anisotropy(descriptor.max_anisotropy)
294 .border_color(descriptor.border_color)
295 .unnormalized_coordinates(descriptor.unnormalized_coordinates)
296 .compare_enable(descriptor.compare_enable)
297 .mipmap_mode(descriptor.mipmap_mode);
298
299 let handle = unsafe { device.logical_device().create_sampler(&create_info, None) }
300 .map_err(ErrorKind::Vulkan)
301 .map_err(Error::fatal)?;
302
303 Ok(Self { handle })
304 }
305
306 pub fn handle(&self) -> vk::Sampler {
307 self.handle
308 }
309
310 pub fn destroy(&self, device: &Device) {
311 unsafe { device.logical_device().destroy_sampler(self.handle, None) };
312 }
313}