source: opengl-game/vulkan-game.cpp@ 909b51a

feature/imgui-sdl points-test
Last change on this file since 909b51a was 909b51a, checked in by Dmitry Portnoy <dmitry.portnoy@…>, 6 years ago

Select a physical device and create a logical device for it

  • Property mode set to 100644
File size: 12.7 KB
RevLine 
[826df16]1#include <vulkan/vulkan.h>
[03f4c64]2
[826df16]3#include <SDL2/SDL.h>
4#include <SDL2/SDL_vulkan.h>
5
6//#define _USE_MATH_DEFINES // Will be needed when/if I need to # include <cmath>
[03f4c64]7
8#define GLM_FORCE_RADIANS
9#define GLM_FORCE_DEPTH_ZERO_TO_ONE
10#include <glm/vec4.hpp>
11#include <glm/mat4x4.hpp>
12
13#include <iostream>
[826df16]14#include <vector>
15#include <stdexcept>
16#include <cstdlib>
[909b51a]17#include <optional>
[826df16]18
19#include "game-gui-sdl.hpp"
[03f4c64]20
21using namespace std;
22using namespace glm;
23
[826df16]24const int SCREEN_WIDTH = 800;
25const int SCREEN_HEIGHT = 600;
26
27const vector<const char*> validationLayers = {
28 "VK_LAYER_KHRONOS_validation"
29};
30
31#ifdef NDEBUG
32 const bool enableValidationLayers = false;
33#else
34 const bool enableValidationLayers = true;
35#endif
36
[909b51a]37struct QueueFamilyIndices {
38 optional<uint32_t> graphicsFamily;
39
40 bool isComplete() {
41 return graphicsFamily.has_value();
42 }
43};
44
[b6127d2]45static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
46 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
47 VkDebugUtilsMessageTypeFlagsEXT messageType,
48 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
49 void* pUserData) {
50 cerr << "validation layer: " << pCallbackData->pMessage << endl;
51
52 return VK_FALSE;
53}
54
55VkResult CreateDebugUtilsMessengerEXT(VkInstance instance,
56 const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
57 const VkAllocationCallbacks* pAllocator,
58 VkDebugUtilsMessengerEXT* pDebugMessenger) {
59 auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(
60 instance, "vkCreateDebugUtilsMessengerEXT");
61
62 if (func != nullptr) {
63 return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
64 } else {
65 return VK_ERROR_EXTENSION_NOT_PRESENT;
66 }
67}
68
[80de39d]69void DestroyDebugUtilsMessengerEXT(VkInstance instance,
70 VkDebugUtilsMessengerEXT debugMessenger,
71 const VkAllocationCallbacks* pAllocator) {
72 auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(
73 instance, "vkDestroyDebugUtilsMessengerEXT");
74
75 if (func != nullptr) {
76 func(instance, debugMessenger, pAllocator);
77 }
78}
79
[826df16]80class VulkanGame {
81 public:
82 void run() {
83 if (initWindow() == RTWO_ERROR) {
84 return;
85 }
86 initVulkan();
87 mainLoop();
88 cleanup();
89 }
90 private:
91 GameGui_SDL gui;
[80de39d]92 SDL_Window* window = nullptr;
[826df16]93
94 VkInstance instance;
[b6127d2]95 VkDebugUtilsMessengerEXT debugMessenger;
[909b51a]96 VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
97 VkDevice device;
98 VkQueue graphicsQueue;
[826df16]99
100 // both SDL and GLFW create window functions return NULL on failure
101 bool initWindow() {
102 if (gui.Init() == RTWO_ERROR) {
103 cout << "UI library could not be initialized!" << endl;
104 return RTWO_ERROR;
105 } else {
106 // On Apple's OS X you must set the NSHighResolutionCapable Info.plist property to YES,
107 // otherwise you will not receive a High DPI OpenGL canvas.
108
109 // TODO: Move this into some generic method in game-gui-sdl
110 window = SDL_CreateWindow("Vulkan Game",
111 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
112 SCREEN_WIDTH, SCREEN_HEIGHT,
113 SDL_WINDOW_VULKAN | SDL_WINDOW_SHOWN);
114
[80de39d]115 if (window == nullptr) {
[826df16]116 cout << "Window could not be created!" << endl;
117 return RTWO_ERROR;
118 } else {
119 return RTWO_SUCCESS;
120 }
121 }
122 }
123
124 void initVulkan() {
125 createInstance();
[7dcd925]126 setupDebugMessenger();
[909b51a]127 pickPhysicalDevice();
128 createLogicalDevice();
[826df16]129 }
130
131 void createInstance() {
[b6127d2]132 if (enableValidationLayers && !checkValidationLayerSupport()) {
133 throw runtime_error("validation layers requested, but not available!");
134 }
135
[826df16]136 VkApplicationInfo appInfo = {};
137 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
138 appInfo.pApplicationName = "Vulkan Game";
139 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
140 appInfo.pEngineName = "No Engine";
141 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
142 appInfo.apiVersion = VK_API_VERSION_1_0;
143
144 VkInstanceCreateInfo createInfo = {};
145 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
146 createInfo.pApplicationInfo = &appInfo;
147
[a8f0577]148 vector<const char*> extensions = getRequiredExtensions();
[b6127d2]149 createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
150 createInfo.ppEnabledExtensionNames = extensions.data();
[826df16]151
[80de39d]152 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
[b6127d2]153 if (enableValidationLayers) {
154 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
155 createInfo.ppEnabledLayerNames = validationLayers.data();
[80de39d]156
157 populateDebugMessengerCreateInfo(debugCreateInfo);
158 createInfo.pNext = &debugCreateInfo;
[b6127d2]159 } else {
160 createInfo.enabledLayerCount = 0;
[80de39d]161
162 createInfo.pNext = nullptr;
[b6127d2]163 }
[826df16]164
165 if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
166 throw runtime_error("failed to create instance!");
167 }
168 }
169
[80de39d]170 void setupDebugMessenger() {
171 if (!enableValidationLayers) return;
172
173 VkDebugUtilsMessengerCreateInfoEXT createInfo;
174 populateDebugMessengerCreateInfo(createInfo);
[b6127d2]175
176 if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
177 throw runtime_error("failed to setup debug messenger!");
178 }
179 }
180
[909b51a]181 void pickPhysicalDevice() {
182 uint32_t deviceCount = 0;
183 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
184
185 if (deviceCount == 0) {
186 throw runtime_error("failed to find GPUs with Vulkan support!");
187 }
188
189 vector<VkPhysicalDevice> devices(deviceCount);
190 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
191
192 cout << endl << "Graphics cards:" << endl;
193 for (const VkPhysicalDevice& device : devices) {
194 if (isDeviceSuitable(device)) {
195 physicalDevice = device;
196 break;
197 }
198 }
199 cout << endl;
200
201 if (physicalDevice == VK_NULL_HANDLE) {
202 throw runtime_error("failed to find a suitable GPU!");
203 }
204 }
205
206 bool isDeviceSuitable(VkPhysicalDevice device) {
207 VkPhysicalDeviceProperties deviceProperties;
208 VkPhysicalDeviceFeatures deviceFeatures;
209
210 vkGetPhysicalDeviceProperties(device, &deviceProperties);
211 vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
212
213 cout << "Device: " << deviceProperties.deviceName << endl;
214
215 QueueFamilyIndices indices = findQueueFamilies(device);
216
217 return indices.isComplete();
218 }
219
220 void createLogicalDevice() {
221 QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
222
223 VkDeviceQueueCreateInfo queueCreateInfo = {};
224 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
225 queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value();
226 queueCreateInfo.queueCount = 1;
227
228 float queuePriority = 1.0f;
229 queueCreateInfo.pQueuePriorities = &queuePriority;
230
231 VkPhysicalDeviceFeatures deviceFeatures = {};
232
233 VkDeviceCreateInfo createInfo = {};
234 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
235
236 createInfo.pQueueCreateInfos = &queueCreateInfo;
237 createInfo.queueCreateInfoCount = 1;
238
239 createInfo.pEnabledFeatures = &deviceFeatures;
240
241 createInfo.enabledExtensionCount = 0;
242
243 // These fields are ignored by up-to-date Vulkan implementations,
244 // but it's a good idea to set them for backwards compatibility
245 if (enableValidationLayers) {
246 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
247 createInfo.ppEnabledLayerNames = validationLayers.data();
248 } else {
249 createInfo.enabledLayerCount = 0;
250 }
251
252 if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
253 throw runtime_error("failed to create logical device!");
254 }
255
256 vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
257 }
258
[a8f0577]259 bool checkValidationLayerSupport() {
260 uint32_t layerCount;
261 vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
262
263 vector<VkLayerProperties> availableLayers(layerCount);
264 vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
265
266 for (const char* layerName : validationLayers) {
267 bool layerFound = false;
268
269 for (const auto& layerProperties : availableLayers) {
270 if (strcmp(layerName, layerProperties.layerName) == 0) {
271 layerFound = true;
272 break;
273 }
274 }
275
276 if (!layerFound) {
277 return false;
278 }
279 }
280
281 return true;
282 }
283
[909b51a]284 QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
285 QueueFamilyIndices indices;
286
287 uint32_t queueFamilyCount = 0;
288 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
289
290 vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
291 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
292
293 int i = 0;
294 for (const auto& queueFamily : queueFamilies) {
295 if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
296 indices.graphicsFamily = i;
297 }
298
299 if (indices.isComplete()) {
300 break;
301 }
302
303 i++;
304 }
305
306 return indices;
307 }
308
309 void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
310 createInfo = {};
311 createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
312 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;
313 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;
314 createInfo.pfnUserCallback = debugCallback;
315 }
316
[a8f0577]317 vector<const char*> getRequiredExtensions() {
318 uint32_t extensionCount = 0;
319 SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, nullptr);
320
321 vector<const char*> extensions(extensionCount);
322 SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, extensions.data());
323
324 if (enableValidationLayers) {
325 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
326 }
327
328 return extensions;
329 }
330
[826df16]331 void mainLoop() {
332 // TODO: Create some generic event-handling functions in game-gui-*
333 SDL_Event e;
334 bool quit = false;
335
336 /*
337 SDL_Surface* screenSurface = nullptr;
338 VkSurfaceKHR surface;
339
340 if (!SDL_Vulkan_CreateSurface(window, instance, &surface)) {
341 cout << "Couild not create Vulkan surface" << endl;
342 }
343
344 screenSurface = SDL_GetWindowSurface(window);
345 cout << "Got here" << endl;
346 cout << (screenSurface == nullptr ? "true" : "false") << endl;
[03f4c64]347
[826df16]348 SDL_FillRect(screenSurface, nullptr, SDL_MapRGB(screenSurface->format, 0xFF, 0xFF, 0xFF));
349 cout << "Filled" << endl;
350
351 SDL_UpdateWindowSurface(window);
352 cout << "Updated" << endl;
353 */
354
[7dcd925]355 while (!quit) {
[826df16]356 while (SDL_PollEvent(&e)) {
357 if (e.type == SDL_QUIT) {
358 quit = true;
359 }
360 if (e.type == SDL_KEYDOWN) {
361 quit = true;
362 }
363 if (e.type == SDL_MOUSEBUTTONDOWN) {
364 quit = true;
365 }
366 }
367 }
368 }
369
370 void cleanup() {
[909b51a]371 vkDestroyDevice(device, nullptr);
372
[80de39d]373 if (enableValidationLayers) {
374 DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
375 }
376
[826df16]377 vkDestroyInstance(instance, nullptr);
378
379 // TODO: Move this into some generic method in game-gui-sdl
380 SDL_DestroyWindow(window);
381
382 gui.Shutdown();
383 }
384};
385
[b6127d2]386int main() {
[826df16]387
[b6127d2]388#ifdef NDEBUG
389 cout << "DEBUGGING IS OFF" << endl;
390#else
391 cout << "DEBUGGING IS ON" << endl;
392#endif
[a8f0577]393
[826df16]394 /*
395 mat4 matrix;
396 vec4 vec;
397 vec4 test = matrix * vec;
398 */
399
400 cout << "Starting Vulkan game..." << endl;
401
402 VulkanGame game;
403
404 try {
405 game.run();
406 } catch (const exception& e) {
407 cerr << e.what() << endl;
408 return EXIT_FAILURE;
409 }
[03f4c64]410
[826df16]411 cout << "Finished running the game" << endl;
[03f4c64]412
[826df16]413 return EXIT_SUCCESS;
[03f4c64]414}
Note: See TracBrowser for help on using the repository browser.