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
This commit is contained in:
martina.kollarova 2016-08-09 01:41:55 -07:00 committed by Commit bot
parent 643ede6921
commit fc3ea41ceb

View File

@ -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");