I am porting my code to D3D12 from D3D11 and I'm trying to obtain display's refresh rate on D3D12. I use the refresh rate for precise animation timing (this is a hard requirement). This code works on D3D11:
HRESULT GetRefreshRate(IUnknown* device, IDXGISwapChain* swapChain, double* outRefreshRate)
{
Microsoft::WRL::ComPtr<IDXGIOutput> dxgiOutput;
HRESULT hr = swapChain->GetContainingOutput(&dxgiOutput);
if (FAILED(hr))
return hr;
Microsoft::WRL::ComPtr<IDXGIOutput1> dxgiOutput1;
hr = dxgiOutput.As(&dxgiOutput1);
if (FAILED(hr))
return hr;
DXGI_MODE_DESC1 emptyMode = {};
DXGI_MODE_DESC1 modeDescription;
hr = dxgiOutput1->FindClosestMatchingMode1(&emptyMode, &modeDescription, device);
if (SUCCEEDED(hr))
*outRefreshRate = (double)modeDescription.RefreshRate.Numerator / (double)modeDescription.RefreshRate.Denominator;
return hr;
}
Unfortunately, ID3D12Device does not implement IDXGIDevice interface, and FindClosestMatchingMode1 therefore fails with this error:
DXGI ERROR: IDXGIOutput::FindClosestMatchingMode: pConcernedDevice doesn't support the IDXGIDevice interface [ MISCELLANEOUS ERROR #69: ]
Is there a way to obtain IDXGIDevice when using D3D12? Alternatively, how do I determine display's refresh rate on D3D12?
I know about EnumDisplaySettings
however it returns an integer and therefore lacks precision, causing drift in animations. I also found DwmGetCompositionTimingInfo
, however, it seems to only support getting info for the main monitor.
I also need a solution that would work on both traditional Win32 and UWP applications. I am open to having to use two code paths for different application models if needed.
We can get the refresh rate using CCD api, here is the code for your reference:
HRESULT GetRefreshRate(IDXGISwapChain* swapChain, double* outRefreshRate)
{
ComPtr<IDXGIOutput> dxgiOutput;
HRESULT hr = swapChain->GetContainingOutput(&dxgiOutput);
// if swap chain get failed to get DXGIoutput then follow the below link get the details from remarks section
//https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-getcontainingoutput
if (SUCCEEDED(hr))
{
ComPtr<IDXGIOutput1> dxgiOutput1;
hr = dxgiOutput.As(&dxgiOutput1);
if (SUCCEEDED(hr))
{
// get the descriptor for current output
// from which associated mornitor will be fetched
DXGI_OUTPUT_DESC outputDes{};
hr = dxgiOutput->GetDesc(&outputDes);
if (SUCCEEDED(hr))
{
MONITORINFOEXW info;
info.cbSize = sizeof(info);
// get the associated monitor info
if (GetMonitorInfoW(outputDes.Monitor, &info) != 0)
{
// using the CCD get the associated path and display configuration
UINT32 requiredPaths, requiredModes;
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, &requiredModes) == ERROR_SUCCESS)
{
std::vector<DISPLAYCONFIG_PATH_INFO> paths(requiredPaths);
std::vector<DISPLAYCONFIG_MODE_INFO> modes2(requiredModes);
if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, paths.data(), &requiredModes, modes2.data(), nullptr) == ERROR_SUCCESS)
{
// iterate through all the paths until find the exact source to match
for (auto& p : paths) {
DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName;
sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceName.header.size = sizeof(sourceName);
sourceName.header.adapterId = p.sourceInfo.adapterId;
sourceName.header.id = p.sourceInfo.id;
if (DisplayConfigGetDeviceInfo(&sourceName.header) == ERROR_SUCCESS)
{
// find the matched device which is associated with current device
// there may be the possibility that display may be duplicated and windows may be one of them in such scenario
// there may be two callback because source is same target will be different
// as window is on both the display so either selecting either one is ok
if (wcscmp(info.szDevice, sourceName.viewGdiDeviceName) == 0) {
// get the refresh rate
UINT numerator = p.targetInfo.refreshRate.Numerator;
UINT denominator = p.targetInfo.refreshRate.Denominator;
double refrate = (double)numerator / (double)denominator;
*outRefreshRate = refrate;
break;
}
}
}
}
else
{
hr = E_FAIL;
}
}
else
{
hr = E_FAIL;
}
}
}
}
}
return hr;
}
More details about CCD API, you can refer the link below:
https://learn.microsoft.com/en-us/windows-hardware/drivers/display/ccd-apis