• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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