尊敬的IMGUI和DirectX 12叠加层DXGI_ERROR_INVALID_CALL

问题描述

我正在尝试使用Dear IMGUI为DirectX 12游戏制作一个简单的帧计数器。我只想覆盖一个小的透明窗口,该窗口在游戏过程中显示帧的顺序。为此,我钩上Present(),这样我就可以获得SwapChain,并计算该方法调用次数(帧计数)。 这不是骗子。我不是在为游戏编写作弊工具,我只是想记录帧号以供分析。

我已经使用https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp

中提供的ShowExampleAppSimpleOverlay()示例为DirectX 11成功完成了此操作

这是显示DX 11游戏中帧计数器的图像样本。

An example of the frame counter in DX 11

我现在正在尝试对DirectX 12进行同样的操作。钩住Present()并不是问题。

使用此处提供的示例代码https://github.com/ocornut/imgui/blob/master/examples/example_win32_directx12/main.cpp

我尝试再次使用ShowExampleAppSimpleOverlay()方法,但是在我对d3d12CommandQueue->ExecuteCommandLists(1,(ID3D12CommandList* const*)&d3d12CommandList);进行调用代码(以呈现叠加层)中,它导致错误提示(0x887A0001: dxgi_ERROR_INVALID_CALL)。这是下面提供的代码示例中的最后一行代码

我不确定如何继续。有什么想法吗?

编辑:我忘了提一下,我也很着迷并获得游戏命令que。因此d3d12CommandQueue是直接从游戏中获取的。它不返回NULL,所以我假设它是正确的对象。我可能是错的...

对于Present()的每次调用,请执行以下操作:

//iterate frame
Frame_Number = Frame_Number + 1;

//Get Device,using IdxgiSwapChain3
ID3D12Device* device;
HRESULT gd = pSwapChain->GetDevice(__uuidof(ID3D12Device),(void**)&device);
assert(gd == S_OK);

//Get window handle from swapchain for IMGUI
dxgi_SWAP_CHAIN_DESC sd;
pSwapChain->GetDesc(&sd);
window = sd.Outputwindow;

//Get backbuffers
buffersCounts = sd.BufferCount;
frameContext = new FrameContext[buffersCounts];

D3D12_DESCRIPTOR_HEAP_DESC descriptorImGuiRender = {};
descriptorImGuiRender.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
descriptorImGuiRender.NumDescriptors = buffersCounts;
descriptorImGuiRender.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;

// Create Descriptor Heap IMGUI render
if (device->CreateDescriptorHeap(&descriptorImGuiRender,IID_PPV_ARGS(&d3d12DescriptorHeapImGuiRender)) != S_OK)
    return false;

//Create Command Allocator
ID3D12CommandAllocator* allocator;
if (device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,IID_PPV_ARGS(&allocator)) != S_OK)
    return false;

for (size_t i = 0; i < buffersCounts; i++) {
    frameContext[i].commandAllocator = allocator;
}

if (device->CreateCommandList(0,D3D12_COMMAND_LIST_TYPE_DIRECT,allocator,NULL,IID_PPV_ARGS(&d3d12CommandList)) != S_OK ||
    d3d12CommandList->Close() != S_OK)
    return false;

//create descriptor heap,describe and create a render target view (RTV) descriptor heap.
D3D12_DESCRIPTOR_HEAP_DESC descriptorBackBuffers;
descriptorBackBuffers.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
descriptorBackBuffers.NumDescriptors = buffersCounts;
descriptorBackBuffers.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
descriptorBackBuffers.NodeMask = 1;

if (device->CreateDescriptorHeap(&descriptorBackBuffers,IID_PPV_ARGS(&d3d12DescriptorHeapBackBuffers)) != S_OK)
    return false;
const auto rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);

// Create frame resources.
D3D12_cpu_DESCRIPTOR_HANDLE rtvHandle = d3d12DescriptorHeapBackBuffers->GetcpuDescriptorHandleForHeapStart();

// Create a RTV for each frame.
for (size_t i = 0; i < buffersCounts; i++) {
    ID3D12Resource* pBackBuffer = nullptr;

    frameContext[i].main_render_target_descriptor = rtvHandle;
    pSwapChain->GetBuffer(i,IID_PPV_ARGS(&pBackBuffer));
    device->CreaterendertargetView(pBackBuffer,nullptr,rtvHandle);
    frameContext[i].main_render_target_resource = pBackBuffer;
    rtvHandle.ptr += rtvDescriptorSize;
}

// Setup Platform/Renderer bindings dor IMGUI
ImGui_ImplWin32_Init(window);
ImGui_ImplDX12_Init(device,buffersCounts,dxgi_FORMAT_R8G8B8A8_UnorM,d3d12DescriptorHeapImGuiRender,d3d12DescriptorHeapImGuiRender->GetcpuDescriptorHandleForHeapStart(),d3d12DescriptorHeapImGuiRender->GetGPUDescriptorHandleForHeapStart());
ImGui::GetIO().ImeWindowHandle = window;

// Start the Dear ImGui frame
ImGui_ImplDX12_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();

//call imgui menues here
bool bShow = true;
ShowExampleAppSimpleOverlay(&bShow);

// Rendering (imgui)
FrameContext& currentFrameContext = frameContext[pSwapChain->GetCurrentBackBufferIndex()];
currentFrameContext.commandAllocator->Reset();

D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = currentFrameContext.main_render_target_resource;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;

d3d12CommandList->Reset(currentFrameContext.commandAllocator,nullptr);
d3d12CommandList->ResourceBarrier(1,&barrier);
d3d12CommandList->OMSetrendertargets(1,&currentFrameContext.main_render_target_descriptor,FALSE,nullptr);

d3d12CommandList->SetDescriptorHeaps(1,&d3d12DescriptorHeapImGuiRender);

ImGui::Render();
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(),d3d12CommandList);

barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;

d3d12CommandList->ResourceBarrier(1,&barrier);
d3d12CommandList->Close();

d3d12CommandQueue->ExecuteCommandLists(1,(ID3D12CommandList* const*)&d3d12CommandList);

解决方法

DXGI_ERROR_INVALID_CALL告知列表中的一个命令无效,但无效。
您需要在创建命令列表时使用d3d12调试层进行运行时检查。 调试层还会告诉您它无效的原因。
有关更多信息,请参见msdn

您可以使用以下代码来吸引它,但是需要在创建设备之前调用它

ID3D12Debug* debugInterface;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface)))) {
    debugInterface->EnableDebugLayer();
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...