如何从交换链获取DirectX 12命令队列

如何从交换链获取DirectX 12命令队列,directx,directx-12,Directx,Directx 12,假设DX12被挂接用于覆盖渲染,那么最好的挂接函数是IDXGISwapChain::Present,与DX11的挂接方式相同。将此功能挂接后,交换链可用,并且可以从中检索设备以创建资源。有了这些资源,也可以记录渲染命令。当我们尝试执行渲染命令时,会出现问题,因为没有从交换链检索关联命令队列的选项,因此没有类似的选项: CComPtr<ID3D12Device> pD3D12Device; if (pSwapChain->GetDevice(__uuidof(ID3D12Devi

假设DX12被挂接用于覆盖渲染,那么最好的挂接函数是IDXGISwapChain::Present,与DX11的挂接方式相同。将此功能挂接后,交换链可用,并且可以从中检索设备以创建资源。有了这些资源,也可以记录渲染命令。当我们尝试执行渲染命令时,会出现问题,因为没有从交换链检索关联命令队列的选项,因此没有类似的选项:

CComPtr<ID3D12Device> pD3D12Device;
if (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)
{
    pD3D12Device->GetCommandQueueForSwapChain( swapChain )->ExecuteCommandLists(…);
}
CComPtr<ID3D12Device> pD3D12Device;
if (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)
{
    D3D12_COMMAND_QUEUE_DESC queue_desc = {};
    queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
    queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
    HRESULT commandQueueRes = _device->CreateCommandQueue( &queue_desc, IID_PPV_ARGS( &_commandQueue ) );

    _commandQueue->ExecuteCommandLists( ... );
}
#ifdef _M_X64
    size_t* pOffset = (size_t*)((BYTE*)swapChain + 216);
#else
    size_t* pOffset = (size_t*)((BYTE*)swapChain + 132);
#endif
    *(&_commandQueue) = reinterpret_cast<ID3D12CommandQueue*>(*pOffset);
CComPtr pd3d12设备;
如果(pSwapChain->GetDevice(u uuidof(ID3D12Device),(void**)(&pD3D12Device))==S_确定)
{
pD3D12Device->GetCommandQueueForSwapChain(swapChain)->ExecuteCommandList(…);
}
另一个选项是创建要在其上执行的新命令队列,如下所示:

CComPtr<ID3D12Device> pD3D12Device;
if (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)
{
    pD3D12Device->GetCommandQueueForSwapChain( swapChain )->ExecuteCommandLists(…);
}
CComPtr<ID3D12Device> pD3D12Device;
if (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)
{
    D3D12_COMMAND_QUEUE_DESC queue_desc = {};
    queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
    queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
    HRESULT commandQueueRes = _device->CreateCommandQueue( &queue_desc, IID_PPV_ARGS( &_commandQueue ) );

    _commandQueue->ExecuteCommandLists( ... );
}
#ifdef _M_X64
    size_t* pOffset = (size_t*)((BYTE*)swapChain + 216);
#else
    size_t* pOffset = (size_t*)((BYTE*)swapChain + 132);
#endif
    *(&_commandQueue) = reinterpret_cast<ID3D12CommandQueue*>(*pOffset);
CComPtr pd3d12设备;
如果(pSwapChain->GetDevice(u uuidof(ID3D12Device),(void**)(&pD3D12Device))==S_确定)
{
D3D12_命令_队列_描述队列_描述={};
queue_desc.Flags=D3D12_命令_队列_标志_无;
queue_desc.Type=D3D12_COMMAND_LIST_Type_DIRECT;
HRESULT commandQueueRes=\u device->CreateCommandQueue(&queue\u desc,IID\u PPV\u ARGS(&u commandQueue));
_命令队列->执行命令列表(…);
}
这将导致错误和随后的设备删除。请参阅下面的错误消息

D3D12错误:ID3D12CommandQueue::ExecuteCommandLists:写入交换链回缓冲区的命令列表只能在与该缓冲区关联的命令队列上执行。[状态设置错误907:EXECUTECOMMANDLISTS错误SwapChainBufferReference]

即使ID3D12CommandQueue::ExecuteCommandLists也被钩住,问题也没有得到解决,因为也无法从命令队列检索关联的交换链


因此,我的问题是,在交换链创建发生在挂钩可能发生之前的情况下,建议采用什么方法来处理此问题?

如果有人在寻找答案,我发现了以下内容。 没有官方的方法可以做到这一点,对于叠加渲染,推荐的方法是使用DirectComposition,但这会对性能产生影响,这对于游戏叠加来说不是很好

稍微研究一下内存,有一种可能的解决方案,可以通过如下方式从交换链获取CommandQueue:

CComPtr<ID3D12Device> pD3D12Device;
if (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)
{
    pD3D12Device->GetCommandQueueForSwapChain( swapChain )->ExecuteCommandLists(…);
}
CComPtr<ID3D12Device> pD3D12Device;
if (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)
{
    D3D12_COMMAND_QUEUE_DESC queue_desc = {};
    queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
    queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
    HRESULT commandQueueRes = _device->CreateCommandQueue( &queue_desc, IID_PPV_ARGS( &_commandQueue ) );

    _commandQueue->ExecuteCommandLists( ... );
}
#ifdef _M_X64
    size_t* pOffset = (size_t*)((BYTE*)swapChain + 216);
#else
    size_t* pOffset = (size_t*)((BYTE*)swapChain + 132);
#endif
    *(&_commandQueue) = reinterpret_cast<ID3D12CommandQueue*>(*pOffset);
#ifdef_M_X64
size_t*pOffset=(size_t*)((字节*)交换链+216);
#否则
size_t*pOffset=(size_t*)((字节*)交换链+132);
#恩迪夫
*(&_commandQueue)=重新解释强制转换(*pOffset);
显然,不建议使用此解决方案,但如果有人只是想进行一些调试,那么它可能会很有用


我的最终解决方案是挂接到一个使用CommandQueue(我使用ExecuteCommandList)的函数中,并在那里获取指针,稍后使用它来呈现覆盖。这并不完全令人满意,但只要没有多个交换链,它就可以工作。

我没有解决方案,如果您无法钩住创建,最好的办法是钩住工厂交换链,插入
SetPrivateData
,以便稍后检索值。您还需要挂接ResizeBuffer1,因为它可以更改命令队列,甚至可以关联swapchain中每个缓冲区的命令列表。正如我提到的,挂接swapchain创建不是一个选项,因为它可以发生在挂接之前。谢谢你提到ResizeBuffer1,我知道它,但是如果将来有人读到这个话题,把它放在这里很好。