BsLinuxGLSupport.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Linux/BsLinuxPlatform.h"
  4. #include "Linux/BsLinuxGLSupport.h"
  5. #include "Linux/BsLinuxContext.h"
  6. #include "Linux/BsLinuxRenderWindow.h"
  7. #include "BsLinuxVideoModeInfo.h"
  8. #include "BsGLRenderAPI.h"
  9. namespace bs { namespace ct
  10. {
  11. bool extGLX_ARB_multisample = false;
  12. bool extGLX_ARB_framebuffer_sRGB = false;
  13. bool extGLX_EXT_framebuffer_sRGB = false;
  14. bool extGLX_ARB_create_context = false;
  15. bool extGLX_ARB_create_context_profile = false;
  16. bool extGLX_EXT_swap_control = false;
  17. bool extGLX_MESA_swap_control = false;
  18. bool extGLX_SGI_swap_control = false;
  19. typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
  20. glXCreateContextAttribsARBProc glXCreateContextAttribsARB = nullptr;
  21. bool Load_ARB_create_context()
  22. {
  23. glXCreateContextAttribsARB =
  24. (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
  25. return glXCreateContextAttribsARB != nullptr;
  26. }
  27. glXSwapIntervalEXTProc glXSwapIntervalEXT = nullptr;
  28. glXSwapIntervalMESAProc glXSwapIntervalMESA = nullptr;
  29. glXSwapIntervalSGIProc glXSwapIntervalSGI = nullptr;
  30. glXChooseFBConfigProc glXChooseFBConfig = nullptr;
  31. glXGetFBConfigAttribProc glXGetFBConfigAttrib = nullptr;
  32. glXGetVisualFromFBConfigProc glXGetVisualFromFBConfig = nullptr;
  33. bool Load_EXT_swap_control()
  34. {
  35. glXSwapIntervalEXT = (glXSwapIntervalEXTProc)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalEXT");
  36. return glXSwapIntervalEXT != nullptr;
  37. }
  38. bool Load_MESA_swap_control()
  39. {
  40. glXSwapIntervalMESA = (glXSwapIntervalMESAProc)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalMESA");
  41. return glXSwapIntervalMESA != nullptr;
  42. }
  43. bool Load_SGI_swap_control()
  44. {
  45. glXSwapIntervalSGI = (glXSwapIntervalSGIProc)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalSGI");
  46. return glXSwapIntervalSGI != nullptr;
  47. }
  48. typedef bool (*ExtensionFunc)(void);
  49. struct GLExtension
  50. {
  51. const char* name;
  52. bool* status;
  53. ExtensionFunc func;
  54. };
  55. static GLExtension gExtensionMap[] = {
  56. { "GLX_ARB_multisample", &extGLX_ARB_multisample, nullptr },
  57. { "GLX_ARB_framebuffer_sRGB", &extGLX_ARB_framebuffer_sRGB, nullptr },
  58. { "GLX_EXT_framebuffer_sRGB", &extGLX_EXT_framebuffer_sRGB, nullptr },
  59. { "GLX_ARB_create_context", &extGLX_ARB_create_context, Load_ARB_create_context },
  60. { "GLX_ARB_create_context_profile", &extGLX_ARB_create_context_profile, nullptr },
  61. { "GLX_EXT_swap_control", &extGLX_EXT_swap_control, Load_EXT_swap_control },
  62. { "GLX_MESA_swap_control", &extGLX_MESA_swap_control, Load_MESA_swap_control },
  63. { "GLX_SGI_swap_control", &extGLX_SGI_swap_control, Load_SGI_swap_control },
  64. };
  65. LinuxGLSupport::LinuxGLSupport()
  66. { }
  67. SPtr<bs::RenderWindow> LinuxGLSupport::newWindow(RENDER_WINDOW_DESC& desc, UINT32 windowId,
  68. SPtr<bs::RenderWindow> parentWindow)
  69. {
  70. if(parentWindow != nullptr)
  71. {
  72. ::Window x11window;
  73. parentWindow->getCustomAttribute("WINDOW", &x11window);
  74. desc.platformSpecific["parentWindowHandle"] = toString((UINT64)x11window);
  75. }
  76. bs::LinuxRenderWindow* window = new (bs_alloc<bs::LinuxRenderWindow>()) bs::LinuxRenderWindow(desc, windowId, *this);
  77. return SPtr<bs::RenderWindow>(window, &bs::CoreObject::_delete<bs::LinuxRenderWindow, GenAlloc>);
  78. }
  79. SPtr<RenderWindow> LinuxGLSupport::newWindowCore(RENDER_WINDOW_DESC& desc, UINT32 windowId)
  80. {
  81. LinuxRenderWindow* window = new (bs_alloc<LinuxRenderWindow>()) LinuxRenderWindow(desc, windowId, *this);
  82. return bs_shared_ptr<LinuxRenderWindow>(window);
  83. }
  84. void LinuxGLSupport::start()
  85. {
  86. // Retrieve all essential extensions
  87. LinuxPlatform::lockX();
  88. ::Display* display = LinuxPlatform::getXDisplay();
  89. const char* glExtensions = glXQueryExtensionsString(display, DefaultScreen(display));
  90. const char* iter = glExtensions;
  91. do
  92. {
  93. const char* start = iter;
  94. while(*iter != ' ' && *iter)
  95. iter++;
  96. const char* end = iter;
  97. std::string name(start, end);
  98. UINT32 numExtensions = sizeof(gExtensionMap) / sizeof(gExtensionMap[0]);
  99. for (UINT32 i = 0; i < numExtensions; ++i)
  100. {
  101. if(strcmp(name.c_str(), gExtensionMap[i].name) == 0)
  102. {
  103. if(gExtensionMap[i].status != nullptr)
  104. {
  105. if (gExtensionMap[i].func != nullptr)
  106. *gExtensionMap[i].status = gExtensionMap[i].func();
  107. else
  108. *gExtensionMap[i].status = true;
  109. }
  110. else
  111. {
  112. if (gExtensionMap[i].func != nullptr)
  113. gExtensionMap[i].func();
  114. }
  115. }
  116. }
  117. } while(*iter++);
  118. glXChooseFBConfig = (glXChooseFBConfigProc)glXGetProcAddressARB((const GLubyte*)"glXChooseFBConfig");
  119. glXGetFBConfigAttrib = (glXGetFBConfigAttribProc)glXGetProcAddressARB((const GLubyte*)"glXGetFBConfigAttrib");
  120. glXGetVisualFromFBConfig = (glXGetVisualFromFBConfigProc)glXGetProcAddressARB((const GLubyte*)"glXGetVisualFromFBConfig");
  121. LinuxPlatform::unlockX();
  122. }
  123. void LinuxGLSupport::stop()
  124. {
  125. // Do nothing
  126. }
  127. SPtr<LinuxContext> LinuxGLSupport::createContext(::Display* x11display, XVisualInfo& visualInfo)
  128. {
  129. GLRenderAPI* rapi = static_cast<GLRenderAPI*>(RenderAPI::instancePtr());
  130. // If RenderAPI has initialized a context use that, otherwise we create our own
  131. if (!rapi->_isContextInitialized())
  132. return bs_shared_ptr_new<LinuxContext>(x11display, visualInfo);
  133. else
  134. {
  135. SPtr<GLContext> context = rapi->getMainContext();
  136. context->setCurrent();
  137. return std::static_pointer_cast<LinuxContext>(context);
  138. }
  139. }
  140. void* LinuxGLSupport::getProcAddress(const String& procname)
  141. {
  142. return (void*)glXGetProcAddressARB((const GLubyte*)procname.c_str());
  143. }
  144. GLVisualConfig LinuxGLSupport::findBestVisual(::Display* display, bool depthStencil, UINT32 multisample, bool srgb) const
  145. {
  146. INT32 VISUAL_ATTRIBS[] =
  147. {
  148. GLX_X_RENDERABLE, True,
  149. GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
  150. GLX_RENDER_TYPE, GLX_RGBA_BIT,
  151. GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
  152. GLX_RED_SIZE, 8,
  153. GLX_GREEN_SIZE, 8,
  154. GLX_BLUE_SIZE, 8,
  155. GLX_ALPHA_SIZE, 8,
  156. GLX_DOUBLEBUFFER, True,
  157. GLX_DEPTH_SIZE, depthStencil ? 24 : 0,
  158. GLX_STENCIL_SIZE, depthStencil ? 8 : 0,
  159. GLX_SAMPLE_BUFFERS, multisample > 1 ? 1 : 0,
  160. 0
  161. };
  162. INT32 numConfigs;
  163. GLXFBConfig* configs = glXChooseFBConfig(display, DefaultScreen(display), VISUAL_ATTRIBS, &numConfigs);
  164. GLVisualCapabilities* caps = bs_stack_new<GLVisualCapabilities>(numConfigs);
  165. // Find a config that best matches the requested properties
  166. INT32 bestScore = 0;
  167. INT32 bestConfig = -1;
  168. for (int i = 0; i < numConfigs; ++i)
  169. {
  170. INT32 configScore = 0;
  171. // Depth buffer contributes the most to score
  172. INT32 depth, stencil;
  173. glXGetFBConfigAttrib(display, configs[i], GLX_DEPTH_SIZE, &depth);
  174. glXGetFBConfigAttrib(display, configs[i], GLX_STENCIL_SIZE, &stencil);
  175. // Depth buffer was requested
  176. if(depthStencil)
  177. {
  178. INT32 score = 0;
  179. if (depth == 24 && stencil == 8)
  180. score = 10000;
  181. else if (depth == 32 && stencil == 8)
  182. score = 9000;
  183. else if (depth == 32)
  184. score = 8000;
  185. else if (depth == 24)
  186. score = 7000;
  187. else if (depth == 16)
  188. score = 6000;
  189. if (score > 0)
  190. {
  191. configScore += score;
  192. caps[i].depthStencil = true;
  193. }
  194. }
  195. else // Depth buffer not requested, prefer configs without it
  196. {
  197. if(depth == 0 && stencil == 0)
  198. configScore += 10000;
  199. }
  200. // sRGB contributes second most
  201. if(srgb)
  202. {
  203. INT32 hasSRGB = 0;
  204. if(extGLX_EXT_framebuffer_sRGB)
  205. glXGetFBConfigAttrib(display, configs[i], GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, &hasSRGB);
  206. if(!hasSRGB && extGLX_ARB_framebuffer_sRGB)
  207. glXGetFBConfigAttrib(display, configs[i], GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, &hasSRGB);
  208. if(hasSRGB)
  209. {
  210. configScore += 500;
  211. caps[i].srgb = true;
  212. }
  213. }
  214. if((multisample >= 1) && extGLX_ARB_multisample)
  215. {
  216. INT32 hasMultisample, numSamples;
  217. glXGetFBConfigAttrib(display, configs[i], GLX_SAMPLE_BUFFERS, &hasMultisample);
  218. glXGetFBConfigAttrib(display, configs[i], GLX_SAMPLES, &numSamples);
  219. if(hasMultisample && (numSamples <= (INT32)multisample))
  220. {
  221. configScore += (32 - (multisample - numSamples)) * 10;
  222. caps[i].numSamples = (UINT32)numSamples;
  223. }
  224. }
  225. if(configScore > bestScore)
  226. {
  227. bestScore = configScore;
  228. bestConfig = i;
  229. }
  230. }
  231. GLVisualConfig output;
  232. if(bestConfig == -1)
  233. {
  234. if(numConfigs > 0)
  235. bestConfig = 0;
  236. else
  237. {
  238. // Something went wrong
  239. XFree(configs);
  240. bs_stack_delete(caps, (UINT32) numConfigs);
  241. return output;
  242. }
  243. }
  244. XVisualInfo* visualInfo = glXGetVisualFromFBConfig(display, configs[bestConfig]);
  245. output.visualInfo = *visualInfo;
  246. output.caps = caps[bestConfig];
  247. XFree(configs);
  248. XFree(visualInfo);
  249. bs_stack_delete(caps, numConfigs);
  250. return output;
  251. }
  252. SPtr<VideoModeInfo> LinuxGLSupport::getVideoModeInfo() const
  253. {
  254. return bs_shared_ptr_new<LinuxVideoModeInfo>();
  255. }
  256. }}