Skip to main content

rotex_vulkan/backend/vulkan/
image.rs

1use 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}