File indexing completed on 2024-11-10 04:56:54

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2010 Fredrik Höglund <fredrik@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "opengl/glplatform.h"
0011 // include kwinglutils_funcs.h to avoid the redeclaration issues
0012 // between qopengl.h and epoxy/gl.h
0013 #include "effect/xcb.h"
0014 #include "opengl/glutils_funcs.h"
0015 #include <epoxy/gl.h>
0016 
0017 #include <QDebug>
0018 #include <QOpenGLContext>
0019 #include <QRegularExpression>
0020 #include <QStringList>
0021 
0022 #include <sys/utsname.h>
0023 
0024 #include <iomanip>
0025 #include <ios>
0026 #include <iostream>
0027 
0028 namespace KWin
0029 {
0030 
0031 std::unique_ptr<GLPlatform> GLPlatform::s_platform;
0032 
0033 // Extracts the portion of a string that matches a regular expression
0034 static QString extract(const QString &text, const QString &pattern)
0035 {
0036     const QRegularExpression regexp(pattern);
0037     const QRegularExpressionMatch match = regexp.match(text);
0038     if (!match.hasMatch()) {
0039         return QString();
0040     }
0041     return match.captured();
0042 }
0043 
0044 static ChipClass detectRadeonClass(QByteArrayView chipset)
0045 {
0046     if (chipset.isEmpty()) {
0047         return UnknownRadeon;
0048     }
0049 
0050     if (chipset.contains("R100")
0051         || chipset.contains("RV100")
0052         || chipset.contains("RS100")) {
0053         return R100;
0054     }
0055 
0056     if (chipset.contains("RV200")
0057         || chipset.contains("RS200")
0058         || chipset.contains("R200")
0059         || chipset.contains("RV250")
0060         || chipset.contains("RS300")
0061         || chipset.contains("RV280")) {
0062         return R200;
0063     }
0064 
0065     if (chipset.contains("R300")
0066         || chipset.contains("R350")
0067         || chipset.contains("R360")
0068         || chipset.contains("RV350")
0069         || chipset.contains("RV370")
0070         || chipset.contains("RV380")) {
0071         return R300;
0072     }
0073 
0074     if (chipset.contains("R420")
0075         || chipset.contains("R423")
0076         || chipset.contains("R430")
0077         || chipset.contains("R480")
0078         || chipset.contains("R481")
0079         || chipset.contains("RV410")
0080         || chipset.contains("RS400")
0081         || chipset.contains("RC410")
0082         || chipset.contains("RS480")
0083         || chipset.contains("RS482")
0084         || chipset.contains("RS600")
0085         || chipset.contains("RS690")
0086         || chipset.contains("RS740")) {
0087         return R400;
0088     }
0089 
0090     if (chipset.contains("RV515")
0091         || chipset.contains("R520")
0092         || chipset.contains("RV530")
0093         || chipset.contains("R580")
0094         || chipset.contains("RV560")
0095         || chipset.contains("RV570")) {
0096         return R500;
0097     }
0098 
0099     if (chipset.contains("R600")
0100         || chipset.contains("RV610")
0101         || chipset.contains("RV630")
0102         || chipset.contains("RV670")
0103         || chipset.contains("RV620")
0104         || chipset.contains("RV635")
0105         || chipset.contains("RS780")
0106         || chipset.contains("RS880")) {
0107         return R600;
0108     }
0109 
0110     if (chipset.contains("R700")
0111         || chipset.contains("RV770")
0112         || chipset.contains("RV730")
0113         || chipset.contains("RV710")
0114         || chipset.contains("RV740")) {
0115         return R700;
0116     }
0117 
0118     if (chipset.contains("EVERGREEN") // Not an actual chipset, but returned by R600G in 7.9
0119         || chipset.contains("CEDAR")
0120         || chipset.contains("REDWOOD")
0121         || chipset.contains("JUNIPER")
0122         || chipset.contains("CYPRESS")
0123         || chipset.contains("HEMLOCK")
0124         || chipset.contains("PALM")) {
0125         return Evergreen;
0126     }
0127 
0128     if (chipset.contains("SUMO")
0129         || chipset.contains("SUMO2")
0130         || chipset.contains("BARTS")
0131         || chipset.contains("TURKS")
0132         || chipset.contains("CAICOS")
0133         || chipset.contains("CAYMAN")) {
0134         return NorthernIslands;
0135     }
0136 
0137     if (chipset.contains("TAHITI")
0138         || chipset.contains("PITCAIRN")
0139         || chipset.contains("VERDE")
0140         || chipset.contains("OLAND")
0141         || chipset.contains("HAINAN")) {
0142         return SouthernIslands;
0143     }
0144 
0145     if (chipset.contains("BONAIRE")
0146         || chipset.contains("KAVERI")
0147         || chipset.contains("KABINI")
0148         || chipset.contains("HAWAII")
0149         || chipset.contains("MULLINS")) {
0150         return SeaIslands;
0151     }
0152 
0153     if (chipset.contains("TONGA")
0154         || chipset.contains("TOPAZ")
0155         || chipset.contains("FIJI")
0156         || chipset.contains("CARRIZO")
0157         || chipset.contains("STONEY")) {
0158         return VolcanicIslands;
0159     }
0160 
0161     if (chipset.contains("POLARIS10")
0162         || chipset.contains("POLARIS11")
0163         || chipset.contains("POLARIS12")
0164         || chipset.contains("VEGAM")) {
0165         return ArcticIslands;
0166     }
0167 
0168     if (chipset.contains("VEGA10")
0169         || chipset.contains("VEGA12")
0170         || chipset.contains("VEGA20")
0171         || chipset.contains("RAVEN")
0172         || chipset.contains("RAVEN2")
0173         || chipset.contains("RENOIR")
0174         || chipset.contains("ARCTURUS")) {
0175         return Vega;
0176     }
0177 
0178     if (chipset.contains("NAVI10")
0179         || chipset.contains("NAVI12")
0180         || chipset.contains("NAVI14")) {
0181         return Navi;
0182     }
0183 
0184     const QString chipset16 = QString::fromLatin1(chipset);
0185     QString name = extract(chipset16, QStringLiteral("HD [0-9]{4}")); // HD followed by a space and 4 digits
0186     if (!name.isEmpty()) {
0187         const int id = QStringView(name).right(4).toInt();
0188         if (id == 6250 || id == 6310) { // Palm
0189             return Evergreen;
0190         }
0191 
0192         if (id >= 6000 && id < 7000) {
0193             return NorthernIslands; // HD 6xxx
0194         }
0195 
0196         if (id >= 5000 && id < 6000) {
0197             return Evergreen; // HD 5xxx
0198         }
0199 
0200         if (id >= 4000 && id < 5000) {
0201             return R700; // HD 4xxx
0202         }
0203 
0204         if (id >= 2000 && id < 4000) { // HD 2xxx/3xxx
0205             return R600;
0206         }
0207 
0208         return UnknownRadeon;
0209     }
0210 
0211     name = extract(chipset16, QStringLiteral("X[0-9]{3,4}")); // X followed by 3-4 digits
0212     if (!name.isEmpty()) {
0213         const int id = QStringView(name).mid(1, -1).toInt();
0214 
0215         // X1xxx
0216         if (id >= 1300) {
0217             return R500;
0218         }
0219 
0220         // X7xx, X8xx, X12xx, 2100
0221         if ((id >= 700 && id < 1000) || id >= 1200) {
0222             return R400;
0223         }
0224 
0225         // X200, X3xx, X5xx, X6xx, X10xx, X11xx
0226         if ((id >= 300 && id < 700) || (id >= 1000 && id < 1200)) {
0227             return R300;
0228         }
0229 
0230         return UnknownRadeon;
0231     }
0232 
0233     name = extract(chipset16, QStringLiteral("\\b[0-9]{4}\\b")); // A group of 4 digits
0234     if (!name.isEmpty()) {
0235         const int id = name.toInt();
0236 
0237         // 7xxx
0238         if (id >= 7000 && id < 8000) {
0239             return R100;
0240         }
0241 
0242         // 8xxx, 9xxx
0243         if (id >= 8000 && id < 9500) {
0244             return R200;
0245         }
0246 
0247         // 9xxx
0248         if (id >= 9500) {
0249             return R300;
0250         }
0251 
0252         if (id == 2100) {
0253             return R400;
0254         }
0255     }
0256 
0257     return UnknownRadeon;
0258 }
0259 
0260 static ChipClass detectNVidiaClass(const QString &chipset)
0261 {
0262     QString name = extract(chipset, QStringLiteral("\\bNV[0-9,A-F]{2}\\b")); // NV followed by two hexadecimal digits
0263     if (!name.isEmpty()) {
0264         const int id = QStringView(chipset).mid(2, -1).toInt(nullptr, 16); // Strip the 'NV' from the id
0265 
0266         switch (id & 0xf0) {
0267         case 0x00:
0268         case 0x10:
0269             return NV10;
0270 
0271         case 0x20:
0272             return NV20;
0273 
0274         case 0x30:
0275             return NV30;
0276 
0277         case 0x40:
0278         case 0x60:
0279             return NV40;
0280 
0281         case 0x50:
0282         case 0x80:
0283         case 0x90:
0284         case 0xA0:
0285             return G80;
0286 
0287         default:
0288             return UnknownNVidia;
0289         }
0290     }
0291 
0292     if (chipset.contains(QLatin1String("GeForce2")) || chipset.contains(QLatin1String("GeForce 256"))) {
0293         return NV10;
0294     }
0295 
0296     if (chipset.contains(QLatin1String("GeForce3"))) {
0297         return NV20;
0298     }
0299 
0300     if (chipset.contains(QLatin1String("GeForce4"))) {
0301         if (chipset.contains(QLatin1String("MX 420"))
0302             || chipset.contains(QLatin1String("MX 440")) // including MX 440SE
0303             || chipset.contains(QLatin1String("MX 460"))
0304             || chipset.contains(QLatin1String("MX 4000"))
0305             || chipset.contains(QLatin1String("PCX 4300"))) {
0306             return NV10;
0307         }
0308 
0309         return NV20;
0310     }
0311 
0312     // GeForce 5,6,7,8,9
0313     name = extract(chipset, QStringLiteral("GeForce (FX |PCX |Go )?\\d{4}(M|\\b)")).trimmed();
0314     if (!name.isEmpty()) {
0315         if (!name[name.length() - 1].isDigit()) {
0316             name.chop(1);
0317         }
0318 
0319         const int id = QStringView(name).right(4).toInt();
0320         if (id < 6000) {
0321             return NV30;
0322         }
0323 
0324         if (id >= 6000 && id < 8000) {
0325             return NV40;
0326         }
0327 
0328         if (id >= 8000) {
0329             return G80;
0330         }
0331 
0332         return UnknownNVidia;
0333     }
0334 
0335     // GeForce 100/200/300/400/500
0336     name = extract(chipset, QStringLiteral("GeForce (G |GT |GTX |GTS )?\\d{3}(M|\\b)")).trimmed();
0337     if (!name.isEmpty()) {
0338         if (!name[name.length() - 1].isDigit()) {
0339             name.chop(1);
0340         }
0341 
0342         const int id = QStringView(name).right(3).toInt();
0343         if (id >= 100 && id < 600) {
0344             if (id >= 400) {
0345                 return GF100;
0346             }
0347 
0348             return G80;
0349         }
0350         return UnknownNVidia;
0351     }
0352 
0353     return UnknownNVidia;
0354 }
0355 static inline ChipClass detectNVidiaClass(QByteArrayView chipset)
0356 {
0357     return detectNVidiaClass(QString::fromLatin1(chipset));
0358 }
0359 
0360 static ChipClass detectIntelClass(QByteArrayView chipset)
0361 {
0362     // see mesa repository: src/mesa/drivers/dri/intel/intel_context.c
0363     // GL 1.3, DX8? SM ?
0364     if (chipset.contains("845G")
0365         || chipset.contains("830M")
0366         || chipset.contains("852GM/855GM")
0367         || chipset.contains("865G")) {
0368         return I8XX;
0369     }
0370 
0371     // GL 1.4, DX 9.0, SM 2.0
0372     if (chipset.contains("915G")
0373         || chipset.contains("E7221G")
0374         || chipset.contains("915GM")
0375         || chipset.contains("945G") // DX 9.0c
0376         || chipset.contains("945GM")
0377         || chipset.contains("945GME")
0378         || chipset.contains("Q33") // GL1.5
0379         || chipset.contains("Q35")
0380         || chipset.contains("G33")
0381         || chipset.contains("965Q") // GMA 3000, but apparently considered gen 4 by the driver
0382         || chipset.contains("946GZ") // GMA 3000, but apparently considered gen 4 by the driver
0383         || chipset.contains("IGD")) {
0384         return I915;
0385     }
0386 
0387     // GL 2.0, DX 9.0c, SM 3.0
0388     if (chipset.contains("965G")
0389         || chipset.contains("G45/G43") // SM 4.0
0390         || chipset.contains("965GM") // GL 2.1
0391         || chipset.contains("965GME/GLE")
0392         || chipset.contains("GM45")
0393         || chipset.contains("Q45/Q43")
0394         || chipset.contains("G41")
0395         || chipset.contains("B43")
0396         || chipset.contains("Ironlake")) {
0397         return I965;
0398     }
0399 
0400     // GL 3.1, CL 1.1, DX 10.1
0401     if (chipset.contains("Sandybridge") || chipset.contains("SNB GT")) {
0402         return SandyBridge;
0403     }
0404 
0405     // GL4.0, CL1.1, DX11, SM 5.0
0406     if (chipset.contains("Ivybridge") || chipset.contains("IVB GT")) {
0407         return IvyBridge;
0408     }
0409 
0410     // GL4.0, CL1.2, DX11.1, SM 5.0
0411     if (chipset.contains("Haswell") || chipset.contains("HSW GT")) {
0412         return Haswell;
0413     }
0414     if (chipset.contains("BYT")) {
0415         return BayTrail;
0416     }
0417     if (chipset.contains("CHV") || chipset.contains("BSW")) {
0418         return Cherryview;
0419     }
0420     if (chipset.contains("BDW GT")) {
0421         return Broadwell;
0422     }
0423     if (chipset.contains("SKL GT")) {
0424         return Skylake;
0425     }
0426     if (chipset.contains("APL")) {
0427         return ApolloLake;
0428     }
0429     if (chipset.contains("KBL GT")) {
0430         return KabyLake;
0431     }
0432     if (chipset.contains("WHL GT")) {
0433         return WhiskeyLake;
0434     }
0435     if (chipset.contains("CML GT")) {
0436         return CometLake;
0437     }
0438     if (chipset.contains("CNL GT")) {
0439         return CannonLake;
0440     }
0441     if (chipset.contains("CFL GT")) {
0442         return CoffeeLake;
0443     }
0444     if (chipset.contains("ICL GT")) {
0445         return IceLake;
0446     }
0447     if (chipset.contains("TGL GT")) {
0448         return TigerLake;
0449     }
0450 
0451     return UnknownIntel;
0452 }
0453 
0454 static ChipClass detectQualcommClass(QByteArrayView chipClass)
0455 {
0456     if (!chipClass.contains("Adreno")) {
0457         return UnknownChipClass;
0458     }
0459     const auto parts = chipClass.toByteArray().split(' ');
0460     if (parts.count() < 3) {
0461         return UnknownAdreno;
0462     }
0463     bool ok = false;
0464     const int value = parts.at(2).toInt(&ok);
0465     if (ok) {
0466         if (value >= 100 && value < 200) {
0467             return Adreno1XX;
0468         } else if (value >= 200 && value < 300) {
0469             return Adreno2XX;
0470         } else if (value >= 300 && value < 400) {
0471             return Adreno3XX;
0472         } else if (value >= 400 && value < 500) {
0473             return Adreno4XX;
0474         } else if (value >= 500 && value < 600) {
0475             return Adreno5XX;
0476         }
0477     }
0478     return UnknownAdreno;
0479 }
0480 
0481 static ChipClass detectPanfrostClass(QByteArrayView chipClass)
0482 {
0483     // Keep the list of supported Mali chipset up to date with https://docs.mesa3d.org/drivers/panfrost.html
0484     if (chipClass.contains("T720") || chipClass.contains("T760")) {
0485         return MaliT7XX;
0486     }
0487 
0488     if (chipClass.contains("T820") || chipClass.contains("T830") || chipClass.contains("T860") || chipClass.contains("T880")) {
0489         return MaliT8XX;
0490     }
0491 
0492     if (chipClass.contains("G31") || chipClass.contains("G51") || chipClass.contains("G52") || chipClass.contains("G57") || chipClass.contains("G72") || chipClass.contains("G76")) {
0493         return MaliGXX;
0494     }
0495 
0496     return UnknownPanfrost;
0497 }
0498 
0499 static ChipClass detectLimaClass(QByteArrayView chipClass)
0500 {
0501     if (chipClass.contains("400")) {
0502         return Mali400;
0503     } else if (chipClass.contains("450")) {
0504         return Mali450;
0505     } else if (chipClass.contains("470")) {
0506         return Mali470;
0507     }
0508 
0509     return UnknownLima;
0510 }
0511 
0512 static ChipClass detectVC4Class(QByteArrayView chipClass)
0513 {
0514     if (chipClass.contains("2.1")) {
0515         return VC4_2_1;
0516     }
0517 
0518     return UnknownVideoCore4;
0519 }
0520 
0521 static ChipClass detectV3DClass(QByteArrayView chipClass)
0522 {
0523     if (chipClass.contains("4.2")) {
0524         return V3D_4_2;
0525     }
0526 
0527     return UnknownVideoCore3D;
0528 }
0529 
0530 QString GLPlatform::driverToString(Driver driver)
0531 {
0532     return QString::fromLatin1(driverToString8(driver));
0533 }
0534 QByteArray GLPlatform::driverToString8(Driver driver)
0535 {
0536     switch (driver) {
0537     case Driver_R100:
0538         return QByteArrayLiteral("Radeon");
0539     case Driver_R200:
0540         return QByteArrayLiteral("R200");
0541     case Driver_R300C:
0542         return QByteArrayLiteral("R300C");
0543     case Driver_R300G:
0544         return QByteArrayLiteral("R300G");
0545     case Driver_R600C:
0546         return QByteArrayLiteral("R600C");
0547     case Driver_R600G:
0548         return QByteArrayLiteral("R600G");
0549     case Driver_RadeonSI:
0550         return QByteArrayLiteral("RadeonSI");
0551     case Driver_Nouveau:
0552         return QByteArrayLiteral("Nouveau");
0553     case Driver_Intel:
0554         return QByteArrayLiteral("Intel");
0555     case Driver_NVidia:
0556         return QByteArrayLiteral("NVIDIA");
0557     case Driver_Catalyst:
0558         return QByteArrayLiteral("Catalyst");
0559     case Driver_Swrast:
0560         return QByteArrayLiteral("Software rasterizer");
0561     case Driver_Softpipe:
0562         return QByteArrayLiteral("softpipe");
0563     case Driver_Llvmpipe:
0564         return QByteArrayLiteral("LLVMpipe");
0565     case Driver_VirtualBox:
0566         return QByteArrayLiteral("VirtualBox (Chromium)");
0567     case Driver_VMware:
0568         return QByteArrayLiteral("VMware (SVGA3D)");
0569     case Driver_Qualcomm:
0570         return QByteArrayLiteral("Qualcomm");
0571     case Driver_Virgl:
0572         return QByteArrayLiteral("Virgl (virtio-gpu, Qemu/KVM guest)");
0573     case Driver_Panfrost:
0574         return QByteArrayLiteral("Panfrost");
0575     case Driver_Lima:
0576         return QByteArrayLiteral("Mali (Lima)");
0577     case Driver_VC4:
0578         return QByteArrayLiteral("VideoCore IV");
0579     case Driver_V3D:
0580         return QByteArrayLiteral("VideoCore 3D");
0581 
0582     default:
0583         return QByteArrayLiteral("Unknown");
0584     }
0585 }
0586 
0587 QString GLPlatform::chipClassToString(ChipClass chipClass)
0588 {
0589     return QString::fromLatin1(chipClassToString8(chipClass));
0590 }
0591 QByteArray GLPlatform::chipClassToString8(ChipClass chipClass)
0592 {
0593     switch (chipClass) {
0594     case R100:
0595         return QByteArrayLiteral("R100");
0596     case R200:
0597         return QByteArrayLiteral("R200");
0598     case R300:
0599         return QByteArrayLiteral("R300");
0600     case R400:
0601         return QByteArrayLiteral("R400");
0602     case R500:
0603         return QByteArrayLiteral("R500");
0604     case R600:
0605         return QByteArrayLiteral("R600");
0606     case R700:
0607         return QByteArrayLiteral("R700");
0608     case Evergreen:
0609         return QByteArrayLiteral("EVERGREEN");
0610     case NorthernIslands:
0611         return QByteArrayLiteral("Northern Islands");
0612     case SouthernIslands:
0613         return QByteArrayLiteral("Southern Islands");
0614     case SeaIslands:
0615         return QByteArrayLiteral("Sea Islands");
0616     case VolcanicIslands:
0617         return QByteArrayLiteral("Volcanic Islands");
0618     case ArcticIslands:
0619         return QByteArrayLiteral("Arctic Islands");
0620     case Vega:
0621         return QByteArrayLiteral("Vega");
0622     case Navi:
0623         return QByteArrayLiteral("Navi");
0624 
0625     case NV10:
0626         return QByteArrayLiteral("NV10");
0627     case NV20:
0628         return QByteArrayLiteral("NV20");
0629     case NV30:
0630         return QByteArrayLiteral("NV30");
0631     case NV40:
0632         return QByteArrayLiteral("NV40/G70");
0633     case G80:
0634         return QByteArrayLiteral("G80/G90");
0635     case GF100:
0636         return QByteArrayLiteral("GF100");
0637 
0638     case I8XX:
0639         return QByteArrayLiteral("i830/i835");
0640     case I915:
0641         return QByteArrayLiteral("i915/i945");
0642     case I965:
0643         return QByteArrayLiteral("i965");
0644     case SandyBridge:
0645         return QByteArrayLiteral("SandyBridge");
0646     case IvyBridge:
0647         return QByteArrayLiteral("IvyBridge");
0648     case Haswell:
0649         return QByteArrayLiteral("Haswell");
0650     case BayTrail:
0651         return QByteArrayLiteral("Bay Trail");
0652     case Cherryview:
0653         return QByteArrayLiteral("Cherryview");
0654     case Broadwell:
0655         return QByteArrayLiteral("Broadwell");
0656     case ApolloLake:
0657         return QByteArrayLiteral("Apollo Lake");
0658     case Skylake:
0659         return QByteArrayLiteral("Skylake");
0660     case GeminiLake:
0661         return QByteArrayLiteral("Gemini Lake");
0662     case KabyLake:
0663         return QByteArrayLiteral("Kaby Lake");
0664     case CoffeeLake:
0665         return QByteArrayLiteral("Coffee Lake");
0666     case WhiskeyLake:
0667         return QByteArrayLiteral("Whiskey Lake");
0668     case CometLake:
0669         return QByteArrayLiteral("Comet Lake");
0670     case CannonLake:
0671         return QByteArrayLiteral("Cannon Lake");
0672     case IceLake:
0673         return QByteArrayLiteral("Ice Lake");
0674     case TigerLake:
0675         return QByteArrayLiteral("Tiger Lake");
0676 
0677     case Adreno1XX:
0678         return QByteArrayLiteral("Adreno 1xx series");
0679     case Adreno2XX:
0680         return QByteArrayLiteral("Adreno 2xx series");
0681     case Adreno3XX:
0682         return QByteArrayLiteral("Adreno 3xx series");
0683     case Adreno4XX:
0684         return QByteArrayLiteral("Adreno 4xx series");
0685     case Adreno5XX:
0686         return QByteArrayLiteral("Adreno 5xx series");
0687 
0688     case Mali400:
0689         return QByteArrayLiteral("Mali 400 series");
0690     case Mali450:
0691         return QByteArrayLiteral("Mali 450 series");
0692     case Mali470:
0693         return QByteArrayLiteral("Mali 470 series");
0694 
0695     case MaliT7XX:
0696         return QByteArrayLiteral("Mali T7xx series");
0697     case MaliT8XX:
0698         return QByteArrayLiteral("Mali T8xx series");
0699     case MaliGXX:
0700         return QByteArrayLiteral("Mali Gxx series");
0701 
0702     case VC4_2_1:
0703         return QByteArrayLiteral("VideoCore IV");
0704     case V3D_4_2:
0705         return QByteArrayLiteral("VideoCore 3D");
0706 
0707     default:
0708         return QByteArrayLiteral("Unknown");
0709     }
0710 }
0711 
0712 // -------
0713 
0714 GLPlatform::GLPlatform()
0715     : m_driver(Driver_Unknown)
0716     , m_chipClass(UnknownChipClass)
0717     , m_recommendedCompositor(QPainterCompositing)
0718     , m_looseBinding(false)
0719     , m_packInvert(false)
0720     , m_virtualMachine(false)
0721     , m_preferBufferSubData(false)
0722     , m_platformInterface(NoOpenGLPlatformInterface)
0723 {
0724 }
0725 
0726 GLPlatform::~GLPlatform()
0727 {
0728 }
0729 
0730 void GLPlatform::detect(OpenGLPlatformInterface platformInterface)
0731 {
0732     m_platformInterface = platformInterface;
0733 
0734     m_context = std::make_unique<OpenGlContext>();
0735 
0736     // Parse the Mesa version
0737     const auto versionTokens = m_context->openglVersionString().toByteArray().split(' ');
0738     const int mesaIndex = versionTokens.indexOf("Mesa");
0739     if (mesaIndex != -1) {
0740         m_mesaVersion = Version::parseString(versionTokens.at(mesaIndex + 1));
0741     }
0742 
0743     m_glsl_version = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
0744     m_glslVersion = Version::parseString(m_glsl_version);
0745 
0746     m_chipset = QByteArrayLiteral("Unknown");
0747     m_preferBufferSubData = false;
0748     m_packInvert = m_context->hasOpenglExtension("GL_MESA_pack_invert");
0749 
0750     // Mesa classic drivers
0751     // ====================================================
0752 
0753     // Radeon
0754     if (m_context->renderer().startsWith("Mesa DRI R")) {
0755         // Sample renderer string: Mesa DRI R600 (RV740 94B3) 20090101 x86/MMX/SSE2 TCL DRI2
0756         const QList<QByteArray> tokens = m_context->renderer().toByteArray().split(' ');
0757         const QByteArray &chipClass = tokens.at(2);
0758         m_chipset = tokens.at(3).mid(1, -1); // Strip the leading '('
0759 
0760         if (chipClass == "R100") {
0761             // Vendor: Tungsten Graphics, Inc.
0762             m_driver = Driver_R100;
0763 
0764         } else if (chipClass == "R200") {
0765             // Vendor: Tungsten Graphics, Inc.
0766             m_driver = Driver_R200;
0767 
0768         } else if (chipClass == "R300") {
0769             // Vendor: DRI R300 Project
0770             m_driver = Driver_R300C;
0771 
0772         } else if (chipClass == "R600") {
0773             // Vendor: Advanced Micro Devices, Inc.
0774             m_driver = Driver_R600C;
0775         }
0776 
0777         m_chipClass = detectRadeonClass(m_chipset);
0778     }
0779 
0780     // Intel
0781     else if (m_context->renderer().contains("Intel")) {
0782         // Vendor: Tungsten Graphics, Inc.
0783         // Sample renderer string: Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100328 2010Q1
0784 
0785         QByteArrayView chipset;
0786         if (m_context->renderer().startsWith("Intel(R) Integrated Graphics Device")) {
0787             chipset = "IGD";
0788         } else {
0789             chipset = m_context->renderer();
0790         }
0791 
0792         m_driver = Driver_Intel;
0793         m_chipClass = detectIntelClass(chipset);
0794     }
0795 
0796     // Properietary drivers
0797     // ====================================================
0798     else if (m_context->vendor() == "ATI Technologies Inc.") {
0799         m_chipClass = detectRadeonClass(m_context->renderer());
0800         m_driver = Driver_Catalyst;
0801 
0802         if (versionTokens.count() > 1 && versionTokens.at(2)[0] == '(') {
0803             m_driverVersion = Version::parseString(versionTokens.at(1));
0804         } else if (versionTokens.count() > 0) {
0805             m_driverVersion = Version::parseString(versionTokens.at(0));
0806         } else {
0807             m_driverVersion = Version(0, 0, 0);
0808         }
0809     }
0810 
0811     else if (m_context->vendor() == "NVIDIA Corporation") {
0812         m_chipClass = detectNVidiaClass(m_context->renderer());
0813         m_driver = Driver_NVidia;
0814 
0815         int index = versionTokens.indexOf("NVIDIA");
0816         if (versionTokens.count() > index) {
0817             m_driverVersion = Version::parseString(versionTokens.at(index + 1));
0818         } else {
0819             m_driverVersion = Version(0, 0, 0);
0820         }
0821     }
0822 
0823     else if (m_context->vendor() == "Qualcomm") {
0824         m_driver = Driver_Qualcomm;
0825         m_chipClass = detectQualcommClass(m_context->renderer());
0826     }
0827 
0828     else if (m_context->renderer().contains("Panfrost")) {
0829         m_driver = Driver_Panfrost;
0830         m_chipClass = detectPanfrostClass(m_context->renderer());
0831     }
0832 
0833     else if (m_context->renderer().contains("Mali")) {
0834         m_driver = Driver_Lima;
0835         m_chipClass = detectLimaClass(m_context->renderer());
0836     }
0837 
0838     else if (m_context->renderer().startsWith("VC4 ")) {
0839         m_driver = Driver_VC4;
0840         m_chipClass = detectVC4Class(m_context->renderer());
0841     }
0842 
0843     else if (m_context->renderer().startsWith("V3D ")) {
0844         m_driver = Driver_V3D;
0845         m_chipClass = detectV3DClass(m_context->renderer());
0846     }
0847 
0848     else if (m_context->renderer() == "Software Rasterizer") {
0849         m_driver = Driver_Swrast;
0850     }
0851 
0852     // Virtual Hardware
0853     // ====================================================
0854     else if (m_context->vendor() == "Humper" && m_context->renderer() == "Chromium") {
0855         // Virtual Box
0856         m_driver = Driver_VirtualBox;
0857 
0858         const int index = versionTokens.indexOf("Chromium");
0859         if (versionTokens.count() > index) {
0860             m_driverVersion = Version::parseString(versionTokens.at(index + 1));
0861         } else {
0862             m_driverVersion = Version(0, 0, 0);
0863         }
0864     }
0865 
0866     // Gallium drivers
0867     // ====================================================
0868     else {
0869         const QList<QByteArray> tokens = m_context->renderer().toByteArray().split(' ');
0870         if (m_context->renderer().contains("Gallium")) {
0871             // Sample renderer string: Gallium 0.4 on AMD RV740
0872             m_chipset = (tokens.at(3) == "AMD" || tokens.at(3) == "ATI") ? tokens.at(4) : tokens.at(3);
0873         } else {
0874             // The renderer string does not contain "Gallium" anymore.
0875             m_chipset = tokens.at(0);
0876         }
0877 
0878         // R300G
0879         if (m_context->vendor() == QByteArrayLiteral("X.Org R300 Project")) {
0880             m_chipClass = detectRadeonClass(m_chipset);
0881             m_driver = Driver_R300G;
0882         }
0883 
0884         // R600G
0885         else if (m_context->vendor() == "X.Org" && (m_context->renderer().contains("R6") || m_context->renderer().contains("R7") || m_context->renderer().contains("RV6") || m_context->renderer().contains("RV7") || m_context->renderer().contains("RS780") || m_context->renderer().contains("RS880") || m_context->renderer().contains("CEDAR") || m_context->renderer().contains("REDWOOD") || m_context->renderer().contains("JUNIPER") || m_context->renderer().contains("CYPRESS") || m_context->renderer().contains("HEMLOCK") || m_context->renderer().contains("PALM") || m_context->renderer().contains("EVERGREEN") || m_context->renderer().contains("SUMO") || m_context->renderer().contains("SUMO2") || m_context->renderer().contains("BARTS") || m_context->renderer().contains("TURKS") || m_context->renderer().contains("CAICOS") || m_context->renderer().contains("CAYMAN"))) {
0886             m_chipClass = detectRadeonClass(m_chipset);
0887             m_driver = Driver_R600G;
0888         }
0889 
0890         // RadeonSI
0891         else if ((m_context->vendor() == "X.Org" || m_context->vendor() == "AMD") && (m_context->renderer().contains("TAHITI") || m_context->renderer().contains("PITCAIRN") || m_context->renderer().contains("VERDE") || m_context->renderer().contains("OLAND") || m_context->renderer().contains("HAINAN") || m_context->renderer().contains("BONAIRE") || m_context->renderer().contains("KAVERI") || m_context->renderer().contains("KABINI") || m_context->renderer().contains("HAWAII") || m_context->renderer().contains("MULLINS") || m_context->renderer().contains("TOPAZ") || m_context->renderer().contains("TONGA") || m_context->renderer().contains("FIJI") || m_context->renderer().contains("CARRIZO") || m_context->renderer().contains("STONEY") || m_context->renderer().contains("POLARIS10") || m_context->renderer().contains("POLARIS11") || m_context->renderer().contains("POLARIS12") || m_context->renderer().contains("VEGAM") || m_context->renderer().contains("VEGA10") || m_context->renderer().contains("VEGA12") || m_context->renderer().contains("VEGA20") || m_context->renderer().contains("RAVEN") || m_context->renderer().contains("RAVEN2") || m_context->renderer().contains("RENOIR") || m_context->renderer().contains("ARCTURUS") || m_context->renderer().contains("NAVI10") || m_context->renderer().contains("NAVI12") || m_context->renderer().contains("NAVI14"))) {
0892             m_chipClass = detectRadeonClass(m_context->renderer());
0893             m_driver = Driver_RadeonSI;
0894         }
0895 
0896         // Nouveau
0897         else if (m_context->vendor() == "nouveau") {
0898             m_chipClass = detectNVidiaClass(m_chipset);
0899             m_driver = Driver_Nouveau;
0900         }
0901 
0902         // softpipe
0903         else if (m_chipset == "softpipe") {
0904             m_driver = Driver_Softpipe;
0905         }
0906 
0907         // llvmpipe
0908         else if (m_chipset == "llvmpipe") {
0909             m_driver = Driver_Llvmpipe;
0910         }
0911 
0912         // SVGA3D
0913         else if (m_context->vendor() == "VMware, Inc." && m_chipset.contains("SVGA3D")) {
0914             m_driver = Driver_VMware;
0915         }
0916 
0917         // virgl
0918         else if (m_context->renderer() == "virgl") {
0919             m_driver = Driver_Virgl;
0920         }
0921     }
0922 
0923     // Driver/GPU specific features
0924     // ====================================================
0925     if (isRadeon()) {
0926         if (m_chipClass < R300) {
0927             // fallback to NoCompositing for R100 and R200
0928             m_recommendedCompositor = NoCompositing;
0929         } else if (m_chipClass < R600) {
0930             // NoCompositing due to NPOT limitations not supported by KWin's shaders
0931             m_recommendedCompositor = NoCompositing;
0932         } else {
0933             m_recommendedCompositor = OpenGLCompositing;
0934         }
0935 
0936         if (driver() == Driver_R600G || (driver() == Driver_R600C && m_context->renderer().contains("DRI2"))) {
0937             m_looseBinding = true;
0938         }
0939     }
0940 
0941     if (isNvidia()) {
0942         if (m_driver == Driver_NVidia) {
0943             m_looseBinding = true;
0944             m_preferBufferSubData = true;
0945         }
0946 
0947         if (m_chipClass < NV40) {
0948             m_recommendedCompositor = NoCompositing;
0949         } else {
0950             m_recommendedCompositor = OpenGLCompositing;
0951         }
0952     }
0953 
0954     if (isIntel()) {
0955         // see https://bugs.freedesktop.org/show_bug.cgi?id=80349#c1
0956         m_looseBinding = false;
0957 
0958         if (m_chipClass < I915) {
0959             m_recommendedCompositor = NoCompositing;
0960         } else {
0961             m_recommendedCompositor = OpenGLCompositing;
0962         }
0963     }
0964 
0965     if (isPanfrost()) {
0966         m_recommendedCompositor = OpenGLCompositing;
0967     }
0968 
0969     if (isLima()) {
0970         m_recommendedCompositor = OpenGLCompositing;
0971     }
0972 
0973     if (isVideoCore4()) {
0974         // OpenGL works, but is much slower than QPainter
0975         m_recommendedCompositor = QPainterCompositing;
0976     }
0977 
0978     if (isVideoCore3D()) {
0979         // OpenGL works, but is much slower than QPainter
0980         m_recommendedCompositor = QPainterCompositing;
0981     }
0982 
0983     if (isMesaDriver() && platformInterface == EglPlatformInterface) {
0984         // According to the reference implementation in
0985         // mesa/demos/src/egl/opengles1/texture_from_pixmap
0986         // the mesa egl implementation does not require a strict binding (so far).
0987         m_looseBinding = true;
0988     }
0989 
0990     if (isSoftwareEmulation()) {
0991         if (m_driver < Driver_Llvmpipe) {
0992             // we recommend QPainter
0993             m_recommendedCompositor = QPainterCompositing;
0994         } else {
0995             // llvmpipe does support GLSL
0996             m_recommendedCompositor = OpenGLCompositing;
0997         }
0998     }
0999 
1000     if (m_driver == Driver_Qualcomm) {
1001         if (m_chipClass == Adreno1XX) {
1002             m_recommendedCompositor = NoCompositing;
1003         } else {
1004             // all other drivers support at least GLES 2
1005             m_recommendedCompositor = OpenGLCompositing;
1006         }
1007     }
1008 
1009     if (m_chipClass == UnknownChipClass && m_driver == Driver_Unknown) {
1010         // we don't know the hardware. Let's be optimistic and assume OpenGL compatible hardware
1011         m_recommendedCompositor = OpenGLCompositing;
1012     }
1013 
1014     if (isVirtualBox()) {
1015         m_virtualMachine = true;
1016         m_recommendedCompositor = OpenGLCompositing;
1017     }
1018 
1019     if (isVMware()) {
1020         m_virtualMachine = true;
1021         m_recommendedCompositor = OpenGLCompositing;
1022     }
1023 
1024     if (m_driver == Driver_Virgl) {
1025         m_virtualMachine = true;
1026         m_recommendedCompositor = OpenGLCompositing;
1027     }
1028 }
1029 
1030 static void print(const QByteArray &label, QByteArrayView setting)
1031 {
1032     qInfo("%-40s%s", label.data(), setting.data());
1033 }
1034 
1035 void GLPlatform::printResults() const
1036 {
1037     print(QByteArrayLiteral("OpenGL vendor string:"), m_context->vendor());
1038     print(QByteArrayLiteral("OpenGL renderer string:"), m_context->renderer());
1039     print(QByteArrayLiteral("OpenGL version string:"), m_context->openglVersionString());
1040     print(QByteArrayLiteral("OpenGL shading language version string:"), m_glsl_version);
1041     print(QByteArrayLiteral("Driver:"), driverToString8(m_driver));
1042     if (!isMesaDriver()) {
1043         print(QByteArrayLiteral("Driver version:"), m_driverVersion.toByteArray());
1044     }
1045     print(QByteArrayLiteral("GPU class:"), chipClassToString8(m_chipClass));
1046     print(QByteArrayLiteral("OpenGL version:"), m_context->openglVersion().toByteArray());
1047     print(QByteArrayLiteral("GLSL version:"), m_glslVersion.toByteArray());
1048     if (isMesaDriver()) {
1049         print(QByteArrayLiteral("Mesa version:"), mesaVersion().toByteArray());
1050     }
1051     print(QByteArrayLiteral("Requires strict binding:"), !m_looseBinding ? QByteArrayLiteral("yes") : QByteArrayLiteral("no"));
1052     print(QByteArrayLiteral("Virtual Machine:"), m_virtualMachine ? QByteArrayLiteral("yes") : QByteArrayLiteral("no"));
1053     print(QByteArrayLiteral("Timer query support:"), supports(GLFeature::TimerQuery) ? QByteArrayLiteral("yes") : QByteArrayLiteral("no"));
1054 }
1055 
1056 bool GLPlatform::supports(GLFeature feature) const
1057 {
1058     switch (feature) {
1059     case GLFeature::LooseBinding:
1060         return m_looseBinding;
1061     case GLFeature::PackInvert:
1062         return m_packInvert;
1063     case GLFeature::TimerQuery:
1064         return m_context && m_context->supportsTimerQueries();
1065     }
1066     return false;
1067 }
1068 
1069 Version GLPlatform::glVersion() const
1070 {
1071     return m_context ? m_context->openglVersion() : Version();
1072 }
1073 
1074 Version GLPlatform::glslVersion() const
1075 {
1076     return m_glslVersion;
1077 }
1078 
1079 Version GLPlatform::mesaVersion() const
1080 {
1081     return m_mesaVersion;
1082 }
1083 
1084 Version GLPlatform::driverVersion() const
1085 {
1086     if (isMesaDriver()) {
1087         return mesaVersion();
1088     }
1089 
1090     return m_driverVersion;
1091 }
1092 
1093 Driver GLPlatform::driver() const
1094 {
1095     return m_driver;
1096 }
1097 
1098 ChipClass GLPlatform::chipClass() const
1099 {
1100     return m_chipClass;
1101 }
1102 
1103 bool GLPlatform::isMesaDriver() const
1104 {
1105     return mesaVersion().isValid();
1106 }
1107 
1108 bool GLPlatform::isRadeon() const
1109 {
1110     return m_chipClass >= R100 && m_chipClass <= UnknownRadeon;
1111 }
1112 
1113 bool GLPlatform::isNvidia() const
1114 {
1115     return m_chipClass >= NV10 && m_chipClass <= UnknownNVidia;
1116 }
1117 
1118 bool GLPlatform::isIntel() const
1119 {
1120     return m_chipClass >= I8XX && m_chipClass <= UnknownIntel;
1121 }
1122 
1123 bool GLPlatform::isVirtualBox() const
1124 {
1125     return m_driver == Driver_VirtualBox;
1126 }
1127 
1128 bool GLPlatform::isVMware() const
1129 {
1130     return m_driver == Driver_VMware;
1131 }
1132 
1133 bool GLPlatform::isVirgl() const
1134 {
1135     return m_driver == Driver_Virgl;
1136 }
1137 
1138 bool GLPlatform::isSoftwareEmulation() const
1139 {
1140     return m_context ? m_context->isSoftwareRenderer() : false;
1141 }
1142 
1143 bool GLPlatform::isAdreno() const
1144 {
1145     return m_chipClass >= Adreno1XX && m_chipClass <= UnknownAdreno;
1146 }
1147 
1148 bool GLPlatform::isPanfrost() const
1149 {
1150     return m_chipClass >= MaliT7XX && m_chipClass <= UnknownPanfrost;
1151 }
1152 
1153 bool GLPlatform::isLima() const
1154 {
1155     return m_chipClass >= Mali400 && m_chipClass <= UnknownLima;
1156 }
1157 
1158 bool GLPlatform::isVideoCore4() const
1159 {
1160     return m_chipClass >= VC4_2_1 && m_chipClass <= UnknownVideoCore4;
1161 }
1162 
1163 bool GLPlatform::isVideoCore3D() const
1164 {
1165     return m_chipClass >= V3D_4_2 && m_chipClass <= UnknownVideoCore3D;
1166 }
1167 
1168 QByteArrayView GLPlatform::glRendererString() const
1169 {
1170     return m_context ? m_context->renderer() : "";
1171 }
1172 
1173 QByteArrayView GLPlatform::glVendorString() const
1174 {
1175     return m_context ? m_context->vendor() : "";
1176 }
1177 
1178 QByteArrayView GLPlatform::glVersionString() const
1179 {
1180     return m_context ? m_context->openglVersionString() : "";
1181 }
1182 
1183 QByteArrayView GLPlatform::glShadingLanguageVersionString() const
1184 {
1185     return m_glsl_version;
1186 }
1187 
1188 bool GLPlatform::isLooseBinding() const
1189 {
1190     return m_looseBinding;
1191 }
1192 
1193 bool GLPlatform::isVirtualMachine() const
1194 {
1195     return m_virtualMachine;
1196 }
1197 
1198 CompositingType GLPlatform::recommendedCompositor() const
1199 {
1200     return m_recommendedCompositor;
1201 }
1202 
1203 bool GLPlatform::preferBufferSubData() const
1204 {
1205     return m_preferBufferSubData;
1206 }
1207 
1208 OpenGLPlatformInterface GLPlatform::platformInterface() const
1209 {
1210     return m_platformInterface;
1211 }
1212 
1213 bool GLPlatform::isGLES() const
1214 {
1215     return m_context ? m_context->isOpenglES() : false;
1216 }
1217 
1218 void GLPlatform::cleanup()
1219 {
1220     s_platform.reset();
1221 }
1222 
1223 } // namespace KWin