/extlibs/SFML/src/SFML/Window/Linux/GlxContext.cpp
C++ | 300 lines | 195 code | 41 blank | 64 comment | 36 complexity | 509f6ceb130d5987f7c3757815f9562e MD5 | raw file
1//////////////////////////////////////////////////////////// 2// 3// SFML - Simple and Fast Multimedia Library 4// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) 5// 6// This software is provided 'as-is', without any express or implied warranty. 7// In no event will the authors be held liable for any damages arising from the use of this software. 8// 9// Permission is granted to anyone to use this software for any purpose, 10// including commercial applications, and to alter it and redistribute it freely, 11// subject to the following restrictions: 12// 13// 1. The origin of this software must not be misrepresented; 14// you must not claim that you wrote the original software. 15// If you use this software in a product, an acknowledgment 16// in the product documentation would be appreciated but is not required. 17// 18// 2. Altered source versions must be plainly marked as such, 19// and must not be misrepresented as being the original software. 20// 21// 3. This notice may not be removed or altered from any source distribution. 22// 23//////////////////////////////////////////////////////////// 24 25//////////////////////////////////////////////////////////// 26// Headers 27//////////////////////////////////////////////////////////// 28#define GLX_GLXEXT_LEGACY // so that our local glxext.h is used instead of the system one 29#include <SFML/Window/Linux/GlxContext.hpp> 30#include <SFML/Window/Linux/WindowImplX11.hpp> 31#include <SFML/OpenGL.hpp> 32#include <SFML/Window/glext/glxext.h> 33#include <SFML/System/Err.hpp> 34 35 36namespace sf 37{ 38namespace priv 39{ 40//////////////////////////////////////////////////////////// 41GlxContext::GlxContext(GlxContext* shared) : 42myWindow (0), 43myContext (NULL), 44myOwnsWindow(true) 45{ 46 // Open a connection with the X server 47 myDisplay = XOpenDisplay(NULL); 48 49 // Create a dummy window (disabled and hidden) 50 int screen = DefaultScreen(myDisplay); 51 myWindow = XCreateWindow(myDisplay, 52 RootWindow(myDisplay, screen), 53 0, 0, 54 1, 1, 55 0, 56 DefaultDepth(myDisplay, screen), 57 InputOutput, 58 DefaultVisual(myDisplay, screen), 59 0, NULL); 60 61 // Create the context 62 CreateContext(shared, VideoMode::GetDesktopMode().BitsPerPixel, ContextSettings(0, 0, 0)); 63 64 // Activate the context 65 SetActive(true); 66} 67 68 69//////////////////////////////////////////////////////////// 70GlxContext::GlxContext(GlxContext* shared, const WindowImpl* owner, unsigned int bitsPerPixel, const ContextSettings& settings) : 71myWindow (0), 72myContext (NULL), 73myOwnsWindow(false) 74{ 75 // Use the same context as the owner window (important!) 76 myDisplay = static_cast<const WindowImplX11*>(owner)->GetDisplay(); 77 78 // Get the owner window and its device context 79 myWindow = static_cast<Window>(owner->GetSystemHandle()); 80 81 // Create the context 82 if (myWindow) 83 CreateContext(shared, bitsPerPixel, settings); 84 85 // Activate the context 86 SetActive(true); 87} 88 89 90//////////////////////////////////////////////////////////// 91GlxContext::~GlxContext() 92{ 93 // Destroy the context 94 if (myContext) 95 { 96 if (glXGetCurrentContext() == myContext) 97 glXMakeCurrent(myDisplay, None, NULL); 98 glXDestroyContext(myDisplay, myContext); 99 } 100 101 // Destroy the window if we own it 102 if (myWindow && myOwnsWindow) 103 { 104 XDestroyWindow(myDisplay, myWindow); 105 XFlush(myDisplay); 106 } 107 108 // Close the connection with the X server 109 if (myOwnsWindow) 110 { 111 XCloseDisplay(myDisplay); 112 } 113} 114 115 116//////////////////////////////////////////////////////////// 117bool GlxContext::MakeCurrent() 118{ 119 if (myContext) 120 { 121 if (glXGetCurrentContext() != myContext) 122 return glXMakeCurrent(myDisplay, myWindow, myContext) != 0; 123 else 124 return true; 125 } 126 else 127 { 128 return false; 129 } 130} 131 132 133//////////////////////////////////////////////////////////// 134void GlxContext::Display() 135{ 136 if (myWindow) 137 glXSwapBuffers(myDisplay, myWindow); 138} 139 140 141//////////////////////////////////////////////////////////// 142void GlxContext::UseVerticalSync(bool enabled) 143{ 144 const GLubyte* name = reinterpret_cast<const GLubyte*>("glXSwapIntervalSGI"); 145 PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = reinterpret_cast<PFNGLXSWAPINTERVALSGIPROC>(glXGetProcAddress(name)); 146 if (glXSwapIntervalSGI) 147 glXSwapIntervalSGI(enabled ? 1 : 0); 148} 149 150 151//////////////////////////////////////////////////////////// 152void GlxContext::CreateContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) 153{ 154 // Save the creation settings 155 mySettings = settings; 156 157 // Get the attributes of the target window 158 XWindowAttributes windowAttributes; 159 if (XGetWindowAttributes(myDisplay, myWindow, &windowAttributes) == 0) 160 { 161 Err() << "Failed to get the window attributes" << std::endl; 162 return; 163 } 164 165 // Setup the visual infos to match 166 XVisualInfo tpl; 167 tpl.depth = windowAttributes.depth; 168 tpl.visualid = XVisualIDFromVisual(windowAttributes.visual); 169 tpl.screen = DefaultScreen(myDisplay); 170 171 // Get all the visuals matching the template 172 int nbVisuals = 0; 173 XVisualInfo* visuals = XGetVisualInfo(myDisplay, VisualDepthMask | VisualIDMask | VisualScreenMask, &tpl, &nbVisuals); 174 if (!visuals || (nbVisuals == 0)) 175 { 176 if (visuals) 177 XFree(visuals); 178 Err() << "There is no valid visual for the selected screen" << std::endl; 179 return; 180 } 181 182 // Find the best visual 183 int bestScore = 0xFFFF; 184 XVisualInfo* bestVisual = NULL; 185 for (int i = 0; i < nbVisuals; ++i) 186 { 187 // Get the current visual attributes 188 int RGBA, doubleBuffer, red, green, blue, alpha, depth, stencil, multiSampling, samples; 189 glXGetConfig(myDisplay, &visuals[i], GLX_RGBA, &RGBA); 190 glXGetConfig(myDisplay, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer); 191 glXGetConfig(myDisplay, &visuals[i], GLX_RED_SIZE, &red); 192 glXGetConfig(myDisplay, &visuals[i], GLX_GREEN_SIZE, &green); 193 glXGetConfig(myDisplay, &visuals[i], GLX_BLUE_SIZE, &blue); 194 glXGetConfig(myDisplay, &visuals[i], GLX_ALPHA_SIZE, &alpha); 195 glXGetConfig(myDisplay, &visuals[i], GLX_DEPTH_SIZE, &depth); 196 glXGetConfig(myDisplay, &visuals[i], GLX_STENCIL_SIZE, &stencil); 197 glXGetConfig(myDisplay, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling); 198 glXGetConfig(myDisplay, &visuals[i], GLX_SAMPLES_ARB, &samples); 199 200 // First check the mandatory parameters 201 if ((RGBA == 0) || (doubleBuffer == 0)) 202 continue; 203 204 // Evaluate the current configuration 205 int color = red + green + blue + alpha; 206 int score = EvaluateFormat(bitsPerPixel, mySettings, color, depth, stencil, multiSampling ? samples : 0); 207 208 // Keep it if it's better than the current best 209 if (score < bestScore) 210 { 211 bestScore = score; 212 bestVisual = &visuals[i]; 213 } 214 } 215 216 // Make sure that we have found a visual 217 if (!bestVisual) 218 { 219 Err() << "Failed to find a suitable pixel format for the window -- cannot create OpenGL context" << std::endl; 220 return; 221 } 222 223 // Get the context to share display lists with 224 GLXContext toShare = shared ? shared->myContext : NULL; 225 226 // Create the OpenGL context -- first try an OpenGL 3.0 context if it is requested 227 while (!myContext && (mySettings.MajorVersion >= 3)) 228 { 229 const GLubyte* name = reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB"); 230 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddress(name)); 231 if (glXCreateContextAttribsARB) 232 { 233 int nbConfigs = 0; 234 GLXFBConfig* configs = glXChooseFBConfig(myDisplay, DefaultScreen(myDisplay), NULL, &nbConfigs); 235 if (configs && nbConfigs) 236 { 237 // Create the context 238 int attributes[] = 239 { 240 GLX_CONTEXT_MAJOR_VERSION_ARB, mySettings.MajorVersion, 241 GLX_CONTEXT_MINOR_VERSION_ARB, mySettings.MinorVersion, 242 GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 243 0, 0 244 }; 245 myContext = glXCreateContextAttribsARB(myDisplay, configs[0], toShare, true, attributes); 246 } 247 248 if (configs) 249 XFree(configs); 250 } 251 252 // If we couldn't create an OpenGL 3 context, adjust the settings 253 if (!myContext) 254 { 255 if (mySettings.MinorVersion > 0) 256 { 257 // If the minor version is not 0, we decrease it and try again 258 mySettings.MinorVersion--; 259 } 260 else 261 { 262 // If the minor version is 0, we decrease the major version and stop with 3.x contexts 263 mySettings.MajorVersion = 2; 264 } 265 } 266 } 267 268 // If the OpenGL 3.0 context failed or if we don't want one, create a regular OpenGL 1.x/2.x context 269 if (!myContext) 270 { 271 myContext = glXCreateContext(myDisplay, bestVisual, toShare, true); 272 if (!myContext) 273 { 274 Err() << "Failed to create an OpenGL context for this window" << std::endl; 275 return; 276 } 277 } 278 279 // Update the creation settings from the chosen format 280 int depth, stencil, multiSampling, samples; 281 glXGetConfig(myDisplay, bestVisual, GLX_DEPTH_SIZE, &depth); 282 glXGetConfig(myDisplay, bestVisual, GLX_STENCIL_SIZE, &stencil); 283 glXGetConfig(myDisplay, bestVisual, GLX_SAMPLE_BUFFERS_ARB, &multiSampling); 284 glXGetConfig(myDisplay, bestVisual, GLX_SAMPLES_ARB, &samples); 285 mySettings.DepthBits = static_cast<unsigned int>(depth); 286 mySettings.StencilBits = static_cast<unsigned int>(stencil); 287 mySettings.AntialiasingLevel = multiSampling ? samples : 0; 288 289 // Change the target window's colormap so that it matches the context's one 290 ::Window root = RootWindow(myDisplay, DefaultScreen(myDisplay)); 291 Colormap colorMap = XCreateColormap(myDisplay, root, bestVisual->visual, AllocNone); 292 XSetWindowColormap(myDisplay, myWindow, colorMap); 293 294 // Free the temporary visuals array 295 XFree(visuals); 296} 297 298} // namespace priv 299 300} // namespace sf