resize - ID3D11On12Device::AcquireWrappedResources() 中的额外交换链缓冲区引用

标签 resize direct3d direct3d11 direct3d12 direct3d11on12

我有兴趣使用 "Direct 3D 11 on 12"库,但在调整窗口大小时遇到​​麻烦。具体来说,我正在修改 Visual Studio“DirectX 12 App”示例。

我在示例创建 ID3D12CommandQueue 之后立即创建 ID3D11On12Device:

ComPtr<ID3D11Device> d3d11Device;
IUnknown* queues[] = { m_commandQueue.Get() };
DX::ThrowIfFailed(D3D11On12CreateDevice(m_d3dDevice.Get(), D3D11_CREATE_DEVICE_BGRA_SUPPORT, nullptr, 0, queues, 1, 0, d3d11Device.GetAddressOf(), m_d3d11DeviceContext.GetAddressOf(), nullptr));
DX::ThrowIfFailed(d3d11Device.As(&m_d3d11On12Device));

然后,当示例创建其渲染目标 View 时,我添加了包装的 ID3D11Resource 的创建:

for (UINT n = 0; n < c_frameCount; n++)
{
    // Visual studio template calls m_swapChain->GetBuffer() and m_d3dDevice->CreateRenderTargetView() here
    D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
    DX::ThrowIfFailed(m_d3d11On12Device->CreateWrappedResource(m_renderTargets[n].Get(), &d3d11Flags, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT, IID_PPV_ARGS(&m_wrappedBackBuffers[n])));
    rtvDescriptor.Offset(m_rtvDescriptorSize);

    ...
    // m_renderTargets[n]->SetName(), etc.
}

然后,在创建其余的 D3D12 资源后,我正在测试 ID3D11On12Device::AcquireWrappedResources() 和 ID3D11On12Device::ReleaseWrappedResources() (只是作为测试,尝试使代码尽可能简单)

ID3D11Resource* resources[] = { m_wrappedBackBuffers[0].Get() };
m_d3d11On12Device->AcquireWrappedResources(resources, 1);
m_d3d11On12Device->ReleaseWrappedResources(resources, 1);

到目前为止,一切似乎都按预期进行。但是,在调整窗口大小时会出现问题。特别是,调整大小会调用 IDXGISwapChain3::ResizeBuffers()。发生这种情况时,ResizeBuffers() 返回失败,并在控制台上显示以下消息:

DXGI ERROR: IDXGISwapChain::ResizeBuffers: Swapchain cannot be resized unless all outstanding buffer references have been released. [ MISCELLANEOUS ERROR #19: ]

我尝试在 ResizeBuffers() 之前清除 m_wrappedBackBuffers 引用:

for (UINT n = 0; n < c_frameCount; n++)
{
    m_renderTargets[n] = nullptr;
    m_wrappedBackBuffers[n] = nullptr;
}

但这似乎没有效果。我还尝试过对 ID3D11DeviceContext 进行 Flush()ing 和 ClearState()ing,但这些似乎没有效果或产生以下错误:

D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: A command list, which writes to a swapchain back buffer, may only be executed when that back buffer is the back buffer will be presented during the next call to Present*. Such a back buffer is also referred to as the "current back buffer". [ STATE_SETTING ERROR #907: EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE]
D3D12: Removing Device.

注释掉 ID3D11On12Device::AcquireWrappedResources() 和 ID3D11On12Device::ReleaseWrappedResources() 调用可使 ResizeBuffers() 成功返回;但似乎需要调用这两个函数才能使用该库。

似乎在某个地方,ID3D11On12Device 或 ID3D11DeviceContext 保留了对交换链缓冲区的引用,但我无法找到任何有关如何在不破坏整个设备的情况下重置此引用的文档。

这个issue GitHub 上的问题似乎与我遇到的问题相同;然而,响应涉及“在 D2D 上下文中调用 SetTarget(nullptr)”,但我在这个项目中根本没有接触过 Direct2D(并且 Visual Studio 模板已经在 IDXGISwapChain3::ResizeBuffers() 之前调用了 WaitForGpu())。

微软的sample根本不包括交换链缓冲区大小调整。运行示例会导致交换链被拉伸(stretch)以适合窗口。

我在 Microsoft 的 documentation 中没有找到任何有关调整大小的信息.

最佳答案

您遇到的问题是 AcquireWrappedResource 和 ReleaseWrappedResource 方法最终会在 D3D11 直接上下文上排队一些工作。 D3D11On12 的语义要求当您想要从 D3D11 转换到 D3D12 时显式调用 Flush() API,以确保所有排队的命令正确记录在 D3D12 命令列表中,然后关闭并提交。

如果我正确理解了您的描述,并且您只是在创建包装资源后调用 Acquire/Release 一次,那么您的问题应该只是在 Release() 之后调用 Flush() 。这确保了仅当后台缓冲区 0 是交换链的当前后台缓冲区时才提交引用后台缓冲区 0 的命令,从而解决了错误:

D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: A command list, which writes to a swapchain back buffer, may only be executed when that back buffer is the back buffer will be presented during the next call to Present*. Such a back buffer is also referred to as the "current back buffer". [ STATE_SETTING ERROR #907: EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE]

然后,当您准备好调整大小时,请按照 D3D11On12 MSDN documentation 的“清理”部分中的说明进行操作。 :

  1. 释放对 D3D11 资源的所有引用,包括在其上创建的任何 View 。
  2. 在直接上下文上调用 ID3D11DeviceContext::Flush()。

完成这两件事后,您应该能够调整交换链的大小,而不会出现任何挥之不去的引用,并且最终的 Flush() 不会导致在不适当的时间提交命令。

关于resize - ID3D11On12Device::AcquireWrappedResources() 中的额外交换链缓冲区引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34257212/

相关文章:

java - 如何以编程方式修改 customAlertDialog 的 LinearLayout 的高度和宽度?

objective-c - Cocoa 在保留动画的同时调整 NSImage 的大小

winapi - Direct3d 顶点缓冲区使用类型、性能和 c++amp?

c# - 将按钮控件嵌入到现有的 Direct3D 应用程序中

pixel-shader - 像素着色器实际上是做什么的?

python - 已弃用的 scipy imresize() 函数的替代品?

c++ - 如果新尺寸与旧尺寸相同,标准是否保证 std::string::resize 不会做任何事情?

c++ - 如何从 'normal' IDirect3D9Surface 获取离屏平面

c++ - file_not_found 错误 - 带有 Visual Studio 2015 的 directx 工具包

c++ - 需要澄清 direct3D11 中 vector 的概念