1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/gl/unix/SkNativeGLContext_unix.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,291 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 +#include "gl/SkNativeGLContext.h" 1.12 + 1.13 +#include <GL/glu.h> 1.14 + 1.15 +#define GLX_1_3 1 1.16 + 1.17 +SkNativeGLContext::AutoContextRestore::AutoContextRestore() { 1.18 + fOldGLXContext = glXGetCurrentContext(); 1.19 + fOldDisplay = glXGetCurrentDisplay(); 1.20 + fOldDrawable = glXGetCurrentDrawable(); 1.21 +} 1.22 + 1.23 +SkNativeGLContext::AutoContextRestore::~AutoContextRestore() { 1.24 + if (NULL != fOldDisplay) { 1.25 + glXMakeCurrent(fOldDisplay, fOldDrawable, fOldGLXContext); 1.26 + } 1.27 +} 1.28 + 1.29 +/////////////////////////////////////////////////////////////////////////////// 1.30 + 1.31 +static bool ctxErrorOccurred = false; 1.32 +static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) { 1.33 + ctxErrorOccurred = true; 1.34 + return 0; 1.35 +} 1.36 + 1.37 +SkNativeGLContext::SkNativeGLContext() 1.38 + : fContext(NULL) 1.39 + , fDisplay(NULL) 1.40 + , fPixmap(0) 1.41 + , fGlxPixmap(0) { 1.42 +} 1.43 + 1.44 +SkNativeGLContext::~SkNativeGLContext() { 1.45 + this->destroyGLContext(); 1.46 +} 1.47 + 1.48 +void SkNativeGLContext::destroyGLContext() { 1.49 + if (fDisplay) { 1.50 + glXMakeCurrent(fDisplay, 0, 0); 1.51 + 1.52 + if (fContext) { 1.53 + glXDestroyContext(fDisplay, fContext); 1.54 + fContext = NULL; 1.55 + } 1.56 + 1.57 + if (fGlxPixmap) { 1.58 + glXDestroyGLXPixmap(fDisplay, fGlxPixmap); 1.59 + fGlxPixmap = 0; 1.60 + } 1.61 + 1.62 + if (fPixmap) { 1.63 + XFreePixmap(fDisplay, fPixmap); 1.64 + fPixmap = 0; 1.65 + } 1.66 + 1.67 + XCloseDisplay(fDisplay); 1.68 + fDisplay = NULL; 1.69 + } 1.70 +} 1.71 + 1.72 +const GrGLInterface* SkNativeGLContext::createGLContext() { 1.73 + fDisplay = XOpenDisplay(0); 1.74 + 1.75 + if (!fDisplay) { 1.76 + SkDebugf("Failed to open X display.\n"); 1.77 + this->destroyGLContext(); 1.78 + return NULL; 1.79 + } 1.80 + 1.81 + // Get a matching FB config 1.82 + static int visual_attribs[] = { 1.83 + GLX_X_RENDERABLE , True, 1.84 + GLX_DRAWABLE_TYPE , GLX_PIXMAP_BIT, 1.85 + None 1.86 + }; 1.87 + 1.88 +#ifdef GLX_1_3 1.89 + //SkDebugf("Getting matching framebuffer configs.\n"); 1.90 + int fbcount; 1.91 + GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay), 1.92 + visual_attribs, &fbcount); 1.93 + if (!fbc) { 1.94 + SkDebugf("Failed to retrieve a framebuffer config.\n"); 1.95 + this->destroyGLContext(); 1.96 + return NULL; 1.97 + } 1.98 + //SkDebugf("Found %d matching FB configs.\n", fbcount); 1.99 + 1.100 + // Pick the FB config/visual with the most samples per pixel 1.101 + //SkDebugf("Getting XVisualInfos.\n"); 1.102 + int best_fbc = -1, best_num_samp = -1; 1.103 + 1.104 + int i; 1.105 + for (i = 0; i < fbcount; ++i) { 1.106 + XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]); 1.107 + if (vi) { 1.108 + int samp_buf, samples; 1.109 + glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); 1.110 + glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples); 1.111 + 1.112 + //SkDebugf(" Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," 1.113 + // " SAMPLES = %d\n", 1.114 + // i, (unsigned int)vi->visualid, samp_buf, samples); 1.115 + 1.116 + if (best_fbc < 0 || (samp_buf && samples > best_num_samp)) 1.117 + best_fbc = i, best_num_samp = samples; 1.118 + } 1.119 + XFree(vi); 1.120 + } 1.121 + 1.122 + GLXFBConfig bestFbc = fbc[best_fbc]; 1.123 + 1.124 + // Be sure to free the FBConfig list allocated by glXChooseFBConfig() 1.125 + XFree(fbc); 1.126 + 1.127 + // Get a visual 1.128 + XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc); 1.129 + //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid); 1.130 +#else 1.131 + int numVisuals; 1.132 + XVisualInfo visTemplate, *visReturn; 1.133 + 1.134 + visReturn = XGetVisualInfo(fDisplay, VisualNoMask, &visTemplate, &numVisuals); 1.135 + if (NULL == visReturn) 1.136 + { 1.137 + SkDebugf("Failed to get visual information.\n"); 1.138 + this->destroyGLContext(); 1.139 + return NULL; 1.140 + } 1.141 + 1.142 + int best = -1, best_num_samp = -1; 1.143 + 1.144 + for (int i = 0; i < numVisuals; ++i) 1.145 + { 1.146 + int samp_buf, samples; 1.147 + 1.148 + glXGetConfig(fDisplay, &visReturn[i], GLX_SAMPLE_BUFFERS, &samp_buf); 1.149 + glXGetConfig(fDisplay, &visReturn[i], GLX_SAMPLES, &samples); 1.150 + 1.151 + if (best < 0 || (samp_buf && samples > best_num_samp)) 1.152 + best = i, best_num_samp = samples; 1.153 + } 1.154 + 1.155 + XVisualInfo temp = visReturn[best]; 1.156 + XVisualInfo *vi = &temp; 1.157 + 1.158 + XFree(visReturn); 1.159 +#endif 1.160 + 1.161 + fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth); 1.162 + 1.163 + if (!fPixmap) { 1.164 + SkDebugf("Failed to create pixmap.\n"); 1.165 + this->destroyGLContext(); 1.166 + return NULL; 1.167 + } 1.168 + 1.169 + fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap); 1.170 + 1.171 +#ifdef GLX_1_3 1.172 + // Done with the visual info data 1.173 + XFree(vi); 1.174 +#endif 1.175 + 1.176 + // Create the context 1.177 + 1.178 + // Install an X error handler so the application won't exit if GL 3.0 1.179 + // context allocation fails. 1.180 + // 1.181 + // Note this error handler is global. 1.182 + // All display connections in all threads of a process use the same 1.183 + // error handler, so be sure to guard against other threads issuing 1.184 + // X commands while this code is running. 1.185 + ctxErrorOccurred = false; 1.186 + int (*oldHandler)(Display*, XErrorEvent*) = 1.187 + XSetErrorHandler(&ctxErrorHandler); 1.188 + 1.189 + // Get the default screen's GLX extension list 1.190 + const char *glxExts = glXQueryExtensionsString( 1.191 + fDisplay, DefaultScreen(fDisplay) 1.192 + ); 1.193 + // Check for the GLX_ARB_create_context extension string and the function. 1.194 + // If either is not present, use GLX 1.3 context creation method. 1.195 + if (!gluCheckExtension( 1.196 + reinterpret_cast<const GLubyte*>("GLX_ARB_create_context") 1.197 + , reinterpret_cast<const GLubyte*>(glxExts))) 1.198 + { 1.199 + //SkDebugf("GLX_ARB_create_context not found." 1.200 + // " Using old-style GLX context.\n"); 1.201 +#ifdef GLX_1_3 1.202 + fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True); 1.203 +#else 1.204 + fContext = glXCreateContext(fDisplay, vi, 0, True); 1.205 +#endif 1.206 + 1.207 + } 1.208 +#ifdef GLX_1_3 1.209 + else { 1.210 + //SkDebugf("Creating context.\n"); 1.211 + 1.212 + PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = 1.213 + (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB"); 1.214 + int context_attribs[] = { 1.215 + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, 1.216 + GLX_CONTEXT_MINOR_VERSION_ARB, 0, 1.217 + //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, 1.218 + None 1.219 + }; 1.220 + fContext = glXCreateContextAttribsARB( 1.221 + fDisplay, bestFbc, 0, True, context_attribs 1.222 + ); 1.223 + 1.224 + // Sync to ensure any errors generated are processed. 1.225 + XSync(fDisplay, False); 1.226 + if (!ctxErrorOccurred && fContext) { 1.227 + //SkDebugf( "Created GL 3.0 context.\n" ); 1.228 + } else { 1.229 + // Couldn't create GL 3.0 context. 1.230 + // Fall back to old-style 2.x context. 1.231 + // When a context version below 3.0 is requested, 1.232 + // implementations will return the newest context version compatible 1.233 + // with OpenGL versions less than version 3.0. 1.234 + 1.235 + // GLX_CONTEXT_MAJOR_VERSION_ARB = 1 1.236 + context_attribs[1] = 1; 1.237 + // GLX_CONTEXT_MINOR_VERSION_ARB = 0 1.238 + context_attribs[3] = 0; 1.239 + 1.240 + ctxErrorOccurred = false; 1.241 + 1.242 + //SkDebugf("Failed to create GL 3.0 context." 1.243 + // " Using old-style GLX context.\n"); 1.244 + fContext = glXCreateContextAttribsARB( 1.245 + fDisplay, bestFbc, 0, True, context_attribs 1.246 + ); 1.247 + } 1.248 + } 1.249 +#endif 1.250 + 1.251 + // Sync to ensure any errors generated are processed. 1.252 + XSync(fDisplay, False); 1.253 + 1.254 + // Restore the original error handler 1.255 + XSetErrorHandler(oldHandler); 1.256 + 1.257 + if (ctxErrorOccurred || !fContext) { 1.258 + SkDebugf("Failed to create an OpenGL context.\n"); 1.259 + this->destroyGLContext(); 1.260 + return NULL; 1.261 + } 1.262 + 1.263 + // Verify that context is a direct context 1.264 + if (!glXIsDirect(fDisplay, fContext)) { 1.265 + //SkDebugf("Indirect GLX rendering context obtained.\n"); 1.266 + } else { 1.267 + //SkDebugf("Direct GLX rendering context obtained.\n"); 1.268 + } 1.269 + 1.270 + //SkDebugf("Making context current.\n"); 1.271 + if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { 1.272 + SkDebugf("Could not set the context.\n"); 1.273 + this->destroyGLContext(); 1.274 + return NULL; 1.275 + } 1.276 + 1.277 + const GrGLInterface* interface = GrGLCreateNativeInterface(); 1.278 + if (!interface) { 1.279 + SkDebugf("Failed to create gl interface"); 1.280 + this->destroyGLContext(); 1.281 + return NULL; 1.282 + } 1.283 + return interface; 1.284 +} 1.285 + 1.286 +void SkNativeGLContext::makeCurrent() const { 1.287 + if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { 1.288 + SkDebugf("Could not set the context.\n"); 1.289 + } 1.290 +} 1.291 + 1.292 +void SkNativeGLContext::swapBuffers() const { 1.293 + glXSwapBuffers(fDisplay, fGlxPixmap); 1.294 +}