diff --git a/Modules/opengl/opengl.cpp b/Modules/opengl/opengl.cpp --- a/Modules/opengl/opengl.cpp +++ b/Modules/opengl/opengl.cpp @@ -122,6 +122,65 @@ return newItem(parent, NULL, textCol1, textCol2); } +#if KCM_HAVE_GLX +static const int coreProfileCtxAttribs[][7] = { + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 5, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }, + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 4, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }, + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }, + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }, + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 1, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }, + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 0, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }, + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }, + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }, + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 1, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, /* Ignored in this case but specified to keep the size same */ + None + } +}; +#endif + static bool IsDirect; static struct glinfo { @@ -142,6 +201,7 @@ const char *glVendor; const char *glRenderer; const char *glVersion; + QString glVersionCoreProfile; const char *glExtensions; #if KCM_HAVE_GLX const char *gluVersion; @@ -587,7 +647,10 @@ #ifdef KCM_ENABLE_OPENGLES l3 = newItem(l2, l3, i18n("OpenGL ES version"), gli.glVersion); #else - l3 = newItem(l2, l3, i18n("OpenGL version"), gli.glVersion); + l3 = newItem(l2, l3, i18n("OpenGL version (compat. profile)"), gli.glVersion); + if (!gli.glVersionCoreProfile.isEmpty()) { + l3 = newItem(l2, l3, i18n("OpenGL version (core profile)"), gli.glVersionCoreProfile); + } #endif if (IsDirect) { @@ -652,6 +715,113 @@ #endif #if KCM_HAVE_GLX +static bool have_glx14(Display *dpy) +{ + int glxMajor; + int glxMinor; + + if (!glXQueryVersion(dpy, &glxMajor, &glxMinor)) { + qDebug() << "Error: glXQueryVersion failed\n"; + return false; + } + + if ((glxMajor < 1) || (glxMajor == 1 && glxMinor < 4)) { + qDebug() << "Error: At least GLX 1.4 is required to query OpenGL core profiles\n"; + return false; + } + + return true; +} + +static void get_gl_core_profile_glx(GLXContext &ctx, GLXFBConfig *&fbc, Display *dpy, int scrnum, Window win) +{ + typedef GLXContext (*glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const int *); + static const QLatin1String extName("GLX_ARB_create_context"); + static const int fbcAttrib[] = { + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + None }; + glXCreateContextAttribsARBProc glXCreateContextAttribsARB; + int fbcElems; + + if (!have_glx14(dpy)) { + return; + } + + if (!QString(gli.glxExtensions).contains(extName) || !QString(gli.serverExtensions).contains(extName)) { + qDebug() << "Error:" << extName << "extension is not supported\n"; + return; + } + + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB((const GLubyte *) "glXCreateContextAttribsARB"); + if (!glXCreateContextAttribsARB) { + qDebug() << "Error: Failed to retrieve glXCreateContextAttribsARB\n"; + return; + } + + fbc = glXChooseFBConfig(dpy, scrnum, fbcAttrib, &fbcElems); + if (!fbc) { + qDebug() << "Error: glXChooseFBConfig failed\n"; + return; + } + + size_t idx; + size_t end = sizeof(coreProfileCtxAttribs) / sizeof(coreProfileCtxAttribs[0]); + for (idx = 0; idx < end; idx++) { + const int *attribs = coreProfileCtxAttribs[idx]; + ctx = glXCreateContextAttribsARB(dpy, *fbc, nullptr, IsDirect, attribs); + if (ctx) { + break; + } + } + if (idx == end) { + qDebug() << "Error: glXCreateContextAttribsARB failed\n"; + return; + } + + if (glXMakeCurrent(dpy, win, ctx)) { + gli.glVersionCoreProfile = QLatin1String((const char *) glGetString(GL_VERSION)); + } else { + qDebug() << "Error: glXMakeCurrent failed for core profile\n"; + } +} + +static void get_gl_core_profile_glx_mesaext(Display *dpy) +{ + typedef Bool (*glXQueryCurrentRendererIntegerMESAProc)(int, int *); + glXQueryCurrentRendererIntegerMESAProc glXQueryCurrentRendererIntegerMESA; + int coreProfileVersion[2]; + int mesaVersion[3]; + QString mesaVersionTag; + + if (!have_glx14(dpy)) { + return; + } + + glXQueryCurrentRendererIntegerMESA = (glXQueryCurrentRendererIntegerMESAProc) glXGetProcAddressARB((const GLubyte *) "glXQueryCurrentRendererIntegerMESA"); + if (!glXQueryCurrentRendererIntegerMESA) { + qDebug() << "Error: Failed to retrieve glXQueryCurrentRendererIntegerMESA\n"; + return; + } + + Bool ok = glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA, coreProfileVersion); + if (ok == False) { + qDebug() << "Error: glXQueryCurrentRendererIntegerMESA failed to get core profile version\n"; + return; + } + + ok = glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VERSION_MESA, mesaVersion); + if (ok == True) { + mesaVersionTag = QString("Mesa %1.%2.%3").arg(mesaVersion[0]).arg(mesaVersion[1]).arg(mesaVersion[2]); + } + else { + qDebug() << "Warning: glXQueryCurrentRendererIntegerMESA failed to get mesa version\n"; + } + + gli.glVersionCoreProfile = QString("%1.%2 %3").arg(coreProfileVersion[0]).arg(coreProfileVersion[1]).arg(mesaVersionTag); +} + static QTreeWidgetItem *get_gl_info_glx(Display *dpy, int scrnum, Bool allowDirect, QTreeWidgetItem *l1, QTreeWidgetItem *after) { Window win; @@ -659,6 +829,8 @@ unsigned long mask; Window root; XVisualInfo *visinfo; + GLXContext ctxCoreProf = nullptr; + GLXFBConfig *fbcCoreProf = nullptr; int width = 100, height = 100; QTreeWidgetItem *result = after; @@ -683,7 +855,7 @@ if (!visinfo) { visinfo = glXChooseVisual(dpy, scrnum, const_cast(attribDouble)); if (!visinfo) { - qDebug() << "Error: couldn't find RGB GLX visual\n"; + qDebug() << "Error: couldn't find RGB GLX visual\n"; return result; } } @@ -699,7 +871,7 @@ ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect ); if (!ctx) { - qDebug() << "Error: glXCreateContext failed\n"; + qDebug() << "Error: glXCreateContext failed\n"; XDestroyWindow(dpy, win); return result; } @@ -721,13 +893,26 @@ gli.gluExtensions = (const char *) gluGetString(GLU_EXTENSIONS); IsDirect = glXIsDirect(dpy, ctx); - - result = print_screen_info(l1, after, IsDirect ? i18n("Direct Rendering (GLX)") : i18n("Indirect Rendering (GLX)")); } else { qDebug() << "Error: glXMakeCurrent failed\n"; } + if (QString(gli.glxExtensions).contains(QLatin1String("GLX_MESA_query_renderer"))) { + get_gl_core_profile_glx_mesaext(dpy); + } + else { + get_gl_core_profile_glx(ctxCoreProf, fbcCoreProf, dpy, scrnum, win); + } + + result = print_screen_info(l1, after, IsDirect ? i18n("Direct Rendering (GLX)") : i18n("Indirect Rendering (GLX)")); + + if (ctxCoreProf) { + glXDestroyContext(dpy, ctxCoreProf); + } + if (fbcCoreProf) { + XFree(fbcCoreProf); + } glXDestroyContext(dpy, ctx); XDestroyWindow(dpy, win); return result;