blob: bd130b545cd9af62de9002dfbc6aef2f0e4b85da [file] [log] [blame]
bsalomon@google.com373a6632011-10-19 20:43:20 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
bsalomon10805962014-10-08 04:45:09 -07008#include "gl/SkNativeGLContext.h"
bsalomon@google.com373a6632011-10-19 20:43:20 +00009
10#include <GL/glu.h>
11
joshualittc863ab02014-08-07 13:48:49 -070012/* Note: Skia requires glx 1.3 or newer */
robertphillips@google.combb89cda2012-03-14 18:06:26 +000013
bsalomon10805962014-10-08 04:45:09 -070014SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
15 fOldGLXContext = glXGetCurrentContext();
16 fOldDisplay = glXGetCurrentDisplay();
17 fOldDrawable = glXGetCurrentDrawable();
18}
19
20SkNativeGLContext::AutoContextRestore::~AutoContextRestore() {
21 if (fOldDisplay) {
22 glXMakeCurrent(fOldDisplay, fOldDrawable, fOldGLXContext);
23 }
24}
25
26///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com373a6632011-10-19 20:43:20 +000027
28static bool ctxErrorOccurred = false;
29static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
30 ctxErrorOccurred = true;
31 return 0;
32}
33
bsalomon10805962014-10-08 04:45:09 -070034SkNativeGLContext::SkNativeGLContext()
bsalomon@google.com373a6632011-10-19 20:43:20 +000035 : fContext(NULL)
36 , fDisplay(NULL)
37 , fPixmap(0)
38 , fGlxPixmap(0) {
39}
40
bsalomon10805962014-10-08 04:45:09 -070041SkNativeGLContext::~SkNativeGLContext() {
bsalomon@google.com373a6632011-10-19 20:43:20 +000042 this->destroyGLContext();
43}
44
bsalomon10805962014-10-08 04:45:09 -070045void SkNativeGLContext::destroyGLContext() {
bsalomon@google.com373a6632011-10-19 20:43:20 +000046 if (fDisplay) {
47 glXMakeCurrent(fDisplay, 0, 0);
48
49 if (fContext) {
50 glXDestroyContext(fDisplay, fContext);
51 fContext = NULL;
52 }
53
54 if (fGlxPixmap) {
55 glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
56 fGlxPixmap = 0;
57 }
58
59 if (fPixmap) {
60 XFreePixmap(fDisplay, fPixmap);
61 fPixmap = 0;
62 }
63
64 XCloseDisplay(fDisplay);
65 fDisplay = NULL;
66 }
67}
68
bsalomon10805962014-10-08 04:45:09 -070069const GrGLInterface* SkNativeGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
bsalomon@google.com373a6632011-10-19 20:43:20 +000070 fDisplay = XOpenDisplay(0);
71
72 if (!fDisplay) {
73 SkDebugf("Failed to open X display.\n");
74 this->destroyGLContext();
75 return NULL;
76 }
77
78 // Get a matching FB config
79 static int visual_attribs[] = {
80 GLX_X_RENDERABLE , True,
81 GLX_DRAWABLE_TYPE , GLX_PIXMAP_BIT,
82 None
83 };
84
joshualittc863ab02014-08-07 13:48:49 -070085 int glx_major, glx_minor;
86
87 // FBConfigs were added in GLX version 1.3.
88 if (!glXQueryVersion(fDisplay, &glx_major, &glx_minor) ||
89 ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) {
90 SkDebugf("GLX version 1.3 or higher required.\n");
91 this->destroyGLContext();
92 return NULL;
93 }
94
bsalomon@google.com373a6632011-10-19 20:43:20 +000095 //SkDebugf("Getting matching framebuffer configs.\n");
96 int fbcount;
97 GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay),
98 visual_attribs, &fbcount);
99 if (!fbc) {
100 SkDebugf("Failed to retrieve a framebuffer config.\n");
101 this->destroyGLContext();
102 return NULL;
103 }
104 //SkDebugf("Found %d matching FB configs.\n", fbcount);
105
106 // Pick the FB config/visual with the most samples per pixel
107 //SkDebugf("Getting XVisualInfos.\n");
robertphillips@google.combb89cda2012-03-14 18:06:26 +0000108 int best_fbc = -1, best_num_samp = -1;
bsalomon@google.com373a6632011-10-19 20:43:20 +0000109
110 int i;
111 for (i = 0; i < fbcount; ++i) {
112 XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]);
113 if (vi) {
114 int samp_buf, samples;
115 glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
116 glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples);
117
118 //SkDebugf(" Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
119 // " SAMPLES = %d\n",
120 // i, (unsigned int)vi->visualid, samp_buf, samples);
121
122 if (best_fbc < 0 || (samp_buf && samples > best_num_samp))
123 best_fbc = i, best_num_samp = samples;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000124 }
bsalomon@google.com373a6632011-10-19 20:43:20 +0000125 XFree(vi);
126 }
127
128 GLXFBConfig bestFbc = fbc[best_fbc];
129
130 // Be sure to free the FBConfig list allocated by glXChooseFBConfig()
131 XFree(fbc);
132
133 // Get a visual
134 XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc);
135 //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid);
136
137 fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth);
138
139 if (!fPixmap) {
140 SkDebugf("Failed to create pixmap.\n");
141 this->destroyGLContext();
142 return NULL;
143 }
144
145 fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap);
146
147 // Done with the visual info data
148 XFree(vi);
149
150 // Create the context
151
152 // Install an X error handler so the application won't exit if GL 3.0
153 // context allocation fails.
154 //
155 // Note this error handler is global.
156 // All display connections in all threads of a process use the same
157 // error handler, so be sure to guard against other threads issuing
158 // X commands while this code is running.
159 ctxErrorOccurred = false;
160 int (*oldHandler)(Display*, XErrorEvent*) =
161 XSetErrorHandler(&ctxErrorHandler);
162
163 // Get the default screen's GLX extension list
164 const char *glxExts = glXQueryExtensionsString(
165 fDisplay, DefaultScreen(fDisplay)
166 );
kkinnunen80549fc2014-06-30 06:36:31 -0700167
168
bsalomon@google.com373a6632011-10-19 20:43:20 +0000169 // Check for the GLX_ARB_create_context extension string and the function.
170 // If either is not present, use GLX 1.3 context creation method.
kkinnunen80549fc2014-06-30 06:36:31 -0700171 if (!gluCheckExtension(reinterpret_cast<const GLubyte*>("GLX_ARB_create_context"),
172 reinterpret_cast<const GLubyte*>(glxExts))) {
173 if (kGLES_GrGLStandard != forcedGpuAPI) {
kkinnunen80549fc2014-06-30 06:36:31 -0700174 fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
kkinnunen80549fc2014-06-30 06:36:31 -0700175 }
joshualittc863ab02014-08-07 13:48:49 -0700176 } else {
bsalomon@google.com373a6632011-10-19 20:43:20 +0000177 //SkDebugf("Creating context.\n");
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000178 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB =
bsalomon@google.com373a6632011-10-19 20:43:20 +0000179 (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
kkinnunen80549fc2014-06-30 06:36:31 -0700180
kkinnunen80549fc2014-06-30 06:36:31 -0700181 if (kGLES_GrGLStandard == forcedGpuAPI) {
182 if (gluCheckExtension(
183 reinterpret_cast<const GLubyte*>("GLX_EXT_create_context_es2_profile"),
184 reinterpret_cast<const GLubyte*>(glxExts))) {
joshualittc863ab02014-08-07 13:48:49 -0700185 static const int context_attribs_gles[] = {
186 GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
187 GLX_CONTEXT_MINOR_VERSION_ARB, 0,
188 GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
189 None
190 };
kkinnunen80549fc2014-06-30 06:36:31 -0700191 fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True,
192 context_attribs_gles);
193 }
bsalomon@google.com373a6632011-10-19 20:43:20 +0000194 } else {
joshualittc863ab02014-08-07 13:48:49 -0700195 // Well, unfortunately GLX will not just give us the highest context so instead we have
196 // to do this nastiness
197 for (i = NUM_GL_VERSIONS - 2; i > 0 ; i--) {
198 /* don't bother below GL 3.0 */
199 if (gl_versions[i].major == 3 && gl_versions[i].minor == 0) {
200 break;
201 }
202 // On Nvidia GPUs, to use Nv Path rendering we need a compatibility profile for the
203 // time being.
204 // TODO when Nvidia implements NVPR on Core profiles, we should start requesting
205 // core here
206 static const int context_attribs_gl[] = {
207 GLX_CONTEXT_MAJOR_VERSION_ARB, gl_versions[i].major,
208 GLX_CONTEXT_MINOR_VERSION_ARB, gl_versions[i].minor,
209 GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
210 None
211 };
212 fContext =
213 glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True, context_attribs_gl);
bsalomon@google.com373a6632011-10-19 20:43:20 +0000214
joshualittc863ab02014-08-07 13:48:49 -0700215 // Sync to ensure any errors generated are processed.
216 XSync(fDisplay, False);
217
218 if (!ctxErrorOccurred && fContext) {
219 break;
220 }
221 // try again
222 ctxErrorOccurred = false;
223 }
224
225 // Couldn't create GL 3.0 context.
226 // Fall back to old-style 2.x context.
227 // When a context version below 3.0 is requested,
228 // implementations will return the newest context version
229 // compatible with OpenGL versions less than version 3.0.
kkinnunen80549fc2014-06-30 06:36:31 -0700230 if (ctxErrorOccurred || !fContext) {
joshualittc863ab02014-08-07 13:48:49 -0700231 static const int context_attribs_gl_fallback[] = {
232 GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
233 GLX_CONTEXT_MINOR_VERSION_ARB, 0,
234 None
235 };
bsalomon@google.com373a6632011-10-19 20:43:20 +0000236
kkinnunen80549fc2014-06-30 06:36:31 -0700237 ctxErrorOccurred = false;
bsalomon@google.com373a6632011-10-19 20:43:20 +0000238
kkinnunen80549fc2014-06-30 06:36:31 -0700239 fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True,
240 context_attribs_gl_fallback);
241 }
bsalomon@google.com373a6632011-10-19 20:43:20 +0000242 }
243 }
bsalomon@google.com373a6632011-10-19 20:43:20 +0000244
245 // Sync to ensure any errors generated are processed.
246 XSync(fDisplay, False);
247
248 // Restore the original error handler
249 XSetErrorHandler(oldHandler);
250
251 if (ctxErrorOccurred || !fContext) {
252 SkDebugf("Failed to create an OpenGL context.\n");
253 this->destroyGLContext();
254 return NULL;
255 }
256
257 // Verify that context is a direct context
258 if (!glXIsDirect(fDisplay, fContext)) {
259 //SkDebugf("Indirect GLX rendering context obtained.\n");
260 } else {
261 //SkDebugf("Direct GLX rendering context obtained.\n");
262 }
263
264 //SkDebugf("Making context current.\n");
265 if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
266 SkDebugf("Could not set the context.\n");
267 this->destroyGLContext();
268 return NULL;
269 }
270
271 const GrGLInterface* interface = GrGLCreateNativeInterface();
272 if (!interface) {
273 SkDebugf("Failed to create gl interface");
274 this->destroyGLContext();
275 return NULL;
276 }
277 return interface;
278}
279
bsalomon10805962014-10-08 04:45:09 -0700280void SkNativeGLContext::makeCurrent() const {
bsalomon@google.com373a6632011-10-19 20:43:20 +0000281 if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
282 SkDebugf("Could not set the context.\n");
283 }
284}
djsollen@google.comc9542ca2013-10-09 18:25:38 +0000285
bsalomon10805962014-10-08 04:45:09 -0700286void SkNativeGLContext::swapBuffers() const {
djsollen@google.comc9542ca2013-10-09 18:25:38 +0000287 glXSwapBuffers(fDisplay, fGlxPixmap);
288}