diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e77085..1c18426 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,13 +4,44 @@ project(vksdlproj VERSION 0.1.0 LANGUAGES C CXX) SET(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE) set(EXE_NAME project) +set(PROGRAM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vulkanapp.cc) + +# Get our GLSL shaders +set(SHADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/shaders) +set(SHADER_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}) +file(GLOB SHADERS ${SHADER_DIR}/*.vert + ${SHADER_DIR}/*.frag + ${SHADER_DIR}/*.comp + ${SHADER_DIR}/*.geom + ${SHADER_DIR}/*.tesc + ${SHADER_DIR}/*.tese + ${SHADER_DIR}/*.mesh + ${SHADER_DIR}/*.task + ${SHADER_DIR}/*.rgen + ${SHADER_DIR}/*.rchit + ${SHADER_DIR}/*.rmiss + ) + find_package(SDL2 REQUIRED CONFIG REQUIRED COMPONENTS SDL2) -find_package(Vulkan REQUIRED) +find_package(Vulkan REQUIRED COMPONENTS glslc) -set(PROGRAM_SOURCES ${CMAKE_SOURCE_DIR}/src/vulkanapp.cc) +# Compile each shader +foreach(SHADER IN LISTS SHADERS) + get_filename_component(FILENAME ${SHADER} NAME) + add_custom_command(OUTPUT ${SHADER_BIN_DIR}/${FILENAME}.spv + COMMAND ${Vulkan_GLSLC_EXECUTABLE} ${SHADER} -o ${SHADER_BIN_DIR}/${FILENAME}.spv + DEPENDS ${SHADER} + COMMENT "Compiling Shader ${FILENAME}") + list(APPEND SPV_SHADERS ${SHADER_BIN_DIR}/${FILENAME}.spv) +endForeach() -add_executable(${EXE_NAME} ${CMAKE_SOURCE_DIR}/src/main.cc ${PROGRAM_SOURCES}) +# Shader target +add_custom_target(shaders ALL DEPENDS ${SPV_SHADERS}) + +add_executable(${EXE_NAME} ${CMAKE_SOURCE_DIR}/src/main.cc ${PROGRAM_SOURCES} ${SHADERS}) target_include_directories(${EXE_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include) +add_dependencies(${EXE_NAME} shaders) +# Linking target_link_libraries(${EXE_NAME} PRIVATE SDL2::SDL2) target_link_libraries(${EXE_NAME} PRIVATE Vulkan::Vulkan) \ No newline at end of file diff --git a/include/vulkanapp.hh b/include/vulkanapp.hh index a38e13f..72b3370 100644 --- a/include/vulkanapp.hh +++ b/include/vulkanapp.hh @@ -64,15 +64,29 @@ private: VkPhysicalDevice mPhysicalDevice = VK_NULL_HANDLE; VkDevice mLogicalDevice; VkSurfaceKHR mSurface; + VkSwapchainKHR mSwapChain; std::vector mSwapChainImages; std::vector mSwapChainImageViews; VkFormat mSwapChainImageFormat; VkExtent2D mSwapChainExtent; + std::vector mSwapChainFramebuffers; + + VkRenderPass mRenderPass; + VkPipelineLayout mPipelineLayout; + VkPipeline mGraphicsPipeline; + + VkCommandPool mCommandPool; + VkCommandBuffer mCommandBuffer; VkQueue mGraphicsQueue; VkQueue mPresentQueue; + VkSemaphore mImageAvailableSemaphore; + VkSemaphore mRenderFinishedSemaphore; + VkFence mInFlightFence; + + VkDebugUtilsMessengerEXT mDebugMessenger; void createInstance(); @@ -80,11 +94,20 @@ private: void createLogicalDevice(); void createSwapChain(); void createImageViews(); + void createRenderPass(); void createGraphicsPipeline(); + void createFramebuffers(); + void createCommandPool(); + void createCommandBuffer(); + void createSyncObjects(); + + void recordCommandBuffer(VkCommandBuffer, uint32_t); + void drawFrame(); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice); bool isDeviceSuitable(VkPhysicalDevice); bool checkDeviceExtensionSupport(VkPhysicalDevice); + VkShaderModule createShaderModule(const std::vector&); SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice); VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector&); VkPresentModeKHR chooseSwapPresentMode(const std::vector&); diff --git a/shaders/triangle.frag b/shaders/triangle.frag new file mode 100644 index 0000000..13009da --- /dev/null +++ b/shaders/triangle.frag @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} \ No newline at end of file diff --git a/shaders/triangle.vert b/shaders/triangle.vert new file mode 100644 index 0000000..f5b2f8d --- /dev/null +++ b/shaders/triangle.vert @@ -0,0 +1,20 @@ +#version 450 + +layout(location = 0) out vec3 fragColor; + +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +} diff --git a/src/vulkanapp.cc b/src/vulkanapp.cc index 4690507..2d1d72d 100644 --- a/src/vulkanapp.cc +++ b/src/vulkanapp.cc @@ -37,6 +37,42 @@ void DestroyDebugUtilsMessengerEXT(VkInstance instance, } } +const std::vector readFile(const std::string& path) { + FILE *fd = fopen(path.c_str(), "rb"); + long fileSize = 0; + std::vector buf; + + if(fd == nullptr) { + std::string err = "Could not open "; + throw std::runtime_error(err + path + "\n"); + } + + fseek(fd, 0L, SEEK_END); + fileSize = ftell(fd); + fseek(fd, 0L, SEEK_SET); + + buf.resize(fileSize); + + fread(buf.data(), sizeof(uint8_t), fileSize, fd); + fclose(fd); + + return buf; +} + +VkShaderModule VulkanApp::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(mLogicalDevice, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { + throw std::runtime_error("Could not create shader module!"); + } + + return shaderModule; +} + QueueFamilyIndices VulkanApp::findQueueFamilies(VkPhysicalDevice device) { QueueFamilyIndices indices; @@ -144,11 +180,107 @@ VkExtent2D VulkanApp::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilit } } +void VulkanApp::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = 0; // Optional + beginInfo.pInheritanceInfo = nullptr; // Optional + + if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { + throw std::runtime_error("Could not start recording Vulkan command buffer!"); + } + + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = mRenderPass; + renderPassInfo.framebuffer = mSwapChainFramebuffers[imageIndex]; + renderPassInfo.renderArea.offset = {0, 0}; + renderPassInfo.renderArea.extent = mSwapChainExtent; + + VkClearValue clearColor = {{{0.5f, 0.0f, 0.5f, 1.0f}}}; + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearColor; + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, mGraphicsPipeline); + + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(mSwapChainExtent.width); + viewport.height = static_cast(mSwapChainExtent.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + + VkRect2D scissor{}; + scissor.offset = {0, 0}; + scissor.extent = mSwapChainExtent; + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + + vkCmdDraw(commandBuffer, 3, 1, 0, 0); + vkCmdEndRenderPass(commandBuffer); + + if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { + throw std::runtime_error("Could not record Vulkan command buffer!"); + } +} + +void VulkanApp::drawFrame() { + vkWaitForFences(mLogicalDevice, 1, &mInFlightFence, VK_TRUE, UINT64_MAX); + vkResetFences(mLogicalDevice, 1, &mInFlightFence); + + uint32_t imageIndex; + vkAcquireNextImageKHR(mLogicalDevice, mSwapChain, UINT64_MAX, mImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex); + + vkResetCommandBuffer(mCommandBuffer, /*VkCommandBufferResetFlagBits*/ 0); + recordCommandBuffer(mCommandBuffer, imageIndex); + + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + VkSemaphore waitSemaphores[] = {mImageAvailableSemaphore}; + VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = waitSemaphores; + submitInfo.pWaitDstStageMask = waitStages; + + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &mCommandBuffer; + + VkSemaphore signalSemaphores[] = {mRenderFinishedSemaphore}; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = signalSemaphores; + + if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mInFlightFence) != VK_SUCCESS) { + throw std::runtime_error("Could not submit Vulkan command buffer!"); + } + + VkPresentInfoKHR presentInfo{}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = signalSemaphores; + + VkSwapchainKHR swapChains[] = {mSwapChain}; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = swapChains; + + presentInfo.pImageIndices = &imageIndex; + + vkQueuePresentKHR(mPresentQueue, &presentInfo); +} + void VulkanApp::init() { // Initialize SDL2 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); //SDL_Vulkan_LoadLibrary(nullptr); +#ifndef NDEBUG + // I really hate GNOME + SDL_VideoInit("x11"); +#endif + // Create the window mWin = SDL_CreateWindow("Vulkan+SDL2 Application", SDL_WINDOWPOS_CENTERED, @@ -159,7 +291,7 @@ void VulkanApp::init() { ); if(mWin == nullptr) { - std::string err = "Could not create window " + std::string(SDL_GetError()) + "\n"; + std::string err = "Could not create SDL2 window! " + std::string(SDL_GetError()) + "\n"; throw std::runtime_error(err); } @@ -176,7 +308,12 @@ void VulkanApp::init() { createLogicalDevice(); createSwapChain(); createImageViews(); + createRenderPass(); createGraphicsPipeline(); + createFramebuffers(); + createCommandPool(); + createCommandBuffer(); + createSyncObjects(); } void VulkanApp::createInstance() { @@ -382,7 +519,212 @@ void VulkanApp::createImageViews() { } } +void VulkanApp::createRenderPass() { + VkAttachmentDescription colorAttachment{}; + colorAttachment.format = mSwapChainImageFormat; + 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 colorAttachmentRef{}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass{}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + + VkRenderPassCreateInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = 1; + renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + + if (vkCreateRenderPass(mLogicalDevice, &renderPassInfo, nullptr, &mRenderPass) != VK_SUCCESS) { + throw std::runtime_error("Could not create Vulkan render pass!"); + } +} + void VulkanApp::createGraphicsPipeline() { + const std::vector vertShaderCode = readFile("triangle.vert.spv"); + const std::vector fragShaderCode = readFile("triangle.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}; + + 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; + + 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_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.logicOp = VK_LOGIC_OP_COPY; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + colorBlending.blendConstants[0] = 0.0f; + colorBlending.blendConstants[1] = 0.0f; + colorBlending.blendConstants[2] = 0.0f; + colorBlending.blendConstants[3] = 0.0f; + + 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(); + + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 0; + pipelineLayoutInfo.pushConstantRangeCount = 0; + + if (vkCreatePipelineLayout(mLogicalDevice, &pipelineLayoutInfo, nullptr, &mPipelineLayout) != VK_SUCCESS) { + throw std::runtime_error("Could not create Vulkan 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.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = &dynamicState; + pipelineInfo.layout = mPipelineLayout; + pipelineInfo.renderPass = mRenderPass; + pipelineInfo.subpass = 0; + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + + if (vkCreateGraphicsPipelines(mLogicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &mGraphicsPipeline) != VK_SUCCESS) { + throw std::runtime_error("Could not create Vulkan graphics pipeline!"); + } + + vkDestroyShaderModule(mLogicalDevice, fragShaderModule, nullptr); + vkDestroyShaderModule(mLogicalDevice, vertShaderModule, nullptr); +} + +void VulkanApp::createFramebuffers() { + mSwapChainFramebuffers.resize(mSwapChainImageViews.size()); + + + + for (size_t i = 0; i < mSwapChainImageViews.size(); i++) { + VkImageView attachments[] = { + mSwapChainImageViews[i] + }; + + VkFramebufferCreateInfo framebufferInfo{}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = mRenderPass; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = attachments; + framebufferInfo.width = mSwapChainExtent.width; + framebufferInfo.height = mSwapChainExtent.height; + framebufferInfo.layers = 1; + + if (vkCreateFramebuffer(mLogicalDevice, &framebufferInfo, nullptr, &mSwapChainFramebuffers[i]) != VK_SUCCESS) { + throw std::runtime_error("Could not create Vulkan framebuffer!"); + } + } +} + +void VulkanApp::createCommandPool() { + QueueFamilyIndices queueFamilyIndices = findQueueFamilies(mPhysicalDevice); + + 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(mLogicalDevice, &poolInfo, nullptr, &mCommandPool) != VK_SUCCESS) { + throw std::runtime_error("Could not create Vulkan command pool!"); + } +} + +void VulkanApp::createCommandBuffer() { + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = mCommandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = 1; + + if (vkAllocateCommandBuffers(mLogicalDevice, &allocInfo, &mCommandBuffer) != VK_SUCCESS) { + throw std::runtime_error("Could not allocate Vulkan command buffers!"); + } +} + +void VulkanApp::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; + + VkResult imageAvailableResult = vkCreateSemaphore(mLogicalDevice, &semaphoreInfo, nullptr, &mImageAvailableSemaphore); + VkResult renderFinishedResult = vkCreateSemaphore(mLogicalDevice, &semaphoreInfo, nullptr, &mRenderFinishedSemaphore); + VkResult inFlightResult = vkCreateFence(mLogicalDevice, &fenceInfo, nullptr, &mInFlightFence); + + if(imageAvailableResult != VK_SUCCESS || renderFinishedResult != VK_SUCCESS || inFlightResult != VK_SUCCESS) { + throw std::runtime_error("Could not create needed semaphores or other memory handling objects for Vulkan!"); + } } @@ -464,14 +806,29 @@ void VulkanApp::loop() { //SDL_RenderClear(rend); //SDL_RenderPresent(rend); - + drawFrame(); SDL_ShowWindow(mWin); } + vkDeviceWaitIdle(mLogicalDevice); //SDL_DestroyRenderer(rend); } void VulkanApp::cleanup() { + vkDestroySemaphore(mLogicalDevice, mImageAvailableSemaphore, nullptr); + vkDestroySemaphore(mLogicalDevice, mRenderFinishedSemaphore, nullptr); + vkDestroyFence(mLogicalDevice, mInFlightFence, nullptr); + + vkDestroyCommandPool(mLogicalDevice, mCommandPool, nullptr); + + for (VkFramebuffer framebuffer : mSwapChainFramebuffers) { + vkDestroyFramebuffer(mLogicalDevice, framebuffer, nullptr); + } + + vkDestroyPipeline(mLogicalDevice, mGraphicsPipeline, nullptr); + vkDestroyPipelineLayout(mLogicalDevice, mPipelineLayout, nullptr); + vkDestroyRenderPass(mLogicalDevice, mRenderPass, nullptr); + for (VkImageView imageView : mSwapChainImageViews) { vkDestroyImageView(mLogicalDevice, imageView, nullptr); }