1 /*
2 * Copyright © 2010-2011 Linaro Limited
3 * Copyright © 2013 Canonical Ltd
4 *
5 * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
6 *
7 * glmark2 is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later
10 * version.
11 *
12 * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15 * details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * glmark2. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * Authors:
21 * Alexandros Frantzis
22 */
23 #include "gl-state-glx.h"
24 #include "log.h"
25 #include "options.h"
26
27 #include <climits>
28
29 /******************
30 * Public methods *
31 ******************/
32
33 bool
init_display(void * native_display,GLVisualConfig & visual_config)34 GLStateGLX::init_display(void* native_display, GLVisualConfig& visual_config)
35 {
36 xdpy_ = reinterpret_cast<Display*>(native_display);
37 requested_visual_config_ = visual_config;
38
39 if (!lib_.open_from_alternatives({"libGL.so", "libGL.so.1"})) {
40 Log::error("Failed to load libGL\n");
41 return false;
42 }
43
44 gladLoadGLXUserPtr(xdpy_, DefaultScreen(xdpy_), load_proc, this);
45 return (xdpy_ != 0);
46 }
47
48 bool
init_surface(void * native_window)49 GLStateGLX::init_surface(void* native_window)
50 {
51 xwin_ = reinterpret_cast<Window>(native_window);
52
53 return (xwin_ != 0);
54 }
55
56 bool
init_gl_extensions()57 GLStateGLX::init_gl_extensions()
58 {
59 GLExtensions::MapBuffer = glMapBuffer;
60 GLExtensions::UnmapBuffer = glUnmapBuffer;
61
62 GLExtensions::GenFramebuffers = glGenFramebuffersEXT;
63 GLExtensions::DeleteFramebuffers = glDeleteFramebuffersEXT;
64 GLExtensions::BindFramebuffer = glBindFramebufferEXT;
65 GLExtensions::FramebufferTexture2D = glFramebufferTexture2DEXT;
66 GLExtensions::FramebufferRenderbuffer = glFramebufferRenderbufferEXT;
67 GLExtensions::CheckFramebufferStatus = glCheckFramebufferStatusEXT;
68
69 GLExtensions::GenRenderbuffers = glGenRenderbuffersEXT;
70 GLExtensions::DeleteRenderbuffers = glDeleteRenderbuffersEXT;
71 GLExtensions::BindRenderbuffer = glBindRenderbufferEXT;
72 GLExtensions::RenderbufferStorage = glRenderbufferStorageEXT;
73
74 GLExtensions::GenerateMipmap = glGenerateMipmapEXT;
75
76 return true;
77 }
78
79 bool
valid()80 GLStateGLX::valid()
81 {
82 if (!ensure_glx_fbconfig())
83 return false;
84
85 if (!ensure_glx_context())
86 return false;
87
88 if (glx_context_ == glXGetCurrentContext())
89 return true;
90
91 init_extensions();
92
93 if (!glXMakeCurrent(xdpy_, xwin_, glx_context_)) {
94 Log::error("glXMakeCurrent failed\n");
95 return false;
96 }
97
98 if (gladLoadGLUserPtr(load_proc, this) == 0) {
99 Log::error("Failed to load GL entry points\n");
100 return false;
101 }
102
103 if (!init_gl_extensions())
104 return false;
105
106 unsigned int desired_swap(0);
107 unsigned int actual_swap(-1);
108 if (glXSwapIntervalEXT) {
109 glXSwapIntervalEXT(xdpy_, xwin_, desired_swap);
110 glXQueryDrawable(xdpy_, xwin_, GLX_SWAP_INTERVAL_EXT, &actual_swap);
111 if (actual_swap == desired_swap)
112 return true;
113 }
114
115 if (glXSwapIntervalMESA) {
116 glXSwapIntervalMESA(desired_swap);
117 actual_swap = glXGetSwapIntervalMESA();
118 if (actual_swap == desired_swap)
119 return true;
120 }
121
122 Log::info("** Failed to set swap interval. Results may be bounded above by refresh rate.\n");
123
124 return true;
125 }
126
127
128 bool
reset()129 GLStateGLX::reset()
130 {
131 if (glx_context_)
132 {
133 glXDestroyContext(xdpy_, glx_context_);
134 glx_context_ = 0;
135 }
136
137 return true;
138 }
139
140 void
swap()141 GLStateGLX::swap()
142 {
143 glXSwapBuffers(xdpy_, xwin_);
144 }
145
146 bool
gotNativeConfig(intptr_t & vid)147 GLStateGLX::gotNativeConfig(intptr_t& vid)
148 {
149 if (!ensure_glx_fbconfig())
150 return false;
151
152 int native_id;
153 if (glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_VISUAL_ID, &native_id) != Success)
154 {
155 Log::debug("Failed to get native visual id for GLXFBConfig 0x%x\n", glx_fbconfig_);
156 return false;
157 }
158
159 vid = native_id;
160 return true;
161 }
162
163 void
getVisualConfig(GLVisualConfig & vc)164 GLStateGLX::getVisualConfig(GLVisualConfig& vc)
165 {
166 if (!ensure_glx_fbconfig())
167 return;
168
169 get_glvisualconfig_glx(glx_fbconfig_, vc);
170 }
171
172 /*******************
173 * Private methods *
174 *******************/
175
176 bool
check_glx_version()177 GLStateGLX::check_glx_version()
178 {
179 int glx_major, glx_minor;
180
181 if (!glXQueryVersion(xdpy_, &glx_major, &glx_minor ) ||
182 (glx_major == 1 && glx_minor < 3) || glx_major < 1)
183 {
184 Log::error("GLX version >= 1.3 is required\n");
185 return false;
186 }
187
188 return true;
189 }
190
191 void
init_extensions()192 GLStateGLX::init_extensions()
193 {
194 /*
195 * Parse the extensions we care about from the extension string.
196 * Don't even bother to get function pointers until we know the
197 * extension is present.
198 */
199 std::string extString;
200 const char* exts = glXQueryExtensionsString(xdpy_, 0);
201 if (exts) {
202 extString = exts;
203 }
204
205 /*
206 * GLX_EXT_swap_control or GL_MESA_swap_control. Note that
207 * GLX_SGI_swap_control is not enough because it doesn't allow 0 as a valid
208 * value (i.e. you can't turn off VSync).
209 */
210 if (!glXSwapIntervalEXT && !glXSwapIntervalMESA) {
211 Log::info("** GLX does not support GLX_EXT_swap_control or GLX_MESA_swap_control!\n");
212 }
213 }
214
215 bool
ensure_glx_fbconfig()216 GLStateGLX::ensure_glx_fbconfig()
217 {
218 static int attribs[] = {
219 GLX_X_RENDERABLE, True,
220 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
221 GLX_RENDER_TYPE, GLX_RGBA_BIT,
222 GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
223 GLX_RED_SIZE, requested_visual_config_.red,
224 GLX_GREEN_SIZE, requested_visual_config_.green,
225 GLX_BLUE_SIZE, requested_visual_config_.blue,
226 GLX_ALPHA_SIZE, requested_visual_config_.alpha,
227 GLX_DEPTH_SIZE, requested_visual_config_.depth,
228 GLX_STENCIL_SIZE, requested_visual_config_.stencil,
229 GLX_BUFFER_SIZE, requested_visual_config_.buffer,
230 GLX_DOUBLEBUFFER, True,
231 None
232 };
233 int num_configs;
234
235 if (glx_fbconfig_)
236 return true;
237
238 if (!check_glx_version())
239 return false;
240
241 GLXFBConfig *fbc = glXChooseFBConfig(xdpy_, DefaultScreen(xdpy_),
242 attribs, &num_configs);
243 if (!fbc) {
244 Log::error("glXChooseFBConfig() failed\n");
245 return false;
246 }
247
248 std::vector<GLXFBConfig> configs(fbc, fbc + num_configs);
249
250 Log::debug("Found %d matching FB configs.\n", num_configs);
251
252 /* Select the best matching config */
253 glx_fbconfig_ = select_best_config(configs);
254
255 XFree(fbc);
256
257 if (Options::show_debug) {
258 int buf, red, green, blue, alpha, depth, stencil, id, native_id;
259 glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_FBCONFIG_ID, &id);
260 glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_VISUAL_ID, &native_id);
261 glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_BUFFER_SIZE, &buf);
262 glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_RED_SIZE, &red);
263 glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_GREEN_SIZE, &green);
264 glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_BLUE_SIZE, &blue);
265 glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_ALPHA_SIZE, &alpha);
266 glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_DEPTH_SIZE, &depth);
267 glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_STENCIL_SIZE, &stencil);
268 Log::debug("GLX chosen config ID: 0x%x Native Visual ID: 0x%x\n"
269 " Buffer: %d bits\n"
270 " Red: %d bits\n"
271 " Green: %d bits\n"
272 " Blue: %d bits\n"
273 " Alpha: %d bits\n"
274 " Depth: %d bits\n"
275 " Stencil: %d bits\n",
276 id, native_id,
277 buf, red, green, blue, alpha, depth, stencil);
278 }
279
280
281 return true;
282 }
283
284 bool
ensure_glx_context()285 GLStateGLX::ensure_glx_context()
286 {
287 if (glx_context_)
288 return true;
289
290 if (!ensure_glx_fbconfig())
291 return false;
292
293 glx_context_ = glXCreateNewContext(xdpy_, glx_fbconfig_, GLX_RGBA_TYPE,
294 0, True);
295 if (!glx_context_) {
296 Log::error("glXCreateNewContext failed\n");
297 return false;
298 }
299
300
301 return true;
302 }
303
304 void
get_glvisualconfig_glx(const GLXFBConfig config,GLVisualConfig & visual_config)305 GLStateGLX::get_glvisualconfig_glx(const GLXFBConfig config, GLVisualConfig &visual_config)
306 {
307 glXGetFBConfigAttrib(xdpy_, config, GLX_BUFFER_SIZE, &visual_config.buffer);
308 glXGetFBConfigAttrib(xdpy_, config, GLX_RED_SIZE, &visual_config.red);
309 glXGetFBConfigAttrib(xdpy_, config, GLX_GREEN_SIZE, &visual_config.green);
310 glXGetFBConfigAttrib(xdpy_, config, GLX_BLUE_SIZE, &visual_config.blue);
311 glXGetFBConfigAttrib(xdpy_, config, GLX_ALPHA_SIZE, &visual_config.alpha);
312 glXGetFBConfigAttrib(xdpy_, config, GLX_DEPTH_SIZE, &visual_config.depth);
313 glXGetFBConfigAttrib(xdpy_, config, GLX_STENCIL_SIZE, &visual_config.stencil);
314 }
315
316 GLXFBConfig
select_best_config(std::vector<GLXFBConfig> configs)317 GLStateGLX::select_best_config(std::vector<GLXFBConfig> configs)
318 {
319 int best_score(INT_MIN);
320 GLXFBConfig best_config(0);
321
322 /*
323 * Go through all the configs and choose the one with the best score,
324 * i.e., the one better matching the requested config.
325 */
326 for (std::vector<GLXFBConfig>::const_iterator iter = configs.begin();
327 iter != configs.end();
328 iter++)
329 {
330 const GLXFBConfig config(*iter);
331 GLVisualConfig vc;
332 int score;
333
334 get_glvisualconfig_glx(config, vc);
335
336 score = vc.match_score(requested_visual_config_);
337
338 if (score > best_score) {
339 best_score = score;
340 best_config = config;
341 }
342 }
343
344 return best_config;
345 }
346
347 GLADapiproc
load_proc(void * userptr,const char * name)348 GLStateGLX::load_proc(void *userptr, const char* name)
349 {
350 if (glXGetProcAddress) {
351 const GLubyte* bytes = reinterpret_cast<const GLubyte*>(name);
352 GLADapiproc sym = glXGetProcAddress(bytes);
353 if (sym) {
354 return sym;
355 }
356 }
357
358 GLStateGLX* state = reinterpret_cast<GLStateGLX*>(userptr);
359 return reinterpret_cast<GLADapiproc>(state->lib_.load(name));
360 }
361