亲爱的 IMGUI 和 DirectX 12 覆盖 (DXGI_ERROR_INVALID_CALL)
Posted
技术标签:
【中文标题】亲爱的 IMGUI 和 DirectX 12 覆盖 (DXGI_ERROR_INVALID_CALL)【英文标题】:Dear IMGUI and DirectX 12 Overlay (DXGI_ERROR_INVALID_CALL) 【发布时间】:2020-08-27 12:07:26 【问题描述】:我正在尝试使用 Dear IMGUI 为 DirectX 12 游戏制作一个简单的帧计数器。我只是想覆盖一个小的透明窗口,在游戏过程中显示帧的顺序。为此,我挂钩 Present(),因此我可以获得SwapChain
,并计算该方法被调用的次数(帧计数)。 这不是作弊。我不是为游戏写作弊,我只是想记录帧数以用于分析目的。
我已使用此处提供的 ShowExampleAppSimpleOverlay()
示例成功为 DirectX 11 完成此操作:https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp
这是一个显示 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, ¤tFrameContext.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);
【问题讨论】:
【参考方案1】:DXGI_ERROR_INVALID_CALL 告诉列表中的一个命令无效,但不是哪个。 您需要在创建命令列表时使用 d3d12 调试层进行运行时检查。 调试层也会告诉你无效的原因。 请参阅msdn 了解更多信息。
您可以使用以下代码激活它,但需要在创建设备之前调用它
ID3D12Debug* debugInterface;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface))))
debugInterface->EnableDebugLayer();
【讨论】:
以上是关于亲爱的 IMGUI 和 DirectX 12 覆盖 (DXGI_ERROR_INVALID_CALL)的主要内容,如果未能解决你的问题,请参考以下文章