diff --git a/src/VulkanRenderer.h b/src/VulkanRenderer.h index 1814e12..0d6c381 100644 --- a/src/VulkanRenderer.h +++ b/src/VulkanRenderer.h @@ -11,5 +11,6 @@ #include #include +#include #include #include diff --git a/src/managers/VulkanManager.cpp b/src/managers/VulkanManager.cpp index 62525d1..83ef66b 100644 --- a/src/managers/VulkanManager.cpp +++ b/src/managers/VulkanManager.cpp @@ -20,6 +20,13 @@ namespace PB::Renderer VkExtent2D VulkanManager::s_SwapChainExtent = {}; VkRenderPass VulkanManager::s_RenderPass = VK_NULL_HANDLE; + std::vector VulkanManager::s_Framebuffers = {}; + + VkPipelineLayout VulkanManager::s_PipelineLayout = {}; + VkPipeline VulkanManager::s_RenderPipeline = {}; + + VkCommandPool VulkanManager::s_CommandPool = VK_NULL_HANDLE; + std::vector VulkanManager::s_CommandBuffers = {}; bool VulkanManager::InitAll(GLFWwindow* window) { @@ -30,12 +37,15 @@ namespace PB::Renderer return false; if (!( - VulkanManager::PickPhysicalDevice() || - VulkanManager::PickPhysicalDevice() || - VulkanManager::CreateLogicalDevice() || - VulkanManager::CreateSwapChain(window) || - VulkanManager::CreateImageViews() || - VulkanManager::CreateRenderPass() + VulkanManager::PickPhysicalDevice() || + VulkanManager::PickPhysicalDevice() || + VulkanManager::CreateLogicalDevice() || + VulkanManager::CreateSwapChain(window) || + VulkanManager::CreateImageViews() || + VulkanManager::CreateRenderPass() || + VulkanManager::CreateFramebuffer() || + VulkanManager::CreateGraphicsPipeline() || + VulkanManager::CreateCommandBuffers() )) { return false; } @@ -492,4 +502,211 @@ namespace PB::Renderer return true; } + bool VulkanManager::CreateFramebuffer() + { + s_Framebuffers.resize(s_SwapChainImageViews.size()); + + for (size_t index = 0; index < s_SwapChainImageViews.size(); index++) + { + const VkImageView attachments[] = { + s_SwapChainImageViews[index] + }; + + VkFramebufferCreateInfo framebufferInfo{}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = s_RenderPass; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = attachments; + framebufferInfo.width = s_SwapChainExtent.width; + framebufferInfo.height = s_SwapChainExtent.height; + framebufferInfo.layers = 1; + + if (VkResult result = vkCreateFramebuffer(s_Device, &framebufferInfo, nullptr, &s_Framebuffers[index]); result != VK_SUCCESS) + { + std::cout << "PB::Renderer::VulkanManager::CreateFramebuffers(): Failed to create framebuffers" << std::endl; + return false; + } + } + + return true; + } + + bool VulkanManager::CreateGraphicsPipeline() + { + VkShaderModule vertShaderModule = CreateShaderModule("shaders/vert.spv"); + VkShaderModule fragShaderModule = CreateShaderModule("shaders/frag.spv"); + + 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 }; + + VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = 0; + vertexInputInfo.vertexAttributeDescriptionCount = 0; + + VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + inputAssembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(s_SwapChainExtent.width); + viewport.height = static_cast(s_SwapChainExtent.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor{}; + scissor.offset = {0,0}; + scissor.extent = s_SwapChainExtent; + + VkPipelineViewportStateCreateInfo viewportState{}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer{}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_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; + + if (vkCreatePipelineLayout(s_Device, &pipelineLayoutInfo, nullptr, &s_PipelineLayout) != VK_SUCCESS) + return false; + + 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.pColorBlendState = &colorBlending; + pipelineInfo.layout = s_PipelineLayout; + pipelineInfo.renderPass = s_RenderPass; + pipelineInfo.subpass = 0; + + if (vkCreateGraphicsPipelines(s_Device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &s_RenderPipeline) != VK_SUCCESS) + return false; + + vkDestroyShaderModule(s_Device, vertShaderModule, nullptr); + vkDestroyShaderModule(s_Device, fragShaderModule, nullptr); + + return true; + } + + VkShaderModule VulkanManager::CreateShaderModule(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 shader file: " + filename); + } + + const size_t fileSize = file.tellg(); + std::vector buffer(fileSize); + file.seekg(0); + file.read(buffer.data(), fileSize); + file.close(); + + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = buffer.size(); + createInfo.pCode = reinterpret_cast(buffer.data()); + + VkShaderModule shaderModule; + if (vkCreateShaderModule(s_Device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) + { + return VK_NULL_HANDLE; + } + + return shaderModule; + } + + bool VulkanManager::CreateCommandBuffers() + { + s_CommandBuffers.resize(s_Framebuffers.size()); + + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = s_CommandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = static_cast(s_CommandBuffers.size()); + + if (vkAllocateCommandBuffers(s_Device, &allocInfo, s_CommandBuffers.data()) != VK_SUCCESS) + return false; + + for (size_t i = 0; i < s_CommandBuffers.size(); i++) + { + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + vkBeginCommandBuffer(s_CommandBuffers[i], &beginInfo); + + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = s_RenderPass; + renderPassInfo.framebuffer = s_Framebuffers[i]; + renderPassInfo.renderArea.offset = {0, 0}; + renderPassInfo.renderArea.extent = s_SwapChainExtent; + + VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearColor; + + vkCmdBeginRenderPass(s_CommandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(s_CommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, s_RenderPipeline); + + vkCmdDraw(s_CommandBuffers[i], 3, 1, 0, 0); + + vkCmdEndRenderPass(s_CommandBuffers[i]); + + if (vkEndCommandBuffer(s_CommandBuffers[i]) != VK_SUCCESS) + return false; + } + + return true; + } } diff --git a/src/managers/VulkanManager.h b/src/managers/VulkanManager.h index bb459ad..672523c 100644 --- a/src/managers/VulkanManager.h +++ b/src/managers/VulkanManager.h @@ -35,6 +35,9 @@ namespace PB::Renderer static bool CreateSwapChain(GLFWwindow* window); static bool CreateImageViews(); static bool CreateRenderPass(); + static bool CreateFramebuffer(); + static bool CreateGraphicsPipeline(); + static bool CreateCommandBuffers(); private: static bool IsDeviceSuitable(VkPhysicalDevice device, VkSurfaceKHR surface); @@ -46,6 +49,8 @@ namespace PB::Renderer static VkPresentModeKHR ChoosePresentMode(const std::vector& availablePresentModes); static VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window); + static VkShaderModule CreateShaderModule(const std::string& filename); + static std::optional s_Instance; static std::optional s_Surface; @@ -64,5 +69,12 @@ namespace PB::Renderer static VkExtent2D s_SwapChainExtent; static VkRenderPass s_RenderPass; + static std::vector s_Framebuffers; + + static VkPipelineLayout s_PipelineLayout; + static VkPipeline s_RenderPipeline; + + static VkCommandPool s_CommandPool; + static std::vector s_CommandBuffers; }; }