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
This commit is contained in:
Subs 2020-10-01 00:04:47 +02:00
parent f2973312dc
commit a19bac6bc0
6 changed files with 215 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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 <dlfcn.h>
#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 <windows.h>
//#include <string>
#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

View File

@ -3,6 +3,10 @@
#include "vid_support.h"
#include "vid_softfx.h"
#ifdef INCLUDE_SWITCHRES
#include "vid_switchres.h"
#endif
#include <SDL.h>
#include <SDL_image.h>
@ -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)
{

View File

@ -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();
}

View File

@ -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();