librashader_test/render/vk/
mod.rs

1use crate::render::vk::base::VulkanBase;
2use crate::render::vk::memory::{VulkanBuffer, VulkanImageMemory};
3use crate::render::{CommonFrameOptions, RenderTest};
4use anyhow::anyhow;
5use ash::vk;
6use gpu_allocator::MemoryLocation;
7use image::RgbaImage;
8use librashader::presets::ShaderPreset;
9use librashader::runtime::vk::{FilterChain, FilterChainOptions, FrameOptions, VulkanImage};
10use librashader::runtime::{FilterChainParameters, RuntimeParameters};
11use librashader::runtime::{Size, Viewport};
12use librashader_runtime::image::{Image, UVDirection, BGRA8};
13use std::path::Path;
14
15mod base;
16mod memory;
17mod physical_device;
18mod util;
19
20pub struct Vulkan {
21    vk: VulkanBase,
22    image_bytes: Image<BGRA8>,
23    image: vk::Image,
24    _image_alloc: VulkanImageMemory,
25}
26
27impl RenderTest for Vulkan {
28    fn new(path: &Path) -> anyhow::Result<Self>
29    where
30        Self: Sized,
31    {
32        Vulkan::new(path)
33    }
34
35    fn image_size(&self) -> Size<u32> {
36        self.image_bytes.size
37    }
38
39    fn render_with_preset_and_params(
40        &mut self,
41        preset: ShaderPreset,
42        frame_count: usize,
43        output_size: Option<Size<u32>>,
44        param_setter: Option<&dyn Fn(&RuntimeParameters)>,
45        frame_options: Option<CommonFrameOptions>,
46    ) -> anyhow::Result<image::RgbaImage> {
47        unsafe {
48            let mut filter_chain = FilterChain::load_from_preset(
49                preset,
50                &self.vk,
51                Some(&FilterChainOptions {
52                    frames_in_flight: 3,
53                    force_no_mipmaps: false,
54                    use_dynamic_rendering: false,
55                    disable_cache: false,
56                }),
57            )?;
58
59            if let Some(setter) = param_setter {
60                setter(filter_chain.parameters());
61            }
62
63            let image_info = vk::ImageCreateInfo::default()
64                .image_type(vk::ImageType::TYPE_2D)
65                .format(vk::Format::B8G8R8A8_UNORM)
66                .extent(output_size.map_or(self.image_bytes.size.into(), |size| size.into()))
67                .mip_levels(1)
68                .array_layers(1)
69                .samples(vk::SampleCountFlags::TYPE_1)
70                .tiling(vk::ImageTiling::OPTIMAL)
71                .usage(vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::TRANSFER_SRC)
72                .initial_layout(vk::ImageLayout::UNDEFINED);
73
74            let render_texture = { self.vk.device().create_image(&image_info, None)? };
75
76            // This just needs to stay alive until the read.
77            let _memory = {
78                let mem_reqs = self
79                    .vk
80                    .device()
81                    .get_image_memory_requirements(render_texture);
82                VulkanImageMemory::new(
83                    self.vk.device(),
84                    &self.vk.allocator(),
85                    mem_reqs,
86                    &render_texture,
87                    MemoryLocation::GpuOnly,
88                )?
89            };
90
91            let transfer_texture = self.vk.device().create_image(
92                &vk::ImageCreateInfo::default()
93                    .image_type(vk::ImageType::TYPE_2D)
94                    .format(vk::Format::R8G8B8A8_UNORM)
95                    .extent(self.image_bytes.size.into())
96                    .mip_levels(1)
97                    .array_layers(1)
98                    .samples(vk::SampleCountFlags::TYPE_1)
99                    .tiling(vk::ImageTiling::LINEAR)
100                    .usage(vk::ImageUsageFlags::TRANSFER_DST)
101                    .initial_layout(vk::ImageLayout::UNDEFINED),
102                None,
103            )?;
104
105            let mut transfer_memory = {
106                let mem_reqs = self
107                    .vk
108                    .device()
109                    .get_image_memory_requirements(transfer_texture);
110                VulkanImageMemory::new(
111                    self.vk.device(),
112                    &self.vk.allocator(),
113                    mem_reqs,
114                    &transfer_texture,
115                    MemoryLocation::GpuToCpu,
116                )?
117            };
118
119            self.vk.queue_work(|cmd| {
120                util::vulkan_image_layout_transition_levels(
121                    &self.vk.device(),
122                    cmd,
123                    render_texture,
124                    vk::REMAINING_MIP_LEVELS,
125                    vk::ImageLayout::UNDEFINED,
126                    vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
127                    vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
128                    vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
129                    vk::PipelineStageFlags::ALL_GRAPHICS,
130                    vk::PipelineStageFlags::ALL_GRAPHICS,
131                    vk::QUEUE_FAMILY_IGNORED,
132                    vk::QUEUE_FAMILY_IGNORED,
133                );
134
135                util::vulkan_image_layout_transition_levels(
136                    &self.vk.device(),
137                    cmd,
138                    transfer_texture,
139                    vk::REMAINING_MIP_LEVELS,
140                    vk::ImageLayout::UNDEFINED,
141                    vk::ImageLayout::GENERAL,
142                    vk::AccessFlags::TRANSFER_WRITE | vk::AccessFlags::TRANSFER_READ,
143                    vk::AccessFlags::TRANSFER_WRITE | vk::AccessFlags::TRANSFER_READ,
144                    vk::PipelineStageFlags::ALL_GRAPHICS,
145                    vk::PipelineStageFlags::TRANSFER,
146                    vk::QUEUE_FAMILY_IGNORED,
147                    vk::QUEUE_FAMILY_IGNORED,
148                );
149
150                let options = frame_options.map(|options| FrameOptions {
151                    clear_history: options.clear_history,
152                    frame_direction: options.frame_direction,
153                    rotation: options.rotation,
154                    total_subframes: options.total_subframes,
155                    current_subframe: options.current_subframe,
156                    aspect_ratio: options.aspect_ratio,
157                    frametime_delta: options.frametime_delta,
158                    frames_per_second: options.frames_per_second,
159                });
160
161                let viewport = Viewport::new_render_target_sized_origin(
162                    VulkanImage {
163                        image: render_texture,
164                        size: self.image_bytes.size.into(),
165                        format: vk::Format::B8G8R8A8_UNORM,
166                    },
167                    None,
168                )?;
169
170                for frame in 0..=frame_count {
171                    filter_chain.frame(
172                        &VulkanImage {
173                            image: self.image,
174                            size: self.image_bytes.size,
175                            format: vk::Format::B8G8R8A8_UNORM,
176                        },
177                        &viewport,
178                        cmd,
179                        frame,
180                        options.as_ref(),
181                    )?;
182                }
183
184                {
185                    util::vulkan_image_layout_transition_levels(
186                        &self.vk.device(),
187                        cmd,
188                        render_texture,
189                        vk::REMAINING_MIP_LEVELS,
190                        vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
191                        vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
192                        vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
193                        vk::AccessFlags::TRANSFER_READ,
194                        vk::PipelineStageFlags::ALL_GRAPHICS,
195                        vk::PipelineStageFlags::TRANSFER,
196                        vk::QUEUE_FAMILY_IGNORED,
197                        vk::QUEUE_FAMILY_IGNORED,
198                    )
199                }
200
201                let offsets = [
202                    vk::Offset3D { x: 0, y: 0, z: 0 },
203                    vk::Offset3D {
204                        x: self.image_bytes.size.width as i32,
205                        y: self.image_bytes.size.height as i32,
206                        z: 1,
207                    },
208                ];
209
210                let subresource = vk::ImageSubresourceLayers::default()
211                    .aspect_mask(vk::ImageAspectFlags::COLOR)
212                    .base_array_layer(0)
213                    .layer_count(1);
214
215                let image_blit = vk::ImageBlit::default()
216                    .src_subresource(subresource.clone())
217                    .src_offsets(offsets.clone())
218                    .dst_subresource(subresource)
219                    .dst_offsets(offsets);
220
221                self.vk.device().cmd_blit_image(
222                    cmd,
223                    render_texture,
224                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
225                    transfer_texture,
226                    vk::ImageLayout::GENERAL,
227                    &[image_blit],
228                    vk::Filter::NEAREST,
229                );
230
231                Ok::<_, anyhow::Error>(())
232            })??;
233
234            // should have read now.
235            let mut memory = transfer_memory
236                .allocation
237                .mapped_slice_mut()
238                .ok_or(anyhow!("readback buffer was not mapped"))?;
239
240            let layout = self.vk.device().get_image_subresource_layout(
241                transfer_texture,
242                vk::ImageSubresource::default()
243                    .aspect_mask(vk::ImageAspectFlags::COLOR)
244                    .array_layer(0),
245            );
246            memory = &mut memory[layout.offset as usize..];
247
248            // let mut pixels = Vec::with_capacity(layout.size as usize);
249
250            let image = RgbaImage::from_raw(
251                self.image_bytes.size.width,
252                self.image_bytes.size.height,
253                Vec::from(memory),
254            )
255            .ok_or(anyhow!("failed to create image from slice"));
256
257            self.vk.device().destroy_image(transfer_texture, None);
258            self.vk.device().destroy_image(render_texture, None);
259
260            Ok(image?)
261        }
262    }
263}
264
265impl Vulkan {
266    pub fn new(image_path: &Path) -> anyhow::Result<Self> {
267        let vk = VulkanBase::new()?;
268
269        let (image_bytes, image_alloc, image, _view) = Self::load_image(&vk, image_path)?;
270
271        Ok(Self {
272            vk,
273            image,
274            image_bytes,
275            _image_alloc: image_alloc,
276        })
277    }
278
279    pub fn load_image(
280        vk: &VulkanBase,
281        image_path: &Path,
282    ) -> anyhow::Result<(Image<BGRA8>, VulkanImageMemory, vk::Image, vk::ImageView)> {
283        let image: Image<BGRA8> = Image::load(image_path, UVDirection::TopLeft)?;
284
285        let image_info = vk::ImageCreateInfo::default()
286            .image_type(vk::ImageType::TYPE_2D)
287            .format(vk::Format::B8G8R8A8_UNORM)
288            .extent(image.size.into())
289            .mip_levels(1)
290            .array_layers(1)
291            .samples(vk::SampleCountFlags::TYPE_1)
292            .tiling(vk::ImageTiling::OPTIMAL)
293            .usage(
294                vk::ImageUsageFlags::SAMPLED
295                    | vk::ImageUsageFlags::TRANSFER_SRC
296                    | vk::ImageUsageFlags::TRANSFER_DST,
297            )
298            .initial_layout(vk::ImageLayout::UNDEFINED);
299
300        let texture = unsafe { vk.device().create_image(&image_info, None)? };
301
302        let memory = unsafe {
303            let mem_reqs = vk.device().get_image_memory_requirements(texture);
304            VulkanImageMemory::new(
305                vk.device(),
306                &vk.allocator(),
307                mem_reqs,
308                &texture,
309                MemoryLocation::GpuOnly,
310            )?
311        };
312
313        let image_subresource = vk::ImageSubresourceRange::default()
314            .level_count(image_info.mip_levels)
315            .layer_count(1)
316            .aspect_mask(vk::ImageAspectFlags::COLOR);
317
318        let swizzle_components = vk::ComponentMapping::default()
319            .r(vk::ComponentSwizzle::R)
320            .g(vk::ComponentSwizzle::G)
321            .b(vk::ComponentSwizzle::B)
322            .a(vk::ComponentSwizzle::A);
323
324        let view_info = vk::ImageViewCreateInfo::default()
325            .view_type(vk::ImageViewType::TYPE_2D)
326            .format(vk::Format::B8G8R8A8_UNORM)
327            .image(texture)
328            .subresource_range(image_subresource)
329            .components(swizzle_components);
330
331        let texture_view = unsafe { vk.device().create_image_view(&view_info, None)? };
332
333        let mut staging = VulkanBuffer::new(
334            &vk.device(),
335            &vk.allocator(),
336            vk::BufferUsageFlags::TRANSFER_SRC,
337            image.bytes.len(),
338        )?;
339
340        staging.as_mut_slice()?.copy_from_slice(&image.bytes);
341
342        vk.queue_work(|cmd| unsafe {
343            util::vulkan_image_layout_transition_levels(
344                &vk.device(),
345                cmd,
346                texture,
347                vk::REMAINING_MIP_LEVELS,
348                vk::ImageLayout::UNDEFINED,
349                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
350                vk::AccessFlags::empty(),
351                vk::AccessFlags::TRANSFER_WRITE,
352                vk::PipelineStageFlags::TOP_OF_PIPE,
353                vk::PipelineStageFlags::TRANSFER,
354                vk::QUEUE_FAMILY_IGNORED,
355                vk::QUEUE_FAMILY_IGNORED,
356            );
357
358            let builder = vk::BufferImageCopy::default()
359                .image_subresource(
360                    vk::ImageSubresourceLayers::default()
361                        .aspect_mask(vk::ImageAspectFlags::COLOR)
362                        .mip_level(0)
363                        .base_array_layer(0)
364                        .layer_count(1),
365                )
366                .image_extent(image.size.into());
367
368            vk.device().cmd_copy_buffer_to_image(
369                cmd,
370                staging.handle,
371                texture,
372                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
373                &[builder],
374            );
375
376            util::vulkan_image_layout_transition_levels(
377                &vk.device(),
378                cmd,
379                texture,
380                vk::REMAINING_MIP_LEVELS,
381                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
382                vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
383                vk::AccessFlags::TRANSFER_WRITE,
384                vk::AccessFlags::SHADER_READ,
385                vk::PipelineStageFlags::TRANSFER,
386                vk::PipelineStageFlags::ALL_GRAPHICS,
387                vk::QUEUE_FAMILY_IGNORED,
388                vk::QUEUE_FAMILY_IGNORED,
389            );
390        })?;
391
392        Ok((image, memory, texture, texture_view))
393    }
394}