diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2019-09-17 08:32:43 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2019-09-17 08:32:43 +0200 |
commit | d49d076431d7579ecb33147187fe07eb148112ba (patch) | |
tree | 668370fb9a2eec50000e371125136921ef4518ab /src/plugins/platforms/windows | |
parent | b01e69684b9b36492cc43472edeb72058be9f706 (diff) | |
parent | 35cdcddd605d8823b7b57129e8d7279133a3ca89 (diff) |
Merge remote-tracking branch 'origin/5.15' into dev
Change-Id: Ic1fd51143f903b7e9086fc19ca960dfd9654ee00
Diffstat (limited to 'src/plugins/platforms/windows')
7 files changed, 256 insertions, 28 deletions
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index dcdf9a5622..3591b2c505 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -196,6 +196,7 @@ bool QWindowsOpengl32DLL::init(bool softwareRendering) wglShareLists = reinterpret_cast<BOOL (WINAPI *)(HGLRC, HGLRC)>(resolve("wglShareLists")); wglSwapBuffers = reinterpret_cast<BOOL (WINAPI *)(HDC)>(resolve("wglSwapBuffers")); wglSetPixelFormat = reinterpret_cast<BOOL (WINAPI *)(HDC, int, const PIXELFORMATDESCRIPTOR *)>(resolve("wglSetPixelFormat")); + wglDescribePixelFormat = reinterpret_cast<int (WINAPI *)(HDC, int, UINT, PIXELFORMATDESCRIPTOR *)>(resolve("wglDescribePixelFormat")); glGetError = reinterpret_cast<GLenum (APIENTRY *)()>(resolve("glGetError")); glGetIntegerv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint *)>(resolve("glGetIntegerv")); @@ -214,6 +215,11 @@ BOOL QWindowsOpengl32DLL::setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRI return moduleIsNotOpengl32() ? wglSetPixelFormat(dc, pf, pfd) : SetPixelFormat(dc, pf, pfd); } +int QWindowsOpengl32DLL::describePixelFormat(HDC dc, int pf, UINT size, PIXELFORMATDESCRIPTOR *pfd) +{ + return moduleIsNotOpengl32() ? wglDescribePixelFormat(dc, pf, size, pfd) : DescribePixelFormat(dc, pf, size, pfd); +} + QWindowsOpenGLContext *QOpenGLStaticContext::createContext(QOpenGLContext *context) { return new QWindowsGLContext(this, context); @@ -322,11 +328,11 @@ static inline bool static void describeFormats(HDC hdc) { - const int pfiMax = DescribePixelFormat(hdc, 0, 0, nullptr); + const int pfiMax = QOpenGLStaticContext::opengl32.describePixelFormat(hdc, 0, 0, nullptr); for (int i = 1; i <= pfiMax; i++) { PIXELFORMATDESCRIPTOR pfd; initPixelFormatDescriptor(&pfd); - DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + QOpenGLStaticContext::opengl32.describePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd); qCDebug(lcQpaGl) << '#' << i << '/' << pfiMax << ':' << pfd; } } @@ -617,7 +623,7 @@ static int choosePixelFormat(HDC hdc, // Verify if format is acceptable. Note that the returned // formats have been observed to not contain PFD_SUPPORT_OPENGL, ignore. initPixelFormatDescriptor(obtainedPfd); - DescribePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd); + QOpenGLStaticContext::opengl32.describePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd); if (!isAcceptableFormat(additional, *obtainedPfd, true)) { qCDebug(lcQpaGl) << __FUNCTION__ << " obtained px #" << pixelFormat << " not acceptable=" << *obtainedPfd; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 1abe2eb390..e962af39c2 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -107,6 +107,7 @@ struct QWindowsOpengl32DLL // Wrappers. Always use these instead of SwapBuffers/wglSwapBuffers/etc. BOOL swapBuffers(HDC dc); BOOL setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); + int describePixelFormat(HDC dc, int pf, UINT size, PIXELFORMATDESCRIPTOR *pfd); // WGL HGLRC (WINAPI * wglCreateContext)(HDC dc); @@ -130,6 +131,7 @@ private: // For Mesa llvmpipe shipped with a name other than opengl32.dll BOOL (WINAPI * wglSwapBuffers)(HDC dc); BOOL (WINAPI * wglSetPixelFormat)(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); + int (WINAPI * wglDescribePixelFormat)(HDC dc, int pf, UINT size, PIXELFORMATDESCRIPTOR *pfd); }; class QOpenGLStaticContext : public QWindowsStaticOpenGLContext diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index afc1991e2c..63ecbfe0ea 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -47,6 +47,7 @@ #include <QtCore/qfile.h> #include <QtCore/qfileinfo.h> #include <QtCore/qstandardpaths.h> +#include <QtCore/qlibrary.h> #include <QtCore/qlibraryinfo.h> #include <QtCore/qhash.h> @@ -57,6 +58,8 @@ #include <QtCore/qt_windows.h> #include <private/qsystemlibrary_p.h> #include <d3d9.h> +#include <d3d10.h> +#include <dxgi.h> QT_BEGIN_NAMESPACE @@ -80,52 +83,259 @@ static GpuDescription adapterIdentifierToGpuDescription(const D3DADAPTER_IDENTIF return result; } -class QDirect3D9Handle +class QGraphicsAdapterInfo { public: - Q_DISABLE_COPY_MOVE(QDirect3D9Handle) + Q_DISABLE_COPY_MOVE(QGraphicsAdapterInfo) - QDirect3D9Handle(); - ~QDirect3D9Handle(); + QGraphicsAdapterInfo(); + ~QGraphicsAdapterInfo(); - bool isValid() const { return m_direct3D9 != nullptr; } + bool isValid() const; - UINT adapterCount() const { return m_direct3D9 ? m_direct3D9->GetAdapterCount() : 0u; } + UINT adapterCount() const; bool retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const; private: + QSystemLibrary m_dxgilib; + IDXGIFactory1 *m_dxgiFactory1 = nullptr; + QSystemLibrary m_d3d9lib; IDirect3D9 *m_direct3D9 = nullptr; + + /* This is a value from the DXGI_ADAPTER_FLAG enum. + * However, it's not available in dxgi.h from MinGW, + * so define it here in any case. */ + enum { DXGI_ADAPTER_FLAG_SOFTWARE = 2 }; + + UINT adapterCountDXGI() const; + bool retrieveAdapterIdentifierDXGI(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const; + + UINT adapterCountD3D9() const; + bool retrieveAdapterIdentifierD3D9(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const; }; -QDirect3D9Handle::QDirect3D9Handle() : +QGraphicsAdapterInfo::QGraphicsAdapterInfo() : + m_dxgilib(QStringLiteral("dxgi")), m_d3d9lib(QStringLiteral("d3d9")) { - using PtrDirect3DCreate9 = IDirect3D9 *(WINAPI *)(UINT); + using PtrCreateDXGIFactory1 = HRESULT (WINAPI *)(REFIID, void**); - if (m_d3d9lib.load()) { - if (auto direct3DCreate9 = (PtrDirect3DCreate9)m_d3d9lib.resolve("Direct3DCreate9")) - m_direct3D9 = direct3DCreate9(D3D_SDK_VERSION); + if (m_dxgilib.load()) { + if (auto createDXGIFactory1 = (PtrCreateDXGIFactory1)m_dxgilib.resolve("CreateDXGIFactory1")) + createDXGIFactory1(IID_PPV_ARGS(&m_dxgiFactory1)); + } + + if (!m_dxgiFactory1) { + using PtrDirect3DCreate9 = IDirect3D9 *(WINAPI *)(UINT); + + if (m_d3d9lib.load()) { + if (auto direct3DCreate9 = (PtrDirect3DCreate9)m_d3d9lib.resolve("Direct3DCreate9")) + m_direct3D9 = direct3DCreate9(D3D_SDK_VERSION); + } } } -QDirect3D9Handle::~QDirect3D9Handle() +QGraphicsAdapterInfo::~QGraphicsAdapterInfo() { + if (m_dxgiFactory1) + m_dxgiFactory1->Release(); if (m_direct3D9) m_direct3D9->Release(); } -bool QDirect3D9Handle::retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const +bool QGraphicsAdapterInfo::isValid() const +{ + return m_dxgiFactory1 != nullptr || m_direct3D9 != nullptr; +} + +UINT QGraphicsAdapterInfo::adapterCount() const +{ + if (m_dxgiFactory1) + return adapterCountDXGI(); + if (m_direct3D9) + return adapterCountD3D9(); + return 0; +} + +bool QGraphicsAdapterInfo::retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const +{ + if (m_dxgiFactory1) + return retrieveAdapterIdentifierDXGI(n, adapterIdentifier); + if (m_direct3D9) + return retrieveAdapterIdentifierD3D9(n, adapterIdentifier); + return false; +} + +UINT QGraphicsAdapterInfo::adapterCountDXGI() const +{ + /* DXGI doesn't have an adapterCount(), instead we have to call EnumAdapters1() + * until DXGI_ERROR_NOT_FOUND is returned. */ + UINT n = 0; + + IDXGIAdapter1 *adapter; + while (SUCCEEDED(m_dxgiFactory1->EnumAdapters1(n, &adapter))) { + adapter->Release(); + ++n; + } + + return n; +} + +// Detect whether we are running under 64-bit Windows. +static bool isWow64Process() +{ + typedef BOOL (WINAPI *IsWow64ProcessPtr)(HANDLE hProcess, PBOOL Wow64Process); + IsWow64ProcessPtr IsWow64Process = (IsWow64ProcessPtr)QLibrary::resolve( + QStringLiteral("kernel32.dll"), "IsWow64Process"); + + if (IsWow64Process) { + BOOL IsWow64 = FALSE; + if (IsWow64Process(GetCurrentProcess(), &IsWow64)) + return IsWow64; + } + return false; +} + +// Read a string value from registry +static QString regGetString(HKEY key, const wchar_t* valueName) +{ + QVarLengthArray<wchar_t, MAX_PATH> buf (MAX_PATH); + LRESULT res; + DWORD bufSize = buf.size() * sizeof(wchar_t); + res = RegGetValue(key, nullptr, valueName, + RRF_RT_REG_SZ | RRF_RT_REG_MULTI_SZ, nullptr, + buf.data(), &bufSize); + if (res == ERROR_MORE_DATA) { + buf.resize(bufSize / sizeof(wchar_t)); + bufSize = buf.size() * sizeof(wchar_t); + res = RegGetValue(key, nullptr, valueName, + RRF_RT_REG_SZ | RRF_RT_REG_MULTI_SZ, nullptr, + buf.data(), &bufSize); + } + /* In case of REG_MULTI_SZ, this returns just the first string, + * but that is sufficient for our purposes. */ + if (res == ERROR_SUCCESS) + return QString::fromWCharArray(buf.data()); + return QString(); +} + +// Read driver name given a DeviceKey +static QString retrieveDriverName(const wchar_t *driverKey) +{ + /* Kernel-style prefix, maps to HKLM + * (see https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/registry-key-object-routines) */ + static const wchar_t prefixMappingHKLM[] = L"\\Registry\\Machine\\"; + const size_t prefixMappingHKLMLen = wcslen(prefixMappingHKLM); + if (wcsnicmp(driverKey, prefixMappingHKLM, prefixMappingHKLMLen) != 0) + return QString(); + + driverKey += prefixMappingHKLMLen; + QString driverPath; + HKEY key; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, driverKey, 0, KEY_READ | KEY_WOW64_64KEY, &key) == ERROR_SUCCESS) { + const wchar_t *valueName = + isWow64Process() ? L"UserModeDriverNameWow" : L"UserModeDriverName"; + driverPath = regGetString(key, valueName); + RegCloseKey(key); + } + if (!driverPath.isEmpty()) { + int fileNameSep = driverPath.lastIndexOf(QLatin1Char('\\')); + if (fileNameSep >= 0) + driverPath = driverPath.mid(fileNameSep + 1); + return driverPath; + } + return QString(); +} + +// Retrieve driver name for a display device from registry. +static QString driverNameForDevice(const wchar_t *displayDevice) +{ + QString driverName; + DISPLAY_DEVICE dd; + memset(&dd, 0, sizeof(dd)); + dd.cb = sizeof(dd); + for (int dev = 0; EnumDisplayDevices(nullptr, dev, &dd, 0); ++dev) { + if (wcsicmp(displayDevice, dd.DeviceName) == 0) { + // DeviceKey is documented as "internal", but it's a registry key in kernel format + driverName = retrieveDriverName(dd.DeviceKey); + break; + } + } + if (driverName.isEmpty()) { + /* Fall back to driver name from EnumDisplaySettings. + * This is only a fallback as on Windows 10 this just returns an device-independent + * name. OTOH, it's possible to recognize RDP connections from the driver name. */ + DEVMODE devMode; + if (EnumDisplaySettings(displayDevice, ENUM_CURRENT_SETTINGS, &devMode)) + driverName = QString::fromWCharArray(devMode.dmDeviceName); + } + return driverName; +} + +bool QGraphicsAdapterInfo::retrieveAdapterIdentifierDXGI(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const +{ + IDXGIAdapter1 *adapter; + if (FAILED(m_dxgiFactory1->EnumAdapters1(n, &adapter))) + return false; + + bool result = false; + + DXGI_ADAPTER_DESC1 adapterDesc; + if (SUCCEEDED(adapter->GetDesc1(&adapterDesc))) { + if ((adapterDesc.VendorId != 0) && (adapterDesc.DeviceId != 0) // Don't use adapter description of Software Devices + && ((adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) == 0)) { + memset(adapterIdentifier, 0, sizeof(*adapterIdentifier)); + WideCharToMultiByte(1252, 0, adapterDesc.Description, -1, + adapterIdentifier->Description, + sizeof(adapterIdentifier->Description), nullptr, nullptr); + adapterIdentifier->Description[sizeof(adapterIdentifier->Description) - 1] = 0; + adapterIdentifier->VendorId = adapterDesc.VendorId; + adapterIdentifier->DeviceId = adapterDesc.DeviceId; + adapterIdentifier->SubSysId = adapterDesc.SubSysId; + adapterIdentifier->Revision = adapterDesc.Revision; + + LARGE_INTEGER umdVersion; + if (SUCCEEDED(adapter->CheckInterfaceSupport(__uuidof(ID3D10Device), &umdVersion))) { + adapterIdentifier->DriverVersion = umdVersion; + result = true; + } + + /* DXGI doesn't expose the driver name, but we can get it from the registry. + * But we need a device name to follow. */ + IDXGIOutput *output = nullptr; + if (SUCCEEDED(adapter->EnumOutputs (0, &output))) { + DXGI_OUTPUT_DESC outputDesc; + if (SUCCEEDED(output->GetDesc (&outputDesc))) { + QString driverName = driverNameForDevice(outputDesc.DeviceName); + qstrncpy(adapterIdentifier->Driver, driverName.toLatin1().constData(), + sizeof(adapterIdentifier->Driver)); + } + output->Release(); + } + } + } + + adapter->Release(); + + return result; +} + +UINT QGraphicsAdapterInfo::adapterCountD3D9() const +{ + return m_direct3D9->GetAdapterCount(); +} + +bool QGraphicsAdapterInfo::retrieveAdapterIdentifierD3D9(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const { - return m_direct3D9 - && SUCCEEDED(m_direct3D9->GetAdapterIdentifier(n, 0, adapterIdentifier)); + return SUCCEEDED(m_direct3D9->GetAdapterIdentifier(n, 0, adapterIdentifier)); } GpuDescription GpuDescription::detect() { GpuDescription result; - QDirect3D9Handle direct3D9; - if (!direct3D9.isValid()) + QGraphicsAdapterInfo adapterInfo; + if (!adapterInfo.isValid()) return result; D3DADAPTER_IDENTIFIER9 adapterIdentifier; @@ -136,7 +346,7 @@ GpuDescription GpuDescription::detect() // and D3D uses by default. Therefore querying any additional adapters is // futile and not useful for our purposes in general, except for // identifying a few special cases later on. - if (direct3D9.retrieveAdapterIdentifier(0, &adapterIdentifier)) { + if (adapterInfo.retrieveAdapterIdentifier(0, &adapterIdentifier)) { result = adapterIdentifierToGpuDescription(adapterIdentifier); isAMD = result.vendorId == VENDOR_ID_AMD; } @@ -145,9 +355,9 @@ GpuDescription GpuDescription::detect() // when starting apps on a screen connected to the Intel card) by looking // for a default AMD adapter and an additional non-AMD one. if (isAMD) { - const UINT adapterCount = direct3D9.adapterCount(); + const UINT adapterCount = adapterInfo.adapterCount(); for (UINT adp = 1; adp < adapterCount; ++adp) { - if (direct3D9.retrieveAdapterIdentifier(adp, &adapterIdentifier) + if (adapterInfo.retrieveAdapterIdentifier(adp, &adapterIdentifier) && adapterIdentifier.VendorId != VENDOR_ID_AMD) { // Bingo. Now figure out the display for the AMD card. DISPLAY_DEVICE dd; @@ -172,11 +382,11 @@ GpuDescription GpuDescription::detect() QVector<GpuDescription> GpuDescription::detectAll() { QVector<GpuDescription> result; - QDirect3D9Handle direct3D9; - if (const UINT adapterCount = direct3D9.adapterCount()) { + QGraphicsAdapterInfo adapterInfo; + if (const UINT adapterCount = adapterInfo.adapterCount()) { for (UINT adp = 0; adp < adapterCount; ++adp) { D3DADAPTER_IDENTIFIER9 adapterIdentifier; - if (direct3D9.retrieveAdapterIdentifier(adp, &adapterIdentifier)) + if (adapterInfo.retrieveAdapterIdentifier(adp, &adapterIdentifier)) result.append(adapterIdentifierToGpuDescription(adapterIdentifier)); } } diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 8cd09a34eb..df63adf558 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -42,6 +42,7 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowscursor.h" +#include "qwindowstheme.h" #include <QtCore/qt_windows.h> @@ -543,10 +544,13 @@ bool QWindowsScreenManager::handleScreenChanges() // Look for changed monitors, add new ones const WindowsScreenDataList newDataList = monitorData(); const bool lockScreen = newDataList.size() == 1 && (newDataList.front().flags & QWindowsScreenData::LockScreen); + bool primaryScreenChanged = false; for (const QWindowsScreenData &newData : newDataList) { const int existingIndex = indexOfMonitor(m_screens, newData.name); if (existingIndex != -1) { m_screens.at(existingIndex)->handleChanges(newData); + if (existingIndex == 0) + primaryScreenChanged = true; } else { auto *newScreen = new QWindowsScreen(newData); m_screens.push_back(newScreen); @@ -563,6 +567,8 @@ bool QWindowsScreenManager::handleScreenChanges() removeScreen(i); } // for existing screens } // not lock screen + if (primaryScreenChanged) + QWindowsTheme::instance()->refreshFonts(); return true; } diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 4e24308445..07120230ce 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -85,6 +85,8 @@ public: static bool useNativeMenus(); + void refreshFonts(); + static const char *name; private: @@ -92,7 +94,6 @@ private: void clearPalettes(); void refreshPalettes(); void clearFonts(); - void refreshFonts(); void refreshIconPixmapSizes(); static QWindowsTheme *m_instance; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp index 8e395669f8..d8b8f7281d 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp @@ -48,6 +48,7 @@ #include <QtGui/qaccessible.h> #include <QtCore/qloggingcategory.h> #include <QtCore/qstring.h> +#include <QtCore/qvarlengtharray.h> QT_BEGIN_NAMESPACE @@ -227,7 +228,7 @@ HRESULT QWindowsUiaTextRangeProvider::GetBoundingRectangles(SAFEARRAY **pRetVal) return UIA_E_ELEMENTNOTAVAILABLE; int len = textInterface->characterCount(); - QList<QRect> rectList; + QVarLengthArray<QRect> rectList; if ((m_startOffset >= 0) && (m_endOffset <= len) && (m_startOffset < m_endOffset)) { int start, end; diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 95ba961df1..7de6369541 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -12,6 +12,8 @@ LIBS += -lshlwapi -lwtsapi32 QMAKE_USE_PRIVATE += \ advapi32 \ d3d9/nolink \ + d3d11/nolink \ + dxgi/nolink \ ole32 \ shell32 \ user32 \ |