Fabian Vogt
84970c4034
thus not crashing (kde#384005): * 0001-Don-t-dissallow-open-with-write-flag-syscall-on-NVID.patch OBS-URL: https://build.opensuse.org/package/show/KDE:Frameworks5/kscreenlocker?expand=0&rev=96
1641 lines
49 KiB
Diff
1641 lines
49 KiB
Diff
From abe0c021226e5bf97ac61171941e75a75becf0e2 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= <mgraesslin@kde.org>
|
|
Date: Thu, 31 Aug 2017 09:10:28 +0200
|
|
Subject: [PATCH] Don't dissallow open with write flag syscall on NVIDIA
|
|
|
|
Summary:
|
|
The latest NVIDIA driver crashes the greeter due to our seccomp enabled
|
|
sandbox being too restrictive. The driver is now opening files for
|
|
writing after our dummy context got created and this causes a crash. In
|
|
order to provide our users a working system again we better disable the
|
|
seccomp rule for NVIDIA users for the time being.
|
|
|
|
To detect whether an NVIDIA driver is used I copied the glplatform from
|
|
KWin which is known to work and more reliable than writing new custom
|
|
code even if it's a code copy. For master I'll look into splitting that
|
|
one out from KWin and putting it into a dedicated library so that we can
|
|
link it.
|
|
|
|
This of course means that the seccomp based sandbox is now incomplete
|
|
for NVIDIA users. An idea is to add an additional apparmor rule in
|
|
master to enforce the write restrictions in similar way without forcing
|
|
it for /dev.
|
|
|
|
BUG: 384005
|
|
|
|
Test Plan: I don't have an NVIDIA
|
|
|
|
Reviewers: #plasma, davidedmundson
|
|
|
|
Reviewed By: #plasma, davidedmundson
|
|
|
|
Subscribers: davidedmundson, jriddell, plasma-devel
|
|
|
|
Tags: #plasma
|
|
|
|
Differential Revision: https://phabricator.kde.org/D7616
|
|
---
|
|
greeter/CMakeLists.txt | 1 +
|
|
greeter/autotests/CMakeLists.txt | 2 +-
|
|
greeter/autotests/seccomp_test.cpp | 4 +
|
|
greeter/kwinglplatform.cpp | 1062 ++++++++++++++++++++++++++++++++++++
|
|
greeter/kwinglplatform.h | 416 ++++++++++++++
|
|
greeter/seccomp_filter.cpp | 25 +-
|
|
6 files changed, 1506 insertions(+), 4 deletions(-)
|
|
create mode 100644 greeter/kwinglplatform.cpp
|
|
create mode 100644 greeter/kwinglplatform.h
|
|
|
|
diff --git a/greeter/CMakeLists.txt b/greeter/CMakeLists.txt
|
|
index c5b639a..49836b8 100644
|
|
--- a/greeter/CMakeLists.txt
|
|
+++ b/greeter/CMakeLists.txt
|
|
@@ -13,6 +13,7 @@ set(kscreenlocker_greet_SRCS
|
|
main.cpp
|
|
noaccessnetworkaccessmanagerfactory.cpp
|
|
wallpaper_integration.cpp
|
|
+ kwinglplatform.cpp
|
|
)
|
|
|
|
if(HAVE_SECCOMP)
|
|
diff --git a/greeter/autotests/CMakeLists.txt b/greeter/autotests/CMakeLists.txt
|
|
index d5cb23d..d44f308 100644
|
|
--- a/greeter/autotests/CMakeLists.txt
|
|
+++ b/greeter/autotests/CMakeLists.txt
|
|
@@ -32,7 +32,7 @@ target_link_libraries(killTest Qt5::Test)
|
|
# Seccomp Test
|
|
#######################################
|
|
if(HAVE_SECCOMP)
|
|
- add_executable(seccompTest seccomp_test.cpp ../seccomp_filter.cpp)
|
|
+ add_executable(seccompTest seccomp_test.cpp ../seccomp_filter.cpp ../kwinglplatform.cpp)
|
|
add_test(kscreenlocker-seccompTest seccompTest)
|
|
ecm_mark_as_test(seccompTest)
|
|
target_link_libraries(seccompTest
|
|
diff --git a/greeter/autotests/seccomp_test.cpp b/greeter/autotests/seccomp_test.cpp
|
|
index 0006140..571c79d 100644
|
|
--- a/greeter/autotests/seccomp_test.cpp
|
|
+++ b/greeter/autotests/seccomp_test.cpp
|
|
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*********************************************************************/
|
|
#include <config-kscreenlocker.h>
|
|
#include "../seccomp_filter.h"
|
|
+#include "../kwinglplatform.h"
|
|
|
|
#include <QtTest/QtTest>
|
|
#include <QTemporaryFile>
|
|
@@ -55,6 +56,9 @@ void SeccompTest::testCreateFile()
|
|
|
|
void SeccompTest::testOpenFile()
|
|
{
|
|
+ if (KWin::GLPlatform::instance()->driver() == KWin::Driver_NVidia) {
|
|
+ QSKIP("Write protection not supported on NVIDIA");
|
|
+ }
|
|
QFile file(QStringLiteral(KCHECKPASS_BIN));
|
|
QVERIFY(file.exists());
|
|
QVERIFY(!file.open(QIODevice::WriteOnly));
|
|
diff --git a/greeter/kwinglplatform.cpp b/greeter/kwinglplatform.cpp
|
|
new file mode 100644
|
|
index 0000000..ee98b50
|
|
--- /dev/null
|
|
+++ b/greeter/kwinglplatform.cpp
|
|
@@ -0,0 +1,1062 @@
|
|
+/********************************************************************
|
|
+ KWin - the KDE window manager
|
|
+ This file is part of the KDE project.
|
|
+
|
|
+Copyright (C) 2010 Fredrik Höglund <fredrik@kde.org>
|
|
+
|
|
+This program is free software; you can redistribute it and/or modify
|
|
+it under the terms of the GNU General Public License as published by
|
|
+the Free Software Foundation; either version 2 of the License, or
|
|
+(at your option) any later version.
|
|
+
|
|
+This program is distributed in the hope that it will be useful,
|
|
+but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+GNU General Public License for more details.
|
|
+
|
|
+You should have received a copy of the GNU General Public License
|
|
+along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
+*********************************************************************/
|
|
+
|
|
+#include "kwinglplatform.h"
|
|
+
|
|
+#include <QRegExp>
|
|
+#include <QStringList>
|
|
+#include <QDebug>
|
|
+#include <QOpenGLContext>
|
|
+#include <QOpenGLFunctions>
|
|
+
|
|
+#include <sys/utsname.h>
|
|
+
|
|
+#include <iostream>
|
|
+#include <iomanip>
|
|
+#include <ios>
|
|
+
|
|
+namespace KWin
|
|
+{
|
|
+
|
|
+GLPlatform *GLPlatform::s_platform = 0;
|
|
+
|
|
+static qint64 parseVersionString(const QByteArray &version)
|
|
+{
|
|
+ // Skip any leading non digit
|
|
+ int start = 0;
|
|
+ while (start < version.length() && !QChar::fromLatin1(version[start]).isDigit())
|
|
+ start++;
|
|
+
|
|
+ // Strip any non digit, non '.' characters from the end
|
|
+ int end = start;
|
|
+ while (end < version.length() && (version[end] == '.' || QChar::fromLatin1(version[end]).isDigit()))
|
|
+ end++;
|
|
+
|
|
+ const QByteArray result = version.mid(start, end-start);
|
|
+ const QList<QByteArray> tokens = result.split('.');
|
|
+ const qint64 major = tokens.at(0).toInt();
|
|
+ const qint64 minor = tokens.count() > 1 ? tokens.at(1).toInt() : 0;
|
|
+ const qint64 patch = tokens.count() > 2 ? tokens.at(2).toInt() : 0;
|
|
+
|
|
+ return kVersionNumber(major, minor, patch);
|
|
+}
|
|
+
|
|
+static qint64 getKernelVersion()
|
|
+{
|
|
+ struct utsname name;
|
|
+ uname(&name);
|
|
+
|
|
+ if (qstrcmp(name.sysname, "Linux") == 0)
|
|
+ return parseVersionString(name.release);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+// Extracts the portion of a string that matches a regular expression
|
|
+static QString extract(const QString &string, const QString &match, int offset = 0)
|
|
+{
|
|
+ QString result;
|
|
+ QRegExp rx(match);
|
|
+ int pos = rx.indexIn(string, offset);
|
|
+ if (pos != -1)
|
|
+ result = string.mid(pos, rx.matchedLength());
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static ChipClass detectRadeonClass(const QByteArray &chipset)
|
|
+{
|
|
+ if (chipset.isEmpty())
|
|
+ return UnknownRadeon;
|
|
+
|
|
+ if (chipset.contains("R100") ||
|
|
+ chipset.contains("RV100") ||
|
|
+ chipset.contains("RS100"))
|
|
+ return R100;
|
|
+
|
|
+ if (chipset.contains("RV200") ||
|
|
+ chipset.contains("RS200") ||
|
|
+ chipset.contains("R200") ||
|
|
+ chipset.contains("RV250") ||
|
|
+ chipset.contains("RS300") ||
|
|
+ chipset.contains("RV280"))
|
|
+ return R200;
|
|
+
|
|
+ if (chipset.contains("R300") ||
|
|
+ chipset.contains("R350") ||
|
|
+ chipset.contains("R360") ||
|
|
+ chipset.contains("RV350") ||
|
|
+ chipset.contains("RV370") ||
|
|
+ chipset.contains("RV380"))
|
|
+ return R300;
|
|
+
|
|
+ if (chipset.contains("R420") ||
|
|
+ chipset.contains("R423") ||
|
|
+ chipset.contains("R430") ||
|
|
+ chipset.contains("R480") ||
|
|
+ chipset.contains("R481") ||
|
|
+ chipset.contains("RV410") ||
|
|
+ chipset.contains("RS400") ||
|
|
+ chipset.contains("RC410") ||
|
|
+ chipset.contains("RS480") ||
|
|
+ chipset.contains("RS482") ||
|
|
+ chipset.contains("RS600") ||
|
|
+ chipset.contains("RS690") ||
|
|
+ chipset.contains("RS740"))
|
|
+ return R400;
|
|
+
|
|
+ if (chipset.contains("RV515") ||
|
|
+ chipset.contains("R520") ||
|
|
+ chipset.contains("RV530") ||
|
|
+ chipset.contains("R580") ||
|
|
+ chipset.contains("RV560") ||
|
|
+ chipset.contains("RV570"))
|
|
+ return R500;
|
|
+
|
|
+ if (chipset.contains("R600") ||
|
|
+ chipset.contains("RV610") ||
|
|
+ chipset.contains("RV630") ||
|
|
+ chipset.contains("RV670") ||
|
|
+ chipset.contains("RV620") ||
|
|
+ chipset.contains("RV635") ||
|
|
+ chipset.contains("RS780") ||
|
|
+ chipset.contains("RS880"))
|
|
+ return R600;
|
|
+
|
|
+ if (chipset.contains("R700") ||
|
|
+ chipset.contains("RV770") ||
|
|
+ chipset.contains("RV730") ||
|
|
+ chipset.contains("RV710") ||
|
|
+ chipset.contains("RV740"))
|
|
+ return R700;
|
|
+
|
|
+ if (chipset.contains("EVERGREEN") || // Not an actual chipset, but returned by R600G in 7.9
|
|
+ chipset.contains("CEDAR") ||
|
|
+ chipset.contains("REDWOOD") ||
|
|
+ chipset.contains("JUNIPER") ||
|
|
+ chipset.contains("CYPRESS") ||
|
|
+ chipset.contains("HEMLOCK") ||
|
|
+ chipset.contains("PALM"))
|
|
+ return Evergreen;
|
|
+
|
|
+ if (chipset.contains("SUMO") ||
|
|
+ chipset.contains("SUMO2") ||
|
|
+ chipset.contains("BARTS") ||
|
|
+ chipset.contains("TURKS") ||
|
|
+ chipset.contains("CAICOS") ||
|
|
+ chipset.contains("CAYMAN"))
|
|
+ return NorthernIslands;
|
|
+
|
|
+ const QString chipset16 = QString::fromLatin1(chipset);
|
|
+ QString name = extract(chipset16, QStringLiteral("HD [0-9]{4}")); // HD followed by a space and 4 digits
|
|
+ if (!name.isEmpty()) {
|
|
+ const int id = name.rightRef(4).toInt();
|
|
+ if (id == 6250 || id == 6310) // Palm
|
|
+ return Evergreen;
|
|
+
|
|
+ if (id >= 6000 && id < 7000)
|
|
+ return NorthernIslands; // HD 6xxx
|
|
+
|
|
+ if (id >= 5000 && id < 6000)
|
|
+ return Evergreen; // HD 5xxx
|
|
+
|
|
+ if (id >= 4000 && id < 5000)
|
|
+ return R700; // HD 4xxx
|
|
+
|
|
+ if (id >= 2000 && id < 4000) // HD 2xxx/3xxx
|
|
+ return R600;
|
|
+
|
|
+ return UnknownRadeon;
|
|
+ }
|
|
+
|
|
+ name = extract(chipset16, QStringLiteral("X[0-9]{3,4}")); // X followed by 3-4 digits
|
|
+ if (!name.isEmpty()) {
|
|
+ const int id = name.midRef(1, -1).toInt();
|
|
+
|
|
+ // X1xxx
|
|
+ if (id >= 1300)
|
|
+ return R500;
|
|
+
|
|
+ // X7xx, X8xx, X12xx, 2100
|
|
+ if ((id >= 700 && id < 1000) || id >= 1200)
|
|
+ return R400;
|
|
+
|
|
+ // X200, X3xx, X5xx, X6xx, X10xx, X11xx
|
|
+ if ((id >= 300 && id < 700) || (id >= 1000 && id < 1200))
|
|
+ return R300;
|
|
+
|
|
+ return UnknownRadeon;
|
|
+ }
|
|
+
|
|
+ name = extract(chipset16, QStringLiteral("\\b[0-9]{4}\\b")); // A group of 4 digits
|
|
+ if (!name.isEmpty()) {
|
|
+ const int id = name.toInt();
|
|
+
|
|
+ // 7xxx
|
|
+ if (id >= 7000 && id < 8000)
|
|
+ return R100;
|
|
+
|
|
+ // 8xxx, 9xxx
|
|
+ if (id >= 8000 && id < 9500)
|
|
+ return R200;
|
|
+
|
|
+ // 9xxx
|
|
+ if (id >= 9500)
|
|
+ return R300;
|
|
+
|
|
+ if (id == 2100)
|
|
+ return R400;
|
|
+ }
|
|
+
|
|
+ return UnknownRadeon;
|
|
+}
|
|
+
|
|
+static ChipClass detectNVidiaClass(const QString &chipset)
|
|
+{
|
|
+ QString name = extract(chipset, QStringLiteral("\\bNV[0-9,A-F]{2}\\b")); // NV followed by two hexadecimal digits
|
|
+ if (!name.isEmpty()) {
|
|
+ const int id = chipset.midRef(2, -1).toInt(0, 16); // Strip the 'NV' from the id
|
|
+
|
|
+ switch(id & 0xf0) {
|
|
+ case 0x00:
|
|
+ case 0x10:
|
|
+ return NV10;
|
|
+
|
|
+ case 0x20:
|
|
+ return NV20;
|
|
+
|
|
+ case 0x30:
|
|
+ return NV30;
|
|
+
|
|
+ case 0x40:
|
|
+ case 0x60:
|
|
+ return NV40;
|
|
+
|
|
+ case 0x50:
|
|
+ case 0x80:
|
|
+ case 0x90:
|
|
+ case 0xA0:
|
|
+ return G80;
|
|
+
|
|
+ default:
|
|
+ return UnknownNVidia;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (chipset.contains(QLatin1String("GeForce2")) || chipset.contains(QLatin1String("GeForce 256")))
|
|
+ return NV10;
|
|
+
|
|
+ if (chipset.contains(QLatin1String("GeForce3")))
|
|
+ return NV20;
|
|
+
|
|
+ if (chipset.contains(QLatin1String("GeForce4"))) {
|
|
+ if (chipset.contains(QLatin1String("MX 420")) ||
|
|
+ chipset.contains(QLatin1String("MX 440")) || // including MX 440SE
|
|
+ chipset.contains(QLatin1String("MX 460")) ||
|
|
+ chipset.contains(QLatin1String("MX 4000")) ||
|
|
+ chipset.contains(QLatin1String("PCX 4300")))
|
|
+ return NV10;
|
|
+
|
|
+ return NV20;
|
|
+ }
|
|
+
|
|
+ // GeForce 5,6,7,8,9
|
|
+ name = extract(chipset, QStringLiteral("GeForce (FX |PCX |Go )?\\d{4}(M|\\b)")).trimmed();
|
|
+ if (!name.isEmpty()) {
|
|
+ if (!name[name.length() - 1].isDigit())
|
|
+ name.chop(1);
|
|
+
|
|
+ const int id = name.rightRef(4).toInt();
|
|
+ if (id < 6000)
|
|
+ return NV30;
|
|
+
|
|
+ if (id >= 6000 && id < 8000)
|
|
+ return NV40;
|
|
+
|
|
+ if (id >= 8000)
|
|
+ return G80;
|
|
+
|
|
+ return UnknownNVidia;
|
|
+ }
|
|
+
|
|
+ // GeForce 100/200/300/400/500
|
|
+ name = extract(chipset, QStringLiteral("GeForce (G |GT |GTX |GTS )?\\d{3}(M|\\b)")).trimmed();
|
|
+ if (!name.isEmpty()) {
|
|
+ if (!name[name.length() - 1].isDigit())
|
|
+ name.chop(1);
|
|
+
|
|
+ const int id = name.rightRef(3).toInt();
|
|
+ if (id >= 100 && id < 600) {
|
|
+ if (id >= 400)
|
|
+ return GF100;
|
|
+
|
|
+ return G80;
|
|
+ }
|
|
+ return UnknownNVidia;
|
|
+ }
|
|
+
|
|
+ return UnknownNVidia;
|
|
+}
|
|
+static inline ChipClass detectNVidiaClass(const QByteArray &chipset)
|
|
+{
|
|
+ return detectNVidiaClass(QString::fromLatin1(chipset));
|
|
+}
|
|
+
|
|
+static ChipClass detectIntelClass(const QByteArray &chipset)
|
|
+{
|
|
+ // see mesa repository: src/mesa/drivers/dri/intel/intel_context.c
|
|
+ // GL 1.3, DX8? SM ?
|
|
+ if (chipset.contains("845G") ||
|
|
+ chipset.contains("830M") ||
|
|
+ chipset.contains("852GM/855GM") ||
|
|
+ chipset.contains("865G"))
|
|
+ return I8XX;
|
|
+
|
|
+ // GL 1.4, DX 9.0, SM 2.0
|
|
+ if (chipset.contains("915G") ||
|
|
+ chipset.contains("E7221G") ||
|
|
+ chipset.contains("915GM") ||
|
|
+ chipset.contains("945G") || // DX 9.0c
|
|
+ chipset.contains("945GM") ||
|
|
+ chipset.contains("945GME") ||
|
|
+ chipset.contains("Q33") || // GL1.5
|
|
+ chipset.contains("Q35") ||
|
|
+ chipset.contains("G33") ||
|
|
+ chipset.contains("965Q") || // GMA 3000, but apparently considered gen 4 by the driver
|
|
+ chipset.contains("946GZ") || // GMA 3000, but apparently considered gen 4 by the driver
|
|
+ chipset.contains("IGD"))
|
|
+ return I915;
|
|
+
|
|
+ // GL 2.0, DX 9.0c, SM 3.0
|
|
+ if (chipset.contains("965G") ||
|
|
+ chipset.contains("G45/G43") || // SM 4.0
|
|
+ chipset.contains("965GM") || // GL 2.1
|
|
+ chipset.contains("965GME/GLE") ||
|
|
+ chipset.contains("GM45") ||
|
|
+ chipset.contains("Q45/Q43") ||
|
|
+ chipset.contains("G41") ||
|
|
+ chipset.contains("B43") ||
|
|
+ chipset.contains("Ironlake"))
|
|
+ return I965;
|
|
+
|
|
+ // GL 3.1, CL 1.1, DX 10.1
|
|
+ if (chipset.contains("Sandybridge")) {
|
|
+ return SandyBridge;
|
|
+ }
|
|
+
|
|
+ // GL4.0, CL1.1, DX11, SM 5.0
|
|
+ if (chipset.contains("Ivybridge")) {
|
|
+ return IvyBridge;
|
|
+ }
|
|
+
|
|
+ // GL4.0, CL1.2, DX11.1, SM 5.0
|
|
+ if (chipset.contains("Haswell")) {
|
|
+ return Haswell;
|
|
+ }
|
|
+
|
|
+ return UnknownIntel;
|
|
+}
|
|
+
|
|
+static ChipClass detectQualcommClass(const QByteArray &chipClass)
|
|
+{
|
|
+ if (!chipClass.contains("Adreno")) {
|
|
+ return UnknownChipClass;
|
|
+ }
|
|
+ const auto parts = chipClass.split(' ');
|
|
+ if (parts.count() < 3) {
|
|
+ return UnknownAdreno;
|
|
+ }
|
|
+ bool ok = false;
|
|
+ const int value = parts.at(2).toInt(&ok);
|
|
+ if (ok) {
|
|
+ if (value >= 100 && value < 200) {
|
|
+ return Adreno1XX;
|
|
+ }
|
|
+ if (value >= 200 && value < 300) {
|
|
+ return Adreno2XX;
|
|
+ }
|
|
+ if (value >= 300 && value < 400) {
|
|
+ return Adreno3XX;
|
|
+ }
|
|
+ if (value >= 400 && value < 500) {
|
|
+ return Adreno4XX;
|
|
+ }
|
|
+ if (value >= 500 && value < 600) {
|
|
+ return Adreno5XX;
|
|
+ }
|
|
+ }
|
|
+ return UnknownAdreno;
|
|
+}
|
|
+
|
|
+QString GLPlatform::versionToString(qint64 version)
|
|
+{
|
|
+ return QString::fromLatin1(versionToString8(version));
|
|
+}
|
|
+QByteArray GLPlatform::versionToString8(qint64 version)
|
|
+{
|
|
+ int major = (version >> 32);
|
|
+ int minor = (version >> 16) & 0xffff;
|
|
+ int patch = version & 0xffff;
|
|
+
|
|
+ QByteArray string = QByteArray::number(major) + '.' + QByteArray::number(minor);
|
|
+ if (patch != 0)
|
|
+ string += '.' + QByteArray::number(patch);
|
|
+
|
|
+ return string;
|
|
+}
|
|
+
|
|
+QString GLPlatform::driverToString(Driver driver)
|
|
+{
|
|
+ return QString::fromLatin1(driverToString8(driver));
|
|
+}
|
|
+QByteArray GLPlatform::driverToString8(Driver driver)
|
|
+{
|
|
+ switch(driver) {
|
|
+ case Driver_R100:
|
|
+ return QByteArrayLiteral("Radeon");
|
|
+ case Driver_R200:
|
|
+ return QByteArrayLiteral("R200");
|
|
+ case Driver_R300C:
|
|
+ return QByteArrayLiteral("R300C");
|
|
+ case Driver_R300G:
|
|
+ return QByteArrayLiteral("R300G");
|
|
+ case Driver_R600C:
|
|
+ return QByteArrayLiteral("R600C");
|
|
+ case Driver_R600G:
|
|
+ return QByteArrayLiteral("R600G");
|
|
+ case Driver_Nouveau:
|
|
+ return QByteArrayLiteral("Nouveau");
|
|
+ case Driver_Intel:
|
|
+ return QByteArrayLiteral("Intel");
|
|
+ case Driver_NVidia:
|
|
+ return QByteArrayLiteral("NVIDIA");
|
|
+ case Driver_Catalyst:
|
|
+ return QByteArrayLiteral("Catalyst");
|
|
+ case Driver_Swrast:
|
|
+ return QByteArrayLiteral("Software rasterizer");
|
|
+ case Driver_Softpipe:
|
|
+ return QByteArrayLiteral("softpipe");
|
|
+ case Driver_Llvmpipe:
|
|
+ return QByteArrayLiteral("LLVMpipe");
|
|
+ case Driver_VirtualBox:
|
|
+ return QByteArrayLiteral("VirtualBox (Chromium)");
|
|
+ case Driver_VMware:
|
|
+ return QByteArrayLiteral("VMware (SVGA3D)");
|
|
+ case Driver_Qualcomm:
|
|
+ return QByteArrayLiteral("Qualcomm");
|
|
+
|
|
+ default:
|
|
+ return QByteArrayLiteral("Unknown");
|
|
+ }
|
|
+}
|
|
+
|
|
+QString GLPlatform::chipClassToString(ChipClass chipClass)
|
|
+{
|
|
+ return QString::fromLatin1(chipClassToString8(chipClass));
|
|
+}
|
|
+QByteArray GLPlatform::chipClassToString8(ChipClass chipClass)
|
|
+{
|
|
+ switch(chipClass) {
|
|
+ case R100:
|
|
+ return QByteArrayLiteral("R100");
|
|
+ case R200:
|
|
+ return QByteArrayLiteral("R200");
|
|
+ case R300:
|
|
+ return QByteArrayLiteral("R300");
|
|
+ case R400:
|
|
+ return QByteArrayLiteral("R400");
|
|
+ case R500:
|
|
+ return QByteArrayLiteral("R500");
|
|
+ case R600:
|
|
+ return QByteArrayLiteral("R600");
|
|
+ case R700:
|
|
+ return QByteArrayLiteral("R700");
|
|
+ case Evergreen:
|
|
+ return QByteArrayLiteral("EVERGREEN");
|
|
+ case NorthernIslands:
|
|
+ return QByteArrayLiteral("NI");
|
|
+
|
|
+ case NV10:
|
|
+ return QByteArrayLiteral("NV10");
|
|
+ case NV20:
|
|
+ return QByteArrayLiteral("NV20");
|
|
+ case NV30:
|
|
+ return QByteArrayLiteral("NV30");
|
|
+ case NV40:
|
|
+ return QByteArrayLiteral("NV40/G70");
|
|
+ case G80:
|
|
+ return QByteArrayLiteral("G80/G90");
|
|
+ case GF100:
|
|
+ return QByteArrayLiteral("GF100");
|
|
+
|
|
+ case I8XX:
|
|
+ return QByteArrayLiteral("i830/i835");
|
|
+ case I915:
|
|
+ return QByteArrayLiteral("i915/i945");
|
|
+ case I965:
|
|
+ return QByteArrayLiteral("i965");
|
|
+ case SandyBridge:
|
|
+ return QByteArrayLiteral("SandyBridge");
|
|
+ case IvyBridge:
|
|
+ return QByteArrayLiteral("IvyBridge");
|
|
+ case Haswell:
|
|
+ return QByteArrayLiteral("Haswell");
|
|
+
|
|
+ case Adreno1XX:
|
|
+ return QByteArrayLiteral("Adreno 1xx series");
|
|
+ case Adreno2XX:
|
|
+ return QByteArrayLiteral("Adreno 2xx series");
|
|
+ case Adreno3XX:
|
|
+ return QByteArrayLiteral("Adreno 3xx series");
|
|
+ case Adreno4XX:
|
|
+ return QByteArrayLiteral("Adreno 4xx series");
|
|
+ case Adreno5XX:
|
|
+ return QByteArrayLiteral("Adreno 5xx series");
|
|
+
|
|
+ default:
|
|
+ return QByteArrayLiteral("Unknown");
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+// -------
|
|
+
|
|
+
|
|
+
|
|
+GLPlatform::GLPlatform()
|
|
+ : m_driver(Driver_Unknown),
|
|
+ m_chipClass(UnknownChipClass),
|
|
+ m_glVersion(0),
|
|
+ m_glslVersion(0),
|
|
+ m_mesaVersion(0),
|
|
+ m_driverVersion(0),
|
|
+ m_galliumVersion(0),
|
|
+ m_serverVersion(0),
|
|
+ m_kernelVersion(0),
|
|
+ m_looseBinding(false),
|
|
+ m_supportsGLSL(false),
|
|
+ m_limitedGLSL(false),
|
|
+ m_textureNPOT(false),
|
|
+ m_limitedNPOT(false),
|
|
+ m_virtualMachine(false),
|
|
+ m_preferBufferSubData(false),
|
|
+ m_gles(false)
|
|
+{
|
|
+}
|
|
+
|
|
+GLPlatform::~GLPlatform()
|
|
+{
|
|
+}
|
|
+
|
|
+void GLPlatform::detect()
|
|
+{
|
|
+ QOpenGLFunctions gl;
|
|
+ gl.initializeOpenGLFunctions();
|
|
+
|
|
+ m_vendor = (const char*)gl.glGetString(GL_VENDOR);
|
|
+ m_renderer = (const char*)gl.glGetString(GL_RENDERER);
|
|
+ m_version = (const char*)gl.glGetString(GL_VERSION);
|
|
+
|
|
+ // Parse the OpenGL version
|
|
+ const QList<QByteArray> versionTokens = m_version.split(' ');
|
|
+ if (versionTokens.count() > 0) {
|
|
+ const QByteArray version = QByteArray(m_version);
|
|
+ m_glVersion = parseVersionString(version);
|
|
+ if (version.startsWith("OpenGL ES")) {
|
|
+ // from GLES 2: "Returns a version or release number of the form OpenGL<space>ES<space><version number><space><vendor-specific information>."
|
|
+ // from GLES 3: "Returns a version or release number." and "The version number uses one of these forms: major_number.minor_number major_number.minor_number.release_number"
|
|
+ m_gles = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ const QByteArray extensions = (const char *) gl.glGetString(GL_EXTENSIONS);
|
|
+ m_extensions = QSet<QByteArray>::fromList(extensions.split(' '));
|
|
+
|
|
+ // Parse the Mesa version
|
|
+ const int mesaIndex = versionTokens.indexOf("Mesa");
|
|
+ if (mesaIndex != -1) {
|
|
+ const QByteArray version = versionTokens.at(mesaIndex + 1);
|
|
+ m_mesaVersion = parseVersionString(version);
|
|
+ }
|
|
+
|
|
+ if (isGLES()) {
|
|
+ m_supportsGLSL = true;
|
|
+ m_textureNPOT = true;
|
|
+ } else {
|
|
+ m_supportsGLSL = m_extensions.contains("GL_ARB_shader_objects") &&
|
|
+ m_extensions.contains("GL_ARB_fragment_shader") &&
|
|
+ m_extensions.contains("GL_ARB_vertex_shader");
|
|
+
|
|
+ m_textureNPOT = m_extensions.contains("GL_ARB_texture_non_power_of_two");
|
|
+ }
|
|
+
|
|
+ m_kernelVersion = getKernelVersion();
|
|
+
|
|
+ m_glslVersion = 0;
|
|
+ m_glsl_version.clear();
|
|
+
|
|
+ if (m_supportsGLSL) {
|
|
+ // Parse the GLSL version
|
|
+ m_glsl_version = (const char*)gl.glGetString(GL_SHADING_LANGUAGE_VERSION);
|
|
+ m_glslVersion = parseVersionString(m_glsl_version);
|
|
+ }
|
|
+
|
|
+ m_chipset = QByteArrayLiteral("Unknown");
|
|
+ m_preferBufferSubData = false;
|
|
+
|
|
+
|
|
+ // Mesa classic drivers
|
|
+ // ====================================================
|
|
+
|
|
+ // Radeon
|
|
+ if (m_renderer.startsWith("Mesa DRI R")) {
|
|
+ // Sample renderer string: Mesa DRI R600 (RV740 94B3) 20090101 x86/MMX/SSE2 TCL DRI2
|
|
+ const QList<QByteArray> tokens = m_renderer.split(' ');
|
|
+ const QByteArray chipClass = tokens.at(2);
|
|
+ m_chipset = tokens.at(3).mid(1, -1); // Strip the leading '('
|
|
+
|
|
+ if (chipClass == "R100")
|
|
+ // Vendor: Tungsten Graphics, Inc.
|
|
+ m_driver = Driver_R100;
|
|
+
|
|
+ else if (chipClass == "R200")
|
|
+ // Vendor: Tungsten Graphics, Inc.
|
|
+ m_driver = Driver_R200;
|
|
+
|
|
+ else if (chipClass == "R300")
|
|
+ // Vendor: DRI R300 Project
|
|
+ m_driver = Driver_R300C;
|
|
+
|
|
+ else if (chipClass == "R600")
|
|
+ // Vendor: Advanced Micro Devices, Inc.
|
|
+ m_driver = Driver_R600C;
|
|
+
|
|
+ m_chipClass = detectRadeonClass(m_chipset);
|
|
+ }
|
|
+
|
|
+ // Intel
|
|
+ else if (m_renderer.contains("Intel")) {
|
|
+ // Vendor: Tungsten Graphics, Inc.
|
|
+ // Sample renderer string: Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100328 2010Q1
|
|
+
|
|
+ QByteArray chipset;
|
|
+ if (m_renderer.startsWith("Intel(R) Integrated Graphics Device"))
|
|
+ chipset = "IGD";
|
|
+ else
|
|
+ chipset = m_renderer;
|
|
+
|
|
+ m_driver = Driver_Intel;
|
|
+ m_chipClass = detectIntelClass(chipset);
|
|
+ }
|
|
+
|
|
+ // Gallium drivers
|
|
+ // ====================================================
|
|
+ else if (m_renderer.contains("Gallium")) {
|
|
+ // Sample renderer string: Gallium 0.4 on AMD RV740
|
|
+ const QList<QByteArray> tokens = m_renderer.split(' ');
|
|
+ m_galliumVersion = parseVersionString(tokens.at(1));
|
|
+ m_chipset = (tokens.at(3) == "AMD" || tokens.at(3) == "ATI") ?
|
|
+ tokens.at(4) : tokens.at(3);
|
|
+
|
|
+ // R300G
|
|
+ if (m_vendor == QByteArrayLiteral("X.Org R300 Project")) {
|
|
+ m_chipClass = detectRadeonClass(m_chipset);
|
|
+ m_driver = Driver_R300G;
|
|
+ }
|
|
+
|
|
+ // R600G
|
|
+ else if (m_vendor == "X.Org" &&
|
|
+ (m_renderer.contains("R6") ||
|
|
+ m_renderer.contains("R7") ||
|
|
+ m_renderer.contains("RV6") ||
|
|
+ m_renderer.contains("RV7") ||
|
|
+ m_renderer.contains("RS780") ||
|
|
+ m_renderer.contains("RS880") ||
|
|
+ m_renderer.contains("CEDAR") ||
|
|
+ m_renderer.contains("REDWOOD") ||
|
|
+ m_renderer.contains("JUNIPER") ||
|
|
+ m_renderer.contains("CYPRESS") ||
|
|
+ m_renderer.contains("HEMLOCK") ||
|
|
+ m_renderer.contains("PALM") ||
|
|
+ m_renderer.contains("EVERGREEN") ||
|
|
+ m_renderer.contains("SUMO") ||
|
|
+ m_renderer.contains("SUMO2") ||
|
|
+ m_renderer.contains("BARTS") ||
|
|
+ m_renderer.contains("TURKS") ||
|
|
+ m_renderer.contains("CAICOS") ||
|
|
+ m_renderer.contains("CAYMAN"))) {
|
|
+ m_chipClass = detectRadeonClass(m_chipset);
|
|
+ m_driver = Driver_R600G;
|
|
+ }
|
|
+
|
|
+ // Nouveau
|
|
+ else if (m_vendor == "nouveau") {
|
|
+ m_chipClass = detectNVidiaClass(m_chipset);
|
|
+ m_driver = Driver_Nouveau;
|
|
+ }
|
|
+
|
|
+ // softpipe
|
|
+ else if (m_vendor == "VMware, Inc." && m_chipset == "softpipe" ) {
|
|
+ m_driver = Driver_Softpipe;
|
|
+ }
|
|
+
|
|
+ // llvmpipe
|
|
+ else if (m_vendor == "VMware, Inc." && m_chipset == "llvmpipe") {
|
|
+ m_driver = Driver_Llvmpipe;
|
|
+ }
|
|
+
|
|
+ // SVGA3D
|
|
+ else if (m_vendor == "VMware, Inc." && m_chipset.contains("SVGA3D")) {
|
|
+ m_driver = Driver_VMware;
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
+ // Properietary drivers
|
|
+ // ====================================================
|
|
+ else if (m_vendor == "ATI Technologies Inc.") {
|
|
+ m_chipClass = detectRadeonClass(m_renderer);
|
|
+ m_driver = Driver_Catalyst;
|
|
+
|
|
+ if (versionTokens.count() > 1 && versionTokens.at(2)[0] == '(')
|
|
+ m_driverVersion = parseVersionString(versionTokens.at(1));
|
|
+ else if (versionTokens.count() > 0)
|
|
+ m_driverVersion = parseVersionString(versionTokens.at(0));
|
|
+ else
|
|
+ m_driverVersion = 0;
|
|
+ }
|
|
+
|
|
+ else if (m_vendor == "NVIDIA Corporation") {
|
|
+ m_chipClass = detectNVidiaClass(m_renderer);
|
|
+ m_driver = Driver_NVidia;
|
|
+
|
|
+ int index = versionTokens.indexOf("NVIDIA");
|
|
+ if (versionTokens.count() > index)
|
|
+ m_driverVersion = parseVersionString(versionTokens.at(index + 1));
|
|
+ else
|
|
+ m_driverVersion = 0;
|
|
+ }
|
|
+
|
|
+ else if (m_vendor == "Qualcomm") {
|
|
+ m_driver = Driver_Qualcomm;
|
|
+ m_chipClass = detectQualcommClass(m_renderer);
|
|
+ }
|
|
+
|
|
+ else if (m_renderer == "Software Rasterizer") {
|
|
+ m_driver = Driver_Swrast;
|
|
+ }
|
|
+
|
|
+ // Virtual Hardware
|
|
+ // ====================================================
|
|
+ else if (m_vendor == "Humper" && m_renderer == "Chromium") {
|
|
+ // Virtual Box
|
|
+ m_driver = Driver_VirtualBox;
|
|
+
|
|
+ const int index = versionTokens.indexOf("Chromium");
|
|
+ if (versionTokens.count() > index)
|
|
+ m_driverVersion = parseVersionString(versionTokens.at(index + 1));
|
|
+ else
|
|
+ m_driverVersion = 0;
|
|
+ }
|
|
+
|
|
+
|
|
+ // Driver/GPU specific features
|
|
+ // ====================================================
|
|
+ if (isRadeon()) {
|
|
+ // R200 technically has a programmable pipeline, but since it's SM 1.4,
|
|
+ // it's too limited to to be of any practical value to us.
|
|
+ if (m_chipClass < R300)
|
|
+ m_supportsGLSL = false;
|
|
+
|
|
+ m_limitedGLSL = false;
|
|
+ m_limitedNPOT = false;
|
|
+
|
|
+ if (m_chipClass < R600) {
|
|
+ if (driver() == Driver_Catalyst)
|
|
+ m_textureNPOT = m_limitedNPOT = false; // Software fallback
|
|
+ else if (driver() == Driver_R300G)
|
|
+ m_limitedNPOT = m_textureNPOT;
|
|
+
|
|
+ m_limitedGLSL = m_supportsGLSL;
|
|
+ }
|
|
+
|
|
+ if (driver() == Driver_R600G ||
|
|
+ (driver() == Driver_R600C && m_renderer.contains("DRI2"))) {
|
|
+ m_looseBinding = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (isNvidia()) {
|
|
+ if (m_driver == Driver_NVidia && m_chipClass < NV40)
|
|
+ m_supportsGLSL = false; // High likelihood of software emulation
|
|
+
|
|
+ if (m_driver == Driver_NVidia) {
|
|
+ m_looseBinding = true;
|
|
+ m_preferBufferSubData = true;
|
|
+ }
|
|
+
|
|
+ m_limitedNPOT = m_textureNPOT && m_chipClass < NV40;
|
|
+ m_limitedGLSL = m_supportsGLSL && m_chipClass < G80;
|
|
+ }
|
|
+
|
|
+ if (isIntel()) {
|
|
+ if (m_chipClass < I915)
|
|
+ m_supportsGLSL = false;
|
|
+
|
|
+ m_limitedGLSL = m_supportsGLSL && m_chipClass < I965;
|
|
+ // see https://bugs.freedesktop.org/show_bug.cgi?id=80349#c1
|
|
+ m_looseBinding = false;
|
|
+ }
|
|
+
|
|
+ if (isSoftwareEmulation()) {
|
|
+ if (m_driver < Driver_Llvmpipe) {
|
|
+ // Software emulation does not provide GLSL
|
|
+ m_limitedGLSL = m_supportsGLSL = false;
|
|
+ } else {
|
|
+ m_limitedGLSL = false;
|
|
+ m_supportsGLSL = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (m_chipClass == UnknownChipClass && m_driver == Driver_Unknown) {
|
|
+ // we don't know the hardware. Let's be optimistic and assume OpenGL compatible hardware
|
|
+ m_supportsGLSL = true;
|
|
+ }
|
|
+
|
|
+ if (isVirtualBox()) {
|
|
+ m_virtualMachine = true;
|
|
+ }
|
|
+
|
|
+ if (isVMware()) {
|
|
+ m_virtualMachine = true;
|
|
+ }
|
|
+
|
|
+ // and force back to shader supported on gles, we wouldn't have got a context if not supported
|
|
+ if (isGLES()) {
|
|
+ m_supportsGLSL = true;
|
|
+ m_limitedGLSL = false;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void print(const QByteArray &label, const QByteArray &setting)
|
|
+{
|
|
+ std::cout << std::setw(40) << std::left
|
|
+ << label.data() << setting.data() << std::endl;
|
|
+}
|
|
+
|
|
+void GLPlatform::printResults() const
|
|
+{
|
|
+ print(QByteArrayLiteral("OpenGL vendor string:"), m_vendor);
|
|
+ print(QByteArrayLiteral("OpenGL renderer string:"), m_renderer);
|
|
+ print(QByteArrayLiteral("OpenGL version string:"), m_version);
|
|
+
|
|
+ if (m_supportsGLSL)
|
|
+ print(QByteArrayLiteral("OpenGL shading language version string:"), m_glsl_version);
|
|
+
|
|
+ print(QByteArrayLiteral("Driver:"), driverToString8(m_driver));
|
|
+ if (!isMesaDriver())
|
|
+ print(QByteArrayLiteral("Driver version:"), versionToString8(m_driverVersion));
|
|
+
|
|
+ print(QByteArrayLiteral("GPU class:"), chipClassToString8(m_chipClass));
|
|
+
|
|
+ print(QByteArrayLiteral("OpenGL version:"), versionToString8(m_glVersion));
|
|
+
|
|
+ if (m_supportsGLSL)
|
|
+ print(QByteArrayLiteral("GLSL version:"), versionToString8(m_glslVersion));
|
|
+
|
|
+ if (isMesaDriver())
|
|
+ print(QByteArrayLiteral("Mesa version:"), versionToString8(mesaVersion()));
|
|
+ //if (galliumVersion() > 0)
|
|
+ // print("Gallium version:", versionToString(m_galliumVersion));
|
|
+ if (serverVersion() > 0)
|
|
+ print(QByteArrayLiteral("X server version:"), versionToString8(m_serverVersion));
|
|
+ if (kernelVersion() > 0)
|
|
+ print(QByteArrayLiteral("Linux kernel version:"), versionToString8(m_kernelVersion));
|
|
+
|
|
+ print(QByteArrayLiteral("Requires strict binding:"), !m_looseBinding ? QByteArrayLiteral("yes") : QByteArrayLiteral("no"));
|
|
+ print(QByteArrayLiteral("GLSL shaders:"), m_supportsGLSL ? (m_limitedGLSL ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no"));
|
|
+ print(QByteArrayLiteral("Texture NPOT support:"), m_textureNPOT ? (m_limitedNPOT ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no"));
|
|
+ print(QByteArrayLiteral("Virtual Machine:"), m_virtualMachine ? QByteArrayLiteral("yes") : QByteArrayLiteral("no"));
|
|
+}
|
|
+
|
|
+bool GLPlatform::supports(GLFeature feature) const
|
|
+{
|
|
+ switch(feature) {
|
|
+ case LooseBinding:
|
|
+ return m_looseBinding;
|
|
+
|
|
+ case GLSL:
|
|
+ return m_supportsGLSL;
|
|
+
|
|
+ case LimitedGLSL:
|
|
+ return m_limitedGLSL;
|
|
+
|
|
+ case TextureNPOT:
|
|
+ return m_textureNPOT;
|
|
+
|
|
+ case LimitedNPOT:
|
|
+ return m_limitedNPOT;
|
|
+
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+qint64 GLPlatform::glVersion() const
|
|
+{
|
|
+ return m_glVersion;
|
|
+}
|
|
+
|
|
+qint64 GLPlatform::glslVersion() const
|
|
+{
|
|
+ return m_glslVersion;
|
|
+}
|
|
+
|
|
+qint64 GLPlatform::mesaVersion() const
|
|
+{
|
|
+ return m_mesaVersion;
|
|
+}
|
|
+
|
|
+qint64 GLPlatform::galliumVersion() const
|
|
+{
|
|
+ return m_galliumVersion;
|
|
+}
|
|
+
|
|
+qint64 GLPlatform::serverVersion() const
|
|
+{
|
|
+ return m_serverVersion;
|
|
+}
|
|
+
|
|
+qint64 GLPlatform::kernelVersion() const
|
|
+{
|
|
+ return m_kernelVersion;
|
|
+}
|
|
+
|
|
+qint64 GLPlatform::driverVersion() const
|
|
+{
|
|
+ if (isMesaDriver())
|
|
+ return mesaVersion();
|
|
+
|
|
+ return m_driverVersion;
|
|
+}
|
|
+
|
|
+Driver GLPlatform::driver() const
|
|
+{
|
|
+ return m_driver;
|
|
+}
|
|
+
|
|
+ChipClass GLPlatform::chipClass() const
|
|
+{
|
|
+ return m_chipClass;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isMesaDriver() const
|
|
+{
|
|
+ return mesaVersion() > 0;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isGalliumDriver() const
|
|
+{
|
|
+ return galliumVersion() > 0;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isRadeon() const
|
|
+{
|
|
+ return m_chipClass >= R100 && m_chipClass <= UnknownRadeon;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isNvidia() const
|
|
+{
|
|
+ return m_chipClass >= NV10 && m_chipClass <= UnknownNVidia;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isIntel() const
|
|
+{
|
|
+ return m_chipClass >= I8XX && m_chipClass <= UnknownIntel;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isVirtualBox() const
|
|
+{
|
|
+ return m_driver == Driver_VirtualBox;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isVMware() const
|
|
+{
|
|
+ return m_driver == Driver_VMware;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isSoftwareEmulation() const
|
|
+{
|
|
+ return m_driver == Driver_Softpipe || m_driver == Driver_Swrast || m_driver == Driver_Llvmpipe;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isAdreno() const
|
|
+{
|
|
+ return m_chipClass >= Adreno1XX && m_chipClass <= UnknownAdreno;
|
|
+}
|
|
+
|
|
+const QByteArray &GLPlatform::glRendererString() const
|
|
+{
|
|
+ return m_renderer;
|
|
+}
|
|
+
|
|
+const QByteArray &GLPlatform::glVendorString() const
|
|
+{
|
|
+ return m_vendor;
|
|
+}
|
|
+
|
|
+const QByteArray &GLPlatform::glVersionString() const
|
|
+{
|
|
+ return m_version;
|
|
+}
|
|
+
|
|
+const QByteArray &GLPlatform::glShadingLanguageVersionString() const
|
|
+{
|
|
+ return m_glsl_version;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isLooseBinding() const
|
|
+{
|
|
+ return m_looseBinding;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isVirtualMachine() const
|
|
+{
|
|
+ return m_virtualMachine;
|
|
+}
|
|
+
|
|
+bool GLPlatform::preferBufferSubData() const
|
|
+{
|
|
+ return m_preferBufferSubData;
|
|
+}
|
|
+
|
|
+bool GLPlatform::isGLES() const
|
|
+{
|
|
+ return m_gles;
|
|
+}
|
|
+
|
|
+void GLPlatform::cleanup()
|
|
+{
|
|
+ delete s_platform;
|
|
+ s_platform = nullptr;
|
|
+}
|
|
+
|
|
+} // namespace KWin
|
|
+
|
|
diff --git a/greeter/kwinglplatform.h b/greeter/kwinglplatform.h
|
|
new file mode 100644
|
|
index 0000000..60bebe1
|
|
--- /dev/null
|
|
+++ b/greeter/kwinglplatform.h
|
|
@@ -0,0 +1,416 @@
|
|
+/********************************************************************
|
|
+ KWin - the KDE window manager
|
|
+ This file is part of the KDE project.
|
|
+
|
|
+Copyright (C) 2010 Fredrik Höglund <fredrik@kde.org>
|
|
+
|
|
+This program is free software; you can redistribute it and/or modify
|
|
+it under the terms of the GNU General Public License as published by
|
|
+the Free Software Foundation; either version 2 of the License, or
|
|
+(at your option) any later version.
|
|
+
|
|
+This program is distributed in the hope that it will be useful,
|
|
+but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+GNU General Public License for more details.
|
|
+
|
|
+You should have received a copy of the GNU General Public License
|
|
+along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
+*********************************************************************/
|
|
+
|
|
+#ifndef KWIN_GLPLATFORM_H
|
|
+#define KWIN_GLPLATFORM_H
|
|
+
|
|
+#include <QByteArray>
|
|
+#include <QSet>
|
|
+
|
|
+namespace KWin
|
|
+{
|
|
+// forward declare method
|
|
+void cleanupGL();
|
|
+
|
|
+inline qint64 kVersionNumber(qint64 major, qint64 minor, qint64 patch = 0)
|
|
+{
|
|
+ return ((major & 0xffff) << 32) | ((minor & 0xffff) << 16) | (patch & 0xffff);
|
|
+}
|
|
+
|
|
+enum GLFeature {
|
|
+ /**
|
|
+ * Set when a texture bound to a pixmap uses the same storage as the pixmap,
|
|
+ * and thus doesn't need to be rebound when the contents of the pixmap
|
|
+ * has changed.
|
|
+ */
|
|
+ LooseBinding,
|
|
+
|
|
+ /**
|
|
+ * Set if the driver supports the following extensions:
|
|
+ * - GL_ARB_shader_objects
|
|
+ * - GL_ARB_fragment_shader
|
|
+ * - GL_ARB_vertex_shader
|
|
+ * - GL_ARB_shading_language_100
|
|
+ */
|
|
+ GLSL,
|
|
+
|
|
+ /**
|
|
+ * If set, assume the following:
|
|
+ * - No flow control or branches
|
|
+ * - No loops, unless the loops have a fixed iteration count and can be unrolled
|
|
+ * - No functions, unless they can be inlined
|
|
+ * - No indirect indexing of arrays
|
|
+ * - No support for gl_ClipVertex or gl_FrontFacing
|
|
+ * - No texture fetches in vertex shaders
|
|
+ * - Max 32 texture fetches in fragment shaders
|
|
+ * - Max 4 texture indirections
|
|
+ */
|
|
+ LimitedGLSL,
|
|
+
|
|
+ /**
|
|
+ * Set when the driver supports GL_ARB_texture_non_power_of_two.
|
|
+ */
|
|
+ TextureNPOT,
|
|
+
|
|
+ /**
|
|
+ * If set, the driver supports GL_ARB_texture_non_power_of_two with the
|
|
+ * GL_ARB_texture_rectangle limitations.
|
|
+ *
|
|
+ * This means no support for mipmap filters, and that only the following
|
|
+ * wrap modes are supported:
|
|
+ * - GL_CLAMP
|
|
+ * - GL_CLAMP_TO_EDGE
|
|
+ * - GL_CLAMP_TO_BORDER
|
|
+ */
|
|
+ LimitedNPOT
|
|
+};
|
|
+
|
|
+enum Driver {
|
|
+ Driver_R100, // Technically "Radeon"
|
|
+ Driver_R200,
|
|
+ Driver_R300C,
|
|
+ Driver_R300G,
|
|
+ Driver_R600C,
|
|
+ Driver_R600G,
|
|
+ Driver_Nouveau,
|
|
+ Driver_Intel,
|
|
+ Driver_NVidia,
|
|
+ Driver_Catalyst,
|
|
+ Driver_Swrast,
|
|
+ Driver_Softpipe,
|
|
+ Driver_Llvmpipe,
|
|
+ Driver_VirtualBox,
|
|
+ Driver_VMware,
|
|
+ Driver_Qualcomm,
|
|
+ Driver_Unknown
|
|
+};
|
|
+
|
|
+enum ChipClass {
|
|
+ // Radeon
|
|
+ R100 = 0, // GL1.3 DX7 2000
|
|
+ R200, // GL1.4 DX8.1 SM 1.4 2001
|
|
+ R300, // GL2.0 DX9 SM 2.0 2002
|
|
+ R400, // GL2.0 DX9b SM 2.0b 2004
|
|
+ R500, // GL2.0 DX9c SM 3.0 2005
|
|
+ R600, // GL3.3 DX10 SM 4.0 2006
|
|
+ R700, // GL3.3 DX10.1 SM 4.1 2008
|
|
+ Evergreen, // GL4.0 CL1.0 DX11 SM 5.0 2009
|
|
+ NorthernIslands, // GL4.0 CL1.1 DX11 SM 5.0 2010
|
|
+ UnknownRadeon = 999,
|
|
+
|
|
+ // NVIDIA
|
|
+ NV10 = 1000, // GL1.2 DX7 1999
|
|
+ NV20, // GL1.3 DX8 SM 1.1 2001
|
|
+ NV30, // GL1.5 DX9a SM 2.0 2003
|
|
+ NV40, // GL2.1 DX9c SM 3.0 2004
|
|
+ G80, // GL3.3 DX10 SM 4.0 2006
|
|
+ GF100, // GL4.1 CL1.1 DX11 SM 5.0 2010
|
|
+ UnknownNVidia = 1999,
|
|
+
|
|
+ // Intel
|
|
+ I8XX = 2000, // GL1.3 DX7 2001
|
|
+ I915, // GL1.4/1.5 DX9/DX9c SM 2.0 2004
|
|
+ I965, // GL2.0/2.1 DX9/DX10 SM 3.0/4.0 2006
|
|
+ SandyBridge, // GL3.1 CL1.1 DX10.1 SM 4.0 2010
|
|
+ IvyBridge, // GL4.0 CL1.1 DX11 SM 5.0 2012
|
|
+ Haswell, // GL4.0 CL1.2 DX11.1 SM 5.0 2013
|
|
+ UnknownIntel = 2999,
|
|
+
|
|
+ // Qualcomm Adreno
|
|
+ // from https://en.wikipedia.org/wiki/Adreno
|
|
+ Adreno1XX = 3000, // GLES1.1
|
|
+ Adreno2XX, // GLES2.0 DX9c
|
|
+ Adreno3XX, // GLES3.0 CL1.1 DX11.1
|
|
+ Adreno4XX, // GLES3.1 CL1.2 DX11.2
|
|
+ Adreno5XX, // GLES3.1 CL2.0 DX11.2
|
|
+ UnknownAdreno = 3999,
|
|
+
|
|
+ UnknownChipClass = 99999
|
|
+};
|
|
+
|
|
+
|
|
+class GLPlatform
|
|
+{
|
|
+public:
|
|
+ ~GLPlatform();
|
|
+
|
|
+ /**
|
|
+ * Runs the detection code using the current OpenGL context.
|
|
+ */
|
|
+ void detect();
|
|
+
|
|
+ /**
|
|
+ * Prints the results of the detection code.
|
|
+ */
|
|
+ void printResults() const;
|
|
+
|
|
+ /**
|
|
+ * Returns a pointer to the GLPlatform instance.
|
|
+ */
|
|
+ static GLPlatform *instance();
|
|
+
|
|
+ /**
|
|
+ * Returns true if the driver support the given feature, and false otherwise.
|
|
+ */
|
|
+ bool supports(GLFeature feature) const;
|
|
+
|
|
+ /**
|
|
+ * Returns the OpenGL version.
|
|
+ */
|
|
+ qint64 glVersion() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the GLSL version if the driver supports GLSL, and 0 otherwise.
|
|
+ */
|
|
+ qint64 glslVersion() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the Mesa version if the driver is a Mesa driver, and 0 otherwise.
|
|
+ */
|
|
+ qint64 mesaVersion() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the Gallium version if the driver is a Gallium driver, and 0 otherwise.
|
|
+ */
|
|
+ qint64 galliumVersion() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the X server version.
|
|
+ *
|
|
+ * Note that the version number changed from 7.2 to 1.3 in the first release
|
|
+ * following the doupling of the X server from the katamari.
|
|
+ *
|
|
+ * For non X.org servers, this method returns 0.
|
|
+ */
|
|
+ qint64 serverVersion() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the Linux kernel version.
|
|
+ *
|
|
+ * If the kernel is not a Linux kernel, this method returns 0.
|
|
+ */
|
|
+ qint64 kernelVersion() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the driver version.
|
|
+ *
|
|
+ * For Mesa drivers, this is the same as the Mesa version number.
|
|
+ */
|
|
+ qint64 driverVersion() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the driver.
|
|
+ */
|
|
+ Driver driver() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the chip class.
|
|
+ */
|
|
+ ChipClass chipClass() const;
|
|
+
|
|
+ /**
|
|
+ * Returns true if the driver is a Mesa driver, and false otherwise.
|
|
+ */
|
|
+ bool isMesaDriver() const;
|
|
+
|
|
+ /**
|
|
+ * Returns true if the driver is a Gallium driver, and false otherwise.
|
|
+ */
|
|
+ bool isGalliumDriver() const;
|
|
+
|
|
+ /**
|
|
+ * Returns true if the GPU is a Radeon GPU, and false otherwise.
|
|
+ */
|
|
+ bool isRadeon() const;
|
|
+
|
|
+ /**
|
|
+ * Returns true if the GPU is an NVIDIA GPU, and false otherwise.
|
|
+ */
|
|
+ bool isNvidia() const;
|
|
+
|
|
+ /**
|
|
+ * Returns true if the GPU is an Intel GPU, and false otherwise.
|
|
+ */
|
|
+ bool isIntel() const;
|
|
+
|
|
+ /**
|
|
+ * @returns @c true if the "GPU" is a VirtualBox GPU, and @c false otherwise.
|
|
+ * @since 4.10
|
|
+ **/
|
|
+ bool isVirtualBox() const;
|
|
+
|
|
+ /**
|
|
+ * @returns @c true if the "GPU" is a VMWare GPU, and @c false otherwise.
|
|
+ * @since 4.10
|
|
+ **/
|
|
+ bool isVMware() const;
|
|
+
|
|
+ /**
|
|
+ * @returns @c true if OpenGL is emulated in software.
|
|
+ * @since 4.7
|
|
+ **/
|
|
+ bool isSoftwareEmulation() const;
|
|
+
|
|
+ /**
|
|
+ * @returns @c true if the driver is known to be from a virtual machine.
|
|
+ * @since 4.10
|
|
+ **/
|
|
+ bool isVirtualMachine() const;
|
|
+
|
|
+ /**
|
|
+ * @returns @c true if the GPU is a Qualcomm Adreno GPU, and false otherwise
|
|
+ * @since 5.8
|
|
+ **/
|
|
+ bool isAdreno() const;
|
|
+
|
|
+ /**
|
|
+ * @returns the GL_VERSION string as provided by the driver.
|
|
+ * @since 4.9
|
|
+ **/
|
|
+ const QByteArray &glVersionString() const;
|
|
+ /**
|
|
+ * @returns the GL_RENDERER string as provided by the driver.
|
|
+ * @since 4.9
|
|
+ **/
|
|
+ const QByteArray &glRendererString() const;
|
|
+ /**
|
|
+ * @returns the GL_VENDOR string as provided by the driver.
|
|
+ * @since 4.9
|
|
+ **/
|
|
+ const QByteArray &glVendorString() const;
|
|
+ /**
|
|
+ * @returns the GL_SHADING_LANGUAGE_VERSION string as provided by the driver.
|
|
+ * If the driver does not support the OpenGL Shading Language a null bytearray is returned.
|
|
+ * @since 4.9
|
|
+ **/
|
|
+ const QByteArray &glShadingLanguageVersionString() const;
|
|
+ /**
|
|
+ * @returns Whether the driver supports loose texture binding.
|
|
+ * @since 4.9
|
|
+ **/
|
|
+ bool isLooseBinding() const;
|
|
+ /**
|
|
+ * @returns Whether OpenGL ES is used
|
|
+ */
|
|
+ bool isGLES() const;
|
|
+
|
|
+ /**
|
|
+ * Returns true if glMapBufferRange() is likely to perform worse than glBufferSubData()
|
|
+ * when updating an unused range of a buffer object, and false otherwise.
|
|
+ *
|
|
+ * @since 4.11
|
|
+ */
|
|
+ bool preferBufferSubData() const;
|
|
+
|
|
+ /**
|
|
+ * @returns a human readable form of the @p version as a QString.
|
|
+ * @since 4.9
|
|
+ * @see glVersion
|
|
+ * @see glslVersion
|
|
+ * @see driverVersion
|
|
+ * @see mesaVersion
|
|
+ * @see galliumVersion
|
|
+ * @see kernelVersion
|
|
+ * @see serverVersion
|
|
+ **/
|
|
+ static QString versionToString(qint64 version);
|
|
+ /**
|
|
+ * @returns a human readable form of the @p version as a QByteArray.
|
|
+ * @since 5.5
|
|
+ * @see glVersion
|
|
+ * @see glslVersion
|
|
+ * @see driverVersion
|
|
+ * @see mesaVersion
|
|
+ * @see galliumVersion
|
|
+ * @see kernelVersion
|
|
+ * @see serverVersion
|
|
+ **/
|
|
+ static QByteArray versionToString8(qint64 version);
|
|
+
|
|
+ /**
|
|
+ * @returns a human readable form for the @p driver as a QString.
|
|
+ * @since 4.9
|
|
+ * @see driver
|
|
+ **/
|
|
+ static QString driverToString(Driver driver);
|
|
+ /**
|
|
+ * @returns a human readable form for the @p driver as a QByteArray.
|
|
+ * @since 5.5
|
|
+ * @see driver
|
|
+ **/
|
|
+ static QByteArray driverToString8(Driver driver);
|
|
+
|
|
+ /**
|
|
+ * @returns a human readable form for the @p chipClass as a QString.
|
|
+ * @since 4.9
|
|
+ * @see chipClass
|
|
+ **/
|
|
+ static QString chipClassToString(ChipClass chipClass);
|
|
+ /**
|
|
+ * @returns a human readable form for the @p chipClass as a QByteArray.
|
|
+ * @since 5.5
|
|
+ * @see chipClass
|
|
+ **/
|
|
+ static QByteArray chipClassToString8(ChipClass chipClass);
|
|
+
|
|
+private:
|
|
+ GLPlatform();
|
|
+ friend void KWin::cleanupGL();
|
|
+ static void cleanup();
|
|
+
|
|
+private:
|
|
+ QByteArray m_renderer;
|
|
+ QByteArray m_vendor;
|
|
+ QByteArray m_version;
|
|
+ QByteArray m_glsl_version;
|
|
+ QByteArray m_chipset;
|
|
+ QSet<QByteArray> m_extensions;
|
|
+ Driver m_driver;
|
|
+ ChipClass m_chipClass;
|
|
+ qint64 m_glVersion;
|
|
+ qint64 m_glslVersion;
|
|
+ qint64 m_mesaVersion;
|
|
+ qint64 m_driverVersion;
|
|
+ qint64 m_galliumVersion;
|
|
+ qint64 m_serverVersion;
|
|
+ qint64 m_kernelVersion;
|
|
+ bool m_looseBinding: 1;
|
|
+ bool m_supportsGLSL: 1;
|
|
+ bool m_limitedGLSL: 1;
|
|
+ bool m_textureNPOT: 1;
|
|
+ bool m_limitedNPOT: 1;
|
|
+ bool m_virtualMachine: 1;
|
|
+ bool m_preferBufferSubData: 1;
|
|
+ bool m_gles: 1;
|
|
+ static GLPlatform *s_platform;
|
|
+};
|
|
+
|
|
+inline GLPlatform *GLPlatform::instance()
|
|
+{
|
|
+ if (!s_platform)
|
|
+ s_platform = new GLPlatform;
|
|
+
|
|
+ return s_platform;
|
|
+}
|
|
+
|
|
+} // namespace KWin
|
|
+
|
|
+#endif // KWIN_GLPLATFORM_H
|
|
+
|
|
diff --git a/greeter/seccomp_filter.cpp b/greeter/seccomp_filter.cpp
|
|
index 79244f9..9d61d4a 100644
|
|
--- a/greeter/seccomp_filter.cpp
|
|
+++ b/greeter/seccomp_filter.cpp
|
|
@@ -21,9 +21,11 @@ You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*********************************************************************/
|
|
#include "seccomp_filter.h"
|
|
+#include "kwinglplatform.h"
|
|
|
|
#include <QDBusConnection>
|
|
#include <QOpenGLContext>
|
|
+#include <QOffscreenSurface>
|
|
|
|
#include <seccomp.h>
|
|
#include <sys/socket.h>
|
|
@@ -38,7 +40,22 @@ void init()
|
|
{
|
|
// trigger OpenGL context creation
|
|
// we need this to ensure that all required files are opened for write
|
|
- QOpenGLContext::supportsThreadedOpenGL();
|
|
+ // on NVIDIA we need to keep write around, otherwise BUG 384005 happens
|
|
+ bool writeSupported = true;
|
|
+ QScopedPointer<QOffscreenSurface> dummySurface(new QOffscreenSurface);
|
|
+ dummySurface->create();
|
|
+ QOpenGLContext dummyGlContext;
|
|
+ if (dummyGlContext.create()) {
|
|
+ if (dummyGlContext.makeCurrent(dummySurface.data())) {
|
|
+ auto gl = KWin::GLPlatform::instance();
|
|
+ gl->detect();
|
|
+ gl->printResults();
|
|
+ if (gl->driver() == KWin::Driver_NVidia) {
|
|
+ // BUG: 384005
|
|
+ writeSupported = false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
|
|
// access DBus to have the socket open
|
|
QDBusConnection::sessionBus();
|
|
@@ -57,8 +74,10 @@ void init()
|
|
|
|
// instead disallow opening new files for writing
|
|
// they should fail with EPERM error
|
|
- seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY));
|
|
- seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR));
|
|
+ if (writeSupported) {
|
|
+ seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY));
|
|
+ seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR));
|
|
+ }
|
|
seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT));
|
|
|
|
// disallow going to a socket
|
|
--
|
|
2.14.1
|
|
|