1use ash::util::read_spv;
38use ash::vk;
39use ash::vk::Handle;
40use imgui::internal::RawWrapper;
41use imgui::{Context, DrawCmd, DrawData, DrawIdx, DrawVert, TextureId};
42use std::io::Cursor;
43use std::mem;
44
45#[derive(Debug)]
47pub enum RendererError {
48 Vulkan(vk::Result),
50}
51
52impl std::fmt::Display for RendererError {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 match self {
55 RendererError::Vulkan(e) => write!(f, "Vulkan error: {e}"),
56 }
57 }
58}
59
60impl std::error::Error for RendererError {}
61
62impl From<vk::Result> for RendererError {
63 fn from(e: vk::Result) -> Self {
64 RendererError::Vulkan(e)
65 }
66}
67
68pub struct RendererCreateInfo {
70 pub device: ash::Device,
72 pub memory_properties: vk::PhysicalDeviceMemoryProperties,
74 pub render_pass: vk::RenderPass,
76 pub command_pool: vk::CommandPool,
78 pub queue: vk::Queue,
80}
81
82pub struct Renderer {
84 device: ash::Device,
85 memory_properties: vk::PhysicalDeviceMemoryProperties,
86 pipeline_layout: vk::PipelineLayout,
87 pipeline: vk::Pipeline,
88 descriptor_set_layout: vk::DescriptorSetLayout,
89 descriptor_pool: vk::DescriptorPool,
90 #[allow(dead_code)] font_descriptor_set: vk::DescriptorSet,
92 font_image: vk::Image,
93 font_image_memory: vk::DeviceMemory,
94 font_image_view: vk::ImageView,
95 font_sampler: vk::Sampler,
96 vertex_buffer: vk::Buffer,
97 vertex_buffer_memory: vk::DeviceMemory,
98 vertex_buffer_size: vk::DeviceSize,
99 index_buffer: vk::Buffer,
100 index_buffer_memory: vk::DeviceMemory,
101 index_buffer_size: vk::DeviceSize,
102 retired_buffers: Vec<(vk::Buffer, vk::DeviceMemory)>,
104}
105
106const INITIAL_BUFFER_SIZE: vk::DeviceSize = 64 * 1024;
107
108impl Renderer {
109 pub fn new(imgui: &mut Context, create_info: &RendererCreateInfo) -> Result<Self, RendererError> {
116 let device = &create_info.device;
117 let memory_properties = create_info.memory_properties;
118
119 let sampler_binding = vk::DescriptorSetLayoutBinding::default()
121 .binding(0)
122 .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
123 .descriptor_count(1)
124 .stage_flags(vk::ShaderStageFlags::FRAGMENT);
125 let ds_layout_info = vk::DescriptorSetLayoutCreateInfo::default()
126 .bindings(std::slice::from_ref(&sampler_binding));
127 let descriptor_set_layout =
128 unsafe { device.create_descriptor_set_layout(&ds_layout_info, None)? };
129
130 let push_constant_range = vk::PushConstantRange {
132 stage_flags: vk::ShaderStageFlags::VERTEX,
133 offset: 0,
134 size: 64, };
136 let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default()
137 .set_layouts(std::slice::from_ref(&descriptor_set_layout))
138 .push_constant_ranges(std::slice::from_ref(&push_constant_range));
139 let pipeline_layout = unsafe {
140 device
141 .create_pipeline_layout(&pipeline_layout_info, None)
142 .inspect_err(|_| {
143 device.destroy_descriptor_set_layout(descriptor_set_layout, None);
144 })?
145 };
146
147 let vert_spv = read_spv(&mut Cursor::new(
149 &include_bytes!("shaders/imgui.vert.spv")[..],
150 ))
151 .expect("failed to read vertex shader SPIR-V");
152 let frag_spv = read_spv(&mut Cursor::new(
153 &include_bytes!("shaders/imgui.frag.spv")[..],
154 ))
155 .expect("failed to read fragment shader SPIR-V");
156
157 let vert_module_info = vk::ShaderModuleCreateInfo::default().code(&vert_spv);
158 let frag_module_info = vk::ShaderModuleCreateInfo::default().code(&frag_spv);
159
160 let vert_module = unsafe {
161 device
162 .create_shader_module(&vert_module_info, None)
163 .inspect_err(|_| {
164 device.destroy_pipeline_layout(pipeline_layout, None);
165 device.destroy_descriptor_set_layout(descriptor_set_layout, None);
166 })?
167 };
168 let frag_module = unsafe {
169 device
170 .create_shader_module(&frag_module_info, None)
171 .inspect_err(|_| {
172 device.destroy_shader_module(vert_module, None);
173 device.destroy_pipeline_layout(pipeline_layout, None);
174 device.destroy_descriptor_set_layout(descriptor_set_layout, None);
175 })?
176 };
177
178 let entry_point = c"main";
179
180 let shader_stages = [
181 vk::PipelineShaderStageCreateInfo::default()
182 .stage(vk::ShaderStageFlags::VERTEX)
183 .module(vert_module)
184 .name(entry_point),
185 vk::PipelineShaderStageCreateInfo::default()
186 .stage(vk::ShaderStageFlags::FRAGMENT)
187 .module(frag_module)
188 .name(entry_point),
189 ];
190
191 let binding_desc = vk::VertexInputBindingDescription {
193 binding: 0,
194 stride: mem::size_of::<DrawVert>() as u32,
195 input_rate: vk::VertexInputRate::VERTEX,
196 };
197 let attribute_descs = [
198 vk::VertexInputAttributeDescription {
200 location: 0,
201 binding: 0,
202 format: vk::Format::R32G32_SFLOAT,
203 offset: 0,
204 },
205 vk::VertexInputAttributeDescription {
207 location: 1,
208 binding: 0,
209 format: vk::Format::R32G32_SFLOAT,
210 offset: 8,
211 },
212 vk::VertexInputAttributeDescription {
214 location: 2,
215 binding: 0,
216 format: vk::Format::R8G8B8A8_UNORM,
217 offset: 16,
218 },
219 ];
220 let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default()
221 .vertex_binding_descriptions(std::slice::from_ref(&binding_desc))
222 .vertex_attribute_descriptions(&attribute_descs);
223
224 let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
225 .topology(vk::PrimitiveTopology::TRIANGLE_LIST);
226
227 let viewport_state = vk::PipelineViewportStateCreateInfo::default()
228 .viewport_count(1)
229 .scissor_count(1);
230
231 let rasterization = vk::PipelineRasterizationStateCreateInfo::default()
232 .polygon_mode(vk::PolygonMode::FILL)
233 .cull_mode(vk::CullModeFlags::NONE)
234 .front_face(vk::FrontFace::COUNTER_CLOCKWISE)
235 .line_width(1.0);
236
237 let multisample = vk::PipelineMultisampleStateCreateInfo::default()
238 .rasterization_samples(vk::SampleCountFlags::TYPE_1);
239
240 let color_blend_attachment = vk::PipelineColorBlendAttachmentState::default()
241 .blend_enable(true)
242 .src_color_blend_factor(vk::BlendFactor::SRC_ALPHA)
243 .dst_color_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)
244 .color_blend_op(vk::BlendOp::ADD)
245 .src_alpha_blend_factor(vk::BlendFactor::ONE)
246 .dst_alpha_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)
247 .alpha_blend_op(vk::BlendOp::ADD)
248 .color_write_mask(vk::ColorComponentFlags::RGBA);
249
250 let color_blend = vk::PipelineColorBlendStateCreateInfo::default()
251 .attachments(std::slice::from_ref(&color_blend_attachment));
252
253 let dynamic_states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR];
254 let dynamic_state =
255 vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
256
257 let depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default();
258
259 let pipeline_info = vk::GraphicsPipelineCreateInfo::default()
260 .stages(&shader_stages)
261 .vertex_input_state(&vertex_input_info)
262 .input_assembly_state(&input_assembly)
263 .viewport_state(&viewport_state)
264 .rasterization_state(&rasterization)
265 .multisample_state(&multisample)
266 .depth_stencil_state(&depth_stencil)
267 .color_blend_state(&color_blend)
268 .dynamic_state(&dynamic_state)
269 .layout(pipeline_layout)
270 .render_pass(create_info.render_pass)
271 .subpass(0);
272
273 let pipeline = unsafe {
274 let result = device
275 .create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None)
276 .map_err(|(_, e)| e);
277
278 device.destroy_shader_module(vert_module, None);
280 device.destroy_shader_module(frag_module, None);
281
282 result.inspect_err(|_| {
283 device.destroy_pipeline_layout(pipeline_layout, None);
284 device.destroy_descriptor_set_layout(descriptor_set_layout, None);
285 })?[0]
286 };
287
288 let cleanup_base = |device: &ash::Device| unsafe {
292 device.destroy_pipeline(pipeline, None);
293 device.destroy_pipeline_layout(pipeline_layout, None);
294 device.destroy_descriptor_set_layout(descriptor_set_layout, None);
295 };
296
297 let pool_size = vk::DescriptorPoolSize {
299 ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
300 descriptor_count: 1,
301 };
302 let pool_info = vk::DescriptorPoolCreateInfo::default()
303 .max_sets(1)
304 .pool_sizes(std::slice::from_ref(&pool_size));
305 let descriptor_pool = unsafe {
306 device.create_descriptor_pool(&pool_info, None).inspect_err(|_| cleanup_base(device))?
307 };
308
309 let cleanup_pool = |device: &ash::Device| unsafe {
310 device.destroy_descriptor_pool(descriptor_pool, None);
311 cleanup_base(device);
312 };
313
314 let fonts = imgui.fonts();
316 let font_atlas = fonts.build_rgba32_texture();
317 let (width, height) = (font_atlas.width, font_atlas.height);
318 let upload_size = (width * height * 4) as vk::DeviceSize;
319
320 let image_info = vk::ImageCreateInfo::default()
322 .image_type(vk::ImageType::TYPE_2D)
323 .format(vk::Format::R8G8B8A8_UNORM)
324 .extent(vk::Extent3D {
325 width,
326 height,
327 depth: 1,
328 })
329 .mip_levels(1)
330 .array_layers(1)
331 .samples(vk::SampleCountFlags::TYPE_1)
332 .tiling(vk::ImageTiling::OPTIMAL)
333 .usage(vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED)
334 .initial_layout(vk::ImageLayout::UNDEFINED);
335 let font_image = unsafe {
336 device.create_image(&image_info, None).inspect_err(|_| cleanup_pool(device))?
337 };
338
339 let mem_req = unsafe { device.get_image_memory_requirements(font_image) };
340 let font_image_memory = unsafe {
341 let alloc_info = vk::MemoryAllocateInfo::default()
342 .allocation_size(mem_req.size)
343 .memory_type_index(
344 find_memory_type(
345 &memory_properties,
346 mem_req.memory_type_bits,
347 vk::MemoryPropertyFlags::DEVICE_LOCAL,
348 )
349 .expect("no suitable memory type for font image"),
350 );
351 device.allocate_memory(&alloc_info, None).inspect_err(|_| {
352 device.destroy_image(font_image, None);
353 cleanup_pool(device);
354 })?
355 };
356 unsafe {
357 device.bind_image_memory(font_image, font_image_memory, 0).inspect_err(|_| {
358 device.free_memory(font_image_memory, None);
359 device.destroy_image(font_image, None);
360 cleanup_pool(device);
361 })?;
362 }
363
364 let cleanup_image = |device: &ash::Device| unsafe {
365 device.free_memory(font_image_memory, None);
366 device.destroy_image(font_image, None);
367 cleanup_pool(device);
368 };
369
370 let (staging_buffer, staging_memory) = create_buffer(
372 device,
373 &memory_properties,
374 upload_size,
375 vk::BufferUsageFlags::TRANSFER_SRC,
376 vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
377 )
378 .inspect_err(|_| cleanup_image(device))?;
379
380 unsafe {
381 let ptr = device
382 .map_memory(staging_memory, 0, upload_size, vk::MemoryMapFlags::empty())
383 .inspect_err(|_| {
384 device.destroy_buffer(staging_buffer, None);
385 device.free_memory(staging_memory, None);
386 cleanup_image(device);
387 })?;
388 std::ptr::copy_nonoverlapping(
389 font_atlas.data.as_ptr(),
390 ptr as *mut u8,
391 upload_size as usize,
392 );
393 device.unmap_memory(staging_memory);
394 }
395
396 execute_one_time_commands(
398 device,
399 create_info.command_pool,
400 create_info.queue,
401 |cmd| {
402 let barrier = vk::ImageMemoryBarrier::default()
404 .image(font_image)
405 .old_layout(vk::ImageLayout::UNDEFINED)
406 .new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
407 .src_access_mask(vk::AccessFlags::empty())
408 .dst_access_mask(vk::AccessFlags::TRANSFER_WRITE)
409 .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
410 .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
411 .subresource_range(vk::ImageSubresourceRange {
412 aspect_mask: vk::ImageAspectFlags::COLOR,
413 base_mip_level: 0,
414 level_count: 1,
415 base_array_layer: 0,
416 layer_count: 1,
417 });
418 unsafe {
419 device.cmd_pipeline_barrier(
420 cmd,
421 vk::PipelineStageFlags::TOP_OF_PIPE,
422 vk::PipelineStageFlags::TRANSFER,
423 vk::DependencyFlags::empty(),
424 &[],
425 &[],
426 &[barrier],
427 );
428 }
429
430 let region = vk::BufferImageCopy {
432 buffer_offset: 0,
433 buffer_row_length: 0,
434 buffer_image_height: 0,
435 image_subresource: vk::ImageSubresourceLayers {
436 aspect_mask: vk::ImageAspectFlags::COLOR,
437 mip_level: 0,
438 base_array_layer: 0,
439 layer_count: 1,
440 },
441 image_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
442 image_extent: vk::Extent3D {
443 width,
444 height,
445 depth: 1,
446 },
447 };
448 unsafe {
449 device.cmd_copy_buffer_to_image(
450 cmd,
451 staging_buffer,
452 font_image,
453 vk::ImageLayout::TRANSFER_DST_OPTIMAL,
454 &[region],
455 );
456 }
457
458 let barrier = vk::ImageMemoryBarrier::default()
460 .image(font_image)
461 .old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
462 .new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
463 .src_access_mask(vk::AccessFlags::TRANSFER_WRITE)
464 .dst_access_mask(vk::AccessFlags::SHADER_READ)
465 .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
466 .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
467 .subresource_range(vk::ImageSubresourceRange {
468 aspect_mask: vk::ImageAspectFlags::COLOR,
469 base_mip_level: 0,
470 level_count: 1,
471 base_array_layer: 0,
472 layer_count: 1,
473 });
474 unsafe {
475 device.cmd_pipeline_barrier(
476 cmd,
477 vk::PipelineStageFlags::TRANSFER,
478 vk::PipelineStageFlags::FRAGMENT_SHADER,
479 vk::DependencyFlags::empty(),
480 &[],
481 &[],
482 &[barrier],
483 );
484 }
485 },
486 )
487 .inspect_err(|_| {
488 unsafe {
489 device.destroy_buffer(staging_buffer, None);
490 device.free_memory(staging_memory, None);
491 }
492 cleanup_image(device);
493 })?;
494
495 unsafe {
497 device.destroy_buffer(staging_buffer, None);
498 device.free_memory(staging_memory, None);
499 }
500
501 let view_info = vk::ImageViewCreateInfo::default()
503 .image(font_image)
504 .view_type(vk::ImageViewType::TYPE_2D)
505 .format(vk::Format::R8G8B8A8_UNORM)
506 .subresource_range(vk::ImageSubresourceRange {
507 aspect_mask: vk::ImageAspectFlags::COLOR,
508 base_mip_level: 0,
509 level_count: 1,
510 base_array_layer: 0,
511 layer_count: 1,
512 });
513 let font_image_view = unsafe {
514 device.create_image_view(&view_info, None).inspect_err(|_| cleanup_image(device))?
515 };
516
517 let cleanup_view = |device: &ash::Device| unsafe {
518 device.destroy_image_view(font_image_view, None);
519 cleanup_image(device);
520 };
521
522 let sampler_info = vk::SamplerCreateInfo::default()
524 .mag_filter(vk::Filter::LINEAR)
525 .min_filter(vk::Filter::LINEAR)
526 .address_mode_u(vk::SamplerAddressMode::CLAMP_TO_EDGE)
527 .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_EDGE)
528 .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_EDGE);
529 let font_sampler = unsafe {
530 device.create_sampler(&sampler_info, None).inspect_err(|_| cleanup_view(device))?
531 };
532
533 let cleanup_sampler = |device: &ash::Device| unsafe {
534 device.destroy_sampler(font_sampler, None);
535 cleanup_view(device);
536 };
537
538 let alloc_info = vk::DescriptorSetAllocateInfo::default()
540 .descriptor_pool(descriptor_pool)
541 .set_layouts(std::slice::from_ref(&descriptor_set_layout));
542 let font_descriptor_set = unsafe {
543 device
544 .allocate_descriptor_sets(&alloc_info)
545 .inspect_err(|_| cleanup_sampler(device))?[0]
546 };
547
548 let image_write = vk::DescriptorImageInfo::default()
549 .sampler(font_sampler)
550 .image_view(font_image_view)
551 .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL);
552 let write = vk::WriteDescriptorSet::default()
553 .dst_set(font_descriptor_set)
554 .dst_binding(0)
555 .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
556 .image_info(std::slice::from_ref(&image_write));
557 unsafe { device.update_descriptor_sets(&[write], &[]) };
558
559 imgui
562 .fonts()
563 .tex_id = TextureId::new(font_descriptor_set.as_raw() as usize);
564
565 let (vertex_buffer, vertex_buffer_memory) = create_buffer(
567 device,
568 &memory_properties,
569 INITIAL_BUFFER_SIZE,
570 vk::BufferUsageFlags::VERTEX_BUFFER,
571 vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
572 )
573 .inspect_err(|_| cleanup_sampler(device))?;
574
575 let (index_buffer, index_buffer_memory) = create_buffer(
576 device,
577 &memory_properties,
578 INITIAL_BUFFER_SIZE,
579 vk::BufferUsageFlags::INDEX_BUFFER,
580 vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
581 )
582 .inspect_err(|_| unsafe {
583 device.destroy_buffer(vertex_buffer, None);
584 device.free_memory(vertex_buffer_memory, None);
585 cleanup_sampler(device);
586 })?;
587
588 Ok(Renderer {
589 device: device.clone(),
590 memory_properties,
591 pipeline_layout,
592 pipeline,
593 descriptor_set_layout,
594 descriptor_pool,
595 font_descriptor_set,
596 font_image,
597 font_image_memory,
598 font_image_view,
599 font_sampler,
600 vertex_buffer,
601 vertex_buffer_memory,
602 vertex_buffer_size: INITIAL_BUFFER_SIZE,
603 index_buffer,
604 index_buffer_memory,
605 index_buffer_size: INITIAL_BUFFER_SIZE,
606 retired_buffers: Vec::new(),
607 })
608 }
609
610 pub fn render(
618 &mut self,
619 draw_data: &DrawData,
620 command_buffer: vk::CommandBuffer,
621 ) -> Result<(), RendererError> {
622 self.flush_retired_buffers();
627
628 if draw_data.total_vtx_count <= 0 {
629 return Ok(());
630 }
631
632 let device = &self.device;
633
634 let vertex_size =
636 (draw_data.total_vtx_count as usize * mem::size_of::<DrawVert>()) as vk::DeviceSize;
637 let index_size =
638 (draw_data.total_idx_count as usize * mem::size_of::<DrawIdx>()) as vk::DeviceSize;
639
640 if vertex_size > self.vertex_buffer_size {
641 self.retired_buffers
644 .push((self.vertex_buffer, self.vertex_buffer_memory));
645 let (buf, mem) = create_buffer(
646 device,
647 &self.memory_properties,
648 vertex_size,
649 vk::BufferUsageFlags::VERTEX_BUFFER,
650 vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
651 )?;
652 self.vertex_buffer = buf;
653 self.vertex_buffer_memory = mem;
654 self.vertex_buffer_size = vertex_size;
655 }
656
657 if index_size > self.index_buffer_size {
658 self.retired_buffers
659 .push((self.index_buffer, self.index_buffer_memory));
660 let (buf, mem) = create_buffer(
661 device,
662 &self.memory_properties,
663 index_size,
664 vk::BufferUsageFlags::INDEX_BUFFER,
665 vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
666 )?;
667 self.index_buffer = buf;
668 self.index_buffer_memory = mem;
669 self.index_buffer_size = index_size;
670 }
671
672 unsafe {
674 let vtx_ptr = device.map_memory(
675 self.vertex_buffer_memory,
676 0,
677 vertex_size,
678 vk::MemoryMapFlags::empty(),
679 )? as *mut DrawVert;
680 let idx_ptr = device.map_memory(
681 self.index_buffer_memory,
682 0,
683 index_size,
684 vk::MemoryMapFlags::empty(),
685 )? as *mut DrawIdx;
686
687 let mut vtx_offset = 0usize;
688 let mut idx_offset = 0usize;
689 for draw_list in draw_data.draw_lists() {
690 let vtx_buf = draw_list.vtx_buffer();
691 let idx_buf = draw_list.idx_buffer();
692 std::ptr::copy_nonoverlapping(
693 vtx_buf.as_ptr(),
694 vtx_ptr.add(vtx_offset),
695 vtx_buf.len(),
696 );
697 std::ptr::copy_nonoverlapping(
698 idx_buf.as_ptr(),
699 idx_ptr.add(idx_offset),
700 idx_buf.len(),
701 );
702 vtx_offset += vtx_buf.len();
703 idx_offset += idx_buf.len();
704 }
705
706 device.unmap_memory(self.vertex_buffer_memory);
707 device.unmap_memory(self.index_buffer_memory);
708 }
709
710 let fb_scale = draw_data.framebuffer_scale;
712 let display_pos = draw_data.display_pos;
713 let display_size = draw_data.display_size;
714 let fb_width = display_size[0] * fb_scale[0];
715 let fb_height = display_size[1] * fb_scale[1];
716 if fb_width <= 0.0 || fb_height <= 0.0 {
717 return Ok(());
718 }
719
720 let viewport = vk::Viewport {
722 x: 0.0,
723 y: 0.0,
724 width: fb_width,
725 height: fb_height,
726 min_depth: 0.0,
727 max_depth: 1.0,
728 };
729
730 let left = display_pos[0];
731 let right = display_pos[0] + display_size[0];
732 let top = display_pos[1];
733 let bottom = display_pos[1] + display_size[1];
734
735 #[rustfmt::skip]
736 let proj_mtx: [f32; 16] = [
737 2.0 / (right - left), 0.0, 0.0, 0.0,
738 0.0, 2.0 / (bottom - top), 0.0, 0.0,
739 0.0, 0.0, -1.0, 0.0,
740 (right + left) / (left - right), (top + bottom) / (top - bottom), 0.0, 1.0,
741 ];
742 let proj_bytes = bytemuck_cast_slice(&proj_mtx);
743
744 let idx_type = if mem::size_of::<DrawIdx>() == 2 {
745 vk::IndexType::UINT16
746 } else {
747 vk::IndexType::UINT32
748 };
749
750 unsafe {
751 self.setup_render_state(command_buffer, &viewport, proj_bytes, idx_type);
752 }
753
754 let clip_off = display_pos;
755 let clip_scale = fb_scale;
756
757 let mut global_vtx_offset = 0u32;
758 let mut global_idx_offset = 0u32;
759
760 for draw_list in draw_data.draw_lists() {
761 for cmd in draw_list.commands() {
762 match cmd {
763 DrawCmd::Elements { count, cmd_params } => {
764 let clip_min_x =
765 (cmd_params.clip_rect[0] - clip_off[0]) * clip_scale[0];
766 let clip_min_y =
767 (cmd_params.clip_rect[1] - clip_off[1]) * clip_scale[1];
768 let clip_max_x =
769 (cmd_params.clip_rect[2] - clip_off[0]) * clip_scale[0];
770 let clip_max_y =
771 (cmd_params.clip_rect[3] - clip_off[1]) * clip_scale[1];
772
773 if clip_max_x <= clip_min_x || clip_max_y <= clip_min_y {
774 continue;
775 }
776
777 let scissor = vk::Rect2D {
778 offset: vk::Offset2D {
779 x: clip_min_x.max(0.0) as i32,
780 y: clip_min_y.max(0.0) as i32,
781 },
782 extent: vk::Extent2D {
783 width: (clip_max_x - clip_min_x.max(0.0)) as u32,
784 height: (clip_max_y - clip_min_y.max(0.0)) as u32,
785 },
786 };
787
788 let descriptor_set = vk::DescriptorSet::from_raw(
790 cmd_params.texture_id.id() as u64,
791 );
792
793 unsafe {
794 self.device.cmd_set_scissor(command_buffer, 0, &[scissor]);
795 self.device.cmd_bind_descriptor_sets(
796 command_buffer,
797 vk::PipelineBindPoint::GRAPHICS,
798 self.pipeline_layout,
799 0,
800 &[descriptor_set],
801 &[],
802 );
803 self.device.cmd_draw_indexed(
804 command_buffer,
805 count as u32,
806 1,
807 cmd_params.idx_offset as u32 + global_idx_offset,
808 (cmd_params.vtx_offset as i32)
809 + (global_vtx_offset as i32),
810 0,
811 );
812 }
813 }
814 DrawCmd::ResetRenderState => unsafe {
815 self.setup_render_state(
816 command_buffer,
817 &viewport,
818 proj_bytes,
819 idx_type,
820 );
821 },
822 DrawCmd::RawCallback { callback, raw_cmd } => unsafe {
823 callback(draw_list.raw(), raw_cmd);
824 },
825 }
826 }
827
828 global_vtx_offset += draw_list.vtx_buffer().len() as u32;
829 global_idx_offset += draw_list.idx_buffer().len() as u32;
830 }
831
832 Ok(())
833 }
834
835 unsafe fn setup_render_state(
842 &self,
843 command_buffer: vk::CommandBuffer,
844 viewport: &vk::Viewport,
845 proj_bytes: &[u8],
846 idx_type: vk::IndexType,
847 ) {
848 unsafe {
849 self.device.cmd_bind_pipeline(
850 command_buffer,
851 vk::PipelineBindPoint::GRAPHICS,
852 self.pipeline,
853 );
854 self.device
855 .cmd_bind_vertex_buffers(command_buffer, 0, &[self.vertex_buffer], &[0]);
856 self.device.cmd_bind_index_buffer(
857 command_buffer,
858 self.index_buffer,
859 0,
860 idx_type,
861 );
862 self.device
863 .cmd_set_viewport(command_buffer, 0, std::slice::from_ref(viewport));
864 self.device.cmd_push_constants(
865 command_buffer,
866 self.pipeline_layout,
867 vk::ShaderStageFlags::VERTEX,
868 0,
869 proj_bytes,
870 );
871 }
872 }
873
874 fn flush_retired_buffers(&mut self) {
876 for (buffer, memory) in self.retired_buffers.drain(..) {
877 unsafe {
878 self.device.destroy_buffer(buffer, None);
879 self.device.free_memory(memory, None);
880 }
881 }
882 }
883}
884
885impl Drop for Renderer {
886 fn drop(&mut self) {
887 unsafe {
888 let d = &self.device;
889 d.device_wait_idle().ok();
890 for (buffer, memory) in self.retired_buffers.drain(..) {
892 d.destroy_buffer(buffer, None);
893 d.free_memory(memory, None);
894 }
895 d.destroy_buffer(self.index_buffer, None);
896 d.free_memory(self.index_buffer_memory, None);
897 d.destroy_buffer(self.vertex_buffer, None);
898 d.free_memory(self.vertex_buffer_memory, None);
899 d.destroy_sampler(self.font_sampler, None);
900 d.destroy_image_view(self.font_image_view, None);
901 d.free_memory(self.font_image_memory, None);
902 d.destroy_image(self.font_image, None);
903 d.destroy_descriptor_pool(self.descriptor_pool, None);
904 d.destroy_pipeline(self.pipeline, None);
905 d.destroy_pipeline_layout(self.pipeline_layout, None);
906 d.destroy_descriptor_set_layout(self.descriptor_set_layout, None);
907 }
908 }
909}
910
911fn find_memory_type(
916 props: &vk::PhysicalDeviceMemoryProperties,
917 type_filter: u32,
918 flags: vk::MemoryPropertyFlags,
919) -> Option<u32> {
920 for i in 0..props.memory_type_count {
921 if (type_filter & (1 << i)) != 0
922 && props.memory_types[i as usize]
923 .property_flags
924 .contains(flags)
925 {
926 return Some(i);
927 }
928 }
929 None
930}
931
932fn create_buffer(
933 device: &ash::Device,
934 memory_properties: &vk::PhysicalDeviceMemoryProperties,
935 size: vk::DeviceSize,
936 usage: vk::BufferUsageFlags,
937 mem_flags: vk::MemoryPropertyFlags,
938) -> Result<(vk::Buffer, vk::DeviceMemory), RendererError> {
939 let buffer_info = vk::BufferCreateInfo::default()
940 .size(size)
941 .usage(usage)
942 .sharing_mode(vk::SharingMode::EXCLUSIVE);
943 let buffer = unsafe { device.create_buffer(&buffer_info, None)? };
944 let mem_req = unsafe { device.get_buffer_memory_requirements(buffer) };
945 let alloc_info = vk::MemoryAllocateInfo::default()
946 .allocation_size(mem_req.size)
947 .memory_type_index(
948 find_memory_type(memory_properties, mem_req.memory_type_bits, mem_flags)
949 .expect("no suitable memory type for buffer"),
950 );
951 let memory = unsafe {
952 device.allocate_memory(&alloc_info, None).inspect_err(|_| {
953 device.destroy_buffer(buffer, None);
954 })?
955 };
956 unsafe {
957 device
958 .bind_buffer_memory(buffer, memory, 0)
959 .inspect_err(|_| {
960 device.free_memory(memory, None);
961 device.destroy_buffer(buffer, None);
962 })?;
963 }
964 Ok((buffer, memory))
965}
966
967fn execute_one_time_commands(
968 device: &ash::Device,
969 command_pool: vk::CommandPool,
970 queue: vk::Queue,
971 f: impl FnOnce(vk::CommandBuffer),
972) -> Result<(), RendererError> {
973 let alloc_info = vk::CommandBufferAllocateInfo::default()
974 .command_pool(command_pool)
975 .level(vk::CommandBufferLevel::PRIMARY)
976 .command_buffer_count(1);
977 let cmd = unsafe { device.allocate_command_buffers(&alloc_info)?[0] };
978
979 let begin_info =
980 vk::CommandBufferBeginInfo::default().flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
981 unsafe { device.begin_command_buffer(cmd, &begin_info)? };
982
983 f(cmd);
984
985 unsafe { device.end_command_buffer(cmd)? };
986
987 let submit_info = vk::SubmitInfo::default().command_buffers(std::slice::from_ref(&cmd));
988 let fence_info = vk::FenceCreateInfo::default();
989 let fence = unsafe { device.create_fence(&fence_info, None)? };
990
991 unsafe {
992 device.queue_submit(queue, &[submit_info], fence)?;
993 device.wait_for_fences(&[fence], true, u64::MAX)?;
994 device.destroy_fence(fence, None);
995 device.free_command_buffers(command_pool, &[cmd]);
996 }
997
998 Ok(())
999}
1000
1001fn bytemuck_cast_slice(data: &[f32]) -> &[u8] {
1003 unsafe {
1004 std::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::<f32>())
1005 }
1006}