Vulkan Engine 0.0
A simple Vulkan engine demo
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
engine_device.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "defines.hpp"
4#include "engine_window.hpp"
5#include "libs/imgui/imgui_impl_vulkan.h"
6#include <memory>
7#include <numeric>
8#define VMA_IMPLEMENTATION
9#include "libs/vk_mem_alloc.h"
10
11#include <iostream>
12#include <cstring>
13#include <string>
14#include <vector>
15#include <set>
16#include <unordered_set>
17#include <vulkan/vulkan_core.h>
18
19#define STB_IMAGE_IMPLEMENTATION
20#include "libs/stb_image.h"
21
23 VkSurfaceCapabilitiesKHR capabilities;
24 std::vector<VkSurfaceFormatKHR> formats;
25 std::vector<VkPresentModeKHR> presentModes;
26};
27
30 uint32_t presentFamily;
34};
35
36// local callback functions
37static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
38 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
39 VkDebugUtilsMessageTypeFlagsEXT message_type,
40 const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data,
41 void *p_user_data
42) {
43 std::cerr << "validation layer: " << p_callback_data->pMessage << std::endl;
44 return VK_FALSE;
45}
46
48 VkInstance instance,
49 const VkDebugUtilsMessengerCreateInfoEXT *p_create_info,
50 const VkAllocationCallbacks *p_allocator,
51 VkDebugUtilsMessengerEXT *p_debug_messenger
52) {
53 auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
54 instance,
55 "vkCreateDebugUtilsMessengerEXT");
56 if (func != nullptr) {
57 return func(instance, p_create_info, p_allocator, p_debug_messenger);
58 } else {
59 return VK_ERROR_EXTENSION_NOT_PRESENT;
60 }
61}
62
64 VkInstance instance,
65 VkDebugUtilsMessengerEXT debug_messenger,
66 const VkAllocationCallbacks *p_allocator
67) {
68 auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
69 instance,
70 "vkDestroyDebugUtilsMessengerEXT");
71 if (func != nullptr) {
72 func(instance, debug_messenger, p_allocator);
73 }
74}
75
76#define ENGINE_API_VERSION VK_API_VERSION_1_2
77#define MISSING_TEXTURE_PATH (ASSETS_DIR+"/assets/missing_texture.png")
78
80 bool missing = false;
81 std::string cache_key = "";
82 std::string path = "";
83 VkImage image;
84 VmaAllocation allocation;
85 VkImageView image_view;
86 VkSampler sampler;
87
88 VkDevice &device;
89 VmaAllocator &allocator;
90
91 TextureData(VkDevice &device, VmaAllocator &allocator) : device{device}, allocator{allocator} {}
93 cleanup();
94 }
95 void cleanup() {
96 vkDestroySampler(device, sampler, nullptr);
97 vkDestroyImageView(device, image_view, nullptr);
98 vmaDestroyImage(allocator, image, allocation);
99 }
100
101 TextureData(const TextureData&) = delete;
103};
104
110private:
111 void init_vma() {
112 VmaAllocatorCreateInfo allocator_info = {};
113 allocator_info.vulkanApiVersion = ENGINE_API_VERSION;
114 allocator_info.physicalDevice = physical_device;
115 allocator_info.device = device_;
116 allocator_info.instance = instance;
117
118 vmaCreateAllocator(&allocator_info, &allocator);
119 }
120
121 void create_instance() {
122 if (enable_validation_layers && !check_validation_layer_support()) {
123 throw std::runtime_error("validation layers requested, but not available!");
124 }
125 VkApplicationInfo app_info = {};
126 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
127 app_info.pApplicationName = "GabMus Vulkan Engine App";
128 app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
129 app_info.pEngineName = "No Engine";
130 app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
131 app_info.apiVersion = ENGINE_API_VERSION;
132
133 VkInstanceCreateInfo create_info = {};
134 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
135 create_info.pApplicationInfo = &app_info;
136
137 auto extensions = get_required_extensions();
138 create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
139 create_info.ppEnabledExtensionNames = extensions.data();
140
141 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
143 create_info.enabledLayerCount = static_cast<uint32_t>(validation_layers.size());
144 create_info.ppEnabledLayerNames = validation_layers.data();
145
146 populate_debug_messenger_create_info(debugCreateInfo);
147 create_info.pNext = (VkDebugUtilsMessengerCreateInfoEXT *)&debugCreateInfo;
148 } else {
149 create_info.enabledLayerCount = 0;
150 create_info.pNext = nullptr;
151 }
152
153 if (vkCreateInstance(&create_info, nullptr, &instance) != VK_SUCCESS) {
154 throw std::runtime_error("failed to create instance!");
155 }
156
157 has_glfw_required_instance_extensions();
158 }
159 void setup_debug_messenger() {
160 if (!enable_validation_layers) return;
161 VkDebugUtilsMessengerCreateInfoEXT createInfo;
162 populate_debug_messenger_create_info(createInfo);
163 if (create_debug_utils_messenger_EXT(instance, &createInfo, nullptr, &debug_messenger) != VK_SUCCESS) {
164 throw std::runtime_error("failed to set up debug messenger!");
165 }
166 }
167 void create_surface() {
168 window.create_window_surface(instance, &surface_);
169 }
170 void pick_physical_device() {
171 uint32_t deviceCount = 0;
172 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
173 if (deviceCount == 0) {
174 throw std::runtime_error("failed to find GPUs with Vulkan support!");
175 }
176 std::cout << "Device count: " << deviceCount << std::endl;
177 std::vector<VkPhysicalDevice> devices(deviceCount);
178 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
179
180 for (const auto &device : devices) {
181 if (is_device_suitable(device)) {
182 physical_device = device;
183 break;
184 }
185 }
186
187 if (physical_device == VK_NULL_HANDLE) {
188 throw std::runtime_error("failed to find a suitable GPU!");
189 }
190
191 vkGetPhysicalDeviceProperties(physical_device, &properties);
192 minOffsetAlignment = std::lcm(
193 properties.limits.minUniformBufferOffsetAlignment,
194 properties.limits.nonCoherentAtomSize
195 );
196 std::cout << "physical device: " << properties.deviceName << std::endl;
197 }
198 void create_logical_device() {
199 QueueFamilyIndices indices = find_queue_families(physical_device);
200
201 std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
202 std::set<uint32_t> unique_queue_families = {indices.graphicsFamily, indices.presentFamily};
203
204 float queue_priority = 1.0f;
205 for (uint32_t queue_family : unique_queue_families) {
206 VkDeviceQueueCreateInfo queue_create_info = {};
207 queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
208 queue_create_info.queueFamilyIndex = queue_family;
209 queue_create_info.queueCount = 1;
210 queue_create_info.pQueuePriorities = &queue_priority;
211 queue_create_infos.push_back(queue_create_info);
212 }
213
214 VkPhysicalDeviceFeatures device_features = {};
215 device_features.samplerAnisotropy = VK_TRUE;
216 device_features.geometryShader = VK_TRUE;
217
218 VkDeviceCreateInfo create_info = {};
219 create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
220
221 create_info.queueCreateInfoCount = static_cast<uint32_t>(queue_create_infos.size());
222 create_info.pQueueCreateInfos = queue_create_infos.data();
223
224 create_info.pEnabledFeatures = &device_features;
225 create_info.enabledExtensionCount = static_cast<uint32_t>(device_extensions.size());
226 create_info.ppEnabledExtensionNames = device_extensions.data();
227
228 // might not really be necessary anymore because device specific validation layers
229 // have been deprecated
231 create_info.enabledLayerCount = static_cast<uint32_t>(validation_layers.size());
232 create_info.ppEnabledLayerNames = validation_layers.data();
233 } else {
234 create_info.enabledLayerCount = 0;
235 }
236
237 if (vkCreateDevice(physical_device, &create_info, nullptr, &device_) != VK_SUCCESS) {
238 throw std::runtime_error("failed to create logical device!");
239 }
240
241 vkGetDeviceQueue(device_, indices.graphicsFamily, 0, &graphics_queue_);
242 vkGetDeviceQueue(device_, indices.presentFamily, 0, &present_queue_);
243 }
244 void create_command_pool() {
245 QueueFamilyIndices queue_family_indices = find_physical_queue_families();
246
247 VkCommandPoolCreateInfo pool_info = {};
248 pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
249 pool_info.queueFamilyIndex = queue_family_indices.graphicsFamily;
250 pool_info.flags =
251 VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
252
253 if (vkCreateCommandPool(device_, &pool_info, nullptr, &command_pool) != VK_SUCCESS) {
254 throw std::runtime_error("failed to create command pool!");
255 }
256 }
257
258 // helper functions
259 bool is_device_suitable(VkPhysicalDevice device) {
260 QueueFamilyIndices indices = find_queue_families(device);
261
262 bool extensions_supported = check_device_extension_support(device);
263
264 bool swap_chain_adequate = false;
265 if (extensions_supported) {
266 SwapChainSupportDetails swap_chain_support = query_swap_chain_support(device);
267 swap_chain_adequate = !swap_chain_support.formats.empty() && !swap_chain_support.presentModes.empty();
268 }
269
270 VkPhysicalDeviceFeatures supported_features;
271 vkGetPhysicalDeviceFeatures(device, &supported_features);
272
273 return indices.isComplete() && extensions_supported && swap_chain_adequate &&
274 supported_features.samplerAnisotropy;
275 }
276 std::vector<const char *> get_required_extensions() {
277 uint32_t glfw_extension_count = 0;
278 const char **glfw_extensions;
279 glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
280
281 std::vector<const char *> extensions(glfw_extensions, glfw_extensions + glfw_extension_count);
282
284 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
285 }
286
287 return extensions;
288 }
289 bool check_validation_layer_support() {
290 uint32_t layer_count;
291 vkEnumerateInstanceLayerProperties(&layer_count, nullptr);
292
293 std::vector<VkLayerProperties> available_layers(layer_count);
294 vkEnumerateInstanceLayerProperties(&layer_count, available_layers.data());
295
296 for (const char *layer_name : validation_layers) {
297 bool layer_found = false;
298
299 for (const auto &layer_properties : available_layers) {
300 if (strcmp(layer_name, layer_properties.layerName) == 0) {
301 layer_found = true;
302 break;
303 }
304 }
305
306 if (!layer_found) {
307 return false;
308 }
309 }
310
311 return true;
312 }
313 QueueFamilyIndices find_queue_families(VkPhysicalDevice device) {
314 QueueFamilyIndices indices;
315
316 uint32_t queue_family_count = 0;
317 vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, nullptr);
318
319 std::vector<VkQueueFamilyProperties> queue_families(queue_family_count);
320 vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families.data());
321
322 int i = 0;
323 for (const auto &queue_family : queue_families) {
324 if (queue_family.queueCount > 0 && queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
325 indices.graphicsFamily = i;
326 indices.graphicsFamilyHasValue = true;
327 }
328 VkBool32 presentSupport = false;
329 vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface_, &presentSupport);
330 if (queue_family.queueCount > 0 && presentSupport) {
331 indices.presentFamily = i;
332 indices.presentFamilyHasValue = true;
333 }
334 if (indices.isComplete()) {
335 break;
336 }
337
338 i++;
339 }
340
341 return indices;
342 }
343 void populate_debug_messenger_create_info(VkDebugUtilsMessengerCreateInfoEXT &create_info) {
344 create_info = {};
345 create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
346 create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
347 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
348 create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
349 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
350 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
351 create_info.pfnUserCallback = debug_callback;
352 create_info.pUserData = nullptr; // Optional
353 }
354 void has_glfw_required_instance_extensions() {
355 uint32_t extension_count = 0;
356 vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);
357 std::vector<VkExtensionProperties> extensions(extension_count);
358 vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data());
359
360 // std::cout << "available extensions:" << std::endl;
361 std::unordered_set<std::string> available;
362 for (const auto &extension : extensions) {
363 // std::cout << "\t" << extension.extensionName << std::endl;
364 available.insert(extension.extensionName);
365 }
366
367 // std::cout << "required extensions:" << std::endl;
368 auto required_extensions = get_required_extensions();
369 for (const auto &required : required_extensions) {
370 // std::cout << "\t" << required << std::endl;
371 if (available.find(required) == available.end()) {
372 throw std::runtime_error("Missing required glfw extension");
373 }
374 }
375 }
376 bool check_device_extension_support(VkPhysicalDevice device) {
377 uint32_t extension_count;
378 vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr);
379
380 std::vector<VkExtensionProperties> available_extensions(extension_count);
381 vkEnumerateDeviceExtensionProperties(
382 device,
383 nullptr,
384 &extension_count,
385 available_extensions.data());
386
387 std::set<std::string> required_extensions(device_extensions.begin(), device_extensions.end());
388
389 for (const auto &extension : available_extensions) {
390 required_extensions.erase(extension.extensionName);
391 }
392
393 return required_extensions.empty();
394 }
395 SwapChainSupportDetails query_swap_chain_support(VkPhysicalDevice device) {
397 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface_, &details.capabilities);
398
399 uint32_t format_count;
400 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface_, &format_count, nullptr);
401
402 if (format_count != 0) {
403 details.formats.resize(format_count);
404 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface_, &format_count, details.formats.data());
405 }
406
407 uint32_t present_mode_count;
408 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface_, &present_mode_count, nullptr);
409
410 if (present_mode_count != 0) {
411 details.presentModes.resize(present_mode_count);
412 vkGetPhysicalDeviceSurfacePresentModesKHR(
413 device,
414 surface_,
415 &present_mode_count,
416 details.presentModes.data());
417 }
418 return details;
419 }
420
421 VmaAllocator allocator;
422
423 VkInstance instance;
424 VkDebugUtilsMessengerEXT debug_messenger;
425 VkPhysicalDevice physical_device = VK_NULL_HANDLE;
426 EngineWindow &window;
427 VkCommandPool command_pool;
428
429 VkDevice device_;
430 VkSurfaceKHR surface_;
431 VkQueue graphics_queue_;
432 VkQueue present_queue_;
433
434 const std::vector<const char *> validation_layers = {"VK_LAYER_KHRONOS_validation"};
435 const std::vector<const char *> device_extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
436
437 std::unordered_map<std::string, std::shared_ptr<TextureData>> texture_cache{};
438
439public:
440
441 std::unordered_map<std::string, std::shared_ptr<TextureData>> &get_texture_cache() {
442 return texture_cache;
443 }
444
445#ifdef DISABLE_VK_VALIDATION
446 const bool enable_validation_layers = false;
447#else
448 const bool enable_validation_layers = true;
449#endif
450 EngineDevice(EngineWindow &window) : window{window} {
451 create_instance();
452 setup_debug_messenger();
453 create_surface();
454 pick_physical_device();
455 create_logical_device();
456 init_vma();
457 create_command_pool();
459 }
461 texture_cache.clear();
462 vmaDestroyAllocator(allocator);
463 vkDestroyCommandPool(device_, command_pool, nullptr);
464 vkDestroyDevice(device_, nullptr);
467 instance, debug_messenger, nullptr
468 );
469 }
470 vkDestroySurfaceKHR(instance, surface_, nullptr);
471 vkDestroyInstance(instance, nullptr);
472 }
473
474 // RAII
475 EngineDevice(const EngineDevice &) = delete;
479
480 VkCommandPool get_command_pool() { return command_pool; }
481 VmaAllocator get_allocator() const { return allocator; }
482 VkDevice device() { return device_; }
483 VkSurfaceKHR surface() { return surface_; }
484 VkQueue graphics_queue() { return graphics_queue_; }
485 VkQueue present_queue() { return present_queue_; }
486
487 SwapChainSupportDetails get_swap_chain_support() { return query_swap_chain_support(physical_device); }
488 uint32_t find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags properties) {
489 VkPhysicalDeviceMemoryProperties mem_properties;
490 vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_properties);
491 for (uint32_t i = 0; i < mem_properties.memoryTypeCount; i++) {
492 if ((type_filter & (1 << i)) &&
493 (mem_properties.memoryTypes[i].propertyFlags & properties) == properties) {
494 return i;
495 }
496 }
497
498 throw std::runtime_error("failed to find suitable memory type!");
499 }
500 QueueFamilyIndices find_physical_queue_families() { return find_queue_families(physical_device); }
502 const std::vector<VkFormat> &candidates,
503 VkImageTiling tiling,
504 VkFormatFeatureFlags features
505 ) {
506 for (VkFormat format : candidates) {
507 VkFormatProperties props;
508 vkGetPhysicalDeviceFormatProperties(physical_device, format, &props);
509
510 if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) {
511 return format;
512 } else if (
513 tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) {
514 return format;
515 }
516 }
517 throw std::runtime_error("failed to find supported format!");
518 }
519
520 std::shared_ptr<TextureData> create_texture_image(std::string img_path) {
521 return create_texture_image(img_path, VK_FORMAT_R8G8B8A8_SRGB);
522 }
523
524 std::shared_ptr<TextureData> create_texture_image_normal(std::string img_path) {
525 return create_texture_image(img_path, VK_FORMAT_R8G8B8A8_UNORM);
526 }
527
528#define MISSING_TEXDATA_K "~~~MISSING_TEXDATA~~~"
529
530 std::shared_ptr<TextureData> create_texture_image(std::string img_path, VkFormat texture_format) {
531 std::string cache_key = img_path + "~~~format" + std::to_string(texture_format);
532 if (texture_cache.find(cache_key) != texture_cache.end()) {
533 return texture_cache.at(cache_key);
534 }
535 if (img_path.empty()) {
536 if (texture_cache.find(MISSING_TEXDATA_K) != texture_cache.end()) {
537 return texture_cache.at(MISSING_TEXDATA_K);
538 }
539 img_path = MISSING_TEXTURE_PATH;
540 cache_key = MISSING_TEXDATA_K;
541 }
542 std::shared_ptr<TextureData> texture_data = std::make_shared<TextureData>(device_, allocator);
543 texture_data->missing = img_path == MISSING_TEXTURE_PATH;
544 texture_data->path = img_path;
545 texture_data->cache_key = cache_key;
546 int width, height, color_channels;
547 stbi_uc* pixels = stbi_load(
548 img_path.c_str(),
549 &width, &height, &color_channels,
550 STBI_rgb_alpha
551 );
552
553 if (!pixels) {
554 throw std::runtime_error("failed to load texture image "+img_path);
555 }
556
557 VkDeviceSize image_size = width * height * 4;
558
559 VkBuffer staging_buffer;
560 VmaAllocation staging_buffer_allocation;
561
563 image_size,
564 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
565 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
566 staging_buffer, staging_buffer_allocation
567 );
568
569 void *data;
570 vmaMapMemory(allocator, staging_buffer_allocation, &data);
571 std::memcpy(data, pixels, static_cast<size_t>(image_size));
572 vmaUnmapMemory(allocator, staging_buffer_allocation);
573 stbi_image_free(pixels);
574
576 static_cast<uint32_t>(width), static_cast<uint32_t>(height),
577 texture_format, VK_IMAGE_TILING_OPTIMAL,
578 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
579 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
580 texture_data->image, texture_data->allocation
581 );
582
584 texture_data->image,
585 texture_format,
586 VK_IMAGE_LAYOUT_UNDEFINED,
587 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
588 );
589
591 staging_buffer, texture_data->image,
592 static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1
593 );
594
596 texture_data->image,
597 texture_format,
598 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
599 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
600 );
601
602 vmaDestroyBuffer(allocator, staging_buffer, staging_buffer_allocation);
603
605 texture_format, VK_IMAGE_ASPECT_COLOR_BIT,
606 texture_data->image, texture_data->image_view
607 );
608
609 create_sampler(texture_data->sampler);
610
611 texture_cache[cache_key] = texture_data;
612
613 return texture_data;
614 }
615
618 }
619
620 std::shared_ptr<TextureData> create_cubemap_texture(std::array<std::string, 6> img_paths) {
621 std::shared_ptr<TextureData> texture_data = std::make_shared<TextureData>(device_, allocator);
622 texture_data->missing = false;
623 texture_data->path = "~~~CUBEMAP~~~";
624 std::array<VkBuffer, 6> staging_buffers{};
625 std::array<VmaAllocation, 6> staging_buffers_allocations{};
626 stbi_uc* pixels;
627 int width, height, color_channels;
628 VkDeviceSize image_size;
629 void *data;
630 // TODO optimization: use only one staging buffer, and copy images
631 // one by one to it then copy from buffer to image and repeat
632 // in practice, two fors become one
633 for (size_t i=0; i<6; i++) {
634 assert(!img_paths[i].empty() && "Cannot create cubemap without a proper path");
635 pixels = stbi_load(
636 img_paths[i].c_str(),
637 &width, &height, &color_channels,
638 STBI_rgb_alpha
639 );
640
641 if (!pixels) {
642 throw std::runtime_error("failed to load texture image "+img_paths[i]);
643 }
644
645 // yes, I know, this value is overwritten in each cycle, but all images should be the same size, so it's not important
646 // plus it's probably faster than using an if and initializing it just once
647 image_size = width * height * 4;
648
650 image_size,
651 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
652 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
653 staging_buffers[i], staging_buffers_allocations[i]
654 );
655
656 vmaMapMemory(allocator, staging_buffers_allocations[i], &data);
657 std::memcpy(data, pixels, static_cast<size_t>(image_size));
658 vmaUnmapMemory(allocator, staging_buffers_allocations[i]);
659 stbi_image_free(pixels);
660 }
661
662 VkImageCreateInfo cubemap_info{};
663 cubemap_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
664 cubemap_info.imageType = VK_IMAGE_TYPE_2D;
665 cubemap_info.format = VK_FORMAT_R8G8B8A8_SRGB;
666 cubemap_info.mipLevels = 1;
667 // sizing could be problematic, if error come back here
668 cubemap_info.extent.width = width;
669 cubemap_info.extent.height = height;
670 cubemap_info.extent.depth = 1;
671 cubemap_info.arrayLayers = 6;
672 cubemap_info.tiling = VK_IMAGE_TILING_OPTIMAL;
673 cubemap_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
674 cubemap_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
675 cubemap_info.samples = VK_SAMPLE_COUNT_1_BIT;
676 cubemap_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
677 cubemap_info.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
678
680 cubemap_info,
681 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
682 texture_data->image,
683 texture_data->allocation
684 );
685
687 texture_data->image,
688 VK_FORMAT_R8G8B8A8_SRGB,
689 VK_IMAGE_LAYOUT_UNDEFINED,
690 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
691 6, 0
692 );
693
694 for (size_t i=0; i<6; i++) {
696 staging_buffers[i], texture_data->image,
697 static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1, i
698 );
699 }
700
702 texture_data->image,
703 VK_FORMAT_R8G8B8A8_SRGB,
704 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
705 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
706 6, 0
707 );
708
709 for (size_t i=0; i<6; i++) {
710 vmaDestroyBuffer(allocator, staging_buffers[i], staging_buffers_allocations[i]);
711 }
712
713 VkImageViewCreateInfo cubemap_view_info{};
714 cubemap_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
715 cubemap_view_info.image = texture_data->image;
716 cubemap_view_info.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
717 cubemap_view_info.format = VK_FORMAT_R8G8B8A8_SRGB;
718 cubemap_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
719 cubemap_view_info.subresourceRange.baseMipLevel = 0;
720 cubemap_view_info.subresourceRange.levelCount = 1;
721 cubemap_view_info.subresourceRange.baseArrayLayer = 0;
722 cubemap_view_info.subresourceRange.layerCount = 6;
723
725 cubemap_view_info, texture_data->image_view
726 );
727
728 create_sampler(texture_data->sampler);
729
730 return texture_data;
731 }
732
734 VkImage &image, VkFormat format, VkImageLayout src_layout,
735 VkImageLayout dst_layout,
736 uint32_t layer_count=1, uint32_t layer=0,
737 uint32_t level_count=1, uint32_t level=0
738 ) {
739 VkCommandBuffer command_buffer = begin_single_time_commands();
740 VkPipelineStageFlags sourceStage;
741 VkPipelineStageFlags destinationStage;
742
743 VkImageMemoryBarrier barrier;
744
745 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
746 barrier.oldLayout = src_layout;
747 barrier.newLayout = dst_layout;
748 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
749 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
750
751 barrier.image = image;
752 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
753 barrier.subresourceRange.baseMipLevel = level;
754 barrier.subresourceRange.levelCount = level_count;
755 barrier.subresourceRange.baseArrayLayer = layer;
756 barrier.subresourceRange.layerCount = layer_count;
757
758 barrier.srcAccessMask = 0;
759 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
760
761 if (src_layout == VK_IMAGE_LAYOUT_UNDEFINED && dst_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
762 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
763 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
764 }
765 else if (src_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && dst_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
766 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
767 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
768
769 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
770 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
771 }
772 else {
773 throw std::invalid_argument("unsupported layout transition!");
774 }
775
776 vkCmdPipelineBarrier(
777 command_buffer,
778 sourceStage, destinationStage,
779 0,
780 0, nullptr,
781 0, nullptr,
782 1, &barrier
783 );
784 end_single_time_commands(command_buffer);
785 }
786
788 VkDeviceSize size,
789 VkBufferUsageFlags usage,
790 VkMemoryPropertyFlags properties,
791 VkBuffer &buffer,
792 VmaAllocation &allocation
793 ) {
794 create_buffer(size, usage, properties, VMA_MEMORY_USAGE_UNKNOWN, buffer, allocation);
795 }
796
797 // Buffer Helper Functions
799 VkDeviceSize size,
800 VkBufferUsageFlags usage,
801 VkMemoryPropertyFlags properties,
802 VmaMemoryUsage memory_usage,
803 VkBuffer &buffer,
804 VmaAllocation &allocation
805 ) {
806 VkBufferCreateInfo buffer_info{};
807 buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
808 buffer_info.size = size;
809 buffer_info.usage = usage;
810 buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
811
812 VmaAllocationCreateInfo alloc_info{};
813 // this flag is to be able to copy memory from gpu to cpu
814 // TODO this is sus
815 alloc_info.usage = VMA_MEMORY_USAGE_UNKNOWN;
816 /* alloc_info.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; */
817 alloc_info.requiredFlags = properties;
818 vmaCreateBuffer(allocator, &buffer_info, &alloc_info, &buffer, &allocation, VK_NULL_HANDLE);
819 }
820 VkCommandBuffer begin_single_time_commands() {
821 VkCommandBufferAllocateInfo alloc_info{};
822 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
823 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
824 alloc_info.commandPool = command_pool;
825 alloc_info.commandBufferCount = 1;
826
827 VkCommandBuffer command_buffer;
828 vkAllocateCommandBuffers(device_, &alloc_info, &command_buffer);
829
830 VkCommandBufferBeginInfo begin_info{};
831 begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
832 begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
833
834 vkBeginCommandBuffer(command_buffer, &begin_info);
835 return command_buffer;
836 }
837 void end_single_time_commands(VkCommandBuffer command_buffer) {
838 vkEndCommandBuffer(command_buffer);
839
840 VkSubmitInfo submit_info{};
841 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
842 submit_info.commandBufferCount = 1;
843 submit_info.pCommandBuffers = &command_buffer;
844
845 vkQueueSubmit(graphics_queue_, 1, &submit_info, VK_NULL_HANDLE);
846 vkQueueWaitIdle(graphics_queue_);
847
848 vkFreeCommandBuffers(device_, command_pool, 1, &command_buffer);
849 }
850 void copy_buffer(VkBuffer src_buffer, VkBuffer dst_buffer, VkDeviceSize size) {
851 VkCommandBuffer command_buffer = begin_single_time_commands();
852
853 VkBufferCopy copy_region{};
854 copy_region.srcOffset = 0; // Optional
855 copy_region.dstOffset = 0; // Optional
856 copy_region.size = size;
857 vkCmdCopyBuffer(command_buffer, src_buffer, dst_buffer, 1, &copy_region);
858
859 end_single_time_commands(command_buffer);
860 }
862 VkBuffer buffer, VkImage image, uint32_t width, uint32_t height,
863 uint32_t layer_count=1,
864 uint32_t layer=0
865 ) {
866 VkCommandBuffer commandBuffer = begin_single_time_commands();
867
868 VkBufferImageCopy region{};
869 region.bufferOffset = 0;
870 region.bufferRowLength = 0;
871 region.bufferImageHeight = 0;
872
873 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
874 region.imageSubresource.mipLevel = 0;
875 region.imageSubresource.baseArrayLayer = layer;
876 region.imageSubresource.layerCount = layer_count;
877
878 region.imageOffset = {0, 0, 0};
879 region.imageExtent = {width, height, 1};
880
881 vkCmdCopyBufferToImage(
882 commandBuffer,
883 buffer,
884 image,
885 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
886 1,
887 &region
888 );
889 end_single_time_commands(commandBuffer);
890 }
891
893 uint32_t width, uint32_t height, VkFormat format,
894 VkImageTiling tiling, VkImageUsageFlags usage,
895 VkMemoryPropertyFlags properties,
896 VkImage &image, VmaAllocation &image_memory_allocation
897 ) {
898 VkImageCreateInfo image_info{};
899 image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
900 image_info.imageType = VK_IMAGE_TYPE_2D;
901 image_info.extent.width = width;
902 image_info.extent.height = height;
903 image_info.extent.depth = 1;
904 image_info.mipLevels = 1;
905 image_info.arrayLayers = 1;
906 image_info.format = format;
907 image_info.tiling = tiling;
908 image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
909 image_info.usage = usage;
910 image_info.samples = VK_SAMPLE_COUNT_1_BIT;
911 image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
912
914 image_info, properties, image, image_memory_allocation
915 );
916 }
917
919 VkSampler &sampler
920 ) {
921 VkSamplerCreateInfo sampler_info{};
922 sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
923 sampler_info.magFilter = VK_FILTER_LINEAR;
924 sampler_info.minFilter = VK_FILTER_LINEAR;
925 sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
926 sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
927 sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
928 sampler_info.anisotropyEnable = VK_TRUE;
929 sampler_info.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
930 sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
931 sampler_info.unnormalizedCoordinates = VK_FALSE;
932 sampler_info.compareEnable = VK_FALSE;
933 sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
934 sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
935 sampler_info.mipLodBias = 0.0f;
936 sampler_info.minLod = 0.0f;
937 sampler_info.maxLod = 0.0f;
938
939 create_sampler_with_info(sampler_info, sampler);
940 }
941
943 const VkSamplerCreateInfo &sampler_info,
944 VkSampler &sampler
945 ) {
946 if (vkCreateSampler(
947 device_, &sampler_info, nullptr, &sampler
948 ) != VK_SUCCESS) {
949 throw std::runtime_error("failed to create sampler!");
950 }
951 }
952
954 const VkImageCreateInfo &image_info,
955 VkMemoryPropertyFlags properties,
956 VkImage &image,
957 VmaAllocation &image_memory_allocation
958 ) {
959 /* VkMemoryRequirements mem_requirements; */
960 /* vkGetImageMemoryRequirements(device_, image, &mem_requirements); */
961 VmaAllocationCreateInfo alloc_create_info{};
962 alloc_create_info.usage = VMA_MEMORY_USAGE_GPU_ONLY;
963 alloc_create_info.requiredFlags = properties;
964 VmaAllocationInfo alloc_info{};
965 /* alloc_info.size = mem_requirements.size; */
966 /* alloc_info.memoryType = find_memory_type(mem_requirements.memoryTypeBits, properties); */
967 /* alloc_info.deviceMemory = image_memory; */
968 if (vmaCreateImage(
969 allocator, &image_info, &alloc_create_info,
970 &image, &image_memory_allocation, &alloc_info
971 ) != VK_SUCCESS) {
972 throw std::runtime_error("failed to create image!");
973 }
974 }
975
977 VkFormat format,
978 VkImageAspectFlags aspect_mask,
979 VkImage &image,
980 VkImageView &image_view
981 ) {
982 VkImageViewCreateInfo view_info{};
983 view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
984 view_info.image = image;
985 view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
986 view_info.format = format;
987 view_info.subresourceRange.aspectMask = aspect_mask;
988 view_info.subresourceRange.baseMipLevel = 0;
989 view_info.subresourceRange.levelCount = 1;
990 view_info.subresourceRange.baseArrayLayer = 0;
991 view_info.subresourceRange.layerCount = 1;
992 create_image_view_with_info(view_info, image_view);
993 }
994
996 const VkImageViewCreateInfo &view_info,
997 VkImageView &image_view
998 ) {
999 if (vkCreateImageView(
1000 device_, &view_info, nullptr, &image_view
1001 ) != VK_SUCCESS) {
1002 throw std::runtime_error("failed to create texture image view!");
1003 }
1004 }
1005
1006 void destroy_buffer(VkBuffer &buffer, VmaAllocation &allocation) {
1007 vmaDestroyBuffer(allocator, buffer, allocation);
1008 }
1009
1010 void destroy_image(VkImage &image, VmaAllocation &allocation, VkImageView &image_view, VkSampler &sampler) {
1011 vkDestroySampler(device_, sampler, nullptr);
1012 vkDestroyImageView(device_, image_view, nullptr);
1013 vmaDestroyImage(allocator, image, allocation);
1014 }
1015
1017 vkDestroySampler(device_, tdata.sampler, nullptr);
1018 vkDestroyImageView(device_, tdata.image_view, nullptr);
1019 vmaDestroyImage(allocator, tdata.image, tdata.allocation);
1020 }
1021
1022 size_t pad_uniform_buffer_size(size_t original_size) {
1023 // Calculate required alignment based on minimum device offset alignment
1024 size_t minUboAlignment = properties.limits.minUniformBufferOffsetAlignment;
1025 size_t alignedSize = original_size;
1026 if (minUboAlignment > 0) {
1027 alignedSize = (alignedSize + minUboAlignment - 1) & ~(minUboAlignment - 1);
1028 }
1029 return alignedSize;
1030 }
1031
1032 VkPhysicalDeviceProperties properties;
1034
1035 void populate_imgui_init_info(ImGui_ImplVulkan_InitInfo &info) {
1036 assert(info.DescriptorPool && "imgui init info: descriptor pool must be populated");
1037 assert(info.ImageCount && "imgui init info: image count must be populated");
1038 info.Instance = instance;
1039 info.PhysicalDevice = physical_device;
1040 info.Device = device_;
1041 info.QueueFamily = 0; // THIS IS SUS
1042 info.Queue = graphics_queue_;
1043 info.PipelineCache = VK_NULL_HANDLE;
1044 info.Allocator = nullptr;
1045 info.CheckVkResultFn = [](VkResult res) {
1046 if (res != VK_SUCCESS) {
1047 std::cerr << "err code: " << res << std::endl;
1048 throw std::runtime_error("imgui encountered a vulkan error! return code above");
1049 }
1050 };
1051 }
1052
1053 std::string get_device_name() { return properties.deviceName; }
1054};
Abstraction around VkDevice, managing everything to do with the physical and logical device,...
Definition: engine_device.hpp:109
VmaAllocator get_allocator() const
Definition: engine_device.hpp:481
void copy_buffer_to_image(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height, uint32_t layer_count=1, uint32_t layer=0)
Definition: engine_device.hpp:861
VkSurfaceKHR surface()
Definition: engine_device.hpp:483
VkCommandPool get_command_pool()
Definition: engine_device.hpp:480
~EngineDevice()
Definition: engine_device.hpp:460
std::unordered_map< std::string, std::shared_ptr< TextureData > > & get_texture_cache()
Definition: engine_device.hpp:441
void create_sampler(VkSampler &sampler)
Definition: engine_device.hpp:918
EngineDevice(EngineDevice &&)=delete
VkPhysicalDeviceProperties properties
Definition: engine_device.hpp:1032
void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VmaMemoryUsage memory_usage, VkBuffer &buffer, VmaAllocation &allocation)
Definition: engine_device.hpp:798
VkDeviceSize minOffsetAlignment
Definition: engine_device.hpp:1033
SwapChainSupportDetails get_swap_chain_support()
Definition: engine_device.hpp:487
EngineDevice & operator=(const EngineDevice &)=delete
void copy_buffer(VkBuffer src_buffer, VkBuffer dst_buffer, VkDeviceSize size)
Definition: engine_device.hpp:850
std::shared_ptr< TextureData > create_texture_image(std::string img_path, VkFormat texture_format)
Definition: engine_device.hpp:530
void create_sampler_with_info(const VkSamplerCreateInfo &sampler_info, VkSampler &sampler)
Definition: engine_device.hpp:942
VkCommandBuffer begin_single_time_commands()
Definition: engine_device.hpp:820
void destroy_image(VkImage &image, VmaAllocation &allocation, VkImageView &image_view, VkSampler &sampler)
Definition: engine_device.hpp:1010
size_t pad_uniform_buffer_size(size_t original_size)
Definition: engine_device.hpp:1022
const bool enable_validation_layers
Definition: engine_device.hpp:448
uint32_t find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags properties)
Definition: engine_device.hpp:488
void create_missing_texture_data()
Definition: engine_device.hpp:616
void destroy_texture(TextureData &tdata)
Definition: engine_device.hpp:1016
void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VmaAllocation &allocation)
Definition: engine_device.hpp:787
EngineDevice(EngineWindow &window)
Definition: engine_device.hpp:450
void create_image(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VmaAllocation &image_memory_allocation)
Definition: engine_device.hpp:892
EngineDevice(const EngineDevice &)=delete
std::shared_ptr< TextureData > create_cubemap_texture(std::array< std::string, 6 > img_paths)
Definition: engine_device.hpp:620
VkDevice device()
Definition: engine_device.hpp:482
void create_image_with_info(const VkImageCreateInfo &image_info, VkMemoryPropertyFlags properties, VkImage &image, VmaAllocation &image_memory_allocation)
Definition: engine_device.hpp:953
std::shared_ptr< TextureData > create_texture_image(std::string img_path)
Definition: engine_device.hpp:520
std::string get_device_name()
Definition: engine_device.hpp:1053
void transition_image_layout(VkImage &image, VkFormat format, VkImageLayout src_layout, VkImageLayout dst_layout, uint32_t layer_count=1, uint32_t layer=0, uint32_t level_count=1, uint32_t level=0)
Definition: engine_device.hpp:733
void end_single_time_commands(VkCommandBuffer command_buffer)
Definition: engine_device.hpp:837
void create_image_view_with_info(const VkImageViewCreateInfo &view_info, VkImageView &image_view)
Definition: engine_device.hpp:995
void destroy_buffer(VkBuffer &buffer, VmaAllocation &allocation)
Definition: engine_device.hpp:1006
EngineDevice & operator=(EngineDevice &&)=delete
std::shared_ptr< TextureData > create_texture_image_normal(std::string img_path)
Definition: engine_device.hpp:524
QueueFamilyIndices find_physical_queue_families()
Definition: engine_device.hpp:500
VkQueue graphics_queue()
Definition: engine_device.hpp:484
VkFormat find_supported_format(const std::vector< VkFormat > &candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
Definition: engine_device.hpp:501
void populate_imgui_init_info(ImGui_ImplVulkan_InitInfo &info)
Definition: engine_device.hpp:1035
VkQueue present_queue()
Definition: engine_device.hpp:485
void create_image_view(VkFormat format, VkImageAspectFlags aspect_mask, VkImage &image, VkImageView &image_view)
Definition: engine_device.hpp:976
Wrapper around the GLFW window system.
Definition: engine_window.hpp:19
void create_window_surface(VkInstance instance, VkSurfaceKHR *surface)
Definition: engine_window.hpp:95
#define MISSING_TEXTURE_PATH
Definition: engine_device.hpp:77
void destroy_debug_utils_messenger_EXT(VkInstance instance, VkDebugUtilsMessengerEXT debug_messenger, const VkAllocationCallbacks *p_allocator)
Definition: engine_device.hpp:63
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type, const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data)
Definition: engine_device.hpp:37
#define ENGINE_API_VERSION
Definition: engine_device.hpp:76
#define MISSING_TEXDATA_K
Definition: engine_device.hpp:528
VkResult create_debug_utils_messenger_EXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *p_create_info, const VkAllocationCallbacks *p_allocator, VkDebugUtilsMessengerEXT *p_debug_messenger)
Definition: engine_device.hpp:47
Definition: engine_device.hpp:28
bool presentFamilyHasValue
Definition: engine_device.hpp:32
uint32_t graphicsFamily
Definition: engine_device.hpp:29
uint32_t presentFamily
Definition: engine_device.hpp:30
bool isComplete()
Definition: engine_device.hpp:33
bool graphicsFamilyHasValue
Definition: engine_device.hpp:31
Definition: engine_device.hpp:22
std::vector< VkSurfaceFormatKHR > formats
Definition: engine_device.hpp:24
VkSurfaceCapabilitiesKHR capabilities
Definition: engine_device.hpp:23
std::vector< VkPresentModeKHR > presentModes
Definition: engine_device.hpp:25
Definition: engine_device.hpp:79
VkImageView image_view
Definition: engine_device.hpp:85
VkSampler sampler
Definition: engine_device.hpp:86
VkImage image
Definition: engine_device.hpp:83
TextureData & operator=(const TextureData &)=delete
TextureData(const TextureData &)=delete
VmaAllocation allocation
Definition: engine_device.hpp:84
std::string path
Definition: engine_device.hpp:82
std::string cache_key
Definition: engine_device.hpp:81
bool missing
Definition: engine_device.hpp:80
~TextureData()
Definition: engine_device.hpp:92
void cleanup()
Definition: engine_device.hpp:95
VmaAllocator & allocator
Definition: engine_device.hpp:89
TextureData(VkDevice &device, VmaAllocator &allocator)
Definition: engine_device.hpp:91
VkDevice & device
Definition: engine_device.hpp:88