修复clash的问题
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include "AppBase.h"
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <functional>
|
||||
|
||||
struct Texture
|
||||
{
|
||||
@@ -48,8 +49,68 @@ public:
|
||||
virtual void render(VkCommandBuffer commandBuffer, long long frameTime);
|
||||
virtual bool isInited() { return _applicationInited; }
|
||||
std::mutex createTextureMtx;
|
||||
// 全局 GPU 提交互斥锁:任何对 graphicsQueue / presentQueue 的提交
|
||||
// (vkQueueSubmit / vkQueuePresentKHR / vkQueueWaitIdle)以及共享
|
||||
// commandPool 的 vkAllocateCommandBuffers / vkFreeCommandBuffers
|
||||
// 都必须在持有此锁的期间执行,否则驱动内部维护命令池与队列的
|
||||
// pthread_mutex 在长时间多线程并发下会被破坏(FORTIFY: pthread_mutex_lock
|
||||
// called on a destroyed mutex)。
|
||||
// 需要覆盖的 3 条并发线路:
|
||||
// 1) 渲染线程 drawFrame
|
||||
// 2) processImageNative → updateTexture (single-time commands)
|
||||
// 3) passDataToNative → update_face_vertex_buffer → copyBuffer
|
||||
std::mutex poolQueueMtx;
|
||||
void processWithVulkan(uint8_t* data, int width, int height, int rowStride, size_t dataSize, Texture& texture, bool srgb, VkCommandPool pool, std::string tex_path);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 复用式 single-time-command 接口(替代每帧 allocate+submit+waitIdle+free)
|
||||
//
|
||||
// ★ 同步语义(重要):
|
||||
// 本接口 **同步**,返回时 GPU 已经读完 record 里访问的源数据。
|
||||
// 行为上等价于旧的 vkQueueSubmit + vkQueueWaitIdle,但只等自己这次
|
||||
// 提交的 fence,不阻塞渲染线程在 graphicsQueue 上的其它提交。
|
||||
//
|
||||
// 为什么必须同步:调用方 (FaceApp::uploadVertexData /
|
||||
// Application::updateTexture) 紧接着会复用同一个 staging buffer:
|
||||
//
|
||||
// vkMapMemory(staging); memcpy(staging, A); vkUnmapMemory;
|
||||
// runTransferCommand([&](cmd){ vkCmdCopyBuffer(cmd, staging, dstA); });
|
||||
// vkMapMemory(staging); memcpy(staging, B); ← 必须等 dstA 拷完!
|
||||
// vkUnmapMemory;
|
||||
// runTransferCommand([&](cmd){ vkCmdCopyBuffer(cmd, staging, dstB); });
|
||||
//
|
||||
// 如果 runTransferCommand 异步返回,第二次 memcpy 会在 GPU 还没读完
|
||||
// staging 里的 A 时就把它覆盖成 B —— 顶点 / 纹理立刻畸形。
|
||||
//
|
||||
// 行为:
|
||||
// - 共 kTransferSlotCount 个 VkCommandBuffer + 同数 VkFence,
|
||||
// 从 commandPool_ex 一次性分配,在 cleanup 时一次性释放。
|
||||
// - 每次 runTransferCommand:
|
||||
// 1) m_xferMtx.lock() (串行所有 transfer 提交)
|
||||
// 2) 当前 slot 上 vkWaitForFences (等上一次该 slot 的提交完成)
|
||||
// 3) vkResetFences + vkResetCommandBuffer + vkBegin
|
||||
// 4) 调用 record(cmd) 录制命令 (vkCmdCopy* 等)
|
||||
// 5) vkEndCommandBuffer
|
||||
// 6) poolQueueMtx 内 vkQueueSubmit(graphicsQueue, fence)
|
||||
// 7) vkWaitForFences(fence) (★ 等本次 GPU 完成才返回)
|
||||
// 8) m_xferIdx 推进到下一个 slot
|
||||
//
|
||||
// 为什么这样设计:
|
||||
// - 完全消除每帧 vkAllocateCommandBuffers / vkFreeCommandBuffers,
|
||||
// 根除驱动 per-pool mutex 在长时间高频压力下被破坏导致的
|
||||
// FORTIFY: pthread_mutex_lock called on a destroyed mutex 崩溃。
|
||||
// - 用 fence 替代 vkQueueWaitIdle,等待粒度只到自己这一次提交,
|
||||
// 不会 stall 整条 graphicsQueue(包括渲染主路径的提交)。
|
||||
// - 固定使用 commandPool_ex(与渲染主用的 commandPool 物理隔离),
|
||||
// 即使驱动还有内部 contention,也不会波及渲染主管线。
|
||||
//
|
||||
// 调用约束:
|
||||
// - 调用方 **绝不能** 提前持有 poolQueueMtx;本接口内部按需短暂获取。
|
||||
// - record 函数体内只允许 vkCmd*(命令录制)这类操作,不要在里面调
|
||||
// queue / pool 级别的 API(submit / present / pool reset 等)。
|
||||
static constexpr uint32_t kTransferSlotCount = 3;
|
||||
void runTransferCommand(const std::function<void(VkCommandBuffer)>& record);
|
||||
|
||||
protected:
|
||||
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; // 物理设备
|
||||
@@ -104,6 +165,21 @@ public:
|
||||
VkExtent2D _prevSwapChainExtent = {0, 0};
|
||||
VkFormat _prevSwapChainImageFormat = VK_FORMAT_UNDEFINED;
|
||||
|
||||
protected:
|
||||
// Transfer command resources(详见 runTransferCommand 上方注释)。
|
||||
// 命令缓冲来自 commandPool_ex,与渲染主用的 commandPool 物理隔离。
|
||||
VkCommandBuffer m_xferCmd[kTransferSlotCount] = { VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE };
|
||||
VkFence m_xferFence[kTransferSlotCount] = { VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE };
|
||||
uint32_t m_xferIdx = 0;
|
||||
bool m_xferInited = false;
|
||||
std::mutex m_xferMtx;
|
||||
|
||||
// 创建/销毁 transfer 资源。createTransferResources 必须在 createCommandPool
|
||||
// 之后调用;destroyTransferResources 必须在销毁 commandPool_ex 之前调用,
|
||||
// 且 GPU 已 idle(vkDeviceWaitIdle 或确认所有 fence 已 signaled)。
|
||||
void createTransferResources();
|
||||
void destroyTransferResources();
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user