Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "Application.h"
- bool requiredExtensionsAvailable(std::vector<const char*> requiredExtensions, std::vector<VkExtensionProperties> availableExtensions);
- Application::Application() {};
- Application::~Application() {};
- // *************************************************************
- // *************** Uniform Descriptor ************************
- // *************************************************************
- void Application::createDescriptorSetLayout()
- {
- VkDescriptorSetLayoutBinding uboLayoutBinding = {};
- uboLayoutBinding.binding = 0;
- uboLayoutBinding.descriptorCount = 1;
- uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
- uboLayoutBinding.pImmutableSamplers = nullptr;
- VkDescriptorSetLayoutCreateInfo layoutInfo = {};
- layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- layoutInfo.bindingCount = 1;
- layoutInfo.pBindings = &uboLayoutBinding;
- VkResult result = vkCreateDescriptorSetLayout(m_device, &layoutInfo, nullptr, &m_descriptorSetLayout);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create descriptor set layout!");
- }
- void Application::createDescriptorPool()
- {
- VkDescriptorPoolSize poolSize = {};
- poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- poolSize.descriptorCount = static_cast<uint32_t>(m_swapChainImages.size());
- VkDescriptorPoolCreateInfo poolInfo = {};
- poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
- poolInfo.poolSizeCount = 1;
- poolInfo.pPoolSizes = &poolSize;
- poolInfo.maxSets = static_cast<uint32_t>(m_swapChainImages.size());
- poolInfo.flags = 0;
- VkResult result = vkCreateDescriptorPool(m_device, &poolInfo, nullptr, &m_descriptorPool);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create descriptor pool!");
- }
- void Application::createDescriptorSets()
- {
- std::vector<VkDescriptorSetLayout> layouts(m_swapChainImages.size(), m_descriptorSetLayout);
- VkDescriptorSetAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- allocInfo.descriptorPool = m_descriptorPool;
- allocInfo.descriptorSetCount = static_cast<uint32_t>(m_swapChainImages.size());
- allocInfo.pSetLayouts = layouts.data();
- m_descriptorSets.resize(m_swapChainImages.size());
- VkResult result = vkAllocateDescriptorSets(m_device, &allocInfo, m_descriptorSets.data());
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to allocate descriptor sets!");
- for (size_t i = 0; i < m_swapChainImages.size(); i++)
- {
- VkDescriptorBufferInfo bufferInfo = {};
- bufferInfo.buffer = m_uniformBuffers[i];
- bufferInfo.offset = 0;
- bufferInfo.range = sizeof(UniformBufferObject);
- VkWriteDescriptorSet descriptorWrite = {};
- descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- descriptorWrite.dstSet = m_descriptorSets[i];
- descriptorWrite.dstBinding = 0;
- descriptorWrite.dstArrayElement = 0;
- descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptorWrite.descriptorCount = 1;
- descriptorWrite.pBufferInfo = &bufferInfo;
- descriptorWrite.pImageInfo = nullptr;
- descriptorWrite.pTexelBufferView = nullptr;
- vkUpdateDescriptorSets(m_device, 1, &descriptorWrite, 0, nullptr);
- }
- }
- // *************************************************************
- // *************** Buffers ************************
- // *************************************************************
- void Application::createFramebuffers()
- {
- m_swapChainFramebuffers.resize(m_swapChainImageViews.size());
- for (size_t i = 0; i < m_swapChainImageViews.size(); i++)
- {
- VkImageView attachments[] =
- {
- m_swapChainImageViews[i]
- };
- VkFramebufferCreateInfo framebufferInfo = {};
- framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- framebufferInfo.renderPass = m_renderPass;
- framebufferInfo.attachmentCount = 1;
- framebufferInfo.pAttachments = attachments;
- framebufferInfo.width = m_swapChainExtent.width;
- framebufferInfo.height = m_swapChainExtent.height;
- framebufferInfo.layers = 1;
- VkResult result = vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &m_swapChainFramebuffers[i]);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create framebuffer!");
- }
- #ifndef NDEBUG
- if (!m_recreatingSwapChain)
- spdlog::info("Successfully created framebuffers.");
- #endif
- }
- void Application::createVertexBuffers()
- {
- VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
- VkBuffer stagingBuffer;
- VkDeviceMemory stagingBufferMemory;
- createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
- void* data;
- vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &data);
- memcpy(data, vertices.data(), (size_t)bufferSize);
- vkUnmapMemory(m_device, stagingBufferMemory);
- createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_vertexBuffer, m_vertexBufferMemory);
- copyBuffer(stagingBuffer, m_vertexBuffer, bufferSize);
- vkDestroyBuffer(m_device, stagingBuffer, nullptr);
- vkFreeMemory(m_device, stagingBufferMemory, nullptr);
- #ifndef NDEBUG
- spdlog::info("Successfully created vertex buffer.");
- #endif
- }
- void Application::createIndexBuffer()
- {
- VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();
- VkBuffer stagingBuffer;
- VkDeviceMemory stagingBufferMemory;
- createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
- void* data;
- vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &data);
- memcpy(data, indices.data(), (size_t)bufferSize);
- vkUnmapMemory(m_device, stagingBufferMemory);
- createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_indexBuffer, m_indexBufferMemory);
- copyBuffer(stagingBuffer, m_indexBuffer, bufferSize);
- vkDestroyBuffer(m_device, stagingBuffer, nullptr);
- vkFreeMemory(m_device, stagingBufferMemory, nullptr);
- #ifndef NDEBUG
- spdlog::info("Successfully created index buffer.");
- #endif
- }
- void Application::createUniformBuffers()
- {
- VkDeviceSize bufferSize = sizeof(UniformBufferObject);
- m_uniformBuffers.resize(m_swapChainImages.size());
- m_uniformBuffersMemory.resize(m_swapChainImages.size());
- for (size_t i = 0; i < m_swapChainImages.size(); i++)
- {
- createBuffer(
- bufferSize,
- VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
- VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- m_uniformBuffers[i],
- m_uniformBuffersMemory[i]
- );
- }
- }
- void Application::updateUniformBuffers(uint32_t currentImage)
- {
- static auto startTime = std::chrono::high_resolution_clock::now();
- auto currentTime = std::chrono::high_resolution_clock::now();
- float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();
- UniformBufferObject ubo = {};
- ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.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), m_swapChainExtent.width / (float)m_swapChainExtent.height, 0.1f, 10.0f);
- // Flip the Y-axis coordinates, because glm is designed for OpenGL
- ubo.proj[1][1] *= -1;
- void* data;
- vkMapMemory(m_device, m_uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
- memcpy(data, &ubo, sizeof(ubo));
- vkUnmapMemory(m_device, m_uniformBuffersMemory[currentImage]);
- }
- void Application::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory)
- {
- VkBufferCreateInfo bufferInfo = {};
- bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- bufferInfo.size = size;
- bufferInfo.usage = usage;
- bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- VkResult result = vkCreateBuffer(m_device, &bufferInfo, nullptr, &buffer);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create buffer!");
- VkMemoryRequirements memRequirements;
- vkGetBufferMemoryRequirements(m_device, buffer, &memRequirements);
- VkMemoryAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- allocInfo.allocationSize = memRequirements.size;
- allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);
- if (vkAllocateMemory(m_device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS)
- throw std::runtime_error("Failed to allocate buffer memory");
- vkBindBufferMemory(m_device, buffer, bufferMemory, 0);
- }
- void Application::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size)
- {
- VkCommandBufferAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- allocInfo.commandPool = m_tempCommandPool;
- allocInfo.commandBufferCount = 1;
- VkCommandBuffer commandBuffer;
- vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer);
- VkCommandBufferBeginInfo beginInfo = {};
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- vkBeginCommandBuffer(commandBuffer, &beginInfo);
- VkBufferCopy copyRegion = {};
- copyRegion.srcOffset = 0;
- copyRegion.dstOffset = 0;
- copyRegion.size = size;
- vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region);
- vkEndCommandBuffer(commandBuffer);
- VkSubmitInfo submitInfo = {};
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &commandBuffer;
- vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
- vkQueueWaitIdle(m_graphicsQueue);
- vkFreeCommandBuffers(m_device, m_tempCommandPool, 1, &commandBuffer);
- }
- uint32_t Application::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
- {
- VkPhysicalDeviceMemoryProperties memProperties;
- vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memProperties);
- for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
- {
- if (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
- return i;
- }
- throw std::runtime_error("Failed to find suitable memory type!");
- }
- // *************************************************************
- // *************** Swapchain ************************
- // *************************************************************
- void Application::createSwapChain()
- {
- SwapChainSupportDetails swapChainSupport = querySwapChainSupport(m_physicalDevice);
- VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
- VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
- VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
- uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
- if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount)
- imageCount = swapChainSupport.capabilities.maxImageCount;
- VkSwapchainCreateInfoKHR createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- createInfo.surface = m_surface;
- createInfo.minImageCount = imageCount;
- createInfo.imageFormat = surfaceFormat.format;
- createInfo.imageColorSpace = surfaceFormat.colorSpace;
- createInfo.imageExtent = extent;
- createInfo.imageArrayLayers = 1;
- createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- uint32_t queueFamilyIndices[] = { m_indices.graphicsFamily.value(), m_indices.presentFamily.value() };
- if (m_indices.graphicsFamily != m_indices.presentFamily)
- {
- createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
- createInfo.queueFamilyIndexCount = 2;
- createInfo.pQueueFamilyIndices = queueFamilyIndices;
- }
- else
- {
- createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- createInfo.queueFamilyIndexCount = 0;
- createInfo.pQueueFamilyIndices = nullptr;
- }
- createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
- createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- createInfo.presentMode = presentMode;
- createInfo.clipped = VK_TRUE;
- createInfo.oldSwapchain = VK_NULL_HANDLE;
- VkResult result = vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapChain);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create swapchain!");
- vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, nullptr);
- m_swapChainImages.resize(imageCount);
- vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, m_swapChainImages.data());
- m_swapChainImageFormat = surfaceFormat.format;
- m_swapChainExtent = extent;
- #ifndef NDEBUG
- if (!m_recreatingSwapChain)
- spdlog::info("Successfully created swapchain.");
- #endif
- }
- void Application::cleanupSwapChain()
- {
- // Framebuffers
- for (auto framebuffer : m_swapChainFramebuffers)
- vkDestroyFramebuffer(m_device, framebuffer, nullptr);
- // Command buffers
- vkFreeCommandBuffers(m_device, m_commandPool, static_cast<uint32_t>(m_commandBuffers.size()), m_commandBuffers.data());
- // Graphics pipeline
- vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
- vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
- vkDestroyRenderPass(m_device, m_renderPass, nullptr);
- // Image views
- for (auto imageView : m_swapChainImageViews)
- vkDestroyImageView(m_device, imageView, nullptr);
- // Swapchain
- vkDestroySwapchainKHR(m_device, m_swapChain, nullptr);
- }
- void Application::recreateSwapChain()
- {
- m_recreatingSwapChain = true;
- while (m_framebufferWidth == 0 || m_framebufferHeight == 0)
- {
- glfwGetFramebufferSize(m_window, &m_framebufferWidth, &m_framebufferHeight);
- glfwWaitEvents();
- }
- vkDeviceWaitIdle(m_device);
- cleanupSwapChain();
- createSwapChain();
- createImageViews();
- createRenderPass();
- createGraphicsPipeline();
- createFramebuffers();
- createCommandBuffers();
- m_recreatingSwapChain = false;
- }
- SwapChainSupportDetails Application::querySwapChainSupport(VkPhysicalDevice device)
- {
- SwapChainSupportDetails details;
- vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, m_surface, &details.capabilities);
- uint32_t formatCount;
- vkGetPhysicalDeviceSurfaceFormatsKHR(device, m_surface, &formatCount, nullptr);
- if (formatCount != 0)
- {
- details.formats.resize(formatCount);
- vkGetPhysicalDeviceSurfaceFormatsKHR(device, m_surface, &formatCount, details.formats.data());
- }
- uint32_t presentModeCount;
- vkGetPhysicalDeviceSurfacePresentModesKHR(device, m_surface, &presentModeCount, nullptr);
- if (presentModeCount != 0)
- {
- details.presentModes.resize(presentModeCount);
- vkGetPhysicalDeviceSurfacePresentModesKHR(device, m_surface, &presentModeCount, details.presentModes.data());
- }
- return details;
- }
- VkSurfaceFormatKHR Application::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
- {
- if (availableFormats.size() == 1 && availableFormats[0].format == VK_FORMAT_UNDEFINED)
- return { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
- for (const auto& availableFormat : availableFormats)
- {
- if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
- return availableFormat;
- }
- return availableFormats[0];
- }
- VkPresentModeKHR Application::chooseSwapPresentMode(const std::vector<VkPresentModeKHR> availablePresentModes)
- {
- VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
- for (const auto& availablePresentMode : availablePresentModes)
- {
- if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
- return availablePresentMode;
- else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR)
- bestMode = availablePresentMode;
- }
- return bestMode;
- }
- VkExtent2D Application::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
- {
- if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
- return capabilities.currentExtent;
- else
- {
- int width, height;
- glfwGetFramebufferSize(m_window, &width, &height);
- VkExtent2D actualExtent =
- {
- static_cast<uint32_t>(width),
- static_cast<uint32_t>(height)
- };
- return actualExtent;
- }
- }
- // *************************************************************
- // *************** Instance ************************
- // *************************************************************
- void Application::createInstance()
- {
- if (enableValidationLayers && !checkValidationLayerSupport())
- throw std::runtime_error("Validation layers requested, but not available!");
- // Application Info
- VkApplicationInfo appInfo = {};
- appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- appInfo.pApplicationName = "Volcanic Engine";
- appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
- appInfo.pEngineName = "Volcanic Engine";
- appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
- appInfo.apiVersion = VK_API_VERSION_1_0;
- // Instance Create Info
- VkInstanceCreateInfo createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- createInfo.pApplicationInfo = &appInfo;
- auto requiredExtensions = getRequiredExtensions();
- createInfo.enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size());
- createInfo.ppEnabledExtensionNames = requiredExtensions.data();
- if (enableValidationLayers)
- {
- createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
- createInfo.ppEnabledLayerNames = validationLayers.data();
- }
- else
- {
- createInfo.enabledLayerCount = 0;
- }
- VkResult result = vkCreateInstance(&createInfo, nullptr, &m_instance);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create instance!");
- uint32_t extensionCount;
- vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
- std::vector<VkExtensionProperties> availableExtensions(extensionCount);
- vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, availableExtensions.data());
- #if LOGEXTENSIONS
- std::cout << "Available extensions" << std::endl;
- for (const auto& extension : availableExtensions)
- std::cout << "\t" << extension.extensionName << std::endl;
- #endif
- if (requiredExtensionsAvailable(requiredExtensions, availableExtensions))
- {
- #ifndef NDEBUG
- spdlog::info("All required extensions available.");
- #endif
- }
- else
- spdlog::error("Not all required extensions are available!");
- #ifndef NDEBUG
- spdlog::info("Successfully created instance.");
- #endif
- }
- bool Application::checkValidationLayerSupport()
- {
- uint32_t layerCount;
- vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
- std::vector<VkLayerProperties> availableLayers(layerCount);
- vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
- for (const char* layerName : validationLayers)
- {
- bool layerFound;
- for (const auto& layerProperties : availableLayers)
- {
- if (strcmp(layerName, layerProperties.layerName) == 0)
- {
- layerFound = true;
- break;
- }
- }
- if (!layerFound)
- return false;
- }
- return true;
- }
- std::vector<const char*> Application::getRequiredExtensions()
- {
- uint32_t glfwExtensionCount = 0;
- const char** glfwExtensions;
- glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
- std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
- if (enableValidationLayers)
- extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
- #if LOGEXTENSIONS
- std::cout << "Required extensions:" << std::endl;
- for (const auto& extension : extensions)
- std::cout << "\t" << extension << std::endl;
- #endif
- return extensions;
- }
- bool requiredExtensionsAvailable(std::vector<const char*> requiredExtensions, std::vector<VkExtensionProperties> availableExtensions)
- {
- for (const char* requiredExtension : requiredExtensions)
- {
- bool found = false;
- for (const auto& availableExtension : availableExtensions)
- {
- if (strcmp(requiredExtension, availableExtension.extensionName))
- found = true;
- }
- if (!found)
- return false;
- }
- return true;
- }
- // *************************************************************
- // *************** Surface ************************
- // *************************************************************
- void Application::createSurface()
- {
- VkResult result = glfwCreateWindowSurface(m_instance, m_window, nullptr, &m_surface);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create window surface!");
- #ifndef NDEBUG
- spdlog::info("Successfully created window surface.");
- #endif
- }
- void Application::createImageViews()
- {
- m_swapChainImageViews.resize(m_swapChainImages.size());
- for (size_t i = 0; i < m_swapChainImages.size(); i++)
- {
- VkImageViewCreateInfo createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- createInfo.image = m_swapChainImages[i];
- createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
- createInfo.format = m_swapChainImageFormat;
- createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- createInfo.subresourceRange.baseMipLevel = 0;
- createInfo.subresourceRange.levelCount = 1;
- createInfo.subresourceRange.baseArrayLayer = 0;
- createInfo.subresourceRange.layerCount = 1;
- VkResult result = vkCreateImageView(m_device, &createInfo, nullptr, &m_swapChainImageViews[i]);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create image views!");
- }
- #ifndef NDEBUG
- if (!m_recreatingSwapChain)
- spdlog::info("Successfully created image views.");
- #endif
- }
- // *************************************************************
- // *************** Pipeline ************************
- // *************************************************************
- void Application::createRenderPass()
- {
- VkAttachmentDescription colorAttachment = {};
- colorAttachment.format = m_swapChainImageFormat;
- colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
- colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
- VkAttachmentReference colorAttachmentRef = {};
- colorAttachmentRef.attachment = 0;
- colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- VkSubpassDescription subpass = {};
- subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass.colorAttachmentCount = 1;
- subpass.pColorAttachments = &colorAttachmentRef;
- 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_READ_BIT
- | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- VkRenderPassCreateInfo renderPassInfo = {};
- renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- renderPassInfo.attachmentCount = 1;
- renderPassInfo.pAttachments = &colorAttachment;
- renderPassInfo.subpassCount = 1;
- renderPassInfo.pSubpasses = &subpass;
- renderPassInfo.dependencyCount = 1;
- renderPassInfo.pDependencies = &dependency;
- VkResult result = vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &m_renderPass);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create render pass!");
- #ifndef NDEBUG
- if (!m_recreatingSwapChain)
- spdlog::info("Successfully created render pass.");
- #endif
- }
- void Application::compileShaders(const char* vertPath, const char* fragPath)
- {
- // TODO: Automatically compile shaders.
- }
- void Application::createGraphicsPipeline()
- {
- std::vector<char> vertShaderCode = readFile("shaders/vert.spv");
- std::vector<char> fragShaderCode = readFile("shaders/frag.spv");
- VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
- VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
- std::vector<char>().swap(vertShaderCode);
- std::vector<char>().swap(fragShaderCode);
- VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
- vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
- vertShaderStageInfo.module = vertShaderModule;
- vertShaderStageInfo.pName = "main";
- VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
- fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
- fragShaderStageInfo.module = fragShaderModule;
- fragShaderStageInfo.pName = "main";
- VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
- // Get vertex data
- auto bindingDescription = Vertex::getBindingDescription();
- auto attributeDescriptions = Vertex::getAttributeDescriptions();
- VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
- vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- vertexInputInfo.vertexBindingDescriptionCount = 1;
- vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
- vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
- vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
- // Set vertex input assembly to draw a triangle from every 3 vertices without reuse
- VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
- inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
- inputAssembly.primitiveRestartEnable = VK_FALSE;
- // The viewport specifies what region of the framebuffer to render to.
- VkViewport viewport = {};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = (float)m_swapChainExtent.width;
- viewport.height = (float)m_swapChainExtent.height;
- viewport.minDepth = 0.0f;
- viewport.maxDepth = 1.0f;
- // Scissor around the entire framebuffer
- VkRect2D scissor = {};
- scissor.offset = { 0, 0 };
- scissor.extent = m_swapChainExtent;
- VkPipelineViewportStateCreateInfo viewportState = {};
- viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- viewportState.viewportCount = 1;
- viewportState.pViewports = &viewport;
- viewportState.scissorCount = 1;
- viewportState.pScissors = &scissor;
- VkPipelineRasterizationStateCreateInfo rasterizer = {};
- rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rasterizer.depthClampEnable = VK_FALSE;
- rasterizer.rasterizerDiscardEnable = VK_FALSE;
- rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
- rasterizer.lineWidth = 1.0f;
- rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
- rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
- rasterizer.depthBiasEnable = VK_FALSE;
- rasterizer.depthBiasConstantFactor = 0.0f;
- rasterizer.depthBiasClamp = 0.0f;
- rasterizer.depthBiasSlopeFactor = 0.0f;
- // For anti-aliasing
- VkPipelineMultisampleStateCreateInfo multisampling = {};
- multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- multisampling.sampleShadingEnable = VK_FALSE;
- multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
- multisampling.minSampleShading = 1.0f;
- multisampling.pSampleMask = nullptr;
- multisampling.alphaToCoverageEnable = VK_FALSE;
- multisampling.alphaToOneEnable = VK_FALSE;
- VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
- colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT
- | VK_COLOR_COMPONENT_G_BIT
- | VK_COLOR_COMPONENT_B_BIT
- | VK_COLOR_COMPONENT_A_BIT;
- colorBlendAttachment.blendEnable = VK_FALSE;
- colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
- colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
- colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
- colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
- colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
- colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
- VkPipelineColorBlendStateCreateInfo colorBlending = {};
- colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- colorBlending.logicOpEnable = VK_FALSE;
- colorBlending.logicOp = VK_LOGIC_OP_COPY;
- colorBlending.attachmentCount = 1;
- colorBlending.pAttachments = &colorBlendAttachment;
- colorBlending.blendConstants[0] = 0.0f;
- colorBlending.blendConstants[1] = 0.0f;
- colorBlending.blendConstants[2] = 0.0f;
- colorBlending.blendConstants[3] = 0.0f;
- VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
- pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutInfo.setLayoutCount = 1;
- pipelineLayoutInfo.pSetLayouts = &m_descriptorSetLayout;
- pipelineLayoutInfo.pushConstantRangeCount = 0;
- pipelineLayoutInfo.pPushConstantRanges = nullptr;
- VkResult result = vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create pipeline layout!");
- #ifndef NDEBUG
- if (!m_recreatingSwapChain)
- spdlog::info("Successfully created pipeline layout.");
- #endif
- VkGraphicsPipelineCreateInfo pipelineInfo = {};
- pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- pipelineInfo.stageCount = 2;
- pipelineInfo.pStages = shaderStages;
- pipelineInfo.pVertexInputState = &vertexInputInfo;
- pipelineInfo.pInputAssemblyState = &inputAssembly;
- pipelineInfo.pViewportState = &viewportState;
- pipelineInfo.pRasterizationState = &rasterizer;
- pipelineInfo.pMultisampleState = &multisampling;
- pipelineInfo.pDepthStencilState = nullptr;
- pipelineInfo.pColorBlendState = &colorBlending;
- pipelineInfo.pDynamicState = nullptr;
- pipelineInfo.layout = m_pipelineLayout;
- pipelineInfo.renderPass = m_renderPass;
- pipelineInfo.subpass = 0;
- pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
- pipelineInfo.basePipelineIndex = -1;
- result = vkCreateGraphicsPipelines(m_device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_graphicsPipeline);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create graphics pipeline!");
- #ifndef NDEBUG
- if (!m_recreatingSwapChain)
- spdlog::info("Successfully created graphics pipeline.");
- #endif
- vkDestroyShaderModule(m_device, vertShaderModule, nullptr);
- vkDestroyShaderModule(m_device, fragShaderModule, nullptr);
- }
- VkShaderModule Application::createShaderModule(const std::vector<char>& code)
- {
- VkShaderModuleCreateInfo createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- createInfo.codeSize = code.size();
- createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
- VkShaderModule shaderModule;
- VkResult result = vkCreateShaderModule(m_device, &createInfo, nullptr, &shaderModule);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create shader module!");
- #ifndef NDEBUG
- if (!m_recreatingSwapChain)
- spdlog::info("Successfully created shader module.");
- #endif
- return shaderModule;
- }
- // *************************************************************
- // *************** Commands ************************
- // *************************************************************
- void Application::createCommandPools()
- {
- VkCommandPoolCreateInfo poolInfo = {};
- poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- poolInfo.queueFamilyIndex = m_indices.graphicsFamily.value();
- poolInfo.flags = 0;
- VkCommandPoolCreateInfo tempPoolInfo = {};
- tempPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- tempPoolInfo.queueFamilyIndex = m_indices.graphicsFamily.value();
- tempPoolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
- VkResult result = vkCreateCommandPool(m_device, &poolInfo, nullptr, &m_commandPool);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create command pool!");
- result = vkCreateCommandPool(m_device, &tempPoolInfo, nullptr, &m_tempCommandPool);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create temp command pool!");
- #ifndef NDEBUG
- spdlog::info("Successfully created command pools.");
- #endif
- }
- void Application::createCommandBuffers()
- {
- m_commandBuffers.resize(m_swapChainFramebuffers.size());
- VkCommandBufferAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- allocInfo.commandPool = m_commandPool;
- allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- allocInfo.commandBufferCount = (uint32_t)m_commandBuffers.size();
- VkResult result = vkAllocateCommandBuffers(m_device, &allocInfo, m_commandBuffers.data());
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to begin allocate command buffers!");
- #ifndef NDEBUG
- if (!m_recreatingSwapChain)
- spdlog::info("Successfully allocated command buffers.");
- #endif
- for (size_t i = 0; i < m_commandBuffers.size(); i++)
- {
- VkCommandBufferBeginInfo beginInfo = {};
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
- beginInfo.pInheritanceInfo = nullptr;
- result = vkBeginCommandBuffer(m_commandBuffers[i], &beginInfo);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to begin recording command buffer!");
- VkClearValue clearColor = { 0.0f, 0.0f, 0.0f, 1.0f };
- VkRenderPassBeginInfo renderPassInfo = {};
- renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- renderPassInfo.renderPass = m_renderPass;
- renderPassInfo.framebuffer = m_swapChainFramebuffers[i];
- renderPassInfo.renderArea.offset = { 0, 0 };
- renderPassInfo.renderArea.extent = m_swapChainExtent;
- renderPassInfo.clearValueCount = 1;
- renderPassInfo.pClearValues = &clearColor;
- vkCmdBeginRenderPass(m_commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
- vkCmdBindPipeline(m_commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
- VkBuffer vertexBuffers[] = { m_vertexBuffer };
- VkDeviceSize offsets[] = { 0 };
- vkCmdBindVertexBuffers(m_commandBuffers[i], 0, 1, vertexBuffers, offsets);
- vkCmdBindIndexBuffer(m_commandBuffers[i], m_indexBuffer, 0, VK_INDEX_TYPE_UINT16);
- vkCmdBindDescriptorSets(m_commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descriptorSets[i], 0, nullptr);
- vkCmdDrawIndexed(m_commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
- vkCmdEndRenderPass(m_commandBuffers[i]);
- VkResult result = vkEndCommandBuffer(m_commandBuffers[i]);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to record command buffer!");
- }
- #ifndef NDEBUG
- if (!m_recreatingSwapChain)
- spdlog::info("Successfully recorded command buffers.");
- #endif
- }
- void Application::createSyncObjects()
- {
- m_imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
- m_renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
- m_inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
- VkSemaphoreCreateInfo semaphoreInfo = {};
- semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- VkFenceCreateInfo fenceInfo = {};
- fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
- for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
- {
- VkResult result = vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_imageAvailableSemaphores[i]);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create imageavailable semaphore for a frame!");
- result = vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphores[i]);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create renderfinished semaphore for a frame!");
- result = vkCreateFence(m_device, &fenceInfo, nullptr, &m_inFlightFences[i]);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create fence for a frame!");
- }
- #ifndef NDEBUG
- spdlog::info("Successfully created sync objects.");
- #endif
- }
- // *************************************************************
- // *************** Device creations ************************
- // *************************************************************
- void Application::pickPhysicalDevice()
- {
- uint32_t deviceCount = 0;
- vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr);
- if (deviceCount == 0)
- throw std::runtime_error("Failed to find GPUs with Vulkan support!");
- std::vector<VkPhysicalDevice> devices(deviceCount);
- vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data());
- #if MANUALPHYSICALDEVICE
- // Let the user pick the device
- std::cout << std::endl << "Pick a device:" << std::endl;
- int i = 0;
- for (const auto& device : devices)
- {
- VkPhysicalDeviceProperties deviceProperties;
- vkGetPhysicalDeviceProperties(device, &deviceProperties);
- std::cout << i + 1 << ". " << deviceProperties.deviceName << std::endl;
- i++;
- }
- int picked;
- std::cin >> picked;
- while (!isDeviceSuitable(devices.at(picked - 1)))
- throw std::runtime_error("The picked device is not suitable!");
- m_physicalDevice = devices.at(picked - 1);
- #else
- // Automatically pick the first device
- if (isDeviceSuitable(devices.at(0)))
- m_physicalDevice = devices.at(0);
- else
- throw std::runtime_error("The automatically picked device is not suitable!");
- #endif
- if (m_physicalDevice == VK_NULL_HANDLE)
- throw std::runtime_error("None of the found GPUs were suitable!");
- m_indices = findQueueFamilies(m_physicalDevice);
- #ifndef NDEBUG
- VkPhysicalDeviceProperties deviceProperties;
- vkGetPhysicalDeviceProperties(m_physicalDevice, &deviceProperties);
- spdlog::info("Successfully picked physical device: {}", deviceProperties.deviceName);
- #endif
- }
- void Application::createLogicalDevice()
- {
- // Info for specified queue families
- std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
- std::set<uint32_t> uniqueQueueFamilies = { m_indices.graphicsFamily.value(), m_indices.presentFamily.value() };
- float queuePriority = 1.0f;
- for (uint32_t queueFamily : uniqueQueueFamilies)
- {
- VkDeviceQueueCreateInfo queueCreateInfo = {};
- queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queueCreateInfo.queueFamilyIndex = queueFamily;
- queueCreateInfo.queueCount = 1;
- queueCreateInfo.pQueuePriorities = &queuePriority;
- queueCreateInfos.push_back(queueCreateInfo);
- }
- // All features set to VK_FALSE
- VkPhysicalDeviceFeatures deviceFeatures = {};
- // Info for creating logical device
- VkDeviceCreateInfo createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- createInfo.pQueueCreateInfos = queueCreateInfos.data();
- createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
- createInfo.pEnabledFeatures = &deviceFeatures;
- createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
- createInfo.ppEnabledExtensionNames = deviceExtensions.data();
- if (enableValidationLayers)
- {
- createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
- createInfo.ppEnabledLayerNames = validationLayers.data();
- }
- else
- createInfo.enabledLayerCount = 0;
- // Create logical device
- VkResult result = vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device);
- // Throw if failed
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to create logical device!");
- // Create handle for interaction with the graphics queue
- vkGetDeviceQueue(m_device, m_indices.graphicsFamily.value(), 0, &m_graphicsQueue);
- vkGetDeviceQueue(m_device, m_indices.presentFamily.value(), 0, &m_presentQueue);
- #ifndef NDEBUG
- spdlog::info("Successfully created logical device.");
- #endif
- }
- bool Application::isDeviceSuitable(VkPhysicalDevice device)
- {
- QueueFamilyIndices indices = findQueueFamilies(device);
- bool extensionsSupported = checkDeviceExtensionSupport(device);
- bool swapChainAdequate = false;
- if (extensionsSupported)
- {
- SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
- swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
- }
- return indices.isComplete() && extensionsSupported && swapChainAdequate;
- }
- bool Application::checkDeviceExtensionSupport(VkPhysicalDevice device)
- {
- uint32_t extensionCount;
- vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
- std::vector<VkExtensionProperties> availableExtensions(extensionCount);
- vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
- return requiredExtensionsAvailable(deviceExtensions, availableExtensions);
- }
- QueueFamilyIndices Application::findQueueFamilies(VkPhysicalDevice device)
- {
- QueueFamilyIndices indices;
- uint32_t queueFamilyCount = 0;
- vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
- std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
- vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
- int i = 0;
- for (const auto& queueFamily : queueFamilies)
- {
- if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
- indices.graphicsFamily = i;
- VkBool32 presentSupport = false;
- vkGetPhysicalDeviceSurfaceSupportKHR(device, i, m_surface, &presentSupport);
- if (queueFamily.queueCount > 0 && presentSupport)
- indices.presentFamily = i;
- if (indices.isComplete())
- break;
- i++;
- }
- return indices;
- }
- // *************************************************************
- // *************** Application core ************************
- // *************************************************************
- void Application::mainLoop()
- {
- Timer* t = new Timer();
- double time = 1.0;
- int frames = 0;
- while (!glfwWindowShouldClose(m_window))
- {
- glfwPollEvents();
- drawFrame();
- // FPS Counter
- if (t->elapsed() > time)
- {
- time++;
- std::cout << frames << " FPS" << std::endl;
- frames = 0;
- }
- frames++;
- }
- vkDeviceWaitIdle(m_device);
- }
- void Application::drawFrame()
- {
- vkWaitForFences(m_device, 1, &m_inFlightFences[m_currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());
- vkResetFences(m_device, 1, &m_inFlightFences[m_currentFrame]);
- uint32_t imageIndex;
- VkResult result = vkAcquireNextImageKHR(m_device, m_swapChain, std::numeric_limits<uint64_t>::max(), m_imageAvailableSemaphores[m_currentFrame], VK_NULL_HANDLE, &imageIndex);
- if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
- {
- recreateSwapChain();
- return;
- }
- else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
- {
- throw std::runtime_error("Failed to acquire swap chain image!");
- }
- updateUniformBuffers(imageIndex);
- VkSemaphore waitSemaphores[] = { m_imageAvailableSemaphores[m_currentFrame] };
- VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
- VkSemaphore signalSemaphores[] = { m_renderFinishedSemaphores[m_currentFrame] };
- VkSubmitInfo submitInfo = {};
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 1;
- submitInfo.pWaitSemaphores = waitSemaphores;
- submitInfo.pWaitDstStageMask = waitStages;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &m_commandBuffers[imageIndex];
- submitInfo.signalSemaphoreCount = 1;
- submitInfo.pSignalSemaphores = signalSemaphores;
- vkResetFences(m_device, 1, &m_inFlightFences[m_currentFrame]);
- result = vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_inFlightFences[m_currentFrame]);
- if (result != VK_SUCCESS)
- throw std::runtime_error("Failed to submit draw command buffer!");
- VkSwapchainKHR swapChains[] = { m_swapChain };
- VkPresentInfoKHR presentInfo = {};
- presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
- presentInfo.waitSemaphoreCount = 1;
- presentInfo.pWaitSemaphores = signalSemaphores;
- presentInfo.swapchainCount = 1;
- presentInfo.pSwapchains = swapChains;
- presentInfo.pImageIndices = &imageIndex;
- presentInfo.pResults = nullptr;
- result = vkQueuePresentKHR(m_presentQueue, &presentInfo);
- if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || m_framebufferResized)
- {
- m_framebufferResized = false;
- recreateSwapChain();
- }
- else if (result != VK_SUCCESS)
- {
- throw std::runtime_error("Failed to present swap chain image!");
- }
- m_currentFrame = (m_currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
- }
- void Application::cleanup()
- {
- cleanupSwapChain();
- //Descriptor Pool
- vkDestroyDescriptorPool(m_device, m_descriptorPool, nullptr);
- // Desciptor Set Layout
- vkDestroyDescriptorSetLayout(m_device, m_descriptorSetLayout, nullptr);
- // Uniform Buffers
- for (size_t i = 0; i < m_swapChainImages.size(); i++)
- {
- vkDestroyBuffer(m_device, m_uniformBuffers[i], nullptr);
- vkFreeMemory(m_device, m_uniformBuffersMemory[i], nullptr);
- }
- // Vertex buffer
- vkDestroyBuffer(m_device, m_vertexBuffer, nullptr);
- vkFreeMemory(m_device, m_vertexBufferMemory, nullptr);
- // Index Buffer
- vkDestroyBuffer(m_device, m_indexBuffer, nullptr);
- vkFreeMemory(m_device, m_indexBufferMemory, nullptr);
- // Semaphores
- for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
- {
- vkDestroySemaphore(m_device, m_imageAvailableSemaphores[i], nullptr);
- vkDestroySemaphore(m_device, m_renderFinishedSemaphores[i], nullptr);
- vkDestroyFence(m_device, m_inFlightFences[i], nullptr);
- }
- // Command pool
- vkDestroyCommandPool(m_device, m_commandPool, nullptr);
- vkDestroyCommandPool(m_device, m_tempCommandPool, nullptr);
- // Device
- vkDestroyDevice(m_device, nullptr);
- // Debug messenger
- if (enableValidationLayers)
- DestroyDebugUtilsMessengerEXT(m_instance, m_debugMessenger, nullptr);
- // Surface
- vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
- // Instance
- vkDestroyInstance(m_instance, nullptr);
- // GLFW
- glfwDestroyWindow(m_window);
- glfwTerminate();
- }
- void Application::init()
- {
- initWindow();
- initVulkan();
- }
- void Application::run()
- {
- // Run
- mainLoop();
- // Exit
- cleanup();
- }
- void Application::initWindow()
- {
- glfwInit();
- glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
- m_window = glfwCreateWindow(WIDTH, HEIGHT, "Volcanic Engine", nullptr, nullptr);
- glfwSetWindowUserPointer(m_window, this);
- glfwSetFramebufferSizeCallback(m_window, framebufferResizeCallback);
- }
- void Application::initVulkan()
- {
- createInstance();
- setupDebugMessenger();
- createSurface();
- pickPhysicalDevice();
- createLogicalDevice();
- createSwapChain();
- createImageViews();
- createRenderPass();
- createDescriptorSetLayout();
- createGraphicsPipeline();
- createFramebuffers();
- createCommandPools();
- createVertexBuffers();
- createIndexBuffer();
- createUniformBuffers();
- createDescriptorPool();
- createDescriptorSets();
- createCommandBuffers();
- createSyncObjects();
- }
- // *************************************************************
- // *************** Callbacks ************************
- // *************************************************************
- void Application::setupDebugMessenger()
- {
- if (!enableValidationLayers) return;
- VkDebugUtilsMessengerCreateInfoEXT createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
- createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
- | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
- | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
- createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
- | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
- | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
- createInfo.pfnUserCallback = debugCallback;
- createInfo.pUserData = nullptr;
- if (CreateDebugUtilsMessengerEXT(m_instance, &createInfo, nullptr, &m_debugMessenger) != VK_SUCCESS)
- throw std::runtime_error("Failed to set up debug messenger!");
- #ifndef NDEBUG
- spdlog::info("Successfully created debug callback.");
- #endif
- }
- VkResult Application::CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger)
- {
- auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
- if (func != nullptr)
- return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
- else
- return VK_ERROR_EXTENSION_NOT_PRESENT;
- }
- void Application::DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator)
- {
- auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
- if (func != nullptr)
- func(instance, debugMessenger, pAllocator);
- }
- VKAPI_ATTR VkBool32 VKAPI_CALL Application::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData, void * pUserData)
- {
- switch (messageSeverity)
- {
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
- spdlog::info("Validation layer: {}", pCallbackData->pMessage);
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
- spdlog::warn("Validation layer: {}", pCallbackData->pMessage);
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
- spdlog::error("Validation layer: {}", pCallbackData->pMessage);
- break;
- }
- return VK_FALSE;
- }
- void Application::framebufferResizeCallback(GLFWwindow * window, int width, int height)
- {
- auto app = reinterpret_cast<Application*>(glfwGetWindowUserPointer(window));
- app->m_framebufferResized = true;
- app->m_framebufferWidth = width;
- app->m_framebufferHeight = height;
- }
Add Comment
Please, Sign In to add comment