Update to 0.9.24.

This commit is contained in:
Themaister 2012-08-15 21:26:44 +02:00
parent 03fcaf14d4
commit 44d7a687ef
38 changed files with 929 additions and 550 deletions

View File

@ -154,7 +154,7 @@ WARNINGS := -Wall \
-Wno-overflow
FLAGS += $(ENDIANNESS_DEFINES) -DSIZEOF_DOUBLE=8 $(WARNINGS) \
-DMEDNAFEN_VERSION=\"0.9.22\" -DMEDNAFEN_VERSION_NUMERIC=922 -DPSS_STYLE=1 -DMPC_FIXED_POINT -DARCH_X86 \
-DMEDNAFEN_VERSION=\"0.9.24\" -DPACKAGE=\"mednafen\" -DMEDNAFEN_VERSION_NUMERIC=924 -DPSS_STYLE=1 -DMPC_FIXED_POINT -DARCH_X86 \
-DWANT_PSX_EMU -DSTDC_HEADERS
CXXFLAGS += $(FLAGS)

View File

@ -54,7 +54,6 @@ static int16 CDDABuffer[588 * 2];
static int16 ResampBuffer[588 * 2][2]; // Resampler input buffer, * 2 for resampler leftovers
static uint32 ResampBufferPos;
static uint32 PrevRate;
static unsigned int CurrentDisc;
static std::vector<CDIF *> *cdifs;
@ -541,6 +540,7 @@ MDFNGI EmulatedCDPlay =
NULL,
NULL,
NULL,
false,
NULL, //StateAction,
Emulate,
SetInput,

View File

@ -36,6 +36,15 @@ MDFN_Error::MDFN_Error(int errno_code_new, const char *format, ...) throw()
va_end(ap);
}
MDFN_Error::MDFN_Error(const ErrnoHolder &enh)
{
errno_code = enh.Errno();
error_message = trio_aprintf("%s", enh.StrError());
}
MDFN_Error::~MDFN_Error() throw()
{
if(error_message)
@ -78,7 +87,7 @@ const char * MDFN_Error::what(void) const throw()
return(error_message);
}
int MDFN_Error::GetErrno(void) throw()
int MDFN_Error::GetErrno(void) const throw()
{
return(errno_code);
}

View File

@ -6,6 +6,8 @@
#include <exception>
#ifdef __cplusplus
class ErrnoHolder;
class MDFN_Error : public std::exception
{
public:
@ -13,6 +15,7 @@ class MDFN_Error : public std::exception
MDFN_Error() throw();
MDFN_Error(int errno_code_new, const char *format, ...) throw();
MDFN_Error(const ErrnoHolder &enh);
~MDFN_Error() throw();
@ -20,7 +23,7 @@ class MDFN_Error : public std::exception
MDFN_Error & operator=(const MDFN_Error &ze_error) throw();
virtual const char *what(void) const throw();
int GetErrno(void) throw();
int GetErrno(void) const throw();
private:
@ -44,12 +47,12 @@ class ErrnoHolder
SetErrno(the_errno);
}
inline int Errno(void)
inline int Errno(void) const
{
return(local_errno);
}
const char *StrError(void)
const char *StrError(void) const
{
return(local_strerror);
}

View File

@ -312,6 +312,7 @@ typedef struct
void (*RemoveReadPatches)(void);
uint8 (*MemRead)(uint32 addr);
bool SaveStateAltersState; // true for bsnes and some libco-style emulators, false otherwise.
// Main save state routine, called by the save state code in state.cpp.
// When saving, load is set to 0. When loading, load is set to the version field of the save state being loaded.
// data_only is true when the save state data is temporary, such as being saved into memory for state rewinding.

View File

@ -102,10 +102,10 @@ static INLINE void StoreU32_LE(uint32 *a, const uint32 v)
//
// pre_padding and post_padding are specified in units of sizeof(max_unit_type).
//
template<unsigned size, typename max_unit_type, bool big_endian, unsigned pre_padding_count, unsigned post_padding_count>
template<unsigned size, typename max_unit_type, bool big_endian> //, unsigned pre_padding_count, unsigned post_padding_count>
struct MultiAccessSizeMem
{
max_unit_type pre_padding[pre_padding_count];
//max_unit_type pre_padding[pre_padding_count ? pre_padding_count : 1];
union
{
@ -114,7 +114,7 @@ struct MultiAccessSizeMem
uint32 data32[size / sizeof(uint32)];
};
max_unit_type post_padding[post_padding_count];
//max_unit_type post_padding[post_padding_count ? post_padding_count : 1];
INLINE uint8 ReadU8(uint32 address)
{

View File

@ -1,7 +1,23 @@
#ifndef __MDFN_MATH_OPS_H
#define __MDFN_MATH_OPS_H
uint32 round_up_pow2(uint32 v);
// Source: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
// Rounds up to the nearest power of 2.
static INLINE uint64 round_up_pow2(uint64 v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
v++;
v += (v == 0);
return(v);
}
static INLINE uint32 uilog2(uint32 v)
{
@ -38,7 +54,4 @@ static INLINE uint32 uilog2(uint32 v)
// convert those faster with typecasts...
#define sign_x_to_s32(_bits, _value) (((int32)((uint32)(_value) << (32 - _bits))) >> (32 - _bits))
#define INT16_TO_BCD(A) ((((((A) % 100) / 10) * 16 + ((A) % 10))) | (((((((A) / 100) % 100) / 10) * 16 + (((A) / 100) % 10))) << 8)) // convert INT16 --> BCD
#endif

View File

@ -77,7 +77,7 @@ int MDFNI_Initialize(const char *basedir, const std::vector<MDFNSetting> &Driver
void MDFNI_SetBaseDirectory(const char *dir);
/* Call only when a game is loaded. */
int MDFNI_NetplayStart(uint32 local_players, uint32 netmerge, const std::string &nickname, const std::string &game_key, const std::string &connect_password);
int MDFNI_NetplayStart(uint32 local_players, const std::string &nickname, const std::string &game_key, const std::string &connect_password);
/* Emulates a frame. */
void MDFNI_Emulate(EmulateSpecStruct *espec);

View File

@ -138,7 +138,6 @@ static MDFNSetting RenamedSettings[] =
{ "netlocalplayers", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "netplay.localplayers" },
{ "netnick", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "netplay.nick" },
{ "netgamekey", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "netplay.gamekey" },
{ "netmerge", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "netplay.merge" },
{ "netsmallfont", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "netplay.smallfont" },
{ "frameskip", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "video.frameskip" },
@ -295,9 +294,9 @@ void MDFNI_CloseGame(void)
memset(PortDeviceCache, 0, sizeof(PortDeviceCache));
}
int MDFNI_NetplayStart(uint32 local_players, uint32 netmerge, const std::string &nickname, const std::string &game_key, const std::string &connect_password)
int MDFNI_NetplayStart(uint32 local_players, const std::string &nickname, const std::string &game_key, const std::string &connect_password)
{
return(NetplayStart((const char**)PortDeviceCache, PortDataLenCache, local_players, netmerge, nickname, game_key, connect_password));
return(NetplayStart((const char**)PortDeviceCache, PortDataLenCache, local_players, nickname, game_key, connect_password));
}
@ -1054,7 +1053,6 @@ int MDFNI_Initialize(const char *basedir, const std::vector<MDFNSetting> &Driver
return(0);
}
memset(PortDataCache, 0, sizeof(PortDataCache));
memset(PortDataLenCache, 0, sizeof(PortDataLenCache));
memset(PortDeviceCache, 0, sizeof(PortDeviceCache));
@ -1070,9 +1068,9 @@ int MDFNI_Initialize(const char *basedir, const std::vector<MDFNSetting> &Driver
{
MDFNSetting setting;
const char *sysname;
sysname = (const char *)MDFNSystems[i]->shortname;
if(!MDFNSystems[i]->soundchan)
printf("0 sound channels for %s????\n", sysname);
@ -1095,14 +1093,13 @@ int MDFNI_Initialize(const char *basedir, const std::vector<MDFNSetting> &Driver
dynamic_settings.push_back(setting);
}
if(DriverSettings.size())
MDFN_MergeSettings(DriverSettings);
// First merge all settable settings, then load the settings from the SETTINGS FILE OF DOOOOM
MDFN_MergeSettings(MednafenSettings);
MDFN_MergeSettings(dynamic_settings);
MDFN_MergeSettings(MDFNMP_Settings);
if(DriverSettings.size())
MDFN_MergeSettings(DriverSettings);
for(unsigned int x = 0; x < MDFNSystems.size(); x++)
{
@ -1306,6 +1303,12 @@ void MDFNI_Emulate(EmulateSpecStruct *espec)
multiplier_save = 1;
volume_save = 1;
// Initialize some espec member data to zero, to catch some types of bugs.
espec->DisplayRect.x = 0;
espec->DisplayRect.w = 0;
espec->DisplayRect.y = 0;
espec->DisplayRect.h = 0;
assert((bool)(espec->SoundBuf != NULL) == (bool)espec->SoundRate && (bool)espec->SoundRate == (bool)espec->SoundBufMaxSize);
espec->SoundBufSize = 0;
@ -1359,12 +1362,12 @@ void MDFNI_Emulate(EmulateSpecStruct *espec)
if(MDFNMOV_IsPlaying())
{
espec->NeedRewind = 0;
MDFN_DispMessage(_("Can't rewind during movie playback(yet!)."));
MDFN_DispMessage(_("Can't rewind during movie playback."));
}
else if(MDFNnetplay)
{
espec->NeedRewind = 0;
MDFN_DispMessage(_("Silly-billy, can't rewind during netplay."));
MDFN_DispMessage(_("Can't rewind during netplay."));
}
else if(MDFNGameInfo->GameType == GMT_PLAYER)
{
@ -1373,10 +1376,30 @@ void MDFNI_Emulate(EmulateSpecStruct *espec)
}
}
espec->NeedSoundReverse = MDFN_StateEvil(espec->NeedRewind);
// Don't even save states with state rewinding if netplay is enabled, it will degrade netplay performance, and can cause
// desynchs with some emulation(IE SNES based on bsnes).
if(MDFNnetplay)
espec->NeedSoundReverse = false;
else
espec->NeedSoundReverse = MDFN_StateEvil(espec->NeedRewind);
MDFNGameInfo->Emulate(espec);
//
// Sanity checks
//
if(!espec->skip)
{
if(espec->DisplayRect.h == 0)
{
fprintf(stderr, "espec->DisplayRect.h == 0\n");
}
}
//
//
//
if(espec->InterlaceOn)
{
if(!PrevInterlaced)
@ -1556,7 +1579,7 @@ void MDFN_DoSimpleCommand(int cmd)
void MDFN_QSimpleCommand(int cmd)
{
if(MDFNnetplay)
MDFNNET_SendCommand(cmd, 0);
NetplaySendCommand(cmd, 0);
else
{
if(!MDFNMOV_IsPlaying())

View File

@ -37,7 +37,7 @@ static inline void MDFN_FastU32MemsetM8(uint32_t *array, uint32_t value_32, unsi
#else
for(uint32_t *ai = array; ai < array + u32len; ai += 2)
for(uint32 *ai = array; ai < array + u32len; ai += 2)
{
ai[0] = value_32;
ai[1] = value_32;

View File

@ -22,6 +22,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <trio/trio.h>
#include "driver.h"
#include "state.h"
@ -75,6 +76,17 @@ void MDFNI_SaveMovie(char *fname, const MDFN_Surface *surface, const MDFN_Rect *
{
gzFile fp;
if(!MDFNGameInfo->StateAction)
return;
if(MDFNnetplay && (MDFNGameInfo->SaveStateAltersState == true))
{
char sb[256];
trio_snprintf(sb, sizeof(sb), _("Module %s is not compatible with manual movie save starting/stopping during netplay."), MDFNGameInfo->shortname);
MDFND_NetplayText((const uint8*)sb, false);
return;
}
if(current < 0) /* Can't interrupt playback.*/
return;

View File

@ -9,9 +9,8 @@ void MDFNI_NetplayStop(void);
MDFND_RecvData().
*/
/* Return 0 on failure, 1 on success. */
int MDFND_SendData(const void *data, uint32 len);
int MDFND_RecvData(void *data, uint32 len);
void MDFND_SendData(const void *data, uint32 len); // thrown std::exception will be handled
void MDFND_RecvData(void *data, uint32 len); // thrown std::exception will be handled
/* Display text received over the network. */
/* NetEcho will be set to TRUE if the displayed text is a network
@ -23,6 +22,14 @@ void MDFND_NetplayText(const uint8 *text, bool NetEcho);
void MDFNI_NetplayText(const uint8 *text);
void MDFNI_NetplayQuit(const char *quit_message);
void MDFNI_NetplaySwap(uint8 a, uint8 b);
void MDFNI_NetplayTake(uint32 mask);
void MDFNI_NetplayDrop(uint32 mask);
void MDFNI_NetplayDupe(uint32 mask);
void MDFNI_NetplayList(void);
/* Starts a process to determine the integrity(synchronization) of all players
in the current game session on the server. Outputs result via MDFND_NetplayText()
when they are received from the server(not in this function).

View File

@ -18,6 +18,7 @@
// Protocol versions:
// 1 - I forgot!
// 2 - Added support for more versatile input configurations...somewhat
// 3 -
#include "mednafen.h"
@ -46,10 +47,6 @@ static uint32 LocalPlayersMask = 0;
static uint32 TotalInputStateSize = 0;
static uint32 LocalInputStateSize = 0;
/* NetError should only be called after a MDFND_*Data function returned 0, in the function
that called MDFND_*Data, to prevent it from being called twice.
*/
static void NetError(const char *format, ...)
{
char *temp = NULL;
@ -68,6 +65,7 @@ void MDFNI_NetplayStop(void)
{
if(MDFNnetplay)
{
Joined = false;
MDFNnetplay = 0;
MDFN_FlushGameCheats(1); /* Don't save netplay cheats. */
MDFN_LoadGameCheats(0); /* Reload our original cheats. */
@ -80,72 +78,74 @@ void MDFNI_NetplayStop(void)
else puts("Check your code!");
}
int NetplayStart(const char *PortDeviceCache[16], const uint32 PortDataLenCache[16], uint32 local_players, uint32 netmerge, const std::string &nickname, const std::string &game_key, const std::string &connect_password)
int NetplayStart(const char *PortDeviceCache[16], const uint32 PortDataLenCache[16], uint32 local_players, const std::string &nickname, const std::string &game_key, const std::string &connect_password)
{
uint8 *sendbuf;
uint32 sblen;
std::string controller_types;
const char *emu_id = PACKAGE " " MEDNAFEN_VERSION;
// Concatenate!
for(int x = 0; x < MDFNGameInfo->InputInfo->InputPorts; x++)
controller_types += std::string(PortDeviceCache[x]) + "\n";
sblen = 4 + 16 + 16 + 64 + 1 + nickname.size() + controller_types.size();
sendbuf = (uint8 *)malloc(sblen);
memset(sendbuf, 0, sblen);
MDFN_en32lsb(sendbuf, sblen - 4);
if(game_key != "")
try
{
md5_context md5;
uint8 md5out[16];
sblen = 4 + 16 + 16 + 64 + 1 + nickname.size() + strlen(emu_id);
sendbuf = (uint8 *)malloc(sblen);
memset(sendbuf, 0, sblen);
md5.starts();
md5.update(MDFNGameInfo->MD5, 16);
md5.update((uint8 *)game_key.c_str(), game_key.size());
md5.finish(md5out);
memcpy(sendbuf + 4, md5out, 16);
MDFN_en32lsb(sendbuf, sblen - 4);
if(game_key != "")
{
md5_context md5;
uint8 md5out[16];
md5.starts();
md5.update(MDFNGameInfo->MD5, 16);
md5.update((uint8 *)game_key.c_str(), game_key.size());
md5.finish(md5out);
memcpy(sendbuf + 4, md5out, 16);
}
else
memcpy(sendbuf + 4, MDFNGameInfo->MD5, 16);
if(connect_password != "")
{
md5_context md5;
uint8 md5out[16];
md5.starts();
md5.update((uint8*)connect_password.c_str(), connect_password.size());
md5.finish(md5out);
memcpy(sendbuf + 4 + 16, md5out, 16);
}
uint8 *extra = sendbuf + 4 + 16 + 16;
extra[0] = 3; // Protocol version
// Set input device number thingies here.
extra[1] = MDFNGameInfo->InputInfo->InputPorts; // Total number of ports
// The size of the giganto string with the controller types
MDFN_en32lsb(&extra[4], strlen(emu_id));
// 16-32, controller data sizes
for(int x = 0; x < MDFNGameInfo->InputInfo->InputPorts; x++)
extra[16 + x] = PortDataLenCache[x];
sendbuf[4 + 16 + 16 + 64] = local_players;
if(nickname != "")
memcpy(sendbuf + 4 + 16 + 16 + 64 + 1, nickname.c_str(), nickname.size());
memcpy(sendbuf + 4 + 16 + 16 + 64 + 1 + nickname.size(), emu_id, strlen(emu_id));
MDFND_SendData(sendbuf, sblen);
}
else
memcpy(sendbuf + 4, MDFNGameInfo->MD5, 16);
if(connect_password != "")
catch(std::exception &e)
{
md5_context md5;
uint8 md5out[16];
md5.starts();
md5.update((uint8*)connect_password.c_str(), connect_password.size());
md5.finish(md5out);
memcpy(sendbuf + 4 + 16, md5out, 16);
NetError("%s", e.what());
return(false);
}
uint8 *extra = sendbuf + 4 + 16 + 16;
extra[0] = 2; // Protocol version
// Set input device number thingies here.
extra[1] = MDFNGameInfo->InputInfo->InputPorts; // Total number of ports
// The size of the giganto string with the controller types
MDFN_en32lsb(&extra[4], controller_types.size());
// 16-32, controller data sizes
for(int x = 0; x < MDFNGameInfo->InputInfo->InputPorts; x++)
extra[16 + x] = PortDataLenCache[x];
sendbuf[4 + 16 + 16 + 32] = netmerge;
sendbuf[4 + 16 + 16 + 64] = local_players;
if(nickname != "")
memcpy(sendbuf + 4 + 16 + 16 + 64 + 1, nickname.c_str(), nickname.size());
memcpy(sendbuf + 4 + 16 + 16 + 64 + 1 + nickname.size(), controller_types.c_str(), controller_types.size());
MDFND_SendData(sendbuf, sblen);
TotalInputStateSize = 0;
for(int x = 0; x < MDFNGameInfo->InputInfo->InputPorts; x++)
TotalInputStateSize += PortDataLenCache[x];
@ -169,7 +169,7 @@ int NetplayStart(const char *PortDeviceCache[16], const uint32 PortDataLenCache[
return(1);
}
int MDFNNET_SendCommand(uint8 cmd, uint32 len)
static void SendCommand(uint8 cmd, uint32 len)
{
uint8 buf[1 + LocalInputStateSize + 4]; // Command, unused, command length
@ -177,63 +177,171 @@ int MDFNNET_SendCommand(uint8 cmd, uint32 len)
buf[0] = cmd;
MDFN_en32lsb(&buf[1 + LocalInputStateSize], len);
if(!MDFND_SendData(buf,LocalInputStateSize + 1 + 4))
{
NetError("Could not send command.");
return(0);
}
return(1);
MDFND_SendData(buf,LocalInputStateSize + 1 + 4);
}
bool NetplaySendCommand(uint8 cmd, uint32 len)
{
try
{
SendCommand(cmd, len);
}
catch(std::exception &e)
{
NetError("%s", e.what());
return(false);
}
return(true);
}
void MDFNI_NetplaySwap(uint8 a, uint8 b)
{
try
{
SendCommand(MDFNNPCMD_CTRLR_SWAP, (a << 0) | (b << 8));
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
void MDFNI_NetplayTake(uint32 mask)
{
try
{
SendCommand(MDFNNPCMD_CTRLR_TAKE, mask);
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
void MDFNI_NetplayDrop(uint32 mask)
{
try
{
SendCommand(MDFNNPCMD_CTRLR_DROP, mask);
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
void MDFNI_NetplayDupe(uint32 mask)
{
try
{
SendCommand(MDFNNPCMD_CTRLR_DUPE, mask);
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
void MDFNI_NetplayList(void)
{
try
{
SendCommand(MDFNNPCMD_REQUEST_LIST, 0);
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
void MDFNI_NetplayPing(void)
{
uint64 now_time;
try
{
uint64 now_time;
now_time = MDFND_GetTime();
now_time = MDFND_GetTime();
if(!MDFNNET_SendCommand(MDFNNPCMD_ECHO, sizeof(now_time)))
return;
SendCommand(MDFNNPCMD_ECHO, sizeof(now_time));
// Endianness doesn't matter, since it will be echoed back only to us.
if(!MDFND_SendData(&now_time, sizeof(now_time)))
NetError("Could not send echo data.");
// Endianness doesn't matter, since it will be echoed back only to us.
MDFND_SendData(&now_time, sizeof(now_time));
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
void MDFNI_NetplayIntegrity(void)
{
if(!MDFNNET_SendCommand(MDFNNPCMD_INTEGRITY, 0))
return;
try
{
SendCommand(MDFNNPCMD_INTEGRITY, 0);
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
void MDFNI_NetplayText(const uint8 *text)
{
uint32 len;
try
{
uint32 len;
if(!Joined) return;
if(!Joined) return;
len = strlen((char *)text);
len = strlen((char *)text);
if(!MDFNNET_SendCommand(MDFNNPCMD_TEXT,len)) return;
SendCommand(MDFNNPCMD_TEXT, len);
if(!MDFND_SendData(text,len))
NetError("Could not send text data.");
MDFND_SendData(text,len);
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
void MDFNI_NetplayChangeNick(UTF8 *newnick)
{
uint32 len;
try
{
uint32 len;
if(!Joined) return;
if(!Joined) return;
len = strlen((char *)newnick);
len = strlen((char *)newnick);
if(!MDFNNET_SendCommand(MDFNNPCMD_SETNICK,len)) return;
SendCommand(MDFNNPCMD_SETNICK, len);
if(!MDFND_SendData(newnick, len))
NetError("Could not send new nick data.");
MDFND_SendData(newnick, len);
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
int MDFNNET_SendIntegrity(void)
void MDFNI_NetplayQuit(const char *quit_message)
{
try
{
SendCommand(MDFNNPCMD_QUIT, strlen(quit_message));
MDFND_SendData(quit_message, strlen(quit_message));
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
// Integrity checking is experimental, and needs work to function properly(in the emulator cores).
static int SendIntegrity(void)
{
StateMem sm;
md5_context md5;
@ -241,8 +349,11 @@ int MDFNNET_SendIntegrity(void)
memset(&sm, 0, sizeof(StateMem));
if(!MDFNSS_SaveSM(&sm, 0, 0))
return(0);
// Do not do a raw/data-only state for speed, due to lack of endian and bool conversion.
if(!MDFNSS_SaveSM(&sm, 0, false))
{
throw MDFN_Error(0, _("Error during save state generation."));
}
md5.starts();
md5.update(sm.data, sm.len);
@ -254,122 +365,134 @@ int MDFNNET_SendIntegrity(void)
// printf("%02x", digest[i]);
//puts("");
if(!MDFNNET_SendCommand(MDFNNPCMD_INTEGRITY_RES, 16))
{
NetError(_("Could not send the integrity result to the netplay server."));
return(0);
}
if(!MDFND_SendData(digest, 16))
{
NetError(_("Could not send the integrity result to the netplay server."));
return(0);
}
SendCommand(MDFNNPCMD_INTEGRITY_RES, 16);
MDFND_SendData(digest, 16);
return(1);
}
int MDFNNET_SendState(void)
static void SendState(void)
{
StateMem sm;
uLongf clen;
uint8 *cbuf;
std::vector<uint8> cbuf;
memset(&sm, 0, sizeof(StateMem));
if(!MDFNSS_SaveSM(&sm, 0, 0))
return(0);
{
throw MDFN_Error(0, _("Error during save state generation."));
}
clen = sm.len + sm.len / 1000 + 12;
cbuf = (uint8 *)malloc(4 + clen);
MDFN_en32lsb(cbuf, sm.len);
compress2((Bytef *)cbuf + 4, &clen, (Bytef *)sm.data, sm.len, 7);
if(!MDFNNET_SendCommand(MDFNNPCMD_LOADSTATE,clen + 4))
{
free(cbuf);
NetError(_("Could not send the save state command to the netplay server."));
return(0);
}
if(!MDFND_SendData(cbuf, clen + 4))
{
NetError(_("Could not send the save state data to the netplay server."));
free(cbuf);
return(0);
}
cbuf.resize(4 + clen);
MDFN_en32lsb(&cbuf[0], sm.len);
compress2((Bytef *)&cbuf[0] + 4, &clen, (Bytef *)sm.data, sm.len, 7);
free(sm.data);
free(cbuf);
return(1);
SendCommand(MDFNNPCMD_LOADSTATE, clen + 4);
MDFND_SendData(&cbuf[0], clen + 4);
}
int MDFNNET_RecvState(uint32 clen)
static void RecvState(const uint32 clen)
{
StateMem sm;
uint8 *cbuf;
std::vector<uint8> cbuf;
std::vector<uint8> buf;
memset(&sm, 0, sizeof(StateMem));
if(clen > 4000000) // Sanity check
if(clen < 4)
{
NetError("Compressed save state data is too large: %d", clen);
return(0);
throw MDFN_Error(0, _("Compressed save state data is too small: %u"), clen);
}
cbuf = (uint8*)malloc(clen);
if(!MDFND_RecvData(cbuf, clen))
{
NetError("Could not receive compressed save state data.");
free(cbuf);
return(0);
}
uLongf len = MDFN_de32lsb((uint8 *)cbuf);
if(len > 4000000)
{
NetError("Decompressed save state data is too large: %d", clen);
free(cbuf);
return(0);
}
uint8 *buf = (uint8 *)malloc(len);
uncompress((Bytef *)buf, &len, (Bytef *)cbuf + 4, clen - 4);
sm.data = buf;
if(clen > 8 * 1024 * 1024) // Compressed length sanity check - 8 MiB max.
{
throw MDFN_Error(0, _("Compressed save state data is too large: %u"), clen);
}
cbuf.resize(clen);
MDFND_RecvData(&cbuf[0], clen);
uLongf len = MDFN_de32lsb(&cbuf[0]);
if(len > 12 * 1024 * 1024) // Uncompressed length sanity check - 12 MiB max.
{
throw MDFN_Error(0, _("Uncompressed save state data is too large: %u"), len);
}
buf.resize(len);
uncompress((Bytef *)&buf[0], &len, (Bytef *)&cbuf[0] + 4, clen - 4);
sm.data = &buf[0];
sm.len = len;
if(!MDFNSS_LoadSM(&sm, 0, 0))
{
NetError("Error during save state loading.");
return(0);
throw MDFN_Error(0, _("Error during save state loading."));
}
if(MDFNMOV_IsRecording())
MDFNMOV_RecordState();
return(1);
}
std::string GenerateMPSString(uint8 mps)
static std::string GenerateMPSString(uint32 mps, bool ctlr_string = false)
{
char tmpbuf[256];
tmpbuf[0] = 0;
if(!mps)
trio_snprintf(tmpbuf, 256, _("a lurker"));
{
if(!ctlr_string)
trio_snprintf(tmpbuf, sizeof(tmpbuf), _("a lurker"));
}
else
trio_snprintf(tmpbuf, 256, _("player(s)%s%s%s%s%s%s%s%s"),
(mps & 0x01) ? " 1" : "",
(mps & 0x02) ? " 2" : "",
(mps & 0x04) ? " 3" : "",
(mps & 0x08) ? " 4" : "",
(mps & 0x10) ? " 5" : "",
(mps & 0x20) ? " 6" : "",
(mps & 0x40) ? " 7" : "",
(mps & 0x80) ? " 8" : "");
trio_snprintf(tmpbuf, sizeof(tmpbuf), ("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"), ctlr_string ? ((mps == round_up_pow2(mps)) ? _("controller") : _("controllers")) : ((mps == round_up_pow2(mps)) ? _("player") : _("players")),
(mps & 0x0001) ? " 1" : "",
(mps & 0x0002) ? " 2" : "",
(mps & 0x0004) ? " 3" : "",
(mps & 0x0008) ? " 4" : "",
(mps & 0x0010) ? " 5" : "",
(mps & 0x0020) ? " 6" : "",
(mps & 0x0040) ? " 7" : "",
(mps & 0x0080) ? " 8" : "",
(mps & 0x0100) ? " 9" : "",
(mps & 0x0200) ? " 10" : "",
(mps & 0x0400) ? " 11" : "",
(mps & 0x0800) ? " 12" : "",
(mps & 0x1000) ? " 13" : "",
(mps & 0x2000) ? " 14" : "",
(mps & 0x4000) ? " 15" : "",
(mps & 0x8000) ? " 16" : "");
return(std::string(tmpbuf));
}
void NetplaySendState(void)
{
try
{
SendState();
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
}
void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[], int NumPorts)
{
uint8 buf[TotalInputStateSize + 1];
//
//
try
{
if(Joined)
{
uint8 outgoing_buffer[1 + LocalInputStateSize];
@ -381,7 +504,7 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
int wpos = 1;
for(int x = 0; x < NumPorts; x++)
for(int x = 0; x < NumPorts; x++)
{
if(LocalPlayersMask & (1 << x))
{
@ -399,20 +522,12 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
}
}
if(!MDFND_SendData(outgoing_buffer, 1 + LocalInputStateSize))
{
NetError("Sending joystick update data failed.");
return;
}
MDFND_SendData(outgoing_buffer, 1 + LocalInputStateSize);
}
do
{
if(!MDFND_RecvData(buf, TotalInputStateSize + 1))
{
NetError("Could not receive joystick update data.");
return;
}
MDFND_RecvData(buf, TotalInputStateSize + 1);
switch(buf[TotalInputStateSize])
{
@ -421,41 +536,32 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
default: MDFN_DoSimpleCommand(buf[TotalInputStateSize]);break;
case MDFNNPCMD_INTEGRITY:
if(!MDFNNET_SendIntegrity())
return;
SendIntegrity();
break;
case MDFNNPCMD_SAVESTATE:
if(!MDFNNET_SendState())
{
return;
}
case MDFNNPCMD_REQUEST_STATE:
SendState();
break;
case MDFNNPCMD_LOADSTATE:
if(!MDFNNET_RecvState(MDFN_de32lsb(buf)))
{
return;
}
case MDFNNPCMD_LOADSTATE:
RecvState(MDFN_de32lsb(buf));
MDFN_DispMessage(_("Remote state loaded."));
break;
case MDFNNPCMD_SERVERTEXT:
{
uint32 totallen = MDFN_de32lsb(buf);
if(totallen > 2000) // Sanity check
static const uint32 MaxLength = 2000;
uint8 neobuf[MaxLength + 1];
char *textbuf = NULL;
const uint32 totallen = MDFN_de32lsb(buf);
if(totallen > MaxLength) // Sanity check
{
NetError("Text length is too long: %d", totallen);
return;
}
uint8 neobuf[totallen + 1];
char *textbuf = NULL;
if(!MDFND_RecvData(neobuf, totallen))
{
NetError("Could not receive text data.");
return;
throw MDFN_Error(0, _("Text length is too long: %u"), totallen);
}
MDFND_RecvData(neobuf, totallen);
neobuf[totallen] = 0;
trio_asprintf(&textbuf, "** %s", neobuf);
MDFND_NetplayText((UTF8*)textbuf, FALSE);
@ -471,14 +577,11 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
if(totallen != sizeof(then_time))
{
NetError("Echo response length is incorrect size: %d", totallen);
return;
throw MDFN_Error(0, _("Echo response length is incorrect size: %u"), totallen);
}
if(!MDFND_RecvData(&then_time, sizeof(then_time)))
{
NetError("Could not receive echo response data.");
return;
}
MDFND_RecvData(&then_time, sizeof(then_time));
now_time = MDFND_GetTime();
char *textbuf = NULL;
@ -490,28 +593,32 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
case MDFNNPCMD_TEXT:
{
uint32 totallen = MDFN_de32lsb(buf);
if(totallen > 2000) // Sanity check
static const uint32 MaxLength = 2000;
uint8 neobuf[MaxLength + 1];
const uint32 totallen = MDFN_de32lsb(buf);
uint32 nicklen;
bool NetEcho = false;
char *textbuf = NULL;
if(totallen < 4)
{
NetError("Text length is too long: %d", totallen);
return;
}
uint32 nicklen;
uint8 neobuf[totallen + 1];
char *textbuf = NULL;
if(!MDFND_RecvData(neobuf, totallen))
throw MDFN_Error(0, _("Text command length is too short: %u"), totallen);
}
if(totallen > MaxLength) // Sanity check
{
NetError("Could not receive text data.");
return;
throw MDFN_Error(0, _("Text command length is too long: %u"), totallen);
}
MDFND_RecvData(neobuf, totallen);
nicklen = MDFN_de32lsb(neobuf);
if(nicklen > totallen) // Sanity check
if(nicklen > (totallen - 4)) // Sanity check
{
NetError("Received nickname length is too long: %d", nicklen);
return;
throw MDFN_Error(0, _("Received nickname length is too long: %u"), nicklen);
}
neobuf[totallen] = 0;
bool NetEcho = 0;
if(nicklen)
{
@ -521,7 +628,7 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
if(OurNick && !strcasecmp(OurNick, (char *)nickbuf))
{
trio_asprintf(&textbuf, "> %s", &neobuf[4 + nicklen]);
NetEcho = TRUE;
NetEcho = true;
}
else
trio_asprintf(&textbuf, "<%s> %s", nickbuf, &neobuf[4 + nicklen]);
@ -531,29 +638,24 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
trio_asprintf(&textbuf, "* %s", &neobuf[4]);
}
MDFND_NetplayText((UTF8*)textbuf, NetEcho);
free(textbuf);
free(textbuf);
}
break;
case MDFNNPCMD_NICKCHANGED:
{
uint32 len = MDFN_de32lsb(buf);
static const uint32 MaxLength = 2000;
uint8 neobuf[MaxLength + 1];
uint8 *newnick;
char *textbuf = NULL;
const uint32 len = MDFN_de32lsb(buf);
if(len > 2000) // Sanity check
if(len > MaxLength) // Sanity check
{
NetError("Nickname change length is too long: %u", len);
return;
throw MDFN_Error(0, _("Nickname change length is too long: %u"), len);
}
uint8 neobuf[len + 1];
uint8 *newnick;
char *textbuf = NULL;
if(!MDFND_RecvData(neobuf, len))
{
NetError("Unable to receive data for nickname change.");
return;
}
MDFND_RecvData(neobuf, len);
neobuf[len] = 0;
@ -582,39 +684,104 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
}
break;
case MDFNNPCMD_CTRL_CHANGE:
{
const uint32 len = MDFN_de32lsb(buf);
//
// Joined = true;
SendCommand(MDFNNPCMD_CTRL_CHANGE_ACK, len);
//
//
LocalInputStateSize = 0;
LocalPlayersMask = len;
for(int x = 0; x < MDFNGameInfo->InputInfo->InputPorts; x++)
{
if(LocalPlayersMask & (1 << x))
LocalInputStateSize += PortLen[x];
}
}
break;
case MDFNNPCMD_CTRLR_SWAP_NOTIF:
{
const uint32 cm = MDFN_de32lsb(buf);
char textbuf[512];
trio_snprintf(textbuf, sizeof(textbuf), _("* All instances of controllers %u and %u have been swapped."), ((cm & 0xFF) + 1), ((cm >> 8) & 0xFF) + 1);
MDFND_NetplayText((UTF8*)textbuf, false);
}
break;
case MDFNNPCMD_CTRLR_TAKE_NOTIF:
case MDFNNPCMD_CTRLR_DROP_NOTIF:
case MDFNNPCMD_CTRLR_DUPE_NOTIF:
{
static const uint32 MaxNicknameLength = 1000;
static const uint32 MaxLength = 12 + MaxNicknameLength;
const char *fstr = NULL;
const uint32 len = MDFN_de32lsb(buf);
uint8 ntf_buf[MaxLength + 1];
char *textbuf = NULL;
if(len < 12)
throw MDFN_Error(0, _("Take/drop/dupe notification is too short: %u"), len);
if(len > MaxLength)
throw MDFN_Error(0, _("Take/drop/dupe notification is too long: %u"), len);
MDFND_RecvData(ntf_buf, len);
ntf_buf[len] = 0;
switch(buf[TotalInputStateSize])
{
case MDFNNPCMD_CTRLR_TAKE_NOTIF:
fstr = _("* <%s> took all instances of %s, and is now %s.");
break;
case MDFNNPCMD_CTRLR_DUPE_NOTIF:
fstr = _("* <%s> took copies of %s, and is now %s.");
break;
case MDFNNPCMD_CTRLR_DROP_NOTIF:
fstr = _("* <%s> dropped %s, and is now %s.");
break;
}
trio_asprintf(&textbuf, fstr, ntf_buf + 12, GenerateMPSString(MDFN_de32lsb(&ntf_buf[0]), true).c_str(), GenerateMPSString(MDFN_de32lsb(&ntf_buf[4]), false).c_str());
MDFND_NetplayText((UTF8*)textbuf, false);
free(textbuf);
}
break;
case MDFNNPCMD_YOUJOINED:
case MDFNNPCMD_YOULEFT:
case MDFNNPCMD_PLAYERLEFT:
case MDFNNPCMD_PLAYERJOINED:
{
uint32 len = MDFN_de32lsb(buf);
static const uint32 MaxLength = 2000;
uint8 neobuf[MaxLength + 1];
char *textbuf = NULL;
uint32 mps;
std::string mps_string;
const uint32 len = MDFN_de32lsb(buf);
if(len > 2000) // Sanity check
if(len < 8)
{
throw MDFN_Error(0, _("Join/Left length is too short: %u"), len);
}
if(len > MaxLength) // Sanity check
{
NetError("Join/Left length is too long: %u", len);
return;
throw MDFN_Error(0, _("Join/Left length is too long: %u"), len);
}
uint8 neobuf[len + 1];
char *textbuf = NULL;
char mergedstr[] = " merged into: ";
std::string mps_string;
if(!MDFND_RecvData(neobuf, len))
{
NetError("Unable to receive data for join/part message");
return;
}
MDFND_RecvData(neobuf, len);
neobuf[len] = 0; // NULL-terminate the string
if(neobuf[1]) // Player is merged?
{
mergedstr[strlen(mergedstr) - 1] = '1' + (int)rint(log(neobuf[1]) / log(2));
}
else
mergedstr[0] = 0;
mps = MDFN_de32lsb(&neobuf[0]);
mps_string = GenerateMPSString(neobuf[0]);
mps_string = GenerateMPSString(mps);
if(buf[TotalInputStateSize] == MDFNNPCMD_YOULEFT)
{
@ -630,27 +797,28 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
free(OurNick);
OurNick = NULL;
}
OurNick = strdup((char*)neobuf + 2);
OurNick = strdup((char*)neobuf + 8);
trio_asprintf(&textbuf, _("* You, %s, have connected as: %s%s"), neobuf + 2, mps_string.c_str(), mergedstr);
trio_asprintf(&textbuf, _("* You, %s, have connected as: %s"), neobuf + 8, mps_string.c_str());
LocalInputStateSize = 0;
LocalPlayersMask = neobuf[0];
LocalPlayersMask = mps;
for(int x = 0; x < MDFNGameInfo->InputInfo->InputPorts; x++)
{
if(LocalPlayersMask & (1 << x))
LocalInputStateSize += PortLen[x];
}
Joined = TRUE;
MDFNNET_SendCommand(MDFNNPCMD_SETFPS, MDFNGameInfo->fps);
SendCommand(MDFNNPCMD_SETFPS, MDFNGameInfo->fps);
}
else if(buf[TotalInputStateSize] == MDFNNPCMD_PLAYERLEFT)
{
trio_asprintf(&textbuf, _("* %s has left(%s%s)"), neobuf + 2, mps_string.c_str(), mergedstr);
trio_asprintf(&textbuf, _("* %s(%s) has left"), neobuf + 8, mps_string.c_str());
}
else
{
trio_asprintf(&textbuf, _("* %s has connected as: %s%s"), neobuf + 2, mps_string.c_str(), mergedstr);
trio_asprintf(&textbuf, _("* %s has connected as: %s"), neobuf + 8, mps_string.c_str());
}
MDFND_NetplayText((UTF8*)textbuf, FALSE);
free(textbuf);
@ -661,11 +829,18 @@ void NetplayUpdate(const char **PortDNames, void *PortData[], uint32 PortLen[],
int rpos = 0;
for(int x = 0; x < NumPorts; x++)
{
{
//printf("%d %d\n", x, PortLen[x]);
//memset(PortData[x], 0, PortLen[x]);
memcpy(PortData[x], buf + rpos, PortLen[x]);
rpos += PortLen[x];
}
}
catch(std::exception &e)
{
NetError("%s", e.what());
}
//
//
}

View File

@ -4,8 +4,9 @@
int InitNetplay(void);
void NetplayUpdate(const char **, void *PortData[], uint32 PortLen[], int NumPorts);
int NetplayStart(const char *PortDeviceCache[16], const uint32 PortDataLenCache[16], uint32 local_players, uint32 netmerge, const std::string &nickname, const std::string &game_key, const std::string &connect_password);
int NetplayStart(const char *PortDeviceCache[16], const uint32 PortDataLenCache[16], uint32 local_players, const std::string &nickname, const std::string &game_key, const std::string &connect_password);
void NetplaySendState(void);
bool NetplaySendCommand(uint8, uint32);
extern int MDFNnetplay;
@ -19,17 +20,33 @@ extern int MDFNnetplay;
#define MDFNNPCMD_FDSEJECT MDFN_MSC_EJECT_DISK
#define MDFNNPCMD_FDSSELECT MDFN_MSC_SELECT_DISK
#define MDFNNPCMD_SETFPS 0x40 /* Sent from client to server ONLY(it should be ignored server-side if it's not from the first
active player for the game). */
#define MDFNNPCMD_SETFPS 0x40 // Client->server. It should be ignored server-side if it's not from the first
// active player for the game).
#define MDFNNPCMD_LOADSTATE 0x80
#define MDFNNPCMD_NOP 0x41 // Client->server.
#define MDFNNPCMD_SAVESTATE 0x81 /* Sent from server to client. */
//
#define MDFNNPCMD_CTRL_CHANGE 0x43 // Server->client.
#define MDFNNPCMD_CTRL_CHANGE_ACK 0x44 // Client->server. Acknowledge controller change. Sent using old local data length, everything after
// this should be new data size.
//
#define MDFNNPCMD_CTRLR_SWAP_NOTIF 0x68 // Server->Client
#define MDFNNPCMD_CTRLR_TAKE 0x70 // Client->server. Take the specified controllers(from other clients)
#define MDFNNPCMD_CTRLR_DROP 0x71 // Client->server. Drop(relinquish) the specified controllers.
#define MDFNNPCMD_CTRLR_DUPE 0x72 // Client->server. Take the specified controllers(but let other clients still keep their control).
#define MDFNNPCMD_CTRLR_SWAP 0x78 // Client->server.
#define MDFNNPCMD_REQUEST_LIST 0x7F // client->server
#define MDFNNPCMD_LOADSTATE 0x80 // Client->server, and server->client
#define MDFNNPCMD_REQUEST_STATE 0x81 // Server->client
#define MDFNNPCMD_TEXT 0x90
#define MDFNNPCMD_SETSETTING 0x91 /* TODO: WIP */
#define MDFNNPCMD_SERVERTEXT 0x93 // Server text message(informational), server->client
#define MDFNNPCMD_ECHO 0x94 // Echos the string(no larger than 256 bytes) back to the client(used for pinging).
@ -48,6 +65,14 @@ extern int MDFNnetplay;
#define MDFNNPCMD_NICKCHANGED 0xB8
#define MDFNNPCMD_LIST 0xC0 // Server->client
#define MDFNNPCMD_CTRLR_TAKE_NOTIF 0xF0 // Server->client
#define MDFNNPCMD_CTRLR_DROP_NOTIF 0xF1 // Server->client
#define MDFNNPCMD_CTRLR_DUPE_NOTIF 0xF2 // Server->client
#define MDFNNPCMD_QUIT 0xFF // Client->server
int MDFNNET_SendCommand(uint8, uint32);
int MDFNNET_SendState(void);
#endif

Binary file not shown.

View File

@ -80,7 +80,7 @@ cpu.o: cpu.cpp psx.h ../../mednafen/mednafen.h ../../mednafen/types.h \
../../mednafen/state-common.h ../../mednafen/settings-common.h \
../../mednafen/debug.h ../../mednafen/git-virtb.h \
../../mednafen/settings.h ../../mednafen/mednafen-driver.h \
../../mednafen/endian.h ../../mednafen/memory.h \
../../mednafen/endian.h ../../mednafen/memory.h ../../mednafen/masmem.h \
../../include/trio/trio.h ../../include/trio/triop.h \
../../include/trio/triodef.h ../cdrom/cdromif.h ../cdrom/CDUtility.h \
/usr/include/c++/4.4/queue /usr/include/c++/4.4/deque \
@ -368,6 +368,8 @@ psx.h:
../../mednafen/memory.h:
../../mednafen/masmem.h:
../../include/trio/trio.h:
../../include/trio/triop.h:

View File

@ -124,6 +124,8 @@ ALLOCA = @ALLOCA@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AM_CFLAGS = @AM_CFLAGS@
AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
@ -242,6 +244,8 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
SNDFILE_LIBS = @SNDFILE_LIBS@
SNES_EXTRA_CXXFLAGS = @SNES_EXTRA_CXXFLAGS@
SNES_EXTRA_FLAGS = @SNES_EXTRA_FLAGS@
SSE2_CFLAGS = @SSE2_CFLAGS@
SSE3_CFLAGS = @SSE3_CFLAGS@
SSE_CFLAGS = @SSE_CFLAGS@
@ -250,6 +254,7 @@ TRIO_CFLAGS = @TRIO_CFLAGS@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
WARNING_FLAGS = @WARNING_FLAGS@
WINDRES = @WINDRES@
WOE32 = @WOE32@
WOE32DLL = @WOE32DLL@

View File

@ -1,6 +1,8 @@
Soul Reaver - Legacy of Kain has CD load time pauses where it probably shouldn't.
Dead or Alive, Battle Arena Toshinden, Final Fantasy 7 have some kind of GPU timing issues.
Battle Arena Toshinden, Final Fantasy 7 have some kind of GPU timing issues.
Zero Divide runs too fast(related to CPU emulation speed?).
Chrono Cross has several-second freezes during some large special attack/magic sequences.
@ -12,6 +14,10 @@ Rayman (Europe) has somewhat broken FMV.
Crusaders of Might and Magic - The CD-XA buffering increase for ToD II is apparently exacerbating the early voice cutoff problem in this game.
Misadventures of Trone Bonne - Voice problems, lockup, possibly due to excessively long seek delays?
Test time delta between GPU LL DMA end and GPU non-busy status for various primitive types in sequence on a PS1.
Test IRQ and COP0 latencies; PSX IRQ controller latency, software IRQ bit latency, latency of both relevant COP0 IRQ enable bits.
Test IRQ with LWC2.

View File

@ -305,6 +305,9 @@ int PS_CDC::StateAction(StateMem *sm, int load, int data_only)
SFVAR(CommandLoc_Dirty),
SFARRAY16(&xa_previous[0][0], sizeof(xa_previous) / sizeof(xa_previous[0][0])),
SFVAR(xa_cur_set),
SFVAR(xa_cur_file),
SFVAR(xa_cur_chan),
SFEND
};
@ -357,10 +360,8 @@ void PS_CDC::WriteResult(uint8 V)
ResultsWP = (ResultsWP + 1) & 0xF;
ResultsIn = (ResultsIn + 1) & 0x1F;
#ifdef DEBUG
if(!ResultsIn)
PSX_WARNING("[CDC] Results buffer overflow!");
#endif
}
uint8 PS_CDC::ReadResult(void)
@ -468,6 +469,10 @@ struct XA_SoundGroup
#define XA_CODING_189 0x04
#define XA_CODING_STEREO 0x01
// Special regression prevention test cases:
// Um Jammer Lammy (start doing poorly)
// Yarudora Series Vol.1 - Double Cast (non-FMV speech)
bool PS_CDC::XA_Test(const uint8 *sdata)
{
const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4];
@ -478,9 +483,28 @@ bool PS_CDC::XA_Test(const uint8 *sdata)
if(!(sh->submode & XA_SUBMODE_AUDIO))
return false;
//printf("Test File: 0x%02x 0x%02x - Channel: 0x%02x 0x%02x - Submode: 0x%02x 0x%02x - Coding: 0x%02x 0x%02x - \n", sh->file, sh->file_dup, sh->channel, sh->channel_dup, sh->submode, sh->submode_dup, sh->coding, sh->coding_dup);
if((Mode & MODE_SF) && (sh->file != FilterFile || sh->channel != FilterChan))
return false;
if(!xa_cur_set || (Mode & MODE_SF))
{
xa_cur_set = true;
xa_cur_file = sh->file;
xa_cur_chan = sh->channel;
}
else if(sh->file != xa_cur_file || sh->channel != xa_cur_chan)
return false;
if(sh->submode & XA_SUBMODE_EOF)
{
//puts("YAY");
xa_cur_set = false;
xa_cur_file = 0;
xa_cur_chan = 0;
}
return true;
}
@ -489,6 +513,10 @@ void PS_CDC::ClearAudioBuffers(void)
memset(AudioBuffer, 0, sizeof(AudioBuffer));
memset(xa_previous, 0, sizeof(xa_previous));
xa_cur_set = false;
xa_cur_file = 0;
xa_cur_chan = 0;
AudioBuffer_ReadPos = 0;
AudioBuffer_WritePos = 0;
AudioBuffer_UsedCount = 0;
@ -501,6 +529,8 @@ void PS_CDC::XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab)
const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4];
const unsigned unit_index_shift = (sh->coding & XA_CODING_8BIT) ? 0 : 1;
//printf("File: 0x%02x 0x%02x - Channel: 0x%02x 0x%02x - Submode: 0x%02x 0x%02x - Coding: 0x%02x 0x%02x - \n", sh->file, sh->file_dup, sh->channel, sh->channel_dup, sh->submode, sh->submode_dup, sh->coding, sh->coding_dup);
ab->Size = 18 * (4 << unit_index_shift) * 28;
if(sh->coding & XA_CODING_STEREO)
@ -521,10 +551,8 @@ void PS_CDC::XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab)
uint8 ibuffer[28];
int16 obuffer[2 + 28];
#ifdef DEBUG
if(param != param_copy)
printf("%d %02x %02x\n", unit, param, param_copy);
#endif
for(unsigned i = 0; i < 28; i++)
{
@ -594,12 +622,10 @@ void PS_CDC::CheckAIP(void)
void PS_CDC::SetAIP(unsigned irq, unsigned result_count, uint8 *r)
{
#ifdef DEBUG
if(AsyncIRQPending)
{
PSX_WARNING("***WARNING*** Previous notification skipped: CurSector=%d, old_notification=0x%02x", CurSector, AsyncIRQPending);
}
#endif
ClearAIP();
AsyncResultsPendingCount = result_count;
@ -723,9 +749,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
{
if(CurSector >= (int32)toc.tracks[100].lba)
{
#ifdef DEBUG
PSX_WARNING("[CDC] Beyond end!");
#endif
DriveStatus = DS_STOPPED;
SetAIP(CDCIRQ_DISC_ERROR, MakeStatus() | 0x04, 0x04);
@ -736,9 +760,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
}
else
{
bool need_ap = false;
//PSX_WARNING("Read sector: %d", CurSector);
//PSX_WARNING("Read sector: %d", CurSector);
Cur_CDIF->ReadRawSector(buf, CurSector); // FIXME: error out on error.
DecodeSubQ(buf + 2352);
@ -749,28 +771,19 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
{
if(XA_Test(buf))
{
if((Mode & MODE_AUTOPAUSE) && (buf[12 + 6] & 0x80))
{
//need_ap = true;
}
//else
{
#ifdef DEBUG
if(AudioBuffer_ReadPos & 0xFFF)
printf("readpos=%04x(rabl=%04x) writepos=%04x\n", AudioBuffer_ReadPos, AudioBuffer[AudioBuffer_ReadPos >> 12].Size, AudioBuffer_WritePos);
#endif
if(AudioBuffer_ReadPos & 0xFFF)
printf("readpos=%04x(rabl=%04x) writepos=%04x\n", AudioBuffer_ReadPos, AudioBuffer[AudioBuffer_ReadPos >> 12].Size, AudioBuffer_WritePos);
//if(AudioBuffer_UsedCount == 0)
// AudioBuffer_InPrebuffer = true;
//if(AudioBuffer_UsedCount == 0)
// AudioBuffer_InPrebuffer = true;
XA_ProcessSector(buf, &AudioBuffer[AudioBuffer_WritePos >> 12]);
AudioBuffer_UsedCount++;
XA_ProcessSector(buf, &AudioBuffer[AudioBuffer_WritePos >> 12]);
AudioBuffer_UsedCount++;
if(AudioBuffer_UsedCount == AudioBuffer_PreBufferCount)
AudioBuffer_InPrebuffer = false;
if(AudioBuffer_UsedCount == AudioBuffer_PreBufferCount)
AudioBuffer_InPrebuffer = false;
AudioBuffer_WritePos = (AudioBuffer_WritePos & 0xFFF) | ((((AudioBuffer_WritePos >> 12) + 1) % AudioBuffer_Count) << 12);
}
AudioBuffer_WritePos = (AudioBuffer_WritePos & 0xFFF) | ((((AudioBuffer_WritePos >> 12) + 1) % AudioBuffer_Count) << 12);
}
}
else
@ -784,10 +797,8 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
}
}
#ifdef DEBUG
if(!(Mode & 0x30) && (buf[12 + 6] & 0x20))
PSX_WARNING("BORK: %d", CurSector);
#endif
{
int32 offs = (Mode & 0x20) ? 0 : 12;
@ -806,19 +817,8 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
SetAIP(CDCIRQ_DATA_READY, MakeStatus());
}
if(need_ap)
{
MDFN_DispMessage("Autopause XA");
DriveStatus = DS_PAUSED;
PSRCounter = 0;
SetAIP(CDCIRQ_DATA_END, MakeStatus());
}
else
{
PSRCounter += 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
CurSector++;
}
PSRCounter += 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
CurSector++;
}
}
else if(DriveStatus == DS_PLAYING)
@ -924,10 +924,8 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
else
CurSector++;
}
#ifdef DEBUG
else
PSX_WARNING("[CDC] BUG CDDA buffer full");
#endif
}
} // end if playing
@ -960,9 +958,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
}
else if(PendingCommand >= 0x20 || !Commands[PendingCommand].func)
{
#ifdef DEBUG
PSX_WARNING("[CDC] Unknown command: 0x%02x", PendingCommand);
#endif
WriteResult(MakeStatus(true));
WriteResult(ERRCODE_BAD_COMMAND);
@ -972,9 +968,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
}
else if(ArgsIn < Commands[PendingCommand].args_min || ArgsIn > Commands[PendingCommand].args_max)
{
#ifdef DEBUG
PSX_WARNING("[CDC] Bad number(%d) of args(first check) for command 0x%02x", ArgsIn, PendingCommand);
#endif
WriteResult(MakeStatus(true));
WriteResult(ERRCODE_BAD_NUMARGS);
@ -987,7 +981,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
const CDC_CTEntry *command = &Commands[PendingCommand];
//PSX_WARNING("[CDC] Command: %s --- %d", command->name, Results.CanRead());
#ifdef DEBUG
#if 1
printf("[CDC] Command: %s --- ", command->name);
for(unsigned int i = 0; i < ArgsIn; i++)
printf(" 0x%02x", ArgsBuf[i]);
@ -1035,13 +1029,10 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
switch(reg_index)
{
default:
#ifdef DEBUG
PSX_WARNING("[CDC] Unknown write to register 0x%02x: 0x%02x\n", reg_index, V);
#endif
break;
case 0x00:
#ifdef DEBUG
if(PendingCommandCounter > 0)
{
PSX_WARNING("[CDC] WARNING: Interrupting command 0x%02x, phase=%d, timeleft=%d with command=0x%02x", PendingCommand, PendingCommandPhase,
@ -1057,7 +1048,6 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
{
PSX_WARNING("[CDC] Attempting to start command(0x%02x) while command results(count=%d) still in buffer.", V, ResultsIn);
}
#endif
PendingCommandCounter = 8192; //1024; //128; //256; //16; //1024;
PendingCommand = V;
@ -1068,12 +1058,10 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
ArgsBuf[ArgsIn & 0xF] = V;
ArgsIn = (ArgsIn + 1) & 0x1F;
#ifdef DEBUG
if(!(ArgsIn & 0x0F))
{
PSX_WARNING("[CDC] Argument buffer overflow");
}
#endif
break;
case 0x02:
@ -1083,9 +1071,7 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
{
if(!SB_In)
{
#ifdef DEBUG
PSX_WARNING("[CDC] Data read begin when no data to read!");
#endif
DMABuffer.Write(SB, 2340);
@ -1115,9 +1101,7 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
if(V & 0x20)
{
#ifdef DEBUG
PSX_WARNING("[CDC] Mystery IRQ trigger bit set.");
#endif
IRQBuffer |= 0x10;
}
break;
@ -1133,9 +1117,7 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
if(V & 0x80) // Forced CD hardware reset of some kind(interface, controller, and drive?) Seems to take a while(relatively speaking) to complete.
{
#ifdef DEBUG
PSX_WARNING("[CDC] Soft Reset");
#endif
SoftReset();
}
@ -1166,7 +1148,6 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
{
memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume));
#ifdef DEBUG
for(int i = 0; i < 2; i++)
{
for(int o = 0; o < 2; o++)
@ -1174,7 +1155,6 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
//fprintf(stderr, "Input Channel %d, Output Channel %d -- Volume=%d\n", i, o, DecodeVolume[i][o]);
}
}
#endif
}
break;
}
@ -1216,12 +1196,10 @@ uint8 PS_CDC::Read(const pscpu_timestamp_t timestamp, uint32 A)
case 0x02:
if(DMABuffer.CanRead())
ret = DMABuffer.ReadByte();
#ifdef DEBUG
else
{
PSX_WARNING("[CDC] CD data transfer port read, but no data present!");
}
#endif
break;
case 0x03:
@ -1280,9 +1258,7 @@ bool PS_CDC::CommandCheckDiscPresent(void)
int32 PS_CDC::Command_Sync(const int arg_count, const uint8 *args)
{
#ifdef DEBUG
PSX_WARNING("[CDC] Unimplemented command: 0x%02x", PendingCommand);
#endif
return(0);
}
@ -1328,9 +1304,7 @@ static int32 CalcSeekTime(int32 initial, int32 target, bool motor_on, bool pause
else if(paused)
ret += (int64)33868800 * 150 / 1000;
#ifdef DEBUG
printf("%d\n", ret);
#endif
return(ret);
}
@ -1381,16 +1355,12 @@ int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
if(track < toc.first_track)
{
#ifdef DEBUG
PSX_WARNING("[CDC] Attempt to play track before first track.");
#endif
track = toc.first_track;
}
else if(track > toc.last_track)
{
#ifdef DEBUG
PSX_WARNING("[CDC] Attempt to play track before first track.");
#endif
track = toc.last_track;
}
@ -1398,9 +1368,7 @@ int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
PlayTrackMatch = track;
#ifdef DEBUG
printf("[CDC] Play track: %d\n", track);
#endif
SeekTarget = toc.tracks[track].lba;
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
PreSeekHack(SeekTarget);
@ -1533,11 +1501,18 @@ int32 PS_CDC::Command_Stop(const int arg_count, const uint8 *args)
WriteResult(MakeStatus());
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
ClearAudioBuffers();
ClearAIP();
DriveStatus = DS_STOPPED;
if(DriveStatus == DS_STOPPED)
{
return(5000);
}
else
{
ClearAudioBuffers();
ClearAIP();
DriveStatus = DS_STOPPED;
return(33868);
return(33868); // FIXME, should be much higher.
}
}
int32 PS_CDC::Command_Stop_Part2(void)
@ -1551,6 +1526,7 @@ int32 PS_CDC::Command_Stop_Part2(void)
}
// TODO: Pause speed depends on speed(1x/2x) and current position. Also check restart(for ReadN/ReadS and Play) 'delay'.
int32 PS_CDC::Command_Pause(const int arg_count, const uint8 *args)
{
if(!CommandCheckDiscPresent())
@ -1559,12 +1535,19 @@ int32 PS_CDC::Command_Pause(const int arg_count, const uint8 *args)
WriteResult(MakeStatus());
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
// "Viewpoint" flips out and crashes if reading isn't stopped (almost?) immediately.
ClearAudioBuffers();
ClearAIP();
DriveStatus = DS_PAUSED;
if(DriveStatus == DS_PAUSED || DriveStatus == DS_STOPPED)
{
return(5000);
}
else
{
// "Viewpoint" flips out and crashes if reading isn't stopped (almost?) immediately.
ClearAudioBuffers();
ClearAIP();
DriveStatus = DS_PAUSED;
return((int64)33868800 * 100 / 1000);
return((int64)33868800 * 100 / 1000);
}
}
int32 PS_CDC::Command_Pause_Part2(void)
@ -1817,9 +1800,7 @@ int32 PS_CDC::Command_Test(const int arg_count, const uint8 *args)
switch(args[0])
{
default:
#ifdef DEBUG
PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
#endif
WriteResult(MakeStatus(true));
WriteResult(0x10);
WriteIRQ(CDCIRQ_DISC_ERROR);
@ -1840,9 +1821,7 @@ int32 PS_CDC::Command_Test(const int arg_count, const uint8 *args)
case 0x18:
case 0x19:
case 0x1A:
#ifdef DEBUG
PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
#endif
WriteResult(MakeStatus());
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
break;
@ -1857,18 +1836,14 @@ int32 PS_CDC::Command_Test(const int arg_count, const uint8 *args)
#endif
case 0x51: // *Need to retest this test command
#ifdef DEBUG
PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
#endif
WriteResult(0x01);
WriteResult(0x00);
WriteResult(0x00);
break;
case 0x75: // *Need to retest this test command
#ifdef DEBUG
PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
#endif
WriteResult(0x00);
WriteResult(0xC0);
WriteResult(0x00);

View File

@ -238,6 +238,9 @@ class PS_CDC
bool XA_Test(const uint8 *sdata);
void XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab);
int16 xa_previous[2][2];
bool xa_cur_set;
uint8 xa_cur_file;
uint8 xa_cur_chan;
struct CDC_CTEntry
{

View File

@ -209,7 +209,6 @@ uint32 PS_CPU::Exception(uint32 code, uint32 PC, const uint32 NPM)
const bool InBDSlot = !(NPM & 0x3);
uint32 handler = 0x80000080;
#ifdef DEBUG
assert(code < 16);
if(code != EXCEPTION_INT && code != EXCEPTION_BP && code != EXCEPTION_SYSCALL)
@ -218,7 +217,6 @@ uint32 PS_CPU::Exception(uint32 code, uint32 PC, const uint32 NPM)
IRQ_GetRegister(IRQ_GSREG_STATUS, NULL, 0), IRQ_GetRegister(IRQ_GSREG_MASK, NULL, 0));
//assert(0);
}
#endif
if(CP0.SR & (1 << 22)) // BEV
handler = 0xBFC00180;
@ -413,9 +411,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
{
BEGIN_OPF(ILL, 0, 0);
#ifdef DEBUG
PSX_WARNING("[CPU] Unknown instruction @%08x = %08x, op=%02x, funct=%02x", PC, instr, instr >> 26, (instr & 0x3F));
#endif
DO_LDS();
new_PC = Exception(EXCEPTION_RI, PC, new_PC_mask);
new_PC_mask = 0;
@ -602,9 +598,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
// BREAK - Breakpoint
//
BEGIN_OPF(BREAK, 0, 0x0D);
#ifdef DEBUG
PSX_WARNING("[CPU] BREAK BREAK BREAK BREAK DAAANCE -- PC=0x%08x", PC);
#endif
DO_LDS();
new_PC = Exception(EXCEPTION_BP, PC, new_PC_mask);
@ -646,12 +640,10 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
uint32 rd = (instr >> 11) & 0x1F;
uint32 val = GPR[rt];
#ifdef DEBUG
if(rd != CP0REG_CAUSE && rd != CP0REG_SR && val)
{
PSX_WARNING("[CPU] Unimplemented MTC0: rt=%d(%08x) -> rd=%d", rt, GPR[rt], rd);
}
#endif
switch(rd)
{
@ -689,10 +681,8 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
CP0.SR = val & ~( (0x3 << 26) | (0x3 << 23) | (0x3 << 6));
RecalcIPCache();
#ifdef DEBUG
if(CP0.SR & 0x10000)
PSX_WARNING("[CPU] IsC set");
#endif
break;
}
}

View File

@ -461,11 +461,8 @@ void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
RecalcIRQOut();
break;
default:
#ifdef DEBUG
PSX_WARNING("[DMA] Unknown write: %08x %08x", A, V);
default: PSX_WARNING("[DMA] Unknown write: %08x %08x", A, V);
assert(0);
#endif
break;
}
return;
@ -499,10 +496,8 @@ PSX_WARNING("[DMA] Unknown write: %08x %08x", A, V);
GPU->Write(timestamp, 0x04, 0x01 << 24);
}
#ifdef DEBUG
PSX_WARNING("[DMA] Forced stop for channel %d -- scanline=%d", ch, GPU->GetScanlineNum());
MDFN_DispMessage("[DMA] Forced stop for channel %d", ch);
#endif
}
if(ch == 6)
@ -549,11 +544,8 @@ uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A)
{
switch(A & 0xC)
{
default:
#ifdef DEBUG
PSX_WARNING("[DMA] Unknown read: %08x", A);
assert(0);
#endif
default: PSX_WARNING("[DMA] Unknown read: %08x", A);
assert(0);
break;
case 0x0: ret = DMAControl;

View File

@ -156,18 +156,18 @@ FrontIO::FrontIO(bool emulate_memcards_[8], bool emulate_multitap_[2])
memcpy(emulate_memcards, emulate_memcards_, sizeof(emulate_memcards));
memcpy(emulate_multitap, emulate_multitap_, sizeof(emulate_multitap));
DummyDevice = new InputDevice;
DummyDevice = new InputDevice();
for(int i = 0; i < 8; i++)
{
DeviceData[i] = NULL;
Devices[i] = new InputDevice;
Devices[i] = new InputDevice();
DevicesMC[i] = Device_Memcard_Create();
}
for(unsigned i = 0; i < 2; i++)
{
DevicesTap[i] = new InputDevice_Multitap;
DevicesTap[i] = new InputDevice_Multitap();
}
MapDevicesToPorts();
@ -197,6 +197,12 @@ FrontIO::~FrontIO()
DevicesTap[i] = NULL;
}
}
if(DummyDevice)
{
delete DummyDevice;
DummyDevice = NULL;
}
}
int32 FrontIO::CalcNextEvent(int32 next_event)
@ -598,7 +604,7 @@ void FrontIO::SetInput(unsigned int port, const char *type, void *ptr)
else if(!strcmp(type, "mouse"))
Devices[port] = Device_Mouse_Create();
else
Devices[port] = new InputDevice;
Devices[port] = new InputDevice();
DeviceData[port] = ptr;

View File

@ -406,13 +406,14 @@ void PS_GPU::Command_FBFill(const uint32 *cb)
for(int32 y = 0; y < height; y++)
{
if(LineSkipTest(y))
const int32 d_y = (y + destY) & 511;
if(LineSkipTest(d_y))
continue;
for(int32 x = 0; x < width; x++)
{
int32 d_y = (y + destY) & 511;
int32 d_x = (x + destX) & 1023;
const int32 d_x = (x + destX) & 1023;
GPURAM[d_y][d_x] = fill_value;
}
@ -509,45 +510,23 @@ void PS_GPU::Command_FBRead(const uint32 *cb)
void PS_GPU::RecalcTexWindowLUT(void)
{
const unsigned TexWindowX_AND = ~(tww << 3);
const unsigned TexWindowX_OR = (twx & tww) << 3;
const unsigned TexWindowY_AND = ~(twh << 3);
const unsigned TexWindowY_OR = (twy & twh) << 3;
// printf("TWX: 0x%02x, TWW: 0x%02x\n", twx, tww);
// printf("TWY: 0x%02x, TWH: 0x%02x\n", twy, twh);
for(unsigned x = 0; x < 256; x++)
{
uint8 targ_x = 0;
uint8 targ_wc = 0;
uint8 x = twx * 8;
do
{
if(!targ_wc)
{
targ_x = twx * 8;
targ_wc = tww * 8;
}
TexWindowXLUT[x] = targ_x;
x++;
targ_x++;
targ_wc++;
} while(x != (twx * 8));
TexWindowXLUT[x] = (x & TexWindowX_AND) | TexWindowX_OR;
}
for(unsigned y = 0; y < 256; y++)
{
uint8 targ_y = 0;
uint8 targ_hc = 0;
uint8 y = twy * 8;
do
{
if(!targ_hc)
{
targ_y = twy * 8;
targ_hc = twh * 8;
}
//printf("Texture window y: %d %d\n", y, targ_y);
TexWindowYLUT[y] = targ_y;
y++;
targ_y++;
targ_hc++;
} while(y != (twy * 8));
TexWindowYLUT[y] = (y & TexWindowY_AND) | TexWindowY_OR;
}
memset(TexWindowXLUT_Pre, TexWindowXLUT[0], sizeof(TexWindowXLUT_Pre));
@ -569,7 +548,7 @@ void PS_GPU::Command_DrawMode(const uint32 *cb)
dtd = (*cb >> 9) & 1;
dfe = (*cb >> 10) & 1;
//printf("DFE: %d -- scanline=%d\n", dfe, scanline);
//printf("*******************DFE: %d -- scanline=%d\n", dfe, scanline);
}
void PS_GPU::Command_TexWindow(const uint32 *cb)

View File

@ -113,13 +113,13 @@ void PS_GPU::DrawLine(line_point *points)
if(i_dx >= 1024)
{
PSX_WARNING("[GPU] Line too long: i_dx=%d", i_dx);
//PSX_WARNING("[GPU] Line too long: i_dx=%d", i_dx);
return;
}
if(i_dy >= 512)
{
PSX_WARNING("[GPU] Line too long: i_dy=%d", i_dy);
//PSX_WARNING("[GPU] Line too long: i_dy=%d", i_dy);
return;
}
@ -146,8 +146,9 @@ void PS_GPU::DrawLine(line_point *points)
//
for(int32 i = 0; i <= k; i++) // <= is not a typo.
{
const int32 x = cur_point.x >> Line_XY_FractBits;
const int32 y = cur_point.y >> Line_XY_FractBits;
// Sign extension is not necessary here for x and y, due to the maximum values that ClipX1 and ClipY1 can contain.
const int32 x = (cur_point.x >> Line_XY_FractBits) & 2047;
const int32 y = (cur_point.y >> Line_XY_FractBits) & 2047;
uint16 pix = 0x8000;
if(!LineSkipTest(y))
@ -209,8 +210,8 @@ void PS_GPU::Command_DrawLine(const uint32 *cb)
points[0].b = (*cb >> 16) & 0xFF;
cb++;
points[0].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF) + OffsX);
points[0].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF) + OffsY);
points[0].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + OffsX;
points[0].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + OffsY;
cb++;
}
@ -228,8 +229,8 @@ void PS_GPU::Command_DrawLine(const uint32 *cb)
points[1].b = points[0].b;
}
points[1].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF) + OffsX);
points[1].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF) + OffsY);
points[1].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + OffsX;
points[1].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + OffsY;
cb++;
if(polyline)

View File

@ -64,8 +64,35 @@ void PS_GPU::DrawSprite(int32 x_arg, int32 y_arg, int32 w, int32 h, uint8 u_arg,
if(y_bound > y_start && x_bound > x_start)
{
//
// Note(TODO): From tests on a PS1, even a 0-width sprite takes up time to "draw" proportional to its height.
//
int32 suck_time = (x_bound - x_start) * (y_bound - y_start);
// Disabled until we can get it to take into account texture windowing, which can cause large sprites to be drawn entirely from cache(and not suffer from a texturing
// penalty); and disabled until we find a game that needs more accurate sprite draw timing. :b
#if 0
if(textured)
{
// Empirically-observed approximations of time(66MHz cycles) taken to draw large textured sprites in the various texture depths, when the texture data and CLUT data
// was zero(non-zero takes longer to draw, TODO test that more):
// 4bpp - area * 2
// 8bpp - area * 3
// 15/16bpp - area * 5
// (other factors come into more importance for smaller sprites)
static const int cw[4] = { 64, 32, 32, 32 };
static const int ch[4] = { 64, 64, 32, 32 };
static const int mm[4] = { 2 - 1, 3 - 1, 5 - 1, 5 - 1 };
// Parts of the first few(up to texture cache height) horizontal lines can be in cache, so assume they are.
suck_time += mm[TexMode_TA] * std::max<int>(0, (x_bound - x_start) - cw[TexMode_TA]) * std::min<int>(ch[TexMode_TA], y_bound - y_start);
// The rest of the horizontal lines should not possibly have parts in the cache now.
suck_time += mm[TexMode_TA] * (x_bound - x_start) * std::max<int>(0, (y_bound - y_start) - ch[TexMode_TA]);
}
else
#endif
if((BlendMode >= 0) || MaskEval_TA)
{
suck_time += ((((x_bound + 1) & ~1) - (x_start & ~1)) * (y_bound - y_start)) >> 1;
@ -144,8 +171,8 @@ void PS_GPU::Command_DrawSprite(const uint32 *cb)
{
default:
case 0:
w = *cb & 0xFFFF;
h = *cb >> 16;
w = (*cb & 0x3FF);
h = (*cb >> 16) & 0x1FF;
cb++;
break;

View File

@ -416,12 +416,10 @@ void MDEC_DMAWrite(uint32 V)
InCounter--;
}
}
#ifdef DEBUG
else
{
printf("MYSTERY1: %08x\n", V);
}
#endif
}
uint32 MDEC_DMARead(void)
@ -446,9 +444,7 @@ bool MDEC_DMACanRead(void)
void MDEC_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
{
#ifdef DEBUG
PSX_WARNING("[MDEC] Write: 0x%08x 0x%08x, %d", A, V, timestamp);
#endif
if(A & 4)
{
if(V & 0x80000000) // Reset?

View File

@ -72,15 +72,15 @@ PS_GPU *GPU = NULL;
PS_CDC *CDC = NULL;
FrontIO *FIO = NULL;
static MultiAccessSizeMem<512 * 1024, uint32, false, 0, 0> *BIOSROM = NULL;
static MultiAccessSizeMem<65536, uint32, false, 0, 0> *PIOMem = NULL;
static MultiAccessSizeMem<512 * 1024, uint32, false> *BIOSROM = NULL;
static MultiAccessSizeMem<65536, uint32, false> *PIOMem = NULL;
MultiAccessSizeMem<2048 * 1024, uint32, false, 0, 0> MainRAM;
MultiAccessSizeMem<2048 * 1024, uint32, false> MainRAM;
static uint32 TextMem_Start;
static std::vector<uint8> TextMem;
static MultiAccessSizeMem<1024, uint32, false, 0, 0> ScratchRAM;
static MultiAccessSizeMem<1024, uint32, false> ScratchRAM;
static const uint32 SysControl_Mask[9] = { 0x00ffffff, 0x00ffffff, 0xffffffff, 0x2f1fffff,
0xffffffff, 0x2f1fffff, 0x2f1fffff, 0xffffffff,
@ -499,16 +499,12 @@ template<typename T, bool IsWrite, bool Access24, bool Peek> static INLINE void
{
if(IsWrite)
{
#ifdef DEBUG
PSX_WARNING("[MEM] Unknown write%d to %08x at time %d, =%08x(%d)", (int)(sizeof(T) * 8), A, timestamp, V, V);
#endif
}
else
{
V = 0;
#ifdef DEBUG
PSX_WARNING("[MEM] Unknown read%d from %08x at time %d", (int)(sizeof(T) * 8), A, timestamp);
#endif
}
}
else
@ -930,8 +926,8 @@ static bool InitCommon(std::vector<CDIF *> *CDInterfaces, const bool EmulateMemc
(CD_SelectedDisc >= 0 && !CD_TrayOpen) ? cdifs_scex_ids[CD_SelectedDisc] : NULL);
BIOSROM = new MultiAccessSizeMem<512 * 1024, uint32, false, 0, 0>();
PIOMem = new MultiAccessSizeMem<65536, uint32, false, 0, 0>();
BIOSROM = new MultiAccessSizeMem<512 * 1024, uint32, false>();
PIOMem = new MultiAccessSizeMem<65536, uint32, false>();
for(uint32 ma = 0x00000000; ma < 0x00800000; ma += 2048 * 1024)
{
@ -1179,7 +1175,8 @@ static int Load(const char *name, MDFNFILE *fp)
#if 0
static std::vector<CDIF *> CDInterfaces;
CDInterfaces.push_back(new CDIF("/extra/games/PSX/Tony Hawk's Pro Skater 2 (USA)/Tony Hawk's Pro Skater 2 (USA).cue"));
CDInterfaces.push_back(new CDIF("/extra/games/PSX/Jumping Flash! (USA)/Jumping Flash! (USA).cue"));
//CDInterfaces.push_back(new CDIF("/extra/games/PSX/Tony Hawk's Pro Skater 2 (USA)/Tony Hawk's Pro Skater 2 (USA).cue"));
if(!InitCommon(&CDInterfaces, !IsPSF))
return(0);
@ -1319,7 +1316,6 @@ static void SetInput(int port, const char *type, void *ptr)
static int StateAction(StateMem *sm, int load, int data_only)
{
return(0);
SFORMAT StateRegs[] =
{
SFVAR(CD_TrayOpen),
@ -1347,6 +1343,9 @@ static int StateAction(StateMem *sm, int load, int data_only)
ret &= TIMER_StateAction(sm, load, data_only);
ret &= CDC->StateAction(sm, load, data_only);
ret &= MDEC_StateAction(sm, load, data_only);
ret &= SPU->StateAction(sm, load, data_only);
//ret &= FIO->StateAction(sm, load, data_only);
//ret &= GPU->StateAction(sm, load, data_only);
ret &= IRQ_StateAction(sm, load, data_only);
if(load)
@ -1496,6 +1495,7 @@ MDFNGI EmulatedPSX =
NULL,
NULL,
NULL,
false,
StateAction,
Emulate,
SetInput,

View File

@ -74,7 +74,7 @@ namespace MDFN_IEN_PSX
extern PS_GPU *GPU;
extern PS_CDC *CDC;
extern PS_SPU *SPU;
extern MultiAccessSizeMem<2048 * 1024, uint32, false, 0, 0> MainRAM;
extern MultiAccessSizeMem<2048 * 1024, uint32, false> MainRAM;
};

View File

@ -45,9 +45,7 @@ uint32 SIO_Read(pscpu_timestamp_t timestamp, uint32 A)
switch(A & 0xE)
{
default:
#ifdef DEBUG
PSX_WARNING("[SIO] Unknown read: 0x%08x -- %d\n", A, timestamp);
#endif
break;
case 0x0:
@ -82,9 +80,7 @@ void SIO_Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
switch(A & 0xE)
{
default:
#ifdef DEBUG
PSX_WARNING("[SIO] Unknown write: 0x%08x 0x%08x -- %d\n", A, V, timestamp);
#endif
break;
case 0x0:

View File

@ -169,14 +169,11 @@ void PS_SPU::Power(void)
BlockEnd = 0;
CDAudioCWA = 0;
CWA = 0;
memset(CDXA_ResampBuffer, 0, sizeof(CDXA_ResampBuffer));
CDXA_CurPhase = 0;
VoiceCWP[0] = 0;
VoiceCWP[1] = 0;
memset(Regs, 0, sizeof(Regs));
memset(RDSB, 0, sizeof(RDSB));
@ -488,10 +485,7 @@ void PS_SPU::RunEnvelope(SPU_Voice *voice)
//static INLINE void CalcVCDelta(const uint8 zs, uint8 speed, bool log_mode, bool decrement, int16 Current, int &increment, int &divinco)
switch(ADSR->Phase)
{
default:
#ifdef DEBUG
assert(0);
#endif
default: assert(0);
break;
case ADSR_ATTACK:
@ -729,8 +723,7 @@ int32 PS_SPU::UpdateFromCDC(int32 clocks)
{
int index = voice_num >> 1;
WriteSPURAM(0x400 | (index * 0x200) | VoiceCWP[index], voice_pvs);
VoiceCWP[index] = (VoiceCWP[index] + 1) & 0x1FF;
WriteSPURAM(0x400 | (index * 0x200) | CWA, voice_pvs);
}
@ -765,9 +758,7 @@ int32 PS_SPU::UpdateFromCDC(int32 clocks)
phase_inc = voice->Pitch + (((int16)voice->Pitch * ((voice - 1)->PreLRSample)) >> 15);
if(phase_inc < 0)
{
#ifdef DEBUG
printf("phase_inc < 0 (THIS SHOULD NOT HAPPEN)\n");
#endif
phase_inc = 0;
}
}
@ -806,9 +797,6 @@ int32 PS_SPU::UpdateFromCDC(int32 clocks)
voice->CurPhase_SD = 28 << 12; // Trigger initial sample decode
voice->CurAddr = voice->StartAddr & ~0x7;
if(voice_num == 1 || voice_num == 3)
VoiceCWP[voice_num >> 1] = 0;
}
}
@ -848,12 +836,11 @@ int32 PS_SPU::UpdateFromCDC(int32 clocks)
}
}
}
WriteSPURAM(CDAudioCWA | 0x000, cda_raw[0]);
WriteSPURAM(CDAudioCWA | 0x200, cda_raw[1]);
CDAudioCWA = (CDAudioCWA + 1) & 0x1FF;
WriteSPURAM(CWA | 0x000, cda_raw[0]);
WriteSPURAM(CWA | 0x200, cda_raw[1]);
}
CWA = (CWA + 1) & 0x1FF;
NoiseCounter += NoiseFreqTable[(SPUControl >> 8) & 0x3F];
if(NoiseCounter >= 0x8000)
@ -888,9 +875,7 @@ int32 PS_SPU::UpdateFromCDC(int32 clocks)
clamp(&output_l, -32768, 32767);
clamp(&output_r, -32768, 32767);
#ifdef DEBUG
assert(IntermediateBufferPos < 4096);
#endif
IntermediateBuffer[IntermediateBufferPos][0] = output_l;
IntermediateBuffer[IntermediateBufferPos][1] = output_r;
IntermediateBufferPos++;
@ -1238,9 +1223,7 @@ int32 PS_SPU::EndFrame(int16 *SoundBuf)
speex_resampler_process_interleaved_int(resampler, (const spx_int16_t *)IntermediateBuffer, &in_len, (spx_int16_t *)SoundBuf, &out_len);
#ifdef DEBUG
assert(in_len <= IntermediateBufferPos);
#endif
if((IntermediateBufferPos - in_len) > 0)
memmove(IntermediateBuffer, IntermediateBuffer + in_len, (IntermediateBufferPos - in_len) * sizeof(int16) * 2);
@ -1256,6 +1239,135 @@ int32 PS_SPU::EndFrame(int16 *SoundBuf)
}
}
int PS_SPU::StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
#define SFSWEEP(r) SFVAR((r).Control), \
SFVAR((r).Current), \
SFVAR((r).Divider)
#define SFVOICE(n) SFARRAY32(&Voices[n].DecodeBuffer[0], sizeof(Voices[n].DecodeBuffer) / sizeof(Voices[n].DecodeBuffer[0])), \
SFVAR(Voices[n].DecodeWritePos), \
SFVAR(Voices[n].DecodeFlags), \
\
SFSWEEP(Voices[n].Sweep[0]), \
SFSWEEP(Voices[n].Sweep[1]), \
\
SFVAR(Voices[n].Pitch), \
SFVAR(Voices[n].CurPhase), \
SFVAR(Voices[n].CurPhase_SD), \
\
SFVAR(Voices[n].StartAddr), \
SFVAR(Voices[n].CurAddr), \
SFVAR(Voices[n].ADSRControl), \
SFVAR(Voices[n].LoopAddr), \
SFVAR(Voices[n].PreLRSample), \
\
SFVAR(Voices[n].ADSR.EnvLevel), \
SFVAR(Voices[n].ADSR.Divider), \
SFVAR(Voices[n].ADSR.Phase), \
\
SFVAR(Voices[n].ADSR.AttackExp), \
SFVAR(Voices[n].ADSR.SustainExp), \
SFVAR(Voices[n].ADSR.SustainDec), \
SFVAR(Voices[n].ADSR.ReleaseExp), \
\
SFVAR(Voices[n].ADSR.AttackRate), \
SFVAR(Voices[n].ADSR.DecayRate), \
SFVAR(Voices[n].ADSR.SustainRate), \
SFVAR(Voices[n].ADSR.ReleaseRate), \
\
SFVAR(Voices[n].ADSR.SustainLevel)
SFVOICE(0),
SFVOICE(1),
SFVOICE(2),
SFVOICE(3),
SFVOICE(4),
SFVOICE(5),
SFVOICE(6),
SFVOICE(7),
SFVOICE(8),
SFVOICE(9),
SFVOICE(10),
SFVOICE(11),
SFVOICE(12),
SFVOICE(13),
SFVOICE(14),
SFVOICE(15),
SFVOICE(16),
SFVOICE(17),
SFVOICE(18),
SFVOICE(19),
SFVOICE(20),
SFVOICE(21),
SFVOICE(22),
SFVOICE(23),
#undef SFVOICE
SFVAR(NoiseCounter),
SFVAR(LFSR),
SFVAR(FM_Mode),
SFVAR(Noise_Mode),
SFVAR(Reverb_Mode),
SFVAR(ReverbWA),
SFSWEEP(GlobalSweep[0]),
SFSWEEP(GlobalSweep[1]),
SFARRAY32(ReverbVol, sizeof(ReverbVol) / sizeof(ReverbVol[0])),
SFARRAY32(CDVol, sizeof(CDVol) / sizeof(CDVol[0])),
SFARRAY32(ExternVol, sizeof(ExternVol) / sizeof(ExternVol[0])),
SFVAR(IRQAddr),
SFVAR(RWAddr),
SFVAR(SPUControl),
SFVAR(VoiceOn),
SFVAR(VoiceOff),
SFVAR(BlockEnd),
SFVAR(CWA),
SFARRAY32(&CDXA_ResampBuffer[0][0], sizeof(CDXA_ResampBuffer) / sizeof(CDXA_ResampBuffer[0][0])),
SFVAR(CDXA_CurPhase),
SFARRAY16(Regs, sizeof(Regs) / sizeof(Regs[0])),
SFARRAY16(AuxRegs, sizeof(AuxRegs) / sizeof(AuxRegs[0])),
SFARRAY16(&RDSB[0][0], sizeof(RDSB) / sizeof(RDSB[0][0])),
SFVAR(RDSB_WP),
SFARRAY16(&RUSB[0][0], sizeof(RUSB) / sizeof(RUSB[0][0])),
SFVAR(RUSB_WP),
SFVAR(ReverbCur),
SFVAR(IRQAsserted),
SFVAR(clock_divider),
SFARRAY16(SPURAM, 524288 / sizeof(uint16)),
SFEND
};
#undef SFSWEEP
int ret = 1;
ret &= MDFNSS_StateAction(sm, load, data_only, StateRegs, "SPU");
if(load)
{
}
return(ret);
}
uint16 PS_SPU::PeekSPURAM(uint32 address)
{

View File

@ -34,8 +34,11 @@ struct SPU_ADSR
int32 SustainLevel; // (Sl + 1) << 11
};
class PS_SPU;
class SPU_Sweep
{
friend class PS_SPU; // For save states - FIXME(remove in future?)
public:
SPU_Sweep() { }
~SPU_Sweep() { }
@ -88,6 +91,8 @@ class PS_SPU
PS_SPU();
~PS_SPU();
int StateAction(StateMem *sm, int load, int data_only);
void Power(void);
void Write(pscpu_timestamp_t timestamp, uint32 A, uint16 V);
uint16 Read(pscpu_timestamp_t timestamp, uint32 A);
@ -144,20 +149,17 @@ class PS_SPU
uint32 RWAddr;
uint16 SPUControl;
uint16 AddressMult; // Just a guess!
uint32 VoiceOn;
uint32 VoiceOff;
uint32 BlockEnd;
uint32 CDAudioCWA;
uint32 CWA;
int32 CDXA_ResampBuffer[2][4];
int32 CDXA_CurPhase;
uint32 VoiceCWP[2];
union
{
uint16 Regs[0x100];
@ -233,14 +235,13 @@ class PS_SPU
bool IRQAsserted;
int last_rate;
uint32 last_quality;
//pscpu_timestamp_t lastts;
int32 clock_divider;
uint16 SPURAM[524288 / sizeof(uint16)];
int last_rate;
uint32 last_quality;
SpeexResamplerState *resampler;
// Buffers 44.1KHz samples, should have enough for one video frame(~735 frames NTSC, ~882 PAL) plus jitter plus enough for the resampler leftovers.

View File

@ -116,9 +116,7 @@ static int32 CalcNextEvent(int32 next_event)
count_delta = target - Timers[i].Counter;
if(count_delta <= 0)
{
#ifdef DEBUG
fprintf(stderr, "timer %d count_delta <= 0!!! %d %d\n", i, target, Timers[i].Counter);
#endif
continue;
}
@ -130,17 +128,13 @@ static int32 CalcNextEvent(int32 next_event)
if((i == 0x2) && (Timers[i].Mode & 0x200))
{
#ifdef DEBUG
assert(Timers[i].Div8Counter >= 0 && Timers[i].Div8Counter < 8);
#endif
tmp_clocks = ((count_delta - 1) * 8) + (8 - Timers[i].Div8Counter);
}
else
tmp_clocks = count_delta;
#ifdef DEBUG
assert(tmp_clocks > 0);
#endif
if(next_event > tmp_clocks)
next_event = tmp_clocks;
@ -184,7 +178,7 @@ static void ClockTimer(int i, uint32 clocks)
if((before < target && Timers[i].Counter >= target) || zero_tm || Timers[i].Counter > 0xFFFF)
{
#ifdef DEBUG
#if 1
if(Timers[i].Mode & 0x10)
{
if((Timers[i].Counter - target) > 3)
@ -261,11 +255,9 @@ void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V)
int which = (A >> 4) & 0x3;
#ifdef DEBUG
assert(!(A & 3));
PSX_DBGINFO("[TIMER] Write: %08x %04x", A, V);
#endif
if(which >= 3)
return;
@ -322,12 +314,10 @@ uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A)
uint16 ret = 0;
int which = (A >> 4) & 0x3;
#ifdef DEBUG
assert(!(A & 3));
if(which >= 3)
assert(0);
#endif
TIMER_Update(timestamp);

View File

@ -254,6 +254,12 @@ void QTRecord::WriteFrame(const MDFN_Surface *surface, const MDFN_Rect &DisplayR
memset(&qts, 0, sizeof(qts));
if(DisplayRect.h <= 0)
{
fprintf(stderr, "[BUG] qtrecord.cpp: DisplayRect.h <= 0\n");
return;
}
qts.video_foffset = qtfile.tell();
@ -304,6 +310,17 @@ void QTRecord::WriteFrame(const MDFN_Surface *surface, const MDFN_Rect &DisplayR
dest_line++;
}
#if 0
while(dest_x < ((QTVideoWidth - (xscale_factor * width)) / 2))
{
dest_line[dest_x * 3 + 0] = 0;
dest_line[dest_x * 3 + 1] = 0;
dest_line[dest_x * 3 + 2] = 0;
dest_x++;
}
#endif
for(int x = x_start; x < x_start + width; x++)
{
for(int sub_x = 0; sub_x < xscale_factor; sub_x++)

View File

@ -7,7 +7,7 @@
void MDFNI_SelectState(int);
/* "fname" overrides the default save state filename code if non-NULL. */
/* If suffix is set, just override the default suffix(nc0-nc9) */
/* If suffix is set, just override the default suffix(mc0-mc9) */
void MDFNI_SaveState(const char *fname, const char *suffix, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths);
void MDFNI_LoadState(const char *fname, const char *suffix);
void MDFNI_EnableStateRewind(int enable);

View File

@ -21,6 +21,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <trio/trio.h>
#include "driver.h"
@ -547,12 +548,15 @@ int MDFNSS_StateAction(StateMem *st, int load, int data_only, SFORMAT *sf, const
return(MDFNSS_StateAction(st, load, data_only, love));
}
int MDFNSS_SaveSM(StateMem *st, int wantpreview, int data_only, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths)
int MDFNSS_SaveSM(StateMem *st, int wantpreview_and_ts, int data_only, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths)
{
static uint8 header[32]="MEDNAFENSVESTATE";
static const char *header_magic = "MDFNSVST";
uint8 header[32];
int neowidth = 0, neoheight = 0;
if(wantpreview)
memset(header, 0, sizeof(header));
if(wantpreview_and_ts)
{
bool is_multires = FALSE;
@ -585,14 +589,18 @@ int MDFNSS_SaveSM(StateMem *st, int wantpreview, int data_only, const MDFN_Surfa
if(!data_only)
{
memset(header+16,0,16);
memcpy(header, header_magic, 8);
if(wantpreview_and_ts)
MDFN_en64lsb(header + 8, time(NULL));
MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC);
MDFN_en32lsb(header + 24, neowidth);
MDFN_en32lsb(header + 28, neoheight);
smem_write(st, header, 32);
}
if(wantpreview)
if(wantpreview_and_ts)
{
uint8 *previewbuffer = (uint8 *)malloc(4 * neowidth * neoheight);
MDFN_Surface *dest_surface = new MDFN_Surface((uint32 *)previewbuffer, neowidth, neoheight, neowidth, surface->format);
@ -730,16 +738,11 @@ int MDFNSS_LoadSM(StateMem *st, int haspreview, int data_only)
else
{
smem_read(st, header, 32);
if(memcmp(header,"MEDNAFENSVESTATE",16))
if(memcmp(header, "MEDNAFENSVESTATE", 16) && memcmp(header, "MDFNSVST", 8))
return(0);
stateversion = MDFN_de32lsb(header + 16);
if(stateversion < 0x0600)
{
printf("State too old: %08x\n", stateversion);
return(0);
}
}
if(haspreview)
@ -959,6 +962,14 @@ void MDFNI_SaveState(const char *fname, const char *suffix, const MDFN_Surface *
if(!MDFNGameInfo->StateAction)
return;
if(MDFNnetplay && (MDFNGameInfo->SaveStateAltersState == true))
{
char sb[256];
trio_snprintf(sb, sizeof(sb), _("Module %s is not compatible with manual state saving during netplay."), MDFNGameInfo->shortname);
MDFND_NetplayText((const uint8*)sb, false);
return;
}
MDFND_SetStateStatus(NULL);
MDFNSS_Save(fname, suffix, surface, DisplayRect, LineWidths);
}
@ -978,7 +989,9 @@ void MDFNI_LoadState(const char *fname, const char *suffix)
if(MDFNSS_Load(fname, suffix))
{
if(MDFNnetplay)
MDFNNET_SendState();
{
NetplaySendState();
}
if(MDFNMOV_IsRecording())
MDFNMOV_RecordState();

View File

@ -34,7 +34,7 @@ int32 smem_seek(StateMem *st, uint32 offset, int whence);
int smem_write32le(StateMem *st, uint32 b);
int smem_read32le(StateMem *st, uint32 *b);
int MDFNSS_SaveSM(StateMem *st, int wantpreview, int data_only, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const MDFN_Rect *LineWidths = (MDFN_Rect *)NULL);
int MDFNSS_SaveSM(StateMem *st, int wantpreview_and_ts, int data_only, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const MDFN_Rect *LineWidths = (MDFN_Rect *)NULL);
int MDFNSS_LoadSM(StateMem *st, int haspreview, int data_only);
void MDFNSS_CheckStates(void);

View File

@ -89,8 +89,8 @@ int MDFND_UnlockMutex(MDFN_Mutex *lock)
return 0;
}
int MDFND_SendData(const void*, uint32) { return 0; }
int MDFND_RecvData(void *, uint32) { return 0; }
void MDFND_SendData(const void*, uint32) {}
void MDFND_RecvData(void *, uint32) {}
void MDFND_NetplayText(const uint8*, bool) {}
void MDFND_NetworkClose() {}