(WIN32) 从Vulkan切换到D3D11渲染器时无法释放窗口的问题求助
(WIN32) 从Vulkan切换到D3D11渲染器时无法释放窗口的问题求助
我正在开发一款游戏引擎,引擎内置了图形后端切换菜单,目前已实现Vulkan(红背景)、D3D11(蓝背景)、D3D9这几个后端。
原本大部分切换逻辑都正常:D3D9与D3D11之间切换流畅,从D3D切到Vulkan也能正常渲染画面。但从Vulkan切回D3D时出现了异常——Vulkan明明已经退出,却好像没有释放窗口的控制权:
- Vulkan的所有对象都按正确顺序完成释放,调试验证层未报任何错误,封装类的析构函数确实被调用,甚至连Vulkan的DLL都通过
FreeLibrary()完成卸载 - D3D11/D3D9在Vulkan退出后能成功初始化,Draw命令正常执行,
DXGISwapChain::Present()也未返回错误码 - 但窗口始终停留在Vulkan最后一帧的画面,D3D的渲染内容完全无法显示
- 拉伸窗口时,原Vulkan画面会被强制放大,超出原视口的区域会显示黑边
- 反过来从D3D切回Vulkan却一切正常,就像Vulkan重新“夺回”了窗口的控制权
我特意通过调试器逐流程验证:Vulkan封装类的析构逻辑完整执行,D3D11的初始化与渲染步骤均无遗漏,但就是无法在窗口上看到D3D的输出。
以下是我封装的Vulkan核心状态代码与析构函数:
Vulkan封装的核心状态
HMODULE dll_; VkInstance instance_; VkSurfaceKHR surface_; VkPhysicalDevice GPU_; VkDevice device_; VkSwapchainKHR swapChain_; VkImage *swapChainImages_; VkImageView *swapChainViews_; VkFramebuffer *swapChainFrameBuffers_; VkExtent2D swapChainExtent_; VkFormat swapChainFormat_; u32 swapChainImageCount_, frameIndex_, imageIndex_; VkRenderPass renderPass_; VkPipelineLayout pipelineLayout_; VkPipeline pipeline_; VkCommandPool commandPool_; VkCommandBuffer commandBuffers_ [MAX_CONCURRENT_FRAMES]; // FENCE SYNCED VkCommandBuffer drawCommandBuffers_ [MAX_CONCURRENT_FRAMES]; // FENCE SYNCED VkFence frameFence_ [MAX_CONCURRENT_FRAMES]; // SYNC CMD BUFS VkSemaphore imageReadySemaphores_[MAX_CONCURRENT_FRAMES]; VkSemaphore *drawDoneSemaphores_; // N = scImageCount vk::q::FamilyIndices queueFamilyIndices_; vk::q::Queues queues_;
Vulkan的析构函数
VK::~VK() { if (dll_) { // Queues do not need to be released // Logical device CAN be destroyed if (device_) { freeSyncObjects(); // Waits for device idling freeCommandPools(); if (pipeline_) { vkDestroyPipeline(device_, pipeline_, nullptr); pipeline_ = nullptr; } if (pipelineLayout_) { vkDestroyPipelineLayout(device_, pipelineLayout_, nullptr); pipelineLayout_ = nullptr; } if (renderPass_) { vkDestroyRenderPass(device_, renderPass_, nullptr); renderPass_ = nullptr; } freeSwapchain(); vkDestroyDevice(device_, nullptr); device_ = nullptr; } // Physical device cannot be destroyed if (surface_) { vkDestroySurfaceKHR(instance_, surface_, nullptr); surface_ = nullptr; } if (instance_) { vkDestroyInstance(instance_, nullptr); instance_ = nullptr; } FreeLibrary(dll_); dll_ = nullptr; } }
问题根源已找到!
查阅Vulkan官方规范后终于明确了原因:
对于Win32窗口,一旦为其创建了Vulkan交换链,后续将该窗口传递给其他图形API属于未定义行为。窗口会被Vulkan永久“标记”,即便销毁了交换链,该窗口也无法再被D3D等其他API复用——相当于Vulkan占用了窗口的前台缓冲区,即使自身退出也不会释放控制权。
也就是说,我在同一个窗口上交替使用Vulkan与D3D的做法,本身就不符合图形API的规范,出现异常是必然结果。
内容来源于stack exchange
相关产品推荐
相关产品推荐

