Windows QPA: Lookup DISPLAYCONFIG data for monitors

Gives more accurate orientation and refresh-rate.

Change-Id: I90b0b7563efc35c9bace07ccb3996350a957e8e5
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
bb10
Allan Sandfeld Jensen 2019-07-02 12:44:58 +02:00
parent ac970d48fd
commit 4c6c094895
1 changed files with 94 additions and 2 deletions

View File

@ -74,6 +74,70 @@ static inline QDpi monitorDPI(HMONITOR hMonitor)
return {0, 0};
}
static bool getPathInfo(const MONITORINFOEX &viewInfo, DISPLAYCONFIG_PATH_INFO *pathInfo)
{
// We might want to consider storing adapterId/id from DISPLAYCONFIG_PATH_TARGET_INFO.
std::vector<DISPLAYCONFIG_PATH_INFO> pathInfos;
std::vector<DISPLAYCONFIG_MODE_INFO> modeInfos;
// Fetch paths
LONG result;
UINT32 numPathArrayElements;
UINT32 numModeInfoArrayElements;
do {
// QueryDisplayConfig documentation doesn't say the number of needed elements is updated
// when the call fails with ERROR_INSUFFICIENT_BUFFER, so we need a separate call to
// look up the needed buffer sizes.
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements,
&numModeInfoArrayElements) != ERROR_SUCCESS) {
return false;
}
pathInfos.resize(numPathArrayElements);
modeInfos.resize(numModeInfoArrayElements);
result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pathInfos.data(),
&numModeInfoArrayElements, modeInfos.data(), nullptr);
} while (result == ERROR_INSUFFICIENT_BUFFER);
if (result != ERROR_SUCCESS)
return false;
// Find path matching monitor name
for (uint32_t p = 0; p < numPathArrayElements; p++) {
DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName;
deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
deviceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
deviceName.header.adapterId = pathInfos[p].sourceInfo.adapterId;
deviceName.header.id = pathInfos[p].sourceInfo.id;
if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
if (wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) == 0) {
*pathInfo = pathInfos[p];
return true;
}
}
}
return false;
}
#if 0
// Needed later for HDR support
static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo)
{
const float defaultSdrWhiteLevel = 200.0;
if (!targetInfo)
return defaultSdrWhiteLevel;
DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {};
whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
whiteLevel.header.size = sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL);
whiteLevel.header.adapterId = targetInfo->adapterId;
whiteLevel.header.id = targetInfo->id;
if (DisplayConfigGetDeviceInfo(&whiteLevel.header) != ERROR_SUCCESS)
return defaultSdrWhiteLevel;
return whiteLevel.SDRWhiteLevel * 80.0 / 1000.0;
}
#endif
using WindowsScreenDataList = QList<QWindowsScreenData>;
static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
@ -107,8 +171,36 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
data->dpi.first);
} // CreateDC() failed
} // not lock screen
data->orientation = data->geometry.height() > data->geometry.width() ?
Qt::PortraitOrientation : Qt::LandscapeOrientation;
// ### We might want to consider storing adapterId/id from DISPLAYCONFIG_PATH_TARGET_INFO,
// if we are going to use DISPLAYCONFIG lookups more.
DISPLAYCONFIG_PATH_INFO pathInfo = {};
if (getPathInfo(info, &pathInfo)) {
switch (pathInfo.targetInfo.rotation) {
case DISPLAYCONFIG_ROTATION_IDENTITY:
data->orientation = Qt::LandscapeOrientation;
break;
case DISPLAYCONFIG_ROTATION_ROTATE90:
data->orientation = Qt::PortraitOrientation;
break;
case DISPLAYCONFIG_ROTATION_ROTATE180:
data->orientation = Qt::InvertedLandscapeOrientation;
break;
case DISPLAYCONFIG_ROTATION_ROTATE270:
data->orientation = Qt::InvertedPortraitOrientation;
break;
case DISPLAYCONFIG_ROTATION_FORCE_UINT32:
Q_UNREACHABLE();
break;
}
if (pathInfo.targetInfo.refreshRate.Numerator && pathInfo.targetInfo.refreshRate.Denominator)
data->refreshRateHz = static_cast<qreal>(pathInfo.targetInfo.refreshRate.Numerator)
/ pathInfo.targetInfo.refreshRate.Denominator;
} else {
data->orientation = data->geometry.height() > data->geometry.width()
? Qt::PortraitOrientation
: Qt::LandscapeOrientation;
}
// EnumDisplayMonitors (as opposed to EnumDisplayDevices) enumerates only
// virtual desktop screens.
data->flags |= QWindowsScreenData::VirtualDesktop;