From a8a8cdd24b99f1d984e8395d77025d1d11817afd Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 23 Jun 2015 16:37:16 +0200 Subject: Add support for driver_description and os.release in GPU blacklists os.version is the kernel version which is just not very useful or easy to use for us. Instead, introduce a string that allows easy differentiation between Windows 7 and 8. From the adapter identifier the driver description is often helpful too, especially in virtual machines. These allow writing rules like: { "description": "Use WARP in some Win 8 and 8.1 VMs", "os": { "type": "win", "release": [ "8", "8.1" ] }, "driver_description": "VMware SVGA 3D", "features": [ "disable_desktopgl", "disable_d3d9", "disable_d3d11" ] } Change-Id: I196f6b44d7bb9e42ef47f61f4c28d8aa79afb7c4 Reviewed-by: Simon Hausmann --- src/gui/opengl/qopengl.cpp | 120 ++++++++++++++++----- src/gui/opengl/qopengl_p.h | 10 +- .../platforms/windows/qwindowsopengltester.cpp | 2 +- tests/auto/gui/qopenglconfig/buglist.json | 22 ++++ tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp | 26 ++++- 5 files changed, 142 insertions(+), 38 deletions(-) diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp index 1c008ccb42..68cd8a82b4 100644 --- a/src/gui/opengl/qopengl.cpp +++ b/src/gui/opengl/qopengl.cpp @@ -135,20 +135,42 @@ static const char operators[][3] = {"!=", "<", "<=", "=", ">", ">="}; static inline QString valueKey() { return QStringLiteral("value"); } static inline QString opKey() { return QStringLiteral("op"); } static inline QString versionKey() { return QStringLiteral("version"); } +static inline QString releaseKey() { return QStringLiteral("release"); } static inline QString typeKey() { return QStringLiteral("type"); } static inline QString osKey() { return QStringLiteral("os"); } static inline QString vendorIdKey() { return QStringLiteral("vendor_id"); } static inline QString glVendorKey() { return QStringLiteral("gl_vendor"); } static inline QString deviceIdKey() { return QStringLiteral("device_id"); } static inline QString driverVersionKey() { return QStringLiteral("driver_version"); } +static inline QString driverDescriptionKey() { return QStringLiteral("driver_description"); } static inline QString featuresKey() { return QStringLiteral("features"); } static inline QString idKey() { return QStringLiteral("id"); } static inline QString descriptionKey() { return QStringLiteral("description"); } static inline QString exceptionsKey() { return QStringLiteral("exceptions"); } +typedef QJsonArray::ConstIterator JsonArrayConstIt; + +static inline bool contains(const QJsonArray &haystack, unsigned needle) +{ + for (JsonArrayConstIt it = haystack.constBegin(), cend = haystack.constEnd(); it != cend; ++it) { + if (needle == it->toString().toUInt(Q_NULLPTR, /* base */ 0)) + return true; + } + return false; +} + +static inline bool contains(const QJsonArray &haystack, const QString &needle) +{ + for (JsonArrayConstIt it = haystack.constBegin(), cend = haystack.constEnd(); it != cend; ++it) { + if (needle == it->toString()) + return true; + } + return false; +} + namespace { // VersionTerm describing a version term consisting of number and operator -// found in "os", "driver_version", "gl_version". +// found in os.version and driver_version. struct VersionTerm { VersionTerm() : op(NotEqual) {} static VersionTerm fromJson(const QJsonValue &v); @@ -206,9 +228,38 @@ struct OsTypeTerm static OsTypeTerm fromJson(const QJsonValue &v); static QString hostOs(); static QVersionNumber hostKernelVersion() { return QVersionNumber::fromString(QSysInfo::kernelVersion()); } + static QString hostOsRelease() { + QString ver; +#ifdef Q_OS_WIN + switch (QSysInfo::windowsVersion()) { + case QSysInfo::WV_XP: + case QSysInfo::WV_2003: + ver = QStringLiteral("xp"); + break; + case QSysInfo::WV_VISTA: + ver = QStringLiteral("vista"); + break; + case QSysInfo::WV_WINDOWS7: + ver = QStringLiteral("7"); + break; + case QSysInfo::WV_WINDOWS8: + ver = QStringLiteral("8"); + break; + case QSysInfo::WV_WINDOWS8_1: + ver = QStringLiteral("8.1"); + break; + case QSysInfo::WV_WINDOWS10: + ver = QStringLiteral("10"); + break; + default: + break; + } +#endif + return ver; + } bool isNull() const { return type.isEmpty(); } - bool matches(const QString &osName, const QVersionNumber &kernelVersion) const + bool matches(const QString &osName, const QVersionNumber &kernelVersion, const QString &osRelease) const { if (isNull() || osName.isEmpty() || kernelVersion.isNull()) { qWarning() << Q_FUNC_INFO << "called with invalid parameters"; @@ -216,11 +267,17 @@ struct OsTypeTerm } if (type != osName) return false; - return versionTerm.isNull() || versionTerm.matches(kernelVersion); + if (!versionTerm.isNull() && !versionTerm.matches(kernelVersion)) + return false; + // release is a list of Windows versions where the rule should match + if (!release.isEmpty() && !contains(release, osRelease)) + return false; + return true; } QString type; VersionTerm versionTerm; + QJsonArray release; }; OsTypeTerm OsTypeTerm::fromJson(const QJsonValue &v) @@ -231,6 +288,7 @@ OsTypeTerm OsTypeTerm::fromJson(const QJsonValue &v) const QJsonObject o = v.toObject(); result.type = o.value(typeKey()).toString(); result.versionTerm = VersionTerm::fromJson(o.value(versionKey())); + result.release = o.value(releaseKey()).toArray(); return result; } @@ -251,17 +309,6 @@ QString OsTypeTerm::hostOs() } } // anonymous namespace -typedef QJsonArray::ConstIterator JsonArrayConstIt; - -static inline bool contains(const QJsonArray &a, unsigned needle) -{ - for (JsonArrayConstIt it = a.constBegin(), cend = a.constEnd(); it != cend; ++it) { - if (needle == it->toString().toUInt(Q_NULLPTR, /* base */ 0)) - return true; - } - return false; -} - static QString msgSyntaxWarning(const QJsonObject &object, const QString &what) { QString result; @@ -277,17 +324,18 @@ static QString msgSyntaxWarning(const QJsonObject &object, const QString &what) static bool matches(const QJsonObject &object, const QString &osName, const QVersionNumber &kernelVersion, + const QString &osRelease, const QOpenGLConfig::Gpu &gpu) { const OsTypeTerm os = OsTypeTerm::fromJson(object.value(osKey())); - if (!os.isNull() && !os.matches(osName, kernelVersion)) + if (!os.isNull() && !os.matches(osName, kernelVersion, osRelease)) return false; const QJsonValue exceptionsV = object.value(exceptionsKey()); if (exceptionsV.isArray()) { const QJsonArray exceptionsA = exceptionsV.toArray(); for (JsonArrayConstIt it = exceptionsA.constBegin(), cend = exceptionsA.constEnd(); it != cend; ++it) { - if (matches(it->toObject(), osName, kernelVersion, gpu)) + if (matches(it->toObject(), osName, kernelVersion, osRelease, gpu)) return false; } } @@ -336,12 +384,22 @@ static bool matches(const QJsonObject &object, QLatin1String("Driver version must be of type object.")); } } + + if (!gpu.driverDescription.isEmpty()) { + const QJsonValue driverDescriptionV = object.value(driverDescriptionKey()); + if (driverDescriptionV.isString()) { + if (!gpu.driverDescription.contains(driverDescriptionV.toString().toUtf8())) + return false; + } + } + return true; } static bool readGpuFeatures(const QOpenGLConfig::Gpu &gpu, const QString &osName, const QVersionNumber &kernelVersion, + const QString &osRelease, const QJsonDocument &doc, QSet *result, QString *errorMessage) @@ -358,7 +416,7 @@ static bool readGpuFeatures(const QOpenGLConfig::Gpu &gpu, for (JsonArrayConstIt eit = entriesA.constBegin(), ecend = entriesA.constEnd(); eit != ecend; ++eit) { if (eit->isObject()) { const QJsonObject object = eit->toObject(); - if (matches(object, osName, kernelVersion, gpu)) { + if (matches(object, osName, kernelVersion, osRelease, gpu)) { const QJsonValue featuresListV = object.value(featuresKey()); if (featuresListV.isArray()) { const QJsonArray featuresListA = featuresListV.toArray(); @@ -374,6 +432,7 @@ static bool readGpuFeatures(const QOpenGLConfig::Gpu &gpu, static bool readGpuFeatures(const QOpenGLConfig::Gpu &gpu, const QString &osName, const QVersionNumber &kernelVersion, + const QString &osRelease, const QByteArray &jsonAsciiData, QSet *result, QString *errorMessage) { @@ -389,12 +448,13 @@ static bool readGpuFeatures(const QOpenGLConfig::Gpu &gpu, << error.offset << ")."; return false; } - return readGpuFeatures(gpu, osName, kernelVersion, document, result, errorMessage); + return readGpuFeatures(gpu, osName, kernelVersion, osRelease, document, result, errorMessage); } static bool readGpuFeatures(const QOpenGLConfig::Gpu &gpu, const QString &osName, const QVersionNumber &kernelVersion, + const QString &osRelease, const QString &fileName, QSet *result, QString *errorMessage) { @@ -407,7 +467,7 @@ static bool readGpuFeatures(const QOpenGLConfig::Gpu &gpu, << file.errorString(); return false; } - const bool success = readGpuFeatures(gpu, osName, kernelVersion, file.readAll(), result, errorMessage); + const bool success = readGpuFeatures(gpu, osName, kernelVersion, osRelease, file.readAll(), result, errorMessage); if (!success) { errorMessage->prepend(QLatin1String("Error reading \"") + QDir::toNativeSeparators(fileName) @@ -417,37 +477,39 @@ static bool readGpuFeatures(const QOpenGLConfig::Gpu &gpu, } QSet QOpenGLConfig::gpuFeatures(const QOpenGLConfig::Gpu &gpu, - const QString &osName, - const QVersionNumber &kernelVersion, - const QJsonDocument &doc) + const QString &osName, + const QVersionNumber &kernelVersion, + const QString &osRelease, + const QJsonDocument &doc) { QSet result; QString errorMessage; - if (!readGpuFeatures(gpu, osName, kernelVersion, doc, &result, &errorMessage)) + if (!readGpuFeatures(gpu, osName, kernelVersion, osRelease, doc, &result, &errorMessage)) qWarning().noquote() << errorMessage; return result; } QSet QOpenGLConfig::gpuFeatures(const QOpenGLConfig::Gpu &gpu, - const QString &osName, - const QVersionNumber &kernelVersion, - const QString &fileName) + const QString &osName, + const QVersionNumber &kernelVersion, + const QString &osRelease, + const QString &fileName) { QSet result; QString errorMessage; - if (!readGpuFeatures(gpu, osName, kernelVersion, fileName, &result, &errorMessage)) + if (!readGpuFeatures(gpu, osName, kernelVersion, osRelease, fileName, &result, &errorMessage)) qWarning().noquote() << errorMessage; return result; } QSet QOpenGLConfig::gpuFeatures(const Gpu &gpu, const QJsonDocument &doc) { - return gpuFeatures(gpu, OsTypeTerm::hostOs(), OsTypeTerm::hostKernelVersion(), doc); + return gpuFeatures(gpu, OsTypeTerm::hostOs(), OsTypeTerm::hostKernelVersion(), OsTypeTerm::hostOsRelease(), doc); } QSet QOpenGLConfig::gpuFeatures(const Gpu &gpu, const QString &fileName) { - return gpuFeatures(gpu, OsTypeTerm::hostOs(), OsTypeTerm::hostKernelVersion(), fileName); + return gpuFeatures(gpu, OsTypeTerm::hostOs(), OsTypeTerm::hostKernelVersion(), OsTypeTerm::hostOsRelease(), fileName); } QOpenGLConfig::Gpu QOpenGLConfig::Gpu::fromContext() diff --git a/src/gui/opengl/qopengl_p.h b/src/gui/opengl/qopengl_p.h index 980e02aea6..31a083d96f 100644 --- a/src/gui/opengl/qopengl_p.h +++ b/src/gui/opengl/qopengl_p.h @@ -79,19 +79,21 @@ public: bool isValid() const { return deviceId || !glVendor.isEmpty(); } bool equals(const Gpu &other) const { return vendorId == other.vendorId && deviceId == other.deviceId && driverVersion == other.driverVersion - && glVendor == other.glVendor; + && driverDescription == other.driverDescription && glVendor == other.glVendor; } uint vendorId; uint deviceId; QVersionNumber driverVersion; + QByteArray driverDescription; QByteArray glVendor; - static Gpu fromDevice(uint vendorId, uint deviceId, QVersionNumber driverVersion) { + static Gpu fromDevice(uint vendorId, uint deviceId, QVersionNumber driverVersion, const QByteArray &driverDescription) { Gpu gpu; gpu.vendorId = vendorId; gpu.deviceId = deviceId; gpu.driverVersion = driverVersion; + gpu.driverDescription = driverDescription; return gpu; } @@ -105,10 +107,10 @@ public: }; static QSet gpuFeatures(const Gpu &gpu, - const QString &osName, const QVersionNumber &kernelVersion, + const QString &osName, const QVersionNumber &kernelVersion, const QString &osVersion, const QJsonDocument &doc); static QSet gpuFeatures(const Gpu &gpu, - const QString &osName, const QVersionNumber &kernelVersion, + const QString &osName, const QVersionNumber &kernelVersion, const QString &osVersion, const QString &fileName); static QSet gpuFeatures(const Gpu &gpu, const QJsonDocument &doc); static QSet gpuFeatures(const Gpu &gpu, const QString &fileName); diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index dbee86a707..244fc72332 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -224,7 +224,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c #elif defined(Q_OS_WINCE) return QWindowsOpenGLTester::Gles; #else - QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.deviceId, gpu.vendorId, gpu.driverVersion); + QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.deviceId, gpu.vendorId, gpu.driverVersion, gpu.description); SupportedRenderersCache *srCache = supportedRenderersCache(); SupportedRenderersCache::const_iterator it = srCache->find(qgpu); if (it != srCache->cend()) diff --git a/tests/auto/gui/qopenglconfig/buglist.json b/tests/auto/gui/qopenglconfig/buglist.json index c7b8e61bc8..ef311612b2 100644 --- a/tests/auto/gui/qopenglconfig/buglist.json +++ b/tests/auto/gui/qopenglconfig/buglist.json @@ -102,6 +102,28 @@ "feature1" ] }, + { + "id": 7, + "description": "driver description test", + "driver_description": "Long And Special Driver Description", + "os": { + "type": "win" + }, + "features": [ + "feature2" + ] + }, + { + "id": 8, + "description": "Windows version test", + "os": { + "type": "win", + "release": [ "10" ] + }, + "features": [ + "win10_feature" + ] + }, { "id": 128, "description": "check for matching GL_VENDOR", diff --git a/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp b/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp index f88cbdc758..3bf59910f3 100644 --- a/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp +++ b/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp @@ -243,25 +243,43 @@ void tst_QOpenGlConfig::testBugList() QSet expectedFeatures; expectedFeatures << "feature1"; + // adapter info QVersionNumber driverVersion(QVector() << 9 << 18 << 13 << 4460); - QOpenGLConfig::Gpu gpu = QOpenGLConfig::Gpu::fromDevice(0x10DE, 0x0DE9, driverVersion); + QOpenGLConfig::Gpu gpu = QOpenGLConfig::Gpu::fromDevice(0x10DE, 0x0DE9, driverVersion, QByteArrayLiteral("Unknown")); QSet actualFeatures = QOpenGLConfig::gpuFeatures(gpu, QStringLiteral("win"), - QVersionNumber(6, 3), fileName); + QVersionNumber(6, 3), QStringLiteral("7"), fileName); QVERIFY2(expectedFeatures == actualFeatures, msgSetMismatch(expectedFeatures, actualFeatures)); + // driver_description + gpu = QOpenGLConfig::Gpu::fromDevice(0xDEAD, 0xBEEF, driverVersion, QByteArrayLiteral("Very Long And Special Driver Description")); + actualFeatures = QOpenGLConfig::gpuFeatures(gpu, QStringLiteral("win"), + QVersionNumber(6, 3), QStringLiteral("8"), fileName); + expectedFeatures = QSet() << "feature2"; + QVERIFY2(expectedFeatures == actualFeatures, + msgSetMismatch(expectedFeatures, actualFeatures)); + + // os.release + gpu = QOpenGLConfig::Gpu::fromDevice(0xDEAD, 0xBEEF, driverVersion, QByteArrayLiteral("WinVerTest")); + actualFeatures = QOpenGLConfig::gpuFeatures(gpu, QStringLiteral("win"), + QVersionNumber(12, 34), QStringLiteral("10"), fileName); + expectedFeatures = QSet() << "win10_feature"; + QVERIFY2(expectedFeatures == actualFeatures, + msgSetMismatch(expectedFeatures, actualFeatures)); + + // gl_vendor gpu = QOpenGLConfig::Gpu::fromGLVendor(QByteArrayLiteral("Somebody Else")); expectedFeatures.clear(); actualFeatures = QOpenGLConfig::gpuFeatures(gpu, QStringLiteral("linux"), - QVersionNumber(1, 0), fileName); + QVersionNumber(1, 0), QString(), fileName); QVERIFY2(expectedFeatures == actualFeatures, msgSetMismatch(expectedFeatures, actualFeatures)); gpu = QOpenGLConfig::Gpu::fromGLVendor(QByteArrayLiteral("The Qt Company")); expectedFeatures = QSet() << "cool_feature"; actualFeatures = QOpenGLConfig::gpuFeatures(gpu, QStringLiteral("linux"), - QVersionNumber(1, 0), fileName); + QVersionNumber(1, 0), QString(), fileName); QVERIFY2(expectedFeatures == actualFeatures, msgSetMismatch(expectedFeatures, actualFeatures)); } -- cgit v1.2.3