c++ - 亲爱的 IMGUI 和 DirectX 12 覆盖 (DXGI_ERROR_INVALID_CALL)

标签 c++ directx-12 imgui

我正在尝试使用 Dear IMGUI 为 DirectX 12 游戏制作一个简单的帧计数器。我只是想覆盖一个小的透明窗口,在游戏过程中显示帧的顺序。为此,我 Hook Present(),所以我可以得到 SwapChain ,并计算该方法被调用的次数(帧计数)。 这不是为了作弊。 我不是为游戏写秘籍,我只是想记录帧数以用于分析目的。
我已经使用 ShowExampleAppSimpleOverlay() 为 DirectX 11 成功完成了此操作。此处提供的示例:https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp
这是一个显示 DX 11 游戏中的帧计数器的图像示例。
An example of the frame counter in DX 11
我现在正尝试对 DirectX 12 做同样的事情。 Hook 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了解更多信息。
您可以使用以下代码激活它,但需要在创 build 备之前调用它

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

关于c++ - 亲爱的 IMGUI 和 DirectX 12 覆盖 (DXGI_ERROR_INVALID_CALL),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63615630/

相关文章:

c++ - Visual Studio SFML 教程图形显示不正确

textures - 共享 ID3D11Buffer 和 ID3D12Resource

c++ - 在D3D12中绘制多个对象

c++ - D3D12CreateDevice 抛出 _com_error

c++ - 什么是 undefined reference /未解析的外部符号错误,我该如何解决?

c++ - winapi 从函数的地址中获取损坏的名称

c++ - 如果没有未定义的行为 [c++],哪些浮点值不能转换为 int?

java - Java 和 C 之间的代码点不匹配

c++ - 亲爱的 ImGui 窗口适合背景