diff options
Diffstat (limited to 'tests/glmark2/src/canvas-x11-glx.cpp')
-rw-r--r-- | tests/glmark2/src/canvas-x11-glx.cpp | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/tests/glmark2/src/canvas-x11-glx.cpp b/tests/glmark2/src/canvas-x11-glx.cpp new file mode 100644 index 00000000..db3ac708 --- /dev/null +++ b/tests/glmark2/src/canvas-x11-glx.cpp @@ -0,0 +1,304 @@ +/* + * Copyright © 2010-2011 Linaro Limited + * + * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark. + * + * glmark2 is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * glmark2. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Alexandros Frantzis (glmark2) + */ +#include "canvas-x11-glx.h" +#include "log.h" +#include "options.h" + +#include <string> +#include <climits> + +static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT_; +static PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESA_; +static PFNGLXGETSWAPINTERVALMESAPROC glXGetSwapIntervalMESA_; + +/********************* + * Protected methods * + *********************/ + +XVisualInfo * +CanvasX11GLX::get_xvisualinfo() +{ + if (!ensure_glx_fbconfig()) + return 0; + + XVisualInfo *vis_info = glXGetVisualFromFBConfig(xdpy_, glx_fbconfig_ ); + + return vis_info; +} + +bool +CanvasX11GLX::make_current() +{ + if (!ensure_glx_context()) + return false; + + if (glx_context_ == glXGetCurrentContext()) + return true; + + init_extensions(); + + if (!glXMakeCurrent(xdpy_, xwin_, glx_context_)) { + Log::error("glXMakeCurrent failed\n"); + return false; + } + + unsigned int desired_swap(0); + unsigned int actual_swap(-1); + if (glXSwapIntervalEXT_) { + glXSwapIntervalEXT_(xdpy_, xwin_, desired_swap); + glXQueryDrawable(xdpy_, xwin_, GLX_SWAP_INTERVAL_EXT, &actual_swap); + if (actual_swap == desired_swap) + return true; + } + + if (glXSwapIntervalMESA_) { + glXSwapIntervalMESA_(desired_swap); + actual_swap = glXGetSwapIntervalMESA_(); + if (actual_swap == desired_swap) + return true; + } + + Log::info("** Failed to set swap interval. Results may be bounded above by refresh rate.\n"); + + return true; +} + +void +CanvasX11GLX::get_glvisualconfig(GLVisualConfig &visual_config) +{ + if (!ensure_glx_fbconfig()) + return; + + get_glvisualconfig_glx(glx_fbconfig_, visual_config); +} + +/******************* + * Private methods * + *******************/ + +bool +CanvasX11GLX::check_glx_version() +{ + int glx_major, glx_minor; + + if (!glXQueryVersion(xdpy_, &glx_major, &glx_minor ) || + (glx_major == 1 && glx_minor < 3) || glx_major < 1) + { + Log::error("GLX version >= 1.3 is required\n"); + return false; + } + + return true; +} + +void +CanvasX11GLX::init_extensions() +{ + /* + * Parse the extensions we care about from the extension string. + * Don't even bother to get function pointers until we know the + * extension is present. + */ + std::string extString; + const char* exts = glXQueryExtensionsString(xdpy_, 0); + if (exts) { + extString = exts; + } + + /* + * GLX_EXT_swap_control or GL_MESA_swap_control. Note that + * GLX_SGI_swap_control is not enough because it doesn't allow 0 as a valid + * value (i.e. you can't turn off VSync). + */ + if (extString.find("GLX_EXT_swap_control") != std::string::npos) { + glXSwapIntervalEXT_ = + reinterpret_cast<PFNGLXSWAPINTERVALEXTPROC>( + glXGetProcAddress( + reinterpret_cast<const GLubyte *>("glXSwapIntervalEXT") + ) + ); + } + else if (extString.find("GLX_MESA_swap_control") != std::string::npos) { + glXSwapIntervalMESA_ = + reinterpret_cast<PFNGLXSWAPINTERVALMESAPROC>( + glXGetProcAddress( + reinterpret_cast<const GLubyte *>("glXSwapIntervalMESA") + ) + ); + glXGetSwapIntervalMESA_ = + reinterpret_cast<PFNGLXGETSWAPINTERVALMESAPROC>( + glXGetProcAddress( + reinterpret_cast<const GLubyte *>("glXGetSwapIntervalMESA") + ) + ); + } + + + if (!glXSwapIntervalEXT_ && !glXSwapIntervalMESA_) { + Log::info("** GLX does not support GLX_EXT_swap_control or GLX_MESA_swap_control!\n"); + } +} + +bool +CanvasX11GLX::ensure_glx_fbconfig() +{ + static int attribs[] = { + GLX_X_RENDERABLE, True, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + GLX_RED_SIZE, visual_config_.red, + GLX_GREEN_SIZE, visual_config_.green, + GLX_BLUE_SIZE, visual_config_.blue, + GLX_ALPHA_SIZE, visual_config_.alpha, + GLX_DEPTH_SIZE, visual_config_.depth, + GLX_BUFFER_SIZE, visual_config_.buffer, + GLX_DOUBLEBUFFER, True, + None + }; + int num_configs; + + if (glx_fbconfig_) + return true; + + if (!check_glx_version()) + return false; + + GLXFBConfig *fbc = glXChooseFBConfig(xdpy_, DefaultScreen(xdpy_), + attribs, &num_configs); + if (!fbc) { + Log::error("glXChooseFBConfig() failed\n"); + return false; + } + + std::vector<GLXFBConfig> configs(fbc, fbc + num_configs); + + Log::debug("Found %d matching FB configs.\n", num_configs); + + /* Select the best matching config */ + glx_fbconfig_ = select_best_config(configs); + + XFree(fbc); + + if (Options::show_debug) { + int buf, red, green, blue, alpha, depth, id, native_id; + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_FBCONFIG_ID, &id); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_VISUAL_ID, &native_id); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_BUFFER_SIZE, &buf); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_RED_SIZE, &red); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_GREEN_SIZE, &green); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_BLUE_SIZE, &blue); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_ALPHA_SIZE, &alpha); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_DEPTH_SIZE, &depth); + Log::debug("GLX chosen config ID: 0x%x Native Visual ID: 0x%x\n" + " Buffer: %d bits\n" + " Red: %d bits\n" + " Green: %d bits\n" + " Blue: %d bits\n" + " Alpha: %d bits\n" + " Depth: %d bits\n", + id, native_id, + buf, red, green, blue, alpha, depth); + } + + + return true; +} + +void +CanvasX11GLX::init_gl_extensions() +{ + GLExtensions::MapBuffer = glMapBuffer; + GLExtensions::UnmapBuffer = glUnmapBuffer; +} + +bool +CanvasX11GLX::reset_context() +{ + glXDestroyContext(xdpy_, glx_context_); + glx_context_ = 0; + + return true; +} + +bool +CanvasX11GLX::ensure_glx_context() +{ + if (glx_context_) + return true; + + if (!ensure_glx_fbconfig()) + return false; + + glx_context_ = glXCreateNewContext(xdpy_, glx_fbconfig_, GLX_RGBA_TYPE, + 0, True); + if (!glx_context_) { + Log::error("glXCreateNewContext failed\n"); + return false; + } + + init_gl_extensions(); + + return true; +} + +void +CanvasX11GLX::get_glvisualconfig_glx(const GLXFBConfig config, GLVisualConfig &visual_config) +{ + glXGetFBConfigAttrib(xdpy_, config, GLX_BUFFER_SIZE, &visual_config.buffer); + glXGetFBConfigAttrib(xdpy_, config, GLX_RED_SIZE, &visual_config.red); + glXGetFBConfigAttrib(xdpy_, config, GLX_GREEN_SIZE, &visual_config.green); + glXGetFBConfigAttrib(xdpy_, config, GLX_BLUE_SIZE, &visual_config.blue); + glXGetFBConfigAttrib(xdpy_, config, GLX_ALPHA_SIZE, &visual_config.alpha); + glXGetFBConfigAttrib(xdpy_, config, GLX_DEPTH_SIZE, &visual_config.depth); +} + +GLXFBConfig +CanvasX11GLX::select_best_config(std::vector<GLXFBConfig> configs) +{ + int best_score(INT_MIN); + GLXFBConfig best_config(0); + + /* + * Go through all the configs and choose the one with the best score, + * i.e., the one better matching the requested config. + */ + for (std::vector<GLXFBConfig>::const_iterator iter = configs.begin(); + iter != configs.end(); + iter++) + { + const GLXFBConfig config(*iter); + GLVisualConfig vc; + int score; + + get_glvisualconfig_glx(config, vc); + + score = vc.match_score(visual_config_); + + if (score > best_score) { + best_score = score; + best_config = config; + } + } + + return best_config; +} |