SimpleGL  1.1.0
A framework for platform independent rendering
physical_device.cpp
Go to the documentation of this file.
1 
9 
10 #include <cstdlib>
11 #include <cstring>
12 
13 #include <stdexcept>
14 #include <string>
15 
16 #include <SimpleGL/logging.hpp>
17 
20 
21 using namespace std;
22 
23 namespace sgl {
24 
25  bool QueueFamilyIndices::isValid() {
26  return graphics >= 0 && presentation >= 0;
27  }
28 
29  std::vector<PhysicalDevice*> PhysicalDevice::getAvailablePhysicalDevices(Surface* surface) {
30  Instance* instance = VulkanContext::getCurrent()->getInstance();
31 
32  /* Get all available graphic cards */
33  vector<VkPhysicalDevice> devices = instance->enumeratePhysicalDevices();
34  vector<PhysicalDevice*> physicalDevices(devices.size());
35  for (uint32_t i = 0; i < devices.size(); i++) {
36  physicalDevices[i] = new PhysicalDevice(devices[i], surface);
37  }
38 
39  return physicalDevices;
40  }
41 
42  PhysicalDevice* PhysicalDevice::getSuitablePhysicalDevice(std::vector<PhysicalDevice*> physicalDevices) {
43  PhysicalDevice* suitablePhysicalDevice = physicalDevices[0];
44 
45  for (uint32_t i = 0; i < physicalDevices.size(); i++) {
46  /* Get physical device properties */
47  VkPhysicalDeviceProperties currentProperties = suitablePhysicalDevice->getProperties();
48  VkPhysicalDeviceProperties candidateProperties = physicalDevices[i]->getProperties();
49 
50  /* Prefer discrete GPUs over integrated or virtual GPUs */
51  if (candidateProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
52  currentProperties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
53  if (suitablePhysicalDevice->queueFamilyIndices.isValid()) {
54  suitablePhysicalDevice = physicalDevices[i];
55  break;
56  }
57  }
58  }
59 
60  /* Check if the selected device supports the necessary requirements */
61  suitablePhysicalDevice->validate();
62 
63  return suitablePhysicalDevice;
64  }
65 
66  PhysicalDevice::PhysicalDevice(VkPhysicalDevice handle, Surface* surface) {
67  this->handle = handle;
68  queueFamilyIndices.graphics = -1;
69  queueFamilyIndices.presentation = -1;
70 
71  /* Find the queue family indices */
72  vector<VkQueueFamilyProperties> queueFamilyProperties = getQueueFamilyProperties();
73  for (uint32_t i = 0; i < queueFamilyProperties.size(); i++) {
74  /* Check for graphics support */
75  bool graphicsSupport = queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT;
76  if (queueFamilyProperties[i].queueCount > 0 && graphicsSupport) {
77  queueFamilyIndices.graphics = i;
78  }
79 
80  /* Check for presentation support */
81  VkBool32 presentationSupport = VK_FALSE;
82  vkGetPhysicalDeviceSurfaceSupportKHR(handle, i, surface->getHandle(), &presentationSupport);
83  if (queueFamilyProperties[i].queueCount > 0 && presentationSupport) {
84  queueFamilyIndices.presentation = i;
85  }
86 
87  /* Check if necesarry indices are found */
88  if (queueFamilyIndices.isValid()) {
89  break;
90  }
91  }
92 
93  /* Get surface capabilities */
94  vkGetPhysicalDeviceSurfaceCapabilitiesKHR(handle, surface->getHandle(), &swapchainSupportDetails.surfaceCapabilities);
95 
96  /* Get number of supported surface formats */
97  uint32_t surfaceFormatCount = 0;
98  vkGetPhysicalDeviceSurfaceFormatsKHR(handle, surface->getHandle(), &surfaceFormatCount, nullptr);
99 
100  /* Get all supported surface formats */
101  if (surfaceFormatCount > 0) {
102  swapchainSupportDetails.surfaceFormats.resize(surfaceFormatCount);
103  vkGetPhysicalDeviceSurfaceFormatsKHR(handle, surface->getHandle(), &surfaceFormatCount, swapchainSupportDetails.surfaceFormats.data());
104  }
105 
106  /* Get number of supported present modes */
107  uint32_t presentModeCount = 0;
108  vkGetPhysicalDeviceSurfacePresentModesKHR(handle, surface->getHandle(), &presentModeCount, nullptr);
109 
110  /* Get all supported present modes */
111  if (presentModeCount > 0) {
112  swapchainSupportDetails.presentModes.resize(presentModeCount);
113  vkGetPhysicalDeviceSurfacePresentModesKHR(handle, surface->getHandle(), &presentModeCount, swapchainSupportDetails.presentModes.data());
114  }
115  }
116 
117  PhysicalDevice::~PhysicalDevice(void) {
118  /* Nothing to do here */
119  }
120 
121  VkPhysicalDevice PhysicalDevice::getHandle() {
122  return handle;
123  }
124 
125  QueueFamilyIndices PhysicalDevice::getQueueFamilyIndices() {
126  return queueFamilyIndices;
127  }
128 
129  SwapchainSupportDetails PhysicalDevice::getSwapchainSupportDetails() {
130  return swapchainSupportDetails;
131  }
132 
133  VkPhysicalDeviceProperties PhysicalDevice::getProperties() {
134  VkPhysicalDeviceProperties properties;
135  vkGetPhysicalDeviceProperties(handle, &properties);
136 
137  return properties;
138  }
139 
140  VkPhysicalDeviceFeatures PhysicalDevice::getFeatures() {
141  VkPhysicalDeviceFeatures features;
142  vkGetPhysicalDeviceFeatures(handle, &features);
143 
144  return features;
145  }
146 
147  std::vector<VkQueueFamilyProperties> PhysicalDevice::getQueueFamilyProperties() {
148  /* Get number of queue families */
149  uint32_t queueFamilyCount = 0;
150  vkGetPhysicalDeviceQueueFamilyProperties(handle, &queueFamilyCount, nullptr);
151 
152  /* Get all queue family properties */
153  vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyCount);
154  vkGetPhysicalDeviceQueueFamilyProperties(handle, &queueFamilyCount, queueFamilyProperties.data());
155 
156  return queueFamilyProperties;
157  }
158 
159  void PhysicalDevice::validate() {
160  /* Check if the device supports the necessary queue families */
161  if (queueFamilyIndices.graphics < 0) {
162  throw runtime_error("Could not find a queue family that supports graphics!");
163  } else if (queueFamilyIndices.presentation < 0) {
164  throw runtime_error("Could not find a queue family that supports presentation!");
165  }
166 
167  /* Get number of extension properties */
168  uint32_t availableExtensionCount = 0;
169  vkEnumerateDeviceExtensionProperties(handle, nullptr, &availableExtensionCount, nullptr);
170 
171  /* Get all extension properties */
172  vector<VkExtensionProperties> availableExtensions(availableExtensionCount);
173  vkEnumerateDeviceExtensionProperties(handle, nullptr, &availableExtensionCount, availableExtensions.data());
174 
175  /* Add required extensions */
176  vector<const char*> requiredExtensions;
177  requiredExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
178 
179  /* Check required extensions */
180  for (uint32_t i = 0; i < requiredExtensions.size(); i++) {
181  bool found = false;
182  for (uint32_t j = 0; j < availableExtensions.size(); j++) {
183  if (strcmp(requiredExtensions[i], availableExtensions[j].extensionName)) {
184  found = true;
185  break;
186  }
187  }
188  if (found) {
189  Logger::logInfo(string(requiredExtensions[i]) + " is supported!");
190  } else {
191  Logger::logError(string(requiredExtensions[i]) + " is not supported.");
192  exit(EXIT_FAILURE);
193  }
194  }
195 
196  /* Check if the swapchain support is sufficient */
197  if (swapchainSupportDetails.surfaceFormats.empty()) {
198  throw runtime_error("Could not find a supported surface format!");
199  } else if (swapchainSupportDetails.presentModes.empty()) {
200  throw runtime_error("Could not find a supported present mode!");
201  }
202  }
203 }
This class wraps a Vulkan instance.
This class wraps a Vulkan physical device and represents a graphics card.
This struct stores relevant queue family indices.
This struct stores necessary data for swapchain support.
Generic namespace for the SimpleGL framework.
Definition: application.hpp:18
VkSurfaceKHR getHandle()
Returns the hande of the surface.
Definition: surface.cpp:37
std::vector< VkPhysicalDevice > enumeratePhysicalDevices()
Enumerates the physical devices accessible to this instance.
bool isValid()
Checks if the queue family indices are valid.
This class wraps a Vulkan surface.
Definition: surface.hpp:25
VkPhysicalDeviceProperties getProperties()
Returns the properties of this physical device.