aboutsummaryrefslogtreecommitdiff
path: root/tests/glmark2/src/canvas-x11-glx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/glmark2/src/canvas-x11-glx.cpp')
-rw-r--r--tests/glmark2/src/canvas-x11-glx.cpp304
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;
+}