| Index: tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp
|
| diff --git a/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp b/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp
|
| index a3069dc0285f4ea377857ef55f56fb4d8ef28aa6..c483fecabec5f751fef470cd2f3cce4d92f308a3 100644
|
| --- a/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp
|
| +++ b/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp
|
| @@ -1,4 +1,3 @@
|
| -
|
| /*
|
| * Copyright 2011 Google Inc.
|
| *
|
| @@ -11,12 +10,15 @@
|
| #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");
|
|
|