Lugdunum  0.1.0
Device.cpp
Go to the documentation of this file.
2 
3 #define NOMINMAX
4 #include <algorithm>
5 
7 
8 namespace lug {
9 namespace Graphics {
10 namespace Vulkan {
11 namespace API {
12 namespace Builder {
13 
14 Device::Device(const PhysicalDeviceInfo& physicalDeviceInfo): _physicalDeviceInfo(physicalDeviceInfo) {
15  // Initialize the list of queues to the available queues
17  for (uint32_t i = 0; i < _physicalDeviceInfo.queueFamilies.size(); ++i) {
18  _queueFamiliesInfos[i].flags = _physicalDeviceInfo.queueFamilies[i].queueFlags;
19  _queueFamiliesInfos[i].queues.resize(_physicalDeviceInfo.queueFamilies[i].queueCount);
20  }
21 }
22 
23 uint8_t Device::addQueues(VkQueueFlags queueFlags, const std::vector<std::string>& queuesNames) {
24  int8_t queuesNb = 0;
25 
26  for (const std::string& queueName: queuesNames) {
27  if (!addQueue(queueFlags, queueName)) {
28  // If queueFlags contains VK_QUEUE_TRANSFER_BIT and queue is not found,
29  // we can use either VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT instead of VK_QUEUE_TRANSFER_BIT
30  if (queueFlags & VK_QUEUE_TRANSFER_BIT) {
31  // We try to find a queue first by replacing VK_QUEUE_TRANSFER_BIT with VK_QUEUE_GRAPHICS_BIT
32  // then with VK_QUEUE_COMPUTE_BIT
33  VkQueueFlags queueFlagsTmp = queueFlags & ~VK_QUEUE_TRANSFER_BIT;
34  if (!addQueue(queueFlagsTmp | VK_QUEUE_GRAPHICS_BIT, queueName) &&
35  !addQueue(queueFlagsTmp | VK_QUEUE_COMPUTE_BIT, queueName)) {
36  return queuesNb;
37  }
38  } else {
39  return queuesNb;
40  }
41  }
42 
43  ++queuesNb;
44  }
45 
46  return queuesNb;
47 }
48 
49 bool Device::build(API::Device& device, VkResult* returnResult) {
50  std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
51  const float priorities[256] = {1.0f};
52 
53  // Fill the queueCreateInfos
54  for (uint32_t i = 0; i < _queueFamiliesInfos.size(); ++i) {
55  if (_queueFamiliesInfos[i].queuesUsed == 0) {
56  continue;
57  }
58  const VkDeviceQueueCreateInfo queueCreateInfo {
59  /* queueCreateInfo.sType */ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
60  /* queueCreateInfo.pNext */ nullptr,
61  /* queueCreateInfo.flags */ 0,
62  /* queueCreateInfo.queueFamilyIndex */ i,
63  /* queueCreateInfo.queueCount */ _queueFamiliesInfos[i].queuesUsed,
64  /* queueCreateInfo.pQueuePriorities */ priorities,
65  };
66 
67  queueCreateInfos.push_back(std::move(queueCreateInfo));
68  }
69 
70  // Create the device creation information for vkCreateDevice
71  const VkDeviceCreateInfo createInfo{
72  /* createInfo.sType */ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
73  /* createInfo.pNext */ nullptr,
74  /* createInfo.flags */ 0,
75  /* createInfo.queueCreateInfoCount */ static_cast<uint32_t>(queueCreateInfos.size()),
76  /* createInfo.pQueueCreateInfos */ queueCreateInfos.data(),
77  /* createInfo.enabledLayerCount */ 0, // Deprecated
78  /* createInfo.ppEnabledLayerNames */ nullptr, // Deprecated
79  /* createInfo.enabledExtensionCount */ static_cast<uint32_t>(_extensions.size()),
80  /* createInfo.ppEnabledExtensionNames */ _extensions.data(),
81  /* createInfo.pEnabledFeatures */ &_features
82  };
83 
84  // Create the device
85  VkDevice vkDevice{VK_NULL_HANDLE};
86  VkResult result = vkCreateDevice(_physicalDeviceInfo.handle, &createInfo, nullptr, &vkDevice);
87 
88  if (returnResult) {
89  *returnResult = result;
90  }
91 
92  if (result != VK_SUCCESS) {
93  return false;
94  }
95 
96  device = API::Device(vkDevice, &_physicalDeviceInfo);
97 
98  auto getDeviceQueue = device.getProcAddr<PFN_vkGetDeviceQueue>("vkGetDeviceQueue");
99  if (!getDeviceQueue) {
100  LUG_LOG.error("Device::addQueue: Can't load function vkGetDeviceQueue");
101  return false;
102  }
103 
104  // Create queues
105  {
106  for (uint32_t i = 0; i < _queueFamiliesInfos.size(); ++i) {
107  if (_queueFamiliesInfos[i].queuesUsed == 0) {
108  continue;
109  }
110 
111  VkQueueFlags queueFlags = _queueFamiliesInfos[i].flags;
112  device._queueFamilies.push_back(API::QueueFamily(i, queueFlags));
113 
114  auto& queueFamily = device._queueFamilies.back();
115 
116  // Create queues for the queue family
117  for (uint8_t j = 0; j < _queueFamiliesInfos[i].queuesUsed; ++j) {
118  VkQueue queue{VK_NULL_HANDLE};
119  getDeviceQueue(static_cast<VkDevice>(device), i, j, &queue);
120 
121  queueFamily._queues.push_back(API::Queue(queue, &queueFamily));
122 
123  for (const std::string& name: _queueFamiliesInfos[i].queues[j].names) {
124  queueFamily._queuesIndices[name] = static_cast<uint32_t>(queueFamily._queues.size() - 1);
125  }
126  }
127  }
128  }
129 
130  return true;
131 }
132 
133 std::unique_ptr<API::Device> Device::build(VkResult* returnResult) {
134  std::unique_ptr<API::Device> device = std::make_unique<API::Device>();
135  return build(*device, returnResult) ? std::move(device) : nullptr;
136 }
137 
138 bool Device::addQueue(VkQueueFlags queueFlags, const std::string& queueName) {
139  for (uint32_t queueFamilyIdx = 0; queueFamilyIdx < _physicalDeviceInfo.queueFamilies.size(); ++queueFamilyIdx) {
140  if ((_queueFamiliesInfos[queueFamilyIdx].flags & queueFlags) != queueFlags) {
141  continue;
142  }
143 
144  for (uint32_t i = 0; i < _queueFamiliesInfos[queueFamilyIdx].queues.size(); ++i) {
145  if (!_queueFamiliesInfos[queueFamilyIdx].queues[i].flagsUsed) {
146  _queueFamiliesInfos[queueFamilyIdx].queuesUsed++;
147  _queueFamiliesInfos[queueFamilyIdx].queues[i].flagsUsed |= queueFlags;
148  _queueFamiliesInfos[queueFamilyIdx].queues[i].names.push_back(queueName);
149 
150  return true;
151  }
152  }
153  }
154 
155  for (uint32_t queueFamilyIdx = 0; queueFamilyIdx < _physicalDeviceInfo.queueFamilies.size(); ++queueFamilyIdx) {
156  if ((_queueFamiliesInfos[queueFamilyIdx].flags & queueFlags) != queueFlags) {
157  continue;
158  }
159 
160  for (uint32_t i = 0; i < _queueFamiliesInfos[queueFamilyIdx].queues.size(); ++i) {
161  if (!(_queueFamiliesInfos[queueFamilyIdx].queues[i].flagsUsed & queueFlags)) {
162  _queueFamiliesInfos[queueFamilyIdx].queuesUsed += _queueFamiliesInfos[queueFamilyIdx].queues[i].flagsUsed ? 0 : 1;
163  _queueFamiliesInfos[queueFamilyIdx].queues[i].flagsUsed |= queueFlags;
164  _queueFamiliesInfos[queueFamilyIdx].queues[i].names.push_back(queueName);
165 
166  return true;
167  }
168  }
169  }
170 
171  return false;
172 }
173 
174 } // Builder
175 } // API
176 } // Vulkan
177 } // Graphics
178 } // lug
std::vector< VkQueueFamilyProperties > queueFamilies
Definition: Vulkan.hpp:186
VkPhysicalDeviceFeatures _features
Definition: Device.hpp:57
Function getProcAddr(const char *name) const
bool addQueue(VkQueueFlags queueFlags, const std::string &queueName)
Definition: Device.cpp:138
std::vector< QueueFamily > _queueFamiliesInfos
Definition: Device.hpp:59
uint8_t addQueues(VkQueueFlags queueFlags, const std::vector< std::string > &queuesNames)
Definition: Device.cpp:23
bool build(API::Device &device, VkResult *returnResult=nullptr)
Definition: Device.cpp:49
Device(const PhysicalDeviceInfo &physicalDeviceInfo)
Definition: Device.cpp:14
#define LUG_LOG
Definition: Logger.hpp:73
std::vector< QueueFamily > _queueFamilies
Definition: Device.hpp:58
std::vector< const char * > _extensions
Definition: Device.hpp:56
const PhysicalDeviceInfo & _physicalDeviceInfo
Definition: Device.hpp:53