96
|
1 import std/enumerate
|
|
2 import std/options
|
|
3 import std/tables
|
|
4 import std/sequtils
|
|
5
|
|
6 import ./api
|
|
7 import ./utils
|
|
8 import ./instance
|
|
9
|
|
10 type
|
|
11 PhysicalDevice* = object
|
|
12 vk*: VkPhysicalDevice
|
|
13 name*: string
|
|
14 devicetype*: VkPhysicalDeviceType
|
|
15 surface*: VkSurfaceKHR
|
|
16 QueueFamily* = object
|
|
17 device: PhysicalDevice
|
|
18 properties*: VkQueueFamilyProperties
|
|
19 index*: uint32
|
|
20 flags*: seq[VkQueueFlagBits]
|
|
21
|
|
22 proc getProperties*(device: PhysicalDevice): VkPhysicalDeviceProperties =
|
|
23 assert device.vk.valid
|
|
24 device.vk.vkGetPhysicalDeviceProperties(addr result)
|
|
25
|
|
26 proc getPhysicalDevices*(instance: Instance): seq[PhysicalDevice] =
|
|
27 assert instance.vk.valid
|
|
28 assert instance.surface.valid
|
|
29 var nDevices: uint32
|
|
30 checkVkResult vkEnumeratePhysicalDevices(instance.vk, addr(nDevices), nil)
|
|
31 var devices = newSeq[VkPhysicalDevice](nDevices)
|
|
32 checkVkResult vkEnumeratePhysicalDevices(instance.vk, addr(nDevices), devices.toCPointer)
|
|
33 for i in 0 ..< nDevices:
|
|
34 var device = PhysicalDevice(vk: devices[i], surface: instance.surface)
|
|
35 let props = device.getProperties()
|
|
36 device.name = props.deviceName.cleanString()
|
|
37 device.devicetype = props.deviceType
|
|
38 result.add device
|
|
39
|
|
40 proc getExtensions*(device: PhysicalDevice): seq[string] =
|
|
41 assert device.vk.valid
|
|
42 var extensionCount: uint32
|
|
43 checkVkResult vkEnumerateDeviceExtensionProperties(device.vk, nil, addr(extensionCount), nil)
|
|
44 if extensionCount > 0:
|
|
45 var extensions = newSeq[VkExtensionProperties](extensionCount)
|
|
46 checkVkResult vkEnumerateDeviceExtensionProperties(device.vk, nil, addr(extensionCount), extensions.toCPointer)
|
|
47 for extension in extensions:
|
|
48 result.add(cleanString(extension.extensionName))
|
|
49
|
|
50 proc getFeatures*(device: PhysicalDevice): VkPhysicalDeviceFeatures =
|
|
51 assert device.vk.valid
|
|
52 device.vk.vkGetPhysicalDeviceFeatures(addr result)
|
|
53
|
|
54 proc getSurfaceCapabilities*(device: PhysicalDevice): VkSurfaceCapabilitiesKHR =
|
|
55 assert device.vk.valid
|
|
56 assert device.surface.valid
|
|
57 checkVkResult device.vk.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.surface, addr(result))
|
|
58
|
|
59 proc getSurfaceFormats*(device: PhysicalDevice): seq[VkSurfaceFormatKHR] =
|
|
60 assert device.vk.valid
|
|
61 assert device.surface.valid
|
|
62 var n_formats: uint32
|
|
63 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device.vk, device.surface, addr(n_formats), nil)
|
|
64 result = newSeq[VkSurfaceFormatKHR](n_formats)
|
|
65 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device.vk, device.surface, addr(n_formats), result.toCPointer)
|
|
66
|
|
67 func filterSurfaceFormat*(
|
|
68 formats: seq[VkSurfaceFormatKHR],
|
|
69 imageFormat = VK_FORMAT_B8G8R8A8_SRGB,
|
|
70 colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
|
|
71 ): VkSurfaceFormatKHR =
|
|
72 for format in formats:
|
|
73 if format.format == imageFormat and format.colorSpace == colorSpace:
|
|
74 return format
|
|
75
|
|
76 proc filterSurfaceFormat*(device: PhysicalDevice): VkSurfaceFormatKHR =
|
|
77 assert device.vk.valid
|
|
78 assert device.surface.valid
|
|
79 device.getSurfaceFormats().filterSurfaceFormat()
|
|
80
|
|
81 proc getSurfacePresentModes*(device: PhysicalDevice): seq[VkPresentModeKHR] =
|
|
82 assert device.vk.valid
|
|
83 assert device.surface.valid
|
|
84 var n_modes: uint32
|
|
85 checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(device.vk, device.surface, addr(n_modes), nil)
|
|
86 result = newSeq[VkPresentModeKHR](n_modes)
|
|
87 checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(device.vk, device.surface, addr(n_modes), result.toCPointer)
|
|
88
|
|
89 proc getQueueFamilies*(device: PhysicalDevice): seq[QueueFamily] =
|
|
90 assert device.vk.valid
|
|
91 var nQueuefamilies: uint32
|
|
92 vkGetPhysicalDeviceQueueFamilyProperties(device.vk, addr nQueuefamilies, nil)
|
|
93 var queuFamilies = newSeq[VkQueueFamilyProperties](nQueuefamilies)
|
|
94 vkGetPhysicalDeviceQueueFamilyProperties(device.vk, addr nQueuefamilies , queuFamilies.toCPointer)
|
|
95 for i in 0 ..< nQueuefamilies:
|
|
96 result.add QueueFamily(
|
|
97 device: device,
|
|
98 properties: queuFamilies[i],
|
|
99 index: i,
|
|
100 flags: queuFamilies[i].queueFlags.toEnums,
|
|
101 )
|
|
102
|
|
103 proc hasGraphics*(family: QueueFamily): bool =
|
|
104 VK_QUEUE_GRAPHICS_BIT in family.flags
|
|
105 proc hasPresentation*(family: QueueFamily, surface: VkSurfaceKHR): bool =
|
|
106 assert surface.valid
|
|
107 var presentation = VkBool32(false)
|
|
108 checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(family.device.vk, family.index, surface, addr presentation)
|
|
109 return presentation
|
|
110
|
|
111 proc filterForGraphicsPresentationQueues*(device: PhysicalDevice): seq[QueueFamily] =
|
|
112 var hasGraphics = false
|
|
113 var hasPresentation = false
|
|
114 var queues: Table[uint32, QueueFamily]
|
|
115 for family in device.getQueueFamilies():
|
|
116 if family.hasGraphics:
|
|
117 queues[family.index] = family
|
|
118 hasGraphics = true
|
|
119 if family.hasPresentation(device.surface):
|
|
120 queues[family.index] = family
|
|
121 hasPresentation = true
|
|
122 if hasGraphics and hasPresentation:
|
|
123 return queues.values.toSeq
|
|
124
|
|
125 proc filterGraphics(families: seq[QueueFamily]): seq[QueueFamily] =
|
|
126 for family in families:
|
|
127 if family.hasGraphics:
|
|
128 result.add family
|
|
129
|
|
130 proc filterPresentation(families: seq[QueueFamily], surface: VkSurfaceKHR): seq[QueueFamily] =
|
|
131 assert surface.valid
|
|
132 for family in families:
|
|
133 if family.hasPresentation(surface):
|
|
134 result.add family
|
|
135
|
|
136 proc rateGraphics*(device: PhysicalDevice): float =
|
|
137 assert device.vk.valid
|
|
138 assert device.surface.valid
|
|
139 if device.getQueueFamilies().filterGraphics().filterPresentation(device.surface).len == 0:
|
|
140 return -1
|
|
141 if not ("VK_KHR_swapchain" in device.getExtensions()):
|
|
142 return -1
|
|
143 const deviceTypeMap = [
|
|
144 VK_PHYSICAL_DEVICE_TYPE_OTHER,
|
|
145 VK_PHYSICAL_DEVICE_TYPE_CPU,
|
|
146 VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU,
|
|
147 VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
|
|
148 VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU,
|
|
149 ]
|
|
150 for (i, devicetype) in enumerate(deviceTypeMap):
|
|
151 if device.devicetype == devicetype:
|
|
152 result = float(i)
|
|
153
|
|
154 proc filterBestGraphics*(devices: seq[PhysicalDevice]): PhysicalDevice =
|
|
155 var bestVal = -1'f
|
|
156 for device in devices:
|
|
157 assert device.vk.valid
|
|
158 assert device.surface.valid
|
|
159 let rating = device.rateGraphics()
|
|
160 if rating > bestVal:
|
|
161 bestVal = rating
|
|
162 result = device
|
|
163 assert bestVal >= 0
|