blob: 40a1b5d366bd3838167b72ad1be57b7212f3cf8b [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +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 */
bungeman@google.com16bab872011-05-17 14:24:46 +00008#include "SkEGLContext.h"
9#include "SkTypes.h"
10
11#include <GL/gl.h>
12#include <GL/glext.h>
13#include <GL/glu.h>
14#include <GL/glx.h>
15#include <X11/Xlib.h>
16
17#define SK_GL_GET_PROC(T, F) T F = NULL; \
18 F = (T) glXGetProcAddressARB(reinterpret_cast<const GLubyte*>(#F));
19
20static bool ctxErrorOccurred = false;
21static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
22 ctxErrorOccurred = true;
23 return 0;
24}
25
bsalomon@google.com971d0c82011-08-19 17:22:05 +000026SkEGLContext::SkEGLContext()
27 : fFBO(0)
28 , context(NULL)
29 , display(NULL)
30 , pixmap(0)
31 , glxPixmap(0) {
bungeman@google.com16bab872011-05-17 14:24:46 +000032}
33
34SkEGLContext::~SkEGLContext() {
35 if (this->display) {
36 glXMakeCurrent(this->display, 0, 0);
37
38 if (this->context)
39 glXDestroyContext(this->display, this->context);
40
41 if (this->glxPixmap)
42 glXDestroyGLXPixmap(this->display, this->glxPixmap);
43
44 if (this->pixmap)
45 XFreePixmap(this->display, this->pixmap);
46
47 XCloseDisplay(this->display);
48 }
49}
50
51bool SkEGLContext::init(const int width, const int height) {
52 Display *display = XOpenDisplay(0);
53 this->display = display;
54
55 if (!display) {
56 SkDebugf("Failed to open X display.\n");
57 return false;
58 }
59
60 // Get a matching FB config
61 static int visual_attribs[] = {
62 GLX_X_RENDERABLE , True,
63 GLX_DRAWABLE_TYPE , GLX_PIXMAP_BIT,
64 GLX_RENDER_TYPE , GLX_RGBA_BIT,
65 GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
66 GLX_RED_SIZE , 8,
67 GLX_GREEN_SIZE , 8,
68 GLX_BLUE_SIZE , 8,
69 GLX_ALPHA_SIZE , 8,
70 GLX_DEPTH_SIZE , 24,
71 GLX_STENCIL_SIZE , 8,
72 GLX_DOUBLEBUFFER , True,
73 //GLX_SAMPLE_BUFFERS , 1,
74 //GLX_SAMPLES , 4,
75 None
76 };
77
78 int glx_major, glx_minor;
79
80 // FBConfigs were added in GLX version 1.3.
81 if (!glXQueryVersion( display, &glx_major, &glx_minor) ||
82 ( (glx_major == 1) && (glx_minor < 3) ) || (glx_major < 1))
83 {
84 SkDebugf("Invalid GLX version.");
85 return false;
86 }
87
88 //SkDebugf("Getting matching framebuffer configs.\n");
89 int fbcount;
90 GLXFBConfig *fbc = glXChooseFBConfig(display, DefaultScreen(display),
91 visual_attribs, &fbcount);
92 if (!fbc) {
93 SkDebugf("Failed to retrieve a framebuffer config.\n");
94 return false;
95 }
96 //SkDebugf("Found %d matching FB configs.\n", fbcount);
97
98 // Pick the FB config/visual with the most samples per pixel
99 //SkDebugf("Getting XVisualInfos.\n");
100 int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
101
102 int i;
103 for (i = 0; i < fbcount; ++i) {
104 XVisualInfo *vi = glXGetVisualFromFBConfig(display, fbc[i]);
105 if (vi) {
106 int samp_buf, samples;
107 glXGetFBConfigAttrib(display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
108 glXGetFBConfigAttrib(display, fbc[i], GLX_SAMPLES, &samples);
109
110 //SkDebugf(" Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
111 // " SAMPLES = %d\n",
112 // i, (unsigned int)vi->visualid, samp_buf, samples);
113
114 if (best_fbc < 0 || (samp_buf && samples > best_num_samp))
115 best_fbc = i, best_num_samp = samples;
116 if (worst_fbc < 0 || !samp_buf || samples < worst_num_samp)
117 worst_fbc = i, worst_num_samp = samples;
118 }
119 XFree(vi);
120 }
121
122 GLXFBConfig bestFbc = fbc[best_fbc];
123
124 // Be sure to free the FBConfig list allocated by glXChooseFBConfig()
125 XFree(fbc);
126
127 // Get a visual
128 XVisualInfo *vi = glXGetVisualFromFBConfig(display, bestFbc);
129 //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid);
130
131 Pixmap pixmap = XCreatePixmap(
132 display, RootWindow(display, vi->screen), width, height, vi->depth
133 );
134
135 this->pixmap = pixmap;
136 if (!pixmap) {
137 SkDebugf("Failed to create pixmap.\n");
138 return false;
139 }
140
141 GLXPixmap glxPixmap = glXCreateGLXPixmap(display, vi, pixmap);
142 this->glxPixmap = glxPixmap;
143
144 // Done with the visual info data
145 XFree(vi);
146
147 // Create the context
148 GLXContext ctx = 0;
149
150 // Install an X error handler so the application won't exit if GL 3.0
151 // context allocation fails.
152 //
153 // Note this error handler is global.
154 // All display connections in all threads of a process use the same
155 // error handler, so be sure to guard against other threads issuing
156 // X commands while this code is running.
157 ctxErrorOccurred = false;
158 int (*oldHandler)(Display*, XErrorEvent*) =
159 XSetErrorHandler(&ctxErrorHandler);
160
161 // Get the default screen's GLX extension list
162 const char *glxExts = glXQueryExtensionsString(
163 display, DefaultScreen(display)
164 );
165 // Check for the GLX_ARB_create_context extension string and the function.
166 // If either is not present, use GLX 1.3 context creation method.
167 if (!gluCheckExtension(
168 reinterpret_cast<const GLubyte*>("GLX_ARB_create_context")
169 , reinterpret_cast<const GLubyte*>(glxExts)))
170 {
171 //SkDebugf("GLX_ARB_create_context not found."
172 // " Using old-style GLX context.\n");
173 ctx = glXCreateNewContext(display, bestFbc, GLX_RGBA_TYPE, 0, True);
174
175 } else {
176 //SkDebugf("Creating context.\n");
177
178 SK_GL_GET_PROC(PFNGLXCREATECONTEXTATTRIBSARBPROC, glXCreateContextAttribsARB)
179 int context_attribs[] = {
180 GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
181 GLX_CONTEXT_MINOR_VERSION_ARB, 0,
182 //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
183 None
184 };
185 ctx = glXCreateContextAttribsARB(
186 display, bestFbc, 0, True, context_attribs
187 );
188
189 // Sync to ensure any errors generated are processed.
190 XSync(display, False);
191 if (!ctxErrorOccurred && ctx) {
192 //SkDebugf( "Created GL 3.0 context.\n" );
193 } else {
194 // Couldn't create GL 3.0 context.
195 // Fall back to old-style 2.x context.
196 // When a context version below 3.0 is requested,
197 // implementations will return the newest context version compatible
198 // with OpenGL versions less than version 3.0.
199
200 // GLX_CONTEXT_MAJOR_VERSION_ARB = 1
201 context_attribs[1] = 1;
202 // GLX_CONTEXT_MINOR_VERSION_ARB = 0
203 context_attribs[3] = 0;
204
205 ctxErrorOccurred = false;
206
207 //SkDebugf("Failed to create GL 3.0 context."
208 // " Using old-style GLX context.\n");
209 ctx = glXCreateContextAttribsARB(
210 display, bestFbc, 0, True, context_attribs
211 );
212 }
213 }
214
215 // Sync to ensure any errors generated are processed.
216 XSync(display, False);
217
218 // Restore the original error handler
219 XSetErrorHandler(oldHandler);
220
221 if (ctxErrorOccurred || !ctx) {
222 SkDebugf("Failed to create an OpenGL context.\n");
223 return false;
224 }
225 this->context = ctx;
226
227 // Verify that context is a direct context
228 if (!glXIsDirect(display, ctx)) {
229 //SkDebugf("Indirect GLX rendering context obtained.\n");
230 } else {
231 //SkDebugf("Direct GLX rendering context obtained.\n");
232 }
233
234 //SkDebugf("Making context current.\n");
235 if (!glXMakeCurrent(display, glxPixmap, ctx)) {
236 SkDebugf("Could not set the context.\n");
237 return false;
238 }
239
240 //Setup the framebuffers
241 const GLubyte* glExts = glGetString(GL_EXTENSIONS);
242 if (!gluCheckExtension(
243 reinterpret_cast<const GLubyte*>("GL_EXT_framebuffer_object")
244 , glExts))
245 {
246 SkDebugf("GL_EXT_framebuffer_object not found.\n");
247 return false;
248 }
249 SK_GL_GET_PROC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT)
250 SK_GL_GET_PROC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT)
251 SK_GL_GET_PROC(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffersEXT)
252 SK_GL_GET_PROC(PFNGLBINDRENDERBUFFERPROC, glBindRenderbufferEXT)
253 SK_GL_GET_PROC(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorageEXT)
254 SK_GL_GET_PROC(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbufferEXT)
255 SK_GL_GET_PROC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatusEXT)
256
bungeman@google.com16bab872011-05-17 14:24:46 +0000257 GLuint cbID;
258 GLuint dsID;
bsalomon@google.com971d0c82011-08-19 17:22:05 +0000259 glGenFramebuffersEXT(1, &fFBO);
260 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFBO);
bungeman@google.com16bab872011-05-17 14:24:46 +0000261 glGenRenderbuffersEXT(1, &cbID);
262 glBindRenderbufferEXT(GL_RENDERBUFFER, cbID);
263 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA, width, height);
264 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cbID);
265 glGenRenderbuffersEXT(1, &dsID);
266 glBindRenderbufferEXT(GL_RENDERBUFFER, dsID);
267 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
268 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dsID);
269 glViewport(0, 0, width, height);
270 glClearStencil(0);
271 glClear(GL_STENCIL_BUFFER_BIT);
272
273 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
274 return GL_FRAMEBUFFER_COMPLETE == status;
275}