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 #ifdef CTS_USES_VULKANSC
85 #define DEQP_VULKAN_LIBRARY_BASENAME "libvulkansc"
86 #else
87 #define DEQP_VULKAN_LIBRARY_BASENAME "libvulkan"
88 #endif
89 #if (DE_OS == DE_OS_ANDROID)
90 #define DEQP_VULKAN_LIBRARY_SUFFIX ".so"
91 #else
92 #define DEQP_VULKAN_LIBRARY_SUFFIX ".so.1"
93 #endif
94 #define DEQP_VULKAN_LIBRARY_PATH DEQP_VULKAN_LIBRARY_BASENAME DEQP_VULKAN_LIBRARY_SUFFIX
95 #endif
96
97 namespace tcu
98 {
99 namespace surfaceless
100 {
101
102 class VulkanLibrary : public vk::Library
103 {
104 public:
VulkanLibrary(const char * libraryPath)105 VulkanLibrary(const char *libraryPath)
106 : m_library(libraryPath != nullptr ? libraryPath : DEQP_VULKAN_LIBRARY_PATH)
107 , m_driver(m_library)
108 {
109 }
110
getPlatformInterface(void) const111 const vk::PlatformInterface &getPlatformInterface(void) const
112 {
113 return m_driver;
114 }
getFunctionLibrary(void) const115 const tcu::FunctionLibrary &getFunctionLibrary(void) const
116 {
117 return m_library;
118 }
119
120 private:
121 const tcu::DynamicFunctionLibrary m_library;
122 const vk::PlatformDriver m_driver;
123 };
124
125 // Copied from tcuX11Platform.cpp
126 class VulkanPlatform : public vk::Platform
127 {
128 public:
createLibrary(const char * libraryPath) const129 vk::Library *createLibrary(const char *libraryPath) const
130 {
131 return new VulkanLibrary(libraryPath);
132 }
133
describePlatform(std::ostream & dst) const134 void describePlatform(std::ostream &dst) const
135 {
136 utsname sysInfo;
137
138 deMemset(&sysInfo, 0, sizeof(sysInfo));
139
140 if (uname(&sysInfo) != 0)
141 throw std::runtime_error("uname() failed");
142
143 dst << "OS: " << sysInfo.sysname << " " << sysInfo.release << " " << sysInfo.version << "\n";
144 dst << "CPU: " << sysInfo.machine << "\n";
145 }
146 };
147
isEGLExtensionSupported(const eglw::Library & egl,eglw::EGLDisplay,const std::string & extName)148 bool isEGLExtensionSupported(const eglw::Library &egl, eglw::EGLDisplay, const std::string &extName)
149 {
150 const vector<string> exts = eglu::getClientExtensions(egl);
151 return de::contains(exts.begin(), exts.end(), extName);
152 }
153
154 class GetProcFuncLoader : public glw::FunctionLoader
155 {
156 public:
GetProcFuncLoader(const eglw::Library & egl)157 GetProcFuncLoader(const eglw::Library &egl) : m_egl(egl)
158 {
159 }
160
get(const char * name) const161 glw::GenericFuncType get(const char *name) const
162 {
163 return (glw::GenericFuncType)m_egl.getProcAddress(name);
164 }
165
166 protected:
167 const eglw::Library &m_egl;
168 };
169
170 class DynamicFuncLoader : public glw::FunctionLoader
171 {
172 public:
DynamicFuncLoader(de::DynamicLibrary * library)173 DynamicFuncLoader(de::DynamicLibrary *library) : m_library(library)
174 {
175 }
176
get(const char * name) const177 glw::GenericFuncType get(const char *name) const
178 {
179 return (glw::GenericFuncType)m_library->getFunction(name);
180 }
181
182 private:
183 de::DynamicLibrary *m_library;
184 };
185
186 class Platform : public tcu::Platform, public glu::Platform
187 {
188 public:
189 Platform(void);
getGLPlatform(void) const190 const glu::Platform &getGLPlatform(void) const
191 {
192 return *this;
193 }
getVulkanPlatform(void) const194 const vk::Platform &getVulkanPlatform(void) const
195 {
196 return m_vkPlatform;
197 }
198
199 private:
200 VulkanPlatform m_vkPlatform;
201 };
202
203 class ContextFactory : public glu::ContextFactory
204 {
205 public:
206 ContextFactory(void);
207 glu::RenderContext *createContext(const glu::RenderConfig &config, const tcu::CommandLine &,
208 const glu::RenderContext *) const;
209 };
210
211 class EglRenderContext : public glu::RenderContext
212 {
213 public:
214 EglRenderContext(const glu::RenderConfig &config, const tcu::CommandLine &cmdLine,
215 const glu::RenderContext *sharedContext);
216 ~EglRenderContext(void);
217
getType(void) const218 glu::ContextType getType(void) const
219 {
220 return m_contextType;
221 }
getEglContext(void) const222 eglw::EGLContext getEglContext(void) const
223 {
224 return m_eglContext;
225 }
getFunctions(void) const226 const glw::Functions &getFunctions(void) const
227 {
228 return m_glFunctions;
229 }
230 const tcu::RenderTarget &getRenderTarget(void) const;
231 void postIterate(void);
232 virtual void makeCurrent(void);
233
getProcAddress(const char * name) const234 virtual glw::GenericFuncType getProcAddress(const char *name) const
235 {
236 return m_egl.getProcAddress(name);
237 }
238
239 private:
240 const eglw::DefaultLibrary m_egl;
241 const glu::ContextType m_contextType;
242 eglw::EGLDisplay m_eglDisplay;
243 eglw::EGLContext m_eglContext;
244 eglw::EGLSurface m_eglSurface;
245 de::DynamicLibrary *m_glLibrary;
246 glw::Functions m_glFunctions;
247 tcu::RenderTarget m_renderTarget;
248 };
249
Platform(void)250 Platform::Platform(void)
251 {
252 m_contextFactoryRegistry.registerFactory(new ContextFactory());
253 }
254
ContextFactory()255 ContextFactory::ContextFactory() : glu::ContextFactory("default", "EGL surfaceless context")
256 {
257 }
258
createContext(const glu::RenderConfig & config,const tcu::CommandLine & cmdLine,const glu::RenderContext * sharedContext) const259 glu::RenderContext *ContextFactory::createContext(const glu::RenderConfig &config, const tcu::CommandLine &cmdLine,
260 const glu::RenderContext *sharedContext) const
261 {
262 return new EglRenderContext(config, cmdLine, sharedContext);
263 }
264
EglRenderContext(const glu::RenderConfig & config,const tcu::CommandLine & cmdLine,const glu::RenderContext * sharedContext)265 EglRenderContext::EglRenderContext(const glu::RenderConfig &config, const tcu::CommandLine &cmdLine,
266 const glu::RenderContext *sharedContext)
267 : m_egl("libEGL.so")
268 , m_contextType(config.type)
269 , m_eglDisplay(EGL_NO_DISPLAY)
270 , m_eglContext(EGL_NO_CONTEXT)
271 , m_renderTarget(config.width, config.height,
272 tcu::PixelFormat(config.redBits, config.greenBits, config.blueBits, config.alphaBits),
273 config.depthBits, config.stencilBits, config.numSamples)
274
275 {
276 vector<eglw::EGLint> context_attribs;
277 vector<eglw::EGLint> frame_buffer_attribs;
278 vector<eglw::EGLint> surface_attribs;
279
280 const glu::ContextType &contextType = config.type;
281 eglw::EGLint eglMajorVersion;
282 eglw::EGLint eglMinorVersion;
283 eglw::EGLint flags = 0;
284 eglw::EGLint num_configs;
285 eglw::EGLConfig egl_config = NULL;
286
287 (void)cmdLine;
288
289 m_eglDisplay = m_egl.getDisplay(NULL);
290 EGLU_CHECK_MSG(m_egl, "eglGetDisplay()");
291 if (m_eglDisplay == EGL_NO_DISPLAY)
292 throw tcu::ResourceError("eglGetDisplay() failed");
293
294 EGLU_CHECK_CALL(m_egl, initialize(m_eglDisplay, &eglMajorVersion, &eglMinorVersion));
295
296 frame_buffer_attribs.push_back(EGL_RENDERABLE_TYPE);
297 switch (contextType.getMajorVersion())
298 {
299 case 3:
300 frame_buffer_attribs.push_back(EGL_OPENGL_ES3_BIT);
301 break;
302 case 2:
303 frame_buffer_attribs.push_back(EGL_OPENGL_ES2_BIT);
304 break;
305 default:
306 frame_buffer_attribs.push_back(EGL_OPENGL_ES_BIT);
307 }
308
309 frame_buffer_attribs.push_back(EGL_SURFACE_TYPE);
310 switch (config.surfaceType)
311 {
312 case glu::RenderConfig::SURFACETYPE_DONT_CARE:
313 frame_buffer_attribs.push_back(EGL_DONT_CARE);
314 break;
315 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
316 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
317 frame_buffer_attribs.push_back(EGL_PBUFFER_BIT);
318 surface_attribs.push_back(EGL_WIDTH);
319 surface_attribs.push_back(config.width);
320 surface_attribs.push_back(EGL_HEIGHT);
321 surface_attribs.push_back(config.height);
322 break;
323 case glu::RenderConfig::SURFACETYPE_WINDOW:
324 throw tcu::NotSupportedError("surfaceless platform does not support --deqp-surface-type=window");
325 case glu::RenderConfig::SURFACETYPE_LAST:
326 TCU_CHECK_INTERNAL(false);
327 }
328
329 surface_attribs.push_back(EGL_NONE);
330
331 frame_buffer_attribs.push_back(EGL_RED_SIZE);
332 frame_buffer_attribs.push_back(config.redBits);
333
334 frame_buffer_attribs.push_back(EGL_GREEN_SIZE);
335 frame_buffer_attribs.push_back(config.greenBits);
336
337 frame_buffer_attribs.push_back(EGL_BLUE_SIZE);
338 frame_buffer_attribs.push_back(config.blueBits);
339
340 frame_buffer_attribs.push_back(EGL_ALPHA_SIZE);
341 frame_buffer_attribs.push_back(config.alphaBits);
342
343 frame_buffer_attribs.push_back(EGL_DEPTH_SIZE);
344 frame_buffer_attribs.push_back(config.depthBits);
345
346 frame_buffer_attribs.push_back(EGL_STENCIL_SIZE);
347 frame_buffer_attribs.push_back(config.stencilBits);
348
349 frame_buffer_attribs.push_back(EGL_SAMPLES);
350 frame_buffer_attribs.push_back(config.numSamples);
351
352 frame_buffer_attribs.push_back(EGL_NONE);
353
354 if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], NULL, 0, &num_configs))
355 throw tcu::ResourceError("surfaceless couldn't find any config");
356
357 eglw::EGLConfig all_configs[num_configs];
358
359 if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], all_configs, num_configs, &num_configs))
360 throw tcu::ResourceError("surfaceless couldn't find any config");
361
362 for (int i = 0; i < num_configs; i++)
363 {
364 EGLint red, green, blue, alpha, depth, stencil, samples;
365 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_RED_SIZE, &red);
366 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_GREEN_SIZE, &green);
367 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_BLUE_SIZE, &blue);
368 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_ALPHA_SIZE, &alpha);
369 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_DEPTH_SIZE, &depth);
370 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_STENCIL_SIZE, &stencil);
371 eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_SAMPLES, &samples);
372
373 if ((glu::RenderConfig::DONT_CARE == config.redBits || red == config.redBits) &&
374 (glu::RenderConfig::DONT_CARE == config.greenBits || green == config.greenBits) &&
375 (glu::RenderConfig::DONT_CARE == config.blueBits || blue == config.blueBits) &&
376 (glu::RenderConfig::DONT_CARE == config.alphaBits || alpha == config.alphaBits) &&
377 (glu::RenderConfig::DONT_CARE == config.depthBits || depth == config.depthBits) &&
378 (glu::RenderConfig::DONT_CARE == config.stencilBits || stencil == config.stencilBits) &&
379 (glu::RenderConfig::DONT_CARE == config.numSamples || samples == config.numSamples))
380 {
381 egl_config = all_configs[i];
382 break;
383 }
384 }
385
386 if (!egl_config)
387 throw tcu::ResourceError("surfaceless couldn't find a matching config");
388
389 switch (config.surfaceType)
390 {
391 case glu::RenderConfig::SURFACETYPE_DONT_CARE:
392 m_eglSurface = EGL_NO_SURFACE;
393 break;
394 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
395 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
396 m_eglSurface = eglCreatePbufferSurface(m_eglDisplay, egl_config, &surface_attribs[0]);
397 break;
398 case glu::RenderConfig::SURFACETYPE_WINDOW:
399 case glu::RenderConfig::SURFACETYPE_LAST:
400 TCU_CHECK_INTERNAL(false);
401 }
402
403 context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
404 context_attribs.push_back(contextType.getMajorVersion());
405 context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
406 context_attribs.push_back(contextType.getMinorVersion());
407
408 switch (contextType.getProfile())
409 {
410 case glu::PROFILE_ES:
411 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_ES_API));
412 break;
413 case glu::PROFILE_CORE:
414 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
415 context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
416 context_attribs.push_back(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
417 break;
418 case glu::PROFILE_COMPATIBILITY:
419 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
420 context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
421 context_attribs.push_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
422 break;
423 case glu::PROFILE_LAST:
424 TCU_CHECK_INTERNAL(false);
425 }
426
427 if ((contextType.getFlags() & glu::CONTEXT_DEBUG) != 0)
428 flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
429
430 if ((contextType.getFlags() & glu::CONTEXT_ROBUST) != 0)
431 flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
432
433 if ((contextType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0)
434 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
435
436 context_attribs.push_back(EGL_CONTEXT_FLAGS_KHR);
437 context_attribs.push_back(flags);
438
439 context_attribs.push_back(EGL_NONE);
440
441 const EglRenderContext *sharedEglRenderContext = dynamic_cast<const EglRenderContext *>(sharedContext);
442 eglw::EGLContext sharedEglContext =
443 sharedEglRenderContext ? sharedEglRenderContext->getEglContext() : EGL_NO_CONTEXT;
444
445 m_eglContext = m_egl.createContext(m_eglDisplay, egl_config, sharedEglContext, &context_attribs[0]);
446 EGLU_CHECK_MSG(m_egl, "eglCreateContext()");
447 if (!m_eglContext)
448 throw tcu::ResourceError("eglCreateContext failed");
449
450 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
451
452 if ((eglMajorVersion == 1 && eglMinorVersion >= 5) ||
453 isEGLExtensionSupported(m_egl, m_eglDisplay, "EGL_KHR_get_all_proc_addresses") ||
454 isEGLExtensionSupported(m_egl, EGL_NO_DISPLAY, "EGL_KHR_client_get_all_proc_addresses"))
455 {
456 // Use eglGetProcAddress() for core functions
457 GetProcFuncLoader funcLoader(m_egl);
458 glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
459 }
460 #if !defined(DEQP_GLES2_RUNTIME_LOAD)
461 else if (contextType.getAPI() == glu::ApiType::es(2, 0))
462 {
463 glw::initES20Direct(&m_glFunctions);
464 }
465 #endif
466 #if !defined(DEQP_GLES3_RUNTIME_LOAD)
467 else if (contextType.getAPI() == glu::ApiType::es(3, 0))
468 {
469 glw::initES30Direct(&m_glFunctions);
470 }
471 #endif
472 else
473 {
474 const char *libraryPath = NULL;
475
476 if (glu::isContextTypeES(contextType))
477 {
478 if (contextType.getMinorVersion() <= 2)
479 libraryPath = DEQP_GLES2_LIBRARY_PATH;
480 else
481 libraryPath = DEQP_GLES3_LIBRARY_PATH;
482 }
483 else
484 {
485 libraryPath = DEQP_OPENGL_LIBRARY_PATH;
486 }
487
488 m_glLibrary = new de::DynamicLibrary(libraryPath);
489
490 DynamicFuncLoader funcLoader(m_glLibrary);
491 glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
492 }
493
494 {
495 GetProcFuncLoader extLoader(m_egl);
496 glu::initExtensionFunctions(&m_glFunctions, &extLoader, contextType.getAPI());
497 }
498 }
499
~EglRenderContext(void)500 EglRenderContext::~EglRenderContext(void)
501 {
502 try
503 {
504 if (m_eglDisplay != EGL_NO_DISPLAY)
505 {
506 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
507
508 if (m_eglContext != EGL_NO_CONTEXT)
509 EGLU_CHECK_CALL(m_egl, destroyContext(m_eglDisplay, m_eglContext));
510 }
511
512 EGLU_CHECK_CALL(m_egl, terminate(m_eglDisplay));
513 }
514 catch (...)
515 {
516 }
517 }
518
getRenderTarget(void) const519 const tcu::RenderTarget &EglRenderContext::getRenderTarget(void) const
520 {
521 return m_renderTarget;
522 }
523
makeCurrent(void)524 void EglRenderContext::makeCurrent(void)
525 {
526 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
527 }
528
postIterate(void)529 void EglRenderContext::postIterate(void)
530 {
531 this->getFunctions().finish();
532 }
533
534 } // namespace surfaceless
535 } // namespace tcu
536
createPlatform(void)537 tcu::Platform *createPlatform(void)
538 {
539 return new tcu::surfaceless::Platform();
540 }
541