Engine
Frameworkcreatedbymeusableforthecreationofsimplegames.CurrentlysupportsOpenGL(Verysimple)andVulkan.
VulkanPhysicalDevice.cpp
Go to the documentation of this file.
2 #ifdef USING_VULKAN
3 
5 #include <ThirdParty/EASTL-master/include/EASTL/map.h>
6 #include <ThirdParty/EASTL-master/include/EASTL/vector.h>
7 #include <ThirdParty/EASTL-master/include/EASTL/utility.h>
8 #include <ThirdParty/EASTL-master/include/EASTL/algorithm.h>
9 #include <ThirdParty/EASTL-master/include/EASTL/numeric_limits.h>
10 
11 namespace Engine {
12 
13  static VulkanDeviceQueueFamilies_t GetDeviceQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface) {
14  VulkanDeviceQueueFamilies_t families = {};
15 
16  uint32_t familyCount = 0;
17  vkGetPhysicalDeviceQueueFamilyProperties(device, &familyCount, nullptr);
18  eastl::vector<VkQueueFamilyProperties> properties(familyCount);
19  vkGetPhysicalDeviceQueueFamilyProperties(device, &familyCount, properties.data());
20 
21  for (int i = 0; i < static_cast<int>(properties.size()); i++) {
22  if (properties[i].queueCount > 0 && properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
23  families.graphics = i;
24  }
25  if (properties[i].queueCount > 0 && properties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
26  families.compute = i;
27  }
28  if (properties[i].queueCount > 0 && properties[i].queueFlags & VK_QUEUE_TRANSFER_BIT) {
29  families.transfere = i;
30  }
31  if (properties[i].queueCount > 0 && properties[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) {
32  families.sparseBinding = i;
33  }
34 
35  VkBool32 presentSupport = false;
36 
37  vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
38 
39  if (presentSupport && properties[i].queueCount > 0)
40  families.present = i;
41 
42  if (families.graphics >= 0 && families.compute >= 0 && families.transfere >= 0 && families.sparseBinding >= 0 && families.present >= 0)
43  break;
44  }
45 
46  return families;
47 
48  }
49 
50  static VulkanSwapChainSupportDetails_t GetDeviceSwapChainSupportDetails(VkPhysicalDevice device, VkSurfaceKHR surface) {
51  VulkanSwapChainSupportDetails_t details = {};
52 
53  vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
54 
55  uint32_t formatCount = 0;
56  vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
57  if (formatCount != 0) {
58  details.formats.resize(formatCount);
59  vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
60  }
61 
62  uint32_t presentModeCount = 0;
63  vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
64  if (presentModeCount != 0) {
65  details.presentModes.resize(presentModeCount);
66  vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
67  }
68 
69  return details;
70  }
71 
72  VulkanPhysicalDevice * VulkanPhysicalDevice::GetBestPhysicalDevice(VulkanInstance * instance, VkSurfaceKHR surface, eastl::vector<const char*> requiredExtensions, VulkanDeviceFeatures_t requiredFeatures, VulkanDeviceFeatures_t optionalFeatures, VulkanDeviceQueueRequestedFamilies_t requestedQueueFamilies, bool GPU)
73  {
74  //return nullptr;
75  uint32_t deviceCount = 0;
76  vkEnumeratePhysicalDevices(instance->GetInstance(), &deviceCount, nullptr);
77  if (deviceCount < 1)
78  return nullptr;
79  eastl::vector<VkPhysicalDevice> devices(deviceCount);
80  vkEnumeratePhysicalDevices(instance->GetInstance(), &deviceCount, devices.data());
81  eastl::multimap<float, VkPhysicalDevice> selectedDevices;
82  for (int i = 0; i < static_cast<int>(devices.size()); i++) {
83  VkPhysicalDeviceProperties deviceProperties;
84  VkPhysicalDeviceFeatures deviceFeatures;
85  vkGetPhysicalDeviceProperties(devices[i], &deviceProperties);
86  vkGetPhysicalDeviceFeatures(devices[i], &deviceFeatures);
87 
88 
89  if (GPU && !(deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU || deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)) {
90  continue;
91  }
92 
93  uint32_t extensionCount = 0;
94  vkEnumerateDeviceExtensionProperties(devices[i], NULL, &extensionCount, nullptr);
95  eastl::vector<VkExtensionProperties> extensions(extensionCount);
96  vkEnumerateDeviceExtensionProperties(devices[i], NULL, &extensionCount, extensions.data());
97 
98  bool extensionNotFound = false;
99  for (int i = 0; i < static_cast<int>(requiredExtensions.size()); i++) {
100  bool extensionFound = false;
101  for (int j = 0; j < static_cast<int>(extensions.size()); j++) {
102  if (strcmp(extensions[j].extensionName, requiredExtensions[i]) == 0) {
103  extensionFound = true;
104  break;
105  }
106  }
107  if (extensionFound == false) {
108  extensionNotFound = true;
109  break;
110  }
111  }
112 
113  if (extensionNotFound)
114  continue;
115 
116  VulkanDeviceQueueFamilies_t families = GetDeviceQueueFamilies(devices[i], surface);
117 
118  if (requestedQueueFamilies.graphics == true && families.graphics < 0)
119  continue;
120  if (requestedQueueFamilies.compute == true && families.compute < 0)
121  continue;
122  if (requestedQueueFamilies.transfere == true && families.transfere < 0)
123  continue;
124  if (requestedQueueFamilies.sparseBinding == true && families.sparseBinding < 0)
125  continue;
126  if (requestedQueueFamilies.present == true && families.present < 0)
127  continue;
128 
129  VulkanSwapChainSupportDetails_t details = GetDeviceSwapChainSupportDetails(devices[i], surface);
130 
131  if (details.formats.size() == 0 || details.presentModes.size() == 0)
132  continue;
133 
134  float* requiredFeaturesValues = (float*)&requiredFeatures;
135  VkBool32* requiredFeaturesFoundValues = (VkBool32*)&deviceFeatures;
136  bool success = true;
137  for (int j = 0; j < sizeof(VulkanDeviceFeatures_t) / sizeof(float); j++) {
138  if (requiredFeaturesValues[j] > 0.f&&requiredFeaturesFoundValues[j] != VK_TRUE) {
139  success = false;
140  break;
141  }
142  if (requiredFeaturesValues[j] < 0.f&&requiredFeaturesFoundValues[j] == VK_TRUE) {
143  success = false;
144  break;
145  }
146  }
147  if (success) {
148  float* optionalFeaturesValues = (float*)&optionalFeatures;
149  float score = 0.01f;
150  for (int j = 0; j < sizeof(VulkanDeviceFeatures_t) / sizeof(float); j++) {
151  if (optionalFeaturesValues[j] != 0.f) {
152  if (optionalFeaturesValues[j] > 0.f&&requiredFeaturesFoundValues[j] == VK_TRUE)
153  score += optionalFeaturesValues[j];
154  if (optionalFeaturesValues[j] < 0.f&&requiredFeaturesFoundValues[j] != VK_TRUE)
155  score += -1.f*optionalFeaturesValues[j];
156  }
157  }
158  selectedDevices.insert(eastl::make_pair(score, devices[i]));
159  }
160  }
161  if (selectedDevices.rbegin()->first > 0.f) {
162  return new VulkanPhysicalDevice(selectedDevices.rbegin()->second, surface);
163  }
164  return nullptr;
165  }
166  eastl::vector<VulkanPhysicalDevice*> VulkanPhysicalDevice::GetAllPhysicalDevices(VulkanInstance* instance, VkSurfaceKHR surface)
167  {
168  uint32_t deviceCount = 0;
169  vkEnumeratePhysicalDevices(instance->GetInstance(), &deviceCount, nullptr);
170  eastl::vector<VulkanPhysicalDevice*> Vulkandevices(deviceCount);
171  eastl::vector<VkPhysicalDevice> devices(deviceCount);
172  vkEnumeratePhysicalDevices(instance->GetInstance(), &deviceCount, devices.data());
173  for (int i = 0; i < static_cast<int>(devices.size()); i++) {
174  Vulkandevices[i] = new VulkanPhysicalDevice(devices[i], surface);
175  }
176  return Vulkandevices;
177  }
178 
179  VulkanDeviceQueueFamilies_t VulkanPhysicalDevice::GetQueueFamilies()
180  {
181  //if (!queueFamiliesFound) {
182  QueueFamilies = GetDeviceQueueFamilies(device, surface);
183  queueFamiliesFound = true;
184  //}
185  return QueueFamilies;
186  }
187 
188  VulkanSwapChainSupportDetails_t VulkanPhysicalDevice::GetSwapChainSupportDetails()
189  {
190  if (!swapChainDetailsFound) {
191  details = GetDeviceSwapChainSupportDetails(device, surface);
192  swapChainDetailsFound = true;
193  }
194  return details;
195  }
196  VulkanSwapChainSupportDetails_t VulkanPhysicalDevice::ReloadSwapChainSupportDetails()
197  {
198  details = GetDeviceSwapChainSupportDetails(device, surface);
199  return details;
200  }
201 
202  VkSurfaceFormatKHR VulkanPhysicalDevice::ChooseSwapSurfaceFormat(const eastl::vector<VkSurfaceFormatKHR>& availableFormats)
203  {
204 
205  if (availableFormats.size() == 1 && availableFormats[0].format == VK_FORMAT_UNDEFINED) {
206  return { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
207  }
208 
209  for (const auto& availableFormat : availableFormats) {
210  if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
211  return availableFormat;
212  }
213  }
214 
215  return availableFormats[0];
216 
217  }
218 
219  VkPresentModeKHR VulkanPhysicalDevice::ChooseSwapPresentMode(const eastl::vector<VkPresentModeKHR> availablePresentModes)
220  {
221  VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
222 
223  for (const auto& availablePresentMode : availablePresentModes) {
224  if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
225  return availablePresentMode;
226  }
227  else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
228  //bestMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
229  }
230 
231  }
232 
233  return bestMode;
234  }
235 
236  VkExtent2D VulkanPhysicalDevice::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR & capabilities, int width, int height)
237  {
238  if (capabilities.currentExtent.width != eastl::numeric_limits<uint32_t>::max()) {
239  return capabilities.currentExtent;
240  }
241  else {
242  VkExtent2D actualExtend = { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
243 
244  uint32_t minWidth = actualExtend.width < capabilities.maxImageExtent.width ? actualExtend.width : capabilities.maxImageExtent.width;
245  actualExtend.width = capabilities.minImageExtent.width < minWidth ? minWidth : capabilities.minImageExtent.width;
246 
247  uint32_t minHeight = actualExtend.height < capabilities.maxImageExtent.height ? actualExtend.height : capabilities.maxImageExtent.height;
248  actualExtend.height = capabilities.minImageExtent.height < minHeight ? minHeight : capabilities.minImageExtent.height;
249 
250  return actualExtend;
251  }
252  }
253 
254  VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice device, VkSurfaceKHR surface): queueFamiliesFound(false),
255  swapChainDetailsFound(false)
256  {
257  this->device = device;
258  this->surface = surface;
259  }
260 
261 
262  VulkanPhysicalDevice::~VulkanPhysicalDevice()
263  {
264  }
265 }
266 
267 #endif // USING_VULKAN