Merge in changes from Khronos Vulkan CTS repository
[platform/upstream/VK-GL-CTS.git] / framework / egl / egluUtil.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 EGL utilities
22  *//*--------------------------------------------------------------------*/
23
24 #include "egluUtil.hpp"
25 #include "egluDefs.hpp"
26 #include "egluNativeDisplay.hpp"
27 #include "egluConfigFilter.hpp"
28 #include "eglwLibrary.hpp"
29 #include "eglwEnums.hpp"
30 #include "tcuCommandLine.hpp"
31 #include "deSTLUtil.hpp"
32 #include "deStringUtil.hpp"
33 #include "glwEnums.hpp"
34
35 #include <algorithm>
36 #include <sstream>
37
38 using std::string;
39 using std::vector;
40
41 namespace eglu
42 {
43
44 using namespace eglw;
45
46 vector<EGLint> attribMapToList (const AttribMap& attribs)
47 {
48         vector<EGLint> attribList;
49
50         for (AttribMap::const_iterator it = attribs.begin(); it != attribs.end(); ++it)
51         {
52                 attribList.push_back(it->first);
53                 attribList.push_back(it->second);
54         }
55
56         attribList.push_back(EGL_NONE);
57
58         return attribList;
59 }
60
61 Version getVersion (const Library& egl, EGLDisplay display)
62 {
63         EGLint major, minor;
64
65         // eglInitialize on already initialized displays just returns the version.
66         EGLU_CHECK_CALL(egl, initialize(display, &major, &minor));
67
68         return Version(major, minor);
69 }
70
71 vector<string> getExtensions (const Library& egl, EGLDisplay display)
72 {
73         const char*     const extensionStr = egl.queryString(display, EGL_EXTENSIONS);
74
75         EGLU_CHECK_MSG(egl, "Querying extensions failed");
76
77         return de::splitString(extensionStr, ' ');
78 }
79
80 bool hasExtension (const Library& egl, EGLDisplay display, const string& str)
81 {
82         const vector<string> extensions = getExtensions(egl, display);
83         return de::contains(extensions.begin(), extensions.end(), str);
84 }
85
86 vector<string> getClientExtensions (const Library& egl)
87 {
88         return getExtensions(egl, EGL_NO_DISPLAY);
89 }
90
91 vector<string> getDisplayExtensions (const Library& egl, EGLDisplay display)
92 {
93         DE_ASSERT(display != EGL_NO_DISPLAY);
94
95         return getExtensions(egl, display);
96 }
97
98 vector<EGLConfig> getConfigs (const Library& egl, EGLDisplay display)
99 {
100         vector<EGLConfig>       configs;
101         EGLint                          configCount     = 0;
102         EGLU_CHECK_CALL(egl, getConfigs(display, DE_NULL, 0, &configCount));
103
104         if (configCount > 0)
105         {
106                 configs.resize(configCount);
107                 EGLU_CHECK_CALL(egl, getConfigs(display, &(configs[0]), (EGLint)configs.size(), &configCount));
108         }
109
110         return configs;
111 }
112
113 vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const EGLint* attribList)
114 {
115         EGLint  numConfigs      = 0;
116
117         EGLU_CHECK_CALL(egl, chooseConfig(display, attribList, DE_NULL, 0, &numConfigs));
118
119         {
120                 vector<EGLConfig> configs(numConfigs);
121
122                 if (numConfigs > 0)
123                         EGLU_CHECK_CALL(egl, chooseConfig(display, attribList, &configs.front(), numConfigs, &numConfigs));
124
125                 return configs;
126         }
127 }
128
129 vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const FilterList& filters)
130 {
131         const vector<EGLConfig> allConfigs              (getConfigs(egl, display));
132         vector<EGLConfig>               matchingConfigs;
133
134         for (vector<EGLConfig>::const_iterator cfg = allConfigs.begin(); cfg != allConfigs.end(); ++cfg)
135         {
136                 if (filters.match(egl, display, *cfg))
137                         matchingConfigs.push_back(*cfg);
138         }
139
140         return matchingConfigs;
141 }
142
143 EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const FilterList& filters)
144 {
145         const vector<EGLConfig> allConfigs      (getConfigs(egl, display));
146
147         for (vector<EGLConfig>::const_iterator cfg = allConfigs.begin(); cfg != allConfigs.end(); ++cfg)
148         {
149                 if (filters.match(egl, display, *cfg))
150                         return *cfg;
151         }
152
153         TCU_THROW(NotSupportedError, "No matching EGL config found");
154 }
155
156 EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const EGLint* attribList)
157 {
158         const vector<EGLConfig> configs (chooseConfigs(egl, display, attribList));
159         if (configs.empty())
160                 TCU_THROW(NotSupportedError, "No matching EGL config found");
161
162         return configs.front();
163 }
164
165 vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const AttribMap& attribs)
166 {
167         const vector<EGLint>    attribList      = attribMapToList(attribs);
168         return chooseConfigs(egl, display, &attribList.front());
169 }
170
171 EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const AttribMap& attribs)
172 {
173         const vector<EGLint>    attribList      = attribMapToList(attribs);
174         return chooseSingleConfig(egl, display, &attribList.front());
175 }
176
177 EGLConfig chooseConfigByID (const Library& egl, EGLDisplay display, EGLint id)
178 {
179         AttribMap attribs;
180
181         attribs[EGL_CONFIG_ID]                  = id;
182         attribs[EGL_TRANSPARENT_TYPE]   = EGL_DONT_CARE;
183         attribs[EGL_COLOR_BUFFER_TYPE]  = EGL_DONT_CARE;
184         attribs[EGL_RENDERABLE_TYPE]    = EGL_DONT_CARE;
185         attribs[EGL_SURFACE_TYPE]               = EGL_DONT_CARE;
186
187         return chooseSingleConfig(egl, display, attribs);
188 }
189
190 EGLint getConfigAttribInt (const Library& egl, EGLDisplay display, EGLConfig config, EGLint attrib)
191 {
192         EGLint value = 0;
193         EGLU_CHECK_CALL(egl, getConfigAttrib(display, config, attrib, &value));
194         return value;
195 }
196
197 EGLint getConfigID (const Library& egl, EGLDisplay display, EGLConfig config)
198 {
199         return getConfigAttribInt(egl, display, config, EGL_CONFIG_ID);
200 }
201
202 EGLint querySurfaceInt (const Library& egl, EGLDisplay display, EGLSurface surface, EGLint attrib)
203 {
204         EGLint value = 0;
205         EGLU_CHECK_CALL(egl, querySurface(display, surface, attrib, &value));
206         return value;
207 }
208
209 tcu::IVec2 getSurfaceSize (const Library& egl, EGLDisplay display, EGLSurface surface)
210 {
211         const EGLint width      = querySurfaceInt(egl, display, surface, EGL_WIDTH);
212         const EGLint height     = querySurfaceInt(egl, display, surface, EGL_HEIGHT);
213         return tcu::IVec2(width, height);
214 }
215
216 tcu::IVec2 getSurfaceResolution (const Library& egl, EGLDisplay display, EGLSurface surface)
217 {
218         const EGLint hRes       = querySurfaceInt(egl, display, surface, EGL_HORIZONTAL_RESOLUTION);
219         const EGLint vRes       = querySurfaceInt(egl, display, surface, EGL_VERTICAL_RESOLUTION);
220
221         if (hRes == EGL_UNKNOWN || vRes == EGL_UNKNOWN)
222                 TCU_THROW(NotSupportedError, "Surface doesn't support pixel density queries");
223         return tcu::IVec2(hRes, vRes);
224 }
225
226 //! Get EGLdisplay using eglGetDisplay() or eglGetPlatformDisplayEXT()
227 EGLDisplay getDisplay (NativeDisplay& nativeDisplay)
228 {
229         const Library&  egl                                                             = nativeDisplay.getLibrary();
230         const bool              supportsLegacyGetDisplay                = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY) != 0;
231         const bool              supportsPlatformGetDisplay              = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM) != 0;
232         bool                    usePlatformExt                                  = false;
233         EGLDisplay              display                                                 = EGL_NO_DISPLAY;
234
235         TCU_CHECK_INTERNAL(supportsLegacyGetDisplay || supportsPlatformGetDisplay);
236
237         if (supportsPlatformGetDisplay)
238         {
239                 const vector<string> platformExts = getClientExtensions(egl);
240                 usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
241                                                  de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
242         }
243
244         if (usePlatformExt)
245         {
246                 const vector<EGLint>    legacyAttribs   = toLegacyAttribList(nativeDisplay.getPlatformAttributes());
247
248                 display = egl.getPlatformDisplayEXT(nativeDisplay.getPlatformType(), nativeDisplay.getPlatformNative(), &legacyAttribs[0]);
249                 EGLU_CHECK_MSG(egl, "eglGetPlatformDisplayEXT()");
250                 TCU_CHECK(display != EGL_NO_DISPLAY);
251         }
252         else if (supportsLegacyGetDisplay)
253         {
254                 display = egl.getDisplay(nativeDisplay.getLegacyNative());
255                 EGLU_CHECK_MSG(egl, "eglGetDisplay()");
256                 TCU_CHECK(display != EGL_NO_DISPLAY);
257         }
258         else
259                 throw tcu::InternalError("No supported way to get EGL display", DE_NULL, __FILE__, __LINE__);
260
261         DE_ASSERT(display != EGL_NO_DISPLAY);
262         return display;
263 }
264
265 EGLDisplay getAndInitDisplay (NativeDisplay& nativeDisplay, Version* version)
266 {
267         const Library&  egl             = nativeDisplay.getLibrary();
268         EGLDisplay              display = getDisplay(nativeDisplay);
269         int                             major, minor;
270
271         EGLU_CHECK_CALL(egl, initialize(display, &major, &minor));
272
273         if (version)
274                 *version = Version(major, minor);
275
276         return display;
277 }
278
279 //! Create EGL window surface using eglCreateWindowSurface() or eglCreatePlatformWindowSurfaceEXT()
280 EGLSurface createWindowSurface (NativeDisplay& nativeDisplay, NativeWindow& window, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
281 {
282         const Library&  egl                                                     = nativeDisplay.getLibrary();
283         const bool              supportsLegacyCreate            = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
284         const bool              supportsPlatformCreate          = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
285         bool                    usePlatformExt                          = false;
286         EGLSurface              surface                                         = EGL_NO_SURFACE;
287
288         TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
289
290         if (supportsPlatformCreate)
291         {
292                 const vector<string> platformExts = getClientExtensions(egl);
293                 usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
294                                                  de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
295         }
296
297         // \todo [2014-03-13 pyry] EGL 1.5 core support
298         if (usePlatformExt)
299         {
300                 const vector<EGLint>    legacyAttribs   = toLegacyAttribList(attribList);
301
302                 surface = egl.createPlatformWindowSurfaceEXT(display, config, window.getPlatformNative(), &legacyAttribs[0]);
303                 EGLU_CHECK_MSG(egl, "eglCreatePlatformWindowSurfaceEXT()");
304                 TCU_CHECK(surface != EGL_NO_SURFACE);
305         }
306         else if (supportsLegacyCreate)
307         {
308                 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
309                 surface = egl.createWindowSurface(display, config, window.getLegacyNative(), &legacyAttribs[0]);
310                 EGLU_CHECK_MSG(egl, "eglCreateWindowSurface()");
311                 TCU_CHECK(surface != EGL_NO_SURFACE);
312         }
313         else
314                 throw tcu::InternalError("No supported way to create EGL window surface", DE_NULL, __FILE__, __LINE__);
315
316         DE_ASSERT(surface != EGL_NO_SURFACE);
317         return surface;
318 }
319
320 //! Create EGL pixmap surface using eglCreatePixmapSurface() or eglCreatePlatformPixmapSurfaceEXT()
321 EGLSurface createPixmapSurface (NativeDisplay& nativeDisplay, NativePixmap& pixmap, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
322 {
323         const Library&  egl                                                     = nativeDisplay.getLibrary();
324         const bool              supportsLegacyCreate            = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
325         const bool              supportsPlatformCreate          = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
326         bool                    usePlatformExt                          = false;
327         EGLSurface              surface                                         = EGL_NO_SURFACE;
328
329         TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
330
331         if (supportsPlatformCreate)
332         {
333                 const vector<string> platformExts = getClientExtensions(egl);
334                 usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
335                                                  de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
336         }
337
338         if (usePlatformExt)
339         {
340                 const vector<EGLint>    legacyAttribs   = toLegacyAttribList(attribList);
341
342                 surface = egl.createPlatformPixmapSurfaceEXT(display, config, pixmap.getPlatformNative(), &legacyAttribs[0]);
343                 EGLU_CHECK_MSG(egl, "eglCreatePlatformPixmapSurfaceEXT()");
344                 TCU_CHECK(surface != EGL_NO_SURFACE);
345         }
346         else if (supportsLegacyCreate)
347         {
348                 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
349                 surface = egl.createPixmapSurface(display, config, pixmap.getLegacyNative(), &legacyAttribs[0]);
350                 EGLU_CHECK_MSG(egl, "eglCreatePixmapSurface()");
351                 TCU_CHECK(surface != EGL_NO_SURFACE);
352         }
353         else
354                 throw tcu::InternalError("No supported way to create EGL pixmap surface", DE_NULL, __FILE__, __LINE__);
355
356         DE_ASSERT(surface != EGL_NO_SURFACE);
357         return surface;
358 }
359
360 static WindowParams::Visibility getWindowVisibility (tcu::WindowVisibility visibility)
361 {
362         switch (visibility)
363         {
364                 case tcu::WINDOWVISIBILITY_WINDOWED:    return WindowParams::VISIBILITY_VISIBLE;
365                 case tcu::WINDOWVISIBILITY_FULLSCREEN:  return WindowParams::VISIBILITY_FULLSCREEN;
366                 case tcu::WINDOWVISIBILITY_HIDDEN:              return WindowParams::VISIBILITY_HIDDEN;
367
368                 default:
369                         DE_ASSERT(false);
370                         return WindowParams::VISIBILITY_DONT_CARE;
371         }
372 }
373
374 WindowParams::Visibility parseWindowVisibility (const tcu::CommandLine& commandLine)
375 {
376         return getWindowVisibility(commandLine.getVisibility());
377 }
378
379 EGLenum parseClientAPI (const std::string& api)
380 {
381         if (api == "OpenGL")
382                 return EGL_OPENGL_API;
383         else if (api == "OpenGL_ES")
384                 return EGL_OPENGL_ES_API;
385         else if (api == "OpenVG")
386                 return EGL_OPENVG_API;
387         else
388                 throw tcu::InternalError("Unknown EGL client API '" + api + "'");
389 }
390
391 vector<EGLenum> parseClientAPIs (const std::string& apiList)
392 {
393         const vector<string>    apiStrs = de::splitString(apiList, ' ');
394         vector<EGLenum>                 apis;
395
396         for (vector<string>::const_iterator api = apiStrs.begin(); api != apiStrs.end(); ++api)
397                 apis.push_back(parseClientAPI(*api));
398
399         return apis;
400 }
401
402 vector<EGLenum> getClientAPIs (const eglw::Library& egl, eglw::EGLDisplay display)
403 {
404         return parseClientAPIs(egl.queryString(display, EGL_CLIENT_APIS));
405 }
406
407 EGLint getRenderableAPIsMask (const eglw::Library& egl, eglw::EGLDisplay display)
408 {
409         const vector<EGLConfig> configs = getConfigs(egl, display);
410         EGLint                                  allAPIs = 0;
411
412         for (vector<EGLConfig>::const_iterator i = configs.begin(); i != configs.end(); ++i)
413                 allAPIs |= getConfigAttribInt(egl, display, *i, EGL_RENDERABLE_TYPE);
414
415         return allAPIs;
416 }
417
418 vector<EGLint> toLegacyAttribList (const EGLAttrib* attribs)
419 {
420         const deUint64  attribMask              = 0xffffffffull;        //!< Max bits that can be used
421         vector<EGLint>  legacyAttribs;
422
423         if (attribs)
424         {
425                 for (const EGLAttrib* attrib = attribs; *attrib != EGL_NONE; attrib += 2)
426                 {
427                         if ((attrib[0] & ~attribMask) || (attrib[1] & ~attribMask))
428                                 throw tcu::InternalError("Failed to translate EGLAttrib to EGLint", DE_NULL, __FILE__, __LINE__);
429
430                         legacyAttribs.push_back((EGLint)attrib[0]);
431                         legacyAttribs.push_back((EGLint)attrib[1]);
432                 }
433         }
434
435         legacyAttribs.push_back(EGL_NONE);
436
437         return legacyAttribs;
438 }
439
440 template<typename Factory>
441 static const Factory& selectFactory (const tcu::FactoryRegistry<Factory>& registry, const char* objectTypeName, const char* cmdLineArg)
442 {
443         if (cmdLineArg)
444         {
445                 const Factory* factory = registry.getFactoryByName(cmdLineArg);
446
447                 if (factory)
448                         return *factory;
449                 else
450                 {
451                         tcu::print("ERROR: Unknown or unsupported EGL %s type '%s'", objectTypeName, cmdLineArg);
452                         tcu::print("Available EGL %s types:\n", objectTypeName);
453                         for (size_t ndx = 0; ndx < registry.getFactoryCount(); ndx++)
454                                 tcu::print("  %s: %s\n", registry.getFactoryByIndex(ndx)->getName(), registry.getFactoryByIndex(ndx)->getDescription());
455
456                         TCU_THROW(NotSupportedError, (string("Unsupported or unknown EGL ") + objectTypeName + " type '" + cmdLineArg + "'").c_str());
457                 }
458         }
459         else if (!registry.empty())
460                 return *registry.getDefaultFactory();
461         else
462                 TCU_THROW(NotSupportedError, (string("No factory supporting EGL '") + objectTypeName + "' type").c_str());
463 }
464
465 const NativeDisplayFactory& selectNativeDisplayFactory (const NativeDisplayFactoryRegistry& registry, const tcu::CommandLine& cmdLine)
466 {
467         return selectFactory(registry, "display", cmdLine.getEGLDisplayType());
468 }
469
470 const NativeWindowFactory& selectNativeWindowFactory (const NativeDisplayFactory& factory, const tcu::CommandLine& cmdLine)
471 {
472         return selectFactory(factory.getNativeWindowRegistry(), "window", cmdLine.getEGLWindowType());
473 }
474
475 const NativePixmapFactory& selectNativePixmapFactory (const NativeDisplayFactory& factory, const tcu::CommandLine& cmdLine)
476 {
477         return selectFactory(factory.getNativePixmapRegistry(), "pixmap", cmdLine.getEGLPixmapType());
478 }
479
480 } // eglu