• 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);
203 					~EglRenderContext(void);
204 
getType(void) const205 	glu::ContextType		getType		(void) const	{ return m_contextType; }
getFunctions(void) const206 	const glw::Functions&		getFunctions	(void) const	{ return m_glFunctions; }
207 	const tcu::RenderTarget&	getRenderTarget	(void) const;
208 	void				postIterate	(void);
209 
getProcAddress(const char * name) const210 	virtual glw::GenericFuncType    getProcAddress	(const char* name) const { return m_egl.getProcAddress(name); }
211 
212 private:
213 	const eglw::DefaultLibrary      m_egl;
214 	const glu::ContextType		m_contextType;
215 	eglw::EGLDisplay		m_eglDisplay;
216 	eglw::EGLContext		m_eglContext;
217 	de::DynamicLibrary*		m_glLibrary;
218 	glw::Functions			m_glFunctions;
219 	tcu::RenderTarget		m_renderTarget;
220 };
221 
Platform(void)222 Platform::Platform(void)
223 {
224 	m_contextFactoryRegistry.registerFactory(new ContextFactory());
225 }
226 
ContextFactory()227 ContextFactory::ContextFactory()
228 	: glu::ContextFactory("default", "EGL surfaceless context")
229 {}
230 
createContext(const glu::RenderConfig & config,const tcu::CommandLine & cmdLine,const glu::RenderContext *) const231 glu::RenderContext* ContextFactory::createContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine, const glu::RenderContext*) const
232 {
233 	return new EglRenderContext(config, cmdLine);
234 }
235 
EglRenderContext(const glu::RenderConfig & config,const tcu::CommandLine & cmdLine)236 EglRenderContext::EglRenderContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine)
237 	: m_egl("libEGL.so")
238 	, m_contextType(config.type)
239 	, m_eglDisplay(EGL_NO_DISPLAY)
240 	, m_eglContext(EGL_NO_CONTEXT)
241 	, m_renderTarget(
242 			config.width,
243 			config.height,
244 			tcu::PixelFormat(
245 					config.redBits,
246 					config.greenBits,
247 					config.blueBits,
248 					config.alphaBits),
249 			config.depthBits,
250 			config.stencilBits,
251 			config.numSamples)
252 
253 {
254 	vector<eglw::EGLint>	context_attribs;
255 	vector<eglw::EGLint>	frame_buffer_attribs;
256 	vector<eglw::EGLint>	surface_attribs;
257 
258 	const glu::ContextType&	contextType = config.type;
259 	eglw::EGLint		eglMajorVersion;
260 	eglw::EGLint		eglMinorVersion;
261 	eglw::EGLint		flags = 0;
262 	eglw::EGLint		num_configs;
263 	eglw::EGLConfig		egl_config = NULL;
264 	eglw::EGLSurface	egl_surface;
265 
266 	(void) cmdLine;
267 
268 	m_eglDisplay = m_egl.getDisplay(NULL);
269 	EGLU_CHECK_MSG(m_egl, "eglGetDisplay()");
270 	if (m_eglDisplay == EGL_NO_DISPLAY)
271 		throw tcu::ResourceError("eglGetDisplay() failed");
272 
273 	EGLU_CHECK_CALL(m_egl, initialize(m_eglDisplay, &eglMajorVersion, &eglMinorVersion));
274 
275 	frame_buffer_attribs.push_back(EGL_RENDERABLE_TYPE);
276 	switch(contextType.getMajorVersion())
277 	{
278 		case 3:
279 			frame_buffer_attribs.push_back(EGL_OPENGL_ES3_BIT);
280 			break;
281 		case 2:
282 			frame_buffer_attribs.push_back(EGL_OPENGL_ES2_BIT);
283 			break;
284 		default:
285 			frame_buffer_attribs.push_back(EGL_OPENGL_ES_BIT);
286 	}
287 
288 	frame_buffer_attribs.push_back(EGL_SURFACE_TYPE);
289 	switch (config.surfaceType)
290 	{
291 		case glu::RenderConfig::SURFACETYPE_DONT_CARE:
292 			frame_buffer_attribs.push_back(EGL_DONT_CARE);
293 			break;
294 		case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
295 		case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
296 			frame_buffer_attribs.push_back(EGL_PBUFFER_BIT);
297 			surface_attribs.push_back(EGL_WIDTH);
298 			surface_attribs.push_back(config.width);
299 			surface_attribs.push_back(EGL_HEIGHT);
300 			surface_attribs.push_back(config.height);
301 			break;
302 		case glu::RenderConfig::SURFACETYPE_WINDOW:
303 			throw tcu::NotSupportedError("surfaceless platform does not support --deqp-surface-type=window");
304 		case glu::RenderConfig::SURFACETYPE_LAST:
305 			TCU_CHECK_INTERNAL(false);
306 	}
307 
308 	surface_attribs.push_back(EGL_NONE);
309 
310 	frame_buffer_attribs.push_back(EGL_RED_SIZE);
311 	frame_buffer_attribs.push_back(config.redBits);
312 
313 	frame_buffer_attribs.push_back(EGL_GREEN_SIZE);
314 	frame_buffer_attribs.push_back(config.greenBits);
315 
316 	frame_buffer_attribs.push_back(EGL_BLUE_SIZE);
317 	frame_buffer_attribs.push_back(config.blueBits);
318 
319 	frame_buffer_attribs.push_back(EGL_ALPHA_SIZE);
320 	frame_buffer_attribs.push_back(config.alphaBits);
321 
322 	frame_buffer_attribs.push_back(EGL_DEPTH_SIZE);
323 	frame_buffer_attribs.push_back(config.depthBits);
324 
325 	frame_buffer_attribs.push_back(EGL_STENCIL_SIZE);
326 	frame_buffer_attribs.push_back(config.stencilBits);
327 
328 	frame_buffer_attribs.push_back(EGL_SAMPLES);
329 	frame_buffer_attribs.push_back(config.numSamples);
330 
331 	frame_buffer_attribs.push_back(EGL_NONE);
332 
333 	if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], NULL, 0, &num_configs))
334 		throw tcu::ResourceError("surfaceless couldn't find any config");
335 
336 	eglw::EGLConfig		all_configs[num_configs];
337 
338 	if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], all_configs, num_configs, &num_configs))
339 		throw tcu::ResourceError("surfaceless couldn't find any config");
340 
341 	for (int i = 0; i < num_configs; i++) {
342 		EGLint red, green, blue, alpha, depth, stencil, samples;
343 		eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_RED_SIZE, &red);
344 		eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_GREEN_SIZE, &green);
345 		eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_BLUE_SIZE, &blue);
346 		eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_ALPHA_SIZE, &alpha);
347 		eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_DEPTH_SIZE, &depth);
348 		eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_STENCIL_SIZE, &stencil);
349 		eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_SAMPLES, &samples);
350 
351 		if (
352 				(glu::RenderConfig::DONT_CARE == config.redBits		|| red		== config.redBits)		&&
353 				(glu::RenderConfig::DONT_CARE == config.greenBits	|| green	== config.greenBits)	&&
354 				(glu::RenderConfig::DONT_CARE == config.blueBits	|| blue		== config.blueBits)		&&
355 				(glu::RenderConfig::DONT_CARE == config.alphaBits	|| alpha	== config.alphaBits)	&&
356 				(glu::RenderConfig::DONT_CARE == config.depthBits	|| depth	== config.depthBits)	&&
357 				(glu::RenderConfig::DONT_CARE == config.stencilBits	|| stencil	== config.stencilBits)	&&
358 				(glu::RenderConfig::DONT_CARE == config.numSamples	|| samples	== config.numSamples)) {
359 			egl_config = all_configs[i];
360 			break;
361 		}
362 	}
363 
364 	if (!egl_config)
365 		throw tcu::ResourceError("surfaceless couldn't find a matching config");
366 
367 	switch (config.surfaceType)
368 	{
369 		case glu::RenderConfig::SURFACETYPE_DONT_CARE:
370 			egl_surface = EGL_NO_SURFACE;
371 			break;
372 		case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
373 		case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
374 			egl_surface = eglCreatePbufferSurface(m_eglDisplay, egl_config, &surface_attribs[0]);
375 			break;
376 		case glu::RenderConfig::SURFACETYPE_WINDOW:
377 		case glu::RenderConfig::SURFACETYPE_LAST:
378 			TCU_CHECK_INTERNAL(false);
379 	}
380 
381 	context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
382 	context_attribs.push_back(contextType.getMajorVersion());
383 	context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
384 	context_attribs.push_back(contextType.getMinorVersion());
385 
386 	switch (contextType.getProfile())
387 	{
388 		case glu::PROFILE_ES:
389 			EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_ES_API));
390 			break;
391 		case glu::PROFILE_CORE:
392 			EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
393 			context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
394 			context_attribs.push_back(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
395 			break;
396 		case glu::PROFILE_COMPATIBILITY:
397 			EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
398 			context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
399 			context_attribs.push_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
400 			break;
401 		case glu::PROFILE_LAST:
402 			TCU_CHECK_INTERNAL(false);
403 	}
404 
405 	if ((contextType.getFlags() & glu::CONTEXT_DEBUG) != 0)
406 		flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
407 
408 	if ((contextType.getFlags() & glu::CONTEXT_ROBUST) != 0)
409 		flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
410 
411 	if ((contextType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0)
412 		flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
413 
414 	context_attribs.push_back(EGL_CONTEXT_FLAGS_KHR);
415 	context_attribs.push_back(flags);
416 
417 	context_attribs.push_back(EGL_NONE);
418 
419 	m_eglContext = m_egl.createContext(m_eglDisplay, egl_config, EGL_NO_CONTEXT, &context_attribs[0]);
420 	EGLU_CHECK_MSG(m_egl, "eglCreateContext()");
421 	if (!m_eglContext)
422 		throw tcu::ResourceError("eglCreateContext failed");
423 
424 	EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, egl_surface, egl_surface, m_eglContext));
425 
426 	if ((eglMajorVersion == 1 && eglMinorVersion >= 5) ||
427 		isEGLExtensionSupported(m_egl, m_eglDisplay, "EGL_KHR_get_all_proc_addresses") ||
428 		isEGLExtensionSupported(m_egl, EGL_NO_DISPLAY, "EGL_KHR_client_get_all_proc_addresses"))
429 	{
430 		// Use eglGetProcAddress() for core functions
431 		GetProcFuncLoader funcLoader(m_egl);
432 		glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
433 	}
434 #if !defined(DEQP_GLES2_RUNTIME_LOAD)
435 	else if (contextType.getAPI() == glu::ApiType::es(2,0))
436 	{
437 		glw::initES20Direct(&m_glFunctions);
438 	}
439 #endif
440 #if !defined(DEQP_GLES3_RUNTIME_LOAD)
441 	else if (contextType.getAPI() == glu::ApiType::es(3,0))
442 	{
443 		glw::initES30Direct(&m_glFunctions);
444 	}
445 #endif
446 	else
447 	{
448 		const char* libraryPath = NULL;
449 
450 		if (glu::isContextTypeES(contextType))
451 		{
452 			if (contextType.getMinorVersion() <= 2)
453 				libraryPath = DEQP_GLES2_LIBRARY_PATH;
454 			else
455 				libraryPath = DEQP_GLES3_LIBRARY_PATH;
456 		}
457 		else
458 		{
459 			libraryPath = DEQP_OPENGL_LIBRARY_PATH;
460 		}
461 
462 		m_glLibrary = new de::DynamicLibrary(libraryPath);
463 
464 		DynamicFuncLoader funcLoader(m_glLibrary);
465 		glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
466 	}
467 
468 	{
469 		GetProcFuncLoader extLoader(m_egl);
470 		glu::initExtensionFunctions(&m_glFunctions, &extLoader, contextType.getAPI());
471 	}
472 }
473 
~EglRenderContext(void)474 EglRenderContext::~EglRenderContext(void)
475 {
476 	try
477 	{
478 		if (m_eglDisplay != EGL_NO_DISPLAY)
479 		{
480 			EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
481 
482 			if (m_eglContext != EGL_NO_CONTEXT)
483 				EGLU_CHECK_CALL(m_egl, destroyContext(m_eglDisplay, m_eglContext));
484 		}
485 
486 		EGLU_CHECK_CALL(m_egl, terminate(m_eglDisplay));
487 	}
488 	catch (...)
489 	{
490 	}
491 }
492 
getRenderTarget(void) const493 const tcu::RenderTarget& EglRenderContext::getRenderTarget(void) const
494 {
495 	return m_renderTarget;
496 }
497 
postIterate(void)498 void EglRenderContext::postIterate(void)
499 {
500 	this->getFunctions().finish();
501 }
502 
503 } // namespace surfaceless
504 } // namespace tcu
505 
createPlatform(void)506 tcu::Platform* createPlatform(void)
507 {
508 	return new tcu::surfaceless::Platform();
509 }
510