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 "tcuCommandLine.hpp"
28 #include "deSTLUtil.hpp"
29
30 #include <algorithm>
31 #include <sstream>
32
33 using std::string;
34 using std::vector;
35
36 #if !defined(EGL_EXT_platform_base)
37 # define EGL_EXT_platform_base 1
38 typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
39 typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
40 typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
41 #endif // EGL_EXT_platform_base
42
43 namespace eglu
44 {
45
getPlatformExtensions(void)46 vector<string> getPlatformExtensions (void)
47 {
48 const char* const extensionStr = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
49 const EGLint result = eglGetError();
50
51 if (result == EGL_SUCCESS)
52 {
53 std::istringstream stream (extensionStr);
54 string currentExtension;
55 vector<string> extensions;
56
57 while (std::getline(stream, currentExtension, ' '))
58 extensions.push_back(currentExtension);
59
60 return extensions;
61 }
62 else if (result != EGL_BAD_DISPLAY)
63 throw Error(result, "eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)", DE_NULL, __FILE__, __LINE__);
64 else
65 return vector<string>();
66 }
67
getClientExtensions(EGLDisplay display)68 vector<string> getClientExtensions (EGLDisplay display)
69 {
70 const char* const extensionStr = eglQueryString(display, EGL_EXTENSIONS);
71 const EGLint result = eglGetError();
72
73 if (result == EGL_SUCCESS)
74 {
75 std::istringstream stream (extensionStr);
76 string currentExtension;
77 vector<string> extensions;
78
79 while (std::getline(stream, currentExtension, ' '))
80 extensions.push_back(currentExtension);
81
82 return extensions;
83 }
84 else
85 throw Error(result, "eglQueryString(display, EGL_EXTENSIONS)", DE_NULL, __FILE__, __LINE__);
86 }
87
getConfigs(EGLDisplay display)88 vector<EGLConfig> getConfigs (EGLDisplay display)
89 {
90 vector<EGLConfig> configs;
91 EGLint configCount = 0;
92 EGLU_CHECK_CALL(eglGetConfigs(display, DE_NULL, 0, &configCount));
93
94 if (configCount > 0)
95 {
96 configs.resize(configCount);
97 EGLU_CHECK_CALL(eglGetConfigs(display, &(configs[0]), (EGLint)configs.size(), &configCount));
98 }
99
100 return configs;
101 }
102
chooseConfig(EGLDisplay display,const AttribMap & attribs)103 vector<EGLConfig> chooseConfig (EGLDisplay display, const AttribMap& attribs)
104 {
105 vector<EGLint> attribList;
106
107 for (AttribMap::const_iterator it = attribs.begin(); it != attribs.end(); ++it)
108 {
109 attribList.push_back(it->first);
110 attribList.push_back(it->second);
111 }
112
113 attribList.push_back(EGL_NONE);
114
115 {
116 EGLint numConfigs = 0;
117 EGLU_CHECK_CALL(eglChooseConfig(display, &attribList.front(), DE_NULL, 0, &numConfigs));
118
119 {
120 vector<EGLConfig> configs(numConfigs);
121
122 if (numConfigs > 0)
123 EGLU_CHECK_CALL(eglChooseConfig(display, &attribList.front(), &configs.front(), numConfigs, &numConfigs));
124
125 return configs;
126 }
127 }
128 }
129
chooseSingleConfig(EGLDisplay display,const AttribMap & attribs)130 EGLConfig chooseSingleConfig (EGLDisplay display, const AttribMap& attribs)
131 {
132 vector<EGLConfig> configs (chooseConfig(display, attribs));
133 if (configs.empty())
134 TCU_THROW(NotSupportedError, "No suitable EGL configuration found");
135
136 return configs.front();
137 }
138
getConfigAttribInt(EGLDisplay display,EGLConfig config,EGLint attrib)139 EGLint getConfigAttribInt (EGLDisplay display, EGLConfig config, EGLint attrib)
140 {
141 EGLint value = 0;
142 EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, attrib, &value));
143 return value;
144 }
145
querySurfaceInt(EGLDisplay display,EGLSurface surface,EGLint attrib)146 EGLint querySurfaceInt (EGLDisplay display, EGLSurface surface, EGLint attrib)
147 {
148 EGLint value = 0;
149 EGLU_CHECK_CALL(eglQuerySurface(display, surface, attrib, &value));
150 return value;
151 }
152
getSurfaceSize(EGLDisplay display,EGLSurface surface)153 tcu::IVec2 getSurfaceSize (EGLDisplay display, EGLSurface surface)
154 {
155 const EGLint width = querySurfaceInt(display, surface, EGL_WIDTH);
156 const EGLint height = querySurfaceInt(display, surface, EGL_HEIGHT);
157 return tcu::IVec2(width, height);
158 }
159
getSurfaceResolution(EGLDisplay display,EGLSurface surface)160 tcu::IVec2 getSurfaceResolution (EGLDisplay display, EGLSurface surface)
161 {
162 const EGLint hRes = querySurfaceInt(display, surface, EGL_HORIZONTAL_RESOLUTION);
163 const EGLint vRes = querySurfaceInt(display, surface, EGL_VERTICAL_RESOLUTION);
164
165 if (hRes == EGL_UNKNOWN || vRes == EGL_UNKNOWN)
166 TCU_THROW(NotSupportedError, "Surface doesn't support pixel density queries");
167 return tcu::IVec2(hRes, vRes);
168 }
169
170 //! Get EGLdisplay using eglGetDisplay() or eglGetPlatformDisplayEXT()
getDisplay(NativeDisplay & nativeDisplay)171 EGLDisplay getDisplay (NativeDisplay& nativeDisplay)
172 {
173 const bool supportsLegacyGetDisplay = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY) != 0;
174 const bool supportsPlatformGetDisplay = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM) != 0;
175 bool usePlatformExt = false;
176 EGLDisplay display = EGL_NO_DISPLAY;
177
178 TCU_CHECK_INTERNAL(supportsLegacyGetDisplay || supportsPlatformGetDisplay);
179
180 if (supportsPlatformGetDisplay)
181 {
182 const vector<string> platformExts = getPlatformExtensions();
183 usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
184 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
185 }
186
187 if (usePlatformExt)
188 {
189 const PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
190
191 EGLU_CHECK_MSG("eglGetProcAddress()");
192 TCU_CHECK(getPlatformDisplay);
193
194 display = getPlatformDisplay(nativeDisplay.getPlatformType(), nativeDisplay.getPlatformNative(), DE_NULL);
195 EGLU_CHECK_MSG("eglGetPlatformDisplayEXT()");
196 TCU_CHECK(display != EGL_NO_DISPLAY);
197 }
198 else if (supportsLegacyGetDisplay)
199 {
200 display = eglGetDisplay(nativeDisplay.getLegacyNative());
201 EGLU_CHECK_MSG("eglGetDisplay()");
202 TCU_CHECK(display != EGL_NO_DISPLAY);
203 }
204 else
205 throw tcu::InternalError("No supported way to get EGL display", DE_NULL, __FILE__, __LINE__);
206
207 DE_ASSERT(display != EGL_NO_DISPLAY);
208 return display;
209 }
210
211 //! Create EGL window surface using eglCreateWindowSurface() or eglCreatePlatformWindowSurfaceEXT()
createWindowSurface(NativeDisplay & nativeDisplay,NativeWindow & window,EGLDisplay display,EGLConfig config,const EGLAttrib * attribList)212 EGLSurface createWindowSurface (NativeDisplay& nativeDisplay, NativeWindow& window, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
213 {
214 const bool supportsLegacyCreate = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
215 const bool supportsPlatformCreate = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
216 bool usePlatformExt = false;
217 EGLSurface surface = EGL_NO_SURFACE;
218
219 TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
220
221 if (supportsPlatformCreate)
222 {
223 const vector<string> platformExts = getPlatformExtensions();
224 usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
225 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
226 }
227
228 // \todo [2014-03-13 pyry] EGL 1.5 core support
229 if (usePlatformExt)
230 {
231 const PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC createPlatformWindowSurface = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
232 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
233
234 EGLU_CHECK_MSG("eglGetProcAddress()");
235 TCU_CHECK(createPlatformWindowSurface);
236
237 surface = createPlatformWindowSurface(display, config, window.getPlatformNative(), &legacyAttribs[0]);
238 EGLU_CHECK_MSG("eglCreatePlatformWindowSurfaceEXT()");
239 TCU_CHECK(surface != EGL_NO_SURFACE);
240 }
241 else if (supportsLegacyCreate)
242 {
243 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
244 surface = eglCreateWindowSurface(display, config, window.getLegacyNative(), &legacyAttribs[0]);
245 EGLU_CHECK_MSG("eglCreateWindowSurface()");
246 TCU_CHECK(surface != EGL_NO_SURFACE);
247 }
248 else
249 throw tcu::InternalError("No supported way to create EGL window surface", DE_NULL, __FILE__, __LINE__);
250
251 DE_ASSERT(surface != EGL_NO_SURFACE);
252 return surface;
253 }
254
255 //! Create EGL pixmap surface using eglCreatePixmapSurface() or eglCreatePlatformPixmapSurfaceEXT()
createPixmapSurface(NativeDisplay & nativeDisplay,NativePixmap & pixmap,EGLDisplay display,EGLConfig config,const EGLAttrib * attribList)256 EGLSurface createPixmapSurface (NativeDisplay& nativeDisplay, NativePixmap& pixmap, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
257 {
258 const bool supportsLegacyCreate = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
259 const bool supportsPlatformCreate = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
260 bool usePlatformExt = false;
261 EGLSurface surface = EGL_NO_SURFACE;
262
263 TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
264
265 if (supportsPlatformCreate)
266 {
267 const vector<string> platformExts = getPlatformExtensions();
268 usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
269 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
270 }
271
272 if (usePlatformExt)
273 {
274 const PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC createPlatformPixmapSurface = (PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformPixmapSurfaceEXT");
275 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
276
277 EGLU_CHECK_MSG("eglGetProcAddress()");
278 TCU_CHECK(createPlatformPixmapSurface);
279
280 surface = createPlatformPixmapSurface(display, config, pixmap.getPlatformNative(), &legacyAttribs[0]);
281 EGLU_CHECK_MSG("eglCreatePlatformPixmapSurfaceEXT()");
282 TCU_CHECK(surface != EGL_NO_SURFACE);
283 }
284 else if (supportsLegacyCreate)
285 {
286 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
287 surface = eglCreatePixmapSurface(display, config, pixmap.getLegacyNative(), &legacyAttribs[0]);
288 EGLU_CHECK_MSG("eglCreatePixmapSurface()");
289 TCU_CHECK(surface != EGL_NO_SURFACE);
290 }
291 else
292 throw tcu::InternalError("No supported way to create EGL pixmap surface", DE_NULL, __FILE__, __LINE__);
293
294 DE_ASSERT(surface != EGL_NO_SURFACE);
295 return surface;
296 }
297
getWindowVisibility(tcu::WindowVisibility visibility)298 static WindowParams::Visibility getWindowVisibility (tcu::WindowVisibility visibility)
299 {
300 switch (visibility)
301 {
302 case tcu::WINDOWVISIBILITY_WINDOWED: return WindowParams::VISIBILITY_VISIBLE;
303 case tcu::WINDOWVISIBILITY_FULLSCREEN: return WindowParams::VISIBILITY_FULLSCREEN;
304 case tcu::WINDOWVISIBILITY_HIDDEN: return WindowParams::VISIBILITY_HIDDEN;
305
306 default:
307 DE_ASSERT(false);
308 return WindowParams::VISIBILITY_DONT_CARE;
309 }
310 }
311
parseWindowVisibility(const tcu::CommandLine & commandLine)312 WindowParams::Visibility parseWindowVisibility (const tcu::CommandLine& commandLine)
313 {
314 return getWindowVisibility(commandLine.getVisibility());
315 }
316
toLegacyAttribList(const EGLAttrib * attribs)317 vector<EGLint> toLegacyAttribList (const EGLAttrib* attribs)
318 {
319 const deUint64 attribMask = 0xffffffffull; //!< Max bits that can be used
320 vector<EGLint> legacyAttribs;
321
322 if (attribs)
323 {
324 for (const EGLAttrib* attrib = attribs; *attrib != EGL_NONE; attrib += 2)
325 {
326 if ((attrib[0] & ~attribMask) || (attrib[1] & ~attribMask))
327 throw tcu::InternalError("Failed to translate EGLAttrib to EGLint", DE_NULL, __FILE__, __LINE__);
328
329 legacyAttribs.push_back((EGLint)attrib[0]);
330 legacyAttribs.push_back((EGLint)attrib[1]);
331 }
332 }
333
334 legacyAttribs.push_back(EGL_NONE);
335
336 return legacyAttribs;
337 }
338
339 } // eglu
340