egl-headless.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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_texture,
  57. bool backing_y_0_top,
  58. uint32_t backing_width,
  59. uint32_t backing_height)
  60. {
  61. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  62. edpy->y_0_top = backing_y_0_top;
  63. /* source framebuffer */
  64. egl_fb_setup_for_tex(&edpy->guest_fb,
  65. backing_width, backing_height, backing_texture, false);
  66. /* dest framebuffer */
  67. if (edpy->blit_fb.width != backing_width ||
  68. edpy->blit_fb.height != backing_height) {
  69. egl_fb_destroy(&edpy->blit_fb);
  70. egl_fb_setup_new_tex(&edpy->blit_fb, backing_width, backing_height);
  71. }
  72. }
  73. static void egl_scanout_texture(DisplayChangeListener *dcl,
  74. uint32_t backing_id,
  75. DisplayGLTextureBorrower backing_borrow,
  76. uint32_t x, uint32_t y,
  77. uint32_t w, uint32_t h)
  78. {
  79. bool backing_y_0_top;
  80. uint32_t backing_width;
  81. uint32_t backing_height;
  82. GLuint backing_texture = backing_borrow(backing_id, &backing_y_0_top,
  83. &backing_width, &backing_height);
  84. egl_scanout_imported_texture(dcl, backing_texture, backing_y_0_top,
  85. backing_width, backing_height);
  86. }
  87. #ifdef CONFIG_GBM
  88. static void egl_scanout_dmabuf(DisplayChangeListener *dcl, QemuDmaBuf *dmabuf)
  89. {
  90. egl_dmabuf_import_texture(dmabuf);
  91. if (!dmabuf->texture) {
  92. return;
  93. }
  94. egl_scanout_imported_texture(dcl, dmabuf->texture,
  95. false, dmabuf->width, dmabuf->height);
  96. }
  97. static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
  98. QemuDmaBuf *dmabuf, bool have_hot,
  99. uint32_t hot_x, uint32_t hot_y)
  100. {
  101. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  102. if (dmabuf) {
  103. egl_dmabuf_import_texture(dmabuf);
  104. if (!dmabuf->texture) {
  105. return;
  106. }
  107. egl_fb_setup_for_tex(&edpy->cursor_fb, dmabuf->width, dmabuf->height,
  108. dmabuf->texture, false);
  109. } else {
  110. egl_fb_destroy(&edpy->cursor_fb);
  111. }
  112. }
  113. static void egl_cursor_position(DisplayChangeListener *dcl,
  114. uint32_t pos_x, uint32_t pos_y)
  115. {
  116. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  117. edpy->pos_x = pos_x;
  118. edpy->pos_y = pos_y;
  119. }
  120. static void egl_release_dmabuf(DisplayChangeListener *dcl,
  121. QemuDmaBuf *dmabuf)
  122. {
  123. egl_dmabuf_release_texture(dmabuf);
  124. }
  125. #endif
  126. static void egl_scanout_flush(DisplayChangeListener *dcl,
  127. uint32_t x, uint32_t y,
  128. uint32_t w, uint32_t h)
  129. {
  130. egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
  131. if (!edpy->guest_fb.texture || !edpy->ds) {
  132. return;
  133. }
  134. assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8);
  135. if (edpy->cursor_fb.texture) {
  136. /* have cursor -> render using textures */
  137. egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb,
  138. !edpy->y_0_top, false);
  139. egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb,
  140. false, !edpy->y_0_top, edpy->pos_x, edpy->pos_y,
  141. 1.0, 1.0);
  142. } else {
  143. /* no cursor -> use simple framebuffer blit */
  144. egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top);
  145. }
  146. egl_fb_read(edpy->ds, &edpy->blit_fb);
  147. dpy_gfx_update(edpy->dcl.con, x, y, w, h);
  148. }
  149. static const DisplayChangeListenerOps egl_ops = {
  150. .dpy_name = "egl-headless",
  151. .dpy_refresh = egl_refresh,
  152. .dpy_gfx_update = egl_gfx_update,
  153. .dpy_gfx_switch = egl_gfx_switch,
  154. .dpy_gl_scanout_disable = egl_scanout_disable,
  155. .dpy_gl_scanout_texture = egl_scanout_texture,
  156. #ifdef CONFIG_GBM
  157. .dpy_gl_scanout_dmabuf = egl_scanout_dmabuf,
  158. .dpy_gl_cursor_dmabuf = egl_cursor_dmabuf,
  159. .dpy_gl_cursor_position = egl_cursor_position,
  160. .dpy_gl_release_dmabuf = egl_release_dmabuf,
  161. #endif
  162. .dpy_gl_update = egl_scanout_flush,
  163. };
  164. static bool
  165. egl_is_compatible_dcl(DisplayGLCtx *dgc,
  166. DisplayChangeListener *dcl)
  167. {
  168. if (!dcl->ops->dpy_gl_update) {
  169. /*
  170. * egl-headless is compatible with all 2d listeners, as it blits the GL
  171. * updates on the 2d console surface.
  172. */
  173. return true;
  174. }
  175. return dcl->ops == &egl_ops;
  176. }
  177. static const DisplayGLCtxOps eglctx_ops = {
  178. .dpy_gl_ctx_is_compatible_dcl = egl_is_compatible_dcl,
  179. .dpy_gl_ctx_create = egl_create_context,
  180. .dpy_gl_ctx_destroy = qemu_egl_destroy_context,
  181. .dpy_gl_ctx_make_current = qemu_egl_make_context_current,
  182. };
  183. static void early_egl_headless_init(DisplayOptions *opts)
  184. {
  185. DisplayGLMode mode = DISPLAYGL_MODE_ON;
  186. if (opts->has_gl) {
  187. mode = opts->gl;
  188. }
  189. #ifdef CONFIG_GBM
  190. egl_init(opts->u.egl_headless.rendernode, mode, &error_fatal);
  191. #else
  192. if (qemu_egl_init_dpy_surfaceless(mode)) {
  193. error_report("egl: display init failed");
  194. exit(1);
  195. }
  196. ctx = qemu_egl_init_ctx();
  197. if (!ctx) {
  198. error_report("egl: egl_init_ctx failed");
  199. exit(1);
  200. }
  201. #endif
  202. }
  203. static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)
  204. {
  205. QemuConsole *con;
  206. egl_dpy *edpy;
  207. int idx;
  208. for (idx = 0;; idx++) {
  209. DisplayGLCtx *ctx;
  210. con = qemu_console_lookup_by_index(idx);
  211. if (!con || !qemu_console_is_graphic(con)) {
  212. break;
  213. }
  214. edpy = g_new0(egl_dpy, 1);
  215. edpy->dcl.con = con;
  216. edpy->dcl.ops = &egl_ops;
  217. edpy->gls = qemu_gl_init_shader();
  218. ctx = g_new0(DisplayGLCtx, 1);
  219. ctx->ops = &eglctx_ops;
  220. qemu_console_set_display_gl_ctx(con, ctx);
  221. register_displaychangelistener(&edpy->dcl);
  222. }
  223. }
  224. static QemuDisplay qemu_display_egl = {
  225. .type = DISPLAY_TYPE_EGL_HEADLESS,
  226. .early_init = early_egl_headless_init,
  227. .init = egl_headless_init,
  228. };
  229. static void register_egl(void)
  230. {
  231. qemu_display_register(&qemu_display_egl);
  232. }
  233. type_init(register_egl);
  234. module_dep("ui-opengl");