qemu/ui/gtk-gl-area.c
<<
>>
Prefs
   1/*
   2 * GTK UI -- glarea opengl code.
   3 *
   4 * Requires 3.16+ (GtkGLArea widget).
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 */
   9
  10#include "qemu/osdep.h"
  11
  12#include "trace.h"
  13
  14#include "ui/console.h"
  15#include "ui/gtk.h"
  16#include "ui/egl-helpers.h"
  17
  18#include "sysemu/sysemu.h"
  19
  20static void gtk_gl_area_set_scanout_mode(VirtualConsole *vc, bool scanout)
  21{
  22    if (vc->gfx.scanout_mode == scanout) {
  23        return;
  24    }
  25
  26    vc->gfx.scanout_mode = scanout;
  27    if (!vc->gfx.scanout_mode) {
  28        egl_fb_destroy(&vc->gfx.guest_fb);
  29        if (vc->gfx.surface) {
  30            surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
  31            surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
  32        }
  33    }
  34}
  35
  36/** DisplayState Callbacks (opengl version) **/
  37
  38void gd_gl_area_draw(VirtualConsole *vc)
  39{
  40    int ww, wh, y1, y2;
  41
  42    if (!vc->gfx.gls) {
  43        return;
  44    }
  45
  46    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
  47    ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area);
  48    wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area);
  49
  50    if (vc->gfx.scanout_mode) {
  51        if (!vc->gfx.guest_fb.framebuffer) {
  52            return;
  53        }
  54
  55        glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.guest_fb.framebuffer);
  56        /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */
  57
  58        glViewport(0, 0, ww, wh);
  59        y1 = vc->gfx.y0_top ? 0 : vc->gfx.h;
  60        y2 = vc->gfx.y0_top ? vc->gfx.h : 0;
  61        glBlitFramebuffer(0, y1, vc->gfx.w, y2,
  62                          0, 0, ww, wh,
  63                          GL_COLOR_BUFFER_BIT, GL_NEAREST);
  64    } else {
  65        if (!vc->gfx.ds) {
  66            return;
  67        }
  68        gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
  69
  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    }
  73}
  74
  75void gd_gl_area_update(DisplayChangeListener *dcl,
  76                   int x, int y, int w, int h)
  77{
  78    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  79
  80    if (!vc->gfx.gls || !vc->gfx.ds) {
  81        return;
  82    }
  83
  84    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
  85    surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h);
  86    vc->gfx.glupdates++;
  87}
  88
  89void gd_gl_area_refresh(DisplayChangeListener *dcl)
  90{
  91    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
  92
  93    if (!vc->gfx.gls) {
  94        if (!gtk_widget_get_realized(vc->gfx.drawing_area)) {
  95            return;
  96        }
  97        gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
  98        vc->gfx.gls = qemu_gl_init_shader();
  99        if (vc->gfx.ds) {
 100            surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
 101        }
 102    }
 103
 104    graphic_hw_update(dcl->con);
 105
 106    if (vc->gfx.glupdates) {
 107        vc->gfx.glupdates = 0;
 108        gtk_gl_area_set_scanout_mode(vc, false);
 109        gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
 110    }
 111}
 112
 113void gd_gl_area_switch(DisplayChangeListener *dcl,
 114                       DisplaySurface *surface)
 115{
 116    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 117    bool resized = true;
 118
 119    trace_gd_switch(vc->label, surface_width(surface), surface_height(surface));
 120
 121    if (vc->gfx.ds &&
 122        surface_width(vc->gfx.ds) == surface_width(surface) &&
 123        surface_height(vc->gfx.ds) == surface_height(surface)) {
 124        resized = false;
 125    }
 126
 127    if (vc->gfx.gls) {
 128        gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
 129        surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
 130        surface_gl_create_texture(vc->gfx.gls, surface);
 131    }
 132    vc->gfx.ds = surface;
 133
 134    if (resized) {
 135        gd_update_windowsize(vc);
 136    }
 137}
 138
 139QEMUGLContext gd_gl_area_create_context(DisplayChangeListener *dcl,
 140                                        QEMUGLParams *params)
 141{
 142    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 143    GdkWindow *window;
 144    GdkGLContext *ctx;
 145    GError *err = NULL;
 146
 147    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
 148    window = gtk_widget_get_window(vc->gfx.drawing_area);
 149    ctx = gdk_window_create_gl_context(window, &err);
 150    gdk_gl_context_set_required_version(ctx,
 151                                        params->major_ver,
 152                                        params->minor_ver);
 153    gdk_gl_context_realize(ctx, &err);
 154    return ctx;
 155}
 156
 157void gd_gl_area_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx)
 158{
 159    /* FIXME */
 160}
 161
 162void gd_gl_area_scanout_texture(DisplayChangeListener *dcl,
 163                                uint32_t backing_id,
 164                                bool backing_y_0_top,
 165                                uint32_t backing_width,
 166                                uint32_t backing_height,
 167                                uint32_t x, uint32_t y,
 168                                uint32_t w, uint32_t h)
 169{
 170    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 171
 172    vc->gfx.x = x;
 173    vc->gfx.y = y;
 174    vc->gfx.w = w;
 175    vc->gfx.h = h;
 176    vc->gfx.y0_top = backing_y_0_top;
 177
 178    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
 179
 180    if (backing_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) {
 181        gtk_gl_area_set_scanout_mode(vc, false);
 182        return;
 183    }
 184
 185    gtk_gl_area_set_scanout_mode(vc, true);
 186    egl_fb_setup_for_tex(&vc->gfx.guest_fb, backing_width, backing_height,
 187                         backing_id, false);
 188}
 189
 190void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
 191                          uint32_t x, uint32_t y, uint32_t w, uint32_t h)
 192{
 193    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 194
 195    gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
 196}
 197
 198void gtk_gl_area_init(void)
 199{
 200    display_opengl = 1;
 201}
 202
 203QEMUGLContext gd_gl_area_get_current_context(DisplayChangeListener *dcl)
 204{
 205    return gdk_gl_context_get_current();
 206}
 207
 208int gd_gl_area_make_current(DisplayChangeListener *dcl,
 209                            QEMUGLContext ctx)
 210{
 211    gdk_gl_context_make_current(ctx);
 212    return 0;
 213}
 214