Skip to main content

rotex_vulkan/bridge/
init.rs

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