xref: /aosp_15_r20/external/deqp/framework/platform/surfaceless/tcuSurfacelessPlatform.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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