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
use {
    super::{Instance, Surface},
    ash::vk,
    std::{
        ffi::CStr,
        fmt::{Debug, Formatter},
        ops::Deref,
        sync::Arc,
    },
};

/// Execution queue selected by the current device.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct QueueFamily {
    /// Physical queue index.
    pub idx: u32,

    /// Properties of the selected execution queue.
    pub props: QueueFamilyProperties,
}

/// Describes additional propeties of the current execution queue.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct QueueFamilyProperties {
    /// Bitmask specifying capabilities of queues in a queue family.
    pub queue_flags: vk::QueueFlags,

    /// Number of queues which are available.
    pub queue_count: u32,

    /// The unsigned integer count of meaningful bits in the timestamps written via
    /// `vkCmdWriteTimestamp2` or `vkCmdWriteTimestamp`.
    ///
    /// The valid range for the count is 36 to 64 bits, or a value of 0, indicating no support for
    /// timestamps. Bits outside the valid range are guaranteed to be zeros.
    pub timestamp_valid_bits: u32,

    /// The minimum granularity supported for image transfer operations on the queues in this queue
    /// family.
    pub min_image_transfer_granularity: [u32; 3],
}

/// Structure which holds data about the physical hardware selected by the current device.
#[derive(Clone)]
pub struct PhysicalDevice {
    /// Memory properties of the physical device.
    pub mem_props: vk::PhysicalDeviceMemoryProperties,
    physical_device: vk::PhysicalDevice,

    /// Device properties of the physical device.
    pub props: vk::PhysicalDeviceProperties,
    queue_families: Vec<QueueFamily>,
}

impl PhysicalDevice {
    pub(super) fn new(
        physical_device: vk::PhysicalDevice,
        mem_props: vk::PhysicalDeviceMemoryProperties,
        props: vk::PhysicalDeviceProperties,
        queue_families: Vec<QueueFamily>,
    ) -> Self {
        Self {
            mem_props,
            physical_device,
            props,
            queue_families,
        }
    }

    pub(super) fn has_presentation_support(
        _this: &Self,
        _instance: &Arc<Instance>,
        _surface: &Surface,
    ) -> bool {
        // if let Ok(device) = Device::create(
        //     instance,
        //     this.clone(),
        //     DriverConfig::new().presentation(true).build().unwrap(),
        // ) {
        //     this.queue_families
        //         .iter()
        //         .enumerate()
        //         .any(|(queue_idx, info)| unsafe {
        //             info.props.queue_flags.contains(vk::QueueFlags::GRAPHICS)
        //                 && device
        //                     .surface_ext
        //                     .get_physical_device_surface_support(
        //                         this.physical_device,
        //                         queue_idx as _,
        //                         **surface,
        //                     )
        //                     .ok()
        //                     .unwrap_or_default()
        //         })
        // } else {
        //     false
        // }

        // TODO!
        true
    }

    pub(super) fn has_ray_tracing_support(_this: &Self) -> bool {
        // TODO!
        true
    }

    pub(super) fn queue_families(this: &Self) -> impl Iterator<Item = QueueFamily> + '_ {
        this.queue_families.iter().copied()
    }

    pub(super) fn score_device_type(this: &Self) -> usize {
        match this.props.device_type {
            vk::PhysicalDeviceType::DISCRETE_GPU => 1000,
            vk::PhysicalDeviceType::INTEGRATED_GPU => 200,
            vk::PhysicalDeviceType::VIRTUAL_GPU => 1,
            _ => 0,
        }
    }
}

impl Debug for PhysicalDevice {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        unsafe {
            write!(
                f,
                "{:?} ({:?})",
                CStr::from_ptr(self.props.device_name.as_ptr()),
                self.props.device_type
            )
        }
    }
}

impl Deref for PhysicalDevice {
    type Target = vk::PhysicalDevice;

    fn deref(&self) -> &Self::Target {
        &self.physical_device
    }
}