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

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct QueueFamily {
    pub idx: u32,
    pub props: QueueFamilyProperties,
}

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct QueueFamilyProperties {
    pub queue_flags: vk::QueueFlags,
    pub queue_count: u32,
    pub timestamp_valid_bits: u32,
    pub min_image_transfer_granularity: [u32; 3],
}

#[derive(Clone)]
pub struct PhysicalDevice {
    pub mem_props: vk::PhysicalDeviceMemoryProperties,
    physical_device: vk::PhysicalDevice,
    pub props: vk::PhysicalDeviceProperties,
    queue_families: Vec<QueueFamily>,
}

impl PhysicalDevice {
    pub 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 fn has_presentation_support<P>(
        _this: &Self,
        _instance: &SharedPointer<Instance, P>,
        _surface: &Surface<P>,
    ) -> bool
    where
        P: SharedPointerKind,
    {
        // 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 fn has_ray_tracing_support(_this: &Self) -> bool {
        // TODO!
        true
    }

    pub 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
    }
}