librashader_runtime_vk/
texture.rs

1use crate::filter_chain::VulkanObjects;
2use crate::memory::VulkanImageMemory;
3use crate::{error, util};
4use ash::vk;
5use gpu_allocator::vulkan::Allocator;
6use parking_lot::Mutex;
7use std::sync::Arc;
8
9use crate::error::FilterChainError;
10use librashader_common::{FilterMode, GetSize, ImageFormat, Size, WrapMode};
11use librashader_presets::Scale2D;
12use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
13
14pub struct OwnedImage {
15    pub device: Arc<ash::Device>,
16    pub allocator: Arc<Mutex<Allocator>>,
17    pub image_view: vk::ImageView,
18    pub image: VulkanImage,
19    pub max_miplevels: u32,
20    pub levels: u32,
21    pub _memory: VulkanImageMemory,
22}
23
24#[derive(Clone)]
25pub struct OwnedImageLayout {
26    pub(crate) dst_layout: vk::ImageLayout,
27    pub(crate) dst_access: vk::AccessFlags,
28    pub(crate) src_stage: vk::PipelineStageFlags,
29    pub(crate) dst_stage: vk::PipelineStageFlags,
30    pub(crate) cmd: vk::CommandBuffer,
31}
32
33impl OwnedImage {
34    fn new_internal(
35        device: Arc<ash::Device>,
36        alloc: &Arc<Mutex<Allocator>>,
37        size: Size<u32>,
38        mut format: ImageFormat,
39        max_miplevels: u32,
40    ) -> error::Result<OwnedImage> {
41        // default to something sane
42        if format == ImageFormat::Unknown {
43            format = ImageFormat::R8G8B8A8Unorm
44        }
45        let image_create_info = vk::ImageCreateInfo::default()
46            .image_type(vk::ImageType::TYPE_2D)
47            .format(format.into())
48            .extent(size.into())
49            .mip_levels(std::cmp::min(max_miplevels, size.calculate_miplevels()))
50            .array_layers(1)
51            .samples(vk::SampleCountFlags::TYPE_1)
52            .tiling(vk::ImageTiling::OPTIMAL)
53            .flags(vk::ImageCreateFlags::MUTABLE_FORMAT)
54            .usage(
55                vk::ImageUsageFlags::SAMPLED
56                    | vk::ImageUsageFlags::COLOR_ATTACHMENT
57                    | vk::ImageUsageFlags::TRANSFER_DST
58                    | vk::ImageUsageFlags::TRANSFER_SRC,
59            )
60            .sharing_mode(vk::SharingMode::EXCLUSIVE)
61            .initial_layout(vk::ImageLayout::UNDEFINED);
62
63        let image = unsafe { device.create_image(&image_create_info, None)? };
64        let mem_reqs = unsafe { device.get_image_memory_requirements(image) };
65
66        let memory = VulkanImageMemory::new(&device, alloc, mem_reqs, &image)?;
67        let image_subresource = vk::ImageSubresourceRange::default()
68            .base_mip_level(0)
69            .base_array_layer(0)
70            .level_count(image_create_info.mip_levels)
71            .layer_count(1)
72            .aspect_mask(vk::ImageAspectFlags::COLOR);
73
74        let swizzle_components = vk::ComponentMapping::default()
75            .r(vk::ComponentSwizzle::R)
76            .g(vk::ComponentSwizzle::G)
77            .b(vk::ComponentSwizzle::B)
78            .a(vk::ComponentSwizzle::A);
79
80        let view_info = vk::ImageViewCreateInfo::default()
81            .view_type(vk::ImageViewType::TYPE_2D)
82            .format(format.into())
83            .image(image)
84            .subresource_range(image_subresource)
85            .components(swizzle_components);
86
87        let image_view = unsafe { device.create_image_view(&view_info, None)? };
88
89        Ok(OwnedImage {
90            device,
91            allocator: Arc::clone(alloc),
92            image_view,
93            image: VulkanImage {
94                image,
95                size,
96                format: format.into(),
97            },
98            _memory: memory,
99            max_miplevels,
100            levels: std::cmp::min(max_miplevels, size.calculate_miplevels()),
101        })
102    }
103
104    pub fn new(
105        vulkan: &VulkanObjects,
106        size: Size<u32>,
107        format: ImageFormat,
108        max_miplevels: u32,
109    ) -> error::Result<OwnedImage> {
110        Self::new_internal(
111            vulkan.device.clone(),
112            &vulkan.alloc,
113            size,
114            format,
115            max_miplevels,
116        )
117    }
118
119    pub(crate) fn scale(
120        &mut self,
121        scaling: Scale2D,
122        format: ImageFormat,
123        viewport_size: &Size<u32>,
124        source_size: &Size<u32>,
125        original_size: &Size<u32>,
126        mipmap: bool,
127        layout: Option<OwnedImageLayout>,
128    ) -> error::Result<Size<u32>> {
129        let size = source_size.scale_viewport(scaling, *viewport_size, *original_size, None);
130        if self.image.size != size
131            || (mipmap && self.max_miplevels == 1)
132            || (!mipmap && self.max_miplevels != 1)
133            || vk::Format::from(format) != self.image.format
134        {
135            let max_levels = if mipmap { u32::MAX } else { 1 };
136
137            let new = OwnedImage::new_internal(
138                self.device.clone(),
139                &self.allocator,
140                size,
141                if format == ImageFormat::Unknown {
142                    ImageFormat::R8G8B8A8Unorm
143                } else {
144                    format
145                },
146                max_levels,
147            )?;
148
149            let old = std::mem::replace(self, new);
150            drop(old);
151
152            if let Some(layout) = layout {
153                unsafe {
154                    util::vulkan_image_layout_transition_levels(
155                        &self.device,
156                        layout.cmd,
157                        self.image.image,
158                        self.levels,
159                        vk::ImageLayout::UNDEFINED,
160                        layout.dst_layout,
161                        vk::AccessFlags::empty(),
162                        layout.dst_access,
163                        layout.src_stage,
164                        layout.dst_stage,
165                        vk::QUEUE_FAMILY_IGNORED,
166                        vk::QUEUE_FAMILY_IGNORED,
167                    )
168                }
169            }
170        }
171        Ok(size)
172    }
173
174    pub(crate) fn as_input(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputImage {
175        InputImage {
176            image: self.image.clone(),
177            image_view: self.image_view,
178            wrap_mode,
179            filter_mode: filter,
180            mip_filter: filter,
181        }
182    }
183
184    pub fn generate_mipmaps_and_end_pass(&self, cmd: vk::CommandBuffer) {
185        let input_barrier = vk::ImageMemoryBarrier::default()
186            .src_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE)
187            .dst_access_mask(vk::AccessFlags::TRANSFER_READ)
188            .old_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
189            .new_layout(vk::ImageLayout::TRANSFER_SRC_OPTIMAL)
190            .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
191            .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
192            .image(self.image.image)
193            .subresource_range(vk::ImageSubresourceRange {
194                aspect_mask: vk::ImageAspectFlags::COLOR,
195                base_mip_level: 0,
196                level_count: 1,
197                base_array_layer: 0,
198                layer_count: vk::REMAINING_ARRAY_LAYERS,
199            });
200
201        let mipchain_barrier = vk::ImageMemoryBarrier::default()
202            .src_access_mask(vk::AccessFlags::empty())
203            .dst_access_mask(vk::AccessFlags::TRANSFER_WRITE)
204            .old_layout(vk::ImageLayout::UNDEFINED)
205            .new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
206            .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
207            .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
208            .image(self.image.image)
209            .subresource_range(vk::ImageSubresourceRange {
210                aspect_mask: vk::ImageAspectFlags::COLOR,
211                base_mip_level: 1,
212                base_array_layer: 0,
213                level_count: vk::REMAINING_MIP_LEVELS,
214                layer_count: vk::REMAINING_ARRAY_LAYERS,
215            });
216
217        unsafe {
218            self.device.cmd_pipeline_barrier(
219                cmd,
220                vk::PipelineStageFlags::ALL_GRAPHICS,
221                vk::PipelineStageFlags::TRANSFER,
222                vk::DependencyFlags::empty(),
223                &[],
224                &[],
225                &[input_barrier, mipchain_barrier],
226            );
227
228            for level in 1..self.levels {
229                // need to transition from DST to SRC, one level at a time.
230                if level > 1 {
231                    let next_barrier = vk::ImageMemoryBarrier::default()
232                        .src_access_mask(vk::AccessFlags::TRANSFER_WRITE)
233                        .dst_access_mask(vk::AccessFlags::TRANSFER_READ)
234                        .old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
235                        .new_layout(vk::ImageLayout::TRANSFER_SRC_OPTIMAL)
236                        .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
237                        .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
238                        .image(self.image.image)
239                        .subresource_range(vk::ImageSubresourceRange {
240                            aspect_mask: vk::ImageAspectFlags::COLOR,
241                            base_mip_level: level - 1,
242                            base_array_layer: 0,
243                            level_count: 1,
244                            layer_count: vk::REMAINING_ARRAY_LAYERS,
245                        });
246
247                    self.device.cmd_pipeline_barrier(
248                        cmd,
249                        vk::PipelineStageFlags::TRANSFER,
250                        vk::PipelineStageFlags::TRANSFER,
251                        vk::DependencyFlags::empty(),
252                        &[],
253                        &[],
254                        &[next_barrier],
255                    );
256                }
257
258                let source_size = self.image.size.scale_mipmap(level - 1);
259                let target_size = self.image.size.scale_mipmap(level);
260
261                let src_offsets = [
262                    vk::Offset3D { x: 0, y: 0, z: 0 },
263                    vk::Offset3D {
264                        x: source_size.width as i32,
265                        y: source_size.height as i32,
266                        z: 1,
267                    },
268                ];
269
270                let dst_offsets = [
271                    vk::Offset3D { x: 0, y: 0, z: 0 },
272                    vk::Offset3D {
273                        x: target_size.width as i32,
274                        y: target_size.height as i32,
275                        z: 1,
276                    },
277                ];
278
279                let src_subresource = vk::ImageSubresourceLayers::default()
280                    .aspect_mask(vk::ImageAspectFlags::COLOR)
281                    .mip_level(level - 1)
282                    .base_array_layer(0)
283                    .layer_count(1);
284
285                let dst_subresource = vk::ImageSubresourceLayers::default()
286                    .aspect_mask(vk::ImageAspectFlags::COLOR)
287                    .mip_level(level)
288                    .base_array_layer(0)
289                    .layer_count(1);
290
291                let image_blit = vk::ImageBlit::default()
292                    .src_subresource(src_subresource)
293                    .src_offsets(src_offsets)
294                    .dst_subresource(dst_subresource)
295                    .dst_offsets(dst_offsets);
296
297                self.device.cmd_blit_image(
298                    cmd,
299                    self.image.image,
300                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
301                    self.image.image,
302                    vk::ImageLayout::TRANSFER_DST_OPTIMAL,
303                    &[image_blit],
304                    vk::Filter::LINEAR,
305                );
306            }
307
308            // move everything to SHADER_READ_ONLY_OPTIMAL
309
310            let input_barrier = vk::ImageMemoryBarrier::default()
311                .src_access_mask(vk::AccessFlags::TRANSFER_READ)
312                .dst_access_mask(vk::AccessFlags::SHADER_READ)
313                .old_layout(vk::ImageLayout::TRANSFER_SRC_OPTIMAL)
314                .new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
315                .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
316                .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
317                .image(self.image.image)
318                .subresource_range(vk::ImageSubresourceRange {
319                    aspect_mask: vk::ImageAspectFlags::COLOR,
320                    base_mip_level: 0,
321                    level_count: self.levels - 1,
322                    base_array_layer: 0,
323                    layer_count: vk::REMAINING_ARRAY_LAYERS,
324                });
325
326            let mipchain_barrier = vk::ImageMemoryBarrier::default()
327                .src_access_mask(vk::AccessFlags::TRANSFER_WRITE)
328                .dst_access_mask(vk::AccessFlags::SHADER_READ)
329                .old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
330                .new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
331                .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
332                .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
333                .image(self.image.image)
334                .subresource_range(vk::ImageSubresourceRange {
335                    aspect_mask: vk::ImageAspectFlags::COLOR,
336                    base_mip_level: self.levels - 1,
337                    base_array_layer: 0,
338                    level_count: 1,
339                    layer_count: vk::REMAINING_ARRAY_LAYERS,
340                });
341
342            // next past waits for ALL_GRAPHICS, use dependency chain and FRAGMENT_SHADER dst stage
343            // to ensure that next pass doesn't start until mipchain is complete.
344            self.device.cmd_pipeline_barrier(
345                cmd,
346                vk::PipelineStageFlags::TRANSFER,
347                vk::PipelineStageFlags::FRAGMENT_SHADER,
348                vk::DependencyFlags::empty(),
349                &[],
350                &[],
351                &[input_barrier, mipchain_barrier],
352            );
353        }
354    }
355
356    /// SAFETY: self must fit the source image
357    pub unsafe fn copy_from(
358        &self,
359        cmd: vk::CommandBuffer,
360        source: &VulkanImage,
361        source_layout: vk::ImageLayout,
362    ) {
363        let region = vk::ImageCopy::default()
364            .src_subresource(
365                vk::ImageSubresourceLayers::default()
366                    .aspect_mask(vk::ImageAspectFlags::COLOR)
367                    .mip_level(0)
368                    .base_array_layer(0)
369                    .layer_count(1),
370            )
371            .dst_subresource(
372                vk::ImageSubresourceLayers::default()
373                    .aspect_mask(vk::ImageAspectFlags::COLOR)
374                    .mip_level(0)
375                    .base_array_layer(0)
376                    .layer_count(1),
377            )
378            .src_offset(Default::default())
379            .dst_offset(Default::default())
380            .extent(source.size.into());
381
382        unsafe {
383            util::vulkan_image_layout_transition_levels(
384                &self.device,
385                cmd,
386                self.image.image,
387                vk::REMAINING_MIP_LEVELS,
388                vk::ImageLayout::UNDEFINED,
389                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
390                vk::AccessFlags::empty(),
391                vk::AccessFlags::TRANSFER_WRITE,
392                vk::PipelineStageFlags::FRAGMENT_SHADER,
393                vk::PipelineStageFlags::TRANSFER,
394                vk::QUEUE_FAMILY_IGNORED,
395                vk::QUEUE_FAMILY_IGNORED,
396            );
397
398            self.device.cmd_copy_image(
399                cmd,
400                source.image,
401                source_layout,
402                self.image.image,
403                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
404                &[region],
405            );
406            util::vulkan_image_layout_transition_levels(
407                &self.device,
408                cmd,
409                self.image.image,
410                vk::REMAINING_MIP_LEVELS,
411                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
412                vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
413                vk::AccessFlags::TRANSFER_WRITE,
414                vk::AccessFlags::SHADER_READ,
415                vk::PipelineStageFlags::TRANSFER,
416                vk::PipelineStageFlags::FRAGMENT_SHADER,
417                vk::QUEUE_FAMILY_IGNORED,
418                vk::QUEUE_FAMILY_IGNORED,
419            );
420        }
421    }
422
423    pub fn clear(&self, cmd: vk::CommandBuffer) {
424        unsafe {
425            util::vulkan_image_layout_transition_levels(
426                &self.device,
427                cmd,
428                self.image.image,
429                vk::REMAINING_MIP_LEVELS,
430                vk::ImageLayout::UNDEFINED,
431                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
432                vk::AccessFlags::empty(),
433                vk::AccessFlags::TRANSFER_WRITE,
434                vk::PipelineStageFlags::TOP_OF_PIPE,
435                vk::PipelineStageFlags::TRANSFER,
436                vk::QUEUE_FAMILY_IGNORED,
437                vk::QUEUE_FAMILY_IGNORED,
438            );
439            self.device.cmd_clear_color_image(
440                cmd,
441                self.image.image,
442                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
443                &vk::ClearColorValue {
444                    float32: [0.0, 0.0, 0.0, 0.0],
445                },
446                &[vk::ImageSubresourceRange::default()
447                    .aspect_mask(vk::ImageAspectFlags::COLOR)
448                    .base_mip_level(0)
449                    .level_count(1)
450                    .base_array_layer(0)
451                    .layer_count(1)],
452            );
453
454            util::vulkan_image_layout_transition_levels(
455                &self.device,
456                cmd,
457                self.image.image,
458                vk::REMAINING_MIP_LEVELS,
459                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
460                vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
461                vk::AccessFlags::TRANSFER_WRITE,
462                vk::AccessFlags::SHADER_READ,
463                vk::PipelineStageFlags::TRANSFER,
464                vk::PipelineStageFlags::FRAGMENT_SHADER,
465                vk::QUEUE_FAMILY_IGNORED,
466                vk::QUEUE_FAMILY_IGNORED,
467            );
468        }
469    }
470}
471
472impl Drop for OwnedImage {
473    fn drop(&mut self) {
474        unsafe {
475            if self.image_view != vk::ImageView::null() {
476                self.device.destroy_image_view(self.image_view, None);
477            }
478            if self.image.image != vk::Image::null() {
479                self.device.destroy_image(self.image.image, None);
480            }
481        }
482    }
483}
484
485/// A handle to a `VkImage` with size and format information.
486#[derive(Clone)]
487pub struct VulkanImage {
488    /// A handle to the `VkImage`.
489    pub image: vk::Image,
490    /// The size of the image.
491    pub size: Size<u32>,
492    /// The `VkFormat` of the image.
493    pub format: vk::Format,
494}
495
496#[derive(Clone)]
497pub struct InputImage {
498    /// A handle to the `VkImage`.
499    pub image: VulkanImage,
500    /// A handle to the `VkImageView` for the image.
501    pub image_view: vk::ImageView,
502    pub wrap_mode: WrapMode,
503    pub filter_mode: FilterMode,
504    pub mip_filter: FilterMode,
505}
506
507impl AsRef<InputImage> for InputImage {
508    fn as_ref(&self) -> &InputImage {
509        self
510    }
511}
512
513impl ScaleFramebuffer for OwnedImage {
514    type Error = FilterChainError;
515    type Context = Option<OwnedImageLayout>;
516
517    fn scale(
518        &mut self,
519        scaling: Scale2D,
520        format: ImageFormat,
521        viewport_size: &Size<u32>,
522        source_size: &Size<u32>,
523        original_size: &Size<u32>,
524        should_mipmap: bool,
525        context: &Self::Context,
526    ) -> Result<Size<u32>, Self::Error> {
527        self.scale(
528            scaling,
529            format,
530            viewport_size,
531            source_size,
532            original_size,
533            should_mipmap,
534            context.clone(),
535        )
536    }
537}
538
539impl GetSize<u32> for VulkanImage {
540    type Error = std::convert::Infallible;
541
542    fn size(&self) -> Result<Size<u32>, Self::Error> {
543        Ok(self.size)
544    }
545}