📄 qgl_x11.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtOpenGL module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qgl.h"#include "qgl_p.h"#include "qmap.h"#include "qapplication.h"#include "qcolormap.h"#include "qdesktopwidget.h"#include "qpixmap.h"#include "qhash.h"#include "qlibrary.h"#include "qdebug.h"#include <private/qfontengine_ft_p.h>#include <private/qt_x11_p.h>#ifdef Q_OS_HPUX// for GLXPBuffer#include <private/qglpixelbuffer_p.h>#endif#define INT8 dummy_INT8#define INT32 dummy_INT32#include <GL/glx.h>#undef INT8#undef INT32#include <X11/Xlib.h>#include <X11/Xutil.h>#include <X11/Xos.h>#include <X11/Xatom.h>extern Drawable qt_x11Handle(const QPaintDevice *pd);extern const QX11Info *qt_x11Info(const QPaintDevice *pd);#ifndef GLX_ARB_multisample#define GLX_SAMPLE_BUFFERS_ARB 100000#define GLX_SAMPLES_ARB 100001#endif/* The choose_cmap function is internal and used by QGLWidget::setContext() and GLX (not Windows). If the application can't find any sharable colormaps, it must at least create as few colormaps as possible. The dictionary solution below ensures only one colormap is created per visual. Colormaps are also deleted when the application terminates.*/struct QCMapEntry { QCMapEntry(); ~QCMapEntry(); Colormap cmap; bool alloc; XStandardColormap scmap;};QCMapEntry::QCMapEntry(){ cmap = 0; alloc = false; scmap.colormap = 0;}QCMapEntry::~QCMapEntry(){ if (alloc) XFreeColormap(X11->display, cmap);}typedef QHash<int, QCMapEntry *> CMapEntryHash;typedef QHash<int, QMap<int, QRgb> > GLCMapHash;static bool mesa_gl = false;static bool first_time = true;static void cleanup_cmaps();struct QGLCMapCleanupHandler { QGLCMapCleanupHandler() { cmap_hash = new CMapEntryHash; qglcmap_hash = new GLCMapHash; cleaned_up = false; qAddPostRoutine(cleanup_cmaps); } ~QGLCMapCleanupHandler() { qRemovePostRoutine(cleanup_cmaps); cleanup_cmaps(); delete cmap_hash; delete qglcmap_hash; } CMapEntryHash *cmap_hash; GLCMapHash *qglcmap_hash; bool cleaned_up;};Q_GLOBAL_STATIC(QGLCMapCleanupHandler, cmap_handler);static void cleanup_cmaps(){ if (!cmap_handler()->cleaned_up) { CMapEntryHash *hash = cmap_handler()->cmap_hash; QHash<int, QCMapEntry *>::ConstIterator it = hash->constBegin(); while (it != hash->constEnd()) { delete it.value(); ++it; } hash->clear(); cmap_handler()->cleaned_up = true; }}static Colormap choose_cmap(Display *dpy, XVisualInfo *vi){ if (first_time) { const char *v = glXQueryServerString(dpy, vi->screen, GLX_VERSION); if (v) mesa_gl = (strstr(v, "Mesa") != 0); first_time = false; } CMapEntryHash *hash = cmap_handler()->cmap_hash; CMapEntryHash::ConstIterator it = hash->constFind((long) vi->visualid + (vi->screen * 256)); if (it != hash->constEnd()) return it.value()->cmap; // found colormap for visual if (vi->visualid == XVisualIDFromVisual((Visual *) QX11Info::appVisual(vi->screen))) { // qDebug("Using x11AppColormap"); return QX11Info::appColormap(vi->screen); } QCMapEntry *x = new QCMapEntry(); XStandardColormap *c; int n, i; // qDebug("Choosing cmap for vID %0x", vi->visualid); if (mesa_gl) { // we're using MesaGL Atom hp_cmaps = XInternAtom(dpy, "_HP_RGB_SMOOTH_MAP_LIST", true); if (hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8) { if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n, hp_cmaps)) { i = 0; while (i < n && x->cmap == 0) { if (c[i].visualid == vi->visual->visualid) { x->cmap = c[i].colormap; x->scmap = c[i]; //qDebug("Using HP_RGB scmap"); } i++; } XFree((char *)c); } } } if (!x->cmap) { if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n, XA_RGB_DEFAULT_MAP)) { for (int i = 0; i < n && x->cmap == 0; ++i) { if (!c[i].red_max || !c[i].green_max || !c[i].blue_max || !c[i].red_mult || !c[i].green_mult || !c[i].blue_mult) continue; // invalid stdcmap if (c[i].visualid == vi->visualid) { x->cmap = c[i].colormap; x->scmap = c[i]; //qDebug("Using RGB_DEFAULT scmap"); } } XFree((char *)c); } } if (!x->cmap) { // no shared cmap found x->cmap = XCreateColormap(dpy, RootWindow(dpy,vi->screen), vi->visual, AllocNone); x->alloc = true; // qDebug("Allocating cmap"); } // associate cmap with visualid hash->insert((long) vi->visualid + (vi->screen * 256), x); return x->cmap;}struct QTransColor{ VisualID vis; int screen; long color;};static QVector<QTransColor> trans_colors;static int trans_colors_init = false;static void find_trans_colors(){ struct OverlayProp { long visual; long type; long value; long layer; }; trans_colors_init = true; Display* appDisplay = X11->display; int scr; int lastsize = 0; for (scr = 0; scr < ScreenCount(appDisplay); scr++) { QWidget* rootWin = QApplication::desktop()->screen(scr); if (!rootWin) return; // Should not happen Atom overlayVisualsAtom = XInternAtom(appDisplay, "SERVER_OVERLAY_VISUALS", True); if (overlayVisualsAtom == XNone) return; // Server has no overlays Atom actualType; int actualFormat; ulong nItems; ulong bytesAfter; unsigned char *retval = 0; int res = XGetWindowProperty(appDisplay, rootWin->winId(), overlayVisualsAtom, 0, 10000, False, overlayVisualsAtom, &actualType, &actualFormat, &nItems, &bytesAfter, &retval); if (res != Success || actualType != overlayVisualsAtom || actualFormat != 32 || nItems < 4 || !retval) return; // Error reading property OverlayProp *overlayProps = (OverlayProp *)retval; int numProps = nItems / 4; trans_colors.resize(lastsize + numProps); int j = lastsize; for (int i = 0; i < numProps; i++) { if (overlayProps[i].type == 1) { trans_colors[j].vis = (VisualID)overlayProps[i].visual; trans_colors[j].screen = scr; trans_colors[j].color = (int)overlayProps[i].value; j++; } } XFree(overlayProps); lastsize = j; trans_colors.resize(lastsize); }}/***************************************************************************** QGLFormat UNIX/GLX-specific code *****************************************************************************/bool QGLFormat::hasOpenGL(){ return glXQueryExtension(X11->display, 0, 0) != 0;}bool QGLFormat::hasOpenGLOverlays(){ if (!trans_colors_init) find_trans_colors(); return trans_colors.size() > 0;}/***************************************************************************** QGLContext UNIX/GLX-specific code *****************************************************************************/bool QGLContext::chooseContext(const QGLContext* shareContext){ Q_D(QGLContext); const QX11Info *xinfo = qt_x11Info(d->paintDevice); Display* disp = xinfo->display(); d->vi = chooseVisual(); if (!d->vi) return false; if (deviceIsPixmap() && (((XVisualInfo*)d->vi)->depth != xinfo->depth() || ((XVisualInfo*)d->vi)->screen != xinfo->screen())) { XFree(d->vi); XVisualInfo appVisInfo; memset(&appVisInfo, 0, sizeof(XVisualInfo)); appVisInfo.visualid = XVisualIDFromVisual((Visual *) xinfo->visual()); appVisInfo.screen = xinfo->screen(); int nvis; d->vi = XGetVisualInfo(disp, VisualIDMask | VisualScreenMask, &appVisInfo, &nvis); if (!d->vi) return false; int useGL; glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_USE_GL, &useGL); if (!useGL) return false; //# Chickening out already... } int res; glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_LEVEL, &res); d->glFormat.setPlane(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DOUBLEBUFFER, &res); d->glFormat.setDoubleBuffer(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DEPTH_SIZE, &res); d->glFormat.setDepth(res); if (d->glFormat.depth()) d->glFormat.setDepthBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RGBA, &res); d->glFormat.setRgba(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RED_SIZE, &res); d->glFormat.setRedBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_GREEN_SIZE, &res); d->glFormat.setGreenBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_BLUE_SIZE, &res); d->glFormat.setBlueBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ALPHA_SIZE, &res); d->glFormat.setAlpha(res); if (d->glFormat.alpha()) d->glFormat.setAlphaBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ACCUM_RED_SIZE, &res); d->glFormat.setAccum(res); if (d->glFormat.accum()) d->glFormat.setAccumBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STENCIL_SIZE, &res); d->glFormat.setStencil(res); if (d->glFormat.stencil()) d->glFormat.setStencilBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STEREO, &res); d->glFormat.setStereo(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLE_BUFFERS_ARB, &res); d->glFormat.setSampleBuffers(res); if (d->glFormat.sampleBuffers()) { glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLES_ARB, &res); d->glFormat.setSamples(res); } Bool direct = format().directRendering() ? True : False; if (shareContext && (!shareContext->isValid() || !shareContext->d_func()->cx)) { qWarning("QGLContext::chooseContext(): Cannot share with invalid context"); shareContext = 0; } // 1. Sharing between rgba and color-index will give wrong colors. // 2. Contexts cannot be shared btw. direct/non-direct renderers. // 3. Pixmaps cannot share contexts that are set up for direct rendering. // 4. If the contexts are not created on the same screen, they can't be shared if (shareContext && (format().rgba() != shareContext->format().rgba() || (deviceIsPixmap() && glXIsDirect(disp, (GLXContext)shareContext->d_func()->cx)) || (shareContext->d_func()->screen != xinfo->screen()))) { shareContext = 0; } d->cx = 0; if (shareContext) { d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, (GLXContext)shareContext->d_func()->cx, direct); d->screen = ((XVisualInfo*)d->vi)->screen; if (d->cx) { QGLContext *share = const_cast<QGLContext *>(shareContext); d->sharing = true; share->d_func()->sharing = true; } } if (!d->cx) { d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, NULL, direct); d->screen = ((XVisualInfo*)d->vi)->screen; } if (!d->cx) return false; d->glFormat.setDirectRendering(glXIsDirect(disp, (GLXContext)d->cx)); if (deviceIsPixmap()) {#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT) d->gpm = glXCreateGLXPixmapMESA(disp, (XVisualInfo *)d->vi, qt_x11Handle(d->paintDevice), choose_cmap(disp, (XVisualInfo *)d->vi));#else d->gpm = (quint32)glXCreateGLXPixmap(disp, (XVisualInfo *)d->vi, qt_x11Handle(d->paintDevice));#endif if (!d->gpm) return false; } return true;}/*! \bold{X11 only:} This virtual function tries to find a visual that matches the format, reducing the demands if the original request cannot be met. The algorithm for reducing the demands of the format is quite simple-minded, so override this method in your subclass if your application has spcific requirements on visual selection. \sa chooseContext()*/void *QGLContext::chooseVisual(){ Q_D(QGLContext); static int bufDepths[] = { 8, 4, 2, 1 }; // Try 16, 12 also? //todo: if pixmap, also make sure that vi->depth == pixmap->depth void* vis = 0; int i = 0; bool fail = false; QGLFormat fmt = format(); bool tryDouble = !fmt.doubleBuffer(); // Some GL impl's only have double bool triedDouble = false; bool triedSample = false; if (fmt.sampleBuffers()) fmt.setSampleBuffers(QGLExtensions::glExtensions & QGLExtensions::SampleBuffers); while(!fail && !(vis = tryVisual(fmt, bufDepths[i]))) { if (!fmt.rgba() && bufDepths[i] > 1) { i++; continue; } if (tryDouble) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -