BsLinuxGLSupport.cpp 8.0 KB

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