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