From 9db334275fa9879f3aceb623ff89dca0862a0110 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 8 Jun 2020 09:14:01 -0400 Subject: [PATCH] Added logic to allow for switching from openGL to cairo draw functions. There is still an issue with the GTK draw update stops getting called when switch from openGL to cairo. --- src/drivers/sdl/glxwin.cpp | 81 +++++++++++++--- src/drivers/sdl/glxwin.h | 10 ++ src/drivers/sdl/gui.cpp | 104 ++++++++++++++++---- src/drivers/sdl/gui.h | 5 + src/drivers/sdl/sdl-video.cpp | 178 ++++++++++++++++++---------------- 5 files changed, 266 insertions(+), 112 deletions(-) diff --git a/src/drivers/sdl/glxwin.cpp b/src/drivers/sdl/glxwin.cpp index 12a84801..6e496dfe 100644 --- a/src/drivers/sdl/glxwin.cpp +++ b/src/drivers/sdl/glxwin.cpp @@ -30,7 +30,7 @@ static XVisualInfo *vi = NULL; static Colormap cmap; static XSetWindowAttributes swa; static Window win; -static GLXContext glc; +static GLXContext glc = NULL; static XWindowAttributes gwa; static XEvent xev; @@ -77,6 +77,10 @@ static glxwin_shm_t *open_shm(void) sem_init( &vaddr->sem, 1, 1 ); + vaddr->ncol = 256; + vaddr->nrow = 256; + vaddr->pitch = 256 * 4; + return vaddr; } //************************************************************************ @@ -84,6 +88,11 @@ static void genTextures(void) { int ipolate = 1; + if ( gltexture ) + { + printf("GL Texture already exists\n"); + return; + } glEnable(GL_TEXTURE_2D); glGenTextures(1, &gltexture); @@ -131,11 +140,18 @@ static int open_window(void) XStoreName(dpy, win, "FCEUX VIEWPORT"); - glc = glXCreateContext(dpy, vi, NULL, GL_TRUE); - if ( glc == NULL ) { - printf("Error: glXCreateContext Failed\n"); + glc = glXCreateContext(dpy, vi, NULL, GL_TRUE); + + if ( glc == NULL ) + { + printf("Error: glXCreateContext Failed\n"); + } + } + else + { + printf("GLX Context Already Exists\n"); } glXMakeCurrent(dpy, win, glc); @@ -166,11 +182,13 @@ static void print_pixbuf(void) //************************************************************************ static void render_image(void) { - int l=0, r=GLX_NES_WIDTH; - int t=0, b=GLX_NES_HEIGHT; + static int null_glc_error = 0; + int l=0, r=glx_shm->ncol; + int t=0, b=glx_shm->nrow; + + float xscale = (float)screen_width / (float)glx_shm->ncol; + float yscale = (float)screen_height / (float)glx_shm->nrow; - float xscale = (float)screen_width / (float)GLX_NES_WIDTH; - float yscale = (float)screen_height / (float)GLX_NES_HEIGHT; if (xscale < yscale ) { yscale = xscale; @@ -184,6 +202,17 @@ static void render_image(void) int sx=(screen_width-rw)/2; int sy=(screen_height-rh)/2; + if ( glc == NULL ) + { + if ( !null_glc_error ) + { + printf("Error: GLX Render has NULL Context\n"); + null_glc_error = 1; + } + return; + } + null_glc_error = 0; + glXMakeCurrent(dpy, win, glc); //printf("Viewport: (%i,%i) %i %i %i %i \n", // screen_width, screen_height, sx, sy, rw, rh ); @@ -251,7 +280,7 @@ static int mainWindowLoop(void) //glViewport(0, 0, gwa.width, gwa.height); //DrawAQuad(); glXSwapBuffers(dpy, win); - printf("Expose\n"); + //printf("Expose\n"); } else if (xev.type == ConfigureNotify) { @@ -267,7 +296,7 @@ static int mainWindowLoop(void) //genTextures(); - printf("Resize Request: (%i,%i)\n", screen_width, screen_height ); + //printf("Resize Request: (%i,%i)\n", screen_width, screen_height ); render_image(); //glViewport(0, 0, gwa.width, gwa.height); //DrawAQuad(); @@ -350,6 +379,8 @@ int init_gtk3_GLXContext( void ) { XWindowAttributes xattrb; + printf("Init GLX Context\n"); + GdkWindow *gdkWin = gtk_widget_get_window(evbox); if ( gdkWin == NULL ) @@ -390,11 +421,14 @@ int init_gtk3_GLXContext( void ) printf("\n\tvisual %p selected\n", (void *)vi->visualid); /* %p creates hexadecimal output like in glxinfo */ } - glc = glXCreateContext(dpy, vi, NULL, GL_TRUE); - if ( glc == NULL ) { - printf("Error: glXCreateContext Failed\n"); + glc = glXCreateContext(dpy, vi, NULL, GL_TRUE); + + if ( glc == NULL ) + { + printf("Error: glXCreateContext Failed\n"); + } } glXMakeCurrent(dpy, win, glc); @@ -412,6 +446,27 @@ int init_gtk3_GLXContext( void ) return 0; } //************************************************************************ +int destroy_gtk3_GLXContext(void) +{ + if ( dpy != NULL ) + { + glXMakeCurrent(dpy, None, NULL); + } + + if (gltexture) + { + printf("Destroying GLX Texture\n"); + glDeleteTextures(1, &gltexture); + gltexture=0; + } + if ( glc != NULL ) + { + printf("Destroying GLX Context\n"); + glXDestroyContext(dpy, glc); glc = NULL; + } + return 0; +} +//************************************************************************ int gtk3_glx_render(void) { screen_width = gtk_draw_area_width; diff --git a/src/drivers/sdl/glxwin.h b/src/drivers/sdl/glxwin.h index ed1b64e5..2f2fad40 100644 --- a/src/drivers/sdl/glxwin.h +++ b/src/drivers/sdl/glxwin.h @@ -11,6 +11,7 @@ int spawn_glxwin( int flags ); int init_gtk3_GLXContext( void ); +int destroy_gtk3_GLXContext( void ); int gtk3_glx_render(void); @@ -25,6 +26,10 @@ struct glxwin_shm_t uint32_t blit_count; sem_t sem; + int ncol; + int nrow; + int pitch; + // Pass Key Events back to GTK Gui struct { @@ -56,6 +61,11 @@ struct glxwin_shm_t } guiEvent; uint32_t pixbuf[65536]; // 256 x 256 + + void clear_pixbuf(void) + { + memset( pixbuf, 0, sizeof(pixbuf) ); + } }; extern glxwin_shm_t *glx_shm; diff --git a/src/drivers/sdl/gui.cpp b/src/drivers/sdl/gui.cpp index 796ca4be..90e006ac 100644 --- a/src/drivers/sdl/gui.cpp +++ b/src/drivers/sdl/gui.cpp @@ -85,6 +85,8 @@ unsigned int gtk_draw_area_height = NES_HEIGHT; static GtkTreeStore *hotkey_store = NULL; static cairo_surface_t *cairo_surface = NULL; static int *cairo_pix_remapper = NULL; +static int numRendLines = 0; +static void cairo_recalc_mapper(void); static gint convertKeypress (GtkWidget * grab, GdkEventKey * event, gpointer user_data); @@ -3104,6 +3106,7 @@ union cairo_pixel_t static void transferPix2CairoSurface(void) { union cairo_pixel_t *p; + union cairo_pixel_t *g; int x, y, i,j, w, h; if ( cairo_surface == NULL ) @@ -3112,10 +3115,16 @@ static void transferPix2CairoSurface(void) } cairo_surface_flush( cairo_surface ); + if ( numRendLines != glx_shm->nrow ) + { + cairo_recalc_mapper(); + } + w = cairo_image_surface_get_width (cairo_surface); h = cairo_image_surface_get_height (cairo_surface); p = (cairo_pixel_t*)cairo_image_surface_get_data (cairo_surface); + g = (cairo_pixel_t*)glx_shm->pixbuf; i=0; for (y=0; ypixbuf[j]; + // RGBA to ARGB + #ifdef LSB_FIRST + p[i].u8[2] = g[j].u8[0]; + p[i].u8[1] = g[j].u8[1]; + p[i].u8[0] = g[j].u8[2]; + p[i].u8[3] = g[j].u8[3]; + #else + p[i].u32 = g[j].u32; + #endif //p[i].u32 = 0xffffffff; } i++; @@ -3268,7 +3285,7 @@ static void cairo_recalc_mapper(void) { int w, h, s; int i, j, x, y; - int sw, sh, rx, ry; + int sw, sh, rx, ry, gw, gh; int llx, lly, urx, ury; float sx, sy, nw, nh; @@ -3276,6 +3293,9 @@ static void cairo_recalc_mapper(void) h = cairo_image_surface_get_height (cairo_surface); s = w * h * 4; + gw = glx_shm->ncol; + gh = glx_shm->nrow; + if ( cairo_pix_remapper != NULL ) { ::free( cairo_pix_remapper ); cairo_pix_remapper = NULL; @@ -3289,8 +3309,8 @@ static void cairo_recalc_mapper(void) } memset( cairo_pix_remapper, 0, s ); - sx = (float)w / (float)GLX_NES_WIDTH; - sy = (float)h / (float)GLX_NES_HEIGHT; + sx = (float)w / (float)gw; + sy = (float)h / (float)gh; if (sx < sy ) { @@ -3301,8 +3321,8 @@ static void cairo_recalc_mapper(void) sx = sy; } - sw = (int) ( (float)GLX_NES_WIDTH * sx ); - sh = (int) ( (float)GLX_NES_HEIGHT * sy ); + sw = (int) ( (float)gw * sx ); + sh = (int) ( (float)gh * sy ); llx = (w - sw) / 2; lly = (h - sh) / 2; @@ -3332,8 +3352,8 @@ static void cairo_recalc_mapper(void) nw = (float)(x - llx) / (float)sw; nh = (float)(y - lly) / (float)sh; - rx = (int)((float)GLX_NES_WIDTH * nw); - ry = (int)((float)GLX_NES_HEIGHT * nh); + rx = (int)((float)gw * nw); + ry = (int)((float)gh * nh); if ( rx < 0 ) { @@ -3353,7 +3373,6 @@ static void cairo_recalc_mapper(void) } j = (ry * GLX_NES_WIDTH) + rx; - //j = (rx * GLX_NES_WIDTH) + ry; cairo_pix_remapper[i] = j; i++; @@ -3362,9 +3381,10 @@ static void cairo_recalc_mapper(void) } } } + numRendLines = gh; } -static void cairo_handle_resize( int width, int height ) +static void cairo_handle_resize(void) { int w, h; cairo_format_t cairo_format; @@ -3376,18 +3396,15 @@ static void cairo_handle_resize( int width, int height ) w = gtk_widget_get_allocated_width( evbox ); h = gtk_widget_get_allocated_height( evbox ); + //cairo_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, w, h ); cairo_surface = cairo_image_surface_create( CAIRO_FORMAT_RGB24, w, h ); printf("Cairo Surface: %p \n", cairo_surface ); cairo_format = cairo_image_surface_get_format( cairo_surface ); - printf("Cairo Format: %i \n", cairo_format ); + //printf("Cairo Format: %i \n", cairo_format ); - if ( cairo_format == CAIRO_FORMAT_ARGB32 ) - { - printf("Cairo Format: ARGB32 \n" ); - } cairo_recalc_mapper(); guiClearSurface(); @@ -3397,6 +3414,54 @@ static void cairo_handle_resize( int width, int height ) //cairo_surface_mark_dirty( cairo_surface ); } +int destroy_gui_video( void ) +{ + printf("Destroy GUI Video\n"); + + destroy_cairo_screen(); + + destroy_gtk3_GLXContext(); + + return 0; +} + +int init_gui_video( int use_openGL ) +{ + drawAreaGL = use_openGL; + useCairoDraw = !drawAreaGL; + + if ( use_openGL ) + { + destroy_cairo_screen(); + init_gtk3_GLXContext(); + } + else + { + destroy_gtk3_GLXContext(); + init_cairo_screen(); + } + return 0; +} + +void init_cairo_screen(void) +{ + cairo_handle_resize(); +} + +void destroy_cairo_screen(void) +{ + if (cairo_surface) + { + printf("Destroying Cairo Surface\n"); + cairo_surface_destroy (cairo_surface); cairo_surface = NULL; + } + if ( cairo_pix_remapper != NULL ) + { + printf("Destroying Cairo Pixel Remapper\n"); + ::free( cairo_pix_remapper ); cairo_pix_remapper = NULL; + } +} + gboolean handle_resize (GtkWindow * win, GdkEvent * event, gpointer data) { @@ -3435,9 +3500,9 @@ gboolean handle_resize (GtkWindow * win, GdkEvent * event, gpointer data) if (yscale > xscale) yscale = xscale; - if ( useCairoDraw ) + if ( useCairoDraw && winsize_changed ) { - cairo_handle_resize( width, height ); + cairo_handle_resize(); } //TODO if openGL make these integers @@ -3518,7 +3583,10 @@ drawAreaRealizeCB (GtkWidget *widget, { printf("Draw Area Realize\n"); - init_gtk3_GLXContext(); + if ( drawAreaGL ) + { + init_gtk3_GLXContext(); + } } diff --git a/src/drivers/sdl/gui.h b/src/drivers/sdl/gui.h index 73147ee9..b3313bb6 100644 --- a/src/drivers/sdl/gui.h +++ b/src/drivers/sdl/gui.h @@ -89,4 +89,9 @@ int InitGTKSubsystem(int argc, char** argv); uint32_t *getGuiPixelBuffer( int *w, int *h, int *s ); int guiPixelBufferReDraw(void); +int init_gui_video( int use_openGL ); +int destroy_gui_video( void ); +void init_cairo_screen(void); +void destroy_cairo_screen(void); + #endif // ifndef FCEUX_GUI_H diff --git a/src/drivers/sdl/sdl-video.cpp b/src/drivers/sdl/sdl-video.cpp index 7a42a3c2..bc555fcb 100644 --- a/src/drivers/sdl/sdl-video.cpp +++ b/src/drivers/sdl/sdl-video.cpp @@ -23,6 +23,7 @@ #include "sdl.h" #include "sdl-opengl.h" +#include "glxwin.h" #include "../common/vidblit.h" #include "../../fceu.h" #include "../../version.h" @@ -80,6 +81,7 @@ static int s_fullscreen = 0; static int noframe = 0; static int s_nativeWidth = -1; static int s_nativeHeight = -1; +static int initBlitToHighDone = 0; #define NWIDTH (256 - (s_clipSides ? 16 : 0)) #define NOFFSET (s_clipSides ? 8 : 0) @@ -136,6 +138,13 @@ bool FCEUD_ShouldDrawInputAids() int KillVideo() { + printf("Killing Video\n"); + + if ( glx_shm != NULL ) + { + glx_shm->clear_pixbuf(); + } + // if the IconSurface has been initialized, destroy it if (s_IconSurface) { @@ -143,51 +152,53 @@ KillVideo() s_IconSurface=0; } + //destroy_gui_video(); + // return failure if the video system was not initialized - if(s_inited == 0) + if (s_inited == 0) return -1; - + // if the rest of the system has been initialized, shut it down -#ifdef OPENGL - // check for OpenGL and shut it down - if(s_useOpenGL) - { - KillOpenGL(); - } - else -#endif - { - // shut down the system that converts from 8 to 16/32 bpp - if (s_curbpp > 8) - { - KillBlitToHigh(); - } - } +//#ifdef OPENGL +// // check for OpenGL and shut it down +// if(s_useOpenGL) +// { +// KillOpenGL(); +// } +// else +//#endif +// { +// // shut down the system that converts from 8 to 16/32 bpp +// if (s_curbpp > 8) +// { +// KillBlitToHigh(); +// } +// } -#if SDL_VERSION_ATLEAST(2, 0, 0) - - if ( s_screen != NULL ) - { - SDL_FreeSurface( s_screen ); s_screen = NULL; - } - - if ( s_texture != NULL ) - { - SDL_DestroyTexture( s_texture ); s_texture = NULL; - } - - if ( s_renderer != NULL ) - { - SDL_DestroyRenderer( s_renderer ); s_renderer = NULL; - } - - if ( s_window != NULL ) - { - SDL_DestroyWindow( s_window ); - s_window = NULL; - } - -#endif +//#if SDL_VERSION_ATLEAST(2, 0, 0) +// +// if ( s_screen != NULL ) +// { +// SDL_FreeSurface( s_screen ); s_screen = NULL; +// } +// +// if ( s_texture != NULL ) +// { +// SDL_DestroyTexture( s_texture ); s_texture = NULL; +// } +// +// if ( s_renderer != NULL ) +// { +// SDL_DestroyRenderer( s_renderer ); s_renderer = NULL; +// } +// +// if ( s_window != NULL ) +// { +// SDL_DestroyWindow( s_window ); +// s_window = NULL; +// } +// +//#endif // shut down the SDL video sub-system //SDL_QuitSubSystem(SDL_INIT_VIDEO); @@ -198,7 +209,7 @@ KillVideo() // this variable contains information about the special scaling filters -static int s_sponge; +static int s_sponge = 0; /** * These functions determine an appropriate scale factor for fullscreen/ @@ -240,7 +251,7 @@ int InitVideo(FCEUGI *gi) #ifdef OPENGL g_config->getOption("SDL.OpenGL", &s_useOpenGL); #endif - g_config->getOption("SDL.SpecialFilter", &s_sponge); + //g_config->getOption("SDL.SpecialFilter", &s_sponge); g_config->getOption("SDL.XStretch", &xstretch); g_config->getOption("SDL.YStretch", &ystretch); //g_config->getOption("SDL.LastXRes", &xres); @@ -248,10 +259,11 @@ int InitVideo(FCEUGI *gi) g_config->getOption("SDL.ClipSides", &s_clipSides); g_config->getOption("SDL.NoFrame", &noframe); g_config->getOption("SDL.ShowFPS", &show_fps); - g_config->getOption("SDL.XScale", &s_exs); - g_config->getOption("SDL.YScale", &s_eys); + //g_config->getOption("SDL.XScale", &s_exs); + //g_config->getOption("SDL.YScale", &s_eys); uint32_t rmask, gmask, bmask; + s_sponge = 0; s_exs = 1.0; s_eys = 1.0; xres = gtk_draw_area_width; @@ -271,6 +283,8 @@ int InitVideo(FCEUGI *gi) //} #endif + init_gui_video( s_useOpenGL ); + s_inited = 1; // check to see if we are showing FPS @@ -280,9 +294,6 @@ int InitVideo(FCEUGI *gi) rmask = 0x000000FF; gmask = 0x0000FF00; bmask = 0x00FF0000; - //rmask = 0x00FF0000; - //gmask = 0x0000FF00; - //bmask = 0x000000FF; #else rmask = 0x00FF0000; gmask = 0x0000FF00; @@ -356,36 +367,36 @@ int InitVideo(FCEUGI *gi) //s_paletterefresh = 1; // -Video Modes Tag- - if (s_sponge) - { - if (s_sponge <= 3 && s_sponge >= 1) - { - s_exs = s_eys = 2; - } - else if (s_sponge >=4 && s_sponge <= 5) - { - s_exs = s_eys = 3; - } - else if (s_sponge >= 6 && s_sponge <= 8) - { - s_exs = s_eys = s_sponge - 4; - } - else if(s_sponge == 9) - { - s_exs = s_eys = 3; - } - else - { - s_exs = s_eys = 1; - } - if(s_sponge == 3) { - xres = 301 * s_exs; - } - s_eefx = 0; - //if(s_sponge == 1 || s_sponge == 4) { - // desbpp = 32; - //} - } + //if (s_sponge) + //{ + // if (s_sponge <= 3 && s_sponge >= 1) + // { + // s_exs = s_eys = 2; + // } + // else if (s_sponge >=4 && s_sponge <= 5) + // { + // s_exs = s_eys = 3; + // } + // else if (s_sponge >= 6 && s_sponge <= 8) + // { + // s_exs = s_eys = s_sponge - 4; + // } + // else if(s_sponge == 9) + // { + // s_exs = s_eys = 3; + // } + // else + // { + // s_exs = s_eys = 1; + // } + // if(s_sponge == 3) { + // xres = 301 * s_exs; + // } + // s_eefx = 0; + // //if(s_sponge == 1 || s_sponge == 4) { + // // desbpp = 32; + // //} + //} //int scrw = NWIDTH * s_exs; //if(s_sponge == 3) { @@ -414,13 +425,15 @@ int InitVideo(FCEUGI *gi) } #endif - if (s_curbpp > 8) + if ( !initBlitToHighDone ) { InitBlitToHigh(s_curbpp >> 3, rmask, gmask, bmask, s_eefx, s_sponge, 0); + + initBlitToHighDone = 1; } return 0; @@ -466,7 +479,7 @@ InitVideo(FCEUGI *gi) // check for OpenGL and set the global flags #ifdef OPENGL - if(s_useOpenGL && !s_sponge) { + if (s_useOpenGL && !s_sponge) { flags = SDL_OPENGL; } #endif @@ -941,7 +954,9 @@ BlitScreen(uint8 *XBuf) //dest = (uint8*)TmpScreen->pixels; dest = (uint8*)getGuiPixelBuffer( &w, &h, &pitch ); - pitch = w * 4; + glx_shm->ncol = NWIDTH; + glx_shm->nrow = s_tlines; + glx_shm->pitch = pitch; if ( dest == NULL ) return; @@ -954,6 +969,7 @@ BlitScreen(uint8 *XBuf) // } //} + //Blit8ToHigh(XBuf + NOFFSET, dest, NWIDTH, s_tlines, pitch, 1, 1); Blit8ToHigh(XBuf + NOFFSET, dest, NWIDTH, s_tlines, pitch, 1, 1); // XXX soules - again, I'm surprised SDL can't handle this