egl-headless.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. #include "qemu/osdep.h"
  2. #include "qemu/error-report.h"
  3. #include "qemu/module.h"
  4. #include "qapi/error.h"
  5. #include "ui/console.h"
  6. #include "ui/egl-helpers.h"
  7. #include "ui/egl-context.h"
  8. #include "ui/shader.h"
  9. typedef struct egl_dpy {
  10. DisplayChangeListener dcl;
  11. DisplaySurface *ds;
  12. QemuGLShader *gls;
  13. egl_fb guest_fb;
  14. egl_fb cursor_fb;
  15. egl_fb blit_fb;
  16. bool y_0_top;
  17. uint32_t pos_x;
  18. uint32_t pos_y;
  19. } egl_dpy;
  20. #ifndef CONFIG_GBM
  21. static EGLContext ctx;
  22. #endif
  23. /* ------------------------------------------------------------------ */
  24. static void egl_refresh(DisplayChangeListener *dcl)
  25. {
  26. graphic_hw_update(dcl->con);
  27. }
  28. static void egl_gfx_update(DisplayChangeListener *dcl,
  29. int x, int y, int w, int h)
  30. {
  31. }
  32. static void egl_gfx_switch(DisplayChangeListener *dcl,
  33. struct DisplaySurface *new_surface)
  34. {
  35. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  36. edpy->ds = new_surface;
  37. }
  38. static QEMUGLContext egl_create_context(DisplayGLCtx *dgc,
  39. QEMUGLParams *params)
  40. {
  41. #ifdef CONFIG_GBM
  42. eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
  43. qemu_egl_rn_ctx);
  44. #else
  45. eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx);
  46. #endif
  47. return qemu_egl_create_context(dgc, params);
  48. }
  49. static void egl_scanout_disable(DisplayChangeListener *dcl)
  50. {
  51. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  52. egl_fb_destroy(&edpy->guest_fb);
  53. egl_fb_destroy(&edpy->blit_fb);
  54. }
  55. static void egl_scanout_imported_texture(DisplayChangeListener *dcl,
  56. uint32_t backing_id,
  57. bool backing_y_0_top,
  58. uint32_t backing_width,
  59. uint32_t backing_height,
  60. uint32_t x, uint32_t y,
  61. uint32_t w, uint32_t h,
  62. void *d3d_tex2d)
  63. {
  64. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  65. edpy->y_0_top = backing_y_0_top;
  66. /* source framebuffer */
  67. egl_fb_setup_for_tex(&edpy->guest_fb,
  68. backing_width, backing_height, backing_id, false);
  69. /* dest framebuffer */
  70. if (edpy->blit_fb.width != backing_width ||
  71. edpy->blit_fb.height != backing_height) {
  72. egl_fb_destroy(&edpy->blit_fb);
  73. egl_fb_setup_new_tex(&edpy->blit_fb, backing_width, backing_height);
  74. }
  75. }
  76. static void egl_scanout_texture(DisplayChangeListener *dcl,
  77. uint32_t backing_id,
  78. DisplayGLTextureBorrower backing_borrow,
  79. uint32_t x, uint32_t y,
  80. uint32_t w, uint32_t h)
  81. {
  82. bool backing_y_0_top;
  83. uint32_t backing_width;
  84. uint32_t backing_height;
  85. void *d3d_tex2d;
  86. GLuint backing_texture = backing_borrow(backing_id, &backing_y_0_top,
  87. &backing_width, &backing_height,
  88. &d3d_tex2d);
  89. egl_scanout_imported_texture(dcl, backing_texture, backing_y_0_top,
  90. backing_width, backing_height,
  91. x, y, w, h, d3d_tex2d);
  92. }
  93. #ifdef CONFIG_GBM
  94. static void egl_scanout_dmabuf(DisplayChangeListener *dcl,
  95. QemuDmaBuf *dmabuf)
  96. {
  97. uint32_t width, height, texture;
  98. egl_dmabuf_import_texture(dmabuf);
  99. texture = qemu_dmabuf_get_texture(dmabuf);
  100. if (!texture) {
  101. return;
  102. }
  103. width = qemu_dmabuf_get_width(dmabuf);
  104. height = qemu_dmabuf_get_height(dmabuf);
  105. egl_scanout_imported_texture(dcl, texture, false, width, height, 0, 0,
  106. width, height, NULL);
  107. }
  108. static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
  109. QemuDmaBuf *dmabuf, bool have_hot,
  110. uint32_t hot_x, uint32_t hot_y)
  111. {
  112. uint32_t width, height, texture;
  113. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  114. if (dmabuf) {
  115. egl_dmabuf_import_texture(dmabuf);
  116. texture = qemu_dmabuf_get_texture(dmabuf);
  117. if (!texture) {
  118. return;
  119. }
  120. width = qemu_dmabuf_get_width(dmabuf);
  121. height = qemu_dmabuf_get_height(dmabuf);
  122. egl_fb_setup_for_tex(&edpy->cursor_fb, width, height, texture, false);
  123. } else {
  124. egl_fb_destroy(&edpy->cursor_fb);
  125. }
  126. }
  127. static void egl_release_dmabuf(DisplayChangeListener *dcl,
  128. QemuDmaBuf *dmabuf)
  129. {
  130. egl_dmabuf_release_texture(dmabuf);
  131. }
  132. #endif
  133. static void egl_cursor_position(DisplayChangeListener *dcl,
  134. uint32_t pos_x, uint32_t pos_y)
  135. {
  136. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  137. edpy->pos_x = pos_x;
  138. edpy->pos_y = pos_y;
  139. }
  140. static void egl_scanout_flush(DisplayChangeListener *dcl,
  141. uint32_t x, uint32_t y,
  142. uint32_t w, uint32_t h)
  143. {
  144. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  145. if (!edpy->guest_fb.texture || !edpy->ds) {
  146. return;
  147. }
  148. assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8);
  149. if (edpy->cursor_fb.texture) {
  150. /* have cursor -> render using textures */
  151. egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb,
  152. !edpy->y_0_top, false);
  153. egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb,
  154. !edpy->y_0_top, false, edpy->pos_x, edpy->pos_y,
  155. 1.0, 1.0);
  156. } else {
  157. /* no cursor -> use simple framebuffer blit */
  158. egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top);
  159. }
  160. egl_fb_read(edpy->ds, &edpy->blit_fb);
  161. dpy_gfx_update(edpy->dcl.con, x, y, w, h);
  162. }
  163. static const DisplayChangeListenerOps egl_ops = {
  164. .dpy_name = "egl-headless",
  165. .dpy_refresh = egl_refresh,
  166. .dpy_gfx_update = egl_gfx_update,
  167. .dpy_gfx_switch = egl_gfx_switch,
  168. .dpy_gl_scanout_disable = egl_scanout_disable,
  169. .dpy_gl_scanout_texture = egl_scanout_texture,
  170. #ifdef CONFIG_GBM
  171. .dpy_gl_scanout_dmabuf = egl_scanout_dmabuf,
  172. .dpy_gl_cursor_dmabuf = egl_cursor_dmabuf,
  173. .dpy_gl_release_dmabuf = egl_release_dmabuf,
  174. #endif
  175. .dpy_gl_cursor_position = egl_cursor_position,
  176. .dpy_gl_update = egl_scanout_flush,
  177. };
  178. static bool
  179. egl_is_compatible_dcl(DisplayGLCtx *dgc,
  180. DisplayChangeListener *dcl)
  181. {
  182. if (!dcl->ops->dpy_gl_update) {
  183. /*
  184. * egl-headless is compatible with all 2d listeners, as it blits the GL
  185. * updates on the 2d console surface.
  186. */
  187. return true;
  188. }
  189. return dcl->ops == &egl_ops;
  190. }
  191. static const DisplayGLCtxOps eglctx_ops = {
  192. .dpy_gl_ctx_is_compatible_dcl = egl_is_compatible_dcl,
  193. .dpy_gl_ctx_create = egl_create_context,
  194. .dpy_gl_ctx_destroy = qemu_egl_destroy_context,
  195. .dpy_gl_ctx_make_current = qemu_egl_make_context_current,
  196. };
  197. static void early_egl_headless_init(DisplayOptions *opts)
  198. {
  199. DisplayGLMode mode = DISPLAY_GL_MODE_ON;
  200. if (opts->has_gl) {
  201. mode = opts->gl;
  202. }
  203. #ifdef CONFIG_GBM
  204. egl_init(opts->u.egl_headless.rendernode, mode, &error_fatal);
  205. #else
  206. if (qemu_egl_init_dpy_surfaceless(mode)) {
  207. error_report("egl: display init failed");
  208. exit(1);
  209. }
  210. ctx = qemu_egl_init_ctx();
  211. if (!ctx) {
  212. error_report("egl: egl_init_ctx failed");
  213. exit(1);
  214. }
  215. #endif
  216. }
  217. static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)
  218. {
  219. QemuConsole *con;
  220. egl_dpy *edpy;
  221. int idx;
  222. for (idx = 0;; idx++) {
  223. DisplayGLCtx *ctx;
  224. con = qemu_console_lookup_by_index(idx);
  225. if (!con || !qemu_console_is_graphic(con)) {
  226. break;
  227. }
  228. edpy = g_new0(egl_dpy, 1);
  229. edpy->dcl.con = con;
  230. edpy->dcl.ops = &egl_ops;
  231. edpy->gls = qemu_gl_init_shader();
  232. ctx = g_new0(DisplayGLCtx, 1);
  233. ctx->ops = &eglctx_ops;
  234. qemu_console_set_display_gl_ctx(con, ctx);
  235. register_displaychangelistener(&edpy->dcl);
  236. }
  237. }
  238. static QemuDisplay qemu_display_egl = {
  239. .type = DISPLAY_TYPE_EGL_HEADLESS,
  240. .early_init = early_egl_headless_init,
  241. .init = egl_headless_init,
  242. };
  243. static void register_egl(void)
  244. {
  245. qemu_display_register(&qemu_display_egl);
  246. }
  247. type_init(register_egl);
  248. module_dep("ui-opengl");