diff --git a/main.cpp b/main.cpp index 972881a..9f4d702 100644 --- a/main.cpp +++ b/main.cpp @@ -155,6 +155,14 @@ private: VkPipeline graphicsPipeline; + VkCommandPool commandPool; + VkCommandBuffer commandBuffer; + + VkSemaphore imageAvailableSemaphore, renderFinishedSemaphore; + VkFence inFlightFence; + + std::vector swapChainFramebuffers; + void createInstance(){ if(enableValidationLayers && !checkValidationLayerSupport()){ throw std::runtime_error("Func: createInstance\nError: Validation Layers requested, but not available!\n"); @@ -541,6 +549,7 @@ private: inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; inputAssembly.primitiveRestartEnable = VK_FALSE; + /* VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; @@ -548,17 +557,20 @@ private: viewport.height = (float)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); + */ VkPipelineViewportStateCreateInfo viewportState{}; viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewportState.viewportCount = 1; - viewportState.pViewports = &viewport; // possibly made immutable + // viewportState.pViewports = &viewport; // possibly made immutable viewportState.scissorCount = 1; - viewportState.pScissors = &scissor; // possibly made immutable + // viewportState.pScissors = &scissor; // possibly made immutable VkPipelineRasterizationStateCreateInfo rasterizer{}; rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; @@ -660,18 +672,175 @@ private: subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_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("Func: createRenderPass\nError: Failed to create render pass!\n"); } } + 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("Func: createFrameBuffers\nError: Failed to create Framebuffer!\n"); + } + } + } + + 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("Func: createCommandPool\nError: Failed to create Command Pool!\n"); + } + } + + void createCommandBuffer(){ + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = commandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = 1; + + if(vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer) != VK_SUCCESS){ + throw std::runtime_error("Func: createCommandBuffer\nError: Failed to allocate Command Buffers!\n"); + } + } + + 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("Func: recordCommandBuffer\nError: Failed to begin recording command buffer!\n"); + } + + 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}}}; // Background color after clear (Black 100%) + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearColor; + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); + + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = (float)swapChainExtent.width; + viewport.height = (float)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); + + vkCmdDraw(commandBuffer, 3, 1, 0, 0); + + vkCmdEndRenderPass(commandBuffer); + if(vkEndCommandBuffer(commandBuffer) != VK_SUCCESS){ + throw std::runtime_error("Func: recordCommandBuffer\nError: Failed to record command buffer!\n"); + } + } + + void createSyncObjects(){ + 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; + + if(vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS + || vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore) != VK_SUCCESS + || vkCreateFence(device, &fenceInfo, nullptr, &inFlightFence) != VK_SUCCESS){ + throw std::runtime_error("Func: createSyncObjects\nError: Failed to create semaphores!\n"); + } + } + + void drawFrame(){ + vkWaitForFences(device, 1, &inFlightFence, VK_TRUE, UINT64_MAX); + vkResetFences(device, 1, &inFlightFence); + + uint32_t imageIndex; + vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex); + + vkResetCommandBuffer(commandBuffer, 0); + recordCommandBuffer(commandBuffer, imageIndex); + + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + VkSemaphore waitSemaphores[] = { imageAvailableSemaphore }; + VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = waitSemaphores; + submitInfo.pWaitDstStageMask = waitStages; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + VkSemaphore signalSemaphore[] = { renderFinishedSemaphore }; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = signalSemaphore; + + if(vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFence) != VK_SUCCESS){ + throw std::runtime_error("Func: drawFrame\nError: Failed to submit draw command buffer!\n"); + } + + 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; + + vkQueuePresentKHR(presentQueue, &presentInfo); + } + void initWindow(){ glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // tell glfw to not use opengl @@ -689,17 +858,32 @@ private: createImageViews(); createRenderPass(); createGraphicsPipeline(); + createFrameBuffers(); + createCommandPool(); + createCommandBuffer(); + createSyncObjects(); } void mainLoop(){ while(!glfwWindowShouldClose(this->window)){ - glfwSwapBuffers(window); + // glfwSwapBuffers(window); glfwPollEvents(); + drawFrame(); } } void cleanup(){ // Vulkan + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroyFence(device, inFlightFence, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + for(VkFramebuffer framebuffer : swapChainFramebuffers){ + vkDestroyFramebuffer(device, framebuffer, nullptr); + } + vkDestroyPipeline(device, graphicsPipeline, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyRenderPass(device, renderPass, nullptr);