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 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 let options = frame_options.map(|options| FrameOptions {
121 clear_history: options.clear_history,
122 frame_direction: options.frame_direction,
123 rotation: options.rotation,
124 total_subframes: options.total_subframes,
125 current_subframe: options.current_subframe,
126 aspect_ratio: options.aspect_ratio,
127 frametime_delta: options.frametime_delta,
128 frames_per_second: options.frames_per_second,
129 ..Default::default()
130 });
131
132 let viewport = Viewport::new_render_target_sized_origin(
133 VulkanImage {
134 image: render_texture,
135 size: self.image_bytes.size.into(),
136 format: vk::Format::B8G8R8A8_UNORM,
137 },
138 None,
139 )?;
140
141 let input = VulkanImage {
142 image: self.image,
143 size: self.image_bytes.size,
144 format: vk::Format::B8G8R8A8_UNORM,
145 };
146
147 self.vk.queue_work(|cmd| {
148 util::vulkan_image_layout_transition_levels(
149 &self.vk.device(),
150 cmd,
151 render_texture,
152 vk::REMAINING_MIP_LEVELS,
153 vk::ImageLayout::UNDEFINED,
154 vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
155 vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
156 vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
157 vk::PipelineStageFlags::ALL_GRAPHICS,
158 vk::PipelineStageFlags::ALL_GRAPHICS,
159 vk::QUEUE_FAMILY_IGNORED,
160 vk::QUEUE_FAMILY_IGNORED,
161 );
162
163 util::vulkan_image_layout_transition_levels(
164 &self.vk.device(),
165 cmd,
166 transfer_texture,
167 vk::REMAINING_MIP_LEVELS,
168 vk::ImageLayout::UNDEFINED,
169 vk::ImageLayout::GENERAL,
170 vk::AccessFlags::TRANSFER_WRITE | vk::AccessFlags::TRANSFER_READ,
171 vk::AccessFlags::TRANSFER_WRITE | vk::AccessFlags::TRANSFER_READ,
172 vk::PipelineStageFlags::ALL_GRAPHICS,
173 vk::PipelineStageFlags::TRANSFER,
174 vk::QUEUE_FAMILY_IGNORED,
175 vk::QUEUE_FAMILY_IGNORED,
176 );
177 })?;
178
179 for frame in 0..=frame_count {
180 self.vk.queue_work(|cmd| {
181 filter_chain.frame(&input, &viewport, cmd, frame, options.as_ref())?;
182 Ok::<_, anyhow::Error>(())
183 })??;
184 }
185
186 self.vk.queue_work(|cmd| {
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 let offsets = [
203 vk::Offset3D { x: 0, y: 0, z: 0 },
204 vk::Offset3D {
205 x: self.image_bytes.size.width as i32,
206 y: self.image_bytes.size.height as i32,
207 z: 1,
208 },
209 ];
210
211 let subresource = vk::ImageSubresourceLayers::default()
212 .aspect_mask(vk::ImageAspectFlags::COLOR)
213 .base_array_layer(0)
214 .layer_count(1);
215
216 let image_blit = vk::ImageBlit::default()
217 .src_subresource(subresource.clone())
218 .src_offsets(offsets.clone())
219 .dst_subresource(subresource)
220 .dst_offsets(offsets);
221
222 self.vk.device().cmd_blit_image(
223 cmd,
224 render_texture,
225 vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
226 transfer_texture,
227 vk::ImageLayout::GENERAL,
228 &[image_blit],
229 vk::Filter::NEAREST,
230 );
231
232 Ok::<_, anyhow::Error>(())
233 })??;
234
235 let mut memory = transfer_memory
237 .allocation
238 .mapped_slice_mut()
239 .ok_or(anyhow!("readback buffer was not mapped"))?;
240
241 let layout = self.vk.device().get_image_subresource_layout(
242 transfer_texture,
243 vk::ImageSubresource::default()
244 .aspect_mask(vk::ImageAspectFlags::COLOR)
245 .array_layer(0),
246 );
247 memory = &mut memory[layout.offset as usize..];
248
249 let width = self.image_bytes.size.width as usize;
252 let height = self.image_bytes.size.height as usize;
253 let row_bytes = width * 4;
254 let row_pitch = layout.row_pitch as usize;
255
256 let mut pixels = Vec::with_capacity(row_bytes * height);
257 for row in 0..height {
258 let start = row * row_pitch;
259 pixels.extend_from_slice(&memory[start..start + row_bytes]);
260 }
261
262 let image = RgbaImage::from_raw(
263 self.image_bytes.size.width,
264 self.image_bytes.size.height,
265 pixels,
266 )
267 .ok_or(anyhow!("failed to create image from slice"));
268
269 self.vk.device().destroy_image(transfer_texture, None);
270 self.vk.device().destroy_image(render_texture, None);
271
272 Ok(image?)
273 }
274 }
275}
276
277impl Vulkan {
278 pub fn new(image_path: &Path) -> anyhow::Result<Self> {
279 let vk = VulkanBase::new()?;
280
281 let (image_bytes, image_alloc, image, _view) = Self::load_image(&vk, image_path)?;
282
283 Ok(Self {
284 vk,
285 image,
286 image_bytes,
287 _image_alloc: image_alloc,
288 })
289 }
290
291 pub fn load_image(
292 vk: &VulkanBase,
293 image_path: &Path,
294 ) -> anyhow::Result<(Image<BGRA8>, VulkanImageMemory, vk::Image, vk::ImageView)> {
295 let image: Image<BGRA8> = Image::load(image_path, UVDirection::TopLeft)?;
296
297 let image_info = vk::ImageCreateInfo::default()
298 .image_type(vk::ImageType::TYPE_2D)
299 .format(vk::Format::B8G8R8A8_UNORM)
300 .extent(image.size.into())
301 .mip_levels(1)
302 .array_layers(1)
303 .samples(vk::SampleCountFlags::TYPE_1)
304 .tiling(vk::ImageTiling::OPTIMAL)
305 .usage(
306 vk::ImageUsageFlags::SAMPLED
307 | vk::ImageUsageFlags::TRANSFER_SRC
308 | vk::ImageUsageFlags::TRANSFER_DST,
309 )
310 .initial_layout(vk::ImageLayout::UNDEFINED);
311
312 let texture = unsafe { vk.device().create_image(&image_info, None)? };
313
314 let memory = unsafe {
315 let mem_reqs = vk.device().get_image_memory_requirements(texture);
316 VulkanImageMemory::new(
317 vk.device(),
318 &vk.allocator(),
319 mem_reqs,
320 &texture,
321 MemoryLocation::GpuOnly,
322 )?
323 };
324
325 let image_subresource = vk::ImageSubresourceRange::default()
326 .level_count(image_info.mip_levels)
327 .layer_count(1)
328 .aspect_mask(vk::ImageAspectFlags::COLOR);
329
330 let swizzle_components = vk::ComponentMapping::default()
331 .r(vk::ComponentSwizzle::R)
332 .g(vk::ComponentSwizzle::G)
333 .b(vk::ComponentSwizzle::B)
334 .a(vk::ComponentSwizzle::A);
335
336 let view_info = vk::ImageViewCreateInfo::default()
337 .view_type(vk::ImageViewType::TYPE_2D)
338 .format(vk::Format::B8G8R8A8_UNORM)
339 .image(texture)
340 .subresource_range(image_subresource)
341 .components(swizzle_components);
342
343 let texture_view = unsafe { vk.device().create_image_view(&view_info, None)? };
344
345 let mut staging = VulkanBuffer::new(
346 &vk.device(),
347 &vk.allocator(),
348 vk::BufferUsageFlags::TRANSFER_SRC,
349 image.bytes.len(),
350 )?;
351
352 staging.as_mut_slice()?.copy_from_slice(&image.bytes);
353
354 vk.queue_work(|cmd| unsafe {
355 util::vulkan_image_layout_transition_levels(
356 &vk.device(),
357 cmd,
358 texture,
359 vk::REMAINING_MIP_LEVELS,
360 vk::ImageLayout::UNDEFINED,
361 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
362 vk::AccessFlags::empty(),
363 vk::AccessFlags::TRANSFER_WRITE,
364 vk::PipelineStageFlags::TOP_OF_PIPE,
365 vk::PipelineStageFlags::TRANSFER,
366 vk::QUEUE_FAMILY_IGNORED,
367 vk::QUEUE_FAMILY_IGNORED,
368 );
369
370 let builder = vk::BufferImageCopy::default()
371 .image_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 .image_extent(image.size.into());
379
380 vk.device().cmd_copy_buffer_to_image(
381 cmd,
382 staging.handle,
383 texture,
384 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
385 &[builder],
386 );
387
388 util::vulkan_image_layout_transition_levels(
389 &vk.device(),
390 cmd,
391 texture,
392 vk::REMAINING_MIP_LEVELS,
393 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
394 vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
395 vk::AccessFlags::TRANSFER_WRITE,
396 vk::AccessFlags::SHADER_READ,
397 vk::PipelineStageFlags::TRANSFER,
398 vk::PipelineStageFlags::ALL_GRAPHICS,
399 vk::QUEUE_FAMILY_IGNORED,
400 vk::QUEUE_FAMILY_IGNORED,
401 );
402 })?;
403
404 Ok((image, memory, texture, texture_view))
405 }
406}