qemu/ui/sdl2-gl.c
<<
>>
Prefs
   1/*
   2 * QEMU SDL display driver -- opengl support
   3 *
   4 * Copyright (c) 2014 Red Hat
   5 *
   6 * Authors:
   7 *     Gerd Hoffmann <kraxel@redhat.com>
   8 *
   9 * Permission is hereby granted, free of charge, to any person obtaining a copy
  10 * of this software and associated documentation files (the "Software"), to deal
  11 * in the Software without restriction, including without limitation the rights
  12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13 * copies of the Software, and to permit persons to whom the Software is
  14 * furnished to do so, subject to the following conditions:
  15 *
  16 * The above copyright notice and this permission notice shall be included in
  17 * all copies or substantial portions of the Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25 * THE SOFTWARE.
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "qemu-common.h"
  30#include "ui/console.h"
  31#include "ui/input.h"
  32#include "ui/sdl2.h"
  33#include "sysemu/sysemu.h"
  34
  35static void sdl2_set_scanout_mode(struct sdl2_console *scon, bool scanout)
  36{
  37    if (scon->scanout_mode == scanout) {
  38        return;
  39    }
  40
  41    scon->scanout_mode = scanout;
  42    if (!scon->scanout_mode) {
  43        egl_fb_destroy(&scon->guest_fb);
  44        if (scon->surface) {
  45            surface_gl_destroy_texture(scon->gls, scon->surface);
  46            surface_gl_create_texture(scon->gls, scon->surface);
  47        }
  48    }
  49}
  50
  51static void sdl2_gl_render_surface(struct sdl2_console *scon)
  52{
  53    int ww, wh;
  54
  55    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
  56    sdl2_set_scanout_mode(scon, false);
  57
  58    SDL_GetWindowSize(scon->real_window, &ww, &wh);
  59    surface_gl_setup_viewport(scon->gls, scon->surface, ww, wh);
  60
  61    surface_gl_render_texture(scon->gls, scon->surface);
  62    SDL_GL_SwapWindow(scon->real_window);
  63}
  64
  65void sdl2_gl_update(DisplayChangeListener *dcl,
  66                    int x, int y, int w, int h)
  67{
  68    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
  69
  70    assert(scon->opengl);
  71
  72    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
  73    surface_gl_update_texture(scon->gls, scon->surface, x, y, w, h);
  74    scon->updates++;
  75}
  76
  77void sdl2_gl_switch(DisplayChangeListener *dcl,
  78                    DisplaySurface *new_surface)
  79{
  80    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
  81    DisplaySurface *old_surface = scon->surface;
  82
  83    assert(scon->opengl);
  84
  85    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
  86    surface_gl_destroy_texture(scon->gls, scon->surface);
  87
  88    scon->surface = new_surface;
  89
  90    if (!new_surface) {
  91        qemu_gl_fini_shader(scon->gls);
  92        scon->gls = NULL;
  93        sdl2_window_destroy(scon);
  94        return;
  95    }
  96
  97    if (!scon->real_window) {
  98        sdl2_window_create(scon);
  99        scon->gls = qemu_gl_init_shader();
 100    } else if (old_surface &&
 101               ((surface_width(old_surface)  != surface_width(new_surface)) ||
 102                (surface_height(old_surface) != surface_height(new_surface)))) {
 103        sdl2_window_resize(scon);
 104    }
 105
 106    surface_gl_create_texture(scon->gls, scon->surface);
 107}
 108
 109void sdl2_gl_refresh(DisplayChangeListener *dcl)
 110{
 111    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 112
 113    assert(scon->opengl);
 114
 115    graphic_hw_update(dcl->con);
 116    if (scon->updates && scon->surface) {
 117        scon->updates = 0;
 118        sdl2_gl_render_surface(scon);
 119    }
 120    sdl2_poll_events(scon);
 121}
 122
 123void sdl2_gl_redraw(struct sdl2_console *scon)
 124{
 125    assert(scon->opengl);
 126
 127    if (scon->scanout_mode) {
 128        /* sdl2_gl_scanout_flush actually only care about
 129         * the first argument. */
 130        return sdl2_gl_scanout_flush(&scon->dcl, 0, 0, 0, 0);
 131    }
 132    if (scon->surface) {
 133        sdl2_gl_render_surface(scon);
 134    }
 135}
 136
 137QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl,
 138                                     QEMUGLParams *params)
 139{
 140    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 141    SDL_GLContext ctx;
 142
 143    assert(scon->opengl);
 144
 145    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 146
 147    SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
 148    if (scon->opts->gl == DISPLAYGL_MODE_ON ||
 149        scon->opts->gl == DISPLAYGL_MODE_CORE) {
 150        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
 151                            SDL_GL_CONTEXT_PROFILE_CORE);
 152    } else if (scon->opts->gl == DISPLAYGL_MODE_ES) {
 153        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
 154                            SDL_GL_CONTEXT_PROFILE_ES);
 155    }
 156    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, params->major_ver);
 157    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, params->minor_ver);
 158
 159    ctx = SDL_GL_CreateContext(scon->real_window);
 160
 161    /* If SDL fail to create a GL context and we use the "on" flag,
 162     * then try to fallback to GLES.
 163     */
 164    if (!ctx && scon->opts->gl == DISPLAYGL_MODE_ON) {
 165        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
 166                            SDL_GL_CONTEXT_PROFILE_ES);
 167        ctx = SDL_GL_CreateContext(scon->real_window);
 168    }
 169    return (QEMUGLContext)ctx;
 170}
 171
 172void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx)
 173{
 174    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
 175
 176    SDL_GL_DeleteContext(sdlctx);
 177}
 178
 179int sdl2_gl_make_context_current(DisplayChangeListener *dcl,
 180                                 QEMUGLContext ctx)
 181{
 182    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 183    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
 184
 185    assert(scon->opengl);
 186
 187    return SDL_GL_MakeCurrent(scon->real_window, sdlctx);
 188}
 189
 190QEMUGLContext sdl2_gl_get_current_context(DisplayChangeListener *dcl)
 191{
 192    SDL_GLContext sdlctx;
 193
 194    sdlctx = SDL_GL_GetCurrentContext();
 195    return (QEMUGLContext)sdlctx;
 196}
 197
 198void sdl2_gl_scanout_disable(DisplayChangeListener *dcl)
 199{
 200    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 201
 202    assert(scon->opengl);
 203    scon->w = 0;
 204    scon->h = 0;
 205    sdl2_set_scanout_mode(scon, false);
 206}
 207
 208void sdl2_gl_scanout_texture(DisplayChangeListener *dcl,
 209                             uint32_t backing_id,
 210                             bool backing_y_0_top,
 211                             uint32_t backing_width,
 212                             uint32_t backing_height,
 213                             uint32_t x, uint32_t y,
 214                             uint32_t w, uint32_t h)
 215{
 216    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 217
 218    assert(scon->opengl);
 219    scon->x = x;
 220    scon->y = y;
 221    scon->w = w;
 222    scon->h = h;
 223    scon->y0_top = backing_y_0_top;
 224
 225    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 226
 227    sdl2_set_scanout_mode(scon, true);
 228    egl_fb_setup_for_tex(&scon->guest_fb, backing_width, backing_height,
 229                         backing_id, false);
 230}
 231
 232void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
 233                           uint32_t x, uint32_t y, uint32_t w, uint32_t h)
 234{
 235    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 236    int ww, wh;
 237
 238    assert(scon->opengl);
 239    if (!scon->scanout_mode) {
 240        return;
 241    }
 242    if (!scon->guest_fb.framebuffer) {
 243        return;
 244    }
 245
 246    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 247
 248    SDL_GetWindowSize(scon->real_window, &ww, &wh);
 249    egl_fb_setup_default(&scon->win_fb, ww, wh);
 250    egl_fb_blit(&scon->win_fb, &scon->guest_fb, !scon->y0_top);
 251
 252    SDL_GL_SwapWindow(scon->real_window);
 253}
 254