xref: /openbmc/qemu/ui/sdl2-gl.c (revision b8eada54b2ad8a7d98d93d5ab4d3e888c5880097)
10b71a5d5SGerd Hoffmann /*
20b71a5d5SGerd Hoffmann  * QEMU SDL display driver -- opengl support
30b71a5d5SGerd Hoffmann  *
40b71a5d5SGerd Hoffmann  * Copyright (c) 2014 Red Hat
50b71a5d5SGerd Hoffmann  *
60b71a5d5SGerd Hoffmann  * Authors:
70b71a5d5SGerd Hoffmann  *     Gerd Hoffmann <kraxel@redhat.com>
80b71a5d5SGerd Hoffmann  *
90b71a5d5SGerd Hoffmann  * Permission is hereby granted, free of charge, to any person obtaining a copy
100b71a5d5SGerd Hoffmann  * of this software and associated documentation files (the "Software"), to deal
110b71a5d5SGerd Hoffmann  * in the Software without restriction, including without limitation the rights
120b71a5d5SGerd Hoffmann  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
130b71a5d5SGerd Hoffmann  * copies of the Software, and to permit persons to whom the Software is
140b71a5d5SGerd Hoffmann  * furnished to do so, subject to the following conditions:
150b71a5d5SGerd Hoffmann  *
160b71a5d5SGerd Hoffmann  * The above copyright notice and this permission notice shall be included in
170b71a5d5SGerd Hoffmann  * all copies or substantial portions of the Software.
180b71a5d5SGerd Hoffmann  *
190b71a5d5SGerd Hoffmann  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
200b71a5d5SGerd Hoffmann  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
210b71a5d5SGerd Hoffmann  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
220b71a5d5SGerd Hoffmann  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
230b71a5d5SGerd Hoffmann  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
240b71a5d5SGerd Hoffmann  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
250b71a5d5SGerd Hoffmann  * THE SOFTWARE.
260b71a5d5SGerd Hoffmann  */
270b71a5d5SGerd Hoffmann 
28e16f4c87SPeter Maydell #include "qemu/osdep.h"
290b71a5d5SGerd Hoffmann #include "ui/console.h"
300b71a5d5SGerd Hoffmann #include "ui/input.h"
310b71a5d5SGerd Hoffmann #include "ui/sdl2.h"
320b71a5d5SGerd Hoffmann 
sdl2_set_scanout_mode(struct sdl2_console * scon,bool scanout)33cb47dc9aSGerd Hoffmann static void sdl2_set_scanout_mode(struct sdl2_console *scon, bool scanout)
34cb47dc9aSGerd Hoffmann {
35cb47dc9aSGerd Hoffmann     if (scon->scanout_mode == scanout) {
36cb47dc9aSGerd Hoffmann         return;
37cb47dc9aSGerd Hoffmann     }
38cb47dc9aSGerd Hoffmann 
39cb47dc9aSGerd Hoffmann     scon->scanout_mode = scanout;
40cb47dc9aSGerd Hoffmann     if (!scon->scanout_mode) {
41371c4ef6SGerd Hoffmann         egl_fb_destroy(&scon->guest_fb);
42cb47dc9aSGerd Hoffmann         if (scon->surface) {
43cb47dc9aSGerd Hoffmann             surface_gl_destroy_texture(scon->gls, scon->surface);
44cb47dc9aSGerd Hoffmann             surface_gl_create_texture(scon->gls, scon->surface);
45cb47dc9aSGerd Hoffmann         }
46cb47dc9aSGerd Hoffmann     }
47cb47dc9aSGerd Hoffmann }
48cb47dc9aSGerd Hoffmann 
sdl2_gl_render_surface(struct sdl2_console * scon)490b71a5d5SGerd Hoffmann static void sdl2_gl_render_surface(struct sdl2_console *scon)
500b71a5d5SGerd Hoffmann {
510b71a5d5SGerd Hoffmann     int ww, wh;
520b71a5d5SGerd Hoffmann 
530b71a5d5SGerd Hoffmann     SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
54cb47dc9aSGerd Hoffmann     sdl2_set_scanout_mode(scon, false);
550b71a5d5SGerd Hoffmann 
560b71a5d5SGerd Hoffmann     SDL_GetWindowSize(scon->real_window, &ww, &wh);
570b71a5d5SGerd Hoffmann     surface_gl_setup_viewport(scon->gls, scon->surface, ww, wh);
580b71a5d5SGerd Hoffmann 
590b71a5d5SGerd Hoffmann     surface_gl_render_texture(scon->gls, scon->surface);
600b71a5d5SGerd Hoffmann     SDL_GL_SwapWindow(scon->real_window);
610b71a5d5SGerd Hoffmann }
620b71a5d5SGerd Hoffmann 
sdl2_gl_update(DisplayChangeListener * dcl,int x,int y,int w,int h)630b71a5d5SGerd Hoffmann void sdl2_gl_update(DisplayChangeListener *dcl,
640b71a5d5SGerd Hoffmann                     int x, int y, int w, int h)
650b71a5d5SGerd Hoffmann {
660b71a5d5SGerd Hoffmann     struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
670b71a5d5SGerd Hoffmann 
680b71a5d5SGerd Hoffmann     assert(scon->opengl);
690b71a5d5SGerd Hoffmann 
70b3a654d8SMarc-André Lureau     if (!scon->real_window) {
71b3a654d8SMarc-André Lureau         return;
72b3a654d8SMarc-André Lureau     }
73b3a654d8SMarc-André Lureau 
740b71a5d5SGerd Hoffmann     SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
750b71a5d5SGerd Hoffmann     surface_gl_update_texture(scon->gls, scon->surface, x, y, w, h);
760b71a5d5SGerd Hoffmann     scon->updates++;
770b71a5d5SGerd Hoffmann }
780b71a5d5SGerd Hoffmann 
sdl2_gl_switch(DisplayChangeListener * dcl,DisplaySurface * new_surface)790b71a5d5SGerd Hoffmann void sdl2_gl_switch(DisplayChangeListener *dcl,
800b71a5d5SGerd Hoffmann                     DisplaySurface *new_surface)
810b71a5d5SGerd Hoffmann {
820b71a5d5SGerd Hoffmann     struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
830b71a5d5SGerd Hoffmann     DisplaySurface *old_surface = scon->surface;
840b71a5d5SGerd Hoffmann 
850b71a5d5SGerd Hoffmann     assert(scon->opengl);
860b71a5d5SGerd Hoffmann 
870b71a5d5SGerd Hoffmann     SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
880b71a5d5SGerd Hoffmann     surface_gl_destroy_texture(scon->gls, scon->surface);
890b71a5d5SGerd Hoffmann 
900b71a5d5SGerd Hoffmann     scon->surface = new_surface;
910b71a5d5SGerd Hoffmann 
929badf12aSGerd Hoffmann     if (surface_is_placeholder(new_surface) && qemu_console_get_index(dcl->con)) {
9346e19e14SGerd Hoffmann         qemu_gl_fini_shader(scon->gls);
940b71a5d5SGerd Hoffmann         scon->gls = NULL;
950b71a5d5SGerd Hoffmann         sdl2_window_destroy(scon);
960b71a5d5SGerd Hoffmann         return;
970b71a5d5SGerd Hoffmann     }
980b71a5d5SGerd Hoffmann 
990b71a5d5SGerd Hoffmann     if (!scon->real_window) {
1000b71a5d5SGerd Hoffmann         sdl2_window_create(scon);
10146e19e14SGerd Hoffmann         scon->gls = qemu_gl_init_shader();
1020b71a5d5SGerd Hoffmann     } else if (old_surface &&
1030b71a5d5SGerd Hoffmann                ((surface_width(old_surface)  != surface_width(new_surface)) ||
1040b71a5d5SGerd Hoffmann                 (surface_height(old_surface) != surface_height(new_surface)))) {
1050b71a5d5SGerd Hoffmann         sdl2_window_resize(scon);
1060b71a5d5SGerd Hoffmann     }
1070b71a5d5SGerd Hoffmann 
1080b71a5d5SGerd Hoffmann     surface_gl_create_texture(scon->gls, scon->surface);
1090b71a5d5SGerd Hoffmann }
1100b71a5d5SGerd Hoffmann 
sdl2_gl_refresh(DisplayChangeListener * dcl)1110b71a5d5SGerd Hoffmann void sdl2_gl_refresh(DisplayChangeListener *dcl)
1120b71a5d5SGerd Hoffmann {
1130b71a5d5SGerd Hoffmann     struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
1140b71a5d5SGerd Hoffmann 
1150b71a5d5SGerd Hoffmann     assert(scon->opengl);
1160b71a5d5SGerd Hoffmann 
1170b71a5d5SGerd Hoffmann     graphic_hw_update(dcl->con);
118c821a58eSAkihiko Odaki     if (scon->updates && scon->real_window) {
1190b71a5d5SGerd Hoffmann         scon->updates = 0;
1200b71a5d5SGerd Hoffmann         sdl2_gl_render_surface(scon);
1210b71a5d5SGerd Hoffmann     }
1220b71a5d5SGerd Hoffmann     sdl2_poll_events(scon);
1230b71a5d5SGerd Hoffmann }
1240b71a5d5SGerd Hoffmann 
sdl2_gl_redraw(struct sdl2_console * scon)1250b71a5d5SGerd Hoffmann void sdl2_gl_redraw(struct sdl2_console *scon)
1260b71a5d5SGerd Hoffmann {
1270b71a5d5SGerd Hoffmann     assert(scon->opengl);
1280b71a5d5SGerd Hoffmann 
12977f60fb4STao Wu     if (scon->scanout_mode) {
13077f60fb4STao Wu         /* sdl2_gl_scanout_flush actually only care about
13177f60fb4STao Wu          * the first argument. */
13277f60fb4STao Wu         return sdl2_gl_scanout_flush(&scon->dcl, 0, 0, 0, 0);
13377f60fb4STao Wu     }
1340b71a5d5SGerd Hoffmann     if (scon->surface) {
1350b71a5d5SGerd Hoffmann         sdl2_gl_render_surface(scon);
1360b71a5d5SGerd Hoffmann     }
1370b71a5d5SGerd Hoffmann }
138cb47dc9aSGerd Hoffmann 
sdl2_gl_create_context(DisplayGLCtx * dgc,QEMUGLParams * params)1395e79d516SMarc-André Lureau QEMUGLContext sdl2_gl_create_context(DisplayGLCtx *dgc,
140cb47dc9aSGerd Hoffmann                                      QEMUGLParams *params)
141cb47dc9aSGerd Hoffmann {
1425e79d516SMarc-André Lureau     struct sdl2_console *scon = container_of(dgc, struct sdl2_console, dgc);
143cb47dc9aSGerd Hoffmann     SDL_GLContext ctx;
144cb47dc9aSGerd Hoffmann 
145cb47dc9aSGerd Hoffmann     assert(scon->opengl);
146cb47dc9aSGerd Hoffmann 
147cb47dc9aSGerd Hoffmann     SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
148cb47dc9aSGerd Hoffmann 
149cb47dc9aSGerd Hoffmann     SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
150*154fd4d1SMarkus Armbruster     if (scon->opts->gl == DISPLAY_GL_MODE_ON ||
151*154fd4d1SMarkus Armbruster         scon->opts->gl == DISPLAY_GL_MODE_CORE) {
152cb47dc9aSGerd Hoffmann         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
153cb47dc9aSGerd Hoffmann                             SDL_GL_CONTEXT_PROFILE_CORE);
154*154fd4d1SMarkus Armbruster     } else if (scon->opts->gl == DISPLAY_GL_MODE_ES) {
1554867e47cSElie Tournier         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
1564867e47cSElie Tournier                             SDL_GL_CONTEXT_PROFILE_ES);
1574867e47cSElie Tournier     }
158cb47dc9aSGerd Hoffmann     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, params->major_ver);
159cb47dc9aSGerd Hoffmann     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, params->minor_ver);
160cb47dc9aSGerd Hoffmann 
161cb47dc9aSGerd Hoffmann     ctx = SDL_GL_CreateContext(scon->real_window);
1624867e47cSElie Tournier 
1634867e47cSElie Tournier     /* If SDL fail to create a GL context and we use the "on" flag,
1644867e47cSElie Tournier      * then try to fallback to GLES.
1654867e47cSElie Tournier      */
166*154fd4d1SMarkus Armbruster     if (!ctx && scon->opts->gl == DISPLAY_GL_MODE_ON) {
1674867e47cSElie Tournier         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
1684867e47cSElie Tournier                             SDL_GL_CONTEXT_PROFILE_ES);
1694867e47cSElie Tournier         ctx = SDL_GL_CreateContext(scon->real_window);
1704867e47cSElie Tournier     }
171cb47dc9aSGerd Hoffmann     return (QEMUGLContext)ctx;
172cb47dc9aSGerd Hoffmann }
173cb47dc9aSGerd Hoffmann 
sdl2_gl_destroy_context(DisplayGLCtx * dgc,QEMUGLContext ctx)1745e79d516SMarc-André Lureau void sdl2_gl_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx)
175cb47dc9aSGerd Hoffmann {
176cb47dc9aSGerd Hoffmann     SDL_GLContext sdlctx = (SDL_GLContext)ctx;
177cb47dc9aSGerd Hoffmann 
178cb47dc9aSGerd Hoffmann     SDL_GL_DeleteContext(sdlctx);
179cb47dc9aSGerd Hoffmann }
180cb47dc9aSGerd Hoffmann 
sdl2_gl_make_context_current(DisplayGLCtx * dgc,QEMUGLContext ctx)1815e79d516SMarc-André Lureau int sdl2_gl_make_context_current(DisplayGLCtx *dgc,
182cb47dc9aSGerd Hoffmann                                  QEMUGLContext ctx)
183cb47dc9aSGerd Hoffmann {
1845e79d516SMarc-André Lureau     struct sdl2_console *scon = container_of(dgc, struct sdl2_console, dgc);
185cb47dc9aSGerd Hoffmann     SDL_GLContext sdlctx = (SDL_GLContext)ctx;
186cb47dc9aSGerd Hoffmann 
187cb47dc9aSGerd Hoffmann     assert(scon->opengl);
188cb47dc9aSGerd Hoffmann 
189cb47dc9aSGerd Hoffmann     return SDL_GL_MakeCurrent(scon->real_window, sdlctx);
190cb47dc9aSGerd Hoffmann }
191cb47dc9aSGerd Hoffmann 
sdl2_gl_scanout_disable(DisplayChangeListener * dcl)192db6cdfbeSGerd Hoffmann void sdl2_gl_scanout_disable(DisplayChangeListener *dcl)
193db6cdfbeSGerd Hoffmann {
194db6cdfbeSGerd Hoffmann     struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
195db6cdfbeSGerd Hoffmann 
196db6cdfbeSGerd Hoffmann     assert(scon->opengl);
197db6cdfbeSGerd Hoffmann     scon->w = 0;
198db6cdfbeSGerd Hoffmann     scon->h = 0;
199db6cdfbeSGerd Hoffmann     sdl2_set_scanout_mode(scon, false);
200db6cdfbeSGerd Hoffmann }
201db6cdfbeSGerd Hoffmann 
sdl2_gl_scanout_texture(DisplayChangeListener * dcl,uint32_t backing_id,bool backing_y_0_top,uint32_t backing_width,uint32_t backing_height,uint32_t x,uint32_t y,uint32_t w,uint32_t h,void * d3d_tex2d)202f4c36bdaSGerd Hoffmann void sdl2_gl_scanout_texture(DisplayChangeListener *dcl,
203f4c36bdaSGerd Hoffmann                              uint32_t backing_id,
204f4c36bdaSGerd Hoffmann                              bool backing_y_0_top,
205f4c36bdaSGerd Hoffmann                              uint32_t backing_width,
206f4c36bdaSGerd Hoffmann                              uint32_t backing_height,
207cb47dc9aSGerd Hoffmann                              uint32_t x, uint32_t y,
208bf41ab61SMarc-André Lureau                              uint32_t w, uint32_t h,
209bf41ab61SMarc-André Lureau                              void *d3d_tex2d)
210cb47dc9aSGerd Hoffmann {
211cb47dc9aSGerd Hoffmann     struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
212cb47dc9aSGerd Hoffmann 
213cb47dc9aSGerd Hoffmann     assert(scon->opengl);
214cb47dc9aSGerd Hoffmann     scon->x = x;
215cb47dc9aSGerd Hoffmann     scon->y = y;
216cb47dc9aSGerd Hoffmann     scon->w = w;
217cb47dc9aSGerd Hoffmann     scon->h = h;
218cb47dc9aSGerd Hoffmann     scon->y0_top = backing_y_0_top;
219cb47dc9aSGerd Hoffmann 
220cb47dc9aSGerd Hoffmann     SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
221cb47dc9aSGerd Hoffmann 
222cb47dc9aSGerd Hoffmann     sdl2_set_scanout_mode(scon, true);
22374083f9cSGerd Hoffmann     egl_fb_setup_for_tex(&scon->guest_fb, backing_width, backing_height,
22474083f9cSGerd Hoffmann                          backing_id, false);
225cb47dc9aSGerd Hoffmann }
226cb47dc9aSGerd Hoffmann 
sdl2_gl_scanout_flush(DisplayChangeListener * dcl,uint32_t x,uint32_t y,uint32_t w,uint32_t h)227cb47dc9aSGerd Hoffmann void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
228cb47dc9aSGerd Hoffmann                            uint32_t x, uint32_t y, uint32_t w, uint32_t h)
229cb47dc9aSGerd Hoffmann {
230cb47dc9aSGerd Hoffmann     struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
231371c4ef6SGerd Hoffmann     int ww, wh;
232cb47dc9aSGerd Hoffmann 
233cb47dc9aSGerd Hoffmann     assert(scon->opengl);
234cb47dc9aSGerd Hoffmann     if (!scon->scanout_mode) {
235cb47dc9aSGerd Hoffmann         return;
236cb47dc9aSGerd Hoffmann     }
237371c4ef6SGerd Hoffmann     if (!scon->guest_fb.framebuffer) {
238cb47dc9aSGerd Hoffmann         return;
239cb47dc9aSGerd Hoffmann     }
240cb47dc9aSGerd Hoffmann 
241cb47dc9aSGerd Hoffmann     SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
242cb47dc9aSGerd Hoffmann 
243cb47dc9aSGerd Hoffmann     SDL_GetWindowSize(scon->real_window, &ww, &wh);
244371c4ef6SGerd Hoffmann     egl_fb_setup_default(&scon->win_fb, ww, wh);
245371c4ef6SGerd Hoffmann     egl_fb_blit(&scon->win_fb, &scon->guest_fb, !scon->y0_top);
246cb47dc9aSGerd Hoffmann 
247cb47dc9aSGerd Hoffmann     SDL_GL_SwapWindow(scon->real_window);
248cb47dc9aSGerd Hoffmann }
249