在D3D12上获取显示器的刷新率

问题描述 投票:1回答:1

我正在将代码从D3D11移植到D3D12,并且我试图在D3D12上获得显示器的刷新率。我将刷新率用于精确的动画计时(这是一个硬要求)。此代码适用于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;
}

不幸的是,ID3D12Device没有实现IDXGIDevice接口,因此FindClosestMatchingMode1失败并出现此错误:

DXGI ERROR: IDXGIOutput::FindClosestMatchingMode: pConcernedDevice doesn't support the IDXGIDevice interface [ MISCELLANEOUS ERROR #69: ]

使用D3D12时是否可以获取IDXGIDevice?另外,如何确定D3D12上显示器的刷新率?

我知道EnumDisplaySettings,但是它返回一个整数,因此缺乏精度,从而导致动画漂移。我也找到了DwmGetCompositionTimingInfo,但是,它似乎仅支持获取主显示器的信息。

我还需要一个可以在传统Win32和UWP应用程序上运行的解决方案。如果需要,我愿意为不同的应用程序模型使用两个代码路径。

c++ winapi directx direct3d12
1个回答
0
投票

我们可以使用CCD API获得刷新率,这是供您参考的代码:

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://docs.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;

}

有关CCD API的更多详细信息,您可以参考下面的链接:

https://docs.microsoft.com/en-us/windows-hardware/drivers/display/ccd-apis

© www.soinside.com 2019 - 2024. All rights reserved.