/extlibs/SFML/src/SFML/Window/Linux/GlxContext.cpp

https://bitbucket.org/hugoruscitti/pilascpp · 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. // Headers
  26. ////////////////////////////////////////////////////////////
  27. #define GLX_GLXEXT_LEGACY // so that our local glxext.h is used instead of the system one
  28. #include <SFML/Window/Linux/GlxContext.hpp>
  29. #include <SFML/Window/Linux/WindowImplX11.hpp>
  30. #include <SFML/OpenGL.hpp>
  31. #include <SFML/Window/glext/glxext.h>
  32. #include <SFML/System/Err.hpp>
  33. namespace sf
  34. {
  35. namespace priv
  36. {
  37. ////////////////////////////////////////////////////////////
  38. GlxContext::GlxContext(GlxContext* shared) :
  39. myWindow (0),
  40. myContext (NULL),
  41. myOwnsWindow(true)
  42. {
  43. // Open a connection with the X server
  44. myDisplay = XOpenDisplay(NULL);
  45. // Create a dummy window (disabled and hidden)
  46. int screen = DefaultScreen(myDisplay);
  47. myWindow = XCreateWindow(myDisplay,
  48. RootWindow(myDisplay, screen),
  49. 0, 0,
  50. 1, 1,
  51. 0,
  52. DefaultDepth(myDisplay, screen),
  53. InputOutput,
  54. DefaultVisual(myDisplay, screen),
  55. 0, NULL);
  56. // Create the context
  57. CreateContext(shared, VideoMode::GetDesktopMode().BitsPerPixel, ContextSettings(0, 0, 0));
  58. // Activate the context
  59. SetActive(true);
  60. }
  61. ////////////////////////////////////////////////////////////
  62. GlxContext::GlxContext(GlxContext* shared, const WindowImpl* owner, unsigned int bitsPerPixel, const ContextSettings& settings) :
  63. myWindow (0),
  64. myContext (NULL),
  65. myOwnsWindow(false)
  66. {
  67. // Use the same context as the owner window (important!)
  68. myDisplay = static_cast<const WindowImplX11*>(owner)->GetDisplay();
  69. // Get the owner window and its device context
  70. myWindow = static_cast<Window>(owner->GetSystemHandle());
  71. // Create the context
  72. if (myWindow)
  73. CreateContext(shared, bitsPerPixel, settings);
  74. // Activate the context
  75. SetActive(true);
  76. }
  77. ////////////////////////////////////////////////////////////
  78. GlxContext::~GlxContext()
  79. {
  80. // Destroy the context
  81. if (myContext)
  82. {
  83. if (glXGetCurrentContext() == myContext)
  84. glXMakeCurrent(myDisplay, None, NULL);
  85. glXDestroyContext(myDisplay, myContext);
  86. }
  87. // Destroy the window if we own it
  88. if (myWindow && myOwnsWindow)
  89. {
  90. XDestroyWindow(myDisplay, myWindow);
  91. XFlush(myDisplay);
  92. }
  93. // Close the connection with the X server
  94. if (myOwnsWindow)
  95. {
  96. XCloseDisplay(myDisplay);
  97. }
  98. }
  99. ////////////////////////////////////////////////////////////
  100. bool GlxContext::MakeCurrent()
  101. {
  102. if (myContext)
  103. {
  104. if (glXGetCurrentContext() != myContext)
  105. return glXMakeCurrent(myDisplay, myWindow, myContext) != 0;
  106. else
  107. return true;
  108. }
  109. else
  110. {
  111. return false;
  112. }
  113. }
  114. ////////////////////////////////////////////////////////////
  115. void GlxContext::Display()
  116. {
  117. if (myWindow)
  118. glXSwapBuffers(myDisplay, myWindow);
  119. }
  120. ////////////////////////////////////////////////////////////
  121. void GlxContext::UseVerticalSync(bool enabled)
  122. {
  123. const GLubyte* name = reinterpret_cast<const GLubyte*>("glXSwapIntervalSGI");
  124. PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = reinterpret_cast<PFNGLXSWAPINTERVALSGIPROC>(glXGetProcAddress(name));
  125. if (glXSwapIntervalSGI)
  126. glXSwapIntervalSGI(enabled ? 1 : 0);
  127. }
  128. ////////////////////////////////////////////////////////////
  129. void GlxContext::CreateContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings)
  130. {
  131. // Save the creation settings
  132. mySettings = settings;
  133. // Get the attributes of the target window
  134. XWindowAttributes windowAttributes;
  135. if (XGetWindowAttributes(myDisplay, myWindow, &windowAttributes) == 0)
  136. {
  137. Err() << "Failed to get the window attributes" << std::endl;
  138. return;
  139. }
  140. // Setup the visual infos to match
  141. XVisualInfo tpl;
  142. tpl.depth = windowAttributes.depth;
  143. tpl.visualid = XVisualIDFromVisual(windowAttributes.visual);
  144. tpl.screen = DefaultScreen(myDisplay);
  145. // Get all the visuals matching the template
  146. int nbVisuals = 0;
  147. XVisualInfo* visuals = XGetVisualInfo(myDisplay, VisualDepthMask | VisualIDMask | VisualScreenMask, &tpl, &nbVisuals);
  148. if (!visuals || (nbVisuals == 0))
  149. {
  150. if (visuals)
  151. XFree(visuals);
  152. Err() << "There is no valid visual for the selected screen" << std::endl;
  153. return;
  154. }
  155. // Find the best visual
  156. int bestScore = 0xFFFF;
  157. XVisualInfo* bestVisual = NULL;
  158. for (int i = 0; i < nbVisuals; ++i)
  159. {
  160. // Get the current visual attributes
  161. int RGBA, doubleBuffer, red, green, blue, alpha, depth, stencil, multiSampling, samples;
  162. glXGetConfig(myDisplay, &visuals[i], GLX_RGBA, &RGBA);
  163. glXGetConfig(myDisplay, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer);
  164. glXGetConfig(myDisplay, &visuals[i], GLX_RED_SIZE, &red);
  165. glXGetConfig(myDisplay, &visuals[i], GLX_GREEN_SIZE, &green);
  166. glXGetConfig(myDisplay, &visuals[i], GLX_BLUE_SIZE, &blue);
  167. glXGetConfig(myDisplay, &visuals[i], GLX_ALPHA_SIZE, &alpha);
  168. glXGetConfig(myDisplay, &visuals[i], GLX_DEPTH_SIZE, &depth);
  169. glXGetConfig(myDisplay, &visuals[i], GLX_STENCIL_SIZE, &stencil);
  170. glXGetConfig(myDisplay, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
  171. glXGetConfig(myDisplay, &visuals[i], GLX_SAMPLES_ARB, &samples);
  172. // First check the mandatory parameters
  173. if ((RGBA == 0) || (doubleBuffer == 0))
  174. continue;
  175. // Evaluate the current configuration
  176. int color = red + green + blue + alpha;
  177. int score = EvaluateFormat(bitsPerPixel, mySettings, color, depth, stencil, multiSampling ? samples : 0);
  178. // Keep it if it's better than the current best
  179. if (score < bestScore)
  180. {
  181. bestScore = score;
  182. bestVisual = &visuals[i];
  183. }
  184. }
  185. // Make sure that we have found a visual
  186. if (!bestVisual)
  187. {
  188. Err() << "Failed to find a suitable pixel format for the window -- cannot create OpenGL context" << std::endl;
  189. return;
  190. }
  191. // Get the context to share display lists with
  192. GLXContext toShare = shared ? shared->myContext : NULL;
  193. // Create the OpenGL context -- first try an OpenGL 3.0 context if it is requested
  194. while (!myContext && (mySettings.MajorVersion >= 3))
  195. {
  196. const GLubyte* name = reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB");
  197. PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddress(name));
  198. if (glXCreateContextAttribsARB)
  199. {
  200. int nbConfigs = 0;
  201. GLXFBConfig* configs = glXChooseFBConfig(myDisplay, DefaultScreen(myDisplay), NULL, &nbConfigs);
  202. if (configs && nbConfigs)
  203. {
  204. // Create the context
  205. int attributes[] =
  206. {
  207. GLX_CONTEXT_MAJOR_VERSION_ARB, mySettings.MajorVersion,
  208. GLX_CONTEXT_MINOR_VERSION_ARB, mySettings.MinorVersion,
  209. GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
  210. 0, 0
  211. };
  212. myContext = glXCreateContextAttribsARB(myDisplay, configs[0], toShare, true, attributes);
  213. }
  214. if (configs)
  215. XFree(configs);
  216. }
  217. // If we couldn't create an OpenGL 3 context, adjust the settings
  218. if (!myContext)
  219. {
  220. if (mySettings.MinorVersion > 0)
  221. {
  222. // If the minor version is not 0, we decrease it and try again
  223. mySettings.MinorVersion--;
  224. }
  225. else
  226. {
  227. // If the minor version is 0, we decrease the major version and stop with 3.x contexts
  228. mySettings.MajorVersion = 2;
  229. }
  230. }
  231. }
  232. // If the OpenGL 3.0 context failed or if we don't want one, create a regular OpenGL 1.x/2.x context
  233. if (!myContext)
  234. {
  235. myContext = glXCreateContext(myDisplay, bestVisual, toShare, true);
  236. if (!myContext)
  237. {
  238. Err() << "Failed to create an OpenGL context for this window" << std::endl;
  239. return;
  240. }
  241. }
  242. // Update the creation settings from the chosen format
  243. int depth, stencil, multiSampling, samples;
  244. glXGetConfig(myDisplay, bestVisual, GLX_DEPTH_SIZE, &depth);
  245. glXGetConfig(myDisplay, bestVisual, GLX_STENCIL_SIZE, &stencil);
  246. glXGetConfig(myDisplay, bestVisual, GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
  247. glXGetConfig(myDisplay, bestVisual, GLX_SAMPLES_ARB, &samples);
  248. mySettings.DepthBits = static_cast<unsigned int>(depth);
  249. mySettings.StencilBits = static_cast<unsigned int>(stencil);
  250. mySettings.AntialiasingLevel = multiSampling ? samples : 0;
  251. // Change the target window's colormap so that it matches the context's one
  252. ::Window root = RootWindow(myDisplay, DefaultScreen(myDisplay));
  253. Colormap colorMap = XCreateColormap(myDisplay, root, bestVisual->visual, AllocNone);
  254. XSetWindowColormap(myDisplay, myWindow, colorMap);
  255. // Free the temporary visuals array
  256. XFree(visuals);
  257. }
  258. } // namespace priv
  259. } // namespace sf