1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184


use crate::ffi::vk::*;
use super::error::Result;
use super::error::ErrorCode;
use super::instance::{Instance, QueueFamily, PhysicalDevice, PhysicalDevicesBuilder};
use super::device::{Device, Queue};
use super::surface::{Surface};

use std::ptr;
use std::mem;
use std::mem::MaybeUninit;
use libc::{c_float, c_void, c_char};
use std::sync::Arc;
use std::ffi::CString;

enum DeviceQueuesCapabilities {
    Default,
    RayTracing,
}

impl DeviceQueuesCapabilities {
    fn extension_names(&self) -> Vec<CString> {
        match &self {
            &Self::Default => vec![
                CString::new("VK_KHR_swapchain").unwrap(),
            ],
            &Self::RayTracing => vec![
                CString::new("VK_KHR_swapchain").unwrap(),
                CString::new("VK_KHR_ray_tracing").unwrap(),
                CString::new("VK_KHR_dedicated_allocation").unwrap(),
                CString::new("VK_KHR_get_memory_requirements2").unwrap(),
                CString::new("VK_KHR_buffer_device_address").unwrap(),
                CString::new("VK_KHR_deferred_host_operations").unwrap(),
                CString::new("VK_EXT_descriptor_indexing").unwrap(),
                CString::new("VK_KHR_pipeline_library").unwrap(),
            ],
        }
    }
}

pub struct DeviceQueuesBuilder {
    surface: Arc<Surface>,
    capabilities: DeviceQueuesCapabilities,
}

impl DeviceQueuesBuilder {
    pub fn new(surface: &Arc<Surface>) -> Self {
        DeviceQueuesBuilder { 
            surface: Arc::clone(surface),
            capabilities: DeviceQueuesCapabilities::Default,
        }
    }

    pub fn with_raytracing(self) -> Self {
        DeviceQueuesBuilder { 
            surface: self.surface,
            capabilities: DeviceQueuesCapabilities::RayTracing,
        }
    }

    pub fn build(self) -> Result<Arc<DeviceQueues>> {
        let surface = &self.surface;
        let instance = surface.instance();
        let physical_devices = PhysicalDevicesBuilder::new(instance).build()?;
        let physical_device = physical_devices.into_iter()
            .nth(0)
            .ok_or_else(|| ErrorCode::SuitablePhysicalDeviceNotFound)?;
        // choose families
        let families = physical_device.queue_families()?;
        let graphics_family = families.iter()
            .find(|v| v.is_graphics());
        let present_family = families.iter()
            .find(|v| surface.is_supported(v, &physical_device).unwrap_or(false));
        let (graphics_family, present_family) = graphics_family
            .and_then(|a| present_family.map(|b| (a, b)))
            .ok_or_else(|| ErrorCode::SuitableQueueFamilyNotFound)?;
        // create infos
        let extension_names = self.capabilities.extension_names();
        let extension_name_ptrs: Vec<*const c_char> = extension_names.iter()
            .map(|v| v.as_ptr())
            .collect();
        let priority: c_float = 0.0;
        if (graphics_family as *const QueueFamily) == (present_family as *const QueueFamily) {
            // unique family
            log_debug!("Unique family");
            let family = graphics_family;
            let family_index = family.index();
            let queue_create_info = VkDeviceQueueCreateInfo::new(family_index, 1, &priority);
            let device_create_info = unsafe { VkDeviceCreateInfo::new(1, &queue_create_info, &extension_name_ptrs) };
            unsafe {
                let mut handle = MaybeUninit::<VkDevice>::zeroed();
                vkCreateDevice(physical_device.handle(), &device_create_info, std::ptr::null(), handle.as_mut_ptr())
                    .into_result()?;
                let handle = handle.assume_init();
                let device = Device::new(handle, &physical_device);
                // queue
                let mut queue = MaybeUninit::<VkQueue>::zeroed();
                vkGetDeviceQueue(device.handle(), family_index, 0, queue.as_mut_ptr());
                let queue = queue.assume_init();
                let queue = Queue::new(queue, family.clone(), &device);
                // device queues
                let device_queues = DeviceQueues::new(instance, device, &queue, &queue);
                Ok(device_queues)
            }
        } else {
            let queue_create_infos = vec![
                VkDeviceQueueCreateInfo::new(graphics_family.index(), 1, &priority),
                VkDeviceQueueCreateInfo::new(present_family.index(), 1, &priority),
            ];
            let device_create_info = unsafe { 
                VkDeviceCreateInfo::new(
                    queue_create_infos.len() as u32, 
                    queue_create_infos.as_ptr(),
                    &extension_name_ptrs)
            };
            unsafe {
                let mut handle = MaybeUninit::<VkDevice>::zeroed();
                vkCreateDevice(physical_device.handle(), &device_create_info, std::ptr::null(), handle.as_mut_ptr())
                    .into_result()?;
                let handle = handle.assume_init();
                let device = Device::new(handle, &physical_device);
                // graphics queue
                let mut graphics_queue = MaybeUninit::<VkQueue>::zeroed();
                vkGetDeviceQueue(device.handle(), graphics_family.index(), 0, graphics_queue.as_mut_ptr());
                let graphics_queue = graphics_queue.assume_init();
                let graphics_queue = Queue::new(graphics_queue, graphics_family.clone(), &device);
                // present queue
                let mut present_queue = MaybeUninit::<VkQueue>::zeroed();
                vkGetDeviceQueue(device.handle(), present_family.index(), 1, present_queue.as_mut_ptr());
                let present_queue = present_queue.assume_init();
                let present_queue = Queue::new(present_queue, present_family.clone(), &device);
                // device queues
                let device_queues = DeviceQueues::new(instance, device, &graphics_queue, &present_queue);
                Ok(device_queues)
            }
        }
    }
}

pub struct DeviceQueues {
    instance: Arc<Instance>,
    device: Arc<Device>,
    graphics_queue: Arc<Queue>,
    present_queue: Arc<Queue>,
}

impl DeviceQueues {
    fn new(instance: &Arc<Instance>, device: Arc<Device>, graphics_queue: &Arc<Queue>, present_queue: &Arc<Queue>) -> Arc<Self> {
        let device_queues = DeviceQueues {
            instance: Arc::clone(instance),
            device,
            graphics_queue: Arc::clone(graphics_queue),
            present_queue: Arc::clone(present_queue),
        };
        Arc::new(device_queues)
    }

    #[inline]
    pub fn instance(&self) -> &Arc<Instance> {
        &self.instance
    }

    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }

    #[inline]
    pub fn graphics_queue(&self) -> &Arc<Queue> {
        &self.graphics_queue
    }

    #[inline]
    pub fn present_queue(&self) -> &Arc<Queue> {
        &self.present_queue
    }

    pub fn is_sharing_exclusive(&self) -> bool {
        std::ptr::eq(
            self.graphics_queue.as_ref() as *const Queue,
            self.present_queue.as_ref() as *const Queue)
    }
}