#include "first_app.hpp" #include #include #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #include namespace cve { struct SimplePushConstantData{ glm::vec2 offset; alignas(16) glm::vec3 color; }; FirstApp::FirstApp() { loadModels(); createPipelineLayout(); recreateSwapChain(); createCommandBuffers(); } FirstApp::~FirstApp() { vkDestroyPipelineLayout(cveDevice.device(), pipelineLayout, nullptr); } void FirstApp::run() { while (!cveWindow.shouldClose()) { glfwPollEvents(); drawFrame(); } vkDeviceWaitIdle(cveDevice.device()); } void FirstApp::loadModels() { std::vector verticies { {{0.0f, -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}} }; cveModel = std::make_unique(cveDevice, verticies); } void FirstApp::createPipelineLayout() { VkPushConstantRange pushConstantRange{}; pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; pushConstantRange.offset = 0; pushConstantRange.size = sizeof(SimplePushConstantData); VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pSetLayouts = nullptr; pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; if (vkCreatePipelineLayout(cveDevice.device(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { throw std::runtime_error("Failed to create pipeline layout"); } } void FirstApp::createPipeline() { assert(cveSwapChain != nullptr && "Cannot create pipeline before swap chain"); assert(pipelineLayout != nullptr && "Cannot create pipeline before pipeline layout"); PipelineConfigInfo pipelineConfig{}; CvePipeline::defaultPipelineConfigInfo(pipelineConfig); pipelineConfig.renderPass = cveSwapChain->getRenderPass(); pipelineConfig.pipelineLayout = pipelineLayout; cvePipeline = std::make_unique( cveDevice, "shaders/simple_shader.vert.spv", "shaders/simple_shader.frag.spv", pipelineConfig ); } void FirstApp::recreateSwapChain() { auto extent = cveWindow.getExtent(); while (extent.width == 0 || extent.height == 0) { extent = cveWindow.getExtent(); glfwWaitEvents(); } vkDeviceWaitIdle(cveDevice.device()); if (cveSwapChain == nullptr) { cveSwapChain = std::make_unique(cveDevice, extent); } else { cveSwapChain = std::make_unique(cveDevice, extent, std::move(cveSwapChain)); if (cveSwapChain->imageCount() != commandBuffers.size()) { freeCommandBuffers(); createCommandBuffers(); } } // Check if render pass is compatible createPipeline(); } void FirstApp::createCommandBuffers() { commandBuffers.resize(cveSwapChain->imageCount()); VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandPool = cveDevice.getCommandPool(); allocInfo.commandBufferCount = static_cast(commandBuffers.size()); if (vkAllocateCommandBuffers(cveDevice.device(), &allocInfo, commandBuffers.data()) != VK_SUCCESS) { throw std::runtime_error("Failed to allocate command buffers"); } } void FirstApp::freeCommandBuffers() { vkFreeCommandBuffers(cveDevice.device(), cveDevice.getCommandPool(), static_cast(commandBuffers.size()), commandBuffers.data()); commandBuffers.clear(); } void FirstApp::recordCommandBuffer(int imageIndex) { static int frame = 30; frame = (frame+1) % 2000; VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; if (vkBeginCommandBuffer(commandBuffers[imageIndex], &beginInfo) != VK_SUCCESS) { throw std::runtime_error("Failed to begin command buffer recording"); } VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassInfo.renderPass = cveSwapChain->getRenderPass(); renderPassInfo.framebuffer = cveSwapChain->getFrameBuffer(imageIndex); renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.extent = cveSwapChain->getSwapChainExtent(); std::array clearValues{}; clearValues[0].color = {0.01f, 0.01f, 0.01f, 1.0f}; clearValues[1].depthStencil = {1.0f, 0}; renderPassInfo.clearValueCount = static_cast(clearValues.size()); renderPassInfo.pClearValues = clearValues.data(); vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; viewport.width = static_cast(cveSwapChain->getSwapChainExtent().width); viewport.height = static_cast(cveSwapChain->getSwapChainExtent().height); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor{{0, 0}, cveSwapChain->getSwapChainExtent()}; vkCmdSetViewport(commandBuffers[imageIndex], 0, 1, &viewport); vkCmdSetScissor(commandBuffers[imageIndex], 0, 1, &scissor); cvePipeline->bind(commandBuffers[imageIndex]); cveModel->bind(commandBuffers[imageIndex]); for (int j = 0; j < 4; j++) { SimplePushConstantData push{}; push.offset = {-0.5f + frame * 0.0005f, -0.4f + j * 0.25f}; push.color = {0.0f, 0.0f, 0.2f + 0.2f * j}; vkCmdPushConstants( commandBuffers[imageIndex], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(SimplePushConstantData), &push ); cveModel->draw(commandBuffers[imageIndex]); } vkCmdEndRenderPass(commandBuffers[imageIndex]); if (vkEndCommandBuffer(commandBuffers[imageIndex]) != VK_SUCCESS) { throw std::runtime_error("Failed to record command buffer!"); } } void FirstApp::drawFrame() { uint32_t imageIndex; auto result = cveSwapChain->acquireNextImage(&imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR) { recreateSwapChain(); return; } if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { throw std::runtime_error("Failed to acquire swap chain image!"); } recordCommandBuffer(imageIndex); result = cveSwapChain->submitCommandBuffers(&commandBuffers[imageIndex], &imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || cveWindow.wasWindowResized()) { cveWindow.resetWindowResizedFlag(); recreateSwapChain(); return; } if (result != VK_SUCCESS) { throw std::runtime_error("Failed to present swap chain image!"); } } }