5#include "libs/imgui/imgui_impl_vulkan.h"
8#define VMA_IMPLEMENTATION
9#include "libs/vk_mem_alloc.h"
16#include <unordered_set>
17#include <vulkan/vulkan_core.h>
19#define STB_IMAGE_IMPLEMENTATION
20#include "libs/stb_image.h"
38 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
39 VkDebugUtilsMessageTypeFlagsEXT message_type,
40 const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data,
43 std::cerr <<
"validation layer: " << p_callback_data->pMessage << std::endl;
49 const VkDebugUtilsMessengerCreateInfoEXT *p_create_info,
50 const VkAllocationCallbacks *p_allocator,
51 VkDebugUtilsMessengerEXT *p_debug_messenger
53 auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
55 "vkCreateDebugUtilsMessengerEXT");
56 if (func !=
nullptr) {
57 return func(instance, p_create_info, p_allocator, p_debug_messenger);
59 return VK_ERROR_EXTENSION_NOT_PRESENT;
65 VkDebugUtilsMessengerEXT debug_messenger,
66 const VkAllocationCallbacks *p_allocator
68 auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
70 "vkDestroyDebugUtilsMessengerEXT");
71 if (func !=
nullptr) {
72 func(instance, debug_messenger, p_allocator);
76#define ENGINE_API_VERSION VK_API_VERSION_1_2
77#define MISSING_TEXTURE_PATH (ASSETS_DIR+"/assets/missing_texture.png")
112 VmaAllocatorCreateInfo allocator_info = {};
114 allocator_info.physicalDevice = physical_device;
115 allocator_info.device = device_;
116 allocator_info.instance = instance;
118 vmaCreateAllocator(&allocator_info, &allocator);
121 void create_instance() {
123 throw std::runtime_error(
"validation layers requested, but not available!");
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);
133 VkInstanceCreateInfo create_info = {};
134 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
135 create_info.pApplicationInfo = &app_info;
137 auto extensions = get_required_extensions();
138 create_info.enabledExtensionCount =
static_cast<uint32_t
>(extensions.size());
139 create_info.ppEnabledExtensionNames = extensions.data();
141 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
143 create_info.enabledLayerCount =
static_cast<uint32_t
>(validation_layers.size());
144 create_info.ppEnabledLayerNames = validation_layers.data();
146 populate_debug_messenger_create_info(debugCreateInfo);
147 create_info.pNext = (VkDebugUtilsMessengerCreateInfoEXT *)&debugCreateInfo;
149 create_info.enabledLayerCount = 0;
150 create_info.pNext =
nullptr;
153 if (vkCreateInstance(&create_info,
nullptr, &instance) != VK_SUCCESS) {
154 throw std::runtime_error(
"failed to create instance!");
157 has_glfw_required_instance_extensions();
159 void setup_debug_messenger() {
161 VkDebugUtilsMessengerCreateInfoEXT createInfo;
162 populate_debug_messenger_create_info(createInfo);
164 throw std::runtime_error(
"failed to set up debug messenger!");
167 void create_surface() {
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!");
176 std::cout <<
"Device count: " << deviceCount << std::endl;
177 std::vector<VkPhysicalDevice> devices(deviceCount);
178 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
180 for (
const auto &
device : devices) {
181 if (is_device_suitable(
device)) {
187 if (physical_device == VK_NULL_HANDLE) {
188 throw std::runtime_error(
"failed to find a suitable GPU!");
191 vkGetPhysicalDeviceProperties(physical_device, &
properties);
193 properties.limits.minUniformBufferOffsetAlignment,
196 std::cout <<
"physical device: " <<
properties.deviceName << std::endl;
198 void create_logical_device() {
201 std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
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);
214 VkPhysicalDeviceFeatures device_features = {};
215 device_features.samplerAnisotropy = VK_TRUE;
216 device_features.geometryShader = VK_TRUE;
218 VkDeviceCreateInfo create_info = {};
219 create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
221 create_info.queueCreateInfoCount =
static_cast<uint32_t
>(queue_create_infos.size());
222 create_info.pQueueCreateInfos = queue_create_infos.data();
224 create_info.pEnabledFeatures = &device_features;
225 create_info.enabledExtensionCount =
static_cast<uint32_t
>(device_extensions.size());
226 create_info.ppEnabledExtensionNames = device_extensions.data();
231 create_info.enabledLayerCount =
static_cast<uint32_t
>(validation_layers.size());
232 create_info.ppEnabledLayerNames = validation_layers.data();
234 create_info.enabledLayerCount = 0;
237 if (vkCreateDevice(physical_device, &create_info,
nullptr, &device_) != VK_SUCCESS) {
238 throw std::runtime_error(
"failed to create logical device!");
241 vkGetDeviceQueue(device_, indices.
graphicsFamily, 0, &graphics_queue_);
242 vkGetDeviceQueue(device_, indices.
presentFamily, 0, &present_queue_);
244 void create_command_pool() {
247 VkCommandPoolCreateInfo pool_info = {};
248 pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
251 VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
253 if (vkCreateCommandPool(device_, &pool_info,
nullptr, &command_pool) != VK_SUCCESS) {
254 throw std::runtime_error(
"failed to create command pool!");
259 bool is_device_suitable(VkPhysicalDevice
device) {
262 bool extensions_supported = check_device_extension_support(
device);
264 bool swap_chain_adequate =
false;
265 if (extensions_supported) {
267 swap_chain_adequate = !swap_chain_support.
formats.empty() && !swap_chain_support.
presentModes.empty();
270 VkPhysicalDeviceFeatures supported_features;
271 vkGetPhysicalDeviceFeatures(
device, &supported_features);
273 return indices.
isComplete() && extensions_supported && swap_chain_adequate &&
274 supported_features.samplerAnisotropy;
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);
281 std::vector<const char *> extensions(glfw_extensions, glfw_extensions + glfw_extension_count);
284 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
289 bool check_validation_layer_support() {
290 uint32_t layer_count;
291 vkEnumerateInstanceLayerProperties(&layer_count,
nullptr);
293 std::vector<VkLayerProperties> available_layers(layer_count);
294 vkEnumerateInstanceLayerProperties(&layer_count, available_layers.data());
296 for (
const char *layer_name : validation_layers) {
297 bool layer_found =
false;
299 for (
const auto &layer_properties : available_layers) {
300 if (strcmp(layer_name, layer_properties.layerName) == 0) {
316 uint32_t queue_family_count = 0;
317 vkGetPhysicalDeviceQueueFamilyProperties(
device, &queue_family_count,
nullptr);
319 std::vector<VkQueueFamilyProperties> queue_families(queue_family_count);
320 vkGetPhysicalDeviceQueueFamilyProperties(
device, &queue_family_count, queue_families.data());
323 for (
const auto &queue_family : queue_families) {
324 if (queue_family.queueCount > 0 && queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
328 VkBool32 presentSupport =
false;
329 vkGetPhysicalDeviceSurfaceSupportKHR(
device, i, surface_, &presentSupport);
330 if (queue_family.queueCount > 0 && presentSupport) {
343 void populate_debug_messenger_create_info(VkDebugUtilsMessengerCreateInfoEXT &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;
352 create_info.pUserData =
nullptr;
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());
361 std::unordered_set<std::string> available;
362 for (
const auto &extension : extensions) {
364 available.insert(extension.extensionName);
368 auto required_extensions = get_required_extensions();
369 for (
const auto &required : required_extensions) {
371 if (available.find(required) == available.end()) {
372 throw std::runtime_error(
"Missing required glfw extension");
376 bool check_device_extension_support(VkPhysicalDevice
device) {
377 uint32_t extension_count;
378 vkEnumerateDeviceExtensionProperties(
device,
nullptr, &extension_count,
nullptr);
380 std::vector<VkExtensionProperties> available_extensions(extension_count);
381 vkEnumerateDeviceExtensionProperties(
385 available_extensions.data());
387 std::set<std::string> required_extensions(device_extensions.begin(), device_extensions.end());
389 for (
const auto &extension : available_extensions) {
390 required_extensions.erase(extension.extensionName);
393 return required_extensions.empty();
399 uint32_t format_count;
400 vkGetPhysicalDeviceSurfaceFormatsKHR(
device, surface_, &format_count,
nullptr);
402 if (format_count != 0) {
403 details.
formats.resize(format_count);
404 vkGetPhysicalDeviceSurfaceFormatsKHR(
device, surface_, &format_count, details.
formats.data());
407 uint32_t present_mode_count;
408 vkGetPhysicalDeviceSurfacePresentModesKHR(
device, surface_, &present_mode_count,
nullptr);
410 if (present_mode_count != 0) {
412 vkGetPhysicalDeviceSurfacePresentModesKHR(
421 VmaAllocator allocator;
424 VkDebugUtilsMessengerEXT debug_messenger;
425 VkPhysicalDevice physical_device = VK_NULL_HANDLE;
427 VkCommandPool command_pool;
430 VkSurfaceKHR surface_;
431 VkQueue graphics_queue_;
432 VkQueue present_queue_;
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};
437 std::unordered_map<std::string, std::shared_ptr<TextureData>> texture_cache{};
442 return texture_cache;
445#ifdef DISABLE_VK_VALIDATION
452 setup_debug_messenger();
454 pick_physical_device();
455 create_logical_device();
457 create_command_pool();
461 texture_cache.clear();
462 vmaDestroyAllocator(allocator);
463 vkDestroyCommandPool(device_, command_pool,
nullptr);
464 vkDestroyDevice(device_,
nullptr);
467 instance, debug_messenger,
nullptr
470 vkDestroySurfaceKHR(instance, surface_,
nullptr);
471 vkDestroyInstance(instance,
nullptr);
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)) &&
498 throw std::runtime_error(
"failed to find suitable memory type!");
502 const std::vector<VkFormat> &candidates,
503 VkImageTiling tiling,
504 VkFormatFeatureFlags features
506 for (VkFormat format : candidates) {
507 VkFormatProperties props;
508 vkGetPhysicalDeviceFormatProperties(physical_device, format, &props);
510 if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) {
513 tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) {
517 throw std::runtime_error(
"failed to find supported format!");
528#define MISSING_TEXDATA_K "~~~MISSING_TEXDATA~~~"
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);
535 if (img_path.empty()) {
542 std::shared_ptr<TextureData> texture_data = std::make_shared<TextureData>(device_, allocator);
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(
549 &width, &height, &color_channels,
554 throw std::runtime_error(
"failed to load texture image "+img_path);
557 VkDeviceSize image_size = width * height * 4;
559 VkBuffer staging_buffer;
560 VmaAllocation staging_buffer_allocation;
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
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);
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
586 VK_IMAGE_LAYOUT_UNDEFINED,
587 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
591 staging_buffer, texture_data->image,
592 static_cast<uint32_t
>(width),
static_cast<uint32_t
>(height), 1
598 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
599 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
602 vmaDestroyBuffer(allocator, staging_buffer, staging_buffer_allocation);
605 texture_format, VK_IMAGE_ASPECT_COLOR_BIT,
606 texture_data->image, texture_data->image_view
611 texture_cache[cache_key] = texture_data;
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{};
627 int width, height, color_channels;
628 VkDeviceSize image_size;
633 for (
size_t i=0; i<6; i++) {
634 assert(!img_paths[i].empty() &&
"Cannot create cubemap without a proper path");
636 img_paths[i].c_str(),
637 &width, &height, &color_channels,
642 throw std::runtime_error(
"failed to load texture image "+img_paths[i]);
647 image_size = width * height * 4;
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]
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);
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;
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;
681 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
683 texture_data->allocation
688 VK_FORMAT_R8G8B8A8_SRGB,
689 VK_IMAGE_LAYOUT_UNDEFINED,
690 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
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
703 VK_FORMAT_R8G8B8A8_SRGB,
704 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
705 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
709 for (
size_t i=0; i<6; i++) {
710 vmaDestroyBuffer(allocator, staging_buffers[i], staging_buffers_allocations[i]);
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;
725 cubemap_view_info, texture_data->image_view
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
740 VkPipelineStageFlags sourceStage;
741 VkPipelineStageFlags destinationStage;
743 VkImageMemoryBarrier barrier;
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;
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;
758 barrier.srcAccessMask = 0;
759 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
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;
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;
769 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
770 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
773 throw std::invalid_argument(
"unsupported layout transition!");
776 vkCmdPipelineBarrier(
778 sourceStage, destinationStage,
789 VkBufferUsageFlags usage,
792 VmaAllocation &allocation
800 VkBufferUsageFlags usage,
802 VmaMemoryUsage memory_usage,
804 VmaAllocation &allocation
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;
812 VmaAllocationCreateInfo alloc_info{};
815 alloc_info.usage = VMA_MEMORY_USAGE_UNKNOWN;
818 vmaCreateBuffer(allocator, &buffer_info, &alloc_info, &buffer, &allocation, VK_NULL_HANDLE);
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;
827 VkCommandBuffer command_buffer;
828 vkAllocateCommandBuffers(device_, &alloc_info, &command_buffer);
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;
834 vkBeginCommandBuffer(command_buffer, &begin_info);
835 return command_buffer;
838 vkEndCommandBuffer(command_buffer);
840 VkSubmitInfo submit_info{};
841 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
842 submit_info.commandBufferCount = 1;
843 submit_info.pCommandBuffers = &command_buffer;
845 vkQueueSubmit(graphics_queue_, 1, &submit_info, VK_NULL_HANDLE);
846 vkQueueWaitIdle(graphics_queue_);
848 vkFreeCommandBuffers(device_, command_pool, 1, &command_buffer);
850 void copy_buffer(VkBuffer src_buffer, VkBuffer dst_buffer, VkDeviceSize size) {
853 VkBufferCopy copy_region{};
854 copy_region.srcOffset = 0;
855 copy_region.dstOffset = 0;
856 copy_region.size = size;
857 vkCmdCopyBuffer(command_buffer, src_buffer, dst_buffer, 1, ©_region);
862 VkBuffer buffer, VkImage image, uint32_t width, uint32_t height,
863 uint32_t layer_count=1,
868 VkBufferImageCopy region{};
869 region.bufferOffset = 0;
870 region.bufferRowLength = 0;
871 region.bufferImageHeight = 0;
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;
878 region.imageOffset = {0, 0, 0};
879 region.imageExtent = {width, height, 1};
881 vkCmdCopyBufferToImage(
885 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
893 uint32_t width, uint32_t height, VkFormat format,
894 VkImageTiling tiling, VkImageUsageFlags usage,
896 VkImage &image, VmaAllocation &image_memory_allocation
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;
914 image_info,
properties, image, image_memory_allocation
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;
943 const VkSamplerCreateInfo &sampler_info,
947 device_, &sampler_info,
nullptr, &sampler
949 throw std::runtime_error(
"failed to create sampler!");
954 const VkImageCreateInfo &image_info,
957 VmaAllocation &image_memory_allocation
961 VmaAllocationCreateInfo alloc_create_info{};
962 alloc_create_info.usage = VMA_MEMORY_USAGE_GPU_ONLY;
964 VmaAllocationInfo alloc_info{};
969 allocator, &image_info, &alloc_create_info,
970 &image, &image_memory_allocation, &alloc_info
972 throw std::runtime_error(
"failed to create image!");
978 VkImageAspectFlags aspect_mask,
980 VkImageView &image_view
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;
996 const VkImageViewCreateInfo &view_info,
997 VkImageView &image_view
999 if (vkCreateImageView(
1000 device_, &view_info,
nullptr, &image_view
1002 throw std::runtime_error(
"failed to create texture image view!");
1007 vmaDestroyBuffer(allocator, buffer, allocation);
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);
1017 vkDestroySampler(device_, tdata.
sampler,
nullptr);
1018 vkDestroyImageView(device_, tdata.
image_view,
nullptr);
1024 size_t minUboAlignment =
properties.limits.minUniformBufferOffsetAlignment;
1025 size_t alignedSize = original_size;
1026 if (minUboAlignment > 0) {
1027 alignedSize = (alignedSize + minUboAlignment - 1) & ~(minUboAlignment - 1);
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;
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");
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