path = frontend/warm
url = https://github.com/notaz/warm.git
[submodule "libchdr"]
- path = libchdr
+ path = deps/libchdr
url = https://github.com/rtissera/libchdr.git
# cdrcimg
OBJS += plugins/cdrcimg/cdrcimg.o
-#ifeq "$(CHD_SUPPORT)" "1"
-OBJS += libchdr/src/libchdr_bitstream.o
-OBJS += libchdr/src/libchdr_cdrom.o
-OBJS += libchdr/src/libchdr_chd.o
-OBJS += libchdr/src/libchdr_flac.o
-OBJS += libchdr/src/libchdr_huffman.o
-OBJS += libchdr/deps/lzma-19.00/src/Alloc.o libchdr/deps/lzma-19.00/src/Bra86.o libchdr/deps/lzma-19.00/src/BraIA64.o libchdr/deps/lzma-19.00/src/CpuArch.o libchdr/deps/lzma-19.00/src/Delta.o
-OBJS += libchdr/deps/lzma-19.00/src/LzFind.o libchdr/deps/lzma-19.00/src/Lzma86Dec.o libchdr/deps/lzma-19.00/src/LzmaDec.o libchdr/deps/lzma-19.00/src/LzmaEnc.o libchdr/deps/lzma-19.00/src/Sort.o
-CFLAGS += -DHAVE_CHD -Ilibchdr/include
+
+# libchdr
+#ifeq "$(HAVE_CHD)" "1"
+LCHDR = deps/libchdr
+LCHDR_LZMA = $(LCHDR)/deps/lzma-22.01
+LCHDR_ZSTD = $(LCHDR)/deps/zstd-1.5.5/lib
+OBJS += $(LCHDR)/src/libchdr_bitstream.o
+OBJS += $(LCHDR)/src/libchdr_cdrom.o
+OBJS += $(LCHDR)/src/libchdr_chd.o
+OBJS += $(LCHDR)/src/libchdr_flac.o
+OBJS += $(LCHDR)/src/libchdr_huffman.o
+$(LCHDR)/src/%.o: CFLAGS += -Wno-unused -std=gnu11
+OBJS += $(LCHDR_LZMA)/src/Alloc.o
+OBJS += $(LCHDR_LZMA)/src/Bra86.o
+OBJS += $(LCHDR_LZMA)/src/BraIA64.o
+OBJS += $(LCHDR_LZMA)/src/CpuArch.o
+OBJS += $(LCHDR_LZMA)/src/Delta.o
+OBJS += $(LCHDR_LZMA)/src/LzFind.o
+OBJS += $(LCHDR_LZMA)/src/Lzma86Dec.o
+OBJS += $(LCHDR_LZMA)/src/LzmaDec.o
+OBJS += $(LCHDR_LZMA)/src/LzmaEnc.o
+OBJS += $(LCHDR_LZMA)/src/Sort.o
+$(LCHDR_LZMA)/src/%.o: CFLAGS += -Wno-unused -D_7ZIP_ST -I$(LCHDR_LZMA)/include
+$(LCHDR)/src/%.o: CFLAGS += -I$(LCHDR_LZMA)/include
+OBJS += $(LCHDR_ZSTD)/common/debug.o
+OBJS += $(LCHDR_ZSTD)/common/entropy_common.o
+OBJS += $(LCHDR_ZSTD)/common/error_private.o
+OBJS += $(LCHDR_ZSTD)/common/fse_decompress.o
+OBJS += $(LCHDR_ZSTD)/common/pool.o
+OBJS += $(LCHDR_ZSTD)/common/threading.o
+OBJS += $(LCHDR_ZSTD)/common/xxhash.o
+OBJS += $(LCHDR_ZSTD)/common/zstd_common.o
+OBJS += $(LCHDR_ZSTD)/decompress/huf_decompress.o
+OBJS += $(LCHDR_ZSTD)/decompress/zstd_ddict.o
+OBJS += $(LCHDR_ZSTD)/decompress/zstd_decompress_block.o
+OBJS += $(LCHDR_ZSTD)/decompress/zstd_decompress.o
+$(LCHDR_ZSTD)/common/%.o \
+$(LCHDR_ZSTD)/decompress/%.o: CFLAGS += -DZSTD_DISABLE_ASM -I$(LCHDR_ZSTD)
+$(LCHDR)/src/%.o: CFLAGS += -I$(LCHDR_ZSTD)
libpcsxcore/cdriso.o: CFLAGS += -Wno-unused-function
-libchdr/src/%.o: CFLAGS += -Wno-unused -Ilibchdr/deps/lzma-19.00/include -std=gnu11
-libchdr/deps/lzma-19.00/src/%.o: CFLAGS += -Wno-unused -D_7ZIP_ST -Ilibchdr/deps/lzma-19.00/include
+CFLAGS += -DHAVE_CHD -I$(LCHDR)/include
#endif
# frontend/gui
--- /dev/null
+Subproject commit 5c598c2df3a7717552a76410d79f5af01ff51b1d
static unsigned previous_height = 0;
static int plugins_opened;
-static int is_pal_mode;
+
+#define is_pal_mode Config.PsxType
/* memory card data */
extern char Mcd1Data[MCD_SIZE];
static void addCrosshair(int port, int crosshair_color, unsigned short *buffer, int bufferStride, int pos_x, int pos_y, int thickness, int size_x, int size_y) {
for (port = 0; port < 2; port++) {
// Draw the horizontal line of the crosshair
- for (int i = pos_y - thickness / 2; i <= pos_y + thickness / 2; i++) {
- for (int j = pos_x - size_x / 2; j <= pos_x + size_x / 2; j++) {
+ int i, j;
+ for (i = pos_y - thickness / 2; i <= pos_y + thickness / 2; i++) {
+ for (j = pos_x - size_x / 2; j <= pos_x + size_x / 2; j++) {
if ((i + vout_height) >= 0 && (i + vout_height) < bufferStride && j >= 0 && j < bufferStride && in_enable_crosshair[port] > 0)
buffer[i * bufferStride + j] = crosshair_color;
- }
}
+ }
// Draw the vertical line of the crosshair
- for (int i = pos_x - thickness / 2; i <= pos_x + thickness / 2; i++) {
- for (int j = pos_y - size_y / 2; j <= pos_y + size_y / 2; j++) {
+ for (i = pos_x - thickness / 2; i <= pos_x + thickness / 2; i++) {
+ for (j = pos_y - size_y / 2; j <= pos_y + size_y / 2; j++) {
if (i >= 0 && i < bufferStride && (j + vout_height) >= 0 && (j + vout_height) < bufferStride && in_enable_crosshair[port] > 0)
buffer[j * bufferStride + i] = crosshair_color;
}
for (port = 0; port < 2; port++) {
if (in_enable_crosshair[port] > 0 && (in_type[port] == PSE_PAD_TYPE_GUNCON || in_type[port] == PSE_PAD_TYPE_GUN))
{
- struct CrosshairInfo crosshairInfo;
- CrosshairDimensions(port, &crosshairInfo);
+ struct CrosshairInfo crosshairInfo;
+ CrosshairDimensions(port, &crosshairInfo);
addCrosshair(port, in_enable_crosshair[port], dest, dstride, crosshairInfo.pos_x, crosshairInfo.pos_y, crosshairInfo.thickness, crosshairInfo.size_x, crosshairInfo.size_y);
}
}
void pl_timing_prepare(int is_pal)
{
- is_pal_mode = is_pal;
}
void plat_trigger_vibrate(int pad, int low, int high)
"pcsx_rearmed_negcon_deadzone",
"pcsx_rearmed_negcon_response",
"pcsx_rearmed_input_sensitivity",
- "pcsx_rearmed_crosshair1",
- "pcsx_rearmed_crosshair2",
+ "pcsx_rearmed_crosshair1",
+ "pcsx_rearmed_crosshair2",
"pcsx_rearmed_konamigunadjustx",
"pcsx_rearmed_konamigunadjusty",
"pcsx_rearmed_gunconadjustx",
unsigned geom_width = vout_width;
memset(info, 0, sizeof(*info));
- info->timing.fps = is_pal_mode ? 50.0 : 60.0;
+ info->timing.fps = psxGetFps();
info->timing.sample_rate = 44100.0;
info->geometry.base_width = geom_width;
info->geometry.base_height = geom_height;
int gpu_peops_fix = GPU_PEOPS_OLD_FRAME_SKIP;
#endif
frameskip_type_t prev_frameskip_type;
+ double old_fps = psxGetFps();
var.value = NULL;
var.key = "pcsx_rearmed_frameskip_type";
Config.GpuListWalking = -1;
}
+ var.value = NULL;
+ var.key = "pcsx_rearmed_fractional_framerate";
+ if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+ {
+ if (strcmp(var.value, "disabled") == 0)
+ Config.FractionalFramerate = 0;
+ else if (strcmp(var.value, "enabled") == 0)
+ Config.FractionalFramerate = 1;
+ else // auto
+ Config.FractionalFramerate = -1;
+ }
+
var.value = NULL;
var.key = "pcsx_rearmed_screen_centering";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
}
update_option_visibility();
+
+ if (old_fps != psxGetFps())
+ {
+ struct retro_system_av_info info;
+ retro_get_system_av_info(&info);
+ environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &info);
+ }
}
// Taken from beetle-psx-libretro
},
"disabled",
},
+ {
+ "pcsx_rearmed_fractional_framerate",
+ "Use fractional frame rate",
+ NULL,
+ "Instead of the exact 50 or 60 (maximum) fps for PAL/NTSC the real console runs closer to something like 49.75 and 59.81fps (varies slightly between hw versions). PCSX-ReARMed uses the former \"round\" framerates to better match modern displays, however that may cause audio/video desync in games like DDR and Spyro 2 (intro). With this option you can try to use fractional framerates.",
+ NULL,
+ "video",
+ {
+ { "auto", "Auto" },
+ { "disabled", NULL },
+ { "enabled", NULL },
+ { NULL, NULL },
+ },
+ "auto",
+ },
{
"pcsx_rearmed_gpu_slow_llists",
"(GPU) Slow linked list processing",
NULL,
"video",
{
- { "auto", NULL },
+ { "auto", "Auto" },
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL },
Config.PsxAuto = 1;
Config.cycle_multiplier = CYCLE_MULT_DEFAULT;
Config.GpuListWalking = -1;
+ Config.FractionalFramerate = -1;
pl_rearmed_cbs.gpu_neon.allow_interlace = 2; // auto
pl_rearmed_cbs.gpu_neon.enhancement_enable =
CE_CONFIG_VAL(DisableStalls),
CE_CONFIG_VAL(Cpu),
CE_CONFIG_VAL(GpuListWalking),
+ CE_CONFIG_VAL(FractionalFramerate),
CE_CONFIG_VAL(PreciseExceptions),
CE_INTVAL(region),
CE_INTVAL_V(g_scaler, 3),
return 0;
}
-static const char *men_gpul[] = { "Auto", "Off", "On", NULL };
+static const char *men_autooo[] = { "Auto", "Off", "On", NULL };
static const char h_cfg_cpul[] = "Shows CPU usage in %";
static const char h_cfg_spu[] = "Shows active SPU channels\n"
"and exceptions (slow, interpreter only, keep off)";
static const char h_cfg_gpul[] = "Try enabling this if the game misses some graphics\n"
"causes a performance hit";
+static const char h_cfg_ffps[] = "Instead of 50/60fps for PAL/NTSC use ~49.75/59.81\n"
+ "Closer to real hw but doesn't match modern displays.";
static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
"(adjust this if the game is too slow/too fast/hangs)";
-enum { AMO_XA, AMO_CDDA, AMO_IC, AMO_BP, AMO_CPU, AMO_GPUL };
+enum { AMO_XA, AMO_CDDA, AMO_IC, AMO_BP, AMO_CPU, AMO_GPUL, AMO_FFPS };
static menu_entry e_menu_adv_options[] =
{
mee_onoff_h ("Disable CD Audio", 0, menu_iopts[AMO_CDDA], 1, h_cfg_cdda),
mee_onoff_h ("ICache emulation", 0, menu_iopts[AMO_IC], 1, h_cfg_icache),
mee_onoff_h ("BP exception emulation", 0, menu_iopts[AMO_BP], 1, h_cfg_exc),
- mee_enum_h ("GPU l-list slow walking",0, menu_iopts[AMO_GPUL], men_gpul, h_cfg_gpul),
+ mee_enum_h ("GPU l-list slow walking",0, menu_iopts[AMO_GPUL], men_autooo, h_cfg_gpul),
+ mee_enum_h ("Fractional framerate", 0, menu_iopts[AMO_FFPS], men_autooo, h_cfg_ffps),
#if !defined(DRC_DISABLE) || defined(LIGHTREC)
mee_onoff_h ("Disable dynarec (slow!)",0, menu_iopts[AMO_CPU], 1, h_cfg_nodrc),
#endif
for (i = 0; i < ARRAY_SIZE(opts); i++)
*opts[i].mopt = *opts[i].opt;
menu_iopts[AMO_GPUL] = Config.GpuListWalking + 1;
+ menu_iopts[AMO_FFPS] = Config.FractionalFramerate + 1;
me_loop(e_menu_adv_options, &sel);
for (i = 0; i < ARRAY_SIZE(opts); i++)
*opts[i].opt = *opts[i].mopt;
Config.GpuListWalking = menu_iopts[AMO_GPUL] - 1;
+ Config.FractionalFramerate = menu_iopts[AMO_FFPS] - 1;
return 0;
}
#include "../libpcsxcore/psxmem_map.h"
#include "../libpcsxcore/gpu.h"
#include "../libpcsxcore/r3000a.h"
+#include "../libpcsxcore/psxcounters.h"
#define HUD_HEIGHT 10
void pl_timing_prepare(int is_pal_)
{
+ double fps;
pl_rearmed_cbs.fskip_advice = 0;
pl_rearmed_cbs.flips_per_sec = 0;
pl_rearmed_cbs.cpu_usage = 0;
is_pal = is_pal_;
- frame_interval = is_pal ? 20000 : 16667;
- frame_interval1024 = is_pal ? 20000*1024 : 17066667;
+ fps = psxGetFps();
+ frame_interval = (int)(1000000.0 / fps);
+ frame_interval1024 = (int)(1000000.0 * 1024.0 / fps);
// used by P.E.Op.S. frameskip code
- pl_rearmed_cbs.gpu_peops.fFrameRateHz = is_pal ? 50.0f : 59.94f;
+ pl_rearmed_cbs.gpu_peops.fFrameRateHz = (float)fps;
pl_rearmed_cbs.gpu_peops.dwFrameRateTicks =
- (100000*100 / (unsigned long)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
+ (100000*100 / (int)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
}
static void pl_get_layer_pos(int *x, int *y, int *w, int *h)
+++ /dev/null
-Subproject commit 54bfb871ccae31903b95a8feb7f2bf7121f304be
int cyclesSinceRS = psxRegs.cycle - cdr.LastReadSeekCycles;
seekTime = MAX_VALUE(seekTime, 20000);
- // need this stupidly long penalty or else Spyro2 intro desyncs
- // note: if misapplied this breaks MGS cutscenes among other things
- if (cdr.DriveState == DRIVESTATE_PAUSED && cyclesSinceRS > cdReadTime * 50)
- seekTime += cdReadTime * 25;
// Transformers Beast Wars Transmetals does Setloc(x),SeekL,Setloc(x),ReadN
// and then wants some slack time
- else if (cdr.DriveState == DRIVESTATE_PAUSED || cyclesSinceRS < cdReadTime *3/2)
+ if (cdr.DriveState == DRIVESTATE_PAUSED || cyclesSinceRS < cdReadTime *3/2)
seekTime += cdReadTime;
seekTime = MIN_VALUE(seekTime, PSXCLK * 2 / 3);
- CDR_LOG("seek: %.2f %.2f (%.2f) st %d\n", (float)seekTime / PSXCLK,
+ CDR_LOG("seek: %.2f %.2f (%.2f) st %d di %d\n", (float)seekTime / PSXCLK,
(float)seekTime / cdReadTime, (float)cyclesSinceRS / cdReadTime,
- cdr.DriveState);
+ cdr.DriveState, diff);
return seekTime;
}
cdr.sectorsRead = 0;
/*
- Gundam Battle Assault 2: much slower (*)
- - Fixes boot, gameplay
-
- Hokuto no Ken 2: slower
- - Fixes intro + subtitles
-
- InuYasha - Feudal Fairy Tale: slower
- - Fixes battles
+ Gundam Battle Assault 2
+ Hokuto no Ken 2
+ InuYasha - Feudal Fairy Tale
+ Dance Dance Revolution Konamix
+ ...
*/
- /* Gameblabla - Tightening the timings (as taken from Duckstation).
- * The timings from Duckstation are based upon hardware tests.
- * Mednafen's timing don't work for Gundam Battle Assault 2 in PAL/50hz mode,
- * seems to be timing sensitive as it can depend on the CPU's clock speed.
- * */
if (!(cdr.StatP & (STATUS_PLAY | STATUS_READ)))
{
second_resp_time = 7000;
}
else
{
- second_resp_time = (((cdr.Mode & MODE_SPEED) ? 1 : 2) * 1097107);
+ second_resp_time = 2 * 1097107;
}
SetPlaySeekRead(cdr.StatP, 0);
DriveStateOld = cdr.DriveState;
subhdr->file, subhdr->chan, cdr.CurFile, cdr.CurChannel, cdr.FilterFile, cdr.FilterChannel);
if ((cdr.Mode & MODE_SF) && (subhdr->file != cdr.FilterFile || subhdr->chan != cdr.FilterChannel))
break;
- if (subhdr->chan & 0xe0) { // ?
+ if (subhdr->chan & 0x80) { // ?
if (subhdr->chan != 0xff)
log_unhandled("adpcm %d:%d\n", subhdr->file, subhdr->chan);
break;
"SLUS00546",
};
+static const char * const fractional_Framerate_hack_db[] =
+{
+ /* Dance Dance Revolution */
+ "SLPM86503", // 3rd Mix
+ "SLPM86752", // 4th Mix
+ "SLPM86266", // 4thMix: The Beat Goes On
+ "SLPM86831", // Extra Mix
+ "SLUS01446", // Konamix
+ /* Dancing Stage Fever */
+ "SLES04097",
+ /* Dancing Stage Fusion */
+ "SLES04163",
+ /* Spyro 2 */
+ "SCUS94425", "SCES02104",
+};
+
#define HACK_ENTRY(var, list) \
{ #var, &Config.hacks.var, list, ARRAY_SIZE(list) }
HACK_ENTRY(gpu_centering, gpu_centering_hack_db),
HACK_ENTRY(gpu_timing1024, dualshock_timing1024_hack_db),
HACK_ENTRY(dualshock_init_analog, dualshock_init_analog_hack_db),
+ HACK_ENTRY(fractional_Framerate, fractional_Framerate_hack_db),
};
static const struct
/* Super Robot Taisen Alpha - on the edge with 175,
* changing memcard settings is enough to break/unbreak it */
{ 190, { "SLPS02528", "SLPS02636" } },
+ /* Colin McRae Rally - language selection menu does not work with 175 */
+ { 174, { "SLES00477" } },
/* Brave Fencer Musashi - cd sectors arrive too fast */
{ 170, { "SLUS00726", "SLPS01490" } },
#if defined(DRC_DISABLE) || defined(LIGHTREC) /* new_dynarec has a hack for this game */
boolean icache_emulation;
boolean DisableStalls;
boolean PreciseExceptions;
- int GpuListWalking;
int cycle_multiplier; // 100 for 1.0
int cycle_multiplier_override;
+ s8 GpuListWalking;
+ s8 FractionalFramerate; // ~49.75 and ~59.81 instead of 50 and 60
u8 Cpu; // CPU_DYNAREC or CPU_INTERPRETER
u8 PsxType; // PSX_TYPE_NTSC or PSX_TYPE_PAL
struct {
boolean gpu_centering;
boolean dualshock_init_analog;
boolean gpu_timing1024;
+ boolean fractional_Framerate;
} hacks;
} PcsxConfig;
/******************************************************************************/
+#define FPS_FRACTIONAL_PAL (53203425/314./3406) // ~49.75
+#define FPS_FRACTIONAL_NTSC (53693175/263./3413) // ~59.81
+
+static inline
+u32 frameCycles(void)
+{
+ int ff = Config.FractionalFramerate >= 0
+ ? Config.FractionalFramerate : Config.hacks.fractional_Framerate;
+ if (ff)
+ {
+ if (Config.PsxType)
+ return (u32)(PSXCLK / FPS_FRACTIONAL_PAL);
+ else
+ return (u32)(PSXCLK / FPS_FRACTIONAL_NTSC);
+ }
+ return Config.PsxType ? (PSXCLK / 50) : (PSXCLK / 60);
+}
+
+// used to inform the frontend about the exact framerate
+double psxGetFps()
+{
+ int ff = Config.FractionalFramerate >= 0
+ ? Config.FractionalFramerate : Config.hacks.fractional_Framerate;
+ if (ff)
+ return Config.PsxType ? FPS_FRACTIONAL_PAL : FPS_FRACTIONAL_NTSC;
+ else
+ return Config.PsxType ? 50.0 : 60.0;
+}
+
+// to inform the frontend about the exact famerate
static inline
u32 lineCycles(void)
{
+ // should be more like above, but our timing is already poor anyway
if (Config.PsxType)
return PSXCLK / 50 / HSyncTotal[1];
else
if (hSyncCount + hsync_steps == HSyncTotal[Config.PsxType])
{
- rcnts[3].cycle = Config.PsxType ? PSXCLK / 50 : PSXCLK / 60;
+ rcnts[3].cycle = frameCycles();
}
else
{
if( hSyncCount >= HSyncTotal[Config.PsxType] )
{
u32 status, field = 0;
- rcnts[3].cycleStart += Config.PsxType ? PSXCLK / 50 : PSXCLK / 60;
+ rcnts[3].cycleStart += frameCycles();
hSyncCount = 0;
frame_counter++;
s32 psxRcntFreeze(void *f, s32 Mode);
+double psxGetFps();
+
#ifdef __cplusplus
}
#endif
#define MAXCHAN 24\r
\r
// note: must be even due to the way reverb works now\r
-#define NSSIZE ((44100 / 50 + 16) & ~1)\r
+#define NSSIZE ((44100 / 50 + 32) & ~1)\r
\r
///////////////////////////////////////////////////////////\r
// struct defines\r
int iLeftXAVol;\r
int iRightXAVol;\r
\r
+ int cdClearSamples; // extra samples to clear the capture buffers\r
struct { // channel volume in the cd controller\r
unsigned char ll, lr, rl, rr; // see cdr.Attenuator* in cdrom.c\r
} cdv; // applied on spu side for easier emulation\r
\r
spu.XAPlay = spu.XAFeed = spu.XAStart;\r
spu.CDDAPlay = spu.CDDAFeed = spu.CDDAStart;\r
+ spu.cdClearSamples = 512;\r
if (pFO && pFO->xa_left && pF->xaS.nsamples) { // start xa again\r
FeedXA(&pF->xaS);\r
spu.XAPlay = spu.XAFeed - pFO->xa_left;\r
FeedXA(xap); // call main XA feeder
spu.xapGlobal = xap; // store info for save states
+ spu.cdClearSamples = 512;
}
// CDDA AUDIO
do_samples(cycle, 1); // catch up to prevent source underflows later
FeedCDDA((unsigned char *)pcm, nbytes);
+ spu.cdClearSamples = 512;
return 0;
}
}
spu.XALastVal = v;
}
- else
+ else if (spu.cdClearSamples > 0)
+ {
+ for(ns = 0; ns < ns_to; ns++)
+ {
+ spu.spuMem[cursor] = spu.spuMem[cursor + 0x400/2] = 0;
+ cursor = (cursor + 1) & 0x1ff;
+ }
+ spu.cdClearSamples -= ns_to;
spu.XALastVal = 0;
+ }
}
////////////////////////////////////////////////////////////////////////