• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
checkGLX(T value,const char * expr,const char * file,int line)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 
getEventState(void) const83 	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);
getGlxMajorVersion(void) const97 	int						getGlxMajorVersion		(void) const { return m_majorVersion; }
getGlxMinorVersion(void) const98 	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);
getXVisual(void)114 	Visual*					getXVisual			(void) { return m_visual; }
115 	GLXContext				createContext		(const GlxContextFactory&	factory,
116 												 const ContextType&			contextType);
117 	GLXWindow				createWindow		(::Window xWindow);
getGlxDisplay(void)118 	GlxDisplay&				getGlxDisplay		(void) { return m_display; }
getXDisplay(void)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:
~GlxDrawable(void)130 	virtual					~GlxDrawable		(void) {}
131 
processEvents(void)132 	virtual void			processEvents		(void) {}
133 	virtual void			getDimensions		(int* width, int* height) = 0;
134 	int						getWidth			(void);
135 	int						getHeight			(void);
swapBuffers(void)136 	void					swapBuffers			(void) { glXSwapBuffers(getXDisplay(), getGLXDrawable()); }
137 
138 	virtual ::Display*		getXDisplay			(void) = 0;
139 	virtual GLXDrawable		getGLXDrawable		(void) = 0;
140 
141 protected:
GlxDrawable()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);
processEvents(void)151 	void					processEvents		(void) { m_x11Window.processEvents(); }
getXDisplay(void)152 	::Display*				getXDisplay			(void) { return m_x11Display.getXDisplay(); }
153 	void					getDimensions		(int* width, int* height);
154 
155 protected:
getGLXDrawable()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 {
tcuLnxX11GlxErrorHandler(::Display * display,XErrorEvent * event)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 
GlxContextFactory(EventState & eventState)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 
createContext(const RenderConfig & config,const CommandLine & cmdLine) const211 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 
~GlxContextFactory(void)219 GlxContextFactory::~GlxContextFactory (void)
220 {
221 }
222 
GlxDisplay(EventState & eventState,const char * name)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 
isGlxExtensionSupported(const char * extName) const245 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`.
checkGlxVersion(const GlxDisplay & dpy,int major,int 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`.
checkGlxExtension(const GlxDisplay & dpy,const char * 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 
GlxVisual(GlxDisplay & display,GLXFBConfig fbConfig)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 
getAttrib(int attribute)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 
createContext(const GlxContextFactory & factory,const ContextType & contextType)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 
createWindow(::Window xWindow)336 GLXWindow GlxVisual::createWindow (::Window xWindow)
337 {
338 	return TCU_CHECK_GLX(glXCreateWindow(getXDisplay(), m_fbConfig, xWindow, NULL));
339 }
340 
getAttrib(int attrib)341 unsigned GlxDrawable::getAttrib (int attrib)
342 {
343 	unsigned int value = 0;
344 	glXQueryDrawable(getXDisplay(), getGLXDrawable(), attrib, &value);
345 	return value;
346 }
347 
getWidth(void)348 int GlxDrawable::getWidth (void)
349 {
350 	int width = 0;
351 	getDimensions(&width, DE_NULL);
352 	return width;
353 }
354 
getHeight(void)355 int GlxDrawable::getHeight (void)
356 {
357 	int height = 0;
358 	getDimensions(DE_NULL, &height);
359 	return height;
360 }
361 
GlxWindow(GlxVisual & visual,const RenderConfig & cfg)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 
getDimensions(int * width,int * height)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 
~GlxWindow(void)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 
surfaceTypeToDrawableBits(RenderConfig::SurfaceType type)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 
configMatches(GlxVisual & visual,const RenderConfig & renderCfg)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:
Rank(void)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);
getValue(void)457 	deUint64	getValue	(void) { return m_value; }
458 
459 private:
460 	deUint64	m_value;
461 	size_t		m_bitsLeft;
462 };
463 
add(size_t bits,deUint32 value)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 
sub(size_t bits,deUint32 value)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 
configRank(GlxVisual & visual)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 
chooseVisual(GlxDisplay & display,const RenderConfig & cfg)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 
createDrawable(GlxVisual & visual,const RenderConfig & config)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 {
GlxFunctionLoadertcu::lnx::x11::glx::GlxFunctionLoader608 							GlxFunctionLoader	(void) {}
609 
gettcu::lnx::x11::glx::GlxFunctionLoader610 	glw::GenericFuncType	get					(const char* name) const
611 	{
612 		return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
613 	}
614 };
615 
GlxRenderContext(const GlxContextFactory & factory,const RenderConfig & config)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 
~GlxRenderContext(void)637 GlxRenderContext::~GlxRenderContext (void)
638 {
639 	clearCurrent();
640 	if (m_GLXContext != DE_NULL)
641 		glXDestroyContext(m_glxDisplay.getXDisplay(), m_GLXContext);
642 }
643 
makeCurrent(void)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 
clearCurrent(void)651 void GlxRenderContext::clearCurrent (void)
652 {
653 	TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(),
654 										None, None, DE_NULL));
655 }
656 
getType(void) const657 ContextType GlxRenderContext::getType (void) const
658 {
659 	return m_type;
660 }
661 
postIterate(void)662 void GlxRenderContext::postIterate (void)
663 {
664 	m_glxDrawable->swapBuffers();
665 	m_glxDrawable->processEvents();
666 	m_glxDisplay.processEvents();
667 }
668 
getRenderTarget(void) const669 const RenderTarget& GlxRenderContext::getRenderTarget (void) const
670 {
671 	return m_renderTarget;
672 }
673 
getFunctions(void) const674 const glw::Functions& GlxRenderContext::getFunctions (void) const
675 {
676 	return m_functions;
677 }
678 
createContextFactory(EventState & eventState)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