From db3bd3a1e76f6c3c76148c07544edc3a56aba2af Mon Sep 17 00:00:00 2001 From: Nigel Barink Date: Thu, 8 May 2025 19:41:59 +0200 Subject: [PATCH] Fixed issue plane not showing up --- .gitignore | 14 +- CMakeLists.txt | 33 + HelloTriangle/compile_commands.json | 13 + HelloTriangle/main.cpp | 2738 ++++++++++++++------------- HelloVulkan/premake5.lua | 12 +- premake5.lua | 54 +- 6 files changed, 1475 insertions(+), 1389 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 HelloTriangle/compile_commands.json diff --git a/.gitignore b/.gitignore index 0928eac..5159335 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,16 @@ -.vscode -bin +# Visual Studio 2024 +**.vcxproj **.spv **.filters +**.sln +# Visual Studio Code +.vscode +# Gnu Make Makefile **/Makefile + +# project specific +libs +bin +obj +build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..617dbc8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 4.0) + +set(CXX_STANDARD 17) +set(CXX_STANDARD_REQUIRED ON) +set(CMAKE_GENERATOR_PLATFORM x64) + +project (LearnVulkan VERSION 1.0.0) + +# project 1 +add_executable(HelloTriangle) + +# linker settings +target_link_options(HelloTriangle PUBLIC nodefaultlibs) +target_link_directories( HelloTriangle PUBLIC ) +target_link_libraries(HelloTriangle msvcrt user32 kernel32 libcmt gdi32 glu32 shell32 opengl32 + glfw3 vulkan-1) + +target_include_directories(HelloTriangle PUBLIC "c:/VulkanSDK/1.4.304.1/Include" "libs") + +target_compile_definitions(HelloTriangle PUBLIC $:NDEBUG) +target_compile_definitions(HelloTriangle PUBLIC $:DEBUG) + +# project 2 +add_executable(HelloVulkan) + +# linker settings +target_link_options(HelloVulkan PUBLIC nodefaultlibs) +target_include_directories(HelloVulkan PUBLIC "c:/VulkanSDK/1.4.304.1/Include" "libs") +target_link_libraries(HelloVulkan msvcrt user32 kernel32 libcmt gdi32 glu32 shell32 opengl32 + glfw3 vulkan-1) + +target_compile_definitions(HelloVulkan PUBLIC $:NDEBUG) +target_compile_definitions(HelloVulkan PUBLIC $:DEBUG) diff --git a/HelloTriangle/compile_commands.json b/HelloTriangle/compile_commands.json new file mode 100644 index 0000000..f86d3ec --- /dev/null +++ b/HelloTriangle/compile_commands.json @@ -0,0 +1,13 @@ +[ + { + "directory": "J:/git/Graphics API/LearnVulkan/HelloVulkan", + "file": "J:/git/Graphics API/LearnVulkan/HelloVulkan/main.cpp", + "command": "cc -MD -MP -DDEBUG -IC:/VulkanSDK/1.4.304.1/Include -I\"J:/git/Graphics API/LearnVulkan/libs\" -m64 -g -o J:/git/Graphics API/LearnVulkan/HelloVulkan/obj/Debug/main.o -MF J:/git/Graphics API/LearnVulkan/HelloVulkan/obj/Debug/main.d -c J:/git/Graphics API/LearnVulkan/HelloVulkan/main.cpp" + } +, + { + "directory": "J:/git/Graphics API/LearnVulkan/HelloTriangle", + "file": "J:/git/Graphics API/LearnVulkan/HelloTriangle/main.cpp", + "command": "cc -MD -MP -DDEBUG -IC:/VulkanSDK/1.4.304.1/Include -I\"J:/git/Graphics API/LearnVulkan/libs\" -m64 -g -o J:/git/Graphics API/LearnVulkan/HelloTriangle/obj/Debug/main.o -MF J:/git/Graphics API/LearnVulkan/HelloTriangle/obj/Debug/main.d -c J:/git/Graphics API/LearnVulkan/HelloTriangle/main.cpp" + } +] \ No newline at end of file diff --git a/HelloTriangle/main.cpp b/HelloTriangle/main.cpp index e9363b2..f3be627 100644 --- a/HelloTriangle/main.cpp +++ b/HelloTriangle/main.cpp @@ -4,1377 +4,1411 @@ */ #define GLFW_INCLUDE_VULKAN -#define GLM_FORCE_RADIANS #include + +#define GLM_FORCE_RADIANS #include #include -#include -#include -#include -#include -#include -#include #include -#include +#include +#include +#include +#include #include +#include +#include +#include #include #include -#include -#include +#include +#include const uint32_t WIDTH = 800; const uint32_t HEIGHT = 600; const int MAX_FRAMES_IN_FLIGHT = 2; -const std::vector validationLayers ={ - "VK_LAYER_KHRONOS_validation" -}; +const std::vector validationLayers = { + "VK_LAYER_KHRONOS_validation"}; -const std::vector deviceExtensions = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME -}; +const std::vector deviceExtensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME}; -#ifdef NDEBUG - const bool enableValidationLayers = false; -# else - const bool enableValidationLayers = true; +#ifdef NDEBUG +const bool enableValidationLayers = false; +#else +const bool enableValidationLayers = true; #endif - struct Vertex { - glm::vec2 pos; - glm::vec3 color; - static VkVertexInputBindingDescription getBindingDescription() { - VkVertexInputBindingDescription bindingDescription{}; - bindingDescription.binding = 0; - bindingDescription.stride = sizeof(Vertex); - bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - return bindingDescription; - } - - static std::array getAttributeDescriptions() { - std::array attributeDescription{}; - - attributeDescription[0].binding = 0; - attributeDescription[0].location = 0; - attributeDescription[0].format = VK_FORMAT_R32G32_SFLOAT; - attributeDescription[0].offset = offsetof(Vertex, pos); - - - attributeDescription[1].binding = 0; - attributeDescription[1].location = 1; - attributeDescription[1].format = VK_FORMAT_R32G32B32_SFLOAT; - attributeDescription[1].offset = offsetof(Vertex, color); - - return attributeDescription; - } - }; - - struct UniformBufferObject { - alignas(16) glm::mat4 model; - alignas(16) glm::mat4 view; - alignas(16) glm::mat4 proj; - }; - - const std::vector vertices = { - {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, - {{0.5f, -0.5f}, {0.0f,1.0f, 0.0f}}, - {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}, - {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}} - }; - - const std::vector indices = { - 0,1,2,2,3,0 - }; - - class HelloTriangleApplication { - public: - void run() { - initWindow(); - initVulkan(); - mainLoop(); - cleanup(); - } - - private: - GLFWwindow* window; - VkInstance instance; - VkDebugUtilsMessengerEXT debugMessenger; - VkSurfaceKHR surface; - VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VkDevice device; - VkQueue graphicsQueue; - VkQueue presentQueue; - VkSwapchainKHR swapChain; - std::vector swapChainImages; - VkFormat swapChainImageFormat; - VkExtent2D swapChainExtent; - std::vector swapChainImageViews; - VkRenderPass renderPass; - VkDescriptorSetLayout descriptorSetLayout; - VkPipelineLayout pipelineLayout; - VkPipeline graphicsPipeline; - std::vector swapchainFrameBuffers; - VkCommandPool commandPool; - VkDescriptorPool descriptorPool; - std::vector descriptorSets; - - - VkBuffer vertexBuffer; - VkDeviceMemory vertexBufferMemory; - VkBuffer indexBuffer; - VkDeviceMemory indexBufferMemory; - - std::vector uniformBuffers; - std::vector uniformBuffersMemory; - std::vector uniformBuffersMapped; - - - std::vector commandBuffers; - std::vector imageAvailableSemaphores; - std::vector renderFinishedSemaphores; - std::vector inFlightFences; - bool framebufferResized = false; - uint32_t currentFrame = 0; - - struct SwapChainSupportDetails { - VkSurfaceCapabilitiesKHR capabilities; - std::vector formats; - std::vector presentModes; - }; - - - void initWindow() { - glfwInit(); - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); - - window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); - glfwSetWindowUserPointer(window, this); - glfwSetFramebufferSizeCallback(window, framebufferResizeCallback); - } - - - static void framebufferResizeCallback(GLFWwindow* window, int width, int height) { - auto app = reinterpret_cast(glfwGetWindowUserPointer(window)); - app->framebufferResized = true; - } - - void initVulkan() { - createInstance(); - setupDebugMessenger(); - createSurface(); - pickPhysicalDevice(); - createLogicalDevice(); - createSwapChain(); - createImageViews(); - createRenderPass(); - createDescriptorSetLayout(); - createGraphicsPipeline(); - createFramebuffers(); - createCommandPool(); - createVertexBuffer(); - createIndexBuffer(); - createUniformBuffers(); - createDescriptorPool(); - createDescriptorSets(); - createCommandBuffers(); - createSyncObjects(); - } - - void createDescriptorSets() { - std::vector layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout); - VkDescriptorSetAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = descriptorPool; - allocInfo.descriptorSetCount = static_cast(MAX_FRAMES_IN_FLIGHT); - allocInfo.pSetLayouts = layouts.data(); - - descriptorSets.resize(MAX_FRAMES_IN_FLIGHT); - if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate descriptor sets!"); - } - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - VkDescriptorBufferInfo bufferInfo{}; - bufferInfo.buffer = uniformBuffers[i]; - bufferInfo.offset = 0; - bufferInfo.range = sizeof(UniformBufferObject); - - VkWriteDescriptorSet descriptorWrite{}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = descriptorSets[i]; - descriptorWrite.dstBinding = 0; - descriptorWrite.dstArrayElement = 0; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptorWrite.descriptorCount = 1; - descriptorWrite.pBufferInfo = &bufferInfo; - descriptorWrite.pImageInfo = nullptr; // Optional - descriptorWrite.pTexelBufferView = nullptr; // Optional - - vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); - - } - - } - - void createDescriptorPool() { - VkDescriptorPoolSize poolSize{}; - poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - poolSize.descriptorCount = static_cast (MAX_FRAMES_IN_FLIGHT); - - VkDescriptorPoolCreateInfo poolInfo{}; - poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.poolSizeCount = 1; - poolInfo.pPoolSizes = &poolSize; - poolInfo.maxSets = static_cast(MAX_FRAMES_IN_FLIGHT); - - if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { - throw std::runtime_error("failed to create descriptor pool!"); - } - - } - - - void createUniformBuffers() { - VkDeviceSize buffersize = sizeof(UniformBufferObject); - - uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT); - uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT); - uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT); - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - CreateBuffer(buffersize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]); - - vkMapMemory(device, uniformBuffersMemory[i], 0, buffersize, 0, &uniformBuffersMapped[i]); - } - } - - void createDescriptorSetLayout() { - VkDescriptorSetLayoutBinding uboLayoutBinding{}; - uboLayoutBinding.binding = 0; - uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - uboLayoutBinding.descriptorCount = 1; - - uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - uboLayoutBinding.pImmutableSamplers = nullptr; // Optional - - VkDescriptorSetLayoutCreateInfo layoutInfo{}; - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = 1; - layoutInfo.pBindings = &uboLayoutBinding; - - if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { - throw std::runtime_error("failed to create descriptor set layout!"); - } - - } - - - uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) { - VkPhysicalDeviceMemoryProperties memProperties; - vkGetPhysicalDeviceMemoryProperties(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!"); - } - - - void 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; - - if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { - throw std::runtime_error("failed to create vertex buffer!"); - } - - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(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(device, &allocInfo, nullptr, &buffermemory) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate vertex buffer memory!"); - } - vkBindBufferMemory(device, buffer, buffermemory, 0); - } - - - // copy from staging to the vertex buffer - void 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 = commandPool; - allocInfo.commandBufferCount = 1; - - VkCommandBuffer commandBuffer; - vkAllocateCommandBuffers(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; // Optional - copyRegion.dstOffset = 0; // Optional - 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(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); - vkQueueWaitIdle(graphicsQueue); - - vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); - } - - // Create a staging and vertex buffer - void createVertexBuffer() { - - 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(device, stagingBufferMemory, 0, buffersize, 0, &data); - memcpy(data, vertices.data(), (size_t)buffersize); - vkUnmapMemory(device, stagingBufferMemory); - - CreateBuffer(buffersize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); - - copyBuffer(stagingBuffer, vertexBuffer, buffersize); - - vkDestroyBuffer(device, stagingBuffer, nullptr); - vkFreeMemory(device, stagingBufferMemory, nullptr); - } - - void createIndexBuffer() { - VkDeviceSize buffersize = sizeof(indices[0]) * indices.size(); - - VkBuffer stagingBuffer; - VkDeviceMemory stagingBufferMemory; - CreateBuffer(buffersize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - stagingBuffer, stagingBufferMemory); - - void* data; - vkMapMemory(device, stagingBufferMemory, 0, buffersize, 0, &data); - memcpy(data, indices.data(), (size_t)buffersize); - vkUnmapMemory(device, stagingBufferMemory); - - CreateBuffer(buffersize, - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); - - copyBuffer(stagingBuffer, indexBuffer, buffersize); - - vkDestroyBuffer(device, stagingBuffer, nullptr); - vkFreeMemory(device, stagingBufferMemory, nullptr); - } - - void recreateSwapChain() { - int width = 0, height = 0; - glfwGetFramebufferSize(window, &width, &height); - - while (width == 0 || height == 0) { - glfwGetFramebufferSize(window, &width, &height); - glfwWaitEvents(); - } - - - vkDeviceWaitIdle(device); - - cleanupSwapChain(); - - createSwapChain(); - createImageViews(); - createFramebuffers(); - - } - - void cleanupSwapChain() { - for (size_t i = 0; i < swapchainFrameBuffers.size(); i++) { - vkDestroyFramebuffer(device, swapchainFrameBuffers[i], nullptr); - } - - for (size_t i = 0; i < swapChainImageViews.size(); i++) { - vkDestroyImageView(device, swapChainImageViews[i], nullptr); - } - - vkDestroySwapchainKHR(device, swapChain, nullptr); - - } - - - void createSyncObjects() { - imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); - renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); - 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++) { - - if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS || - vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS || - vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) { - throw std::runtime_error("failed to create semaphores!"); - } - } - - - - - - } - - void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { - VkCommandBufferBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { - throw std::runtime_error("failed to begin recording command buffer!"); - } - - VkRenderPassBeginInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = renderPass; - renderPassInfo.framebuffer = swapchainFrameBuffers[imageIndex]; - - renderPassInfo.renderArea.offset = { 0,0 }; - renderPassInfo.renderArea.extent = swapChainExtent; - - VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; - renderPassInfo.clearValueCount = 1; - renderPassInfo.pClearValues = &clearColor; - - vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); - - VkBuffer vertexBuffers[] = { vertexBuffer }; - VkDeviceSize offsets[] = { 0 }; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); - - vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT16); - - VkViewport viewport{}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = static_cast(swapChainExtent.width); - viewport.height = static_cast(swapChainExtent.height); - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - vkCmdSetViewport(commandBuffer, 0, 1, &viewport); - - VkRect2D scissor{}; - scissor.offset = { 0,0 }; - scissor.extent = swapChainExtent; - vkCmdSetScissor(commandBuffer, 0, 1, &scissor); - - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[currentFrame], 0, nullptr); - - vkCmdDrawIndexed(commandBuffer, static_cast(indices.size()), 1, 0, 0, 0); - - vkCmdEndRenderPass(commandBuffer); - - if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { - throw std::runtime_error("failed to record command buffer!"); - } - - } - - void createCommandBuffers() { - commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); - - VkCommandBufferAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = commandPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = (uint32_t) commandBuffers.size(); - - if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate command buffers!"); - } - } - - void createSurface() { - if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) { - throw std::runtime_error("failed ot create window surface!"); - } - } - - - void createLogicalDevice() { - QueueFamilyIndices indices = findQueueFamilies(physicalDevice); - - - std::vectorqueueCreateInfos; - std::set uniqueQueueFamilies = { indices.graphicsFamily.value(), 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); - } - - - VkPhysicalDeviceFeatures deviceFeatures{}; - - - VkDeviceCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - - createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); - createInfo.pQueueCreateInfos = queueCreateInfos.data(); - - createInfo.pEnabledFeatures = &deviceFeatures; - - createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); - - createInfo.ppEnabledExtensionNames = deviceExtensions.data(); - - if (enableValidationLayers) { - createInfo.enabledLayerCount = static_cast(validationLayers.size()); - createInfo.ppEnabledLayerNames = validationLayers.data(); - } - else { - createInfo.enabledLayerCount = 0; - } - - if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) { - throw std::runtime_error("failed to create logical device"); - } - - - vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue); - vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue); - } - - - void createSwapChain() { - SwapChainSupportDetails swapChainSupport = querySwapChainSupport(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 = 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; - - QueueFamilyIndices indices = findQueueFamilies(physicalDevice); - uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value()}; - - if (indices.graphicsFamily != 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; - - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain)!= VK_SUCCESS ) { - throw std::runtime_error("failed to create swap chain!"); - } - - - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); - swapChainImages.resize(imageCount); - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); - - - swapChainImageFormat = surfaceFormat.format; - swapChainExtent = extent; - - } - - void createImageViews() { - swapChainImageViews.resize(swapChainImages.size()); - for (size_t i = 0; i < swapChainImages.size(); i++) { - VkImageViewCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.image = swapChainImages[i]; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = 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; - - if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) { - throw std::runtime_error("Failed to create image views!"); - } - } - } - - - void createRenderPass() { - VkAttachmentDescription colorAttachment{}; - colorAttachment.format = 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 colorAttachementRef{}; - colorAttachementRef.attachment = 0; - colorAttachementRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass{}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachementRef; - - 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 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; - - - - if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) { - throw std::runtime_error("Failed to create render pass!"); - } - - } - - void createGraphicsPipeline() { - auto vertShaderCode = readFile("shaders/vert.spv"); - auto fragShaderCode = readFile("shaders/frag.spv"); - - VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); - VkShaderModule fragShaderModule = createShaderModule(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 }; - - - 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(attributeDescriptions.size()); - vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); - - VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; - inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - inputAssembly.primitiveRestartEnable = VK_FALSE; - - - // DYNAMIC VIEWPORT & SCISSOR - - std::vector dynamicStates = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR - }; - - VkPipelineDynamicStateCreateInfo dynamicState{}; - dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); - dynamicState.pDynamicStates = dynamicStates.data(); - - - VkPipelineViewportStateCreateInfo viewportState{}; - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportState.viewportCount = 1; - viewportState.scissorCount = 1; - - 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; - - - VkPipelineMultisampleStateCreateInfo multisampling{}; - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - - - 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; - - VkPipelineColorBlendStateCreateInfo colorBlending{}; - colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlending.logicOpEnable = VK_FALSE; - colorBlending.attachmentCount = 1; - colorBlending.pAttachments = &colorBlendAttachment; - - VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; - pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - - if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { - throw std::runtime_error("failed to create pipeline layout!"); - } - - - - 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 = &dynamicState; - - pipelineInfo.layout = pipelineLayout; - - pipelineInfo.renderPass = renderPass; - pipelineInfo.subpass = 0; - - if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) { - throw std::runtime_error("Failed to create graphics pipeline!"); - } - - - vkDestroyShaderModule(device, vertShaderModule, nullptr); - vkDestroyShaderModule(device, fragShaderModule, nullptr); - - } - - void createFramebuffers() { - swapchainFrameBuffers.resize(swapChainImageViews.size()); - - for (size_t i = 0; i < swapChainImageViews.size(); i++) { - VkImageView attachements[] = { - swapChainImageViews[i] - }; - - - VkFramebufferCreateInfo framebufferInfo{}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = 1; - framebufferInfo.pAttachments = attachements; - framebufferInfo.width = swapChainExtent.width; - framebufferInfo.height = swapChainExtent.height; - framebufferInfo.layers = 1; - - if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapchainFrameBuffers[i]) != VK_SUCCESS) { - throw std::runtime_error("failed to create framebuffer!"); - } - } - } - - void createCommandPool() { - QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice); - - VkCommandPoolCreateInfo poolInfo{}; - poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value(); - - if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { - throw std::runtime_error("Failed to create command pool!"); - } - - - } - - VkShaderModule createShaderModule(const std::vector& code) { - VkShaderModuleCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = code.size(); - createInfo.pCode = reinterpret_cast(code.data()); - VkShaderModule shaderModule; - if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { - throw std::runtime_error("Failed to create shader module!"); - } - return shaderModule; - } - - static std::vector readFile(const std::string& filename) { - std::ifstream file(filename, std::ios::ate | std::ios::binary); - - if (!file.is_open()) { - throw std::runtime_error("failed to open file!"); - } - - size_t fileSize = (size_t)file.tellg(); - std::vector buffer(fileSize); - - file.seekg(0); - file.read(buffer.data(), fileSize); - - file.close(); - return buffer; - } - - void pickPhysicalDevice() { - uint32_t deviceCount = 0; - vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); - - if (deviceCount == 0) { - throw std::runtime_error("failed to find GPU's with Vulkan support!"); - } - - std::vector devices(deviceCount); - vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); - - for (const auto& device : devices) { - if (isDeviceSuitable(device)) { - physicalDevice = device; - break; - } - } - - if (physicalDevice == VK_NULL_HANDLE) { - throw std::runtime_error("failed to find a suitable GPU"); - } - } - - bool isDeviceSuitable(VkPhysicalDevice device) { - - QueueFamilyIndices indices = findQueueFamilies(device); - bool extensionSupported = checkDeviceExtensionSupport(device); - - VkPhysicalDeviceProperties deviceProperties; - vkGetPhysicalDeviceProperties(device, &deviceProperties); - - VkPhysicalDeviceFeatures deviceFeatures; - vkGetPhysicalDeviceFeatures(device, &deviceFeatures); - - bool swapChainAdequate = false; - if (extensionSupported) { - SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device); - swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty(); - } - - - return indices.isComplete() && extensionSupported && swapChainAdequate; - } - - struct QueueFamilyIndices { - std::optional graphicsFamily; - std::optional presentFamily; - - bool isComplete() { - return graphicsFamily.has_value() && presentFamily.has_value(); - } - - }; - - QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) { - QueueFamilyIndices indices; - - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); - - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); - - - - int i = 0; - for (const auto& queueFamily : queueFamilies) { - - - VkBool32 presentSupport = false; - vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); - - if (presentSupport) { - indices.presentFamily = i; - } - - - if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - indices.graphicsFamily = i; - } - - if (indices.isComplete()) { - break; - } - - i++; - } - - return indices; - } - - SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) { - SwapChainSupportDetails details; - - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities); - - uint32_t formatCount; - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); - - if (formatCount != 0) { - details.formats.resize(formatCount); - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data()); - } - - uint32_t presentModeCount; - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr); - - if (presentModeCount != 0) { - details.presentModes.resize(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data()); - } - - return details; - } - - VkResult 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 setupDebugMessenger() { - if (!enableValidationLayers) return; - - VkDebugUtilsMessengerCreateInfoEXT createinfo; - populateDebugMessengerCreateInfo(createinfo); - - if (CreateDebugUtilsMessengerEXT(instance, &createinfo, nullptr, &debugMessenger) != VK_SUCCESS) { - throw std::runtime_error("failed to set up debug messenger!"); - } - } - - bool checkValidationLayerSupport() { - uint32_t layerCount; - vkEnumerateInstanceLayerProperties(&layerCount, nullptr); - - std::vector availableLayers(layerCount); - vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); - - for (const char* layerName : validationLayers) { - bool layerFound = false; - - for (const auto& layerProperties : availableLayers) { - if (strcmp(layerName, layerProperties.layerName) == 0) { - layerFound = true; - break; - } - } - - if (!layerFound) { - return false; - } - } - - return true; - - } - - bool checkDeviceExtensionSupport(VkPhysicalDevice device) { - uint32_t extensionCount; - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); - - std::vector availableExtensions(extensionCount); - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); - - std::set < std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); - - for (const auto& extension : availableExtensions) { - requiredExtensions.erase(extension.extensionName); - } - - return requiredExtensions.empty(); - } - - std::vector getRequiredExtensions() { - uint32_t glfwExtensionCount = 0; - const char** glfwExtensions; - glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); - - std::vector extensions(glfwExtensions, glfwExtensions + glfwExtensionCount); - - if (enableValidationLayers) { - extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } - - return extensions; - } - - void createInstance() { - if (enableValidationLayers && !checkValidationLayerSupport()) { - throw std::runtime_error("Validation layer requested, but not available!"); - } - - VkApplicationInfo appInfo{}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = "Hello Triangle"; - appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.pEngineName = "No Engine"; - appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.apiVersion = VK_API_VERSION_1_0; - - VkInstanceCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.pApplicationInfo = &appInfo; - - VkDebugUtilsMessengerCreateInfoEXT debugcreateinfo{}; - if (enableValidationLayers) { - createInfo.enabledLayerCount = static_cast(validationLayers.size()); - createInfo.ppEnabledLayerNames = validationLayers.data(); - - populateDebugMessengerCreateInfo(debugcreateinfo); - createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugcreateinfo; - - } - else { - createInfo.enabledLayerCount = 0; - createInfo.pNext = nullptr; - } - - - auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = static_cast(extensions.size()); - createInfo.ppEnabledExtensionNames = extensions.data(); - - if (enableValidationLayers) { - createInfo.enabledLayerCount = static_cast (validationLayers.size()); - createInfo.ppEnabledLayerNames = validationLayers.data(); - } - else { - createInfo.enabledLayerCount = 0; - } - - - - - if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { - throw std::runtime_error("Failed to create instance!"); - } - - - - } - - VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { - for (const auto& availableFormat : availableFormats) { - if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - return availableFormat; - } - } - - return availableFormats[0]; - } - - VkPresentModeKHR chooseSwapPresentMode(const std::vector& availablePresentModes) { - for (const auto& availablePresentMode : availablePresentModes) { - if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { - return availablePresentMode; - } - } - return VK_PRESENT_MODE_FIFO_KHR; - } - - VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) { - 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::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); - actualExtent.height = std::clamp(actualExtent.width, capabilities.minImageExtent.height, capabilities.minImageExtent.height); - - return actualExtent; - } - } - - void mainLoop(){ - while (!glfwWindowShouldClose(window)){ - glfwPollEvents(); - drawFrame(); - } - - vkDeviceWaitIdle(device); - } - - void drawFrame() { - vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); - - uint32_t imageIndex; - VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); - - - - if (result == VK_ERROR_OUT_OF_DATE_KHR) { - recreateSwapChain(); - return; - } - else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - throw std::runtime_error("failed to acquire swap chain image!"); - } - - updateUniformBuffer(currentFrame); - - vkResetFences(device, 1, &inFlightFences[currentFrame]); - - - vkResetCommandBuffer(commandBuffers[currentFrame], 0); - recordCommandBuffer(commandBuffers[currentFrame], imageIndex); - - VkSubmitInfo submitInfo{}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - - VkSemaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame]}; - VkPipelineStageFlags waitstages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = waitSemaphores; - submitInfo.pWaitDstStageMask = waitstages; - - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffers[currentFrame]; - - VkSemaphore signalSemaphore[] = { renderFinishedSemaphores[currentFrame]}; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = signalSemaphore; - - if (vkQueueSubmit(graphicsQueue,1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) { - throw std::runtime_error("failed to submit draw command buffer"); - } - - VkPresentInfoKHR presentInfo{}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = signalSemaphore; - - VkSwapchainKHR swapChains[] = { swapChain }; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = swapChains; - presentInfo.pImageIndices = &imageIndex; - - result = vkQueuePresentKHR(presentQueue, &presentInfo); - - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } - else if (result != VK_SUCCESS) { - throw std::runtime_error("failed to present swap chain image!"); - } - - currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; - } - - void updateUniformBuffer(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(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), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f); - ubo.proj[1][1] *= -1; // Invert Y to correct for left or right handedness - - memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo)); - } - - - - void cleanup(){ - cleanupSwapChain(); - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - vkDestroyBuffer(device, uniformBuffers[i], nullptr); - vkFreeMemory(device, uniformBuffersMemory[i], nullptr); - } - vkDestroyDescriptorPool(device, descriptorPool, nullptr); - - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - - vkDestroyBuffer(device, indexBuffer, nullptr); - vkFreeMemory(device, vertexBufferMemory, nullptr); - - vkDestroyBuffer(device, vertexBuffer, nullptr); - vkFreeMemory(device, vertexBufferMemory, nullptr); - - vkDestroyPipeline(device, graphicsPipeline, nullptr); - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyRenderPass(device, renderPass, nullptr); - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr); - vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr); - vkDestroyFence(device, inFlightFences[i], nullptr); - - } - - vkDestroyCommandPool(device, commandPool, nullptr); - - - vkDestroyDevice(device, nullptr); - if(enableValidationLayers){ - DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr); - } - - - vkDestroySurfaceKHR(instance, surface, nullptr); - vkDestroyInstance(instance, nullptr); - - - glfwDestroyWindow(window); - glfwTerminate(); - } - - void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) { - 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; - } - - void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) { - auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); - if (func != nullptr) { - func(instance, debugMessenger, pAllocator); - } - } - - static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData){ - - - std::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl; - return VK_FALSE; - } - +struct SwapChainSupportDetails { + VkSurfaceCapabilitiesKHR capabilities; + std::vector formats; + std::vector presentModes; }; -int main ( ) { - HelloTriangleApplication app; +struct Vertex { + glm::vec2 pos; + glm::vec3 color; - try{ - app.run(); - } catch (const std::exception& e){ - std::cerr << e.what() << std::endl; - return EXIT_FAILURE; + static VkVertexInputBindingDescription getBindingDescription() { + VkVertexInputBindingDescription bindingDescription{}; + bindingDescription.binding = 0; + bindingDescription.stride = sizeof(Vertex); + bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + return bindingDescription; + } + + static std::array + getAttributeDescriptions() { + std::array attributeDescription{}; + + attributeDescription[0].binding = 0; + attributeDescription[0].location = 0; + attributeDescription[0].format = VK_FORMAT_R32G32_SFLOAT; + attributeDescription[0].offset = offsetof(Vertex, pos); + + attributeDescription[1].binding = 0; + attributeDescription[1].location = 1; + attributeDescription[1].format = VK_FORMAT_R32G32B32_SFLOAT; + attributeDescription[1].offset = offsetof(Vertex, color); + + return attributeDescription; + } +}; + +struct UniformBufferObject { + alignas(16) glm::mat4 model; + alignas(16) glm::mat4 view; + alignas(16) glm::mat4 proj; +}; + +const std::vector vertices = {{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, + {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, + {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}, + {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}}; + +const std::vector indices = {0, 1, 2, 2, 3, 0}; + +class HelloTriangleApplication { +public: + void run() { + initWindow(); + initVulkan(); + mainLoop(); + cleanup(); + } + +private: + GLFWwindow *window; + + VkInstance instance; + VkDebugUtilsMessengerEXT debugMessenger; + VkSurfaceKHR surface; + + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + VkDevice device; + + VkQueue graphicsQueue; + VkQueue presentQueue; + + VkSwapchainKHR swapChain; + std::vector swapChainImages; + VkFormat swapChainImageFormat; + VkExtent2D swapChainExtent; + std::vector swapChainImageViews; + std::vector swapchainFrameBuffers; + + VkRenderPass renderPass; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; + + VkCommandPool commandPool; + + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; + + VkBuffer indexBuffer; + VkDeviceMemory indexBufferMemory; + + std::vector uniformBuffers; + std::vector uniformBuffersMemory; + std::vector uniformBuffersMapped; + + VkDescriptorPool descriptorPool; + std::vector descriptorSets; + + std::vector commandBuffers; + + std::vector imageAvailableSemaphores; + std::vector renderFinishedSemaphores; + std::vector inFlightFences; + uint32_t currentFrame = 0; + + bool framebufferResized = false; + + void initWindow() { + glfwInit(); + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + + window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); + glfwSetWindowUserPointer(window, this); + glfwSetFramebufferSizeCallback(window, framebufferResizeCallback); + } + + static void framebufferResizeCallback(GLFWwindow *window, int width, + int height) { + auto app = reinterpret_cast( + glfwGetWindowUserPointer(window)); + app->framebufferResized = true; + } + + void initVulkan() { + createInstance(); + setupDebugMessenger(); + createSurface(); + pickPhysicalDevice(); + createLogicalDevice(); + createSwapChain(); + createImageViews(); + createRenderPass(); + createDescriptorSetLayout(); + createGraphicsPipeline(); + createFramebuffers(); + createCommandPool(); + createVertexBuffer(); + createIndexBuffer(); + createUniformBuffers(); + createDescriptorPool(); + createDescriptorSets(); + createCommandBuffers(); + createSyncObjects(); + } + + void mainLoop() { + while (!glfwWindowShouldClose(window)) { + glfwPollEvents(); + drawFrame(); } - return EXIT_SUCCESS; - -} \ No newline at end of file + vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapchainFrameBuffers.size(); i++) { + vkDestroyFramebuffer(device, swapchainFrameBuffers[i], nullptr); + } + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + vkDestroyBuffer(device, uniformBuffers[i], nullptr); + vkFreeMemory(device, uniformBuffersMemory[i], nullptr); + } + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr); + vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr); + vkDestroyFence(device, inFlightFences[i], nullptr); + } + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + if (enableValidationLayers) { + DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr); + } + + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); + + glfwDestroyWindow(window); + glfwTerminate(); + } + + void recreateSwapChain() { + int width = 0, height = 0; + glfwGetFramebufferSize(window, &width, &height); + + while (width == 0 || height == 0) { + glfwGetFramebufferSize(window, &width, &height); + glfwWaitEvents(); + } + + vkDeviceWaitIdle(device); + + cleanupSwapChain(); + + createSwapChain(); + createImageViews(); + createFramebuffers(); + } + + void createInstance() { + if (enableValidationLayers && !checkValidationLayerSupport()) { + throw std::runtime_error( + "Validation layer requested, but not available!"); + } + + VkApplicationInfo appInfo{}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "Hello Triangle"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "No Engine"; + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.apiVersion = VK_API_VERSION_1_0; + + VkInstanceCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &appInfo; + + VkDebugUtilsMessengerCreateInfoEXT debugcreateinfo{}; + if (enableValidationLayers) { + createInfo.enabledLayerCount = + static_cast(validationLayers.size()); + createInfo.ppEnabledLayerNames = validationLayers.data(); + + populateDebugMessengerCreateInfo(debugcreateinfo); + createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT *)&debugcreateinfo; + + } else { + createInfo.enabledLayerCount = 0; + createInfo.pNext = nullptr; + } + + auto extensions = getRequiredExtensions(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); + createInfo.ppEnabledExtensionNames = extensions.data(); + + if (enableValidationLayers) { + createInfo.enabledLayerCount = + static_cast(validationLayers.size()); + createInfo.ppEnabledLayerNames = validationLayers.data(); + } else { + createInfo.enabledLayerCount = 0; + } + + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { + throw std::runtime_error("Failed to create instance!"); + } + } + + void createDescriptorSets() { + std::vector layouts(MAX_FRAMES_IN_FLIGHT, + descriptorSetLayout); + VkDescriptorSetAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = descriptorPool; + allocInfo.descriptorSetCount = static_cast(MAX_FRAMES_IN_FLIGHT); + allocInfo.pSetLayouts = layouts.data(); + + descriptorSets.resize(MAX_FRAMES_IN_FLIGHT); + if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != + VK_SUCCESS) { + throw std::runtime_error("failed to allocate descriptor sets!"); + } + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + VkDescriptorBufferInfo bufferInfo{}; + bufferInfo.buffer = uniformBuffers[i]; + bufferInfo.offset = 0; + bufferInfo.range = sizeof(UniformBufferObject); + + VkWriteDescriptorSet descriptorWrite{}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSets[i]; + descriptorWrite.dstBinding = 0; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + descriptorWrite.pImageInfo = nullptr; // Optional + descriptorWrite.pTexelBufferView = nullptr; // Optional + + vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); + } + } + + void createDescriptorPool() { + VkDescriptorPoolSize poolSize{}; + poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSize.descriptorCount = static_cast(MAX_FRAMES_IN_FLIGHT); + + VkDescriptorPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = 1; + poolInfo.pPoolSizes = &poolSize; + poolInfo.maxSets = static_cast(MAX_FRAMES_IN_FLIGHT); + + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != + VK_SUCCESS) { + throw std::runtime_error("failed to create descriptor pool!"); + } + } + + void createUniformBuffers() { + VkDeviceSize buffersize = sizeof(UniformBufferObject); + + uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT); + uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT); + uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT); + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + CreateBuffer(buffersize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + uniformBuffers[i], uniformBuffersMemory[i]); + + vkMapMemory(device, uniformBuffersMemory[i], 0, buffersize, 0, + &uniformBuffersMapped[i]); + } + } + + void createDescriptorSetLayout() { + VkDescriptorSetLayoutBinding uboLayoutBinding{}; + uboLayoutBinding.binding = 0; + uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uboLayoutBinding.descriptorCount = 1; + + uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + uboLayoutBinding.pImmutableSamplers = nullptr; // Optional + + VkDescriptorSetLayoutCreateInfo layoutInfo{}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = 1; + layoutInfo.pBindings = &uboLayoutBinding; + + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, + &descriptorSetLayout) != VK_SUCCESS) { + throw std::runtime_error("failed to create descriptor set layout!"); + } + } + + uint32_t findMemoryType(uint32_t typeFilter, + VkMemoryPropertyFlags properties) { + VkPhysicalDeviceMemoryProperties memProperties; + vkGetPhysicalDeviceMemoryProperties(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!"); + } + + void 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; + + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { + throw std::runtime_error("failed to create vertex buffer!"); + } + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(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(device, &allocInfo, nullptr, &buffermemory) != + VK_SUCCESS) { + throw std::runtime_error("failed to allocate vertex buffer memory!"); + } + vkBindBufferMemory(device, buffer, buffermemory, 0); + } + + // copy from staging to the vertex buffer + void 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 = commandPool; + allocInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + vkAllocateCommandBuffers(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; // Optional + copyRegion.dstOffset = 0; // Optional + 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(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(graphicsQueue); + + vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); + } + + // Create a staging and vertex buffer + void createVertexBuffer() { + + 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(device, stagingBufferMemory, 0, buffersize, 0, &data); + memcpy(data, vertices.data(), (size_t)buffersize); + vkUnmapMemory(device, stagingBufferMemory); + + CreateBuffer( + buffersize, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); + + copyBuffer(stagingBuffer, vertexBuffer, buffersize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); + } + + void createIndexBuffer() { + VkDeviceSize buffersize = sizeof(indices[0]) * indices.size(); + + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + CreateBuffer(buffersize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + stagingBuffer, stagingBufferMemory); + + void *data; + vkMapMemory(device, stagingBufferMemory, 0, buffersize, 0, &data); + memcpy(data, indices.data(), (size_t)buffersize); + vkUnmapMemory(device, stagingBufferMemory); + + CreateBuffer( + buffersize, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); + + copyBuffer(stagingBuffer, indexBuffer, buffersize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); + } + + void createSyncObjects() { + imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + 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++) { + + if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, + &imageAvailableSemaphores[i]) != VK_SUCCESS || + vkCreateSemaphore(device, &semaphoreInfo, nullptr, + &renderFinishedSemaphores[i]) != VK_SUCCESS || + vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != + VK_SUCCESS) { + throw std::runtime_error("failed to create semaphores!"); + } + } + } + + void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { + throw std::runtime_error("failed to begin recording command buffer!"); + } + + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = renderPass; + renderPassInfo.framebuffer = swapchainFrameBuffers[imageIndex]; + + renderPassInfo.renderArea.offset = {0, 0}; + renderPassInfo.renderArea.extent = swapChainExtent; + + VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearColor; + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, + VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + graphicsPipeline); + + VkBuffer vertexBuffers[] = {vertexBuffer}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); + + vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT16); + + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(swapChainExtent.width); + viewport.height = static_cast(swapChainExtent.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + + VkRect2D scissor{}; + scissor.offset = {0, 0}; + scissor.extent = swapChainExtent; + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + pipelineLayout, 0, 1, &descriptorSets[currentFrame], + 0, nullptr); + + vkCmdDrawIndexed(commandBuffer, static_cast(indices.size()), 1, 0, + 0, 0); + + vkCmdEndRenderPass(commandBuffer); + + if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { + throw std::runtime_error("failed to record command buffer!"); + } + } + + void createCommandBuffers() { + commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); + + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = commandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = (uint32_t)commandBuffers.size(); + + if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != + VK_SUCCESS) { + throw std::runtime_error("failed to allocate command buffers!"); + } + } + + void createSurface() { + if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != + VK_SUCCESS) { + throw std::runtime_error("failed ot create window surface!"); + } + } + + void createLogicalDevice() { + QueueFamilyIndices indices = findQueueFamilies(physicalDevice); + + std::vector queueCreateInfos; + std::set uniqueQueueFamilies = {indices.graphicsFamily.value(), + 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); + } + + VkPhysicalDeviceFeatures deviceFeatures{}; + + VkDeviceCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + + createInfo.queueCreateInfoCount = + static_cast(queueCreateInfos.size()); + createInfo.pQueueCreateInfos = queueCreateInfos.data(); + + createInfo.pEnabledFeatures = &deviceFeatures; + + createInfo.enabledExtensionCount = + static_cast(deviceExtensions.size()); + + createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + + if (enableValidationLayers) { + createInfo.enabledLayerCount = + static_cast(validationLayers.size()); + createInfo.ppEnabledLayerNames = validationLayers.data(); + } else { + createInfo.enabledLayerCount = 0; + } + + if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != + VK_SUCCESS) { + throw std::runtime_error("failed to create logical device"); + } + + vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue); + vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue); + } + + void createSwapChain() { + SwapChainSupportDetails swapChainSupport = + querySwapChainSupport(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 = 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; + + QueueFamilyIndices indices = findQueueFamilies(physicalDevice); + uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), + indices.presentFamily.value()}; + + if (indices.graphicsFamily != 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; + + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != + VK_SUCCESS) { + throw std::runtime_error("failed to create swap chain!"); + } + + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); + swapChainImages.resize(imageCount); + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, + swapChainImages.data()); + + swapChainImageFormat = surfaceFormat.format; + swapChainExtent = extent; + } + + void createImageViews() { + swapChainImageViews.resize(swapChainImages.size()); + for (size_t i = 0; i < swapChainImages.size(); i++) { + VkImageViewCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = swapChainImages[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = 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; + + if (vkCreateImageView(device, &createInfo, nullptr, + &swapChainImageViews[i]) != VK_SUCCESS) { + throw std::runtime_error("Failed to create image views!"); + } + } + } + + void createRenderPass() { + VkAttachmentDescription colorAttachment{}; + colorAttachment.format = 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 colorAttachementRef{}; + colorAttachementRef.attachment = 0; + colorAttachementRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass{}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachementRef; + + 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 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; + + if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != + VK_SUCCESS) { + throw std::runtime_error("Failed to create render pass!"); + } + } + + void createGraphicsPipeline() { + auto vertShaderCode = readFile("shaders/vert.spv"); + auto fragShaderCode = readFile("shaders/frag.spv"); + + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(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}; + + 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(attributeDescriptions.size()); + vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); + + VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; + inputAssembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + inputAssembly.primitiveRestartEnable = VK_FALSE; + + // DYNAMIC VIEWPORT & SCISSOR + + std::vector dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR}; + + VkPipelineDynamicStateCreateInfo dynamicState{}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = + static_cast(dynamicStates.size()); + dynamicState.pDynamicStates = dynamicStates.data(); + + VkPipelineViewportStateCreateInfo viewportState{}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.scissorCount = 1; + + 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; + + VkPipelineMultisampleStateCreateInfo multisampling{}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + 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; + + VkPipelineColorBlendStateCreateInfo colorBlending{}; + colorBlending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.logicOpEnable = VK_FALSE; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; + + if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, + &pipelineLayout) != VK_SUCCESS) { + throw std::runtime_error("failed to create pipeline layout!"); + } + + 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 = &dynamicState; + + pipelineInfo.layout = pipelineLayout; + + pipelineInfo.renderPass = renderPass; + pipelineInfo.subpass = 0; + + if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, + nullptr, &graphicsPipeline) != VK_SUCCESS) { + throw std::runtime_error("Failed to create graphics pipeline!"); + } + + vkDestroyShaderModule(device, vertShaderModule, nullptr); + vkDestroyShaderModule(device, fragShaderModule, nullptr); + } + + void createFramebuffers() { + swapchainFrameBuffers.resize(swapChainImageViews.size()); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + VkImageView attachements[] = {swapChainImageViews[i]}; + + VkFramebufferCreateInfo framebufferInfo{}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = renderPass; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = attachements; + framebufferInfo.width = swapChainExtent.width; + framebufferInfo.height = swapChainExtent.height; + framebufferInfo.layers = 1; + + if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, + &swapchainFrameBuffers[i]) != VK_SUCCESS) { + throw std::runtime_error("failed to create framebuffer!"); + } + } + } + + void createCommandPool() { + QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice); + + VkCommandPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value(); + + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != + VK_SUCCESS) { + throw std::runtime_error("Failed to create command pool!"); + } + } + + VkShaderModule createShaderModule(const std::vector &code) { + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = code.size(); + createInfo.pCode = reinterpret_cast(code.data()); + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != + VK_SUCCESS) { + throw std::runtime_error("Failed to create shader module!"); + } + return shaderModule; + } + + static std::vector readFile(const std::string &filename) { + std::ifstream file(filename, std::ios::ate | std::ios::binary); + + if (!file.is_open()) { + throw std::runtime_error("failed to open file!"); + } + + size_t fileSize = (size_t)file.tellg(); + std::vector buffer(fileSize); + + file.seekg(0); + file.read(buffer.data(), fileSize); + + file.close(); + return buffer; + } + + void pickPhysicalDevice() { + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); + + if (deviceCount == 0) { + throw std::runtime_error("failed to find GPU's with Vulkan support!"); + } + + std::vector devices(deviceCount); + vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); + + for (const auto &device : devices) { + if (isDeviceSuitable(device)) { + physicalDevice = device; + break; + } + } + + if (physicalDevice == VK_NULL_HANDLE) { + throw std::runtime_error("failed to find a suitable GPU"); + } + } + + bool isDeviceSuitable(VkPhysicalDevice device) { + + QueueFamilyIndices indices = findQueueFamilies(device); + bool extensionSupported = checkDeviceExtensionSupport(device); + + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(device, &deviceProperties); + + VkPhysicalDeviceFeatures deviceFeatures; + vkGetPhysicalDeviceFeatures(device, &deviceFeatures); + + bool swapChainAdequate = false; + if (extensionSupported) { + SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device); + swapChainAdequate = !swapChainSupport.formats.empty() && + !swapChainSupport.presentModes.empty(); + } + + return indices.isComplete() && extensionSupported && swapChainAdequate; + } + + struct QueueFamilyIndices { + std::optional graphicsFamily; + std::optional presentFamily; + + bool isComplete() { + return graphicsFamily.has_value() && presentFamily.has_value(); + } + }; + + QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) { + QueueFamilyIndices indices; + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, + nullptr); + + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, + queueFamilies.data()); + + int i = 0; + for (const auto &queueFamily : queueFamilies) { + + VkBool32 presentSupport = false; + vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); + + if (presentSupport) { + indices.presentFamily = i; + } + + if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { + indices.graphicsFamily = i; + } + + if (indices.isComplete()) { + break; + } + + i++; + } + + return indices; + } + + SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) { + SwapChainSupportDetails details; + + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, + &details.capabilities); + + uint32_t formatCount; + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, + nullptr); + + if (formatCount != 0) { + details.formats.resize(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, + details.formats.data()); + } + + uint32_t presentModeCount; + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, + &presentModeCount, nullptr); + + if (presentModeCount != 0) { + details.presentModes.resize(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR( + device, surface, &presentModeCount, details.presentModes.data()); + } + + return details; + } + + VkResult 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 setupDebugMessenger() { + if (!enableValidationLayers) + return; + + VkDebugUtilsMessengerCreateInfoEXT createinfo; + populateDebugMessengerCreateInfo(createinfo); + + if (CreateDebugUtilsMessengerEXT(instance, &createinfo, nullptr, + &debugMessenger) != VK_SUCCESS) { + throw std::runtime_error("failed to set up debug messenger!"); + } + } + + bool checkValidationLayerSupport() { + uint32_t layerCount; + vkEnumerateInstanceLayerProperties(&layerCount, nullptr); + + std::vector availableLayers(layerCount); + vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); + + for (const char *layerName : validationLayers) { + bool layerFound = false; + + for (const auto &layerProperties : availableLayers) { + if (strcmp(layerName, layerProperties.layerName) == 0) { + layerFound = true; + break; + } + } + + if (!layerFound) { + return false; + } + } + + return true; + } + + bool checkDeviceExtensionSupport(VkPhysicalDevice device) { + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, + nullptr); + + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, + availableExtensions.data()); + + std::set requiredExtensions(deviceExtensions.begin(), + deviceExtensions.end()); + + for (const auto &extension : availableExtensions) { + requiredExtensions.erase(extension.extensionName); + } + + return requiredExtensions.empty(); + } + + std::vector getRequiredExtensions() { + uint32_t glfwExtensionCount = 0; + const char **glfwExtensions; + glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); + + std::vector extensions(glfwExtensions, + glfwExtensions + glfwExtensionCount); + + if (enableValidationLayers) { + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + } + + return extensions; + } + + VkSurfaceFormatKHR chooseSwapSurfaceFormat( + const std::vector &availableFormats) { + for (const auto &availableFormat : availableFormats) { + if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && + availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + return availableFormat; + } + } + + return availableFormats[0]; + } + + VkPresentModeKHR chooseSwapPresentMode( + const std::vector &availablePresentModes) { + for (const auto &availablePresentMode : availablePresentModes) { + if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { + return availablePresentMode; + } + } + return VK_PRESENT_MODE_FIFO_KHR; + } + + VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities) { + 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::clamp(actualExtent.width, capabilities.minImageExtent.width, + capabilities.maxImageExtent.width); + actualExtent.height = + std::clamp(actualExtent.width, capabilities.minImageExtent.height, + capabilities.minImageExtent.height); + + return actualExtent; + } + } + + void drawFrame() { + vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, + UINT64_MAX); + + uint32_t imageIndex; + VkResult result = vkAcquireNextImageKHR( + device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], + VK_NULL_HANDLE, &imageIndex); + + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + recreateSwapChain(); + return; + } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + throw std::runtime_error("failed to acquire swap chain image!"); + } + + updateUniformBuffer(currentFrame); + + vkResetFences(device, 1, &inFlightFences[currentFrame]); + + vkResetCommandBuffer(commandBuffers[currentFrame], 0); + + recordCommandBuffer(commandBuffers[currentFrame], imageIndex); + + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]}; + VkPipelineStageFlags waitstages[] = { + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = waitSemaphores; + submitInfo.pWaitDstStageMask = waitstages; + + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffers[currentFrame]; + + VkSemaphore signalSemaphore[] = {renderFinishedSemaphores[currentFrame]}; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = signalSemaphore; + + if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, + inFlightFences[currentFrame]) != VK_SUCCESS) { + throw std::runtime_error("failed to submit draw command buffer"); + } + + VkPresentInfoKHR presentInfo{}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = signalSemaphore; + + VkSwapchainKHR swapChains[] = {swapChain}; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = swapChains; + presentInfo.pImageIndices = &imageIndex; + + result = vkQueuePresentKHR(presentQueue, &presentInfo); + + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || + framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != VK_SUCCESS) { + throw std::runtime_error("failed to present swap chain image!"); + } + + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + } + + void updateUniformBuffer(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( + 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), + swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f); + ubo.proj[1][1] *= -1; // Invert Y to correct for left or right handedness + + memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo)); + } + + void populateDebugMessengerCreateInfo( + VkDebugUtilsMessengerCreateInfoEXT &createInfo) { + 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; + } + + void DestroyDebugUtilsMessengerEXT(VkInstance instance, + VkDebugUtilsMessengerEXT debugMessenger, + const VkAllocationCallbacks *pAllocator) { + auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( + instance, "vkDestroyDebugUtilsMessengerEXT"); + if (func != nullptr) { + func(instance, debugMessenger, pAllocator); + } + } + + static VKAPI_ATTR VkBool32 VKAPI_CALL + debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, + void *pUserData) { + + std::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl; + return VK_FALSE; + } +}; + +int main() { + // Start application + HelloTriangleApplication app; + + try { + app.run(); + } catch (const std::exception &e) { + std::cerr << e.what() << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/HelloVulkan/premake5.lua b/HelloVulkan/premake5.lua index c6da72c..764d0d0 100644 --- a/HelloVulkan/premake5.lua +++ b/HelloVulkan/premake5.lua @@ -1,8 +1,6 @@ -require("premake", ">=5.0-beta2") - project "HelloVulkan" - files{ - "**.cpp", - "**.h" - } - \ No newline at end of file +files { + "**.cpp", + "**.h" +} + diff --git a/premake5.lua b/premake5.lua index c7fc5c4..bf264b0 100644 --- a/premake5.lua +++ b/premake5.lua @@ -1,3 +1,5 @@ +require "../export-compile-commands" + workspace "LearnVulkan" kind "ConsoleApp" language "C++" @@ -7,6 +9,7 @@ targetdir "%{prj.location}/bin/%{cfg.buildcfg}" configurations { "Debug", "Release" } + filter "configurations:Debug" defines { "DEBUG" } symbols "On" @@ -16,46 +19,41 @@ defines { "NDEBUG" } optimize "On" filter "system:windows" --- buildoptions { --- "/MD" --- } linkoptions { - -- "/NODEFAULTLIB:library" - "-nodefaultlibs" + "-nodefaultlibs" } libdirs { - "C:/VulkanSDK/1.4.304.1/Lib", - "libs/GLFW", + "C:/VulkanSDK/1.4.304.1/Lib", + "libs/GLFW", } includedirs { - "C:/VulkanSDK/1.4.304.1/Include", - "libs" + "C:/VulkanSDK/1.4.304.1/Include", + "libs" } links { - "msvcrt", - "user32", - "kernel32", - "libcmt", - "gdi32", - "glu32", - "shell32", - "opengl32", - "glfw3", - "vulkan-1" - + "msvcrt", + "user32", + "kernel32", + "libcmt", + "gdi32", + "glu32", + "shell32", + "opengl32", + "glfw3", + "vulkan-1" } filter "system:linux" links { - "glfw3", - "vulkan", - "dl", - "pthread", - "X11", - "Xxf86vm", - "Xrandr", - "Xi" + "glfw3", + "vulkan", + "dl", + "pthread", + "X11", + "Xxf86vm", + "Xrandr", + "Xi" } include("HelloVulkan/premake5.lua")