atagen

monolith

public
Star0
Watch0
824bf02b6e554e9c0b86328878fc8eb8caa6926d
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/render-vk/src/image.rsRust276 lines7.9 KB
1
use crate::Error;
2
use crate::device::Shared;
3
use crate::format::{components, vk_format};
4
use ash::vk;
5
use gpu_allocator::MemoryLocation;
6
use gpu_allocator::vulkan::{Allocation, AllocationCreateDesc, AllocationScheme};
7
use smithay::backend::allocator::Fourcc;
8
use smithay::backend::renderer::{Texture, TextureMapping};
9
use std::fmt;
10
use std::sync::{Arc, Mutex};
11
12
pub(crate) struct ImageInner {
13
    pub shared: Arc<Shared>,
14
    pub image: vk::Image,
15
    pub view: vk::ImageView,
16
    pub allocation: Mutex<Option<Allocation>>,
17
    pub fourcc: Fourcc,
18
    pub format: vk::Format,
19
    pub width: u32,
20
    pub height: u32,
21
    pub layout: Mutex<vk::ImageLayout>,
22
}
23
24
impl fmt::Debug for ImageInner {
25
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26
        f.debug_struct("ImageInner")
27
            .field("image", &self.image)
28
            .field("fourcc", &self.fourcc)
29
            .field("size", &(self.width, self.height))
30
            .finish()
31
    }
32
}
33
34
impl Drop for ImageInner {
35
    fn drop(&mut self) {
36
        let d = &self.shared.device.device;
37
        unsafe {
38
            d.destroy_image_view(self.view, None);
39
            d.destroy_image(self.image, None);
40
        }
41
        if let Some(a) = self
42
            .allocation
43
            .lock()
44
            .unwrap_or_else(|e| e.into_inner())
45
            .take()
46
        {
47
            let _ = self
48
                .shared
49
                .allocator
50
                .lock()
51
                .unwrap_or_else(|e| e.into_inner())
52
                .free(a);
53
        }
54
    }
55
}
56
57
impl ImageInner {
58
    pub fn create(
59
        shared: &Arc<Shared>,
60
        fourcc: Fourcc,
61
        width: u32,
62
        height: u32,
63
        usage: vk::ImageUsageFlags,
64
    ) -> Result<Arc<Self>, Error> {
65
        let fmt = vk_format(fourcc).ok_or(Error::UnsupportedFormat(fourcc))?;
66
        if width == 0 || height == 0 {
67
            return Err(Error::InvalidSize(width as i32, height as i32));
68
        }
69
        let d = &shared.device.device;
70
        let info = vk::ImageCreateInfo::default()
71
            .image_type(vk::ImageType::TYPE_2D)
72
            .format(fmt.format)
73
            .extent(vk::Extent3D {
74
                width,
75
                height,
76
                depth: 1,
77
            })
78
            .mip_levels(1)
79
            .array_layers(1)
80
            .samples(vk::SampleCountFlags::TYPE_1)
81
            .tiling(vk::ImageTiling::OPTIMAL)
82
            .usage(usage)
83
            .initial_layout(vk::ImageLayout::UNDEFINED);
84
        let image = unsafe { d.create_image(&info, None)? };
85
        let requirements = unsafe { d.get_image_memory_requirements(image) };
86
        let allocation = shared
87
            .allocator
88
            .lock()
89
            .unwrap_or_else(|e| e.into_inner())
90
            .allocate(&AllocationCreateDesc {
91
                name: "image",
92
                requirements,
93
                location: MemoryLocation::GpuOnly,
94
                linear: false,
95
                allocation_scheme: AllocationScheme::GpuAllocatorManaged,
96
            });
97
        let allocation = match allocation {
98
            Ok(a) => a,
99
            Err(e) => {
100
                unsafe { d.destroy_image(image, None) };
101
                return Err(e.into());
102
            }
103
        };
104
        unsafe { d.bind_image_memory(image, allocation.memory(), allocation.offset())? };
105
        let view_info = vk::ImageViewCreateInfo::default()
106
            .image(image)
107
            .view_type(vk::ImageViewType::TYPE_2D)
108
            .format(fmt.format)
109
            .components(components(fmt.opaque))
110
            .subresource_range(color_range());
111
        let view = unsafe { d.create_image_view(&view_info, None)? };
112
        Ok(Arc::new(Self {
113
            shared: shared.clone(),
114
            image,
115
            view,
116
            allocation: Mutex::new(Some(allocation)),
117
            fourcc,
118
            format: fmt.format,
119
            width,
120
            height,
121
            layout: Mutex::new(vk::ImageLayout::UNDEFINED),
122
        }))
123
    }
124
125
    pub fn layout(&self) -> vk::ImageLayout {
126
        *self.layout.lock().unwrap_or_else(|e| e.into_inner())
127
    }
128
129
    pub fn set_layout(&self, layout: vk::ImageLayout) {
130
        *self.layout.lock().unwrap_or_else(|e| e.into_inner()) = layout;
131
    }
132
}
133
134
pub(crate) fn color_range() -> vk::ImageSubresourceRange {
135
    vk::ImageSubresourceRange::default()
136
        .aspect_mask(vk::ImageAspectFlags::COLOR)
137
        .level_count(1)
138
        .layer_count(1)
139
}
140
141
/// A host-visible buffer for uploads and readbacks.
142
pub(crate) struct Staging {
143
    pub shared: Arc<Shared>,
144
    pub buffer: vk::Buffer,
145
    pub allocation: Option<Allocation>,
146
}
147
148
impl Staging {
149
    pub fn new(
150
        shared: &Arc<Shared>,
151
        size: usize,
152
        usage: vk::BufferUsageFlags,
153
        location: MemoryLocation,
154
    ) -> Result<Self, Error> {
155
        let d = &shared.device.device;
156
        let buffer = unsafe {
157
            d.create_buffer(
158
                &vk::BufferCreateInfo::default()
159
                    .size(size as u64)
160
                    .usage(usage),
161
                None,
162
            )?
163
        };
164
        let requirements = unsafe { d.get_buffer_memory_requirements(buffer) };
165
        let allocation = shared
166
            .allocator
167
            .lock()
168
            .unwrap_or_else(|e| e.into_inner())
169
            .allocate(&AllocationCreateDesc {
170
                name: "staging",
171
                requirements,
172
                location,
173
                linear: true,
174
                allocation_scheme: AllocationScheme::GpuAllocatorManaged,
175
            });
176
        let allocation = match allocation {
177
            Ok(a) => a,
178
            Err(e) => {
179
                unsafe { d.destroy_buffer(buffer, None) };
180
                return Err(e.into());
181
            }
182
        };
183
        unsafe { d.bind_buffer_memory(buffer, allocation.memory(), allocation.offset())? };
184
        Ok(Self {
185
            shared: shared.clone(),
186
            buffer,
187
            allocation: Some(allocation),
188
        })
189
    }
190
191
    pub fn bytes(&self) -> &[u8] {
192
        self.allocation
193
            .as_ref()
194
            .and_then(|a| a.mapped_slice())
195
            .unwrap_or(&[])
196
    }
197
198
    pub fn bytes_mut(&mut self) -> &mut [u8] {
199
        self.allocation
200
            .as_mut()
201
            .and_then(|a| a.mapped_slice_mut())
202
            .unwrap_or(&mut [])
203
    }
204
}
205
206
impl Drop for Staging {
207
    fn drop(&mut self) {
208
        unsafe { self.shared.device.device.destroy_buffer(self.buffer, None) };
209
        if let Some(a) = self.allocation.take() {
210
            let _ = self
211
                .shared
212
                .allocator
213
                .lock()
214
                .unwrap_or_else(|e| e.into_inner())
215
                .free(a);
216
        }
217
    }
218
}
219
220
/// A sampled texture.
221
#[derive(Clone, Debug)]
222
pub struct VulkanTexture(pub(crate) Arc<ImageInner>);
223
224
/// An image the renderer can draw into, from [`smithay::backend::renderer::Offscreen`].
225
#[derive(Debug)]
226
pub struct VulkanImage(pub(crate) Arc<ImageInner>);
227
228
impl VulkanImage {
229
    /// The image's contents as a texture, for drawing it elsewhere.
230
    pub fn texture(&self) -> VulkanTexture {
231
        VulkanTexture(self.0.clone())
232
    }
233
}
234
235
/// A bound render target.
236
#[derive(Debug)]
237
pub struct VulkanTarget<'a>(pub(crate) &'a mut VulkanImage);
238
239
/// Pixels read back from the GPU.
240
#[derive(Debug)]
241
pub struct VulkanMapping {
242
    pub(crate) data: Vec<u8>,
243
    pub(crate) width: u32,
244
    pub(crate) height: u32,
245
    pub(crate) fourcc: Fourcc,
246
}
247
248
macro_rules! texture_impl {
249
    ($t:ty, |$s:ident| $inner:expr) => {
250
        impl Texture for $t {
251
            fn width(&self) -> u32 {
252
                let $s = self;
253
                $inner.width
254
            }
255
            fn height(&self) -> u32 {
256
                let $s = self;
257
                $inner.height
258
            }
259
            fn format(&self) -> Option<Fourcc> {
260
                let $s = self;
261
                Some($inner.fourcc)
262
            }
263
        }
264
    };
265
}
266
267
texture_impl!(VulkanTexture, |s| s.0);
268
texture_impl!(VulkanImage, |s| s.0);
269
texture_impl!(VulkanTarget<'_>, |s| s.0.0);
270
texture_impl!(VulkanMapping, |s| s);
271
272
impl TextureMapping for VulkanMapping {
273
    fn flipped(&self) -> bool {
274
        false
275
    }
276
}