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