// Copyright © 2011 Canonical Ltd
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation. 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
// .
//
// Authored by:
// Loïc Molinari
// Jay Taoko
// unity_support_test checks for Unity support on a X11 display. All the checks
// are based on what's done in Compiz (core/plugins/opengl/src/screen.cpp).
//
// $ gcc -std=c99 unity_support_test.c -o unity_support_test `pkg-config
// > --cflags --libs gl x11 libpci xcomposite xdamage`
#include
#include
#include
#include
#include
#ifndef NUX_OPENGLES_20
#include
#define GLX_GLXEXT_PROTOTYPES
#include
#undef GLX_GLXEXT_PROTOTYPES
#else
#include
#include
#include
#endif
#include
#include
#include
#include
#include
#include
#ifndef NUX_OPENGLES_20
typedef GLXContext NUXContext;
#else
typedef EGLConfig NUXContext;
#endif
// Enables colored console output at build time.
#define COLORED_OUTPUT 1
// Gets the number of elements in an array.
#define ARRAY_SIZE(array) (sizeof (array) / sizeof ((array)[0]))
enum {
// Extension flags.
FLAG_GLX_SGIX_FBCONFIG = (1 << 0),
FLAG_GLX_EXT_TEXTURE_FROM_PIXMAP = (1 << 1),
FLAG_GL_ARB_NON_POWER_OF_TWO = (1 << 2),
FLAG_GL_NV_TEXTURE_RECTANGLE = (1 << 3),
FLAG_GL_EXT_TEXTURE_RECTANGLE = (1 << 4),
FLAG_GL_ARB_TEXTURE_RECTANGLE = (1 << 5),
FLAG_GL_ARB_VERTEX_PROGRAM = (1 << 6),
FLAG_GL_ARB_FRAGMENT_PROGRAM = (1 << 7),
FLAG_GL_ARB_VERTEX_BUFFER_OBJECT = (1 << 8),
FLAG_GL_EXT_FRAMEBUFFER_OBJECT = (1 << 9),
FLAG_GL_ARB_FRAMEBUFFER_OBJECT = (1 << 10),
FLAG_SOFTWARE_RENDERING = (1 << 11),
FLAG_BLACKLISTED = (1 << 12),
FLAG_GL_OES_EGL_IMAGE = (1 << 13),
FLAG_EGL_KHR_IMAGE_PIXMAP = (1 << 14),
// Extension masks.
MASK_GL_NON_POWER_OF_TWO = (FLAG_GL_ARB_NON_POWER_OF_TWO
| FLAG_GL_NV_TEXTURE_RECTANGLE
| FLAG_GL_EXT_TEXTURE_RECTANGLE
| FLAG_GL_ARB_TEXTURE_RECTANGLE),
MASK_GL_FRAMEBUFFER_OBJECT = (FLAG_GL_EXT_FRAMEBUFFER_OBJECT
| FLAG_GL_ARB_FRAMEBUFFER_OBJECT)
};
// PCI device identity.
struct PciDevice {
unsigned short vendor;
unsigned short device;
};
// Blacklists of GPUs for Compiz.
struct PciDevice gpu_blacklist[] = {
{ 0x8086, 0x3577 }, // Intel : 82830M/MG
{ 0x8086, 0x2562 }, // Intel : 82845G aka Poulsbo
{ 0x1002, 0x4c57 }, // ATI : Radeon Mobility 7500
{ 0x10de, 0x0322 }, // nVidia: GeForce FX 5200
{ 0x10de, 0x0326 }, // nVidia: GeForce FX 5500
{ 0x10de, 0x0240 }, // nVidia: GeForce 6150
{ 0x10de, 0x01d3 }, // nVidia: GeForce Go 7300 SE / 7200 GS
{ 0x10de, 0x01d7 }, // nVidia: GeForce Go 7300 / Quadro NVS 110M
{ 0x10de, 0x01d8 } // nVidia: GeForce Go 7400
};
typedef struct _TestResults {
char *vendor, *renderer, *version;
int result, major, minor;
int indirect;
int compiz;
unsigned int flags;
char *error;
} TestResults;
// Checks whether an extension is supported by the GLX/OpenGL implementation
// given the extension name and the list of supported extensions.
static int is_extension_supported (const char* extensions,
const char* extension) {
if (extensions != NULL && extension != NULL) {
const size_t len = strlen (extension);
char* p = (char*) extensions;
char* end = p + strlen (p);
while (p < end) {
const size_t size = strcspn (p, " ");
if (len == size && strncmp (extension, p, size) == 0)
return 1;
p += size + 1;
}
}
return 0;
}
// Gets the OpenGL version number given the string.
static void get_opengl_version (const char *version, int* major, int* minor) {
int tmp = 0, i;
if (!version)
{
*major = 0;
*minor = 0;
return;
}
for (i = 0; isdigit (version[i]); i++)
tmp = tmp * 10 + (version[i] - 48);
if (version[i++] == '.') {
*major = tmp;
*minor = (version[i] - 48);
} else {
*major = 0;
*minor = 0;
}
}
static void print_help () {
fprintf (stdout,
"Check for Unity support on a X11 display.\n"
"\n"
"Usage:\n"
" unity-support-test [ options ]\n"
" -d, --display name: Specify the X11 display\n"
" -i, --indirect: Force an indirect rendering context\n"
" -p, --print: Print detection results on stdout\n"
" -c, --compiz: Only check for Compiz support\n"
" -h, --help: Show help\n");
}
static void print_report (const char* vendor, const char* renderer,
const char* version, int major, int minor,
unsigned int flags, int compiz, int result,
const char* error) {
if (error == NULL) {
#if COLORED_OUTPUT == 1
const char* yes = "\033[32;01myes\033[00m";
const char* no = "\033[31;01mno\033[00m";
#else
const char* yes = "yes";
const char* no = "no";
#endif
fprintf (stdout,
"OpenGL vendor string: %s\n"
"OpenGL renderer string: %s\n"
"OpenGL version string: %s\n"
"\n"
"Not software rendered: %s\n"
"Not blacklisted: %s\n"
"GLX fbconfig: %s\n"
"GLX texture from pixmap: %s\n"
"GL npot or rect textures: %s\n",
vendor, renderer, version,
flags & FLAG_SOFTWARE_RENDERING ? no : yes,
flags & FLAG_BLACKLISTED ? no : yes,
flags & FLAG_GLX_SGIX_FBCONFIG ? yes : no,
flags & FLAG_GLX_EXT_TEXTURE_FROM_PIXMAP ? yes : no,
flags & MASK_GL_NON_POWER_OF_TWO ? yes : no);
if (compiz == 0) {
#ifndef NUX_OPENGLES_20
fprintf (stdout,
"GL vertex program: %s\n"
"GL fragment program: %s\n"
"GL vertex buffer object: %s\n"
"GL framebuffer object: %s\n"
"GL version is 1.4+: %s\n"
"\n"
"Unity 3D supported: %s\n",
flags & FLAG_GL_ARB_VERTEX_PROGRAM ? yes : no,
flags & FLAG_GL_ARB_FRAGMENT_PROGRAM ? yes : no,
flags & FLAG_GL_ARB_VERTEX_BUFFER_OBJECT ? yes : no,
flags & MASK_GL_FRAMEBUFFER_OBJECT ? yes : no,
(major >= 2 || (major == 1 && minor >= 4)) ? yes : no,
result == 0 ? yes : no);
#else
fprintf (stdout,
"GL OES EGL image: %s\n"
"EGL KHR image pixmap: %s\n"
"EGL version is 1.4+: %s\n"
"\n"
"Unity supported: %s\n",
flags & FLAG_GL_OES_EGL_IMAGE ? yes : no,
flags & FLAG_EGL_KHR_IMAGE_PIXMAP ? yes : no,
(major >= 2 || (major == 1 && minor >= 4)) ? yes : no,
result == 0 ? yes : no);
#endif
} else {
fprintf (stdout, "\nCompiz supported: %s\n",
result == 0 ? yes : no);
}
} else {
fprintf (stdout, "Error: %s\n", error);
}
}
static int check_root_visual (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
// Retrieve root window visual.
XWindowAttributes attr;
XVisualInfo vinfo_template;
int nr_vinfos;
if (XGetWindowAttributes (display, root, &attr) == 0) {
results->error = strdup ("unable to get root window attributes");
results->result = 1;
return 0;
}
vinfo_template.visualid = XVisualIDFromVisual (attr.visual);
*vinfos = XGetVisualInfo (display, VisualIDMask, &vinfo_template, &nr_vinfos);
if (nr_vinfos == 0) {
results->error = strdup ("unable to get visual informations for default visual");
results->result = 1;
return 0;
}
return 1;
}
static int check_xcomposite (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
// Check for XComposite
int composite_major, composite_minor;
unsigned int composite_tmp;
if (!XQueryExtension (display, COMPOSITE_NAME, &composite_tmp, &composite_tmp, &composite_tmp))
{
results->error = strdup ("no composite extension");
results->result = 1;
return 0;
}
XCompositeQueryVersion (display, &composite_major, &composite_minor);
if (composite_major == 0 && composite_minor < 2)
{
results->error = strdup ("old composite extension");
results->result = 1;
return 0;
}
return 1;
}
static int check_damage_extension (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
int damage_tmp;
if (!XDamageQueryExtension (display, &damage_tmp, &damage_tmp))
{
results->error = strdup ("no damage extension");
results->result = 1;
return 0;
}
return 1;
}
static int check_fixes_extension (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
int fixes_tmp;
if (!XFixesQueryExtension (display, &fixes_tmp, &fixes_tmp))
{
results->error = strdup ("no fixes extension");
results->result = 1;
return 0;
}
return 1;
}
#ifdef NUX_OPENGLES_20
static int check_egl_config (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
EGLint attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_NONE
};
EGLint ctx_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
XVisualInfo *visInfo, visTemplate;
XSetWindowAttributes attr;
Window win;
int num_visuals;
unsigned long mask;
const int width = 400, height = 300;
const char* name = "Unity Support Test";
EGLDisplay egl_dpy;
EGLSurface egl_surf;
EGLContext egl_ctx;
EGLConfig config;
EGLint num_configs;
EGLint vid;
egl_dpy = eglGetDisplay(display);
if (!eglChooseConfig (egl_dpy, attribs, &config, 1, &num_configs)) {
results->error = strdup ("OpenGLES: couldn't get an EGL visual config");
results->result = 1;
return 0;
}
if (num_configs <= 0) {
results->error = strdup ("OpenGLES: no valid config found (!num_configs)");
results->result = 1;
return 0;
}
if (!eglGetConfigAttrib (egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
results->error = strdup ("OpenGLES: eglGetConfigAttrib() failed");
results->result = 1;
return 0;
}
/* The X window visual must match the EGL config */
visTemplate.visualid = vid;
visInfo = XGetVisualInfo (display, VisualIDMask, &visTemplate, &num_visuals);
if (!visInfo) {
results->error = strdup ("OpenGLES: unable to get a matching X visual");
results->result = 1;
return 0;
}
/* window attributes */
attr.background_pixel = 0;
attr.border_pixel = 0;
attr.colormap = XCreateColormap (display, root, visInfo->visual, AllocNone);
attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
win = XCreateWindow (display, root, 0, 0, width, height,
0, visInfo->depth, InputOutput,
visInfo->visual, mask, &attr);
/* set hints and properties */
{
XSizeHints sizehints;
sizehints.x = 0;
sizehints.y = 0;
sizehints.width = width;
sizehints.height = height;
sizehints.flags = USSize | USPosition;
XSetNormalHints (display, win, &sizehints);
XSetStandardProperties (display, win, name, name,
None, (char **)NULL, 0, &sizehints);
}
eglBindAPI (EGL_OPENGL_ES_API);
egl_surf = eglCreateWindowSurface (egl_dpy, config, win, NULL);
if (egl_surf == EGL_NO_SURFACE) {
results->error = strdup ("OpenGLES: eglCreateWindowSurface failed");
results->result = 1;
return 0;
}
context = eglCreateContext (egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs);
if (context == EGL_NO_CONTEXT) {
results->error = strdup ("OpenGLES: eglCreateContext failed");
results->result = 1;
return 0;
}
if (!eglMakeCurrent (egl_dpy, egl_surf, egl_surf, context)) {
results->error = strdup ("OpenGLES: eglMakeCurrent() failed");
results->result = 1;
return 0;
}
XFree(visInfo);
eglDestroySurface (egl_dpy, egl_surf);
XDestroyWindow (display, win);
return 1;
}
#else
static int check_glx_config (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
// Check root window visual capabilities.
int value;
glXGetConfig (display, *vinfos, GLX_USE_GL, &value);
if (value == 0) {
results->error = strdup ("OpenGL rendering is not supported by the root visual");
results->result = 1;
return 0;
}
return 1;
}
static int check_colorbuffers (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
int value;
glXGetConfig (display,*vinfos, GLX_DOUBLEBUFFER, &value);
if (value == 0) {
results->error = strdup ("color buffers of the root visual are not double-buffered");
results->result = 1;
return 0;
}
return 1;
}
#endif
static int check_context (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
#ifndef NUX_OPENGLES_20
// Create and map the OpenGL context to the root window and get the strings.
*context = glXCreateContext (display, *vinfos, NULL, !results->indirect);
if (*context == NULL) {
results->error = strdup ("unable to create the OpenGL context");
results->result = 1;
return 0;
}
glXMakeCurrent (display, root, *context);
#endif
results->vendor = (char*) glGetString (GL_VENDOR);
results->renderer = (char*) glGetString (GL_RENDERER);
results->version = (char*) glGetString (GL_VERSION);
return 1;
}
static int check_extensions (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
// Fill flags with the supported OpenGL extensions.
const char* gl_extensions = glGetString (GL_EXTENSIONS);
if (gl_extensions == NULL) {
results->error = strdup ("invalid OpenGL extensions string");
results->result = 1;
return 0;
}
const struct { const char* name; const unsigned int flag; } gl_extension[] = {
{ "GL_ARB_texture_non_power_of_two", FLAG_GL_ARB_NON_POWER_OF_TWO },
{ "GL_NV_texture_rectangle", FLAG_GL_NV_TEXTURE_RECTANGLE },
{ "GL_EXT_texture_rectangle", FLAG_GL_EXT_TEXTURE_RECTANGLE },
{ "GL_ARB_texture_rectangle", FLAG_GL_ARB_TEXTURE_RECTANGLE },
{ "GL_ARB_vertex_program", FLAG_GL_ARB_VERTEX_PROGRAM },
{ "GL_ARB_fragment_program", FLAG_GL_ARB_FRAGMENT_PROGRAM },
{ "GL_ARB_vertex_buffer_object", FLAG_GL_ARB_VERTEX_BUFFER_OBJECT },
{ "GL_EXT_framebuffer_object", FLAG_GL_EXT_FRAMEBUFFER_OBJECT },
{ "GL_ARB_framebuffer_object", FLAG_GL_ARB_FRAMEBUFFER_OBJECT },
{ "GL_OES_EGL_image", FLAG_GL_OES_EGL_IMAGE },
{ NULL, 0 }
};
for (int i = 0; gl_extension[i].name != NULL; i++)
if (is_extension_supported (gl_extensions, gl_extension[i].name) == 1)
results->flags |= gl_extension[i].flag;
#ifndef NUX_OPENGLES_20
// Fill results->flags with the supported GLX extensions.
const char* glx_extensions = glXQueryExtensionsString (display, screen);
const struct { const char* name; const unsigned int flag; } glx_extension[] = {
{ "GLX_SGIX_fbconfig", FLAG_GLX_SGIX_FBCONFIG },
{ "GLX_EXT_texture_from_pixmap", FLAG_GLX_EXT_TEXTURE_FROM_PIXMAP },
{ NULL, 0 }
};
for (int i = 0; glx_extension[i].name != NULL; i++)
if (is_extension_supported (glx_extensions, glx_extension[i].name) == 1)
results->flags |= glx_extension[i].flag;
if (results->flags & FLAG_GLX_SGIX_FBCONFIG) {
if (glXGetProcAddressARB ("glXQueryDrawable") == NULL ||
glXGetProcAddressARB ("glXGetFBConfigs") == NULL ||
glXGetProcAddressARB ("glXGetFBConfigAttrib") == NULL ||
glXGetProcAddressARB ("glXCreatePixmap") == NULL ||
glXGetProcAddressARB ("glXDestroyPixmap") == NULL) {
results->flags &= ~FLAG_GLX_SGIX_FBCONFIG;
}
}
if (results->flags & FLAG_GLX_EXT_TEXTURE_FROM_PIXMAP) {
if (glXGetProcAddressARB ("glXBindTexImageEXT") == NULL ||
glXGetProcAddressARB ("glXReleaseTexImageEXT") == NULL) {
results->flags &= ~FLAG_GLX_EXT_TEXTURE_FROM_PIXMAP;
}
}
#else
EGLDisplay egl_dpy = eglGetDisplay(display);
const char* egl_extensions = eglQueryString (egl_dpy, EGL_EXTENSIONS);
const struct { const char* name; const unsigned int flag; } egl_extension[] = {
{ "EGL_KHR_image_pixmap", FLAG_EGL_KHR_IMAGE_PIXMAP },
{ NULL, 0 }
};
for (int i = 0; egl_extension[i].name != NULL; i++)
if (is_extension_supported (egl_extensions, egl_extension[i].name) == 1)
results->flags |= egl_extension[i].flag;
#endif
return 1;
}
static int check_blacklist (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results)
{
// Check for software rendering.
if (results->renderer != NULL &&
(strncmp (results->renderer, "Software Rasterizer", 19) == 0 ||
strncmp (results->renderer, "Mesa X11", 8) == 0 ||
strstr (results->renderer, "on softpipe") != NULL)) {
results->flags |= FLAG_SOFTWARE_RENDERING;
}
// jaytaoko: Balcklist the Geforce FX cards
if (results->renderer != NULL) {
char* str = strstr (results->renderer, "GeForce FX");
if (str != NULL) {
results->flags |= FLAG_BLACKLISTED;
}
}
// FIXME(loicm): Compiz does a last check to test whether there's a fbconfig
// available for the default depth or not.
// Scan the PCI devices searching for blacklisted GPUs.
// FIXME: pci or not is not actually related with PCI, it's just that if pci_init
// fails it exit directly :-(
#ifndef NUX_OPENGLES_20
const int gpu_blacklist_size = ARRAY_SIZE (gpu_blacklist);
struct pci_access* access;
struct pci_dev* dev;
access = pci_alloc ();
pci_init (access);
pci_scan_bus (access);
dev = access->devices;
while (dev != NULL) {
pci_fill_info (dev, PCI_FILL_IDENT);
for (int i = 0; i < gpu_blacklist_size; i++) {
if (dev->vendor_id == gpu_blacklist[i].vendor &&
dev->device_id == gpu_blacklist[i].device) {
results->flags |= FLAG_BLACKLISTED;
}
}
dev = dev->next;
}
pci_cleanup (access);
#endif
return 1;
}
int (*tests[]) (Display *display,
unsigned int screen,
Window root,
NUXContext *context,
XVisualInfo **vinfos,
TestResults *results) = {
check_root_visual,
check_xcomposite,
check_damage_extension,
check_fixes_extension,
#ifndef NUX_OPENGLES_20
check_glx_config,
check_colorbuffers,
#else
check_egl_config,
#endif
check_context,
check_extensions,
check_blacklist
};
#ifndef NUX_OPENGLES_20
const unsigned int c_num_tests = 9;
#else
const unsigned int c_num_tests = 8;
#endif
int main (int argc, char* argv[]) {
char *display_name = NULL;
int screen;
unsigned int print = 0;
Window root;
XVisualInfo *vinfos = NULL;
Display *display = NULL;
NUXContext context = NULL;
TestResults results;
#ifdef NUX_OPENGLES_20
EGLDisplay egl_dpy;
#endif
char resultfilename[30];
int resultfile;
int forcecheck = 0;
results.indirect = 0;
results.compiz = 0;
results.flags = 0;
results.error = NULL;
// Basic command-line parsing.
for (int i = 1; i < argc; i++) {
if (((strncmp (argv[i], "-d", 2) == 0) ||
(strncmp (argv[i], "--display", 9) == 0)) &&
(i + 1 < argc)) {
display_name = argv[i + 1];
i++;
} else if ((strncmp (argv[i], "-i", 2) == 0) ||
(strncmp (argv[i], "--indirect", 10) == 0)) {
results.indirect = 1;
} else if ((strncmp (argv[i], "-p", 2) == 0) ||
(strncmp (argv[i], "--print", 7) == 0)) {
print = 1;
} else if ((strncmp (argv[i], "-c", 2) == 0) ||
(strncmp (argv[i], "--compiz", 8) == 0)) {
results.compiz = 1;
} else if ((strncmp (argv[i], "-f", 2) == 0) ||
(strncmp (argv[i], "--force-check", 13) == 0)) {
forcecheck = 1;
} else if ((strncmp (argv[i], "-h", 2) == 0) ||
(strncmp (argv[i], "--help", 6) == 0)) {
print_help ();
return 2;
} else {
fprintf (stderr, "Error: unknown command-line option `%s'\n\n", argv[i]);
print_help ();
return 2;
}
}
// can skip some tests if not forced
if (!forcecheck && !print) {
if (access("/tmp/unity_support_test.0", F_OK) == 0) {
return 0;
}
if (getenv ("UNITY_FORCE_START")) {
fprintf (stdout, "Warning: UNITY_FORCE_START enabled, no check for unity or compiz support.\n");
return 0;
}
}
// Open a X11 connection and get the root window.
display = XOpenDisplay (display_name);
#ifndef NUX_OPENGLES_20
// Before doing anything with GLX, check that it is supported on the system.
Bool glx_supported = False;
int dummy0, dummy1;
if (display)
glx_supported = glXQueryExtension(display, &dummy0, &dummy1);
#endif
if (!display) {
results.error = strdup ("unable to open display");
// exit with 5, to tell "it's not an error we should cache"
results.result = 5;
}
#ifndef NUX_OPENGLES_20
else if (!glx_supported) {
results.error = strdup ("GLX is not available on the system");
// exit with 5, to tell "it's not an error we should cache"
results.result = 5;
}
#endif
else
{
screen = DefaultScreen (display);
root = XRootWindow (display, screen);
#ifndef NUX_OPENGLES_20
// Do the tests, if one of them fails break out of the loop
for (unsigned int i = 0; i < c_num_tests; i++)
if (!(*tests[i]) (display, screen, root, &context, &vinfos, &results))
break;
if (results.compiz == 0) {
// Unity compatibility checks.
get_opengl_version (results.version, &results.major, &results.minor);
if ((results.major >= 2 || (results.major == 1 && results.minor >= 4)) &&
(results.flags & FLAG_GLX_SGIX_FBCONFIG) &&
(results.flags & FLAG_GLX_EXT_TEXTURE_FROM_PIXMAP) &&
(results.flags & MASK_GL_NON_POWER_OF_TWO) &&
(results.flags & FLAG_GL_ARB_VERTEX_PROGRAM) &&
(results.flags & FLAG_GL_ARB_FRAGMENT_PROGRAM) &&
(results.flags & FLAG_GL_ARB_VERTEX_BUFFER_OBJECT) &&
(results.flags & MASK_GL_FRAMEBUFFER_OBJECT) &&
(~results.flags & FLAG_SOFTWARE_RENDERING) &&
(~results.flags & FLAG_BLACKLISTED)) {
results.result = 0;
} else {
results.result = 1;
}
} else {
// Compiz compatibility checks.
if ((results.flags & FLAG_GLX_SGIX_FBCONFIG) &&
(results.flags & FLAG_GLX_EXT_TEXTURE_FROM_PIXMAP) &&
(results.flags & MASK_GL_NON_POWER_OF_TWO) &&
(~results.flags & FLAG_SOFTWARE_RENDERING) &&
(~results.flags & FLAG_BLACKLISTED)) {
results.result = 0;
} else {
results.result = 1;
}
}
#else
egl_dpy = eglGetDisplay(display);
if (!eglInitialize (egl_dpy, &results.major, &results.minor)) {
results.error = strdup ("OpenGLES: eglInitialize() failed");
results.result = 1;
} else {
// Do the tests, if one of them fails break out of the loop
for (unsigned int i = 0; i < c_num_tests; i++)
if (!(*tests[i]) (display, screen, root, &context, &vinfos, &results))
break;
if (results.compiz == 0) {
// Unity compatibility checks.
if ((results.major >= 2 || (results.major == 1 && results.minor >= 4)) &&
(results.flags & FLAG_GL_OES_EGL_IMAGE) &&
(results.flags & FLAG_EGL_KHR_IMAGE_PIXMAP) &&
(~results.flags & FLAG_SOFTWARE_RENDERING) &&
(~results.flags & FLAG_BLACKLISTED)) {
results.result = 0;
} else {
results.result = 1;
}
} else {
// Compiz compatibility checks.
if ((results.flags & FLAG_GL_OES_EGL_IMAGE) &&
(results.flags & FLAG_EGL_KHR_IMAGE_PIXMAP) &&
(~results.flags & FLAG_SOFTWARE_RENDERING) &&
(~results.flags & FLAG_BLACKLISTED)) {
results.result = 0;
} else {
results.result = 1;
}
}
}
#endif
}
if (print == 1) {
print_report (results.vendor, results.renderer,
results.version, results.major,
results.minor, results.flags,
results.compiz, results.result, results.error);
}
if (vinfos != NULL)
XFree (vinfos);
#ifndef NUX_OPENGLES_20
if (context != NULL)
glXDestroyContext (display, context);
#else
if (context == EGL_NO_CONTEXT)
eglDestroyContext (egl_dpy, context);
if (egl_dpy)
eglTerminate (egl_dpy);
#endif
if (display != NULL)
XCloseDisplay (display);
if (results.error != NULL)
free (results.error);
// drop result file
if (results.result != 5) {
snprintf(resultfilename, sizeof(resultfilename), "/tmp/unity_support_test.%i", results.result);
resultfile = open(resultfilename, O_CREAT|O_WRONLY|O_EXCL, 0666);
if (resultfile > 0)
close(resultfile);
}
return results.result;
}