diff options
-rw-r--r-- | include/ui/sdl2.h | 22 | ||||
-rw-r--r-- | ui/sdl2-gl.c | 135 | ||||
-rw-r--r-- | ui/sdl2.c | 7 |
3 files changed, 163 insertions, 1 deletions
diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h index 2fdad8f300..b7ac38f198 100644 --- a/include/ui/sdl2.h +++ b/include/ui/sdl2.h @@ -15,12 +15,18 @@ struct sdl2_console { SDL_Renderer *real_renderer; int idx; int last_vm_running; /* per console for caption reasons */ - int x, y; + int x, y, w, h; int hidden; int opengl; int updates; SDL_GLContext winctx; +#ifdef CONFIG_OPENGL ConsoleGLState *gls; + GLuint tex_id; + GLuint fbo_id; + bool y0_top; + bool scanout_mode; +#endif }; void sdl2_window_create(struct sdl2_console *scon); @@ -48,4 +54,18 @@ void sdl2_gl_switch(DisplayChangeListener *dcl, void sdl2_gl_refresh(DisplayChangeListener *dcl); void sdl2_gl_redraw(struct sdl2_console *scon); +QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params); +void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx); +int sdl2_gl_make_context_current(DisplayChangeListener *dcl, + QEMUGLContext ctx); +QEMUGLContext sdl2_gl_get_current_context(DisplayChangeListener *dcl); + +void sdl2_gl_scanout(DisplayChangeListener *dcl, + uint32_t backing_id, bool backing_y_0_top, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h); +void sdl2_gl_scanout_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h); + #endif /* SDL2_H */ diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c index b604c0671e..2bb3d06bab 100644 --- a/ui/sdl2-gl.c +++ b/ui/sdl2-gl.c @@ -31,11 +31,37 @@ #include "ui/sdl2.h" #include "sysemu/sysemu.h" +#include <epoxy/gl.h> + +static void sdl2_set_scanout_mode(struct sdl2_console *scon, bool scanout) +{ + if (scon->scanout_mode == scanout) { + return; + } + + scon->scanout_mode = scanout; + if (!scon->scanout_mode) { + if (scon->fbo_id) { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, 0, 0); + glDeleteFramebuffers(1, &scon->fbo_id); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + scon->fbo_id = 0; + } + if (scon->surface) { + surface_gl_destroy_texture(scon->gls, scon->surface); + surface_gl_create_texture(scon->gls, scon->surface); + } + } +} + static void sdl2_gl_render_surface(struct sdl2_console *scon) { int ww, wh; SDL_GL_MakeCurrent(scon->real_window, scon->winctx); + sdl2_set_scanout_mode(scon, false); SDL_GetWindowSize(scon->real_window, &ww, &wh); surface_gl_setup_viewport(scon->gls, scon->surface, ww, wh); @@ -110,3 +136,112 @@ void sdl2_gl_redraw(struct sdl2_console *scon) sdl2_gl_render_surface(scon); } } + +QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params) +{ + struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); + SDL_GLContext ctx; + + assert(scon->opengl); + + SDL_GL_MakeCurrent(scon->real_window, scon->winctx); + + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, params->major_ver); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, params->minor_ver); + + ctx = SDL_GL_CreateContext(scon->real_window); + return (QEMUGLContext)ctx; +} + +void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx) +{ + SDL_GLContext sdlctx = (SDL_GLContext)ctx; + + SDL_GL_DeleteContext(sdlctx); +} + +int sdl2_gl_make_context_current(DisplayChangeListener *dcl, + QEMUGLContext ctx) +{ + struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); + SDL_GLContext sdlctx = (SDL_GLContext)ctx; + + assert(scon->opengl); + + return SDL_GL_MakeCurrent(scon->real_window, sdlctx); +} + +QEMUGLContext sdl2_gl_get_current_context(DisplayChangeListener *dcl) +{ + SDL_GLContext sdlctx; + + sdlctx = SDL_GL_GetCurrentContext(); + return (QEMUGLContext)sdlctx; +} + +void sdl2_gl_scanout(DisplayChangeListener *dcl, + uint32_t backing_id, bool backing_y_0_top, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h) +{ + struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); + + assert(scon->opengl); + scon->x = x; + scon->y = y; + scon->w = w; + scon->h = h; + scon->tex_id = backing_id; + scon->y0_top = backing_y_0_top; + + SDL_GL_MakeCurrent(scon->real_window, scon->winctx); + + if (scon->tex_id == 0 || scon->w == 0 || scon->h == 0) { + sdl2_set_scanout_mode(scon, false); + return; + } + + sdl2_set_scanout_mode(scon, true); + if (!scon->fbo_id) { + glGenFramebuffers(1, &scon->fbo_id); + } + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, scon->fbo_id); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, scon->tex_id, 0); +} + +void sdl2_gl_scanout_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); + int ww, wh, y1, y2; + + assert(scon->opengl); + if (!scon->scanout_mode) { + return; + } + if (!scon->fbo_id) { + return; + } + + SDL_GL_MakeCurrent(scon->real_window, scon->winctx); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, scon->fbo_id); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + SDL_GetWindowSize(scon->real_window, &ww, &wh); + glViewport(0, 0, ww, wh); + y1 = scon->y0_top ? 0 : scon->h; + y2 = scon->y0_top ? scon->h : 0; + glBlitFramebuffer(0, y1, scon->w, y2, + 0, 0, ww, wh, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, scon->fbo_id); + + SDL_GL_SwapWindow(scon->real_window); +} @@ -700,6 +700,13 @@ static const DisplayChangeListenerOps dcl_gl_ops = { .dpy_refresh = sdl2_gl_refresh, .dpy_mouse_set = sdl_mouse_warp, .dpy_cursor_define = sdl_mouse_define, + + .dpy_gl_ctx_create = sdl2_gl_create_context, + .dpy_gl_ctx_destroy = sdl2_gl_destroy_context, + .dpy_gl_ctx_make_current = sdl2_gl_make_context_current, + .dpy_gl_ctx_get_current = sdl2_gl_get_current_context, + .dpy_gl_scanout = sdl2_gl_scanout, + .dpy_gl_update = sdl2_gl_scanout_flush, }; #endif |