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