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:
@@ -103,6 +103,9 @@ typedef struct CaptureFrame
|
||||
uint64_t captureTime;
|
||||
uint64_t postProcessTime;
|
||||
uint64_t copyTime;
|
||||
uint64_t readyTime;
|
||||
// True when Copy is an explicit stage rather than the getFrame residual.
|
||||
bool copyTimingValid;
|
||||
}
|
||||
CaptureFrame;
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ static bool d12_copyTimingInit(
|
||||
|
||||
static void d12_copyTimingDeinit(void);
|
||||
static void d12_copyTimingUpdateCalibration(void);
|
||||
static bool d12_copyTimingGetStart(uint64_t * start);
|
||||
static bool d12_copyTimingGetTimes(uint64_t * start, uint64_t * end);
|
||||
|
||||
// implementation
|
||||
|
||||
@@ -241,7 +241,7 @@ static bool d12_copyTimingInit(
|
||||
D3D12_QUERY_HEAP_DESC queryDesc =
|
||||
{
|
||||
.Type = D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP,
|
||||
.Count = 1
|
||||
.Count = 2
|
||||
};
|
||||
|
||||
comRef_defineLocal(ID3D12QueryHeap, heap);
|
||||
@@ -262,7 +262,7 @@ static bool d12_copyTimingInit(
|
||||
D3D12_RESOURCE_DESC resourceDesc =
|
||||
{
|
||||
.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
|
||||
.Width = sizeof(UINT64),
|
||||
.Width = sizeof(UINT64) * 2,
|
||||
.Height = 1,
|
||||
.DepthOrArraySize = 1,
|
||||
.MipLevels = 1,
|
||||
@@ -285,7 +285,7 @@ static bool d12_copyTimingInit(
|
||||
if (FAILED(hr))
|
||||
goto exit;
|
||||
|
||||
D3D12_RANGE readRange = {0, sizeof(UINT64)};
|
||||
D3D12_RANGE readRange = {0, sizeof(UINT64) * 2};
|
||||
void * timestampMap = NULL;
|
||||
hr = ID3D12Resource_Map(*readback, 0, &readRange, ×tampMap);
|
||||
if (FAILED(hr))
|
||||
@@ -340,41 +340,47 @@ static void d12_copyTimingUpdateCalibration(void)
|
||||
}
|
||||
}
|
||||
|
||||
static bool d12_copyTimingGetStart(uint64_t * start)
|
||||
static bool d12_copyTimingConvert(UINT64 gpuTime, uint64_t * cpuTime)
|
||||
{
|
||||
if (!this->copyTiming.supported)
|
||||
return false;
|
||||
|
||||
const UINT64 gpuStart = *this->copyTiming.map;
|
||||
UINT64 cpuStart;
|
||||
if (gpuStart < this->copyTiming.calibrationGPU)
|
||||
UINT64 qpcTime;
|
||||
if (gpuTime < this->copyTiming.calibrationGPU)
|
||||
{
|
||||
const UINT64 delta = d12_scaleTicks(
|
||||
this->copyTiming.calibrationGPU - gpuStart,
|
||||
this->copyTiming.calibrationGPU - gpuTime,
|
||||
this->copyTiming.qpcFrequency,
|
||||
this->copyTiming.timestampFrequency);
|
||||
if (delta > this->copyTiming.calibrationCPU)
|
||||
return false;
|
||||
|
||||
cpuStart = this->copyTiming.calibrationCPU - delta;
|
||||
qpcTime = this->copyTiming.calibrationCPU - delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
const UINT64 delta = d12_scaleTicks(
|
||||
gpuStart - this->copyTiming.calibrationGPU,
|
||||
gpuTime - this->copyTiming.calibrationGPU,
|
||||
this->copyTiming.qpcFrequency,
|
||||
this->copyTiming.timestampFrequency);
|
||||
if (UINT64_MAX - this->copyTiming.calibrationCPU < delta)
|
||||
return false;
|
||||
|
||||
cpuStart = this->copyTiming.calibrationCPU + delta;
|
||||
qpcTime = this->copyTiming.calibrationCPU + delta;
|
||||
}
|
||||
|
||||
*start = d12_scaleTicks(
|
||||
cpuStart, 1000000000ULL, this->copyTiming.qpcFrequency);
|
||||
*cpuTime = d12_scaleTicks(
|
||||
qpcTime, 1000000000ULL, this->copyTiming.qpcFrequency);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool d12_copyTimingGetTimes(uint64_t * start, uint64_t * end)
|
||||
{
|
||||
if (!this->copyTiming.supported ||
|
||||
this->copyTiming.map[1] < this->copyTiming.map[0])
|
||||
return false;
|
||||
|
||||
return d12_copyTimingConvert(this->copyTiming.map[0], start) &&
|
||||
d12_copyTimingConvert(this->copyTiming.map[1], end);
|
||||
}
|
||||
|
||||
static void d12_initOptions(void)
|
||||
{
|
||||
struct Option options[] =
|
||||
@@ -980,6 +986,10 @@ static CaptureResult d12_getFrame(
|
||||
CaptureFrame * captureFrame)
|
||||
{
|
||||
const uint64_t postProcessStart = nanotime();
|
||||
captureFrame->postProcessTime = 0;
|
||||
captureFrame->copyTime = 0;
|
||||
captureFrame->readyTime = 0;
|
||||
captureFrame->copyTimingValid = false;
|
||||
CaptureResult result = CAPTURE_RESULT_ERROR;
|
||||
comRef_scopePush(3);
|
||||
|
||||
@@ -1139,14 +1149,22 @@ static CaptureResult d12_getFrame(
|
||||
}
|
||||
|
||||
if (this->copyTiming.supported)
|
||||
{
|
||||
ID3D12GraphicsCommandList_EndQuery(
|
||||
*this->copyCommand.gfxList,
|
||||
*this->copyTiming.heap,
|
||||
D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
1);
|
||||
|
||||
ID3D12GraphicsCommandList_ResolveQueryData(
|
||||
*this->copyCommand.gfxList,
|
||||
*this->copyTiming.heap,
|
||||
D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
*this->copyTiming.readback,
|
||||
0);
|
||||
}
|
||||
|
||||
// execute the compute commands
|
||||
if (this->effectsActive)
|
||||
@@ -1171,14 +1189,22 @@ static CaptureResult d12_getFrame(
|
||||
d12_commandGroupWait(&this->copyCommand);
|
||||
|
||||
const uint64_t copyComplete = nanotime();
|
||||
uint64_t copyStart;
|
||||
if (!d12_copyTimingGetStart(©Start) ||
|
||||
copyStart < postProcessStart || copyStart > copyComplete)
|
||||
copyStart = fallbackCopyStart;
|
||||
|
||||
// The caller derives Copy from its getFrame wall time minus Post, preserving
|
||||
// the exact producer total while moving the real queue wait to Post.
|
||||
captureFrame->postProcessTime = copyStart - postProcessStart;
|
||||
uint64_t copyStart;
|
||||
uint64_t copyEnd = 0;
|
||||
if (d12_copyTimingGetTimes(©Start, ©End) &&
|
||||
copyStart >= postProcessStart && copyStart <= copyEnd &&
|
||||
copyEnd <= copyComplete)
|
||||
{
|
||||
captureFrame->postProcessTime = copyStart - postProcessStart;
|
||||
captureFrame->copyTime = copyEnd - copyStart;
|
||||
captureFrame->copyTimingValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Preserve the legacy attribution when copy-queue timestamps are not
|
||||
// available or cannot be correlated safely with the producer clock.
|
||||
captureFrame->postProcessTime = fallbackCopyStart - postProcessStart;
|
||||
}
|
||||
|
||||
if (this->indirectCopy)
|
||||
{
|
||||
@@ -1205,6 +1231,10 @@ static CaptureResult d12_getFrame(
|
||||
this->dstFormat.desc.Height * this->pitch);
|
||||
}
|
||||
|
||||
const uint64_t readyEnd = nanotime();
|
||||
if (captureFrame->copyTimingValid)
|
||||
captureFrame->readyTime = readyEnd - copyEnd;
|
||||
|
||||
// reset the command queues
|
||||
if (this->effectsActive)
|
||||
{
|
||||
|
||||
@@ -401,6 +401,7 @@ static bool sendFrame(CaptureResult result, bool * restart)
|
||||
fi->captureTime = frame.captureTime;
|
||||
fi->postProcessTime = 0;
|
||||
fi->copyTime = 0;
|
||||
fi->readyTime = 0;
|
||||
fi->timingSerial = 0;
|
||||
__atomic_store_n(&fi->timingValid, 0, __ATOMIC_RELAXED);
|
||||
if (frame.hdrMetadata)
|
||||
@@ -449,9 +450,19 @@ static bool sendFrame(CaptureResult result, bool * restart)
|
||||
const uint64_t copyEnd = nanotime();
|
||||
|
||||
fi->postProcessTime = frame.postProcessTime;
|
||||
frame.copyTime = copyEnd - copyStart > frame.postProcessTime ?
|
||||
copyEnd - copyStart - frame.postProcessTime : 0;
|
||||
const uint64_t totalTime = copyEnd - copyStart;
|
||||
const bool splitTimingValid = frame.copyTimingValid &&
|
||||
frame.postProcessTime <= totalTime &&
|
||||
frame.copyTime <= totalTime - frame.postProcessTime &&
|
||||
frame.readyTime <= totalTime - frame.postProcessTime - frame.copyTime;
|
||||
if (!splitTimingValid)
|
||||
{
|
||||
frame.copyTime = totalTime > frame.postProcessTime ?
|
||||
totalTime - frame.postProcessTime : 0;
|
||||
frame.readyTime = 0;
|
||||
}
|
||||
fi->copyTime = frame.copyTime;
|
||||
fi->readyTime = frame.readyTime;
|
||||
fi->timingSerial = fi->frameSerial;
|
||||
__atomic_store_n(&fi->timingValid, 1, __ATOMIC_RELEASE);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user