Home | History | Annotate | Download | only in surfaceless
      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:
     91 	VulkanLibrary (void)
     92 		: m_library	("libvulkan.so.1")
     93 		, m_driver	(m_library)
     94 	{
     95 	}
     96 
     97 	const vk::PlatformInterface& getPlatformInterface (void) const
     98 	{
     99 		return m_driver;
    100 	}
    101 	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:
    114 	vk::Library* createLibrary (void) const
    115 	{
    116 		return new VulkanLibrary();
    117 	}
    118 
    119 	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.
    136 	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 
    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:
    159 	GetProcFuncLoader(const eglw::Library& egl): m_egl(egl)
    160 	{
    161 	}
    162 
    163 	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:
    174 	DynamicFuncLoader(de::DynamicLibrary* library): m_library(library)
    175 	{
    176 	}
    177 
    178 	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);
    191 	const glu::Platform&		getGLPlatform	(void) const { return *this; }
    192 	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 
    211 	glu::ContextType		getType		(void) const	{ return m_contextType; }
    212 	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 
    226 Platform::Platform(void)
    227 {
    228 	m_contextFactoryRegistry.registerFactory(new ContextFactory());
    229 }
    230 
    231 ContextFactory::ContextFactory()
    232 	: glu::ContextFactory("default", "EGL surfaceless context")
    233 {}
    234 
    235 glu::RenderContext* ContextFactory::createContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const
    236 {
    237 	return new EglRenderContext(config, cmdLine);
    238 }
    239 
    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 
    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 
    463 const tcu::RenderTarget& EglRenderContext::getRenderTarget(void) const
    464 {
    465 	return m_renderTarget;
    466 }
    467 
    468 void EglRenderContext::postIterate(void)
    469 {
    470 	this->getFunctions().finish();
    471 }
    472 
    473 } // namespace surfaceless
    474 } // namespace tcu
    475 
    476 tcu::Platform* createPlatform(void)
    477 {
    478 	return new tcu::surfaceless::Platform();
    479 }
    480