#include "UwURenderEngine.hpp" #include #include #include #include #include #include #include "Core/CoreInstance.hpp" #include "Log/Log.hpp" #include "Game/GameInstance.hpp" #include "Game/World/World.hpp" #include "Game/Actors/Mesh/Mesh.hpp" #include "GLFW/glfw3.h" const std::vector UwURenderEngine::deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; #ifdef _DEBUG static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { std::string msg = "validation layer: "; msg += pCallbackData->pMessage; Loging::Log(msg); return VK_FALSE; } VkResult UwURenderEngine::enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info) { PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT")); return debug_creator(instance_, create_info, nullptr, &debug_messenger_); } #endif UwURenderEngine::SwapchainSupportDetails UwURenderEngine::query_swapchain_details() const { SwapchainSupportDetails details; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device_, surface_, &details.capabilities); uint32_t surface_format_cnt = 0; VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, nullptr)); details.formats.resize(surface_format_cnt); VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, details.formats.data())); uint32_t present_modes_cnt = 0; VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, nullptr)); details.present_modes.resize(surface_format_cnt); VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, details.present_modes.data())); return details; } std::vector UwURenderEngine::get_required_extensions() { uint32_t extensions_count = 0; const char** glfw_extension = glfwGetRequiredInstanceExtensions(&extensions_count); std::vector extensions(glfw_extension, glfw_extension + extensions_count); #ifdef _DEBUG extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); #endif return extensions; } VkVertexInputBindingDescription UwURenderEngine::Vertex::get_binding_description() { VkVertexInputBindingDescription description; description.binding = 0; description.stride = sizeof(Vertex); description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; return description; } std::array UwURenderEngine::Vertex::get_vertex_attribute_descriptions() { std::array descriptions; // Bind vertex loc descriptions[0].binding = 0; descriptions[0].location = 0; descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; descriptions[0].offset = offsetof(Vertex, pos); // Bind color descriptions[1].binding = 0; descriptions[1].location = 1; descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; descriptions[1].offset = offsetof(Vertex, color); return descriptions; } bool UwURenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface) { VkPhysicalDeviceProperties device_properties; VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties(device, &device_properties); vkGetPhysicalDeviceFeatures(device, &device_features); try { // Ловить исключения имеет смысыл только здесь QueueFamilyIndices indices = find_queue_family_indices(device, surface); } catch (...) { return false; } return check_device_extensions_support(device); } bool UwURenderEngine::check_device_extensions_support(VkPhysicalDevice device) { uint32_t extension_count; VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr)); std::vector available_extensions(extension_count); VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, available_extensions.data())); for (const auto& extension : deviceExtensions) { bool isFind = false; for (const auto& i : available_extensions) { if (std::strcmp(i.extensionName, extension) == 0) { isFind = true; break; } } if (!isFind) return false; } return true; } UwURenderEngine::QueueFamilyIndices UwURenderEngine::find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface) { QueueFamilyIndices queue_family_indices; uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, nullptr); std::vector family_properties(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_properties.data()); // Find graphics for(uint32_t i = 0; i < family_properties.size(); ++i) { if (family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { queue_family_indices.graphics_family = i; break; } } if (queue_family_indices.graphics_family.has_value() == false) throw std::runtime_error("Failed to find a graphics queue family"); // Find present VkBool32 present_support = false; VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_indices.graphics_family.value(), surface, &present_support)); // Если графическая очередь поддерживет презентацию кадров, то используем её if (present_support == VK_TRUE) queue_family_indices.present_family = queue_family_indices.graphics_family; // иначе ищем другую подходящую очередь else { for(uint32_t i = 0; i < family_properties.size(); ++i) { present_support = false; VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support)); if (present_support == VK_TRUE) { queue_family_indices.present_family = i; break; } } } if (queue_family_indices.present_family.has_value() == false) throw std::runtime_error("Failed to find a present queue family"); // С начала пытаемся найти очередь специалезированную // для копирования отличную от графической for(uint32_t i = 0; i < family_properties.size(); ++i) { if (i == queue_family_indices.graphics_family.value()) continue; if (family_properties[i].queueFlags & VK_QUEUE_TRANSFER_BIT) queue_family_indices.transfer_family = i; } // Если не находим, то используем графическую if (queue_family_indices.transfer_family.has_value() == false) queue_family_indices.transfer_family = queue_family_indices.graphics_family; return queue_family_indices; } VkSurfaceFormatKHR UwURenderEngine::choose_surface_format(const std::vector& surface_formats) { for (const auto& i : surface_formats) { if (i.format == VK_FORMAT_B8G8R8A8_SRGB && i.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) return i; } return surface_formats[0]; } VkPresentModeKHR UwURenderEngine::choose_present_mode(const std::vector& present_modes, VkPresentModeKHR desired_present_mode) { for (const auto& i : present_modes) { if (i == desired_present_mode) return i; } return VK_PRESENT_MODE_FIFO_KHR; } VkExtent2D UwURenderEngine::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window) { // Здесь вычисляется допустимое разрешение рендера if (capabilities.currentExtent.width != std::numeric_limits::max()) return capabilities.currentExtent; else { int width, height; glfwGetFramebufferSize(window, &width, &height); VkExtent2D actualExtent = { static_cast(width), static_cast(height) }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); return actualExtent; } } VkShaderModule UwURenderEngine::create_shader_module(const std::string& code) const { VkShaderModuleCreateInfo shader_module_info{}; shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shader_module_info.codeSize = code.size(); shader_module_info.pCode = reinterpret_cast(code.c_str()); VkShaderModule shader_module; VK_CHECK(vkCreateShaderModule(device_, &shader_module_info, nullptr, &shader_module)); return shader_module; } void UwURenderEngine::create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, VkBuffer* buffer, const std::vector& queue_families) { VkBufferCreateInfo buffer_info{}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = size; buffer_info.usage = usage; if (queue_families.size() > 1) { buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT; buffer_info.queueFamilyIndexCount = static_cast(queue_families.size()); buffer_info.pQueueFamilyIndices = queue_families.data(); } else { buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; buffer_info.queueFamilyIndexCount = 0; buffer_info.pQueueFamilyIndices = nullptr; } VK_CHECK(vkCreateBuffer(device_, &buffer_info, nullptr, buffer)); } void UwURenderEngine::allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory) { VkMemoryRequirements requirements{}; vkGetBufferMemoryRequirements(device_, buffer, &requirements); VkMemoryAllocateInfo allocate_info{}; allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocate_info.allocationSize = requirements.size; allocate_info.memoryTypeIndex = find_memory_type(requirements.memoryTypeBits, property); VK_CHECK(vkAllocateMemory(device_, &allocate_info, nullptr, device_memory)); } void UwURenderEngine::create_instance() { std::vector extensions = get_required_extensions(); VkApplicationInfo app_info{}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.apiVersion = VK_API_VERSION_1_0; app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0); app_info.pApplicationName = core_.getGameName().c_str(); app_info.pEngineName = "UwU Engine"; app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0); VkInstanceCreateInfo instance_create_info{}; instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_create_info.pApplicationInfo = &app_info; instance_create_info.enabledExtensionCount = static_cast(extensions.size()); instance_create_info.ppEnabledExtensionNames = extensions.data(); #ifdef _DEBUG const std::vector layers_validation = { "VK_LAYER_KHRONOS_validation" }; instance_create_info.enabledLayerCount = static_cast(layers_validation.size()); instance_create_info.ppEnabledLayerNames = layers_validation.data(); VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{}; debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; debug_messenger_create_info.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; debug_messenger_create_info.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; debug_messenger_create_info.pfnUserCallback = &debugCallback; instance_create_info.pNext = &debug_messenger_create_info; #endif VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_)); #ifdef _DEBUG VK_CHECK(enable_layer_validation(&debug_messenger_create_info)); #endif } void UwURenderEngine::pick_physical_device() { uint32_t device_count = 0; std::vector devices; VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr)); devices.resize(device_count); VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data())); for (const auto& device : devices) { if (is_device_suitable(device, surface_)) { physical_device_ = device; VkPhysicalDeviceProperties device_properties; vkGetPhysicalDeviceProperties(physical_device_, &device_properties); Loging::Log("Using device: " + std::string(device_properties.deviceName)); break; } } if (VK_NULL_HANDLE == physical_device_) throw std::runtime_error("No suitable device found"); } void UwURenderEngine::create_logical_device() { QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); VkPhysicalDeviceFeatures device_features{}; std::vector queue_create_infos; std::set unique_queue_families = {indices.graphics_family.value(), indices.present_family.value(), indices.transfer_family.value()}; float queue_priority = 1.0f; VkDeviceQueueCreateInfo device_queue_create_info{}; device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; device_queue_create_info.pQueuePriorities = &queue_priority; for (auto queue_family : unique_queue_families) { device_queue_create_info.queueFamilyIndex = queue_family; device_queue_create_info.queueCount = 1; queue_create_infos.push_back(device_queue_create_info); } VkDeviceCreateInfo device_create_info{}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.queueCreateInfoCount = static_cast(unique_queue_families.size()); device_create_info.pQueueCreateInfos = queue_create_infos.data(); device_create_info.pEnabledFeatures = &device_features; device_create_info.enabledExtensionCount = static_cast(deviceExtensions.size()); device_create_info.ppEnabledExtensionNames = deviceExtensions.data(); #ifdef _DEBUG const std::vector layers_validation = { "VK_LAYER_KHRONOS_validation" }; device_create_info.enabledLayerCount = static_cast(layers_validation.size()); device_create_info.ppEnabledLayerNames = layers_validation.data(); #else device_create_info.enabledLayerCount = 0; device_create_info.ppEnabledLayerNames = nullptr; #endif VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_)); vkGetDeviceQueue(device_, indices.graphics_family.value(), 0, &graphics_queue_); vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_); vkGetDeviceQueue(device_, indices.transfer_family.value(), 0, &transfer_queue_); } void UwURenderEngine::create_swapchain() { SwapchainSupportDetails swapchain_support = query_swapchain_details(); VkSurfaceFormatKHR surface_format = choose_surface_format(swapchain_support.formats); VkPresentModeKHR present_mode = choose_present_mode(swapchain_support.present_modes, VK_PRESENT_MODE_MAILBOX_KHR); VkExtent2D extent = choose_extent(swapchain_support.capabilities, get_window()); uint32_t image_count = swapchain_support.capabilities.minImageCount + 1; if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount) image_count = swapchain_support.capabilities.maxImageCount; VkSwapchainCreateInfoKHR swapchain_create_info{}; swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_create_info.surface = surface_; swapchain_create_info.minImageCount = image_count; swapchain_create_info.imageFormat = surface_format.format; swapchain_create_info.imageColorSpace = surface_format.colorSpace; swapchain_create_info.imageExtent = extent; swapchain_create_info.imageArrayLayers = 1; swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform; swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchain_create_info.presentMode = present_mode; swapchain_create_info.clipped = VK_TRUE; swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_); const std::set queue_family_indices = { family_indices.graphics_family.value(), family_indices.present_family.value(), family_indices.transfer_family.value() }; std::vector arr_families; if (queue_family_indices.size() > 1) { arr_families.reserve(queue_family_indices.size()); for(auto& i : queue_family_indices) arr_families.push_back(i); swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; swapchain_create_info.queueFamilyIndexCount = static_cast(arr_families.size()); swapchain_create_info.pQueueFamilyIndices = arr_families.data(); } else { swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_create_info.queueFamilyIndexCount = 0; swapchain_create_info.pQueueFamilyIndices = nullptr; } VK_CHECK(vkCreateSwapchainKHR(device_, &swapchain_create_info, nullptr, &swapchain_)); vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, nullptr); swapchain_images_.resize(image_count); vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, swapchain_images_.data()); swapchain_image_format_ = surface_format.format; swapchain_extent_ = extent; } void UwURenderEngine::create_image_views() { VkImageViewCreateInfo image_view_info{}; image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_info.format = swapchain_image_format_; image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_view_info.subresourceRange.baseMipLevel = 0; image_view_info.subresourceRange.levelCount = 1; image_view_info.subresourceRange.baseArrayLayer = 0; image_view_info.subresourceRange.layerCount = 1; swapchain_image_views_.resize(swapchain_images_.size()); for (uint32_t i = 0; i < swapchain_images_.size(); ++i) { image_view_info.image = swapchain_images_[i]; VK_CHECK(vkCreateImageView(device_, &image_view_info, nullptr, &swapchain_image_views_[i])); } } void UwURenderEngine::create_render_pass() { VkAttachmentDescription attachment_description{}; attachment_description.format = swapchain_image_format_; attachment_description.samples = VK_SAMPLE_COUNT_1_BIT; attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; attachment_description.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference attachment_reference; attachment_reference.attachment = 0; attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass_description{}; subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass_description.colorAttachmentCount = 1; subpass_description.pColorAttachments = &attachment_reference; VkSubpassDependency dependency{}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; dependency.dstSubpass = 0; dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.srcAccessMask = 0; dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; VkRenderPassCreateInfo render_pass_info{}; render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; render_pass_info.attachmentCount = 1; render_pass_info.pAttachments = &attachment_description; render_pass_info.subpassCount = 1; render_pass_info.pSubpasses = &subpass_description; render_pass_info.dependencyCount = 1; render_pass_info.pDependencies = &dependency; VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_)); } void UwURenderEngine::create_description_set_layout() { VkDescriptorSetLayoutBinding ubo_layout_binding{}; ubo_layout_binding.binding = 0; ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ubo_layout_binding.descriptorCount = 1; ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; ubo_layout_binding.pImmutableSamplers = nullptr; VkDescriptorSetLayoutCreateInfo ubo_layout_info{}; ubo_layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ubo_layout_info.bindingCount = 1; ubo_layout_info.pBindings = &ubo_layout_binding; VK_CHECK(vkCreateDescriptorSetLayout(device_, &ubo_layout_info, nullptr, &ubo_layout_binding_)); } void UwURenderEngine::create_uniform_buffers() { uniform_buffers_.resize(swapchain_images_.size()); uniform_buffers_memory_.resize(swapchain_images_.size()); uniform_buffers_mapped_.resize(swapchain_images_.size()); std::vector arr_indices = get_unique_family_indices(find_queue_family_indices(physical_device_, surface_)); for (size_t i = 0; i < swapchain_images_.size(); ++i) { const VkDeviceSize size = sizeof(UniformBufferObject); create_buffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, &uniform_buffers_[i], arr_indices); allocate_memory(uniform_buffers_[i], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniform_buffers_memory_[i]); vkBindBufferMemory(device_, uniform_buffers_[i], uniform_buffers_memory_[i], 0); vkMapMemory(device_, uniform_buffers_memory_[i], 0, size, 0, &uniform_buffers_mapped_[i]); } } void UwURenderEngine::create_descriptor_pool() { VkDescriptorPoolSize pool_size{}; pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; pool_size.descriptorCount = static_cast(swapchain_images_.size()); VkDescriptorPoolCreateInfo descriptor_pool_info{}; descriptor_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; descriptor_pool_info.poolSizeCount = 1; descriptor_pool_info.pPoolSizes = &pool_size; descriptor_pool_info.maxSets = static_cast(swapchain_images_.size()); VK_CHECK(vkCreateDescriptorPool(device_, &descriptor_pool_info, nullptr, &descriptor_pool_)); } void UwURenderEngine::create_descriptor_sets() { std::vector layouts(swapchain_images_.size(), ubo_layout_binding_); VkDescriptorSetAllocateInfo descriptor_set_allocate_info{}; descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; descriptor_set_allocate_info.descriptorPool = descriptor_pool_; descriptor_set_allocate_info.descriptorSetCount = static_cast(swapchain_images_.size()); descriptor_set_allocate_info.pSetLayouts = layouts.data(); descriptor_sets_.resize(swapchain_images_.size()); VK_CHECK(vkAllocateDescriptorSets(device_, &descriptor_set_allocate_info, descriptor_sets_.data())); for (size_t i = 0; i < swapchain_images_.size(); ++i) { VkDescriptorBufferInfo buffer_info{}; buffer_info.buffer = uniform_buffers_[i]; buffer_info.offset = 0; buffer_info.range = sizeof(UniformBufferObject); VkWriteDescriptorSet write_descriptor_set{}; write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_descriptor_set.dstSet = descriptor_sets_[i]; write_descriptor_set.dstBinding = 0; write_descriptor_set.dstArrayElement = 0; write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; write_descriptor_set.descriptorCount = 1; write_descriptor_set.pBufferInfo = &buffer_info; write_descriptor_set.pImageInfo = nullptr; write_descriptor_set.pTexelBufferView = nullptr; vkUpdateDescriptorSets(device_, 1, &write_descriptor_set, 0, nullptr); } } void UwURenderEngine::create_graphics_pipeline() { std::ifstream vertex_shader_file("Shaders/vertex.spv", std::ios::binary); if (!vertex_shader_file.is_open()) throw std::runtime_error("Vertex shader not found"); std::ifstream fragment_shader_file("Shaders/fragment.spv", std::ios::binary); if (!fragment_shader_file.is_open()) { vertex_shader_file.close(); throw std::runtime_error("Fragment shader not found"); } std::string vertex_shader_code((std::istreambuf_iterator(vertex_shader_file)), std::istreambuf_iterator()); std::string fragment_shader_code((std::istreambuf_iterator(fragment_shader_file)), std::istreambuf_iterator()); vertex_shader_file.close(); fragment_shader_file.close(); VkShaderModule vertex_shader = create_shader_module(vertex_shader_code); VkShaderModule fragment_shader = create_shader_module(fragment_shader_code); VkPipelineShaderStageCreateInfo vertex_shader_stage_info{}; vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; vertex_shader_stage_info.module = vertex_shader; vertex_shader_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo fragment_shader_stage_info{}; fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragment_shader_stage_info.module = fragment_shader; fragment_shader_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info}; const std::vector dynamic_states = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamic_state_info{}; dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamic_state_info.dynamicStateCount = static_cast(dynamic_states.size()); dynamic_state_info.pDynamicStates = dynamic_states.data(); VkVertexInputBindingDescription binding_description = Vertex::get_binding_description(); std::array attribute_descriptions = Vertex::get_vertex_attribute_descriptions(); VkPipelineVertexInputStateCreateInfo vertex_input_info{}; vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertex_input_info.vertexBindingDescriptionCount = 1; vertex_input_info.pVertexBindingDescriptions = &binding_description; vertex_input_info.vertexAttributeDescriptionCount = static_cast(attribute_descriptions.size()); vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data(); VkPipelineInputAssemblyStateCreateInfo input_assembly_info{}; input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; input_assembly_info.primitiveRestartEnable = VK_FALSE; VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; viewport.width = static_cast(swapchain_extent_.width); viewport.height = static_cast(swapchain_extent_.height); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor{}; scissor.offset = {0, 0}; scissor.extent = swapchain_extent_; VkPipelineViewportStateCreateInfo viewport_info{}; viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewport_info.viewportCount = 1; viewport_info.pViewports = &viewport; viewport_info.scissorCount = 1; viewport_info.pScissors = &scissor; VkPipelineRasterizationStateCreateInfo rasterization_info{}; rasterization_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterization_info.depthClampEnable = VK_FALSE; rasterization_info.rasterizerDiscardEnable = VK_FALSE; rasterization_info.polygonMode = VK_POLYGON_MODE_FILL; rasterization_info.lineWidth = 1.0f; rasterization_info.cullMode = VK_CULL_MODE_BACK_BIT; rasterization_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rasterization_info.depthBiasEnable = VK_FALSE; VkPipelineMultisampleStateCreateInfo multisample_info{}; multisample_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisample_info.sampleShadingEnable = VK_FALSE; multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState color_blend_attachment_state{}; color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; color_blend_attachment_state.blendEnable = VK_TRUE; color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; VkPipelineColorBlendStateCreateInfo color_blend_info{}; color_blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; color_blend_info.logicOpEnable = VK_FALSE; color_blend_info.attachmentCount = 1; color_blend_info.pAttachments = &color_blend_attachment_state; color_blend_info.blendConstants[0] = 0.0f; color_blend_info.blendConstants[1] = 0.0f; color_blend_info.blendConstants[2] = 0.0f; color_blend_info.blendConstants[3] = 0.0f; VkPipelineLayoutCreateInfo pipeline_layout_info{}; pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_info.setLayoutCount = 1; pipeline_layout_info.pSetLayouts = &ubo_layout_binding_; VK_CHECK(vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, &pipeline_layout_)); VkGraphicsPipelineCreateInfo graphics_pipeline_info{}; graphics_pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; graphics_pipeline_info.stageCount = 2; graphics_pipeline_info.pStages = shader_stages; graphics_pipeline_info.layout = pipeline_layout_; graphics_pipeline_info.pColorBlendState = &color_blend_info; graphics_pipeline_info.pDynamicState = &dynamic_state_info; graphics_pipeline_info.pInputAssemblyState = &input_assembly_info; graphics_pipeline_info.pMultisampleState = &multisample_info; graphics_pipeline_info.pRasterizationState = &rasterization_info; graphics_pipeline_info.pViewportState = &viewport_info; graphics_pipeline_info.pVertexInputState = &vertex_input_info; graphics_pipeline_info.pDepthStencilState = nullptr; graphics_pipeline_info.renderPass = render_pass_; graphics_pipeline_info.subpass = 0; graphics_pipeline_info.basePipelineHandle = nullptr; graphics_pipeline_info.basePipelineIndex = -1; VK_CHECK(vkCreateGraphicsPipelines(device_, nullptr, 1, &graphics_pipeline_info, nullptr, &graphics_pipeline_)); vkDestroyShaderModule(device_, vertex_shader, nullptr); vkDestroyShaderModule(device_, fragment_shader, nullptr); } void UwURenderEngine::create_framebuffers() { framebuffers_.resize(swapchain_images_.size()); VkFramebufferCreateInfo framebuffer_info{}; framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebuffer_info.renderPass = render_pass_; framebuffer_info.attachmentCount = 1; framebuffer_info.width = swapchain_extent_.width; framebuffer_info.height = swapchain_extent_.height; framebuffer_info.layers = 1; for (size_t i = 0; i < framebuffers_.size(); ++i) { framebuffer_info.pAttachments = &swapchain_image_views_[i]; VK_CHECK(vkCreateFramebuffer(device_, &framebuffer_info, nullptr, &framebuffers_[i])); } } void UwURenderEngine::create_command_pool() { QueueFamilyIndices queue_family_indices = find_queue_family_indices(physical_device_, surface_); VkCommandPoolCreateInfo command_pool_info{}; command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; command_pool_info.queueFamilyIndex = queue_family_indices.graphics_family.value(); command_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VK_CHECK(vkCreateCommandPool(device_, &command_pool_info, nullptr, &command_pool_)); } uint32_t UwURenderEngine::find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const { VkPhysicalDeviceMemoryProperties memory_properties{}; vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties); for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i) { if (typeFilter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties) return i; } throw std::runtime_error("failed to find suitable memory type!"); } std::vector UwURenderEngine::get_unique_family_indices(const QueueFamilyIndices& indices) { std::set set_indices = {indices.graphics_family.value(), indices.present_family.value(), indices.transfer_family.value()}; std::vector arr_indices; arr_indices.reserve(set_indices.size()); for (auto& i : set_indices) arr_indices.push_back(i); return arr_indices; } void UwURenderEngine::allocate_vertex_buffer() { QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); std::vector arr_indices = get_unique_family_indices(indices); std::vector transfer_index = {indices.transfer_family.value()}; VkBuffer staging_buffer = VK_NULL_HANDLE; VkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE; VkDeviceSize size_buffer = sizeof(vertices_[0]) * vertices_.size(); create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &staging_buffer, transfer_index); allocate_memory(staging_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buffer_memory); create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &vertex_buffer_, arr_indices); allocate_memory(vertex_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertex_buffer_memory_); VK_CHECK(vkBindBufferMemory(device_, staging_buffer, staging_buffer_memory, 0)); VK_CHECK(vkBindBufferMemory(device_, vertex_buffer_, vertex_buffer_memory_, 0)); void* data; VK_CHECK(vkMapMemory(device_, staging_buffer_memory, 0, size_buffer, 0, &data)); memcpy(data, vertices_.data(), size_buffer); vkUnmapMemory(device_, staging_buffer_memory); copy_memory(staging_buffer, vertex_buffer_, size_buffer); vkFreeMemory(device_, staging_buffer_memory, nullptr); vkDestroyBuffer(device_, staging_buffer, nullptr); } void UwURenderEngine::allocate_index_buffer() { QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); std::set set_indices = {indices.graphics_family.value(), indices.present_family.value(), indices.transfer_family.value()}; std::vector arr_indices = get_unique_family_indices(indices); std::vector transfer_index = {indices.transfer_family.value()}; VkBuffer staging_buffer = VK_NULL_HANDLE; VkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE; VkDeviceSize size_buffer = sizeof(indices_[0]) * indices_.size(); create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &staging_buffer, transfer_index); allocate_memory(staging_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buffer_memory); vkBindBufferMemory(device_, staging_buffer, staging_buffer_memory, 0); void* data; vkMapMemory(device_, staging_buffer_memory, 0, size_buffer, 0, &data); memcpy(data, indices_.data(), size_buffer); vkUnmapMemory(device_, staging_buffer_memory); create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, &index_buffer_, arr_indices); allocate_memory(index_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &index_buffer_memory_); vkBindBufferMemory(device_, index_buffer_, index_buffer_memory_, 0); copy_memory(staging_buffer, index_buffer_, size_buffer); vkDestroyBuffer(device_, staging_buffer, nullptr); vkFreeMemory(device_, staging_buffer_memory, nullptr); } void UwURenderEngine::copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size) { QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); VkCommandPool copy_pool; VkCommandPoolCreateInfo copy_pool_info{}; copy_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; copy_pool_info.queueFamilyIndex = indices.transfer_family.value(); copy_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VK_CHECK(vkCreateCommandPool(device_, ©_pool_info, nullptr, ©_pool)); VkCommandBufferAllocateInfo command_buffer_allocate_info{}; command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_buffer_allocate_info.commandPool = copy_pool; command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; command_buffer_allocate_info.commandBufferCount = 1; VkCommandBuffer copy_buffer; VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, ©_buffer)); VkCommandBufferBeginInfo command_buffer_begin_info{}; command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; VK_CHECK(vkBeginCommandBuffer(copy_buffer, &command_buffer_begin_info)); VkBufferCopy buffer_copy{}; buffer_copy.srcOffset = 0; buffer_copy.dstOffset = 0; buffer_copy.size = size; vkCmdCopyBuffer(copy_buffer, src, dst, 1, &buffer_copy); vkEndCommandBuffer(copy_buffer); VkSubmitInfo submit_info{}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = ©_buffer; vkQueueSubmit(transfer_queue_, 1, &submit_info, VK_NULL_HANDLE); vkQueueWaitIdle(transfer_queue_); vkFreeCommandBuffers(device_, copy_pool, 1, ©_buffer); vkDestroyCommandPool(device_, copy_pool, nullptr); } void UwURenderEngine::allocate_command_buffers() { command_buffers_.resize(swapchain_images_.size()); VkCommandBufferAllocateInfo command_buffer_allocate_info{}; command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_buffer_allocate_info.commandPool = command_pool_; command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; command_buffer_allocate_info.commandBufferCount = static_cast(command_buffers_.size()); VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, command_buffers_.data())); } void UwURenderEngine::create_sync_objects() { image_available_semaphores_.resize(swapchain_images_.size()); render_finished_semaphores_.resize(swapchain_images_.size()); in_flight_fences_.resize(swapchain_images_.size()); VkSemaphoreCreateInfo semaphore_info{}; semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VkFenceCreateInfo fence_info{}; fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; for (size_t i = 0; i < swapchain_images_.size(); ++i) { VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &image_available_semaphores_[i])); VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &render_finished_semaphores_[i])); VK_CHECK(vkCreateFence(device_, &fence_info, nullptr, &in_flight_fences_[i])); } } void UwURenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const { VkCommandBufferBeginInfo command_buffer_begin_info{}; command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; VK_CHECK(vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info)); constexpr VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; VkRenderPassBeginInfo render_pass_begin_info{}; render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin_info.renderPass = render_pass_; render_pass_begin_info.framebuffer = framebuffers_[image_index]; render_pass_begin_info.renderArea.offset = {0, 0}; render_pass_begin_info.renderArea.extent = swapchain_extent_; render_pass_begin_info.clearValueCount = 1; render_pass_begin_info.pClearValues = &clear_color; vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_); VkBuffer vertex_buffers[] = {vertex_buffer_}; VkDeviceSize offset[] = {0}; vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offset); vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_, 0, 1, &descriptor_sets_[current_frame_], 0, nullptr); vkCmdBindIndexBuffer(command_buffer, index_buffer_, 0, VK_INDEX_TYPE_UINT16); VkViewport viewport; viewport.x = 0.0f; viewport.y = 0.0f; viewport.width = static_cast(swapchain_extent_.width); viewport.height = static_cast(swapchain_extent_.height); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; vkCmdSetViewport(command_buffer, 0, 1, &viewport); VkRect2D scissor; scissor.offset = {0, 0}; scissor.extent = swapchain_extent_; vkCmdSetScissor(command_buffer, 0, 1, &scissor); vkCmdDrawIndexed(command_buffer, static_cast(indices_.size()), 1, 0, 0, 0); vkCmdEndRenderPass(command_buffer); VK_CHECK(vkEndCommandBuffer(command_buffer)); } void UwURenderEngine::update_uniform_buffer(uint32_t current_frame) { static auto start_time = std::chrono::high_resolution_clock::now(); auto current_time = std::chrono::high_resolution_clock::now(); float time = std::chrono::duration_cast>(current_time - start_time).count(); UniformBufferObject ubo{}; ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f)); ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); ubo.proj = glm::perspective(glm::radians(45.0f), static_cast(swapchain_extent_.width) / static_cast(swapchain_extent_.height), 0.1f, 256.0f); ubo.proj[1][1] *= -1; memcpy(uniform_buffers_mapped_[current_frame], &ubo, sizeof(ubo)); } void UwURenderEngine::draw_frame() { vkWaitForFences(device_, 1, &in_flight_fences_[current_frame_], VK_TRUE, UINT64_MAX); vkResetFences(device_, 1, &in_flight_fences_[current_frame_]); uint32_t image_index; vkAcquireNextImageKHR(device_, swapchain_, UINT64_MAX, image_available_semaphores_[current_frame_], VK_NULL_HANDLE, &image_index); vkResetCommandBuffer(command_buffers_[current_frame_], 0); record_command_buffer(command_buffers_[current_frame_], image_index); update_uniform_buffer(current_frame_); VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submit_info{}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &command_buffers_[current_frame_]; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &image_available_semaphores_[current_frame_]; submit_info.pWaitDstStageMask = &wait_stage; submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = &render_finished_semaphores_[current_frame_]; VK_CHECK(vkQueueSubmit(graphics_queue_, 1, &submit_info, in_flight_fences_[current_frame_])); VkPresentInfoKHR present_info{}; present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present_info.waitSemaphoreCount = 1; present_info.pWaitSemaphores = &render_finished_semaphores_[current_frame_]; present_info.swapchainCount = 1; present_info.pSwapchains = &swapchain_; present_info.pImageIndices = &image_index; present_info.pResults = nullptr; vkQueuePresentKHR(present_queue_, &present_info); current_frame_ = (current_frame_ + 1) % static_cast(swapchain_images_.size()); } void UwURenderEngine::create_surface() { VK_CHECK(glfwCreateWindowSurface(instance_, get_window(), nullptr, &surface_)); } UwURenderEngine::UwURenderEngine(CoreInstance& core): core_(core) #ifdef _DEBUG ,debug_messenger_(nullptr) #endif { create_instance(); create_surface(); pick_physical_device(); create_logical_device(); create_swapchain(); create_image_views(); create_render_pass(); create_description_set_layout(); create_uniform_buffers(); create_descriptor_pool(); create_descriptor_sets(); create_graphics_pipeline(); create_framebuffers(); create_command_pool(); allocate_vertex_buffer(); allocate_command_buffers(); allocate_index_buffer(); create_sync_objects(); } UwURenderEngine::~UwURenderEngine() { vkDeviceWaitIdle(device_); if (index_buffer_memory_ != VK_NULL_HANDLE) vkFreeMemory(device_, index_buffer_memory_, nullptr); if (index_buffer_ != VK_NULL_HANDLE) vkDestroyBuffer(device_, index_buffer_, nullptr); if (vertex_buffer_memory_ != VK_NULL_HANDLE) vkFreeMemory(device_, vertex_buffer_memory_, nullptr); if (vertex_buffer_ != VK_NULL_HANDLE) vkDestroyBuffer(device_, vertex_buffer_, nullptr); for (auto& i : image_available_semaphores_) vkDestroySemaphore(device_, i, nullptr); for (auto& i : render_finished_semaphores_) vkDestroySemaphore(device_, i, nullptr); for (auto& i : in_flight_fences_) vkDestroyFence(device_, i, nullptr); if (command_buffers_.empty() == false) vkFreeCommandBuffers(device_, command_pool_, static_cast(command_buffers_.size()), command_buffers_.data()); if (command_pool_ != VK_NULL_HANDLE) vkDestroyCommandPool(device_, command_pool_, nullptr); for (auto& i : framebuffers_) vkDestroyFramebuffer(device_, i, nullptr); if (graphics_pipeline_ != VK_NULL_HANDLE) vkDestroyPipeline(device_, graphics_pipeline_, nullptr); if (pipeline_layout_ != VK_NULL_HANDLE) vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr); for (size_t i = 0; i < uniform_buffers_.size(); ++i) { vkUnmapMemory(device_, uniform_buffers_memory_[i]); vkFreeMemory(device_, uniform_buffers_memory_[i], nullptr); vkDestroyBuffer(device_, uniform_buffers_[i], nullptr); } uniform_buffers_.clear(); uniform_buffers_memory_.clear(); uniform_buffers_mapped_.clear(); vkDestroyDescriptorPool(device_, descriptor_pool_, nullptr); if (ubo_layout_binding_ != VK_NULL_HANDLE) vkDestroyDescriptorSetLayout(device_, ubo_layout_binding_, nullptr); if (render_pass_ != VK_NULL_HANDLE) vkDestroyRenderPass(device_, render_pass_, nullptr); for (auto image_view : swapchain_image_views_) vkDestroyImageView(device_, image_view, nullptr); swapchain_image_views_.clear(); if (swapchain_ != VK_NULL_HANDLE) vkDestroySwapchainKHR(device_, swapchain_, nullptr); if (device_ != VK_NULL_HANDLE) vkDestroyDevice(device_, nullptr); if (surface_ != VK_NULL_HANDLE) vkDestroySurfaceKHR(instance_, surface_, nullptr); #ifdef _DEBUG if (debug_messenger_ != nullptr && instance_ != nullptr) { PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT")); destroyer_messenger(instance_, debug_messenger_, nullptr); } #endif if (instance_ != VK_NULL_HANDLE) vkDestroyInstance(instance_, nullptr); } void UwURenderEngine::start() { World* world = core_.GetGameInstance()->GetWorld(); std::vector> meshes = world->GetActorsByClass(); for (auto& i : meshes) i->load_model(i->GetModelName()); while (!glfwWindowShouldClose(get_window())) { glfwPollEvents(); draw_frame(); } } void UwURenderEngine::stop_render() const { if (!glfwWindowShouldClose(get_window())) glfwSetWindowShouldClose(get_window(), true); }