1 //
2 // Copyright © 2012 Linaro Limited
3 //
4 // This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
5 //
6 // glmark2 is free software: you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the Free Software
8 // Foundation, either version 3 of the License, or (at your option) any later
9 // version.
10 //
11 // glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
12 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 // details.
15 //
16 // You should have received a copy of the GNU General Public License along with
17 // glmark2. If not, see <http://www.gnu.org/licenses/>.
18 //
19 // Authors:
20 // Jesse Barker
21 //
22 #include "gl-state-egl.h"
23 #include "log.h"
24 #include "options.h"
25 #include "gl-headers.h"
26 #include "limits.h"
27 #include "gl-headers.h"
28 #include <iomanip>
29 #include <sstream>
30 #include <cstring>
31
32 using std::vector;
33 using std::string;
34
load_egl_func(void * userdata,const char * name)35 GLADapiproc load_egl_func(void *userdata, const char *name)
36 {
37 SharedLibrary *lib = reinterpret_cast<SharedLibrary *>(userdata);
38 return reinterpret_cast<GLADapiproc>(lib->load(name));
39 }
40
41 /****************************
42 * EGLConfig public methods *
43 ****************************/
44
EglConfig(EGLDisplay dpy,EGLConfig config)45 EglConfig::EglConfig(EGLDisplay dpy, EGLConfig config) :
46 handle_(config),
47 bufferSize_(0),
48 redSize_(0),
49 greenSize_(0),
50 blueSize_(0),
51 luminanceSize_(0),
52 alphaSize_(0),
53 alphaMaskSize_(0),
54 bindTexRGB_(false),
55 bindTexRGBA_(false),
56 bufferType_(EGL_RGB_BUFFER),
57 caveat_(0),
58 configID_(0),
59 conformant_(0),
60 depthSize_(0),
61 level_(0),
62 pbufferWidth_(0),
63 pbufferHeight_(0),
64 pbufferPixels_(0),
65 minSwapInterval_(0),
66 maxSwapInterval_(0),
67 nativeID_(0),
68 nativeType_(0),
69 nativeRenderable_(false),
70 sampleBuffers_(0),
71 samples_(0),
72 stencilSize_(0),
73 surfaceType_(0),
74 xparentType_(0),
75 xparentRedValue_(0),
76 xparentGreenValue_(0),
77 xparentBlueValue_(0)
78 {
79 vector<string> badAttribVec;
80 if (!eglGetConfigAttrib(dpy, handle_, EGL_CONFIG_ID, &configID_))
81 {
82 badAttribVec.push_back("EGL_CONFIG_ID");
83 }
84 if (!eglGetConfigAttrib(dpy, handle_, EGL_CONFIG_CAVEAT, &caveat_))
85 {
86 badAttribVec.push_back("EGL_CONFIG_CAVEAT");
87 }
88 if (!eglGetConfigAttrib(dpy, handle_, EGL_CONFORMANT, &conformant_))
89 {
90 badAttribVec.push_back("EGL_CONFORMANT");
91 }
92 if (!eglGetConfigAttrib(dpy, handle_, EGL_COLOR_BUFFER_TYPE, &bufferType_))
93 {
94 badAttribVec.push_back("EGL_COLOR_BUFFER_TYPE");
95 }
96 if (!eglGetConfigAttrib(dpy, handle_, EGL_BUFFER_SIZE, &bufferSize_))
97 {
98 badAttribVec.push_back("EGL_BUFFER_SIZE");
99 }
100
101 if (bufferType_ == EGL_RGB_BUFFER)
102 {
103 if (!eglGetConfigAttrib(dpy, handle_, EGL_RED_SIZE, &redSize_))
104 {
105 badAttribVec.push_back("EGL_RED_SIZE");
106 }
107 if (!eglGetConfigAttrib(dpy, handle_, EGL_GREEN_SIZE, &greenSize_))
108 {
109 badAttribVec.push_back("EGL_GREEN_SIZE");
110 }
111 if (!eglGetConfigAttrib(dpy, handle_, EGL_BLUE_SIZE, &blueSize_))
112 {
113 badAttribVec.push_back("EGL_BLUE_SIZE");
114 }
115 }
116 else
117 {
118 if (!eglGetConfigAttrib(dpy, handle_, EGL_LUMINANCE_SIZE, &luminanceSize_))
119 {
120 badAttribVec.push_back("EGL_LUMINANCE_SIZE");
121 }
122 }
123 if (!eglGetConfigAttrib(dpy, handle_, EGL_ALPHA_SIZE, &alphaSize_))
124 {
125 badAttribVec.push_back("EGL_ALPHA_SIZE");
126 }
127 if (!eglGetConfigAttrib(dpy, handle_, EGL_ALPHA_MASK_SIZE, &alphaMaskSize_))
128 {
129 badAttribVec.push_back("EGL_ALPHA_MASK_SIZE");
130 }
131 if (!eglGetConfigAttrib(dpy, handle_, EGL_DEPTH_SIZE, &depthSize_))
132 {
133 badAttribVec.push_back("EGL_DEPTH_SIZE");
134 }
135 if (!eglGetConfigAttrib(dpy, handle_, EGL_STENCIL_SIZE, &stencilSize_))
136 {
137 badAttribVec.push_back("EGL_STENCIL_SIZE");
138 }
139 EGLint doBind(EGL_FALSE);
140 if (!eglGetConfigAttrib(dpy, handle_, EGL_BIND_TO_TEXTURE_RGB, &doBind))
141 {
142 badAttribVec.push_back("EGL_BIND_TO_TEXTURE_RGB");
143 }
144 bindTexRGB_ = (doBind == EGL_TRUE);
145 if (!eglGetConfigAttrib(dpy, handle_, EGL_BIND_TO_TEXTURE_RGBA, &doBind))
146 {
147 badAttribVec.push_back("EGL_BIND_TO_TEXTURE_RGBA");
148 }
149 bindTexRGBA_ = (doBind == EGL_TRUE);
150 if (!eglGetConfigAttrib(dpy, handle_, EGL_LEVEL, &level_))
151 {
152 badAttribVec.push_back("EGL_LEVEL");
153 }
154 if (!eglGetConfigAttrib(dpy, handle_, EGL_MAX_PBUFFER_WIDTH, &pbufferWidth_))
155 {
156 badAttribVec.push_back("EGL_MAX_PBUFFER_WIDTH");
157 }
158 if (!eglGetConfigAttrib(dpy, handle_, EGL_MAX_PBUFFER_HEIGHT, &pbufferHeight_))
159 {
160 badAttribVec.push_back("EGL_MAX_PBUFFER_HEIGHT");
161 }
162 if (!eglGetConfigAttrib(dpy, handle_, EGL_MAX_PBUFFER_PIXELS, &pbufferPixels_))
163 {
164 badAttribVec.push_back("EGL_MAX_PBUFFER_PIXELS");
165 }
166 if (!eglGetConfigAttrib(dpy, handle_, EGL_MIN_SWAP_INTERVAL, &minSwapInterval_))
167 {
168 badAttribVec.push_back("EGL_MIN_SWAP_INTERVAL");
169 }
170 if (!eglGetConfigAttrib(dpy, handle_, EGL_MAX_SWAP_INTERVAL, &maxSwapInterval_))
171 {
172 badAttribVec.push_back("EGL_MAX_SWAP_INTERVAL");
173 }
174 EGLint doNative(EGL_FALSE);
175 if (!eglGetConfigAttrib(dpy, handle_, EGL_NATIVE_RENDERABLE, &doNative))
176 {
177 badAttribVec.push_back("EGL_NATIVE_RENDERABLE");
178 }
179 nativeRenderable_ = (doNative == EGL_TRUE);
180 if (!eglGetConfigAttrib(dpy, handle_, EGL_NATIVE_VISUAL_TYPE, &nativeType_))
181 {
182 badAttribVec.push_back("EGL_NATIVE_VISUAL_TYPE");
183 }
184 if (!eglGetConfigAttrib(dpy, handle_, EGL_NATIVE_VISUAL_ID, &nativeID_))
185 {
186 badAttribVec.push_back("EGL_NATIVE_VISUAL_ID");
187 }
188 if (!eglGetConfigAttrib(dpy, handle_, EGL_SURFACE_TYPE, &surfaceType_))
189 {
190 badAttribVec.push_back("EGL_SURFACE_TYPE");
191 }
192 if (!eglGetConfigAttrib(dpy, handle_, EGL_SAMPLE_BUFFERS, &sampleBuffers_))
193 {
194 badAttribVec.push_back("EGL_SAMPLE_BUFFERS");
195 }
196 if (sampleBuffers_)
197 {
198 if (!eglGetConfigAttrib(dpy, handle_, EGL_SAMPLES, &samples_))
199 {
200 badAttribVec.push_back("EGL_SAMPLES");
201 }
202 }
203 if (!eglGetConfigAttrib(dpy, handle_, EGL_TRANSPARENT_TYPE, &xparentType_))
204 {
205 badAttribVec.push_back("EGL_TRANSPARENT_TYPE");
206 }
207 //if (xparentType_ != EGL_NONE)
208 {
209 if (!eglGetConfigAttrib(dpy, handle_, EGL_TRANSPARENT_RED_VALUE, &xparentRedValue_))
210 {
211 badAttribVec.push_back("EGL_TRANSPARENT_RED_VALUE");
212 }
213 if (!eglGetConfigAttrib(dpy, handle_, EGL_TRANSPARENT_GREEN_VALUE, &xparentGreenValue_))
214 {
215 badAttribVec.push_back("EGL_TRANSPARENT_GREEN_VALUE");
216 }
217 if (!eglGetConfigAttrib(dpy, handle_, EGL_TRANSPARENT_BLUE_VALUE, &xparentBlueValue_))
218 {
219 badAttribVec.push_back("EGL_TRANSPARENT_BLUE_VALUE");
220 }
221 }
222
223 if (!badAttribVec.empty())
224 {
225 Log::error("Failed to get the following config attributes for config 0x%x:\n",
226 config);
227 for (vector<string>::const_iterator attribIt = badAttribVec.begin();
228 attribIt != badAttribVec.end();
229 attribIt++)
230 {
231 Log::error("%s\n", attribIt->c_str());
232 }
233 }
234 }
235
236 void
print_header()237 EglConfig::print_header()
238 {
239 Log::debug("\n");
240 Log::debug(" cfg buf rgb colorbuffer dp st config native support surface sample\n");
241 Log::debug(" id sz lum r g b a th cl caveat render visid type buf ns\n");
242 Log::debug("------------------------------------------------------------------------\n");
243 }
244
245 void
print() const246 EglConfig::print() const
247 {
248 std::ostringstream s;
249 s.setf(std::ios::showbase);
250 s.fill(' ');
251 s << std::setw(7) << std::hex << configID_;
252 s << std::setw(4) << std::dec << bufferSize_;
253 if (bufferType_ == EGL_RGB_BUFFER)
254 {
255 s << std::setw(5) << "rgb";
256 s << std::setw(3) << redSize_;
257 s << std::setw(3) << greenSize_;
258 s << std::setw(3) << blueSize_;
259 }
260 else
261 {
262 s << std::setw(5) << "lum";
263 s << std::setw(3) << luminanceSize_;
264 s << std::setw(3) << 0;
265 s << std::setw(3) << 0;
266 }
267 s << std::setw(3) << alphaSize_;
268 s << std::setw(4) << depthSize_;
269 s << std::setw(3) << stencilSize_;
270 string caveat("None");
271 switch (caveat_)
272 {
273 case EGL_SLOW_CONFIG:
274 caveat = string("Slow");
275 break;
276 case EGL_NON_CONFORMANT_CONFIG:
277 caveat = string("Ncon");
278 break;
279 case EGL_NONE:
280 // Initialized to none.
281 break;
282 }
283 s << std::setw(7) << caveat;
284 string doNative(nativeRenderable_ ? "true" : "false");
285 s << std::setw(7) << doNative;
286 s << std::setw(8) << std::hex << nativeID_;
287 s << std::setw(8) << std::hex << surfaceType_;
288 s << std::setw(4) << std::dec << sampleBuffers_;
289 s << std::setw(3) << std::dec << samples_;
290 Log::debug("%s\n", s.str().c_str());
291 }
292
293 /*****************************
294 * GLStateEGL public methods *
295 ****************************/
296
~GLStateEGL()297 GLStateEGL::~GLStateEGL()
298 {
299 if(egl_display_ != nullptr){
300 if(!eglTerminate(egl_display_))
301 Log::error("eglTerminate failed\n");
302 }
303
304 if(eglReleaseThread && !eglReleaseThread())
305 Log::error("eglReleaseThread failed\n");
306 }
307
308 bool
init_display(void * native_display,GLVisualConfig & visual_config)309 GLStateEGL::init_display(void* native_display, GLVisualConfig& visual_config)
310 {
311 #if defined(WIN32)
312 if (!egl_lib_.open("libEGL.dll")) {
313 #else
314 if (!egl_lib_.open_from_alternatives({"libEGL.so", "libEGL.so.1" })) {
315 #endif
316 Log::error("Error loading EGL library\n");
317 return false;
318 }
319
320 native_display_ = reinterpret_cast<EGLNativeDisplayType>(native_display);
321 requested_visual_config_ = visual_config;
322
323 return gotValidDisplay();
324 }
325
326 bool
327 GLStateEGL::init_surface(void* native_window)
328 {
329 native_window_ = reinterpret_cast<EGLNativeWindowType>(native_window);
330
331 return gotValidSurface();
332 }
333
334 bool
335 GLStateEGL::init_gl_extensions()
336 {
337 #if GLMARK2_USE_GLESv2
338 if (!gladLoadGLES2UserPtr(load_proc, this)) {
339 Log::error("Loading GLESv2 entry points failed.");
340 return false;
341 }
342
343 GLExtensions::MapBuffer = glMapBufferOES;
344 GLExtensions::UnmapBuffer = glUnmapBufferOES;
345
346 GLExtensions::GenFramebuffers = glGenFramebuffers;
347 GLExtensions::DeleteFramebuffers = glDeleteFramebuffers;
348 GLExtensions::BindFramebuffer = glBindFramebuffer;
349 GLExtensions::FramebufferTexture2D = glFramebufferTexture2D;
350 GLExtensions::FramebufferRenderbuffer = glFramebufferRenderbuffer;
351 GLExtensions::CheckFramebufferStatus = glCheckFramebufferStatus;
352
353 GLExtensions::GenRenderbuffers = glGenRenderbuffers;
354 GLExtensions::DeleteRenderbuffers = glDeleteRenderbuffers;
355 GLExtensions::BindRenderbuffer = glBindRenderbuffer;
356 GLExtensions::RenderbufferStorage = glRenderbufferStorage;
357
358 GLExtensions::GenerateMipmap = glGenerateMipmap;
359 #elif GLMARK2_USE_GL
360 if (!gladLoadGLUserPtr(load_proc, this)) {
361 Log::error("Loading GL entry points failed.");
362 return false;
363 }
364 GLExtensions::MapBuffer = glMapBuffer;
365 GLExtensions::UnmapBuffer = glUnmapBuffer;
366
367 GLExtensions::GenFramebuffers = glGenFramebuffersEXT;
368 GLExtensions::DeleteFramebuffers = glDeleteFramebuffersEXT;
369 GLExtensions::BindFramebuffer = glBindFramebufferEXT;
370 GLExtensions::FramebufferTexture2D = glFramebufferTexture2DEXT;
371 GLExtensions::FramebufferRenderbuffer = glFramebufferRenderbufferEXT;
372 GLExtensions::CheckFramebufferStatus = glCheckFramebufferStatusEXT;
373
374 GLExtensions::GenRenderbuffers = glGenRenderbuffersEXT;
375 GLExtensions::DeleteRenderbuffers = glDeleteRenderbuffersEXT;
376 GLExtensions::BindRenderbuffer = glBindRenderbufferEXT;
377 GLExtensions::RenderbufferStorage = glRenderbufferStorageEXT;
378
379 GLExtensions::GenerateMipmap = glGenerateMipmapEXT;
380 #endif
381 return true;
382 }
383
384 bool
385 GLStateEGL::valid()
386 {
387 if (!gotValidDisplay())
388 return false;
389
390 if (!gotValidConfig())
391 return false;
392
393 if (!gotValidSurface())
394 return false;
395
396 if (!gotValidContext())
397 return false;
398
399 if (eglGetCurrentContext && egl_context_ == eglGetCurrentContext())
400 return true;
401
402 if (!eglMakeCurrent(egl_display_, egl_surface_, egl_surface_, egl_context_)) {
403 Log::error("eglMakeCurrent failed with error: 0x%x\n", eglGetError());
404 return false;
405 }
406
407 if (!eglSwapInterval || !eglSwapInterval(egl_display_, 0)) {
408 Log::info("** Failed to set swap interval. Results may be bounded above by refresh rate.\n");
409 }
410
411 if (!init_gl_extensions()) {
412 return false;
413 }
414
415 return true;
416 }
417
418 bool
419 GLStateEGL::reset()
420 {
421 if (!gotValidDisplay()) {
422 return false;
423 }
424
425 if (!egl_context_) {
426 return true;
427 }
428
429 if (EGL_FALSE == eglDestroyContext(egl_display_, egl_context_)) {
430 Log::debug("eglDestroyContext failed with error: 0x%x\n", eglGetError());
431 }
432
433 egl_context_ = 0;
434
435 return true;
436 }
437
438 void
439 GLStateEGL::swap()
440 {
441 eglSwapBuffers(egl_display_, egl_surface_);
442 }
443
444 bool
445 GLStateEGL::gotNativeConfig(intptr_t& vid)
446 {
447 if (!gotValidConfig())
448 return false;
449
450 EGLint native_id;
451 if (!eglGetConfigAttrib(egl_display_, egl_config_, EGL_NATIVE_VISUAL_ID,
452 &native_id))
453 {
454 Log::debug("Failed to get native visual id for EGLConfig 0x%x\n", egl_config_);
455 return false;
456 }
457
458 vid = native_id;
459 return true;
460 }
461
462 void
463 GLStateEGL::getVisualConfig(GLVisualConfig& vc)
464 {
465 if (!gotValidConfig())
466 return;
467
468 get_glvisualconfig(egl_config_, vc);
469 }
470
471 /******************************
472 * GLStateEGL private methods *
473 *****************************/
474
475 #ifdef GLMARK2_USE_X11
476 #define GLMARK2_NATIVE_EGL_DISPLAY_ENUM EGL_PLATFORM_X11_KHR
477 #elif GLMARK2_USE_WAYLAND
478 #define GLMARK2_NATIVE_EGL_DISPLAY_ENUM EGL_PLATFORM_WAYLAND_KHR
479 #elif GLMARK2_USE_DRM
480 #define GLMARK2_NATIVE_EGL_DISPLAY_ENUM EGL_PLATFORM_GBM_KHR
481 #elif GLMARK2_USE_MIR
482 #define GLMARK2_NATIVE_EGL_DISPLAY_ENUM EGL_PLATFORM_MIR_KHR
483 #else
484 // Platforms not in the above platform enums fall back to eglGetDisplay.
485 #define GLMARK2_NATIVE_EGL_DISPLAY_ENUM 0
486 #endif
487
488 bool
489 GLStateEGL::gotValidDisplay()
490 {
491 if (egl_display_)
492 return true;
493
494 /* Until we initialize glad EGL, load and use our own function pointers. */
495 PFNEGLQUERYSTRINGPROC egl_query_string =
496 reinterpret_cast<PFNEGLQUERYSTRINGPROC>(egl_lib_.load("eglQueryString"));
497 PFNEGLGETPROCADDRESSPROC egl_get_proc_address =
498 reinterpret_cast<PFNEGLGETPROCADDRESSPROC>(egl_lib_.load("eglGetProcAddress"));
499 PFNEGLGETERRORPROC egl_get_error =
500 reinterpret_cast<PFNEGLGETERRORPROC>(egl_lib_.load("eglGetError"));
501 PFNEGLGETDISPLAYPROC egl_get_display =
502 reinterpret_cast<PFNEGLGETDISPLAYPROC>(egl_lib_.load("eglGetDisplay"));
503 PFNEGLINITIALIZEPROC egl_initialize =
504 reinterpret_cast<PFNEGLINITIALIZEPROC>(egl_lib_.load("eglInitialize"));
505
506 if (!egl_query_string || !egl_get_proc_address || !egl_get_error ||
507 !egl_get_display || !egl_initialize)
508 {
509 return false;
510 }
511
512 char const * __restrict const supported_extensions =
513 egl_query_string(EGL_NO_DISPLAY, EGL_EXTENSIONS);
514
515 if (GLMARK2_NATIVE_EGL_DISPLAY_ENUM != 0 && supported_extensions
516 && strstr(supported_extensions, "EGL_EXT_platform_base"))
517 {
518 Log::debug("Using eglGetPlatformDisplayEXT()\n");
519 PFNEGLGETPLATFORMDISPLAYEXTPROC egl_get_platform_display =
520 reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
521 egl_get_proc_address("eglGetPlatformDisplayEXT"));
522
523 if (egl_get_platform_display != nullptr) {
524 egl_display_ = egl_get_platform_display(
525 GLMARK2_NATIVE_EGL_DISPLAY_ENUM,
526 reinterpret_cast<void*>(native_display_),
527 nullptr);
528 }
529
530 if (!egl_display_) {
531 Log::debug("eglGetPlatformDisplayEXT() failed with error: 0x%x\n",
532 egl_get_error());
533 }
534 }
535 else
536 {
537 Log::debug("eglGetPlatformDisplayEXT() seems unsupported\n");
538 }
539
540 /* Just in case get_platform_display failed... */
541 if (!egl_display_) {
542 Log::debug("Falling back to eglGetDisplay()\n");
543 egl_display_ = egl_get_display(native_display_);
544 }
545
546 if (!egl_display_) {
547 Log::error("eglGetDisplay() failed with error: 0x%x\n", egl_get_error());
548 return false;
549 }
550
551 int egl_major(-1);
552 int egl_minor(-1);
553 if (!egl_initialize(egl_display_, &egl_major, &egl_minor)) {
554 Log::error("eglInitialize() failed with error: 0x%x\n", egl_get_error());
555 egl_display_ = 0;
556 return false;
557 }
558
559 /* Reinitialize GLAD with a known display */
560 if (gladLoadEGLUserPtr(egl_display_, load_egl_func, &egl_lib_) == 0) {
561 Log::error("Loading EGL entry points failed\n");
562 return false;
563 }
564
565 /* From this point on we can use the normal EGL function calls. */
566
567 #if GLMARK2_USE_GLESv2
568 EGLenum apiType(EGL_OPENGL_ES_API);
569 #if defined(WIN32)
570 std::initializer_list<const char *> libNames = { "libGLESv2.dll" };
571 #else
572 std::initializer_list<const char *> libNames = { "libGLESv2.so", "libGLESv2.so.2" };
573 #endif
574 #elif GLMARK2_USE_GL
575 EGLenum apiType(EGL_OPENGL_API);
576 std::initializer_list<const char *> libNames = { "libGL.so", "libGL.so.1" };
577 if (!GLAD_EGL_VERSION_1_4) {
578 Log::error("EGL version %d.%d does not support the OpenGL API\n",
579 egl_major, egl_minor);
580 return false;
581 }
582 #endif
583
584 if (eglBindAPI && !eglBindAPI(apiType)) {
585 Log::error("Failed to bind api\n");
586 return false;
587 }
588
589 if (!gl_lib_.open_from_alternatives(libNames)) {
590 Log::error("Error loading GL library\n");
591 return false;
592 }
593
594 return true;
595 }
596
597 void
598 GLStateEGL::get_glvisualconfig(EGLConfig config, GLVisualConfig& visual_config)
599 {
600 eglGetConfigAttrib(egl_display_, config, EGL_BUFFER_SIZE, &visual_config.buffer);
601 eglGetConfigAttrib(egl_display_, config, EGL_RED_SIZE, &visual_config.red);
602 eglGetConfigAttrib(egl_display_, config, EGL_GREEN_SIZE, &visual_config.green);
603 eglGetConfigAttrib(egl_display_, config, EGL_BLUE_SIZE, &visual_config.blue);
604 eglGetConfigAttrib(egl_display_, config, EGL_ALPHA_SIZE, &visual_config.alpha);
605 eglGetConfigAttrib(egl_display_, config, EGL_DEPTH_SIZE, &visual_config.depth);
606 eglGetConfigAttrib(egl_display_, config, EGL_STENCIL_SIZE, &visual_config.stencil);
607 }
608
609 EGLConfig
610 GLStateEGL::select_best_config(std::vector<EGLConfig>& configs)
611 {
612 int best_score(INT_MIN);
613 EGLConfig best_config(0);
614
615 /*
616 * Go through all the configs and choose the one with the best score,
617 * i.e., the one better matching the requested config.
618 */
619 for (std::vector<EGLConfig>::const_iterator iter = configs.begin();
620 iter != configs.end();
621 iter++)
622 {
623 const EGLConfig config(*iter);
624 GLVisualConfig vc;
625 int score;
626
627 get_glvisualconfig(config, vc);
628
629 score = vc.match_score(requested_visual_config_);
630
631 if (score > best_score) {
632 best_score = score;
633 best_config = config;
634 }
635 }
636
637 return best_config;
638 }
639
640 bool
641 GLStateEGL::gotValidConfig()
642 {
643 if (egl_config_)
644 return true;
645
646 if (!gotValidDisplay())
647 return false;
648
649 const EGLint config_attribs[] = {
650 EGL_RED_SIZE, requested_visual_config_.red,
651 EGL_GREEN_SIZE, requested_visual_config_.green,
652 EGL_BLUE_SIZE, requested_visual_config_.blue,
653 EGL_ALPHA_SIZE, requested_visual_config_.alpha,
654 EGL_DEPTH_SIZE, requested_visual_config_.depth,
655 EGL_STENCIL_SIZE, requested_visual_config_.stencil,
656 #if GLMARK2_USE_GLESv2
657 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
658 #elif GLMARK2_USE_GL
659 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
660 #endif
661 EGL_NONE
662 };
663
664 // Find out how many configs match the attributes.
665 EGLint num_configs(0);
666 if (!eglChooseConfig(egl_display_, config_attribs, 0, 0, &num_configs)) {
667 Log::error("eglChooseConfig() (count query) failed with error: %d\n",
668 eglGetError());
669 return false;
670 }
671
672 if (num_configs == 0) {
673 Log::error("eglChooseConfig() didn't return any configs\n");
674 return false;
675 }
676
677 // Get all the matching configs
678 vector<EGLConfig> configs(num_configs);
679 if (!eglChooseConfig(egl_display_, config_attribs, &configs.front(),
680 num_configs, &num_configs))
681 {
682 Log::error("eglChooseConfig() failed with error: %d\n",
683 eglGetError());
684 return false;
685 }
686
687 // Select the best matching config
688 egl_config_ = select_best_config(configs);
689
690 vector<EglConfig> configVec;
691 for (vector<EGLConfig>::const_iterator configIt = configs.begin();
692 configIt != configs.end();
693 configIt++)
694 {
695 EglConfig cfg(egl_display_, *configIt);
696 configVec.push_back(cfg);
697 if (*configIt == egl_config_) {
698 best_config_ = cfg;
699 }
700 }
701
702 // Print out the config information, and let the user know the decision
703 // about the "best" one with respect to the options.
704 unsigned int lineNumber(0);
705 Log::debug("Got %u suitable EGLConfigs:\n", num_configs);
706 for (vector<EglConfig>::const_iterator configIt = configVec.begin();
707 configIt != configVec.end();
708 configIt++, lineNumber++)
709 {
710 if (!(lineNumber % 32))
711 {
712 configIt->print_header();
713 }
714 configIt->print();
715 }
716 Log::debug("\n");
717 Log::debug("Best EGLConfig ID: 0x%x\n", best_config_.configID());
718
719 return true;
720 }
721
722 bool
723 GLStateEGL::gotValidSurface()
724 {
725 if (egl_surface_)
726 return true;
727
728 if (!gotValidDisplay())
729 return false;
730
731 if (!gotValidConfig())
732 return false;
733
734 egl_surface_ = eglCreateWindowSurface(egl_display_, egl_config_, native_window_, 0);
735 if (!egl_surface_) {
736 Log::error("eglCreateWindowSurface failed with error: 0x%x\n", eglGetError());
737 return false;
738 }
739
740 return true;
741 }
742
743 bool
744 GLStateEGL::gotValidContext()
745 {
746 if (egl_context_)
747 return true;
748
749 if (!gotValidDisplay())
750 return false;
751
752 if (!gotValidConfig())
753 return false;
754
755 static const EGLint context_attribs[] = {
756 #ifdef GLMARK2_USE_GLESv2
757 EGL_CONTEXT_CLIENT_VERSION, 2,
758 #endif
759 EGL_NONE
760 };
761
762 egl_context_ = eglCreateContext(egl_display_, egl_config_,
763 EGL_NO_CONTEXT, context_attribs);
764 if (!egl_context_) {
765 Log::error("eglCreateContext() failed with error: 0x%x\n",
766 eglGetError());
767 return false;
768 }
769
770 return true;
771 }
772
773 GLADapiproc
774 GLStateEGL::load_proc(void *userptr, const char* name)
775 {
776 if (eglGetProcAddress) {
777 GLADapiproc sym = reinterpret_cast<GLADapiproc>(eglGetProcAddress(name));
778 if (sym) {
779 return sym;
780 }
781 }
782
783 GLStateEGL* state = reinterpret_cast<GLStateEGL*>(userptr);
784 return reinterpret_cast<GLADapiproc>(state->gl_lib_.load(name));
785 }
786