AI 修复横竖屏的问题

This commit is contained in:
xsl
2026-04-23 23:43:48 +08:00
parent 27b7075818
commit 2066b3b124
5 changed files with 127 additions and 18 deletions
+7 -3
View File
@@ -54,9 +54,13 @@ void handle_cmd(android_app *pApp, int32_t cmd) {
case APP_CMD_INIT_WINDOW: case APP_CMD_INIT_WINDOW:
aout << "APP_CMD_INIT_WINDOW" << std::endl; aout << "APP_CMD_INIT_WINDOW" << std::endl;
DebugLog::log("handle_cmd APP_CMD_INIT_WINDOW: calling onWindowInit()"); DebugLog::log("handle_cmd APP_CMD_INIT_WINDOW: calling onWindowInit()");
g_Application->onWindowInit(); if (g_Application != nullptr) {
DebugLog::log("handle_cmd APP_CMD_INIT_WINDOW: onWindowInit() returned, isInited=%d", g_Application->onWindowInit();
(int)g_Application->isInited()); DebugLog::log("handle_cmd APP_CMD_INIT_WINDOW: onWindowInit() returned, isInited=%d",
(int)g_Application->isInited());
} else {
DebugLog::log("handle_cmd APP_CMD_INIT_WINDOW: g_Application is null, skipping");
}
break; break;
case APP_CMD_TERM_WINDOW: case APP_CMD_TERM_WINDOW:
aout << "APP_CMD_TERM_WINDOW" << std::endl; aout << "APP_CMD_TERM_WINDOW" << std::endl;
+63 -10
View File
@@ -112,9 +112,12 @@ void Application::initVulkan()
createSyncObjects(); // 创建同步对象 createSyncObjects(); // 创建同步对象
_lastDrawFrameTime = getCurrentTimeMillis(); _lastDrawFrameTime = getCurrentTimeMillis();
_applicationInited = true; _applicationInited = true;
// The first branch above already built all of the window-dependent
// objects. Mark _sceondInited so we don't fall into the recovery
// branch below and leak a second copy of surface/swapChain/etc.
_sceondInited = true;
} }
else if (!_sceondInited) {
if (!_sceondInited) {
createSurface(); createSurface();
createSwapChain(); createSwapChain();
createImageViews(); createImageViews();
@@ -155,8 +158,14 @@ void Application::cleanupForWindowLost()
(int)_applicationInited, (int)_sceondInited); (int)_applicationInited, (int)_sceondInited);
return; return;
} }
FACE_DBG_LOG("cleanupForWindowLost: begin (imageCount=%zu MAX_FRAMES_IN_FLIGHT=%d)", FACE_DBG_LOG("cleanupForWindowLost: begin (imageCount=%zu MAX_FRAMES_IN_FLIGHT=%d extent=%ux%u format=%d)",
swapChainImages.size(), MAX_FRAMES_IN_FLIGHT); swapChainImages.size(), MAX_FRAMES_IN_FLIGHT,
swapChainExtent.width, swapChainExtent.height, (int)swapChainImageFormat);
// Snapshot before we destroy the swapchain so reinitForNewWindow() can
// decide whether the new swapchain needs renderPass / pipelines rebuilt.
_prevSwapChainExtent = swapChainExtent;
_prevSwapChainImageFormat = swapChainImageFormat;
// Block until GPU is no longer using any of the resources we are about // Block until GPU is no longer using any of the resources we are about
// to destroy. Anything weaker than this risks hitting VK_ERROR_DEVICE_LOST // to destroy. Anything weaker than this risks hitting VK_ERROR_DEVICE_LOST
@@ -222,29 +231,73 @@ void Application::cleanupForWindowLost()
FACE_DBG_LOG("cleanupForWindowLost: done"); FACE_DBG_LOG("cleanupForWindowLost: done");
} }
void Application::reinitForNewWindow() bool Application::reinitForNewWindow()
{ {
if (!_applicationInited) { if (!_applicationInited) {
FACE_DBG_LOG("reinitForNewWindow: skip, _applicationInited=0 (must go through initVulkan first)"); FACE_DBG_LOG("reinitForNewWindow: skip, _applicationInited=0 (must go through initVulkan first)");
return; return false;
} }
if (_sceondInited) { if (_sceondInited) {
FACE_DBG_LOG("reinitForNewWindow: skip, already _sceondInited=1"); FACE_DBG_LOG("reinitForNewWindow: skip, already _sceondInited=1");
return; return false;
} }
FACE_DBG_LOG("reinitForNewWindow: begin"); FACE_DBG_LOG("reinitForNewWindow: begin (prev extent=%ux%u format=%d)",
_prevSwapChainExtent.width, _prevSwapChainExtent.height,
(int)_prevSwapChainImageFormat);
createSurface(); createSurface();
createSwapChain(); createSwapChain();
const bool extentChanged = (swapChainExtent.width != _prevSwapChainExtent.width) ||
(swapChainExtent.height != _prevSwapChainExtent.height);
const bool formatChanged = (swapChainImageFormat != _prevSwapChainImageFormat);
const bool swapchainIncompatible = extentChanged || formatChanged;
if (formatChanged) {
// renderPass bakes in swapChainImageFormat, so it must be rebuilt
// when the surface chose a different format. The old Application
// graphicsPipeline is tied to the old renderPass, so destroy it
// first to make the handle invalidation explicit.
FACE_DBG_LOG("reinitForNewWindow: format changed (%d -> %d), rebuilding renderPass",
(int)_prevSwapChainImageFormat, (int)swapChainImageFormat);
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;
}
createRenderPass();
createPipelineLayout();
createGraphicsPipeline();
} else if (extentChanged) {
// renderPass is still fine, but the Application pipeline has a static
// viewport baked to the old extent and must be rebuilt.
FACE_DBG_LOG("reinitForNewWindow: extent changed (%ux%u -> %ux%u), rebuilding graphicsPipeline",
_prevSwapChainExtent.width, _prevSwapChainExtent.height,
swapChainExtent.width, swapChainExtent.height);
if (graphicsPipeline != VK_NULL_HANDLE) {
vkDestroyPipeline(device, graphicsPipeline, nullptr);
graphicsPipeline = VK_NULL_HANDLE;
}
createGraphicsPipeline();
}
createImageViews(); createImageViews();
createFramebuffers(); createFramebuffers();
createCommandBuffer(); createCommandBuffer();
createSyncObjects(); createSyncObjects();
_sceondInited = true; _sceondInited = true;
FACE_DBG_LOG("reinitForNewWindow: done (imageCount=%zu extent=%ux%u MAX_FRAMES_IN_FLIGHT=%d)", FACE_DBG_LOG("reinitForNewWindow: done (imageCount=%zu extent=%ux%u format=%d MAX_FRAMES_IN_FLIGHT=%d swapchainIncompatible=%d)",
swapChainImages.size(), swapChainExtent.width, swapChainExtent.height, swapChainImages.size(), swapChainExtent.width, swapChainExtent.height,
MAX_FRAMES_IN_FLIGHT); (int)swapChainImageFormat, MAX_FRAMES_IN_FLIGHT, (int)swapchainIncompatible);
return swapchainIncompatible;
} }
+13 -1
View File
@@ -90,7 +90,19 @@ public:
// Rebuild the window-dependent Vulkan objects torn down above. // Rebuild the window-dependent Vulkan objects torn down above.
// Safe to call only after cleanupForWindowLost(). // Safe to call only after cleanupForWindowLost().
void reinitForNewWindow(); // Returns true when the new swapchain's extent or format differs from the
// one in use before cleanupForWindowLost(). When true, any pipeline baked
// with a static viewport/scissor from swapChainExtent -- including the
// FaceApp pipelines -- must be destroyed and recreated against the new
// renderPass / extent. Application's own renderPass + graphicsPipeline are
// already handled internally.
bool reinitForNewWindow();
// Extent / format captured by the most recent cleanupForWindowLost().
// Used by reinitForNewWindow() to decide whether renderPass / pipelines
// must be rebuilt against the new swapchain.
VkExtent2D _prevSwapChainExtent = {0, 0};
VkFormat _prevSwapChainImageFormat = VK_FORMAT_UNDEFINED;
protected: protected:
void loadTexture(std::string path, Texture& tex, bool srgb, VkCommandPool pool); void loadTexture(std::string path, Texture& tex, bool srgb, VkCommandPool pool);
+34 -3
View File
@@ -9,8 +9,10 @@
#ifndef _WIN32 #ifndef _WIN32
#include "../app/src/main/cpp/DebugLog.h" #include "../app/src/main/cpp/DebugLog.h"
#define FACE_DBG_LOG(...) DebugLog::log(__VA_ARGS__) #define FACE_DBG_LOG(...) DebugLog::log(__VA_ARGS__)
#define FACE_DBG_LOG_THROTTLED(key, ...) DebugLog::log_throttled(key, __VA_ARGS__)
#else #else
#define FACE_DBG_LOG(...) ((void)0) #define FACE_DBG_LOG(...) ((void)0)
#define FACE_DBG_LOG_THROTTLED(key, ...) ((void)0)
#endif #endif
@@ -906,12 +908,18 @@ void FaceApp::onWindowInit()
} else { } else {
// Recovery path after an earlier onWindowLost. Rebuild only the // Recovery path after an earlier onWindowLost. Rebuild only the
// window-dependent Vulkan objects; keep renderPass / pipelines / // window-dependent Vulkan objects; keep renderPass / pipelines /
// FaceApp GPU resources intact. // FaceApp GPU resources intact unless the new swapchain is
// incompatible (e.g. rotation changed extent).
std::unique_lock<std::mutex> lk_point(mtx_point); std::unique_lock<std::mutex> lk_point(mtx_point);
std::unique_lock<std::mutex> lk_motion(changeMotionMtx); std::unique_lock<std::mutex> lk_motion(changeMotionMtx);
std::unique_lock<std::mutex> lk_tex(createTextureMtx); std::unique_lock<std::mutex> lk_tex(createTextureMtx);
Application::reinitForNewWindow(); bool swapchainIncompatible = Application::reinitForNewWindow();
if (swapchainIncompatible && _faceAppInited) {
FACE_DBG_LOG("FaceApp::onWindowInit: swapchain incompatible, rebuilding FaceApp pipelines");
recreatePipelinesForSwapchain();
}
if (!_secondfaceAppInited) { if (!_secondfaceAppInited) {
_secondfaceAppInited = true; _secondfaceAppInited = true;
@@ -925,6 +933,29 @@ void FaceApp::onWindowInit()
(int)_secondfaceAppInited, (int)_running); (int)_secondfaceAppInited, (int)_running);
} }
void FaceApp::recreatePipelinesForSwapchain()
{
// Destroy the two FaceApp pipelines. Layouts / descriptor set layouts are
// swapchain-independent and kept as-is so existing descriptor sets keep
// pointing at the same texture/uniform resources.
if (m_graphicsPipeline != VK_NULL_HANDLE) {
vkDestroyPipeline(device, m_graphicsPipeline, nullptr);
m_graphicsPipeline = VK_NULL_HANDLE;
}
if (m_graphicsPipeline_bg != VK_NULL_HANDLE) {
vkDestroyPipeline(device, m_graphicsPipeline_bg, nullptr);
m_graphicsPipeline_bg = VK_NULL_HANDLE;
}
// Recreate against the fresh renderPass (if format changed) and the new
// swapChainExtent (viewport/scissor are baked statically into these).
create_face_pipelines();
create_pipelines_bg();
FACE_DBG_LOG("FaceApp::recreatePipelinesForSwapchain: rebuilt for extent=%ux%u",
swapChainExtent.width, swapChainExtent.height);
}
void FaceApp::update_uniform_buffers() void FaceApp::update_uniform_buffers()
{ {
uint32_t width = 480; uint32_t width = 480;
@@ -1637,7 +1668,7 @@ Motion FaceApp::getMotionByName(string name)
void FaceApp::changeMotionList(vector<string> motions, AnimationFinishedCallback callback, bool loop) void FaceApp::changeMotionList(vector<string> motions, AnimationFinishedCallback callback, bool loop)
{ {
DebugLog::log_throttled("FaceApp.changeMotionList", FACE_DBG_LOG_THROTTLED("FaceApp.changeMotionList",
"FaceApp::changeMotionList called count=%zu loop=%d _isLoadMotion=%d", "FaceApp::changeMotionList called count=%zu loop=%d _isLoadMotion=%d",
motions.size(), (int)loop, (int)_isLoadMotion); motions.size(), (int)loop, (int)_isLoadMotion);
if (_isLoadMotion) if (_isLoadMotion)
+10 -1
View File
@@ -191,8 +191,17 @@ public:
// Called from main thread in response to APP_CMD_INIT_WINDOW. // Called from main thread in response to APP_CMD_INIT_WINDOW.
// Does the full first-time initVulkan() on the very first call, and a // Does the full first-time initVulkan() on the very first call, and a
// lightweight swapchain/surface rebuild on subsequent calls. // lightweight swapchain/surface rebuild on subsequent calls. When the
// new swapchain's extent or format differs from the previous one, the
// FaceApp pipelines (baked with static viewport / old renderPass) are
// also destroyed and recreated via recreatePipelinesForSwapchain().
void onWindowInit(); void onWindowInit();
// Destroy and recreate m_graphicsPipeline / m_graphicsPipeline_bg so they
// match the current renderPass and swapChainExtent. Descriptor set layouts,
// pipeline layouts, vertex/index buffers, uniform buffers and textures are
// all kept. Must be called with device idle and the FaceApp mutexes held.
void recreatePipelinesForSwapchain();
void loadMotionThread(); void loadMotionThread();
std::thread worker_; std::thread worker_;
bool _isLoadMotion = false; bool _isLoadMotion = false;