Skip to content

Instantly share code, notes, and snippets.

@fredemmott
Last active December 16, 2024 15:10
Show Gist options
  • Select an option

  • Save fredemmott/2247ff7259dfc7b3c2d0f4fec0431b7f to your computer and use it in GitHub Desktop.

Select an option

Save fredemmott/2247ff7259dfc7b3c2d0f4fec0431b7f to your computer and use it in GitHub Desktop.
struct D3D11Timer {
D3D11Timer() = default;
explicit D3D11Timer(ID3D11Device* device) {
device->GetImmediateContext(mContext.put());
D3D11_QUERY_DESC desc {D3D11_QUERY_TIMESTAMP_DISJOINT};
device->CreateQuery(&desc, mDisjointQuery.put());
desc = {D3D11_QUERY_TIMESTAMP};
device->CreateQuery(&desc, mBeginRenderTimestampQuery.put());
device->CreateQuery(&desc, mEndRenderTimestampQuery.put());
}
uint64_t GetDisplayTime() const noexcept {
return mDisplayTime;
}
void StartRender() {
if (!(mContext && mDisjointQuery && mBeginRenderTimestampQuery)) {
return;
}
mDisplayTime = {};
QueryPerformanceCounter(&mBeginRenderCpu);
mContext->Begin(mDisjointQuery.get());
// TIMESTAMP queries only have `End()` and `GetData()` called, never
// `Begin()`
mContext->End(mBeginRenderTimestampQuery.get());
}
void StopRender(uint64_t displayTime) {
if (!(mContext && mDisjointQuery && mBeginRenderTimestampQuery)) {
return;
}
mDisplayTime = displayTime;
mContext->End(mEndRenderTimestampQuery.get());
mContext->End(mDisjointQuery.get());
QueryPerformanceCounter(&mEndRenderCpu);
}
uint64_t GetRenderMicroseconds() {
if (!(mContext && mDisjointQuery && mBeginRenderTimestampQuery)) {
return 0;
}
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjoint {};
uint64_t begin {};
uint64_t end {};
const auto disjointOk
= mContext->GetData(mDisjointQuery.get(), &disjoint, sizeof(disjoint), 0)
== S_OK;
const auto beginOk
= mContext->GetData(
mBeginRenderTimestampQuery.get(), &begin, sizeof(begin), 0)
== S_OK;
const auto endOk
= mContext->GetData(mEndRenderTimestampQuery.get(), &end, sizeof(end), 0)
== S_OK;
if (disjoint.Disjoint || !(disjoint.Frequency && begin && end)) {
return 0;
}
if (!(disjointOk && beginOk && endOk)) {
return 0;
}
const auto diff = end - begin;
const auto gcd = std::gcd(1000000, disjoint.Frequency);
const auto gpuMicros
= (diff * (1000000 / gcd)) / (disjoint.Frequency / gcd);
{
const LARGE_INTEGER cpuDiff {
.QuadPart = mEndRenderCpu.QuadPart - mBeginRenderCpu.QuadPart};
LARGE_INTEGER frequency {};
QueryPerformanceFrequency(&frequency);
const auto cpuGcd = std::gcd(frequency.QuadPart, 1000000);
const auto cpuMicros = (cpuDiff.QuadPart * (1000000 / cpuGcd))
/ (frequency.QuadPart / cpuGcd);
dprint("CPU {} GPU {}", cpuMicros, gpuMicros);
}
return gpuMicros;
}
private:
uint64_t mDisplayTime {};
wil::com_ptr<ID3D11DeviceContext> mContext;
wil::com_ptr<ID3D11Query> mDisjointQuery;
wil::com_ptr<ID3D11Query> mBeginRenderTimestampQuery;
wil::com_ptr<ID3D11Query> mEndRenderTimestampQuery;
LARGE_INTEGER mBeginRenderCpu {};
LARGE_INTEGER mEndRenderCpu {};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment