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

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

Add renderScene and renderUI functions to vulkangame

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