fix bug and add log

This commit is contained in:
xsl
2026-04-23 22:18:22 +08:00
parent fb434f09b8
commit 27b7075818
7 changed files with 327 additions and 40 deletions
+115 -4
View File
@@ -148,6 +148,105 @@ void Application::cleanupSecondInit()
_sceondInited = false;
}
void Application::cleanupForWindowLost()
{
if (!_applicationInited || !_sceondInited) {
FACE_DBG_LOG("cleanupForWindowLost: skip (_applicationInited=%d _sceondInited=%d)",
(int)_applicationInited, (int)_sceondInited);
return;
}
FACE_DBG_LOG("cleanupForWindowLost: begin (imageCount=%zu MAX_FRAMES_IN_FLIGHT=%d)",
swapChainImages.size(), MAX_FRAMES_IN_FLIGHT);
// 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
// on drivers that don't tolerate destroying in-flight resources.
vkDeviceWaitIdle(device);
for (auto framebuffer : swapChainFramebuffers) {
if (framebuffer != VK_NULL_HANDLE) {
vkDestroyFramebuffer(device, framebuffer, nullptr);
}
}
swapChainFramebuffers.clear();
for (auto imageView : swapChainImageViews) {
if (imageView != VK_NULL_HANDLE) {
vkDestroyImageView(device, imageView, nullptr);
}
}
swapChainImageViews.clear();
// Free the command buffers allocated from commandPool. The pool itself is
// kept alive so textures/staging uploads that run concurrently off the
// render thread (via commandPool_ex) aren't disrupted.
if (!commandBuffers.empty()) {
vkFreeCommandBuffers(device, commandPool,
(uint32_t)commandBuffers.size(), commandBuffers.data());
commandBuffers.clear();
}
for (size_t i = 0; i < imageAvailableSemaphores.size(); ++i) {
if (imageAvailableSemaphores[i] != VK_NULL_HANDLE) {
vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
}
}
imageAvailableSemaphores.clear();
for (size_t i = 0; i < renderFinishedSemaphores.size(); ++i) {
if (renderFinishedSemaphores[i] != VK_NULL_HANDLE) {
vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
}
}
renderFinishedSemaphores.clear();
for (size_t i = 0; i < inFlightFences.size(); ++i) {
if (inFlightFences[i] != VK_NULL_HANDLE) {
vkDestroyFence(device, inFlightFences[i], nullptr);
}
}
inFlightFences.clear();
imagesInFlight.clear();
if (swapChain != VK_NULL_HANDLE) {
vkDestroySwapchainKHR(device, swapChain, nullptr);
swapChain = VK_NULL_HANDLE;
}
swapChainImages.clear();
if (surface != VK_NULL_HANDLE) {
vkDestroySurfaceKHR(instance, surface, nullptr);
surface = VK_NULL_HANDLE;
}
currentFrame = 0;
_sceondInited = false;
FACE_DBG_LOG("cleanupForWindowLost: done");
}
void Application::reinitForNewWindow()
{
if (!_applicationInited) {
FACE_DBG_LOG("reinitForNewWindow: skip, _applicationInited=0 (must go through initVulkan first)");
return;
}
if (_sceondInited) {
FACE_DBG_LOG("reinitForNewWindow: skip, already _sceondInited=1");
return;
}
FACE_DBG_LOG("reinitForNewWindow: begin");
createSurface();
createSwapChain();
createImageViews();
createFramebuffers();
createCommandBuffer();
createSyncObjects();
_sceondInited = true;
FACE_DBG_LOG("reinitForNewWindow: done (imageCount=%zu extent=%ux%u MAX_FRAMES_IN_FLIGHT=%d)",
swapChainImages.size(), swapChainExtent.width, swapChainExtent.height,
MAX_FRAMES_IN_FLIGHT);
}
void Application::createImageViews() {
@@ -590,18 +689,24 @@ void Application::drawFrame(long long frameTime)
// 1. 等待前一帧完成
VkResult waitRes = vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
if (waitRes != VK_SUCCESS) {
FACE_DBG_LOG("drawFrame[%llu] vkWaitForFences -> %d (%s) currentFrame=%u",
#ifndef _WIN32
DebugLog::log_throttled("drawFrame.waitFences",
"drawFrame[%llu] vkWaitForFences -> %d (%s) currentFrame=%u",
(unsigned long long)s_drawFrameCount,
(int)waitRes, VkResultStr(waitRes), currentFrame);
#endif
}
// 2. 获取交换链图像
uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
if (result != VK_SUCCESS) {
FACE_DBG_LOG("drawFrame[%llu] vkAcquireNextImageKHR -> %d (%s) currentFrame=%u",
#ifndef _WIN32
DebugLog::log_throttled("drawFrame.acquire",
"drawFrame[%llu] vkAcquireNextImageKHR -> %d (%s) currentFrame=%u",
(unsigned long long)s_drawFrameCount,
(int)result, VkResultStr(result), currentFrame);
#endif
throw std::runtime_error("failed to acquire swap chain image!");
}
@@ -634,10 +739,13 @@ void Application::drawFrame(long long frameTime)
VkResult submitRes = vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]);
if (submitRes != VK_SUCCESS) {
FACE_DBG_LOG("drawFrame[%llu] vkQueueSubmit -> %d (%s) currentFrame=%u imageIndex=%u",
#ifndef _WIN32
DebugLog::log_throttled("drawFrame.submit",
"drawFrame[%llu] vkQueueSubmit -> %d (%s) currentFrame=%u imageIndex=%u",
(unsigned long long)s_drawFrameCount,
(int)submitRes, VkResultStr(submitRes),
currentFrame, imageIndex);
#endif
throw std::runtime_error("failed to submit draw command buffer!");
}
// 7. 呈现图像
@@ -652,10 +760,13 @@ void Application::drawFrame(long long frameTime)
result = vkQueuePresentKHR(presentQueue, &presentInfo);
if (result != VK_SUCCESS) {
FACE_DBG_LOG("drawFrame[%llu] vkQueuePresentKHR -> %d (%s) currentFrame=%u imageIndex=%u",
#ifndef _WIN32
DebugLog::log_throttled("drawFrame.present",
"drawFrame[%llu] vkQueuePresentKHR -> %d (%s) currentFrame=%u imageIndex=%u",
(unsigned long long)s_drawFrameCount,
(int)result, VkResultStr(result),
currentFrame, imageIndex);
#endif
throw std::runtime_error("failed to present swap chain image!");
}
+11
View File
@@ -81,6 +81,17 @@ public:
bool _applicationInited = false;
void cleanupSecondInit();
// Tear down only the window-dependent Vulkan objects so we can survive an
// Android APP_CMD_TERM_WINDOW (screen off / background / rotate).
// Keeps renderPass / pipelines / VMA / textures / FaceApp resources intact,
// so pipelines created by FaceApp remain valid for the new swapchain.
// Caller MUST hold any app-level mutexes that serialize JNI -> Vulkan access.
void cleanupForWindowLost();
// Rebuild the window-dependent Vulkan objects torn down above.
// Safe to call only after cleanupForWindowLost().
void reinitForNewWindow();
protected:
void loadTexture(std::string path, Texture& tex, bool srgb, VkCommandPool pool);
void loadTexture(std::vector<unsigned char>& image_data, size_t image_size, int w, int h, Texture& tex, bool srgb, VkCommandPool pool, std::string path);
+71 -1
View File
@@ -32,11 +32,14 @@ FaceApp::~FaceApp()
void FaceApp::Stop()
{
FACE_DBG_LOG("FaceApp::Stop called (_running=%d worker_joinable=%d)",
(int)_running, (int)worker_.joinable());
_running = false;
if(worker_.joinable())
{
worker_.join();
}
FACE_DBG_LOG("FaceApp::Stop done");
}
void ReceiveFacePoint(float* pos, int pointCount, int width, int height)
@@ -858,14 +861,70 @@ void FaceApp::initVulkan()
void FaceApp::clearnSecondFaceApp()
{
FACE_DBG_LOG("FaceApp::clearnSecondFaceApp: _secondfaceAppInited %d -> 0",
(int)_secondfaceAppInited);
_secondfaceAppInited = false;
}
void FaceApp::Start()
{
FACE_DBG_LOG("FaceApp::Start: _running %d -> 1", (int)_running);
_running = true;
}
void FaceApp::onWindowLost()
{
FACE_DBG_LOG("FaceApp::onWindowLost enter _applicationInited=%d _faceAppInited=%d _sceondInited=%d _secondfaceAppInited=%d _running=%d",
(int)_applicationInited, (int)_faceAppInited, (int)_sceondInited,
(int)_secondfaceAppInited, (int)_running);
// Stop the render loop from touching Vulkan while we tear down.
_running = false;
// Serialize against JNI callbacks that may concurrently submit GPU work
// via commandPool / commandPool_ex (processImageNative -> update texture,
// passDataToNative -> update vertex buffer, changeMotionList).
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::cleanupForWindowLost();
_secondfaceAppInited = false;
FACE_DBG_LOG("FaceApp::onWindowLost done");
}
void FaceApp::onWindowInit()
{
FACE_DBG_LOG("FaceApp::onWindowInit enter _applicationInited=%d _faceAppInited=%d _sceondInited=%d _secondfaceAppInited=%d",
(int)_applicationInited, (int)_faceAppInited, (int)_sceondInited,
(int)_secondfaceAppInited);
if (!_applicationInited) {
// First-time path: go through the full initVulkan pipeline.
initVulkan();
} else {
// Recovery path after an earlier onWindowLost. Rebuild only the
// window-dependent Vulkan objects; keep renderPass / pipelines /
// FaceApp GPU resources intact.
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();
if (!_secondfaceAppInited) {
_secondfaceAppInited = true;
_playMotion = true;
_running = true;
}
}
FACE_DBG_LOG("FaceApp::onWindowInit done _applicationInited=%d _faceAppInited=%d _sceondInited=%d _secondfaceAppInited=%d _running=%d",
(int)_applicationInited, (int)_faceAppInited, (int)_sceondInited,
(int)_secondfaceAppInited, (int)_running);
}
void FaceApp::update_uniform_buffers()
{
uint32_t width = 480;
@@ -1340,6 +1399,7 @@ void FaceApp::cleanupResources(VkDevice device, VmaAllocator allocator) {
void FaceApp::cleanup()
{
FACE_DBG_LOG("FaceApp::cleanup enter");
vkDeviceWaitIdle(device);
if (uniform_buffer_mapped != nullptr)
@@ -1375,7 +1435,7 @@ void FaceApp::cleanup()
// allocator = VK_NULL_HANDLE;
//}
FACE_DBG_LOG("FaceApp::cleanup done");
}
@@ -1481,6 +1541,8 @@ void FaceApp::drawFrame(long long frameTime)
string FaceApp::preLoadMotionList(string motion_list_str, Callback callback)
{
FACE_DBG_LOG("FaceApp::preLoadMotionList called str_len=%zu _isLoadMotion=%d",
motion_list_str.size(), (int)_isLoadMotion);
if (_isLoadMotion)
{
return "failue load not finished";
@@ -1496,11 +1558,13 @@ string FaceApp::preLoadMotionList(string motion_list_str, Callback callback)
worker_.join();
}
worker_ = std::thread(&FaceApp::loadMotionThread, this);
FACE_DBG_LOG("FaceApp::preLoadMotionList worker_ started, todo_count=%zu", _curLoadMotionList.size());
return "ok";
}
void FaceApp::loadMotionThread()
{
FACE_DBG_LOG("FaceApp::loadMotionThread enter, todo_count=%zu", _curLoadMotionList.size());
while (!isInited())
{
std::this_thread::sleep_for(std::chrono::milliseconds(50));
@@ -1561,6 +1625,7 @@ void FaceApp::loadMotionThread()
// }
update_descriptor_set(m_texs_left, m_descriptor_sets_left);
_isLoadMotion = false;
FACE_DBG_LOG("FaceApp::loadMotionThread done, loaded_total=%zu", motion_list_map.size());
_callback_loadfinish();
}
@@ -1572,6 +1637,9 @@ Motion FaceApp::getMotionByName(string name)
void FaceApp::changeMotionList(vector<string> motions, AnimationFinishedCallback callback, bool loop)
{
DebugLog::log_throttled("FaceApp.changeMotionList",
"FaceApp::changeMotionList called count=%zu loop=%d _isLoadMotion=%d",
motions.size(), (int)loop, (int)_isLoadMotion);
if (_isLoadMotion)
{
return;
@@ -1623,10 +1691,12 @@ void FaceApp::changeMotionList(vector<string> motions, AnimationFinishedCallback
}
void FaceApp::StopMotion() {
FACE_DBG_LOG("FaceApp::StopMotion: _playMotion %d -> 0", (int)_playMotion);
_playMotion = false;
}
void FaceApp::ResumeMotion() {
FACE_DBG_LOG("FaceApp::ResumeMotion: _playMotion %d -> 1", (int)_playMotion);
_playMotion = true;
}
+11
View File
@@ -182,6 +182,17 @@ public:
void clearnSecondFaceApp();
void Start();
void Stop();
// Called from main thread in response to APP_CMD_TERM_WINDOW.
// Serializes against JNI callbacks (processImageNative / passDataToNative /
// changeMotionList) by taking all three FaceApp mutexes + createTextureMtx,
// then tears down window-dependent Vulkan objects via Application.
void onWindowLost();
// 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.
void onWindowInit();
void loadMotionThread();
std::thread worker_;
bool _isLoadMotion = false;