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