refactor: encapsulate frame fence synchronization in CommandQueue
- Add WaitForPreviousFrame() and GetCurrentFrame() to RHICommandQueue interface - D3D12CommandQueue now manages frame fence internally - ExecuteCommandLists automatically signals fence after command execution - OpenGLCommandQueue provides stub implementations for interface compliance - Minimal test now uses CommandQueue::WaitForPreviousFrame() instead of manual fence
This commit is contained in:
@@ -38,10 +38,16 @@ public:
|
|||||||
void Signal(ID3D12Fence* fence, uint64_t value);
|
void Signal(ID3D12Fence* fence, uint64_t value);
|
||||||
void Wait(ID3D12Fence* fence, uint64_t value);
|
void Wait(ID3D12Fence* fence, uint64_t value);
|
||||||
|
|
||||||
|
void WaitForPreviousFrame();
|
||||||
|
uint64_t GetCurrentFrame() const { return m_currentFrame; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ComPtr<ID3D12CommandQueue> m_commandQueue;
|
ComPtr<ID3D12CommandQueue> m_commandQueue;
|
||||||
CommandQueueType m_type;
|
CommandQueueType m_type;
|
||||||
uint64_t m_timestampFrequency;
|
uint64_t m_timestampFrequency;
|
||||||
|
ComPtr<ID3D12Fence> m_frameFence;
|
||||||
|
uint64_t m_currentFrame = 0;
|
||||||
|
void* m_frameEvent = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace RHI
|
} // namespace RHI
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ public:
|
|||||||
uint64_t GetTimestampFrequency() const override { return 0; }
|
uint64_t GetTimestampFrequency() const override { return 0; }
|
||||||
|
|
||||||
void* GetNativeHandle() override { return nullptr; }
|
void* GetNativeHandle() override { return nullptr; }
|
||||||
|
void WaitForPreviousFrame() override {}
|
||||||
|
uint64_t GetCurrentFrame() const override { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace RHI
|
} // namespace RHI
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ public:
|
|||||||
virtual uint64_t GetTimestampFrequency() const = 0;
|
virtual uint64_t GetTimestampFrequency() const = 0;
|
||||||
|
|
||||||
virtual void* GetNativeHandle() = 0;
|
virtual void* GetNativeHandle() = 0;
|
||||||
|
virtual void WaitForPreviousFrame() = 0;
|
||||||
|
virtual uint64_t GetCurrentFrame() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace RHI
|
} // namespace RHI
|
||||||
|
|||||||
@@ -27,12 +27,27 @@ bool D3D12CommandQueue::Initialize(ID3D12Device* device, CommandQueueType type)
|
|||||||
return false;
|
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_type = type;
|
||||||
m_commandQueue->GetTimestampFrequency(&m_timestampFrequency);
|
m_commandQueue->GetTimestampFrequency(&m_timestampFrequency);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12CommandQueue::Shutdown() {
|
void D3D12CommandQueue::Shutdown() {
|
||||||
|
if (m_frameEvent) {
|
||||||
|
CloseHandle(m_frameEvent);
|
||||||
|
m_frameEvent = nullptr;
|
||||||
|
}
|
||||||
|
m_frameFence.Reset();
|
||||||
m_commandQueue.Reset();
|
m_commandQueue.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +57,8 @@ void D3D12CommandQueue::ExecuteCommandLists(uint32_t count, void** lists) {
|
|||||||
|
|
||||||
void D3D12CommandQueue::ExecuteCommandListsInternal(uint32_t count, ID3D12CommandList** lists) {
|
void D3D12CommandQueue::ExecuteCommandListsInternal(uint32_t count, ID3D12CommandList** lists) {
|
||||||
m_commandQueue->ExecuteCommandLists(count, lists);
|
m_commandQueue->ExecuteCommandLists(count, lists);
|
||||||
|
m_currentFrame++;
|
||||||
|
m_commandQueue->Signal(m_frameFence.Get(), m_currentFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12CommandQueue::Signal(RHIFence* fence, uint64_t value) {
|
void D3D12CommandQueue::Signal(RHIFence* fence, uint64_t value) {
|
||||||
@@ -93,5 +110,14 @@ void D3D12CommandQueue::WaitForIdle() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 RHI
|
||||||
} // namespace XCEngine
|
} // namespace XCEngine
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ D3D12CommandQueue gCommandQueue;
|
|||||||
D3D12SwapChain gSwapChain;
|
D3D12SwapChain gSwapChain;
|
||||||
D3D12CommandAllocator gCommandAllocator;
|
D3D12CommandAllocator gCommandAllocator;
|
||||||
D3D12CommandList gCommandList;
|
D3D12CommandList gCommandList;
|
||||||
D3D12Fence gFence;
|
|
||||||
|
|
||||||
// Render targets
|
// Render targets
|
||||||
D3D12Texture gColorRTs[2];
|
D3D12Texture gColorRTs[2];
|
||||||
@@ -55,7 +54,6 @@ D3D12DepthStencilView gDSV;
|
|||||||
UINT gRTVDescriptorSize = 0;
|
UINT gRTVDescriptorSize = 0;
|
||||||
UINT gDSVDescriptorSize = 0;
|
UINT gDSVDescriptorSize = 0;
|
||||||
int gCurrentRTIndex = 0;
|
int gCurrentRTIndex = 0;
|
||||||
UINT64 gFenceValue = 0;
|
|
||||||
|
|
||||||
// Window
|
// Window
|
||||||
HWND gHWND = nullptr;
|
HWND gHWND = nullptr;
|
||||||
@@ -162,9 +160,6 @@ bool InitD3D12() {
|
|||||||
gCommandAllocator.Initialize(device, CommandQueueType::Direct);
|
gCommandAllocator.Initialize(device, CommandQueueType::Direct);
|
||||||
gCommandList.Initialize(device, CommandQueueType::Direct, gCommandAllocator.GetCommandAllocator());
|
gCommandList.Initialize(device, CommandQueueType::Direct, gCommandAllocator.GetCommandAllocator());
|
||||||
|
|
||||||
// Create fence
|
|
||||||
gFence.Initialize(device, 0);
|
|
||||||
|
|
||||||
Log("[INFO] D3D12 initialized successfully");
|
Log("[INFO] D3D12 initialized successfully");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -179,8 +174,6 @@ void ExecuteCommandList() {
|
|||||||
gCommandList.Close();
|
gCommandList.Close();
|
||||||
void* commandLists[] = { gCommandList.GetCommandList() };
|
void* commandLists[] = { gCommandList.GetCommandList() };
|
||||||
gCommandQueue.ExecuteCommandLists(1, commandLists);
|
gCommandQueue.ExecuteCommandLists(1, commandLists);
|
||||||
gFenceValue += 1;
|
|
||||||
gCommandQueue.Signal(gFence.GetFence(), gFenceValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin rendering
|
// Begin rendering
|
||||||
@@ -277,7 +270,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
} else {
|
} else {
|
||||||
// Wait for previous frame to complete before resetting
|
// Wait for previous frame to complete before resetting
|
||||||
if (frameCount > 0) {
|
if (frameCount > 0) {
|
||||||
gFence.Wait(gFenceValue);
|
gCommandQueue.WaitForPreviousFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset command list for this frame
|
// Reset command list for this frame
|
||||||
@@ -324,7 +317,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
// Shutdown
|
// Shutdown
|
||||||
gCommandList.Shutdown();
|
gCommandList.Shutdown();
|
||||||
gCommandAllocator.Shutdown();
|
gCommandAllocator.Shutdown();
|
||||||
gFence.Shutdown();
|
|
||||||
gSwapChain.Shutdown();
|
gSwapChain.Shutdown();
|
||||||
gDevice.Shutdown();
|
gDevice.Shutdown();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user