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
  35#include <epoxy/gl.h>
  36
  37static void sdl2_set_scanout_mode(struct sdl2_console *scon, bool scanout)
  38{
  39    if (scon->scanout_mode == scanout) {
  40        return;
  41    }
  42
  43    scon->scanout_mode = scanout;
  44    if (!scon->scanout_mode) {
  45        if (scon->fbo_id) {
  46            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
  47                                      GL_COLOR_ATTACHMENT0_EXT,
  48                                      GL_TEXTURE_2D, 0, 0);
  49            glDeleteFramebuffers(1, &scon->fbo_id);
  50            glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
  51            scon->fbo_id = 0;
  52        }
  53        if (scon->surface) {
  54            surface_gl_destroy_texture(scon->gls, scon->surface);
  55            surface_gl_create_texture(scon->gls, scon->surface);
  56        }
  57    }
  58}
  59
  60static void sdl2_gl_render_surface(struct sdl2_console *scon)
  61{
  62    int ww, wh;
  63
  64    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
  65    sdl2_set_scanout_mode(scon, false);
  66
  67    SDL_GetWindowSize(scon->real_window, &ww, &wh);
  68    surface_gl_setup_viewport(scon->gls, scon->surface, ww, wh);
  69
  70    surface_gl_render_texture(scon->gls, scon->surface);
  71    SDL_GL_SwapWindow(scon->real_window);
  72}
  73
  74void sdl2_gl_update(DisplayChangeListener *dcl,
  75                    int x, int y, int w, int h)
  76{
  77    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
  78
  79    assert(scon->opengl);
  80
  81    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
  82    surface_gl_update_texture(scon->gls, scon->surface, x, y, w, h);
  83    scon->updates++;
  84}
  85
  86void sdl2_gl_switch(DisplayChangeListener *dcl,
  87                    DisplaySurface *new_surface)
  88{
  89    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
  90    DisplaySurface *old_surface = scon->surface;
  91
  92    assert(scon->opengl);
  93
  94    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
  95    surface_gl_destroy_texture(scon->gls, scon->surface);
  96
  97    scon->surface = new_surface;
  98
  99    if (!new_surface) {
 100        console_gl_fini_context(scon->gls);
 101        scon->gls = NULL;
 102        sdl2_window_destroy(scon);
 103        return;
 104    }
 105
 106    if (!scon->real_window) {
 107        sdl2_window_create(scon);
 108        scon->gls = console_gl_init_context();
 109    } else if (old_surface &&
 110               ((surface_width(old_surface)  != surface_width(new_surface)) ||
 111                (surface_height(old_surface) != surface_height(new_surface)))) {
 112        sdl2_window_resize(scon);
 113    }
 114
 115    surface_gl_create_texture(scon->gls, scon->surface);
 116}
 117
 118void sdl2_gl_refresh(DisplayChangeListener *dcl)
 119{
 120    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 121
 122    assert(scon->opengl);
 123
 124    graphic_hw_update(dcl->con);
 125    if (scon->updates && scon->surface) {
 126        scon->updates = 0;
 127        sdl2_gl_render_surface(scon);
 128    }
 129    sdl2_poll_events(scon);
 130}
 131
 132void sdl2_gl_redraw(struct sdl2_console *scon)
 133{
 134    assert(scon->opengl);
 135
 136    if (scon->surface) {
 137        sdl2_gl_render_surface(scon);
 138    }
 139}
 140
 141QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl,
 142                                     QEMUGLParams *params)
 143{
 144    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 145    SDL_GLContext ctx;
 146
 147    assert(scon->opengl);
 148
 149    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 150
 151    SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
 152    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
 153                        SDL_GL_CONTEXT_PROFILE_CORE);
 154    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, params->major_ver);
 155    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, params->minor_ver);
 156
 157    ctx = SDL_GL_CreateContext(scon->real_window);
 158    return (QEMUGLContext)ctx;
 159}
 160
 161void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx)
 162{
 163    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
 164
 165    SDL_GL_DeleteContext(sdlctx);
 166}
 167
 168int sdl2_gl_make_context_current(DisplayChangeListener *dcl,
 169                                 QEMUGLContext ctx)
 170{
 171    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 172    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
 173
 174    assert(scon->opengl);
 175
 176    return SDL_GL_MakeCurrent(scon->real_window, sdlctx);
 177}
 178
 179QEMUGLContext sdl2_gl_get_current_context(DisplayChangeListener *dcl)
 180{
 181    SDL_GLContext sdlctx;
 182
 183    sdlctx = SDL_GL_GetCurrentContext();
 184    return (QEMUGLContext)sdlctx;
 185}
 186
 187void sdl2_gl_scanout(DisplayChangeListener *dcl,
 188                     uint32_t backing_id, bool backing_y_0_top,
 189                     uint32_t backing_width, uint32_t backing_height,
 190                     uint32_t x, uint32_t y,
 191                     uint32_t w, uint32_t h)
 192{
 193    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 194
 195    assert(scon->opengl);
 196    scon->x = x;
 197    scon->y = y;
 198    scon->w = w;
 199    scon->h = h;
 200    scon->tex_id = backing_id;
 201    scon->y0_top = backing_y_0_top;
 202
 203    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 204
 205    if (scon->tex_id == 0 || scon->w == 0 || scon->h == 0) {
 206        sdl2_set_scanout_mode(scon, false);
 207        return;
 208    }
 209
 210    sdl2_set_scanout_mode(scon, true);
 211    if (!scon->fbo_id) {
 212        glGenFramebuffers(1, &scon->fbo_id);
 213    }
 214
 215    glBindFramebuffer(GL_FRAMEBUFFER_EXT, scon->fbo_id);
 216    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
 217                              GL_TEXTURE_2D, scon->tex_id, 0);
 218}
 219
 220void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
 221                           uint32_t x, uint32_t y, uint32_t w, uint32_t h)
 222{
 223    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 224    int ww, wh, y1, y2;
 225
 226    assert(scon->opengl);
 227    if (!scon->scanout_mode) {
 228        return;
 229    }
 230    if (!scon->fbo_id) {
 231        return;
 232    }
 233
 234    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 235
 236    glBindFramebuffer(GL_READ_FRAMEBUFFER, scon->fbo_id);
 237    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
 238
 239    SDL_GetWindowSize(scon->real_window, &ww, &wh);
 240    glViewport(0, 0, ww, wh);
 241    y1 = scon->y0_top ? 0 : scon->h;
 242    y2 = scon->y0_top ? scon->h : 0;
 243    glBlitFramebuffer(0, y1, scon->w, y2,
 244                      0, 0, ww, wh,
 245                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
 246    glBindFramebuffer(GL_FRAMEBUFFER_EXT, scon->fbo_id);
 247
 248    SDL_GL_SwapWindow(scon->real_window);
 249}
 250