Home | History | Annotate | Download | only in X11
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program Tester Core
      3  * ----------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      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 Platform that uses X11 via GLX.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "tcuLnxX11GlxPlatform.hpp"
     25 
     26 #include "tcuRenderTarget.hpp"
     27 #include "glwInitFunctions.hpp"
     28 #include "deUniquePtr.hpp"
     29 #include "glwEnums.hpp"
     30 
     31 #include <sstream>
     32 #include <iterator>
     33 #include <set>
     34 
     35 #define GLX_GLXEXT_PROTOTYPES
     36 #include <GL/glx.h>
     37 
     38 #ifndef GLX_CONTEXT_OPENGL_NO_ERROR_ARB
     39 #define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3
     40 #endif
     41 
     42 namespace tcu
     43 {
     44 namespace lnx
     45 {
     46 namespace x11
     47 {
     48 namespace glx
     49 {
     50 
     51 using de::UniquePtr;
     52 using de::MovePtr;
     53 using glu::ApiType;
     54 using glu::ContextFactory;
     55 using glu::ContextType;
     56 using glu::RenderConfig;
     57 using glu::RenderContext;
     58 using tcu::CommandLine;
     59 using tcu::RenderTarget;
     60 using std::string;
     61 using std::set;
     62 using std::istringstream;
     63 using std::ostringstream;
     64 using std::istream_iterator;
     65 
     66 typedef RenderConfig::Visibility Visibility;
     67 
     68 
     69 template<typename T>
     70 static inline T checkGLX(T value, const char* expr, const char* file, int line)
     71 {
     72 	if (!value)
     73 		throw tcu::TestError("GLX call failed", expr, file, line);
     74 	return value;
     75 }
     76 
     77 #define TCU_CHECK_GLX(EXPR) checkGLX(EXPR, #EXPR, __FILE__, __LINE__)
     78 #define TCU_CHECK_GLX_CONFIG(EXPR) checkGLX((EXPR) == Success, #EXPR, __FILE__, __LINE__)
     79 
     80 class GlxContextFactory : public glu::ContextFactory
     81 {
     82 public:
     83 							GlxContextFactory	(EventState& eventState);
     84 							~GlxContextFactory	(void);
     85 	RenderContext*			createContext		(const RenderConfig&	   config,
     86 												 const CommandLine&		   cmdLine,
     87 												 const glu::RenderContext* sharedContext) const;
     88 
     89 	EventState&				getEventState		(void) const { return m_eventState;}
     90 
     91 	const PFNGLXCREATECONTEXTATTRIBSARBPROC
     92 							m_glXCreateContextAttribsARB;
     93 
     94 private:
     95 	EventState&				m_eventState;
     96 };
     97 
     98 class GlxDisplay : public XlibDisplay
     99 {
    100 public:
    101 							GlxDisplay				(EventState&	eventState,
    102 													 const char*	name);
    103 	int						getGlxMajorVersion		(void) const { return m_majorVersion; }
    104 	int						getGlxMinorVersion		(void) const { return m_minorVersion; }
    105 	bool					isGlxExtensionSupported (const char* extName) const;
    106 
    107 private:
    108 	int						m_errorBase;
    109 	int						m_eventBase;
    110 	int						m_majorVersion;
    111 	int						m_minorVersion;
    112 	set<string>				m_extensions;
    113 };
    114 
    115 class GlxVisual
    116 {
    117 public:
    118 							GlxVisual			(GlxDisplay& display, GLXFBConfig fbConfig);
    119 	int						getAttrib			(int attribute);
    120 	Visual*					getXVisual			(void) { return m_visual; }
    121 	GLXContext				createContext		(const GlxContextFactory&		factory,
    122 												 const ContextType&				contextType,
    123 												 const glu::RenderContext*		sharedContext,
    124 												 glu::ResetNotificationStrategy	resetNotificationStrategy);
    125 	GLXWindow				createWindow		(::Window xWindow);
    126 	GlxDisplay&				getGlxDisplay		(void) { return m_display; }
    127 	::Display*				getXDisplay			(void) { return m_display.getXDisplay(); }
    128 
    129 private:
    130 	GlxDisplay&				m_display;
    131 	::Visual*				m_visual;
    132 	const GLXFBConfig		m_fbConfig;
    133 };
    134 
    135 class GlxDrawable
    136 {
    137 public:
    138 	virtual					~GlxDrawable		(void) {}
    139 
    140 	virtual void			processEvents		(void) {}
    141 	virtual void			getDimensions		(int* width, int* height) = 0;
    142 	int						getWidth			(void);
    143 	int						getHeight			(void);
    144 	void					swapBuffers			(void) { glXSwapBuffers(getXDisplay(), getGLXDrawable()); }
    145 
    146 	virtual ::Display*		getXDisplay			(void) = 0;
    147 	virtual GLXDrawable		getGLXDrawable		(void) = 0;
    148 
    149 protected:
    150 							GlxDrawable			() {}
    151 	unsigned int			getAttrib			(int attribute);
    152 };
    153 
    154 class GlxWindow : public GlxDrawable
    155 {
    156 public:
    157 							GlxWindow			(GlxVisual& visual, const RenderConfig& cfg);
    158 							~GlxWindow			(void);
    159 	void					processEvents		(void) { m_x11Window.processEvents(); }
    160 	::Display*				getXDisplay			(void) { return m_x11Display.getXDisplay(); }
    161 	void					getDimensions		(int* width, int* height);
    162 
    163 protected:
    164 	GLXDrawable				getGLXDrawable		() { return m_GLXDrawable; }
    165 
    166 private:
    167 	XlibDisplay&			m_x11Display;
    168 	XlibWindow				m_x11Window;
    169 	const GLXDrawable		m_GLXDrawable;
    170 };
    171 
    172 class GlxRenderContext : public RenderContext
    173 {
    174 public:
    175 										GlxRenderContext	(const GlxContextFactory&	factory,
    176 															 const RenderConfig&		config,
    177 															 const glu::RenderContext*	sharedContext
    178 															 );
    179 										~GlxRenderContext	(void);
    180 	virtual ContextType					getType				(void) const;
    181 	virtual void						postIterate			(void);
    182 	virtual void						makeCurrent			(void);
    183 	void								clearCurrent		(void);
    184 	virtual const glw::Functions&		getFunctions		(void) const;
    185 	virtual const tcu::RenderTarget&	getRenderTarget		(void) const;
    186 	virtual glw::GenericFuncType		getProcAddress		(const char* name) const;
    187 	const GLXContext&					getGLXContext		(void) const;
    188 
    189 private:
    190 	GlxDisplay							m_glxDisplay;
    191 	GlxVisual							m_glxVisual;
    192 	ContextType							m_type;
    193 	GLXContext							m_GLXContext;
    194 	UniquePtr<GlxDrawable>				m_glxDrawable;
    195 	RenderTarget						m_renderTarget;
    196 	glw::Functions						m_functions;
    197 };
    198 
    199 extern "C"
    200 {
    201 	static int tcuLnxX11GlxErrorHandler (::Display* display, XErrorEvent* event)
    202 	{
    203 		char buf[80];
    204 		XGetErrorText(display, event->error_code, buf, sizeof(buf));
    205 		tcu::print("X operation %u:%u failed: %s\n",
    206 				   event->request_code, event->minor_code, buf);
    207 		return 0;
    208 	}
    209 }
    210 
    211 GlxContextFactory::GlxContextFactory (EventState& eventState)
    212 	: glu::ContextFactory			("glx", "X11 GLX OpenGL Context")
    213 	, m_glXCreateContextAttribsARB	(
    214 		reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(
    215 			TCU_CHECK_GLX(
    216 				glXGetProcAddress(
    217 					reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB")))))
    218 	, m_eventState					(eventState)
    219 {
    220 	XSetErrorHandler(tcuLnxX11GlxErrorHandler);
    221 }
    222 
    223 RenderContext* GlxContextFactory::createContext (const RenderConfig&		config,
    224 												 const CommandLine&			cmdLine,
    225 												 const glu::RenderContext*	sharedContext) const
    226 {
    227 	DE_UNREF(cmdLine);
    228 	GlxRenderContext* const renderContext = new GlxRenderContext(*this, config, sharedContext);
    229 	return renderContext;
    230 }
    231 
    232 GlxContextFactory::~GlxContextFactory (void)
    233 {
    234 }
    235 
    236 GlxDisplay::GlxDisplay (EventState& eventState, const char* name)
    237 	: XlibDisplay	(eventState, name)
    238 {
    239 	const Bool supported = glXQueryExtension(m_display, &m_errorBase, &m_eventBase);
    240 	if (!supported)
    241 		TCU_THROW(NotSupportedError, "GLX protocol not supported by X server");
    242 
    243 	TCU_CHECK_GLX(glXQueryVersion(m_display, &m_majorVersion, &m_minorVersion));
    244 
    245 	{
    246 		const int screen = XDefaultScreen(m_display);
    247 		// nVidia doesn't seem to report client-side extensions correctly,
    248 		// so only use server side
    249 		const char* const extensions =
    250 			TCU_CHECK_GLX(glXQueryServerString(m_display, screen, GLX_EXTENSIONS));
    251 		istringstream extStream(extensions);
    252 		m_extensions = set<string>(istream_iterator<string>(extStream),
    253 								   istream_iterator<string>());
    254 	}
    255 }
    256 
    257 
    258 bool GlxDisplay::isGlxExtensionSupported (const char* extName) const
    259 {
    260 	return m_extensions.find(extName) != m_extensions.end();
    261 }
    262 
    263 //! Throw `tcu::NotSupportedError` if `dpy` is not compatible with GLX
    264 //! version `major`.`minor`.
    265 static void checkGlxVersion (const GlxDisplay& dpy, int major, int minor)
    266 {
    267 	const int dpyMajor = dpy.getGlxMajorVersion();
    268 	const int dpyMinor = dpy.getGlxMinorVersion();
    269 	if (!(dpyMajor == major && dpyMinor >= minor))
    270 	{
    271 		ostringstream oss;
    272 		oss << "Server GLX version "
    273 			<< dpyMajor << "." << dpyMinor
    274 			<< " not compatible with required version "
    275 			<< major << "." << minor;
    276 		TCU_THROW(NotSupportedError, oss.str().c_str());
    277 	}
    278 }
    279 
    280 //! Throw `tcu::NotSupportedError` if `dpy` does not support extension `extName`.
    281 static void checkGlxExtension (const GlxDisplay& dpy, const char* extName)
    282 {
    283 	if (!dpy.isGlxExtensionSupported(extName))
    284 	{
    285 		ostringstream oss;
    286 		oss << "GLX extension \"" << extName << "\" not supported";
    287 		TCU_THROW(NotSupportedError, oss.str().c_str());
    288 	}
    289 }
    290 
    291 GlxVisual::GlxVisual (GlxDisplay& display, GLXFBConfig fbConfig)
    292 	: m_display		(display)
    293 	, m_visual		(DE_NULL)
    294 	, m_fbConfig	(fbConfig)
    295 {
    296 	XVisualInfo* visualInfo = glXGetVisualFromFBConfig(getXDisplay(), fbConfig);
    297 
    298 	if (!visualInfo)
    299 		TCU_THROW(ResourceError, "glXGetVisualFromFBConfig() returned NULL");
    300 
    301 	m_visual = visualInfo->visual;
    302 	XFree(visualInfo);
    303 }
    304 
    305 int GlxVisual::getAttrib (int attribute)
    306 {
    307 	int fbvalue;
    308 	TCU_CHECK_GLX_CONFIG(glXGetFBConfigAttrib(getXDisplay(), m_fbConfig, attribute, &fbvalue));
    309 	return fbvalue;
    310 }
    311 
    312 GLXContext GlxVisual::createContext (const GlxContextFactory&		factory,
    313 									 const ContextType&				contextType,
    314 									 const glu::RenderContext*		sharedContext,
    315 									 glu::ResetNotificationStrategy	resetNotificationStrategy)
    316 {
    317 	std::vector<int>	attribs;
    318 
    319 	checkGlxVersion(m_display, 1, 4);
    320 	checkGlxExtension(m_display, "GLX_ARB_create_context");
    321 	checkGlxExtension(m_display, "GLX_ARB_create_context_profile");
    322 
    323 	{
    324 		const ApiType	apiType		= contextType.getAPI();
    325 		int				profileMask	= 0;
    326 
    327 		switch (apiType.getProfile())
    328 		{
    329 			case glu::PROFILE_ES:
    330 				checkGlxExtension(m_display, "GLX_EXT_create_context_es2_profile");
    331 				profileMask = GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
    332 				break;
    333 			case glu::PROFILE_CORE:
    334 				profileMask = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
    335 				break;
    336 			case glu::PROFILE_COMPATIBILITY:
    337 				profileMask = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
    338 				break;
    339 			default:
    340 				DE_FATAL("Impossible context profile");
    341 		}
    342 
    343 		attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
    344 		attribs.push_back(apiType.getMajorVersion());
    345 		attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
    346 		attribs.push_back(apiType.getMinorVersion());
    347 		attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
    348 		attribs.push_back(profileMask);
    349 	}
    350 
    351 	// Context flags
    352 	{
    353 		int		flags	= 0;
    354 
    355 		if ((contextType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0)
    356 		{
    357 			if (glu::isContextTypeES(contextType))
    358 				TCU_THROW(InternalError, "Only OpenGL core contexts can be forward-compatible");
    359 
    360 			flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
    361 		}
    362 
    363 		if ((contextType.getFlags() & glu::CONTEXT_DEBUG) != 0)
    364 			flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
    365 
    366 		if ((contextType.getFlags() & glu::CONTEXT_ROBUST) != 0)
    367 			flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
    368 
    369 		if ((contextType.getFlags() & glu::CONTEXT_NO_ERROR) != 0)
    370 		{
    371 			if (m_display.isGlxExtensionSupported("GLX_ARB_create_context_no_error"))
    372 			{
    373 				attribs.push_back(GLX_CONTEXT_OPENGL_NO_ERROR_ARB);
    374 				attribs.push_back(True);
    375 			}
    376 			else
    377 				TCU_THROW(NotSupportedError, "GLX_ARB_create_context_no_error is required for creating no-error contexts");
    378 		}
    379 
    380 		if (flags != 0)
    381 		{
    382 			attribs.push_back(GLX_CONTEXT_FLAGS_ARB);
    383 			attribs.push_back(flags);
    384 		}
    385 	}
    386 
    387 	if (resetNotificationStrategy != glu::RESET_NOTIFICATION_STRATEGY_NOT_SPECIFIED)
    388 	{
    389 		attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
    390 
    391 		if (resetNotificationStrategy == glu::RESET_NOTIFICATION_STRATEGY_NO_RESET_NOTIFICATION)
    392 			attribs.push_back(GLX_NO_RESET_NOTIFICATION_ARB);
    393 		else if (resetNotificationStrategy == glu::RESET_NOTIFICATION_STRATEGY_LOSE_CONTEXT_ON_RESET)
    394 			attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB);
    395 		else
    396 			TCU_THROW(InternalError, "Unknown reset notification strategy");
    397 	}
    398 
    399 	// Terminate attrib list
    400 	attribs.push_back(None);
    401 
    402 	const GlxRenderContext* sharedGlxRenderContext = dynamic_cast<const GlxRenderContext*>(sharedContext);
    403 	const GLXContext& sharedGLXContext = sharedGlxRenderContext ? sharedGlxRenderContext->getGLXContext() : DE_NULL;
    404 
    405 	return TCU_CHECK_GLX(factory.m_glXCreateContextAttribsARB(
    406 							 getXDisplay(), m_fbConfig, sharedGLXContext, True, &attribs[0]));
    407 }
    408 
    409 GLXWindow GlxVisual::createWindow (::Window xWindow)
    410 {
    411 	return TCU_CHECK_GLX(glXCreateWindow(getXDisplay(), m_fbConfig, xWindow, NULL));
    412 }
    413 
    414 unsigned GlxDrawable::getAttrib (int attrib)
    415 {
    416 	unsigned int value = 0;
    417 	glXQueryDrawable(getXDisplay(), getGLXDrawable(), attrib, &value);
    418 	return value;
    419 }
    420 
    421 int GlxDrawable::getWidth (void)
    422 {
    423 	int width = 0;
    424 	getDimensions(&width, DE_NULL);
    425 	return width;
    426 }
    427 
    428 int GlxDrawable::getHeight (void)
    429 {
    430 	int height = 0;
    431 	getDimensions(DE_NULL, &height);
    432 	return height;
    433 }
    434 
    435 GlxWindow::GlxWindow (GlxVisual& visual, const RenderConfig& cfg)
    436 	: m_x11Display	(visual.getGlxDisplay())
    437 	, m_x11Window	(m_x11Display, cfg.width, cfg.height,
    438 					 visual.getXVisual())
    439 	, m_GLXDrawable	(visual.createWindow(m_x11Window.getXID()))
    440 {
    441 	m_x11Window.setVisibility(cfg.windowVisibility != RenderConfig::VISIBILITY_HIDDEN);
    442 }
    443 
    444 void GlxWindow::getDimensions (int* width, int* height)
    445 {
    446 	if (width != DE_NULL)
    447 		*width = getAttrib(GLX_WIDTH);
    448 	if (height != DE_NULL)
    449 		*height = getAttrib(GLX_HEIGHT);
    450 
    451 	// glXQueryDrawable may be buggy, so fall back to X geometry if needed
    452 	if ((width != DE_NULL && *width == 0) || (height != DE_NULL && *height == 0))
    453 		m_x11Window.getDimensions(width, height);
    454 }
    455 
    456 GlxWindow::~GlxWindow (void)
    457 {
    458 	glXDestroyWindow(m_x11Display.getXDisplay(), m_GLXDrawable);
    459 }
    460 
    461 static const struct Attribute
    462 {
    463 	int						glxAttribute;
    464 	int	RenderConfig::*		cfgMember;
    465 } s_attribs[] =
    466 {
    467 	{ GLX_RED_SIZE,		&RenderConfig::redBits		},
    468 	{ GLX_GREEN_SIZE,	&RenderConfig::greenBits	},
    469 	{ GLX_BLUE_SIZE,	&RenderConfig::blueBits		},
    470 	{ GLX_ALPHA_SIZE,	&RenderConfig::alphaBits	},
    471 	{ GLX_DEPTH_SIZE,	&RenderConfig::depthBits	},
    472 	{ GLX_STENCIL_SIZE,	&RenderConfig::stencilBits	},
    473 	{ GLX_SAMPLES,		&RenderConfig::numSamples	},
    474 	{ GLX_FBCONFIG_ID,	&RenderConfig::id			},
    475 };
    476 
    477 static deUint32 surfaceTypeToDrawableBits (RenderConfig::SurfaceType type)
    478 {
    479 	switch (type)
    480 	{
    481 		case RenderConfig::SURFACETYPE_WINDOW:
    482 			return GLX_WINDOW_BIT;
    483 		case RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
    484 			return GLX_PIXMAP_BIT;
    485 		case RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
    486 			return GLX_PBUFFER_BIT;
    487 		case RenderConfig::SURFACETYPE_DONT_CARE:
    488 			return GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;
    489 		default:
    490 			DE_FATAL("Impossible case");
    491 	}
    492 	return 0;
    493 }
    494 
    495 static bool configMatches (GlxVisual& visual, const RenderConfig& renderCfg)
    496 {
    497 	if (renderCfg.id != RenderConfig::DONT_CARE)
    498 		return visual.getAttrib(GLX_FBCONFIG_ID) == renderCfg.id;
    499 
    500 	for (const Attribute* it = DE_ARRAY_BEGIN(s_attribs); it != DE_ARRAY_END(s_attribs); it++)
    501 	{
    502 		const int requested = renderCfg.*it->cfgMember;
    503 		if (requested != RenderConfig::DONT_CARE &&
    504 			requested != visual.getAttrib(it->glxAttribute))
    505 			return false;
    506 	}
    507 
    508 	{
    509 		deUint32 bits = surfaceTypeToDrawableBits(renderCfg.surfaceType);
    510 
    511 		if ((visual.getAttrib(GLX_DRAWABLE_TYPE) & bits) == 0)
    512 			return false;
    513 
    514 		// It shouldn't be possible to have GLX_WINDOW_BIT set without a visual,
    515 		// but let's make sure.
    516 		if (renderCfg.surfaceType == RenderConfig::SURFACETYPE_WINDOW &&
    517 			visual.getXVisual() == DE_NULL)
    518 			return false;
    519 	}
    520 
    521 	return true;
    522 }
    523 
    524 class Rank
    525 {
    526 public:
    527 				Rank		(void) : m_value(0), m_bitsLeft(64) {}
    528 	void		add			(size_t bits, deUint32 value);
    529 	void		sub			(size_t bits, deUint32 value);
    530 	deUint64	getValue	(void) { return m_value; }
    531 
    532 private:
    533 	deUint64	m_value;
    534 	size_t		m_bitsLeft;
    535 };
    536 
    537 void Rank::add (size_t bits, deUint32 value)
    538 {
    539 	TCU_CHECK_INTERNAL(m_bitsLeft >= bits);
    540 	m_bitsLeft -= bits;
    541 	m_value = m_value << bits | de::min((1U << bits) - 1, value);
    542 }
    543 
    544 void Rank::sub (size_t bits, deUint32 value)
    545 {
    546 	TCU_CHECK_INTERNAL(m_bitsLeft >= bits);
    547 	m_bitsLeft -= bits;
    548 	m_value = m_value << bits | ((1U << bits) - 1 - de::min((1U << bits) - 1U, value));
    549 }
    550 
    551 static deUint64 configRank (GlxVisual& visual)
    552 {
    553 	// Sanity checks.
    554 	if (visual.getAttrib(GLX_DOUBLEBUFFER)					== False	||
    555 		(visual.getAttrib(GLX_RENDER_TYPE) & GLX_RGBA_BIT)	== 0)
    556 		return 0;
    557 
    558 	Rank rank;
    559 	int caveat		= visual.getAttrib(GLX_CONFIG_CAVEAT);
    560 	int redSize		= visual.getAttrib(GLX_RED_SIZE);
    561 	int greenSize	= visual.getAttrib(GLX_GREEN_SIZE);
    562 	int blueSize	= visual.getAttrib(GLX_BLUE_SIZE);
    563 	int alphaSize	= visual.getAttrib(GLX_ALPHA_SIZE);
    564 	int depthSize	= visual.getAttrib(GLX_DEPTH_SIZE);
    565 	int stencilSize	= visual.getAttrib(GLX_STENCIL_SIZE);
    566 	int minRGB		= de::min(redSize, de::min(greenSize, blueSize));
    567 
    568 	// Prefer conformant configurations.
    569 	rank.add(1, (caveat != GLX_NON_CONFORMANT_CONFIG));
    570 
    571 	// Prefer non-transparent configurations.
    572 	rank.add(1, visual.getAttrib(GLX_TRANSPARENT_TYPE) == GLX_NONE);
    573 
    574 	// Avoid stereo
    575 	rank.add(1, visual.getAttrib(GLX_STEREO) == False);
    576 
    577 	// Avoid overlays
    578 	rank.add(1, visual.getAttrib(GLX_LEVEL) == 0);
    579 
    580 	// Prefer to have some alpha.
    581 	rank.add(1, alphaSize > 0);
    582 
    583 	// Prefer to have a depth buffer.
    584 	rank.add(1, depthSize > 0);
    585 
    586 	// Prefer to have a stencil buffer.
    587 	rank.add(1, stencilSize > 0);
    588 
    589 	// Avoid slow configurations.
    590 	rank.add(1, (caveat != GLX_SLOW_CONFIG));
    591 
    592 	// Prefer larger, evenly distributed color depths
    593 	rank.add(4, de::min(minRGB, alphaSize));
    594 
    595 	// If alpha is low, choose best RGB
    596 	rank.add(4, minRGB);
    597 
    598 	// Prefer larger depth and stencil buffers
    599 	rank.add(6, deUint32(depthSize + stencilSize));
    600 
    601 	// Avoid excessive sampling
    602 	rank.sub(5, visual.getAttrib(GLX_SAMPLES));
    603 
    604 	// Prefer True/DirectColor
    605 	int visualType = visual.getAttrib(GLX_X_VISUAL_TYPE);
    606 	rank.add(1, visualType == GLX_TRUE_COLOR || visualType == GLX_DIRECT_COLOR);
    607 
    608 	return rank.getValue();
    609 }
    610 
    611 static GlxVisual chooseVisual (GlxDisplay& display, const RenderConfig& cfg)
    612 {
    613 	::Display*	dpy			= display.getXDisplay();
    614 	deUint64	maxRank		= 0;
    615 	GLXFBConfig	maxConfig	= DE_NULL;
    616 	int			numElems	= 0;
    617 
    618 	GLXFBConfig* const fbConfigs = glXGetFBConfigs(dpy, DefaultScreen(dpy), &numElems);
    619 	TCU_CHECK_MSG(fbConfigs != DE_NULL, "Couldn't query framebuffer configurations");
    620 
    621 	for (int i = 0; i < numElems; i++)
    622 	{
    623 		try
    624 		{
    625 			GlxVisual visual(display, fbConfigs[i]);
    626 
    627 			if (!configMatches(visual, cfg))
    628 				continue;
    629 
    630 			deUint64 cfgRank = configRank(visual);
    631 
    632 			if (cfgRank > maxRank)
    633 			{
    634 				maxRank		= cfgRank;
    635 				maxConfig	= fbConfigs[i];
    636 			}
    637 		}
    638 		catch (const tcu::ResourceError&)
    639 		{
    640 			// Some drivers report invalid visuals. Ignore them.
    641 		}
    642 	}
    643 	XFree(fbConfigs);
    644 
    645 	if (maxRank == 0)
    646 		TCU_THROW(NotSupportedError, "Requested GLX configuration not found or unusable");
    647 
    648 	return GlxVisual(display, maxConfig);
    649 }
    650 
    651 GlxDrawable* createDrawable (GlxVisual& visual, const RenderConfig& config)
    652 {
    653 	RenderConfig::SurfaceType surfaceType = config.surfaceType;
    654 
    655 	if (surfaceType == RenderConfig::SURFACETYPE_DONT_CARE)
    656 	{
    657 		if (visual.getXVisual() == DE_NULL)
    658 			// No visual, cannot create X window
    659 			surfaceType = RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE;
    660 		else
    661 			surfaceType = RenderConfig::SURFACETYPE_WINDOW;
    662 	}
    663 
    664 	switch (surfaceType)
    665 	{
    666 		case RenderConfig::SURFACETYPE_DONT_CARE:
    667 			DE_FATAL("Impossible case");
    668 			break;
    669 
    670 		case RenderConfig::SURFACETYPE_WINDOW:
    671 			return new GlxWindow(visual, config);
    672 			break;
    673 
    674 		case RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
    675 			// \todo [2013-11-28 lauri] Pixmaps
    676 
    677 		case RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
    678 			// \todo [2013-11-28 lauri] Pbuffers
    679 
    680 		default:
    681 			TCU_THROW(NotSupportedError, "Unsupported surface type");
    682 	}
    683 
    684 	return DE_NULL;
    685 }
    686 
    687 struct GlxFunctionLoader : public glw::FunctionLoader
    688 {
    689 							GlxFunctionLoader	(void) {}
    690 
    691 	glw::GenericFuncType	get					(const char* name) const
    692 	{
    693 		return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
    694 	}
    695 };
    696 
    697 GlxRenderContext::GlxRenderContext (const GlxContextFactory&	factory,
    698 									const RenderConfig&			config,
    699 									const glu::RenderContext*	sharedContext)
    700 	: m_glxDisplay		(factory.getEventState(), DE_NULL)
    701 	, m_glxVisual		(chooseVisual(m_glxDisplay, config))
    702 	, m_type			(config.type)
    703 	, m_GLXContext		(m_glxVisual.createContext(factory, config.type, sharedContext, config.resetNotificationStrategy))
    704 	, m_glxDrawable		(createDrawable(m_glxVisual, config))
    705 	, m_renderTarget	(m_glxDrawable->getWidth(), m_glxDrawable->getHeight(),
    706 						 PixelFormat(m_glxVisual.getAttrib(GLX_RED_SIZE),
    707 									 m_glxVisual.getAttrib(GLX_GREEN_SIZE),
    708 									 m_glxVisual.getAttrib(GLX_BLUE_SIZE),
    709 									 m_glxVisual.getAttrib(GLX_ALPHA_SIZE)),
    710 						 m_glxVisual.getAttrib(GLX_DEPTH_SIZE),
    711 						 m_glxVisual.getAttrib(GLX_STENCIL_SIZE),
    712 						 m_glxVisual.getAttrib(GLX_SAMPLES))
    713 {
    714 	const GlxFunctionLoader loader;
    715 	makeCurrent();
    716 	glu::initFunctions(&m_functions, &loader, config.type.getAPI());
    717 }
    718 
    719 GlxRenderContext::~GlxRenderContext (void)
    720 {
    721 	clearCurrent();
    722 	if (m_GLXContext != DE_NULL)
    723 		glXDestroyContext(m_glxDisplay.getXDisplay(), m_GLXContext);
    724 }
    725 
    726 void GlxRenderContext::makeCurrent (void)
    727 {
    728 	const GLXDrawable drawRead = m_glxDrawable->getGLXDrawable();
    729 	TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(),
    730 										drawRead, drawRead, m_GLXContext));
    731 }
    732 
    733 void GlxRenderContext::clearCurrent (void)
    734 {
    735 	TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(),
    736 										None, None, DE_NULL));
    737 }
    738 
    739 glw::GenericFuncType GlxRenderContext::getProcAddress(const char *name) const
    740 {
    741 	return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
    742 }
    743 
    744 ContextType GlxRenderContext::getType (void) const
    745 {
    746 	return m_type;
    747 }
    748 
    749 void GlxRenderContext::postIterate (void)
    750 {
    751 	m_glxDrawable->swapBuffers();
    752 	m_glxDrawable->processEvents();
    753 	m_glxDisplay.processEvents();
    754 }
    755 
    756 const RenderTarget& GlxRenderContext::getRenderTarget (void) const
    757 {
    758 	return m_renderTarget;
    759 }
    760 
    761 const glw::Functions& GlxRenderContext::getFunctions (void) const
    762 {
    763 	return m_functions;
    764 }
    765 
    766 const GLXContext& GlxRenderContext::getGLXContext (void) const
    767 {
    768 	return m_GLXContext;
    769 }
    770 
    771 MovePtr<ContextFactory> createContextFactory (EventState& eventState)
    772 {
    773 	return MovePtr<ContextFactory>(new GlxContextFactory(eventState));
    774 }
    775 
    776 } // glx
    777 } // x11
    778 } // lnx
    779 } // tcu
    780