qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

sdl2-gl.c (7637B)


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