src/opengl/qgl_x11.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
--- a/src/opengl/qgl_x11.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/src/opengl/qgl_x11.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -115,6 +115,20 @@
 #define GLX_FRONT_LEFT_EXT                 0x20DE
 #endif
 
+#ifndef GLX_ARB_create_context
+#define GLX_CONTEXT_DEBUG_BIT_ARB          0x00000001
+#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define GLX_CONTEXT_MAJOR_VERSION_ARB      0x2091
+#define GLX_CONTEXT_MINOR_VERSION_ARB      0x2092
+#define GLX_CONTEXT_FLAGS_ARB              0x2094
+#endif
+
+#ifndef GLX_ARB_create_context_profile
+#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB   0x00000001
+#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
+#define GLX_CONTEXT_PROFILE_MASK_ARB       0x9126
+#endif
+
 /*
   The qt_gl_choose_cmap function is internal and used by QGLWidget::setContext()
   and GLX (not Windows).  If the application can't find any sharable
@@ -401,6 +415,148 @@
     return trans_colors.size() > 0;
 }
 
+static bool buildSpec(int* spec, const QGLFormat& f, QPaintDevice* paintDevice,
+                      int bufDepth, bool onlyFBConfig = false)
+{
+    int i = 0;
+    spec[i++] = GLX_LEVEL;
+    spec[i++] = f.plane();
+    const QX11Info *xinfo = qt_x11Info(paintDevice);
+    bool useFBConfig = onlyFBConfig;
+
+#if defined(GLX_VERSION_1_3) && !defined(QT_NO_XRENDER) && !defined(Q_OS_HPUX)
+    /*
+      HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions.
+      Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented.
+     */
+    QWidget* widget = 0;
+    if (paintDevice->devType() == QInternal::Widget)
+        widget = static_cast<QWidget*>(paintDevice);
+
+    // Only use glXChooseFBConfig for widgets if we're trying to get an ARGB visual
+    if (widget && widget->testAttribute(Qt::WA_TranslucentBackground) && X11->use_xrender)
+        useFBConfig = true;
+#endif
+
+#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
+    static bool useTranspExt = false;
+    static bool useTranspExtChecked = false;
+    if (f.plane() && !useTranspExtChecked && paintDevice) {
+        QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
+        useTranspExt = extensions.match("GLX_EXT_visual_info");
+        //# (A bit simplistic; that could theoretically be a substring)
+        if (useTranspExt) {
+            QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR));
+            useTranspExt = !cstr.contains("Xi Graphics"); // bug workaround
+            if (useTranspExt) {
+                // bug workaround - some systems (eg. FireGL) refuses to return an overlay
+                // visual if the GLX_TRANSPARENT_TYPE_EXT attribute is specified, even if
+                // the implementation supports transparent overlays
+                int tmpSpec[] = { GLX_LEVEL, f.plane(), GLX_TRANSPARENT_TYPE_EXT,
+                                  f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT,
+                                  XNone };
+                XVisualInfo * vinf = glXChooseVisual(xinfo->display(), xinfo->screen(), tmpSpec);
+                if (!vinf) {
+                    useTranspExt = false;
+                }
+            }
+        }
+
+        useTranspExtChecked = true;
+    }
+    if (f.plane() && useTranspExt && !useFBConfig) {
+        // Required to avoid non-transparent overlay visual(!) on some systems
+        spec[i++] = GLX_TRANSPARENT_TYPE_EXT;
+        spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT;
+    }
+#endif
+
+#if defined(GLX_VERSION_1_3)  && !defined(Q_OS_HPUX)
+    // GLX_RENDER_TYPE is only in glx >=1.3
+    if (useFBConfig) {
+        spec[i++] = GLX_RENDER_TYPE;
+        spec[i++] = f.rgba() ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
+    }
+#endif
+
+    if (f.doubleBuffer())
+        spec[i++] = GLX_DOUBLEBUFFER;
+        if (useFBConfig)
+            spec[i++] = True;
+    if (f.depth()) {
+        spec[i++] = GLX_DEPTH_SIZE;
+        spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
+    }
+    if (f.stereo()) {
+        spec[i++] = GLX_STEREO;
+        if (useFBConfig)
+            spec[i++] = True;
+    }
+    if (f.stencil()) {
+        spec[i++] = GLX_STENCIL_SIZE;
+        spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
+    }
+    if (f.rgba()) {
+        if (!useFBConfig)
+            spec[i++] = GLX_RGBA;
+        spec[i++] = GLX_RED_SIZE;
+        spec[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize();
+        spec[i++] = GLX_GREEN_SIZE;
+        spec[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize();
+        spec[i++] = GLX_BLUE_SIZE;
+        spec[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize();
+        if (f.alpha()) {
+            spec[i++] = GLX_ALPHA_SIZE;
+            spec[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
+        }
+        if (f.accum()) {
+            spec[i++] = GLX_ACCUM_RED_SIZE;
+            spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+            spec[i++] = GLX_ACCUM_GREEN_SIZE;
+            spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+            spec[i++] = GLX_ACCUM_BLUE_SIZE;
+            spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+            if (f.alpha()) {
+                spec[i++] = GLX_ACCUM_ALPHA_SIZE;
+                spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+            }
+        }
+    } else {
+        spec[i++] = GLX_BUFFER_SIZE;
+        spec[i++] = bufDepth;
+    }
+
+    if (f.sampleBuffers()) {
+        spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
+        spec[i++] = 1;
+        spec[i++] = GLX_SAMPLES_ARB;
+        spec[i++] = f.samples() == -1 ? 4 : f.samples();
+    }
+
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+    if (useFBConfig) {
+        spec[i++] = GLX_DRAWABLE_TYPE;
+        switch(paintDevice->devType()) {
+        case QInternal::Pixmap:
+            spec[i++] = GLX_PIXMAP_BIT;
+            break;
+        case QInternal::Pbuffer:
+            spec[i++] = GLX_PBUFFER_BIT;
+            break;
+        default:
+            qWarning("QGLContext: Unknown paint device type %d", paintDevice->devType());
+            // Fall-through & assume it's a window
+        case QInternal::Widget:
+            spec[i++] = GLX_WINDOW_BIT;
+            break;
+        };
+    }
+#endif
+
+    spec[i] = XNone;
+    return useFBConfig;
+}
+
 /*****************************************************************************
   QGLContext UNIX/GLX-specific code
  *****************************************************************************/
@@ -493,21 +649,85 @@
         shareContext = 0;
     }
 
+    const int major = d->reqFormat.majorVersion();
+    const int minor = d->reqFormat.minorVersion();
+    const int profile = d->reqFormat.profile() == QGLFormat::CompatibilityProfile
+        ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
+        : GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+
     d->cx = 0;
-    if (shareContext) {
+
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+    /*
+      HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions.
+      Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented.
+     */
+    if ((major == 3 && minor >= 2) || major > 3) {
+        QGLTemporaryContext *tmpContext = 0;
+        if (!QGLContext::currentContext())
+            tmpContext = new QGLTemporaryContext;
+
+        int attributes[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, major,
+                             GLX_CONTEXT_MINOR_VERSION_ARB, minor,
+                             GLX_CONTEXT_PROFILE_MASK_ARB, profile,
+                             0 };
+
+        typedef GLXContext ( * Q_PFNGLXCREATECONTEXTATTRIBSARBPROC)
+            (Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
+
+
+        Q_PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs =
+            (Q_PFNGLXCREATECONTEXTATTRIBSARBPROC) qglx_getProcAddress("glXCreateContextAttribsARB");
+
+        if (glXCreateContextAttribs) {
+            int spec[45];
+            glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_BUFFER_SIZE, &res);
+            buildSpec(spec, format(), d->paintDevice, res, true);
+
+            GLXFBConfig *configs;
+            int configCount = 0;
+            configs = glXChooseFBConfig(disp, xinfo->screen(), spec, &configCount);
+
+            if (configs && configCount > 0) {
+                d->cx = glXCreateContextAttribs(disp, configs[0],
+                    shareContext ? (GLXContext)shareContext->d_func()->cx : 0, direct, attributes);
+                if (!d->cx && shareContext) {
+                    shareContext = 0;
+                    d->cx = glXCreateContextAttribs(disp, configs[0], 0, direct, attributes);
+                }
+                d->screen = ((XVisualInfo*)d->vi)->screen;
+            }
+            XFree(configs);
+        } else {
+            qWarning("QGLContext::chooseContext(): OpenGL %d.%d is not supported", major, minor);
+        }
+
+        if (tmpContext)
+            delete tmpContext;
+    }
+#else
+    Q_UNUSED(major);
+    Q_UNUSED(minor);
+    Q_UNUSED(profile);
+#endif
+
+    if (!d->cx && 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;
+        shareContext = 0;
     }
+
+    if (shareContext && d->cx) {
+        QGLContext *share = const_cast<QGLContext *>(shareContext);
+        d->sharing = true;
+        share->d_func()->sharing = true;
+    }
+
     if (!d->cx)
         return false;
     d->glFormat.setDirectRendering(glXIsDirect(disp, (GLXContext)d->cx));
@@ -606,143 +826,8 @@
 {
     Q_D(QGLContext);
     int spec[45];
-    int i = 0;
-    spec[i++] = GLX_LEVEL;
-    spec[i++] = f.plane();
     const QX11Info *xinfo = qt_x11Info(d->paintDevice);
-    bool useFBConfig = false;
-
-#if defined(GLX_VERSION_1_3) && !defined(QT_NO_XRENDER) && !defined(Q_OS_HPUX)
-    /*
-      HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions.
-      Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented.
-     */
-    QWidget* widget = 0;
-    if (d->paintDevice->devType() == QInternal::Widget)
-        widget = static_cast<QWidget*>(d->paintDevice);
-
-    // Only use glXChooseFBConfig for widgets if we're trying to get an ARGB visual
-    if (widget && widget->testAttribute(Qt::WA_TranslucentBackground) && X11->use_xrender)
-        useFBConfig = true;
-#endif
-
-#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
-    static bool useTranspExt = false;
-    static bool useTranspExtChecked = false;
-    if (f.plane() && !useTranspExtChecked && d->paintDevice) {
-        QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
-        useTranspExt = extensions.match("GLX_EXT_visual_info");
-        //# (A bit simplistic; that could theoretically be a substring)
-        if (useTranspExt) {
-            QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR));
-            useTranspExt = !cstr.contains("Xi Graphics"); // bug workaround
-            if (useTranspExt) {
-                // bug workaround - some systems (eg. FireGL) refuses to return an overlay
-                // visual if the GLX_TRANSPARENT_TYPE_EXT attribute is specified, even if
-                // the implementation supports transparent overlays
-                int tmpSpec[] = { GLX_LEVEL, f.plane(), GLX_TRANSPARENT_TYPE_EXT,
-                                  f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT,
-                                  XNone };
-                XVisualInfo * vinf = glXChooseVisual(xinfo->display(), xinfo->screen(), tmpSpec);
-                if (!vinf) {
-                    useTranspExt = false;
-                }
-            }
-        }
-
-        useTranspExtChecked = true;
-    }
-    if (f.plane() && useTranspExt && !useFBConfig) {
-        // Required to avoid non-transparent overlay visual(!) on some systems
-        spec[i++] = GLX_TRANSPARENT_TYPE_EXT;
-        spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT;
-    }
-#endif
-
-#if defined(GLX_VERSION_1_3)  && !defined(Q_OS_HPUX)
-    // GLX_RENDER_TYPE is only in glx >=1.3
-    if (useFBConfig) {
-        spec[i++] = GLX_RENDER_TYPE;
-        spec[i++] = f.rgba() ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
-    }
-#endif
-
-    if (f.doubleBuffer())
-        spec[i++] = GLX_DOUBLEBUFFER;
-        if (useFBConfig)
-            spec[i++] = True;
-    if (f.depth()) {
-        spec[i++] = GLX_DEPTH_SIZE;
-        spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
-    }
-    if (f.stereo()) {
-        spec[i++] = GLX_STEREO;
-        if (useFBConfig)
-            spec[i++] = True;
-    }
-    if (f.stencil()) {
-        spec[i++] = GLX_STENCIL_SIZE;
-        spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
-    }
-    if (f.rgba()) {
-        if (!useFBConfig)
-            spec[i++] = GLX_RGBA;
-        spec[i++] = GLX_RED_SIZE;
-        spec[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize();
-        spec[i++] = GLX_GREEN_SIZE;
-        spec[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize();
-        spec[i++] = GLX_BLUE_SIZE;
-        spec[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize();
-        if (f.alpha()) {
-            spec[i++] = GLX_ALPHA_SIZE;
-            spec[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
-        }
-        if (f.accum()) {
-            spec[i++] = GLX_ACCUM_RED_SIZE;
-            spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
-            spec[i++] = GLX_ACCUM_GREEN_SIZE;
-            spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
-            spec[i++] = GLX_ACCUM_BLUE_SIZE;
-            spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
-            if (f.alpha()) {
-                spec[i++] = GLX_ACCUM_ALPHA_SIZE;
-                spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
-            }
-        }
-    } else {
-        spec[i++] = GLX_BUFFER_SIZE;
-        spec[i++] = bufDepth;
-    }
-
-    if (f.sampleBuffers()) {
-        spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
-        spec[i++] = 1;
-        spec[i++] = GLX_SAMPLES_ARB;
-        spec[i++] = f.samples() == -1 ? 4 : f.samples();
-    }
-
-#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
-    if (useFBConfig) {
-        spec[i++] = GLX_DRAWABLE_TYPE;
-        switch(d->paintDevice->devType()) {
-        case QInternal::Pixmap:
-            spec[i++] = GLX_PIXMAP_BIT;
-            break;
-        case QInternal::Pbuffer:
-            spec[i++] = GLX_PBUFFER_BIT;
-            break;
-        default:
-            qWarning("QGLContext: Unknown paint device type %d", d->paintDevice->devType());
-            // Fall-through & assume it's a window
-        case QInternal::Widget:
-            spec[i++] = GLX_WINDOW_BIT;
-            break;
-        };
-    }
-#endif
-
-    spec[i] = XNone;
-
+    bool useFBConfig = buildSpec(spec, f, d->paintDevice, bufDepth, false);
 
     XVisualInfo* chosenVisualInfo = 0;
 
@@ -755,7 +840,7 @@
         if (!configs)
             break; // fallback to trying glXChooseVisual
 
-        for (i = 0; i < configCount; ++i) {
+        for (int i = 0; i < configCount; ++i) {
             XVisualInfo* vi;
             vi = glXGetVisualFromFBConfig(xinfo->display(), configs[i]);
             if (!vi)
@@ -843,7 +928,7 @@
     } else if (d->paintDevice->devType() == QInternal::Pbuffer) {
         ok = glXMakeCurrent(xinfo->display(), (GLXPbuffer)d->pbuf, (GLXContext)d->cx);
     } else if (d->paintDevice->devType() == QInternal::Widget) {
-        ok = glXMakeCurrent(xinfo->display(), ((QWidget *)d->paintDevice)->winId(), (GLXContext)d->cx);
+        ok = glXMakeCurrent(xinfo->display(), ((QWidget *)d->paintDevice)->internalWinId(), (GLXContext)d->cx);
     }
     if (!ok)
         qWarning("QGLContext::makeCurrent(): Failed.");
@@ -1773,6 +1858,9 @@
     glXBindTexImageEXT(x11Info.display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT, 0);
 
     glBindTexture(GL_TEXTURE_2D, textureId);
+    GLuint filtering = (options & QGLContext::LinearFilteringBindOption) ? GL_LINEAR : GL_NEAREST;
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
 
     if (!((hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted)))
         options &= ~QGLContext::InvertedYBindOption;