rotex_vulkan/bridge/
init.rs1use std::collections::HashMap;
2use std::ffi::CString;
3
4use ash::vk;
5
6use super::VulkanBridge;
7use crate::backend::vulkan::{
8 CommandPool, DescriptorPool, DescriptorSetLayout, DeviceDescriptor, Fence,
9 QueueCategory as BackendQueueCategory, QueueRequest as BackendQueueRequest, VulkanInstance,
10};
11use crate::core::InstanceOptions;
12use crate::error::{Error, ErrorKind};
13use rotex_types::{
14 DeviceDescriptor as FrontendDeviceDescriptor, DeviceFeatures as FrontendDeviceFeatures,
15 Extent2D as FrontendExtent2D, InstanceDescriptor as FrontendInstanceDescriptor,
16 QueueCategory,
17};
18
19impl VulkanBridge {
20 pub fn new(
21 instance_descriptor: FrontendInstanceDescriptor,
22 device_descriptor: FrontendDeviceDescriptor,
23 ) -> Result<Self, Error> {
24 let options = InstanceOptions {
25 enable_validation: instance_descriptor.enable_validation,
26 enable_debug_utils: instance_descriptor.enable_validation,
27 ..Default::default()
28 };
29 let extension_names = instance_descriptor
30 .required_instance_extensions
31 .iter()
32 .map(|name| {
33 CString::new(name.as_str()).map_err(|_| {
34 Error::fatal(ErrorKind::Unsupported(
35 "Instance extension contains interior NUL byte",
36 ))
37 })
38 })
39 .collect::<Result<Vec<_>, _>>()?;
40 let extension_ptrs = extension_names
41 .iter()
42 .map(|name| name.as_ptr())
43 .collect::<Vec<_>>();
44 let instance = VulkanInstance::new(&options, &extension_ptrs)?;
45 let backend_desc = DeviceDescriptor {
46 enable_swapchain: device_descriptor.enable_swapchain,
47 queues: device_descriptor.queues.into_iter().map(map_queue_request).collect(),
48 required_features: map_device_features(device_descriptor.required_features),
49 };
50 let device = instance.request_device(backend_desc)?;
51 let command_pool = CommandPool::new(device.raw())?;
52 let mut command_buffers = command_pool.allocate_buffers(device.raw(), 1)?;
53 let command_buffer = command_buffers.pop().expect("one command buffer");
54 let in_flight_fence = Fence::new(device.raw(), true)?;
55 let texture_layout_bindings = [vk::DescriptorSetLayoutBinding::default()
56 .binding(0)
57 .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
58 .descriptor_count(1)
59 .stage_flags(vk::ShaderStageFlags::FRAGMENT)];
60 let texture_set_layout = DescriptorSetLayout::new(device.raw(), &texture_layout_bindings)?;
61 let texture_pool_sizes = [vk::DescriptorPoolSize {
62 ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
63 descriptor_count: 4096,
64 }];
65 let texture_descriptor_pool = DescriptorPool::new(device.raw(), 4096, &texture_pool_sizes)?;
66 let graphics_queue_index = device
67 .raw()
68 .queues()
69 .iter()
70 .find(|q| q.category == BackendQueueCategory::Graphics)
71 .ok_or(Error::fatal(ErrorKind::NoCompatibleDevice))?
72 .family_index;
73 Ok(Self {
74 instance,
75 device,
76 command_pool,
77 command_buffer,
78 in_flight_fence,
79 graphics_queue_index,
80 surface_state: None,
81 meshes: HashMap::new(),
82 materials: HashMap::new(),
83 textures: HashMap::new(),
84 default_texture: None,
85 texture_descriptor_pool,
86 texture_set_layout,
87 material_pipelines: HashMap::new(),
88 pipelines_by_material: HashMap::new(),
89 vertex_layouts: HashMap::new(),
90 next_mesh_id: 1,
91 next_material_id: 1,
92 next_texture_id: 1,
93 })
94 }
95}
96
97fn map_queue_request(req: rotex_types::QueueRequest) -> BackendQueueRequest {
98 BackendQueueRequest {
99 category: match req.category {
100 QueueCategory::Graphics => BackendQueueCategory::Graphics,
101 QueueCategory::Compute => BackendQueueCategory::Compute,
102 QueueCategory::Transfer => BackendQueueCategory::Transfer,
103 },
104 count: req.count,
105 }
106}
107
108fn map_device_features(features: FrontendDeviceFeatures) -> vk::PhysicalDeviceFeatures {
109 let mut mapped = vk::PhysicalDeviceFeatures::default();
110 mapped.sampler_anisotropy = features.sampler_anisotropy as u32;
111 mapped.fill_mode_non_solid = features.fill_mode_non_solid as u32;
112 mapped.wide_lines = features.wide_lines as u32;
113 mapped
114}
115
116pub(super) fn to_vk_extent(extent: FrontendExtent2D) -> vk::Extent2D {
117 let extent = extent.clamped();
118 vk::Extent2D {
119 width: extent.width,
120 height: extent.height,
121 }
122}