Chronos 0.0
A advanced 2D rendering and animation system
Loading...
Searching...
No Matches
device.cpp
Go to the documentation of this file.
1/*
2Copyright (c) 2024 Rahul Satish Vadhyar
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20SOFTWARE.
21*/
22
23#include <set>
24#include "logging.hpp"
25#include "helper.hpp"
26#include "swapchain.hpp"
27
28void Chronos::Engine::Device::init(VkInstance instance, VkSurfaceKHR surface)
29{
30 pickPhysicalDevice(instance, surface);
31 LOG(3, "Physical device picked")
32 createLogicalDevice(surface);
33 LOG(3, "Logical device created")
34}
35
36void Chronos::Engine::Device::destroy() { vkDestroyDevice(device, nullptr); }
37
47static inline bool checkDeviceExtensionSupport(VkPhysicalDevice device)
48{
49 uint32_t extensionCount;
50 vkEnumerateDeviceExtensionProperties(
51 device, nullptr, &extensionCount, nullptr);
52
53 std::vector<VkExtensionProperties> availableExtensions(extensionCount);
54 vkEnumerateDeviceExtensionProperties(
55 device, nullptr, &extensionCount, availableExtensions.data());
56
57 std::set<std::string> requiredExtensions(
60
61 for (const auto& extension : availableExtensions) {
62 requiredExtensions.erase(extension.extensionName);
63 }
64
65 return requiredExtensions.empty();
66}
67
81static inline bool isDeviceSuitable(
82 VkPhysicalDevice device, VkSurfaceKHR surface)
83{
84 // check if the device has the required queue families
86 = Chronos::Engine::findQueueFamilies(device, surface);
87 bool extensionsSupported = checkDeviceExtensionSupport(device);
88
89 bool swapChainAdequate = false;
90 if (extensionsSupported) {
93 swapChainAdequate = !swapChainSupport.formats.empty()
94 && !swapChainSupport.presentModes.empty();
95 }
96
97 VkPhysicalDeviceFeatures supportedFeatures;
98 vkGetPhysicalDeviceFeatures(device, &supportedFeatures);
99 return indices.isComplete() && extensionsSupported && swapChainAdequate
100 && supportedFeatures.samplerAnisotropy;
101}
102
113VkSampleCountFlagBits getMaxUsableSampleCount(VkPhysicalDevice physicalDevice)
114{
115 // used to get max MSAA count
116 VkPhysicalDeviceProperties physicalDeviceProperties;
117 vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
118
119 VkSampleCountFlags counts
120 = physicalDeviceProperties.limits.framebufferColorSampleCounts;
121 if (counts & VK_SAMPLE_COUNT_64_BIT) {
122 return VK_SAMPLE_COUNT_64_BIT;
123 }
124 if (counts & VK_SAMPLE_COUNT_32_BIT) {
125 return VK_SAMPLE_COUNT_32_BIT;
126 }
127 if (counts & VK_SAMPLE_COUNT_16_BIT) {
128 return VK_SAMPLE_COUNT_16_BIT;
129 }
130 if (counts & VK_SAMPLE_COUNT_8_BIT) {
131 return VK_SAMPLE_COUNT_8_BIT;
132 }
133 if (counts & VK_SAMPLE_COUNT_4_BIT) {
134 return VK_SAMPLE_COUNT_4_BIT;
135 }
136 if (counts & VK_SAMPLE_COUNT_2_BIT) {
137 return VK_SAMPLE_COUNT_2_BIT;
138 }
139 return VK_SAMPLE_COUNT_1_BIT;
140}
141
143 VkInstance instance, VkSurfaceKHR surface)
144{
145 // get the number of devices
146 uint32_t deviceCount = 0;
147 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
148 if (deviceCount == 0) {
149 LOG(1, "Failed to find GPUs with Vulkan support")
150 throw std::runtime_error("Failed to find GPUs with Vulkan support");
151 }
152 LOG(3, "Number of devices found: " + std::to_string(deviceCount))
153 std::vector<VkPhysicalDevice> devices(deviceCount);
154 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
155
156 // check if the device is suitable
157 for (const auto& device : devices) {
158 if (isDeviceSuitable(device, surface)) {
159 physicalDevice = device;
160 maxMsaaSamples = getMaxUsableSampleCount(device);
161 break;
162 }
163 }
164 if (physicalDevice == VK_NULL_HANDLE) {
165 LOG(1, "Failed to find a suitable GPU")
166 throw std::runtime_error("Failed to find a suitable GPU");
167 }
168#ifdef CHRONOS_ENABLE_LOGGING
169 VkPhysicalDeviceProperties deviceProperties;
170 vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
171 LOG(3, "****PHYSICAL DEVICE INFORMATION*****")
172 LOG(3,
173 "Physical device picked: " + std::string(deviceProperties.deviceName))
174 LOG(3, "Driver version: " + std::to_string(deviceProperties.driverVersion))
175 LOG(3, "API version: " + std::to_string(deviceProperties.apiVersion))
176 LOG(3, "Device ID: " + std::to_string(deviceProperties.deviceID))
177 LOG(3, "Vendor ID: " + std::to_string(deviceProperties.vendorID))
178 LOG(3, "MSAA samples: " + std::to_string(msaaSamples))
179#endif
180}
181
183{
184 QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface);
185
186 std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
187 std::set<uint32_t> uniqueQueueFamilies
188 = { indices.graphicsFamily.value(), indices.presentFamily.value() };
189
190 float queuePriority = 1.0f;
191 for (uint32_t queueFamily : uniqueQueueFamilies) {
192 VkDeviceQueueCreateInfo queueCreateInfo {};
193 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
194 queueCreateInfo.queueFamilyIndex = queueFamily;
195 queueCreateInfo.queueCount = 1;
196 queueCreateInfo.pQueuePriorities = &queuePriority;
197 queueCreateInfos.push_back(queueCreateInfo);
198 }
199
200 VkPhysicalDeviceFeatures deviceFeatures {};
201 deviceFeatures.samplerAnisotropy = VK_TRUE;
202 deviceFeatures.sampleRateShading = VK_TRUE;
203
204 VkDeviceCreateInfo createInfo {};
205 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
206 createInfo.pQueueCreateInfos = queueCreateInfos.data();
207 createInfo.queueCreateInfoCount
208 = static_cast<uint32_t>(queueCreateInfos.size());
209 createInfo.pEnabledFeatures = &deviceFeatures;
210 createInfo.enabledExtensionCount
211 = static_cast<uint32_t>(deviceExtensions.size());
212 createInfo.ppEnabledExtensionNames = deviceExtensions.data();
213 createInfo.enabledLayerCount = 0;
214#ifdef ENABLE_VALIDATION_LAYERS
215 createInfo.enabledLayerCount
216 = static_cast<uint32_t>(validationLayers.size());
217 createInfo.ppEnabledLayerNames = validationLayers.data();
218#endif
219
220 if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device)
221 != VK_SUCCESS) {
222 LOG(1, "Failed to create logical device")
223 throw std::runtime_error("Failed to create logical device");
224 }
225
226 LOG(3, "Logical device created")
227 // get the queue handle
228 vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
229 vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
230}
void destroy()
This is the function that destroys the device.
Definition device.cpp:36
void pickPhysicalDevice(VkInstance instance, VkSurfaceKHR surface)
This is the function that picks the best device based on the requirements and features that we requir...
Definition device.cpp:142
void init(VkInstance instance, VkSurfaceKHR surface)
This is the function that initializes the devices and queues.
Definition device.cpp:28
void createLogicalDevice(VkSurfaceKHR surface)
This creates the logical device.
Definition device.cpp:182
static bool isDeviceSuitable(VkPhysicalDevice device, VkSurfaceKHR surface)
Checks if the physical device that we provide it is suitable for our needs.
Definition device.cpp:81
VkSampleCountFlagBits getMaxUsableSampleCount(VkPhysicalDevice physicalDevice)
Gets the maxmimum supported MSAA sample count.
Definition device.cpp:113
static bool checkDeviceExtensionSupport(VkPhysicalDevice device)
Checks if the physical device that we provide it supports the extestions we need. This is used to che...
Definition device.cpp:47
Contains various common functions used by other classes in the Engine namespace.
#define LOG(LEVEL, MESSAGE)
Definition logging.hpp:60
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR surface)
For a given swapchain mode, it gets the capabilites, formats and present modes.
Definition swapchain.cpp:65
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface)
Gets the indices of the needed queue families.
Definition helper.cpp:126
const std::vector< const char * > deviceExtensions
THis contain the device extensions that are needed to be enabled in vulkan.
Definition device.hpp:37
This is used to check if a given familty supports graphics and presentation.
Definition helper.hpp:44
std::optional< uint32_t > presentFamily
Definition helper.hpp:46
std::optional< uint32_t > graphicsFamily
Definition helper.hpp:45
Contains the fields to the support details of a physical device.
Definition swapchain.hpp:36
std::vector< VkSurfaceFormatKHR > formats
Definition swapchain.hpp:38
std::vector< VkPresentModeKHR > presentModes
Definition swapchain.hpp:39
Contains the swapChain class along with all the swapChain related functions.