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 namespace tcu
84 {
85 namespace surfaceless
86 {
87
88 class VulkanLibrary : public vk::Library
89 {
90 public:
VulkanLibrary(void)91 VulkanLibrary (void)
92 : m_library ("libvulkan.so.1")
93 , m_driver (m_library)
94 {
95 }
96
getPlatformInterface(void) const97 const vk::PlatformInterface& getPlatformInterface (void) const
98 {
99 return m_driver;
100 }
getFunctionLibrary(void) const101 const tcu::FunctionLibrary& getFunctionLibrary (void) const
102 {
103 return m_library;
104 }
105 private:
106 const tcu::DynamicFunctionLibrary m_library;
107 const vk::PlatformDriver m_driver;
108 };
109
110 // Copied from tcuX11Platform.cpp
111 class VulkanPlatform : public vk::Platform
112 {
113 public:
createLibrary(void) const114 vk::Library* createLibrary (void) const
115 {
116 return new VulkanLibrary();
117 }
118
describePlatform(std::ostream & dst) const119 void describePlatform (std::ostream& dst) const
120 {
121 utsname sysInfo;
122
123 deMemset(&sysInfo, 0, sizeof(sysInfo));
124
125 if (uname(&sysInfo) != 0)
126 throw std::runtime_error("uname() failed");
127
128 dst << "OS: " << sysInfo.sysname << " " << sysInfo.release << " " << sysInfo.version << "\n";
129 dst << "CPU: " << sysInfo.machine << "\n";
130 }
131
132 // FINISHME: Query actual memory limits.
133 //
134 // These hard-coded memory limits were copied from tcuX11Platform.cpp,
135 // and they work well enough for Intel platforms.
getMemoryLimits(vk::PlatformMemoryLimits & limits) const136 void getMemoryLimits (vk::PlatformMemoryLimits& limits) const
137 {
138 limits.totalSystemMemory = 256*1024*1024;
139 limits.totalDeviceLocalMemory = 128*1024*1024;
140 limits.deviceMemoryAllocationGranularity = 64*1024;
141 limits.devicePageSize = 4096;
142 limits.devicePageTableEntrySize = 8;
143 limits.devicePageTableHierarchyLevels = 3;
144 }
145 };
146
isEGLExtensionSupported(const eglw::Library & egl,eglw::EGLDisplay display,const std::string & extName)147 bool isEGLExtensionSupported(
148 const eglw::Library& egl,
149 eglw::EGLDisplay display,
150 const std::string& extName)
151 {
152 const vector<string> exts = eglu::getClientExtensions(egl);
153 return de::contains(exts.begin(), exts.end(), extName);
154 }
155
156 class GetProcFuncLoader : public glw::FunctionLoader
157 {
158 public:
GetProcFuncLoader(const eglw::Library & egl)159 GetProcFuncLoader(const eglw::Library& egl): m_egl(egl)
160 {
161 }
162
get(const char * name) const163 glw::GenericFuncType get(const char* name) const
164 {
165 return (glw::GenericFuncType)m_egl.getProcAddress(name);
166 }
167 protected:
168 const eglw::Library& m_egl;
169 };
170
171 class DynamicFuncLoader : public glw::FunctionLoader
172 {
173 public:
DynamicFuncLoader(de::DynamicLibrary * library)174 DynamicFuncLoader(de::DynamicLibrary* library): m_library(library)
175 {
176 }
177
get(const char * name) const178 glw::GenericFuncType get(const char* name) const
179 {
180 return (glw::GenericFuncType)m_library->getFunction(name);
181 }
182
183 private:
184 de::DynamicLibrary* m_library;
185 };
186
187 class Platform : public tcu::Platform, public glu::Platform
188 {
189 public:
190 Platform (void);
getGLPlatform(void) const191 const glu::Platform& getGLPlatform (void) const { return *this; }
getVulkanPlatform(void) const192 const vk::Platform& getVulkanPlatform (void) const { return m_vkPlatform; }
193
194 private:
195 VulkanPlatform m_vkPlatform;
196 };
197
198 class ContextFactory : public glu::ContextFactory
199 {
200 public:
201 ContextFactory (void);
202 glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const;
203 };
204
205 class EglRenderContext : public glu::RenderContext
206 {
207 public:
208 EglRenderContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine);
209 ~EglRenderContext(void);
210
getType(void) const211 glu::ContextType getType (void) const { return m_contextType; }
getFunctions(void) const212 const glw::Functions& getFunctions (void) const { return m_glFunctions; }
213 const tcu::RenderTarget& getRenderTarget (void) const;
214 void postIterate (void);
215
216 private:
217 const eglw::DefaultLibrary m_egl;
218 const glu::ContextType m_contextType;
219 eglw::EGLDisplay m_eglDisplay;
220 eglw::EGLContext m_eglContext;
221 de::DynamicLibrary* m_glLibrary;
222 glw::Functions m_glFunctions;
223 tcu::RenderTarget m_renderTarget;
224 };
225
Platform(void)226 Platform::Platform(void)
227 {
228 m_contextFactoryRegistry.registerFactory(new ContextFactory());
229 }
230
ContextFactory()231 ContextFactory::ContextFactory()
232 : glu::ContextFactory("default", "EGL surfaceless context")
233 {}
234
createContext(const glu::RenderConfig & config,const tcu::CommandLine & cmdLine) const235 glu::RenderContext* ContextFactory::createContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const
236 {
237 return new EglRenderContext(config, cmdLine);
238 }
239
EglRenderContext(const glu::RenderConfig & config,const tcu::CommandLine & cmdLine)240 EglRenderContext::EglRenderContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine)
241 : m_egl("libEGL.so")
242 , m_contextType(config.type)
243 , m_eglDisplay(EGL_NO_DISPLAY)
244 , m_eglContext(EGL_NO_CONTEXT)
245 , m_renderTarget(
246 config.width,
247 config.height,
248 tcu::PixelFormat(
249 config.redBits,
250 config.greenBits,
251 config.blueBits,
252 config.alphaBits),
253 config.depthBits,
254 config.stencilBits,
255 config.numSamples)
256
257 {
258 vector<eglw::EGLint> context_attribs;
259 vector<eglw::EGLint> frame_buffer_attribs;
260 vector<eglw::EGLint> surface_attribs;
261
262 const glu::ContextType& contextType = config.type;
263 eglw::EGLint eglMajorVersion;
264 eglw::EGLint eglMinorVersion;
265 eglw::EGLint flags = 0;
266 eglw::EGLint num_configs;
267 eglw::EGLConfig egl_config;
268 eglw::EGLSurface egl_surface;
269
270 (void) cmdLine;
271
272 m_eglDisplay = m_egl.getDisplay(NULL);
273 EGLU_CHECK_MSG(m_egl, "eglGetDisplay()");
274 if (m_eglDisplay == EGL_NO_DISPLAY)
275 throw tcu::ResourceError("eglGetDisplay() failed");
276
277 EGLU_CHECK_CALL(m_egl, initialize(m_eglDisplay, &eglMajorVersion, &eglMinorVersion));
278
279 frame_buffer_attribs.push_back(EGL_RENDERABLE_TYPE);
280 switch(contextType.getMajorVersion())
281 {
282 case 3:
283 frame_buffer_attribs.push_back(EGL_OPENGL_ES3_BIT);
284 break;
285 case 2:
286 frame_buffer_attribs.push_back(EGL_OPENGL_ES2_BIT);
287 break;
288 default:
289 frame_buffer_attribs.push_back(EGL_OPENGL_ES_BIT);
290 }
291
292 frame_buffer_attribs.push_back(EGL_SURFACE_TYPE);
293 switch (config.surfaceType)
294 {
295 case glu::RenderConfig::SURFACETYPE_DONT_CARE:
296 frame_buffer_attribs.push_back(EGL_DONT_CARE);
297 break;
298 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
299 break;
300 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
301 frame_buffer_attribs.push_back(EGL_PBUFFER_BIT);
302 surface_attribs.push_back(EGL_WIDTH);
303 surface_attribs.push_back(config.width);
304 surface_attribs.push_back(EGL_HEIGHT);
305 surface_attribs.push_back(config.height);
306 break;
307 case glu::RenderConfig::SURFACETYPE_WINDOW:
308 throw tcu::NotSupportedError("surfaceless platform does not support --deqp-surface-type=window");
309 case glu::RenderConfig::SURFACETYPE_LAST:
310 TCU_CHECK_INTERNAL(false);
311 }
312
313 surface_attribs.push_back(EGL_NONE);
314
315 frame_buffer_attribs.push_back(EGL_RED_SIZE);
316 frame_buffer_attribs.push_back(config.redBits);
317
318 frame_buffer_attribs.push_back(EGL_GREEN_SIZE);
319 frame_buffer_attribs.push_back(config.greenBits);
320
321 frame_buffer_attribs.push_back(EGL_BLUE_SIZE);
322 frame_buffer_attribs.push_back(config.blueBits);
323
324 frame_buffer_attribs.push_back(EGL_ALPHA_SIZE);
325 frame_buffer_attribs.push_back(config.alphaBits);
326
327 frame_buffer_attribs.push_back(EGL_DEPTH_SIZE);
328 frame_buffer_attribs.push_back(config.depthBits);
329
330 frame_buffer_attribs.push_back(EGL_STENCIL_SIZE);
331 frame_buffer_attribs.push_back(config.stencilBits);
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 if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], &egl_config, 1, &num_configs))
339 throw tcu::ResourceError("surfaceless couldn't find any config");
340
341 switch (config.surfaceType)
342 {
343 case glu::RenderConfig::SURFACETYPE_DONT_CARE:
344 egl_surface = EGL_NO_SURFACE;
345 break;
346 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
347 egl_surface = eglCreatePbufferSurface(m_eglDisplay, egl_config, &surface_attribs[0]);
348 break;
349 }
350
351 context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
352 context_attribs.push_back(contextType.getMajorVersion());
353 context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
354 context_attribs.push_back(contextType.getMinorVersion());
355
356 switch (contextType.getProfile())
357 {
358 case glu::PROFILE_ES:
359 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_ES_API));
360 break;
361 case glu::PROFILE_CORE:
362 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
363 context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
364 context_attribs.push_back(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
365 break;
366 case glu::PROFILE_COMPATIBILITY:
367 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
368 context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
369 context_attribs.push_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
370 break;
371 case glu::PROFILE_LAST:
372 TCU_CHECK_INTERNAL(false);
373 }
374
375 if ((contextType.getFlags() & glu::CONTEXT_DEBUG) != 0)
376 flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
377
378 if ((contextType.getFlags() & glu::CONTEXT_ROBUST) != 0)
379 flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
380
381 if ((contextType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0)
382 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
383
384 context_attribs.push_back(EGL_CONTEXT_FLAGS_KHR);
385 context_attribs.push_back(flags);
386
387 context_attribs.push_back(EGL_NONE);
388
389 m_eglContext = m_egl.createContext(m_eglDisplay, egl_config, EGL_NO_CONTEXT, &context_attribs[0]);
390 EGLU_CHECK_MSG(m_egl, "eglCreateContext()");
391 if (!m_eglContext)
392 throw tcu::ResourceError("eglCreateContext failed");
393
394 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, egl_surface, egl_surface, m_eglContext));
395
396 if ((eglMajorVersion == 1 && eglMinorVersion >= 5) ||
397 isEGLExtensionSupported(m_egl, m_eglDisplay, "EGL_KHR_get_all_proc_addresses") ||
398 isEGLExtensionSupported(m_egl, EGL_NO_DISPLAY, "EGL_KHR_client_get_all_proc_addresses"))
399 {
400 // Use eglGetProcAddress() for core functions
401 GetProcFuncLoader funcLoader(m_egl);
402 glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
403 }
404 #if !defined(DEQP_GLES2_RUNTIME_LOAD)
405 else if (contextType.getAPI() == glu::ApiType::es(2,0))
406 {
407 glw::initES20Direct(&m_glFunctions);
408 }
409 #endif
410 #if !defined(DEQP_GLES3_RUNTIME_LOAD)
411 else if (contextType.getAPI() == glu::ApiType::es(3,0))
412 {
413 glw::initES30Direct(&m_glFunctions);
414 }
415 #endif
416 else
417 {
418 const char* libraryPath = NULL;
419
420 if (glu::isContextTypeES(contextType))
421 {
422 if (contextType.getMinorVersion() <= 2)
423 libraryPath = DEQP_GLES2_LIBRARY_PATH;
424 else
425 libraryPath = DEQP_GLES3_LIBRARY_PATH;
426 }
427 else
428 {
429 libraryPath = DEQP_OPENGL_LIBRARY_PATH;
430 }
431
432 m_glLibrary = new de::DynamicLibrary(libraryPath);
433
434 DynamicFuncLoader funcLoader(m_glLibrary);
435 glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
436 }
437
438 {
439 GetProcFuncLoader extLoader(m_egl);
440 glu::initExtensionFunctions(&m_glFunctions, &extLoader, contextType.getAPI());
441 }
442 }
443
~EglRenderContext(void)444 EglRenderContext::~EglRenderContext(void)
445 {
446 try
447 {
448 if (m_eglDisplay != EGL_NO_DISPLAY)
449 {
450 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
451
452 if (m_eglContext != EGL_NO_CONTEXT)
453 EGLU_CHECK_CALL(m_egl, destroyContext(m_eglDisplay, m_eglContext));
454 }
455
456 EGLU_CHECK_CALL(m_egl, terminate(m_eglDisplay));
457 }
458 catch (...)
459 {
460 }
461 }
462
getRenderTarget(void) const463 const tcu::RenderTarget& EglRenderContext::getRenderTarget(void) const
464 {
465 return m_renderTarget;
466 }
467
postIterate(void)468 void EglRenderContext::postIterate(void)
469 {
470 this->getFunctions().finish();
471 }
472
473 } // namespace surfaceless
474 } // namespace tcu
475
createPlatform(void)476 tcu::Platform* createPlatform(void)
477 {
478 return new tcu::surfaceless::Platform();
479 }
480