From b753fd36a2ff4771ffc45f1a9a6893719c662230 Mon Sep 17 00:00:00 2001 From: xiangsilian Date: Sun, 26 Apr 2026 12:42:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=87=E6=8D=A2=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=E7=9A=84=20clash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/cpp/main.cpp | 2 ++ vulkan/Application.cpp | 58 +++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp index 40c1f91..0097c40 100644 --- a/app/src/main/cpp/main.cpp +++ b/app/src/main/cpp/main.cpp @@ -209,6 +209,8 @@ void android_main(struct android_app *pApp) { // 头再进 MakeupActivity 时,onWindowInit 看到 _applicationInited=1 走 reinit // 复用路径,引用悬空的 renderPass 调 vkCreateFramebuffer,validation // layer 检测出 use-after-free 直接 SEGV。 + //application.cleanup(); + //g_Application->cleanupSecondInit(); g_Application->clearnSecondFaceApp(); DebugLog::log("android_main: exit"); } diff --git a/vulkan/Application.cpp b/vulkan/Application.cpp index 705b902..04a237a 100644 --- a/vulkan/Application.cpp +++ b/vulkan/Application.cpp @@ -150,14 +150,55 @@ void Application::initVulkan() // 这个函数目前只保留给 vulkan/main.cpp 那个独立 desktop 入口的进程退出路径。 void Application::cleanupSecondInit() { - vkDestroySwapchainKHR(device, swapChain, nullptr); - vkDestroySurfaceKHR(instance, surface, nullptr); - vkDestroyPipeline(device, graphicsPipeline, nullptr); - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyRenderPass(device, renderPass, nullptr); - for (auto imageView : swapChainImageViews) { - vkDestroyImageView(device, imageView, nullptr); + // ★ 幂等:销毁后立刻把句柄置 VK_NULL_HANDLE / 清空 vector。 + // + // 这个函数过去在 Android 路径 (android_main 退出) 上被错误地调用过; + // 由于销毁后没有清零句柄,紧接着重新进入的 reinitForNewWindow() 在 + // extent/format 不变时会跳过重建,让 framebuffer / drawFrame 在 + // 已经销毁的 renderPass 上继续工作,最终在 + // vkCmdBeginRenderPass 内部 (libGLES_mali) 触发 SIGSEGV。 + // + // 现在 android_main 退出路径已经不再调本函数;本函数只剩 Windows + // 路径 (mainLoop → cleanupSecondInit → initVulkan 的"二次 session" + // 复用) 在用。把它写成幂等的可以兜住将来任何对它的误用。 + FACE_DBG_LOG("cleanupSecondInit: begin (swapChain=%s surface=%s renderPass=%s pipelineLayout=%s graphicsPipeline=%s imageViews=%zu framebuffers=%zu)", + swapChain == VK_NULL_HANDLE ? "null" : "live", + surface == VK_NULL_HANDLE ? "null" : "live", + renderPass == VK_NULL_HANDLE ? "null" : "live", + pipelineLayout == VK_NULL_HANDLE ? "null" : "live", + graphicsPipeline == VK_NULL_HANDLE ? "null" : "live", + swapChainImageViews.size(), swapChainFramebuffers.size()); + + if (device != VK_NULL_HANDLE) { + vkDeviceWaitIdle(device); } + + if (swapChain != VK_NULL_HANDLE) { + vkDestroySwapchainKHR(device, swapChain, nullptr); + swapChain = VK_NULL_HANDLE; + } + if (surface != VK_NULL_HANDLE) { + vkDestroySurfaceKHR(instance, surface, nullptr); + surface = VK_NULL_HANDLE; + } + if (graphicsPipeline != VK_NULL_HANDLE) { + vkDestroyPipeline(device, graphicsPipeline, nullptr); + graphicsPipeline = VK_NULL_HANDLE; + } + if (pipelineLayout != VK_NULL_HANDLE) { + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + pipelineLayout = VK_NULL_HANDLE; + } + if (renderPass != VK_NULL_HANDLE) { + vkDestroyRenderPass(device, renderPass, nullptr); + renderPass = VK_NULL_HANDLE; + } + for (auto imageView : swapChainImageViews) { + if (imageView != VK_NULL_HANDLE) { + vkDestroyImageView(device, imageView, nullptr); + } + } + swapChainImageViews.clear(); for (auto framebuffer : swapChainFramebuffers) { if (framebuffer != VK_NULL_HANDLE) @@ -166,7 +207,8 @@ void Application::cleanupSecondInit() } } swapChainFramebuffers.clear(); - + swapChainImages.clear(); + _sceondInited = false; }