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
+63 -10
View File
@@ -112,9 +112,12 @@ void Application::initVulkan()
createSyncObjects(); // 创建同步对象
_lastDrawFrameTime = getCurrentTimeMillis();
_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;
}
if (!_sceondInited) {
else if (!_sceondInited) {
createSurface();
createSwapChain();
createImageViews();
@@ -155,8 +158,14 @@ void Application::cleanupForWindowLost()
(int)_applicationInited, (int)_sceondInited);
return;
}
FACE_DBG_LOG("cleanupForWindowLost: begin (imageCount=%zu MAX_FRAMES_IN_FLIGHT=%d)",
swapChainImages.size(), MAX_FRAMES_IN_FLIGHT);
FACE_DBG_LOG("cleanupForWindowLost: begin (imageCount=%zu MAX_FRAMES_IN_FLIGHT=%d extent=%ux%u format=%d)",
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
// to destroy. Anything weaker than this risks hitting VK_ERROR_DEVICE_LOST
@@ -222,29 +231,73 @@ void Application::cleanupForWindowLost()
FACE_DBG_LOG("cleanupForWindowLost: done");
}
void Application::reinitForNewWindow()
bool Application::reinitForNewWindow()
{
if (!_applicationInited) {
FACE_DBG_LOG("reinitForNewWindow: skip, _applicationInited=0 (must go through initVulkan first)");
return;
return false;
}
if (_sceondInited) {
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();
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();
createFramebuffers();
createCommandBuffer();
createSyncObjects();
_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,
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.
// 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:
void loadTexture(std::string path, Texture& tex, bool srgb, VkCommandPool pool);
+34 -3
View File
@@ -9,8 +9,10 @@
#ifndef _WIN32
#include "../app/src/main/cpp/DebugLog.h"
#define FACE_DBG_LOG(...) DebugLog::log(__VA_ARGS__)
#define FACE_DBG_LOG_THROTTLED(key, ...) DebugLog::log_throttled(key, __VA_ARGS__)
#else
#define FACE_DBG_LOG(...) ((void)0)
#define FACE_DBG_LOG_THROTTLED(key, ...) ((void)0)
#endif
@@ -906,12 +908,18 @@ void FaceApp::onWindowInit()
} else {
// Recovery path after an earlier onWindowLost. Rebuild only the
// 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_motion(changeMotionMtx);
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) {
_secondfaceAppInited = true;
@@ -925,6 +933,29 @@ void FaceApp::onWindowInit()
(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()
{
uint32_t width = 480;
@@ -1637,7 +1668,7 @@ Motion FaceApp::getMotionByName(string name)
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",
motions.size(), (int)loop, (int)_isLoadMotion);
if (_isLoadMotion)
+10 -1
View File
@@ -191,8 +191,17 @@ public:
// Called from main thread in response to APP_CMD_INIT_WINDOW.
// 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();
// 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();
std::thread worker_;
bool _isLoadMotion = false;