From a19bac6bc0d1a1deed96ccca207f73de674245ff Mon Sep 17 00:00:00 2001 From: Subs Date: Thu, 1 Oct 2020 00:04:47 +0200 Subject: [PATCH] Add switchres to linux/sdl2 This allows perfect display on CRT The work is based on https://github.com/antonioginer/switchres which is the switchres code extracted from GroovyMAME and made available to other emulators that wish to add CRT display. This first commit simply concerns linux using the SDL2 video backend. Add INCLUDE_SWITCHRES=1 to enable switchres functionnality at make. To test under Linux you need: * a valid switchres.ini in /etc * libswitchres.so in your LD_LIBRARY_PATH --- makefile | 2 + makefile.sdl2 | 14 ++++ src/dep/libs/switchres/switchres_wrapper.h | 94 ++++++++++++++++++++++ src/intf/video/sdl/vid_sdl2.cpp | 25 +++++- src/intf/video/switchres/vid_switchres.cpp | 77 ++++++++++++++++++ src/intf/video/switchres/vid_switchres.h | 5 ++ 6 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 src/dep/libs/switchres/switchres_wrapper.h create mode 100644 src/intf/video/switchres/vid_switchres.cpp create mode 100644 src/intf/video/switchres/vid_switchres.h diff --git a/makefile b/makefile index 6b9ffdb0a..3f6ae4fc4 100644 --- a/makefile +++ b/makefile @@ -68,6 +68,8 @@ LSB_FIRST = 1 # Include png.h from burner.h INCLUDE_LIB_PNGH = 1 +# Enable CRT resolution switching +# INCLUDE_SWITCHRES = 1 # # execute an appropriate system-specific makefile diff --git a/makefile.sdl2 b/makefile.sdl2 index 6c59c081f..05517d7fa 100644 --- a/makefile.sdl2 +++ b/makefile.sdl2 @@ -86,6 +86,12 @@ depobj += un7z.o \ Delta.o LzmaDec.o Lzma2Dec.o Ppmd7.o Ppmd7Dec.o Sha256.o Xz.o XzCrc64.o XzCrc64Opt.o XzDec.o endif +ifdef INCLUDE_SWITCHRES +$(info Switchres will be enabled) +alldir += dep/libs/switchres intf/video/switchres +depobj += vid_switchres.o +endif + autobj += $(depobj) ifdef BUILD_X86_ASM @@ -112,6 +118,10 @@ ifdef DARWIN lib += -L/System/Library/Frameworks/OpenGL.framework/Libraries/ endif +ifdef INCLUDE_SWITCHRES +lib += -ldl +endif + autdep = $(depobj:.o=.d) drvdep = $(drvsrc:.o=.d) @@ -256,6 +266,10 @@ ifdef BUILD_X64_EXE DEF := $(DEF) -DBUILD_X64_EXE -DXBYAK_NO_OP_NAMES -DMIPS3_X64_DRC endif +ifdef INCLUDE_SWITCHRES + DEF := $(DEF) -DINCLUDE_SWITCHRES +endif + ifdef SYMBOL CFLAGS += -ggdb3 -fno-omit-frame-pointer diff --git a/src/dep/libs/switchres/switchres_wrapper.h b/src/dep/libs/switchres/switchres_wrapper.h new file mode 100644 index 000000000..63576da45 --- /dev/null +++ b/src/dep/libs/switchres/switchres_wrapper.h @@ -0,0 +1,94 @@ +/************************************************************** + + log.h - Simple logging for Switchres + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2020 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + + #ifdef __cplusplus +extern "C" { +#endif + +#ifdef __linux__ +#include +#define LIBTYPE void* +#define OPENLIB(libname) dlopen((libname), RTLD_LAZY) +#define LIBFUNC(libh, fn) dlsym((libh), (fn)) +#define LIBERROR dlerror +#define CLOSELIB(libh) dlclose((libh)) + +#elif defined _WIN32 +#include +//#include +#define LIBTYPE HINSTANCE +#define OPENLIB(libname) LoadLibrary(TEXT((libname))) +#define LIBFUNC(lib, fn) GetProcAddress((lib), (fn)) +char* LIBERROR() +{ + //Get the error message, if any. + DWORD errorMessageID = GetLastError(); + if(errorMessageID == 0) + return NULL; //No error message has been recorded + + LPSTR messageBuffer; + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + + SetLastError(0); + + static char error_msg[256] = {0}; + strncpy(error_msg, messageBuffer, sizeof(error_msg)-1); + LocalFree(messageBuffer); + return error_msg; +} +#define CLOSELIB(libp) FreeLibrary((libp)) +#endif + +#ifdef _WIN32 + #ifdef MODULE_API_EXPORTS + #define MODULE_API __declspec(dllexport) + #else + #define MODULE_API __declspec(dllimport) + #endif +#else + #define MODULE_API +#endif + +// That's all the exposed data from Switchres calculation +typedef struct MODULE_API { + int width; + int height; + double refresh; + unsigned char is_refresh_off; + unsigned char is_stretched; + int x_scale; + int y_scale; + unsigned char interlace; +} sr_mode; + +MODULE_API void sr_init(); +MODULE_API void sr_deinit(); +MODULE_API unsigned char sr_add_mode(int, int, double, unsigned char, sr_mode*); +MODULE_API unsigned char sr_switch_to_mode(int, int, double, unsigned char, sr_mode*); +MODULE_API void sr_set_monitor(const char*); + + +// Inspired by https://stackoverflow.com/a/1067684 +typedef struct MODULE_API { + void (*init)(void); + void (*deinit)(void); + unsigned char (*sr_add_mode)(int, int, double, unsigned char, sr_mode*); + unsigned char (*sr_switch_to_mode)(int, int, double, unsigned char, sr_mode*); +} srAPI; + + +#ifdef __cplusplus +} +#endif diff --git a/src/intf/video/sdl/vid_sdl2.cpp b/src/intf/video/sdl/vid_sdl2.cpp index e99cfe43e..a1a455317 100644 --- a/src/intf/video/sdl/vid_sdl2.cpp +++ b/src/intf/video/sdl/vid_sdl2.cpp @@ -3,6 +3,10 @@ #include "vid_support.h" #include "vid_softfx.h" +#ifdef INCLUDE_SWITCHRES +#include "vid_switchres.h" +#endif + #include #include @@ -42,6 +46,7 @@ void RenderMessage() static int Exit() { + switchres_exit(); kill_inline_font(); //TODO: This is not supposed to be here SDL_DestroyTexture(sdlTexture); SDL_DestroyRenderer(sdlRenderer); @@ -74,16 +79,21 @@ static int Init() BurnDrvGetAspect(&GameAspectX, &GameAspectY); display_w = nVidImageWidth; +#ifdef INCLUDE_SWITCHRES + // Don't force 4:3 aspect-ratio, until there is a command-line switch + display_h = nVidImageHeight; +#else display_h = nVidImageWidth * GameAspectY / GameAspectX; +#endif if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) { BurnDrvGetVisibleSize(&nVidImageHeight, &nVidImageWidth); BurnDrvGetAspect(&GameAspectY, &GameAspectX); - //BurnDrvGetAspect(&GameAspectX, &GameAspectY); printf("Vertical\n"); nRotateGame = 1; display_w = nVidImageHeight * GameAspectX / GameAspectY; + display_w = nVidImageWidth; display_h = nVidImageHeight; } @@ -110,6 +120,16 @@ static int Init() dstrect.h = display_h; dstrect.w = display_w; + //Test refresh rate availability + printf("Game resolution: %dx%d@%f\n", nVidImageWidth, nVidImageHeight, nBurnFPS/100.0); + +#ifdef INCLUDE_SWITCHRES + unsigned char interlace = 0; // FBN doesn't handle interlace yet, force it to disabled + double rr = nBurnFPS / 100.0; + switchres_init(); + switchres_switch_resolution(display_w, display_h, rr, interlace); +#endif + if (nRotateGame) { sdlWindow = SDL_CreateWindow( @@ -132,14 +152,15 @@ static int Init() title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - display_w, display_h, + display_w, screenFlags ); } + // Check that the window was successfully created if (sdlWindow == NULL) { diff --git a/src/intf/video/switchres/vid_switchres.cpp b/src/intf/video/switchres/vid_switchres.cpp new file mode 100644 index 000000000..1faeb407f --- /dev/null +++ b/src/intf/video/switchres/vid_switchres.cpp @@ -0,0 +1,77 @@ +#include "switchres_wrapper.h" +#include "burner.h" + + +#ifdef __linux__ +#define LIBSWR "libswitchres.so" +#elif _WIN32 +#define LIBSWR "libswitchres.dll" +#endif + +srAPI* SRobj; + +unsigned char switchres_init() { + const char* err_msg; + + printf("About to open %s.\n", LIBSWR); + + // Load the lib + LIBTYPE dlp = OPENLIB(LIBSWR); + + // Loading failed, inform and exit + if (!dlp) { + printf("Loading %s failed.\n", LIBSWR); + printf("Error: %s\n", LIBERROR()); + return 0; + } + + printf("Loading %s succeded.\n", LIBSWR); + + // Load the init() + LIBERROR(); + SRobj = (srAPI*)LIBFUNC(dlp, "srlib"); + if ((err_msg = LIBERROR()) != NULL) { + printf("Failed to load srAPI: %s\n", err_msg); + return 0; + } + + // Testing the function + printf("Init a new switchres_manager object:\n"); + SRobj->init(); + + return 1; +} + +unsigned char switchres_switch_resolution(int& w, int& h, double& rr, unsigned char& interlace) { + // Call mode + get result values + unsigned char ret; + sr_mode srm; + + printf("Orignial resolution expected: %dx%d@%f-%d\n", w, h, rr, interlace); + ret = SRobj->sr_add_mode(w, h, rr, interlace, &srm); + if(!ret) + { + printf("ERROR: couldn't add the required mode. Exiting!\n"); + return 0; + } + + printf("Got resolution: %dx%d%c@%f\n", srm.width, srm.height, srm.interlace, srm.refresh); + ret = SRobj->sr_switch_to_mode(srm.width, srm.height, srm.refresh, srm.interlace, &srm); + if(!ret) + { + printf("ERROR: couldn't switch to the required mode. Exiting!\n"); + return 0; + } + + // Set the values + w = srm.width; + h = srm.height; + rr = srm.refresh; + interlace = srm.interlace; + return 1; +} + +void switchres_exit() { + SRobj->deinit(); +} + diff --git a/src/intf/video/switchres/vid_switchres.h b/src/intf/video/switchres/vid_switchres.h new file mode 100644 index 000000000..514f8b31d --- /dev/null +++ b/src/intf/video/switchres/vid_switchres.h @@ -0,0 +1,5 @@ +unsigned char switchres_init(); + +unsigned char switchres_switch_resolution(int& w, int& h, double& rr, unsigned char& interlace); + +void switchres_exit();