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