Cleanup of context initialization

Cleanup context initialization on linux

BUG=skia:
R=bsalomon@chromium.org, bsalomon@google.com

Author: joshualitt@chromium.org

Review URL: https://codereview.chromium.org/422323003
diff --git a/include/gpu/gl/SkNativeGLContext.h b/include/gpu/gl/SkNativeGLContext.h
index 01b7309..3bb6530 100644
--- a/include/gpu/gl/SkNativeGLContext.h
+++ b/include/gpu/gl/SkNativeGLContext.h
@@ -10,6 +10,29 @@
 
 #include "SkGLContextHelper.h"
 
+/* This struct is taken from a mesa demo.  Please update as required */
+static const struct { int major, minor; } gl_versions[] = {
+   {1, 0},
+   {1, 1},
+   {1, 2},
+   {1, 3},
+   {1, 4},
+   {1, 5},
+   {2, 0},
+   {2, 1},
+   {3, 0},
+   {3, 1},
+   {3, 2},
+   {3, 3},
+   {4, 0},
+   {4, 1},
+   {4, 2},
+   {4, 3},
+   {4, 4},
+   {0, 0} /* end of list */
+};
+#define NUM_GL_VERSIONS SK_ARRAY_COUNT(gl_versions)
+
 #if defined(SK_BUILD_FOR_MAC)
     #include <OpenGL/OpenGL.h>
 #elif defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_NACL)
diff --git a/src/gpu/gl/unix/SkNativeGLContext_unix.cpp b/src/gpu/gl/unix/SkNativeGLContext_unix.cpp
index 4da1eb2..4910057 100644
--- a/src/gpu/gl/unix/SkNativeGLContext_unix.cpp
+++ b/src/gpu/gl/unix/SkNativeGLContext_unix.cpp
@@ -9,7 +9,7 @@
 
 #include <GL/glu.h>
 
-#define GLX_1_3 1
+/* Note: Skia requires glx 1.3 or newer */
 
 SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
     fOldGLXContext = glXGetCurrentContext();
@@ -82,7 +82,16 @@
         None
     };
 
-#ifdef GLX_1_3
+    int glx_major, glx_minor;
+
+    // FBConfigs were added in GLX version 1.3.
+    if (!glXQueryVersion(fDisplay, &glx_major, &glx_minor) ||
+            ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) {
+        SkDebugf("GLX version 1.3 or higher required.\n");
+        this->destroyGLContext();
+        return NULL;
+    }
+
     //SkDebugf("Getting matching framebuffer configs.\n");
     int fbcount;
     GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay),
@@ -124,36 +133,6 @@
     // Get a visual
     XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc);
     //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid);
-#else
-    int numVisuals;
-    XVisualInfo visTemplate, *visReturn;
-
-    visReturn = XGetVisualInfo(fDisplay, VisualNoMask, &visTemplate, &numVisuals);
-    if (NULL == visReturn)
-    {
-        SkDebugf("Failed to get visual information.\n");
-        this->destroyGLContext();
-        return NULL;
-    }
-
-    int best = -1, best_num_samp = -1;
-
-    for (int i = 0; i < numVisuals; ++i)
-    {
-        int samp_buf, samples;
-
-        glXGetConfig(fDisplay, &visReturn[i], GLX_SAMPLE_BUFFERS, &samp_buf);
-        glXGetConfig(fDisplay, &visReturn[i], GLX_SAMPLES, &samples);
-
-        if (best < 0 || (samp_buf && samples > best_num_samp))
-            best = i, best_num_samp = samples;
-    }
-
-    XVisualInfo temp = visReturn[best];
-    XVisualInfo *vi = &temp;
-
-    XFree(visReturn);
-#endif
 
     fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth);
 
@@ -165,10 +144,8 @@
 
     fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap);
 
-#ifdef GLX_1_3
     // Done with the visual info data
     XFree(vi);
-#endif
 
     // Create the context
 
@@ -191,58 +168,71 @@
 
     // 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"),
                            reinterpret_cast<const GLubyte*>(glxExts))) {
         if (kGLES_GrGLStandard != forcedGpuAPI) {
-#ifdef GLX_1_3
             fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
-#else
-            fContext = glXCreateContext(fDisplay, vi, 0, True);
-#endif
         }
-    }
-#ifdef GLX_1_3
-    else {
+    } else {
         //SkDebugf("Creating context.\n");
         PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB =
             (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
 
-        static const int context_attribs_gl[] = {
-            GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
-            GLX_CONTEXT_MINOR_VERSION_ARB, 0,
-            None
-        };
-        static const int context_attribs_gl_fallback[] = {
-            GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
-            GLX_CONTEXT_MINOR_VERSION_ARB, 0,
-            None
-        };
-        static const int context_attribs_gles[] = {
-            GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
-            GLX_CONTEXT_MINOR_VERSION_ARB, 0,
-            GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
-            None
-        };
-
         if (kGLES_GrGLStandard == forcedGpuAPI) {
             if (gluCheckExtension(
                     reinterpret_cast<const GLubyte*>("GLX_EXT_create_context_es2_profile"),
                     reinterpret_cast<const GLubyte*>(glxExts))) {
+                static const int context_attribs_gles[] = {
+                    GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+                    GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+                    GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
+                    None
+                };
                 fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True,
                                                       context_attribs_gles);
             }
         } else {
-            fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True, context_attribs_gl);
+            // 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 && gl_versions[i].minor == 0) {
+                    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
+                static 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, 0, True, context_attribs_gl);
 
-            // Sync to ensure any errors generated are processed.
-            XSync(fDisplay, False);
+                // 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) {
-                // 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.
+                static const int context_attribs_gl_fallback[] = {
+                    GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
+                    GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+                    None
+                };
 
                 ctxErrorOccurred = false;
 
@@ -251,7 +241,6 @@
             }
         }
     }
-#endif
 
     // Sync to ensure any errors generated are processed.
     XSync(fDisplay, False);