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