From fc3ea41cebb8272c3f683f9cf585ff780b18f09b Mon Sep 17 00:00:00 2001 From: "martina.kollarova" Date: Tue, 9 Aug 2016 01:41:55 -0700 Subject: [PATCH] Check more GLES versions when creating context 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 --- .../gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp | 166 ++++++++++----------- 1 file changed, 76 insertions(+), 90 deletions(-) diff --git a/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp b/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp index a3069dc..c483fec 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 #include +#include +#include + 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> 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> 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("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("GLX_EXT_create_context_es2_profile"), reinterpret_cast(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 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"); -- 2.7.4