diff --git a/src/Framework.cpp b/src/Framework.cpp index 14974a3b..1dc9fa21 100644 --- a/src/Framework.cpp +++ b/src/Framework.cpp @@ -586,57 +586,65 @@ void Framework::on_frame_d3d12() { m_mods->on_present(); } - if (FAILED(m_d3d12.cmd_allocator->Reset())) { - spdlog::error("[D3D12] Failed to reset command allocator"); + if (m_d3d12.cmd_ctxs.empty()) { return; } - m_d3d12.cmd_list->Reset(m_d3d12.cmd_allocator.Get(), nullptr); + auto& cmd_ctx = m_d3d12.cmd_ctxs[m_d3d12.cmd_ctx_index++ % m_d3d12.cmd_ctxs.size()]; - // Draw to our render target. - D3D12_RESOURCE_BARRIER barrier{}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = m_d3d12.get_rt(D3D12::RTV::IMGUI).Get(); - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; - m_d3d12.cmd_list->ResourceBarrier(1, &barrier); + if (cmd_ctx == nullptr) { + return; + } - float clear_color[]{0.0f, 0.0f, 0.0f, 0.0f}; - D3D12_CPU_DESCRIPTOR_HANDLE rts[1]{}; - m_d3d12.cmd_list->ClearRenderTargetView(m_d3d12.get_cpu_rtv(device, D3D12::RTV::IMGUI), clear_color, 0, nullptr); - rts[0] = m_d3d12.get_cpu_rtv(device, D3D12::RTV::IMGUI); - m_d3d12.cmd_list->OMSetRenderTargets(1, rts, FALSE, NULL); - m_d3d12.cmd_list->SetDescriptorHeaps(1, m_d3d12.srv_desc_heap.GetAddressOf()); - - ImGui::GetIO().BackendRendererUserData = m_d3d12.imgui_backend_datas[1]; - ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), m_d3d12.cmd_list.Get()); - - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - m_d3d12.cmd_list->ResourceBarrier(1, &barrier); - - // Draw to the back buffer. - auto swapchain = m_d3d12_hook->get_swap_chain(); - auto bb_index = swapchain->GetCurrentBackBufferIndex(); - barrier.Transition.pResource = m_d3d12.rts[bb_index].Get(); - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; - m_d3d12.cmd_list->ResourceBarrier(1, &barrier); - rts[0] = m_d3d12.get_cpu_rtv(device, (D3D12::RTV)bb_index); - m_d3d12.cmd_list->OMSetRenderTargets(1, rts, FALSE, NULL); - m_d3d12.cmd_list->SetDescriptorHeaps(1, m_d3d12.srv_desc_heap.GetAddressOf()); - - ImGui::GetIO().BackendRendererUserData = m_d3d12.imgui_backend_datas[0]; - ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), m_d3d12.cmd_list.Get()); - - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; - m_d3d12.cmd_list->ResourceBarrier(1, &barrier); - m_d3d12.cmd_list->Close(); - - command_queue->ExecuteCommandLists(1, (ID3D12CommandList* const*)m_d3d12.cmd_list.GetAddressOf()); + cmd_ctx->wait(INFINITE); + { + std::scoped_lock _{ cmd_ctx->mtx }; + cmd_ctx->has_commands = true; + + // Draw to our render target. + D3D12_RESOURCE_BARRIER barrier{}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = m_d3d12.get_rt(D3D12::RTV::IMGUI).Get(); + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; + cmd_ctx->cmd_list->ResourceBarrier(1, &barrier); + + float clear_color[]{0.0f, 0.0f, 0.0f, 0.0f}; + D3D12_CPU_DESCRIPTOR_HANDLE rts[1]{}; + cmd_ctx->cmd_list->ClearRenderTargetView(m_d3d12.get_cpu_rtv(device, D3D12::RTV::IMGUI), clear_color, 0, nullptr); + rts[0] = m_d3d12.get_cpu_rtv(device, D3D12::RTV::IMGUI); + cmd_ctx->cmd_list->OMSetRenderTargets(1, rts, FALSE, NULL); + cmd_ctx->cmd_list->SetDescriptorHeaps(1, m_d3d12.srv_desc_heap.GetAddressOf()); + + ImGui::GetIO().BackendRendererUserData = m_d3d12.imgui_backend_datas[1]; + ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), cmd_ctx->cmd_list.Get()); + + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + cmd_ctx->cmd_list->ResourceBarrier(1, &barrier); + + // Draw to the back buffer. + auto swapchain = m_d3d12_hook->get_swap_chain(); + auto bb_index = swapchain->GetCurrentBackBufferIndex(); + barrier.Transition.pResource = m_d3d12.rts[bb_index].Get(); + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; + cmd_ctx->cmd_list->ResourceBarrier(1, &barrier); + rts[0] = m_d3d12.get_cpu_rtv(device, (D3D12::RTV)bb_index); + cmd_ctx->cmd_list->OMSetRenderTargets(1, rts, FALSE, NULL); + cmd_ctx->cmd_list->SetDescriptorHeaps(1, m_d3d12.srv_desc_heap.GetAddressOf()); + + ImGui::GetIO().BackendRendererUserData = m_d3d12.imgui_backend_datas[0]; + ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), cmd_ctx->cmd_list.Get()); + + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + cmd_ctx->cmd_list->ResourceBarrier(1, &barrier); + + cmd_ctx->execute(); + } if (is_init_ok) { m_mods->on_post_frame(); @@ -1671,26 +1679,15 @@ bool Framework::init_d3d12() { spdlog::info("[D3D12] Creating command allocator..."); - if (FAILED(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_d3d12.cmd_allocator)))) { - spdlog::error("[D3D12] Failed to create command allocator."); - return false; - } - - m_d3d12.cmd_allocator->SetName(L"Framework::m_d3d12.cmd_allocator"); + m_d3d12.cmd_ctxs.clear(); - spdlog::info("[D3D12] Creating command list..."); + for (auto i = 0; i < 3; ++i) { + auto& ctx = m_d3d12.cmd_ctxs.emplace_back(std::make_unique()); - if (FAILED(device->CreateCommandList( - 0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_d3d12.cmd_allocator.Get(), nullptr, IID_PPV_ARGS(&m_d3d12.cmd_list)))) { - spdlog::error("[D3D12] Failed to create command list."); - return false; - } - - m_d3d12.cmd_list->SetName(L"Framework::m_d3d12.cmd_list"); - - if (FAILED(m_d3d12.cmd_list->Close())) { - spdlog::error("[D3D12] Failed to close command list after creation."); - return false; + if (!ctx->setup(L"Framework::m_d3d12.cmd_ctx")) { + spdlog::error("[D3D12] Failed to create command context."); + return false; + } } spdlog::info("[D3D12] Creating RTV descriptor heap..."); diff --git a/src/Framework.hpp b/src/Framework.hpp index ab0cf3aa..8d8225bd 100644 --- a/src/Framework.hpp +++ b/src/Framework.hpp @@ -12,6 +12,7 @@ #include #include +#include class Mods; @@ -307,8 +308,8 @@ class Framework { private: // D3D12 members struct D3D12 { - ComPtr cmd_allocator{}; - ComPtr cmd_list{}; + std::vector> cmd_ctxs{}; + uint32_t cmd_ctx_index{0}; enum class RTV : int{ BACKBUFFER_0,