为什么我在关闭 SDL 后无法使用 CreateWICTextureFromFileEx

Why am I unable to use CreateWICTextureFromFileEx after shutting down SDL

我正在尝试关闭我的 DX12 渲染器,然后在同一进程中重新启动它。

所述应用程序主要基于 Microsoft MiniEngine 示例代码,现在进行了一些修改以允许重新初始化全局变量。我将 SDL 用于 window 和事件管理。

干净关闭和重新初始化的最后一个绊脚石似乎是在纹理管理器 class 中加载纹理,后者又使用 DirectXTK12 代码加载纹理,通过 CreateWICTextureFromFileEx 获取 .png 个文件。

总结一下我正在尝试做的事情:

纹理管理 class 作为渲染关闭的一部分被关闭,删除所有纹理痕迹及其资源句柄等。

作为渲染重新初始化的一部分,默认纹理是通过 CreateWICTextureFromFileEx 创建的。 (参见 here)并在尝试执行此操作时崩溃。

编辑:自第一次发布以来,我可以说这种崩溃是在调用 SDL_Quit() 后直接开始的(并在调用 SDL_Init(SDL_INIT_VIDEO) 重新启动后持续存在)

我现在相当有信心这是这个区域的问题,而不是渲染器的其他部分没有正确重新初始化,因为我可以强制它使用 .DDS 纹理而不是.pngs,系统再次正常启动。在这种情况下,它使用 DDSTextureLoader 没有任何(明显的)问题。

我已经将源代码添加到我的项目中,并且可以看到在尝试执行此操作时发生了崩溃:

ComPtr<IWICBitmapDecoder> decoder;
    HRESULT hr = pWIC->CreateDecoderFromFilename(fileName,
        nullptr,
        GENERIC_READ,
        WICDecodeMetadataCacheOnDemand,
        decoder.GetAddressOf());

报告的失败是

Unhandled exception thrown: read access violation.
pWIC->**** was 0x7FFAC0B0C610.

pWIC 这里是通过 _GetWIC() 获得的,它使用单例初始化:

IWICImagingFactory2* _GetWIC() noexcept
    {
        static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT;

        IWICImagingFactory2* factory = nullptr;
        if (!InitOnceExecuteOnce(
            &s_initOnce,
            InitializeWICFactory,
            nullptr,
            reinterpret_cast<LPVOID*>(&factory)))
        {
            return nullptr;
        }

        return factory;
    }

自从第一次发帖以来,我现在可以说这个崩溃是在调用 SDL_Quit() 后直接开始的。我有测试代码启动图形足以获得设备和纹理,它将在 SDL_Quit 之前的任何时候成功完成。 使用 SDL_Init(SDL_INIT_VIDEO) 重新初始化 SDL 没有帮助。

我还注意到 WICTextureLoader 评论指出“假设应用程序已经调用了 CoInitializeEx”。这是 SDL_Quit 可能搞砸的区域吗?

我会 post 在这里回答,但如果@ChuckWalbourn 想要 post 他自己的答案,我会删除它。

这是因为让 SDL 为我调用 CoInitialize
当它通过 SDL_Quit 清理时,它调用 CoUninitialize 然后(大概)使 WICTextureLoader 设置的 IWICImagingFactory2 无效。
在我的渲染启动中添加对 CoInitialize 的调用,CoInitialize 中的内部计数使 IWICImagingFactory2 保持活动状态并且一切正常。