diff --git a/vulkan/vulkan_app.cpp b/vulkan/vulkan_app.cpp index 36d3759..ca336fe 100644 --- a/vulkan/vulkan_app.cpp +++ b/vulkan/vulkan_app.cpp @@ -13,17 +13,12 @@ namespace vapp{ VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; - static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, - void *pUserData){ + 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; } - VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkDebugUtilsMessengerEXT *pDebugMessenger){ + VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pDebugMessenger){ auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr( instance, "vkCreateDebugUtilsMessengerEXT"); if(func == nullptr) return VK_ERROR_EXTENSION_NOT_PRESENT; @@ -31,8 +26,7 @@ namespace vapp{ return func(instance, pCreateInfo, pAllocator, pDebugMessenger); } - void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, - const VkAllocationCallbacks *pAllocator){ + void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks *pAllocator){ if(auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( instance, "vkDestroyDebugUtilsMessengerEXT"); func != nullptr){ func(instance, debugMessenger, pAllocator); @@ -481,10 +475,15 @@ namespace vapp{ dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); dynamicState.pDynamicStates = dynamicStates.data(); + auto bindingDescription = Vertex::getBindingDescription(); + auto attributeDescription = Vertex::getAttributeDescriptions(); + VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputInfo.vertexBindingDescriptionCount = 0; - vertexInputInfo.vertexAttributeDescriptionCount = 0; + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescription.size()); + vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; + vertexInputInfo.pVertexAttributeDescriptions = attributeDescription.data(); VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -675,6 +674,97 @@ namespace vapp{ } } + uint32_t Vulkan::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("Func: findMemoryType\nError: Failed to find suitable memory type!\n"); + } + + void Vulkan::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("Func: createBuffer\nError: Failed to create buffer!\n"); + } + + 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("Func: createBuffer\nError: Failed to allocate memory for buffer!\n"); + } + + vkBindBufferMemory(device, buffer, bufferMemory, 0); + } + + void Vulkan::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.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); + } + + void Vulkan::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 Vulkan::createCommandBuffers(){ commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); @@ -711,6 +801,10 @@ namespace vapp{ 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); + VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; @@ -725,7 +819,7 @@ namespace vapp{ scissor.extent = swapChainExtent; vkCmdSetScissor(commandBuffer, 0, 1, &scissor); - vkCmdDraw(commandBuffer, 3, 1, 0, 0); + vkCmdDraw(commandBuffer, static_cast(vertices.size()), 1, 0, 0); vkCmdEndRenderPass(commandBuffer); if(vkEndCommandBuffer(commandBuffer) != VK_SUCCESS){ @@ -862,6 +956,7 @@ namespace vapp{ createGraphicsPipeline(); createFrameBuffers(); createCommandPool(); + createVertexBuffer(); createCommandBuffers(); createSyncObjects(); } @@ -879,6 +974,9 @@ namespace vapp{ // Vulkan cleanupSwapChain(); + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + vkDestroyPipeline(device, graphicsPipeline, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr); diff --git a/vulkan/vulkan_app.hpp b/vulkan/vulkan_app.hpp index f60a168..dc83997 100644 --- a/vulkan/vulkan_app.hpp +++ b/vulkan/vulkan_app.hpp @@ -19,114 +19,160 @@ #include #include #include +#include +#include namespace vapp{ + // Change here for other presentMode + const VkPresentModeKHR WISHED_PRESENT_MODE = VK_PRESENT_MODE_MAILBOX_KHR; -// Change here for other presentMode -const VkPresentModeKHR WISHED_PRESENT_MODE = VK_PRESENT_MODE_MAILBOX_KHR; + struct Vertex{ + glm::vec2 pos; + glm::vec3 color; -typedef struct _QueueFamilyIndices{ - std::optional graphicsFamily; - std::optional presentFamily; + static VkVertexInputBindingDescription getBindingDescription(){ + VkVertexInputBindingDescription bindingDescription{}; + bindingDescription.binding = 0; + bindingDescription.stride = sizeof(Vertex); + bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + return bindingDescription; + } - bool isComplete(){ - return graphicsFamily.has_value(); - } -} QueueFamilyIndices; + static std::array getAttributeDescriptions(){ + std::array attributeDescriptions{}; -typedef struct{ - VkSurfaceCapabilitiesKHR capabilities; - std::vector formats; - std::vector presentModes; -} SwapChainSupportDetails; + attributeDescriptions[0].binding = 0; + attributeDescriptions[0].location = 0; + attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + attributeDescriptions[0].offset = offsetof(Vertex, pos); -static std::vector readFile(const std::string &filename); + attributeDescriptions[1].binding = 0; + attributeDescriptions[1].location = 1; + attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; + attributeDescriptions[1].offset = offsetof(Vertex, color); -class Vulkan{ -private: + return attributeDescriptions; + } + }; + + // TODO: Remove + const std::vector vertices = { + {{0.0f, -0.5f}, {0.0f, 1.0f, 0.0f}}, +{{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}}, +{{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}} + }; + + struct QueueFamilyIndices{ + std::optional graphicsFamily; + std::optional presentFamily; + + bool isComplete(){ + return graphicsFamily.has_value(); + } + }; + + struct SwapChainSupportDetails{ + VkSurfaceCapabilitiesKHR capabilities; + std::vector formats; + std::vector presentModes; + }; + + static std::vector readFile(const std::string& filename); + static std::array getAttributeDescription(); + + + class Vulkan{ + private: #pragma region Fields - GLFWwindow *window; - uint32_t _width, _height; + GLFWwindow *window; + uint32_t _width, _height; - VkInstance instance; - VkDebugUtilsMessengerEXT debugMessenger; + VkInstance instance; + VkDebugUtilsMessengerEXT debugMessenger; - VkSurfaceKHR surface; + VkSurfaceKHR surface; - VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VkDevice device; + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + VkDevice device; - VkQueue graphicsQueue; - VkQueue presentQueue; + VkQueue graphicsQueue; + VkQueue presentQueue; - VkSwapchainKHR swapChain; - std::vector swapChainImages; - VkFormat swapChainImageFormat; - VkExtent2D swapChainExtent; + VkSwapchainKHR swapChain; + std::vector swapChainImages; + VkFormat swapChainImageFormat; + VkExtent2D swapChainExtent; - std::vector swapChainImageViews; + std::vector swapChainImageViews; - VkRenderPass renderPass; - VkPipelineLayout pipelineLayout; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; - VkPipeline graphicsPipeline; + VkPipeline graphicsPipeline; - VkCommandPool commandPool; - std::vector commandBuffers; + VkCommandPool commandPool; + std::vector commandBuffers; - std::vector imageAvailableSemaphores, renderFinishedSemaphores; - std::vector inFlightFences; + std::vector imageAvailableSemaphores, renderFinishedSemaphores; + std::vector inFlightFences; - std::vector swapChainFramebuffers; + std::vector swapChainFramebuffers; - const int MAX_FRAMES_IN_FLIGHT = 2; - uint32_t currentFrame = 0; + const int MAX_FRAMES_IN_FLIGHT = 2; + uint32_t currentFrame = 0; + + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; #pragma endregion - bool checkValidationLayerSupport(); - std::vector getRequiredExtensions(); + bool checkValidationLayerSupport(); + std::vector getRequiredExtensions(); - void createInstance(); - void setupDebugMessenger(); - void pickPhysicalDevice(); - void createLogicalDevice(); - QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); - bool checkDeviceExtensionSupport(VkPhysicalDevice device); - bool isDeviceSuitable(VkPhysicalDevice device); - void createSurface(); - SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device); - VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats); - VkPresentModeKHR chooseSwapPresentMode(const std::vector availablePresentModes); - VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); - void createSwapChain(); - void createImageViews(); - void createGraphicsPipeline(); - VkShaderModule createShaderModule(const std::vector &code); - void createRenderPass(); - void createFrameBuffers(); - void createCommandPool(); - void createCommandBuffers(); - void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex); - void createSyncObjects(); - void drawFrame(); - void cleanupSwapChain(); - void recreateSwapChain(); - void initWindow(const char* windowName); - void initVulkan(); - void mainLoop(); - void cleanup(); + void createInstance(); + void setupDebugMessenger(); + void pickPhysicalDevice(); + void createLogicalDevice(); + QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); + bool checkDeviceExtensionSupport(VkPhysicalDevice device); + bool isDeviceSuitable(VkPhysicalDevice device); + void createSurface(); + SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device); + VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats); + VkPresentModeKHR chooseSwapPresentMode(const std::vector availablePresentModes); + VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); + void createSwapChain(); + void createImageViews(); + void createGraphicsPipeline(); + VkShaderModule createShaderModule(const std::vector& code); + void createRenderPass(); + void createFrameBuffers(); + void createCommandPool(); + uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory); + void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); + void createVertexBuffer(); + void createCommandBuffers(); + void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex); + void createSyncObjects(); + void drawFrame(); + void cleanupSwapChain(); + void recreateSwapChain(); + void initWindow(const char *windowName); + void initVulkan(); + void mainLoop(); + void cleanup(); -public: - #ifdef DEBUG + public: +#ifdef DEBUG const bool enableValidationLayers = true; - #else +#else const bool enableValidationLayers = false; - #endif +#endif - bool framebufferResized = false; + bool framebufferResized = false; - void run(const char* windowName, const uint32_t width = 800, const uint32_t height = 600); -}; + void run(const char *windowName, const uint32_t width = 800, const uint32_t height = 600); + }; } // vapp #endif //VULKAN_APP_H