mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-04 06:12:04 +00:00
[host] measure ready time at framebuffer publication
Exclude command queue reset and cleanup from the ready stage, and keep the wall-clock residual only as the legacy timing fallback.
This commit is contained in:
@@ -56,7 +56,7 @@ bool CD3D12CommandQueue::InitTiming(ID3D12Device3 * device,
|
||||
|
||||
D3D12_QUERY_HEAP_DESC queryDesc = {};
|
||||
queryDesc.Type = D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP;
|
||||
queryDesc.Count = 1;
|
||||
queryDesc.Count = 2;
|
||||
|
||||
hr = device->CreateQueryHeap(&queryDesc, IID_PPV_ARGS(&m_timestampHeap));
|
||||
if (FAILED(hr))
|
||||
@@ -71,7 +71,7 @@ bool CD3D12CommandQueue::InitTiming(ID3D12Device3 * device,
|
||||
|
||||
D3D12_RESOURCE_DESC resourceDesc = {};
|
||||
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
resourceDesc.Width = sizeof(UINT64);
|
||||
resourceDesc.Width = sizeof(UINT64) * 2;
|
||||
resourceDesc.Height = 1;
|
||||
resourceDesc.DepthOrArraySize = 1;
|
||||
resourceDesc.MipLevels = 1;
|
||||
@@ -91,7 +91,7 @@ bool CD3D12CommandQueue::InitTiming(ID3D12Device3 * device,
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D12_RANGE readRange = { 0, sizeof(UINT64) };
|
||||
D3D12_RANGE readRange = { 0, sizeof(UINT64) * 2 };
|
||||
void * timestampMap = nullptr;
|
||||
hr = m_timestampReadback->Map(0, &readRange, ×tampMap);
|
||||
if (FAILED(hr))
|
||||
@@ -298,37 +298,47 @@ void CD3D12CommandQueue::EndTiming()
|
||||
if (!m_timingActive)
|
||||
return;
|
||||
|
||||
m_gfxList->EndQuery(
|
||||
m_timestampHeap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, 1);
|
||||
m_gfxList->ResolveQueryData(
|
||||
m_timestampHeap.Get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
0, 1, m_timestampReadback.Get(), 0);
|
||||
0, 2, m_timestampReadback.Get(), 0);
|
||||
}
|
||||
|
||||
bool CD3D12CommandQueue::GetGPUStartTime(uint64_t& start)
|
||||
bool CD3D12CommandQueue::ConvertGPUTimestamp(
|
||||
UINT64 timestamp, uint64_t& result) const
|
||||
{
|
||||
if (!m_timingActive)
|
||||
return false;
|
||||
|
||||
const UINT64 gpuStart = m_timestampMap[0];
|
||||
|
||||
UINT64 cpuStart;
|
||||
if (gpuStart < m_calibrationGPU)
|
||||
UINT64 cpuTimestamp;
|
||||
if (timestamp < m_calibrationGPU)
|
||||
{
|
||||
const UINT64 delta = ScaleTicks(
|
||||
m_calibrationGPU - gpuStart, m_qpcFrequency, m_timestampFrequency);
|
||||
m_calibrationGPU - timestamp, m_qpcFrequency, m_timestampFrequency);
|
||||
if (delta > m_calibrationCPU)
|
||||
return false;
|
||||
cpuStart = m_calibrationCPU - delta;
|
||||
cpuTimestamp = m_calibrationCPU - delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
const UINT64 delta = ScaleTicks(
|
||||
gpuStart - m_calibrationGPU, m_qpcFrequency, m_timestampFrequency);
|
||||
timestamp - m_calibrationGPU, m_qpcFrequency, m_timestampFrequency);
|
||||
if (UINT64_MAX - m_calibrationCPU < delta)
|
||||
return false;
|
||||
cpuStart = m_calibrationCPU + delta;
|
||||
cpuTimestamp = m_calibrationCPU + delta;
|
||||
}
|
||||
|
||||
start = TicksToNanoseconds(cpuStart, m_qpcFrequency);
|
||||
result = TicksToNanoseconds(cpuTimestamp, m_qpcFrequency);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CD3D12CommandQueue::GetGPUTimes(
|
||||
uint64_t& start, uint64_t& end) const
|
||||
{
|
||||
if (!m_timingActive ||
|
||||
!ConvertGPUTimestamp(m_timestampMap[0], start) ||
|
||||
!ConvertGPUTimestamp(m_timestampMap[1], end) ||
|
||||
end < start)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ class CD3D12CommandQueue
|
||||
|
||||
bool InitTiming(ID3D12Device3 * device, D3D12_COMMAND_LIST_TYPE type);
|
||||
void UpdateClockCalibration();
|
||||
bool ConvertGPUTimestamp(UINT64 timestamp, uint64_t& result) const;
|
||||
|
||||
void OnCompletion()
|
||||
{
|
||||
@@ -108,8 +109,8 @@ class CD3D12CommandQueue
|
||||
bool BeginTiming();
|
||||
void EndTiming();
|
||||
|
||||
// Return the command-list start in QueryPerformanceCounter-domain ns.
|
||||
bool GetGPUStartTime(uint64_t& start);
|
||||
// Return the copy boundaries in QueryPerformanceCounter-domain ns.
|
||||
bool GetGPUTimes(uint64_t& start, uint64_t& end) const;
|
||||
|
||||
//void Wait();
|
||||
bool IsReady () const { return !m_pending ; }
|
||||
|
||||
@@ -1302,6 +1302,7 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
||||
fi->captureTime = 0;
|
||||
fi->postProcessTime = 0;
|
||||
fi->copyTime = 0;
|
||||
fi->readyTime = 0;
|
||||
fi->timingSerial = 0;
|
||||
InterlockedExchange((volatile LONG *)&fi->timingValid, 0);
|
||||
fi->rotation = FRAME_ROT_0;
|
||||
@@ -1370,7 +1371,8 @@ bool CIndirectDeviceContext::PublishFrameBuffer(unsigned frameIndex)
|
||||
}
|
||||
|
||||
void CIndirectDeviceContext::SetFrameTiming(unsigned frameIndex,
|
||||
uint64_t captureTime, uint64_t postProcessTime, uint64_t copyTime)
|
||||
uint64_t captureTime, uint64_t postProcessTime, uint64_t copyTime,
|
||||
uint64_t readyTime)
|
||||
{
|
||||
if (frameIndex >= LGMP_Q_FRAME_LEN)
|
||||
return;
|
||||
@@ -1379,6 +1381,7 @@ void CIndirectDeviceContext::SetFrameTiming(unsigned frameIndex,
|
||||
frame->captureTime = captureTime;
|
||||
frame->postProcessTime = postProcessTime;
|
||||
frame->copyTime = copyTime;
|
||||
frame->readyTime = readyTime;
|
||||
frame->timingSerial = frame->frameSerial;
|
||||
InterlockedExchange((volatile LONG *)&frame->timingValid, 1);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ public:
|
||||
PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat, const RECT * dirtyRects, unsigned nbDirtyRects);
|
||||
bool PublishFrameBuffer(unsigned frameIndex);
|
||||
void SetFrameTiming(unsigned frameIndex, uint64_t captureTime,
|
||||
uint64_t postProcessTime, uint64_t copyTime);
|
||||
uint64_t postProcessTime, uint64_t copyTime, uint64_t readyTime);
|
||||
void WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) const;
|
||||
void FinalizeFrameBuffer(unsigned frameIndex) const;
|
||||
|
||||
|
||||
@@ -318,32 +318,38 @@ void CSwapChainProcessor::CompletionFunction(
|
||||
auto sc = (CSwapChainProcessor *)param1;
|
||||
auto fbRes = (CFrameBufferResource *)param2;
|
||||
|
||||
uint64_t copyStart = fbRes->GetCopyStart();
|
||||
uint64_t gpuCopyStart = 0;
|
||||
const uint64_t cpuCopyStart = fbRes->GetCopyStart();
|
||||
uint64_t gpuCopyStart = 0;
|
||||
uint64_t gpuCopyEnd = 0;
|
||||
|
||||
if (result && sc->m_dx12Device->IsIndirectCopy())
|
||||
sc->m_devContext->WriteFrameBuffer(
|
||||
fbRes->GetFrameIndex(), fbRes->GetMap(), 0, fbRes->GetFrameSize(), false);
|
||||
|
||||
// Queue waits execute before this timestamp. Use it as the boundary so the
|
||||
// source fence and effects are charged to Post, while Copy retains the full
|
||||
// time through buffer readiness and any indirect memcpy.
|
||||
const bool gpuTimingValid = result && queue->GetGPUStartTime(gpuCopyStart);
|
||||
// Queue waits execute before the start timestamp. The end timestamp follows
|
||||
// the last CopyTextureRegion, separating GPU work from readiness dispatch.
|
||||
const bool gpuTimingValid = result &&
|
||||
queue->GetGPUTimes(gpuCopyStart, gpuCopyEnd);
|
||||
|
||||
// Publish readiness before sampling the endpoint. Timing has its own valid
|
||||
// flag and is published immediately afterwards.
|
||||
sc->m_devContext->FinalizeFrameBuffer(fbRes->GetFrameIndex());
|
||||
const uint64_t copyEnd = Nanotime();
|
||||
const uint64_t readyEnd = Nanotime();
|
||||
|
||||
uint64_t postProcessTime = cpuCopyStart - fbRes->GetPostProcessStart();
|
||||
uint64_t copyTime = readyEnd - cpuCopyStart;
|
||||
uint64_t readyTime = 0;
|
||||
if (gpuTimingValid &&
|
||||
gpuCopyStart >= fbRes->GetPostProcessStart() &&
|
||||
gpuCopyStart <= copyEnd)
|
||||
copyStart = gpuCopyStart;
|
||||
gpuCopyEnd <= readyEnd)
|
||||
{
|
||||
postProcessTime = gpuCopyStart - fbRes->GetPostProcessStart();
|
||||
copyTime = gpuCopyEnd - gpuCopyStart;
|
||||
readyTime = readyEnd - gpuCopyEnd;
|
||||
}
|
||||
|
||||
const uint64_t postProcessTime = copyStart -
|
||||
fbRes->GetPostProcessStart();
|
||||
const uint64_t copyTime = copyEnd - copyStart;
|
||||
sc->m_devContext->SetFrameTiming(fbRes->GetFrameIndex(),
|
||||
fbRes->GetCaptureTime(), postProcessTime, copyTime);
|
||||
fbRes->GetCaptureTime(), postProcessTime, copyTime, readyTime);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user