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