Check more GLES versions when creating context
authormartina.kollarova <martina.kollarova@intel.com>
Tue, 9 Aug 2016 08:41:55 +0000 (01:41 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 9 Aug 2016 08:41:55 +0000 (01:41 -0700)
Unifies the context creation for GL and GLES into a single loop.

BUG=skia:5403
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2201033003

Review-Url: https://codereview.chromium.org/2201033003

tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp

index a3069dc..c483fec 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2011 Google Inc.
  *
 #include <GL/glx.h>
 #include <GL/glu.h>
 
+#include <vector>
+#include <utility>
+
 namespace {
 
 /* Note: Skia requires glx 1.3 or newer */
 
 /* This struct is taken from a mesa demo.  Please update as required */
-static const struct { int major, minor; } gl_versions[] = {
+static const std::vector<std::pair<int, int>> gl_versions = {
    {1, 0},
    {1, 1},
    {1, 2},
@@ -34,9 +36,12 @@ static const struct { int major, minor; } gl_versions[] = {
    {4, 2},
    {4, 3},
    {4, 4},
-   {0, 0} /* end of list */
 };
-#define NUM_GL_VERSIONS SK_ARRAY_COUNT(gl_versions)
+
+static const std::vector<std::pair<int, int>> gles_versions = {
+    {2, 0},
+    {3, 0},
+};
 
 static bool ctxErrorOccurred = false;
 static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
@@ -51,6 +56,8 @@ public:
 
 private:
     void destroyGLContext();
+    static GLXContext CreateBestContext(bool isES, Display* display, GLXFBConfig bestFbc,
+                                        GLXContext glxSharedContext);
 
     void onPlatformMakeCurrent() const override;
     void onPlatformSwapBuffers() const override;
@@ -149,25 +156,10 @@ GLXGLTestContext::GLXGLTestContext(GrGLStandard forcedGpuAPI, GLXGLTestContext*
     // Done with the visual info data
     XFree(vi);
 
-    // Create the context
-
-    // Install an X error handler so the application won't exit if GL 3.0
-    // context allocation fails.
-    //
-    // Note this error handler is global.
-    // All display connections in all threads of a process use the same
-    // error handler, so be sure to guard against other threads issuing
-    // X commands while this code is running.
-    ctxErrorOccurred = false;
-    int (*oldHandler)(Display*, XErrorEvent*) =
-        XSetErrorHandler(&ctxErrorHandler);
-
     // Get the default screen's GLX extension list
     const char *glxExts = glXQueryExtensionsString(
         fDisplay, DefaultScreen(fDisplay)
     );
-
-
     // Check for the GLX_ARB_create_context extension string and the function.
     // If either is not present, use GLX 1.3 context creation method.
     if (!gluCheckExtension(reinterpret_cast<const GLubyte*>("GLX_ARB_create_context"),
@@ -176,85 +168,17 @@ GLXGLTestContext::GLXGLTestContext(GrGLStandard forcedGpuAPI, GLXGLTestContext*
             fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
         }
     } else {
-        //SkDebugf("Creating context.\n");
-        PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB =
-            (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
-
         if (kGLES_GrGLStandard == forcedGpuAPI) {
             if (gluCheckExtension(
                     reinterpret_cast<const GLubyte*>("GLX_EXT_create_context_es2_profile"),
                     reinterpret_cast<const GLubyte*>(glxExts))) {
-                const int context_attribs_gles[] = {
-                    GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
-                    GLX_CONTEXT_MINOR_VERSION_ARB, 0,
-                    GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
-                    None
-                };
-                fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, glxShareContext, True,
-                                                      context_attribs_gles);
+                fContext = CreateBestContext(true, fDisplay, bestFbc, glxShareContext);
             }
         } else {
-            // Well, unfortunately GLX will not just give us the highest context so instead we have
-            // to do this nastiness
-            for (i = NUM_GL_VERSIONS - 2; i > 0 ; i--) {
-                /* don't bother below GL 3.0 */
-                if (gl_versions[i].major < 3) {
-                    break;
-                }
-                // On Nvidia GPUs, to use Nv Path rendering we need a compatibility profile for the
-                // time being.
-                // TODO when Nvidia implements NVPR on Core profiles, we should start requesting
-                // core here
-                // Warning: This array should not be set to static. The
-                // glXCreateContextAttribsARB call writes to it upon failure and
-                // the next call would fail too.
-                const int context_attribs_gl[] = {
-                      GLX_CONTEXT_MAJOR_VERSION_ARB, gl_versions[i].major,
-                      GLX_CONTEXT_MINOR_VERSION_ARB, gl_versions[i].minor,
-                      GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
-                      None
-                };
-                fContext =
-                        glXCreateContextAttribsARB(fDisplay, bestFbc, glxShareContext, True,
-                                                   context_attribs_gl);
-
-                // Sync to ensure any errors generated are processed.
-                XSync(fDisplay, False);
-
-                if (!ctxErrorOccurred && fContext) {
-                    break;
-                }
-                // try again
-                ctxErrorOccurred = false;
-            }
-
-            // Couldn't create GL 3.0 context.
-            // Fall back to old-style 2.x context.
-            // When a context version below 3.0 is requested,
-            // implementations will return the newest context version
-            // compatible with OpenGL versions less than version 3.0.
-            if (ctxErrorOccurred || !fContext) {
-                const int context_attribs_gl_fallback[] = {
-                    GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
-                    GLX_CONTEXT_MINOR_VERSION_ARB, 0,
-                    None
-                };
-
-                ctxErrorOccurred = false;
-
-                fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, glxShareContext, True,
-                                                      context_attribs_gl_fallback);
-            }
+            fContext = CreateBestContext(false, fDisplay, bestFbc, glxShareContext);
         }
     }
-
-    // Sync to ensure any errors generated are processed.
-    XSync(fDisplay, False);
-
-    // Restore the original error handler
-    XSetErrorHandler(oldHandler);
-
-    if (ctxErrorOccurred || !fContext) {
+    if (!fContext) {
         SkDebugf("Failed to create an OpenGL context.\n");
         this->destroyGLContext();
         return;
@@ -320,6 +244,68 @@ void GLXGLTestContext::destroyGLContext() {
     }
 }
 
+/* Create a context with the highest possible version.
+ *
+ * Disable Xlib errors for the duration of this function (by default they abort
+ * the program) and try to get a context starting from the highest version
+ * number - there is no way to just directly ask what the highest supported
+ * version is.
+ *
+ * Returns the correct context or NULL on failure.
+ */
+GLXContext GLXGLTestContext::CreateBestContext(bool isES, Display* display, GLXFBConfig bestFbc,
+                                               GLXContext glxShareContext) {
+    auto glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
+        glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
+    if (!glXCreateContextAttribsARB) {
+        SkDebugf("Failed to get address of glXCreateContextAttribsARB");
+        return nullptr;
+    }
+    GLXContext context = nullptr;
+    // Install Xlib error handler that will set ctxErrorOccurred.
+    // WARNING: It is global for all threads.
+    ctxErrorOccurred = false;
+    int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
+
+    auto versions = isES ? gles_versions : gl_versions;
+    // Well, unfortunately GLX will not just give us the highest context so
+    // instead we have to do this nastiness
+    for (int i = versions.size() - 1; i >= 0 ; i--) {
+        // WARNING: Don't try to optimize this and make this array static. The
+        // glXCreateContextAttribsARB call writes to it upon failure and the
+        // next call would fail too.
+        std::vector<int> flags = {
+            GLX_CONTEXT_MAJOR_VERSION_ARB, versions[i].first,
+            GLX_CONTEXT_MINOR_VERSION_ARB, versions[i].second,
+        };
+        if (isES) {
+            flags.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
+            // the ES2 flag should work even for higher versions
+            flags.push_back(GLX_CONTEXT_ES2_PROFILE_BIT_EXT);
+        } else if (versions[i].first > 2) {
+            flags.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
+            // TODO When Nvidia implements NVPR on Core profiles, we should start
+            // requesting core here - currently Nv Path rendering on Nvidia
+            // requires a compatibility profile.
+            flags.push_back(GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
+        }
+        flags.push_back(0);
+        context = glXCreateContextAttribsARB(display, bestFbc, glxShareContext, true,
+                                             &flags[0]);
+        // Sync to ensure any errors generated are processed.
+        XSync(display, False);
+
+        if (!ctxErrorOccurred && context) {
+            break;
+        }
+        // try again
+        ctxErrorOccurred = false;
+    }
+    // Restore the original error handler.
+    XSetErrorHandler(oldHandler);
+    return context;
+}
+
 void GLXGLTestContext::onPlatformMakeCurrent() const {
     if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
         SkDebugf("Could not set the context.\n");