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