vkQuake2 doxygen  1.0 dev
vk_device.c File Reference
#include "vk_local.h"

Go to the source code of this file.

Macros

#define DEVTYPESTR(r)   case VK_ ##r: return "VK_"#r
 

Functions

static qboolean deviceExtensionsSupported (const VkPhysicalDevice *physicalDevice)
 
static void getBestPhysicalDevice (const VkPhysicalDevice *devices, int preferredIdx, int count)
 
static qboolean selectPhysicalDevice (int preferredDeviceIdx)
 
static VkResult createLogicalDevice ()
 
static const char * deviceTypeString (VkPhysicalDeviceType dType)
 
static const char * vendorNameString (uint32_t vendorId)
 
qboolean QVk_CreateDevice (int preferredDeviceIdx)
 

Macro Definition Documentation

◆ DEVTYPESTR

#define DEVTYPESTR (   r)    case VK_ ##r: return "VK_"#r

Function Documentation

◆ createLogicalDevice()

static VkResult createLogicalDevice ( )
static

Definition at line 161 of file vk_device.c.

162 {
163  // at least one queue (graphics and present combined) has to be present
164  uint32_t numQueues = 1;
165  float queuePriority = 1.f;
166  VkDeviceQueueCreateInfo queueCreateInfo[3];
167  queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
168  queueCreateInfo[0].pNext = NULL;
169  queueCreateInfo[0].flags = 0;
170  queueCreateInfo[0].queueFamilyIndex = vk_device.gfxFamilyIndex;
171  queueCreateInfo[0].queueCount = 1;
172  queueCreateInfo[0].pQueuePriorities = &queuePriority;
173  queueCreateInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
174  queueCreateInfo[1].pNext = NULL;
175  queueCreateInfo[1].flags = 0;
176  queueCreateInfo[1].queueFamilyIndex = 0;
177  queueCreateInfo[1].queueCount = 1;
178  queueCreateInfo[1].pQueuePriorities = &queuePriority;
179  queueCreateInfo[2].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
180  queueCreateInfo[2].pNext = NULL;
181  queueCreateInfo[2].flags = 0;
182  queueCreateInfo[2].queueFamilyIndex = 0;
183  queueCreateInfo[2].queueCount = 1;
184  queueCreateInfo[2].pQueuePriorities = &queuePriority;
185 
186  VkPhysicalDeviceFeatures wantedDeviceFeatures = {
187  .samplerAnisotropy = vk_device.features.samplerAnisotropy,
188  .fillModeNonSolid = vk_device.features.fillModeNonSolid, // for wireframe rendering
189  .sampleRateShading = vk_device.features.sampleRateShading, // for sample shading
190  };
191 
192  // a graphics and present queue are different - two queues have to be created
194  {
195  queueCreateInfo[numQueues++].queueFamilyIndex = vk_device.presentFamilyIndex;
196  }
197 
198  // a separate transfer queue exists that's different from present and graphics queue?
200  {
201  queueCreateInfo[numQueues++].queueFamilyIndex = vk_device.transferFamilyIndex;
202  }
203 
204  const char *deviceExtensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
205 
206  VkDeviceCreateInfo deviceCreateInfo = {
207  .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
208  .pEnabledFeatures = &wantedDeviceFeatures,
209  .ppEnabledExtensionNames = deviceExtensions,
210  .enabledExtensionCount = 1,
211  .enabledLayerCount = 0,
212  .ppEnabledLayerNames = NULL,
213  .queueCreateInfoCount = numQueues,
214  .pQueueCreateInfos = queueCreateInfo
215  };
216 
217 #if VK_HEADER_VERSION > 101
218  const char *validationLayers[] = { "VK_LAYER_KHRONOS_validation" };
219 #else
220  const char *validationLayers[] = { "VK_LAYER_LUNARG_standard_validation" };
221 #endif
222 
223  if (vk_validation->value)
224  {
225  deviceCreateInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]);
226  deviceCreateInfo.ppEnabledLayerNames = validationLayers;
227  }
228 
229  return vkCreateDevice(vk_device.physical, &deviceCreateInfo, NULL, &vk_device.logical);
230 }

Referenced by QVk_CreateDevice().

◆ deviceExtensionsSupported()

static qboolean deviceExtensionsSupported ( const VkPhysicalDevice *  physicalDevice)
static

Definition at line 24 of file vk_device.c.

25 {
26  uint32_t availableExtCount = 0;
27  qboolean vk_khr_swapchain_extension_available = false;
28  VK_VERIFY(vkEnumerateDeviceExtensionProperties(*physicalDevice, NULL, &availableExtCount, NULL));
29 
30  if (availableExtCount > 0)
31  {
32  VkExtensionProperties *extensions = (VkExtensionProperties *)malloc(availableExtCount * sizeof(VkExtensionProperties));
33  VK_VERIFY(vkEnumerateDeviceExtensionProperties(*physicalDevice, NULL, &availableExtCount, extensions));
34 
35  for (uint32_t i = 0; i < availableExtCount; ++i)
36  {
37  vk_khr_swapchain_extension_available |= strcmp(extensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0;
38  }
39 
40  free(extensions);
41  }
42 
43  // lack of swapchain extension disqualifies the device
44  return vk_khr_swapchain_extension_available;
45 }

Referenced by getBestPhysicalDevice().

◆ deviceTypeString()

static const char* deviceTypeString ( VkPhysicalDeviceType  dType)
static

Definition at line 233 of file vk_device.c.

234 {
235 #define DEVTYPESTR(r) case VK_ ##r: return "VK_"#r
236  switch (dType)
237  {
238  DEVTYPESTR(PHYSICAL_DEVICE_TYPE_OTHER);
239  DEVTYPESTR(PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU);
240  DEVTYPESTR(PHYSICAL_DEVICE_TYPE_DISCRETE_GPU);
241  DEVTYPESTR(PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU);
242  DEVTYPESTR(PHYSICAL_DEVICE_TYPE_CPU);
243  default: return "<unknown>";
244  }
245 #undef DEVTYPESTR
246  return "UNKNOWN DEVICE";
247 }

Referenced by QVk_CreateDevice().

◆ getBestPhysicalDevice()

static void getBestPhysicalDevice ( const VkPhysicalDevice *  devices,
int  preferredIdx,
int  count 
)
static

Definition at line 48 of file vk_device.c.

49 {
50  VkPhysicalDeviceProperties deviceProperties;
51  VkPhysicalDeviceFeatures deviceFeatures;
52  uint32_t queueFamilyCount = 0;
53 
54  for (int i = 0; i < count; ++i)
55  {
56  vkGetPhysicalDeviceProperties(devices[i], &deviceProperties);
57  vkGetPhysicalDeviceFeatures(devices[i], &deviceFeatures);
58  vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &queueFamilyCount, NULL);
59 
60  if (queueFamilyCount == 0)
61  continue;
62 
63  // prefer discrete GPU but if it's the only one available then don't be picky
64  // also - if the user specifies a preferred device, select it
65  qboolean bestProperties = deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
66  if (preferredIdx == i || (bestProperties && preferredIdx < 0) || count == 1)
67  {
68  uint32_t formatCount = 0;
69  uint32_t presentModesCount = 0;
70 
71  // check if requested device extensions are present
72  qboolean extSupported = deviceExtensionsSupported(&devices[i]);
73 
74  // no required extensions? try next device
75  if (!extSupported || !deviceFeatures.samplerAnisotropy || !deviceFeatures.fillModeNonSolid)
76  continue;
77 
78  // if extensions are fine, query surface formats and present modes to see if the device can be used
79  VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(devices[i], vk_surface, &formatCount, NULL));
80  VK_VERIFY(vkGetPhysicalDeviceSurfacePresentModesKHR(devices[i], vk_surface, &presentModesCount, NULL));
81 
82  if (formatCount == 0 || presentModesCount == 0)
83  continue;
84 
85  VkQueueFamilyProperties *queueFamilies = (VkQueueFamilyProperties *)malloc(queueFamilyCount * sizeof(VkQueueFamilyProperties));
86  vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &queueFamilyCount, queueFamilies);
87 
88  // secondary check - device is OK if there's at least on queue with VK_QUEUE_GRAPHICS_BIT set
89  for (uint32_t j = 0; j < queueFamilyCount; ++j)
90  {
91  // check if this queue family has support for presentation
92  VkBool32 presentSupported;
93  VK_VERIFY(vkGetPhysicalDeviceSurfaceSupportKHR(devices[i], j, vk_surface, &presentSupported));
94 
95  // good optimization would be to find a queue where presentIdx == gfxQueueIdx for less overhead
96  if (vk_device.presentFamilyIndex < 0 && queueFamilies[j].queueCount > 0 && presentSupported)
97  {
99  }
100 
101  if (vk_device.gfxFamilyIndex < 0 && queueFamilies[j].queueCount > 0 && (queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT))
102  {
104  }
105 
106  if (vk_device.transferFamilyIndex < 0 && queueFamilies[j].queueCount > 0 && !(queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) && (queueFamilies[j].queueFlags & VK_QUEUE_TRANSFER_BIT))
107  {
109  }
110  }
111 
112  free(queueFamilies);
113 
114  // accept only device that has support for presentation and drawing
116  {
118  {
120  }
121 
122  vk_device.physical = devices[i];
123  vk_device.properties = deviceProperties;
124  vk_device.features = deviceFeatures;
125  return;
126  }
127  }
128  }
129 }

Referenced by selectPhysicalDevice().

◆ QVk_CreateDevice()

qboolean QVk_CreateDevice ( int  preferredDeviceIdx)

Definition at line 264 of file vk_device.c.

265 {
266  if (!selectPhysicalDevice(preferredDeviceIdx))
267  return false;
268 
271 
272  VkResult res = createLogicalDevice();
273  if (res != VK_SUCCESS)
274  {
275  ri.Con_Printf(PRINT_ALL, "Could not create Vulkan logical device: %s\n", QVk_GetError(res));
276  return false;
277  }
278 
282 
283  return true;
284 }

Referenced by QVk_Init().

◆ selectPhysicalDevice()

static qboolean selectPhysicalDevice ( int  preferredDeviceIdx)
static

Definition at line 132 of file vk_device.c.

133 {
134  uint32_t physicalDeviceCount = 0;
135  VK_VERIFY(vkEnumeratePhysicalDevices(vk_instance, &physicalDeviceCount, NULL));
136 
137  if (physicalDeviceCount == 0)
138  {
139  ri.Con_Printf(PRINT_ALL, "No Vulkan-capable devices found!\n");
140  return false;
141  }
142 
143  ri.Con_Printf(PRINT_ALL, "...found %d Vulkan-capable device(s)\n", physicalDeviceCount);
144 
145  VkPhysicalDevice *physicalDevices = (VkPhysicalDevice *)malloc(physicalDeviceCount * sizeof(VkPhysicalDevice));
146  VK_VERIFY(vkEnumeratePhysicalDevices(vk_instance, &physicalDeviceCount, physicalDevices));
147 
148  getBestPhysicalDevice(physicalDevices, preferredDeviceIdx < physicalDeviceCount ? preferredDeviceIdx : -1, physicalDeviceCount);
149  free(physicalDevices);
150 
151  if (vk_device.physical == VK_NULL_HANDLE)
152  {
153  ri.Con_Printf(PRINT_ALL, "Could not find a suitable physical device!\n");
154  return false;
155  }
156 
157  return true;
158 }

Referenced by QVk_CreateDevice().

◆ vendorNameString()

static const char* vendorNameString ( uint32_t  vendorId)
static

Definition at line 250 of file vk_device.c.

251 {
252  switch (vendorId)
253  {
254  case 0x1002: return "AMD";
255  case 0x1010: return "ImgTec";
256  case 0x10DE: return "NVIDIA";
257  case 0x13B5: return "ARM";
258  case 0x5143: return "Qualcomm";
259  case 0x8086: return "Intel";
260  default: return "unknown";
261  }
262 }

Referenced by QVk_CreateDevice().

qvkdevice_t::gfxQueue
VkQueue gfxQueue
Definition: qvk.h:43
qvkdevice_t::logical
VkDevice logical
Definition: qvk.h:40
vendorNameString
static const char * vendorNameString(uint32_t vendorId)
Definition: vk_device.c:250
vk_instance
VkInstance vk_instance
Definition: vk_common.c:46
vkconfig_t::device_type
const char * device_type
Definition: vk_local.h:308
ri
refimport_t ri
Definition: r_main.c:25
createLogicalDevice
static VkResult createLogicalDevice()
Definition: vk_device.c:161
qvkdevice_t::properties
VkPhysicalDeviceProperties properties
Definition: qvk.h:41
qboolean
qboolean
Definition: q_shared.h:63
i
int i
Definition: q_shared.c:305
qvkdevice_t::gfxFamilyIndex
int gfxFamilyIndex
Definition: qvk.h:46
vk_device
qvkdevice_t vk_device
Definition: vk_common.c:51
j
GLint j
Definition: qgl_win.c:150
qvkdevice_t::presentFamilyIndex
int presentFamilyIndex
Definition: qvk.h:47
deviceExtensionsSupported
static qboolean deviceExtensionsSupported(const VkPhysicalDevice *physicalDevice)
Definition: vk_device.c:24
refimport_t::Con_Printf
void(* Con_Printf)(int print_level, char *str,...)
Definition: ref.h:202
PRINT_ALL
#define PRINT_ALL
Definition: qcommon.h:751
selectPhysicalDevice
static qboolean selectPhysicalDevice(int preferredDeviceIdx)
Definition: vk_device.c:132
cvar_s::value
float value
Definition: q_shared.h:331
vk_validation
cvar_t * vk_validation
Definition: vk_rmain.c:90
qvkdevice_t::features
VkPhysicalDeviceFeatures features
Definition: qvk.h:42
NULL
#define NULL
Definition: q_shared.h:67
vk_config
vkconfig_t vk_config
Definition: vk_rmain.c:30
VK_VERIFY
#define VK_VERIFY(x)
Definition: vk_local.h:59
qvkdevice_t::presentQueue
VkQueue presentQueue
Definition: qvk.h:44
vkconfig_t::vendor_name
const char * vendor_name
Definition: vk_local.h:307
qvkdevice_t::transferQueue
VkQueue transferQueue
Definition: qvk.h:45
vk_surface
VkSurfaceKHR vk_surface
Definition: vk_common.c:47
qvkdevice_t::transferFamilyIndex
int transferFamilyIndex
Definition: qvk.h:48
getBestPhysicalDevice
static void getBestPhysicalDevice(const VkPhysicalDevice *devices, int preferredIdx, int count)
Definition: vk_device.c:48
DEVTYPESTR
#define DEVTYPESTR(r)
deviceTypeString
static const char * deviceTypeString(VkPhysicalDeviceType dType)
Definition: vk_device.c:233
qvkdevice_t::physical
VkPhysicalDevice physical
Definition: qvk.h:39
count
GLint GLsizei count
Definition: qgl_win.c:128
QVk_GetError
const char * QVk_GetError(VkResult errorCode)
Definition: vk_common.c:2293