Skip to main content

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