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