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	GLXFBConfig							m_fbConfig;
181	GLXContext							m_GLXContext;
182	UniquePtr<GlxDrawable>				m_glxDrawable;
183	RenderTarget						m_renderTarget;
184	glw::Functions						m_functions;
185};
186
187extern "C"
188{
189	static int tcuX11GlxErrorHandler (::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
199GlxContextFactory::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(tcuX11GlxErrorHandler);
209}
210
211RenderContext* 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
219GlxContextFactory::~GlxContextFactory (void)
220{
221}
222
223GlxDisplay::GlxDisplay (EventState& eventState, const char* name)
224	: x11::Display	(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
245bool 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`.
252static 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`.
268static 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
278GlxVisual::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
291int GlxVisual::getAttrib (int attribute)
292{
293	int fbvalue;
294	TCU_CHECK_GLX_CONFIG(glXGetFBConfigAttrib(getXDisplay(), m_fbConfig, attribute, &fbvalue));
295	return fbvalue;
296}
297
298GLXContext 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_ASSERT(!"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
336GLXWindow GlxVisual::createWindow (::Window xWindow)
337{
338	return TCU_CHECK_GLX(glXCreateWindow(getXDisplay(), m_fbConfig, xWindow, NULL));
339}
340
341unsigned GlxDrawable::getAttrib (int attrib)
342{
343	unsigned int value = 0;
344	glXQueryDrawable(getXDisplay(), getGLXDrawable(), attrib, &value);
345	return value;
346}
347
348int GlxDrawable::getWidth (void)
349{
350	int width = 0;
351	getDimensions(&width, DE_NULL);
352	return width;
353}
354
355int GlxDrawable::getHeight (void)
356{
357	int height = 0;
358	getDimensions(DE_NULL, &height);
359	return height;
360}
361
362GlxWindow::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
371void 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
383GlxWindow::~GlxWindow (void)
384{
385	glXDestroyWindow(m_x11Display.getXDisplay(), m_GLXDrawable);
386}
387
388static 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
404static 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_ASSERT(!"Impossible case");
418	}
419	return 0;
420}
421
422static 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
451class Rank
452{
453public:
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
459private:
460	deUint64	m_value;
461	size_t		m_bitsLeft;
462};
463
464void 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
471void 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
478static 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
538static 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
571GlxDrawable* 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_ASSERT(!"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
606struct 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
616GlxRenderContext::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
637GlxRenderContext::~GlxRenderContext (void)
638{
639	clearCurrent();
640	if (m_GLXContext != DE_NULL)
641		glXDestroyContext(m_glxDisplay.getXDisplay(), m_GLXContext);
642}
643
644void 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
651void GlxRenderContext::clearCurrent (void)
652{
653	TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(),
654										None, None, DE_NULL));
655}
656
657ContextType GlxRenderContext::getType (void) const
658{
659	return m_type;
660}
661
662void GlxRenderContext::postIterate (void)
663{
664	m_glxDrawable->swapBuffers();
665	m_glxDrawable->processEvents();
666	m_glxDisplay.processEvents();
667}
668
669const RenderTarget& GlxRenderContext::getRenderTarget (void) const
670{
671	return m_renderTarget;
672}
673
674const glw::Functions& GlxRenderContext::getFunctions (void) const
675{
676	return m_functions;
677}
678
679MovePtr<ContextFactory> createContextFactory (EventState& eventState)
680{
681	return MovePtr<ContextFactory>(new GlxContextFactory(eventState));
682}
683
684} // glx
685} // x11
686} // tcu
687