Дополнительная ссылка на буфер цепочки подкачки в ID3D11On12Device::AcquireWrappedResources()

Я заинтересован в использовании " Direct 3D 11 на 12-дюймовой библиотеке, но у меня возникают проблемы при изменении размера окна. В частности, я модифицирую образец приложения DirectX 12 для Visual Studio.

Я создаю ID3D11On12Device сразу после того, как пример создает 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));

Затем, когда образец создает свои целевые представления рендеринга, я добавил создание обернутого 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: ]

Я пытался очистить ссылки m_wrappedBackBuffers перед ResizeBuffers():

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

но это, кажется, не имеет никакого эффекта. Я также пробовал использовать Flush() и ClearState() для ID3D11DeviceContext, но они, похоже, либо не имеют никакого эффекта, либо вызывают следующую ошибку:

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 удерживает ссылку на буферы цепочки подкачки, но мне не удалось найти никакой документации о том, как сбросить эту ссылку, не разрушая все устройство.

Эта проблема на GitHub кажется той же проблемой, что и у меня; однако ответ включает «вызов SetTarget(nullptr) в контексте D2D», но я вообще не касался Direct2D в этом проекте (и шаблон Visual Studio уже вызывает WaitForGpu() до IDXGISwapChain3::ResizeBuffers()).

пример от Microsoft не включает буфер цепочки подкачки изменение размера вообще. Запуск примера приводит к тому, что цепочка обмена растягивается, чтобы соответствовать окну.

Я не нашел ничего об изменении размера в Microsoft документация.


person Litherum    schedule 13.12.2015    source источник


Ответы (1)


Проблема, с которой вы столкнулись, заключается в том, что методы AcquireWrappedResource и ReleaseWrappedResource в конечном итоге ставят в очередь некоторую работу в непосредственном контексте D3D11. Семантика D3D11On12 требует, чтобы Flush() API вызывался явно, когда вы хотите перейти от D3D11 к D3D12, чтобы убедиться, что все команды в очереди правильно записаны в список команд D3D12, который затем закрывается и отправляется.

Если я правильно понял ваше описание, и вы просто вызываете Acquire/Release один раз после создания обернутого ресурса, тогда ваша проблема должна заключаться в простом вызове Flush() после Release(). Это гарантирует, что команды, которые ссылаются на задний буфер 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:

  1. Освободите все ссылки на ресурс D3D11, включая все созданные на нем представления.
  2. Вызовите ID3D11DeviceContext::Flush() в непосредственном контексте.

После того, как вы сделаете обе эти вещи, вы сможете изменить размер цепочки обмена без каких-либо устаревших ссылок и без окончательного Flush(), вызывающего отправку команд в неподходящее время.

person SoldierOfLight    schedule 15.12.2015
comment
Ух ты! Оно работает! Большое спасибо! Я надеюсь, что часть о требовании Flush() во время перехода D3D11 -> D3D12 есть где-нибудь в документации! Спасибо еще раз! :D - person Litherum; 15.12.2015
comment
Со страницы MSDN: для взаимодействия важно понимать, как D3D11On12 взаимодействует с объектами D3D12, созданными и предоставленными приложением. Чтобы гарантировать, что работа выполняется в правильном порядке, непосредственный контекст D3D11 должен быть очищен до того, как дополнительная работа D3D12 может быть отправлена ​​в эту очередь. - person SoldierOfLight; 15.12.2015
comment
Хрм. Похоже, что еще чего-то не хватает. В частности, если я перемещаю AcquireWrappedResources()/Release в функцию рендеринга и постоянно изменяю размер, синхронизация кажется не совсем правильной. У тебя есть идеи? Объект ID3D12DescriptorHeap окончательно выпускается до завершения всех операций графического процессора, использующих этот объект. Это недопустимо и может привести к нестабильности приложения. [ОШИБКА ВЫПОЛНЕНИЯ #921: OBJECT_DELETED_WHILE_STILL_IN_USE] (Код находится по адресу github.com/litherum/Direct2DHelloWorld) - person Litherum; 18.12.2015
comment
Я понятия не имею. D3D11On12 не должен быть причиной этого. Единственная куча дескрипторов, на которую я вижу ссылку в вашем приложении, — это m_cbvHeap, которая, похоже, создается только один раз в CreateDeviceDependentResources. - person SoldierOfLight; 01.01.2016
comment
Спасибо, что заглянули! Думаю, я напишу об ошибке на connect.microsoft.com :) - person Litherum; 02.01.2016
comment
Кажется, сейчас это исправлено. - person Litherum; 10.02.2019