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