diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp index e22efc7..bb06b85 100644 --- a/app/src/main/cpp/main.cpp +++ b/app/src/main/cpp/main.cpp @@ -191,8 +191,38 @@ void android_main(struct android_app *pApp) { } } while (!pApp->destroyRequested); DebugLog::log("android_main: destroyRequested, running cleanup"); + // ⚠️ 不要在这里调 cleanupSecondInit()。 + // + // 在 Android 上,Activity 销毁(APP_CMD_DESTROY) 之前已经先收到了 + // APP_CMD_TERM_WINDOW,handle_cmd 里走的是 onWindowLost() + // → Application::cleanupForWindowLost():销毁 swapChain / surface / + // framebuffers / imageViews / commandBuffers / 同步对象,但故意保留 + // renderPass / pipelineLayout / graphicsPipeline,以便下一次进入 + // Activity 时 reinitForNewWindow() 在 extent/format 不变的情况下 + // 直接复用,省下重建 RenderPass / 重新编译 Pipeline 的开销。 + // + // 而 cleanupSecondInit() 是 Windows 路径 + // (mainLoop → cleanupSecondInit → initVulkan → mainLoop) 的对偶—— + // 它会把 renderPass / pipelineLayout / graphicsPipeline 全部销毁。 + // 又因为 g_Application 是一个跨 Activity 存活的全局 FaceApp 实例 + // (android_main 入口处只在 g_Application == nullptr 时才 new), + // _applicationInited 也不会被复位; + // 下一次同一进程内进入另一个继承自 FaceActivity 的 Activity 时, + // onWindowInit() 看到 _applicationInited=1 走恢复分支调用 + // reinitForNewWindow(),extent/format 与上次相同(480x480 / 同 format) + // 时**不会**重建 renderPass / pipelineLayout / graphicsPipeline—— + // 用着已经被销毁的 renderPass 句柄继续 createFramebuffers() → + // recordCommandBuffer() → vkCmdBeginRenderPass(), + // Mali 驱动 (libGLES_mali) 在校验层后解引用已释放的 RenderPass 内部 + // 数据,触发 SIGSEGV / si_addr=0x4 + // (recordCommandBuffer + 0xBC,正好是 vkCmdBeginRenderPass)。 + // + // 解决办法:android_main 退出时只信任 cleanupForWindowLost 已经做的 + // 那部分清理,不再额外调 cleanupSecondInit(),让 renderPass / + // pipelineLayout / graphicsPipeline / FaceApp 的 m_graphicsPipeline* + // 都能存活到下一次 android_main 重新进来被复用。 //application.cleanup(); - g_Application->cleanupSecondInit(); + //g_Application->cleanupSecondInit(); g_Application->clearnSecondFaceApp(); DebugLog::log("android_main: exit"); } diff --git a/vulkan/Application.cpp b/vulkan/Application.cpp index b23940b..b213dc6 100644 --- a/vulkan/Application.cpp +++ b/vulkan/Application.cpp @@ -136,14 +136,55 @@ void Application::initVulkan() 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) @@ -152,7 +193,8 @@ void Application::cleanupSecondInit() } } swapChainFramebuffers.clear(); - + swapChainImages.clear(); + _sceondInited = false; }