3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
8 #include "gl/SkGLContext.h"
16 /* Note: Skia requires glx 1.3 or newer */
18 /* This struct is taken from a mesa demo. Please update as required */
19 static const struct { int major, minor; } gl_versions[] = {
37 {0, 0} /* end of list */
39 #define NUM_GL_VERSIONS SK_ARRAY_COUNT(gl_versions)
41 static bool ctxErrorOccurred = false;
42 static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
43 ctxErrorOccurred = true;
47 class GLXGLContext : public SkGLContext {
49 GLXGLContext(GrGLStandard forcedGpuAPI);
50 ~GLXGLContext() SK_OVERRIDE;
51 void makeCurrent() const SK_OVERRIDE;
52 void swapBuffers() const SK_OVERRIDE;
55 void destroyGLContext();
63 GLXGLContext::GLXGLContext(GrGLStandard forcedGpuAPI)
69 fDisplay = XOpenDisplay(0);
72 SkDebugf("Failed to open X display.\n");
73 this->destroyGLContext();
77 // Get a matching FB config
78 static int visual_attribs[] = {
79 GLX_X_RENDERABLE , True,
80 GLX_DRAWABLE_TYPE , GLX_PIXMAP_BIT,
84 int glx_major, glx_minor;
86 // FBConfigs were added in GLX version 1.3.
87 if (!glXQueryVersion(fDisplay, &glx_major, &glx_minor) ||
88 ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) {
89 SkDebugf("GLX version 1.3 or higher required.\n");
90 this->destroyGLContext();
94 //SkDebugf("Getting matching framebuffer configs.\n");
96 GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay),
97 visual_attribs, &fbcount);
99 SkDebugf("Failed to retrieve a framebuffer config.\n");
100 this->destroyGLContext();
103 //SkDebugf("Found %d matching FB configs.\n", fbcount);
105 // Pick the FB config/visual with the most samples per pixel
106 //SkDebugf("Getting XVisualInfos.\n");
107 int best_fbc = -1, best_num_samp = -1;
110 for (i = 0; i < fbcount; ++i) {
111 XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]);
113 int samp_buf, samples;
114 glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
115 glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples);
117 //SkDebugf(" Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
118 // " SAMPLES = %d\n",
119 // i, (unsigned int)vi->visualid, samp_buf, samples);
121 if (best_fbc < 0 || (samp_buf && samples > best_num_samp))
122 best_fbc = i, best_num_samp = samples;
127 GLXFBConfig bestFbc = fbc[best_fbc];
129 // Be sure to free the FBConfig list allocated by glXChooseFBConfig()
133 XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc);
134 //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid);
136 fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth);
139 SkDebugf("Failed to create pixmap.\n");
140 this->destroyGLContext();
144 fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap);
146 // Done with the visual info data
149 // Create the context
151 // Install an X error handler so the application won't exit if GL 3.0
152 // context allocation fails.
154 // Note this error handler is global.
155 // All display connections in all threads of a process use the same
156 // error handler, so be sure to guard against other threads issuing
157 // X commands while this code is running.
158 ctxErrorOccurred = false;
159 int (*oldHandler)(Display*, XErrorEvent*) =
160 XSetErrorHandler(&ctxErrorHandler);
162 // Get the default screen's GLX extension list
163 const char *glxExts = glXQueryExtensionsString(
164 fDisplay, DefaultScreen(fDisplay)
168 // Check for the GLX_ARB_create_context extension string and the function.
169 // If either is not present, use GLX 1.3 context creation method.
170 if (!gluCheckExtension(reinterpret_cast<const GLubyte*>("GLX_ARB_create_context"),
171 reinterpret_cast<const GLubyte*>(glxExts))) {
172 if (kGLES_GrGLStandard != forcedGpuAPI) {
173 fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
176 //SkDebugf("Creating context.\n");
177 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB =
178 (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
180 if (kGLES_GrGLStandard == forcedGpuAPI) {
181 if (gluCheckExtension(
182 reinterpret_cast<const GLubyte*>("GLX_EXT_create_context_es2_profile"),
183 reinterpret_cast<const GLubyte*>(glxExts))) {
184 static const int context_attribs_gles[] = {
185 GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
186 GLX_CONTEXT_MINOR_VERSION_ARB, 0,
187 GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
190 fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True,
191 context_attribs_gles);
194 // Well, unfortunately GLX will not just give us the highest context so instead we have
195 // to do this nastiness
196 for (i = NUM_GL_VERSIONS - 2; i > 0 ; i--) {
197 /* don't bother below GL 3.0 */
198 if (gl_versions[i].major == 3 && gl_versions[i].minor == 0) {
201 // On Nvidia GPUs, to use Nv Path rendering we need a compatibility profile for the
203 // TODO when Nvidia implements NVPR on Core profiles, we should start requesting
205 static const int context_attribs_gl[] = {
206 GLX_CONTEXT_MAJOR_VERSION_ARB, gl_versions[i].major,
207 GLX_CONTEXT_MINOR_VERSION_ARB, gl_versions[i].minor,
208 GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
212 glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True, context_attribs_gl);
214 // Sync to ensure any errors generated are processed.
215 XSync(fDisplay, False);
217 if (!ctxErrorOccurred && fContext) {
221 ctxErrorOccurred = false;
224 // Couldn't create GL 3.0 context.
225 // Fall back to old-style 2.x context.
226 // When a context version below 3.0 is requested,
227 // implementations will return the newest context version
228 // compatible with OpenGL versions less than version 3.0.
229 if (ctxErrorOccurred || !fContext) {
230 static const int context_attribs_gl_fallback[] = {
231 GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
232 GLX_CONTEXT_MINOR_VERSION_ARB, 0,
236 ctxErrorOccurred = false;
238 fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True,
239 context_attribs_gl_fallback);
244 // Sync to ensure any errors generated are processed.
245 XSync(fDisplay, False);
247 // Restore the original error handler
248 XSetErrorHandler(oldHandler);
250 if (ctxErrorOccurred || !fContext) {
251 SkDebugf("Failed to create an OpenGL context.\n");
252 this->destroyGLContext();
256 // Verify that context is a direct context
257 if (!glXIsDirect(fDisplay, fContext)) {
258 //SkDebugf("Indirect GLX rendering context obtained.\n");
260 //SkDebugf("Direct GLX rendering context obtained.\n");
263 //SkDebugf("Making context current.\n");
264 if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
265 SkDebugf("Could not set the context.\n");
266 this->destroyGLContext();
270 fGL.reset(GrGLCreateNativeInterface());
271 if (NULL == fGL.get()) {
272 SkDebugf("Failed to create gl interface");
273 this->destroyGLContext();
277 if (!fGL->validate()) {
278 SkDebugf("Failed to validate gl interface");
279 this->destroyGLContext();
285 GLXGLContext::~GLXGLContext() {
286 this->destroyGLContext();
289 void GLXGLContext::destroyGLContext() {
292 glXMakeCurrent(fDisplay, 0, 0);
295 glXDestroyContext(fDisplay, fContext);
300 glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
305 XFreePixmap(fDisplay, fPixmap);
309 XCloseDisplay(fDisplay);
314 void GLXGLContext::makeCurrent() const {
315 if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
316 SkDebugf("Could not set the context.\n");
320 void GLXGLContext::swapBuffers() const {
321 glXSwapBuffers(fDisplay, fGlxPixmap);
324 } // anonymous namespace
326 SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) {
327 GLXGLContext* ctx = SkNEW_ARGS(GLXGLContext, (forcedGpuAPI));
328 if (!ctx->isValid()) {