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