diff --git a/.github/workflows/xpinmame.yml b/.github/workflows/xpinmame.yml index c23fb5b4a..ec907a883 100644 --- a/.github/workflows/xpinmame.yml +++ b/.github/workflows/xpinmame.yml @@ -57,7 +57,7 @@ jobs: - if: matrix.os == 'ubuntu-latest' run: | - sudo apt install libx11-dev libxv-dev libasound2-dev + sudo apt install libx11-dev libxv-dev libasound2-dev sdl2-dev - name: Build xpinmame-${{ matrix.platform }} run: | cp cmake/xpinmame/CMakeLists_${{ matrix.platform }}.txt CMakeLists.txt diff --git a/cmake/xpinmame/CMakeLists_linux-x64.txt b/cmake/xpinmame/CMakeLists_linux-x64.txt index ed5e793f1..cb1b8edae 100644 --- a/cmake/xpinmame/CMakeLists_linux-x64.txt +++ b/cmake/xpinmame/CMakeLists_linux-x64.txt @@ -103,9 +103,10 @@ add_compile_definitions( XMAMEROOT="/usr/local/share/xpinmame" HAVE_SNPRINTF HAVE_GETTIMEOFDAY - #SYSDEP_DSP_ALSA - #SYSDEP_MIXER_ALSA - SYSDEP_DSP_OSS +# SYSDEP_DSP_ALSA +# SYSDEP_MIXER_ALSA + SYSDEP_DSP_SDL + SDL_DEBUG ) add_executable(xpinmame @@ -615,10 +616,11 @@ add_executable(xpinmame src/unix/sysdep/sysdep_mixer.c # src/unix/sysdep/dsp-drivers/alsa.c # src/unix/sysdep/mixer-drivers/alsa.c - src/unix/sysdep/dsp-drivers/oss.c - src/unix/video-drivers/x11.c - src/unix/video-drivers/xinput.c - src/unix/video-drivers/x11_window.c + src/unix/sysdep/dsp-drivers/sdl.c +# src/unix/video-drivers/x11.c +# src/unix/video-drivers/xinput.c +# src/unix/video-drivers/x11_window.c + src/unix/video-drivers/sdl.c src/unix/joystick-drivers/joy_i386.c src/unix/joystick-drivers/joy_pad.c src/unix/joystick-drivers/joy_x11.c @@ -639,6 +641,10 @@ find_package( ALSA ) +find_package( + SDL2 +) + target_include_directories(xpinmame PUBLIC src src/wpc @@ -649,6 +655,7 @@ target_include_directories(xpinmame PUBLIC ${X11_X11_INCLUDE_PATH} ${X11_Xv_INCLUDE_PATH} ${ALSA_INCLUDE_DIRS} + ${SDL2_INCLUDE_DIRS} ) target_link_libraries(xpinmame PUBLIC @@ -657,6 +664,7 @@ target_link_libraries(xpinmame PUBLIC ${X11_Xv_LIB} ${X11_Xext_LIB} ${ALSA_LIBRARIES} + ${SDL2_LIBRARIES} ) set_target_properties(xpinmame PROPERTIES diff --git a/src/unix/sysdep/dsp-drivers/sdl.c b/src/unix/sysdep/dsp-drivers/sdl.c index b9dd358d8..cf396ecb9 100644 --- a/src/unix/sysdep/dsp-drivers/sdl.c +++ b/src/unix/sysdep/dsp-drivers/sdl.c @@ -30,34 +30,23 @@ Version 0.1, January 2002 */ + +// SDL defines this to __inline__ which no longer works with gcc 5+ ? +// TODO find the correct way to handle this, similar issue with ALSA +#ifndef SDL_FORCE_INLINE +#if ( (defined(__GNUC__) && (__GNUC__ >= 5))) +#define SDL_FORCE_INLINE __attribute__((always_inline)) static inline +#endif +#endif /* take the definition from SDL */ + #include #include #include -#include -#include "SDL.h" +#include "SDL2/SDL.h" #include "sysdep/sysdep_dsp.h" #include "sysdep/sysdep_dsp_priv.h" #include "sysdep/plugin_manager.h" -#ifdef __BEOS__ -#define BUFFERSIZE 1470 * 4 /* in my experience, BeOS likes buffers to be 4x */ -#else -#define BUFFERSIZE 1024 -#endif - -/* private variables */ -static struct { - Uint8 *data; - int amountRemain; - int amountWrite; - int amountRead; - int tmp; - Uint32 soundlen; - int sound_n_pos; - int sound_w_pos; - int sound_r_pos; -} sample; - /* callback function prototype */ static void sdl_fill_sound(void *unused, Uint8 *stream, int len); @@ -80,6 +69,10 @@ const struct plugin_struct sysdep_dsp_sdl = { 3 /* high priority */ }; +struct sdl_info { + SDL_AudioDeviceID id; +}; + /* public methods (static but exported through the sysdep_dsp or plugin struct) */ static void *sdl_dsp_create(const void *flags) @@ -105,14 +98,6 @@ static void *sdl_dsp_create(const void *flags) sdl_dsp_destroy(dsp); return NULL; } - - - if (!(sample.data = calloc(BUFFERSIZE, sizeof(Uint8)))) - { - fprintf(stderr, "error malloc failed for data\n"); - sdl_dsp_destroy(dsp); - return NULL; - } /* fill in the functions and some data */ dsp->_priv = priv; @@ -120,39 +105,58 @@ static void *sdl_dsp_create(const void *flags) dsp->destroy = sdl_dsp_destroy; dsp->hw_info.type = params->type; dsp->hw_info.samplerate = params->samplerate; - - - /* set the number of bits */ + audiospec->format = (dsp->hw_info.type & SYSDEP_DSP_16BIT)? AUDIO_S16SYS : AUDIO_S8; - - /* set the number of channels */ audiospec->channels = (dsp->hw_info.type & SYSDEP_DSP_STEREO)? 2:1; - - /* set the samplerate */ audiospec->freq = dsp->hw_info.samplerate; - - /* set samples size */ - audiospec->samples = BUFFERSIZE; - - /* set callback funcion */ - audiospec->callback = sdl_fill_sound; - - audiospec->userdata = NULL; - + /* Open audio device */ if(SDL_WasInit(SDL_INIT_VIDEO)!=0) /* If sdl video system is already */ SDL_InitSubSystem(SDL_INIT_AUDIO);/* initialized, we just initialize */ else /* the audio subsystem */ SDL_Init(SDL_INIT_AUDIO); /* else we MUST use "SDL_Init" */ /* (untested) */ - if (SDL_OpenAudio(audiospec, NULL) != 0) { - fprintf(stderr, "failed opening audio device\n"); - return NULL; - } - SDL_PauseAudio(0); + + fprintf(stderr, "sdl info: driver = %s\n", SDL_GetCurrentAudioDriver()); + + // get audio subsystem and open a queue with above spec + SDL_AudioSpec *obtained; + if (!(obtained = calloc(1, sizeof(SDL_AudioSpec)))) + { + fprintf(stderr, "sdl error: malloc failed for SDL_AudioSpec\n"); + sdl_dsp_destroy(dsp); + return NULL; + } + + const SDL_AudioDeviceID id = SDL_OpenAudioDevice(NULL, 0, audiospec, obtained, 0); + if (id == 0) { + fprintf(stderr, "sdl error: SDL_OpenAudioDevice() failed: %s\n", SDL_GetError()); + return NULL; + } + + // free the spec + free(audiospec); + + // print the id + fprintf(stderr, "sdl info: device id = %d\n", id); + // print the obtained contents + fprintf(stderr, "sdl info: obtained->format = %d\n", obtained->format); + fprintf(stderr, "sdl info: obtained->channels = %d\n", obtained->channels); + fprintf(stderr, "sdl info: obtained->freq = %d\n", obtained->freq); + fprintf(stderr, "sdl info: obtained->samples = %d\n", obtained->samples); + fprintf(stderr, "sdl info: obtained->callback = %p\n", obtained->callback); + fprintf(stderr, "sdl info: obtained->userdata = %p\n", obtained->userdata); + + // resume playing on device + SDL_PauseAudioDevice(id, 0); + + struct sdl_info *info = (struct sdl_info *)calloc(1, sizeof(struct sdl_info)); + info->id = id; + + dsp->_priv = info; - fprintf(stderr, "info: audiodevice %s set to %dbit linear %s %dHz\n", + fprintf(stderr, "sdl info: audiodevice %s set to %dbit linear %s %dHz\n", device, (dsp->hw_info.type & SYSDEP_DSP_16BIT)? 16:8, (dsp->hw_info.type & SYSDEP_DSP_STEREO)? "stereo":"mono", dsp->hw_info.samplerate); @@ -171,74 +175,19 @@ static void sdl_dsp_destroy(struct sysdep_dsp_struct *dsp) static int sdl_dsp_write(struct sysdep_dsp_struct *dsp, unsigned char *data, int count) { - /* sound_n_pos = normal position - sound_r_pos = read position - and so on. */ - int result = 0; - Uint8 *src; - SDL_LockAudio(); - - sample.amountRemain = BUFFERSIZE - sample.sound_n_pos; - sample.amountWrite = (dsp->hw_info.type & SYSDEP_DSP_STEREO)? count * 4 : count * 2; - - if(sample.amountRemain <= 0) { - SDL_UnlockAudio(); - return(result); - } - - if(sample.amountRemain < sample.amountWrite) sample.amountWrite = sample.amountRemain; - result = (int)sample.amountWrite; - sample.sound_n_pos += sample.amountWrite; - - src = (Uint8 *)data; - sample.tmp = BUFFERSIZE - sample.sound_w_pos; - - if(sample.tmp < sample.amountWrite){ - memcpy(sample.data + sample.sound_w_pos, src, sample.tmp); - sample.amountWrite -= sample.tmp; - src += sample.tmp; - memcpy(sample.data, src, sample.amountWrite); - sample.sound_w_pos = sample.amountWrite; - } - else{ - memcpy( sample.data + sample.sound_w_pos, src, sample.amountWrite); - sample.sound_w_pos += sample.amountWrite; - } - SDL_UnlockAudio(); - - return count; -} + // count is the number of samples to write + const int len = (dsp->hw_info.type & SYSDEP_DSP_STEREO)? count * 4 : count * 2; -/* Private method */ -static void sdl_fill_sound(void *unused, Uint8 *stream, int len) -{ - int result; - Uint8 *dst; - SDL_LockAudio(); - sample.amountRead = len; - if(sample.sound_n_pos <= 0) - SDL_UnlockAudio(); - - if(sample.sound_n_pos_priv; + const SDL_AudioDeviceID dev = info->id; + const int result = SDL_QueueAudio(dev, data, len); + if (result != 0) { + fprintf(stderr, "error: SDL_QueueAudio() failed: %s\n", SDL_GetError()); + return 0; + } + return count; } #endif /* ifdef SYSDEP_DSP_SDL */ diff --git a/src/unix/video-drivers/sdl.c b/src/unix/video-drivers/sdl.c index 9115b14c5..5dccfab44 100644 --- a/src/unix/video-drivers/sdl.c +++ b/src/unix/video-drivers/sdl.c @@ -29,12 +29,19 @@ /* #define PARANOIC */ #define __SDL_C -#undef SDL_DEBUG /* #define DIRECT_HERMES */ +// SDL defines this to __inline__ which no longer works with gcc 5+ ? +// TODO find the correct way to handle this, similar issue with ALSA +#ifndef SDL_FORCE_INLINE +#if ( (defined(__GNUC__) && (__GNUC__ >= 5))) +#define SDL_FORCE_INLINE __attribute__((always_inline)) static inline +#endif +#endif /* take the definition from SDL */ + #include #include -#include +#include #include "xmame.h" #include "devices.h" #include "keyboard.h" @@ -48,6 +55,7 @@ static int Vid_width; static int Vid_height; static int Vid_depth = 8; +static SDL_Window *Window; static SDL_Surface* Surface; static SDL_Surface* Offscreen_surface; static int hardware=1; @@ -101,7 +109,7 @@ void sdl_update_rgb_direct_32bpp(struct mame_bitmap *bitmap); int sysdep_init(void) { if (SDL_Init(SDL_INIT_VIDEO) < 0) { - fprintf (stderr, "SDL: Error: %s\n",SDL_GetError()); + fprintf (stderr, "SDL: Init error: %s\n",SDL_GetError()); return OSD_NOT_OK; } #ifdef DIRECT_HERMES @@ -119,8 +127,7 @@ void sysdep_close(void) int sysdep_create_display(int depth) { - SDL_Rect** vid_modes; - const SDL_VideoInfo* video_info; + fprintf(stderr, "SDL: Info: Create display with depth %d\n", depth); int vid_modes_i; #ifdef DIRECT_HERMES HermesFormat* H_src_format; @@ -128,72 +135,84 @@ int sysdep_create_display(int depth) #endif /* DIRECT_HERMES */ int vid_mode_flag; /* Flag to set the video mode */ - video_info = SDL_GetVideoInfo(); + SDL_DisplayMode current_mode; + SDL_GetCurrentDisplayMode(0, ¤t_mode); + + SDL_PixelFormat *format = SDL_AllocFormat(current_mode.format); #ifdef SDL_DEBUG fprintf (stderr,"SDL: create_display(%d): \n",depth); - fprintf (stderr,"SDL: Info: HW blits %d\n" - "SDL: Info: SW blits %d\n" - "SDL: Info: Vid mem %d\n" + fprintf (stderr, + // "SDL: Info: HW blits %d\n" + // "SDL: Info: SW blits %d\n" + // "SDL: Info: Vid mem %d\n" "SDL: Info: Best supported depth %d\n", - video_info->blit_hw, - video_info->blit_sw, - video_info->video_mem, - video_info->vfmt->BitsPerPixel); + // video_info->blit_hw, + // video_info->blit_sw, + // video_info->video_mem, + format->BitsPerPixel); #endif - Vid_depth = video_info->vfmt->BitsPerPixel; + // get SDL_PixelFormat from mode.format - vid_modes = SDL_ListModes(NULL,SDL_FULLSCREEN); - vid_modes_i = 0; + Vid_depth = format->BitsPerPixel; - hardware = video_info->hw_available; + // TODO how do we know if hardware acceleration is available? + // hardware = video_info->hw_available; - if ( (! vid_modes) || ((long)vid_modes == -1)) { + + const int display_index = 0; + const int modes_count = SDL_GetNumDisplayModes(display_index); + /* Best video mode found */ + int best_vid_mode = -1; + int best_width = -1; + int best_height = -1; + if (modes_count < 1) + { #ifdef SDL_DEBUG - fprintf (stderr, "SDL: Info: Possible all video modes available\n"); + fprintf (stderr, "SDL: Error listing display modes: %s\n",SDL_GetError()); #endif Vid_height = visual_height*heightscale; Vid_width = visual_width*widthscale; - } else { - int best_vid_mode; /* Best video mode found */ - int best_width,best_height; - int i; + }else + { #ifdef SDL_DEBUG fprintf (stderr, "SDL: visual w:%d visual h:%d\n", visual_width, visual_height); #endif - best_vid_mode = 0; - best_width = vid_modes[best_vid_mode]->w; - best_height = vid_modes[best_vid_mode]->h; - for (i=0;vid_modes[i];++i) + + + for (int mode_index = 0; mode_index <= modes_count; mode_index++) { - int cur_width, cur_height; + SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; - cur_width = vid_modes[i]->w; - cur_height = vid_modes[i]->h; + if (SDL_GetDisplayMode(display_index, mode_index, &mode) == 0) + { + SDL_Log(" %i bpp\t%i x %i @ %iHz", + SDL_BITSPERPIXEL(mode.format), mode.w, mode.h, mode.refresh_rate); #ifdef SDL_DEBUG - fprintf (stderr, "SDL: Info: Found mode %d x %d\n", cur_width, cur_height); + fprintf (stderr, "SDL: Info: Found mode %d x %d\n", mode.w, mode.h); #endif /* SDL_DEBUG */ - /* If width and height too small, skip to next mode */ - if ((cur_width < visual_width*widthscale) || (cur_height < visual_height*heightscale)) { - continue; - } + /* If width and height too small, skip to next mode */ + if ((mode.w < visual_width*widthscale) || (mode.h < visual_height*heightscale)) { + continue; + } - /* If width or height smaller than current best, keep it */ - if ((cur_width < best_width) || (cur_height < best_height)) { - best_vid_mode = i; - best_width = cur_width; - best_height = cur_height; + /* If width or height smaller than current best, keep it */ + if ((mode.w < best_width) || (mode.h < best_height)) { + best_vid_mode = mode_index; + best_width = mode.w; + best_height = mode.h; + } } } #ifdef SDL_DEBUG fprintf (stderr, "SDL: Info: Best mode found : %d x %d\n", - vid_modes[best_vid_mode]->w, - vid_modes[best_vid_mode]->h); + best_width, + best_height); #endif /* SDL_DEBUG */ vid_modes_i = best_vid_mode; @@ -210,11 +229,8 @@ int sysdep_create_display(int depth) Vid_height = visual_height*heightscale; Vid_width = visual_width*widthscale; } else { - if(*(vid_modes+vid_modes_i)==NULL) - vid_modes_i--; - - Vid_width = (*(vid_modes + vid_modes_i))->w; - Vid_height = (*(vid_modes + vid_modes_i))->h; + Vid_width = best_width; + Vid_height = best_height; } } @@ -260,18 +276,29 @@ int sysdep_create_display(int depth) /* Set video mode according to flags */ - vid_mode_flag = SDL_HWSURFACE; + vid_mode_flag = SDL_WINDOW_SHOWN; if (start_fullscreen) { - vid_mode_flag |= SDL_FULLSCREEN; + vid_mode_flag |= SDL_WINDOW_FULLSCREEN; } - if(! (Surface = SDL_SetVideoMode(Vid_width, Vid_height,Vid_depth, vid_mode_flag))) { + // TODO set scaling factor on canvas + // enable hidpi/scaling support + // on Linux this requires SDL_VIDEODRIVER=wayland + // vid_mode_flag |= SDL_WINDOW_ALLOW_HIGHDPI; + + // https://nlguillemot.wordpress.com/2016/12/11/high-dpi-rendering/ + + // TODO set Vid_dep? + + if(! (Window = SDL_CreateWindow(title,SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED,Vid_width, Vid_height, vid_mode_flag))) { fprintf (stderr, "SDL: Error: Setting video mode failed\n"); SDL_Quit(); exit (OSD_NOT_OK); } else { fprintf (stderr, "SDL: Info: Video mode set as %d x %d, depth %d\n", Vid_width, Vid_height, Vid_depth); } + Surface = SDL_GetWindowSurface(Window); #ifndef DIRECT_HERMES Offscreen_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,Vid_width,Vid_height,Vid_depth,0,0,0,0); @@ -297,8 +324,10 @@ int sysdep_create_display(int depth) /* Creating event mask */ SDL_EventState(SDL_KEYUP, SDL_ENABLE); SDL_EventState(SDL_KEYDOWN, SDL_ENABLE); - SDL_EnableUNICODE(1); - + + // TODO no longer exists + //SDL_EnableUNICODE(1); + /* fill the display_palette_info struct */ memset(&display_palette_info, 0, sizeof(struct sysdep_palette_info)); display_palette_info.depth = Vid_depth; @@ -318,9 +347,6 @@ int sysdep_create_display(int depth) /* Hide mouse cursor and save its previous status */ cursor_state = SDL_ShowCursor(0); - /* Set window title */ - SDL_WM_SetCaption(title, NULL); - effect_init2(depth, Vid_depth, Vid_width); return OSD_OK; @@ -339,7 +365,7 @@ static int sdl_mapkey(struct rc_option *option, const char *arg, int priority) { /* perform tests */ /* fprintf(stderr,"trying to map %x to %x\n", from, to); */ - if (from >= SDLK_FIRST && from < SDLK_LAST && to >= 0 && to <= 127) + if (from < SDL_NUM_SCANCODES && to <= 127) { klookup[from] = to; return OSD_OK; @@ -446,8 +472,12 @@ void sysdep_update_display(struct mame_bitmap *bitmap) if(SDL_BlitSurface (Offscreen_surface, &srect, Surface, &drect)<0) fprintf (stderr,"SDL: Warn: Unsuccessful blitting\n"); - if(hardware==0) - SDL_UpdateRects(Surface,1, &drect); + // FIXME how do we do this? + // if(hardware==0) + // SDL_UpdateRects(Surface,1, &drect); + + // switch buffer + SDL_UpdateWindowSurface(Window); } #else /* DIRECT_HERMES */ void sysdep_update_display(struct mame_bitmap *bitmap) @@ -606,10 +636,14 @@ void sysdep_update_display(struct mame_bitmap *bitmap) /* shut up the display */ void sysdep_display_close(void) { + fprintf(stderr, "SDL: Info: Shutting down display\n"); SDL_FreeSurface(Offscreen_surface); /* Restore cursor state */ SDL_ShowCursor(cursor_state); + + // close the window + SDL_DestroyWindow(Window); } /* @@ -618,9 +652,7 @@ void sysdep_display_close(void) */ int sysdep_display_alloc_palette(int totalcolors) { - int ncolors; - int i; - ncolors = totalcolors; + int ncolors = totalcolors; fprintf (stderr, "SDL: sysdep_display_alloc_palette(%d);\n",totalcolors); if (Vid_depth != 8) @@ -630,12 +662,12 @@ int sysdep_display_alloc_palette(int totalcolors) Colors = (SDL_Color*) malloc (totalcolors * sizeof(SDL_Color)); if( !Colors ) return 1; - for (i=0;ir = 0xFF; (Colors + i)->g = 0x00; (Colors + i)->b = 0x00; } - SDL_SetColors (Offscreen_surface,Colors,0,totalcolors-1); + SDL_SetPaletteColors (Offscreen_surface->format->palette,Colors,0,totalcolors-1); #else /* DIRECT_HERMES */ H_PaletteHandle = Hermes_PaletteInstance(); if ( !(H_Palette = Hermes_PaletteGet(H_PaletteHandle)) ) { @@ -660,7 +692,7 @@ int sysdep_display_set_pen(int pen,unsigned char red, unsigned char green, unsig (Colors + pen)->r = red; (Colors + pen)->g = green; (Colors + pen)->b = blue; - if ( (! SDL_SetColors(Offscreen_surface, Colors + pen, pen,1)) && (! warned)) { + if ( (! SDL_SetPaletteColors(Offscreen_surface->format->palette, Colors + pen, pen,1)) && (! warned)) { printf ("Color allocation failed, or > 8 bit display\n"); warned = 0; } @@ -678,14 +710,12 @@ int sysdep_display_set_pen(int pen,unsigned char red, unsigned char green, unsig void sysdep_mouse_poll (void) { - int i; int x,y; - Uint8 buttons; - buttons = SDL_GetRelativeMouseState( &x, &y); + Uint8 buttons = SDL_GetRelativeMouseState(&x, &y); mouse_data[0].deltas[0] = x; mouse_data[0].deltas[1] = y; - for(i=0;ivfmt->BitsPerPixel >=16); + SDL_DisplayMode mode; + SDL_GetCurrentDisplayMode(0, &mode); + return ( mode.format >=16); } int list_sdl_modes(struct rc_option *option, const char *arg, int priority) { - SDL_Rect** vid_modes; - int vid_modes_i; - - vid_modes = SDL_ListModes(NULL,SDL_FULLSCREEN); - vid_modes_i = 0; - - if ( (! vid_modes) || ((long)vid_modes == -1)) { + // TODO we might want to go over all displays + const int display_index = 0; + const int modes_count = SDL_GetNumDisplayModes(display_index); + if (modes_count < 1) + { printf("This option only works in a full-screen mode (eg: linux's framebuffer)\n"); return - 1; } + // print modes available printf("Modes available:\n"); - while( *(vid_modes+vid_modes_i) ) { - printf("\t%d) Mode %d x %d\n", - vid_modes_i, - (*(vid_modes+vid_modes_i))->w, - (*(vid_modes+vid_modes_i))->h - ); - - vid_modes_i++; + for (int mode_index = 0; mode_index <= modes_count; mode_index++) + { + SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; + + if (SDL_GetDisplayMode(display_index, mode_index, &mode) == 0) + { + printf("\t%d) Mode %d x %d @ %iHz\n", + mode_index, + mode.w, + mode.h, + mode.refresh_rate + ); + } } return -1;