gl-x11.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /******************************************************************************
  2. Copyright (C) 2014 by Zachary Lund <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include <X11/Xlib.h>
  15. #include <stdio.h>
  16. #include "gl-subsystem.h"
  17. #include "GL/glx_obs.h"
  18. static const int fb_attribs[] = {
  19. /* Hardcoded for now... */
  20. GLX_STENCIL_SIZE, 8,
  21. GLX_DEPTH_SIZE, 24,
  22. GLX_BUFFER_SIZE, 32, /* Color buffer depth */
  23. GLX_DOUBLEBUFFER, True,
  24. GLX_X_RENDERABLE, True,
  25. GLX_RENDER_TYPE, GLX_RGBA_BIT,
  26. None
  27. };
  28. static const int ctx_attribs[] = {
  29. #ifdef _DEBUG
  30. GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
  31. #endif
  32. GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
  33. None,
  34. };
  35. struct gl_windowinfo {
  36. Display *display;
  37. uint32_t id;
  38. uint32_t int_id;
  39. uint32_t glxid;
  40. };
  41. struct gl_platform {
  42. GLXContext context;
  43. GLXFBConfig fbcfg;
  44. struct gs_swap_chain swap;
  45. };
  46. extern struct gs_swap_chain *gl_platform_getswap(struct gl_platform *platform)
  47. {
  48. return &platform->swap;
  49. }
  50. extern struct gl_windowinfo *gl_windowinfo_create(struct gs_init_data *info)
  51. {
  52. struct gl_windowinfo *wi = bzalloc(sizeof(struct gl_windowinfo));
  53. wi->id = info->window.id;
  54. wi->display = info->window.display;
  55. return wi;
  56. }
  57. extern void gl_windowinfo_destroy(struct gl_windowinfo *wi)
  58. {
  59. bfree(wi);
  60. }
  61. extern void gl_getclientsize(struct gs_swap_chain *swap,
  62. uint32_t *width, uint32_t *height)
  63. {
  64. XWindowAttributes info = { 0 };
  65. XGetWindowAttributes(swap->wi->display, swap->wi->id, &info);
  66. *height = info.height;
  67. *width = info.width;
  68. }
  69. static void print_info_stuff(struct gs_init_data *info)
  70. {
  71. blog( LOG_INFO,
  72. "X and Y: %i %i\n"
  73. "Backbuffers: %i\n"
  74. "Color Format: %i\n"
  75. "ZStencil Format: %i\n"
  76. "Adapter: %i\n",
  77. info->cx, info->cy,
  78. info->num_backbuffers,
  79. info->format, info->zsformat,
  80. info->adapter
  81. );
  82. }
  83. int wait_for_notify(Display *dpy, XEvent *e, char *arg)
  84. {
  85. UNUSED_PARAMETER(dpy);
  86. return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
  87. }
  88. static bool got_x_error = false;
  89. static int err_handler(Display *disp, XErrorEvent *e)
  90. {
  91. char estr[128];
  92. XGetErrorText(disp, e->error_code, estr, 128);
  93. blog(LOG_DEBUG, "Got X error: %s", estr);
  94. got_x_error = true;
  95. return 0;
  96. }
  97. static bool handle_x_error(Display *disp, const char *error_string)
  98. {
  99. XSync(disp, 0);
  100. if(got_x_error)
  101. {
  102. if(error_string)
  103. blog(LOG_ERROR, "%s", error_string);
  104. got_x_error = false;
  105. return true;
  106. }
  107. return false;
  108. }
  109. struct gl_platform *gl_platform_create(device_t device,
  110. struct gs_init_data *info)
  111. {
  112. int num_configs = 0;
  113. int error_base = 0, event_base = 0;
  114. Display *display = info->window.display;
  115. struct gl_platform *plat = bzalloc(sizeof(struct gl_platform));
  116. GLXFBConfig* configs;
  117. XWindowAttributes attrs;
  118. int screen;
  119. print_info_stuff(info);
  120. if (!display) {
  121. blog(LOG_ERROR, "Unable to find display. DISPLAY variable "
  122. "may not be set correctly.");
  123. goto fail0;
  124. }
  125. if(!XGetWindowAttributes(display, info->window.id, &attrs))
  126. {
  127. blog(LOG_ERROR, "Failed getting window attributes");
  128. goto fail0;
  129. }
  130. screen = XScreenNumberOfScreen(attrs.screen);
  131. if (!glx_LoadFunctions(display, screen)) {
  132. blog(LOG_ERROR, "Unable to load GLX entry functions.");
  133. goto fail0;
  134. }
  135. if (!glXQueryExtension(display, &error_base, &event_base)) {
  136. blog(LOG_ERROR, "GLX not supported.");
  137. goto fail0;
  138. }
  139. /* We require glX version 1.3 */
  140. {
  141. int major = 0, minor = 0;
  142. glXQueryVersion(display, &major, &minor);
  143. if (major < 1 || (major == 1 && minor < 3)) {
  144. blog(LOG_ERROR, "GLX version found: %i.%i\nRequired: "
  145. "1.3", major, minor);
  146. goto fail0;
  147. }
  148. }
  149. if (!glx_ext_ARB_create_context) {
  150. blog(LOG_ERROR, "ARB_GLX_create_context not supported!");
  151. goto fail0;
  152. }
  153. configs = glXChooseFBConfig(display, screen,
  154. fb_attribs, &num_configs);
  155. if(!configs) {
  156. blog(LOG_ERROR, "Attribute list or screen is invalid.");
  157. goto fail0;
  158. }
  159. if(num_configs == 0) {
  160. XFree(configs);
  161. blog(LOG_ERROR, "No framebuffer configurations found.");
  162. goto fail0;
  163. }
  164. plat->fbcfg = configs[0];
  165. XFree(configs);
  166. handle_x_error(display, NULL);
  167. /* We just use the first configuration found... as it does everything
  168. * we want at the very least. */
  169. plat->context = glXCreateContextAttribsARB(display, plat->fbcfg, NULL,
  170. True, ctx_attribs);
  171. if(!plat->context) {
  172. blog(LOG_ERROR, "Failed to create OpenGL context.");
  173. goto fail0;
  174. }
  175. if(handle_x_error(display, "Failed to create OpenGL context."))
  176. goto fail2;
  177. device->plat = plat;
  178. plat->swap.device = device;
  179. plat->swap.info.window.id = info->window.id;
  180. plat->swap.info.window.display = display;
  181. plat->swap.info.format = GS_RGBA;
  182. plat->swap.info.zsformat = GS_Z24_S8;
  183. plat->swap.info.num_backbuffers = 1;
  184. plat->swap.info.adapter = info->adapter;
  185. plat->swap.info.cx = attrs.width;
  186. plat->swap.info.cy = attrs.height;
  187. plat->swap.wi = gl_windowinfo_create(info);
  188. if(!gl_platform_init_swapchain(&plat->swap))
  189. goto fail2;
  190. if(!glXMakeCurrent(display, plat->swap.wi->glxid, plat->context)) {
  191. blog(LOG_ERROR, "Failed to make context current.");
  192. goto fail2;
  193. }
  194. if (!ogl_LoadFunctions()) {
  195. blog(LOG_ERROR, "Failed to load OpenGL entry functions.");
  196. goto fail2;
  197. }
  198. blog(LOG_INFO, "OpenGL version: %s\n", glGetString(GL_VERSION));
  199. /* We assume later that cur_swap is already set. */
  200. device->cur_swap = &plat->swap;
  201. XSync(display, False);
  202. blog(LOG_INFO, "Created new platform data");
  203. return plat;
  204. fail2:
  205. glXMakeCurrent(display, None, NULL);
  206. glXDestroyContext(display, plat->context);
  207. gl_platform_cleanup_swapchain(&plat->swap);
  208. fail0:
  209. bfree(plat);
  210. device->plat = 0;
  211. return NULL;
  212. }
  213. void gl_platform_destroy(struct gl_platform *platform)
  214. {
  215. if (!platform)
  216. return;
  217. Display *dpy = platform->swap.wi->display;
  218. glXMakeCurrent(dpy, None, NULL);
  219. glXDestroyContext(dpy, platform->context);
  220. gl_windowinfo_destroy(platform->swap.wi);
  221. gl_platform_cleanup_swapchain(&platform->swap);
  222. bfree(platform);
  223. }
  224. bool gl_platform_init_swapchain(struct gs_swap_chain *swap)
  225. {
  226. Display *display = swap->wi->display;
  227. struct gl_windowinfo *info = swap->wi;
  228. struct gl_platform *plat = swap->device->plat;
  229. XVisualInfo *vi = 0;
  230. Colormap cmap = 0;
  231. XSetWindowAttributes swa;
  232. XWindowAttributes attrs;
  233. XErrorHandler phandler = XSetErrorHandler(err_handler);
  234. gl_platform_cleanup_swapchain(swap);
  235. if(!XGetWindowAttributes(display, info->id, &attrs))
  236. {
  237. blog(LOG_ERROR, "Failed getting window attributes");
  238. goto fail;
  239. }
  240. vi = glXGetVisualFromFBConfig(display, plat->fbcfg);
  241. if(handle_x_error(display, "Failed to get visual from fb config."))
  242. goto fail;
  243. cmap = XCreateColormap(display, info->id, vi->visual, AllocNone);
  244. if(handle_x_error(display, "Failed creating colormap"))
  245. goto fail;
  246. swa.colormap = cmap;
  247. swa.border_pixel = 0;
  248. info->int_id = XCreateWindow(display, info->id, 0, 0,
  249. attrs.width, attrs.height,
  250. 0, 24, InputOutput, vi->visual,
  251. CWBorderPixel|CWColormap, &swa);
  252. XMapWindow(display, info->int_id);
  253. if(handle_x_error(display, "Failed creating intermediate X window"))
  254. goto fail;
  255. info->glxid = glXCreateWindow(display, plat->fbcfg, info->int_id, 0);
  256. if(handle_x_error(display, "Failed creating intermediate GLX window"))
  257. goto fail;
  258. XFreeColormap(display, cmap);
  259. XFree(vi);
  260. return true;
  261. fail:
  262. gl_platform_cleanup_swapchain(swap);
  263. if(cmap)
  264. XFreeColormap(display, cmap);
  265. if(vi)
  266. XFree(vi);
  267. XSetErrorHandler(phandler);
  268. return false;
  269. }
  270. void gl_platform_cleanup_swapchain(struct gs_swap_chain *swap)
  271. {
  272. Display *display = swap->wi->display;
  273. struct gl_windowinfo *info = swap->wi;
  274. if(!info)
  275. return;
  276. if(info->glxid)
  277. glXDestroyWindow(display, info->glxid);
  278. if(info->int_id)
  279. XDestroyWindow(display, info->int_id);
  280. info->glxid = 0;
  281. info->int_id = 0;
  282. }
  283. void device_entercontext(device_t device)
  284. {
  285. GLXContext context = device->plat->context;
  286. XID window = device->cur_swap->wi->glxid;
  287. Display *display = device->cur_swap->wi->display;
  288. if (!glXMakeCurrent(display, window, context)) {
  289. blog(LOG_ERROR, "Failed to make context current.");
  290. }
  291. }
  292. void device_leavecontext(device_t device)
  293. {
  294. Display *display = device->cur_swap->wi->display;
  295. if(!glXMakeCurrent(display, None, NULL)) {
  296. blog(LOG_ERROR, "Failed to reset current context.");
  297. }
  298. }
  299. void gl_update(device_t device)
  300. {
  301. Display *display = device->cur_swap->wi->display;
  302. XID window = device->cur_swap->wi->int_id;
  303. XResizeWindow(display, window,
  304. device->cur_swap->info.cx, device->cur_swap->info.cy);
  305. }
  306. void device_load_swapchain(device_t device, swapchain_t swap)
  307. {
  308. if(!swap)
  309. swap = &device->plat->swap;
  310. if (device->cur_swap == swap)
  311. return;
  312. Display *dpy = swap->wi->display;
  313. XID window = swap->wi->glxid;
  314. GLXContext ctx = device->plat->context;
  315. device->cur_swap = swap;
  316. if (!glXMakeCurrent(dpy, window, ctx)) {
  317. blog(LOG_ERROR, "Failed to make context current.");
  318. }
  319. }
  320. void device_present(device_t device)
  321. {
  322. Display *display = device->cur_swap->wi->display;
  323. XID window = device->cur_swap->wi->glxid;
  324. glXSwapBuffers(display, window);
  325. }