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 "ui/console.h"
  30#include "ui/input.h"
  31#include "ui/sdl2.h"
  32
  33static void sdl2_set_scanout_mode(struct sdl2_console *scon, bool scanout)
  34{
  35    if (scon->scanout_mode == scanout) {
  36        return;
  37    }
  38
  39    scon->scanout_mode = scanout;
  40    if (!scon->scanout_mode) {
  41        egl_fb_destroy(&scon->guest_fb);
  42        if (scon->surface) {
  43            surface_gl_destroy_texture(scon->gls, scon->surface);
  44            surface_gl_create_texture(scon->gls, scon->surface);
  45        }
  46    }
  47}
  48
  49static void sdl2_gl_render_surface(struct sdl2_console *scon)
  50{
  51    int ww, wh;
  52
  53    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
  54    sdl2_set_scanout_mode(scon, false);
  55
  56    SDL_GetWindowSize(scon->real_window, &ww, &wh);
  57    surface_gl_setup_viewport(scon->gls, scon->surface, ww, wh);
  58
  59    surface_gl_render_texture(scon->gls, scon->surface);
  60    SDL_GL_SwapWindow(scon->real_window);
  61}
  62
  63void sdl2_gl_update(DisplayChangeListener *dcl,
  64                    int x, int y, int w, int h)
  65{
  66    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
  67
  68    assert(scon->opengl);
  69
  70    if (!scon->real_window) {
  71        return;
  72    }
  73
  74    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
  75    surface_gl_update_texture(scon->gls, scon->surface, x, y, w, h);
  76    scon->updates++;
  77}
  78
  79void sdl2_gl_switch(DisplayChangeListener *dcl,
  80                    DisplaySurface *new_surface)
  81{
  82    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
  83    DisplaySurface *old_surface = scon->surface;
  84
  85    assert(scon->opengl);
  86
  87    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
  88    surface_gl_destroy_texture(scon->gls, scon->surface);
  89
  90    scon->surface = new_surface;
  91
  92    if (is_placeholder(new_surface) && qemu_console_get_index(dcl->con)) {
  93        qemu_gl_fini_shader(scon->gls);
  94        scon->gls = NULL;
  95        sdl2_window_destroy(scon);
  96        return;
  97    }
  98
  99    if (!scon->real_window) {
 100        sdl2_window_create(scon);
 101        scon->gls = qemu_gl_init_shader();
 102    } else if (old_surface &&
 103               ((surface_width(old_surface)  != surface_width(new_surface)) ||
 104                (surface_height(old_surface) != surface_height(new_surface)))) {
 105        sdl2_window_resize(scon);
 106    }
 107
 108    surface_gl_create_texture(scon->gls, scon->surface);
 109}
 110
 111void sdl2_gl_refresh(DisplayChangeListener *dcl)
 112{
 113    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 114
 115    assert(scon->opengl);
 116
 117    graphic_hw_update(dcl->con);
 118    if (scon->updates && scon->real_window) {
 119        scon->updates = 0;
 120        sdl2_gl_render_surface(scon);
 121    }
 122    sdl2_poll_events(scon);
 123}
 124
 125void sdl2_gl_redraw(struct sdl2_console *scon)
 126{
 127    assert(scon->opengl);
 128
 129    if (scon->scanout_mode) {
 130        /* sdl2_gl_scanout_flush actually only care about
 131         * the first argument. */
 132        return sdl2_gl_scanout_flush(&scon->dcl, 0, 0, 0, 0);
 133    }
 134    if (scon->surface) {
 135        sdl2_gl_render_surface(scon);
 136    }
 137}
 138
 139QEMUGLContext sdl2_gl_create_context(DisplayGLCtx *dgc,
 140                                     QEMUGLParams *params)
 141{
 142    struct sdl2_console *scon = container_of(dgc, struct sdl2_console, dgc);
 143    SDL_GLContext ctx;
 144
 145    assert(scon->opengl);
 146
 147    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 148
 149    SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
 150    if (scon->opts->gl == DISPLAYGL_MODE_ON ||
 151        scon->opts->gl == DISPLAYGL_MODE_CORE) {
 152        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
 153                            SDL_GL_CONTEXT_PROFILE_CORE);
 154    } else if (scon->opts->gl == DISPLAYGL_MODE_ES) {
 155        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
 156                            SDL_GL_CONTEXT_PROFILE_ES);
 157    }
 158    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, params->major_ver);
 159    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, params->minor_ver);
 160
 161    ctx = SDL_GL_CreateContext(scon->real_window);
 162
 163    /* If SDL fail to create a GL context and we use the "on" flag,
 164     * then try to fallback to GLES.
 165     */
 166    if (!ctx && scon->opts->gl == DISPLAYGL_MODE_ON) {
 167        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
 168                            SDL_GL_CONTEXT_PROFILE_ES);
 169        ctx = SDL_GL_CreateContext(scon->real_window);
 170    }
 171    return (QEMUGLContext)ctx;
 172}
 173
 174void sdl2_gl_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx)
 175{
 176    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
 177
 178    SDL_GL_DeleteContext(sdlctx);
 179}
 180
 181int sdl2_gl_make_context_current(DisplayGLCtx *dgc,
 182                                 QEMUGLContext ctx)
 183{
 184    struct sdl2_console *scon = container_of(dgc, struct sdl2_console, dgc);
 185    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
 186
 187    assert(scon->opengl);
 188
 189    return SDL_GL_MakeCurrent(scon->real_window, sdlctx);
 190}
 191
 192void sdl2_gl_scanout_disable(DisplayChangeListener *dcl)
 193{
 194    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 195
 196    assert(scon->opengl);
 197    scon->w = 0;
 198    scon->h = 0;
 199    sdl2_set_scanout_mode(scon, false);
 200}
 201
 202void sdl2_gl_scanout_texture(DisplayChangeListener *dcl,
 203                             uint32_t backing_id,
 204                             bool backing_y_0_top,
 205                             uint32_t backing_width,
 206                             uint32_t backing_height,
 207                             uint32_t x, uint32_t y,
 208                             uint32_t w, uint32_t h,
 209                             void *d3d_tex2d)
 210{
 211    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 212
 213    assert(scon->opengl);
 214    scon->x = x;
 215    scon->y = y;
 216    scon->w = w;
 217    scon->h = h;
 218    scon->y0_top = backing_y_0_top;
 219
 220    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 221
 222    sdl2_set_scanout_mode(scon, true);
 223    egl_fb_setup_for_tex(&scon->guest_fb, backing_width, backing_height,
 224                         backing_id, false);
 225}
 226
 227void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
 228                           uint32_t x, uint32_t y, uint32_t w, uint32_t h)
 229{
 230    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 231    int ww, wh;
 232
 233    assert(scon->opengl);
 234    if (!scon->scanout_mode) {
 235        return;
 236    }
 237    if (!scon->guest_fb.framebuffer) {
 238        return;
 239    }
 240
 241    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 242
 243    SDL_GetWindowSize(scon->real_window, &ww, &wh);
 244    egl_fb_setup_default(&scon->win_fb, ww, wh);
 245    egl_fb_blit(&scon->win_fb, &scon->guest_fb, !scon->y0_top);
 246
 247    SDL_GL_SwapWindow(scon->real_window);
 248}
 249