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.
28 #include <QTextStream>
30 #include <KPluginFactory>
31 #include <KPluginLoader>
33 #include <kaboutdata.h>
36 #include <kmessagebox.h>
41 #include <X11/Xutil.h>
53 K_PLUGIN_FACTORY(KCMOpenGLFactory
,
54 registerPlugin
<KCMOpenGL
>();
56 K_EXPORT_PLUGIN(KCMOpenGLFactory("kcmopengl"))
59 bool GetInfo_OpenGL(QTreeWidget
*treeWidget
);
61 KCMOpenGL::KCMOpenGL(QWidget
*parent
, const QVariantList
&)
62 : KCModule(KCMOpenGLFactory::componentData(), parent
)
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()));
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)"));
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
);
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
);
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
;
141 static int ReadPipe(QString FileName
, QStringList
&list
)
145 if ((pipe
= popen(FileName
.toAscii(), "r")) == NULL
) {
150 QTextStream
t(pipe
, QIODevice::ReadOnly
);
152 while (!t
.atEnd()) list
.append(t
.readLine());
158 #if defined(Q_OS_LINUX)
160 #define INFO_DRI "/proc/dri/0/name"
162 static bool get_dri_device()
165 file
.setFileName(INFO_DRI
);
166 if (!file
.exists() || !file
.open(QIODevice::ReadOnly
))
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
;
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
++) {
194 line
.remove(QRegExp("[^:]*:[ ]*"));
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;
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));
223 static bool get_dri_device() { return false; }
228 mesa_hack(Display
*dpy
, int scrnum
)
230 static int attribs
[] = {
237 GLX_ACCUM_RED_SIZE
, 1,
238 GLX_ACCUM_GREEN_SIZE
, 1,
239 GLX_ACCUM_BLUE_SIZE
, 1,
240 GLX_ACCUM_ALPHA_SIZE
, 1,
244 XVisualInfo
*visinfo
;
246 visinfo
= glXChooseVisual(dpy
, scrnum
, attribs
);
253 print_extension_list(const char *ext
, QTreeWidgetItem
*l1
)
259 QString qext
= QString::fromLatin1(ext
);
260 QTreeWidgetItem
*l2
= NULL
;
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
));
285 #if defined(GLX_ARB_get_proc_address) && defined(__GLXextFuncPtr)
287 extern __GLXextFuncPtr
glXGetProcAddressARB (const GLubyte
*);
292 print_limits(QTreeWidgetItem
*l1
, const char * glExtensions
, bool GetProcAddress
)
297 GL_COMPRESSED_TEXTURE_FORMATS
304 GLuint type
; // count and flags, !!! count must be <=2 for now
312 const token_name
*group
;
317 QTreeWidgetItem
*l2
= NULL
, *l3
= NULL
;
318 #if defined(PFNGLGETPROGRAMIVARBPROC)
319 PFNGLGETPROGRAMIVARBPROC kcm_glGetProgramivARB
= NULL
;
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")},
338 #ifdef GL_MAX_VERTEX_UNITS_ARB
339 { 1, GL_MAX_VERTEX_UNITS_ARB
, i18n("Max. vertex blend matrices") },
341 #ifdef GL_MAX_PALETTE_MATRICES_ARB
342 { 1, GL_MAX_PALETTE_MATRICES_ARB
, i18n("Max. vertex blend matrix palette size") },
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") },
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") },
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"},
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"},
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" },
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"},
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"},
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"},
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")},
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"},
471 #ifdef GL_ARB_fragment_program
472 {KCMGL_SIZE(arb_fp
), GL_FRAGMENT_PROGRAM_ARB
, arb_fp
, "ARB_fragment_program", "GL_ARB_fragment_program"},
474 #ifdef GL_ARB_vertex_shader
475 {KCMGL_SIZE(arb_vs
), 0, arb_vs
, "ARB_vertex_shader", "GL_ARB_vertex_shader"},
477 #ifdef GL_ARB_fragment_shader
478 {KCMGL_SIZE(arb_fs
), 0, arb_fs
, "ARB_fragment_shader", "GL_ARB_fragment_shader"},
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");
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
);
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
);
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
);
507 if (tfloat
) glGetFloatv(cur_token
->token
, fmax
);
508 else glGetIntegerv(cur_token
->token
, max
);
510 if (glGetError() == GL_NONE
) {
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
;
531 l1
= newItem(l1
, after
, IsDirect
? i18n("Direct Rendering") : i18n("Indirect Rendering"));
533 l1
= newItem(l1
, IsDirect
? i18n("Direct Rendering") : i18n("Indirect Rendering"));
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
);
545 l2
= newItem(l1
, l2
, i18n("3D Accelerator"), i18n("unknown"));
550 l2
= newItem(l1
, l2
, i18n("Driver"));
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
);
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
);
575 void print_glx_glu(QTreeWidgetItem
*l1
, QTreeWidgetItem
*l2
)
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
)
602 int attribSingle
[] = {
608 int attribDouble
[] = {
616 XSetWindowAttributes attr
;
620 XVisualInfo
*visinfo
;
621 int width
= 100, height
= 100;
622 QTreeWidgetItem
*result
= after
;
624 root
= RootWindow(dpy
, scrnum
);
626 visinfo
= glXChooseVisual(dpy
, scrnum
, attribSingle
);
628 visinfo
= glXChooseVisual(dpy
, scrnum
, attribDouble
);
630 kDebug() << "Error: couldn't find RGB GLX visual\n";
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
);
646 kDebug() << "Error: glXCreateContext failed\n";
647 XDestroyWindow(dpy
, win
);
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
);
672 kDebug() << "Error: glXMakeCurrent failed\n";
675 glXDestroyContext(dpy
, ctx
);
676 XDestroyWindow(dpy
, win
);
681 bool GetInfo_OpenGL(QTreeWidget
*treeWidget
)
683 QTreeWidgetItem
*l1
, *l2
= NULL
;
685 char *displayName
= NULL
;
687 int numScreens
, scrnum
;
689 dpy
= XOpenDisplay(displayName
);
691 // kDebug() << "Error: unable to open display " << displayName;
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
);
711 #ifdef KCMGL_MANY_SCREENS
712 for (; scrnum
< numScreens
; scrnum
++)
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);
725 print_glx_glu(l1
, l2
);
727 KMessageBox::error(0, i18n("Could not initialize OpenGL"));
729 treeWidget
->resizeColumnToContents(0);
730 treeWidget
->resizeColumnToContents(1);