Better background game loader
Pass LoadProgress object to report load progress and cancel Better UI Cancel with exception Fix issues when stopping/exiting in !threaded dx9: call gui_term on shutdown
This commit is contained in:
parent
c1bcf91dd6
commit
5bcfa35737
|
@ -37,9 +37,9 @@
|
|||
#include "network/ggpo.h"
|
||||
#include "hw/mem/mem_watch.h"
|
||||
#include "network/net_handshake.h"
|
||||
#include "rend/gui.h"
|
||||
#include <chrono>
|
||||
|
||||
std::atomic<bool> loading_canceled;
|
||||
settings_t settings;
|
||||
|
||||
static void loadSpecialSettings()
|
||||
|
@ -396,7 +396,7 @@ static int getGamePlatform(const char *path)
|
|||
return DC_PLATFORM_DREAMCAST;
|
||||
}
|
||||
|
||||
void Emulator::loadGame(const char *path)
|
||||
void Emulator::loadGame(const char *path, LoadProgress *progress)
|
||||
{
|
||||
init();
|
||||
try {
|
||||
|
@ -458,9 +458,7 @@ void Emulator::loadGame(const char *path)
|
|||
else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||
{
|
||||
LoadRomFiles();
|
||||
naomi_cart_LoadRom(path);
|
||||
if (loading_canceled)
|
||||
return;
|
||||
naomi_cart_LoadRom(path, progress);
|
||||
loadGameSpecificSettings();
|
||||
// Reload the BIOS in case a game-specific region is set
|
||||
naomi_cart_LoadBios(path);
|
||||
|
@ -641,7 +639,8 @@ bool dc_loadstate(const void **data, u32 size)
|
|||
|
||||
void Emulator::setNetworkState(bool online)
|
||||
{
|
||||
DEBUG_LOG(NETWORK, "Network state %d", online);
|
||||
if (settings.online != online)
|
||||
DEBUG_LOG(NETWORK, "Network state %d", online);
|
||||
settings.online = online;
|
||||
settings.input.fastForwardMode &= !online;
|
||||
}
|
||||
|
|
|
@ -25,25 +25,19 @@
|
|||
#include <vector>
|
||||
#include <future>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
void loadGameSpecificSettings();
|
||||
void SaveSettings();
|
||||
|
||||
extern std::atomic<bool> loading_canceled;
|
||||
|
||||
int flycast_init(int argc, char* argv[]);
|
||||
void dc_reset(bool hard);
|
||||
void dc_term();
|
||||
void flycast_term();
|
||||
void dc_exit();
|
||||
void dc_savestate(int index = 0);
|
||||
void dc_loadstate(int index = 0);
|
||||
bool dc_loadstate(const void **data, unsigned size);
|
||||
|
||||
void dc_load_game(const std::string& path);
|
||||
bool dc_is_load_done();
|
||||
void dc_cancel_load();
|
||||
void dc_get_load_status();
|
||||
|
||||
enum class Event {
|
||||
Start,
|
||||
Pause,
|
||||
|
@ -80,6 +74,19 @@ private:
|
|||
std::map<Event, std::vector<Callback>> callbacks;
|
||||
};
|
||||
|
||||
struct LoadProgress
|
||||
{
|
||||
void reset()
|
||||
{
|
||||
cancelled = false;
|
||||
label = nullptr;
|
||||
progress = 0.f;
|
||||
}
|
||||
std::atomic<bool> cancelled;
|
||||
std::atomic<const char *> label;
|
||||
std::atomic<float> progress;
|
||||
};
|
||||
|
||||
class Emulator
|
||||
{
|
||||
public:
|
||||
|
@ -96,7 +103,7 @@ public:
|
|||
* May throw if the game cannot be loaded.
|
||||
* If a game is already loaded, or the emulator is in the error state, unloadGame() must be called first.
|
||||
*/
|
||||
void loadGame(const char *path);
|
||||
void loadGame(const char *path, LoadProgress *progress = nullptr);
|
||||
/**
|
||||
* Reset the emulator in order to load another game. After calling this method, only loadGame() and term() can be called.
|
||||
* Does nothing if no game is loaded.
|
||||
|
|
|
@ -333,7 +333,7 @@ u16 AWCartridge::decrypt(u16 cipherText, u32 address, const u8 key)
|
|||
}
|
||||
|
||||
|
||||
void AWCartridge::Init()
|
||||
void AWCartridge::Init(LoadProgress *progress)
|
||||
{
|
||||
mpr_offset = decrypt16(0x58/2) | (decrypt16(0x5a/2) << 16);
|
||||
INFO_LOG(NAOMI, "AWCartridge::SetKey rombd_key %02x mpr_offset %08x", rombd_key, mpr_offset);
|
||||
|
|
|
@ -19,7 +19,7 @@ class AWCartridge: public Cartridge
|
|||
public:
|
||||
AWCartridge(u32 size) : Cartridge(size) {}
|
||||
|
||||
void Init() override;
|
||||
void Init(LoadProgress *progress = nullptr) override;
|
||||
u32 ReadMem(u32 address, u32 size) override;
|
||||
void WriteMem(u32 address, u32 data, u32 size) override;
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "gdcartridge.h"
|
||||
#include "stdclass.h"
|
||||
#include "emulator.h"
|
||||
#include "rend/gui.h"
|
||||
|
||||
/*
|
||||
|
||||
|
@ -436,12 +435,12 @@ void GDCartridge::find_file(const char *name, const u8 *dir_sector, u32 &file_st
|
|||
}
|
||||
}
|
||||
|
||||
void GDCartridge::read_gdrom(Disc *gdrom, u32 sector, u8* dst, u32 count)
|
||||
void GDCartridge::read_gdrom(Disc *gdrom, u32 sector, u8* dst, u32 count, LoadProgress *progress)
|
||||
{
|
||||
gdrom->ReadSectors(sector + 150, count, dst, 2048);
|
||||
gdrom->ReadSectors(sector + 150, count, dst, 2048, progress);
|
||||
}
|
||||
|
||||
void GDCartridge::device_start()
|
||||
void GDCartridge::device_start(LoadProgress *progress)
|
||||
{
|
||||
if (dimm_data != NULL)
|
||||
{
|
||||
|
@ -494,15 +493,15 @@ void GDCartridge::device_start()
|
|||
|
||||
u8 buffer[2048];
|
||||
std::string gdrom_path = get_game_basename() + "/" + gdrom_name;
|
||||
Disc *gdrom = OpenDisc(gdrom_path + ".chd");
|
||||
std::unique_ptr<Disc> gdrom = std::unique_ptr<Disc>(OpenDisc(gdrom_path + ".chd"));
|
||||
if (gdrom == nullptr)
|
||||
gdrom = OpenDisc(gdrom_path + ".gdi");
|
||||
gdrom = std::unique_ptr<Disc>(OpenDisc(gdrom_path + ".gdi"));
|
||||
if (gdrom_parent_name != nullptr && gdrom == nullptr)
|
||||
{
|
||||
std::string gdrom_parent_path = get_game_dir() + "/" + gdrom_parent_name + "/" + gdrom_name;
|
||||
gdrom = OpenDisc(gdrom_parent_path + ".chd");
|
||||
gdrom = std::unique_ptr<Disc>(OpenDisc(gdrom_parent_path + ".chd"));
|
||||
if (gdrom == nullptr)
|
||||
gdrom = OpenDisc(gdrom_parent_path + ".gdi");
|
||||
gdrom = std::unique_ptr<Disc>(OpenDisc(gdrom_parent_path + ".gdi"));
|
||||
}
|
||||
if (gdrom == nullptr)
|
||||
throw NaomiCartException("Naomi GDROM: Cannot open " + gdrom_path + ".chd or " + gdrom_path + ".gdi");
|
||||
|
@ -510,13 +509,13 @@ void GDCartridge::device_start()
|
|||
// primary volume descriptor
|
||||
// read frame 0xb06e (frame=sector+150)
|
||||
// dimm board firmware starts straight from this frame
|
||||
read_gdrom(gdrom, (netpic ? 0 : 45000) + 16, buffer);
|
||||
read_gdrom(gdrom.get(), (netpic ? 0 : 45000) + 16, buffer);
|
||||
u32 path_table = ((buffer[0x8c+0] << 0) |
|
||||
(buffer[0x8c+1] << 8) |
|
||||
(buffer[0x8c+2] << 16) |
|
||||
(buffer[0x8c+3] << 24));
|
||||
// path table
|
||||
read_gdrom(gdrom, path_table, buffer);
|
||||
read_gdrom(gdrom.get(), path_table, buffer);
|
||||
|
||||
// directory
|
||||
u8 dir_sector[2048];
|
||||
|
@ -529,12 +528,12 @@ void GDCartridge::device_start()
|
|||
(buffer[0x2 + 2] << 16) |
|
||||
(buffer[0x2 + 3] << 24));
|
||||
|
||||
read_gdrom(gdrom, dir, dir_sector);
|
||||
read_gdrom(gdrom.get(), dir, dir_sector);
|
||||
find_file(name, dir_sector, file_start, file_size);
|
||||
|
||||
if (file_start && (file_size == 0x100)) {
|
||||
// read file
|
||||
read_gdrom(gdrom, file_start, buffer);
|
||||
read_gdrom(gdrom.get(), file_start, buffer);
|
||||
// get "rom" file name
|
||||
memset(name, '\0', 128);
|
||||
memcpy(name, buffer + 0xc0, FILENAME_LENGTH - 1);
|
||||
|
@ -550,7 +549,7 @@ void GDCartridge::device_start()
|
|||
(buffer[i + 4] << 16) |
|
||||
(buffer[i + 5] << 24));
|
||||
memcpy(name, "ROM.BIN", 7);
|
||||
read_gdrom(gdrom, dir, dir_sector);
|
||||
read_gdrom(gdrom.get(), dir, dir_sector);
|
||||
break;
|
||||
}
|
||||
i += buffer[i] + 8 + (buffer[i] & 1);
|
||||
|
@ -570,31 +569,25 @@ void GDCartridge::device_start()
|
|||
|
||||
// read encrypted data into dimm_data
|
||||
u32 sectors = file_rounded_size / 2048;
|
||||
read_gdrom(gdrom, file_start, dimm_data, sectors);
|
||||
read_gdrom(gdrom.get(), file_start, dimm_data, sectors, progress);
|
||||
|
||||
// decrypt loaded data
|
||||
u32 des_subkeys[32];
|
||||
des_generate_subkeys(rev64(key), des_subkeys);
|
||||
|
||||
u32 progress = ~0;
|
||||
for (u32 i = 0; i < file_rounded_size; i += 8)
|
||||
{
|
||||
const u32 new_progress = (u32)(((u64)i + 8) * 100 / file_rounded_size);
|
||||
if (progress != new_progress)
|
||||
if (progress != nullptr)
|
||||
{
|
||||
if (loading_canceled)
|
||||
break;
|
||||
progress = new_progress;
|
||||
char status_str[16];
|
||||
sprintf(status_str, "Decrypting %d%%", progress);
|
||||
gui_display_notification(status_str, 2000);
|
||||
if (progress->cancelled)
|
||||
throw LoadCancelledException();
|
||||
progress->label = "Decrypting...";
|
||||
progress->progress = (float)(i + 8) / file_rounded_size;
|
||||
}
|
||||
*(u64 *)(dimm_data + i) = des_encrypt_decrypt<true>(*(u64 *)(dimm_data + i), des_subkeys);
|
||||
}
|
||||
}
|
||||
|
||||
delete gdrom;
|
||||
|
||||
if (!dimm_data)
|
||||
throw NaomiCartException("Naomi GDROM: Could not find the file to decrypt.");
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@ public:
|
|||
{
|
||||
free(dimm_data);
|
||||
}
|
||||
void Init() override
|
||||
void Init(LoadProgress *progress = nullptr) override
|
||||
{
|
||||
device_start();
|
||||
device_start(progress);
|
||||
device_reset();
|
||||
}
|
||||
void* GetDmaPtr(u32 &size) override;
|
||||
|
@ -61,7 +61,7 @@ private:
|
|||
static const u32 DES_MASK_TABLE[];
|
||||
static const u8 DES_ROTATE_TABLE[16];
|
||||
|
||||
void device_start();
|
||||
void device_start(LoadProgress *progress);
|
||||
void device_reset();
|
||||
void find_file(const char *name, const u8 *dir_sector, u32 &file_start, u32 &file_size);
|
||||
|
||||
|
@ -70,7 +70,7 @@ private:
|
|||
template<bool decrypt>
|
||||
u64 des_encrypt_decrypt(u64 src, const u32 *des_subkeys);
|
||||
u64 rev64(u64 src);
|
||||
void read_gdrom(Disc *gdrom, u32 sector, u8* dst, u32 count = 1);
|
||||
void read_gdrom(Disc *gdrom, u32 sector, u8* dst, u32 count = 1, LoadProgress *progress = nullptr);
|
||||
};
|
||||
|
||||
#endif /* CORE_HW_NAOMI_GDCARTRIDGE_H_ */
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
M4Cartridge(u32 size) : NaomiCartridge(size) { }
|
||||
~M4Cartridge() override;
|
||||
|
||||
void Init() override
|
||||
void Init(LoadProgress *progress = nullptr) override
|
||||
{
|
||||
device_start();
|
||||
device_reset();
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include "archive/archive.h"
|
||||
#include "stdclass.h"
|
||||
#include "emulator.h"
|
||||
#include "rend/gui.h"
|
||||
#include "cfg/option.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
|
@ -197,7 +196,7 @@ void naomi_cart_LoadBios(const char *filename)
|
|||
bios_loaded = true;
|
||||
}
|
||||
|
||||
static void naomi_cart_LoadZip(const char *filename)
|
||||
static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
|
||||
{
|
||||
Game *game = FindGame(filename);
|
||||
if (game == NULL)
|
||||
|
@ -257,12 +256,22 @@ static void naomi_cart_LoadZip(const char *filename)
|
|||
CurrentCartridge->SetKey(game->key);
|
||||
NaomiGameInputs = game->inputs;
|
||||
|
||||
for (int romid = 0; game->blobs[romid].filename != NULL && !loading_canceled; romid++)
|
||||
int romCount = 0;
|
||||
while (game->blobs[romCount].filename != nullptr)
|
||||
romCount++;
|
||||
for (int romid = 0; romid < romCount; romid++)
|
||||
{
|
||||
if (game->cart_type != GD)
|
||||
if (progress != nullptr)
|
||||
{
|
||||
std::string progress = "ROM " + std::to_string(romid + 1);
|
||||
gui_display_notification(progress.c_str(), 1000);
|
||||
if (progress->cancelled)
|
||||
throw LoadCancelledException();
|
||||
if (game->cart_type != GD)
|
||||
{
|
||||
static std::string label;
|
||||
label = "ROM " + std::to_string(romid + 1);
|
||||
progress->label = label.c_str();
|
||||
progress->progress = (float)(romid + 1) / romCount;
|
||||
}
|
||||
}
|
||||
|
||||
u32 len = game->blobs[romid].length;
|
||||
|
@ -350,31 +359,26 @@ static void naomi_cart_LoadZip(const char *filename)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (loading_canceled)
|
||||
return;
|
||||
if (naomi_default_eeprom == NULL && game->eeprom_dump != NULL)
|
||||
naomi_default_eeprom = game->eeprom_dump;
|
||||
if (game->rotation_flag == ROT270)
|
||||
config::Rotate90.override(true);
|
||||
|
||||
CurrentCartridge->Init();
|
||||
if (loading_canceled)
|
||||
return;
|
||||
CurrentCartridge->Init(progress);
|
||||
|
||||
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
|
||||
if (naomi_game_id[0] == '\0')
|
||||
strcpy(naomi_game_id, game->name);
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
|
||||
|
||||
} catch (const FlycastException& ex) {
|
||||
} catch (...) {
|
||||
delete CurrentCartridge;
|
||||
CurrentCartridge = NULL;
|
||||
|
||||
throw ex;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void naomi_cart_LoadRom(const char* file)
|
||||
void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
||||
{
|
||||
naomi_cart_Close();
|
||||
|
||||
|
@ -382,7 +386,7 @@ void naomi_cart_LoadRom(const char* file)
|
|||
|
||||
if (extension == "zip" || extension == "7z")
|
||||
{
|
||||
naomi_cart_LoadZip(file);
|
||||
naomi_cart_LoadZip(file, progress);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -609,6 +613,11 @@ std::string Cartridge::GetGameId() {
|
|||
}
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
if (RomSize < 0x138)
|
||||
printf("GAME EEPROM ID: (ROM too small)\n");
|
||||
else
|
||||
printf("GAME EEPROM ID: %c%c%c%c\n", RomPtr[0x134], RomPtr[0x135], RomPtr[0x136], RomPtr[0x137]);
|
||||
|
||||
return game_id;
|
||||
}
|
||||
|
||||
|
@ -918,6 +927,10 @@ std::string M2Cartridge::GetGameId()
|
|||
game_id = std::string((char *)RomPtr + 0x800030, 0x20);
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
if (RomSize < 0x800138)
|
||||
printf("m2 GAME EEPROM ID: (ROM too small)\n");
|
||||
else
|
||||
printf("m2 GAME EEPROM ID: %c%c%c%c\n", RomPtr[0x800134], RomPtr[0x800135], RomPtr[0x800136], RomPtr[0x800137]);
|
||||
}
|
||||
return game_id;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <algorithm>
|
||||
#include <string>
|
||||
#include "types.h"
|
||||
#include "emulator.h"
|
||||
|
||||
class Cartridge
|
||||
{
|
||||
|
@ -10,7 +11,7 @@ public:
|
|||
Cartridge(u32 size);
|
||||
virtual ~Cartridge();
|
||||
|
||||
virtual void Init() {}
|
||||
virtual void Init(LoadProgress *progress = nullptr) {}
|
||||
virtual u32 ReadMem(u32 address, u32 size) = 0;
|
||||
virtual void WriteMem(u32 address, u32 data, u32 size) = 0;
|
||||
|
||||
|
@ -83,7 +84,7 @@ public:
|
|||
NaomiCartException(const std::string& reason) : FlycastException(reason) {}
|
||||
};
|
||||
|
||||
void naomi_cart_LoadRom(const char* file);
|
||||
void naomi_cart_LoadRom(const char* file, LoadProgress *progress);
|
||||
void naomi_cart_Close();
|
||||
int naomi_cart_GetPlatform(const char *path);
|
||||
void naomi_cart_LoadBios(const char *filename);
|
||||
|
|
|
@ -275,28 +275,20 @@ DiscType GuessDiscType(bool m1, bool m2, bool da)
|
|||
return CdRom;
|
||||
}
|
||||
|
||||
void Disc::ReadSectors(u32 FAD, u32 count, u8* dst, u32 fmt)
|
||||
void Disc::ReadSectors(u32 FAD, u32 count, u8* dst, u32 fmt, LoadProgress *progress)
|
||||
{
|
||||
u8 temp[2448];
|
||||
SectorFormat secfmt;
|
||||
SubcodeFormat subfmt;
|
||||
|
||||
u32 progress = ~0;
|
||||
for (u32 i = 1; i <= count; i++)
|
||||
{
|
||||
if (count >= 1000)
|
||||
if (progress != nullptr)
|
||||
{
|
||||
if (loading_canceled)
|
||||
break;
|
||||
// Progress report when loading naomi gd-rom games
|
||||
const u32 new_progress = i * 100 / count;
|
||||
if (progress != new_progress)
|
||||
{
|
||||
progress = new_progress;
|
||||
char status_str[16];
|
||||
sprintf(status_str, "%d%%", progress);
|
||||
gui_display_notification(status_str, 2000);
|
||||
}
|
||||
if (progress->cancelled)
|
||||
throw LoadCancelledException();
|
||||
progress->label = "Loading...";
|
||||
progress->progress = (float)i / count;
|
||||
}
|
||||
if (ReadSector(FAD,temp,&secfmt,q_subchannel,&subfmt))
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "emulator.h"
|
||||
#include "hw/gdrom/gdrom_if.h"
|
||||
#include "rend/gui.h"
|
||||
|
||||
/*
|
||||
Mode2 Subheader:
|
||||
|
@ -119,7 +118,7 @@ struct Disc
|
|||
return false;
|
||||
}
|
||||
|
||||
void ReadSectors(u32 FAD,u32 count,u8* dst,u32 fmt);
|
||||
void ReadSectors(u32 FAD, u32 count, u8 *dst, u32 fmt, LoadProgress *progress = nullptr);
|
||||
|
||||
virtual ~Disc()
|
||||
{
|
||||
|
|
|
@ -391,7 +391,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
mainui_loop();
|
||||
|
||||
emu.term();
|
||||
flycast_term();
|
||||
|
||||
os_UninstallFaultHandler();
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#ifndef LIBRETRO
|
||||
#include "types.h"
|
||||
#include <future>
|
||||
|
||||
#include "emulator.h"
|
||||
#include "hw/mem/_vmem.h"
|
||||
#include "cfg/cfg.h"
|
||||
|
@ -9,14 +7,11 @@
|
|||
#include "log/LogManager.h"
|
||||
#include "rend/gui.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "hw/sh4/sh4_if.h"
|
||||
#include "debug/gdb_server.h"
|
||||
#include "archive/rzip.h"
|
||||
#include "rend/mainui.h"
|
||||
#include "input/gamepad_device.h"
|
||||
|
||||
static std::future<void> loadingDone;
|
||||
|
||||
int flycast_init(int argc, char* argv[])
|
||||
{
|
||||
#if defined(TEST_AUTOMATION)
|
||||
|
@ -58,7 +53,7 @@ int flycast_init(int argc, char* argv[])
|
|||
|
||||
void dc_exit()
|
||||
{
|
||||
emu.term();
|
||||
emu.stop();
|
||||
mainui_stop();
|
||||
}
|
||||
|
||||
|
@ -73,11 +68,10 @@ void SaveSettings()
|
|||
#endif
|
||||
}
|
||||
|
||||
void dc_term()
|
||||
void flycast_term()
|
||||
{
|
||||
dc_cancel_load();
|
||||
gui_cancel_load();
|
||||
emu.term();
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
void dc_savestate(int index)
|
||||
|
@ -215,38 +209,4 @@ void dc_loadstate(int index)
|
|||
INFO_LOG(SAVESTATE, "Loaded state from %s size %d", filename.c_str(), total_size) ;
|
||||
}
|
||||
|
||||
void dc_load_game(const std::string& path)
|
||||
{
|
||||
loading_canceled = false;
|
||||
|
||||
loadingDone = std::async(std::launch::async, [path] {
|
||||
emu.loadGame(path.c_str());
|
||||
});
|
||||
}
|
||||
|
||||
bool dc_is_load_done()
|
||||
{
|
||||
if (!loadingDone.valid())
|
||||
return true;
|
||||
if (loadingDone.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void dc_cancel_load()
|
||||
{
|
||||
if (loadingDone.valid())
|
||||
{
|
||||
loading_canceled = true;
|
||||
loadingDone.get();
|
||||
}
|
||||
settings.content.path.clear();
|
||||
}
|
||||
|
||||
void dc_get_load_status()
|
||||
{
|
||||
if (loadingDone.valid())
|
||||
loadingDone.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ bool DXContext::Init(bool keepCurrentWindow)
|
|||
void DXContext::Term()
|
||||
{
|
||||
overlay.term();
|
||||
gui_term();
|
||||
ImGui_ImplDX9_Shutdown();
|
||||
pDevice.reset();
|
||||
pD3D.reset();
|
||||
|
|
|
@ -69,6 +69,7 @@ static void term_vmus();
|
|||
static void displayCrosshairs();
|
||||
|
||||
GameScanner scanner;
|
||||
static BackgroundGameLoader gameLoader;
|
||||
|
||||
static void emuEventCallback(Event event)
|
||||
{
|
||||
|
@ -409,7 +410,7 @@ void gui_open_settings()
|
|||
}
|
||||
else if (gui_state == GuiState::Loading)
|
||||
{
|
||||
dc_cancel_load();
|
||||
gameLoader.cancel();
|
||||
gui_state = GuiState::Main;
|
||||
}
|
||||
else if (gui_state == GuiState::Commands)
|
||||
|
@ -427,7 +428,7 @@ void gui_start_game(const std::string& path)
|
|||
|
||||
scanner.stop();
|
||||
gui_state = GuiState::Loading;
|
||||
dc_load_game(path);
|
||||
gameLoader.load(path);
|
||||
}
|
||||
|
||||
void gui_stop_game(const std::string& message)
|
||||
|
@ -2076,10 +2077,7 @@ static void gui_display_content()
|
|||
|
||||
ImGui::PushID("bios");
|
||||
if (ImGui::Selectable("Dreamcast BIOS"))
|
||||
{
|
||||
gui_state = GuiState::Closed;
|
||||
gui_start_game("");
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
{
|
||||
|
@ -2113,7 +2111,6 @@ static void gui_display_content()
|
|||
{
|
||||
std::string gamePath(game.path);
|
||||
scanner.get_mutex().unlock();
|
||||
gui_state = GuiState::Closed;
|
||||
gui_start_game(gamePath);
|
||||
scanner.get_mutex().lock();
|
||||
ImGui::PopID();
|
||||
|
@ -2197,7 +2194,7 @@ static void gui_network_start()
|
|||
if (networkStatus.get())
|
||||
{
|
||||
gui_state = GuiState::Closed;
|
||||
ImGui::Text("STARTING...");
|
||||
ImGui::Text("Starting...");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2213,7 +2210,7 @@ static void gui_network_start()
|
|||
}
|
||||
else
|
||||
{
|
||||
ImGui::Text("STARTING NETWORK...");
|
||||
ImGui::Text("Starting Network...");
|
||||
if (NetworkHandshake::instance->canStartNow())
|
||||
ImGui::Text("Press Start to start the game now.");
|
||||
}
|
||||
|
@ -2250,10 +2247,9 @@ static void gui_display_loadscreen()
|
|||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20 * scaling, 10 * scaling));
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::SetCursorPosX(20.f * scaling);
|
||||
if (dc_is_load_done())
|
||||
{
|
||||
try {
|
||||
dc_get_load_status();
|
||||
try {
|
||||
if (gameLoader.ready())
|
||||
{
|
||||
if (NetworkHandshake::instance != nullptr)
|
||||
{
|
||||
networkStatus = NetworkHandshake::instance->start();
|
||||
|
@ -2262,32 +2258,36 @@ static void gui_display_loadscreen()
|
|||
else
|
||||
{
|
||||
gui_state = GuiState::Closed;
|
||||
ImGui::Text("STARTING...");
|
||||
ImGui::Text("Starting...");
|
||||
}
|
||||
} catch (const FlycastException& ex) {
|
||||
ERROR_LOG(BOOT, "%s", ex.what());
|
||||
error_msg = ex.what();
|
||||
#ifdef TEST_AUTOMATION
|
||||
die("Game load failed");
|
||||
#endif
|
||||
emu.unloadGame();
|
||||
gui_state = GuiState::Main;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Text("LOADING... ");
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", get_notification().c_str());
|
||||
|
||||
float currentwidth = ImGui::GetContentRegionAvail().x;
|
||||
ImGui::SetCursorPosX((currentwidth - 100.f * scaling) / 2.f + ImGui::GetStyle().WindowPadding.x);
|
||||
ImGui::SetCursorPosY(126.f * scaling);
|
||||
if (ImGui::Button("Cancel", ImVec2(100.f * scaling, 0.f)))
|
||||
else
|
||||
{
|
||||
dc_cancel_load();
|
||||
gui_state = GuiState::Main;
|
||||
const char *label = gameLoader.getProgress().label;
|
||||
if (label == nullptr)
|
||||
label = "Loading...";
|
||||
ImGui::Text("%s", label);
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.557f, 0.268f, 0.965f, 1.f));
|
||||
ImGui::ProgressBar(gameLoader.getProgress().progress, ImVec2(-1, 20.f * scaling), "");
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
float currentwidth = ImGui::GetContentRegionAvail().x;
|
||||
ImGui::SetCursorPosX((currentwidth - 100.f * scaling) / 2.f + ImGui::GetStyle().WindowPadding.x);
|
||||
ImGui::SetCursorPosY(126.f * scaling);
|
||||
if (ImGui::Button("Cancel", ImVec2(100.f * scaling, 0.f)))
|
||||
{
|
||||
gameLoader.cancel();
|
||||
gui_state = GuiState::Main;
|
||||
}
|
||||
}
|
||||
} catch (const FlycastException& ex) {
|
||||
ERROR_LOG(BOOT, "%s", ex.what());
|
||||
error_msg = ex.what();
|
||||
#ifdef TEST_AUTOMATION
|
||||
die("Game load failed");
|
||||
#endif
|
||||
emu.unloadGame();
|
||||
gui_state = GuiState::Main;
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
|
@ -2426,6 +2426,11 @@ void gui_open_onboarding()
|
|||
gui_state = GuiState::Onboarding;
|
||||
}
|
||||
|
||||
void gui_cancel_load()
|
||||
{
|
||||
gameLoader.cancel();
|
||||
}
|
||||
|
||||
void gui_term()
|
||||
{
|
||||
if (inited)
|
||||
|
@ -2436,6 +2441,8 @@ void gui_term()
|
|||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
EventManager::unlisten(Event::Resume, emuEventCallback);
|
||||
EventManager::unlisten(Event::Start, emuEventCallback);
|
||||
EventManager::unlisten(Event::Terminate, emuEventCallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ void gui_display_notification(const char *msg, int duration);
|
|||
void gui_display_osd();
|
||||
void gui_open_onboarding();
|
||||
void gui_term();
|
||||
void gui_cancel_load();
|
||||
void gui_refresh_files();
|
||||
void gui_cheats();
|
||||
void gui_keyboard_input(u16 wc);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "vulkan/vulkan_context.h"
|
||||
#include "dx9/dxcontext.h"
|
||||
#include "gui.h"
|
||||
#include "emulator.h"
|
||||
|
||||
typedef void (*StringCallback)(bool cancelled, std::string selection);
|
||||
|
||||
|
@ -82,3 +83,46 @@ static inline bool operator!=(const ImVec2& l, const ImVec2& r)
|
|||
|
||||
void fullScreenWindow(bool modal);
|
||||
void windowDragScroll();
|
||||
|
||||
class BackgroundGameLoader
|
||||
{
|
||||
public:
|
||||
void load(const std::string& path)
|
||||
{
|
||||
progress.reset();
|
||||
future = std::async(std::launch::async, [this, path] {
|
||||
emu.loadGame(path.c_str(), &progress);
|
||||
});
|
||||
}
|
||||
|
||||
void cancel()
|
||||
{
|
||||
progress.cancelled = true;
|
||||
if (future.valid())
|
||||
try {
|
||||
future.get();
|
||||
} catch (const FlycastException& e) {
|
||||
}
|
||||
emu.unloadGame();
|
||||
}
|
||||
|
||||
bool ready()
|
||||
{
|
||||
if (!future.valid())
|
||||
return true;
|
||||
if (future.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
|
||||
{
|
||||
future.get();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const LoadProgress& getProgress() const {
|
||||
return progress;
|
||||
}
|
||||
|
||||
private:
|
||||
LoadProgress progress;
|
||||
std::future<void> future;
|
||||
};
|
||||
|
|
|
@ -453,6 +453,12 @@ public:
|
|||
FlycastException(const std::string& reason) : std::runtime_error(reason) {}
|
||||
};
|
||||
|
||||
class LoadCancelledException : public FlycastException
|
||||
{
|
||||
public:
|
||||
LoadCancelledException() : FlycastException("") {}
|
||||
};
|
||||
|
||||
enum serialize_version_enum {
|
||||
V1,
|
||||
V2,
|
||||
|
|
|
@ -758,7 +758,7 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
|||
|
||||
mainui_loop();
|
||||
|
||||
emu.term();
|
||||
flycast_term();
|
||||
|
||||
os_UninstallFaultHandler();
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ static bool emulatorRunning;
|
|||
- (void)applicationWillTerminate:(UIApplication *)application
|
||||
{
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
dc_term();
|
||||
flycast_term();
|
||||
LogManager::Shutdown();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
emu_dc_term()
|
||||
emu_flycast_term()
|
||||
}
|
||||
|
||||
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||
|
|
|
@ -71,7 +71,7 @@ class EmuGLView: NSOpenGLView, NSWindowDelegate {
|
|||
let rect = convertToBacking(frame)
|
||||
emu_gles_init(Int32(rect.width), Int32(rect.height))
|
||||
|
||||
if (emu_reicast_init() != 0) {
|
||||
if (emu_flycast_init() != 0) {
|
||||
let alert = NSAlert()
|
||||
alert.alertStyle = .critical
|
||||
alert.messageText = "Flycast initialization failed"
|
||||
|
|
|
@ -14,15 +14,14 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void emu_dc_exit();
|
||||
void emu_dc_term();
|
||||
void emu_flycast_term();
|
||||
void emu_gui_open_settings();
|
||||
bool emu_renderer_enabled();
|
||||
bool emu_fast_forward();
|
||||
bool emu_vsync_enabled();
|
||||
bool emu_single_frame(int w, int h);
|
||||
void emu_gles_init(int width, int height);
|
||||
int emu_reicast_init();
|
||||
int emu_flycast_init();
|
||||
void emu_key_input(UInt16 keyCode, bool pressed, UInt32 modifierFlags);
|
||||
void emu_character_input(const char *characters);
|
||||
void emu_mouse_buttons(int button, bool pressed);
|
||||
|
|
|
@ -90,16 +90,9 @@ void os_SetupInput()
|
|||
|
||||
void common_linux_setup();
|
||||
|
||||
void emu_dc_exit()
|
||||
void emu_flycast_term()
|
||||
{
|
||||
dc_exit();
|
||||
}
|
||||
|
||||
void emu_dc_term()
|
||||
{
|
||||
if (emu.running())
|
||||
dc_exit();
|
||||
dc_term();
|
||||
flycast_term();
|
||||
LogManager::Shutdown();
|
||||
}
|
||||
|
||||
|
@ -238,7 +231,7 @@ void emu_gles_init(int width, int height)
|
|||
mainui_enabled = true;
|
||||
}
|
||||
|
||||
int emu_reicast_init()
|
||||
int emu_flycast_init()
|
||||
{
|
||||
LogManager::Init();
|
||||
common_linux_setup();
|
||||
|
|
|
@ -125,7 +125,6 @@ static double vib_delta[4];
|
|||
unsigned per_content_vmus = 0;
|
||||
|
||||
static bool first_run = true;
|
||||
static bool mute_messages;
|
||||
static bool rotate_screen;
|
||||
static bool rotate_game;
|
||||
static int framebufferWidth;
|
||||
|
@ -151,6 +150,7 @@ static void refresh_devices(bool first_startup);
|
|||
static void init_disk_control_interface();
|
||||
static bool read_m3u(const char *file);
|
||||
void UpdateInputState();
|
||||
void gui_display_notification(const char *msg, int duration);
|
||||
|
||||
static std::string game_data;
|
||||
static char g_base_name[128];
|
||||
|
@ -867,16 +867,13 @@ void retro_run()
|
|||
|
||||
static bool loadGame()
|
||||
{
|
||||
mute_messages = true;
|
||||
try {
|
||||
emu.loadGame(game_data.c_str());
|
||||
} catch (const FlycastException& e) {
|
||||
ERROR_LOG(BOOT, "%s", e.what());
|
||||
mute_messages = false;
|
||||
gui_display_notification(e.what(), 5000);
|
||||
return false;
|
||||
}
|
||||
mute_messages = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2923,8 +2920,6 @@ static bool read_m3u(const char *file)
|
|||
|
||||
void gui_display_notification(const char *msg, int duration)
|
||||
{
|
||||
if (mute_messages)
|
||||
return;
|
||||
retro_message retromsg;
|
||||
retromsg.msg = msg;
|
||||
retromsg.frames = duration / 17;
|
||||
|
|
Loading…
Reference in New Issue