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