michael@0: michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: #include "gl/SkNativeGLContext.h" michael@0: michael@0: #include michael@0: michael@0: #define GLX_1_3 1 michael@0: michael@0: SkNativeGLContext::AutoContextRestore::AutoContextRestore() { michael@0: fOldGLXContext = glXGetCurrentContext(); michael@0: fOldDisplay = glXGetCurrentDisplay(); michael@0: fOldDrawable = glXGetCurrentDrawable(); michael@0: } michael@0: michael@0: SkNativeGLContext::AutoContextRestore::~AutoContextRestore() { michael@0: if (NULL != fOldDisplay) { michael@0: glXMakeCurrent(fOldDisplay, fOldDrawable, fOldGLXContext); michael@0: } michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static bool ctxErrorOccurred = false; michael@0: static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) { michael@0: ctxErrorOccurred = true; michael@0: return 0; michael@0: } michael@0: michael@0: SkNativeGLContext::SkNativeGLContext() michael@0: : fContext(NULL) michael@0: , fDisplay(NULL) michael@0: , fPixmap(0) michael@0: , fGlxPixmap(0) { michael@0: } michael@0: michael@0: SkNativeGLContext::~SkNativeGLContext() { michael@0: this->destroyGLContext(); michael@0: } michael@0: michael@0: void SkNativeGLContext::destroyGLContext() { michael@0: if (fDisplay) { michael@0: glXMakeCurrent(fDisplay, 0, 0); michael@0: michael@0: if (fContext) { michael@0: glXDestroyContext(fDisplay, fContext); michael@0: fContext = NULL; michael@0: } michael@0: michael@0: if (fGlxPixmap) { michael@0: glXDestroyGLXPixmap(fDisplay, fGlxPixmap); michael@0: fGlxPixmap = 0; michael@0: } michael@0: michael@0: if (fPixmap) { michael@0: XFreePixmap(fDisplay, fPixmap); michael@0: fPixmap = 0; michael@0: } michael@0: michael@0: XCloseDisplay(fDisplay); michael@0: fDisplay = NULL; michael@0: } michael@0: } michael@0: michael@0: const GrGLInterface* SkNativeGLContext::createGLContext() { michael@0: fDisplay = XOpenDisplay(0); michael@0: michael@0: if (!fDisplay) { michael@0: SkDebugf("Failed to open X display.\n"); michael@0: this->destroyGLContext(); michael@0: return NULL; michael@0: } michael@0: michael@0: // Get a matching FB config michael@0: static int visual_attribs[] = { michael@0: GLX_X_RENDERABLE , True, michael@0: GLX_DRAWABLE_TYPE , GLX_PIXMAP_BIT, michael@0: None michael@0: }; michael@0: michael@0: #ifdef GLX_1_3 michael@0: //SkDebugf("Getting matching framebuffer configs.\n"); michael@0: int fbcount; michael@0: GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay), michael@0: visual_attribs, &fbcount); michael@0: if (!fbc) { michael@0: SkDebugf("Failed to retrieve a framebuffer config.\n"); michael@0: this->destroyGLContext(); michael@0: return NULL; michael@0: } michael@0: //SkDebugf("Found %d matching FB configs.\n", fbcount); michael@0: michael@0: // Pick the FB config/visual with the most samples per pixel michael@0: //SkDebugf("Getting XVisualInfos.\n"); michael@0: int best_fbc = -1, best_num_samp = -1; michael@0: michael@0: int i; michael@0: for (i = 0; i < fbcount; ++i) { michael@0: XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]); michael@0: if (vi) { michael@0: int samp_buf, samples; michael@0: glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); michael@0: glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples); michael@0: michael@0: //SkDebugf(" Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," michael@0: // " SAMPLES = %d\n", michael@0: // i, (unsigned int)vi->visualid, samp_buf, samples); michael@0: michael@0: if (best_fbc < 0 || (samp_buf && samples > best_num_samp)) michael@0: best_fbc = i, best_num_samp = samples; michael@0: } michael@0: XFree(vi); michael@0: } michael@0: michael@0: GLXFBConfig bestFbc = fbc[best_fbc]; michael@0: michael@0: // Be sure to free the FBConfig list allocated by glXChooseFBConfig() michael@0: XFree(fbc); michael@0: michael@0: // Get a visual michael@0: XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc); michael@0: //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid); michael@0: #else michael@0: int numVisuals; michael@0: XVisualInfo visTemplate, *visReturn; michael@0: michael@0: visReturn = XGetVisualInfo(fDisplay, VisualNoMask, &visTemplate, &numVisuals); michael@0: if (NULL == visReturn) michael@0: { michael@0: SkDebugf("Failed to get visual information.\n"); michael@0: this->destroyGLContext(); michael@0: return NULL; michael@0: } michael@0: michael@0: int best = -1, best_num_samp = -1; michael@0: michael@0: for (int i = 0; i < numVisuals; ++i) michael@0: { michael@0: int samp_buf, samples; michael@0: michael@0: glXGetConfig(fDisplay, &visReturn[i], GLX_SAMPLE_BUFFERS, &samp_buf); michael@0: glXGetConfig(fDisplay, &visReturn[i], GLX_SAMPLES, &samples); michael@0: michael@0: if (best < 0 || (samp_buf && samples > best_num_samp)) michael@0: best = i, best_num_samp = samples; michael@0: } michael@0: michael@0: XVisualInfo temp = visReturn[best]; michael@0: XVisualInfo *vi = &temp; michael@0: michael@0: XFree(visReturn); michael@0: #endif michael@0: michael@0: fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth); michael@0: michael@0: if (!fPixmap) { michael@0: SkDebugf("Failed to create pixmap.\n"); michael@0: this->destroyGLContext(); michael@0: return NULL; michael@0: } michael@0: michael@0: fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap); michael@0: michael@0: #ifdef GLX_1_3 michael@0: // Done with the visual info data michael@0: XFree(vi); michael@0: #endif michael@0: michael@0: // Create the context michael@0: michael@0: // Install an X error handler so the application won't exit if GL 3.0 michael@0: // context allocation fails. michael@0: // michael@0: // Note this error handler is global. michael@0: // All display connections in all threads of a process use the same michael@0: // error handler, so be sure to guard against other threads issuing michael@0: // X commands while this code is running. michael@0: ctxErrorOccurred = false; michael@0: int (*oldHandler)(Display*, XErrorEvent*) = michael@0: XSetErrorHandler(&ctxErrorHandler); michael@0: michael@0: // Get the default screen's GLX extension list michael@0: const char *glxExts = glXQueryExtensionsString( michael@0: fDisplay, DefaultScreen(fDisplay) michael@0: ); michael@0: // Check for the GLX_ARB_create_context extension string and the function. michael@0: // If either is not present, use GLX 1.3 context creation method. michael@0: if (!gluCheckExtension( michael@0: reinterpret_cast("GLX_ARB_create_context") michael@0: , reinterpret_cast(glxExts))) michael@0: { michael@0: //SkDebugf("GLX_ARB_create_context not found." michael@0: // " Using old-style GLX context.\n"); michael@0: #ifdef GLX_1_3 michael@0: fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True); michael@0: #else michael@0: fContext = glXCreateContext(fDisplay, vi, 0, True); michael@0: #endif michael@0: michael@0: } michael@0: #ifdef GLX_1_3 michael@0: else { michael@0: //SkDebugf("Creating context.\n"); michael@0: michael@0: PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = michael@0: (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB"); michael@0: int context_attribs[] = { michael@0: GLX_CONTEXT_MAJOR_VERSION_ARB, 3, michael@0: GLX_CONTEXT_MINOR_VERSION_ARB, 0, michael@0: //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, michael@0: None michael@0: }; michael@0: fContext = glXCreateContextAttribsARB( michael@0: fDisplay, bestFbc, 0, True, context_attribs michael@0: ); michael@0: michael@0: // Sync to ensure any errors generated are processed. michael@0: XSync(fDisplay, False); michael@0: if (!ctxErrorOccurred && fContext) { michael@0: //SkDebugf( "Created GL 3.0 context.\n" ); michael@0: } else { michael@0: // Couldn't create GL 3.0 context. michael@0: // Fall back to old-style 2.x context. michael@0: // When a context version below 3.0 is requested, michael@0: // implementations will return the newest context version compatible michael@0: // with OpenGL versions less than version 3.0. michael@0: michael@0: // GLX_CONTEXT_MAJOR_VERSION_ARB = 1 michael@0: context_attribs[1] = 1; michael@0: // GLX_CONTEXT_MINOR_VERSION_ARB = 0 michael@0: context_attribs[3] = 0; michael@0: michael@0: ctxErrorOccurred = false; michael@0: michael@0: //SkDebugf("Failed to create GL 3.0 context." michael@0: // " Using old-style GLX context.\n"); michael@0: fContext = glXCreateContextAttribsARB( michael@0: fDisplay, bestFbc, 0, True, context_attribs michael@0: ); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // Sync to ensure any errors generated are processed. michael@0: XSync(fDisplay, False); michael@0: michael@0: // Restore the original error handler michael@0: XSetErrorHandler(oldHandler); michael@0: michael@0: if (ctxErrorOccurred || !fContext) { michael@0: SkDebugf("Failed to create an OpenGL context.\n"); michael@0: this->destroyGLContext(); michael@0: return NULL; michael@0: } michael@0: michael@0: // Verify that context is a direct context michael@0: if (!glXIsDirect(fDisplay, fContext)) { michael@0: //SkDebugf("Indirect GLX rendering context obtained.\n"); michael@0: } else { michael@0: //SkDebugf("Direct GLX rendering context obtained.\n"); michael@0: } michael@0: michael@0: //SkDebugf("Making context current.\n"); michael@0: if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { michael@0: SkDebugf("Could not set the context.\n"); michael@0: this->destroyGLContext(); michael@0: return NULL; michael@0: } michael@0: michael@0: const GrGLInterface* interface = GrGLCreateNativeInterface(); michael@0: if (!interface) { michael@0: SkDebugf("Failed to create gl interface"); michael@0: this->destroyGLContext(); michael@0: return NULL; michael@0: } michael@0: return interface; michael@0: } michael@0: michael@0: void SkNativeGLContext::makeCurrent() const { michael@0: if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { michael@0: SkDebugf("Could not set the context.\n"); michael@0: } michael@0: } michael@0: michael@0: void SkNativeGLContext::swapBuffers() const { michael@0: glXSwapBuffers(fDisplay, fGlxPixmap); michael@0: }