3

I make DXGI adapters and monitors enumeration. The second monitor connected to my computer is Dell P2715Q, which has 3840*2160 resolution:

Resolution

However, the program reports it as 2560*1440, the second available resolution. Minimal code to reproduce:

int main()
{
IDXGIFactory1* pFactory1;

HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory1));

if (FAILED(hr))
{
    wcout << L"CreateDXGIFactory1 failed. " << endl;
    return 0;
}

for (UINT i = 0;; i++)
{
    IDXGIAdapter1* pAdapter1 = nullptr;

    hr = pFactory1->EnumAdapters1(i, &pAdapter1);

    if (hr == DXGI_ERROR_NOT_FOUND)
    {
        // no more adapters
        break;
    }

    if (FAILED(hr))
    {
        wcout << L"EnumAdapters1 failed. " << endl;
        return 0;
    }

    DXGI_ADAPTER_DESC1 desc;

    hr = pAdapter1->GetDesc1(&desc);

    if (FAILED(hr))
    {
        wcout << L"GetDesc1 failed. " << endl;
        return 0;
    }

    wcout << L"Adapter: " << desc.Description << endl;

    for (UINT j = 0;; j++)
    {
        IDXGIOutput *pOutput = nullptr;

        HRESULT hr = pAdapter1->EnumOutputs(j, &pOutput);

        if (hr == DXGI_ERROR_NOT_FOUND)
        {
            // no more outputs
            break;
        }

        if (FAILED(hr))
        {
            wcout << L"EnumOutputs failed. " << endl;
            return 0;
        }

        DXGI_OUTPUT_DESC desc;

        hr = pOutput->GetDesc(&desc);

        if (FAILED(hr))
        {
            wcout << L"GetDesc1 failed. " << endl;
            return 0;
        }

        wcout << L"  Output: " << desc.DeviceName <<
            L"  (" << desc.DesktopCoordinates.left << L"," << desc.DesktopCoordinates.top << L")-(" <<
            (desc.DesktopCoordinates.right - desc.DesktopCoordinates.left) << L"," << 
            (desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top) << L")" << endl;

    }
}

return 0;
}

Output:

Adapter: Intel(R) Iris(TM) Pro Graphics 6200
   Output: \\.\DISPLAY1  (0,0)-(1920,1200)
   Output: \\.\DISPLAY2  (1920,0)-(2560,1440)

What can cause this behavior: DirectX restrictions, video memory, display adapter, driver, monitor?

Environment:

Windows 10 x64
Intel(R) Iris(TM) Pro Graphics 6200
DELL P2715Q
Alex F
  • 42,307
  • 41
  • 144
  • 212

2 Answers2

3

Your application is treated as non-aware of DPI scaling. The operating system scales the coordinates for you to, presumably, maintain compatibility with legacy applications.

Let the system know that you are aware of High DPI Desktop Application Development and you will get the coordinates you expect:

#include <ShellScalingAPI.h>

#pragma comment(lib, "shcore.lib")

int main()
{
    SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE);
    // there goes your code
Adapter: Intel(R) HD Graphics 4600
  Output: \\.\DISPLAY4  (0,0)-(3840,2160)
  Output: \\.\DISPLAY5  (3840,0)-(3840,2160)

without SetProcessDpiAwareness:

Adapter: Intel(R) HD Graphics 4600
  Output: \\.\DISPLAY4  (0,0)-(2194,1234)
  Output: \\.\DISPLAY5  (2194,0)-(2194,1234)

Note DXGI_OUTPUT_DESC structure comment on MSDN:

DesktopCoordinates

Type: RECT

A RECT structure containing the bounds of the output in desktop coordinates. Desktop coordinates depend on the dots per inch (DPI) of the desktop. For info about writing DPI-aware Win32 apps, see High DPI.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • Testing. Meanwhile, SetProcessDpiAwareness returned S_OK, but result is the same. – Alex F Jan 09 '18 at 17:34
  • 1
    SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) did the trick in my computer. In another program this didn't help, but setting text size to 100% in Windows Display Settings solved the problem. I need to investigate this more. Thank you for pointing to right direction. – Alex F Jan 10 '18 at 07:49
  • `PROCESS_PER_MONITOR_DPI_AWARE` is certainly most flexible. I suppose with per-system DPI you had first (main) monitor DPI applied to all monitors. Either way it's about High DPI scaling and it might be tricky (MSDN article on this is pretty long and my reference to `SetProcessDpiAwareness` is just a rough example and you already figured out...). – Roman R. Jan 10 '18 at 08:14
  • "Although it is not recommended, it is possible to set the default DPI awareness programmatically. Once a window (an HWND) has been created in your process, changing the DPI awareness mode is no longer supported. If you are setting the process-default DPI awareness mode programmatically, you must call the corresponding API before any HWNDs have been created." – wqw Apr 27 '23 at 09:38
2

As an alternative to Roman answer, you can add a manifest to your project to make it dpi aware.

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>
galop1n
  • 8,573
  • 22
  • 36