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
38namespace tcu
39{
40namespace x11
41{
42namespace glx
43{
44
45using de::UniquePtr;
46using de::MovePtr;
47using glu::ApiType;
48using glu::ContextFactory;
49using glu::ContextType;
50using glu::RenderConfig;
51using glu::RenderContext;
52using tcu::CommandLine;
53using tcu::RenderTarget;
54using std::string;
55using std::set;
56using std::istringstream;
57using std::ostringstream;
58using std::istream_iterator;
59
60typedef RenderConfig::Visibility Visibility;
61
62
63template<typename T>
64static 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
74class GlxContextFactory : public glu::ContextFactory
75{
76public:
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
87private:
88	EventState&				m_eventState;
89};
90
91class GlxDisplay : public x11::Display
92{
93public:
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
100private:
101	int						m_errorBase;
102	int						m_eventBase;
103	int						m_majorVersion;
104	int						m_minorVersion;
105	set<string>				m_extensions;
106};
107
108class GlxVisual
109{
110public:
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
120private:
121	GlxDisplay&				m_display;
122	::Visual*				m_visual;
123	const GLXFBConfig		m_fbConfig;
124};
125
126class GlxDrawable
127{
128public:
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
140protected:
141							GlxDrawable			() {}
142	unsigned int			getAttrib			(int attribute);
143};
144
145class GlxWindow : public GlxDrawable
146{
147public:
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
154protected:
155	GLXDrawable				getGLXDrawable		() { return m_GLXDrawable; }
156
157private:
158	x11::Display&			m_x11Display;
159	x11::Window				m_x11Window;
160	const GLXDrawable		m_GLXDrawable;
161};
162
163class GlxRenderContext : public RenderContext
164{
165public:
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
176private:
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
186extern "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
198GlxContextFactory::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
210RenderContext* 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
218GlxContextFactory::~GlxContextFactory (void)
219{
220}
221
222GlxDisplay::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
244bool 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`.
251static 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`.
267static 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
277GlxVisual::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
290int GlxVisual::getAttrib (int attribute)
291{
292	int fbvalue;
293	TCU_CHECK_GLX_CONFIG(glXGetFBConfigAttrib(getXDisplay(), m_fbConfig, attribute, &fbvalue));
294	return fbvalue;
295}
296
297GLXContext 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_ASSERT(!"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
335GLXWindow GlxVisual::createWindow (::Window xWindow)
336{
337	return TCU_CHECK_GLX(glXCreateWindow(getXDisplay(), m_fbConfig, xWindow, NULL));
338}
339
340unsigned GlxDrawable::getAttrib (int attrib)
341{
342	unsigned int value = 0;
343	glXQueryDrawable(getXDisplay(), getGLXDrawable(), attrib, &value);
344	return value;
345}
346
347int GlxDrawable::getWidth (void)
348{
349	int width = 0;
350	getDimensions(&width, DE_NULL);
351	return width;
352}
353
354int GlxDrawable::getHeight (void)
355{
356	int height = 0;
357	getDimensions(DE_NULL, &height);
358	return height;
359}
360
361GlxWindow::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
370void 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
382GlxWindow::~GlxWindow (void)
383{
384	glXDestroyWindow(m_x11Display.getXDisplay(), m_GLXDrawable);
385}
386
387static 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
403static 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_ASSERT(!"Impossible case");
417	}
418	return 0;
419}
420
421static 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
450class Rank
451{
452public:
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
458private:
459	deUint64	m_value;
460	size_t		m_bitsLeft;
461};
462
463void 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
470void 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
477static 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
537static 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
570GlxDrawable* 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_ASSERT(!"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
605struct 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
615GlxRenderContext::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
636GlxRenderContext::~GlxRenderContext (void)
637{
638	clearCurrent();
639	if (m_GLXContext != DE_NULL)
640		glXDestroyContext(m_glxDisplay.getXDisplay(), m_GLXContext);
641}
642
643void 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
650void GlxRenderContext::clearCurrent (void)
651{
652	TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(),
653										None, None, DE_NULL));
654}
655
656ContextType GlxRenderContext::getType (void) const
657{
658	return m_type;
659}
660
661void GlxRenderContext::postIterate (void)
662{
663	m_glxDrawable->swapBuffers();
664	m_glxDrawable->processEvents();
665	m_glxDisplay.processEvents();
666}
667
668const RenderTarget& GlxRenderContext::getRenderTarget (void) const
669{
670	return m_renderTarget;
671}
672
673const glw::Functions& GlxRenderContext::getFunctions (void) const
674{
675	return m_functions;
676}
677
678MovePtr<ContextFactory> createContextFactory (EventState& eventState)
679{
680	return MovePtr<ContextFactory>(new GlxContextFactory(eventState));
681}
682
683} // glx
684} // x11
685} // tcu
686