add more spacing
[personal-kdebase.git] / apps / kinfocenter / opengl / opengl.cpp
blob719b71645e87bdb121362781f6d63d335f0ed444
1 /*
2 * opengl.cpp
4 * Copyright (C) 2008 Ivo Anjo <knuckles@gmail.com>
5 * Copyright (C) 2004 Ilya Korniyko <k_ilya@ukr.net>
6 * Adapted from Brian Paul's glxinfo from Mesa demos (http://www.mesa3d.org)
7 * Copyright (C) 1999-2002 Brian Paul
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "opengl.h"
26 #include <QRegExp>
27 #include <QFile>
28 #include <QTextStream>
30 #include <KPluginFactory>
31 #include <KPluginLoader>
33 #include <kaboutdata.h>
34 #include <kdialog.h>
35 #include <klocale.h>
36 #include <kmessagebox.h>
37 #include <kdebug.h>
39 // X11 includes
40 #include <X11/Xlib.h>
41 #include <X11/Xutil.h>
43 // GLU includes
44 #include <GL/glu.h>
46 // OpenGL includes
47 #include <GL/gl.h>
48 #include <GL/glext.h>
49 #include <GL/glx.h>
51 #include "opengl.moc"
53 K_PLUGIN_FACTORY(KCMOpenGLFactory,
54 registerPlugin<KCMOpenGL>();
56 K_EXPORT_PLUGIN(KCMOpenGLFactory("kcmopengl"))
58 // FIXME: Temporary!
59 bool GetInfo_OpenGL(QTreeWidget *treeWidget);
61 KCMOpenGL::KCMOpenGL(QWidget *parent, const QVariantList &)
62 : KCModule(KCMOpenGLFactory::componentData(), parent)
64 setupUi(this);
65 layout()->setMargin(0);
67 GetInfo_OpenGL(glinfoTreeWidget);
69 // Watch for expanded and collapsed events, to resize columns
70 connect(glinfoTreeWidget, SIGNAL(expanded(const QModelIndex &)), this, SLOT(treeWidgetChanged()));
71 connect(glinfoTreeWidget, SIGNAL(collapsed(const QModelIndex &)), this, SLOT(treeWidgetChanged()));
73 KAboutData *about =
74 new KAboutData(I18N_NOOP("kcmopengl"), 0,
75 ki18n("KCM OpenGL Information"),
76 0, KLocalizedString(), KAboutData::License_GPL,
77 ki18n("(c) 2008 Ivo Anjo\n(c) 2004 Ilya Korniyko\n(c) 1999-2002 Brian Paul"));
79 about->addAuthor(ki18n("Ivo Anjo"), KLocalizedString(), "knuckles@gmail.com");
80 about->addAuthor(ki18n("Ilya Korniyko"), KLocalizedString(), "k_ilya@ukr.net");
81 about->addCredit(ki18n("Helge Deller"), ki18n("Original Maintainer"), "deller@gmx.de");
82 about->addCredit(ki18n("Brian Paul"), ki18n("Author of glxinfo Mesa demos (http://www.mesa3d.org)"));
83 setAboutData(about);
86 void KCMOpenGL::treeWidgetChanged() {
87 glinfoTreeWidget->resizeColumnToContents(0);
88 glinfoTreeWidget->resizeColumnToContents(1);
91 QTreeWidgetItem *newItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding, QString textCol1, QString textCol2 = QString()) {
92 QTreeWidgetItem *newItem;
93 if ((parent == NULL) && (preceding == NULL)) {
94 newItem = new QTreeWidgetItem();
95 } else if (preceding == NULL) {
96 newItem = new QTreeWidgetItem(parent);
97 } else {
98 newItem = new QTreeWidgetItem(parent, preceding);
100 newItem->setText(0, textCol1);
101 if (!textCol2.isNull()) {
102 newItem->setText(1, textCol2);
105 newItem->setFlags(Qt::ItemIsEnabled);
106 return newItem;
109 QTreeWidgetItem *newItem(QTreeWidgetItem *parent, QString textCol1, QString textCol2 = QString()) {
110 return newItem(parent, NULL, textCol1, textCol2);
113 static bool IsDirect;
115 static struct glinfo {
116 const char *serverVendor;
117 const char *serverVersion;
118 const char *serverExtensions;
119 const char *clientVendor;
120 const char *clientVersion;
121 const char *clientExtensions;
122 const char *glxExtensions;
123 const char *glVendor;
124 const char *glRenderer;
125 const char *glVersion;
126 const char *glExtensions;
127 const char *gluVersion;
128 const char *gluExtensions;
129 char *displayName;
130 } gli;
132 static struct {
133 QString module,
134 pci,
135 vendor,
136 device,
137 subvendor,
138 rev;
139 } dri_info;
141 static int ReadPipe(QString FileName, QStringList &list)
143 FILE *pipe;
145 if ((pipe = popen(FileName.toAscii(), "r")) == NULL) {
146 pclose(pipe);
147 return 0;
150 QTextStream t(pipe, QIODevice::ReadOnly);
152 while (!t.atEnd()) list.append(t.readLine());
154 pclose(pipe);
155 return list.count();
158 #if defined(Q_OS_LINUX)
160 #define INFO_DRI "/proc/dri/0/name"
162 static bool get_dri_device()
164 QFile file;
165 file.setFileName(INFO_DRI);
166 if (!file.exists() || !file.open(QIODevice::ReadOnly))
167 return false;
169 QTextStream stream(&file);
170 QString line = stream.readLine();
171 if (!line.isEmpty()) {
172 dri_info.module = line.mid(0, line.indexOf(0x20));
174 // possible formats, for regression testing
175 // line = " PCI:01:00:0";
176 // line = " pci:0000:01:00.0"
177 QRegExp rx = QRegExp("\\b[Pp][Cc][Ii][:]([0-9a-fA-F]+[:])?([0-9a-fA-F]+[:][0-9a-fA-F]+[:.][0-9a-fA-F]+)\\b");
178 if (rx.indexIn(line)>0) {
179 dri_info.pci = rx.cap(2);
180 int end = dri_info.pci.lastIndexOf(':');
181 int end2 = dri_info.pci.lastIndexOf('.');
182 if (end2>end) end=end2;
183 dri_info.pci[end]='.';
185 QString cmd = QString("lspci -m -v -s ") + dri_info.pci;
186 QStringList pci_info;
187 int num;
188 if (((num = ReadPipe(cmd, pci_info)) ||
189 (num = ReadPipe("/sbin/"+cmd, pci_info)) ||
190 (num = ReadPipe("/usr/sbin/"+cmd, pci_info)) ||
191 (num = ReadPipe("/usr/local/sbin/"+cmd, pci_info))) && num>=7) {
192 for (int i=2; i<=6; i++) {
193 line = pci_info[i];
194 line.remove(QRegExp("[^:]*:[ ]*"));
195 switch (i){
196 case 2: dri_info.vendor = line; break;
197 case 3: dri_info.device = line; break;
198 case 4: dri_info.subvendor = line; break;
199 case 6: dri_info.rev = line; break;
202 return true;
207 return false;
210 #elif defined(Q_OS_FREEBSD)
212 static bool get_dri_device() {
214 QStringList pci_info;
215 if (ReadPipe("sysctl -n hw.dri.0.name",pci_info)) {
216 dri_info.module = pci_info[0].mid(0, pci_info[0].indexOf(0x20));
218 return false;
221 #else
223 static bool get_dri_device() { return false; }
225 #endif
227 static void
228 mesa_hack(Display *dpy, int scrnum)
230 static int attribs[] = {
231 GLX_RGBA,
232 GLX_RED_SIZE, 1,
233 GLX_GREEN_SIZE, 1,
234 GLX_BLUE_SIZE, 1,
235 GLX_DEPTH_SIZE, 1,
236 GLX_STENCIL_SIZE, 1,
237 GLX_ACCUM_RED_SIZE, 1,
238 GLX_ACCUM_GREEN_SIZE, 1,
239 GLX_ACCUM_BLUE_SIZE, 1,
240 GLX_ACCUM_ALPHA_SIZE, 1,
241 GLX_DOUBLEBUFFER,
242 None
244 XVisualInfo *visinfo;
246 visinfo = glXChooseVisual(dpy, scrnum, attribs);
247 if (visinfo)
248 XFree(visinfo);
252 static void
253 print_extension_list(const char *ext, QTreeWidgetItem *l1)
255 int i, j;
257 if (!ext || !ext[0])
258 return;
259 QString qext = QString::fromLatin1(ext);
260 QTreeWidgetItem *l2 = NULL;
262 i = j = 0;
263 while (1) {
264 if (ext[j] == ' ' || ext[j] == 0) {
265 /* found end of an extension name */
266 const int len = j - i;
267 /* print the extension name between ext[i] and ext[j] */
268 if (!l2) l2 = newItem(l1, qext.mid(i, len));
269 else l2 = newItem(l1, l2, qext.mid(i, len));
270 i=j;
271 if (ext[j] == 0) {
272 break;
274 else {
275 i++;
276 j++;
277 if (ext[j] == 0)
278 break;
281 j++;
285 #if defined(GLX_ARB_get_proc_address) && defined(__GLXextFuncPtr)
286 extern "C" {
287 extern __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *);
289 #endif
291 static void
292 print_limits(QTreeWidgetItem *l1, const char * glExtensions, bool GetProcAddress)
294 /* TODO
295 GL_SAMPLE_BUFFERS
296 GL_SAMPLES
297 GL_COMPRESSED_TEXTURE_FORMATS
300 if (!glExtensions)
301 return;
303 struct token_name {
304 GLuint type; // count and flags, !!! count must be <=2 for now
305 GLenum token;
306 const QString name;
309 struct token_group {
310 int count;
311 int type;
312 const token_name *group;
313 const QString descr;
314 const char *ext;
317 QTreeWidgetItem *l2 = NULL, *l3 = NULL;
318 #if defined(PFNGLGETPROGRAMIVARBPROC)
319 PFNGLGETPROGRAMIVARBPROC kcm_glGetProgramivARB = NULL;
320 #endif
322 #define KCMGL_FLOAT 128
323 #define KCMGL_PROG 256
324 #define KCMGL_COUNT_MASK(x) (x & 127)
325 #define KCMGL_SIZE(x) (sizeof(x)/sizeof(x[0]))
327 const struct token_name various_limits[] = {
328 { 1, GL_MAX_LIGHTS, i18n("Max. number of light sources") },
329 { 1, GL_MAX_CLIP_PLANES, i18n("Max. number of clipping planes") },
330 { 1, GL_MAX_PIXEL_MAP_TABLE, i18n("Max. pixel map table size") },
331 { 1, GL_MAX_LIST_NESTING, i18n("Max. display list nesting level") },
332 { 1, GL_MAX_EVAL_ORDER, i18n("Max. evaluator order") },
333 { 1, GL_MAX_ELEMENTS_VERTICES, i18n("Max. recommended vertex count") },
334 { 1, GL_MAX_ELEMENTS_INDICES, i18n("Max. recommended index count") },
335 #ifdef GL_QUERY_COUNTER_BITS
336 { 1, GL_QUERY_COUNTER_BITS, i18n("Occlusion query counter bits")},
337 #endif
338 #ifdef GL_MAX_VERTEX_UNITS_ARB
339 { 1, GL_MAX_VERTEX_UNITS_ARB, i18n("Max. vertex blend matrices") },
340 #endif
341 #ifdef GL_MAX_PALETTE_MATRICES_ARB
342 { 1, GL_MAX_PALETTE_MATRICES_ARB, i18n("Max. vertex blend matrix palette size") },
343 #endif
344 {0,0,0}
347 const struct token_name texture_limits[] = {
348 { 1, GL_MAX_TEXTURE_SIZE, i18n("Max. texture size") },
349 { 1, GL_MAX_TEXTURE_UNITS_ARB, i18n("No. of texture units") },
350 { 1, GL_MAX_3D_TEXTURE_SIZE, i18n("Max. 3D texture size") },
351 { 1, GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, i18n("Max. cube map texture size") },
352 #ifdef GL_MAX_RECTANGLE_TEXTURE_SIZE_NV
353 { 1, GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, i18n("Max. rectangular texture size") },
354 #endif
355 { 1 | KCMGL_FLOAT, GL_MAX_TEXTURE_LOD_BIAS_EXT, i18n("Max. texture LOD bias") },
356 { 1, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, i18n("Max. anisotropy filtering level") },
357 { 1, GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, i18n("No. of compressed texture formats") },
358 {0,0,0}
361 const struct token_name float_limits[] = {
362 { 2 | KCMGL_FLOAT, GL_ALIASED_POINT_SIZE_RANGE, "ALIASED_POINT_SIZE_RANGE" },
363 { 2 | KCMGL_FLOAT, GL_SMOOTH_POINT_SIZE_RANGE, "SMOOTH_POINT_SIZE_RANGE" },
364 { 1 | KCMGL_FLOAT, GL_SMOOTH_POINT_SIZE_GRANULARITY,"SMOOTH_POINT_SIZE_GRANULARITY"},
365 { 2 | KCMGL_FLOAT, GL_ALIASED_LINE_WIDTH_RANGE, "ALIASED_LINE_WIDTH_RANGE" },
366 { 2 | KCMGL_FLOAT, GL_SMOOTH_LINE_WIDTH_RANGE, "SMOOTH_LINE_WIDTH_RANGE" },
367 { 1 | KCMGL_FLOAT, GL_SMOOTH_LINE_WIDTH_GRANULARITY,"SMOOTH_LINE_WIDTH_GRANULARITY"},
368 {0,0,0}
371 const struct token_name stack_depth[] = {
372 { 1, GL_MAX_MODELVIEW_STACK_DEPTH, "MAX_MODELVIEW_STACK_DEPTH" },
373 { 1, GL_MAX_PROJECTION_STACK_DEPTH, "MAX_PROJECTION_STACK_DEPTH" },
374 { 1, GL_MAX_TEXTURE_STACK_DEPTH, "MAX_TEXTURE_STACK_DEPTH" },
375 { 1, GL_MAX_NAME_STACK_DEPTH, "MAX_NAME_STACK_DEPTH" },
376 { 1, GL_MAX_ATTRIB_STACK_DEPTH, "MAX_ATTRIB_STACK_DEPTH" },
377 { 1, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, "MAX_CLIENT_ATTRIB_STACK_DEPTH" },
378 { 1, GL_MAX_COLOR_MATRIX_STACK_DEPTH, "MAX_COLOR_MATRIX_STACK_DEPTH" },
379 #ifdef GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB
380 { 1, GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB,"MAX_MATRIX_PALETTE_STACK_DEPTH"},
381 #endif
382 {0,0,0}
385 #ifdef GL_ARB_fragment_program
386 const struct token_name arb_fp[] = {
387 { 1, GL_MAX_TEXTURE_COORDS_ARB, "MAX_TEXTURE_COORDS" },
388 { 1, GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "MAX_TEXTURE_IMAGE_UNITS" },
389 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, "MAX_PROGRAM_ENV_PARAMETERS" },
390 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, "MAX_PROGRAM_LOCAL_PARAMETERS" },
391 { 1, GL_MAX_PROGRAM_MATRICES_ARB, "MAX_PROGRAM_MATRICES" },
392 { 1, GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB, "MAX_PROGRAM_MATRIX_STACK_DEPTH" },
393 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_INSTRUCTIONS_ARB, "MAX_PROGRAM_INSTRUCTIONS" },
394 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB, "MAX_PROGRAM_ALU_INSTRUCTIONS" },
395 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB, "MAX_PROGRAM_TEX_INSTRUCTIONS" },
396 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB, "MAX_PROGRAM_TEX_INDIRECTIONS" },
397 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_TEMPORARIES_ARB, "MAX_PROGRAM_TEMPORARIES" },
398 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_PARAMETERS_ARB, "MAX_PROGRAM_PARAMETERS" },
399 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_ATTRIBS_ARB, "MAX_PROGRAM_ATTRIBS" },
400 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, "MAX_PROGRAM_NATIVE_INSTRUCTIONS" },
401 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, "MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS" },
402 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB, "MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS" },
403 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB, "MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS" },
404 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, "MAX_PROGRAM_NATIVE_TEMPORARIES" },
405 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB, "MAX_PROGRAM_NATIVE_PARAMETERS" },
406 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, "MAX_PROGRAM_NATIVE_ATTRIBS" },
407 {0,0,0}
409 #endif
411 #ifdef GL_ARB_vertex_program
412 const struct token_name arb_vp[] = {
413 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB,"MAX_PROGRAM_ENV_PARAMETERS"},
414 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB,"MAX_PROGRAM_LOCAL_PARAMETERS"},
415 { 1, GL_MAX_VERTEX_ATTRIBS_ARB, "MAX_VERTEX_ATTRIBS"},
416 { 1, GL_MAX_PROGRAM_MATRICES_ARB,"MAX_PROGRAM_MATRICES"},
417 { 1, GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB,"MAX_PROGRAM_MATRIX_STACK_DEPTH"},
418 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_INSTRUCTIONS_ARB,"MAX_PROGRAM_INSTRUCTIONS"},
419 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_TEMPORARIES_ARB,"MAX_PROGRAM_TEMPORARIES"},
420 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_PARAMETERS_ARB,"MAX_PROGRAM_PARAMETERS"},
421 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_ATTRIBS_ARB,"MAX_PROGRAM_ATTRIBS"},
422 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB,"MAX_PROGRAM_ADDRESS_REGISTERS"},
423 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB,"MAX_PROGRAM_NATIVE_INSTRUCTIONS"},
424 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB,"MAX_PROGRAM_NATIVE_TEMPORARIES"},
425 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB,"MAX_PROGRAM_NATIVE_PARAMETERS"},
426 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB,"MAX_PROGRAM_NATIVE_ATTRIBS"},
427 { 1 | KCMGL_PROG, GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB ,"MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS"},
428 {0,0,0}
430 #endif
432 #ifdef GL_ARB_vertex_shader
433 const struct token_name arb_vs[] = {
434 { 1, GL_MAX_VERTEX_ATTRIBS_ARB,"MAX_VERTEX_ATTRIBS"},
435 { 1, GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB,"MAX_VERTEX_UNIFORM_COMPONENTS"},
436 { 1, GL_MAX_VARYING_FLOATS_ARB,"MAX_VARYING_FLOATS"},
437 { 1, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB,"MAX_COMBINED_TEXTURE_IMAGE_UNITS"},
438 { 1, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB,"MAX_VERTEX_TEXTURE_IMAGE_UNITS"},
439 { 1, GL_MAX_TEXTURE_IMAGE_UNITS_ARB,"MAX_TEXTURE_IMAGE_UNITS"},
440 { 1, GL_MAX_TEXTURE_COORDS_ARB,"MAX_TEXTURE_COORDS"},
441 {0,0,0}
443 #endif
445 #ifdef GL_ARB_fragment_shader
446 const struct token_name arb_fs[] = {
447 { 1, GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB,"MAX_FRAGMENT_UNIFORM_COMPONENTS"},
448 { 1, GL_MAX_TEXTURE_IMAGE_UNITS_ARB,"MAX_TEXTURE_IMAGE_UNITS"},
449 { 1, GL_MAX_TEXTURE_COORDS_ARB,"MAX_TEXTURE_COORDS"},
450 {0,0,0}
452 #endif
454 const struct token_name frame_buffer_props[] = {
455 { 2, GL_MAX_VIEWPORT_DIMS, i18n("Max. viewport dimensions") },
456 { 1, GL_SUBPIXEL_BITS, i18n("Subpixel bits") },
457 { 1, GL_AUX_BUFFERS, i18n("Aux. buffers")},
458 {0,0,0}
461 const struct token_group groups[] =
463 {KCMGL_SIZE(frame_buffer_props), 0, frame_buffer_props, i18n("Frame buffer properties"), NULL},
464 {KCMGL_SIZE(various_limits), 0, texture_limits, i18n("Texturing"), NULL},
465 {KCMGL_SIZE(various_limits), 0, various_limits, i18n("Various limits"), NULL},
466 {KCMGL_SIZE(float_limits), 0, float_limits, i18n("Points and lines"), NULL},
467 {KCMGL_SIZE(stack_depth), 0, stack_depth, i18n("Stack depth limits"), NULL},
468 #ifdef GL_ARB_vertex_program
469 {KCMGL_SIZE(arb_vp), GL_VERTEX_PROGRAM_ARB, arb_vp, "ARB_vertex_program", "GL_ARB_vertex_program"},
470 #endif
471 #ifdef GL_ARB_fragment_program
472 {KCMGL_SIZE(arb_fp), GL_FRAGMENT_PROGRAM_ARB, arb_fp, "ARB_fragment_program", "GL_ARB_fragment_program"},
473 #endif
474 #ifdef GL_ARB_vertex_shader
475 {KCMGL_SIZE(arb_vs), 0, arb_vs, "ARB_vertex_shader", "GL_ARB_vertex_shader"},
476 #endif
477 #ifdef GL_ARB_fragment_shader
478 {KCMGL_SIZE(arb_fs), 0, arb_fs, "ARB_fragment_shader", "GL_ARB_fragment_shader"},
479 #endif
482 #if defined(GLX_ARB_get_proc_address) && defined(PFNGLGETPROGRAMIVARBPROC)
483 if (GetProcAddress && strstr(glExtensions, "GL_ARB_vertex_program"))
484 kcm_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) glXGetProcAddressARB((const GLubyte *)"glGetProgramivARB");
485 #endif
487 for (uint i = 0; i<KCMGL_SIZE(groups); i++) {
488 if (groups[i].ext && !strstr(glExtensions, groups[i].ext)) continue;
490 if (l2) l2 = newItem(l1, l2, groups[i].descr);
491 else l2 = newItem(l1, groups[i].descr);
492 l3 = NULL;
493 const struct token_name *cur_token;
494 for (cur_token = groups[i].group; cur_token->type; cur_token++) {
496 bool tfloat = cur_token->type & KCMGL_FLOAT;
497 int count = KCMGL_COUNT_MASK(cur_token->type);
498 GLint max[2]={0,0};
499 GLfloat fmax[2]={0.0,0.0};
501 #if defined(PFNGLGETPROGRAMIVARBPROC) && defined(GL_ARB_vertex_program)
502 bool tprog = cur_token->type & KCMGL_PROG;
503 if (tprog && kcm_glGetProgramivARB)
504 kcm_glGetProgramivARB(groups[i].type, cur_token->token, max);
505 else
506 #endif
507 if (tfloat) glGetFloatv(cur_token->token, fmax);
508 else glGetIntegerv(cur_token->token, max);
510 if (glGetError() == GL_NONE) {
511 QString s;
512 if (!tfloat && count == 1) s = QString::number(max[0]); else
513 if (!tfloat && count == 2) s = QString("%1, %2").arg(max[0]).arg(max[1]); else
514 if (tfloat && count == 2) s = QString("%1 - %2").arg(fmax[0],0,'f',6).arg(fmax[1],0,'f',6); else
515 if (tfloat && count == 1) s = QString::number(fmax[0],'f',6);
516 if (l3) l3 = newItem(l2, l3, cur_token->name, s);
517 else l3 = newItem(l2, cur_token->name, s);
526 static QTreeWidgetItem *print_screen_info(QTreeWidgetItem *l1, QTreeWidgetItem *after)
528 QTreeWidgetItem *l2 = NULL, *l3 = NULL;
530 if (after) {
531 l1 = newItem(l1, after, IsDirect ? i18n("Direct Rendering") : i18n("Indirect Rendering"));
532 } else {
533 l1 = newItem(l1, IsDirect ? i18n("Direct Rendering") : i18n("Indirect Rendering"));
536 if (IsDirect) {
537 if (get_dri_device()) {
538 l2 = newItem(l1, i18n("3D Accelerator"));
539 l2->setExpanded(true);
540 l3 = newItem(l2, l3, i18n("Vendor"), dri_info.vendor);
541 l3 = newItem(l2, l3, i18n("Device"), dri_info.device);
542 l3 = newItem(l2, l3, i18n("Subvendor"), dri_info.subvendor);
543 l3 = newItem(l2, l3, i18n("Revision"), dri_info.rev);
544 } else {
545 l2 = newItem(l1, l2, i18n("3D Accelerator"), i18n("unknown"));
549 if (l2) {
550 l2 = newItem(l1, l2, i18n("Driver"));
551 }else{
552 l2 = newItem(l1, i18n("Driver"));
555 l2->setExpanded(true);
557 l3 = newItem(l2, i18n("Vendor"), gli.glVendor);
558 l3 = newItem(l2, l3, i18n("Renderer"), gli.glRenderer);
559 l3 = newItem(l2, l3, i18n("OpenGL version"), gli.glVersion);
561 if (IsDirect) {
562 if (dri_info.module.isEmpty()) dri_info.module = i18n("unknown");
563 l3 = newItem(l2, l3, i18n("Kernel module"), dri_info.module);
566 l3 = newItem(l2, l3, i18n("OpenGL extensions"));
567 print_extension_list(gli.glExtensions, l3);
569 l3 = newItem(l2, l3, i18n("Implementation specific"));
570 print_limits(l3, gli.glExtensions, strstr(gli.clientExtensions, "GLX_ARB_get_proc_address") != NULL);
572 return l1;
575 void print_glx_glu(QTreeWidgetItem *l1, QTreeWidgetItem *l2)
577 QTreeWidgetItem *l3;
579 l2 = newItem(l1, l2, i18n("GLX"));
580 l3 = newItem(l2, i18n("server GLX vendor"), gli.serverVendor);
581 l3 = newItem(l2, l3, i18n("server GLX version"), gli.serverVersion);
582 l3 = newItem(l2, l3, i18n("server GLX extensions"));
583 print_extension_list(gli.serverExtensions, l3);
585 l3 = newItem(l2, l3, i18n("client GLX vendor") ,gli.clientVendor);
586 l3 = newItem(l2, l3, i18n("client GLX version"), gli.clientVersion);
587 l3 = newItem(l2, l3, i18n("client GLX extensions"));
588 print_extension_list(gli.clientExtensions, l3);
589 l3 = newItem(l2, l3, i18n("GLX extensions"));
590 print_extension_list(gli.glxExtensions, l3);
592 l2 = newItem(l1, l2, i18n("GLU"));
593 l3 = newItem(l2, i18n("GLU version"), gli.gluVersion);
594 l3 = newItem(l2, l3, i18n("GLU extensions"));
595 print_extension_list(gli.gluExtensions, l3);
599 static QTreeWidgetItem *get_gl_info(Display *dpy, int scrnum, Bool allowDirect, QTreeWidgetItem *l1, QTreeWidgetItem *after)
601 Window win;
602 int attribSingle[] = {
603 GLX_RGBA,
604 GLX_RED_SIZE, 1,
605 GLX_GREEN_SIZE, 1,
606 GLX_BLUE_SIZE, 1,
607 None };
608 int attribDouble[] = {
609 GLX_RGBA,
610 GLX_RED_SIZE, 1,
611 GLX_GREEN_SIZE, 1,
612 GLX_BLUE_SIZE, 1,
613 GLX_DOUBLEBUFFER,
614 None };
616 XSetWindowAttributes attr;
617 unsigned long mask;
618 Window root;
619 GLXContext ctx;
620 XVisualInfo *visinfo;
621 int width = 100, height = 100;
622 QTreeWidgetItem *result = after;
624 root = RootWindow(dpy, scrnum);
626 visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
627 if (!visinfo) {
628 visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
629 if (!visinfo) {
630 kDebug() << "Error: couldn't find RGB GLX visual\n";
631 return result;
635 attr.background_pixel = 0;
636 attr.border_pixel = 0;
637 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
638 attr.event_mask = StructureNotifyMask | ExposureMask;
639 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
640 win = XCreateWindow(dpy, root, 0, 0, width, height,
641 0, visinfo->depth, InputOutput,
642 visinfo->visual, mask, &attr);
644 ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect );
645 if (!ctx) {
646 kDebug() << "Error: glXCreateContext failed\n";
647 XDestroyWindow(dpy, win);
648 return result;
651 if (glXMakeCurrent(dpy, win, ctx)) {
652 gli.serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR);
653 gli.serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION);
654 gli.serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS);
655 gli.clientVendor = glXGetClientString(dpy, GLX_VENDOR);
656 gli.clientVersion = glXGetClientString(dpy, GLX_VERSION);
657 gli.clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS);
658 gli.glxExtensions = glXQueryExtensionsString(dpy, scrnum);
659 gli.glVendor = (const char *) glGetString(GL_VENDOR);
660 gli.glRenderer = (const char *) glGetString(GL_RENDERER);
661 gli.glVersion = (const char *) glGetString(GL_VERSION);
662 gli.glExtensions = (const char *) glGetString(GL_EXTENSIONS);
663 gli.displayName = NULL;
664 gli.gluVersion = (const char *) gluGetString(GLU_VERSION);
665 gli.gluExtensions = (const char *) gluGetString(GLU_EXTENSIONS);
667 IsDirect = glXIsDirect(dpy, ctx);
669 result = print_screen_info(l1, after);
671 else {
672 kDebug() << "Error: glXMakeCurrent failed\n";
675 glXDestroyContext(dpy, ctx);
676 XDestroyWindow(dpy, win);
677 return result;
681 bool GetInfo_OpenGL(QTreeWidget *treeWidget)
683 QTreeWidgetItem *l1, *l2 = NULL;
685 char *displayName = NULL;
686 Display *dpy;
687 int numScreens, scrnum;
689 dpy = XOpenDisplay(displayName);
690 if (!dpy) {
691 // kDebug() << "Error: unable to open display " << displayName;
692 return false;
695 QTreeWidgetItem *header = new QTreeWidgetItem();
696 header->setText(0, i18n("Information"));
697 header->setText(1, i18n("Value"));
698 treeWidget->setHeaderItem(header);
700 treeWidget->setRootIsDecorated(false);
702 l1 = new QTreeWidgetItem(treeWidget);
703 l1->setText(0, i18n("Name of the Display"));
704 l1->setText(1, DisplayString(dpy));
705 l1->setExpanded(true);
706 l1->setFlags(Qt::ItemIsEnabled);
708 numScreens = ScreenCount(dpy);
710 scrnum = 0;
711 #ifdef KCMGL_MANY_SCREENS
712 for (; scrnum < numScreens; scrnum++)
713 #endif
715 mesa_hack(dpy, scrnum);
717 l2 = get_gl_info(dpy, scrnum, true, l1, l2);
718 if (l2) l2->setExpanded(true);
720 if (IsDirect) l2 = get_gl_info(dpy, scrnum, false, l1, l2);
722 // TODO print_visual_info(dpy, scrnum, mode);
724 if (l2)
725 print_glx_glu(l1, l2);
726 else
727 KMessageBox::error(0, i18n("Could not initialize OpenGL"));
729 treeWidget->resizeColumnToContents(0);
730 treeWidget->resizeColumnToContents(1);
732 XCloseDisplay(dpy);
733 return true;