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>
checkGLX(T value,const char * expr,const char * file,int line)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 
getEventState(void) const82 	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 XlibDisplay
92 {
93 public:
94 							GlxDisplay				(EventState&	eventState,
95 													 const char*	name);
getGlxMajorVersion(void) const96 	int						getGlxMajorVersion		(void) const { return m_majorVersion; }
getGlxMinorVersion(void) const97 	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);
getXVisual(void)113 	Visual*					getXVisual			(void) { return m_visual; }
114 	GLXContext				createContext		(const GlxContextFactory&	factory,
115 												 const ContextType&			contextType);
116 	GLXWindow				createWindow		(::Window xWindow);
getGlxDisplay(void)117 	GlxDisplay&				getGlxDisplay		(void) { return m_display; }
getXDisplay(void)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:
~GlxDrawable(void)129 	virtual					~GlxDrawable		(void) {}
130 
processEvents(void)131 	virtual void			processEvents		(void) {}
132 	virtual void			getDimensions		(int* width, int* height) = 0;
133 	int						getWidth			(void);
134 	int						getHeight			(void);
swapBuffers(void)135 	void					swapBuffers			(void) { glXSwapBuffers(getXDisplay(), getGLXDrawable()); }
136 
137 	virtual ::Display*		getXDisplay			(void) = 0;
138 	virtual GLXDrawable		getGLXDrawable		(void) = 0;
139 
140 protected:
GlxDrawable()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);
processEvents(void)150 	void					processEvents		(void) { m_x11Window.processEvents(); }
getXDisplay(void)151 	::Display*				getXDisplay			(void) { return m_x11Display.getXDisplay(); }
152 	void					getDimensions		(int* width, int* height);
153 
154 protected:
getGLXDrawable()155 	GLXDrawable				getGLXDrawable		() { return m_GLXDrawable; }
156 
157 private:
158 	XlibDisplay&			m_x11Display;
159 	XlibWindow				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 {
tcuX11GlxErrorHandler(::Display * display,XErrorEvent * event)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 
GlxContextFactory(EventState & eventState)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 
createContext(const RenderConfig & config,const CommandLine & cmdLine) const210 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 
~GlxContextFactory(void)218 GlxContextFactory::~GlxContextFactory (void)
219 {
220 }
221 
GlxDisplay(EventState & eventState,const char * name)222 GlxDisplay::GlxDisplay (EventState& eventState, const char* name)
223 	: XlibDisplay	(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 
isGlxExtensionSupported(const char * extName) const244 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`.
checkGlxVersion(const GlxDisplay & dpy,int major,int 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`.
checkGlxExtension(const GlxDisplay & dpy,const char * 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 
GlxVisual(GlxDisplay & display,GLXFBConfig fbConfig)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 
getAttrib(int attribute)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 
createContext(const GlxContextFactory & factory,const ContextType & contextType)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 
createWindow(::Window xWindow)335 GLXWindow GlxVisual::createWindow (::Window xWindow)
336 {
337 	return TCU_CHECK_GLX(glXCreateWindow(getXDisplay(), m_fbConfig, xWindow, NULL));
338 }
339 
getAttrib(int attrib)340 unsigned GlxDrawable::getAttrib (int attrib)
341 {
342 	unsigned int value = 0;
343 	glXQueryDrawable(getXDisplay(), getGLXDrawable(), attrib, &value);
344 	return value;
345 }
346 
getWidth(void)347 int GlxDrawable::getWidth (void)
348 {
349 	int width = 0;
350 	getDimensions(&width, DE_NULL);
351 	return width;
352 }
353 
getHeight(void)354 int GlxDrawable::getHeight (void)
355 {
356 	int height = 0;
357 	getDimensions(DE_NULL, &height);
358 	return height;
359 }
360 
GlxWindow(GlxVisual & visual,const RenderConfig & cfg)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 
getDimensions(int * width,int * height)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 
~GlxWindow(void)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 
surfaceTypeToDrawableBits(RenderConfig::SurfaceType type)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 
configMatches(GlxVisual & visual,const RenderConfig & renderCfg)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:
Rank(void)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);
getValue(void)456 	deUint64	getValue	(void) { return m_value; }
457 
458 private:
459 	deUint64	m_value;
460 	size_t		m_bitsLeft;
461 };
462 
add(size_t bits,deUint32 value)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 
sub(size_t bits,deUint32 value)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 
configRank(GlxVisual & visual)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 
chooseVisual(GlxDisplay & display,const RenderConfig & cfg)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 
createDrawable(GlxVisual & visual,const RenderConfig & config)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 {
GlxFunctionLoadertcu::x11::glx::GlxFunctionLoader607 							GlxFunctionLoader	(void) {}
608 
gettcu::x11::glx::GlxFunctionLoader609 	glw::GenericFuncType	get					(const char* name) const
610 	{
611 		return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
612 	}
613 };
614 
GlxRenderContext(const GlxContextFactory & factory,const RenderConfig & config)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 
~GlxRenderContext(void)636 GlxRenderContext::~GlxRenderContext (void)
637 {
638 	clearCurrent();
639 	if (m_GLXContext != DE_NULL)
640 		glXDestroyContext(m_glxDisplay.getXDisplay(), m_GLXContext);
641 }
642 
makeCurrent(void)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 
clearCurrent(void)650 void GlxRenderContext::clearCurrent (void)
651 {
652 	TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(),
653 										None, None, DE_NULL));
654 }
655 
getType(void) const656 ContextType GlxRenderContext::getType (void) const
657 {
658 	return m_type;
659 }
660 
postIterate(void)661 void GlxRenderContext::postIterate (void)
662 {
663 	m_glxDrawable->swapBuffers();
664 	m_glxDrawable->processEvents();
665 	m_glxDisplay.processEvents();
666 }
667 
getRenderTarget(void) const668 const RenderTarget& GlxRenderContext::getRenderTarget (void) const
669 {
670 	return m_renderTarget;
671 }
672 
getFunctions(void) const673 const glw::Functions& GlxRenderContext::getFunctions (void) const
674 {
675 	return m_functions;
676 }
677 
createContextFactory(EventState & eventState)678 MovePtr<ContextFactory> createContextFactory (EventState& eventState)
679 {
680 	return MovePtr<ContextFactory>(new GlxContextFactory(eventState));
681 }
682 
683 } // glx
684 } // x11
685 } // tcu
686