gtk-egl.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /*
  2. * GTK UI -- egl opengl code.
  3. *
  4. * Note that gtk 3.16+ (released 2015-03-23) has a GtkGLArea widget,
  5. * which is GtkDrawingArea like widget with opengl rendering support.
  6. *
  7. * This code handles opengl support on older gtk versions, using egl
  8. * to get a opengl context for the X11 window.
  9. *
  10. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  11. * See the COPYING file in the top-level directory.
  12. */
  13. #include "qemu/osdep.h"
  14. #include "trace.h"
  15. #include "ui/console.h"
  16. #include "ui/gtk.h"
  17. #include "ui/egl-helpers.h"
  18. #include "ui/shader.h"
  19. #include "sysemu/sysemu.h"
  20. static void gtk_egl_set_scanout_mode(VirtualConsole *vc, bool scanout)
  21. {
  22. if (vc->gfx.scanout_mode == scanout) {
  23. return;
  24. }
  25. vc->gfx.scanout_mode = scanout;
  26. if (!vc->gfx.scanout_mode) {
  27. egl_fb_destroy(&vc->gfx.guest_fb);
  28. if (vc->gfx.surface) {
  29. surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
  30. surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
  31. }
  32. }
  33. }
  34. /** DisplayState Callbacks (opengl version) **/
  35. void gd_egl_init(VirtualConsole *vc)
  36. {
  37. GdkWindow *gdk_window = gtk_widget_get_window(vc->gfx.drawing_area);
  38. if (!gdk_window) {
  39. return;
  40. }
  41. Window x11_window = gdk_x11_window_get_xid(gdk_window);
  42. if (!x11_window) {
  43. return;
  44. }
  45. vc->gfx.ectx = qemu_egl_init_ctx();
  46. vc->gfx.esurface = qemu_egl_init_surface_x11
  47. (vc->gfx.ectx, (EGLNativeWindowType)x11_window);
  48. assert(vc->gfx.esurface);
  49. }
  50. void gd_egl_draw(VirtualConsole *vc)
  51. {
  52. GdkWindow *window;
  53. int ww, wh;
  54. if (!vc->gfx.gls) {
  55. return;
  56. }
  57. window = gtk_widget_get_window(vc->gfx.drawing_area);
  58. ww = gdk_window_get_width(window);
  59. wh = gdk_window_get_height(window);
  60. if (vc->gfx.scanout_mode) {
  61. gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h);
  62. vc->gfx.scale_x = (double)ww / vc->gfx.w;
  63. vc->gfx.scale_y = (double)wh / vc->gfx.h;
  64. } else {
  65. if (!vc->gfx.ds) {
  66. return;
  67. }
  68. eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
  69. vc->gfx.esurface, vc->gfx.ectx);
  70. surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
  71. surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
  72. eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
  73. vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds);
  74. vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.ds);
  75. }
  76. }
  77. void gd_egl_update(DisplayChangeListener *dcl,
  78. int x, int y, int w, int h)
  79. {
  80. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  81. if (!vc->gfx.gls || !vc->gfx.ds) {
  82. return;
  83. }
  84. eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
  85. vc->gfx.esurface, vc->gfx.ectx);
  86. surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h);
  87. vc->gfx.glupdates++;
  88. }
  89. void gd_egl_refresh(DisplayChangeListener *dcl)
  90. {
  91. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  92. if (!vc->gfx.esurface) {
  93. gd_egl_init(vc);
  94. if (!vc->gfx.esurface) {
  95. return;
  96. }
  97. vc->gfx.gls = qemu_gl_init_shader();
  98. if (vc->gfx.ds) {
  99. surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
  100. }
  101. }
  102. graphic_hw_update(dcl->con);
  103. if (vc->gfx.glupdates) {
  104. vc->gfx.glupdates = 0;
  105. gtk_egl_set_scanout_mode(vc, false);
  106. gd_egl_draw(vc);
  107. }
  108. }
  109. void gd_egl_switch(DisplayChangeListener *dcl,
  110. DisplaySurface *surface)
  111. {
  112. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  113. bool resized = true;
  114. trace_gd_switch(vc->label, surface_width(surface), surface_height(surface));
  115. if (vc->gfx.ds &&
  116. surface_width(vc->gfx.ds) == surface_width(surface) &&
  117. surface_height(vc->gfx.ds) == surface_height(surface)) {
  118. resized = false;
  119. }
  120. surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
  121. vc->gfx.ds = surface;
  122. if (vc->gfx.gls) {
  123. surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
  124. }
  125. if (resized) {
  126. gd_update_windowsize(vc);
  127. }
  128. }
  129. QEMUGLContext gd_egl_create_context(DisplayChangeListener *dcl,
  130. QEMUGLParams *params)
  131. {
  132. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  133. eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
  134. vc->gfx.esurface, vc->gfx.ectx);
  135. return qemu_egl_create_context(dcl, params);
  136. }
  137. void gd_egl_scanout_disable(DisplayChangeListener *dcl)
  138. {
  139. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  140. vc->gfx.w = 0;
  141. vc->gfx.h = 0;
  142. gtk_egl_set_scanout_mode(vc, false);
  143. }
  144. void gd_egl_scanout_texture(DisplayChangeListener *dcl,
  145. uint32_t backing_id, bool backing_y_0_top,
  146. uint32_t backing_width, uint32_t backing_height,
  147. uint32_t x, uint32_t y,
  148. uint32_t w, uint32_t h)
  149. {
  150. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  151. vc->gfx.x = x;
  152. vc->gfx.y = y;
  153. vc->gfx.w = w;
  154. vc->gfx.h = h;
  155. vc->gfx.y0_top = backing_y_0_top;
  156. eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
  157. vc->gfx.esurface, vc->gfx.ectx);
  158. gtk_egl_set_scanout_mode(vc, true);
  159. egl_fb_setup_for_tex(&vc->gfx.guest_fb, backing_width, backing_height,
  160. backing_id, false);
  161. }
  162. void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
  163. QemuDmaBuf *dmabuf)
  164. {
  165. #ifdef CONFIG_OPENGL_DMABUF
  166. egl_dmabuf_import_texture(dmabuf);
  167. if (!dmabuf->texture) {
  168. return;
  169. }
  170. gd_egl_scanout_texture(dcl, dmabuf->texture,
  171. false, dmabuf->width, dmabuf->height,
  172. 0, 0, dmabuf->width, dmabuf->height);
  173. #endif
  174. }
  175. void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl,
  176. QemuDmaBuf *dmabuf, bool have_hot,
  177. uint32_t hot_x, uint32_t hot_y)
  178. {
  179. #ifdef CONFIG_OPENGL_DMABUF
  180. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  181. if (dmabuf) {
  182. egl_dmabuf_import_texture(dmabuf);
  183. if (!dmabuf->texture) {
  184. return;
  185. }
  186. egl_fb_setup_for_tex(&vc->gfx.cursor_fb, dmabuf->width, dmabuf->height,
  187. dmabuf->texture, false);
  188. } else {
  189. egl_fb_destroy(&vc->gfx.cursor_fb);
  190. }
  191. #endif
  192. }
  193. void gd_egl_cursor_position(DisplayChangeListener *dcl,
  194. uint32_t pos_x, uint32_t pos_y)
  195. {
  196. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  197. vc->gfx.cursor_x = pos_x * vc->gfx.scale_x;
  198. vc->gfx.cursor_y = pos_y * vc->gfx.scale_y;
  199. }
  200. void gd_egl_release_dmabuf(DisplayChangeListener *dcl,
  201. QemuDmaBuf *dmabuf)
  202. {
  203. #ifdef CONFIG_OPENGL_DMABUF
  204. egl_dmabuf_release_texture(dmabuf);
  205. #endif
  206. }
  207. void gd_egl_scanout_flush(DisplayChangeListener *dcl,
  208. uint32_t x, uint32_t y, uint32_t w, uint32_t h)
  209. {
  210. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  211. GdkWindow *window;
  212. int ww, wh;
  213. if (!vc->gfx.scanout_mode) {
  214. return;
  215. }
  216. if (!vc->gfx.guest_fb.framebuffer) {
  217. return;
  218. }
  219. eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
  220. vc->gfx.esurface, vc->gfx.ectx);
  221. window = gtk_widget_get_window(vc->gfx.drawing_area);
  222. ww = gdk_window_get_width(window);
  223. wh = gdk_window_get_height(window);
  224. egl_fb_setup_default(&vc->gfx.win_fb, ww, wh);
  225. if (vc->gfx.cursor_fb.texture) {
  226. egl_texture_blit(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.guest_fb,
  227. vc->gfx.y0_top);
  228. egl_texture_blend(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.cursor_fb,
  229. vc->gfx.y0_top,
  230. vc->gfx.cursor_x, vc->gfx.cursor_y,
  231. vc->gfx.scale_x, vc->gfx.scale_y);
  232. } else {
  233. egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top);
  234. }
  235. eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
  236. }
  237. void gtk_egl_init(DisplayGLMode mode)
  238. {
  239. GdkDisplay *gdk_display = gdk_display_get_default();
  240. Display *x11_display = gdk_x11_display_get_xdisplay(gdk_display);
  241. if (qemu_egl_init_dpy_x11(x11_display, mode) < 0) {
  242. return;
  243. }
  244. display_opengl = 1;
  245. }
  246. int gd_egl_make_current(DisplayChangeListener *dcl,
  247. QEMUGLContext ctx)
  248. {
  249. VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  250. return eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
  251. vc->gfx.esurface, ctx);
  252. }