Make Android integration more robust for API >= 11
[platform/upstream/VK-GL-CTS.git] / framework / egl / egluGLContextFactory.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
3  * ----------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief GL context factory using EGL.
22  *//*--------------------------------------------------------------------*/
23
24 #include "egluGLContextFactory.hpp"
25
26 #include "tcuRenderTarget.hpp"
27 #include "tcuPlatform.hpp"
28 #include "tcuCommandLine.hpp"
29
30 #include "gluDefs.hpp"
31
32 #include "egluDefs.hpp"
33 #include "egluHeaderWrapper.hpp"
34 #include "egluUtil.hpp"
35 #include "egluNativeWindow.hpp"
36 #include "egluNativePixmap.hpp"
37
38 #include "glwInitFunctions.hpp"
39 #include "glwInitES20Direct.hpp"
40 #include "glwInitES30Direct.hpp"
41
42 #include "deDynamicLibrary.hpp"
43 #include "deSTLUtil.hpp"
44
45 #include <string>
46 #include <string>
47 #include <sstream>
48
49 using std::string;
50 using std::vector;
51
52 #if !defined(EGL_KHR_create_context)
53         #define EGL_KHR_create_context 1
54         #define EGL_CONTEXT_MAJOR_VERSION_KHR                                           0x3098
55         #define EGL_CONTEXT_MINOR_VERSION_KHR                                           0x30FB
56         #define EGL_CONTEXT_FLAGS_KHR                                                           0x30FC
57         #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR                                     0x30FD
58         #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR      0x31BD
59         #define EGL_NO_RESET_NOTIFICATION_KHR                                           0x31BE
60         #define EGL_LOSE_CONTEXT_ON_RESET_KHR                                           0x31BF
61         #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR                                        0x00000001
62         #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR           0x00000002
63         #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR                        0x00000004
64         #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR                         0x00000001
65         #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR        0x00000002
66         #define EGL_OPENGL_ES3_BIT_KHR                                                          0x00000040
67 #endif // EGL_KHR_create_context
68
69 // \todo [2014-03-12 pyry] Use command line arguments for libraries?
70
71 // Default library names
72 #if !defined(DEQP_GLES2_LIBRARY_PATH)
73 #       if (DE_OS == DE_OS_WIN32)
74 #               define DEQP_GLES2_LIBRARY_PATH "libGLESv2.dll"
75 #       else
76 #               define DEQP_GLES2_LIBRARY_PATH "libGLESv2.so"
77 #       endif
78 #endif
79
80 #if !defined(DEQP_GLES3_LIBRARY_PATH)
81 #       define DEQP_GLES3_LIBRARY_PATH DEQP_GLES2_LIBRARY_PATH
82 #endif
83
84 #if !defined(DEQP_OPENGL_LIBRARY_PATH)
85 #       if (DE_OS == DE_OS_WIN32)
86 #               define DEQP_OPENGL_LIBRARY_PATH "opengl32.dll"
87 #       else
88 #               define DEQP_OPENGL_LIBRARY_PATH "libGL.so"
89 #       endif
90 #endif
91
92 namespace eglu
93 {
94
95 namespace
96 {
97
98 enum
99 {
100         DEFAULT_OFFSCREEN_WIDTH         = 512,
101         DEFAULT_OFFSCREEN_HEIGHT        = 512
102 };
103
104 class GetProcFuncLoader : public glw::FunctionLoader
105 {
106 public:
107         glw::GenericFuncType get (const char* name) const
108         {
109                 return (glw::GenericFuncType)eglGetProcAddress(name);
110         }
111 };
112
113 class DynamicFuncLoader : public glw::FunctionLoader
114 {
115 public:
116         DynamicFuncLoader       (de::DynamicLibrary* library)
117                 : m_library(library)
118         {
119         }
120
121         glw::GenericFuncType get (const char* name) const
122         {
123                 return (glw::GenericFuncType)m_library->getFunction(name);
124         }
125
126 private:
127         de::DynamicLibrary*     m_library;
128 };
129
130 class RenderContext : public GLRenderContext
131 {
132 public:
133                                                                                 RenderContext                   (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config);
134         virtual                                                         ~RenderContext                  (void);
135
136         virtual glu::ContextType                        getType                                 (void) const { return m_renderConfig.type;      }
137         virtual const glw::Functions&           getFunctions                    (void) const { return m_glFunctions;            }
138         virtual const tcu::RenderTarget&        getRenderTarget                 (void) const { return m_glRenderTarget;         }
139         virtual void                                            postIterate                             (void);
140
141         virtual EGLDisplay                                      getEGLDisplay                   (void) const { return m_eglDisplay;                     }
142         virtual EGLContext                                      getEGLContext                   (void) const { return m_eglContext;                     }
143
144 private:
145         void                                                            create                                  (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config);
146         void                                                            destroy                                 (void);
147
148         const glu::RenderConfig                         m_renderConfig;
149         const NativeWindowFactory* const        m_nativeWindowFactory;  // Stored in case window must be re-created
150
151         NativeDisplay*                                          m_display;
152         NativeWindow*                                           m_window;
153         NativePixmap*                                           m_pixmap;
154
155         EGLDisplay                                                      m_eglDisplay;
156         EGLConfig                                                       m_eglConfig;
157         EGLSurface                                                      m_eglSurface;
158         EGLContext                                                      m_eglContext;
159
160         tcu::RenderTarget                                       m_glRenderTarget;
161         de::DynamicLibrary*                                     m_dynamicGLLibrary;
162         glw::Functions                                          m_glFunctions;
163 };
164
165 RenderContext::RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config)
166         : m_renderConfig                (config)
167         , m_nativeWindowFactory (windowFactory)
168         , m_display                             (DE_NULL)
169         , m_window                              (DE_NULL)
170         , m_pixmap                              (DE_NULL)
171
172         , m_eglDisplay                  (EGL_NO_DISPLAY)
173         , m_eglSurface                  (EGL_NO_SURFACE)
174         , m_eglContext                  (EGL_NO_CONTEXT)
175
176         , m_dynamicGLLibrary    (DE_NULL)
177 {
178         DE_ASSERT(displayFactory);
179
180         try
181         {
182                 create(displayFactory, windowFactory, pixmapFactory, config);
183         }
184         catch (...)
185         {
186                 destroy();
187                 throw;
188         }
189 }
190
191 RenderContext::~RenderContext(void)
192 {
193         try
194         {
195                 destroy();
196         }
197         catch (...)
198         {
199                 // destroy() calls EGL functions that are checked and may throw exceptions
200         }
201
202         delete m_window;
203         delete m_pixmap;
204         delete m_display;
205         delete m_dynamicGLLibrary;
206 }
207
208 bool configMatches (EGLDisplay display, EGLConfig eglConfig, const glu::RenderConfig& renderConfig)
209 {
210         // \todo [2014-03-12 pyry] Check other attributes like double-buffer bit.
211
212         {
213                 EGLint          renderableType          = 0;
214                 EGLint          requiredRenderable      = 0;
215
216                 if (glu::isContextTypeES(renderConfig.type))
217                 {
218                         if (renderConfig.type.getMajorVersion() == 2)
219                                 requiredRenderable = EGL_OPENGL_ES2_BIT;
220                         else if (renderConfig.type.getMajorVersion() == 3)
221                                 requiredRenderable = EGL_OPENGL_ES3_BIT_KHR;
222                         else
223                                 throw tcu::NotSupportedError("Unsupported OpenGL ES version");
224                 }
225                 else
226                 {
227                         DE_ASSERT(glu::isContextTypeGLCore(renderConfig.type) || glu::isContextTypeGLCompatibility(renderConfig.type));
228                         requiredRenderable = EGL_OPENGL_BIT;
229                 }
230
231                 EGLU_CHECK_CALL(eglGetConfigAttrib(display, eglConfig, EGL_RENDERABLE_TYPE, &renderableType));
232
233                 if ((renderableType & requiredRenderable) == 0)
234                         return false;
235         }
236
237         if (renderConfig.surfaceType != (glu::RenderConfig::SurfaceType)glu::RenderConfig::DONT_CARE)
238         {
239                 EGLint          surfaceType             = 0;
240                 EGLint          requiredSurface = 0;
241
242                 switch (renderConfig.surfaceType)
243                 {
244                         case glu::RenderConfig::SURFACETYPE_WINDOW:                             requiredSurface = EGL_WINDOW_BIT;       break;
245                         case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:   requiredSurface = EGL_PIXMAP_BIT;       break;
246                         case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:  requiredSurface = EGL_PBUFFER_BIT;      break;
247                         default:
248                                 DE_ASSERT(false);
249                 }
250
251                 EGLU_CHECK_CALL(eglGetConfigAttrib(display, eglConfig, EGL_SURFACE_TYPE, &surfaceType));
252
253                 if ((surfaceType & requiredSurface) == 0)
254                         return false;
255         }
256
257         {
258                 static const struct
259                 {
260                         int     glu::RenderConfig::*field;
261                         EGLint attrib;
262                 } s_attribs[] =
263                 {
264                         { &glu::RenderConfig::id,                       EGL_CONFIG_ID           },
265                         { &glu::RenderConfig::redBits,          EGL_RED_SIZE            },
266                         { &glu::RenderConfig::greenBits,        EGL_GREEN_SIZE          },
267                         { &glu::RenderConfig::blueBits,         EGL_BLUE_SIZE           },
268                         { &glu::RenderConfig::alphaBits,        EGL_ALPHA_SIZE          },
269                         { &glu::RenderConfig::depthBits,        EGL_DEPTH_SIZE          },
270                         { &glu::RenderConfig::stencilBits,      EGL_STENCIL_SIZE        },
271                         { &glu::RenderConfig::numSamples,       EGL_SAMPLES                     },
272                 };
273
274                 for (int attribNdx = 0; attribNdx < DE_LENGTH_OF_ARRAY(s_attribs); attribNdx++)
275                 {
276                         if (renderConfig.*s_attribs[attribNdx].field != glu::RenderConfig::DONT_CARE)
277                         {
278                                 EGLint value = 0;
279                                 EGLU_CHECK_CALL(eglGetConfigAttrib(display, eglConfig, s_attribs[attribNdx].attrib, &value));
280                                 if (value != renderConfig.*s_attribs[attribNdx].field)
281                                         return false;
282                         }
283                 }
284         }
285
286         return true;
287 }
288
289 EGLConfig chooseConfig (EGLDisplay display, const glu::RenderConfig& config)
290 {
291         const std::vector<EGLConfig> configs = eglu::getConfigs(display);
292
293         for (vector<EGLConfig>::const_iterator iter = configs.begin(); iter != configs.end(); ++iter)
294         {
295                 if (configMatches(display, *iter, config))
296                         return *iter;
297         }
298
299         throw tcu::NotSupportedError("Matching EGL config not found", DE_NULL, __FILE__, __LINE__);
300 }
301
302 static WindowParams::Visibility getNativeWindowVisibility (glu::RenderConfig::Visibility visibility)
303 {
304         using glu::RenderConfig;
305
306         switch (visibility)
307         {
308                 case RenderConfig::VISIBILITY_HIDDEN:           return WindowParams::VISIBILITY_HIDDEN;
309                 case RenderConfig::VISIBILITY_VISIBLE:          return WindowParams::VISIBILITY_VISIBLE;
310                 case RenderConfig::VISIBILITY_FULLSCREEN:       return WindowParams::VISIBILITY_FULLSCREEN;
311                 default:
312                         DE_ASSERT(visibility == (RenderConfig::Visibility)RenderConfig::DONT_CARE);
313                         return WindowParams::VISIBILITY_DONT_CARE;
314         }
315 }
316
317 typedef std::pair<NativeWindow*, EGLSurface> WindowSurfacePair;
318 typedef std::pair<NativePixmap*, EGLSurface> PixmapSurfacePair;
319
320 WindowSurfacePair createWindow (NativeDisplay* nativeDisplay, const NativeWindowFactory* windowFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config)
321 {
322         const int                                               width                   = (config.width         == glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE  : config.width);
323         const int                                               height                  = (config.height        == glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE  : config.height);
324         const WindowParams::Visibility  visibility              = getNativeWindowVisibility(config.windowVisibility);
325         NativeWindow*                                   nativeWindow    = DE_NULL;
326         EGLSurface                                              surface                 = EGL_NO_SURFACE;
327         const EGLAttrib                                 attribList[]    = { EGL_NONE };
328
329         nativeWindow = windowFactory->createWindow(nativeDisplay, eglDisplay, eglConfig, &attribList[0], WindowParams(width, height, visibility));
330
331         try
332         {
333                 surface = eglu::createWindowSurface(*nativeDisplay, *nativeWindow, eglDisplay, eglConfig, attribList);
334         }
335         catch (...)
336         {
337                 delete nativeWindow;
338                 throw;
339         }
340
341         return WindowSurfacePair(nativeWindow, surface);
342 }
343
344 PixmapSurfacePair createPixmap (NativeDisplay* nativeDisplay, const NativePixmapFactory* pixmapFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config)
345 {
346         const int                       width                   = (config.width         == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH       : config.width);
347         const int                       height                  = (config.height        == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT      : config.height);
348         NativePixmap*           nativePixmap    = DE_NULL;
349         EGLSurface                      surface                 = EGL_NO_SURFACE;
350         const EGLAttrib         attribList[]    = { EGL_NONE };
351
352         nativePixmap = pixmapFactory->createPixmap(nativeDisplay, eglDisplay, eglConfig, &attribList[0], width, height);
353
354         try
355         {
356                 surface = eglu::createPixmapSurface(*nativeDisplay, *nativePixmap, eglDisplay, eglConfig, attribList);
357         }
358         catch (...)
359         {
360                 delete nativePixmap;
361                 throw;
362         }
363
364         return PixmapSurfacePair(nativePixmap, surface);
365 }
366
367 EGLSurface createPBuffer (EGLDisplay display, EGLConfig eglConfig, const glu::RenderConfig& config)
368 {
369         const int               width                   = (config.width         == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH       : config.width);
370         const int               height                  = (config.height        == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT      : config.height);
371         EGLSurface              surface;
372         const EGLint    attribList[]    =
373         {
374                 EGL_WIDTH,      width,
375                 EGL_HEIGHT,     height,
376                 EGL_NONE
377         };
378
379         surface = eglCreatePbufferSurface(display, eglConfig, &(attribList[0]));
380         EGLU_CHECK_MSG("eglCreatePbufferSurface()");
381
382         return surface;
383 }
384
385 bool isClientExtensionSupported (EGLDisplay display, const std::string& extName)
386 {
387         const vector<string> exts = getClientExtensions(display);
388         return de::contains(exts.begin(), exts.end(), extName);
389 }
390
391 EGLContext createContext (EGLDisplay display, EGLContext eglConfig, const glu::RenderConfig& config)
392 {
393         const bool                      khrCreateContextSupported       = isClientExtensionSupported(display, "EGL_KHR_create_context");
394         EGLContext                      context                                         = EGL_NO_CONTEXT;
395         EGLenum                         api                                                     = EGL_NONE;
396         vector<EGLint>          attribList;
397
398         if (glu::isContextTypeES(config.type))
399         {
400                 api = EGL_OPENGL_ES_API;
401
402                 if (config.type.getMajorVersion() <= 2)
403                 {
404                         attribList.push_back(EGL_CONTEXT_CLIENT_VERSION);
405                         attribList.push_back(config.type.getMajorVersion());
406                 }
407                 else
408                 {
409                         if (!khrCreateContextSupported)
410                                 throw tcu::NotSupportedError("EGL_KHR_create_context is required for OpenGL ES 3.0 and newer", DE_NULL, __FILE__, __LINE__);
411
412                         attribList.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
413                         attribList.push_back(config.type.getMajorVersion());
414                         attribList.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
415                         attribList.push_back(config.type.getMinorVersion());
416                 }
417         }
418         else
419         {
420                 DE_ASSERT(glu::isContextTypeGLCore(config.type) || glu::isContextTypeGLCompatibility(config.type));
421
422                 if (!khrCreateContextSupported)
423                         throw tcu::NotSupportedError("EGL_KHR_create_context is required for OpenGL context creation", DE_NULL, __FILE__, __LINE__);
424
425                 api = EGL_OPENGL_API;
426
427                 attribList.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
428                 attribList.push_back(config.type.getMajorVersion());
429                 attribList.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
430                 attribList.push_back(config.type.getMinorVersion());
431                 attribList.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
432                 attribList.push_back(glu::isContextTypeGLCore(config.type) ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
433                                                                                                                                    : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
434         }
435
436         if (config.type.getFlags() != glu::ContextFlags(0))
437         {
438                 EGLint flags = 0;
439
440                 if (!khrCreateContextSupported)
441                         throw tcu::NotSupportedError("EGL_KHR_create_context is required for creating robust/debug/forward-compatible contexts");
442
443                 if ((config.type.getFlags() & glu::CONTEXT_DEBUG) != 0)
444                         flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
445
446                 if ((config.type.getFlags() & glu::CONTEXT_ROBUST) != 0)
447                         flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
448
449                 if ((config.type.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0)
450                 {
451                         if (!glu::isContextTypeGLCore(config.type))
452                                 throw tcu::NotSupportedError("Only OpenGL core contexts can be forward-compatible");
453
454                         flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
455                 }
456
457                 attribList.push_back(EGL_CONTEXT_FLAGS_KHR);
458                 attribList.push_back(flags);
459         }
460
461         attribList.push_back(EGL_NONE);
462
463         EGLU_CHECK_CALL(eglBindAPI(api));
464         context = eglCreateContext(display, eglConfig, EGL_NO_CONTEXT, &(attribList[0]));
465         EGLU_CHECK_MSG("eglCreateContext()");
466
467         return context;
468 }
469
470 void RenderContext::create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config)
471 {
472         glu::RenderConfig::SurfaceType  surfaceType     = config.surfaceType;
473
474         DE_ASSERT(displayFactory);
475
476         m_display               = displayFactory->createDisplay();
477         m_eglDisplay    = eglu::getDisplay(*m_display);
478
479         {
480                 EGLint major = 0;
481                 EGLint minor = 0;
482                 EGLU_CHECK_CALL(eglInitialize(m_eglDisplay, &major, &minor));
483         }
484
485         m_eglConfig     = chooseConfig(m_eglDisplay, config);
486
487         if (surfaceType == glu::RenderConfig::SURFACETYPE_DONT_CARE)
488         {
489                 // Choose based on what selected configuration supports
490                 const EGLint supportedTypes = eglu::getConfigAttribInt(m_eglDisplay, m_eglConfig, EGL_SURFACE_TYPE);
491
492                 if ((supportedTypes & EGL_WINDOW_BIT) != 0)
493                         surfaceType = glu::RenderConfig::SURFACETYPE_WINDOW;
494                 else if ((supportedTypes & EGL_PBUFFER_BIT) != 0)
495                         surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC;
496                 else if ((supportedTypes & EGL_PIXMAP_BIT) != 0)
497                         surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE;
498                 else
499                         throw tcu::NotSupportedError("Selected EGL config doesn't support any surface types", DE_NULL, __FILE__, __LINE__);
500         }
501
502         switch (surfaceType)
503         {
504                 case glu::RenderConfig::SURFACETYPE_WINDOW:
505                 {
506                         if (windowFactory)
507                         {
508                                 const WindowSurfacePair windowSurface = createWindow(m_display, windowFactory, m_eglDisplay, m_eglConfig, config);
509                                 m_window                = windowSurface.first;
510                                 m_eglSurface    = windowSurface.second;
511                         }
512                         else
513                                 throw tcu::NotSupportedError("EGL platform doesn't support windows", DE_NULL, __FILE__, __LINE__);
514                         break;
515                 }
516
517                 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
518                 {
519                         if (pixmapFactory)
520                         {
521                                 const PixmapSurfacePair pixmapSurface = createPixmap(m_display, pixmapFactory, m_eglDisplay, m_eglConfig, config);
522                                 m_pixmap                = pixmapSurface.first;
523                                 m_eglSurface    = pixmapSurface.second;
524                         }
525                         else
526                                 throw tcu::NotSupportedError("EGL platform doesn't support pixmaps", DE_NULL, __FILE__, __LINE__);
527                         break;
528                 }
529
530                 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
531                         m_eglSurface = createPBuffer(m_eglDisplay, m_eglConfig, config);
532                         break;
533
534                 default:
535                         throw tcu::InternalError("Invalid surface type");
536         }
537
538         m_eglContext = createContext(m_eglDisplay, m_eglConfig, config);
539
540         EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
541
542         // Init core functions
543
544         if (isClientExtensionSupported(m_eglDisplay, "EGL_KHR_get_all_proc_addresses"))
545         {
546                 // Use eglGetProcAddress() for core functions
547                 GetProcFuncLoader funcLoader;
548                 glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI());
549         }
550 #if !defined(DEQP_GLES2_RUNTIME_LOAD)
551         else if (config.type.getAPI() == glu::ApiType::es(2,0))
552         {
553                 glw::initES20Direct(&m_glFunctions);
554         }
555 #endif
556 #if !defined(DEQP_GLES3_RUNTIME_LOAD)
557         else if (config.type.getAPI() == glu::ApiType::es(3,0))
558         {
559                 glw::initES30Direct(&m_glFunctions);
560         }
561 #endif
562         else
563         {
564                 const char* libraryPath = DE_NULL;
565
566                 if (glu::isContextTypeES(config.type))
567                 {
568                         if (config.type.getMinorVersion() <= 2)
569                                 libraryPath = DEQP_GLES2_LIBRARY_PATH;
570                         else
571                                 libraryPath = DEQP_GLES3_LIBRARY_PATH;
572                 }
573                 else
574                         libraryPath = DEQP_OPENGL_LIBRARY_PATH;
575
576                 m_dynamicGLLibrary = new de::DynamicLibrary(libraryPath);
577
578                 DynamicFuncLoader funcLoader(m_dynamicGLLibrary);
579                 glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI());
580         }
581
582         // Init extension functions
583         {
584                 GetProcFuncLoader extLoader;
585                 glu::initExtensionFunctions(&m_glFunctions, &extLoader, config.type.getAPI());
586         }
587
588         {
589                 EGLint                          width, height, depthBits, stencilBits, numSamples;
590                 tcu::PixelFormat        pixelFmt;
591
592                 eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH, &width);
593                 eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &height);
594
595                 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_RED_SIZE,             &pixelFmt.redBits);
596                 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_GREEN_SIZE,   &pixelFmt.greenBits);
597                 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_BLUE_SIZE,    &pixelFmt.blueBits);
598                 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_ALPHA_SIZE,   &pixelFmt.alphaBits);
599
600                 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_DEPTH_SIZE,   &depthBits);
601                 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_STENCIL_SIZE, &stencilBits);
602                 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_SAMPLES,              &numSamples);
603
604                 EGLU_CHECK_MSG("Failed to query config attributes");
605
606                 m_glRenderTarget = tcu::RenderTarget(width, height, pixelFmt, depthBits, stencilBits, numSamples);
607         }
608 }
609
610 void RenderContext::destroy (void)
611 {
612         if (m_eglDisplay != EGL_NO_DISPLAY)
613         {
614                 EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
615
616                 if (m_eglSurface != EGL_NO_SURFACE)
617                         EGLU_CHECK_CALL(eglDestroySurface(m_eglDisplay, m_eglSurface));
618
619                 if (m_eglContext != EGL_NO_CONTEXT)
620                         EGLU_CHECK_CALL(eglDestroyContext(m_eglDisplay, m_eglContext));
621
622                 EGLU_CHECK_CALL(eglTerminate(m_eglDisplay));
623
624                 m_eglDisplay    = EGL_NO_DISPLAY;
625                 m_eglSurface    = EGL_NO_SURFACE;
626                 m_eglContext    = EGL_NO_CONTEXT;
627         }
628
629         delete m_window;
630         delete m_pixmap;
631         delete m_display;
632         delete m_dynamicGLLibrary;
633
634         m_window                        = DE_NULL;
635         m_pixmap                        = DE_NULL;
636         m_display                       = DE_NULL;
637         m_dynamicGLLibrary      = DE_NULL;
638 }
639
640 void RenderContext::postIterate (void)
641 {
642         if (m_window)
643         {
644                 EGLBoolean      swapOk  = eglSwapBuffers(m_eglDisplay, m_eglSurface);
645                 EGLint          error   = eglGetError();
646
647                 if (!swapOk && error != EGL_BAD_SURFACE)
648                 {
649                         if (error == EGL_BAD_ALLOC)
650                                 throw BadAllocError("eglSwapBuffers()");
651                         else if (error == EGL_CONTEXT_LOST)
652                                 throw tcu::ResourceError("eglSwapBuffers() failed, context lost");
653                         else
654                                 throw Error(error, "eglSwapBuffers()");
655                 }
656
657                 try
658                 {
659                         m_window->processEvents();
660                 }
661                 catch (const WindowDestroyedError&)
662                 {
663                         tcu::print("Warning: Window destroyed, recreating...\n");
664
665                         EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
666                         EGLU_CHECK_CALL(eglDestroySurface(m_eglDisplay, m_eglSurface));
667                         m_eglSurface = EGL_NO_SURFACE;
668
669                         delete m_window;
670                         m_window = DE_NULL;
671
672                         try
673                         {
674                                 WindowSurfacePair windowSurface = createWindow(m_display, m_nativeWindowFactory, m_eglDisplay, m_eglConfig, m_renderConfig);
675                                 m_window                = windowSurface.first;
676                                 m_eglSurface    = windowSurface.second;
677
678                                 EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
679
680                                 swapOk  = EGL_TRUE;
681                                 error   = EGL_SUCCESS;
682                         }
683                         catch (const std::exception& e)
684                         {
685                                 if (m_eglSurface)
686                                 {
687                                         eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
688                                         eglDestroySurface(m_eglDisplay, m_eglSurface);
689                                         m_eglSurface = EGL_NO_SURFACE;
690                                 }
691
692                                 delete m_window;
693                                 m_window = DE_NULL;
694
695                                 throw tcu::ResourceError(string("Failed to re-create window: ") + e.what());
696                         }
697                 }
698
699                 if (!swapOk)
700                 {
701                         DE_ASSERT(error == EGL_BAD_SURFACE);
702                         throw Error(error, "eglSwapBuffers()");
703                 }
704
705                 // Refresh dimensions
706                 {
707                         int     newWidth        = 0;
708                         int     newHeight       = 0;
709
710                         eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH,  &newWidth);
711                         eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &newHeight);
712                         EGLU_CHECK_MSG("Failed to query window size");
713
714                         if (newWidth    != m_glRenderTarget.getWidth() ||
715                                 newHeight       != m_glRenderTarget.getHeight())
716                         {
717                                 tcu::print("Warning: Window size changed (%dx%d -> %dx%d), test results might be invalid!\n",
718                                                    m_glRenderTarget.getWidth(), m_glRenderTarget.getHeight(), newWidth, newHeight);
719
720                                 m_glRenderTarget = tcu::RenderTarget(newWidth, newHeight,
721                                                                                                          m_glRenderTarget.getPixelFormat(),
722                                                                                                          m_glRenderTarget.getDepthBits(),
723                                                                                                          m_glRenderTarget.getStencilBits(),
724                                                                                                          m_glRenderTarget.getNumSamples());
725                         }
726                 }
727         }
728         else
729         {
730                 // \todo [2014-05-02 mika] Should we call flush or finish? Old platform uses finish() but flush() is closer to the behaviour of eglSwapBuffers()
731                 m_glFunctions.flush();
732                 GLU_EXPECT_NO_ERROR(m_glFunctions.getError(), "glFlush()");
733         }
734 }
735
736 } // anonymous
737
738 GLContextFactory::GLContextFactory (const NativeDisplayFactoryRegistry& displayFactoryRegistry)
739         : glu::ContextFactory           ("egl", "EGL OpenGL Context")
740         , m_displayFactoryRegistry      (displayFactoryRegistry)
741 {
742 }
743
744 namespace
745 {
746
747 template<typename Factory>
748 const Factory* selectFactory (const tcu::FactoryRegistry<Factory>& registry, const char* objectTypeName, const char* cmdLineArg)
749 {
750         if (cmdLineArg[0] != 0)
751         {
752                 const Factory* factory = registry.getFactoryByName(cmdLineArg);
753
754                 if (factory)
755                         return factory;
756                 else
757                 {
758                         tcu::print("ERROR: Unknown or unsupported EGL %s type '%s'", objectTypeName, cmdLineArg);
759                         tcu::print("Available EGL %s types:\n", objectTypeName);
760                         for (size_t ndx = 0; ndx < registry.getFactoryCount(); ndx++)
761                                 tcu::print("  %s: %s\n", registry.getFactoryByIndex(ndx)->getName(), registry.getFactoryByIndex(ndx)->getDescription());
762
763                         throw tcu::NotSupportedError((string("Unsupported or unknown EGL ") + objectTypeName + " type '" + cmdLineArg + "'").c_str(), DE_NULL, __FILE__, __LINE__);
764                 }
765         }
766         else if (!registry.empty())
767                 return registry.getDefaultFactory();
768         else
769                 return DE_NULL;
770 }
771
772 } // anonymous
773
774 glu::RenderContext* GLContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const
775 {
776         const NativeDisplayFactory* displayFactory = selectFactory(m_displayFactoryRegistry, "display", cmdLine.getEGLDisplayType());
777
778         if (displayFactory)
779         {
780                 // \note windowFactory & pixmapFactory are not mandatory
781                 const NativeWindowFactory*      windowFactory   = selectFactory(displayFactory->getNativeWindowRegistry(), "window", cmdLine.getEGLWindowType());
782                 const NativePixmapFactory*      pixmapFactory   = selectFactory(displayFactory->getNativePixmapRegistry(), "pixmap", cmdLine.getEGLPixmapType());
783
784                 return new RenderContext(displayFactory, windowFactory, pixmapFactory, config);
785         }
786         else
787                 throw tcu::NotSupportedError("No EGL displays available", DE_NULL, __FILE__, __LINE__);
788 }
789
790 } // eglu