source: trunk/src/opengl/qgl_x11.cpp@ 1110

Last change on this file since 1110 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 63.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qgl.h"
43#include "qgl_p.h"
44
45#include "qmap.h"
46#include "qapplication.h"
47#include "qcolormap.h"
48#include "qdesktopwidget.h"
49#include "qpixmap.h"
50#include "qhash.h"
51#include "qlibrary.h"
52#include "qdebug.h"
53#include <private/qfontengine_ft_p.h>
54#include <private/qt_x11_p.h>
55#include <private/qpixmap_x11_p.h>
56#include <private/qimagepixmapcleanuphooks_p.h>
57#include <private/qunicodetables_p.h>
58#ifdef Q_OS_HPUX
59// for GLXPBuffer
60#include <private/qglpixelbuffer_p.h>
61#endif
62
63// We always define GLX_EXT_texture_from_pixmap ourselves because
64// we can't trust system headers to do it properly
65#define GLX_EXT_texture_from_pixmap 1
66
67#define INT8 dummy_INT8
68#define INT32 dummy_INT32
69#include <GL/glx.h>
70#undef INT8
71#undef INT32
72
73#include <X11/Xlib.h>
74#include <X11/Xutil.h>
75#include <X11/Xos.h>
76#ifdef Q_OS_VXWORS
77# ifdef open
78# undef open
79# endif
80# ifdef getpid
81# undef getpid
82# endif
83#endif // Q_OS_VXWORKS
84#include <X11/Xatom.h>
85
86#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
87#include <dlfcn.h>
88#endif
89
90QT_BEGIN_NAMESPACE
91
92extern Drawable qt_x11Handle(const QPaintDevice *pd);
93extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
94
95#ifndef GLX_ARB_multisample
96#define GLX_SAMPLE_BUFFERS_ARB 100000
97#define GLX_SAMPLES_ARB 100001
98#endif
99
100#ifndef GLX_TEXTURE_2D_BIT_EXT
101#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
102#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
103#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
104#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1
105#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2
106#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
107#define GLX_Y_INVERTED_EXT 0x20D4
108#define GLX_TEXTURE_FORMAT_EXT 0x20D5
109#define GLX_TEXTURE_TARGET_EXT 0x20D6
110#define GLX_MIPMAP_TEXTURE_EXT 0x20D7
111#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8
112#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9
113#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA
114#define GLX_TEXTURE_2D_EXT 0x20DC
115#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD
116#define GLX_FRONT_LEFT_EXT 0x20DE
117#endif
118
119#ifndef GLX_ARB_create_context
120#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
121#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
122#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
123#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
124#define GLX_CONTEXT_FLAGS_ARB 0x2094
125#endif
126
127#ifndef GLX_ARB_create_context_profile
128#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
129#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
130#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
131#endif
132
133/*
134 The qt_gl_choose_cmap function is internal and used by QGLWidget::setContext()
135 and GLX (not Windows). If the application can't find any sharable
136 colormaps, it must at least create as few colormaps as possible. The
137 dictionary solution below ensures only one colormap is created per visual.
138 Colormaps are also deleted when the application terminates.
139*/
140
141struct QCMapEntry {
142 QCMapEntry();
143 ~QCMapEntry();
144
145 Colormap cmap;
146 bool alloc;
147 XStandardColormap scmap;
148};
149
150QCMapEntry::QCMapEntry()
151{
152 cmap = 0;
153 alloc = false;
154 scmap.colormap = 0;
155}
156
157QCMapEntry::~QCMapEntry()
158{
159 if (alloc)
160 XFreeColormap(X11->display, cmap);
161}
162typedef QHash<int, QCMapEntry *> CMapEntryHash;
163typedef QHash<int, QMap<int, QRgb> > GLCMapHash;
164static bool mesa_gl = false;
165static bool first_time = true;
166
167static void cleanup_cmaps();
168
169struct QGLCMapCleanupHandler {
170 QGLCMapCleanupHandler() {
171 cmap_hash = new CMapEntryHash;
172 qglcmap_hash = new GLCMapHash;
173 }
174 ~QGLCMapCleanupHandler() {
175 delete cmap_hash;
176 delete qglcmap_hash;
177 }
178 CMapEntryHash *cmap_hash;
179 GLCMapHash *qglcmap_hash;
180};
181Q_GLOBAL_STATIC(QGLCMapCleanupHandler, cmap_handler)
182
183static void cleanup_cmaps()
184{
185 CMapEntryHash *hash = cmap_handler()->cmap_hash;
186 QHash<int, QCMapEntry *>::ConstIterator it = hash->constBegin();
187 while (it != hash->constEnd()) {
188 delete it.value();
189 ++it;
190 }
191
192 hash->clear();
193 cmap_handler()->qglcmap_hash->clear();
194}
195
196Colormap qt_gl_choose_cmap(Display *dpy, XVisualInfo *vi)
197{
198 if (first_time) {
199 const char *v = glXQueryServerString(dpy, vi->screen, GLX_VERSION);
200 if (v)
201 mesa_gl = (strstr(v, "Mesa") != 0);
202 first_time = false;
203 }
204
205 CMapEntryHash *hash = cmap_handler()->cmap_hash;
206 CMapEntryHash::ConstIterator it = hash->constFind((long) vi->visualid + (vi->screen * 256));
207 if (it != hash->constEnd())
208 return it.value()->cmap; // found colormap for visual
209
210 if (vi->visualid ==
211 XVisualIDFromVisual((Visual *) QX11Info::appVisual(vi->screen))) {
212 // qDebug("Using x11AppColormap");
213 return QX11Info::appColormap(vi->screen);
214 }
215
216 QCMapEntry *x = new QCMapEntry();
217
218 XStandardColormap *c;
219 int n, i;
220
221 // qDebug("Choosing cmap for vID %0x", vi->visualid);
222
223 if (mesa_gl) { // we're using MesaGL
224 Atom hp_cmaps = XInternAtom(dpy, "_HP_RGB_SMOOTH_MAP_LIST", true);
225 if (hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8) {
226 if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
227 hp_cmaps)) {
228 i = 0;
229 while (i < n && x->cmap == 0) {
230 if (c[i].visualid == vi->visual->visualid) {
231 x->cmap = c[i].colormap;
232 x->scmap = c[i];
233 //qDebug("Using HP_RGB scmap");
234
235 }
236 i++;
237 }
238 XFree((char *)c);
239 }
240 }
241 }
242 if (!x->cmap) {
243 if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
244 XA_RGB_DEFAULT_MAP)) {
245 for (int i = 0; i < n && x->cmap == 0; ++i) {
246 if (!c[i].red_max ||
247 !c[i].green_max ||
248 !c[i].blue_max ||
249 !c[i].red_mult ||
250 !c[i].green_mult ||
251 !c[i].blue_mult)
252 continue; // invalid stdcmap
253 if (c[i].visualid == vi->visualid) {
254 x->cmap = c[i].colormap;
255 x->scmap = c[i];
256 //qDebug("Using RGB_DEFAULT scmap");
257 }
258 }
259 XFree((char *)c);
260 }
261 }
262 if (!x->cmap) { // no shared cmap found
263 x->cmap = XCreateColormap(dpy, RootWindow(dpy,vi->screen), vi->visual,
264 AllocNone);
265 x->alloc = true;
266 // qDebug("Allocating cmap");
267 }
268
269 // colormap hash should be cleanup only when the QApplication dtor is called
270 if (hash->isEmpty())
271 qAddPostRoutine(cleanup_cmaps);
272
273 // associate cmap with visualid
274 hash->insert((long) vi->visualid + (vi->screen * 256), x);
275 return x->cmap;
276}
277
278struct QTransColor
279{
280 VisualID vis;
281 int screen;
282 long color;
283};
284
285static QVector<QTransColor> trans_colors;
286static int trans_colors_init = false;
287
288static void find_trans_colors()
289{
290 struct OverlayProp {
291 long visual;
292 long type;
293 long value;
294 long layer;
295 };
296
297 trans_colors_init = true;
298
299 Display* appDisplay = X11->display;
300
301 int scr;
302 int lastsize = 0;
303 for (scr = 0; scr < ScreenCount(appDisplay); scr++) {
304 QWidget* rootWin = QApplication::desktop()->screen(scr);
305 if (!rootWin)
306 return; // Should not happen
307 Atom overlayVisualsAtom = XInternAtom(appDisplay,
308 "SERVER_OVERLAY_VISUALS", True);
309 if (overlayVisualsAtom == XNone)
310 return; // Server has no overlays
311
312 Atom actualType;
313 int actualFormat;
314 ulong nItems;
315 ulong bytesAfter;
316 unsigned char *retval = 0;
317 int res = XGetWindowProperty(appDisplay, rootWin->winId(),
318 overlayVisualsAtom, 0, 10000, False,
319 overlayVisualsAtom, &actualType,
320 &actualFormat, &nItems, &bytesAfter,
321 &retval);
322
323 if (res != Success || actualType != overlayVisualsAtom
324 || actualFormat != 32 || nItems < 4 || !retval)
325 return; // Error reading property
326
327 OverlayProp *overlayProps = (OverlayProp *)retval;
328
329 int numProps = nItems / 4;
330 trans_colors.resize(lastsize + numProps);
331 int j = lastsize;
332 for (int i = 0; i < numProps; i++) {
333 if (overlayProps[i].type == 1) {
334 trans_colors[j].vis = (VisualID)overlayProps[i].visual;
335 trans_colors[j].screen = scr;
336 trans_colors[j].color = (int)overlayProps[i].value;
337 j++;
338 }
339 }
340 XFree(overlayProps);
341 lastsize = j;
342 trans_colors.resize(lastsize);
343 }
344}
345
346/*****************************************************************************
347 QGLFormat UNIX/GLX-specific code
348 *****************************************************************************/
349
350void* qglx_getProcAddress(const char* procName)
351{
352 // On systems where the GL driver is pluggable (like Mesa), we have to use
353 // the glXGetProcAddressARB extension to resolve other function pointers as
354 // the symbols wont be in the GL library, but rather in a plugin loaded by
355 // the GL library.
356 typedef void* (*qt_glXGetProcAddressARB)(const char *);
357 static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
358 static bool triedResolvingGlxGetProcAddress = false;
359 if (!triedResolvingGlxGetProcAddress) {
360 triedResolvingGlxGetProcAddress = true;
361 QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
362 if (extensions.match("GLX_ARB_get_proc_address")) {
363#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
364 void *handle = dlopen(NULL, RTLD_LAZY);
365 if (handle) {
366 glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB");
367 dlclose(handle);
368 }
369 if (!glXGetProcAddressARB)
370#endif
371 {
372#if !defined(QT_NO_LIBRARY)
373 extern const QString qt_gl_library_name();
374 QLibrary lib(qt_gl_library_name());
375 glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
376#endif
377 }
378 }
379 }
380
381 void *procAddress = 0;
382 if (glXGetProcAddressARB)
383 procAddress = glXGetProcAddressARB(procName);
384
385 // If glXGetProcAddress didn't work, try looking the symbol up in the GL library
386#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
387 if (!procAddress) {
388 void *handle = dlopen(NULL, RTLD_LAZY);
389 if (handle) {
390 procAddress = dlsym(handle, procName);
391 dlclose(handle);
392 }
393 }
394#endif
395#if !defined(QT_NO_LIBRARY)
396 if (!procAddress) {
397 extern const QString qt_gl_library_name();
398 QLibrary lib(qt_gl_library_name());
399 procAddress = lib.resolve(procName);
400 }
401#endif
402
403 return procAddress;
404}
405
406bool QGLFormat::hasOpenGL()
407{
408 return glXQueryExtension(X11->display, 0, 0) != 0;
409}
410
411
412bool QGLFormat::hasOpenGLOverlays()
413{
414 if (!trans_colors_init)
415 find_trans_colors();
416 return trans_colors.size() > 0;
417}
418
419static bool buildSpec(int* spec, const QGLFormat& f, QPaintDevice* paintDevice,
420 int bufDepth, bool onlyFBConfig = false)
421{
422 int i = 0;
423 spec[i++] = GLX_LEVEL;
424 spec[i++] = f.plane();
425 const QX11Info *xinfo = qt_x11Info(paintDevice);
426 bool useFBConfig = onlyFBConfig;
427
428#if defined(GLX_VERSION_1_3) && !defined(QT_NO_XRENDER) && !defined(Q_OS_HPUX)
429 /*
430 HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions.
431 Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented.
432 */
433 QWidget* widget = 0;
434 if (paintDevice->devType() == QInternal::Widget)
435 widget = static_cast<QWidget*>(paintDevice);
436
437 // Only use glXChooseFBConfig for widgets if we're trying to get an ARGB visual
438 if (widget && widget->testAttribute(Qt::WA_TranslucentBackground) && X11->use_xrender)
439 useFBConfig = true;
440#endif
441
442#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
443 static bool useTranspExt = false;
444 static bool useTranspExtChecked = false;
445 if (f.plane() && !useTranspExtChecked && paintDevice) {
446 QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
447 useTranspExt = extensions.match("GLX_EXT_visual_info");
448 //# (A bit simplistic; that could theoretically be a substring)
449 if (useTranspExt) {
450 QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR));
451 useTranspExt = !cstr.contains("Xi Graphics"); // bug workaround
452 if (useTranspExt) {
453 // bug workaround - some systems (eg. FireGL) refuses to return an overlay
454 // visual if the GLX_TRANSPARENT_TYPE_EXT attribute is specified, even if
455 // the implementation supports transparent overlays
456 int tmpSpec[] = { GLX_LEVEL, f.plane(), GLX_TRANSPARENT_TYPE_EXT,
457 f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT,
458 XNone };
459 XVisualInfo * vinf = glXChooseVisual(xinfo->display(), xinfo->screen(), tmpSpec);
460 if (!vinf) {
461 useTranspExt = false;
462 }
463 }
464 }
465
466 useTranspExtChecked = true;
467 }
468 if (f.plane() && useTranspExt && !useFBConfig) {
469 // Required to avoid non-transparent overlay visual(!) on some systems
470 spec[i++] = GLX_TRANSPARENT_TYPE_EXT;
471 spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT;
472 }
473#endif
474
475#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
476 // GLX_RENDER_TYPE is only in glx >=1.3
477 if (useFBConfig) {
478 spec[i++] = GLX_RENDER_TYPE;
479 spec[i++] = f.rgba() ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
480 }
481#endif
482
483 if (f.doubleBuffer())
484 spec[i++] = GLX_DOUBLEBUFFER;
485 if (useFBConfig)
486 spec[i++] = True;
487 if (f.depth()) {
488 spec[i++] = GLX_DEPTH_SIZE;
489 spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
490 }
491 if (f.stereo()) {
492 spec[i++] = GLX_STEREO;
493 if (useFBConfig)
494 spec[i++] = True;
495 }
496 if (f.stencil()) {
497 spec[i++] = GLX_STENCIL_SIZE;
498 spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
499 }
500 if (f.rgba()) {
501 if (!useFBConfig)
502 spec[i++] = GLX_RGBA;
503 spec[i++] = GLX_RED_SIZE;
504 spec[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize();
505 spec[i++] = GLX_GREEN_SIZE;
506 spec[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize();
507 spec[i++] = GLX_BLUE_SIZE;
508 spec[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize();
509 if (f.alpha()) {
510 spec[i++] = GLX_ALPHA_SIZE;
511 spec[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
512 }
513 if (f.accum()) {
514 spec[i++] = GLX_ACCUM_RED_SIZE;
515 spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
516 spec[i++] = GLX_ACCUM_GREEN_SIZE;
517 spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
518 spec[i++] = GLX_ACCUM_BLUE_SIZE;
519 spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
520 if (f.alpha()) {
521 spec[i++] = GLX_ACCUM_ALPHA_SIZE;
522 spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
523 }
524 }
525 } else {
526 spec[i++] = GLX_BUFFER_SIZE;
527 spec[i++] = bufDepth;
528 }
529
530 if (f.sampleBuffers()) {
531 spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
532 spec[i++] = 1;
533 spec[i++] = GLX_SAMPLES_ARB;
534 spec[i++] = f.samples() == -1 ? 4 : f.samples();
535 }
536
537#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
538 if (useFBConfig) {
539 spec[i++] = GLX_DRAWABLE_TYPE;
540 switch(paintDevice->devType()) {
541 case QInternal::Pixmap:
542 spec[i++] = GLX_PIXMAP_BIT;
543 break;
544 case QInternal::Pbuffer:
545 spec[i++] = GLX_PBUFFER_BIT;
546 break;
547 default:
548 qWarning("QGLContext: Unknown paint device type %d", paintDevice->devType());
549 // Fall-through & assume it's a window
550 case QInternal::Widget:
551 spec[i++] = GLX_WINDOW_BIT;
552 break;
553 };
554 }
555#endif
556
557 spec[i] = XNone;
558 return useFBConfig;
559}
560
561/*****************************************************************************
562 QGLContext UNIX/GLX-specific code
563 *****************************************************************************/
564
565bool QGLContext::chooseContext(const QGLContext* shareContext)
566{
567 Q_D(QGLContext);
568 const QX11Info *xinfo = qt_x11Info(d->paintDevice);
569
570 Display* disp = xinfo->display();
571 d->vi = chooseVisual();
572 if (!d->vi)
573 return false;
574
575 if (deviceIsPixmap() &&
576 (((XVisualInfo*)d->vi)->depth != xinfo->depth() ||
577 ((XVisualInfo*)d->vi)->screen != xinfo->screen()))
578 {
579 XFree(d->vi);
580 XVisualInfo appVisInfo;
581 memset(&appVisInfo, 0, sizeof(XVisualInfo));
582 appVisInfo.visualid = XVisualIDFromVisual((Visual *) xinfo->visual());
583 appVisInfo.screen = xinfo->screen();
584 int nvis;
585 d->vi = XGetVisualInfo(disp, VisualIDMask | VisualScreenMask, &appVisInfo, &nvis);
586 if (!d->vi)
587 return false;
588
589 int useGL;
590 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_USE_GL, &useGL);
591 if (!useGL)
592 return false; //# Chickening out already...
593 }
594 int res;
595 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_LEVEL, &res);
596 d->glFormat.setPlane(res);
597 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DOUBLEBUFFER, &res);
598 d->glFormat.setDoubleBuffer(res);
599 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DEPTH_SIZE, &res);
600 d->glFormat.setDepth(res);
601 if (d->glFormat.depth())
602 d->glFormat.setDepthBufferSize(res);
603 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RGBA, &res);
604 d->glFormat.setRgba(res);
605 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RED_SIZE, &res);
606 d->glFormat.setRedBufferSize(res);
607 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_GREEN_SIZE, &res);
608 d->glFormat.setGreenBufferSize(res);
609 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_BLUE_SIZE, &res);
610 d->glFormat.setBlueBufferSize(res);
611 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ALPHA_SIZE, &res);
612 d->glFormat.setAlpha(res);
613 if (d->glFormat.alpha())
614 d->glFormat.setAlphaBufferSize(res);
615 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ACCUM_RED_SIZE, &res);
616 d->glFormat.setAccum(res);
617 if (d->glFormat.accum())
618 d->glFormat.setAccumBufferSize(res);
619 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STENCIL_SIZE, &res);
620 d->glFormat.setStencil(res);
621 if (d->glFormat.stencil())
622 d->glFormat.setStencilBufferSize(res);
623 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STEREO, &res);
624 d->glFormat.setStereo(res);
625 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLE_BUFFERS_ARB, &res);
626 d->glFormat.setSampleBuffers(res);
627 if (d->glFormat.sampleBuffers()) {
628 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLES_ARB, &res);
629 d->glFormat.setSamples(res);
630 }
631
632 Bool direct = format().directRendering() ? True : False;
633
634 if (shareContext &&
635 (!shareContext->isValid() || !shareContext->d_func()->cx)) {
636 qWarning("QGLContext::chooseContext(): Cannot share with invalid context");
637 shareContext = 0;
638 }
639
640 // 1. Sharing between rgba and color-index will give wrong colors.
641 // 2. Contexts cannot be shared btw. direct/non-direct renderers.
642 // 3. Pixmaps cannot share contexts that are set up for direct rendering.
643 // 4. If the contexts are not created on the same screen, they can't be shared
644
645 if (shareContext
646 && (format().rgba() != shareContext->format().rgba()
647 || (deviceIsPixmap() && glXIsDirect(disp, (GLXContext)shareContext->d_func()->cx))
648 || (shareContext->d_func()->screen != xinfo->screen())))
649 {
650 shareContext = 0;
651 }
652
653 const int major = d->reqFormat.majorVersion();
654 const int minor = d->reqFormat.minorVersion();
655 const int profile = d->reqFormat.profile() == QGLFormat::CompatibilityProfile
656 ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
657 : GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
658
659 d->cx = 0;
660
661#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
662 /*
663 HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions.
664 Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented.
665 */
666 if ((major == 3 && minor >= 2) || major > 3) {
667 QGLTemporaryContext *tmpContext = 0;
668 if (!QGLContext::currentContext())
669 tmpContext = new QGLTemporaryContext;
670
671 int attributes[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, major,
672 GLX_CONTEXT_MINOR_VERSION_ARB, minor,
673 GLX_CONTEXT_PROFILE_MASK_ARB, profile,
674 0 };
675
676 typedef GLXContext ( * Q_PFNGLXCREATECONTEXTATTRIBSARBPROC)
677 (Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
678
679
680 Q_PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs =
681 (Q_PFNGLXCREATECONTEXTATTRIBSARBPROC) qglx_getProcAddress("glXCreateContextAttribsARB");
682
683 if (glXCreateContextAttribs) {
684 int spec[45];
685 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_BUFFER_SIZE, &res);
686 buildSpec(spec, format(), d->paintDevice, res, true);
687
688 GLXFBConfig *configs;
689 int configCount = 0;
690 configs = glXChooseFBConfig(disp, xinfo->screen(), spec, &configCount);
691
692 if (configs && configCount > 0) {
693 d->cx = glXCreateContextAttribs(disp, configs[0],
694 shareContext ? (GLXContext)shareContext->d_func()->cx : 0, direct, attributes);
695 if (!d->cx && shareContext) {
696 shareContext = 0;
697 d->cx = glXCreateContextAttribs(disp, configs[0], 0, direct, attributes);
698 }
699 d->screen = ((XVisualInfo*)d->vi)->screen;
700 }
701 XFree(configs);
702 } else {
703 qWarning("QGLContext::chooseContext(): OpenGL %d.%d is not supported", major, minor);
704 }
705
706 if (tmpContext)
707 delete tmpContext;
708 }
709#else
710 Q_UNUSED(major);
711 Q_UNUSED(minor);
712 Q_UNUSED(profile);
713#endif
714
715 if (!d->cx && shareContext) {
716 d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi,
717 (GLXContext)shareContext->d_func()->cx, direct);
718 d->screen = ((XVisualInfo*)d->vi)->screen;
719 }
720 if (!d->cx) {
721 d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, NULL, direct);
722 d->screen = ((XVisualInfo*)d->vi)->screen;
723 shareContext = 0;
724 }
725
726 if (shareContext && d->cx) {
727 QGLContext *share = const_cast<QGLContext *>(shareContext);
728 d->sharing = true;
729 share->d_func()->sharing = true;
730 }
731
732 if (!d->cx)
733 return false;
734 d->glFormat.setDirectRendering(glXIsDirect(disp, (GLXContext)d->cx));
735 if (deviceIsPixmap()) {
736#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT)
737 d->gpm = glXCreateGLXPixmapMESA(disp, (XVisualInfo *)d->vi,
738 qt_x11Handle(d->paintDevice),
739 qt_gl_choose_cmap(disp, (XVisualInfo *)d->vi));
740#else
741 d->gpm = (quint32)glXCreateGLXPixmap(disp, (XVisualInfo *)d->vi,
742 qt_x11Handle(d->paintDevice));
743#endif
744 if (!d->gpm)
745 return false;
746 }
747 QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
748 if (extensions.match("GLX_SGI_video_sync")) {
749 if (d->glFormat.swapInterval() == -1)
750 d->glFormat.setSwapInterval(0);
751 } else {
752 d->glFormat.setSwapInterval(-1);
753 }
754 return true;
755}
756
757/*
758 See qgl.cpp for qdoc comment.
759 */
760void *QGLContext::chooseVisual()
761{
762 Q_D(QGLContext);
763 static const int bufDepths[] = { 8, 4, 2, 1 }; // Try 16, 12 also?
764 //todo: if pixmap, also make sure that vi->depth == pixmap->depth
765 void* vis = 0;
766 int i = 0;
767 bool fail = false;
768 QGLFormat fmt = format();
769 bool tryDouble = !fmt.doubleBuffer(); // Some GL impl's only have double
770 bool triedDouble = false;
771 bool triedSample = false;
772 if (fmt.sampleBuffers())
773 fmt.setSampleBuffers(QGLExtensions::glExtensions() & QGLExtensions::SampleBuffers);
774 while(!fail && !(vis = tryVisual(fmt, bufDepths[i]))) {
775 if (!fmt.rgba() && bufDepths[i] > 1) {
776 i++;
777 continue;
778 }
779 if (tryDouble) {
780 fmt.setDoubleBuffer(true);
781 tryDouble = false;
782 triedDouble = true;
783 continue;
784 } else if (triedDouble) {
785 fmt.setDoubleBuffer(false);
786 triedDouble = false;
787 }
788 if (!triedSample && fmt.sampleBuffers()) {
789 fmt.setSampleBuffers(false);
790 triedSample = true;
791 continue;
792 }
793 if (fmt.stereo()) {
794 fmt.setStereo(false);
795 continue;
796 }
797 if (fmt.accum()) {
798 fmt.setAccum(false);
799 continue;
800 }
801 if (fmt.stencil()) {
802 fmt.setStencil(false);
803 continue;
804 }
805 if (fmt.alpha()) {
806 fmt.setAlpha(false);
807 continue;
808 }
809 if (fmt.depth()) {
810 fmt.setDepth(false);
811 continue;
812 }
813 if (fmt.doubleBuffer()) {
814 fmt.setDoubleBuffer(false);
815 continue;
816 }
817 fail = true;
818 }
819 d->glFormat = fmt;
820 return vis;
821}
822
823/*
824 See qgl.cpp for qdoc comment.
825 */
826void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
827{
828 Q_D(QGLContext);
829 int spec[45];
830 const QX11Info *xinfo = qt_x11Info(d->paintDevice);
831 bool useFBConfig = buildSpec(spec, f, d->paintDevice, bufDepth, false);
832
833 XVisualInfo* chosenVisualInfo = 0;
834
835#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
836 while (useFBConfig) {
837 GLXFBConfig *configs;
838 int configCount = 0;
839 configs = glXChooseFBConfig(xinfo->display(), xinfo->screen(), spec, &configCount);
840
841 if (!configs)
842 break; // fallback to trying glXChooseVisual
843
844 for (int i = 0; i < configCount; ++i) {
845 XVisualInfo* vi;
846 vi = glXGetVisualFromFBConfig(xinfo->display(), configs[i]);
847 if (!vi)
848 continue;
849
850#if !defined(QT_NO_XRENDER)
851 QWidget* w = 0;
852 if (d->paintDevice->devType() == QInternal::Widget)
853 w = static_cast<QWidget*>(d->paintDevice);
854
855 if (w && w->testAttribute(Qt::WA_TranslucentBackground) && f.alpha()) {
856 // Attempt to find a config who's visual has a proper alpha channel
857 XRenderPictFormat *pictFormat;
858 pictFormat = XRenderFindVisualFormat(xinfo->display(), vi->visual);
859
860 if (pictFormat && (pictFormat->type == PictTypeDirect) && pictFormat->direct.alphaMask) {
861 // The pict format for the visual matching the FBConfig indicates ARGB
862 if (chosenVisualInfo)
863 XFree(chosenVisualInfo);
864 chosenVisualInfo = vi;
865 break;
866 }
867 } else
868#endif //QT_NO_XRENDER
869 if (chosenVisualInfo) {
870 // If we've got a visual we can use and we're not trying to find one with a
871 // real alpha channel, we might as well just use the one we've got
872 break;
873 }
874
875 if (!chosenVisualInfo)
876 chosenVisualInfo = vi; // Have something to fall back to
877 else
878 XFree(vi);
879 }
880
881 XFree(configs);
882 break;
883 }
884#endif // defined(GLX_VERSION_1_3)
885
886 if (!chosenVisualInfo)
887 chosenVisualInfo = glXChooseVisual(xinfo->display(), xinfo->screen(), spec);
888
889 return chosenVisualInfo;
890}
891
892
893void QGLContext::reset()
894{
895 Q_D(QGLContext);
896 if (!d->valid)
897 return;
898 d->cleanup();
899 const QX11Info *xinfo = qt_x11Info(d->paintDevice);
900 doneCurrent();
901 if (d->gpm)
902 glXDestroyGLXPixmap(xinfo->display(), (GLXPixmap)d->gpm);
903 d->gpm = 0;
904 glXDestroyContext(xinfo->display(), (GLXContext)d->cx);
905 if (d->vi)
906 XFree(d->vi);
907 d->vi = 0;
908 d->cx = 0;
909 d->crWin = false;
910 d->sharing = false;
911 d->valid = false;
912 d->transpColor = QColor();
913 d->initDone = false;
914 QGLContextGroup::removeShare(this);
915}
916
917
918void QGLContext::makeCurrent()
919{
920 Q_D(QGLContext);
921 if (!d->valid) {
922 qWarning("QGLContext::makeCurrent(): Cannot make invalid context current.");
923 return;
924 }
925 const QX11Info *xinfo = qt_x11Info(d->paintDevice);
926 bool ok = true;
927 if (d->paintDevice->devType() == QInternal::Pixmap) {
928 ok = glXMakeCurrent(xinfo->display(), (GLXPixmap)d->gpm, (GLXContext)d->cx);
929 } else if (d->paintDevice->devType() == QInternal::Pbuffer) {
930 ok = glXMakeCurrent(xinfo->display(), (GLXPbuffer)d->pbuf, (GLXContext)d->cx);
931 } else if (d->paintDevice->devType() == QInternal::Widget) {
932 ok = glXMakeCurrent(xinfo->display(), ((QWidget *)d->paintDevice)->internalWinId(), (GLXContext)d->cx);
933 }
934 if (!ok)
935 qWarning("QGLContext::makeCurrent(): Failed.");
936
937 if (ok)
938 QGLContextPrivate::setCurrentContext(this);
939}
940
941void QGLContext::doneCurrent()
942{
943 Q_D(QGLContext);
944 glXMakeCurrent(qt_x11Info(d->paintDevice)->display(), 0, 0);
945 QGLContextPrivate::setCurrentContext(0);
946}
947
948
949void QGLContext::swapBuffers() const
950{
951 Q_D(const QGLContext);
952 if (!d->valid)
953 return;
954 if (!deviceIsPixmap()) {
955 int interval = d->glFormat.swapInterval();
956 if (interval > 0) {
957 typedef int (*qt_glXGetVideoSyncSGI)(uint *);
958 typedef int (*qt_glXWaitVideoSyncSGI)(int, int, uint *);
959 static qt_glXGetVideoSyncSGI glXGetVideoSyncSGI = 0;
960 static qt_glXWaitVideoSyncSGI glXWaitVideoSyncSGI = 0;
961 static bool resolved = false;
962 if (!resolved) {
963 const QX11Info *xinfo = qt_x11Info(d->paintDevice);
964 QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
965 if (extensions.match("GLX_SGI_video_sync")) {
966 glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI)qglx_getProcAddress("glXGetVideoSyncSGI");
967 glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI)qglx_getProcAddress("glXWaitVideoSyncSGI");
968 }
969 resolved = true;
970 }
971 if (glXGetVideoSyncSGI && glXWaitVideoSyncSGI) {
972 uint counter;
973 if (!glXGetVideoSyncSGI(&counter))
974 glXWaitVideoSyncSGI(interval + 1, (counter + interval) % (interval + 1), &counter);
975 }
976 }
977 glXSwapBuffers(qt_x11Info(d->paintDevice)->display(),
978 static_cast<QWidget *>(d->paintDevice)->winId());
979 }
980}
981
982QColor QGLContext::overlayTransparentColor() const
983{
984 if (isValid())
985 return Qt::transparent;
986 return QColor(); // Invalid color
987}
988
989static uint qt_transparent_pixel(VisualID id, int screen)
990{
991 for (int i = 0; i < trans_colors.size(); i++) {
992 if (trans_colors[i].vis == id && trans_colors[i].screen == screen)
993 return trans_colors[i].color;
994 }
995 return 0;
996}
997
998uint QGLContext::colorIndex(const QColor& c) const
999{
1000 Q_D(const QGLContext);
1001 int screen = ((XVisualInfo *)d->vi)->screen;
1002 QColormap colmap = QColormap::instance(screen);
1003 if (isValid()) {
1004 if (format().plane() && c == Qt::transparent) {
1005 return qt_transparent_pixel(((XVisualInfo *)d->vi)->visualid,
1006 ((XVisualInfo *)d->vi)->screen);
1007 }
1008 if (((XVisualInfo*)d->vi)->visualid ==
1009 XVisualIDFromVisual((Visual *) QX11Info::appVisual(screen)))
1010 return colmap.pixel(c); // We're using QColor's cmap
1011
1012 XVisualInfo *info = (XVisualInfo *) d->vi;
1013 CMapEntryHash *hash = cmap_handler()->cmap_hash;
1014 CMapEntryHash::ConstIterator it = hash->constFind(long(info->visualid)
1015 + (info->screen * 256));
1016 QCMapEntry *x = 0;
1017 if (it != hash->constEnd())
1018 x = it.value();
1019 if (x && !x->alloc) { // It's a standard colormap
1020 int rf = (int)(((float)c.red() * (x->scmap.red_max+1))/256.0);
1021 int gf = (int)(((float)c.green() * (x->scmap.green_max+1))/256.0);
1022 int bf = (int)(((float)c.blue() * (x->scmap.blue_max+1))/256.0);
1023 uint p = x->scmap.base_pixel
1024 + (rf * x->scmap.red_mult)
1025 + (gf * x->scmap.green_mult)
1026 + (bf * x->scmap.blue_mult);
1027 return p;
1028 } else {
1029 QMap<int, QRgb> &cmap = (*cmap_handler()->qglcmap_hash)[(long)info->visualid];
1030
1031 // already in the map?
1032 QRgb target = c.rgb();
1033 QMap<int, QRgb>::Iterator it = cmap.begin();
1034 for (; it != cmap.end(); ++it) {
1035 if ((*it) == target)
1036 return it.key();
1037 }
1038
1039 // need to alloc color
1040 unsigned long plane_mask[2];
1041 unsigned long color_map_entry;
1042 if (!XAllocColorCells (QX11Info::display(), x->cmap, true, plane_mask, 0,
1043 &color_map_entry, 1))
1044 return colmap.pixel(c);
1045
1046 XColor col;
1047 col.flags = DoRed | DoGreen | DoBlue;
1048 col.pixel = color_map_entry;
1049 col.red = (ushort)((qRed(c.rgb()) / 255.0) * 65535.0 + 0.5);
1050 col.green = (ushort)((qGreen(c.rgb()) / 255.0) * 65535.0 + 0.5);
1051 col.blue = (ushort)((qBlue(c.rgb()) / 255.0) * 65535.0 + 0.5);
1052 XStoreColor(QX11Info::display(), x->cmap, &col);
1053
1054 cmap.insert(color_map_entry, target);
1055 return color_map_entry;
1056 }
1057 }
1058 return 0;
1059}
1060
1061#ifndef QT_NO_FONTCONFIG
1062/*! \internal
1063 This is basically a substitute for glxUseXFont() which can only
1064 handle XLFD fonts. This version relies on freetype to render the
1065 glyphs, but it works with all fonts that fontconfig provides - both
1066 antialiased and aliased bitmap and outline fonts.
1067*/
1068static void qgl_use_font(QFontEngineFT *engine, int first, int count, int listBase)
1069{
1070 GLfloat color[4];
1071 glGetFloatv(GL_CURRENT_COLOR, color);
1072
1073 // save the pixel unpack state
1074 GLint gl_swapbytes, gl_lsbfirst, gl_rowlength, gl_skiprows, gl_skippixels, gl_alignment;
1075 glGetIntegerv (GL_UNPACK_SWAP_BYTES, &gl_swapbytes);
1076 glGetIntegerv (GL_UNPACK_LSB_FIRST, &gl_lsbfirst);
1077 glGetIntegerv (GL_UNPACK_ROW_LENGTH, &gl_rowlength);
1078 glGetIntegerv (GL_UNPACK_SKIP_ROWS, &gl_skiprows);
1079 glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &gl_skippixels);
1080 glGetIntegerv (GL_UNPACK_ALIGNMENT, &gl_alignment);
1081
1082 glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
1083 glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
1084 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1085 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
1086 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
1087 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1088
1089 const bool antialiased = engine->drawAntialiased();
1090 FT_Face face = engine->lockFace();
1091
1092 // start generating font glyphs
1093 for (int i = first; i < count; ++i) {
1094 int list = listBase + i;
1095 GLfloat x0, y0, dx, dy;
1096
1097 FT_Error err;
1098
1099 err = FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT);
1100 if (err) {
1101 qDebug("failed loading glyph %d from font", i);
1102 Q_ASSERT(!err);
1103 }
1104 err = FT_Render_Glyph(face->glyph, (antialiased ? FT_RENDER_MODE_NORMAL
1105 : FT_RENDER_MODE_MONO));
1106 if (err) {
1107 qDebug("failed rendering glyph %d from font", i);
1108 Q_ASSERT(!err);
1109 }
1110
1111 FT_Bitmap bm = face->glyph->bitmap;
1112 x0 = face->glyph->metrics.horiBearingX >> 6;
1113 y0 = (face->glyph->metrics.height - face->glyph->metrics.horiBearingY) >> 6;
1114 dx = face->glyph->metrics.horiAdvance >> 6;
1115 dy = 0;
1116 int sz = bm.pitch * bm.rows;
1117 uint *aa_glyph = 0;
1118 uchar *ua_glyph = 0;
1119
1120 if (antialiased)
1121 aa_glyph = new uint[sz];
1122 else
1123 ua_glyph = new uchar[sz];
1124
1125 // convert to GL format
1126 for (int y = 0; y < bm.rows; ++y) {
1127 for (int x = 0; x < bm.pitch; ++x) {
1128 int c1 = y*bm.pitch + x;
1129 int c2 = (bm.rows - y - 1) > 0 ? (bm.rows-y-1)*bm.pitch + x : x;
1130 if (antialiased) {
1131 aa_glyph[c1] = (int(color[0]*255) << 24)
1132 | (int(color[1]*255) << 16)
1133 | (int(color[2]*255) << 8) | bm.buffer[c2];
1134 } else {
1135 ua_glyph[c1] = bm.buffer[c2];
1136 }
1137 }
1138 }
1139
1140 glNewList(list, GL_COMPILE);
1141 if (antialiased) {
1142 // calling glBitmap() is just a trick to move the current
1143 // raster pos, since glGet*() won't work in display lists
1144 glBitmap(0, 0, 0, 0, x0, -y0, 0);
1145 glDrawPixels(bm.pitch, bm.rows, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, aa_glyph);
1146 glBitmap(0, 0, 0, 0, dx-x0, y0, 0);
1147 } else {
1148 glBitmap(bm.pitch*8, bm.rows, -x0, y0, dx, dy, ua_glyph);
1149 }
1150 glEndList();
1151 antialiased ? delete[] aa_glyph : delete[] ua_glyph;
1152 }
1153
1154 engine->unlockFace();
1155
1156 // restore pixel unpack settings
1157 glPixelStorei(GL_UNPACK_SWAP_BYTES, gl_swapbytes);
1158 glPixelStorei(GL_UNPACK_LSB_FIRST, gl_lsbfirst);
1159 glPixelStorei(GL_UNPACK_ROW_LENGTH, gl_rowlength);
1160 glPixelStorei(GL_UNPACK_SKIP_ROWS, gl_skiprows);
1161 glPixelStorei(GL_UNPACK_SKIP_PIXELS, gl_skippixels);
1162 glPixelStorei(GL_UNPACK_ALIGNMENT, gl_alignment);
1163}
1164#endif
1165
1166#undef d
1167void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
1168{
1169 QFont f(fnt);
1170 QFontEngine *engine = f.d->engineForScript(QUnicodeTables::Common);
1171
1172 if (engine->type() == QFontEngine::Multi)
1173 engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
1174#ifndef QT_NO_FONTCONFIG
1175 if(engine->type() == QFontEngine::Freetype) {
1176 qgl_use_font(static_cast<QFontEngineFT *>(engine), 0, 256, listBase);
1177 return;
1178 }
1179#endif
1180 // glXUseXFont() only works with XLFD font structures and a few GL
1181 // drivers crash if 0 is passed as the font handle
1182 f.setStyleStrategy(QFont::OpenGLCompatible);
1183 if (f.handle() && engine->type() == QFontEngine::XLFD)
1184 glXUseXFont(static_cast<Font>(f.handle()), 0, 256, listBase);
1185}
1186
1187void *QGLContext::getProcAddress(const QString &proc) const
1188{
1189 typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *);
1190 static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
1191 static bool resolved = false;
1192
1193 if (resolved && !glXGetProcAddressARB)
1194 return 0;
1195 if (!glXGetProcAddressARB) {
1196 QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
1197 if (extensions.match("GLX_ARB_get_proc_address")) {
1198#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
1199 void *handle = dlopen(NULL, RTLD_LAZY);
1200 if (handle) {
1201 glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB");
1202 dlclose(handle);
1203 }
1204 if (!glXGetProcAddressARB)
1205#endif
1206 {
1207#if !defined(QT_NO_LIBRARY)
1208 extern const QString qt_gl_library_name();
1209 QLibrary lib(qt_gl_library_name());
1210 glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
1211#endif
1212 }
1213 }
1214 resolved = true;
1215 }
1216 if (!glXGetProcAddressARB)
1217 return 0;
1218 return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(proc.toLatin1().data()));
1219}
1220
1221/*
1222 QGLTemporaryContext implementation
1223*/
1224
1225class QGLTemporaryContextPrivate {
1226public:
1227 bool initialized;
1228 Window drawable;
1229 GLXContext context;
1230 GLXDrawable oldDrawable;
1231 GLXContext oldContext;
1232};
1233
1234QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
1235 : d(new QGLTemporaryContextPrivate)
1236{
1237 d->initialized = false;
1238 d->oldDrawable = 0;
1239 d->oldContext = 0;
1240 int screen = 0;
1241
1242 int attribs[] = {GLX_RGBA, XNone};
1243 XVisualInfo *vi = glXChooseVisual(X11->display, screen, attribs);
1244 if (!vi) {
1245 qWarning("QGLTempContext: No GL capable X visuals available.");
1246 return;
1247 }
1248
1249 int useGL;
1250 glXGetConfig(X11->display, vi, GLX_USE_GL, &useGL);
1251 if (!useGL) {
1252 XFree(vi);
1253 return;
1254 }
1255
1256 d->oldDrawable = glXGetCurrentDrawable();
1257 d->oldContext = glXGetCurrentContext();
1258
1259 XSetWindowAttributes a;
1260 a.colormap = qt_gl_choose_cmap(X11->display, vi);
1261 d->drawable = XCreateWindow(X11->display, RootWindow(X11->display, screen),
1262 0, 0, 1, 1, 0,
1263 vi->depth, InputOutput, vi->visual,
1264 CWColormap, &a);
1265 d->context = glXCreateContext(X11->display, vi, 0, True);
1266 if (d->context && glXMakeCurrent(X11->display, d->drawable, d->context)) {
1267 d->initialized = true;
1268 } else {
1269 qWarning("QGLTempContext: Unable to create GL context.");
1270 XDestroyWindow(X11->display, d->drawable);
1271 }
1272 XFree(vi);
1273}
1274
1275QGLTemporaryContext::~QGLTemporaryContext()
1276{
1277 if (d->initialized) {
1278 glXMakeCurrent(X11->display, 0, 0);
1279 glXDestroyContext(X11->display, d->context);
1280 XDestroyWindow(X11->display, d->drawable);
1281 }
1282 if (d->oldDrawable && d->oldContext)
1283 glXMakeCurrent(X11->display, d->oldDrawable, d->oldContext);
1284}
1285
1286/*****************************************************************************
1287 QGLOverlayWidget (Internal overlay class for X11)
1288 *****************************************************************************/
1289
1290class QGLOverlayWidget : public QGLWidget
1291{
1292 Q_OBJECT
1293public:
1294 QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent, const QGLWidget* shareWidget=0);
1295
1296protected:
1297 void initializeGL();
1298 void paintGL();
1299 void resizeGL(int w, int h);
1300 bool x11Event(XEvent *e) { return realWidget->x11Event(e); }
1301
1302private:
1303 QGLWidget* realWidget;
1304
1305private:
1306 Q_DISABLE_COPY(QGLOverlayWidget)
1307};
1308
1309
1310QGLOverlayWidget::QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent,
1311 const QGLWidget* shareWidget)
1312 : QGLWidget(format, parent, shareWidget ? shareWidget->d_func()->olw : 0)
1313{
1314 setAttribute(Qt::WA_X11OpenGLOverlay);
1315 realWidget = parent;
1316}
1317
1318
1319
1320void QGLOverlayWidget::initializeGL()
1321{
1322 QColor transparentColor = context()->overlayTransparentColor();
1323 if (transparentColor.isValid())
1324 qglClearColor(transparentColor);
1325 else
1326 qWarning("QGLOverlayWidget::initializeGL(): Could not get transparent color");
1327 realWidget->initializeOverlayGL();
1328}
1329
1330
1331void QGLOverlayWidget::resizeGL(int w, int h)
1332{
1333 glViewport(0, 0, w, h);
1334 realWidget->resizeOverlayGL(w, h);
1335}
1336
1337
1338void QGLOverlayWidget::paintGL()
1339{
1340 realWidget->paintOverlayGL();
1341}
1342
1343#undef Bool
1344QT_BEGIN_INCLUDE_NAMESPACE
1345#include "qgl_x11.moc"
1346QT_END_INCLUDE_NAMESPACE
1347
1348/*****************************************************************************
1349 QGLWidget UNIX/GLX-specific code
1350 *****************************************************************************/
1351void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
1352{
1353 Q_Q(QGLWidget);
1354 initContext(context, shareWidget);
1355 olw = 0;
1356
1357 if (q->isValid() && context->format().hasOverlay()) {
1358 QString olwName = q->objectName();
1359 olwName += QLatin1String("-QGL_internal_overlay_widget");
1360 olw = new QGLOverlayWidget(QGLFormat::defaultOverlayFormat(), q, shareWidget);
1361 olw->setObjectName(olwName);
1362 if (olw->isValid()) {
1363 olw->setAutoBufferSwap(false);
1364 olw->setFocusProxy(q);
1365 }
1366 else {
1367 delete olw;
1368 olw = 0;
1369 glcx->d_func()->glFormat.setOverlay(false);
1370 }
1371 }
1372}
1373
1374bool QGLWidgetPrivate::renderCxPm(QPixmap* pm)
1375{
1376 Q_Q(QGLWidget);
1377 if (((XVisualInfo*)glcx->d_func()->vi)->depth != pm->depth())
1378 return false;
1379
1380 GLXPixmap glPm;
1381#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT)
1382 glPm = glXCreateGLXPixmapMESA(X11->display,
1383 (XVisualInfo*)glcx->vi,
1384 (Pixmap)pm->handle(),
1385 qt_gl_choose_cmap(pm->X11->display,
1386 (XVisualInfo*)glcx->vi));
1387#else
1388 glPm = (quint32)glXCreateGLXPixmap(X11->display,
1389 (XVisualInfo*)glcx->d_func()->vi,
1390 (Pixmap)pm->handle());
1391#endif
1392
1393 if (!glXMakeCurrent(X11->display, glPm, (GLXContext)glcx->d_func()->cx)) {
1394 glXDestroyGLXPixmap(X11->display, glPm);
1395 return false;
1396 }
1397
1398 glDrawBuffer(GL_FRONT);
1399 if (!glcx->initialized())
1400 q->glInit();
1401 q->resizeGL(pm->width(), pm->height());
1402 q->paintGL();
1403 glFlush();
1404 q->makeCurrent();
1405 glXDestroyGLXPixmap(X11->display, glPm);
1406 q->resizeGL(q->width(), q->height());
1407 return true;
1408}
1409
1410/*! \internal
1411 Free up any allocated colormaps. This fn is only called for
1412 top-level widgets.
1413*/
1414void QGLWidgetPrivate::cleanupColormaps()
1415{
1416 if (!cmap.handle()) {
1417 return;
1418 } else {
1419 XFreeColormap(X11->display, (Colormap) cmap.handle());
1420 cmap.setHandle(0);
1421 }
1422}
1423
1424void QGLWidget::setMouseTracking(bool enable)
1425{
1426 Q_D(QGLWidget);
1427 if (d->olw)
1428 d->olw->setMouseTracking(enable);
1429 QWidget::setMouseTracking(enable);
1430}
1431
1432
1433void QGLWidget::resizeEvent(QResizeEvent *)
1434{
1435 Q_D(QGLWidget);
1436 if (!isValid())
1437 return;
1438 makeCurrent();
1439 if (!d->glcx->initialized())
1440 glInit();
1441 glXWaitX();
1442 resizeGL(width(), height());
1443 if (d->olw)
1444 d->olw->setGeometry(rect());
1445}
1446
1447const QGLContext* QGLWidget::overlayContext() const
1448{
1449 Q_D(const QGLWidget);
1450 if (d->olw)
1451 return d->olw->context();
1452 else
1453 return 0;
1454}
1455
1456
1457void QGLWidget::makeOverlayCurrent()
1458{
1459 Q_D(QGLWidget);
1460 if (d->olw)
1461 d->olw->makeCurrent();
1462}
1463
1464
1465void QGLWidget::updateOverlayGL()
1466{
1467 Q_D(QGLWidget);
1468 if (d->olw)
1469 d->olw->updateGL();
1470}
1471
1472/*!
1473 \internal
1474
1475 Sets a new QGLContext, \a context, for this QGLWidget, using the
1476 shared context, \a shareContext. If \a deleteOldContext is true,
1477 the original context is deleted; otherwise it is overridden.
1478*/
1479void QGLWidget::setContext(QGLContext *context,
1480 const QGLContext* shareContext,
1481 bool deleteOldContext)
1482{
1483 Q_D(QGLWidget);
1484 if (context == 0) {
1485 qWarning("QGLWidget::setContext: Cannot set null context");
1486 return;
1487 }
1488 if (!context->deviceIsPixmap() && context->device() != this) {
1489 qWarning("QGLWidget::setContext: Context must refer to this widget");
1490 return;
1491 }
1492
1493 if (d->glcx)
1494 d->glcx->doneCurrent();
1495 QGLContext* oldcx = d->glcx;
1496 d->glcx = context;
1497
1498 if (parentWidget()) {
1499 // force creation of delay-created widgets
1500 parentWidget()->winId();
1501 if (parentWidget()->x11Info().screen() != x11Info().screen())
1502 d_func()->xinfo = parentWidget()->d_func()->xinfo;
1503 }
1504
1505 // If the application has set WA_TranslucentBackground and not explicitly set
1506 // the alpha buffer size to zero, modify the format so it have an alpha channel
1507 QGLFormat& fmt = d->glcx->d_func()->glFormat;
1508 if (testAttribute(Qt::WA_TranslucentBackground) && fmt.alphaBufferSize() == -1)
1509 fmt.setAlphaBufferSize(1);
1510
1511 bool createFailed = false;
1512 if (!d->glcx->isValid()) {
1513 if (!d->glcx->create(shareContext ? shareContext : oldcx))
1514 createFailed = true;
1515 }
1516 if (createFailed) {
1517 if (deleteOldContext)
1518 delete oldcx;
1519 return;
1520 }
1521
1522 if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
1523 if (deleteOldContext)
1524 delete oldcx;
1525 return;
1526 }
1527
1528 bool visible = isVisible();
1529 if (visible)
1530 hide();
1531
1532 XVisualInfo *vi = (XVisualInfo*)d->glcx->d_func()->vi;
1533 XSetWindowAttributes a;
1534
1535 QColormap colmap = QColormap::instance(vi->screen);
1536 a.colormap = qt_gl_choose_cmap(QX11Info::display(), vi); // find best colormap
1537 a.background_pixel = colmap.pixel(palette().color(backgroundRole()));
1538 a.border_pixel = colmap.pixel(Qt::black);
1539 Window p = RootWindow(X11->display, vi->screen);
1540 if (parentWidget())
1541 p = parentWidget()->winId();
1542
1543 Window w = XCreateWindow(X11->display, p, x(), y(), width(), height(),
1544 0, vi->depth, InputOutput, vi->visual,
1545 CWBackPixel|CWBorderPixel|CWColormap, &a);
1546 Window *cmw;
1547 Window *cmwret;
1548 int count;
1549 if (XGetWMColormapWindows(X11->display, window()->winId(),
1550 &cmwret, &count)) {
1551 cmw = new Window[count+1];
1552 memcpy((char *)cmw, (char *)cmwret, sizeof(Window)*count);
1553 XFree((char *)cmwret);
1554 int i;
1555 for (i=0; i<count; i++) {
1556 if (cmw[i] == winId()) { // replace old window
1557 cmw[i] = w;
1558 break;
1559 }
1560 }
1561 if (i >= count) // append new window
1562 cmw[count++] = w;
1563 } else {
1564 count = 1;
1565 cmw = new Window[count];
1566 cmw[0] = w;
1567 }
1568
1569#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT)
1570 if (oldcx && oldcx->windowCreated())
1571 glXReleaseBuffersMESA(X11->display, winId());
1572#endif
1573 if (deleteOldContext)
1574 delete oldcx;
1575 oldcx = 0;
1576
1577 if (testAttribute(Qt::WA_WState_Created))
1578 create(w);
1579 else
1580 d->createWinId(w);
1581 XSetWMColormapWindows(X11->display, window()->winId(), cmw, count);
1582 delete [] cmw;
1583
1584 // calling QWidget::create() will always result in a new paint
1585 // engine being created - get rid of it and replace it with our
1586 // own
1587
1588 if (visible)
1589 show();
1590 XFlush(X11->display);
1591 d->glcx->setWindowCreated(true);
1592}
1593
1594const QGLColormap & QGLWidget::colormap() const
1595{
1596 Q_D(const QGLWidget);
1597 return d->cmap;
1598}
1599
1600/*\internal
1601 Store color values in the given colormap.
1602*/
1603static void qStoreColors(QWidget * tlw, Colormap cmap,
1604 const QGLColormap & cols)
1605{
1606 Q_UNUSED(tlw);
1607 XColor c;
1608 QRgb color;
1609
1610 for (int i = 0; i < cols.size(); i++) {
1611 color = cols.entryRgb(i);
1612 c.pixel = i;
1613 c.red = (ushort)((qRed(color) / 255.0) * 65535.0 + 0.5);
1614 c.green = (ushort)((qGreen(color) / 255.0) * 65535.0 + 0.5);
1615 c.blue = (ushort)((qBlue(color) / 255.0) * 65535.0 + 0.5);
1616 c.flags = DoRed | DoGreen | DoBlue;
1617 XStoreColor(X11->display, cmap, &c);
1618 }
1619}
1620
1621/*\internal
1622 Check whether the given visual supports dynamic colormaps or not.
1623*/
1624static bool qCanAllocColors(QWidget * w)
1625{
1626 bool validVisual = false;
1627 int numVisuals;
1628 long mask;
1629 XVisualInfo templ;
1630 XVisualInfo * visuals;
1631 VisualID id = XVisualIDFromVisual((Visual *) w->window()->x11Info().visual());
1632
1633 mask = VisualScreenMask;
1634 templ.screen = w->x11Info().screen();
1635 visuals = XGetVisualInfo(X11->display, mask, &templ, &numVisuals);
1636
1637 for (int i = 0; i < numVisuals; i++) {
1638 if (visuals[i].visualid == id) {
1639 switch (visuals[i].c_class) {
1640 case TrueColor:
1641 case StaticColor:
1642 case StaticGray:
1643 case XGrayScale:
1644 validVisual = false;
1645 break;
1646 case DirectColor:
1647 case PseudoColor:
1648 validVisual = true;
1649 break;
1650 }
1651 break;
1652 }
1653 }
1654 XFree(visuals);
1655
1656 if (!validVisual)
1657 return false;
1658 return true;
1659}
1660
1661
1662void QGLWidget::setColormap(const QGLColormap & c)
1663{
1664 Q_D(QGLWidget);
1665 QWidget * tlw = window(); // must return a valid widget
1666
1667 d->cmap = c;
1668 if (!d->cmap.handle())
1669 return;
1670
1671 if (!qCanAllocColors(this)) {
1672 qWarning("QGLWidget::setColormap: Cannot create a read/write "
1673 "colormap for this visual");
1674 return;
1675 }
1676
1677 // If the child GL widget is not of the same visual class as the
1678 // toplevel widget we will get in trouble..
1679 Window wid = tlw->winId();
1680 Visual * vis = (Visual *) tlw->x11Info().visual();;
1681 VisualID cvId = XVisualIDFromVisual((Visual *) x11Info().visual());
1682 VisualID tvId = XVisualIDFromVisual((Visual *) tlw->x11Info().visual());
1683 if (cvId != tvId) {
1684 wid = winId();
1685 vis = (Visual *) x11Info().visual();
1686 }
1687
1688 if (!d->cmap.handle()) // allocate a cmap if necessary
1689 d->cmap.setHandle(XCreateColormap(X11->display, wid, vis, AllocAll));
1690
1691 qStoreColors(this, (Colormap) d->cmap.handle(), c);
1692 XSetWindowColormap(X11->display, wid, (Colormap) d->cmap.handle());
1693
1694 // tell the wm that this window has a special colormap
1695 Window * cmw;
1696 Window * cmwret;
1697 int count;
1698 if (XGetWMColormapWindows(X11->display, tlw->winId(), &cmwret, &count))
1699 {
1700 cmw = new Window[count+1];
1701 memcpy((char *) cmw, (char *) cmwret, sizeof(Window) * count);
1702 XFree((char *) cmwret);
1703 int i;
1704 for (i = 0; i < count; i++) {
1705 if (cmw[i] == winId()) {
1706 break;
1707 }
1708 }
1709 if (i >= count) // append new window only if not in the list
1710 cmw[count++] = winId();
1711 } else {
1712 count = 1;
1713 cmw = new Window[count];
1714 cmw[0] = winId();
1715 }
1716 XSetWMColormapWindows(X11->display, tlw->winId(), cmw, count);
1717 delete [] cmw;
1718}
1719
1720// Solaris defines glXBindTexImageEXT as part of the GL library
1721#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
1722typedef void (*qt_glXBindTexImageEXT)(Display*, GLXDrawable, int, const int*);
1723typedef void (*qt_glXReleaseTexImageEXT)(Display*, GLXDrawable, int);
1724static qt_glXBindTexImageEXT glXBindTexImageEXT = 0;
1725static qt_glXReleaseTexImageEXT glXReleaseTexImageEXT = 0;
1726
1727static bool qt_resolveTextureFromPixmap(QPaintDevice *paintDevice)
1728{
1729 static bool resolvedTextureFromPixmap = false;
1730
1731 if (!resolvedTextureFromPixmap) {
1732 resolvedTextureFromPixmap = true;
1733
1734 // Check to see if we have NPOT texture support
1735 if ( !(QGLExtensions::glExtensions() & QGLExtensions::NPOTTextures) &&
1736 !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0))
1737 {
1738 return false; // Can't use TFP without NPOT
1739 }
1740
1741 const QX11Info *xinfo = qt_x11Info(paintDevice);
1742 Display *display = xinfo ? xinfo->display() : X11->display;
1743 int screen = xinfo ? xinfo->screen() : X11->defaultScreen;
1744
1745 QGLExtensionMatcher serverExtensions(glXQueryExtensionsString(display, screen));
1746 QGLExtensionMatcher clientExtensions(glXGetClientString(display, GLX_EXTENSIONS));
1747 if (serverExtensions.match("GLX_EXT_texture_from_pixmap")
1748 && clientExtensions.match("GLX_EXT_texture_from_pixmap"))
1749 {
1750 glXBindTexImageEXT = (qt_glXBindTexImageEXT) qglx_getProcAddress("glXBindTexImageEXT");
1751 glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) qglx_getProcAddress("glXReleaseTexImageEXT");
1752 }
1753 }
1754
1755 return glXBindTexImageEXT && glXReleaseTexImageEXT;
1756}
1757#endif //defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
1758
1759
1760QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key,
1761 QGLContext::BindOptions options)
1762{
1763#if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
1764 return 0;
1765#else
1766
1767 // Check we have GLX 1.3, as it is needed for glXCreatePixmap & glXDestroyPixmap
1768 int majorVersion = 0;
1769 int minorVersion = 0;
1770 glXQueryVersion(X11->display, &majorVersion, &minorVersion);
1771 if (majorVersion < 1 || (majorVersion == 1 && minorVersion < 3))
1772 return 0;
1773
1774 Q_Q(QGLContext);
1775
1776 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data());
1777 Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
1778
1779 // We can't use TFP if the pixmap has a separate X11 mask
1780 if (pixmapData->x11_mask)
1781 return 0;
1782
1783 if (!qt_resolveTextureFromPixmap(paintDevice))
1784 return 0;
1785
1786 const QX11Info &x11Info = pixmapData->xinfo;
1787
1788 // Store the configs (Can be static because configs aren't dependent on current context)
1789 static GLXFBConfig glxRGBPixmapConfig = 0;
1790 static bool RGBConfigInverted = false;
1791 static GLXFBConfig glxRGBAPixmapConfig = 0;
1792 static bool RGBAConfigInverted = false;
1793
1794 bool hasAlpha = pixmapData->hasAlphaChannel();
1795
1796 // Check to see if we need a config
1797 if ( (hasAlpha && !glxRGBAPixmapConfig) || (!hasAlpha && !glxRGBPixmapConfig) ) {
1798 GLXFBConfig *configList = 0;
1799 int configCount = 0;
1800
1801 int configAttribs[] = {
1802 hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True,
1803 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
1804 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
1805 // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can:
1806 GLX_Y_INVERTED_EXT, options & QGLContext::CanFlipNativePixmapBindOption ? GLX_DONT_CARE : False,
1807 XNone
1808 };
1809 configList = glXChooseFBConfig(x11Info.display(), x11Info.screen(), configAttribs, &configCount);
1810 if (!configList)
1811 return 0;
1812
1813 int yInv;
1814 glXGetFBConfigAttrib(x11Info.display(), configList[0], GLX_Y_INVERTED_EXT, &yInv);
1815
1816 if (hasAlpha) {
1817 glxRGBAPixmapConfig = configList[0];
1818 RGBAConfigInverted = yInv;
1819 }
1820 else {
1821 glxRGBPixmapConfig = configList[0];
1822 RGBConfigInverted = yInv;
1823 }
1824
1825 XFree(configList);
1826 }
1827
1828 // Check to see if the surface is still valid
1829 if (pixmapData->gl_surface &&
1830 hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
1831 {
1832 // Surface is invalid!
1833 destroyGlSurfaceForPixmap(pixmapData);
1834 }
1835
1836 // Check to see if we need a surface
1837 if (!pixmapData->gl_surface) {
1838 GLXPixmap glxPixmap;
1839 int pixmapAttribs[] = {
1840 GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
1841 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
1842 GLX_MIPMAP_TEXTURE_EXT, False, // Maybe needs to be don't care
1843 XNone
1844 };
1845
1846 // Wrap the X Pixmap into a GLXPixmap:
1847 glxPixmap = glXCreatePixmap(x11Info.display(),
1848 hasAlpha ? glxRGBAPixmapConfig : glxRGBPixmapConfig,
1849 pixmapData->handle(), pixmapAttribs);
1850
1851 if (!glxPixmap)
1852 return 0;
1853
1854 pixmapData->gl_surface = (void*)glxPixmap;
1855
1856 // Make sure the cleanup hook gets called so we can delete the glx pixmap
1857 QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData);
1858 }
1859
1860 GLuint textureId;
1861 glGenTextures(1, &textureId);
1862 glBindTexture(GL_TEXTURE_2D, textureId);
1863 glXBindTexImageEXT(x11Info.display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT, 0);
1864
1865 glBindTexture(GL_TEXTURE_2D, textureId);
1866 GLuint filtering = (options & QGLContext::LinearFilteringBindOption) ? GL_LINEAR : GL_NEAREST;
1867 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
1868 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
1869
1870 if (!((hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted)))
1871 options &= ~QGLContext::InvertedYBindOption;
1872
1873 QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
1874 if (texture->options & QGLContext::InvertedYBindOption)
1875 pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
1876
1877 // We assume the cost of bound pixmaps is zero
1878 QGLTextureCache::instance()->insert(q, key, texture, 0);
1879
1880 return texture;
1881#endif //!defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
1882}
1883
1884
1885void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
1886{
1887#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
1888 Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
1889 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
1890 if (pixmapData->gl_surface) {
1891 glXDestroyPixmap(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface);
1892 pixmapData->gl_surface = 0;
1893 }
1894#endif
1895}
1896
1897void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
1898{
1899#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
1900 Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
1901 Q_ASSERT(QGLContext::currentContext());
1902 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
1903 if (pixmapData->gl_surface)
1904 glXReleaseTexImageEXT(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT);
1905#endif
1906}
1907
1908QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.