flycast/core/nullDC.cpp

1353 lines
43 KiB
C++
Raw Normal View History

2013-12-19 17:10:14 +00:00
// nullDC.cpp : Makes magic cookies
//
#include <atomic>
#include <future>
#include <thread>
2013-12-19 17:10:14 +00:00
//initialse Emu
#include "types.h"
#include "emulator.h"
2013-12-19 17:10:14 +00:00
#include "oslib/oslib.h"
#include "oslib/audiostream.h"
2013-12-19 17:10:14 +00:00
#include "hw/mem/_vmem.h"
#include "stdclass.h"
#include "cfg/cfg.h"
#include "hw/maple/maple_cfg.h"
#include "hw/sh4/sh4_mem.h"
#include "hw/holly/sb_mem.h"
2013-12-19 17:10:14 +00:00
#include "hw/naomi/naomi_cart.h"
#include "reios/reios.h"
2018-10-29 14:11:34 +00:00
#include "hw/sh4/sh4_sched.h"
#include "hw/sh4/sh4_if.h"
2018-10-29 14:11:34 +00:00
#include "hw/pvr/spg.h"
#include "hw/aica/aica_if.h"
2019-02-06 18:57:13 +00:00
#include "hw/aica/dsp.h"
#include "imgread/common.h"
#include "rend/gui.h"
#include "profiler/profiler.h"
#include "input/gamepad_device.h"
#include "hw/sh4/dyna/blockmanager.h"
#include "log/LogManager.h"
#include "cheats.h"
#include "rend/CustomTexture.h"
2020-03-28 16:58:01 +00:00
#include "hw/maple/maple_devs.h"
#include "network/naomi_network.h"
#include "rend/mainui.h"
2020-12-26 08:58:53 +00:00
#include "archive/rzip.h"
void arm7rec_flush();
static void LoadCustom();
2018-10-29 15:53:26 +00:00
extern bool fast_forward_mode;
2013-12-19 17:10:14 +00:00
settings_t settings;
// Set if game has corresponding option by default, so that it's not saved in the config
static bool rtt_to_buffer_game;
static bool safemode_game;
static bool tr_poly_depth_mask_game;
static bool extra_depth_game;
static bool disable_vmem32_game;
static int forced_game_region = -1;
static int forced_game_cable = -1;
static int saved_screen_stretching = -1;
cThread emu_thread(&dc_run, NULL);
2013-12-19 17:10:14 +00:00
static std::future<void> loading_done;
std::atomic<bool> loading_canceled;
static s32 plugins_Init()
2013-12-19 17:10:14 +00:00
{
if (s32 rv = libPvr_Init())
return rv;
#ifndef TARGET_DISPFRAME
2013-12-19 17:10:14 +00:00
if (s32 rv = libGDR_Init())
return rv;
#endif
2013-12-19 17:10:14 +00:00
if (s32 rv = libAICA_Init())
return rv;
2013-12-19 17:10:14 +00:00
if (s32 rv = libARM_Init())
return rv;
return 0;
2013-12-19 17:10:14 +00:00
}
static void plugins_Term()
2013-12-19 17:10:14 +00:00
{
//term all plugins
libARM_Term();
libAICA_Term();
libGDR_Term();
libPvr_Term();
}
static void plugins_Reset(bool hard)
2013-12-19 17:10:14 +00:00
{
2019-07-10 15:25:11 +00:00
libPvr_Reset(hard);
libGDR_Reset(hard);
libAICA_Reset(hard);
libARM_Reset(hard);
2013-12-19 17:10:14 +00:00
//libExtDevice_Reset(Manual);
}
static void LoadSpecialSettings()
{
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
{
std::string prod_id(ip_meta.product_number, sizeof(ip_meta.product_number));
prod_id = trim_trailing_ws(prod_id);
NOTICE_LOG(BOOT, "Game ID is [%s]", prod_id.c_str());
rtt_to_buffer_game = false;
safemode_game = false;
tr_poly_depth_mask_game = false;
extra_depth_game = false;
disable_vmem32_game = false;
forced_game_region = -1;
forced_game_cable = -1;
if (ip_meta.isWindowsCE() || settings.dreamcast.ForceWindowsCE
|| prod_id == "T26702N") // PBA Tour Bowling 2001
{
INFO_LOG(BOOT, "Enabling Full MMU and Extra depth scaling for Windows CE game");
settings.rend.ExtraDepthScale = 0.1; // taxi 2 needs 0.01 for FMV (amd, per-tri)
extra_depth_game = true;
settings.dreamcast.FullMMU = true;
settings.aica.NoBatch = true;
}
// Tony Hawk's Pro Skater 2
if (prod_id == "T13008D" || prod_id == "T13006N"
// Tony Hawk's Pro Skater 1
|| prod_id == "T40205N"
// Tony Hawk's Skateboarding
|| prod_id == "T40204D"
// Skies of Arcadia
|| prod_id == "MK-51052"
// Eternal Arcadia (JP)
|| prod_id == "HDR-0076"
// Flag to Flag (US)
|| prod_id == "MK-51007"
// Super Speed Racing (JP)
|| prod_id == "HDR-0013"
// Yu Suzuki Game Works Vol. 1
|| prod_id == "6108099"
// L.O.L
|| prod_id == "T2106M"
// Miss Moonlight
|| prod_id == "T18702M"
// Tom Clancy's Rainbow Six (US)
|| prod_id == "T40401N"
// Tom Clancy's Rainbow Six incl. Eagle Watch Missions (EU)
|| prod_id == "T-45001D05")
{
INFO_LOG(BOOT, "Enabling render to texture buffer for game %s", prod_id.c_str());
settings.rend.RenderToTextureBuffer = 1;
rtt_to_buffer_game = true;
}
if (prod_id == "HDR-0176" || prod_id == "RDC-0057")
{
INFO_LOG(BOOT, "Enabling translucent depth multipass for game %s", prod_id.c_str());
// Cosmic Smash
settings.rend.TranslucentPolygonDepthMask = 1;
tr_poly_depth_mask_game = true;
}
// NHL 2K2
if (prod_id == "MK-51182")
{
INFO_LOG(BOOT, "Enabling Extra depth scaling for game %s", prod_id.c_str());
settings.rend.ExtraDepthScale = 1000000; // Mali needs 1M, 10K is enough for others
extra_depth_game = true;
}
// Re-Volt (US, EU)
else if (prod_id == "T-8109N" || prod_id == "T8107D 50")
{
INFO_LOG(BOOT, "Enabling Extra depth scaling for game %s", prod_id.c_str());
settings.rend.ExtraDepthScale = 100;
extra_depth_game = true;
}
// Samurai Shodown 6 dc port
else if (prod_id == "T0002M")
{
INFO_LOG(BOOT, "Enabling Extra depth scaling for game %s", prod_id.c_str());
settings.rend.ExtraDepthScale = 1e26;
extra_depth_game = true;
}
// Super Producers
if (prod_id == "T14303M"
// Giant Killers
|| prod_id == "T45401D 50"
// Wild Metal (US)
|| prod_id == "T42101N 00"
// Wild Metal (EU)
|| prod_id == "T40501D-50"
// Resident Evil 2 (US)
|| prod_id == "T1205N"
// Resident Evil 2 (EU)
|| prod_id == "T7004D 50"
// Rune Jade
|| prod_id == "T14304M"
// Marionette Company
|| prod_id == "T5202M"
// Marionette Company 2
|| prod_id == "T5203M"
// Maximum Pool (for online support)
|| prod_id == "T11010N"
// StarLancer (US) (for online support)
|| prod_id == "T40209N"
// StarLancer (EU) (for online support)
|| prod_id == "T17723D 05"
// Heroes of might and magic III
|| prod_id == "T0000M"
// WebTV
2021-01-03 20:26:23 +00:00
|| prod_id == "6107117" || prod_id == "610-7390" || prod_id == "610-7391"
// PBA
|| prod_id == "T26702N")
{
INFO_LOG(BOOT, "Disabling 32-bit virtual memory for game %s", prod_id.c_str());
settings.dynarec.disable_vmem32 = true;
disable_vmem32_game = true;
}
std::string areas(ip_meta.area_symbols, sizeof(ip_meta.area_symbols));
bool region_usa = areas.find('U') != std::string::npos;
bool region_eu = areas.find('E') != std::string::npos;
bool region_japan = areas.find('J') != std::string::npos;
if (region_usa || region_eu || region_japan)
{
switch (settings.dreamcast.region)
{
case 0: // Japan
if (!region_japan)
{
NOTICE_LOG(BOOT, "Japan region not supported. Using %s instead", region_usa ? "USA" : "Europe");
settings.dreamcast.region = region_usa ? 1 : 2;
forced_game_region = settings.dreamcast.region;
}
break;
case 1: // USA
if (!region_usa)
{
NOTICE_LOG(BOOT, "USA region not supported. Using %s instead", region_eu ? "Europe" : "Japan");
settings.dreamcast.region = region_eu ? 2 : 0;
forced_game_region = settings.dreamcast.region;
}
break;
case 2: // Europe
if (!region_eu)
{
NOTICE_LOG(BOOT, "Europe region not supported. Using %s instead", region_usa ? "USA" : "Japan");
settings.dreamcast.region = region_usa ? 1 : 0;
forced_game_region = settings.dreamcast.region;
}
break;
case 3: // Default
if (region_usa)
settings.dreamcast.region = 1;
else if (region_eu)
settings.dreamcast.region = 2;
else
settings.dreamcast.region = 0;
forced_game_region = settings.dreamcast.region;
break;
}
}
else
WARN_LOG(BOOT, "No region specified in IP.BIN");
if (settings.dreamcast.cable <= 1 && !ip_meta.supportsVGA())
{
NOTICE_LOG(BOOT, "Game doesn't support VGA. Using TV Composite instead");
settings.dreamcast.cable = 3;
forced_game_cable = settings.dreamcast.cable;
}
if (settings.dreamcast.cable == 2 &&
(prod_id == "T40602N" // Centipede
|| prod_id == "T9710N" // Gauntlet Legends (US)
|| prod_id == "MK-51152" // World Series Baseball 2K2
|| prod_id == "T-9701N" // Mortal Kombat Gold (US)
|| prod_id == "T1203N" // Street Fighter Alpha 3 (US)
|| prod_id == "T1203M" // Street Fighter Zero 3 (JP)
|| prod_id == "T13002N" // Vigilante 8 (US)
|| prod_id == "T13003N" // Toy Story 2 (US)
|| prod_id == "T1209N" // Gigawing (US)
|| prod_id == "T1208M" // Gigawing (JP)
|| prod_id == "T1235M")) // Vampire Chronicle for Matching Service
{
NOTICE_LOG(BOOT, "Game doesn't support RGB. Using TV Composite instead");
settings.dreamcast.cable = 3;
forced_game_cable = settings.dreamcast.cable;
}
}
else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE)
{
NOTICE_LOG(BOOT, "Game ID is [%s]", naomi_game_id);
if (!strcmp("SAMURAI SPIRITS 6", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling Extra depth scaling for game %s", naomi_game_id);
settings.rend.ExtraDepthScale = 1e26;
extra_depth_game = true;
}
if (!strcmp("COSMIC SMASH IN JAPAN", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling translucent depth multipass for game %s", naomi_game_id);
settings.rend.TranslucentPolygonDepthMask = true;
tr_poly_depth_mask_game = true;
}
// Input configuration
if (!strcmp("DYNAMIC GOLF", naomi_game_id)
|| !strcmp("SHOOTOUT POOL", naomi_game_id)
|| !strcmp("SHOOTOUT POOL MEDAL", naomi_game_id)
|| !strcmp("CRACKIN'DJ ver JAPAN", naomi_game_id)
|| !strcmp("CRACKIN'DJ PART2 ver JAPAN", naomi_game_id)
|| !strcmp("KICK '4' CASH", naomi_game_id)
|| !strcmp("DRIVE", naomi_game_id)) // Waiwai drive
{
INFO_LOG(BOOT, "Enabling JVS rotary encoders for game %s", naomi_game_id);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::RotaryEncoders;
}
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id) // Naomi
|| !strcmp("GUILTY GEAR isuka", naomi_game_id)) // AW
{
INFO_LOG(BOOT, "Enabling 4-player setup for game %s", naomi_game_id);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::FourPlayers;
}
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id)
|| !strcmp(naomi_game_id, "BASS FISHING SIMULATOR VER.A")) // AW
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::SegaMarineFishing;
}
else if (!strcmp("RINGOUT 4X4 JAPAN", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::DualIOBoards4P;
}
else if (!strcmp("NINJA ASSAULT", naomi_game_id)
|| !strcmp(naomi_game_id, "Sports Shooting USA") // AW
|| !strcmp(naomi_game_id, "SEGA CLAY CHALLENGE") // AW
|| !strcmp(naomi_game_id, "RANGER MISSION") // AW
|| !strcmp(naomi_game_id, "EXTREME HUNTING")) // AW
{
INFO_LOG(BOOT, "Enabling lightgun setup for game %s", naomi_game_id);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::LightGun;
}
else if (!strcmp("MAZAN", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::Mazan;
}
else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::GunSurvivor;
}
2020-01-26 22:23:59 +00:00
else if (!strcmp("WORLD KICKS", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::WorldKicks;
2020-01-26 22:23:59 +00:00
}
else if (!strcmp("WORLD KICKS PCB", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::WorldKicksPCB;
}
else if (!strcmp("THE TYPING OF THE DEAD", naomi_game_id)
|| !strcmp(" LUPIN THE THIRD -THE TYPING-", naomi_game_id)
|| !strcmp("------La Keyboardxyu------", naomi_game_id))
2020-03-23 13:09:50 +00:00
{
INFO_LOG(BOOT, "Enabling keyboard for game %s", naomi_game_id);
settings.input.JammaSetup = JVS::Keyboard;
2020-01-26 22:23:59 +00:00
}
else if (!strcmp("OUTTRIGGER JAPAN", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling JVS rotary encoders for game %s", naomi_game_id);
settings.input.JammaSetup = JVS::OutTrigger;
}
else if (!strcmp(naomi_game_id, "THE MAZE OF THE KINGS")
|| !strcmp(naomi_game_id, " CONFIDENTIAL MISSION ---------")
|| !strcmp(naomi_game_id, "DEATH CRIMSON OX")
|| !strncmp(naomi_game_id, "hotd2", 5) // House of the Dead 2
|| !strcmp(naomi_game_id, "LUPIN THE THIRD -THE SHOOTING-"))
{
INFO_LOG(BOOT, "Enabling lightgun as analog setup for game %s", naomi_game_id);
settings.input.JammaSetup = JVS::LightGunAsAnalog;
}
else if (!strcmp("WAVE RUNNER GP", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
settings.input.JammaSetup = JVS::WaveRunnerGP;
}
else if (!strcmp("INU NO OSANPO", naomi_game_id)) // Dog Walking
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
settings.input.JammaSetup = JVS::DogWalking;
}
else if (!strcmp(" TOUCH DE UNOH -------------", naomi_game_id)
|| !strcmp("POKASUKA GHOST (JAPANESE)", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
settings.input.JammaSetup = JVS::TouchDeUno;
}
settings.rend.Rotate90 = naomi_rotate_screen;
2018-10-21 00:48:24 +00:00
}
}
2019-07-10 15:25:11 +00:00
void dc_reset(bool hard)
{
2019-07-10 15:25:11 +00:00
plugins_Reset(hard);
mem_Reset(hard);
2019-07-10 15:25:11 +00:00
sh4_cpu.Reset(hard);
if (hard)
EventManager::event(Event::Terminate);
}
static bool reset_requested;
int reicast_init(int argc, char* argv[])
2013-12-19 17:10:14 +00:00
{
#if defined(TEST_AUTOMATION)
setbuf(stdout, 0);
setbuf(stderr, 0);
#endif
2013-12-19 17:10:14 +00:00
if (!_vmem_reserve())
{
ERROR_LOG(VMEM, "Failed to alloc mem");
2013-12-19 17:10:14 +00:00
return -1;
}
if (ParseCommandLine(argc, argv))
2013-12-19 17:10:14 +00:00
{
return 69;
2013-12-19 17:10:14 +00:00
}
InitSettings();
LogManager::Shutdown();
if (!cfgOpen())
2013-12-19 17:10:14 +00:00
{
LogManager::Init();
NOTICE_LOG(BOOT, "Config directory is not set. Starting onboarding");
gui_open_onboarding();
2013-12-19 17:10:14 +00:00
}
else
{
LogManager::Init();
LoadSettings(false);
}
settings.pvr.rend = (RenderType)cfgLoadInt("config", "pvr.rend", (int)settings.pvr.rend);
2013-12-19 17:10:14 +00:00
os_CreateWindow();
os_SetupInput();
// Needed to avoid crash calling dc_is_running() in gui
Get_Sh4Interpreter(&sh4_cpu);
sh4_cpu.Init();
return 0;
}
static void set_platform(int platform)
{
if (VRAM_SIZE != 0)
_vmem_unprotect_vram(0, VRAM_SIZE);
switch (platform)
{
case DC_PLATFORM_DREAMCAST:
settings.platform.ram_size = 16 * 1024 * 1024;
settings.platform.vram_size = 8 * 1024 * 1024;
settings.platform.aram_size = 2 * 1024 * 1024;
settings.platform.bios_size = 2 * 1024 * 1024;
settings.platform.flash_size = 128 * 1024;
settings.platform.bbsram_size = 0;
break;
case DC_PLATFORM_NAOMI:
settings.platform.ram_size = 32 * 1024 * 1024;
settings.platform.vram_size = 16 * 1024 * 1024;
settings.platform.aram_size = 8 * 1024 * 1024;
settings.platform.bios_size = 2 * 1024 * 1024;
settings.platform.flash_size = 0;
settings.platform.bbsram_size = 32 * 1024;
break;
case DC_PLATFORM_ATOMISWAVE:
settings.platform.ram_size = 16 * 1024 * 1024;
settings.platform.vram_size = 8 * 1024 * 1024;
settings.platform.aram_size = 8 * 1024 * 1024;
settings.platform.bios_size = 128 * 1024;
settings.platform.flash_size = 0;
settings.platform.bbsram_size = 128 * 1024;
break;
default:
die("Unsupported platform");
break;
}
settings.platform.system = platform;
settings.platform.ram_mask = settings.platform.ram_size - 1;
settings.platform.vram_mask = settings.platform.vram_size - 1;
settings.platform.aram_mask = settings.platform.aram_size - 1;
_vmem_init_mappings();
}
2019-11-04 20:37:16 +00:00
void dc_init()
{
2019-07-08 16:10:43 +00:00
static bool init_done;
if (init_done)
2019-07-11 17:23:21 +00:00
return;
// Default platform
set_platform(DC_PLATFORM_DREAMCAST);
2019-07-11 17:23:21 +00:00
plugins_Init();
mem_Init();
reios_init();
2019-07-11 17:23:21 +00:00
// the recompiler may start generating code at this point and needs a fully configured machine
2015-07-25 06:39:35 +00:00
#if FEAT_SHREC != DYNAREC_NONE
Get_Sh4Recompiler(&sh4_cpu);
sh4_cpu.Init(); // Also initialize the interpreter
2013-12-19 17:10:14 +00:00
if(settings.dynarec.Enable)
{
INFO_LOG(DYNAREC, "Using Recompiler");
2013-12-19 17:10:14 +00:00
}
else
#endif
{
Get_Sh4Interpreter(&sh4_cpu);
sh4_cpu.Init();
INFO_LOG(INTERPRETER, "Using Interpreter");
2013-12-19 17:10:14 +00:00
}
2019-07-08 16:10:43 +00:00
init_done = true;
}
static int get_game_platform(const char *path)
{
if (path == NULL)
// Dreamcast BIOS
return DC_PLATFORM_DREAMCAST;
std::string extension = get_file_extension(path);
if (extension == "")
return DC_PLATFORM_DREAMCAST; // unknown
if (extension == "zip" || extension == "7z")
return naomi_cart_GetPlatform(path);
if (extension == "bin" || extension == "dat" || extension == "lst")
return DC_PLATFORM_NAOMI;
return DC_PLATFORM_DREAMCAST;
}
static void dc_start_game(const char *path)
2019-07-08 16:10:43 +00:00
{
DEBUG_LOG(BOOT, "Loading game %s", path == nullptr ? "(nil)" : path);
bool forced_bios_file = false;
2019-07-08 16:10:43 +00:00
if (path != NULL)
{
strcpy(settings.imgread.ImagePath, path);
}
else
{
// Booting the BIOS requires a BIOS file
forced_bios_file = true;
settings.imgread.ImagePath[0] = '\0';
}
2013-12-19 17:10:14 +00:00
2019-07-11 17:23:21 +00:00
dc_init();
2013-12-19 17:10:14 +00:00
set_platform(get_game_platform(path));
mem_map_default();
2019-07-08 16:10:43 +00:00
InitSettings();
dc_reset(true);
LoadSettings(false);
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
2019-07-08 16:10:43 +00:00
{
if ((settings.bios.UseReios && !forced_bios_file) || !LoadRomFiles())
2019-07-08 16:10:43 +00:00
{
if (forced_bios_file)
throw ReicastException("No BIOS file found");
if (!LoadHle())
throw ReicastException("Failed to initialize HLE BIOS");
NOTICE_LOG(BOOT, "Did not load BIOS, using reios");
}
2019-07-08 16:10:43 +00:00
}
else
{
LoadRomFiles();
}
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
2019-07-08 16:10:43 +00:00
{
mcfg_CreateDevices();
if (path == NULL)
{
// Boot BIOS
TermDrive();
InitDrive();
}
else
{
std::string extension = get_file_extension(settings.imgread.ImagePath);
if (extension != "elf")
{
if (InitDrive())
LoadCustom();
else
{
// Content load failed. Boot the BIOS
settings.imgread.ImagePath[0] = '\0';
forced_bios_file = true;
if (!LoadRomFiles())
throw ReicastException("No BIOS file found");
InitDrive();
}
}
}
FixUpFlash();
2019-07-08 16:10:43 +00:00
}
else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE)
2019-07-08 16:10:43 +00:00
{
2019-07-11 17:23:21 +00:00
naomi_cart_LoadRom(path);
if (loading_canceled)
return;
LoadCustom();
if (settings.platform.system == DC_PLATFORM_NAOMI)
{
mcfg_CreateNAOMIJamma();
SetNaomiNetworkConfig(-1);
}
else if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
mcfg_CreateAtomisWaveControllers();
2019-07-08 16:10:43 +00:00
}
if (cheatManager.Reset())
{
gui_display_notification("Widescreen cheat activated", 1000);
if (saved_screen_stretching == -1)
saved_screen_stretching = settings.rend.ScreenStretching;
settings.rend.ScreenStretching = 133; // 4:3 -> 16:9
}
else
{
if (saved_screen_stretching != -1)
{
settings.rend.ScreenStretching = saved_screen_stretching;
saved_screen_stretching = -1;
}
}
fast_forward_mode = false;
EventManager::event(Event::Start);
2013-12-19 17:10:14 +00:00
}
2018-09-02 13:49:23 +00:00
bool dc_is_running()
{
return sh4_cpu.IsCpuRunning();
}
2018-10-02 16:29:29 +00:00
#ifndef TARGET_DISPFRAME
void* dc_run(void*)
2013-12-19 17:10:14 +00:00
{
InitAudio();
if (settings.dynarec.Enable)
{
Get_Sh4Recompiler(&sh4_cpu);
INFO_LOG(DYNAREC, "Using Recompiler");
}
else
{
Get_Sh4Interpreter(&sh4_cpu);
INFO_LOG(DYNAREC, "Using Interpreter");
}
do {
reset_requested = false;
2019-06-21 11:33:55 +00:00
sh4_cpu.Run();
SaveRomFiles();
if (reset_requested)
{
dc_reset(false);
}
} while (reset_requested);
TermAudio();
return NULL;
2013-12-19 17:10:14 +00:00
}
2018-07-16 15:19:45 +00:00
#endif
2013-12-19 17:10:14 +00:00
void dc_term()
{
dc_cancel_load();
2013-12-19 17:10:14 +00:00
sh4_cpu.Term();
if (settings.platform.system != DC_PLATFORM_DREAMCAST)
naomi_cart_Close();
2013-12-19 17:10:14 +00:00
plugins_Term();
mem_Term();
2013-12-19 17:10:14 +00:00
_vmem_release();
mcfg_DestroyDevices();
2013-12-19 17:10:14 +00:00
SaveSettings();
}
void dc_stop()
{
sh4_cpu.Stop();
rend_cancel_emu_wait();
emu_thread.WaitToEnd();
EventManager::event(Event::Pause);
2013-12-19 17:10:14 +00:00
}
// Called on the emulator thread for soft reset
void dc_request_reset()
{
reset_requested = true;
sh4_cpu.Stop();
}
void dc_exit()
2018-09-02 13:49:23 +00:00
{
dc_stop();
mainui_stop();
2018-09-02 13:49:23 +00:00
}
void InitSettings()
2013-12-19 17:10:14 +00:00
{
settings.dynarec.Enable = true;
settings.dynarec.idleskip = true;
settings.dynarec.unstable_opt = false;
2020-06-15 14:56:09 +00:00
settings.dynarec.safemode = false;
settings.dynarec.disable_vmem32 = false;
settings.dreamcast.cable = 3; // TV composite
settings.dreamcast.region = 3; // default
settings.dreamcast.broadcast = 4; // default
settings.dreamcast.language = 6; // default
settings.dreamcast.FullMMU = false;
2019-08-28 18:47:47 +00:00
settings.dreamcast.ForceWindowsCE = false;
settings.dreamcast.HideLegacyNaomiRoms = true;
2019-05-15 12:00:36 +00:00
settings.aica.DSPEnabled = false;
2020-02-25 11:52:21 +00:00
settings.aica.LimitFPS = true;
2019-05-15 12:00:36 +00:00
settings.aica.NoBatch = false;
settings.aica.NoSound = false;
2019-04-05 20:22:46 +00:00
settings.audio.backend = "auto";
settings.rend.UseMipmaps = true;
settings.rend.WideScreen = false;
settings.rend.ShowFPS = false;
settings.rend.RenderToTextureBuffer = false;
settings.rend.RenderToTextureUpscale = 1;
settings.rend.TranslucentPolygonDepthMask = false;
settings.rend.ModifierVolumes = true;
settings.rend.Clipping = true;
settings.rend.TextureUpscale = 1;
settings.rend.MaxFilteredTextureSize = 256;
settings.rend.ExtraDepthScale = 1.f;
settings.rend.CustomTextures = false;
settings.rend.DumpTextures = false;
2019-02-18 23:49:24 +00:00
settings.rend.ScreenScaling = 100;
settings.rend.ScreenStretching = 100;
2019-04-04 17:26:15 +00:00
settings.rend.Fog = true;
2019-04-08 13:54:37 +00:00
settings.rend.FloatVMUs = false;
settings.rend.Rotate90 = false;
2019-05-17 17:48:25 +00:00
settings.rend.PerStripSorting = false;
settings.rend.DelayFrameSwapping = false;
settings.rend.WidescreenGameHacks = false;
2021-01-23 14:59:57 +00:00
memset(settings.rend.CrosshairColor, 0, sizeof(settings.rend.CrosshairColor));
settings.pvr.ta_skip = 0;
settings.pvr.MaxThreads = 3;
settings.pvr.AutoSkipFrame = 0;
settings.debug.SerialConsole = false;
settings.debug.SerialPTY = false;
2019-07-30 17:04:51 +00:00
settings.bios.UseReios = false;
settings.validate.OpenGlChecks = false;
settings.input.MouseSensitivity = 100;
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = JVS::Default;
settings.input.VirtualGamepadVibration = 20;
for (int i = 0; i < MAPLE_PORTS; i++)
{
settings.input.maple_devices[i] = i == 0 ? MDT_SegaController : MDT_None;
settings.input.maple_expansion_devices[i][0] = i == 0 ? MDT_SegaVMU : MDT_None;
settings.input.maple_expansion_devices[i][1] = i == 0 ? MDT_SegaVMU : MDT_None;
}
settings.network.Enable = false;
settings.network.ActAsServer = false;
settings.network.dns = "46.101.91.123"; // Dreamcast Live DNS
settings.network.server = "";
2021-01-02 20:19:50 +00:00
settings.network.EmulateBBA = false;
#if SUPPORT_DISPMANX
settings.dispmanx.Width = 0;
settings.dispmanx.Height = 0;
settings.dispmanx.Keep_Aspect = true;
#endif
#if HOST_CPU == CPU_ARM
settings.aica.BufferSize = 5644; // 128 ms
#else
settings.aica.BufferSize = 2822; // 64 ms
#endif
#if USE_OMX
settings.omx.Audio_Latency = 100;
settings.omx.Audio_HDMI = true;
#endif
}
void LoadSettings(bool game_specific)
{
const char *config_section = game_specific ? cfgGetGameId() : "config";
const char *input_section = game_specific ? cfgGetGameId() : "input";
2019-04-05 20:22:46 +00:00
const char *audio_section = game_specific ? cfgGetGameId() : "audio";
settings.dynarec.Enable = cfgLoadBool(config_section, "Dynarec.Enabled", settings.dynarec.Enable);
settings.dynarec.idleskip = cfgLoadBool(config_section, "Dynarec.idleskip", settings.dynarec.idleskip);
settings.dynarec.unstable_opt = cfgLoadBool(config_section, "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
settings.dynarec.safemode = cfgLoadBool(config_section, "Dynarec.safe-mode", settings.dynarec.safemode);
settings.dynarec.disable_vmem32 = cfgLoadBool(config_section, "Dynarec.DisableVmem32", settings.dynarec.disable_vmem32);
//disable_nvmem can't be loaded, because nvmem init is before cfg load
settings.dreamcast.cable = cfgLoadInt(config_section, "Dreamcast.Cable", settings.dreamcast.cable);
settings.dreamcast.region = cfgLoadInt(config_section, "Dreamcast.Region", settings.dreamcast.region);
settings.dreamcast.broadcast = cfgLoadInt(config_section, "Dreamcast.Broadcast", settings.dreamcast.broadcast);
settings.dreamcast.language = cfgLoadInt(config_section, "Dreamcast.Language", settings.dreamcast.language);
settings.dreamcast.FullMMU = cfgLoadBool(config_section, "Dreamcast.FullMMU", settings.dreamcast.FullMMU);
2019-08-28 18:47:47 +00:00
settings.dreamcast.ForceWindowsCE = cfgLoadBool(config_section, "Dreamcast.ForceWindowsCE", settings.dreamcast.ForceWindowsCE);
if (settings.dreamcast.ForceWindowsCE)
settings.aica.NoBatch = true;
2020-02-25 11:52:21 +00:00
settings.aica.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS)
|| cfgLoadInt(config_section, "aica.LimitFPS", 0) == 2;
2019-05-15 12:00:36 +00:00
settings.aica.DSPEnabled = cfgLoadBool(config_section, "aica.DSPEnabled", settings.aica.DSPEnabled);
settings.aica.NoSound = cfgLoadBool(config_section, "aica.NoSound", settings.aica.NoSound);
settings.aica.BufferSize = cfgLoadInt(config_section, "aica.BufferSize", settings.aica.BufferSize);
settings.aica.BufferSize = std::max(512u, settings.aica.BufferSize);
2019-04-05 20:22:46 +00:00
settings.audio.backend = cfgLoadStr(audio_section, "backend", settings.audio.backend.c_str());
settings.rend.UseMipmaps = cfgLoadBool(config_section, "rend.UseMipmaps", settings.rend.UseMipmaps);
settings.rend.WideScreen = cfgLoadBool(config_section, "rend.WideScreen", settings.rend.WideScreen);
settings.rend.ShowFPS = cfgLoadBool(config_section, "rend.ShowFPS", settings.rend.ShowFPS);
settings.rend.RenderToTextureBuffer = cfgLoadBool(config_section, "rend.RenderToTextureBuffer", settings.rend.RenderToTextureBuffer);
settings.rend.RenderToTextureUpscale = cfgLoadInt(config_section, "rend.RenderToTextureUpscale", settings.rend.RenderToTextureUpscale);
settings.rend.TranslucentPolygonDepthMask = cfgLoadBool(config_section, "rend.TranslucentPolygonDepthMask", settings.rend.TranslucentPolygonDepthMask);
settings.rend.ModifierVolumes = cfgLoadBool(config_section, "rend.ModifierVolumes", settings.rend.ModifierVolumes);
settings.rend.Clipping = cfgLoadBool(config_section, "rend.Clipping", settings.rend.Clipping);
settings.rend.TextureUpscale = cfgLoadInt(config_section, "rend.TextureUpscale", settings.rend.TextureUpscale);
settings.rend.MaxFilteredTextureSize = cfgLoadInt(config_section,"rend.MaxFilteredTextureSize", settings.rend.MaxFilteredTextureSize);
std::string extra_depth_scale_str = cfgLoadStr(config_section,"rend.ExtraDepthScale", "");
if (!extra_depth_scale_str.empty())
{
settings.rend.ExtraDepthScale = atof(extra_depth_scale_str.c_str());
if (settings.rend.ExtraDepthScale == 0)
settings.rend.ExtraDepthScale = 1.f;
}
settings.rend.CustomTextures = cfgLoadBool(config_section, "rend.CustomTextures", settings.rend.CustomTextures);
settings.rend.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures);
2019-02-18 23:49:24 +00:00
settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling);
2020-03-29 17:29:14 +00:00
settings.rend.ScreenScaling = std::min(std::max(1, settings.rend.ScreenScaling), 800);
settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching);
2019-04-04 17:26:15 +00:00
settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog);
2019-04-08 13:54:37 +00:00
settings.rend.FloatVMUs = cfgLoadBool(config_section, "rend.FloatVMUs", settings.rend.FloatVMUs);
settings.rend.Rotate90 = cfgLoadBool(config_section, "rend.Rotate90", settings.rend.Rotate90);
2019-05-17 17:48:25 +00:00
settings.rend.PerStripSorting = cfgLoadBool(config_section, "rend.PerStripSorting", settings.rend.PerStripSorting);
settings.rend.DelayFrameSwapping = cfgLoadBool(config_section, "rend.DelayFrameSwapping", settings.rend.DelayFrameSwapping);
settings.rend.WidescreenGameHacks = cfgLoadBool(config_section, "rend.WidescreenGameHacks", settings.rend.WidescreenGameHacks);
2021-01-23 14:59:57 +00:00
for (u32 i = 0; i < ARRAY_SIZE(settings.rend.CrosshairColor); i++)
{
std::string name = "rend.CrossHairColor" + std::to_string(i + 1);
settings.rend.CrosshairColor[i] = cfgLoadInt(config_section, name.c_str(), settings.rend.CrosshairColor[i]);
}
settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
settings.pvr.MaxThreads = cfgLoadInt(config_section, "pvr.MaxThreads", settings.pvr.MaxThreads);
if (game_specific)
settings.pvr.AutoSkipFrame = cfgLoadInt(config_section, "pvr.AutoSkipFrame", settings.pvr.AutoSkipFrame);
else
{
// compatibility with previous SynchronousRendering option
int autoskip = cfgLoadInt(config_section, "pvr.AutoSkipFrame", 99);
if (autoskip == 99)
autoskip = cfgLoadBool(config_section, "pvr.SynchronousRendering", true) ? 1 : 2;
settings.pvr.AutoSkipFrame = autoskip;
}
settings.debug.SerialConsole = cfgLoadBool(config_section, "Debug.SerialConsoleEnabled", settings.debug.SerialConsole);
settings.debug.SerialPTY = cfgLoadBool(config_section, "Debug.SerialPTY", settings.debug.SerialPTY);
2015-03-22 00:16:28 +00:00
settings.bios.UseReios = cfgLoadBool(config_section, "bios.UseReios", settings.bios.UseReios);
settings.validate.OpenGlChecks = cfgLoadBool(game_specific ? cfgGetGameId() : "validate", "OpenGlChecks", settings.validate.OpenGlChecks);
2018-09-18 07:27:16 +00:00
settings.input.MouseSensitivity = cfgLoadInt(input_section, "MouseSensitivity", settings.input.MouseSensitivity);
2020-03-23 13:09:50 +00:00
settings.input.JammaSetup = (JVS)cfgLoadInt(input_section, "JammaSetup", (int)settings.input.JammaSetup);
settings.input.VirtualGamepadVibration = cfgLoadInt(input_section, "VirtualGamepadVibration", settings.input.VirtualGamepadVibration);
for (int i = 0; i < MAPLE_PORTS; i++)
{
char device_name[32];
sprintf(device_name, "device%d", i + 1);
settings.input.maple_devices[i] = (MapleDeviceType)cfgLoadInt(input_section, device_name, settings.input.maple_devices[i]);
sprintf(device_name, "device%d.1", i + 1);
settings.input.maple_expansion_devices[i][0] = (MapleDeviceType)cfgLoadInt(input_section, device_name, settings.input.maple_expansion_devices[i][0]);
sprintf(device_name, "device%d.2", i + 1);
settings.input.maple_expansion_devices[i][1] = (MapleDeviceType)cfgLoadInt(input_section, device_name, settings.input.maple_expansion_devices[i][1]);
}
settings.network.Enable = cfgLoadBool("network", "Enable", settings.network.Enable);
settings.network.ActAsServer = cfgLoadBool("network", "ActAsServer", settings.network.ActAsServer);
settings.network.dns = cfgLoadStr("network", "DNS", settings.network.dns.c_str());
settings.network.server = cfgLoadStr("network", "server", settings.network.server.c_str());
2021-01-02 20:19:50 +00:00
settings.network.EmulateBBA = cfgLoadBool("network", "EmulateBBA", settings.network.EmulateBBA);
2016-03-02 05:48:34 +00:00
#if SUPPORT_DISPMANX
settings.dispmanx.Width = cfgLoadInt(game_specific ? cfgGetGameId() : "dispmanx", "width", settings.dispmanx.Width);
settings.dispmanx.Height = cfgLoadInt(game_specific ? cfgGetGameId() : "dispmanx", "height", settings.dispmanx.Height);
settings.dispmanx.Keep_Aspect = cfgLoadBool(game_specific ? cfgGetGameId() : "dispmanx", "maintain_aspect", settings.dispmanx.Keep_Aspect);
2016-03-02 05:48:34 +00:00
#endif
#if USE_OMX
settings.omx.Audio_Latency = cfgLoadInt(game_specific ? cfgGetGameId() : "omx", "audio_latency", settings.omx.Audio_Latency);
settings.omx.Audio_HDMI = cfgLoadBool(game_specific ? cfgGetGameId() : "omx", "audio_hdmi", settings.omx.Audio_HDMI);
2016-03-02 05:48:34 +00:00
#endif
if (!game_specific)
{
settings.dreamcast.ContentPath.clear();
std::string paths = cfgLoadStr(config_section, "Dreamcast.ContentPath", "");
std::string::size_type start = 0;
while (true)
{
std::string::size_type end = paths.find(';', start);
if (end == std::string::npos)
end = paths.size();
if (start != end)
settings.dreamcast.ContentPath.push_back(paths.substr(start, end - start));
if (end == paths.size())
break;
start = end + 1;
}
settings.dreamcast.HideLegacyNaomiRoms = cfgLoadBool(config_section, "Dreamcast.HideLegacyNaomiRoms", settings.dreamcast.HideLegacyNaomiRoms);
}
2013-12-19 17:10:14 +00:00
/*
//make sure values are valid
2020-03-29 17:29:14 +00:00
settings.dreamcast.cable = std::min(std::max(settings.dreamcast.cable, 0),3);
settings.dreamcast.region = std::min(std::max(settings.dreamcast.region, 0),3);
settings.dreamcast.broadcast = std::min(std::max(settings.dreamcast.broadcast,0),4);
2013-12-19 17:10:14 +00:00
*/
}
static void LoadCustom()
{
char *reios_id;
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
{
static char _disk_id[sizeof(ip_meta.product_number) + 1];
reios_disk_id();
memcpy(_disk_id, ip_meta.product_number, sizeof(ip_meta.product_number));
reios_id = _disk_id;
char *p = reios_id + strlen(reios_id) - 1;
while (p >= reios_id && *p == ' ')
*p-- = '\0';
if (*p == '\0')
return;
}
else
{
reios_id = naomi_game_id;
}
2019-02-16 15:59:27 +00:00
// Default per-game settings
LoadSpecialSettings();
cfgSetGameId(reios_id);
2019-02-16 15:59:27 +00:00
// Reload per-game settings
LoadSettings(true);
}
2013-12-19 17:10:14 +00:00
void SaveSettings()
{
2019-10-29 13:34:29 +00:00
cfgSetAutoSave(false);
cfgSaveBool("config", "Dynarec.Enabled", settings.dynarec.Enable);
if (forced_game_cable == -1 || forced_game_cable != (int)settings.dreamcast.cable)
cfgSaveInt("config", "Dreamcast.Cable", settings.dreamcast.cable);
if (forced_game_region == -1 || forced_game_region != (int)settings.dreamcast.region)
cfgSaveInt("config", "Dreamcast.Region", settings.dreamcast.region);
2019-02-06 18:57:13 +00:00
cfgSaveInt("config", "Dreamcast.Broadcast", settings.dreamcast.broadcast);
2019-08-28 18:47:47 +00:00
cfgSaveBool("config", "Dreamcast.ForceWindowsCE", settings.dreamcast.ForceWindowsCE);
cfgSaveBool("config", "Dynarec.idleskip", settings.dynarec.idleskip);
cfgSaveBool("config", "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
if (!safemode_game || !settings.dynarec.safemode)
cfgSaveBool("config", "Dynarec.safe-mode", settings.dynarec.safemode);
2019-07-30 17:04:51 +00:00
cfgSaveBool("config", "bios.UseReios", settings.bios.UseReios);
// if (!disable_vmem32_game || !settings.dynarec.disable_vmem32)
// cfgSaveBool("config", "Dynarec.DisableVmem32", settings.dynarec.disable_vmem32);
2019-02-06 18:57:13 +00:00
cfgSaveInt("config", "Dreamcast.Language", settings.dreamcast.language);
2020-02-25 11:52:21 +00:00
cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS);
2019-05-15 12:00:36 +00:00
cfgSaveBool("config", "aica.DSPEnabled", settings.aica.DSPEnabled);
cfgSaveBool("config", "aica.NoSound", settings.aica.NoSound);
cfgSaveInt("config", "aica.BufferSize", settings.aica.BufferSize);
2019-04-05 20:22:46 +00:00
cfgSaveStr("audio", "backend", settings.audio.backend.c_str());
2019-04-24 19:41:38 +00:00
// Write backend specific settings
// std::map<std::string, std::map<std::string, std::string>>
2019-10-29 13:34:29 +00:00
for (const auto& pair : settings.audio.options)
2019-04-24 19:41:38 +00:00
{
2019-10-29 13:34:29 +00:00
const std::string& section = pair.first;
const auto& options = pair.second;
for (const auto& option : options)
cfgSaveStr(section.c_str(), option.first.c_str(), option.second.c_str());
2019-04-24 19:41:38 +00:00
}
cfgSaveBool("config", "rend.WideScreen", settings.rend.WideScreen);
cfgSaveBool("config", "rend.ShowFPS", settings.rend.ShowFPS);
if (!rtt_to_buffer_game || !settings.rend.RenderToTextureBuffer)
cfgSaveBool("config", "rend.RenderToTextureBuffer", settings.rend.RenderToTextureBuffer);
2019-02-06 18:57:13 +00:00
cfgSaveInt("config", "rend.RenderToTextureUpscale", settings.rend.RenderToTextureUpscale);
cfgSaveBool("config", "rend.ModifierVolumes", settings.rend.ModifierVolumes);
cfgSaveBool("config", "rend.Clipping", settings.rend.Clipping);
2019-02-06 18:57:13 +00:00
cfgSaveInt("config", "rend.TextureUpscale", settings.rend.TextureUpscale);
cfgSaveInt("config", "rend.MaxFilteredTextureSize", settings.rend.MaxFilteredTextureSize);
cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures);
cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures);
2019-02-18 23:49:24 +00:00
cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling);
if (saved_screen_stretching != -1)
cfgSaveInt("config", "rend.ScreenStretching", saved_screen_stretching);
else
cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching);
2019-04-04 17:26:15 +00:00
cfgSaveBool("config", "rend.Fog", settings.rend.Fog);
2019-04-08 13:54:37 +00:00
cfgSaveBool("config", "rend.FloatVMUs", settings.rend.FloatVMUs);
if (!naomi_rotate_screen || !settings.rend.Rotate90)
cfgSaveBool("config", "rend.Rotate90", settings.rend.Rotate90);
2019-02-06 18:57:13 +00:00
cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip);
cfgSaveInt("config", "pvr.rend", (int)settings.pvr.rend);
2019-05-17 17:48:25 +00:00
cfgSaveBool("config", "rend.PerStripSorting", settings.rend.PerStripSorting);
cfgSaveBool("config", "rend.DelayFrameSwapping", settings.rend.DelayFrameSwapping);
cfgSaveBool("config", "rend.WidescreenGameHacks", settings.rend.WidescreenGameHacks);
2021-01-23 14:59:57 +00:00
for (u32 i = 0; i < ARRAY_SIZE(settings.rend.CrosshairColor); i++)
{
std::string name = "rend.CrossHairColor" + std::to_string(i + 1);
cfgSaveInt("config", name.c_str(), settings.rend.CrosshairColor[i]);
}
2019-02-06 18:57:13 +00:00
cfgSaveInt("config", "pvr.MaxThreads", settings.pvr.MaxThreads);
cfgSaveInt("config", "pvr.AutoSkipFrame", settings.pvr.AutoSkipFrame);
2019-02-06 18:57:13 +00:00
cfgSaveBool("config", "Debug.SerialConsoleEnabled", settings.debug.SerialConsole);
cfgSaveBool("config", "Debug.SerialPTY", settings.debug.SerialPTY);
2019-02-06 18:57:13 +00:00
cfgSaveInt("input", "MouseSensitivity", settings.input.MouseSensitivity);
cfgSaveInt("input", "VirtualGamepadVibration", settings.input.VirtualGamepadVibration);
for (int i = 0; i < MAPLE_PORTS; i++)
{
char device_name[32];
sprintf(device_name, "device%d", i + 1);
cfgSaveInt("input", device_name, (s32)settings.input.maple_devices[i]);
sprintf(device_name, "device%d.1", i + 1);
cfgSaveInt("input", device_name, (s32)settings.input.maple_expansion_devices[i][0]);
sprintf(device_name, "device%d.2", i + 1);
cfgSaveInt("input", device_name, (s32)settings.input.maple_expansion_devices[i][1]);
}
// FIXME This should never be a game-specific setting
std::string paths;
for (auto& path : settings.dreamcast.ContentPath)
2018-09-23 14:18:35 +00:00
{
if (!paths.empty())
paths += ";";
paths += path;
2018-09-23 14:18:35 +00:00
}
cfgSaveStr("config", "Dreamcast.ContentPath", paths.c_str());
cfgSaveBool("config", "Dreamcast.HideLegacyNaomiRoms", settings.dreamcast.HideLegacyNaomiRoms);
cfgSaveBool("network", "Enable", settings.network.Enable);
cfgSaveBool("network", "ActAsServer", settings.network.ActAsServer);
cfgSaveStr("network", "DNS", settings.network.dns.c_str());
cfgSaveStr("network", "server", settings.network.server.c_str());
2021-01-02 20:19:50 +00:00
cfgSaveBool("network", "EmulateBBA", settings.network.EmulateBBA);
GamepadDevice::SaveMaplePorts();
#ifdef __ANDROID__
void SaveAndroidSettings();
SaveAndroidSettings();
#endif
2019-10-29 13:34:29 +00:00
cfgSetAutoSave(true);
2019-02-06 18:57:13 +00:00
}
void dc_resume()
2019-02-06 18:57:13 +00:00
{
SetMemoryHandlers();
EventManager::event(Event::Resume);
if (!emu_thread.thread.joinable())
emu_thread.Start();
}
2019-02-06 18:57:13 +00:00
static void cleanup_serialize(void *data)
2018-09-02 13:49:23 +00:00
{
if ( data != NULL )
free(data) ;
}
static std::string get_savestate_file_path(bool writable)
2018-09-20 20:41:10 +00:00
{
2020-03-29 17:29:14 +00:00
std::string state_file = settings.imgread.ImagePath;
2019-09-07 12:37:39 +00:00
size_t lastindex = state_file.find_last_of('/');
#ifdef _WIN32
size_t lastindex2 = state_file.find_last_of('\\');
if (lastindex == std::string::npos)
lastindex = lastindex2;
else if (lastindex2 != std::string::npos)
lastindex = std::max(lastindex, lastindex2);
#endif
if (lastindex != std::string::npos)
2018-09-20 20:41:10 +00:00
state_file = state_file.substr(lastindex + 1);
2019-09-07 12:37:39 +00:00
lastindex = state_file.find_last_of('.');
if (lastindex != std::string::npos)
2018-09-20 20:41:10 +00:00
state_file = state_file.substr(0, lastindex);
state_file = state_file + ".state";
if (writable)
return get_writable_data_path(state_file);
else
return get_readonly_data_path(state_file);
2018-09-20 20:41:10 +00:00
}
void dc_savestate()
2018-09-02 13:49:23 +00:00
{
unsigned int total_size = 0 ;
void *data = NULL ;
dc_stop();
2018-09-02 13:49:23 +00:00
if ( ! dc_serialize(&data, &total_size) )
{
WARN_LOG(SAVESTATE, "Failed to save state - could not initialize total size") ;
gui_display_notification("Save state failed", 2000);
2018-09-02 13:49:23 +00:00
cleanup_serialize(data) ;
return;
2018-09-02 13:49:23 +00:00
}
data = malloc(total_size) ;
if ( data == NULL )
{
WARN_LOG(SAVESTATE, "Failed to save state - could not malloc %d bytes", total_size) ;
gui_display_notification("Save state failed - memory full", 2000);
2018-09-02 13:49:23 +00:00
cleanup_serialize(data) ;
return;
2018-09-02 13:49:23 +00:00
}
2020-12-26 08:58:53 +00:00
void *data_ptr = data;
2018-09-02 13:49:23 +00:00
if ( ! dc_serialize(&data_ptr, &total_size) )
{
WARN_LOG(SAVESTATE, "Failed to save state - could not serialize data") ;
gui_display_notification("Save state failed", 2000);
2018-09-02 13:49:23 +00:00
cleanup_serialize(data) ;
return;
2018-09-02 13:49:23 +00:00
}
2020-12-26 08:58:53 +00:00
std::string filename = get_savestate_file_path(true);
#if 0
FILE *f = nowide::fopen(filename.c_str(), "wb") ;
2018-09-02 13:49:23 +00:00
if ( f == NULL )
{
WARN_LOG(SAVESTATE, "Failed to save state - could not open %s for writing", filename.c_str()) ;
gui_display_notification("Cannot open save file", 2000);
2018-09-02 13:49:23 +00:00
cleanup_serialize(data) ;
return;
2018-09-02 13:49:23 +00:00
}
std::fwrite(data, 1, total_size, f) ;
std::fclose(f);
2020-12-26 08:58:53 +00:00
#else
RZipFile zipFile;
if (!zipFile.Open(filename, true))
{
WARN_LOG(SAVESTATE, "Failed to save state - could not open %s for writing", filename.c_str());
gui_display_notification("Cannot open save file", 2000);
cleanup_serialize(data);
return;
}
if (zipFile.Write(data, total_size) != total_size)
{
WARN_LOG(SAVESTATE, "Failed to save state - error writing %s", filename.c_str());
gui_display_notification("Error saving state", 2000);
zipFile.Close();
cleanup_serialize(data);
return;
}
zipFile.Close();
#endif
2018-09-02 13:49:23 +00:00
cleanup_serialize(data) ;
INFO_LOG(SAVESTATE, "Saved state to %s size %d", filename.c_str(), total_size) ;
gui_display_notification("State saved", 1000);
2018-09-02 13:49:23 +00:00
}
void dc_loadstate()
2018-09-02 13:49:23 +00:00
{
2020-12-26 08:58:53 +00:00
u32 total_size = 0;
FILE *f = nullptr;
2018-09-02 13:49:23 +00:00
dc_stop();
2018-09-02 13:49:23 +00:00
2020-12-26 08:58:53 +00:00
std::string filename = get_savestate_file_path(false);
RZipFile zipFile;
if (zipFile.Open(filename, false))
2018-09-02 13:49:23 +00:00
{
2020-12-26 08:58:53 +00:00
total_size = (u32)zipFile.Size();
2018-09-02 13:49:23 +00:00
}
2020-12-26 08:58:53 +00:00
else
{
f = nowide::fopen(filename.c_str(), "rb") ;
2020-12-26 08:58:53 +00:00
if ( f == NULL )
{
WARN_LOG(SAVESTATE, "Failed to load state - could not open %s for reading", filename.c_str()) ;
gui_display_notification("Save state not found", 2000);
return;
}
std::fseek(f, 0, SEEK_END);
total_size = (u32)std::ftell(f);
std::fseek(f, 0, SEEK_SET);
2020-12-26 08:58:53 +00:00
}
void *data = malloc(total_size);
2018-09-02 13:49:23 +00:00
if ( data == NULL )
{
WARN_LOG(SAVESTATE, "Failed to load state - could not malloc %d bytes", total_size) ;
gui_display_notification("Failed to load state - memory full", 2000);
2020-12-26 08:58:53 +00:00
if (f != nullptr)
std::fclose(f);
2020-12-26 08:58:53 +00:00
else
zipFile.Close();
return;
2018-09-02 13:49:23 +00:00
}
2020-12-26 08:58:53 +00:00
size_t read_size;
if (f == nullptr)
{
read_size = zipFile.Read(data, total_size);
zipFile.Close();
}
else
{
read_size = fread(data, 1, total_size, f) ;
std::fclose(f);
2020-12-26 08:58:53 +00:00
}
if (read_size != total_size)
{
WARN_LOG(SAVESTATE, "Failed to load state - I/O error");
gui_display_notification("Failed to load state - I/O error", 2000);
cleanup_serialize(data) ;
return;
}
2018-09-02 13:49:23 +00:00
2020-12-26 08:58:53 +00:00
void *data_ptr = data;
2018-09-02 13:49:23 +00:00
custom_texture.Terminate();
2018-10-29 14:11:34 +00:00
#if FEAT_AREC == DYNAREC_JIT
arm7rec_flush();
2018-10-29 14:11:34 +00:00
#endif
#ifndef NO_MMU
mmu_flush_table();
#endif
2019-06-21 11:17:34 +00:00
bm_Reset();
2018-09-02 13:49:23 +00:00
u32 unserialized_size = 0;
if ( ! dc_unserialize(&data_ptr, &unserialized_size) )
2018-09-02 13:49:23 +00:00
{
WARN_LOG(SAVESTATE, "Failed to load state - could not unserialize data") ;
gui_display_notification("Invalid save state", 2000);
2018-09-02 13:49:23 +00:00
cleanup_serialize(data) ;
return;
2018-09-02 13:49:23 +00:00
}
if (unserialized_size != total_size)
WARN_LOG(SAVESTATE, "Save state error: read %d bytes but used %d", total_size, unserialized_size);
2018-09-02 13:49:23 +00:00
mmu_set_state();
sh4_cpu.ResetCache();
2019-02-06 18:57:13 +00:00
dsp.dyndirty = true;
2018-10-29 14:11:34 +00:00
sh4_sched_ffts();
cleanup_serialize(data) ;
EventManager::event(Event::LoadState);
INFO_LOG(SAVESTATE, "Loaded state from %s size %d", filename.c_str(), total_size) ;
2018-09-02 13:49:23 +00:00
}
void dc_load_game(const char *path)
{
loading_canceled = false;
loading_done = std::async(std::launch::async, [path] {
dc_start_game(path);
});
}
bool dc_is_load_done()
{
if (!loading_done.valid())
return true;
if (loading_done.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready)
return true;
return false;
}
void dc_cancel_load()
{
if (loading_done.valid())
{
loading_canceled = true;
loading_done.get();
}
settings.imgread.ImagePath[0] = '\0';
}
void dc_get_load_status()
{
if (loading_done.valid())
loading_done.get();
}
EventManager EventManager::Instance;
void EventManager::registerEvent(Event event, Callback callback)
{
unregisterEvent(event, callback);
auto it = callbacks.find(event);
if (it != callbacks.end())
it->second.push_back(callback);
else
callbacks.insert({ event, { callback } });
}
void EventManager::unregisterEvent(Event event, Callback callback) {
auto it = callbacks.find(event);
if (it == callbacks.end())
return;
auto it2 = std::find(it->second.begin(), it->second.end(), callback);
if (it2 == it->second.end())
return;
it->second.erase(it2);
}
void EventManager::broadcastEvent(Event event) {
auto it = callbacks.find(event);
if (it == callbacks.end())
return;
for (auto& callback : it->second)
callback(event);
}