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