Files
LookingGlass/idd/LGIdd/CD3D12CommandQueue.h
Geoffrey McRae aa289fa022 [client/host/idd] correct frame timing attribution
Use calibrated copy-queue timestamps to separate source and effect
waits from the actual framebuffer copy.

Exclude producer readiness waits from client import timing so the
same interval is not counted in both Copy and Import.
2026-08-03 23:53:33 +10:00

126 lines
3.9 KiB
C++

/**
* Looking Glass
* Copyright © 2017-2026 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma once
#include <Windows.h>
#include <wdf.h>
#include <wrl.h>
#include <d3d12.h>
#include <atomic>
#include <stdint.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace Microsoft::WRL::Wrappers::HandleTraits;
class CD3D12CommandQueue
{
private:
const WCHAR * m_name = nullptr;
ComPtr<ID3D12CommandQueue > m_queue;
ComPtr<ID3D12CommandAllocator > m_allocator;
ComPtr<ID3D12GraphicsCommandList> m_gfxList;
ComPtr<ID3D12CommandList > m_cmdList;
ComPtr<ID3D12Fence > m_fence;
ComPtr<ID3D12QueryHeap> m_timestampHeap;
ComPtr<ID3D12Resource > m_timestampReadback;
UINT64 * m_timestampMap = nullptr;
UINT64 m_timestampFrequency = 0;
UINT64 m_calibrationGPU = 0;
UINT64 m_calibrationCPU = 0;
UINT64 m_qpcFrequency = 0;
bool m_timingSupported = false;
bool m_timingActive = false;
std::atomic<bool> m_pending = false;
HandleT<HANDLENullTraits> m_event;
HANDLE m_waitHandle = INVALID_HANDLE_VALUE;
UINT64 m_fenceValue = 0;
bool m_needsReset = false;
typedef void (*CompletionFunction)(CD3D12CommandQueue * queue,
bool result, void * param1, void * param2);
CompletionFunction m_completionCallback = nullptr;
void * m_completionParams[2];
bool m_completionResult = true;
bool InitTiming(ID3D12Device3 * device, D3D12_COMMAND_LIST_TYPE type);
void UpdateClockCalibration();
void OnCompletion()
{
if (m_completionCallback)
m_completionCallback(
this,
m_completionResult,
m_completionParams[0],
m_completionParams[1]);
UpdateClockCalibration();
m_pending = false;
}
public:
~CD3D12CommandQueue() { DeInit(); }
enum CallbackMode
{
DISABLED, // no callbacks
FAST, // callback is expected to return almost immediately
NORMAL // normal callback
};
bool Init(ID3D12Device3 * device, D3D12_COMMAND_LIST_TYPE type, const WCHAR * name,
CallbackMode callbackMode = DISABLED);
void DeInit();
void SetCompletionCallback(CompletionFunction fn, void * param1, void * param2)
{
m_completionCallback = fn;
m_completionParams[0] = param1;
m_completionParams[1] = param2;
}
bool Reset();
bool Execute();
bool BeginTiming();
void EndTiming();
// Return the command-list start in QueryPerformanceCounter-domain ns.
bool GetGPUStartTime(uint64_t& start);
//void Wait();
bool IsReady () const { return !m_pending ; }
HANDLE GetEvent() const { return m_event.Get(); }
void WaitFor(CD3D12CommandQueue& queue)
{
m_queue->Wait(queue.m_fence.Get(), queue.m_fenceValue);
}
ComPtr<ID3D12CommandQueue > GetCmdQueue() { return m_queue; }
ComPtr<ID3D12GraphicsCommandList> GetGfxList() { return m_gfxList; }
};