• 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 #	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