1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2010 Fredrik Höglund <fredrik@kde.org>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include "kwinglplatform.h"
11 // include kwinglutils_funcs.h to avoid the redeclaration issues
12 // between qopengl.h and epoxy/gl.h
13 #include "kwinglutils_funcs.h"
14 #include <epoxy/gl.h>
15 
16 #include <QRegularExpression>
17 #include <QStringList>
18 #include <QDebug>
19 #include <QOpenGLContext>
20 
21 #include <sys/utsname.h>
22 
23 #include <iostream>
24 #include <iomanip>
25 #include <ios>
26 
27 namespace KWin
28 {
29 
30 GLPlatform *GLPlatform::s_platform = nullptr;
31 
parseVersionString(const QByteArray & version)32 static qint64 parseVersionString(const QByteArray &version)
33 {
34     // Skip any leading non digit
35     int start = 0;
36     while (start < version.length() && !QChar::fromLatin1(version[start]).isDigit())
37         start++;
38 
39     // Strip any non digit, non '.' characters from the end
40     int end = start;
41     while (end < version.length() && (version[end] == '.' || QChar::fromLatin1(version[end]).isDigit()))
42         end++;
43 
44     const QByteArray result = version.mid(start, end-start);
45     const QList<QByteArray> tokens = result.split('.');
46     const qint64 major = tokens.at(0).toInt();
47     const qint64 minor = tokens.count() > 1 ? tokens.at(1).toInt() : 0;
48     const qint64 patch = tokens.count() > 2 ? tokens.at(2).toInt() : 0;
49 
50     return kVersionNumber(major, minor, patch);
51 }
52 
getXServerVersion()53 static qint64 getXServerVersion()
54 {
55     qint64 major, minor, patch;
56     major = 0;
57     minor = 0;
58     patch = 0;
59 
60     if (xcb_connection_t *c = connection()) {
61         auto setup = xcb_get_setup(c);
62         const QByteArray vendorName(xcb_setup_vendor(setup), xcb_setup_vendor_length(setup));
63         if (vendorName.contains("X.Org")) {
64             const int release = setup->release_number;
65             major = (release / 10000000);
66             minor = (release /   100000) % 100;
67             patch = (release /     1000) % 100;
68         }
69     }
70 
71     return kVersionNumber(major, minor, patch);
72 }
73 
getKernelVersion()74 static qint64 getKernelVersion()
75 {
76     struct utsname name;
77     uname(&name);
78 
79     if (qstrcmp(name.sysname, "Linux") == 0)
80         return parseVersionString(name.release);
81 
82     return 0;
83 }
84 
85 // Extracts the portion of a string that matches a regular expression
extract(const QString & text,const QString & pattern)86 static QString extract(const QString &text, const QString &pattern)
87 {
88     const QRegularExpression regexp(pattern);
89     const QRegularExpressionMatch match = regexp.match(text);
90     if (!match.hasMatch())
91         return QString();
92     return match.captured();
93 }
94 
detectRadeonClass(const QByteArray & chipset)95 static ChipClass detectRadeonClass(const QByteArray &chipset)
96 {
97     if (chipset.isEmpty())
98         return UnknownRadeon;
99 
100     if (chipset.contains("R100")  ||
101         chipset.contains("RV100") ||
102         chipset.contains("RS100"))
103         return R100;
104 
105     if (chipset.contains("RV200") ||
106         chipset.contains("RS200") ||
107         chipset.contains("R200")  ||
108         chipset.contains("RV250") ||
109         chipset.contains("RS300") ||
110         chipset.contains("RV280"))
111         return R200;
112 
113     if (chipset.contains("R300")  ||
114         chipset.contains("R350")  ||
115         chipset.contains("R360")  ||
116         chipset.contains("RV350") ||
117         chipset.contains("RV370") ||
118         chipset.contains("RV380"))
119         return R300;
120 
121     if (chipset.contains("R420")  ||
122         chipset.contains("R423")  ||
123         chipset.contains("R430")  ||
124         chipset.contains("R480")  ||
125         chipset.contains("R481")  ||
126         chipset.contains("RV410") ||
127         chipset.contains("RS400") ||
128         chipset.contains("RC410") ||
129         chipset.contains("RS480") ||
130         chipset.contains("RS482") ||
131         chipset.contains("RS600") ||
132         chipset.contains("RS690") ||
133         chipset.contains("RS740"))
134         return R400;
135 
136     if (chipset.contains("RV515") ||
137         chipset.contains("R520")  ||
138         chipset.contains("RV530") ||
139         chipset.contains("R580")  ||
140         chipset.contains("RV560") ||
141         chipset.contains("RV570"))
142         return R500;
143 
144     if (chipset.contains("R600")  ||
145         chipset.contains("RV610") ||
146         chipset.contains("RV630") ||
147         chipset.contains("RV670") ||
148         chipset.contains("RV620") ||
149         chipset.contains("RV635") ||
150         chipset.contains("RS780") ||
151         chipset.contains("RS880"))
152         return R600;
153 
154     if (chipset.contains("R700")  ||
155         chipset.contains("RV770") ||
156         chipset.contains("RV730") ||
157         chipset.contains("RV710") ||
158         chipset.contains("RV740"))
159         return R700;
160 
161     if (chipset.contains("EVERGREEN") ||  // Not an actual chipset, but returned by R600G in 7.9
162         chipset.contains("CEDAR")     ||
163         chipset.contains("REDWOOD")   ||
164         chipset.contains("JUNIPER")   ||
165         chipset.contains("CYPRESS")   ||
166         chipset.contains("HEMLOCK")   ||
167         chipset.contains("PALM"))
168         return Evergreen;
169 
170     if (chipset.contains("SUMO")   ||
171         chipset.contains("SUMO2")  ||
172         chipset.contains("BARTS")  ||
173         chipset.contains("TURKS")  ||
174         chipset.contains("CAICOS") ||
175         chipset.contains("CAYMAN"))
176         return NorthernIslands;
177 
178     if (chipset.contains("TAHITI")   ||
179         chipset.contains("PITCAIRN") ||
180         chipset.contains("VERDE")    ||
181         chipset.contains("OLAND")    ||
182         chipset.contains("HAINAN")) {
183         return SouthernIslands;
184     }
185 
186     if (chipset.contains("BONAIRE") ||
187         chipset.contains("KAVERI")  ||
188         chipset.contains("KABINI")  ||
189         chipset.contains("HAWAII")  ||
190         chipset.contains("MULLINS")) {
191         return SeaIslands;
192     }
193 
194     if (chipset.contains("TONGA")   ||
195         chipset.contains("TOPAZ")   ||
196         chipset.contains("FIJI")    ||
197         chipset.contains("CARRIZO") ||
198         chipset.contains("STONEY")) {
199         return VolcanicIslands;
200     }
201 
202     if (chipset.contains("POLARIS10") ||
203         chipset.contains("POLARIS11") ||
204         chipset.contains("POLARIS12") ||
205         chipset.contains("VEGAM")) {
206         return ArcticIslands;
207     }
208 
209     if (chipset.contains("VEGA10") ||
210         chipset.contains("VEGA12") ||
211         chipset.contains("VEGA20") ||
212         chipset.contains("RAVEN")  ||
213         chipset.contains("RAVEN2") ||
214         chipset.contains("RENOIR") ||
215         chipset.contains("ARCTURUS")) {
216         return Vega;
217     }
218 
219     if (chipset.contains("NAVI10") ||
220         chipset.contains("NAVI12") ||
221         chipset.contains("NAVI14")) {
222         return Navi;
223     }
224 
225     const QString chipset16 = QString::fromLatin1(chipset);
226     QString name = extract(chipset16, QStringLiteral("HD [0-9]{4}")); // HD followed by a space and 4 digits
227     if (!name.isEmpty()) {
228         const int id = name.rightRef(4).toInt();
229         if (id == 6250 || id == 6310)   // Palm
230             return Evergreen;
231 
232         if (id >= 6000 && id < 7000)
233             return NorthernIslands;    // HD 6xxx
234 
235         if (id >= 5000 && id < 6000)
236             return Evergreen;          // HD 5xxx
237 
238         if (id >= 4000 && id < 5000)
239             return R700;               // HD 4xxx
240 
241         if (id >= 2000 && id < 4000)    // HD 2xxx/3xxx
242             return R600;
243 
244         return UnknownRadeon;
245     }
246 
247     name = extract(chipset16, QStringLiteral("X[0-9]{3,4}")); // X followed by 3-4 digits
248     if (!name.isEmpty()) {
249         const int id = name.midRef(1, -1).toInt();
250 
251         // X1xxx
252         if (id >= 1300)
253             return R500;
254 
255         // X7xx, X8xx, X12xx, 2100
256         if ((id >= 700 && id < 1000) || id >= 1200)
257             return R400;
258 
259         // X200, X3xx, X5xx, X6xx, X10xx, X11xx
260         if ((id >= 300 && id < 700) || (id >= 1000 && id < 1200))
261             return R300;
262 
263         return UnknownRadeon;
264     }
265 
266     name = extract(chipset16, QStringLiteral("\\b[0-9]{4}\\b")); // A group of 4 digits
267     if (!name.isEmpty()) {
268         const int id = name.toInt();
269 
270         // 7xxx
271         if (id >= 7000 && id < 8000)
272             return R100;
273 
274         // 8xxx, 9xxx
275         if (id >= 8000 && id < 9500)
276             return R200;
277 
278         // 9xxx
279         if (id >= 9500)
280             return R300;
281 
282         if (id == 2100)
283             return R400;
284     }
285 
286     return UnknownRadeon;
287 }
288 
detectNVidiaClass(const QString & chipset)289 static ChipClass detectNVidiaClass(const QString &chipset)
290 {
291     QString name = extract(chipset, QStringLiteral("\\bNV[0-9,A-F]{2}\\b")); // NV followed by two hexadecimal digits
292     if (!name.isEmpty()) {
293         const int id = chipset.midRef(2, -1).toInt(nullptr, 16); // Strip the 'NV' from the id
294 
295         switch(id & 0xf0) {
296         case 0x00:
297         case 0x10:
298             return NV10;
299 
300         case 0x20:
301             return NV20;
302 
303         case 0x30:
304             return NV30;
305 
306         case 0x40:
307         case 0x60:
308             return NV40;
309 
310         case 0x50:
311         case 0x80:
312         case 0x90:
313         case 0xA0:
314             return G80;
315 
316         default:
317             return UnknownNVidia;
318         }
319     }
320 
321     if (chipset.contains(QLatin1String("GeForce2")) || chipset.contains(QLatin1String("GeForce 256")))
322         return NV10;
323 
324     if (chipset.contains(QLatin1String("GeForce3")))
325         return NV20;
326 
327     if (chipset.contains(QLatin1String("GeForce4"))) {
328         if (chipset.contains(QLatin1String("MX 420"))  ||
329                 chipset.contains(QLatin1String("MX 440"))  || // including MX 440SE
330                 chipset.contains(QLatin1String("MX 460"))  ||
331                 chipset.contains(QLatin1String("MX 4000")) ||
332                 chipset.contains(QLatin1String("PCX 4300")))
333             return NV10;
334 
335         return NV20;
336     }
337 
338     // GeForce 5,6,7,8,9
339     name = extract(chipset, QStringLiteral("GeForce (FX |PCX |Go )?\\d{4}(M|\\b)")).trimmed();
340     if (!name.isEmpty()) {
341         if (!name[name.length() - 1].isDigit())
342             name.chop(1);
343 
344         const int id = name.rightRef(4).toInt();
345         if (id < 6000)
346             return NV30;
347 
348         if (id >= 6000 && id < 8000)
349             return NV40;
350 
351         if (id >= 8000)
352             return G80;
353 
354         return UnknownNVidia;
355     }
356 
357     // GeForce 100/200/300/400/500
358     name = extract(chipset, QStringLiteral("GeForce (G |GT |GTX |GTS )?\\d{3}(M|\\b)")).trimmed();
359     if (!name.isEmpty()) {
360         if (!name[name.length() - 1].isDigit())
361             name.chop(1);
362 
363         const int id = name.rightRef(3).toInt();
364         if (id >= 100 && id < 600) {
365             if (id >= 400)
366                 return GF100;
367 
368             return G80;
369         }
370         return UnknownNVidia;
371     }
372 
373     return UnknownNVidia;
374 }
detectNVidiaClass(const QByteArray & chipset)375 static inline ChipClass detectNVidiaClass(const QByteArray &chipset)
376 {
377     return detectNVidiaClass(QString::fromLatin1(chipset));
378 }
379 
detectIntelClass(const QByteArray & chipset)380 static ChipClass detectIntelClass(const QByteArray &chipset)
381 {
382     // see mesa repository: src/mesa/drivers/dri/intel/intel_context.c
383     // GL 1.3, DX8? SM ?
384     if (chipset.contains("845G")        ||
385             chipset.contains("830M")        ||
386             chipset.contains("852GM/855GM") ||
387             chipset.contains("865G"))
388         return I8XX;
389 
390     // GL 1.4, DX 9.0, SM 2.0
391     if (chipset.contains("915G")   ||
392             chipset.contains("E7221G") ||
393             chipset.contains("915GM")  ||
394             chipset.contains("945G")   ||   // DX 9.0c
395             chipset.contains("945GM")  ||
396             chipset.contains("945GME") ||
397             chipset.contains("Q33")    ||   // GL1.5
398             chipset.contains("Q35")    ||
399             chipset.contains("G33")    ||
400             chipset.contains("965Q")   ||   // GMA 3000, but apparently considered gen 4 by the driver
401             chipset.contains("946GZ")  ||   // GMA 3000, but apparently considered gen 4 by the driver
402             chipset.contains("IGD"))
403         return I915;
404 
405     // GL 2.0, DX 9.0c, SM 3.0
406     if (chipset.contains("965G")       ||
407             chipset.contains("G45/G43")    || // SM 4.0
408             chipset.contains("965GM")      || // GL 2.1
409             chipset.contains("965GME/GLE") ||
410             chipset.contains("GM45")       ||
411             chipset.contains("Q45/Q43")    ||
412             chipset.contains("G41")        ||
413             chipset.contains("B43")        ||
414             chipset.contains("Ironlake"))
415         return I965;
416 
417     // GL 3.1, CL 1.1, DX 10.1
418     if (chipset.contains("Sandybridge") || chipset.contains("SNB GT")) {
419         return SandyBridge;
420     }
421 
422     // GL4.0, CL1.1, DX11, SM 5.0
423     if (chipset.contains("Ivybridge") || chipset.contains("IVB GT")) {
424         return IvyBridge;
425     }
426 
427     // GL4.0, CL1.2, DX11.1, SM 5.0
428     if (chipset.contains("Haswell") || chipset.contains("HSW GT")) {
429         return Haswell;
430     }
431     if (chipset.contains("BYT")) {
432         return BayTrail;
433     }
434     if (chipset.contains("CHV") || chipset.contains("BSW")) {
435         return Cherryview;
436     }
437     if (chipset.contains("BDW GT")) {
438         return Broadwell;
439     }
440     if (chipset.contains("SKL GT")) {
441         return Skylake;
442     }
443     if (chipset.contains("APL")) {
444         return ApolloLake;
445     }
446     if (chipset.contains("KBL GT")) {
447         return KabyLake;
448     }
449     if (chipset.contains("WHL GT")) {
450         return WhiskeyLake;
451     }
452     if (chipset.contains("CML GT")) {
453         return CometLake;
454     }
455     if (chipset.contains("CNL GT")) {
456         return CannonLake;
457     }
458     if (chipset.contains("CFL GT")) {
459         return CoffeeLake;
460     }
461     if (chipset.contains("ICL GT")) {
462         return IceLake;
463     }
464     if (chipset.contains("TGL GT")) {
465         return TigerLake;
466     }
467 
468     return UnknownIntel;
469 }
470 
detectQualcommClass(const QByteArray & chipClass)471 static ChipClass detectQualcommClass(const QByteArray &chipClass)
472 {
473     if (!chipClass.contains("Adreno")) {
474         return UnknownChipClass;
475     }
476     const auto parts = chipClass.split(' ');
477     if (parts.count() < 3) {
478         return UnknownAdreno;
479     }
480     bool ok = false;
481     const int value = parts.at(2).toInt(&ok);
482     if (ok) {
483         if (value >= 100 && value < 200) {
484             return Adreno1XX;
485         }
486         if (value >= 200 && value < 300) {
487             return Adreno2XX;
488         }
489         if (value >= 300 && value < 400) {
490             return Adreno3XX;
491         }
492         if (value >= 400 && value < 500) {
493             return Adreno4XX;
494         }
495         if (value >= 500 && value < 600) {
496             return Adreno5XX;
497         }
498     }
499     return UnknownAdreno;
500 }
501 
detectPanfrostClass(const QByteArray & chipClass)502 static ChipClass detectPanfrostClass(const QByteArray &chipClass)
503 {
504 
505     if (chipClass.contains("T720")   ||
506            chipClass.contains("T760"))
507         return MaliT7XX;
508 
509     if (chipClass.contains("T820")   ||
510            chipClass.contains("T860"))
511         return MaliT8XX;
512 
513     if (chipClass.contains("G31")   ||
514            chipClass.contains("G52") ||
515            chipClass.contains("G72"))
516         return MaliGXX;
517 
518     return UnknownPanfrost;
519 }
520 
versionToString(qint64 version)521 QString GLPlatform::versionToString(qint64 version)
522 {
523     return QString::fromLatin1(versionToString8(version));
524 }
versionToString8(qint64 version)525 QByteArray GLPlatform::versionToString8(qint64 version)
526 {
527     int major = (version >> 32);
528     int minor = (version >> 16) & 0xffff;
529     int patch = version & 0xffff;
530 
531     QByteArray string = QByteArray::number(major) + '.' + QByteArray::number(minor);
532     if (patch != 0)
533         string += '.' + QByteArray::number(patch);
534 
535     return string;
536 }
537 
driverToString(Driver driver)538 QString GLPlatform::driverToString(Driver driver)
539 {
540     return QString::fromLatin1(driverToString8(driver));
541 }
driverToString8(Driver driver)542 QByteArray GLPlatform::driverToString8(Driver driver)
543 {
544     switch(driver) {
545     case Driver_R100:
546         return QByteArrayLiteral("Radeon");
547     case Driver_R200:
548         return QByteArrayLiteral("R200");
549     case Driver_R300C:
550         return QByteArrayLiteral("R300C");
551     case Driver_R300G:
552         return QByteArrayLiteral("R300G");
553     case Driver_R600C:
554         return QByteArrayLiteral("R600C");
555     case Driver_R600G:
556         return QByteArrayLiteral("R600G");
557     case Driver_RadeonSI:
558         return QByteArrayLiteral("RadeonSI");
559     case Driver_Nouveau:
560         return QByteArrayLiteral("Nouveau");
561     case Driver_Intel:
562         return QByteArrayLiteral("Intel");
563     case Driver_NVidia:
564         return QByteArrayLiteral("NVIDIA");
565     case Driver_Catalyst:
566         return QByteArrayLiteral("Catalyst");
567     case Driver_Swrast:
568         return QByteArrayLiteral("Software rasterizer");
569     case Driver_Softpipe:
570         return QByteArrayLiteral("softpipe");
571     case Driver_Llvmpipe:
572         return QByteArrayLiteral("LLVMpipe");
573     case Driver_VirtualBox:
574         return QByteArrayLiteral("VirtualBox (Chromium)");
575     case Driver_VMware:
576         return QByteArrayLiteral("VMware (SVGA3D)");
577     case Driver_Qualcomm:
578         return QByteArrayLiteral("Qualcomm");
579     case Driver_Virgl:
580         return QByteArrayLiteral("Virgl (virtio-gpu, Qemu/KVM guest)");
581     case Driver_Panfrost:
582         return QByteArrayLiteral("Panfrost");
583 
584     default:
585         return QByteArrayLiteral("Unknown");
586     }
587 }
588 
chipClassToString(ChipClass chipClass)589 QString GLPlatform::chipClassToString(ChipClass chipClass)
590 {
591     return QString::fromLatin1(chipClassToString8(chipClass));
592 }
chipClassToString8(ChipClass chipClass)593 QByteArray GLPlatform::chipClassToString8(ChipClass chipClass)
594 {
595     switch(chipClass) {
596     case R100:
597         return QByteArrayLiteral("R100");
598     case R200:
599         return QByteArrayLiteral("R200");
600     case R300:
601         return QByteArrayLiteral("R300");
602     case R400:
603         return QByteArrayLiteral("R400");
604     case R500:
605         return QByteArrayLiteral("R500");
606     case R600:
607         return QByteArrayLiteral("R600");
608     case R700:
609         return QByteArrayLiteral("R700");
610     case Evergreen:
611         return QByteArrayLiteral("EVERGREEN");
612     case NorthernIslands:
613         return QByteArrayLiteral("Northern Islands");
614     case SouthernIslands:
615         return QByteArrayLiteral("Southern Islands");
616     case SeaIslands:
617         return QByteArrayLiteral("Sea Islands");
618     case VolcanicIslands:
619         return QByteArrayLiteral("Volcanic Islands");
620     case ArcticIslands:
621         return QByteArrayLiteral("Arctic Islands");
622     case Vega:
623         return QByteArrayLiteral("Vega");
624     case Navi:
625         return QByteArrayLiteral("Navi");
626 
627     case NV10:
628         return QByteArrayLiteral("NV10");
629     case NV20:
630         return QByteArrayLiteral("NV20");
631     case NV30:
632         return QByteArrayLiteral("NV30");
633     case NV40:
634         return QByteArrayLiteral("NV40/G70");
635     case G80:
636         return QByteArrayLiteral("G80/G90");
637     case GF100:
638         return QByteArrayLiteral("GF100");
639 
640     case I8XX:
641         return QByteArrayLiteral("i830/i835");
642     case I915:
643         return QByteArrayLiteral("i915/i945");
644     case I965:
645         return QByteArrayLiteral("i965");
646     case SandyBridge:
647         return QByteArrayLiteral("SandyBridge");
648     case IvyBridge:
649         return QByteArrayLiteral("IvyBridge");
650     case Haswell:
651         return QByteArrayLiteral("Haswell");
652     case BayTrail:
653         return QByteArrayLiteral("Bay Trail");
654     case Cherryview:
655         return QByteArrayLiteral("Cherryview");
656     case Broadwell:
657         return QByteArrayLiteral("Broadwell");
658     case ApolloLake:
659         return QByteArrayLiteral("Apollo Lake");
660     case Skylake:
661         return QByteArrayLiteral("Skylake");
662     case GeminiLake:
663         return QByteArrayLiteral("Gemini Lake");
664     case KabyLake:
665         return QByteArrayLiteral("Kaby Lake");
666     case CoffeeLake:
667         return QByteArrayLiteral("Coffee Lake");
668     case WhiskeyLake:
669         return QByteArrayLiteral("Whiskey Lake");
670     case CometLake:
671         return QByteArrayLiteral("Comet Lake");
672     case CannonLake:
673         return QByteArrayLiteral("Cannon Lake");
674     case IceLake:
675         return QByteArrayLiteral("Ice Lake");
676     case TigerLake:
677         return QByteArrayLiteral("Tiger Lake");
678 
679     case Adreno1XX:
680         return QByteArrayLiteral("Adreno 1xx series");
681     case Adreno2XX:
682         return QByteArrayLiteral("Adreno 2xx series");
683     case Adreno3XX:
684         return QByteArrayLiteral("Adreno 3xx series");
685     case Adreno4XX:
686         return QByteArrayLiteral("Adreno 4xx series");
687     case Adreno5XX:
688         return QByteArrayLiteral("Adreno 5xx series");
689 
690     case MaliT7XX:
691         return QByteArrayLiteral("Mali T7xx series");
692     case MaliT8XX:
693         return QByteArrayLiteral("Mali T8xx series");
694     case MaliGXX:
695         return QByteArrayLiteral("Mali Gxx series");
696 
697     default:
698         return QByteArrayLiteral("Unknown");
699     }
700 }
701 
702 
703 
704 // -------
705 
706 
707 
GLPlatform()708 GLPlatform::GLPlatform()
709     : m_driver(Driver_Unknown),
710       m_chipClass(UnknownChipClass),
711       m_recommendedCompositor(QPainterCompositing),
712       m_glVersion(0),
713       m_glslVersion(0),
714       m_mesaVersion(0),
715       m_driverVersion(0),
716       m_galliumVersion(0),
717       m_serverVersion(0),
718       m_kernelVersion(0),
719       m_looseBinding(false),
720       m_supportsGLSL(false),
721       m_limitedGLSL(false),
722       m_textureNPOT(false),
723       m_limitedNPOT(false),
724       m_packInvert(false),
725       m_virtualMachine(false),
726       m_preferBufferSubData(false),
727       m_platformInterface(NoOpenGLPlatformInterface),
728       m_gles(false)
729 {
730 }
731 
~GLPlatform()732 GLPlatform::~GLPlatform()
733 {
734 }
735 
detect(OpenGLPlatformInterface platformInterface)736 void GLPlatform::detect(OpenGLPlatformInterface platformInterface)
737 {
738     m_platformInterface = platformInterface;
739 
740     m_vendor       = (const char*)glGetString(GL_VENDOR);
741     m_renderer     = (const char*)glGetString(GL_RENDERER);
742     m_version      = (const char*)glGetString(GL_VERSION);
743 
744     // Parse the OpenGL version
745     const QList<QByteArray> versionTokens = m_version.split(' ');
746     if (versionTokens.count() > 0) {
747         const QByteArray version = QByteArray(m_version);
748         m_glVersion = parseVersionString(version);
749         if (platformInterface == EglPlatformInterface) {
750             // only EGL can have OpenGLES, GLX is OpenGL only
751             if (version.startsWith("OpenGL ES")) {
752                 // from GLES 2: "Returns a version or release number of the form OpenGL<space>ES<space><version number><space><vendor-specific information>."
753                 // 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"
754                 m_gles = true;
755             }
756         }
757     }
758 
759     if (!isGLES() && m_glVersion >= kVersionNumber(3, 0)) {
760         int count;
761         glGetIntegerv(GL_NUM_EXTENSIONS, &count);
762 
763         for (int i = 0; i < count; i++) {
764             const char *name = (const char *) glGetStringi(GL_EXTENSIONS, i);
765             m_extensions.insert(name);
766         }
767     } else {
768         const QByteArray extensions = (const char *) glGetString(GL_EXTENSIONS);
769         QList<QByteArray> extensionsList = extensions.split(' ');
770         m_extensions = {extensionsList.constBegin(), extensionsList.constEnd()};
771     }
772 
773     // Parse the Mesa version
774     const int mesaIndex = versionTokens.indexOf("Mesa");
775     if (mesaIndex != -1) {
776         const QByteArray &version = versionTokens.at(mesaIndex + 1);
777         m_mesaVersion = parseVersionString(version);
778     }
779 
780     if (isGLES()) {
781         m_supportsGLSL = true;
782         m_textureNPOT = true;
783     } else {
784         m_supportsGLSL = m_extensions.contains("GL_ARB_shader_objects") &&
785                          m_extensions.contains("GL_ARB_fragment_shader") &&
786                          m_extensions.contains("GL_ARB_vertex_shader");
787 
788         m_textureNPOT = m_extensions.contains("GL_ARB_texture_non_power_of_two");
789     }
790 
791     m_serverVersion = getXServerVersion();
792     m_kernelVersion = getKernelVersion();
793 
794     m_glslVersion = 0;
795     m_glsl_version.clear();
796 
797     if (m_supportsGLSL) {
798         // Parse the GLSL version
799         m_glsl_version = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
800         m_glslVersion = parseVersionString(m_glsl_version);
801     }
802 
803     m_chipset = QByteArrayLiteral("Unknown");
804     m_preferBufferSubData = false;
805     m_packInvert = m_extensions.contains("GL_MESA_pack_invert");
806 
807 
808     // Mesa classic drivers
809     // ====================================================
810 
811     // Radeon
812     if (m_renderer.startsWith("Mesa DRI R")) {
813         // Sample renderer string: Mesa DRI R600 (RV740 94B3) 20090101 x86/MMX/SSE2 TCL DRI2
814         const QList<QByteArray> tokens = m_renderer.split(' ');
815         const QByteArray &chipClass = tokens.at(2);
816         m_chipset = tokens.at(3).mid(1, -1); // Strip the leading '('
817 
818         if (chipClass == "R100")
819             // Vendor: Tungsten Graphics, Inc.
820             m_driver = Driver_R100;
821 
822         else if (chipClass == "R200")
823             // Vendor: Tungsten Graphics, Inc.
824             m_driver = Driver_R200;
825 
826         else if (chipClass == "R300")
827             // Vendor: DRI R300 Project
828             m_driver = Driver_R300C;
829 
830         else if (chipClass == "R600")
831             // Vendor: Advanced Micro Devices, Inc.
832             m_driver = Driver_R600C;
833 
834         m_chipClass = detectRadeonClass(m_chipset);
835     }
836 
837     // Intel
838     else if (m_renderer.contains("Intel")) {
839         // Vendor: Tungsten Graphics, Inc.
840         // Sample renderer string: Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100328 2010Q1
841 
842         QByteArray chipset;
843         if (m_renderer.startsWith("Intel(R) Integrated Graphics Device"))
844             chipset = "IGD";
845         else
846             chipset = m_renderer;
847 
848         m_driver = Driver_Intel;
849         m_chipClass = detectIntelClass(chipset);
850     }
851 
852     // Properietary drivers
853     // ====================================================
854     else if (m_vendor == "ATI Technologies Inc.") {
855         m_chipClass = detectRadeonClass(m_renderer);
856         m_driver = Driver_Catalyst;
857 
858         if (versionTokens.count() > 1 && versionTokens.at(2)[0] == '(')
859             m_driverVersion = parseVersionString(versionTokens.at(1));
860         else if (versionTokens.count() > 0)
861             m_driverVersion = parseVersionString(versionTokens.at(0));
862         else
863             m_driverVersion = 0;
864     }
865 
866     else if (m_vendor == "NVIDIA Corporation") {
867         m_chipClass = detectNVidiaClass(m_renderer);
868         m_driver = Driver_NVidia;
869 
870         int index = versionTokens.indexOf("NVIDIA");
871         if (versionTokens.count() > index)
872             m_driverVersion = parseVersionString(versionTokens.at(index + 1));
873         else
874             m_driverVersion = 0;
875     }
876 
877     else if (m_vendor == "Qualcomm") {
878         m_driver = Driver_Qualcomm;
879         m_chipClass = detectQualcommClass(m_renderer);
880     }
881 
882     else if (m_renderer.contains("Panfrost")) {
883         m_driver = Driver_Panfrost;
884         m_chipClass = detectPanfrostClass(m_renderer);
885      }
886 
887     else if (m_renderer == "Software Rasterizer") {
888         m_driver = Driver_Swrast;
889     }
890 
891     // Virtual Hardware
892     // ====================================================
893     else if (m_vendor == "Humper" && m_renderer == "Chromium") {
894         // Virtual Box
895         m_driver = Driver_VirtualBox;
896 
897         const int index = versionTokens.indexOf("Chromium");
898         if (versionTokens.count() > index)
899             m_driverVersion = parseVersionString(versionTokens.at(index + 1));
900         else
901             m_driverVersion = 0;
902     }
903 
904     // Gallium drivers
905     // ====================================================
906     else {
907         const QList<QByteArray> tokens = m_renderer.split(' ');
908         if (m_renderer.contains("Gallium")) {
909             // Sample renderer string: Gallium 0.4 on AMD RV740
910             m_galliumVersion = parseVersionString(tokens.at(1));
911             m_chipset = (tokens.at(3) == "AMD" || tokens.at(3) == "ATI") ?
912                         tokens.at(4) : tokens.at(3);
913         }
914         else {
915             // The renderer string does not contain "Gallium" anymore.
916             m_chipset = tokens.at(0);
917             // We don't know the actual version anymore, but it's at least 0.4.
918             m_galliumVersion = kVersionNumber(0, 4, 0);
919         }
920 
921         // R300G
922         if (m_vendor == QByteArrayLiteral("X.Org R300 Project")) {
923             m_chipClass = detectRadeonClass(m_chipset);
924             m_driver = Driver_R300G;
925         }
926 
927         // R600G
928         else if (m_vendor == "X.Org" &&
929                 (m_renderer.contains("R6")        ||
930                  m_renderer.contains("R7")        ||
931                  m_renderer.contains("RV6")       ||
932                  m_renderer.contains("RV7")       ||
933                  m_renderer.contains("RS780")     ||
934                  m_renderer.contains("RS880")     ||
935                  m_renderer.contains("CEDAR")     ||
936                  m_renderer.contains("REDWOOD")   ||
937                  m_renderer.contains("JUNIPER")   ||
938                  m_renderer.contains("CYPRESS")   ||
939                  m_renderer.contains("HEMLOCK")   ||
940                  m_renderer.contains("PALM")      ||
941                  m_renderer.contains("EVERGREEN") ||
942                  m_renderer.contains("SUMO")      ||
943                  m_renderer.contains("SUMO2")     ||
944                  m_renderer.contains("BARTS")     ||
945                  m_renderer.contains("TURKS")     ||
946                  m_renderer.contains("CAICOS")    ||
947                  m_renderer.contains("CAYMAN"))) {
948             m_chipClass = detectRadeonClass(m_chipset);
949             m_driver = Driver_R600G;
950         }
951 
952         // RadeonSI
953         else if ((m_vendor == "X.Org" || m_vendor == "AMD") &&
954                 (m_renderer.contains("TAHITI")    ||
955                  m_renderer.contains("PITCAIRN")  ||
956                  m_renderer.contains("VERDE")     ||
957                  m_renderer.contains("OLAND")     ||
958                  m_renderer.contains("HAINAN")    ||
959                  m_renderer.contains("BONAIRE")   ||
960                  m_renderer.contains("KAVERI")    ||
961                  m_renderer.contains("KABINI")    ||
962                  m_renderer.contains("HAWAII")    ||
963                  m_renderer.contains("MULLINS")   ||
964                  m_renderer.contains("TOPAZ")     ||
965                  m_renderer.contains("TONGA")     ||
966                  m_renderer.contains("FIJI")      ||
967                  m_renderer.contains("CARRIZO")   ||
968                  m_renderer.contains("STONEY")    ||
969                  m_renderer.contains("POLARIS10") ||
970                  m_renderer.contains("POLARIS11") ||
971                  m_renderer.contains("POLARIS12") ||
972                  m_renderer.contains("VEGAM")     ||
973                  m_renderer.contains("VEGA10")    ||
974                  m_renderer.contains("VEGA12")    ||
975                  m_renderer.contains("VEGA20")    ||
976                  m_renderer.contains("RAVEN")     ||
977                  m_renderer.contains("RAVEN2")    ||
978                  m_renderer.contains("RENOIR")    ||
979                  m_renderer.contains("ARCTURUS")  ||
980                  m_renderer.contains("NAVI10")    ||
981                  m_renderer.contains("NAVI12")    ||
982                  m_renderer.contains("NAVI14"))) {
983             m_chipClass = detectRadeonClass(m_renderer);
984             m_driver = Driver_RadeonSI;
985         }
986 
987         // Nouveau
988         else if (m_vendor == "nouveau") {
989             m_chipClass = detectNVidiaClass(m_chipset);
990             m_driver = Driver_Nouveau;
991         }
992 
993         // softpipe
994         else if (m_chipset == "softpipe") {
995             m_driver = Driver_Softpipe;
996         }
997 
998         // llvmpipe
999         else if (m_chipset == "llvmpipe") {
1000             m_driver = Driver_Llvmpipe;
1001         }
1002 
1003         // SVGA3D
1004         else if (m_vendor == "VMware, Inc." && m_chipset.contains("SVGA3D")) {
1005             m_driver = Driver_VMware;
1006         }
1007 
1008         // virgl
1009         else if (m_renderer == "virgl") {
1010             m_driver = Driver_Virgl;
1011         }
1012     }
1013 
1014     // Driver/GPU specific features
1015     // ====================================================
1016     if (isRadeon()) {
1017         // R200 technically has a programmable pipeline, but since it's SM 1.4,
1018         // it's too limited to to be of any practical value to us.
1019         if (m_chipClass < R300)
1020             m_supportsGLSL = false;
1021 
1022         m_limitedGLSL = false;
1023         m_limitedNPOT = false;
1024 
1025         if (m_chipClass < R600) {
1026             if (driver() == Driver_Catalyst)
1027                 m_textureNPOT = m_limitedNPOT = false; // Software fallback
1028             else if (driver() == Driver_R300G)
1029                 m_limitedNPOT = m_textureNPOT;
1030 
1031             m_limitedGLSL = m_supportsGLSL;
1032         }
1033 
1034         if (m_chipClass < R300) {
1035             // fallback to NoCompositing for R100 and R200
1036             m_recommendedCompositor = NoCompositing;
1037         } else if (m_chipClass < R600) {
1038             // NoCompositing due to NPOT limitations not supported by KWin's shaders
1039             m_recommendedCompositor = NoCompositing;
1040         } else {
1041             m_recommendedCompositor = OpenGLCompositing;
1042         }
1043 
1044         if (driver() == Driver_R600G ||
1045                 (driver() == Driver_R600C && m_renderer.contains("DRI2"))) {
1046             m_looseBinding = true;
1047         }
1048     }
1049 
1050     if (isNvidia()) {
1051         if (m_driver == Driver_NVidia && m_chipClass < NV40)
1052             m_supportsGLSL = false; // High likelihood of software emulation
1053 
1054         if (m_driver == Driver_NVidia) {
1055             m_looseBinding = true;
1056             m_preferBufferSubData = true;
1057         }
1058 
1059         if (m_chipClass < NV40) {
1060             m_recommendedCompositor = NoCompositing;
1061         } else {
1062             m_recommendedCompositor = OpenGLCompositing;
1063         }
1064 
1065         m_limitedNPOT = m_textureNPOT && m_chipClass < NV40;
1066         m_limitedGLSL = m_supportsGLSL && m_chipClass < G80;
1067     }
1068 
1069     if (isIntel()) {
1070         if (m_chipClass < I915)
1071             m_supportsGLSL = false;
1072 
1073         m_limitedGLSL = m_supportsGLSL && m_chipClass < I965;
1074         // see https://bugs.freedesktop.org/show_bug.cgi?id=80349#c1
1075         m_looseBinding = false;
1076 
1077         if (m_chipClass < I915) {
1078             m_recommendedCompositor = NoCompositing;
1079         } else {
1080             m_recommendedCompositor = OpenGLCompositing;
1081         }
1082     }
1083 
1084     if (isPanfrost()) {
1085         m_recommendedCompositor = OpenGLCompositing;
1086     }
1087 
1088     if (isMesaDriver() && platformInterface == EglPlatformInterface) {
1089         // According to the reference implementation in
1090         // mesa/demos/src/egl/opengles1/texture_from_pixmap
1091         // the mesa egl implementation does not require a strict binding (so far).
1092         m_looseBinding = true;
1093     }
1094 
1095     if (isSoftwareEmulation()) {
1096         if (m_driver < Driver_Llvmpipe) {
1097             // we recommend QPainter
1098             m_recommendedCompositor = QPainterCompositing;
1099             // Software emulation does not provide GLSL
1100             m_limitedGLSL = m_supportsGLSL = false;
1101         } else {
1102             // llvmpipe does support GLSL
1103             m_recommendedCompositor = OpenGLCompositing;
1104             m_limitedGLSL = false;
1105             m_supportsGLSL = true;
1106         }
1107     }
1108 
1109     if (m_driver == Driver_Qualcomm) {
1110         if (m_chipClass == Adreno1XX) {
1111             m_recommendedCompositor = NoCompositing;
1112         } else {
1113             // all other drivers support at least GLES 2
1114             m_recommendedCompositor = OpenGLCompositing;
1115         }
1116     }
1117 
1118     if (m_chipClass == UnknownChipClass && m_driver == Driver_Unknown) {
1119         // we don't know the hardware. Let's be optimistic and assume OpenGL compatible hardware
1120         m_recommendedCompositor = OpenGLCompositing;
1121         m_supportsGLSL = true;
1122     }
1123 
1124     if (isVirtualBox()) {
1125         m_virtualMachine = true;
1126         m_recommendedCompositor = OpenGLCompositing;
1127     }
1128 
1129     if (isVMware()) {
1130         m_virtualMachine = true;
1131         m_recommendedCompositor = OpenGLCompositing;
1132     }
1133 
1134     if (m_driver == Driver_Virgl) {
1135         m_virtualMachine = true;
1136         m_recommendedCompositor = OpenGLCompositing;
1137     }
1138 
1139     // and force back to shader supported on gles, we wouldn't have got a context if not supported
1140     if (isGLES()) {
1141         m_supportsGLSL = true;
1142         m_limitedGLSL = false;
1143     }
1144 }
1145 
print(const QByteArray & label,const QByteArray & setting)1146 static void print(const QByteArray &label, const QByteArray &setting)
1147 {
1148     std::cout << std::setw(40) << std::left
1149               << label.data() << setting.data() << std::endl;
1150 }
1151 
printResults() const1152 void GLPlatform::printResults() const
1153 {
1154     print(QByteArrayLiteral("OpenGL vendor string:"),   m_vendor);
1155     print(QByteArrayLiteral("OpenGL renderer string:"), m_renderer);
1156     print(QByteArrayLiteral("OpenGL version string:"),  m_version);
1157 
1158     if (m_supportsGLSL)
1159         print(QByteArrayLiteral("OpenGL shading language version string:"), m_glsl_version);
1160 
1161     print(QByteArrayLiteral("Driver:"), driverToString8(m_driver));
1162     if (!isMesaDriver())
1163         print(QByteArrayLiteral("Driver version:"), versionToString8(m_driverVersion));
1164 
1165     print(QByteArrayLiteral("GPU class:"), chipClassToString8(m_chipClass));
1166 
1167     print(QByteArrayLiteral("OpenGL version:"), versionToString8(m_glVersion));
1168 
1169     if (m_supportsGLSL)
1170         print(QByteArrayLiteral("GLSL version:"), versionToString8(m_glslVersion));
1171 
1172     if (isMesaDriver())
1173         print(QByteArrayLiteral("Mesa version:"), versionToString8(mesaVersion()));
1174     //if (galliumVersion() > 0)
1175     //    print("Gallium version:", versionToString(m_galliumVersion));
1176     if (serverVersion() > 0)
1177         print(QByteArrayLiteral("X server version:"), versionToString8(m_serverVersion));
1178     if (kernelVersion() > 0)
1179         print(QByteArrayLiteral("Linux kernel version:"), versionToString8(m_kernelVersion));
1180 
1181     print(QByteArrayLiteral("Requires strict binding:"), !m_looseBinding ? QByteArrayLiteral("yes") : QByteArrayLiteral("no"));
1182     print(QByteArrayLiteral("GLSL shaders:"), m_supportsGLSL ? (m_limitedGLSL ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no"));
1183     print(QByteArrayLiteral("Texture NPOT support:"), m_textureNPOT ? (m_limitedNPOT ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no"));
1184     print(QByteArrayLiteral("Virtual Machine:"), m_virtualMachine ? QByteArrayLiteral("yes") : QByteArrayLiteral("no"));
1185 }
1186 
supports(GLFeature feature) const1187 bool GLPlatform::supports(GLFeature feature) const
1188 {
1189     switch(feature) {
1190     case LooseBinding:
1191         return m_looseBinding;
1192 
1193     case GLSL:
1194         return m_supportsGLSL;
1195 
1196     case LimitedGLSL:
1197         return m_limitedGLSL;
1198 
1199     case TextureNPOT:
1200         return m_textureNPOT;
1201 
1202     case LimitedNPOT:
1203         return m_limitedNPOT;
1204 
1205     case PackInvert:
1206         return m_packInvert;
1207 
1208     default:
1209         return false;
1210     }
1211 }
1212 
glVersion() const1213 qint64 GLPlatform::glVersion() const
1214 {
1215     return m_glVersion;
1216 }
1217 
glslVersion() const1218 qint64 GLPlatform::glslVersion() const
1219 {
1220     return m_glslVersion;
1221 }
1222 
mesaVersion() const1223 qint64 GLPlatform::mesaVersion() const
1224 {
1225     return m_mesaVersion;
1226 }
1227 
galliumVersion() const1228 qint64 GLPlatform::galliumVersion() const
1229 {
1230     return m_galliumVersion;
1231 }
1232 
serverVersion() const1233 qint64 GLPlatform::serverVersion() const
1234 {
1235     return m_serverVersion;
1236 }
1237 
kernelVersion() const1238 qint64 GLPlatform::kernelVersion() const
1239 {
1240     return m_kernelVersion;
1241 }
1242 
driverVersion() const1243 qint64 GLPlatform::driverVersion() const
1244 {
1245     if (isMesaDriver())
1246         return mesaVersion();
1247 
1248     return m_driverVersion;
1249 }
1250 
driver() const1251 Driver GLPlatform::driver() const
1252 {
1253     return m_driver;
1254 }
1255 
chipClass() const1256 ChipClass GLPlatform::chipClass() const
1257 {
1258     return m_chipClass;
1259 }
1260 
isMesaDriver() const1261 bool GLPlatform::isMesaDriver() const
1262 {
1263     return mesaVersion() > 0;
1264 }
1265 
isGalliumDriver() const1266 bool GLPlatform::isGalliumDriver() const
1267 {
1268     return galliumVersion() > 0;
1269 }
1270 
isRadeon() const1271 bool GLPlatform::isRadeon() const
1272 {
1273     return m_chipClass >= R100 && m_chipClass <= UnknownRadeon;
1274 }
1275 
isNvidia() const1276 bool GLPlatform::isNvidia() const
1277 {
1278     return m_chipClass >= NV10 && m_chipClass <= UnknownNVidia;
1279 }
1280 
isIntel() const1281 bool GLPlatform::isIntel() const
1282 {
1283     return m_chipClass >= I8XX && m_chipClass <= UnknownIntel;
1284 }
1285 
isVirtualBox() const1286 bool GLPlatform::isVirtualBox() const
1287 {
1288     return m_driver == Driver_VirtualBox;
1289 }
1290 
isVMware() const1291 bool GLPlatform::isVMware() const
1292 {
1293     return m_driver == Driver_VMware;
1294 }
1295 
isVirgl() const1296 bool GLPlatform::isVirgl() const
1297 {
1298     return m_driver == Driver_Virgl;
1299 }
1300 
isSoftwareEmulation() const1301 bool GLPlatform::isSoftwareEmulation() const
1302 {
1303     return m_driver == Driver_Softpipe || m_driver == Driver_Swrast || m_driver == Driver_Llvmpipe;
1304 }
1305 
isAdreno() const1306 bool GLPlatform::isAdreno() const
1307 {
1308     return m_chipClass >= Adreno1XX && m_chipClass <= UnknownAdreno;
1309 }
1310 
isPanfrost() const1311 bool GLPlatform::isPanfrost() const
1312 {
1313     return m_chipClass >= MaliT7XX && m_chipClass <= UnknownPanfrost;
1314 }
1315 
glRendererString() const1316 const QByteArray &GLPlatform::glRendererString() const
1317 {
1318     return m_renderer;
1319 }
1320 
glVendorString() const1321 const QByteArray &GLPlatform::glVendorString() const
1322 {
1323     return m_vendor;
1324 }
1325 
glVersionString() const1326 const QByteArray &GLPlatform::glVersionString() const
1327 {
1328     return m_version;
1329 }
1330 
glShadingLanguageVersionString() const1331 const QByteArray &GLPlatform::glShadingLanguageVersionString() const
1332 {
1333     return m_glsl_version;
1334 }
1335 
isLooseBinding() const1336 bool GLPlatform::isLooseBinding() const
1337 {
1338     return m_looseBinding;
1339 }
1340 
isVirtualMachine() const1341 bool GLPlatform::isVirtualMachine() const
1342 {
1343     return m_virtualMachine;
1344 }
1345 
recommendedCompositor() const1346 CompositingType GLPlatform::recommendedCompositor() const
1347 {
1348     return m_recommendedCompositor;
1349 }
1350 
preferBufferSubData() const1351 bool GLPlatform::preferBufferSubData() const
1352 {
1353     return m_preferBufferSubData;
1354 }
1355 
platformInterface() const1356 OpenGLPlatformInterface GLPlatform::platformInterface() const
1357 {
1358     return m_platformInterface;
1359 }
1360 
isGLES() const1361 bool GLPlatform::isGLES() const
1362 {
1363     return m_gles;
1364 }
1365 
cleanup()1366 void GLPlatform::cleanup()
1367 {
1368     delete s_platform;
1369     s_platform = nullptr;
1370 }
1371 
1372 } // namespace KWin
1373 
1374