• Home
  • History
  • Annotate
  • 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 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