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