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



我对使用"Direct 3D 11 on 12"库很感兴趣,但在调整窗口大小时遇到了麻烦。特别是,我正在修改Visual Studio"DirectX 12应用程序"示例。

在示例创建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));

然后,当示例创建其渲染目标视图时,我添加了包装的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(

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()和ClearState()操作,但这些操作似乎要么没有效果,要么会产生以下错误:

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或ID3D11DeviceContext似乎在某个地方保留了对交换链缓冲区的引用,但我还没有找到任何关于如何在不破坏整个设备的情况下重置此引用的文档。

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

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

我没有在微软的文档中找到任何关于调整大小的内容。

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

如果我正确理解了你的描述,并且你只是在创建包装资源后调用Acquire/Release一次,那么你的问题应该只是在Release()之后调用Flush()。这确保了引用后台缓冲区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文档的"清理"部分中的说明进行操作:

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

一旦你完成了这两件事,你应该能够在没有任何延迟引用的情况下调整swapchain的大小,也没有最终的Flush()导致命令在不合适的时间提交。

最新更新