summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.cpp62
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.h1
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp84
3 files changed, 136 insertions, 11 deletions
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp
index c4ee820211..6af9f168a5 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.cpp
+++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp
@@ -60,6 +60,8 @@
QT_BEGIN_NAMESPACE
+static const DWORD VENDOR_ID_AMD = 0x1002;
+
GpuDescription GpuDescription::detect()
{
typedef IDirect3D9 * (WINAPI *PtrDirect3DCreate9)(UINT);
@@ -74,9 +76,16 @@ GpuDescription GpuDescription::detect()
IDirect3D9 *direct3D9 = direct3DCreate9(D3D_SDK_VERSION);
if (!direct3D9)
return result;
+
D3DADAPTER_IDENTIFIER9 adapterIdentifier;
- const HRESULT hr = direct3D9->GetAdapterIdentifier(0, 0, &adapterIdentifier);
- direct3D9->Release();
+ bool isAMD = false;
+ // Adapter "0" is D3DADAPTER_DEFAULT which returns the default adapter. In
+ // multi-GPU, multi-screen setups this is the GPU that is associated with
+ // the "main display" in the Display Settings, and this is the GPU OpenGL
+ // 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.
+ HRESULT hr = direct3D9->GetAdapterIdentifier(0, 0, &adapterIdentifier);
if (SUCCEEDED(hr)) {
result.vendorId = adapterIdentifier.VendorId;
result.deviceId = adapterIdentifier.DeviceId;
@@ -90,7 +99,37 @@ GpuDescription GpuDescription::detect()
result.driverVersion = QVersionNumber(version);
result.driverName = adapterIdentifier.Driver;
result.description = adapterIdentifier.Description;
+ isAMD = result.vendorId == VENDOR_ID_AMD;
}
+
+ // Detect QTBUG-50371 (having AMD as the default adapter results in a crash
+ // 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->GetAdapterCount();
+ for (UINT adp = 1; adp < adapterCount; ++adp) {
+ hr = direct3D9->GetAdapterIdentifier(adp, 0, &adapterIdentifier);
+ if (SUCCEEDED(hr)) {
+ if (adapterIdentifier.VendorId != VENDOR_ID_AMD) {
+ // Bingo. Now figure out the display for the AMD card.
+ DISPLAY_DEVICE dd;
+ memset(&dd, 0, sizeof(dd));
+ dd.cb = sizeof(dd);
+ for (int dev = 0; EnumDisplayDevices(nullptr, dev, &dd, 0); ++dev) {
+ if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
+ // DeviceName is something like \\.\DISPLAY1 which can be used to
+ // match with the MONITORINFOEX::szDevice queried by QWindowsScreen.
+ result.gpuSuitableScreen = QString::fromWCharArray(dd.DeviceName);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ direct3D9->Release();
return result;
}
@@ -103,7 +142,8 @@ QDebug operator<<(QDebug d, const GpuDescription &gd)
<< ", deviceId=" << gd.deviceId << ", subSysId=" << gd.subSysId
<< dec << noshowbase << ", revision=" << gd.revision
<< ", driver: " << gd.driverName
- << ", version=" << gd.driverVersion << ", " << gd.description << ')';
+ << ", version=" << gd.driverVersion << ", " << gd.description
+ << gd.gpuSuitableScreen << ')';
return d;
}
#endif // !QT_NO_DEBUG_STREAM
@@ -113,15 +153,17 @@ QString GpuDescription::toString() const
{
QString result;
QTextStream str(&result);
- str << " Card name: " << description
- << "\n Driver Name: " << driverName
- << "\n Driver Version: " << driverVersion.toString()
- << "\n Vendor ID: 0x" << qSetPadChar(QLatin1Char('0'))
+ str << " Card name : " << description
+ << "\n Driver Name : " << driverName
+ << "\n Driver Version : " << driverVersion.toString()
+ << "\n Vendor ID : 0x" << qSetPadChar(QLatin1Char('0'))
<< uppercasedigits << hex << qSetFieldWidth(4) << vendorId
- << "\n Device ID: 0x" << qSetFieldWidth(4) << deviceId
- << "\n SubSys ID: 0x" << qSetFieldWidth(8) << subSysId
- << "\n Revision ID: 0x" << qSetFieldWidth(4) << revision
+ << "\n Device ID : 0x" << qSetFieldWidth(4) << deviceId
+ << "\n SubSys ID : 0x" << qSetFieldWidth(8) << subSysId
+ << "\n Revision ID : 0x" << qSetFieldWidth(4) << revision
<< dec;
+ if (!gpuSuitableScreen.isEmpty())
+ str << "\nGL windows forced to screen: " << gpuSuitableScreen;
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h
index 5ee2508462..22170f30b0 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.h
+++ b/src/plugins/platforms/windows/qwindowsopengltester.h
@@ -62,6 +62,7 @@ struct GpuDescription
QVersionNumber driverVersion;
QByteArray driverName;
QByteArray description;
+ QString gpuSuitableScreen;
};
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 528927b0fb..9c31409644 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -58,6 +58,7 @@
#else
# include "qwindowsopenglcontext.h"
#endif
+#include "qwindowsopengltester.h"
#ifdef QT_NO_CURSOR
# include "qwindowscursor.h"
#endif
@@ -541,6 +542,84 @@ static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags)
flags |= Qt::FramelessWindowHint;
}
+static QScreen *screenForName(const QWindow *w, const QString &name)
+{
+ QScreen *winScreen = w ? w->screen() : QGuiApplication::primaryScreen();
+ if (winScreen && winScreen->name() != name) {
+ const auto screens = winScreen->virtualSiblings();
+ for (QScreen *screen : screens) {
+ if (screen->name() == name)
+ return screen;
+ }
+ }
+ return winScreen;
+}
+
+static QScreen *forcedScreenForGLWindow(const QWindow *w)
+{
+ const QString forceToScreen = GpuDescription::detect().gpuSuitableScreen;
+ return forceToScreen.isEmpty() ? nullptr : screenForName(w, forceToScreen);
+}
+
+static QPoint calcPosition(const QWindow *w, const QWindowCreationContextPtr &context, const QMargins &invMargins)
+{
+ const QPoint orgPos(context->frameX - invMargins.left(), context->frameY - invMargins.top());
+
+ if (!w || (!w->isTopLevel() && w->surfaceType() != QWindow::OpenGLSurface))
+ return orgPos;
+
+ // Workaround for QTBUG-50371
+ const QScreen *screenForGL = forcedScreenForGLWindow(w);
+ if (!screenForGL)
+ return orgPos;
+
+ const QPoint posFrame(context->frameX, context->frameY);
+ const QMargins margins = context->margins;
+ const QRect scrGeo = screenForGL->handle()->availableGeometry();
+
+ // Point is already in the required screen.
+ if (scrGeo.contains(orgPos))
+ return orgPos;
+
+ // If the visible part of the window is already in the
+ // required screen, just ignore the invisible offset.
+ if (scrGeo.contains(posFrame))
+ return posFrame;
+
+ // Find the original screen containing the coordinates.
+ const QList<QScreen *> screens = screenForGL->virtualSiblings();
+ const QScreen *orgScreen = nullptr;
+ for (QScreen *screen : screens) {
+ if (screen->handle()->availableGeometry().contains(posFrame)) {
+ orgScreen = screen;
+ break;
+ }
+ }
+ const QPoint ctPos = QPoint(qMax(scrGeo.left(), scrGeo.center().x()
+ + (margins.right() - margins.left() - context->frameWidth)/2),
+ qMax(scrGeo.top(), scrGeo.center().y()
+ + (margins.bottom() - margins.top() - context->frameHeight)/2));
+
+ // If initial coordinates were outside all screens, center the window on the required screen.
+ if (!orgScreen)
+ return ctPos;
+
+ const QRect orgGeo = orgScreen->handle()->availableGeometry();
+ const QRect orgFrame(QPoint(context->frameX, context->frameY),
+ QSize(context->frameWidth, context->frameHeight));
+
+ // Window would be centered on orgScreen. Center it on the required screen.
+ if (orgGeo.center() == (orgFrame - margins).center())
+ return ctPos;
+
+ // Transform the coordinates to map them into the required screen.
+ const QPoint newPos(scrGeo.left() + ((posFrame.x() - orgGeo.left()) * scrGeo.width()) / orgGeo.width(),
+ scrGeo.top() + ((posFrame.y() - orgGeo.top()) * scrGeo.height()) / orgGeo.height());
+ const QPoint newPosNoMargin(newPos.x() - invMargins.left(), newPos.y() - invMargins.top());
+
+ return scrGeo.contains(newPosNoMargin) ? newPosNoMargin : newPos;
+}
+
void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
unsigned creationFlags)
{
@@ -688,9 +767,12 @@ QWindowsWindowData
<< " custom margins: " << context->customMargins
<< " invisible margins: " << invMargins;
+
+ QPoint pos = calcPosition(w, context, invMargins);
+
result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
style,
- context->frameX - invMargins.left(), context->frameY - invMargins.top(),
+ pos.x(), pos.y(),
context->frameWidth, context->frameHeight,
parentHandle, NULL, appinst, NULL);
qCDebug(lcQpaWindows).nospace()