You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 08:29:33