1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright 2015 Intel Corporation
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 surfaceless platform
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuSurfacelessPlatform.hpp"
25
26 #include <string>
27 #include <vector>
28 #include <sys/utsname.h>
29
30 #include "deDynamicLibrary.hpp"
31 #include "deMemory.h"
32 #include "deSTLUtil.hpp"
33 #include "egluUtil.hpp"
34 #include "egluGLUtil.hpp"
35 #include "eglwEnums.hpp"
36 #include "eglwLibrary.hpp"
37 #include "gluPlatform.hpp"
38 #include "gluRenderConfig.hpp"
39 #include "glwInitES20Direct.hpp"
40 #include "glwInitES30Direct.hpp"
41 #include "glwInitFunctions.hpp"
42 #include "tcuFunctionLibrary.hpp"
43 #include "tcuPixelFormat.hpp"
44 #include "tcuPlatform.hpp"
45 #include "tcuRenderTarget.hpp"
46 #include "vkPlatform.hpp"
47
48 #include <EGL/egl.h>
49
50 using std::string;
51 using std::vector;
52
53 #if !defined(EGL_KHR_create_context)
54 #define EGL_CONTEXT_FLAGS_KHR 0x30FC
55 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
56 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
57 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
58 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
59 #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
60 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
61 #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
62 #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD
63 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
64 #define EGL_KHR_create_context 1
65 #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF
66 #define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE
67 #define EGL_OPENGL_ES3_BIT_KHR 0x00000040
68 #endif // EGL_KHR_create_context
69
70 // Default library names
71 #if !defined(DEQP_GLES2_LIBRARY_PATH)
72 #define DEQP_GLES2_LIBRARY_PATH "libGLESv2.so"
73 #endif
74
75 #if !defined(DEQP_GLES3_LIBRARY_PATH)
76 #define DEQP_GLES3_LIBRARY_PATH DEQP_GLES2_LIBRARY_PATH
77 #endif
78
79 #if !defined(DEQP_OPENGL_LIBRARY_PATH)
80 #define DEQP_OPENGL_LIBRARY_PATH "libGL.so"
81 #endif
82
83 #if !defined(DEQP_VULKAN_LIBRARY_PATH)
84 #if (DE_OS == DE_OS_ANDROID)
85 #define DEQP_VULKAN_LIBRARY_PATH "libvulkan.so"
86 #else
87 #define DEQP_VULKAN_LIBRARY_PATH "libvulkan.so.1"
88 #endif
89 #endif
90
91 namespace tcu
92 {
93 namespace surfaceless
94 {
95
96 class VulkanLibrary : public vk::Library
97 {
98 public:
VulkanLibrary(const char * libraryPath)99 VulkanLibrary(const char *libraryPath)
100 : m_library(libraryPath != DE_NULL ? libraryPath : DEQP_VULKAN_LIBRARY_PATH)
101 , m_driver(m_library)
102 {
103 }
104
getPlatformInterface(void) const105 const vk::PlatformInterface &getPlatformInterface(void) const
106 {
107 return m_driver;
108 }
getFunctionLibrary(void) const109 const tcu::FunctionLibrary &getFunctionLibrary(void) const
110 {
111 return m_library;
112 }
113
114 private:
115 const tcu::DynamicFunctionLibrary m_library;
116 const vk::PlatformDriver m_driver;
117 };
118
119 // Copied from tcuX11Platform.cpp
120 class VulkanPlatform : public vk::Platform
121 {
122 public:
createLibrary(const char * libraryPath) const123 vk::Library *createLibrary(const char *libraryPath) const
124 {
125 return new VulkanLibrary(libraryPath);
126 }
127
describePlatform(std::ostream & dst) const128 void describePlatform(std::ostream &dst) const
129 {
130 utsname sysInfo;
131
132 deMemset(&sysInfo, 0, sizeof(sysInfo));
133
134 if (uname(&sysInfo) != 0)
135 throw std::runtime_error("uname() failed");
136
137 dst << "OS: " << sysInfo.sysname << " " << sysInfo.release << " " << sysInfo.version << "\n";
138 dst << "CPU: " << sysInfo.machine << "\n";
139 }
140 };
141
isEGLExtensionSupported(const eglw::Library & egl,eglw::EGLDisplay,const std::string & extName)142 bool isEGLExtensionSupported(const eglw::Library &egl, eglw::EGLDisplay, const std::string &extName)
143 {
144 const vector<string> exts = eglu::getClientExtensions(egl);
145 return de::contains(exts.begin(), exts.end(), extName);
146 }
147
148 class GetProcFuncLoader : public glw::FunctionLoader
149 {
150 public:
GetProcFuncLoader(const eglw::Library & egl)151 GetProcFuncLoader(const eglw::Library &egl) : m_egl(egl)
152 {
153 }
154
get(const char * name) const155 glw::GenericFuncType get(const char *name) const
156 {
157 return (glw::GenericFuncType)m_egl.getProcAddress(name);
158 }
159
160 protected:
161 const eglw::Library &m_egl;
162 };
163
164 class DynamicFuncLoader : public glw::FunctionLoader
165 {
166 public:
DynamicFuncLoader(de::DynamicLibrary * library)167 DynamicFuncLoader(de::DynamicLibrary *library) : m_library(library)
168 {
169 }
170
get(const char * name) const171 glw::GenericFuncType get(const char *name) const
172 {
173 return (glw::GenericFuncType)m_library->getFunction(name);
174 }
175
176 private:
177 de::DynamicLibrary *m_library;
178 };
179
180 class Platform : public tcu::Platform, public glu::Platform
181 {
182 public:
183 Platform(void);
getGLPlatform(void) const184 const glu::Platform &getGLPlatform(void) const
185 {
186 return *this;
187 }
getVulkanPlatform(void) const188 const vk::Platform &getVulkanPlatform(void) const
189 {
190 return m_vkPlatform;
191 }
192
193 private:
194 VulkanPlatform m_vkPlatform;
195 };
196
197 class ContextFactory : public glu::ContextFactory
198 {
199 public:
200 ContextFactory(void);
201 glu::RenderContext *createContext(const glu::RenderConfig &config, const tcu::CommandLine &,
202 const glu::RenderContext *) const;
203 };
204
205 class EglRenderContext : public glu::RenderContext
206 {
207 public:
208 EglRenderContext(const glu::RenderConfig &config, const tcu::CommandLine &cmdLine,
209 const glu::RenderContext *sharedContext);
210 ~EglRenderContext(void);
211
getType(void) const212 glu::ContextType getType(void) const
213 {
214 return m_contextType;
215 }
getEglContext(void) const216 eglw::EGLContext getEglContext(void) const
217 {
218 return m_eglContext;
219 }
getFunctions(void) const220 const glw::Functions &getFunctions(void) const
221 {
222 return m_glFunctions;
223 }
224 const tcu::RenderTarget &getRenderTarget(void) const;
225 void postIterate(void);
226 virtual void makeCurrent(void);
227
getProcAddress(const char * name) const228 virtual glw::GenericFuncType getProcAddress(const char *name) const
229 {
230 return m_egl.getProcAddress(name);
231 }
232
233 private:
234 const eglw::DefaultLibrary m_egl;
235 const glu::ContextType m_contextType;
236 eglw::EGLDisplay m_eglDisplay;
237 eglw::EGLContext m_eglContext;
238 eglw::EGLSurface m_eglSurface;
239 de::DynamicLibrary *m_glLibrary;
240 glw::Functions m_glFunctions;
241 tcu::RenderTarget m_renderTarget;
242 };
243
Platform(void)244 Platform::Platform(void)
245 {
246 m_contextFactoryRegistry.registerFactory(new ContextFactory());
247 }
248
ContextFactory()249 ContextFactory::ContextFactory() : glu::ContextFactory("default", "EGL surfaceless context")
250 {
251 }
252
createContext(const glu::RenderConfig & config,const tcu::CommandLine & cmdLine,const glu::RenderContext * sharedContext) const253 glu::RenderContext *ContextFactory::createContext(const glu::RenderConfig &config, const tcu::CommandLine &cmdLine,
254 const glu::RenderContext *sharedContext) const
255 {
256 return new EglRenderContext(config, cmdLine, sharedContext);
257 }
258
EglRenderContext(const glu::RenderConfig & config,const tcu::CommandLine & cmdLine,const glu::RenderContext * sharedContext)259 EglRenderContext::EglRenderContext(const glu::RenderConfig &config, const tcu::CommandLine &cmdLine,
260 const glu::RenderContext *sharedContext)
261 : m_egl("libEGL.so")
262 , m_contextType(config.type)
263 , m_eglDisplay(EGL_NO_DISPLAY)
264 , m_eglContext(EGL_NO_CONTEXT)
265 , m_renderTarget(config.width, config.height,
266 tcu::PixelFormat(config.redBits, config.greenBits, config.blueBits, config.alphaBits),
267 config.depthBits, config.stencilBits, config.numSamples)
268
269 {
270 vector<eglw::EGLint> context_attribs;
271 vector<eglw::EGLint> frame_buffer_attribs;
272 vector<eglw::EGLint> surface_attribs;
273
274 const glu::ContextType &contextType = config.type;
275 eglw::EGLint eglMajorVersion;
276 eglw::EGLint eglMinorVersion;
277 eglw::EGLint flags = 0;
278 eglw::EGLint num_configs;
279 eglw::EGLConfig egl_config = NULL;
280
281 (void)cmdLine;
282
283 m_eglDisplay = m_egl.getDisplay(NULL);
284 EGLU_CHECK_MSG(m_egl, "eglGetDisplay()");
285 if (m_eglDisplay == EGL_NO_DISPLAY)
286 throw tcu::ResourceError("eglGetDisplay() failed");
287
288 EGLU_CHECK_CALL(m_egl, initialize(m_eglDisplay, &eglMajorVersion, &eglMinorVersion));
289
290 frame_buffer_attribs.push_back(EGL_RENDERABLE_TYPE);
291 switch (contextType.getMajorVersion())
292 {
293 case 3:
294 frame_buffer_attribs.push_back(EGL_OPENGL_ES3_BIT);
295 break;
296 case 2:
297 frame_buffer_attribs.push_back(EGL_OPENGL_ES2_BIT);
298 break;
299 default:
300 frame_buffer_attribs.push_back(EGL_OPENGL_ES_BIT);
301 }
302
303 frame_buffer_attribs.push_back(EGL_SURFACE_TYPE);
304 switch (config.surfaceType)
305 {
306 case glu::RenderConfig::SURFACETYPE_DONT_CARE:
307 frame_buffer_attribs.push_back(EGL_DONT_CARE);
308 break;
309 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
310 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
311 frame_buffer_attribs.push_back(EGL_PBUFFER_BIT);
312 surface_attribs.push_back(EGL_WIDTH);
313 surface_attribs.push_back(config.width);
314 surface_attribs.push_back(EGL_HEIGHT);
315 surface_attribs.push_back(config.height);
316 break;
317 case glu::RenderConfig::SURFACETYPE_WINDOW:
318 throw tcu::NotSupportedError("surfaceless platform does not support --deqp-surface-type=window");
319 case glu::RenderConfig::SURFACETYPE_LAST:
320 TCU_CHECK_INTERNAL(false);
321 }
322
323 surface_attribs.push_back(EGL_NONE);
324
325 frame_buffer_attribs.push_back(EGL_RED_SIZE);
326 frame_buffer_attribs.push_back(config.redBits);
327
328 frame_buffer_attribs.push_back(EGL_GREEN_SIZE);
329 frame_buffer_attribs.push_back(config.greenBits);
330
331 frame_buffer_attribs.push_back(EGL_BLUE_SIZE);
332 frame_buffer_attribs.push_back(config.blueBits);
333
334 frame_buffer_attribs.push_back(EGL_ALPHA_SIZE);
335 frame_buffer_attribs.push_back(config.alphaBits);
336
337 frame_buffer_attribs.push_back(EGL_DEPTH_SIZE);
338 frame_buffer_attribs.push_back(config.depthBits);
339
340 frame_buffer_attribs.push_back(EGL_STENCIL_SIZE);
341 frame_buffer_attribs.push_back(config.stencilBits);
342
343 frame_buffer_attribs.push_back(EGL_SAMPLES);
344 frame_buffer_attribs.push_back(config.numSamples);
345
346 frame_buffer_attribs.push_back(EGL_NONE);
347
348 if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], NULL, 0, &num_configs))
349 throw tcu::ResourceError("surfaceless couldn't find any config");
350
351 eglw::EGLConfig all_configs[num_configs];
352
353 if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], all_configs, num_configs, &num_configs))
354 throw tcu::ResourceError("surfaceless couldn't find any config");
355
356 for (int i = 0; i < num_configs; i++)
357 {
358 EGLint red, green, blue, alpha, depth, stencil, samples;
359 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_RED_SIZE, &red);
360 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_GREEN_SIZE, &green);
361 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_BLUE_SIZE, &blue);
362 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_ALPHA_SIZE, &alpha);
363 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_DEPTH_SIZE, &depth);
364 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_STENCIL_SIZE, &stencil);
365 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_SAMPLES, &samples);
366
367 if ((glu::RenderConfig::DONT_CARE == config.redBits || red == config.redBits) &&
368 (glu::RenderConfig::DONT_CARE == config.greenBits || green == config.greenBits) &&
369 (glu::RenderConfig::DONT_CARE == config.blueBits || blue == config.blueBits) &&
370 (glu::RenderConfig::DONT_CARE == config.alphaBits || alpha == config.alphaBits) &&
371 (glu::RenderConfig::DONT_CARE == config.depthBits || depth == config.depthBits) &&
372 (glu::RenderConfig::DONT_CARE == config.stencilBits || stencil == config.stencilBits) &&
373 (glu::RenderConfig::DONT_CARE == config.numSamples || samples == config.numSamples))
374 {
375 egl_config = all_configs[i];
376 break;
377 }
378 }
379
380 if (!egl_config)
381 throw tcu::ResourceError("surfaceless couldn't find a matching config");
382
383 switch (config.surfaceType)
384 {
385 case glu::RenderConfig::SURFACETYPE_DONT_CARE:
386 m_eglSurface = EGL_NO_SURFACE;
387 break;
388 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
389 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
390 m_eglSurface = eglCreatePbufferSurface(m_eglDisplay, egl_config, &surface_attribs[0]);
391 break;
392 case glu::RenderConfig::SURFACETYPE_WINDOW:
393 case glu::RenderConfig::SURFACETYPE_LAST:
394 TCU_CHECK_INTERNAL(false);
395 }
396
397 context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
398 context_attribs.push_back(contextType.getMajorVersion());
399 context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
400 context_attribs.push_back(contextType.getMinorVersion());
401
402 switch (contextType.getProfile())
403 {
404 case glu::PROFILE_ES:
405 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_ES_API));
406 break;
407 case glu::PROFILE_CORE:
408 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
409 context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
410 context_attribs.push_back(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
411 break;
412 case glu::PROFILE_COMPATIBILITY:
413 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
414 context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
415 context_attribs.push_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
416 break;
417 case glu::PROFILE_LAST:
418 TCU_CHECK_INTERNAL(false);
419 }
420
421 if ((contextType.getFlags() & glu::CONTEXT_DEBUG) != 0)
422 flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
423
424 if ((contextType.getFlags() & glu::CONTEXT_ROBUST) != 0)
425 flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
426
427 if ((contextType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0)
428 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
429
430 context_attribs.push_back(EGL_CONTEXT_FLAGS_KHR);
431 context_attribs.push_back(flags);
432
433 context_attribs.push_back(EGL_NONE);
434
435 const EglRenderContext *sharedEglRenderContext = dynamic_cast<const EglRenderContext *>(sharedContext);
436 eglw::EGLContext sharedEglContext =
437 sharedEglRenderContext ? sharedEglRenderContext->getEglContext() : EGL_NO_CONTEXT;
438
439 m_eglContext = m_egl.createContext(m_eglDisplay, egl_config, sharedEglContext, &context_attribs[0]);
440 EGLU_CHECK_MSG(m_egl, "eglCreateContext()");
441 if (!m_eglContext)
442 throw tcu::ResourceError("eglCreateContext failed");
443
444 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
445
446 if ((eglMajorVersion == 1 && eglMinorVersion >= 5) ||
447 isEGLExtensionSupported(m_egl, m_eglDisplay, "EGL_KHR_get_all_proc_addresses") ||
448 isEGLExtensionSupported(m_egl, EGL_NO_DISPLAY, "EGL_KHR_client_get_all_proc_addresses"))
449 {
450 // Use eglGetProcAddress() for core functions
451 GetProcFuncLoader funcLoader(m_egl);
452 glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
453 }
454 #if !defined(DEQP_GLES2_RUNTIME_LOAD)
455 else if (contextType.getAPI() == glu::ApiType::es(2, 0))
456 {
457 glw::initES20Direct(&m_glFunctions);
458 }
459 #endif
460 #if !defined(DEQP_GLES3_RUNTIME_LOAD)
461 else if (contextType.getAPI() == glu::ApiType::es(3, 0))
462 {
463 glw::initES30Direct(&m_glFunctions);
464 }
465 #endif
466 else
467 {
468 const char *libraryPath = NULL;
469
470 if (glu::isContextTypeES(contextType))
471 {
472 if (contextType.getMinorVersion() <= 2)
473 libraryPath = DEQP_GLES2_LIBRARY_PATH;
474 else
475 libraryPath = DEQP_GLES3_LIBRARY_PATH;
476 }
477 else
478 {
479 libraryPath = DEQP_OPENGL_LIBRARY_PATH;
480 }
481
482 m_glLibrary = new de::DynamicLibrary(libraryPath);
483
484 DynamicFuncLoader funcLoader(m_glLibrary);
485 glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
486 }
487
488 {
489 GetProcFuncLoader extLoader(m_egl);
490 glu::initExtensionFunctions(&m_glFunctions, &extLoader, contextType.getAPI());
491 }
492 }
493
~EglRenderContext(void)494 EglRenderContext::~EglRenderContext(void)
495 {
496 try
497 {
498 if (m_eglDisplay != EGL_NO_DISPLAY)
499 {
500 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
501
502 if (m_eglContext != EGL_NO_CONTEXT)
503 EGLU_CHECK_CALL(m_egl, destroyContext(m_eglDisplay, m_eglContext));
504 }
505
506 EGLU_CHECK_CALL(m_egl, terminate(m_eglDisplay));
507 }
508 catch (...)
509 {
510 }
511 }
512
getRenderTarget(void) const513 const tcu::RenderTarget &EglRenderContext::getRenderTarget(void) const
514 {
515 return m_renderTarget;
516 }
517
makeCurrent(void)518 void EglRenderContext::makeCurrent(void)
519 {
520 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
521 }
522
postIterate(void)523 void EglRenderContext::postIterate(void)
524 {
525 this->getFunctions().finish();
526 }
527
528 } // namespace surfaceless
529 } // namespace tcu
530
createPlatform(void)531 tcu::Platform *createPlatform(void)
532 {
533 return new tcu::surfaceless::Platform();
534 }
535