#include "XCEngine/RHI/D3D12/D3D12CommandQueue.h" #include "XCEngine/RHI/D3D12/D3D12CommandList.h" #include "XCEngine/RHI/D3D12/D3D12Fence.h" #include namespace XCEngine { namespace RHI { D3D12CommandQueue::D3D12CommandQueue() : m_timestampFrequency(0) , m_type(CommandQueueType::Direct) { } D3D12CommandQueue::~D3D12CommandQueue() { Shutdown(); } bool D3D12CommandQueue::Initialize(ID3D12Device* device, CommandQueueType type) { D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = ToD3D12(type); queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.NodeMask = 0; HRESULT hResult = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue)); if (FAILED(hResult)) { return false; } hResult = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_frameFence)); if (FAILED(hResult)) { return false; } m_frameEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (!m_frameEvent) { return false; } m_type = type; m_commandQueue->GetTimestampFrequency(&m_timestampFrequency); return true; } void D3D12CommandQueue::Shutdown() { if (m_frameEvent) { CloseHandle(m_frameEvent); m_frameEvent = nullptr; } m_frameFence.Reset(); m_commandQueue.Reset(); } void D3D12CommandQueue::ExecuteCommandLists(uint32_t count, void** lists) { if (count == 0 || lists == nullptr) { return; } std::vector cmdLists(count); for (uint32_t i = 0; i < count; ++i) { auto* cmdList = static_cast(lists[i]); if (cmdList) { cmdList->Reset(); cmdLists[i] = cmdList->GetCommandList(); } } ExecuteCommandListsInternal(count, cmdLists.data()); } void D3D12CommandQueue::ExecuteCommandListsInternal(uint32_t count, ID3D12CommandList** lists) { if (!m_commandQueue || count == 0 || lists == nullptr) { return; } m_commandQueue->ExecuteCommandLists(count, lists); m_currentFrame++; if (m_frameFence) { m_commandQueue->Signal(m_frameFence.Get(), m_currentFrame); } } void D3D12CommandQueue::Signal(RHIFence* fence, uint64_t value) { if (fence) { m_commandQueue->Signal(static_cast(fence)->GetFence(), value); } } void D3D12CommandQueue::Signal(ID3D12Fence* fence, uint64_t value) { if (fence) { m_commandQueue->Signal(fence, value); } } void D3D12CommandQueue::Wait(RHIFence* fence, uint64_t value) { if (fence) { m_commandQueue->Wait(static_cast(fence)->GetFence(), value); } } void D3D12CommandQueue::Wait(ID3D12Fence* fence, uint64_t value) { if (fence) { m_commandQueue->Wait(fence, value); } } uint64_t D3D12CommandQueue::GetCompletedValue() { return 0; } void D3D12CommandQueue::WaitForIdle() { // Get the device from the command queue ID3D12Device* device = nullptr; HRESULT hr = m_commandQueue->GetDevice(IID_PPV_ARGS(&device)); if (SUCCEEDED(hr)) { // Create a fence to signal when queue is idle ID3D12Fence* fence = nullptr; hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); if (SUCCEEDED(hr)) { // Signal the fence m_commandQueue->Signal(fence, 1); // Wait for it to complete while (fence->GetCompletedValue() < 1) { Sleep(1); } fence->Release(); } device->Release(); } } void D3D12CommandQueue::WaitForPreviousFrame() { if (m_currentFrame > 0 && m_frameFence) { if (m_frameFence->GetCompletedValue() < m_currentFrame) { m_frameFence->SetEventOnCompletion(m_currentFrame, m_frameEvent); WaitForSingleObject(m_frameEvent, INFINITE); } } } } // namespace RHI } // namespace XCEngine