From 966382a7dd68b6bfc4ae8a1ad09e5b9969cebca6 Mon Sep 17 00:00:00 2001 From: Xiang Silian Date: Fri, 17 Oct 2025 18:55:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B6=88=E9=99=A4=E4=BA=86=E6=89=80=E6=9C=89?= =?UTF-8?q?=E7=9A=84=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 6 +-- app/build.gradle | 4 ++ vulkan/Application.cpp | 96 ++++++++++++++++++++++++++++-------------- vulkan/Application.h | 12 +++--- 4 files changed, 79 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 811c413..2b0c6d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.22.1) +cmake_minimum_required(VERSION 3.22.1) project("sample") @@ -16,7 +16,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android") add_library(sample SHARED app/src/main/cpp/main.cpp app/src/main/cpp/AndroidOut.cpp - vulkan/Application.h + vulkan/AppBase.cpp vulkan/Application.cpp ) @@ -53,7 +53,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR WIN32) # 将源代码添加到此项目的可执行文件。 add_executable (sample "vulkan/main.cpp" - "vulkan/Application.h" + "vulkan/AppBase.cpp" "vulkan/Application.cpp" ) endif() diff --git a/app/build.gradle b/app/build.gradle index 860bb84..35296b5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,10 @@ android { versionCode 1 versionName "1.0" + ndk { + abiFilters 'arm64-v8a' + } + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/vulkan/Application.cpp b/vulkan/Application.cpp index cc5a6dd..d9ba85b 100644 --- a/vulkan/Application.cpp +++ b/vulkan/Application.cpp @@ -433,7 +433,6 @@ void Application::createCommandPool() { void Application::createCommandBuffer() { - int MAX_FRAMES_IN_FLIGHT = swapChainImages.size(); commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -448,10 +447,12 @@ void Application::createCommandBuffer() void Application::createSyncObjects() { - int MAX_FRAMES_IN_FLIGHT = swapChainImages.size(); - imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); - renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + int swapChainImageCount = swapChainImages.size(); + + imageAvailableSemaphores.resize(swapChainImageCount); + renderFinishedSemaphores.resize(swapChainImageCount); inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); + imagesInFlight.resize(swapChainImageCount, VK_NULL_HANDLE); VkSemaphoreCreateInfo semaphoreInfo{}; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; @@ -460,18 +461,28 @@ void Application::createSyncObjects() fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + // 为每个交换链图像创建信号量 + for (size_t i = 0; i < swapChainImageCount; i++) { if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS || - vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS || - vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) { + vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS) { + throw std::runtime_error("failed to create synchronization objects!"); + } + } + + // 为每个帧在飞行创建栅栏 + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) { throw std::runtime_error("failed to create synchronization objects!"); } } } -void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { +void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) +{ VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = 0; // 可选标志 + beginInfo.pInheritanceInfo = nullptr; // 仅用于次级命令缓冲区 if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { throw std::runtime_error("failed to begin recording command buffer!"); @@ -481,7 +492,7 @@ void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t im VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassInfo.renderPass = renderPass; - renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex]; + renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex]; // 使用正确的imageIndex renderPassInfo.renderArea.offset = { 0, 0 }; renderPassInfo.renderArea.extent = swapChainExtent; @@ -506,18 +517,38 @@ void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t im } void Application::drawFrame() { + // 1. 等待前一帧完成 vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); + + // 2. 获取交换链图像 - 使用当前帧的信号量 + uint32_t imageIndex; + VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, + imageAvailableSemaphores[currentFrame], + VK_NULL_HANDLE, &imageIndex); + + if (result != VK_SUCCESS) { + throw std::runtime_error("failed to acquire swap chain image!"); + } + + // 3. 检查该图像是否正在被之前的帧使用 + if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) { + vkWaitForFences(device, 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX); + } + // 标记该图像正在被当前帧使用 + imagesInFlight[imageIndex] = inFlightFences[currentFrame]; + + // 4. 重置栅栏 vkResetFences(device, 1, &inFlightFences[currentFrame]); - uint32_t imageIndex; - vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); - + // 5. 记录命令缓冲区 vkResetCommandBuffer(commandBuffers[currentFrame], 0); - recordCommandBuffer(commandBuffers[currentFrame], currentFrame); + recordCommandBuffer(commandBuffers[currentFrame], imageIndex); + // 6. 提交命令缓冲区 VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + // 等待图像获取完成 VkSemaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] }; VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; submitInfo.waitSemaphoreCount = 1; @@ -527,7 +558,8 @@ void Application::drawFrame() { submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffers[currentFrame]; - VkSemaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] }; + // 使用对应图像的渲染完成信号量 + VkSemaphore signalSemaphores[] = { renderFinishedSemaphores[imageIndex] }; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; @@ -535,18 +567,24 @@ void Application::drawFrame() { throw std::runtime_error("failed to submit draw command buffer!"); } + // 7. 呈现图像 VkPresentInfoKHR presentInfo{}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = signalSemaphores; + presentInfo.pWaitSemaphores = signalSemaphores; // 等待对应图像的渲染完成信号量 VkSwapchainKHR swapChains[] = { swapChain }; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = swapChains; presentInfo.pImageIndices = &imageIndex; - vkQueuePresentKHR(presentQueue, &presentInfo); - int MAX_FRAMES_IN_FLIGHT = swapChainImages.size(); + result = vkQueuePresentKHR(presentQueue, &presentInfo); + + if (result != VK_SUCCESS) { + throw std::runtime_error("failed to present swap chain image!"); + } + + // 8. 前进到下一帧 currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } @@ -563,23 +601,19 @@ void Application::cleanup() { } + // 等待设备空闲,确保所有命令都完成 + vkDeviceWaitIdle(device); - int MAX_FRAMES_IN_FLIGHT = swapChainImages.size(); - for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) - { - // 销毁命令缓冲区 - vkFreeCommandBuffers(device, commandPool, 1, &commandBuffers[i]); - // 销毁同步对象 - vkDestroySemaphore(device, imageAvailableSemaphores[0], nullptr); - vkDestroySemaphore(device, renderFinishedSemaphores[0], nullptr); - vkDestroyFence(device, inFlightFences[0], nullptr); + // 正确销毁所有同步对象 + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr); + vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr); + vkDestroyFence(device, inFlightFences[i], nullptr); } - - // 销毁帧缓冲区 - for (auto framebuffer : swapChainFramebuffers) { - vkDestroyFramebuffer(device, framebuffer, nullptr); - } + // 不需要手动释放commandBuffers,销毁命令池时会自动释放 + // 销毁命令池 + vkDestroyCommandPool(device, commandPool, nullptr); // 销毁图形管线 vkDestroyPipeline(device, graphicsPipeline, nullptr); diff --git a/vulkan/Application.h b/vulkan/Application.h index 914802c..549922f 100644 --- a/vulkan/Application.h +++ b/vulkan/Application.h @@ -47,10 +47,12 @@ private: std::vector swapChainFramebuffers; // 帧缓冲区 VkQueue presentQueue; // 呈现队列 - VkCommandPool commandPool; // 命令池 - std::vector commandBuffers; // 命令缓冲区 - std::vector imageAvailableSemaphores; // 图像可用信号量 - std::vector renderFinishedSemaphores; // 渲染完成信号量 - std::vector inFlightFences; // 同步栅栏 + VkCommandPool commandPool; + std::vector commandBuffers; + std::vector imageAvailableSemaphores; // 每个交换链图像一个 + std::vector renderFinishedSemaphores; // 每个交换链图像一个 + std::vector inFlightFences; // 每个帧在飞行一个 + std::vector imagesInFlight; // 跟踪每个图像的使用状态 int currentFrame = 0; + int MAX_FRAMES_IN_FLIGHT = 2; }; \ No newline at end of file