glx.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "os/osDlibrary.h"
  23. #include "os/osLog.h"
  24. #include "util/utilArray.h"
  25. #include "glx.h"
  26. namespace GL
  27. {
  28. using namespace Torque;
  29. using namespace GL;
  30. extern bool gglBindCoreFunctions(DLibrary* dll,GLXExtensionPtrs*);
  31. void gglBindGLX(::Display* display,int screen,GLXExtensionFlags* glx);
  32. bool gglBindExtensions(GLExtensionFlags* gl);
  33. struct GGLContext;
  34. //-----------------------------------------------------------------------------
  35. // The OpenGL DLL is shared by all the devices.
  36. static DLibraryRef _hGL;
  37. // Unlike WGL, GLX does not require a set of function pointers per
  38. // context pixel format. All functions in the DLL are bound in a single
  39. // table and shared by all contexts.
  40. static GLXExtensionPtrs _LibraryFunctions;
  41. //-----------------------------------------------------------------------------
  42. struct GGLDisplay: public _GLDisplay
  43. {
  44. ::Display* display;
  45. int screen;
  46. GLXExtensionFlags glx; // GLX extension flags
  47. Array<GGLContext*> contextList;
  48. };
  49. #define _hasGLXExtension(display,name) (display->glx.has_##name)
  50. GLDisplay gglCreateDisplay(::Display* display,int screen)
  51. {
  52. // Load and bind DLL functions
  53. if (!_hGL) {
  54. static LogCategory log("/Gfx/Device/GL");
  55. _hGL = LoadLibrary("libGL.so");
  56. if (!_hGL) {
  57. log.print("GLDevice: OpenGL dll failed to load");
  58. return false;
  59. }
  60. if (!gglBindCoreFunctions(_hGL.ptr(),&_LibraryFunctions)) {
  61. log.print("GLDevice: Failed to bind all core functions");
  62. return false;
  63. }
  64. _GGLptr = &_LibraryFunctions;
  65. log.print("OpenGL library loaded");
  66. }
  67. //
  68. GGLDisplay* dp = new GGLDisplay;
  69. dp->display = display;
  70. dp->screen = screen;
  71. gglBindGLX(display,screen,&dp->glx);
  72. return dp;
  73. }
  74. void gglDeleteDisplay(GLDisplay dp)
  75. {
  76. GGLDisplay* display = (GGLDisplay*)dp;
  77. Assert(!display->contextList.size(),"gglDeleteDisplay: Not all context destroyed");
  78. delete display;
  79. }
  80. //-----------------------------------------------------------------------------
  81. struct GGLFormat: public _GLFormat {
  82. GLFormatInfo mode;
  83. U32 pformat;
  84. };
  85. static bool _getFBConfig(GGLDisplay* display,U32 pformat,GLXFBConfig& config)
  86. {
  87. // Get config info from format ID
  88. int attributes[] = { GLX_FBCONFIG_ID, pformat, None };
  89. int count = 0;
  90. GLXFBConfig* configList = glXChooseFBConfig(display->display,
  91. display->screen,attributes,&count);
  92. if (!count)
  93. return false;
  94. config = *configList;
  95. XFree(configList);
  96. return true;
  97. }
  98. GLFormat gglSelectFormat(GLDisplay dp,GLFormatInfo& mode)
  99. {
  100. GGLDisplay* display = (GGLDisplay*)dp;
  101. U32 pformat;
  102. if (!_hasGLXExtension(display,GLX_VERSION_1_3)) {
  103. // Find GL compatible X visual using 1.2 interface.
  104. // 1.2 or earlier does not include pbuffer support.
  105. if (mode.target != GLFormatInfo::Window)
  106. return 0;
  107. int attributes[] = {
  108. GLX_RGBA,
  109. GLX_RED_SIZE, mode.red,
  110. GLX_BLUE_SIZE, mode.blue,
  111. GLX_GREEN_SIZE, mode.green,
  112. GLX_DEPTH_SIZE, mode.z,
  113. GLX_ALPHA_SIZE, mode.alpha,
  114. GLX_STENCIL_SIZE, mode.stencil,
  115. GLX_DOUBLEBUFFER, true,
  116. GLX_DOUBLEBUFFER,
  117. None
  118. };
  119. XVisualInfo* visual = glXChooseVisual(display->display, display->screen, attributes);
  120. if (!visual) {
  121. static LogCategory log("/Gfx/Device/GL");
  122. log.print("GGLContext: Could not get an accelerated visual");
  123. return 0;
  124. }
  125. pformat = visual->visualid;
  126. XFree(visual);
  127. }
  128. else {
  129. // Find GL compatible X visual using 1.3 interface.
  130. int attributes[] = {
  131. GLX_DRAWABLE_TYPE, (mode.target == GLFormatInfo::Buffer)?
  132. GLX_PBUFFER_BIT: GLX_WINDOW_BIT,
  133. GLX_RENDER_TYPE, GLX_RGBA_BIT,
  134. GLX_RED_SIZE, mode.red,
  135. GLX_BLUE_SIZE, mode.blue,
  136. GLX_GREEN_SIZE, mode.green,
  137. GLX_DEPTH_SIZE, mode.z,
  138. GLX_ALPHA_SIZE, mode.alpha,
  139. GLX_STENCIL_SIZE, mode.stencil,
  140. GLX_DOUBLEBUFFER, true,
  141. None
  142. };
  143. int count = 0;
  144. GLXFBConfig* configList = glXChooseFBConfig(display->display,
  145. display->screen,attributes,&count);
  146. if (!count)
  147. return 0;
  148. // Return the config ID
  149. int xid;
  150. glXGetFBConfigAttrib(display->display,configList[0],GLX_FBCONFIG_ID,&xid);
  151. XFree(configList);
  152. pformat = xid;
  153. }
  154. if (pformat) {
  155. GGLFormat* format = new GGLFormat;
  156. format->pformat = pformat;
  157. format->mode = mode;
  158. return format;
  159. }
  160. return 0;
  161. }
  162. bool gglFormatInfo(GLDisplay display,GLFormat pformat,GLFormatInfo& mode)
  163. {
  164. return 0;
  165. }
  166. bool gglAreCompatible(GLFormat,GLFormat)
  167. {
  168. return false;
  169. }
  170. void gglDeleteFormat(GLFormat fp)
  171. {
  172. GGLFormat* format = (GGLFormat*)fp;
  173. delete format;
  174. }
  175. XVisualInfo* gglGetFormatVisual(GLDisplay dp,GLFormat fp)
  176. {
  177. GGLDisplay* display = (GGLDisplay*)dp;
  178. GGLFormat* format = (GGLFormat*)fp;
  179. if (!_hasGLXExtension(display,GLX_VERSION_1_3)) {
  180. // Format is a visual id
  181. int count;
  182. XVisualInfo match;
  183. match.visualid = format->pformat;
  184. return XGetVisualInfo(display->display,VisualIDMask,&match,&count);
  185. }
  186. else {
  187. // Format is an FBConfig id
  188. GLXFBConfig config;
  189. if (!_getFBConfig(display,format->pformat,config))
  190. return 0;
  191. return glXGetVisualFromFBConfig(display->display,config);
  192. }
  193. }
  194. //-----------------------------------------------------------------------------
  195. struct GGLSurface: public _GLSurface {
  196. enum Type {
  197. Window, PBuffer,
  198. } type;
  199. GGLDisplay* display;
  200. GLXDrawable drawable; // Used with GLX 1.3 interface
  201. ::Window window; // Used with GLX 1.2 interface
  202. };
  203. GLSurface gglCreateSurface(GLDisplay dp,::Window hwin,GLFormat fp)
  204. {
  205. GGLDisplay* display = (GGLDisplay*)dp;
  206. GGLFormat* format = (GGLFormat*)fp;
  207. GGLSurface* surface = 0;
  208. if (!_hasGLXExtension(display,GLX_VERSION_1_3)) {
  209. // Return our own GGL surface rep.
  210. surface = new GGLSurface;
  211. surface->type = GGLSurface::Window;
  212. surface->display = display;
  213. surface->drawable = 0;
  214. surface->window = hwin;
  215. }
  216. else {
  217. // Get config info from format ID
  218. GLXFBConfig config;
  219. if (!_getFBConfig(display,format->pformat,config))
  220. return 0;
  221. // Create GLX window
  222. GLXWindow window = glXCreateWindow(display->display,config,hwin,0);
  223. if (!window) {
  224. GLenum error = glGetError();
  225. static LogCategory log("/Gfx/Device/GL");
  226. log.print(format("Create window error: %d",error));
  227. return 0;
  228. }
  229. // Return our own GGL surface rep.
  230. surface = new GGLSurface;
  231. surface->type = GGLSurface::Window;
  232. surface->display = display;
  233. surface->drawable = window;
  234. surface->window = 0;
  235. }
  236. return surface;
  237. }
  238. bool gglGetSurfaceSize(GLSurface sp,Vector2I& size)
  239. {
  240. GGLSurface* surface = (GGLSurface*)sp;
  241. if (surface->type != GGLSurface::Window)
  242. return false;
  243. if (!_hasGLXExtension(surface->display,GLX_VERSION_1_3)) {
  244. size.x = 300; size.y = 300;
  245. }
  246. else {
  247. glXQueryDrawable(surface->display->display,surface->drawable,
  248. GLX_WIDTH,(U32*)&size.x);
  249. glXQueryDrawable(surface->display->display,surface->drawable,
  250. GLX_HEIGHT,(U32*)&size.y);
  251. }
  252. return true;
  253. }
  254. void gglDeleteSurface(GLSurface sp)
  255. {
  256. GGLSurface* surface = (GGLSurface*)sp;
  257. if (surface->type = GGLSurface::Window) {
  258. glXDestroyWindow(surface->display->display,surface->drawable);
  259. delete surface;
  260. }
  261. }
  262. //-----------------------------------------------------------------------------
  263. struct GGLContext: public _GLContext
  264. {
  265. GGLDisplay* display;
  266. GLXContext context;
  267. GLExtensionFlags glf; // GL has extension flags
  268. };
  269. GLContext gglCreateContext(GLDisplay dp,GLFormat fp)
  270. {
  271. GGLDisplay* display = (GGLDisplay*)dp;
  272. GGLFormat* format = (GGLFormat*)fp;
  273. GGLContext* context = 0;
  274. GLXContext ctx,share = display->contextList.size()?
  275. display->contextList[0]->context: 0;
  276. if (!_hasGLXExtension(display,GLX_VERSION_1_3)) {
  277. // Get visual from format id.
  278. int count;
  279. XVisualInfo match;
  280. match.visualid = format->pformat;
  281. XVisualInfo* visual = XGetVisualInfo(display->display,VisualIDMask,&match,&count);
  282. ctx = glXCreateContext(display->display,visual,share,true);
  283. XFree(visual);
  284. }
  285. else {
  286. // Get FBConfig from format id
  287. GLXFBConfig config;
  288. if (!_getFBConfig(display,format->pformat,config))
  289. return 0;
  290. // Need to share contexts...
  291. ctx = glXCreateNewContext(display->display,config,
  292. GLX_RGBA_TYPE,share,true);
  293. }
  294. if (ctx) {
  295. context = new GGLContext;
  296. context->context = ctx;
  297. context->display = display;
  298. display->contextList.pushBack(context);
  299. return context;
  300. }
  301. return 0;
  302. }
  303. void gglDeleteContext(GLContext ctx)
  304. {
  305. GGLContext* context = (GGLContext*)ctx;
  306. glXDestroyContext(context->display->display,context->context);
  307. erase(context->display->contextList,context);
  308. delete context;
  309. }
  310. bool gglMakeCurrent(GLSurface sp,GLContext ctx)
  311. {
  312. GGLSurface* surface = (GGLSurface*)sp;
  313. GGLContext* context = (GGLContext*)ctx;
  314. if (!_hasGLXExtension(surface->display,GLX_VERSION_1_3)) {
  315. if (!glXMakeCurrent(surface->display->display,
  316. surface->window,context->context))
  317. return false;
  318. }
  319. else
  320. if (!glXMakeContextCurrent(surface->display->display,
  321. surface->drawable,surface->drawable,context->context))
  322. return false;
  323. // The first time a context is made current we need to
  324. // check which extensions are valid.
  325. if (!context->glf.bound)
  326. gglBindExtensions(&context->glf);
  327. _GGLflag = &context->glf;
  328. return true;
  329. }
  330. void gglSwapBuffers(GLSurface sp)
  331. {
  332. GGLSurface* surface = (GGLSurface*)sp;
  333. if (!_hasGLXExtension(surface->display,GLX_VERSION_1_3))
  334. glXSwapBuffers(surface->display->display,surface->window);
  335. else
  336. glXSwapBuffers(surface->display->display,surface->drawable);
  337. }
  338. //-----------------------------------------------------------------------------
  339. GLSurface gglCreatePBufferSurface(GLDisplay display,U32 width,U32 height,bool cubeMap,GLFormat pformat)
  340. {
  341. return 0;
  342. }
  343. bool gglBindPBufferSurface(GLSurface sp,U32 target)
  344. {
  345. return 0;
  346. }
  347. bool gglReleasePBufferSurface(GLSurface sp,U32 target)
  348. {
  349. return 0;
  350. }
  351. bool gglSetPbufferTarget(GLSurface sp,U32 mip,U32 face)
  352. {
  353. return 0;
  354. }
  355. } // Namespace