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