diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index ed2cc7a..d4c4d5c 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -66,12 +66,6 @@ std::vector RenderEngine::get_required_extensions() return extensions; } - -bool RenderEngine::QueueFamilyIndices::is_complete() const -{ - return graphics_family.has_value() && present_family.has_value(); -} - VkVertexInputBindingDescription RenderEngine::Vertex::get_binding_description() { VkVertexInputBindingDescription description; @@ -103,9 +97,13 @@ bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surf vkGetPhysicalDeviceProperties(device, &device_properties); vkGetPhysicalDeviceFeatures(device, &device_features); - QueueFamilyIndices indices = find_queue_family_indices(device, surface); + try { + QueueFamilyIndices indices = find_queue_family_indices(device, surface); + } catch (...) { + return false; + } - return indices.is_complete() && check_device_extensions_support(device); + return check_device_extensions_support(device); } bool RenderEngine::check_device_extensions_support(VkPhysicalDevice device) @@ -141,19 +139,50 @@ RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysi std::vector family_properties(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_properties.data()); - for (uint32_t i = 0; i < family_properties.size(); ++i) + // 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; - - VkBool32 present_support = false; - VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support)); - if (present_support) - queue_family_indices.present_family = i; - if(queue_family_indices.is_complete()) 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; } @@ -206,6 +235,43 @@ VkShaderModule RenderEngine::create_shader_module(const std::string& code) const return shader_module; } +void RenderEngine::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 RenderEngine::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 RenderEngine::create_instance() { std::vector extensions = get_required_extensions(); @@ -274,7 +340,9 @@ void RenderEngine::create_logical_device() VkPhysicalDeviceFeatures device_features{}; std::vector queue_create_infos; - std::set unique_queue_families = {indices.graphics_family.value(), indices.present_family.value()}; + 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{}; @@ -309,6 +377,7 @@ void RenderEngine::create_logical_device() 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 RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode) @@ -338,12 +407,20 @@ void RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode) swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_); - uint32_t queue_family_indices[] = {family_indices.graphics_family.value(), family_indices.present_family.value()}; - if (family_indices.graphics_family != family_indices.present_family) + 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 = 2; - swapchain_create_info.pQueueFamilyIndices = queue_family_indices; + swapchain_create_info.queueFamilyIndexCount = static_cast(arr_families.size()); + swapchain_create_info.pQueueFamilyIndices = arr_families.data(); } else { @@ -614,29 +691,84 @@ uint32_t RenderEngine::find_memory_type(uint32_t typeFilter, VkMemoryPropertyFla void RenderEngine::allocate_vertex_buffer() { - VkBufferCreateInfo buffer_info{}; - buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_info.size = sizeof(vertices[0]) * vertices.size(); - buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + 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; + std::vector transfer_index = {indices.transfer_family.value()}; + arr_indices.reserve(set_indices.size()); + for (auto& i : set_indices) + arr_indices.push_back(i); - VK_CHECK(vkCreateBuffer(device_, &buffer_info, nullptr, &vertex_buffer_)); - - VkMemoryRequirements requirements{}; - vkGetBufferMemoryRequirements(device_, vertex_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, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - VK_CHECK(vkAllocateMemory(device_, &allocate_info, nullptr, &vertex_buffer_memory_)); + + 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_, vertex_buffer_memory_, 0, buffer_info.size, 0, &data)); - memcpy(data, vertices.data(), buffer_info.size); - vkUnmapMemory(device_, vertex_buffer_memory_); + 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 RenderEngine::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 RenderEngine::allocate_command_buffers() @@ -784,7 +916,7 @@ window_(window) RenderEngine::~RenderEngine() { vkDeviceWaitIdle(device_); - + if (vertex_buffer_memory_ != VK_NULL_HANDLE) vkFreeMemory(device_, vertex_buffer_memory_, nullptr); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index b2b808c..cdef903 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -26,7 +26,7 @@ class RenderEngine { std::optional graphics_family; std::optional present_family; - bool is_complete() const; + std::optional transfer_family; }; struct SwapchainSupportDetails { @@ -52,6 +52,7 @@ class RenderEngine VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE; uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const; void allocate_vertex_buffer(); + void copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size); #pragma endregion static const std::vector deviceExtensions; @@ -66,6 +67,7 @@ class RenderEngine VkDevice device_ = VK_NULL_HANDLE; VkQueue graphics_queue_ = VK_NULL_HANDLE; VkQueue present_queue_ = VK_NULL_HANDLE; + VkQueue transfer_queue_ = VK_NULL_HANDLE; VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; std::vector swapchain_images_; VkFormat swapchain_image_format_; @@ -95,6 +97,9 @@ class RenderEngine static VkPresentModeKHR choose_present_mode(const std::vector& present_modes, VkPresentModeKHR desired_present_mode); static VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window); VkShaderModule create_shader_module(const std::string& code) const; + void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, + VkBuffer* buffer, const std::vector& queue_families); + void allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory); void create_instance(); void create_surface();