2

I'm interested in using the "Direct 3D 11 on 12" library, but am running into trouble when resizing the window. In particular, I'm modifying the Visual Studio "DirectX 12 App" sample.

I'm creating the ID3D11On12Device just after the sample creates the ID3D12CommandQueue:

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));

Then, when the sample creates its render target views, I've added creation of the wrapped 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.
}

Then, after the rest of the D3D12 resources are created, I'm testing out ID3D11On12Device::AcquireWrappedResources() and ID3D11On12Device::ReleaseWrappedResources() (just as a test, to try to make the code as simple as possible)

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

So far, everything seems to be working as expected. The problem, however, occurs when resizing the window. In particular, resizing calls IDXGISwapChain3::ResizeBuffers(). When this occurs, ResizeBuffers() returns failure and the following message is displayed on the console:

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

I've tried clearing the m_wrappedBackBuffers references before ResizeBuffers():

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

but this seems to have no effect. I've also tried Flush()ing and ClearState()ing the ID3D11DeviceContext, but these seem to either have no effect or produce the following error:

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.

Commenting out the ID3D11On12Device::AcquireWrappedResources() and ID3D11On12Device::ReleaseWrappedResources() calls makes ResizeBuffers() return successfully; but it seems that calling these two functions is required to be able to use the library at all.

It seems that somewhere, the ID3D11On12Device or ID3D11DeviceContext is holding on to a reference to the swap chain buffers, but I haven't been able to find any documentation about how to reset this reference without destroying the entire device.

This issue on GitHub seems to be the same issue I'm having; however, the response involves "calling SetTarget(nullptr) on the D2D context" but I haven't touched Direct2D at all in this project (and the Visual Studio template already calls WaitForGpu() before IDXGISwapChain3::ResizeBuffers()).

Microsoft's sample doesn't include swap chain buffer resizing at all. Running the sample causes the swap chain to be stretched to fit the window.

I haven't found anything about resizing in Microsoft's documentation.

Litherum
  • 22,564
  • 3
  • 23
  • 27

1 Answers1

3

The problem you're having is that the AcquireWrappedResource and ReleaseWrappedResource methods end up queueing some work on the D3D11 immediate context. The semantics of D3D11On12 require that the Flush() API is explicitly invoked when you want to transition from D3D11 to D3D12, to ensure all queued commands are properly recorded in a D3D12 command list, which is then closed and submitted.

If I've understood your description correctly, and you're simply calling Acquire/Release once, after creating the wrapped resource, then your problem should be simply by calling Flush() after the Release(). This ensures that the commands which reference back buffer 0 are only submitted while back buffer 0 is the current back buffer of the swapchain, solving the error:

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]

Then, when you're ready to resize, follow the instructions in the "Cleaning Up" section of the D3D11On12 MSDN documentation:

  1. Release all references to the D3D11 resource, including any views that were created on it.
  2. Call ID3D11DeviceContext::Flush() on the immediate context.

Once you've done both of these things, you should be able to resize the swapchain without any lingering references, and without the final Flush() causing commands to be submitted at an inappropriate time.

  • Wow! It works! Thank you so much! I hope that bit about the Flush() requirement during a D3D11 -> D3D12 transition is in the documentation somewhere! Thanks again! :D – Litherum Dec 15 '15 at 08:36
  • From the MSDN page: "For interop, it’s important to understand how D3D11On12 interacts with the D3D12 objects that the app has created and provided. In order to ensure that work happens in the correct order, the D3D11 immediate context must be flushed before additional D3D12 work can be submitted to that queue." – SoldierOfLight Dec 15 '15 at 14:38
  • Hrm. It looks like there is still something missing. In particular, if I move the AcquireWrappedResources()/Release to the render function, and continually resize, the synchronization seems to not be quite right. Do you have any ideas? "An ID3D12DescriptorHeap object is being final-released before all GPU operations using the object have completed. This is invalid and can result in application instability. [ EXECUTION ERROR #921: OBJECT_DELETED_WHILE_STILL_IN_USE]" (Code is at https://github.com/litherum/Direct2DHelloWorld) – Litherum Dec 18 '15 at 06:44
  • I've got no clue. D3D11On12 shouldn't be able to cause that. The only descriptor heap I see that's being referenced in your app is the m_cbvHeap, which it looks like only gets created once, in CreateDeviceDependentResources. – SoldierOfLight Dec 31 '15 at 23:43
  • Thanks for looking into it! I suppose I'll file a bug at connect.microsoft.com :) – Litherum Jan 02 '16 at 06:12
  • This seems to be fixed now. – Litherum Feb 10 '19 at 05:42