#if defined(__WIN32__) || defined(_WIN32)
# include <windows.h>
# if defined(USE_SDL2)
# include "SDL.h"
# endif
#elif defined(__ANDROID__)
# include <EGL/egl.h>
# include <fstream>
#else
# if !defined( NO_GRAPHICS_TESTS )
# if defined(USE_SDL2)
# include "SDL.h"
# else
# include <X11/Xlib.h>
# ifdef HAS_XF86VM
# include <X11/extensions/xf86vmode.h>
# endif
# endif
# if defined(USE_EGL)
# include <EGL/egl.h>
# endif
# endif
# include <fstream>
# include <sys/utsname.h>
#endif
#include <sstream>
#include <iostream>
#include <assert.h>
#include <map>
#include <stdlib.h>
#include <string.h>
#include "StdStreamRedirection.h"
#include "hw.h"
#include "graphic-window.h"
#ifndef APIENTRY
# define APIENTRY
#endif
using namespace std;
#ifndef VER_SUITE_WH_SERVER
#define VER_SUITE_WH_SERVER 0x00008000
#endif
#ifndef SM_SERVERR2
#define SM_SERVERR2 89
#endif
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
#define GL_NO_ERROR 0
#define GL_INVALID_ENUM 0x0500
#ifndef GL_SHADING_LANGUAGE_VERSION
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
#endif
#ifndef GL_CONTEXT_FLAGS
#define GL_CONTEXT_FLAGS 0x821E
#endif
#ifndef GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
#endif
#ifndef GL_CONTEXT_PROFILE_MASK
#define GL_CONTEXT_PROFILE_MASK 0x9126
#endif
#ifndef GL_CONTEXT_CORE_PROFILE_BIT
#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
#endif
#ifndef GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
#endif
#ifndef GL_NUM_EXTENSIONS
#define GL_NUM_EXTENSIONS 0x821D
#endif
#ifndef GL_MAX_TEXTURE_SIZE
#define GL_MAX_TEXTURE_SIZE 0x0D33
#endif
#ifndef GL_MULTISAMPLE_ARB
#define GL_MULTISAMPLE_ARB 0x809D
#endif
#ifndef GL_SAMPLE_BUFFERS_ARB
#define GL_SAMPLE_BUFFERS_ARB 0x80A8
#endif
#ifndef GL_SAMPLES_ARB
#define GL_SAMPLES_ARB 0x80A9
#endif
typedef unsigned int GLenum;
typedef int GLint;
typedef unsigned int GLuint;
typedef unsigned char GLubyte;
typedef GLenum (APIENTRY * PFNGLGETERRORPROC) ( void );
typedef void (APIENTRY * PFNGLGETINTEGERVPROC) ( GLenum pname, GLint* params );
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC) ( GLenum name );
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC) ( GLenum name, GLuint index );
static PFNGLGETERRORPROC glGetError = NULL;
static PFNGLGETINTEGERVPROC glGetIntegerv = NULL;
static PFNGLGETSTRINGPROC glGetString = NULL;
static PFNGLGETSTRINGIPROC glGetStringi = NULL;
#if !defined(NO_GRAPHICS_TESTS) && !defined(USE_SDL2) && !defined(__WIN32__) && !defined(_WIN32) && !defined(USE_EGL)
#define GLX_VERSION_1_2 1
#define GLX_VENDOR 1
#define GLX_SCREEN 0x800C
typedef struct __GLXcontextRec *GLXContext;
extern "C" Display *glXGetCurrentDisplay( void );
extern "C" Bool glXQueryVersion( Display *dpy, int *maj, int *min );
extern "C" const char *glXQueryServerString( Display *dpy, int screen, int name );
extern "C" const char *glXGetClientString( Display *dpy, int name );
extern "C" GLXContext glXGetCurrentContext( void );
extern "C" int glXQueryContext( Display *dpy, GLXContext ctx, int attribute, int *value );
#define GLX_FBCONFIG_ID 0x8013
#define GLX_RED_SIZE 8
#define GLX_GREEN_SIZE 9
#define GLX_BLUE_SIZE 10
#define GLX_ALPHA_SIZE 11
#define GLX_DEPTH_SIZE 12
#define GLX_STENCIL_SIZE 13
#define GLX_ACCUM_RED_SIZE 14
#define GLX_ACCUM_GREEN_SIZE 15
#define GLX_ACCUM_BLUE_SIZE 16
#define GLX_ACCUM_ALPHA_SIZE 17
struct XVisualInfo;
typedef struct __GLXFBConfigRec *GLXFBConfig;
extern "C" int glXGetConfig( Display *dpy, XVisualInfo *visual, int attrib, int *value );
extern "C" GLXFBConfig *glXChooseFBConfig( Display *dpy, int screen,
const int *attribList, int *nitems );
extern "C" XVisualInfo *glXGetVisualFromFBConfig( Display *dpy, GLXFBConfig config );
#endif
//////////////////////////////////////////////////////////////
//
// Description:
// Windows only.
// Returns registry string from the given key and valueName.
//
#if defined(__WIN32__) || defined(_WIN32)
static string getRegistryString(const char *key, const char *valueName)
{
// open the registry key
HKEY hKey;
LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
key,
0,
KEY_READ,
&hKey);
// key could not be opened
if (ret != ERROR_SUCCESS)
return string();
// get registry value length
DWORD type;
DWORD size = 0;
ret = RegQueryValueEx(hKey, valueName, NULL, &type, NULL, &size);
// key could not be read
if (ret != ERROR_SUCCESS) {
RegCloseKey(hKey);
return string();
}
assert(size>0);
// get registry value
char *s = new char[size];
ret = RegQueryValueEx(hKey, valueName, NULL, &type, (LPBYTE)s, &size);
// key could not be read
if (ret != ERROR_SUCCESS) {
delete[] s;
RegCloseKey(hKey);
return string();
}
// return value
RegCloseKey(hKey);
string r(s);
delete[] s;
return r;
}
#endif
int getNumCpus()
{
#if defined(__WIN32__) || defined(_WIN32)
// Windows
// Let's use info stored in registry
int i;
char cpuKeyName[] = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\??";
char *numP = strstr(cpuKeyName, "?");
for (i=0; i<=99; i++)
{
// create registry key name
if (i < 10) {
numP[0] = '0' + i;
numP[1] = 0; // terminating zero
} else {
numP[0] = '0' + i/10;
numP[1] = '0' + i%10;
}
// get cpu string
//
// FIXME: it is known, that Win9x uses different value string:
// instead of "ProcessorNameString" it uses "Identifier".
// However, this was not implemented and tested yet
// as I have no machine with Win9x. PCJohn 2005-11-13
//
// UPDATE: It has probably nothing to do with Win9x.
// Seems that "Identifier" is present always, telling something
// like "x86 Family 6 Model 6 Stepping 0", while
// "ProcessorNameString" is present only when
// processor name retrieval is supported by cpuid instruction.
// PCJohn 2012-04-27
string cpuString = getRegistryString(cpuKeyName,
"ProcessorNameString");
// read ok - processor name exists
if (cpuString.length() > 0)
continue;
// read identifier
cpuString = getRegistryString(cpuKeyName,
"Identifier");
// read ok - processor identifier exists
if (cpuString.length() > 0)
continue;
// read failed - no more processors
return i;
}
// 100 processors (or more) exists
// (this is not expected to happen on standard Windows architectures)
return 100;
#else
// Linux, Unixes,...
// based on number of occurencies of the phrase "model name" in /proc/cpuinfo
int num = 0;
ifstream fs("/proc/cpuinfo", ios::in);
string line;
// read all lines in the file and look for "model name" text
// that is used on x86 and amd64 architecture
while (fs.good()) {
getline(fs, line);
if (line.find("model name") != string::npos) {
num++; // one more processor found
}
}
// if no "model names" were found, let's try "Processor" and "processor" used on ARM architecture
//
// Example line on Nokia N9 (Meego - a Linux clone):
// Processor : ARMv7 Processor rev 2 (v7l)
// BogoMIPS : 996.74
// ....
//
// Example of Samsung Galaxy Tab S 10.5 LTE (Android 4.4):
// Processor : ARMv7 Processor rev 3 (v7l)
// processor : 0
// BogoMIPS : 1590.88
//
// processor : 1
// BogoMIPS : 1590.88
// ...
if (num == 0) {
int n1 = 0;
int n2 = 0;
fs.clear();
fs.seekg(0);
while (fs.good()) {
getline(fs, line);
if (line.find("Processor") != string::npos) {
n1++; // one more processor found
}
if (line.find("processor") != string::npos) {
n2++; // one more processor found
}
}
// return the bigger one
num=n1>n2 ? n1 : n2;
}
// return number of processors
return num;
#endif
}
string getCpuName()
{
#if defined(__WIN32__) || defined(_WIN32)
// Windows
//
// Processor name detection routines use processor info stored in registry
// while "ProcessorNameString" of first processor is returned.
string r;
char cpuKeyName[] = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
// FIXME: it is known, that Win9x uses different value string:
// instead of "ProcessorNameString" it uses "Identifier".
// However, this was not implemented and tested yet
// as I have no machine with Win9x. PCJohn 2005-11-13
//
// UPDATE: It has probably nothing to do with Win9x.
// Seems that "Identifier" is present always, telling something
// like "x86 Family 6 Model 6 Stepping 0", while
// "ProcessorNameString" is present only when
// processor name retrieval is supported by cpuid instruction.
// PCJohn 2012-04-27
string cpuString = getRegistryString(cpuKeyName,
"ProcessorNameString");
// read ok - processor name exists
if (cpuString.length() == 0)
{
// read identifier
cpuString = getRegistryString(cpuKeyName,
"Identifier");
}
if (cpuString.length() > 0) {
// skip spaces
while (cpuString.length() > 0 && cpuString[0] == ' ')
cpuString.erase(0, 1);
// return cpu string
return cpuString;
}
// detection failed
return "<detection failed>";
#else
// Linux, Unixes,...
// based on the text of "model name" line in /proc/cpuinfo
ifstream fs("/proc/cpuinfo", ios::in);
string line;
while (fs.good()) {
getline(fs, line);
if (line.find("model name") != string::npos) {
unsigned int i = line.find(':', 0);
i++;
while (i < line.length()) {
if (line[i] != ' ')
break;
i++;
}
return string(&line.c_str()[i]);
}
}
// if no "model names" were found, let's try "Processor" used on ARM architecture
//
// example line on Nokia N9:
// Processor : ARMv7 Processor rev 2 (v7l)
//
fs.clear();
fs.seekg(0);
while (fs.good()) {
getline(fs, line);
if (line.find("Processor") != string::npos) {
unsigned int i = line.find(':', 0);
i++;
while (i < line.length()) {
if (line[i] != ' ')
break;
i++;
}
return string(&line.c_str()[i]);
}
}
// no result found
return string();
#endif
}
//
// hasCPUID returns true if the processor supports cpu identification.
//
// On x86/amd64 architecture, it returns true if CPUID instruction is supported.
// The test is based on testing writeability ID - bit 21 of eflags
// as recommended by Intel documentation.
//
// On ARM processors, true is returned as the identification is based on register 0
// of the System Control Coprocessor (coprocessor 15, CP15). However, CP15 is not
// present on all ARM chips, only those containing MMU or MPU.
//
bool hasCpuID()
{
#if defined(__arm__) || defined(__aarch64__)
return true;
#else
int r1,r2;
#if __GNUC__
//
// gcc assembler code
//
asm volatile(
"pushf\n" // preserve original flags
"pushf\n"
# if __SIZEOF_POINTER__ == 8
"pop %%rax\n"
"mov %%rax,%%rdx\n"
# else
"pop %%eax\n"
"mov %%eax,%%edx\n"
# endif
"xor $0x00200000,%%eax\n"
# if __SIZEOF_POINTER__ == 8
"push %%rax\n"
# else
"push %%eax\n"
# endif
"popf\n" // put modified EFLAGS.ID (bit 21)
"pushf\n" // get new eflags
# if __SIZEOF_POINTER__ == 8
"pop %%rax\n"
# else
"pop %%eax\n"
# endif
"xor %%edx,%%eax\n" // compare with the original value
"and $0x200000,%%eax\n" // test only bit 21
"movl %%eax,%0\n" // write result to r1
# if __SIZEOF_POINTER__ == 8
"push %%rdx\n"
# else
"push %%edx\n"
# endif
"popf\n"
"pushf\n"
# if __SIZEOF_POINTER__ == 8
"pop %%rax\n"
# else
"pop %%eax\n"
# endif
"xor %%edx,%%eax\n"
"and $0x200000,%%eax\n" // test only bit 21
"movl %%eax,%1\n" // write result to r2
"popf\n" // restore original flags
: "=rm"(r1), "=rm"(r2)
:
# if __SIZEOF_POINTER__ == 8
: "%rax", "%rdx");
# else
: "%eax", "%edx");
# endif
#else
//
// assembler of Intel, Visual C++,...
// for x64 and x86
//
# if _M_X64
unsigned __int64 v1;
v1 = __readeflags(); // get original eflags
const unsigned __int64 v2 = v1;
v1 = v1 ^ 0x00200000;
__writeeflags( v1 ); // put modified EFLAGS.ID (bit 21)
v1 = __readeflags(); // get new eflags
r1 = int( v1 ^ v2 ); // compare with the original value
r1 &= 0x00200000; // test only bit 21
__writeeflags( v2 );
v1 = __readeflags();
r2 = int( v1 ^ v2 );
r2 &= 0x00200000; // test only bit 21
# else
__asm {
pushfd
pushfd // get original eflags
pop eax
mov edx,eax
xor eax,0x00200000
push eax
popfd // put modified EFLAGS.ID (bit 21)
pushfd // get new eflags
pop eax
xor eax,edx // compare with the original value
and eax,0x00200000 // test only bit 21
mov r1,eax // write result to r1
push edx
popfd
pushfd
pop eax
xor eax,edx
and eax,0x00200000 // test only bit 21
mov r2,eax // write result to r2
popfd
};
# endif
#endif
return r1!=0 && r2==0;
#endif
}
string getCpuVendorID()
{
// if no CPUID then unknown manufacturer
if (!hasCpuID())
return "";
#if defined(__arm__) || defined(__aarch64__)
return "";
#else
char buf[4*3+1];
buf[4*3] = '\0';
char *p = &buf[0];
# if __GNUC__
//
// gcc assembler code
//
asm volatile(
"xor %%eax,%%eax\n"
"cpuid\n"
# if __SIZEOF_POINTER__ == 8
"mov %0,%%rax\n"
"mov %%ebx,(%%rax)\n"
"mov %%edx,0x4(%%rax)\n"
"mov %%ecx,0x8(%%rax)\n"
:
: "rm"(p)
: "%rax", "%rbx", "%rcx", "%rdx");
# else
"mov %0,%%eax\n"
"mov %%ebx,(%%eax)\n"
"mov %%edx,0x4(%%eax)\n"
"mov %%ecx,0x8(%%eax)\n"
:
: "rm"(p)
: "%eax", "%ebx", "%ecx", "%edx");
# endif
# else
//
// assembler of Intel, Visual C++,...
//
# if _M_X64
int info[4];
__cpuid( info, 0 );
*reinterpret_cast<int*>(p+0) = info[1];
*reinterpret_cast<int*>(p+4) = info[3];
*reinterpret_cast<int*>(p+8) = info[2];
# else
__asm {
xor eax,eax
cpuid
mov eax,p
mov [eax+0],ebx
mov [eax+4],edx
mov [eax+8],ecx
};
# endif
# endif
return string(buf);
#endif
}
static bool isCpuVendorIntel()
{
return getCpuVendorID() == "GenuineIntel";
}
static bool isCpuVendorAMD()
{
return getCpuVendorID() == "AuthenticAMD" ||
getCpuVendorID() == "AMDisbetter!";
}
static int getCpuidHighestFunction()
{
// if no CPUID then no highest function -> return -1
if (!hasCpuID())
return -1;
#if defined(__arm__) || defined(__aarch64__)
return -1;
#else
int r = -1;
# if __GNUC__
//
// gcc assembler code
//
asm volatile(
"xor %%eax,%%eax\n"
"cpuid\n"
"mov %%eax,%0\n" // write result to r
: "=rm"(r)
:
: "%eax", "%ebx", "%ecx", "%edx");
# else
//
// assembler of Intel, Visual C++,...
//
# if _M_X64
int info[4];
__cpuid( info, 0 );
r = info[0];
# else
__asm {
xor eax,eax
cpuid
mov r,eax // write result to r
};
# endif
# endif
return r;
#endif
}
//
// CPU signatures
//
// x86/amd64 architectures are using family, model and stepping values to describe
// the processor
//
// ARM is using Implementer, Architecture, Variant, Primary part number and revision.
//
string getCpuSignature()
{
#if defined(__arm__) || defined(__aarch64__)
//
// ARM uses Implementer, Variant, Architecture, Partno and Revision
// for cpu identification. We can not access them using
//
// mrc p15, 0, %[result], c0, c0, 0
//
// as this can be done in privileged mode only (even root user seems to not use
// privileged mode). We have to parse /proc/cpuinfo instead. Example of the
// file on N9 follows:
//
// /home/developer $ cat /proc/cpuinfo
// Processor : ARMv7 Processor rev 2 (v7l)
// BogoMIPS : 298.32
// Features : swp half thumb fastmult vfp edsp neon vfpv3
// CPU implementer : 0x41
// CPU architecture: 7
// CPU variant : 0x3
// CPU part : 0xc08
// CPU revision : 2
//
// Hardware : Nokia RM-696 board
// Revision : 1601
// Serial : 0000000000000000
// SoC Info : OMAP3630 ES1.2-hs
// IDCODE : 2b89102f
// Pr. ID : 00000000 00000000 000000cc cafeb891
//
// List of cpuid's:
//
// Cortex-A15 (r2p0) 0x412FC0F0
// Cortex-A9 (r3p0) 0x413FC090
// (r2p2) 0x412FC092
// (r2p1) 0x412FC091
// (r2p0) 0x412FC090
// Cortex-A8 (r3p2) 0x413FCO82
// (r3p1) 0x413FC081
// (r3p0) 0x413FC080
// (r2p3) 0x412FC083
// (r2p2) 0x412FC082
// (r1p1) 0x411FC081
// Cortex-A5 (r0p1) 0x410FCO51
// (r0p0) 0x410FCO50
//
// Cortex-R5 (r1p2) 0x411FC152
// (r1p1) 0x411FC151
// Cortex-R4 (r1p4) 0x411FC144
// (r1p3) 0x411FC143
//
// Cortex-M4 (r0p1) 0x410FC241
// (r0p0) 0x410FC240
// Cortex-M3 (r2p1) 0x412FC231
// (r2p0) 0x412FC230
// (r1p1) 0x411FC231
// Cortex-M1 (r1p0) 0x411CC210
// (r0p1) 0x410CC211
// Cortex-M0 (r0p0) 0x410CC200
//
// ARM1136 (r1p5) 0x4117B365
// (r1p3) 0x4117B363
// (r1p3) 0x4117B361
// ARM1156 0x410FB564
// 0x410FB560
// ARM1176 0x410FB767
// 0x410FB760
// ARM11 MPCore 0x410FB024
//
// Comments:
// r is major revision, p is minor revision
// bits 31..24 - implementer,
// bits 23..20 - variant,
// bits 19..16 - architecture,
// bits 15..4 - primary part number
// bits 3..0 - revision
//
// Implementer:
// 0x41 ('A') - ARM
// 0x44 ('D') - DEC
// 0x54 ('T') - TI
// 0x69 ('i') - Intel
//
// Variant:
// major revision number
//
// Architecture:
// 0xF - Cortex-A*, Cortex-R*, Cortex-M3,M4, ARM1156, ARM1176, ARM11 MPCore
// 0xC - Cortex-M0,M1
// 0x7 - ARM1136
//
// Primary part number:
// 0xC0F - Cortex-A15
// 0xC09 - Cortex-A9
// 0xC08 - Cortex-A8
// 0xC05 - Cortex-A5
// 0xC15 - Cortex-R5
// 0xC14 - Cortex-R4
// 0xC24 - Cortex-M4
// 0xC23 - Cortex-M3
// 0xC21 - Cortex-M1
// 0xC20 - Cortex-M0
// 0xB36 - ARM1136
// 0xB56 - ARM1156
// 0xB76 - ARM1176
//
string implementer, architecture, variant, partno, revision;
ifstream fs("/proc/cpuinfo", ios::in);
string line;
// read all lines in the file and look for "model name" text
// that is used on x86 and amd64 architecture
while (fs.good()) {
getline(fs, line);
string::size_type l = line.length();
if (line.find("CPU") != string::npos ||
line.find("cpu") != string::npos)
{
// implementer:
// 0x41 ('A') - ARM
// 0x44 ('D') - DEC
// 0x54 ('T') - TI
// 0x69 ('i') - Intel
//
if (line.find("implementer") != string::npos ||
line.find("Implementer") != string::npos)
{
string::size_type i = line.find(":");
if (i != string::npos)
{
i++;
while (i<l && line[i] == ' ') i++;
implementer = line.substr(i);
}
}
// architecture
if (line.find("architecture") != string::npos ||
line.find("Architecture") != string::npos)
{
string::size_type i = line.find(":");
if (i != string::npos)
{
i++;
while (i<l && line[i] == ' ') i++;
architecture = line.substr(i);
}
}
// variant
if (line.find("variant") != string::npos ||
line.find("Variant") != string::npos)
{
string::size_type i = line.find(":");
if (i != string::npos)
{
i++;
while (i<l && line[i] == ' ') i++;
variant = line.substr(i);
}
}
// primary part number
if (line.find("part") != string::npos ||
line.find("Part") != string::npos)
{
string::size_type i = line.find(":");
if (i != string::npos)
{
i++;
while (i<l && line[i] == ' ') i++;
partno = line.substr(i);
}
}
// revision
if (line.find("revision") != string::npos ||
line.find("Revision") != string::npos)
{
string::size_type i = line.find(":");
if (i != string::npos)
{
i++;
while (i<l && line[i] == ' ') i++;
revision = line.substr(i);
}
}
}
}
string vendor;
if (implementer == "0x41") // 'A'
vendor = "ARM";
else if (implementer == "0x44") // 'D'
vendor = "DEC";
else if (implementer == "0x54") // 'T'
vendor = "TI";
else if (implementer == "0x69") // 'i'
vendor = "Intel";
else
vendor = "unknown";
stringstream ss;
ss << "Implementer: " << implementer << " (" << vendor << ")"
" Architecture: " << architecture <<
" Variant: " << variant <<
" Partno: " << partno <<
" Revision: " << revision;
return ss.str();
#else
//
// 486 is family 4
// Pentium and Pentium MMX is family 5
// Pentium II, III, Pentium M, Core Solo/Duo, Core 2 is family 6
// Pentium 4, Pentium D is family 0xf
// all processors above has extended family field set to 0
//
// Some (probably newer) Core 2 and Celeron has family set to 6
// and extended family to 1.
// Core i7 and Atom processors has family set to 6 and
// extended family to 1.
//
// Signatures for AMD processors - not lucky to find them
// in AMD documents
//
int family, model, stepping;
// If no CPUID or function 1 is not available
// then no cpu signature. CPUID was introduced in late 486
// processors and all Pentiums has it. Thus, it should be
// 386 or 486 processor (286 and before are not 32-bit
// processors and are not expected to work with this utility.
if (getCpuidHighestFunction() < 1) {
// Let's simply return family 4 and zero for model and
// stepping. (FIXME: extend the code if required)
family = 4;
model = 0;
stepping = 0;
}
else
{
int r;
# if __GNUC__
//
// gcc assembler code
//
asm volatile(
"mov $1,%%eax\n"
"cpuid\n"
"mov %%eax,%0\n" // write result to r
: "=rm"(r)
:
: "%eax", "%ebx", "%ecx", "%edx");
# else
//
// assembler of Intel, Visual C++,...
//
# if _M_X64
int info[4];
__cpuid( info, 1 );
r = info[0];
# else
__asm {
mov eax,1
cpuid
mov r,eax // write result to r
};
# endif
# endif
if (isCpuVendorIntel()) {
// family is obtained by adding extended family code and family code
family = ((r & 0x0ff00000) >> 20) + ((r & 0x0f00) >> 8);
} else {
// AMD ignores extended family if family code is < 0xf
// We will use the approach for all vendors except Intel
family = ((r & 0x0f00) >> 8);
if (family == 0x0f)
family += ((r & 0x0ff00000) >> 20);
}
if (isCpuVendorIntel()) {
// model is obtained by shifting extended model by 4 to the left
// and adding model code
model = ((r & 0x000f0000) >> 12) + ((r & 0x00f0) >> 4);
} else {
// AMD ignores extended model if model code is < 0xf
// We will use the approach for all vendors except Intel
model = ((r & 0x00f0) >> 4);
if (model == 0x0f)
model += ((r & 0x000f0000) >> 12);
}
// stepping is only four bits
stepping = r & 0x000f;
}
// format string and return it
stringstream ss;
ss << "Family: " << family
<< " Model: " << model
<< " Stepping: " << stepping;
return ss.str();
#endif
}
int getCpuFeatureFlags()
{
#if defined(__arm__) || defined(__aarch64__)
return 0;
#else
// if no CPUID or function 1 is not available
// then no feature flag -> return zero
if (getCpuidHighestFunction() < 1)
return 0;
int r = 0;
# if __GNUC__
//
// gcc assembler code
//
asm volatile(
"mov $1,%%eax\n"
"cpuid\n"
"movl %%edx,%0\n" // write result to r
: "=rm"(r)
:
: "%eax", "%ebx", "%ecx", "%edx");
# else
//
// assembler of Intel, Visual C++,...
//
# if _M_X64
int info[4];
__cpuid( info, 1 );
r = info[3];
# else
__asm {
mov eax,1
cpuid
mov r,edx // write result to r
};
# endif
# endif
return r;
#endif
}
int getCpuFeatureFlags2()
{
#if defined(__arm__) || defined(__aarch64__)
return 0;
#else
// if no CPUID or function 1 is not available
// then no feature flag -> return zero
if (getCpuidHighestFunction() < 1)
return 0;
int r = 0;
# if __GNUC__
//
// gcc assembler code
//
asm volatile(
"mov $1,%%eax\n"
"cpuid\n"
"movl %%ecx,%0\n" // write result to r
: "=rm"(r)
:
: "%eax", "%ebx", "%ecx", "%edx");
# else
//
// assembler of Intel, Visual C++,...
//
# if _M_X64
int info[4];
__cpuid( info, 1 );
r = info[2];
# else
__asm {
mov eax,1
cpuid
mov r,ecx // write result to r
};
# endif
# endif
return r;
#endif
}
bool hasCpuX87MathCoprocessor()
{
// test bit 0
return (getCpuFeatureFlags() & 0x00000001) != 0;
}
bool hasCpuMMX()
{
// test bit 23
return (getCpuFeatureFlags() & 0x00800000) != 0;
}
bool hasCpuSSE()
{
// test bit 25
return (getCpuFeatureFlags() & 0x02000000) != 0;
}
bool hasCpuSSE2()
{
// test bit 26
return (getCpuFeatureFlags() & 0x04000000) != 0;
}
bool hasCpuAVX()
{
// test bit 28 of ecx register
return (getCpuFeatureFlags2() & 0x10000000) != 0;
}
double getMemoryTotal()
{
#if defined(__WIN32__) || defined(_WIN32)
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
GlobalMemoryStatusEx(&ms);
return double( ms.ullTotalPhys ); // return in bytes
#else
// based on the text of "MemTotal" line in /proc/meminfo
ifstream fs("/proc/meminfo", ios::in);
string line;
while (fs.good()) {
getline(fs, line);
if (line.find("MemTotal") != string::npos) {
unsigned int i = line.find(':', 0);
i++;
while (i < line.length()) {
if (line[i] != ' ')
break;
i++;
}
istringstream ss(string(&line.c_str()[i]));
double d = 0.;
ss >> d;
return d*1024; // convert KiB back to bytes
}
}
return 0.;
#endif
}
#if !defined( NO_GRAPHICS_TESTS )
static string gpuVendor;
static string gpuRendererString;
static string gpuVersionString;
static string gpuGLSLVersionString;
static list<string> gpuExtensions;
static list<string> guiExtensions;
static int gpuMaxTextureSize;
static string glxVersionString;
static string glxServerVendorString;
static string glxClientVendorString;
static string eglVendorString;
static string eglVersionString;
static string eglClientAPIsString;
static bool gpuBeginEnd = false;
static bool gpuClientSideVA = false;
static bool gpuVBO = false;
static bool gpuVAO = false;
static bool gpuTransformations = false;
static bool gpuAccumBuffer = false;
static bool gpuIndexedGetExtensions = false;
static bool gpuFramebuffer = false;
static bool gpuESProfile = false;
static bool gpuFixedPipeline = false;
static bool gpuCompatibilityShaders = false;
static bool gpuCoreShaders = false;
static bool gpuVertexShader = false;
static bool gpuFragmentShader = false;
static bool gpuGeometryShaderExt = false;
static bool gpuGeometryShader32 = false;
static bool gpuGeometryShader40 = false;
static bool gpuGeometryShader = false;
static bool gpuComputeShader = false;
static bool gpuMultiDrawIndirect = false;
static bool gpuTextureRGBA8 = false;
static bool gpuTextureRGBA32F = false;
static bool gpuImageTexture = false;
static bool gpuShaderStorageBuffer = false;
static bool gpuGetInteger64 = false;
static bool gpuMultisampling = false;
static bool gpuBindlessTexture = false;
string getGpuVendor() { return gpuVendor; }
string getGpuRendererString() { return gpuRendererString; }
string getGpuVersionString() { return gpuVersionString; }
string getGpuGLSLVersionString() { return gpuGLSLVersionString; }
const std::list<std::string>& getGpuExtensions() { return gpuExtensions; }
const std::list<std::string>& getGuiExtensions() { return guiExtensions; }
int getGpuMaxTextureSize() { return gpuMaxTextureSize; }
string getGLXVersionString() { return glxVersionString; }
string getGLXServerVendorString() { return glxServerVendorString; }
string getGLXClientVendorString() { return glxClientVendorString; }
string getEGLVendorString() { return eglVendorString; }
string getEGLVersionString() { return eglVersionString; }
string getEGLClientAPIsString() { return eglClientAPIsString; }
static inline const char* safelyAssign( const char *s ) { return s ? s : ""; }
static bool isExtensionSupported( const char *extension )
{
const unsigned char *extensionsString = NULL;
const unsigned char *start;
unsigned char *p, *terminator;
// extension names should not have spaces
p = (unsigned char *)strchr( extension, ' ' );
if( p || *extension == '\0' )
return false;
if( hasGpuCapability( INDEXED_GET_EXTENSIONS ) )
{
// get the extensions using new way of glGetStringi()
// (this is the only way on core profiles of OpenGL 3.0+)
GLint numExtensions = 0;
glGetIntegerv( GL_NUM_EXTENSIONS, &numExtensions );
for( int i=0; i<numExtensions; i++ )
{
const GLubyte *exName = glGetStringi( GL_EXTENSIONS, i );
if( strcmp( extension, (const char*)( exName ) ) == 0 )
return true;
}
return false;
}
else
{
// get extensions using old way of glGetString()
// get Extensions String
extensionsString = glGetString( GL_EXTENSIONS );
if( extensionsString == NULL )
return false;
// search the extensions string for an exact copy
start = extensionsString;
for(;;) {
p = (unsigned char *) strstr( (const char *)start, extension );
if( !p )
break;
terminator = p + strlen( extension );
if( p == start || *(p - 1) == ' ' )
if( *terminator == ' ' || *terminator == '\0' )
return true;
start = terminator;
}
return false;
}
}
bool hasGpuCapability( GpuCapability capability )
{
switch( capability ) {
case BEGIN_END: return gpuBeginEnd;
case CLIENT_SIDE_VA: return gpuClientSideVA;
case VBO: return gpuVBO;
case VAO: return gpuVAO;
case TRANSFORMATIONS: return gpuTransformations;
case ACCUM_BUFFER: return gpuAccumBuffer;
case INDEXED_GET_EXTENSIONS: return gpuIndexedGetExtensions;
case FRAMEBUFFER: return gpuFramebuffer;
case ES_PROFILE: return gpuESProfile;
case FIXED_PIPELINE: return gpuFixedPipeline;
case SHADERS: return gpuCoreShaders || gpuCompatibilityShaders;
case COMPATIBILITY_SHADERS: return gpuCompatibilityShaders;
case CORE_SHADERS: return gpuCoreShaders;
case VERTEX_SHADER: return gpuVertexShader;
case FRAGMENT_SHADER: return gpuFragmentShader;
case GEOMETRY_SHADER_EXT: return gpuGeometryShaderExt;
case GEOMETRY_SHADER_32: return gpuGeometryShader32;
case GEOMETRY_SHADER_40: return gpuGeometryShader40;
case GEOMETRY_SHADER: return gpuGeometryShader;
case COMPUTE_SHADER: return gpuComputeShader;
case MULTI_DRAW_INDIRECT: return gpuMultiDrawIndirect;
case TEXTURE_RGBA8: return gpuTextureRGBA8;
case TEXTURE_RGBA32F: return gpuTextureRGBA32F;
case IMAGE_TEXTURE: return gpuImageTexture;
case SHADER_STORAGE_BUFFER: return gpuShaderStorageBuffer;
case GET_INTEGER_64: return gpuGetInteger64;
case MULTISAMPLING: return gpuMultisampling;
case BINDLESS_TEXTURE: return gpuBindlessTexture;
default:
assert( 0 && "Not implemented." );
return false;
}
}
void updateGpuInfo()
{
// get function pointers
// (glGetString, glGetIntegerv and glGetError are available
// on OpenGL 1.1+, OpenGL ES 1.0+, and OpenGL 3.0+ core)
glGetString = (PFNGLGETSTRINGPROC) getGLCoreProcAddress( "glGetString" );
glGetStringi = (PFNGLGETSTRINGIPROC) myGetProcAddress( "glGetStringi" );
glGetIntegerv = (PFNGLGETINTEGERVPROC) getGLCoreProcAddress( "glGetIntegerv" );
glGetError = (PFNGLGETERRORPROC) getGLCoreProcAddress( "glGetError" );
if( !glGetString || !glGetIntegerv || !glGetError )
{
cout << "Error: not all OpenGL functions found in the driver." << endl;
return;
}
// clear all possible OpenGL errors
GLenum e = glGetError();
while (e != GL_NO_ERROR) {
cout << "Error: OpenGL in error state (error code: " << e << ")." << endl;
e = glGetError();
}
// get OpenGL strings
gpuVendor = safelyAssign( (const char*)glGetString(GL_VENDOR) );
gpuRendererString = safelyAssign( (const char*)glGetString(GL_RENDERER) );
gpuVersionString = safelyAssign( (const char*)glGetString(GL_VERSION) );
if( gpuVendor.empty() ) gpuVendor = "< empty >";
if( gpuRendererString.empty() ) gpuRendererString = "< empty >";
if( gpuVersionString.empty() ) gpuVersionString = "< empty >";
// get GLX info
#if !defined(USE_SDL2) && !defined(__WIN32__) && !defined(_WIN32) && !defined(USE_EGL)
// following code requires GLX version >=1.2
// (GLX 1.2 spec was released 1997,
// GLX 1.3 on 1998, and GLX 1.4 on 2005)
# if 1 // as we have GLX function prototypes in this file,
// we do not need to test for GLX_VERSION_1_2
// get current display
// (glXGetCurrentDisplay() is supported since GLX 1.2)
Display *d = glXGetCurrentDisplay();
if( d == NULL ) {
cout << "Error: No active OpenGL context." << endl;
return;
}
// get GLX version
// (glXQueryVersion() is probably? supported since GLX beginning)
int versionMajor = 0, versionMinor = 0;
glXQueryVersion( d, &versionMajor, &versionMinor );
glxVersionString = ( '0' + versionMajor );
glxVersionString += ".";
glxVersionString += ( '0' + versionMinor );
int screen;
bool supportsGLX13 = (versionMajor == 1 && versionMinor >= 3) || versionMajor > 1;
if( supportsGLX13 )
{
// (glXGetCurrentContext() is supported maybe since beginning? (1.0?),
// at least it is supported in GLX 1.2)
GLXContext c = glXGetCurrentContext();
// get current screen
// (glXQueryContext() is available since GLX 1.3)
if( c == NULL || glXQueryContext( d, c, GLX_SCREEN, &screen ) != Success )
{
cout << "GLX: failed to get screen number." << endl;
screen = DefaultScreen( d );
}
}
else
{
// GLX version 1.2
// FIXME: how to get screen from OpenGL context in GLX 1.2?
// Alternatives for consideration:
// - let's use default screen.
// screen = DefaultScreen( d );
// - Maybe we could check number of screens
// and if it is one (usual case), to use it.
screen = DefaultScreen( d );
}
// get vendor strings
// (glXQueryServerString() and glXGetClientString() are available since GLX 1.1)
glxServerVendorString = safelyAssign( glXQueryServerString( d, screen, GLX_VENDOR ) );
glxClientVendorString = safelyAssign( glXGetClientString( d, GLX_VENDOR ) );
# else
glxVersionString = "not detected";
glxServerVendorString = "not detected";
glxClientVendorString = "not detected";
# endif
#else
glxVersionString = "";
glxServerVendorString = "";
glxClientVendorString = "";
#endif
// get EGL info
#if defined(USE_EGL)
eglVendorString = safelyAssign( eglQueryString( eglGetCurrentDisplay(), EGL_VENDOR ) );
eglVersionString = safelyAssign( eglQueryString( eglGetCurrentDisplay(), EGL_VERSION ) );
eglClientAPIsString = safelyAssign( eglQueryString( eglGetCurrentDisplay(), EGL_CLIENT_APIS ) );
if( eglVendorString.empty() ) eglVendorString = "< empty >";
if( eglVersionString.empty() ) eglVersionString = "< empty >";
if( eglClientAPIsString.empty() ) eglClientAPIsString = "< empty >";
#else
eglVendorString = "";
eglVersionString = "";
eglClientAPIsString = "";
#endif
// OpenGL ES detection
gpuESProfile = gpuVersionString.find( "ES" ) != string::npos;
float glVersion = 0.f;
// OpenGL version
const char *ptr = gpuVersionString.c_str();
while( *ptr != 0 )
{
if( *ptr>='0' && *ptr<='9' )
{
glVersion = float( atof( ptr ) );
break;
}
++ptr;
}
// OpenGL 3.0 core and compatibility profiles
bool gl30Core = false;
bool gl30Compatibility = false;
if( !gpuESProfile && glVersion >= 3.0f )
{
GLenum e = glGetError();
if( e != GL_NO_ERROR )
cout << "Error: OpenGL is in error state." << endl;
// context profile detection (OpenGL 3.2+)
bool success = false;
if( glVersion >= 3.2f )
{
int profileMask = 0;
glGetIntegerv( GL_CONTEXT_PROFILE_MASK, &profileMask );
e = glGetError();
if( e == GL_NO_ERROR )
{
gl30Core = ( profileMask & GL_CONTEXT_CORE_PROFILE_BIT ) != 0;
gl30Compatibility = ( profileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT ) != 0;
success = true;
// Some (buggy?) drivers returns 0 for profileMask on compatibility context
// (seen on Detonator 310.19 on Linux, renderer: Quadro K1000M/PCIe/SSE2, version: 4.3.0 NVIDIA 310.19).
// Let's handle the case by simply setting gl30Compatibility to true.
if( !gl30Core && !gl30Compatibility )
gl30Compatibility = true;
}
}
// context flags detection (OpenGL 3.0, 3.1)
if( !success )
{
int contextFlags = 0;
glGetIntegerv( GL_CONTEXT_FLAGS, &contextFlags );
e = glGetError();
if( e == GL_NO_ERROR )
{
gl30Core = contextFlags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT;
gl30Compatibility = !gl30Core;
}
else
{
// this is an alternative detection routine on broken
// glGetIntegerv( GL_CONTEXT_FLAGS, ... ) that generates GL_INVALID_ENUM
// (seen on Mobility Radeon 5470 and Catalyst 9.12 released for DELL laptops)
gl30Compatibility = glVersion == 3.0f || isExtensionSupported( "GL_ARB_compatibility" );
gl30Core = !gl30Compatibility;
}
}
}
// GLSL support
bool glslSupported;
if( !gpuESProfile )
{
glslSupported = glVersion >= 2.f || isExtensionSupported( "GL_ARB_shading_language_100" );
}
else
{
// OpenGL ES version 2.0 and above supports GLSL
glslSupported = glVersion >= 2.f;
}
// get GLSL version string
if (!glslSupported)
gpuGLSLVersionString = "not supported";
else {
GLenum e = glGetError();
if( e != GL_NO_ERROR )
cout << "Error: OpenGL is in error state." << endl;
const char *s = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
e = glGetError();
if (e == GL_INVALID_ENUM)
gpuGLSLVersionString = "1.00";
else
gpuGLSLVersionString = s;
}
// assign variables
if( !gpuESProfile )
{
// standard OpenGL
gpuBeginEnd = glVersion < 3.0f || gl30Compatibility;
gpuClientSideVA = glVersion < 3.0f || gl30Compatibility;
gpuVBO = glVersion >= 1.5f || isExtensionSupported( "GL_ARB_vertex_buffer_object" );
gpuVAO = glVersion >= 3.0f || isExtensionSupported( "GL_ARB_vertex_array_object" );
gpuTransformations = glVersion < 3.0f || gl30Compatibility;
gpuAccumBuffer = glVersion < 3.0f || gl30Compatibility;
gpuIndexedGetExtensions = glVersion >= 3.0f;
gpuFramebuffer = glVersion >= 3.0f || isExtensionSupported( "GL_ARB_framebuffer_object" );
gpuFixedPipeline = glVersion < 3.0f || gl30Compatibility;
gpuCompatibilityShaders = glVersion >= 3.0f ? gl30Compatibility
: glVersion >= 2.0f || ( glslSupported && isExtensionSupported( "GL_ARB_vertex_shader" ) &&
isExtensionSupported( "GL_ARB_fragment_shader" ) );
gpuCoreShaders = glVersion >= 3.0f;
gpuVertexShader = glVersion >= 2.0f || ( glslSupported && isExtensionSupported( "GL_ARB_vertex_shader" ) );
gpuFragmentShader = glVersion >= 2.0f || ( glslSupported && isExtensionSupported( "GL_ARB_fragment_shader" ) );
gpuGeometryShaderExt = isExtensionSupported( "GL_ARB_geometry_shader4" ) ||
isExtensionSupported( "GL_EXT_geometry_shader4" );
gpuGeometryShader32 = glVersion >= 3.2f;
gpuGeometryShader40 = glVersion >= 4.0f || isExtensionSupported( "GL_ARB_gpu_shader5" );
gpuGeometryShader = gpuGeometryShaderExt || gpuGeometryShader32 || gpuGeometryShader40;
gpuComputeShader = glVersion >= 4.3f || isExtensionSupported( "GL_ARB_compute_shader" );
gpuMultiDrawIndirect = glVersion >= 4.3f || isExtensionSupported( "GL_ARB_multi_draw_indirect" );
gpuTextureRGBA8 = glVersion >= 1.1f;
gpuTextureRGBA32F = glVersion >= 3.0f;
gpuImageTexture = glVersion >= 4.2f || isExtensionSupported( "GL_ARB_shader_image_load_store" );
gpuShaderStorageBuffer = glVersion >= 4.3f || isExtensionSupported( "GL_ARB_shader_storage_buffer_object" );
gpuGetInteger64 = glVersion >= 3.2f;
gpuMultisampling = glVersion >= 1.3f || isExtensionSupported( "GL_ARB_multisample" );
}
else
{
// OpenGL ES
gpuBeginEnd = false;
gpuClientSideVA = true;
gpuVBO = glVersion >= 1.1f;
gpuVAO = false;
gpuTransformations = glVersion < 2.0f;
gpuAccumBuffer = false;
gpuIndexedGetExtensions = glVersion >= 3.0f;
gpuFramebuffer = glVersion >= 2.0f;
gpuFixedPipeline = glVersion < 2.0f;
gpuCompatibilityShaders = false;
gpuCoreShaders = glVersion >= 2.0f;
gpuVertexShader = glVersion >= 2.0f;
gpuFragmentShader = glVersion >= 2.0f;
gpuGeometryShaderExt = false;
gpuGeometryShader32 = glVersion >= 3.2f;
gpuGeometryShader40 = glVersion >= 3.2f;
gpuGeometryShader = gpuGeometryShaderExt || gpuGeometryShader32 || gpuGeometryShader40;
gpuComputeShader = glVersion >= 3.1f;
gpuMultiDrawIndirect = false; // even 3.2 does not support GL_ARB_multi_draw_indirect
gpuTextureRGBA8 = glVersion >= 3.0f; // GL_RGBA is supported since ES 1.0, consider to use it
gpuTextureRGBA32F = glVersion >= 3.0f; // supported but no filtering except GL_NEAREST and GL_NEAREST_MIPMAP_NEAREST
gpuImageTexture = glVersion >= 3.1f;
gpuShaderStorageBuffer = glVersion >= 3.1f;
gpuGetInteger64 = glVersion >= 3.0f;
gpuMultisampling = true;
}
gpuBindlessTexture = isExtensionSupported( "GL_ARB_bindless_texture" );
// get OpenGL extensions
gpuExtensions.clear();
if( hasGpuCapability( INDEXED_GET_EXTENSIONS ) )
{
// get the extensions using new way of glGetStringi()
// (this is the only way on core profiles of OpenGL 3.0+)
GLint numExtensions = 0;
glGetIntegerv( GL_NUM_EXTENSIONS, &numExtensions );
for( int i=0; i<numExtensions; i++ )
{
const GLubyte *exName = glGetStringi( GL_EXTENSIONS, i );
gpuExtensions.push_back( (const char*)( exName ) );
}
}
else
{
// get extensions using old way of glGetString()
char *extensionsString = (char*)glGetString( GL_EXTENSIONS );
if( extensionsString != NULL )
{
char *p = extensionsString;
char *sep;
while( sep = strchr( p, ' ' ), sep != NULL ) {
gpuExtensions.push_back( string( p, sep-p ) );
p = sep + 1;
while( *p == ' ' )
p++;
}
if( *p != 0 )
gpuExtensions.push_back( string( p ) );
}
}
// get Gui (WGL/GLX) extensions
guiExtensions.clear();
#ifdef _WIN32
typedef const char* WINAPI WGLGETEXTENSIONSSTRINGARB( HDC );
WGLGETEXTENSIONSSTRINGARB* wglGetExtensionsStringARB =
(WGLGETEXTENSIONSSTRINGARB*) myGetProcAddress( "wglGetExtensionsStringARB" );
typedef const char* WINAPI WGLGETEXTENSIONSSTRINGEXT();
WGLGETEXTENSIONSSTRINGEXT* wglGetExtensionsStringEXT =
(WGLGETEXTENSIONSSTRINGEXT*) myGetProcAddress( "wglGetExtensionsStringEXT" );
const char* wglExtensionsString = NULL;
if( wglGetExtensionsStringARB )
wglExtensionsString = wglGetExtensionsStringARB( wglGetCurrentDC() );
else if( wglGetExtensionsStringEXT )
wglExtensionsString = wglGetExtensionsStringEXT();
if( wglExtensionsString != NULL )
{
const char* p = wglExtensionsString;
const char* sep;
while( sep = strchr( p, ' ' ), sep != NULL ) {
guiExtensions.push_back( string( p, sep-p ) );
p = sep + 1;
while( *p == ' ' )
p++;
}
if( *p != 0 )
guiExtensions.push_back( string( p ) );
}
#else
#endif
// get max texture size
if( gpuESProfile==false && glVersion<1.1f )
gpuMaxTextureSize=0;
else
{
glGetIntegerv(GL_MAX_TEXTURE_SIZE,&gpuMaxTextureSize);
}
}
void getDisplayAttributes(int *width, int *height, int *bpp, int *freq)
{
#if defined(USE_SDL2)
// get info from the display that has the center of the current window
SDL_Window *w = SDL_GL_GetCurrentWindow();
if (w == NULL) goto error;
int i;
i = SDL_GetWindowDisplayIndex(w);
if (i < 0) goto error;
SDL_DisplayMode dm;
if (SDL_GetCurrentDisplayMode(i, &dm) < 0)
goto error;
// return the values
if (width) *width = dm.w;
if (height) *height = dm.h;
if (bpp) *bpp = SDL_BITSPERPIXEL(dm.format);
if (freq) *freq = dm.refresh_rate;
return;
// handle error
error:
if (width) *width = -1;
if (height) *height = -1;
if (bpp) *bpp = -1;
if (freq) *freq = -1;
return;
#elif defined(__WIN32__) || defined(_WIN32)
DEVMODE dm;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
assert(0 && "EnumDisplaySettings() failed.");
if (width) *width = dm.dmPelsWidth;
if (height) *height = dm.dmPelsHeight;
if (bpp) *bpp = dm.dmBitsPerPel;
if (freq) *freq = dm.dmDisplayFrequency;
#elif defined(__ANDROID__)
// get width and height
EGLDisplay display = eglGetCurrentDisplay();
EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
EGLBoolean r = EGL_TRUE;
EGLint w = 0;
EGLint h = 0;
r &= eglQuerySurface(display, surface, EGL_WIDTH, &w);
r &= eglQuerySurface(display, surface, EGL_HEIGHT, &h);
// get color depth
EGLint configID = 0;
r &= eglQuerySurface(display, surface, EGL_CONFIG_ID, &configID);
EGLint attribs[] = { EGL_CONFIG_ID, configID, EGL_NONE };
EGLConfig config;
EGLint numConfigs = 0;
EGLint bufferSize = 0;
r &= eglChooseConfig(display, attribs, &config, 1, &numConfigs);
r &= eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &bufferSize);
// write results
if (r) {
if (width) *width = w;
if (height) *height = h;
if (bpp) *bpp = bufferSize;
if (freq) *freq = 0;
}
#else
Display *display = XOpenDisplay(0);
if (display == 0)
{
width = 0;
height = 0;
bpp = 0;
freq = 0;
return;
}
int screenNumber = DefaultScreen(display);
# ifdef HAS_XF86VM
// using XFree86-VidModeExtension
XF86VidModeModeLine ml;
int dotClock;
XF86VidModeGetModeLine(display, screenNumber, &dotClock, &ml);
Screen *screen = XScreenOfDisplay(display, screenNumber);
if (ml.privsize != 0) XFree(ml.c_private);
if (width) *width = ml.hdisplay;
if (height) *height = ml.vdisplay;
if (bpp) *bpp = XDefaultDepthOfScreen(screen);
if (freq) *freq = ml.htotal && ml.vtotal ?
dotClock*1000 / (ml.htotal*ml.vtotal) : 0;
# else
// using Xlib functions (did not know how to get frequency)
// (Xlib functions are available on both archtectures - x86/x64 and arm)
Screen *screen = XScreenOfDisplay(display, screenNumber);
if (width) *width = XWidthOfScreen(screen);
if (height) *height = XHeightOfScreen(screen);
if (bpp) *bpp = XDefaultDepthOfScreen(screen);
if (freq) *freq = 0;
# endif
XCloseDisplay(display);
#endif
}
bool getMultisamplingActive()
{
// GL_ARB_MULTISAMPLE availability:
// - since OpenGL 1.3
// - since OpenGL ES 1.0 while the implementation
// is not required to provide a multisample buffer
if( glGetError() != GL_NO_ERROR )
cout << "Error: OpenGL in error state." << endl;
if( !hasGpuCapability( MULTISAMPLING ) )
return false;
int value;
#if 0
glGetIntegerv(GL_MULTISAMPLE_ARB,&value);
cout<<"Multisample: "<<value<<endl;
glGetIntegerv(GL_SAMPLE_BUFFERS_ARB,&value);
cout<<"Sample buffers: "<<value<<endl;
glGetIntegerv(GL_SAMPLES_ARB,&value);
cout<<"Samples: "<<value<<endl;
#endif
glGetIntegerv(GL_SAMPLE_BUFFERS_ARB,&value);
if( glGetError() != GL_NO_ERROR ) return false;
return value != 0;
}
#if !defined(USE_SDL2) && !defined(__WIN32__) && !defined(_WIN32) && !defined(__ANDROID__)
int getIntGLX( Display *dpy, XVisualInfo *vi, int attribute )
{
int r = 0;
int e = glXGetConfig( dpy, vi, attribute, &r );
if( e != 0 )
cout << "Error in getIntGLX(): Can not get info." << endl;
return r;
}
#endif
void printFBConfig()
{
#if defined(USE_SDL2)
// get info from SDL
int r,g,b,a,d,s,ar,ag,ab,aa;
SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &r );
SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &g );
SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &b );
SDL_GL_GetAttribute( SDL_GL_ALPHA_SIZE, &a );
SDL_GL_GetAttribute( SDL_GL_DEPTH_SIZE, &d );
SDL_GL_GetAttribute( SDL_GL_STENCIL_SIZE, &s );
SDL_GL_GetAttribute( SDL_GL_ACCUM_RED_SIZE, &ar );
SDL_GL_GetAttribute( SDL_GL_ACCUM_GREEN_SIZE, &ag );
SDL_GL_GetAttribute( SDL_GL_ACCUM_BLUE_SIZE, &ab );
SDL_GL_GetAttribute( SDL_GL_ACCUM_ALPHA_SIZE, &aa );
// print info
cout << " Color bits (RGBA): " << r << "," << g << "," << b << "," << a << " "
<< "Depth: " << d << " " << "Stencil: " << s << " " << "Accum: ";
if( hasGpuCapability( ACCUM_BUFFER ) )
cout << ar << "," << ag << "," << ab << "," << aa;
cout << endl;
#elif defined(__WIN32__) || defined(_WIN32)
// get pixel format index
HDC hdc = wglGetCurrentDC();
int iPixelFormat = GetPixelFormat( hdc );
// get pfd
PIXELFORMATDESCRIPTOR pfd;
DescribePixelFormat( hdc, iPixelFormat, sizeof( pfd ), &pfd );
// print info
cout << " Color bits (RGBA): "
<< int( pfd.cRedBits ) << "," << int( pfd.cGreenBits ) << ","
<< int( pfd.cBlueBits ) << "," << int( pfd.cAlphaBits ) << " "
<< "Depth: " << int( pfd.cDepthBits ) << " "
<< "Stencil: " << int( pfd.cStencilBits ) << " " << "Accum: ";
if( hasGpuCapability( ACCUM_BUFFER ) )
cout << int( pfd.cAccumRedBits ) << ","
<< int( pfd.cAccumGreenBits ) << "," << int( pfd.cAccumBlueBits )
<< "," << int( pfd.cAccumAlphaBits );
cout << endl;
#elif defined(__ANDROID__)
// get width and height
int r,g,b,a,d,s;
EGLDisplay display = eglGetCurrentDisplay();
EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
EGLBoolean e = EGL_TRUE;
// get color depth
EGLint configID = 0;
e &= eglQuerySurface(display, surface, EGL_CONFIG_ID, &configID);
EGLint attribs[] = { EGL_CONFIG_ID, configID, EGL_NONE };
EGLConfig config;
EGLint numConfigs = 0;
e &= eglChooseConfig(display, attribs, &config, 1, &numConfigs);
e &= eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
e &= eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
e &= eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
e &= eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
e &= eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &d);
e &= eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &s);
// print info
if (e) {
cout << " Color bits (RGBA): " << r << "," << g << "," << b << "," << a << " "
<< "Depth: " << d << " " << "Stencil: " << s << " ";
if( hasGpuCapability( ACCUM_BUFFER ) )
cout << "Accum: ?,?,?,?";
cout << endl;
} else
cout << " Color bits (RGBA): ?,?,?,? Depth: ? Stencil: ?" << endl;
#else
// get current state
Display *dpy = glXGetCurrentDisplay(); // GLX 1.2+
GLXContext cx = glXGetCurrentContext(); // probably GLX 1.0+
// get current screen and XID
int screen = 0;
int xid = 0;
glXQueryContext( dpy, cx, GLX_SCREEN, &screen ); // GLX 1.3+
glXQueryContext( dpy, cx, GLX_FBCONFIG_ID, &xid );
// get fb configs
int numConfigs = 0;
int attribList[] = { GLX_FBCONFIG_ID, xid, None, None };
GLXFBConfig *configs = glXChooseFBConfig( dpy, screen, attribList, &numConfigs );
// numConfigs should probably be 1 for any valid xid
if( numConfigs == 1 && configs != NULL )
{
// get visual info
XVisualInfo *vi = glXGetVisualFromFBConfig( dpy, configs[0] );
if( vi != NULL )
{
// print info
cout << " Color bits (RGBA): "
<< getIntGLX( dpy, vi, GLX_RED_SIZE ) << "," << getIntGLX( dpy, vi, GLX_GREEN_SIZE ) << ","
<< getIntGLX( dpy, vi, GLX_BLUE_SIZE ) << "," << getIntGLX( dpy, vi, GLX_ALPHA_SIZE ) << " "
<< "Depth: " << getIntGLX( dpy, vi, GLX_DEPTH_SIZE ) << " "
<< "Stencil: " << getIntGLX( dpy, vi, GLX_STENCIL_SIZE ) << " " << "Accum: ";
if( hasGpuCapability( ACCUM_BUFFER ) )
cout << getIntGLX( dpy, vi, GLX_ACCUM_RED_SIZE ) << ","
<< getIntGLX( dpy, vi, GLX_ACCUM_GREEN_SIZE ) << ","
<< getIntGLX( dpy, vi, GLX_ACCUM_BLUE_SIZE ) << ","
<< getIntGLX( dpy, vi, GLX_ACCUM_ALPHA_SIZE );
cout << endl;
// release memory
XFree( vi );
}
else
cout << "Error: No visual found." << endl;
}
else
cout << "Error: numConfigs is " << numConfigs << endl;
// release memory
XFree( configs );
#endif
}
#endif /* NO_GRAPHICS_TESTS */
#if defined(__WIN32__) || defined(_WIN32)
static OSVERSIONINFOEX vi;
static bool hasExtendedInfo;
static bool viInitialized = false;
static std::string kernelVersion;
static int rtmBuild = 0;
static bool kernelVersionInitialized = false;
static bool initVersionInfoStruct()
{
if( viInitialized )
return true;
viInitialized = true;
// MSVC (since version 2013?) start to complain about GetVersionEx()
// telling it is deprecated. Alternative solution might be:
// http://stackoverflow.com/questions/22303824/warning-c4996-getversionexw-was-declared-deprecated
ZeroMemory( &vi, sizeof( OSVERSIONINFOEX ) );
vi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
hasExtendedInfo = GetVersionEx( (OSVERSIONINFO*)&vi ) != 0;
if( !hasExtendedInfo ) {
vi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
if( !GetVersionEx( (OSVERSIONINFO*)&vi ) ) {
ZeroMemory( &vi, sizeof( OSVERSIONINFOEX ) );
return false;
}
}
return true;
}
static bool initKernelVersion()
{
if(kernelVersionInitialized)
return kernelVersion.empty()==false;
kernelVersionInitialized=true;
// load version.dll and required functions
static HMODULE h=LoadLibrary("version.dll");
if(h==NULL)
return false;
typedef DWORD (WINAPI *PFN_GetFileVersionInfoSizeW)(LPCWSTR lptstrFilename,LPDWORD lpdwHandle);
typedef BOOL (APIENTRY *PFN_GetFileVersionInfoW)(LPCWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData);
typedef BOOL (APIENTRY *PFN_VerQueryValueW)(LPCVOID pBlock,LPCWSTR lpSubBlock,LPVOID * lplpBuffer,PUINT puLen);
PFN_GetFileVersionInfoSizeW GetFileVersionInfoSizeW=(PFN_GetFileVersionInfoSizeW)GetProcAddress(h,"GetFileVersionInfoSizeW");
PFN_GetFileVersionInfoW GetFileVersionInfoW=(PFN_GetFileVersionInfoW)GetProcAddress(h,"GetFileVersionInfoW");
PFN_VerQueryValueW VerQueryValueW=(PFN_VerQueryValueW)GetProcAddress(h,"VerQueryValueW");
// get path to kernel32.dll
WCHAR path[ _MAX_PATH ];
if( !GetSystemDirectoryW( path, _MAX_PATH ) )
return false;
wcscat_s( path, L"\\kernel32.dll" );
// get buffer size
DWORD handle;
DWORD len = GetFileVersionInfoSizeW( path, &handle );
if( len==0 )
return false;
// alloc buffer
uint8_t* buff = new(std::nothrow) uint8_t[ len ];
if( !buff )
return false;
// get kernel32.dll version info
if( !GetFileVersionInfoW( path, 0, len, buff ) ) {
delete[] buff;
return false;
}
// extract version data
VS_FIXEDFILEINFO *vInfo = nullptr;
UINT infoSize;
if( !VerQueryValueW( buff, L"\\", reinterpret_cast<LPVOID*>( &vInfo ), &infoSize ) ) {
delete[] buff;
return false;
}
if( !infoSize ) {
delete[] buff;
return false;
}
// set kernelVersion
kernelVersion=to_string(HIWORD(vInfo->dwFileVersionMS))+"."+
to_string(LOWORD(vInfo->dwFileVersionMS))+"."+
to_string(HIWORD(vInfo->dwFileVersionLS))+"."+
to_string(LOWORD(vInfo->dwFileVersionLS));
rtmBuild=HIWORD(vInfo->dwFileVersionLS);
delete[] buff;
return true;
}
string getOSName()
{
if( !initVersionInfoStruct() )
return "Can not get operating system name.";
switch( vi.dwMajorVersion ) {
case 4:
if( vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) {
switch( vi.dwMinorVersion ) {
case 0: return "Windows 95";
case 10: return "Windows 98";
case 90: return "Windows Me";
}
} else if( vi.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
switch( vi.dwMinorVersion ) {
case 0: return "Windows NT 4.0";
}
}
break;
case 5:
switch( vi.dwMinorVersion ) {
case 0: return "Windows 2000";
case 1: return "Windows XP";
case 2:
if( vi.wProductType == VER_NT_WORKSTATION )
return "Windows XP Professional x64 Edition";
else
if( vi.wSuiteMask & VER_SUITE_WH_SERVER )
return "Windows Home Server (2003)";
else
if( GetSystemMetrics(SM_SERVERR2) == 0 )
return "Windows Server 2003";
else
return "Windows Server 2003 R2";
}
break;
case 6:
if(initKernelVersion())
{
if( vi.wProductType == VER_NT_WORKSTATION ) {
static const map<int,string> rtmBuild2name = {
{ 7600, "Windows 7 (no service pack)" },
{ 7601, "Windows 7 (Service Pack 1)" },
{ 9200, "Windows 8" },
{ 9600, "Windows 8.1" },
{ 10240, "Windows 10 (original release, version 1507)" },
{ 10586, "Windows 10 (November Update, version 1511)" },
{ 14393, "Windows 10 (Anniversary Update, version 1607)" },
{ 15063, "Windows 10 (Creators Update, version 1703)" },
};
auto it=rtmBuild2name.find(rtmBuild);
if(it!=rtmBuild2name.end())
return it->second;
}
else
{
static const map<int,string> rtmBuild2name = {
{ 7600, "Windows Server 2008 R2 (no service pack)" },
{ 7601, "Windows Server 2008 R2 (Service Pack 1)" },
{ 8400, "Windows Home Server 2011" },
{ 9200, "Windows Server 2012" },
{ 9600, "Windows Server 2012 R2" },
{ 14393, "Windows Server 2016" },
};
auto it=rtmBuild2name.find(rtmBuild);
if(it!=rtmBuild2name.end())
return it->second;
}
}
if( vi.wProductType == 0 )
break;
if( vi.wProductType == VER_NT_WORKSTATION ) {
switch( vi.dwMinorVersion ) {
case 0: return "Windows Vista";
case 1: return "Windows 7";
case 2: return "Windows 8";
case 3: return "Windows 8.1";
}
} else {
switch( vi.dwMinorVersion ) {
case 0: return "Windows Server 2008";
case 1: return "Windows Server 2008 R2";
case 2: return "Windows Server 2012";
case 3: return "Windows Server 2012 R2";
}
}
break;
case 10:
if( vi.wProductType == VER_NT_WORKSTATION )
return "Windows 10";
else
return "Windows Server 2016";
//break;
}
if( vi.dwMajorVersion > 6 ||
(vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2) )
return "Unknown Windows version (too recent)";
return "Unknown Windows version";
}
string getOSVersionNumber()
{
if( !initVersionInfoStruct() )
return "Can not get operating system name.";
string s;
s += ('0' + char(vi.dwMajorVersion));
s += '.';
s += ('0' + char(vi.dwMinorVersion));
return s;
}
string getOSServicePack()
{
if( vi.wServicePackMajor == 0 )
return "none";
string s;
s += ('0' + vi.wServicePackMajor);
if( vi.wServicePackMinor != 0 ) {
s += '.';
s += ('0' + vi.wServicePackMinor);
}
return s;
}
string getOSDistributionName()
{
return "";
}
string getOSDistributionRelease()
{
return "";
}
string getOSDistributionCodeName()
{
return "";
}
string getOSDistributionDescription()
{
return "";
}
string getOSDistributionHomepage()
{
return "";
}
string getOSKernelInfo()
{
if(initKernelVersion())
return kernelVersion;
else
return "";
}
string getOSExtraInfo()
{
return "";
}
#elif defined(__ANDROID__)
std::string getOSName()
{
return "Android";
}
std::string getOSDistributionName()
{
return "";
}
std::string getOSVersionNumber()
{
return "";
}
std::string getOSServicePack()
{
return "";
}
std::string getOSDistributionRelease()
{
return "";
}
std::string getOSDistributionCodeName()
{
return "";
}
std::string getOSDistributionDescription()
{
return "";
}
string getOSDistributionHomepage()
{
return "";
}
std::string getOSKernelInfo()
{
return "";
}
std::string getOSExtraInfo()
{
return "";
}
#else
// Linux/Unix version files
//
// Ubuntu (verified on versions 11.10 to 15.04):
// /etc/issue - distribution name (f.ex. Ubuntu 11.10 \n \l)
// /etc/issue.net - distribution name (f.ex. Ubuntu 11.10)
// /etc/lsb-release - valuable info, see bellow
// /etc/os-release - valuable info, see bellow, introduced somewhere between 11.10 and 15.04
//
// CentOS (verified on version 7.1):
// /etc/centos-release (f.ex. CentOS-7.1: "CentOS Linux release 7.1.1503 (Core) \n")
// /etc/centos-release-upstream (f.ex. CentOS-7.1: "Derived from Red Hat Enterprise Linux 7.1 (Source)\n")
// /etc/issue* - not useful (f.ex. CentOS-7.1: "\S\nKernel \r on an \m\n")
// /etc/os-release - valuable info, see bellow
// /etc/redhat-release -> centos-release
// /etc/system-release -> centos-release
//
// FreeBSD:
// nothing in /etc
// uname -mrs (f.ex.: FreeBSD 10.2-PRERELEASE amd64)
// uname -a (f.ex.: FreeBSD kazi.fit.vutbr.cz 10.2-PRERELEASE FreeBSD 10.2-PRERELEASE #1 r286358M: Thu Aug 6 12:39:19 CEST 2015 root@kazi.fit.vutbr.cz:/usr/src/sys/amd64/compile/KAZI amd64)
// freebsd-version (f.ex.: 10.2-PRERELEASE)
//
// Ubuntu 15.04 /etc/lsb-release:
// DISTRIB_ID=Ubuntu
// DISTRIB_RELEASE=15.04
// DISTRIB_CODENAME=vivid
// DISTRIB_DESCRIPTION="Ubuntu 15.04"
// Ubuntu 15.04 /etc/os-release:
// NAME="Ubuntu"
// VERSION="15.04 (Vivid Vervet)"
// ID=ubuntu
// ID_LIKE=debian
// PRETTY_NAME="Ubuntu 15.04"
// VERSION_ID="15.04"
// HOME_URL="http://www.ubuntu.com/"
// SUPPORT_URL="http://help.ubuntu.com/"
// BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
// CentOS 7.1 /etc/os-release:
// NAME="CentOS Linux"
// VERSION="7 (Core)"
// ID="centos"
// ID_LIKE="rhel fedora"
// VERSION_ID="7"
// PRETTY_NAME="CentOS Linux 7 (Core)"
// ANSI_COLOR="0;31"
// CPE_NAME="cpe:/o:centos:centos:7"
// HOME_URL="https://www.centos.org/"
// BUG_REPORT_URL="https://bugs.centos.org/"
//
// CENTOS_MANTISBT_PROJECT="CentOS-7"
// CENTOS_MANTISBT_PROJECT_VERSION="7"
// REDHAT_SUPPORT_PRODUCT="centos"
// REDHAT_SUPPORT_PRODUCT_VERSION="7"
//
static string getInfoFromTextFile( fstream &f, const string &name )
{
// sources of information:
// 2005: http://www.unix.com/unix-advanced-expert-users/21468-machine.html?t=21468#post83185
// 2010: http://linux.dsplabs.com.au/cat-etc-release-finding-out-release-version-of-a-linux-distribution-suse-fedora-ubuntu-p35/
// 2011: http://unix.stackexchange.com/questions/6345/how-can-i-get-distribution-name-and-version-number-in-a-simple-shell-script
stringstream line, key, value;
char c;
while( true )
{
line.str( "" );
f.get( *line.rdbuf() );
if( !f.good() )
break;
c = f.get(); // eats '\n'
key.str( "" );
line.get( *key.rdbuf(), '=' );
c = line.get(); // eats '='
if( key.str() == name )
{
line.get( *value.rdbuf() );
string s = value.str();
if( s[0] == '"' )
s.erase( 0, 1 );
if( s[ s.length()-1 ] == '"' )
s.erase( s.length()-1, 1 );
return s;
}
}
return "";
}
/** Returns the whole file, replacing new line characters with spaces. */
static string getInfoFromTextFile( fstream &f )
{
string s1, s2;
while( true )
{
f >> s1;
if( !f )
break;
if( !s2.empty() )
s2 += " ";
s2 += s1;
}
return s2;
}
enum Information { DISTRIB_NAME, DISTRIB_RELEASE, DISTRIB_CODENAME, DISTRIB_DESCRIPTION, DISTRIB_HOMEPAGE, ANYTHING };
static string getLinuxInfo( Information info )
{
fstream f( "/etc/os-release", fstream::in );
if( !f.good() )
f.open( "/etc/lsb-release", fstream::in );
if( !f.good() )
f.open( "/etc/issue.net", fstream::in );
if( !f.good() )
f.open( "/etc/issue", fstream::in );
switch( info )
{
case DISTRIB_NAME:
{
fstream f( "/etc/os-release", fstream::in );
if( f.good() ) return getInfoFromTextFile( f, "NAME" );
f.open( "/etc/lsb-release", fstream::in );
if( f.good() ) return getInfoFromTextFile( f, "DISTRIB_ID" );
return "";
}
case DISTRIB_RELEASE:
{
fstream f( "/etc/os-release", fstream::in );
if( f.good() ) return getInfoFromTextFile( f, "VERSION" );
f.open( "/etc/lsb-release", fstream::in );
if( f.good() ) return getInfoFromTextFile( f, "DISTRIB_RELEASE" );
return "";
}
case DISTRIB_CODENAME:
{
fstream f( "/etc/lsb-release", fstream::in );
if( f.good() ) return getInfoFromTextFile( f, "DISTRIB_CODENAME" );
return "";
}
case DISTRIB_DESCRIPTION:
{
fstream f( "/etc/os-release", fstream::in );
if( f.good() ) return getInfoFromTextFile( f, "PRETTY_NAME" );
f.open( "/etc/lsb-release", fstream::in );
if( f.good() ) return getInfoFromTextFile( f, "DISTRIB_DESCRIPTION" );
f.open( "/etc/centos-release", fstream::in );
if( f.good() ) return getInfoFromTextFile( f );
return "";
}
case DISTRIB_HOMEPAGE:
{
fstream f( "/etc/os-release", fstream::in );
if( f.good() ) return getInfoFromTextFile( f, "HOME_URL" );
return "";
}
case ANYTHING:
{
fstream f( "/etc/os-release", fstream::in );
if( !f.good() )
f.open( "/etc/lsb-release", fstream::in );
if( !f.good() )
f.open( "/etc/issue.net", fstream::in ); // content example: Ubuntu 11.10
if( !f.good() )
f.open( "/etc/issue", fstream::in ); // content example: Ubuntu 11.10 \n \l
return getInfoFromTextFile( f );
}
default:
return "";
}
}
string getOSName()
{
utsname buf;
if( uname( &buf ) != 0 )
return "Can not get system name";
return buf.sysname; // like uname -s, on Ubuntu returns "Linux"
}
string getOSVersionNumber()
{
return "";
}
string getOSServicePack()
{
return "";
}
string getOSDistributionName()
{
return getLinuxInfo( DISTRIB_NAME );
}
string getOSDistributionRelease()
{
return getLinuxInfo( DISTRIB_RELEASE );
}
string getOSDistributionCodeName()
{
return getLinuxInfo( DISTRIB_CODENAME );
}
string getOSDistributionDescription()
{
return getLinuxInfo( DISTRIB_DESCRIPTION );
}
string getOSDistributionHomepage()
{
return getLinuxInfo( DISTRIB_HOMEPAGE );
}
string getOSKernelInfo()
{
utsname buf;
if( uname( &buf ) != 0 )
return "Can not get kernel info";
return buf.release; // uname -r
}
string getOSExtraInfo()
{
return getLinuxInfo( ANYTHING );
}
#endif