1use crate::{Options, RendererResult};
7use ash::{vk, Device};
8pub(crate) use buffer::*;
9use std::{ffi::CString, mem};
10pub(crate) use texture::*;
11
12#[cfg(feature = "dynamic-rendering")]
13use crate::DynamicRendering;
14
15pub(crate) unsafe fn any_as_u8_slice<T: Sized>(any: &T) -> &[u8] {
17 let ptr = (any as *const T) as *const u8;
18 std::slice::from_raw_parts(ptr, std::mem::size_of::<T>())
19}
20
21pub fn create_vulkan_descriptor_set_layout(
23 device: &Device,
24) -> RendererResult<vk::DescriptorSetLayout> {
25 log::debug!("Creating vulkan descriptor set layout");
26 let bindings = [vk::DescriptorSetLayoutBinding::default()
27 .binding(0)
28 .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
29 .descriptor_count(1)
30 .stage_flags(vk::ShaderStageFlags::FRAGMENT)];
31
32 let descriptor_set_create_info =
33 vk::DescriptorSetLayoutCreateInfo::default().bindings(&bindings);
34
35 unsafe { Ok(device.create_descriptor_set_layout(&descriptor_set_create_info, None)?) }
36}
37
38pub(crate) fn create_vulkan_pipeline_layout(
39 device: &Device,
40 descriptor_set_layout: vk::DescriptorSetLayout,
41) -> RendererResult<vk::PipelineLayout> {
42 use ultraviolet::mat::Mat4;
43
44 log::debug!("Creating vulkan pipeline layout");
45 let push_const_range = [vk::PushConstantRange {
46 stage_flags: vk::ShaderStageFlags::VERTEX,
47 offset: 0,
48 size: mem::size_of::<Mat4>() as u32,
49 }];
50
51 let descriptor_set_layouts = [descriptor_set_layout];
52 let layout_info = vk::PipelineLayoutCreateInfo::default()
53 .set_layouts(&descriptor_set_layouts)
54 .push_constant_ranges(&push_const_range);
55 let pipeline_layout = unsafe { device.create_pipeline_layout(&layout_info, None)? };
56 Ok(pipeline_layout)
57}
58
59pub(crate) fn create_vulkan_pipeline(
60 device: &Device,
61 pipeline_layout: vk::PipelineLayout,
62 #[cfg(not(feature = "dynamic-rendering"))] render_pass: vk::RenderPass,
63 #[cfg(feature = "dynamic-rendering")] dynamic_rendering: DynamicRendering,
64 options: Options,
65) -> RendererResult<vk::Pipeline> {
66 let entry_point_name = CString::new("main").unwrap();
67
68 let vertex_shader_source = std::include_bytes!("../shaders/shader.vert.spv");
69 let fragment_shader_source = std::include_bytes!("../shaders/shader.frag.spv");
70
71 let vertex_source = read_shader_from_source(vertex_shader_source)?;
72 let vertex_create_info = vk::ShaderModuleCreateInfo::default().code(&vertex_source);
73 let vertex_module = unsafe { device.create_shader_module(&vertex_create_info, None)? };
74
75 let fragment_source = read_shader_from_source(fragment_shader_source)?;
76 let fragment_create_info = vk::ShaderModuleCreateInfo::default().code(&fragment_source);
77 let fragment_module = unsafe { device.create_shader_module(&fragment_create_info, None)? };
78
79 let shader_states_infos = [
80 vk::PipelineShaderStageCreateInfo::default()
81 .stage(vk::ShaderStageFlags::VERTEX)
82 .module(vertex_module)
83 .name(&entry_point_name),
84 vk::PipelineShaderStageCreateInfo::default()
85 .stage(vk::ShaderStageFlags::FRAGMENT)
86 .module(fragment_module)
87 .name(&entry_point_name),
88 ];
89
90 let binding_desc = [vk::VertexInputBindingDescription::default()
91 .binding(0)
92 .stride(20)
93 .input_rate(vk::VertexInputRate::VERTEX)];
94 let attribute_desc = [
95 vk::VertexInputAttributeDescription::default()
96 .binding(0)
97 .location(0)
98 .format(vk::Format::R32G32_SFLOAT)
99 .offset(0),
100 vk::VertexInputAttributeDescription::default()
101 .binding(0)
102 .location(1)
103 .format(vk::Format::R32G32_SFLOAT)
104 .offset(8),
105 vk::VertexInputAttributeDescription::default()
106 .binding(0)
107 .location(2)
108 .format(vk::Format::R8G8B8A8_UNORM)
109 .offset(16),
110 ];
111
112 let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default()
113 .vertex_binding_descriptions(&binding_desc)
114 .vertex_attribute_descriptions(&attribute_desc);
115
116 let input_assembly_info = vk::PipelineInputAssemblyStateCreateInfo::default()
117 .topology(vk::PrimitiveTopology::TRIANGLE_LIST)
118 .primitive_restart_enable(false);
119
120 let rasterizer_info = vk::PipelineRasterizationStateCreateInfo::default()
121 .depth_clamp_enable(false)
122 .rasterizer_discard_enable(false)
123 .polygon_mode(vk::PolygonMode::FILL)
124 .line_width(1.0)
125 .cull_mode(vk::CullModeFlags::NONE)
126 .front_face(vk::FrontFace::CLOCKWISE)
127 .depth_bias_enable(false)
128 .depth_bias_constant_factor(0.0)
129 .depth_bias_clamp(0.0)
130 .depth_bias_slope_factor(0.0);
131
132 let viewports = [Default::default()];
133 let scissors = [Default::default()];
134 let viewport_info = vk::PipelineViewportStateCreateInfo::default()
135 .viewports(&viewports)
136 .scissors(&scissors);
137
138 let multisampling_info = vk::PipelineMultisampleStateCreateInfo::default()
139 .sample_shading_enable(false)
140 .rasterization_samples(options.sample_count)
141 .min_sample_shading(1.0)
142 .alpha_to_coverage_enable(false)
143 .alpha_to_one_enable(false);
144
145 let color_blend_attachments = [vk::PipelineColorBlendAttachmentState::default()
146 .color_write_mask(
147 vk::ColorComponentFlags::R
148 | vk::ColorComponentFlags::G
149 | vk::ColorComponentFlags::B
150 | vk::ColorComponentFlags::A,
151 )
152 .blend_enable(true)
153 .src_color_blend_factor(vk::BlendFactor::SRC_ALPHA)
154 .dst_color_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)
155 .color_blend_op(vk::BlendOp::ADD)
156 .src_alpha_blend_factor(vk::BlendFactor::ONE)
157 .dst_alpha_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)
158 .alpha_blend_op(vk::BlendOp::ADD)];
159 let color_blending_info = vk::PipelineColorBlendStateCreateInfo::default()
160 .logic_op_enable(false)
161 .logic_op(vk::LogicOp::COPY)
162 .attachments(&color_blend_attachments)
163 .blend_constants([0.0, 0.0, 0.0, 0.0]);
164
165 let depth_stencil_state_create_info = vk::PipelineDepthStencilStateCreateInfo::default()
166 .depth_test_enable(options.enable_depth_test)
167 .depth_write_enable(options.enable_depth_write)
168 .depth_compare_op(vk::CompareOp::ALWAYS)
169 .depth_bounds_test_enable(false)
170 .stencil_test_enable(false);
171
172 let dynamic_states = [vk::DynamicState::SCISSOR, vk::DynamicState::VIEWPORT];
173 let dynamic_states_info =
174 vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
175
176 let pipeline_info = vk::GraphicsPipelineCreateInfo::default()
177 .stages(&shader_states_infos)
178 .vertex_input_state(&vertex_input_info)
179 .input_assembly_state(&input_assembly_info)
180 .rasterization_state(&rasterizer_info)
181 .viewport_state(&viewport_info)
182 .multisample_state(&multisampling_info)
183 .color_blend_state(&color_blending_info)
184 .depth_stencil_state(&depth_stencil_state_create_info)
185 .dynamic_state(&dynamic_states_info)
186 .layout(pipeline_layout)
187 .subpass(options.subpass);
188
189 #[cfg(not(feature = "dynamic-rendering"))]
190 let pipeline_info = pipeline_info.render_pass(render_pass);
191
192 #[cfg(feature = "dynamic-rendering")]
193 let color_attachment_formats = [dynamic_rendering.color_attachment_format];
194 #[cfg(feature = "dynamic-rendering")]
195 let mut rendering_info = {
196 let mut rendering_info = vk::PipelineRenderingCreateInfo::default()
197 .color_attachment_formats(&color_attachment_formats);
198 if let Some(depth_attachment_format) = dynamic_rendering.depth_attachment_format {
199 rendering_info = rendering_info.depth_attachment_format(depth_attachment_format);
200 }
201 rendering_info
202 };
203 #[cfg(feature = "dynamic-rendering")]
204 let pipeline_info = pipeline_info.push_next(&mut rendering_info);
205
206 let pipeline = unsafe {
207 device
208 .create_graphics_pipelines(
209 vk::PipelineCache::null(),
210 std::slice::from_ref(&pipeline_info),
211 None,
212 )
213 .map_err(|e| e.1)?[0]
214 };
215
216 unsafe {
217 device.destroy_shader_module(vertex_module, None);
218 device.destroy_shader_module(fragment_module, None);
219 }
220
221 Ok(pipeline)
222}
223
224fn read_shader_from_source(source: &[u8]) -> RendererResult<Vec<u32>> {
225 use std::io::Cursor;
226 let mut cursor = Cursor::new(source);
227 Ok(ash::util::read_spv(&mut cursor)?)
228}
229
230pub fn create_vulkan_descriptor_pool(
232 device: &Device,
233 max_sets: u32,
234) -> RendererResult<vk::DescriptorPool> {
235 log::debug!("Creating vulkan descriptor pool");
236
237 let sizes = [vk::DescriptorPoolSize {
238 ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
239 descriptor_count: 1,
240 }];
241 let create_info = vk::DescriptorPoolCreateInfo::default()
242 .pool_sizes(&sizes)
243 .max_sets(max_sets)
244 .flags(vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET);
245 unsafe { Ok(device.create_descriptor_pool(&create_info, None)?) }
246}
247
248pub fn create_vulkan_descriptor_set(
250 device: &Device,
251 set_layout: vk::DescriptorSetLayout,
252 descriptor_pool: vk::DescriptorPool,
253 image_view: vk::ImageView,
254 sampler: vk::Sampler,
255) -> RendererResult<vk::DescriptorSet> {
256 log::debug!("Creating vulkan descriptor set");
257
258 let set = {
259 let set_layouts = [set_layout];
260 let allocate_info = vk::DescriptorSetAllocateInfo::default()
261 .descriptor_pool(descriptor_pool)
262 .set_layouts(&set_layouts);
263
264 unsafe { device.allocate_descriptor_sets(&allocate_info)?[0] }
265 };
266
267 unsafe {
268 let image_info = [vk::DescriptorImageInfo {
269 sampler,
270 image_view,
271 image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
272 }];
273
274 let writes = [vk::WriteDescriptorSet::default()
275 .dst_set(set)
276 .dst_binding(0)
277 .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
278 .image_info(&image_info)];
279 device.update_descriptor_sets(&writes, &[])
280 }
281
282 Ok(set)
283}
284
285mod buffer {
286
287 use crate::{
288 renderer::allocator::{Allocate, Allocator, Memory},
289 RendererResult,
290 };
291 use ash::vk;
292 use ash::Device;
293
294 pub fn create_and_fill_buffer<T>(
295 device: &Device,
296 allocator: &mut Allocator,
297 data: &[T],
298 usage: vk::BufferUsageFlags,
299 ) -> RendererResult<(vk::Buffer, Memory)>
300 where
301 T: Copy,
302 {
303 let size = std::mem::size_of_val(data);
304 let (buffer, mut memory) = allocator.create_buffer(device, size, usage)?;
305 allocator.update_buffer(device, &mut memory, data)?;
306 Ok((buffer, memory))
307 }
308}
309
310mod texture {
311
312 use super::buffer::*;
313 use crate::renderer::allocator::{Allocate, Allocator, Memory};
314 use crate::RendererResult;
315 use ash::vk;
316 use ash::Device;
317
318 pub struct Texture {
320 pub image: vk::Image,
321 image_mem: Memory,
322 pub image_view: vk::ImageView,
323 pub sampler: vk::Sampler,
324 }
325
326 impl Texture {
327 pub fn from_rgba8(
341 device: &Device,
342 queue: vk::Queue,
343 command_pool: vk::CommandPool,
344 allocator: &mut Allocator,
345 width: u32,
346 height: u32,
347 data: &[u8],
348 ) -> RendererResult<Self> {
349 let (texture, staging_buff, staging_mem) =
350 execute_one_time_commands(device, queue, command_pool, |buffer| {
351 Self::cmd_from_rgba(device, allocator, buffer, width, height, data)
352 })??;
353
354 allocator.destroy_buffer(device, staging_buff, staging_mem)?;
355
356 Ok(texture)
357 }
358
359 fn cmd_from_rgba(
360 device: &Device,
361 allocator: &mut Allocator,
362 command_buffer: vk::CommandBuffer,
363 width: u32,
364 height: u32,
365 data: &[u8],
366 ) -> RendererResult<(Self, vk::Buffer, Memory)> {
367 let (buffer, buffer_mem) = create_and_fill_buffer(
368 device,
369 allocator,
370 data,
371 vk::BufferUsageFlags::TRANSFER_SRC,
372 )?;
373
374 let (image, image_mem) = allocator.create_image(device, width, height)?;
375
376 {
379 let mut barrier = vk::ImageMemoryBarrier::default()
380 .old_layout(vk::ImageLayout::UNDEFINED)
381 .new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
382 .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
383 .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
384 .image(image)
385 .subresource_range(vk::ImageSubresourceRange {
386 aspect_mask: vk::ImageAspectFlags::COLOR,
387 base_mip_level: 0,
388 level_count: 1,
389 base_array_layer: 0,
390 layer_count: 1,
391 })
392 .src_access_mask(vk::AccessFlags::empty())
393 .dst_access_mask(vk::AccessFlags::TRANSFER_WRITE);
394
395 unsafe {
396 device.cmd_pipeline_barrier(
397 command_buffer,
398 vk::PipelineStageFlags::TOP_OF_PIPE,
399 vk::PipelineStageFlags::TRANSFER,
400 vk::DependencyFlags::empty(),
401 &[],
402 &[],
403 &[barrier],
404 )
405 };
406
407 let region = vk::BufferImageCopy::default()
408 .buffer_offset(0)
409 .buffer_row_length(0)
410 .buffer_image_height(0)
411 .image_subresource(vk::ImageSubresourceLayers {
412 aspect_mask: vk::ImageAspectFlags::COLOR,
413 mip_level: 0,
414 base_array_layer: 0,
415 layer_count: 1,
416 })
417 .image_offset(vk::Offset3D { x: 0, y: 0, z: 0 })
418 .image_extent(vk::Extent3D {
419 width,
420 height,
421 depth: 1,
422 });
423 unsafe {
424 device.cmd_copy_buffer_to_image(
425 command_buffer,
426 buffer,
427 image,
428 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
429 &[region],
430 )
431 }
432
433 barrier.old_layout = vk::ImageLayout::TRANSFER_DST_OPTIMAL;
434 barrier.new_layout = vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL;
435 barrier.src_access_mask = vk::AccessFlags::TRANSFER_WRITE;
436 barrier.dst_access_mask = vk::AccessFlags::SHADER_READ;
437
438 unsafe {
439 device.cmd_pipeline_barrier(
440 command_buffer,
441 vk::PipelineStageFlags::TRANSFER,
442 vk::PipelineStageFlags::FRAGMENT_SHADER,
443 vk::DependencyFlags::empty(),
444 &[],
445 &[],
446 &[barrier],
447 )
448 };
449 }
450
451 let image_view = {
452 let create_info = vk::ImageViewCreateInfo::default()
453 .image(image)
454 .view_type(vk::ImageViewType::TYPE_2D)
455 .format(vk::Format::R8G8B8A8_UNORM)
456 .subresource_range(vk::ImageSubresourceRange {
457 aspect_mask: vk::ImageAspectFlags::COLOR,
458 base_mip_level: 0,
459 level_count: 1,
460 base_array_layer: 0,
461 layer_count: 1,
462 });
463
464 unsafe { device.create_image_view(&create_info, None)? }
465 };
466
467 let sampler = {
468 let sampler_info = vk::SamplerCreateInfo::default()
469 .mag_filter(vk::Filter::LINEAR)
470 .min_filter(vk::Filter::LINEAR)
471 .address_mode_u(vk::SamplerAddressMode::REPEAT)
472 .address_mode_v(vk::SamplerAddressMode::REPEAT)
473 .address_mode_w(vk::SamplerAddressMode::REPEAT)
474 .anisotropy_enable(false)
475 .max_anisotropy(1.0)
476 .border_color(vk::BorderColor::INT_OPAQUE_BLACK)
477 .unnormalized_coordinates(false)
478 .compare_enable(false)
479 .compare_op(vk::CompareOp::ALWAYS)
480 .mipmap_mode(vk::SamplerMipmapMode::LINEAR)
481 .mip_lod_bias(0.0)
482 .min_lod(0.0)
483 .max_lod(1.0);
484 unsafe { device.create_sampler(&sampler_info, None)? }
485 };
486
487 let texture = Self {
488 image,
489 image_mem,
490 image_view,
491 sampler,
492 };
493
494 Ok((texture, buffer, buffer_mem))
495 }
496
497 pub fn destroy(self, device: &Device, allocator: &mut Allocator) -> RendererResult<()> {
499 unsafe {
500 device.destroy_sampler(self.sampler, None);
501 device.destroy_image_view(self.image_view, None);
502 allocator.destroy_image(device, self.image, self.image_mem)?;
503 }
504 Ok(())
505 }
506 }
507
508 fn execute_one_time_commands<R, F: FnOnce(vk::CommandBuffer) -> R>(
509 device: &Device,
510 queue: vk::Queue,
511 pool: vk::CommandPool,
512 executor: F,
513 ) -> RendererResult<R> {
514 let command_buffer = {
515 let alloc_info = vk::CommandBufferAllocateInfo::default()
516 .level(vk::CommandBufferLevel::PRIMARY)
517 .command_pool(pool)
518 .command_buffer_count(1);
519
520 unsafe { device.allocate_command_buffers(&alloc_info)?[0] }
521 };
522 let command_buffers = [command_buffer];
523
524 {
526 let begin_info = vk::CommandBufferBeginInfo::default()
527 .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
528 unsafe { device.begin_command_buffer(command_buffer, &begin_info)? };
529 }
530
531 let executor_result = executor(command_buffer);
533
534 unsafe { device.end_command_buffer(command_buffer)? };
536
537 {
539 let submit_info = vk::SubmitInfo::default().command_buffers(&command_buffers);
540 let submit_infos = [submit_info];
541 unsafe {
542 device.queue_submit(queue, &submit_infos, vk::Fence::null())?;
543 device.queue_wait_idle(queue)?;
544 };
545 }
546
547 unsafe { device.free_command_buffers(pool, &command_buffers) };
549
550 Ok(executor_result)
551 }
552}