- CommandQueue::ExecuteCommandLists: fix type conversion from void** to ID3D12CommandList**, reset command list before execution, add null checks - SwapChain::ShouldClose: add m_shouldClose member and implement getter/setter - SwapChain::SetFullscreen: add m_fullscreen member to track state locally
142 lines
3.9 KiB
C++
142 lines
3.9 KiB
C++
#include "XCEngine/RHI/D3D12/D3D12CommandQueue.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12CommandList.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12Fence.h"
|
|
#include <vector>
|
|
|
|
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<ID3D12CommandList*> cmdLists(count);
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
auto* cmdList = static_cast<D3D12CommandList*>(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<D3D12Fence*>(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<D3D12Fence*>(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
|