d636f677fc29b75e11236a436bf998344510163b
[gltest.git] / glxbackend.cpp
1 /* gltest - small OpenGL tearing test program
2  * Copyright (C) 2012-2013 Ralf Jung <post@ralfj.de>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "glxbackend.h"
20 #include "glutil.h"
21
22 #include <stdio.h>
23 #include <assert.h>
24 #include <GL/glxext.h>
25 #include <string>
26
27 #if !defined(CON_GL1) && !defined(CON_GL3)
28 #error "Valid GL contexts for GLX are: GL1, GL3"
29 #endif
30
31 // attributes for a double buffered framebuffer in RGBA format with at least 4 bits per color
32 static int configAttribs[] =                                             
33 {
34         GLX_RENDER_TYPE, GLX_RGBA_BIT,
35         GLX_DOUBLEBUFFER, True,
36         GLX_RED_SIZE, 4,
37         GLX_GREEN_SIZE, 4,
38         GLX_BLUE_SIZE, 4,
39         None
40 };
41
42 #ifdef CON_GL3
43 // attributes for a GL3 context
44 static int contextAttribs[] =
45 {
46         GLX_CONTEXT_MAJOR_VERSION_ARB,               3,
47         GLX_CONTEXT_MINOR_VERSION_ARB,               0,
48         GLX_CONTEXT_FLAGS_ARB,                       GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
49         None
50 };
51 #endif
52
53 VisualID GLXBackend::initialize(Display *display)
54 {
55         if (this->display == NULL) { // this implies that the context is also unitialized
56                 this->display = display;
57                 // debugging: show version information
58                 int glxMajor, glxMinor;
59                 glXQueryVersion(display, &glxMajor, &glxMinor);
60                 printf("Using GLX version: %d.%d\n", glxMajor, glxMinor);
61                 if (glxMajor == 1 && glxMinor < 4) {
62                         // glXChooseFBConfig and glXCreateNewContext require GLX 1.3; GLX_ARB_create_context requires GLX 1.4
63                         die("Need at least GLX 1.4 to function properly\n");
64                 }
65                 // check for extension-based functions
66                 funSwapIntervalMesa = (PFNGLXSWAPINTERVALMESAPROC)resolveGLXFunction("GLX_MESA_swap_control", "glXSwapIntervalMESA");
67                 funSwapIntervalExt = (PFNGLXSWAPINTERVALEXTPROC)resolveGLXFunction("GLX_EXT_swap_control", "glXSwapIntervalEXT");
68                 funCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)resolveGLXFunction("GLX_ARB_create_context", "glXCreateContextAttribsARB");
69                 // get the first usable framebuffer configuration
70                 int count = 0;
71                 GLXFBConfig *configs = glXChooseFBConfig(display, DefaultScreen(display), configAttribs, &count);
72                 if (count < 1) {
73                         die("Failed to choose framebuffer configuration\n");
74                 }
75                 config = configs[0];
76                 XFree(configs);
77         }
78         // return visual ID
79         XVisualInfo *vi = glXGetVisualFromFBConfig(display, config);
80         VisualID visualid = vi->visualid;
81         XFree(vi);
82         return visualid;
83 }
84
85 bool GLXBackend::haveGLXExtension(const std::string &name)
86 {
87         assert(display != NULL);
88         std::string extensions = glXQueryExtensionsString(display, DefaultScreen(display));
89         return (std::string(" "+extensions+" ").find(" "+name+" ") != std::string::npos);
90 }
91
92 T_proc GLXBackend::resolveGLXFunction(const char *extension, const char *function)
93 {
94         if (!haveGLXExtension(extension)) return NULL;
95         T_proc f = glXGetProcAddress((const GLubyte*)function);
96         if (f)
97                 printf("%s is supported, using it for %s\n", extension, function);
98         return f;
99 }
100
101 void GLXBackend::createContext(Window window)
102 {
103         assert(display != NULL && context == None);
104         this->window = window;
105         // create context with that window
106 #ifdef CON_GL1
107         context = glXCreateNewContext(display, config, GLX_RGBA_TYPE, NULL, GL_TRUE);
108 #else
109         if (!funCreateContextAttribsARB) {
110                 die("Cannot create GL3 context: GLX_ARB_create_context not supported\n");
111         }
112         context = funCreateContextAttribsARB(display, config, NULL, GL_TRUE, contextAttribs);
113 #endif
114         if (!context) {
115                 die("Error creating context\n");
116         }
117         glXMakeCurrent(display, window, context);                                      
118         assert(glXIsDirect(display, context));
119         printf("Using GL version: %s\n", glGetString(GL_VERSION));
120         // initialise GL utilities
121         resolveFunctionPointers((T_glGetProcAddress)glXGetProcAddress);
122 }
123
124 GLXBackend::~GLXBackend()
125 {
126         if (display != NULL) {
127                 if (context != None) {
128                         glXMakeCurrent(display, None, NULL);
129                         glXDestroyContext(display, context);
130                 }
131         }
132 }
133
134 void GLXBackend::swapBuffers() const
135 {
136         assert(context != None); // this implies the display is also initialized
137         glXSwapBuffers(display, window);
138 }
139
140 void GLXBackend::setSwapInterval(int i) const
141 {
142         assert(context != None);
143         // check if swap interval value is supported
144         if (i < 0) {
145                 die("Cannot set swap interval to %d, must not be negative\n", i);
146         }
147         // set it
148         if (funSwapIntervalExt)
149                 funSwapIntervalExt(display, window, i);
150         else if (funSwapIntervalMesa)
151                 funSwapIntervalMesa(i);
152         else {
153                 die("At least one of GLX_EXT_swap_control, GLX_MESA_swap_control must be supported by the system\n");
154         }
155 }