1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Platform that uses X11 via GLX.
22 *//*--------------------------------------------------------------------*/
24 #include "tcuX11GlxPlatform.hpp"
25 #include "tcuX11Platform.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "glwInitFunctions.hpp"
29 #include "deUniquePtr.hpp"
35 #define GLX_GLXEXT_PROTOTYPES
48 using glu::ContextFactory;
49 using glu::ContextType;
50 using glu::RenderConfig;
51 using glu::RenderContext;
52 using tcu::CommandLine;
53 using tcu::RenderTarget;
56 using std::istringstream;
57 using std::ostringstream;
58 using std::istream_iterator;
60 typedef RenderConfig::Visibility Visibility;
64 static inline T checkGLX(T value, const char* expr, const char* file, int line)
67 throw tcu::TestError("GLX call failed", expr, file, line);
71 #define TCU_CHECK_GLX(EXPR) checkGLX(EXPR, #EXPR, __FILE__, __LINE__)
72 #define TCU_CHECK_GLX_CONFIG(EXPR) checkGLX((EXPR) == Success, #EXPR, __FILE__, __LINE__)
74 class GlxContextFactory : public glu::ContextFactory
77 GlxContextFactory (EventState& eventState);
78 ~GlxContextFactory (void);
79 RenderContext* createContext (const RenderConfig& config,
80 const CommandLine& cmdLine) const;
82 EventState& getEventState (void) const { return m_eventState;}
84 const PFNGLXCREATECONTEXTATTRIBSARBPROC
85 m_glXCreateContextAttribsARB;
88 EventState& m_eventState;
91 class GlxDisplay : public XlibDisplay
94 GlxDisplay (EventState& eventState,
96 int getGlxMajorVersion (void) const { return m_majorVersion; }
97 int getGlxMinorVersion (void) const { return m_minorVersion; }
98 bool isGlxExtensionSupported (const char* extName) const;
105 set<string> m_extensions;
111 GlxVisual (GlxDisplay& display, GLXFBConfig fbConfig);
112 int getAttrib (int attribute);
113 Visual* getXVisual (void) { return m_visual; }
114 GLXContext createContext (const GlxContextFactory& factory,
115 const ContextType& contextType);
116 GLXWindow createWindow (::Window xWindow);
117 GlxDisplay& getGlxDisplay (void) { return m_display; }
118 ::Display* getXDisplay (void) { return m_display.getXDisplay(); }
121 GlxDisplay& m_display;
123 const GLXFBConfig m_fbConfig;
129 virtual ~GlxDrawable (void) {}
131 virtual void processEvents (void) {}
132 virtual void getDimensions (int* width, int* height) = 0;
134 int getHeight (void);
135 void swapBuffers (void) { glXSwapBuffers(getXDisplay(), getGLXDrawable()); }
137 virtual ::Display* getXDisplay (void) = 0;
138 virtual GLXDrawable getGLXDrawable (void) = 0;
142 unsigned int getAttrib (int attribute);
145 class GlxWindow : public GlxDrawable
148 GlxWindow (GlxVisual& visual, const RenderConfig& cfg);
150 void processEvents (void) { m_x11Window.processEvents(); }
151 ::Display* getXDisplay (void) { return m_x11Display.getXDisplay(); }
152 void getDimensions (int* width, int* height);
155 GLXDrawable getGLXDrawable () { return m_GLXDrawable; }
158 XlibDisplay& m_x11Display;
159 XlibWindow m_x11Window;
160 const GLXDrawable m_GLXDrawable;
163 class GlxRenderContext : public RenderContext
166 GlxRenderContext (const GlxContextFactory& factory,
167 const RenderConfig& config);
168 ~GlxRenderContext (void);
169 virtual ContextType getType (void) const;
170 virtual void postIterate (void);
171 void makeCurrent (void);
172 void clearCurrent (void);
173 virtual const glw::Functions& getFunctions (void) const;
174 virtual const tcu::RenderTarget& getRenderTarget (void) const;
177 GlxDisplay m_glxDisplay;
178 GlxVisual m_glxVisual;
180 GLXContext m_GLXContext;
181 UniquePtr<GlxDrawable> m_glxDrawable;
182 RenderTarget m_renderTarget;
183 glw::Functions m_functions;
188 static int tcuX11GlxErrorHandler (::Display* display, XErrorEvent* event)
191 XGetErrorText(display, event->error_code, buf, sizeof(buf));
192 tcu::print("X operation %u:%u failed: %s\n",
193 event->request_code, event->minor_code, buf);
198 GlxContextFactory::GlxContextFactory (EventState& eventState)
199 : glu::ContextFactory ("glx", "X11 GLX OpenGL Context")
200 , m_glXCreateContextAttribsARB (
201 reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(
204 reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB")))))
205 , m_eventState (eventState)
207 XSetErrorHandler(tcuX11GlxErrorHandler);
210 RenderContext* GlxContextFactory::createContext (const RenderConfig& config,
211 const CommandLine& cmdLine) const
214 GlxRenderContext* const renderContext = new GlxRenderContext(*this, config);
215 return renderContext;
218 GlxContextFactory::~GlxContextFactory (void)
222 GlxDisplay::GlxDisplay (EventState& eventState, const char* name)
223 : XlibDisplay (eventState, name)
225 const Bool supported = glXQueryExtension(m_display, &m_errorBase, &m_eventBase);
227 TCU_THROW(NotSupportedError, "GLX protocol not supported by X server");
229 TCU_CHECK_GLX(glXQueryVersion(m_display, &m_majorVersion, &m_minorVersion));
232 const int screen = XDefaultScreen(m_display);
233 // nVidia doesn't seem to report client-side extensions correctly,
234 // so only use server side
235 const char* const extensions =
236 TCU_CHECK_GLX(glXQueryServerString(m_display, screen, GLX_EXTENSIONS));
237 istringstream extStream(extensions);
238 m_extensions = set<string>(istream_iterator<string>(extStream),
239 istream_iterator<string>());
244 bool GlxDisplay::isGlxExtensionSupported (const char* extName) const
246 return m_extensions.find(extName) != m_extensions.end();
249 //! Throw `tcu::NotSupportedError` if `dpy` is not compatible with GLX
250 //! version `major`.`minor`.
251 static void checkGlxVersion (const GlxDisplay& dpy, int major, int minor)
253 const int dpyMajor = dpy.getGlxMajorVersion();
254 const int dpyMinor = dpy.getGlxMinorVersion();
255 if (!(dpyMajor == major && dpyMinor >= minor))
258 oss << "Server GLX version "
259 << dpyMajor << "." << dpyMinor
260 << " not compatible with required version "
261 << major << "." << minor;
262 TCU_THROW(NotSupportedError, oss.str().c_str());
266 //! Throw `tcu::NotSupportedError` if `dpy` does not support extension `extName`.
267 static void checkGlxExtension (const GlxDisplay& dpy, const char* extName)
269 if (!dpy.isGlxExtensionSupported(extName))
272 oss << "GLX extension \"" << extName << "\" not supported";
273 TCU_THROW(NotSupportedError, oss.str().c_str());
277 GlxVisual::GlxVisual (GlxDisplay& display, GLXFBConfig fbConfig)
278 : m_display (display)
280 , m_fbConfig (fbConfig)
282 XVisualInfo* visualInfo = glXGetVisualFromFBConfig(getXDisplay(), fbConfig);
283 if (visualInfo != DE_NULL)
285 m_visual = visualInfo->visual;
290 int GlxVisual::getAttrib (int attribute)
293 TCU_CHECK_GLX_CONFIG(glXGetFBConfigAttrib(getXDisplay(), m_fbConfig, attribute, &fbvalue));
297 GLXContext GlxVisual::createContext (const GlxContextFactory& factory,
298 const ContextType& contextType)
301 const ApiType apiType = contextType.getAPI();
303 checkGlxVersion(m_display, 1, 4);
304 checkGlxExtension(m_display, "GLX_ARB_create_context");
305 checkGlxExtension(m_display, "GLX_ARB_create_context_profile");
307 switch (apiType.getProfile())
309 case glu::PROFILE_ES:
310 checkGlxExtension(m_display, "GLX_EXT_create_context_es2_profile");
311 profileMask = GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
313 case glu::PROFILE_CORE:
314 profileMask = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
316 case glu::PROFILE_COMPATIBILITY:
317 profileMask = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
320 DE_FATAL("Impossible context profile");
323 const int attribs[] =
325 GLX_CONTEXT_MAJOR_VERSION_ARB, apiType.getMajorVersion(),
326 GLX_CONTEXT_MINOR_VERSION_ARB, apiType.getMinorVersion(),
327 GLX_CONTEXT_FLAGS_ARB, 0,
328 GLX_CONTEXT_PROFILE_MASK_ARB, profileMask,
331 return TCU_CHECK_GLX(factory.m_glXCreateContextAttribsARB(
332 getXDisplay(), m_fbConfig, DE_NULL, True, attribs));
335 GLXWindow GlxVisual::createWindow (::Window xWindow)
337 return TCU_CHECK_GLX(glXCreateWindow(getXDisplay(), m_fbConfig, xWindow, NULL));
340 unsigned GlxDrawable::getAttrib (int attrib)
342 unsigned int value = 0;
343 glXQueryDrawable(getXDisplay(), getGLXDrawable(), attrib, &value);
347 int GlxDrawable::getWidth (void)
350 getDimensions(&width, DE_NULL);
354 int GlxDrawable::getHeight (void)
357 getDimensions(DE_NULL, &height);
361 GlxWindow::GlxWindow (GlxVisual& visual, const RenderConfig& cfg)
362 : m_x11Display (visual.getGlxDisplay())
363 , m_x11Window (m_x11Display, cfg.width, cfg.height,
365 , m_GLXDrawable (visual.createWindow(m_x11Window.getXID()))
367 m_x11Window.setVisibility(cfg.windowVisibility != RenderConfig::VISIBILITY_HIDDEN);
370 void GlxWindow::getDimensions (int* width, int* height)
372 if (width != DE_NULL)
373 *width = getAttrib(GLX_WIDTH);
374 if (height != DE_NULL)
375 *height = getAttrib(GLX_HEIGHT);
377 // glXQueryDrawable may be buggy, so fall back to X geometry if needed
378 if ((width != DE_NULL && *width == 0) || (height != DE_NULL && *height == 0))
379 m_x11Window.getDimensions(width, height);
382 GlxWindow::~GlxWindow (void)
384 glXDestroyWindow(m_x11Display.getXDisplay(), m_GLXDrawable);
387 static const struct Attribute
390 int RenderConfig::* cfgMember;
393 { GLX_RED_SIZE, &RenderConfig::redBits },
394 { GLX_GREEN_SIZE, &RenderConfig::greenBits },
395 { GLX_BLUE_SIZE, &RenderConfig::blueBits },
396 { GLX_ALPHA_SIZE, &RenderConfig::alphaBits },
397 { GLX_DEPTH_SIZE, &RenderConfig::depthBits },
398 { GLX_STENCIL_SIZE, &RenderConfig::stencilBits },
399 { GLX_SAMPLES, &RenderConfig::numSamples },
400 { GLX_FBCONFIG_ID, &RenderConfig::id },
403 static deUint32 surfaceTypeToDrawableBits (RenderConfig::SurfaceType type)
407 case RenderConfig::SURFACETYPE_WINDOW:
408 return GLX_WINDOW_BIT;
409 case RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
410 return GLX_PIXMAP_BIT;
411 case RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
412 return GLX_PBUFFER_BIT;
413 case RenderConfig::SURFACETYPE_DONT_CARE:
414 return GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;
416 DE_FATAL("Impossible case");
421 static bool configMatches (GlxVisual& visual, const RenderConfig& renderCfg)
423 if (renderCfg.id != RenderConfig::DONT_CARE)
424 return visual.getAttrib(GLX_FBCONFIG_ID) == renderCfg.id;
426 for (const Attribute* it = DE_ARRAY_BEGIN(s_attribs); it != DE_ARRAY_END(s_attribs); it++)
428 const int requested = renderCfg.*it->cfgMember;
429 if (requested != RenderConfig::DONT_CARE &&
430 requested != visual.getAttrib(it->glxAttribute))
435 deUint32 bits = surfaceTypeToDrawableBits(renderCfg.surfaceType);
437 if ((visual.getAttrib(GLX_DRAWABLE_TYPE) & bits) == 0)
440 // It shouldn't be possible to have GLX_WINDOW_BIT set without a visual,
441 // but let's make sure.
442 if (renderCfg.surfaceType == RenderConfig::SURFACETYPE_WINDOW &&
443 visual.getXVisual() == DE_NULL)
453 Rank (void) : m_value(0), m_bitsLeft(64) {}
454 void add (size_t bits, deUint32 value);
455 void sub (size_t bits, deUint32 value);
456 deUint64 getValue (void) { return m_value; }
463 void Rank::add (size_t bits, deUint32 value)
465 TCU_CHECK_INTERNAL(m_bitsLeft >= bits);
467 m_value = m_value << bits | de::min((1U << bits) - 1, value);
470 void Rank::sub (size_t bits, deUint32 value)
472 TCU_CHECK_INTERNAL(m_bitsLeft >= bits);
474 m_value = m_value << bits | ((1U << bits) - 1 - de::min((1U << bits) - 1U, value));
477 static deUint64 configRank (GlxVisual& visual)
480 if (visual.getAttrib(GLX_DOUBLEBUFFER) == False ||
481 (visual.getAttrib(GLX_RENDER_TYPE) & GLX_RGBA_BIT) == 0)
485 int caveat = visual.getAttrib(GLX_CONFIG_CAVEAT);
486 int redSize = visual.getAttrib(GLX_RED_SIZE);
487 int greenSize = visual.getAttrib(GLX_GREEN_SIZE);
488 int blueSize = visual.getAttrib(GLX_BLUE_SIZE);
489 int alphaSize = visual.getAttrib(GLX_ALPHA_SIZE);
490 int depthSize = visual.getAttrib(GLX_DEPTH_SIZE);
491 int stencilSize = visual.getAttrib(GLX_STENCIL_SIZE);
492 int minRGB = de::min(redSize, de::min(greenSize, blueSize));
494 // Prefer conformant configurations.
495 rank.add(1, (caveat != GLX_NON_CONFORMANT_CONFIG));
497 // Prefer non-transparent configurations.
498 rank.add(1, visual.getAttrib(GLX_TRANSPARENT_TYPE) == GLX_NONE);
501 rank.add(1, visual.getAttrib(GLX_STEREO) == False);
504 rank.add(1, visual.getAttrib(GLX_LEVEL) == 0);
506 // Prefer to have some alpha.
507 rank.add(1, alphaSize > 0);
509 // Prefer to have a depth buffer.
510 rank.add(1, depthSize > 0);
512 // Prefer to have a stencil buffer.
513 rank.add(1, stencilSize > 0);
515 // Avoid slow configurations.
516 rank.add(1, (caveat != GLX_SLOW_CONFIG));
518 // Prefer larger, evenly distributed color depths
519 rank.add(4, de::min(minRGB, alphaSize));
521 // If alpha is low, choose best RGB
524 // Prefer larger depth and stencil buffers
525 rank.add(6, deUint32(depthSize + stencilSize));
527 // Avoid excessive sampling
528 rank.sub(5, visual.getAttrib(GLX_SAMPLES));
530 // Prefer True/DirectColor
531 int visualType = visual.getAttrib(GLX_X_VISUAL_TYPE);
532 rank.add(1, visualType == GLX_TRUE_COLOR || visualType == GLX_DIRECT_COLOR);
534 return rank.getValue();
537 static GlxVisual chooseVisual (GlxDisplay& display, const RenderConfig& cfg)
539 ::Display* dpy = display.getXDisplay();
540 deUint64 maxRank = 0;
541 GLXFBConfig maxConfig = DE_NULL;
544 GLXFBConfig* const fbConfigs = glXGetFBConfigs(dpy, DefaultScreen(dpy), &numElems);
545 TCU_CHECK_MSG(fbConfigs != DE_NULL, "Couldn't query framebuffer configurations");
547 for (int i = 0; i < numElems; i++)
549 GlxVisual visual(display, fbConfigs[i]);
551 if (!configMatches(visual, cfg))
554 deUint64 cfgRank = configRank(visual);
556 if (cfgRank > maxRank)
559 maxConfig = fbConfigs[i];
565 TCU_THROW(NotSupportedError, "Requested GLX configuration not found or unusable");
567 return GlxVisual(display, maxConfig);
570 GlxDrawable* createDrawable (GlxVisual& visual, const RenderConfig& config)
572 RenderConfig::SurfaceType surfaceType = config.surfaceType;
574 if (surfaceType == RenderConfig::SURFACETYPE_DONT_CARE)
576 if (visual.getXVisual() == DE_NULL)
577 // No visual, cannot create X window
578 surfaceType = RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE;
580 surfaceType = RenderConfig::SURFACETYPE_WINDOW;
585 case RenderConfig::SURFACETYPE_DONT_CARE:
586 DE_FATAL("Impossible case");
588 case RenderConfig::SURFACETYPE_WINDOW:
589 return new GlxWindow(visual, config);
592 case RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
593 // \todo [2013-11-28 lauri] Pixmaps
595 case RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
596 // \todo [2013-11-28 lauri] Pbuffers
599 TCU_THROW(NotSupportedError, "Unsupported surface type");
605 struct GlxFunctionLoader : public glw::FunctionLoader
607 GlxFunctionLoader (void) {}
609 glw::GenericFuncType get (const char* name) const
611 return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
615 GlxRenderContext::GlxRenderContext (const GlxContextFactory& factory,
616 const RenderConfig& config)
617 : m_glxDisplay (factory.getEventState(), DE_NULL)
618 , m_glxVisual (chooseVisual(m_glxDisplay, config))
619 , m_type (config.type)
620 , m_GLXContext (m_glxVisual.createContext(factory, config.type))
621 , m_glxDrawable (createDrawable(m_glxVisual, config))
622 , m_renderTarget (m_glxDrawable->getWidth(), m_glxDrawable->getHeight(),
623 PixelFormat(m_glxVisual.getAttrib(GLX_RED_SIZE),
624 m_glxVisual.getAttrib(GLX_GREEN_SIZE),
625 m_glxVisual.getAttrib(GLX_BLUE_SIZE),
626 m_glxVisual.getAttrib(GLX_ALPHA_SIZE)),
627 m_glxVisual.getAttrib(GLX_DEPTH_SIZE),
628 m_glxVisual.getAttrib(GLX_STENCIL_SIZE),
629 m_glxVisual.getAttrib(GLX_SAMPLES))
631 const GlxFunctionLoader loader;
633 glu::initFunctions(&m_functions, &loader, config.type.getAPI());
636 GlxRenderContext::~GlxRenderContext (void)
639 if (m_GLXContext != DE_NULL)
640 glXDestroyContext(m_glxDisplay.getXDisplay(), m_GLXContext);
643 void GlxRenderContext::makeCurrent (void)
645 const GLXDrawable drawRead = m_glxDrawable->getGLXDrawable();
646 TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(),
647 drawRead, drawRead, m_GLXContext));
650 void GlxRenderContext::clearCurrent (void)
652 TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(),
653 None, None, DE_NULL));
656 ContextType GlxRenderContext::getType (void) const
661 void GlxRenderContext::postIterate (void)
663 m_glxDrawable->swapBuffers();
664 m_glxDrawable->processEvents();
665 m_glxDisplay.processEvents();
668 const RenderTarget& GlxRenderContext::getRenderTarget (void) const
670 return m_renderTarget;
673 const glw::Functions& GlxRenderContext::getFunctions (void) const
678 MovePtr<ContextFactory> createContextFactory (EventState& eventState)
680 return MovePtr<ContextFactory>(new GlxContextFactory(eventState));