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 <simon.hausmann@theqtcompany.com>
bb10
Laszlo Agocs 2015-06-23 16:37:16 +02:00
parent db377a4202
commit a8a8cdd24b
5 changed files with 142 additions and 38 deletions

View File

@ -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<QString> *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<QString> *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<QString> *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<QString> 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<QString> 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<QString> 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<QString> 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<QString> 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<QString> 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()

View File

@ -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<QString> gpuFeatures(const Gpu &gpu,
const QString &osName, const QVersionNumber &kernelVersion,
const QString &osName, const QVersionNumber &kernelVersion, const QString &osVersion,
const QJsonDocument &doc);
static QSet<QString> gpuFeatures(const Gpu &gpu,
const QString &osName, const QVersionNumber &kernelVersion,
const QString &osName, const QVersionNumber &kernelVersion, const QString &osVersion,
const QString &fileName);
static QSet<QString> gpuFeatures(const Gpu &gpu, const QJsonDocument &doc);
static QSet<QString> gpuFeatures(const Gpu &gpu, const QString &fileName);

View File

@ -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())

View File

@ -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",

View File

@ -243,25 +243,43 @@ void tst_QOpenGlConfig::testBugList()
QSet<QString> expectedFeatures;
expectedFeatures << "feature1";
// adapter info
QVersionNumber driverVersion(QVector<int>() << 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<QString> 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<QString>() << "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<QString>() << "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<QString>() << "cool_feature";
actualFeatures = QOpenGLConfig::gpuFeatures(gpu, QStringLiteral("linux"),
QVersionNumber(1, 0), fileName);
QVersionNumber(1, 0), QString(), fileName);
QVERIFY2(expectedFeatures == actualFeatures,
msgSetMismatch(expectedFeatures, actualFeatures));
}