2010-11-12 05:30:38 +00:00
|
|
|
/********************************************************************
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
|
|
|
|
|
|
|
Copyright (C) 2010 Fredrik Höglund <fredrik@kde.org>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************/
|
|
|
|
|
|
|
|
#include "kwinglplatform.h"
|
|
|
|
#include "kwinglutils.h"
|
|
|
|
|
|
|
|
#include <kwinglobals.h>
|
|
|
|
|
|
|
|
#include <QRegExp>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
|
2010-11-28 17:07:23 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
2010-12-04 21:10:49 +00:00
|
|
|
#include <ios>
|
2010-11-28 17:07:23 +00:00
|
|
|
|
2010-11-12 05:30:38 +00:00
|
|
|
#ifdef KWIN_HAVE_OPENGL
|
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
|
|
|
GLPlatform *GLPlatform::s_platform = 0;
|
|
|
|
|
|
|
|
static qint64 parseVersionString(const QByteArray &version)
|
|
|
|
{
|
|
|
|
// Skip any leading non digit
|
|
|
|
int start = 0;
|
|
|
|
while (start < version.length() && !QChar(version[start]).isDigit())
|
|
|
|
start++;
|
|
|
|
|
|
|
|
// Strip any non digit, non '.' characters from the end
|
|
|
|
int end = start;
|
|
|
|
while (end < version.length() && (version[end] == '.' || QChar(version[end]).isDigit()))
|
|
|
|
end++;
|
|
|
|
|
2011-02-23 05:15:21 +00:00
|
|
|
const QByteArray result = version.mid(start, end-start);
|
2010-11-12 05:30:38 +00:00
|
|
|
const QList<QByteArray> tokens = result.split('.');
|
|
|
|
const qint64 major = tokens.at(0).toInt();
|
|
|
|
const qint64 minor = tokens.count() > 1 ? tokens.at(1).toInt() : 0;
|
|
|
|
const qint64 patch = tokens.count() > 2 ? tokens.at(2).toInt() : 0;
|
|
|
|
|
|
|
|
return kVersionNumber(major, minor, patch);
|
|
|
|
}
|
|
|
|
|
|
|
|
static qint64 getXServerVersion()
|
|
|
|
{
|
|
|
|
qint64 major, minor, patch;
|
|
|
|
|
|
|
|
Display *dpy = display();
|
|
|
|
if (strstr(ServerVendor(dpy), "X.Org")) {
|
|
|
|
const int release = VendorRelease(dpy);
|
|
|
|
major = (release / 10000000);
|
|
|
|
minor = (release / 100000) % 100;
|
|
|
|
patch = (release / 1000) % 100;
|
|
|
|
} else {
|
|
|
|
major = 0;
|
|
|
|
minor = 0;
|
|
|
|
patch = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return kVersionNumber(major, minor, patch);
|
|
|
|
}
|
|
|
|
|
|
|
|
static qint64 getKernelVersion()
|
|
|
|
{
|
|
|
|
struct utsname name;
|
|
|
|
uname(&name);
|
|
|
|
|
|
|
|
if (QByteArray(name.sysname) == "Linux")
|
|
|
|
return parseVersionString(name.release);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extracts the portion of a string that matches a regular expression
|
|
|
|
static QString extract(const QString &string, const QString &match, int offset = 0)
|
|
|
|
{
|
|
|
|
QString result;
|
|
|
|
QRegExp rx(match);
|
|
|
|
int pos = rx.indexIn(string, offset);
|
|
|
|
if (pos != -1)
|
2011-01-30 14:34:42 +00:00
|
|
|
result = string.mid(pos, rx.matchedLength());
|
2010-11-12 05:30:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ChipClass detectRadeonClass(const QString &chipset)
|
|
|
|
{
|
|
|
|
if (chipset.isEmpty())
|
|
|
|
return UnknownRadeon;
|
|
|
|
|
|
|
|
if (chipset.contains("R100") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("RV100") ||
|
|
|
|
chipset.contains("RS100"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return R100;
|
|
|
|
|
|
|
|
if (chipset.contains("RV200") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("RS200") ||
|
|
|
|
chipset.contains("R200") ||
|
|
|
|
chipset.contains("RV250") ||
|
|
|
|
chipset.contains("RS300") ||
|
|
|
|
chipset.contains("RV280"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return R200;
|
|
|
|
|
|
|
|
if (chipset.contains("R300") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("R350") ||
|
|
|
|
chipset.contains("R360") ||
|
|
|
|
chipset.contains("RV350") ||
|
|
|
|
chipset.contains("RV370") ||
|
|
|
|
chipset.contains("RV380"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return R300;
|
|
|
|
|
|
|
|
if (chipset.contains("R420") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("R423") ||
|
|
|
|
chipset.contains("R430") ||
|
|
|
|
chipset.contains("R480") ||
|
|
|
|
chipset.contains("R481") ||
|
|
|
|
chipset.contains("RV410") ||
|
|
|
|
chipset.contains("RS400") ||
|
|
|
|
chipset.contains("RC410") ||
|
|
|
|
chipset.contains("RS480") ||
|
|
|
|
chipset.contains("RS482") ||
|
|
|
|
chipset.contains("RS600") ||
|
|
|
|
chipset.contains("RS690") ||
|
|
|
|
chipset.contains("RS740"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return R400;
|
|
|
|
|
|
|
|
if (chipset.contains("RV515") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("R520") ||
|
|
|
|
chipset.contains("RV530") ||
|
|
|
|
chipset.contains("R580") ||
|
|
|
|
chipset.contains("RV560") ||
|
|
|
|
chipset.contains("RV570"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return R500;
|
|
|
|
|
|
|
|
if (chipset.contains("R600") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("RV610") ||
|
|
|
|
chipset.contains("RV630") ||
|
|
|
|
chipset.contains("RV670") ||
|
|
|
|
chipset.contains("RV620") ||
|
|
|
|
chipset.contains("RV635") ||
|
|
|
|
chipset.contains("RS780") ||
|
|
|
|
chipset.contains("RS880"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return R600;
|
|
|
|
|
|
|
|
if (chipset.contains("R700") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("RV770") ||
|
|
|
|
chipset.contains("RV730") ||
|
|
|
|
chipset.contains("RV710") ||
|
|
|
|
chipset.contains("RV740"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return R700;
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (chipset.contains("EVERGREEN") || // Not an actual chipset, but returned by R600G in 7.9
|
|
|
|
chipset.contains("CEDAR") ||
|
|
|
|
chipset.contains("REDWOOD") ||
|
|
|
|
chipset.contains("JUNIPER") ||
|
|
|
|
chipset.contains("CYPRESS") ||
|
|
|
|
chipset.contains("PALM") ||
|
|
|
|
chipset.contains("HEMLOCK"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return Evergreen;
|
|
|
|
|
2011-01-11 20:14:06 +00:00
|
|
|
if (chipset.contains("BARTS") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("TURKS") ||
|
|
|
|
chipset.contains("CAICOS"))
|
2011-01-11 20:14:06 +00:00
|
|
|
return NorthernIslands;
|
|
|
|
|
2010-12-03 21:23:03 +00:00
|
|
|
QString name = extract(chipset, "HD [0-9]{4}"); // HD followed by a space and 4 digits
|
|
|
|
if (!name.isEmpty()) {
|
|
|
|
const int id = name.right(4).toInt();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (id == 6250 || id == 6310) // Palm
|
2010-11-12 05:30:38 +00:00
|
|
|
return Evergreen;
|
2010-12-03 21:23:03 +00:00
|
|
|
|
|
|
|
if (id >= 6000 && id < 7000)
|
|
|
|
return NorthernIslands; // HD 6xxx
|
|
|
|
|
|
|
|
if (id >= 5000 && id < 6000)
|
|
|
|
return Evergreen; // HD 5xxx
|
|
|
|
|
|
|
|
if (id >= 4000 && id < 5000)
|
|
|
|
return R700; // HD 4xxx
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (id >= 2000 && id < 4000) // HD 2xxx/3xxx
|
2010-11-12 05:30:38 +00:00
|
|
|
return R600;
|
2010-12-03 21:23:03 +00:00
|
|
|
|
|
|
|
return UnknownRadeon;
|
2010-11-12 05:30:38 +00:00
|
|
|
}
|
|
|
|
|
2010-12-03 21:23:03 +00:00
|
|
|
name = extract(chipset, "X[0-9]{3,4}"); // X followed by 3-4 digits
|
2010-11-12 05:30:38 +00:00
|
|
|
if (!name.isEmpty()) {
|
|
|
|
const int id = name.mid(1, -1).toInt();
|
|
|
|
|
|
|
|
// X1xxx
|
|
|
|
if (id >= 1300)
|
|
|
|
return R500;
|
|
|
|
|
|
|
|
// X7xx, X8xx, X12xx, 2100
|
|
|
|
if ((id >= 700 && id < 1000) || id >= 1200)
|
|
|
|
return R400;
|
|
|
|
|
|
|
|
// X200, X3xx, X5xx, X6xx, X10xx, X11xx
|
|
|
|
if ((id >= 300 && id < 700) || (id >= 1000 && id < 1200))
|
|
|
|
return R300;
|
|
|
|
|
|
|
|
return UnknownRadeon;
|
|
|
|
}
|
|
|
|
|
2010-12-03 21:23:03 +00:00
|
|
|
name = extract(chipset, "\\b[0-9]{4}\\b"); // A group of 4 digits
|
2010-11-12 05:30:38 +00:00
|
|
|
if (!name.isEmpty()) {
|
|
|
|
const int id = name.toInt();
|
|
|
|
|
|
|
|
// 7xxx
|
|
|
|
if (id >= 7000 && id < 8000)
|
|
|
|
return R100;
|
|
|
|
|
|
|
|
// 8xxx, 9xxx
|
|
|
|
if (id >= 8000 && id < 9500)
|
|
|
|
return R200;
|
|
|
|
|
|
|
|
// 9xxx
|
|
|
|
if (id >= 9500)
|
|
|
|
return R300;
|
|
|
|
|
|
|
|
if (id == 2100)
|
|
|
|
return R400;
|
|
|
|
}
|
|
|
|
|
|
|
|
return UnknownRadeon;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ChipClass detectNVidiaClass(const QString &chipset)
|
|
|
|
{
|
2010-12-03 23:26:30 +00:00
|
|
|
QString name = extract(chipset, "\\bNV[0-9,A-F]{2}\\b"); // NV followed by two hexadecimal digits
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!name.isEmpty()) {
|
2010-11-12 05:30:38 +00:00
|
|
|
const int id = chipset.mid(2, -1).toInt(0, 16); // Strip the 'NV' from the id
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
switch(id & 0xf0) {
|
2010-11-12 05:30:38 +00:00
|
|
|
case 0x00:
|
|
|
|
case 0x10:
|
|
|
|
return NV10;
|
|
|
|
|
|
|
|
case 0x20:
|
|
|
|
return NV20;
|
|
|
|
|
|
|
|
case 0x30:
|
|
|
|
return NV30;
|
|
|
|
|
|
|
|
case 0x40:
|
|
|
|
case 0x60:
|
|
|
|
return NV40;
|
|
|
|
|
|
|
|
case 0x50:
|
|
|
|
case 0x80:
|
|
|
|
case 0x90:
|
|
|
|
case 0xA0:
|
|
|
|
return G80;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return UnknownNVidia;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-11-12 05:30:38 +00:00
|
|
|
}
|
|
|
|
|
2010-12-03 23:26:30 +00:00
|
|
|
if (chipset.contains("GeForce2") || chipset.contains("GeForce 256"))
|
|
|
|
return NV10;
|
|
|
|
|
|
|
|
if (chipset.contains("GeForce3"))
|
|
|
|
return NV20;
|
|
|
|
|
|
|
|
if (chipset.contains("GeForce4")) {
|
|
|
|
if (chipset.contains("MX 420") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("MX 440") || // including MX 440SE
|
|
|
|
chipset.contains("MX 460") ||
|
|
|
|
chipset.contains("MX 4000") ||
|
|
|
|
chipset.contains("PCX 4300"))
|
2010-12-03 23:26:30 +00:00
|
|
|
return NV10;
|
|
|
|
|
|
|
|
return NV20;
|
|
|
|
}
|
|
|
|
|
|
|
|
// GeForce 5,6,7,8,9
|
|
|
|
name = extract(chipset, "GeForce (FX |PCX |Go )?\\d{4}(M|\\b)").trimmed();
|
|
|
|
if (!name.isEmpty()) {
|
|
|
|
if (!name[name.length() - 1].isDigit())
|
|
|
|
name.chop(1);
|
|
|
|
|
|
|
|
const int id = name.right(4).toInt();
|
|
|
|
if (id < 6000)
|
|
|
|
return NV30;
|
|
|
|
|
|
|
|
if (id >= 6000 && id < 8000)
|
|
|
|
return NV40;
|
|
|
|
|
|
|
|
if (id >= 8000)
|
|
|
|
return G80;
|
|
|
|
|
|
|
|
return UnknownNVidia;
|
|
|
|
}
|
|
|
|
|
|
|
|
// GeForce 100/200/300/400/500
|
|
|
|
name = extract(chipset, "GeForce (G |GT |GTX |GTS )?\\d{3}(M|\\b)").trimmed();
|
|
|
|
if (!name.isEmpty()) {
|
|
|
|
if (!name[name.length() - 1].isDigit())
|
|
|
|
name.chop(1);
|
|
|
|
|
|
|
|
const int id = name.right(3).toInt();
|
|
|
|
if (id >= 100 && id < 600) {
|
|
|
|
if (id >= 400)
|
|
|
|
return GF100;
|
|
|
|
|
|
|
|
return G80;
|
|
|
|
}
|
|
|
|
return UnknownNVidia;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-12-03 23:26:30 +00:00
|
|
|
|
2010-11-12 05:30:38 +00:00
|
|
|
return UnknownNVidia;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ChipClass detectIntelClass(const QByteArray &chipset)
|
|
|
|
{
|
|
|
|
// GL 1.3, DX8? SM ?
|
|
|
|
if (chipset.contains("845G") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("830M") ||
|
|
|
|
chipset.contains("852GM/855GM") ||
|
|
|
|
chipset.contains("865G"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return I8XX;
|
|
|
|
|
|
|
|
// GL 1.4, DX 9.0, SM 2.0
|
|
|
|
if (chipset.contains("915G") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("E7221G") ||
|
|
|
|
chipset.contains("915GM") ||
|
|
|
|
chipset.contains("945G") || // DX 9.0c
|
|
|
|
chipset.contains("945GM") ||
|
|
|
|
chipset.contains("945GME") ||
|
|
|
|
chipset.contains("Q33") || // GL1.5
|
|
|
|
chipset.contains("Q35") ||
|
|
|
|
chipset.contains("G33") ||
|
|
|
|
chipset.contains("965Q") || // GMA 3000, but apparently considered gen 4 by the driver
|
|
|
|
chipset.contains("946GZ") || // GMA 3000, but apparently considered gen 4 by the driver
|
|
|
|
chipset.contains("IGD"))
|
2010-11-12 05:30:38 +00:00
|
|
|
return I915;
|
|
|
|
|
|
|
|
// GL 2.0, DX 9.0c, SM 3.0
|
|
|
|
if (chipset.contains("965G") ||
|
2011-01-30 14:34:42 +00:00
|
|
|
chipset.contains("G45/G43") || // SM 4.0
|
|
|
|
chipset.contains("965GM") || // GL 2.1
|
|
|
|
chipset.contains("965GME/GLE") ||
|
|
|
|
chipset.contains("GM45") ||
|
|
|
|
chipset.contains("Q45/Q43") ||
|
|
|
|
chipset.contains("G41") ||
|
|
|
|
chipset.contains("B43") ||
|
|
|
|
chipset.contains("Ironlake") ||
|
|
|
|
chipset.contains("Sandybridge")) // GL 3.1, CL 1.1, DX 10.1
|
2010-11-12 05:30:38 +00:00
|
|
|
return I965;
|
|
|
|
|
|
|
|
return UnknownIntel;
|
|
|
|
}
|
|
|
|
|
2010-11-28 17:07:23 +00:00
|
|
|
static QString versionToString(qint64 version)
|
|
|
|
{
|
|
|
|
int major = (version >> 32);
|
|
|
|
int minor = (version >> 16) & 0xffff;
|
|
|
|
int patch = version & 0xffff;
|
|
|
|
|
|
|
|
QString string = QString::number(major) + QChar('.') + QString::number(minor);
|
|
|
|
if (patch != 0)
|
|
|
|
string += QChar('.') + QString::number(patch);
|
|
|
|
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QString driverToString(Driver driver)
|
|
|
|
{
|
2011-01-30 14:34:42 +00:00
|
|
|
switch(driver) {
|
2010-11-28 17:07:23 +00:00
|
|
|
case Driver_R100:
|
|
|
|
return "Radeon";
|
|
|
|
case Driver_R200:
|
|
|
|
return "R200";
|
|
|
|
case Driver_R300C:
|
|
|
|
return "R300C";
|
|
|
|
case Driver_R300G:
|
|
|
|
return "R300G";
|
|
|
|
case Driver_R600C:
|
|
|
|
return "R600C";
|
|
|
|
case Driver_R600G:
|
|
|
|
return "R600G";
|
|
|
|
case Driver_Nouveau:
|
|
|
|
return "Nouveau";
|
|
|
|
case Driver_Intel:
|
|
|
|
return "Intel";
|
|
|
|
case Driver_NVidia:
|
|
|
|
return "NVIDIA";
|
|
|
|
case Driver_Catalyst:
|
|
|
|
return "Catalyst";
|
|
|
|
case Driver_Swrast:
|
|
|
|
return "Software rasterizer";
|
|
|
|
case Driver_Softpipe:
|
|
|
|
return "softpipe";
|
|
|
|
case Driver_Llvmpipe:
|
|
|
|
return "LLVMpipe";
|
|
|
|
|
|
|
|
default:
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static QString chipClassToString(ChipClass chipClass)
|
|
|
|
{
|
2011-01-30 14:34:42 +00:00
|
|
|
switch(chipClass) {
|
2010-11-28 17:07:23 +00:00
|
|
|
case R100:
|
|
|
|
return "R100";
|
|
|
|
case R200:
|
|
|
|
return "R200";
|
|
|
|
case R300:
|
|
|
|
return "R300";
|
|
|
|
case R400:
|
|
|
|
return "R400";
|
|
|
|
case R500:
|
|
|
|
return "R500";
|
|
|
|
case R600:
|
|
|
|
return "R600";
|
|
|
|
case R700:
|
|
|
|
return "R700";
|
|
|
|
case Evergreen:
|
|
|
|
return "EVERGREEN";
|
|
|
|
case NorthernIslands:
|
|
|
|
return "NI";
|
|
|
|
|
|
|
|
case NV10:
|
|
|
|
return "NV10";
|
|
|
|
case NV20:
|
|
|
|
return "NV20";
|
|
|
|
case NV30:
|
|
|
|
return "NV30";
|
|
|
|
case NV40:
|
|
|
|
return "NV40/G70";
|
|
|
|
case G80:
|
|
|
|
return "G80/G90";
|
|
|
|
case GF100:
|
|
|
|
return "GF100";
|
|
|
|
|
|
|
|
case I8XX:
|
|
|
|
return "i830/i835";
|
|
|
|
case I915:
|
|
|
|
return "i915/i945";
|
|
|
|
case I965:
|
|
|
|
return "i965";
|
|
|
|
case SandyBridge:
|
|
|
|
return "SandyBridge";
|
|
|
|
|
|
|
|
default:
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 05:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
// -------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GLPlatform::GLPlatform()
|
|
|
|
: m_driver(Driver_Unknown),
|
|
|
|
m_chipClass(UnknownChipClass),
|
|
|
|
m_mesaVersion(0),
|
|
|
|
m_galliumVersion(0),
|
|
|
|
m_looseBinding(false),
|
|
|
|
m_directRendering(false),
|
|
|
|
m_supportsGLSL(false),
|
|
|
|
m_limitedGLSL(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
GLPlatform::~GLPlatform()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLPlatform::detect()
|
|
|
|
{
|
|
|
|
m_vendor = (const char*)glGetString(GL_VENDOR);
|
|
|
|
m_renderer = (const char*)glGetString(GL_RENDERER);
|
|
|
|
m_version = (const char*)glGetString(GL_VERSION);
|
|
|
|
|
|
|
|
const QByteArray extensions = (const char*)glGetString(GL_EXTENSIONS);
|
|
|
|
m_extensions = QSet<QByteArray>::fromList(extensions.split(' '));
|
|
|
|
|
|
|
|
// Parse the OpenGL version
|
|
|
|
const QList<QByteArray> versionTokens = m_version.split(' ');
|
|
|
|
if (versionTokens.count() > 0) {
|
2011-02-23 05:15:21 +00:00
|
|
|
const QByteArray version = QByteArray(m_version);
|
2010-11-12 05:30:38 +00:00
|
|
|
m_glVersion = parseVersionString(version);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the Mesa version
|
|
|
|
const int mesaIndex = versionTokens.indexOf("Mesa");
|
|
|
|
if (mesaIndex != -1) {
|
|
|
|
const QByteArray version = versionTokens.at(mesaIndex + 1);
|
|
|
|
m_mesaVersion = parseVersionString(version);
|
|
|
|
}
|
|
|
|
|
2010-12-12 11:07:56 +00:00
|
|
|
#ifdef KWIN_HAVE_OPENGLES
|
|
|
|
m_directRendering = true;
|
|
|
|
m_supportsGLSL = true;
|
|
|
|
m_textureNPOT = true;
|
|
|
|
#else
|
2010-11-12 05:30:38 +00:00
|
|
|
GLXContext ctx = glXGetCurrentContext();
|
|
|
|
m_directRendering = glXIsDirect(display(), ctx);
|
|
|
|
|
|
|
|
m_supportsGLSL = m_extensions.contains("GL_ARB_shading_language_100") &&
|
|
|
|
m_extensions.contains("GL_ARB_shader_objects") &&
|
|
|
|
m_extensions.contains("GL_ARB_fragment_shader") &&
|
2010-11-28 17:16:45 +00:00
|
|
|
m_extensions.contains("GL_ARB_vertex_shader");
|
2010-11-12 05:30:38 +00:00
|
|
|
|
2010-11-18 21:47:29 +00:00
|
|
|
m_textureNPOT = m_extensions.contains("GL_ARB_texture_non_power_of_two");
|
2010-12-12 11:07:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
m_serverVersion = getXServerVersion();
|
|
|
|
m_kernelVersion = getKernelVersion();
|
2010-11-18 21:47:29 +00:00
|
|
|
|
2010-11-28 17:16:45 +00:00
|
|
|
m_glslVersion = 0;
|
|
|
|
m_glsl_version = QByteArray();
|
|
|
|
|
|
|
|
if (m_supportsGLSL) {
|
|
|
|
// Parse the GLSL version
|
|
|
|
m_glsl_version = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
|
2011-02-23 05:15:21 +00:00
|
|
|
m_glslVersion = parseVersionString(m_glsl_version);
|
2010-11-28 17:16:45 +00:00
|
|
|
}
|
|
|
|
|
2010-11-12 05:30:38 +00:00
|
|
|
m_chipset = "Unknown";
|
|
|
|
|
|
|
|
|
|
|
|
// Mesa classic drivers
|
|
|
|
// ====================================================
|
|
|
|
|
|
|
|
// Radeon
|
|
|
|
if (m_renderer.startsWith("Mesa DRI R")) {
|
|
|
|
// Sample renderer string: Mesa DRI R600 (RV740 94B3) 20090101 x86/MMX/SSE2 TCL DRI2
|
|
|
|
const QList<QByteArray> tokens = m_renderer.split(' ');
|
|
|
|
const QByteArray chipClass = tokens.at(2);
|
|
|
|
m_chipset = tokens.at(3).mid(1, -1); // Strip the leading '('
|
|
|
|
|
|
|
|
if (chipClass == "R100")
|
|
|
|
// Vendor: Tungsten Graphics, Inc.
|
|
|
|
m_driver = Driver_R100;
|
|
|
|
|
|
|
|
else if (chipClass == "R200")
|
|
|
|
// Vendor: Tungsten Graphics, Inc.
|
|
|
|
m_driver = Driver_R200;
|
|
|
|
|
|
|
|
else if (chipClass == "R300")
|
|
|
|
// Vendor: DRI R300 Project
|
|
|
|
m_driver = Driver_R300C;
|
|
|
|
|
|
|
|
else if (chipClass == "R600")
|
|
|
|
// Vendor: Advanced Micro Devices, Inc.
|
|
|
|
m_driver = Driver_R600C;
|
|
|
|
|
|
|
|
m_chipClass = detectRadeonClass(m_chipset);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Intel
|
|
|
|
else if (m_renderer.contains("Intel")) {
|
2011-01-30 14:34:42 +00:00
|
|
|
// Vendor: Tungsten Graphics, Inc.
|
2010-11-12 05:30:38 +00:00
|
|
|
// Sample renderer string: Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100328 2010Q1
|
|
|
|
|
|
|
|
QByteArray chipset;
|
|
|
|
if (m_renderer.startsWith("Intel(R) Integrated Graphics Device"))
|
|
|
|
chipset = "IGD";
|
|
|
|
else
|
|
|
|
chipset = m_renderer;
|
|
|
|
|
|
|
|
m_driver = Driver_Intel;
|
|
|
|
m_chipClass = detectIntelClass(chipset);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-11-12 05:30:38 +00:00
|
|
|
|
|
|
|
// Gallium drivers
|
|
|
|
// ====================================================
|
|
|
|
else if (m_renderer.contains("Gallium")) {
|
2011-01-30 14:34:42 +00:00
|
|
|
// Sample renderer string: Gallium 0.4 on AMD RV740
|
2010-11-12 05:30:38 +00:00
|
|
|
const QList<QByteArray> tokens = m_renderer.split(' ');
|
|
|
|
m_galliumVersion = parseVersionString(tokens.at(1));
|
2011-01-11 20:06:47 +00:00
|
|
|
m_chipset = (tokens.at(3) == "AMD" || tokens.at(3) == "ATI") ?
|
2011-01-30 14:34:42 +00:00
|
|
|
tokens.at(4) : tokens.at(3);
|
2010-11-12 05:30:38 +00:00
|
|
|
|
|
|
|
// R300G
|
|
|
|
if (m_vendor == "X.Org R300 Project") {
|
|
|
|
m_chipClass = detectRadeonClass(m_chipset);
|
|
|
|
m_driver = Driver_R300G;
|
|
|
|
}
|
|
|
|
|
|
|
|
// R600G
|
|
|
|
else if (m_vendor == "X.Org" &&
|
2011-01-30 14:34:42 +00:00
|
|
|
(m_renderer.contains("R6") ||
|
|
|
|
m_renderer.contains("R7") ||
|
|
|
|
m_renderer.contains("RV6") ||
|
|
|
|
m_renderer.contains("RV7") ||
|
|
|
|
m_renderer.contains("RS780") ||
|
|
|
|
m_renderer.contains("RS880") ||
|
|
|
|
m_renderer.contains("CEDAR") ||
|
|
|
|
m_renderer.contains("REDWOOD") ||
|
|
|
|
m_renderer.contains("JUNIPER") ||
|
|
|
|
m_renderer.contains("CYPRESS") ||
|
|
|
|
m_renderer.contains("HEMLOCK") ||
|
|
|
|
m_renderer.contains("PALM") ||
|
|
|
|
m_renderer.contains("EVERGREEN") ||
|
|
|
|
m_renderer.contains("BARTS") ||
|
|
|
|
m_renderer.contains("TURKS") ||
|
|
|
|
m_renderer.contains("CAICOS"))) {
|
2010-11-12 05:30:38 +00:00
|
|
|
m_chipClass = detectRadeonClass(m_chipset);
|
|
|
|
m_driver = Driver_R600G;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nouveau
|
|
|
|
else if (m_vendor == "nouveau") {
|
|
|
|
m_chipClass = detectNVidiaClass(m_chipset);
|
|
|
|
m_driver = Driver_Nouveau;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (m_chipset == "softpipe" || m_chipset == "llvmpipe") {
|
|
|
|
// Vendor: VMware, Inc.
|
|
|
|
// TODO
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-11-12 05:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Properietary drivers
|
|
|
|
// ====================================================
|
|
|
|
else if (m_vendor == "ATI Technologies Inc.") {
|
|
|
|
m_chipClass = detectRadeonClass(m_renderer);
|
|
|
|
m_driver = Driver_Catalyst;
|
|
|
|
|
|
|
|
if (versionTokens.count() > 1 && versionTokens.at(2)[0] == '(')
|
|
|
|
m_driverVersion = parseVersionString(versionTokens.at(1));
|
|
|
|
else if (versionTokens.count() > 0)
|
|
|
|
m_driverVersion = parseVersionString(versionTokens.at(0));
|
|
|
|
else
|
|
|
|
m_driverVersion = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (m_vendor == "NVIDIA Corporation") {
|
2010-12-03 23:26:30 +00:00
|
|
|
m_chipClass = detectNVidiaClass(m_renderer);
|
2010-11-12 05:30:38 +00:00
|
|
|
m_driver = Driver_NVidia;
|
2011-01-30 14:34:42 +00:00
|
|
|
|
2010-11-12 05:30:38 +00:00
|
|
|
int index = versionTokens.indexOf("NVIDIA");
|
|
|
|
if (versionTokens.count() > index)
|
|
|
|
m_driverVersion = parseVersionString(versionTokens.at(index + 1));
|
|
|
|
else
|
|
|
|
m_driverVersion = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Driver/GPU specific features
|
|
|
|
// ====================================================
|
|
|
|
if (isRadeon()) {
|
|
|
|
// R200 technically has a programmable pipeline, but since it's SM 1.4,
|
|
|
|
// it's too limited to to be of any practical value to us.
|
|
|
|
if (m_chipClass < R300)
|
|
|
|
m_supportsGLSL = false;
|
|
|
|
|
2010-11-18 21:47:29 +00:00
|
|
|
m_limitedGLSL = false;
|
|
|
|
m_limitedNPOT = false;
|
|
|
|
|
|
|
|
if (m_chipClass < R600) {
|
|
|
|
if (driver() == Driver_Catalyst)
|
|
|
|
m_textureNPOT = m_limitedNPOT = false; // Software fallback
|
|
|
|
else if (driver() == Driver_R300G)
|
|
|
|
m_limitedNPOT = m_textureNPOT;
|
|
|
|
|
|
|
|
m_limitedGLSL = m_supportsGLSL;
|
|
|
|
}
|
2010-11-12 05:30:38 +00:00
|
|
|
|
|
|
|
if (driver() == Driver_R600G ||
|
2011-01-30 14:34:42 +00:00
|
|
|
(driver() == Driver_R600C && m_renderer.contains("DRI2"))) {
|
2010-11-12 05:30:38 +00:00
|
|
|
m_looseBinding = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isNvidia()) {
|
|
|
|
if (m_driver == Driver_NVidia && m_chipClass < NV40)
|
|
|
|
m_supportsGLSL = false; // High likelihood of software emulation
|
|
|
|
|
|
|
|
if (m_driver == Driver_NVidia)
|
|
|
|
m_looseBinding = true;
|
|
|
|
|
2010-11-18 21:47:29 +00:00
|
|
|
m_limitedNPOT = m_textureNPOT && m_chipClass < NV40;
|
2010-11-12 05:30:38 +00:00
|
|
|
m_limitedGLSL = m_supportsGLSL && m_chipClass < G80;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-11-12 05:30:38 +00:00
|
|
|
|
|
|
|
if (isIntel()) {
|
|
|
|
if (m_chipClass < I915)
|
|
|
|
m_supportsGLSL = false;
|
|
|
|
|
|
|
|
m_limitedGLSL = m_supportsGLSL && m_chipClass < I965;
|
|
|
|
}
|
2011-01-11 22:32:51 +00:00
|
|
|
|
|
|
|
// Loose binding is broken with Gallium drivers in Mesa 7.10
|
|
|
|
if (isGalliumDriver() && mesaVersion() >= kVersionNumber(7, 10))
|
|
|
|
m_looseBinding = false;
|
2010-11-12 05:30:38 +00:00
|
|
|
}
|
|
|
|
|
2010-11-28 17:07:23 +00:00
|
|
|
static void print(const QString &label, const QString &setting)
|
|
|
|
{
|
|
|
|
std::cout << std::setw(40) << std::left
|
2011-01-30 14:34:42 +00:00
|
|
|
<< qPrintable(label) << qPrintable(setting) << std::endl;
|
2010-11-28 17:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLPlatform::printResults() const
|
|
|
|
{
|
|
|
|
print("OpenGL vendor string:", m_vendor);
|
|
|
|
print("OpenGL renderer string:", m_renderer);
|
|
|
|
print("OpenGL version string:", m_version);
|
|
|
|
|
|
|
|
if (m_supportsGLSL)
|
|
|
|
print("OpenGL shading language version string:", m_glsl_version);
|
|
|
|
|
|
|
|
print("Driver:", driverToString(m_driver));
|
|
|
|
if (!isMesaDriver())
|
|
|
|
print("Driver version:", versionToString(m_driverVersion));
|
|
|
|
|
|
|
|
print("GPU class:", chipClassToString(m_chipClass));
|
2011-01-30 14:34:42 +00:00
|
|
|
|
2010-11-28 17:07:23 +00:00
|
|
|
print("OpenGL version:", versionToString(m_glVersion));
|
2011-01-11 20:16:50 +00:00
|
|
|
|
|
|
|
if (m_supportsGLSL)
|
|
|
|
print("GLSL version:", versionToString(m_glslVersion));
|
2010-11-28 17:07:23 +00:00
|
|
|
|
|
|
|
if (isMesaDriver())
|
|
|
|
print("Mesa version:", versionToString(mesaVersion()));
|
|
|
|
//if (galliumVersion() > 0)
|
|
|
|
// print("Gallium version:", versionToString(m_galliumVersion));
|
|
|
|
if (serverVersion() > 0)
|
|
|
|
print("X server version:", versionToString(m_serverVersion));
|
|
|
|
if (kernelVersion() > 0)
|
|
|
|
print("Linux kernel version:", versionToString(m_kernelVersion));
|
|
|
|
|
|
|
|
print("Direct rendering:", m_directRendering ? "yes" : "no");
|
|
|
|
print("Requires strict binding:", !m_looseBinding ? "yes" : "no");
|
2011-01-11 20:22:45 +00:00
|
|
|
print("GLSL shaders:", m_supportsGLSL ? (m_limitedGLSL ? "limited" : "yes") : "no");
|
|
|
|
print("Texture NPOT support:", m_textureNPOT ? (m_limitedNPOT ? "limited" : "yes") : "no");
|
2010-11-28 17:07:23 +00:00
|
|
|
}
|
|
|
|
|
2010-11-12 05:30:38 +00:00
|
|
|
bool GLPlatform::supports(GLFeature feature) const
|
|
|
|
{
|
2011-01-30 14:34:42 +00:00
|
|
|
switch(feature) {
|
2010-11-12 05:30:38 +00:00
|
|
|
case LooseBinding:
|
|
|
|
return m_looseBinding;
|
|
|
|
|
|
|
|
case GLSL:
|
|
|
|
return m_supportsGLSL;
|
|
|
|
|
|
|
|
case LimitedGLSL:
|
|
|
|
return m_limitedGLSL;
|
|
|
|
|
2010-11-18 21:47:29 +00:00
|
|
|
case TextureNPOT:
|
|
|
|
return m_textureNPOT;
|
|
|
|
|
|
|
|
case LimitedNPOT:
|
|
|
|
return m_limitedNPOT;
|
|
|
|
|
2010-11-12 05:30:38 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qint64 GLPlatform::glVersion() const
|
|
|
|
{
|
|
|
|
return m_glVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
qint64 GLPlatform::glslVersion() const
|
|
|
|
{
|
2011-02-19 13:03:04 +00:00
|
|
|
return m_glslVersion;
|
2010-11-12 05:30:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
qint64 GLPlatform::mesaVersion() const
|
|
|
|
{
|
|
|
|
return m_mesaVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
qint64 GLPlatform::galliumVersion() const
|
|
|
|
{
|
|
|
|
return m_galliumVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
qint64 GLPlatform::serverVersion() const
|
|
|
|
{
|
|
|
|
return m_serverVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
qint64 GLPlatform::kernelVersion() const
|
|
|
|
{
|
|
|
|
return m_kernelVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
qint64 GLPlatform::driverVersion() const
|
|
|
|
{
|
|
|
|
if (isMesaDriver())
|
|
|
|
return mesaVersion();
|
|
|
|
|
|
|
|
return m_driverVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
Driver GLPlatform::driver() const
|
|
|
|
{
|
|
|
|
return m_driver;
|
|
|
|
}
|
|
|
|
|
|
|
|
ChipClass GLPlatform::chipClass() const
|
|
|
|
{
|
|
|
|
return m_chipClass;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GLPlatform::isMesaDriver() const
|
|
|
|
{
|
|
|
|
return mesaVersion() > 0;
|
|
|
|
}
|
|
|
|
|
2011-01-11 22:32:51 +00:00
|
|
|
bool GLPlatform::isGalliumDriver() const
|
|
|
|
{
|
|
|
|
return galliumVersion() > 0;
|
|
|
|
}
|
|
|
|
|
2010-11-12 05:30:38 +00:00
|
|
|
bool GLPlatform::isRadeon() const
|
|
|
|
{
|
|
|
|
return m_chipClass >= R100 && m_chipClass <= UnknownRadeon;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GLPlatform::isNvidia() const
|
|
|
|
{
|
|
|
|
return m_chipClass >= NV10 && m_chipClass <= UnknownNVidia;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GLPlatform::isIntel() const
|
|
|
|
{
|
|
|
|
return m_chipClass >= I8XX && m_chipClass <= UnknownIntel;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace KWin
|
|
|
|
|
|
|
|
#endif // KWIN_HAVE_OPENGL
|
|
|
|
|