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 
    102 private:
    103 	const tcu::DynamicFunctionLibrary	m_library;
    104 	const vk::PlatformDriver			m_driver;
    105 };
    106 
    107 // Copied from tcuX11Platform.cpp
    108 class VulkanPlatform : public vk::Platform
    109 {
    110 public:
    111 	vk::Library* createLibrary (void) const
    112 	{
    113 		return new VulkanLibrary();
    114 	}
    115 
    116 	void describePlatform (std::ostream& dst) const
    117 	{
    118 		utsname		sysInfo;
    119 
    120 		deMemset(&sysInfo, 0, sizeof(sysInfo));
    121 
    122 		if (uname(&sysInfo) != 0)
    123 			throw std::runtime_error("uname() failed");
    124 
    125 		dst << "OS: " << sysInfo.sysname << " " << sysInfo.release << " " << sysInfo.version << "\n";
    126 		dst << "CPU: " << sysInfo.machine << "\n";
    127 	}
    128 
    129 	// FINISHME: Query actual memory limits.
    130 	//
    131 	// These hard-coded memory limits were copied from tcuX11Platform.cpp,
    132 	// and they work well enough for Intel platforms.
    133 	void getMemoryLimits (vk::PlatformMemoryLimits& limits) const
    134 	{
    135 		limits.totalSystemMemory					= 256*1024*1024;
    136 		limits.totalDeviceLocalMemory				= 128*1024*1024;
    137 		limits.deviceMemoryAllocationGranularity	= 64*1024;
    138 		limits.devicePageSize						= 4096;
    139 		limits.devicePageTableEntrySize				= 8;
    140 		limits.devicePageTableHierarchyLevels		= 3;
    141 	}
    142 };
    143 
    144 bool isEGLExtensionSupported(
    145 		const eglw::Library& egl,
    146 		eglw::EGLDisplay display,
    147 		const std::string& extName)
    148 {
    149 	const vector<string> exts = eglu::getClientExtensions(egl);
    150 	return de::contains(exts.begin(), exts.end(), extName);
    151 }
    152 
    153 class GetProcFuncLoader : public glw::FunctionLoader
    154 {
    155 public:
    156 	GetProcFuncLoader(const eglw::Library& egl): m_egl(egl)
    157 	{
    158 	}
    159 
    160 	glw::GenericFuncType get(const char* name) const
    161 	{
    162 		return (glw::GenericFuncType)m_egl.getProcAddress(name);
    163 	}
    164 protected:
    165 	const eglw::Library& m_egl;
    166 };
    167 
    168 class DynamicFuncLoader : public glw::FunctionLoader
    169 {
    170 public:
    171 	DynamicFuncLoader(de::DynamicLibrary* library): m_library(library)
    172 	{
    173 	}
    174 
    175 	glw::GenericFuncType get(const char* name) const
    176 	{
    177 		return (glw::GenericFuncType)m_library->getFunction(name);
    178 	}
    179 
    180 private:
    181 	de::DynamicLibrary*		m_library;
    182 };
    183 
    184 class Platform : public tcu::Platform, public glu::Platform
    185 {
    186 public:
    187 					Platform	(void);
    188 	const glu::Platform&		getGLPlatform	(void) const { return *this; }
    189 	const vk::Platform&			getVulkanPlatform	(void) const { return m_vkPlatform; }
    190 
    191 private:
    192 	VulkanPlatform		m_vkPlatform;
    193 };
    194 
    195 class ContextFactory : public glu::ContextFactory
    196 {
    197 public:
    198 					ContextFactory	(void);
    199 	glu::RenderContext*		createContext	(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const;
    200 };
    201 
    202 class EglRenderContext : public glu::RenderContext
    203 {
    204 public:
    205 					EglRenderContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine);
    206 					~EglRenderContext(void);
    207 
    208 	glu::ContextType		getType		(void) const	{ return m_contextType; }
    209 	const glw::Functions&		getFunctions	(void) const	{ return m_glFunctions; }
    210 	const tcu::RenderTarget&	getRenderTarget	(void) const;
    211 	void				postIterate	(void);
    212 
    213 private:
    214 	const eglw::DefaultLibrary      m_egl;
    215 	const glu::ContextType		m_contextType;
    216 	eglw::EGLDisplay		m_eglDisplay;
    217 	eglw::EGLContext		m_eglContext;
    218 	de::DynamicLibrary*		m_glLibrary;
    219 	glw::Functions			m_glFunctions;
    220 	tcu::RenderTarget		m_renderTarget;
    221 };
    222 
    223 Platform::Platform(void)
    224 {
    225 	m_contextFactoryRegistry.registerFactory(new ContextFactory());
    226 }
    227 
    228 ContextFactory::ContextFactory()
    229 	: glu::ContextFactory("default", "EGL surfaceless context")
    230 {}
    231 
    232 glu::RenderContext* ContextFactory::createContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const
    233 {
    234 	return new EglRenderContext(config, cmdLine);
    235 }
    236 
    237 EglRenderContext::EglRenderContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine)
    238 	: m_egl("libEGL.so")
    239 	, m_contextType(config.type)
    240 	, m_eglDisplay(EGL_NO_DISPLAY)
    241 	, m_eglContext(EGL_NO_CONTEXT)
    242 	, m_renderTarget(
    243 			config.width,
    244 			config.height,
    245 			tcu::PixelFormat(
    246 					config.redBits,
    247 					config.greenBits,
    248 					config.blueBits,
    249 					config.alphaBits),
    250 			config.depthBits,
    251 			config.stencilBits,
    252 			config.numSamples)
    253 
    254 {
    255 	vector<eglw::EGLint>	context_attribs;
    256 	vector<eglw::EGLint>	frame_buffer_attribs;
    257 	vector<eglw::EGLint>	surface_attribs;
    258 
    259 	const glu::ContextType&	contextType = config.type;
    260 	eglw::EGLint		eglMajorVersion;
    261 	eglw::EGLint		eglMinorVersion;
    262 	eglw::EGLint		flags = 0;
    263 	eglw::EGLint		num_configs;
    264 	eglw::EGLConfig		egl_config;
    265 	eglw::EGLSurface	egl_surface;
    266 
    267 	(void) cmdLine;
    268 
    269 	m_eglDisplay = m_egl.getDisplay(NULL);
    270 	EGLU_CHECK_MSG(m_egl, "eglGetDisplay()");
    271 	if (m_eglDisplay == EGL_NO_DISPLAY)
    272 		throw tcu::ResourceError("eglGetDisplay() failed");
    273 
    274 	EGLU_CHECK_CALL(m_egl, initialize(m_eglDisplay, &eglMajorVersion, &eglMinorVersion));
    275 
    276 	frame_buffer_attribs.push_back(EGL_RENDERABLE_TYPE);
    277 	switch(contextType.getMajorVersion())
    278 	{
    279 		case 3:
    280 			frame_buffer_attribs.push_back(EGL_OPENGL_ES3_BIT);
    281 			break;
    282 		case 2:
    283 			frame_buffer_attribs.push_back(EGL_OPENGL_ES2_BIT);
    284 			break;
    285 		default:
    286 			frame_buffer_attribs.push_back(EGL_OPENGL_ES_BIT);
    287 	}
    288 
    289 	frame_buffer_attribs.push_back(EGL_SURFACE_TYPE);
    290 	switch (config.surfaceType)
    291 	{
    292 		case glu::RenderConfig::SURFACETYPE_DONT_CARE:
    293 			frame_buffer_attribs.push_back(EGL_DONT_CARE);
    294 			break;
    295 		case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
    296 			break;
    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_NONE);
    331 
    332 	if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], NULL, 0, &num_configs))
    333 		throw tcu::ResourceError("surfaceless couldn't find any config");
    334 
    335 	if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], &egl_config, 1, &num_configs))
    336 		throw tcu::ResourceError("surfaceless couldn't find any config");
    337 
    338 	switch (config.surfaceType)
    339 	{
    340 		case glu::RenderConfig::SURFACETYPE_DONT_CARE:
    341 			egl_surface = EGL_NO_SURFACE;
    342 			break;
    343 		case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
    344 			egl_surface = eglCreatePbufferSurface(m_eglDisplay, egl_config, &surface_attribs[0]);
    345 			break;
    346 	}
    347 
    348 	context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
    349 	context_attribs.push_back(contextType.getMajorVersion());
    350 	context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
    351 	context_attribs.push_back(contextType.getMinorVersion());
    352 
    353 	switch (contextType.getProfile())
    354 	{
    355 		case glu::PROFILE_ES:
    356 			EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_ES_API));
    357 			break;
    358 		case glu::PROFILE_CORE:
    359 			EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
    360 			context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
    361 			context_attribs.push_back(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
    362 			break;
    363 		case glu::PROFILE_COMPATIBILITY:
    364 			EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API));
    365 			context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
    366 			context_attribs.push_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
    367 			break;
    368 		case glu::PROFILE_LAST:
    369 			TCU_CHECK_INTERNAL(false);
    370 	}
    371 
    372 	if ((contextType.getFlags() & glu::CONTEXT_DEBUG) != 0)
    373 		flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
    374 
    375 	if ((contextType.getFlags() & glu::CONTEXT_ROBUST) != 0)
    376 		flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
    377 
    378 	if ((contextType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0)
    379 		flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
    380 
    381 	context_attribs.push_back(EGL_CONTEXT_FLAGS_KHR);
    382 	context_attribs.push_back(flags);
    383 
    384 	context_attribs.push_back(EGL_NONE);
    385 
    386 	m_eglContext = m_egl.createContext(m_eglDisplay, egl_config, EGL_NO_CONTEXT, &context_attribs[0]);
    387 	EGLU_CHECK_MSG(m_egl, "eglCreateContext()");
    388 	if (!m_eglContext)
    389 		throw tcu::ResourceError("eglCreateContext failed");
    390 
    391 	EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, egl_surface, egl_surface, m_eglContext));
    392 
    393 	if ((eglMajorVersion == 1 && eglMinorVersion >= 5) ||
    394 		isEGLExtensionSupported(m_egl, m_eglDisplay, "EGL_KHR_get_all_proc_addresses") ||
    395 		isEGLExtensionSupported(m_egl, EGL_NO_DISPLAY, "EGL_KHR_client_get_all_proc_addresses"))
    396 	{
    397 		// Use eglGetProcAddress() for core functions
    398 		GetProcFuncLoader funcLoader(m_egl);
    399 		glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
    400 	}
    401 #if !defined(DEQP_GLES2_RUNTIME_LOAD)
    402 	else if (contextType.getAPI() == glu::ApiType::es(2,0))
    403 	{
    404 		glw::initES20Direct(&m_glFunctions);
    405 	}
    406 #endif
    407 #if !defined(DEQP_GLES3_RUNTIME_LOAD)
    408 	else if (contextType.getAPI() == glu::ApiType::es(3,0))
    409 	{
    410 		glw::initES30Direct(&m_glFunctions);
    411 	}
    412 #endif
    413 	else
    414 	{
    415 		const char* libraryPath = NULL;
    416 
    417 		if (glu::isContextTypeES(contextType))
    418 		{
    419 			if (contextType.getMinorVersion() <= 2)
    420 				libraryPath = DEQP_GLES2_LIBRARY_PATH;
    421 			else
    422 				libraryPath = DEQP_GLES3_LIBRARY_PATH;
    423 		}
    424 		else
    425 		{
    426 			libraryPath = DEQP_OPENGL_LIBRARY_PATH;
    427 		}
    428 
    429 		m_glLibrary = new de::DynamicLibrary(libraryPath);
    430 
    431 		DynamicFuncLoader funcLoader(m_glLibrary);
    432 		glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI());
    433 	}
    434 
    435 	{
    436 		GetProcFuncLoader extLoader(m_egl);
    437 		glu::initExtensionFunctions(&m_glFunctions, &extLoader, contextType.getAPI());
    438 	}
    439 }
    440 
    441 EglRenderContext::~EglRenderContext(void)
    442 {
    443 	try
    444 	{
    445 		if (m_eglDisplay != EGL_NO_DISPLAY)
    446 		{
    447 			EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
    448 
    449 			if (m_eglContext != EGL_NO_CONTEXT)
    450 				EGLU_CHECK_CALL(m_egl, destroyContext(m_eglDisplay, m_eglContext));
    451 		}
    452 
    453 		EGLU_CHECK_CALL(m_egl, terminate(m_eglDisplay));
    454 	}
    455 	catch (...)
    456 	{
    457 	}
    458 }
    459 
    460 const tcu::RenderTarget& EglRenderContext::getRenderTarget(void) const
    461 {
    462 	return m_renderTarget;
    463 }
    464 
    465 void EglRenderContext::postIterate(void)
    466 {
    467 	this->getFunctions().finish();
    468 }
    469 
    470 } // namespace surfaceless
    471 } // namespace tcu
    472 
    473 tcu::Platform* createPlatform(void)
    474 {
    475 	return new tcu::surfaceless::Platform();
    476 }
    477