source: opengl-game/vulkan-game.cpp@ c1c2021

feature/imgui-sdl points-test
Last change on this file since c1c2021 was c1c2021, checked in by Dmitry Portnoy <dmp1488@…>, 5 years ago

In vulkangame, add code to create a logical device

  • Property mode set to 100644
File size: 11.6 KB
RevLine 
[99d44b2]1#include "vulkan-game.hpp"
[850e84c]2
[0df3c9a]3#include <iostream>
[c1c2021]4#include <set>
[0df3c9a]5
[5edbd58]6#include "consts.hpp"
[c559904]7#include "logger.hpp"
[5edbd58]8
[c1d9b2a]9#include "vulkan-utils.hpp"
10
[0df3c9a]11using namespace std;
12
[99d44b2]13VulkanGame::VulkanGame() {
[0df3c9a]14 gui = nullptr;
15 window = nullptr;
16}
17
[99d44b2]18VulkanGame::~VulkanGame() {
[0df3c9a]19}
20
[b6e60b4]21void VulkanGame::run(int width, int height, unsigned char guiFlags) {
[2e77b3f]22 cout << "DEBUGGING IS " << (ENABLE_VALIDATION_LAYERS ? "ON" : "OFF") << endl;
23
24 cout << "Vulkan Game" << endl;
25
[c559904]26 // This gets the runtime version, use SDL_VERSION() for the comppile-time version
27 // TODO: Create a game-gui function to get the gui version and retrieve it that way
28 SDL_GetVersion(&sdlVersion);
29
30 // TODO: Refactor the logger api to be more flexible,
31 // esp. since gl_log() and gl_log_err() have issues printing anything besides stirngs
32 restart_gl_log();
33 gl_log("starting SDL\n%s.%s.%s",
34 to_string(sdlVersion.major).c_str(),
35 to_string(sdlVersion.minor).c_str(),
36 to_string(sdlVersion.patch).c_str());
37
38 open_log();
39 get_log() << "starting SDL" << endl;
40 get_log() <<
41 (int)sdlVersion.major << "." <<
42 (int)sdlVersion.minor << "." <<
43 (int)sdlVersion.patch << endl;
44
[5edbd58]45 if (initWindow(width, height, guiFlags) == RTWO_ERROR) {
[0df3c9a]46 return;
47 }
[b6e60b4]48
[0df3c9a]49 initVulkan();
50 mainLoop();
51 cleanup();
[c559904]52
53 close_log();
[0df3c9a]54}
55
[c559904]56// TODO: Make some more initi functions, or call this initUI if the
57// amount of things initialized here keeps growing
[b6e60b4]58bool VulkanGame::initWindow(int width, int height, unsigned char guiFlags) {
[c559904]59 // TODO: Put all fonts, textures, and images in the assets folder
[0df3c9a]60 gui = new GameGui_SDL();
61
[b6e60b4]62 if (gui->init() == RTWO_ERROR) {
[c559904]63 // TODO: Also print these sorts of errors to the log
[0df3c9a]64 cout << "UI library could not be initialized!" << endl;
[b6e60b4]65 cout << gui->getError() << endl;
[0df3c9a]66 return RTWO_ERROR;
67 }
68
[b6e60b4]69 window = (SDL_Window*) gui->createWindow("Vulkan Game", width, height, guiFlags & GUI_FLAGS_WINDOW_FULLSCREEN);
[0df3c9a]70 if (window == nullptr) {
71 cout << "Window could not be created!" << endl;
[ed7c953]72 cout << gui->getError() << endl;
[0df3c9a]73 return RTWO_ERROR;
74 }
75
[b6e60b4]76 cout << "Target window size: (" << width << ", " << height << ")" << endl;
[a6f6833]77 cout << "Actual window size: (" << gui->getWindowWidth() << ", " << gui->getWindowHeight() << ")" << endl;
[b6e60b4]78
[c1d9b2a]79 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
80 if (renderer == nullptr) {
81 cout << "Renderer could not be created!" << endl;
82 cout << gui->getError() << endl;
83 return RTWO_ERROR;
84 }
85
[0df3c9a]86 return RTWO_SUCCESS;
87}
88
[99d44b2]89void VulkanGame::initVulkan() {
[c1d9b2a]90 const vector<const char*> validationLayers = {
91 "VK_LAYER_KHRONOS_validation"
92 };
[fe5c3ba]93 const vector<const char*> deviceExtensions = {
94 VK_KHR_SWAPCHAIN_EXTENSION_NAME
95 };
[c1d9b2a]96
97 createVulkanInstance(validationLayers);
98 setupDebugMessenger();
[90a424f]99 createVulkanSurface();
[fe5c3ba]100 pickPhysicalDevice(deviceExtensions);
[c1c2021]101 createLogicalDevice(validationLayers, deviceExtensions);
[0df3c9a]102}
103
[99d44b2]104void VulkanGame::mainLoop() {
[f6521fb]105 UIEvent e;
[0df3c9a]106 bool quit = false;
107
[c1d9b2a]108 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
109
[0df3c9a]110 while (!quit) {
[27c40ce]111 gui->processEvents();
112
[f6521fb]113 while (gui->pollEvent(&e)) {
114 switch(e.type) {
115 case UI_EVENT_QUIT:
116 cout << "Quit event detected" << endl;
117 quit = true;
118 break;
119 case UI_EVENT_WINDOW:
120 cout << "Window event detected" << endl;
121 // Currently unused
122 break;
123 case UI_EVENT_KEY:
124 if (e.key.keycode == SDL_SCANCODE_ESCAPE) {
125 quit = true;
126 } else {
127 cout << "Key event detected" << endl;
128 }
129 break;
130 case UI_EVENT_MOUSEBUTTONDOWN:
131 cout << "Mouse button down event detected" << endl;
132 break;
133 case UI_EVENT_MOUSEBUTTONUP:
134 cout << "Mouse button up event detected" << endl;
135 break;
136 case UI_EVENT_MOUSEMOTION:
137 break;
[c61323a]138 default:
139 cout << "Unhandled UI event: " << e.type << endl;
[0df3c9a]140 }
141 }
[c1d9b2a]142
[a0c5f28]143 renderUI();
144 renderScene();
[0df3c9a]145 }
[c1c2021]146
147 vkDeviceWaitIdle(device);
[0df3c9a]148}
149
[a0c5f28]150void VulkanGame::renderUI() {
151 SDL_RenderClear(renderer);
152 SDL_RenderPresent(renderer);
153}
154
155void VulkanGame::renderScene() {
156}
157
[99d44b2]158void VulkanGame::cleanup() {
[c1c2021]159 cleanupSwapChain();
160
161 vkDestroyDevice(device, nullptr);
162 vkDestroySurfaceKHR(instance, surface, nullptr);
163
[c1d9b2a]164 if (ENABLE_VALIDATION_LAYERS) {
165 VulkanUtils::destroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
166 }
[c1c2021]167
[c1d9b2a]168 vkDestroyInstance(instance, nullptr);
169
170 SDL_DestroyRenderer(renderer);
171 renderer = nullptr;
172
[b6e60b4]173 gui->destroyWindow();
174 gui->shutdown();
[0df3c9a]175 delete gui;
[c1d9b2a]176}
177
[c1c2021]178void VulkanGame::cleanupSwapChain() {
179}
180
[c1d9b2a]181void VulkanGame::createVulkanInstance(const vector<const char*> &validationLayers) {
182 if (ENABLE_VALIDATION_LAYERS && !VulkanUtils::checkValidationLayerSupport(validationLayers)) {
183 throw runtime_error("validation layers requested, but not available!");
184 }
185
186 VkApplicationInfo appInfo = {};
187 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
188 appInfo.pApplicationName = "Vulkan Game";
189 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
190 appInfo.pEngineName = "No Engine";
191 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
192 appInfo.apiVersion = VK_API_VERSION_1_0;
193
194 VkInstanceCreateInfo createInfo = {};
195 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
196 createInfo.pApplicationInfo = &appInfo;
197
198 vector<const char*> extensions = gui->getRequiredExtensions();
199 if (ENABLE_VALIDATION_LAYERS) {
200 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
201 }
202
203 createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
204 createInfo.ppEnabledExtensionNames = extensions.data();
205
206 cout << endl << "Extensions:" << endl;
207 for (const char* extensionName : extensions) {
208 cout << extensionName << endl;
209 }
210 cout << endl;
211
212 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
213 if (ENABLE_VALIDATION_LAYERS) {
214 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
215 createInfo.ppEnabledLayerNames = validationLayers.data();
216
217 populateDebugMessengerCreateInfo(debugCreateInfo);
218 createInfo.pNext = &debugCreateInfo;
219 } else {
220 createInfo.enabledLayerCount = 0;
221
222 createInfo.pNext = nullptr;
223 }
224
225 if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
226 throw runtime_error("failed to create instance!");
227 }
228}
229
230void VulkanGame::setupDebugMessenger() {
231 if (!ENABLE_VALIDATION_LAYERS) return;
232
233 VkDebugUtilsMessengerCreateInfoEXT createInfo;
234 populateDebugMessengerCreateInfo(createInfo);
235
236 if (VulkanUtils::createDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
237 throw runtime_error("failed to set up debug messenger!");
238 }
239}
240
241void VulkanGame::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
242 createInfo = {};
243 createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
244 createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
245 createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
246 createInfo.pfnUserCallback = debugCallback;
247}
248
249VKAPI_ATTR VkBool32 VKAPI_CALL VulkanGame::debugCallback(
250 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
251 VkDebugUtilsMessageTypeFlagsEXT messageType,
252 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
253 void* pUserData) {
254 cerr << "validation layer: " << pCallbackData->pMessage << endl;
255
256 return VK_FALSE;
257}
[90a424f]258
259void VulkanGame::createVulkanSurface() {
260 if (gui->createVulkanSurface(instance, &surface) == RTWO_ERROR) {
261 throw runtime_error("failed to create window surface!");
262 }
263}
264
[fe5c3ba]265void VulkanGame::pickPhysicalDevice(const vector<const char*>& deviceExtensions) {
[90a424f]266 uint32_t deviceCount = 0;
267 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
268
269 if (deviceCount == 0) {
270 throw runtime_error("failed to find GPUs with Vulkan support!");
271 }
272
273 vector<VkPhysicalDevice> devices(deviceCount);
274 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
275
276 cout << endl << "Graphics cards:" << endl;
277 for (const VkPhysicalDevice& device : devices) {
[fe5c3ba]278 if (isDeviceSuitable(device, deviceExtensions)) {
[90a424f]279 physicalDevice = device;
280 break;
281 }
282 }
283 cout << endl;
284
285 if (physicalDevice == VK_NULL_HANDLE) {
286 throw runtime_error("failed to find a suitable GPU!");
287 }
288}
289
[fe5c3ba]290bool VulkanGame::isDeviceSuitable(VkPhysicalDevice device, const vector<const char*>& deviceExtensions) {
[90a424f]291 VkPhysicalDeviceProperties deviceProperties;
292 vkGetPhysicalDeviceProperties(device, &deviceProperties);
293
294 cout << "Device: " << deviceProperties.deviceName << endl;
295
296 QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(device, surface);
297 bool extensionsSupported = VulkanUtils::checkDeviceExtensionSupport(device, deviceExtensions);
298 bool swapChainAdequate = false;
299
300 if (extensionsSupported) {
301 SwapChainSupportDetails swapChainSupport = VulkanUtils::querySwapChainSupport(device, surface);
302 swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
303 }
304
305 VkPhysicalDeviceFeatures supportedFeatures;
306 vkGetPhysicalDeviceFeatures(device, &supportedFeatures);
307
308 return indices.isComplete() && extensionsSupported && swapChainAdequate && supportedFeatures.samplerAnisotropy;
[c1c2021]309}
310
311void VulkanGame::createLogicalDevice(
312 const vector<const char*> validationLayers,
313 const vector<const char*>& deviceExtensions) {
314 QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
315
316 vector<VkDeviceQueueCreateInfo> queueCreateInfos;
317 set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
318
319 float queuePriority = 1.0f;
320 for (uint32_t queueFamily : uniqueQueueFamilies) {
321 VkDeviceQueueCreateInfo queueCreateInfo = {};
322 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
323 queueCreateInfo.queueFamilyIndex = queueFamily;
324 queueCreateInfo.queueCount = 1;
325 queueCreateInfo.pQueuePriorities = &queuePriority;
326
327 queueCreateInfos.push_back(queueCreateInfo);
328 }
329
330 VkPhysicalDeviceFeatures deviceFeatures = {};
331 deviceFeatures.samplerAnisotropy = VK_TRUE;
332
333 VkDeviceCreateInfo createInfo = {};
334 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
335 createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
336 createInfo.pQueueCreateInfos = queueCreateInfos.data();
337
338 createInfo.pEnabledFeatures = &deviceFeatures;
339
340 createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
341 createInfo.ppEnabledExtensionNames = deviceExtensions.data();
342
343 // These fields are ignored by up-to-date Vulkan implementations,
344 // but it's a good idea to set them for backwards compatibility
345 if (ENABLE_VALIDATION_LAYERS) {
346 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
347 createInfo.ppEnabledLayerNames = validationLayers.data();
348 } else {
349 createInfo.enabledLayerCount = 0;
350 }
351
352 if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
353 throw runtime_error("failed to create logical device!");
354 }
355
356 vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
357 vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
[90a424f]358}
Note: See TracBrowser for help on using the repository browser.