xref: /qemu/ui/egl-headless.c (revision bb1599b64c8f94fb2bd745d20f128e11543d891d)
1*bb1599b6SGerd Hoffmann #include "qemu/osdep.h"
2*bb1599b6SGerd Hoffmann #include "qemu-common.h"
3*bb1599b6SGerd Hoffmann #include "sysemu/sysemu.h"
4*bb1599b6SGerd Hoffmann #include "ui/console.h"
5*bb1599b6SGerd Hoffmann #include "ui/egl-helpers.h"
6*bb1599b6SGerd Hoffmann #include "ui/egl-context.h"
7*bb1599b6SGerd Hoffmann 
8*bb1599b6SGerd Hoffmann typedef struct egl_dpy {
9*bb1599b6SGerd Hoffmann     DisplayChangeListener dcl;
10*bb1599b6SGerd Hoffmann     DisplaySurface *ds;
11*bb1599b6SGerd Hoffmann     int width, height;
12*bb1599b6SGerd Hoffmann     GLuint texture;
13*bb1599b6SGerd Hoffmann     GLuint framebuffer;
14*bb1599b6SGerd Hoffmann     GLuint blit_texture;
15*bb1599b6SGerd Hoffmann     GLuint blit_framebuffer;
16*bb1599b6SGerd Hoffmann     bool y_0_top;
17*bb1599b6SGerd Hoffmann } egl_dpy;
18*bb1599b6SGerd Hoffmann 
19*bb1599b6SGerd Hoffmann static void egl_refresh(DisplayChangeListener *dcl)
20*bb1599b6SGerd Hoffmann {
21*bb1599b6SGerd Hoffmann     graphic_hw_update(dcl->con);
22*bb1599b6SGerd Hoffmann }
23*bb1599b6SGerd Hoffmann 
24*bb1599b6SGerd Hoffmann static void egl_gfx_update(DisplayChangeListener *dcl,
25*bb1599b6SGerd Hoffmann                            int x, int y, int w, int h)
26*bb1599b6SGerd Hoffmann {
27*bb1599b6SGerd Hoffmann }
28*bb1599b6SGerd Hoffmann 
29*bb1599b6SGerd Hoffmann static void egl_gfx_switch(DisplayChangeListener *dcl,
30*bb1599b6SGerd Hoffmann                            struct DisplaySurface *new_surface)
31*bb1599b6SGerd Hoffmann {
32*bb1599b6SGerd Hoffmann     egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
33*bb1599b6SGerd Hoffmann 
34*bb1599b6SGerd Hoffmann     edpy->ds = new_surface;
35*bb1599b6SGerd Hoffmann }
36*bb1599b6SGerd Hoffmann 
37*bb1599b6SGerd Hoffmann static void egl_scanout_disable(DisplayChangeListener *dcl)
38*bb1599b6SGerd Hoffmann {
39*bb1599b6SGerd Hoffmann     egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
40*bb1599b6SGerd Hoffmann 
41*bb1599b6SGerd Hoffmann     edpy->texture = 0;
42*bb1599b6SGerd Hoffmann     /* XXX: delete framebuffers here ??? */
43*bb1599b6SGerd Hoffmann }
44*bb1599b6SGerd Hoffmann 
45*bb1599b6SGerd Hoffmann static void egl_scanout_texture(DisplayChangeListener *dcl,
46*bb1599b6SGerd Hoffmann                                 uint32_t backing_id,
47*bb1599b6SGerd Hoffmann                                 bool backing_y_0_top,
48*bb1599b6SGerd Hoffmann                                 uint32_t backing_width,
49*bb1599b6SGerd Hoffmann                                 uint32_t backing_height,
50*bb1599b6SGerd Hoffmann                                 uint32_t x, uint32_t y,
51*bb1599b6SGerd Hoffmann                                 uint32_t w, uint32_t h)
52*bb1599b6SGerd Hoffmann {
53*bb1599b6SGerd Hoffmann     egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
54*bb1599b6SGerd Hoffmann 
55*bb1599b6SGerd Hoffmann     edpy->texture = backing_id;
56*bb1599b6SGerd Hoffmann     edpy->y_0_top = backing_y_0_top;
57*bb1599b6SGerd Hoffmann 
58*bb1599b6SGerd Hoffmann     /* source framebuffer */
59*bb1599b6SGerd Hoffmann     if (!edpy->framebuffer) {
60*bb1599b6SGerd Hoffmann         glGenFramebuffers(1, &edpy->framebuffer);
61*bb1599b6SGerd Hoffmann     }
62*bb1599b6SGerd Hoffmann     glBindFramebuffer(GL_FRAMEBUFFER_EXT, edpy->framebuffer);
63*bb1599b6SGerd Hoffmann     glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
64*bb1599b6SGerd Hoffmann                               GL_TEXTURE_2D, edpy->texture, 0);
65*bb1599b6SGerd Hoffmann 
66*bb1599b6SGerd Hoffmann     /* dest framebuffer */
67*bb1599b6SGerd Hoffmann     if (!edpy->blit_framebuffer) {
68*bb1599b6SGerd Hoffmann         glGenFramebuffers(1, &edpy->blit_framebuffer);
69*bb1599b6SGerd Hoffmann         glGenTextures(1, &edpy->blit_texture);
70*bb1599b6SGerd Hoffmann         edpy->width = 0;
71*bb1599b6SGerd Hoffmann         edpy->height = 0;
72*bb1599b6SGerd Hoffmann     }
73*bb1599b6SGerd Hoffmann     if (edpy->width != backing_width || edpy->height != backing_height) {
74*bb1599b6SGerd Hoffmann         edpy->width   = backing_width;
75*bb1599b6SGerd Hoffmann         edpy->height  = backing_height;
76*bb1599b6SGerd Hoffmann         glBindTexture(GL_TEXTURE_2D, edpy->blit_texture);
77*bb1599b6SGerd Hoffmann         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
78*bb1599b6SGerd Hoffmann                      edpy->width, edpy->height,
79*bb1599b6SGerd Hoffmann                      0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
80*bb1599b6SGerd Hoffmann         glBindFramebuffer(GL_FRAMEBUFFER_EXT, edpy->blit_framebuffer);
81*bb1599b6SGerd Hoffmann         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
82*bb1599b6SGerd Hoffmann                                   GL_TEXTURE_2D, edpy->blit_texture, 0);
83*bb1599b6SGerd Hoffmann     }
84*bb1599b6SGerd Hoffmann }
85*bb1599b6SGerd Hoffmann 
86*bb1599b6SGerd Hoffmann static void egl_scanout_flush(DisplayChangeListener *dcl,
87*bb1599b6SGerd Hoffmann                               uint32_t x, uint32_t y,
88*bb1599b6SGerd Hoffmann                               uint32_t w, uint32_t h)
89*bb1599b6SGerd Hoffmann {
90*bb1599b6SGerd Hoffmann     egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
91*bb1599b6SGerd Hoffmann     GLuint y1, y2;
92*bb1599b6SGerd Hoffmann 
93*bb1599b6SGerd Hoffmann     if (!edpy->texture || !edpy->ds) {
94*bb1599b6SGerd Hoffmann         return;
95*bb1599b6SGerd Hoffmann     }
96*bb1599b6SGerd Hoffmann     assert(surface_width(edpy->ds)  == edpy->width);
97*bb1599b6SGerd Hoffmann     assert(surface_height(edpy->ds) == edpy->height);
98*bb1599b6SGerd Hoffmann     assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8);
99*bb1599b6SGerd Hoffmann 
100*bb1599b6SGerd Hoffmann     /* blit framebuffer, flip if needed */
101*bb1599b6SGerd Hoffmann     glBindFramebuffer(GL_READ_FRAMEBUFFER, edpy->framebuffer);
102*bb1599b6SGerd Hoffmann     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, edpy->blit_framebuffer);
103*bb1599b6SGerd Hoffmann     glViewport(0, 0, edpy->width, edpy->height);
104*bb1599b6SGerd Hoffmann     y1 = edpy->y_0_top ? edpy->height : 0;
105*bb1599b6SGerd Hoffmann     y2 = edpy->y_0_top ? 0 : edpy->height;
106*bb1599b6SGerd Hoffmann     glBlitFramebuffer(0, y1, edpy->width, y2,
107*bb1599b6SGerd Hoffmann                       0, 0, edpy->width, edpy->height,
108*bb1599b6SGerd Hoffmann                       GL_COLOR_BUFFER_BIT, GL_NEAREST);
109*bb1599b6SGerd Hoffmann 
110*bb1599b6SGerd Hoffmann     /* read pixels to surface */
111*bb1599b6SGerd Hoffmann     glBindFramebuffer(GL_READ_FRAMEBUFFER, edpy->blit_framebuffer);
112*bb1599b6SGerd Hoffmann     glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
113*bb1599b6SGerd Hoffmann     glReadPixels(0, 0, edpy->width, edpy->height,
114*bb1599b6SGerd Hoffmann                  GL_BGRA, GL_UNSIGNED_BYTE, surface_data(edpy->ds));
115*bb1599b6SGerd Hoffmann 
116*bb1599b6SGerd Hoffmann     /* notify about updates */
117*bb1599b6SGerd Hoffmann     dpy_gfx_update(edpy->dcl.con, x, y, w, h);
118*bb1599b6SGerd Hoffmann }
119*bb1599b6SGerd Hoffmann 
120*bb1599b6SGerd Hoffmann static const DisplayChangeListenerOps egl_ops = {
121*bb1599b6SGerd Hoffmann     .dpy_name                = "egl-headless",
122*bb1599b6SGerd Hoffmann     .dpy_refresh             = egl_refresh,
123*bb1599b6SGerd Hoffmann     .dpy_gfx_update          = egl_gfx_update,
124*bb1599b6SGerd Hoffmann     .dpy_gfx_switch          = egl_gfx_switch,
125*bb1599b6SGerd Hoffmann 
126*bb1599b6SGerd Hoffmann     .dpy_gl_ctx_create       = qemu_egl_create_context,
127*bb1599b6SGerd Hoffmann     .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,
128*bb1599b6SGerd Hoffmann     .dpy_gl_ctx_make_current = qemu_egl_make_context_current,
129*bb1599b6SGerd Hoffmann     .dpy_gl_ctx_get_current  = qemu_egl_get_current_context,
130*bb1599b6SGerd Hoffmann 
131*bb1599b6SGerd Hoffmann     .dpy_gl_scanout_disable  = egl_scanout_disable,
132*bb1599b6SGerd Hoffmann     .dpy_gl_scanout_texture  = egl_scanout_texture,
133*bb1599b6SGerd Hoffmann     .dpy_gl_update           = egl_scanout_flush,
134*bb1599b6SGerd Hoffmann };
135*bb1599b6SGerd Hoffmann 
136*bb1599b6SGerd Hoffmann void egl_headless_init(void)
137*bb1599b6SGerd Hoffmann {
138*bb1599b6SGerd Hoffmann     QemuConsole *con;
139*bb1599b6SGerd Hoffmann     egl_dpy *edpy;
140*bb1599b6SGerd Hoffmann     int idx;
141*bb1599b6SGerd Hoffmann 
142*bb1599b6SGerd Hoffmann     if (egl_rendernode_init(NULL) < 0) {
143*bb1599b6SGerd Hoffmann         error_report("egl: render node init failed");
144*bb1599b6SGerd Hoffmann         exit(1);
145*bb1599b6SGerd Hoffmann     }
146*bb1599b6SGerd Hoffmann 
147*bb1599b6SGerd Hoffmann     for (idx = 0;; idx++) {
148*bb1599b6SGerd Hoffmann         con = qemu_console_lookup_by_index(idx);
149*bb1599b6SGerd Hoffmann         if (!con || !qemu_console_is_graphic(con)) {
150*bb1599b6SGerd Hoffmann             break;
151*bb1599b6SGerd Hoffmann         }
152*bb1599b6SGerd Hoffmann 
153*bb1599b6SGerd Hoffmann         edpy = g_new0(egl_dpy, 1);
154*bb1599b6SGerd Hoffmann         edpy->dcl.con = con;
155*bb1599b6SGerd Hoffmann         edpy->dcl.ops = &egl_ops;
156*bb1599b6SGerd Hoffmann         register_displaychangelistener(&edpy->dcl);
157*bb1599b6SGerd Hoffmann     }
158*bb1599b6SGerd Hoffmann }
159