Use exception when load content fails. ui: graceful stop on fatal error

libretro: catch/detect fatal errors and shutdown
This commit is contained in:
Flyinghead 2021-08-03 10:05:09 +02:00
parent 2dd7717128
commit 951e70328f
13 changed files with 197 additions and 189 deletions

View File

@ -13,7 +13,7 @@ TA_context* read_frame(const char* file, u8* vram_ref = NULL);
void rend_set_fb_scale(float x,float y);
#ifdef TARGET_DISPFRAME
void *dc_run(void*)
void dc_run()
{
struct sigaction act, segv_oact;
memset(&act, 0, sizeof(act));
@ -58,6 +58,5 @@ void *dc_run(void*)
os_DoEvents();
}
return nullptr;
}
#endif

View File

@ -42,8 +42,10 @@ extern int screen_width, screen_height;
std::atomic<bool> loading_canceled;
settings_t settings;
static cThread emuThread(&dc_run, nullptr);
static void *dc_run_thread(void *);
static cThread emuThread(&dc_run_thread, nullptr);
static bool initDone;
static std::string lastError;
static s32 devicesInit()
{
@ -521,11 +523,27 @@ bool dc_is_running()
return sh4_cpu.IsCpuRunning();
}
#ifndef TARGET_DISPFRAME
void* dc_run(void*)
static void *dc_run_thread(void*)
{
InitAudio();
try {
dc_run();
} catch (const FlycastException& e) {
ERROR_LOG(COMMON, "%s", e.what());
sh4_cpu.Stop();
lastError = e.what();
}
TermAudio();
return nullptr;
}
#ifndef TARGET_DISPFRAME
void dc_run()
{
#if FEAT_SHREC != DYNAREC_NONE
if (config::DynarecEnabled)
{
@ -557,10 +575,6 @@ void* dc_run(void*)
}
} while (resetRequested);
}
TermAudio();
return NULL;
}
#endif
@ -583,8 +597,6 @@ void dc_term_emulator()
dc_term_game();
debugger::term();
sh4_cpu.Term();
if (settings.platform.system != DC_PLATFORM_DREAMCAST)
naomi_cart_Close();
custom_texture.Terminate(); // lr: avoid deadlock on exit (win32)
devicesTerm();
mem_Term();
@ -711,6 +723,13 @@ bool dc_loadstate(const void **data, u32 size)
return true;
}
std::string dc_get_last_error()
{
std::string error(lastError);
lastError.clear();
return error;
}
EventManager EventManager::Instance;
void EventManager::registerEvent(Event event, Callback callback)

View File

@ -31,7 +31,7 @@ extern std::atomic<bool> loading_canceled;
int flycast_init(int argc, char* argv[]);
void dc_reset(bool hard);
void dc_init();
void* dc_run(void*);
void dc_run();
void dc_term();
void dc_stop();
void dc_term_game();
@ -50,6 +50,7 @@ void dc_cancel_load();
void dc_get_load_status();
bool dc_is_running();
void dc_resize_renderer();
std::string dc_get_last_error();
enum class Event {
Start,

View File

@ -1,25 +1,24 @@
#include "common.h"
#include "stdclass.h"
#include "deps/chdpsr/cdipsr.h"
Disc* cdi_parse(const char* file)
{
// Only try to open .cdi files
size_t len = strlen(file);
if (len > 4 && stricmp( &file[len - 4], ".cdi"))
if (get_file_extension(file) != "cdi")
return nullptr;
FILE *fsource = nowide::fopen(file, "rb");
if (!fsource)
return nullptr;
if (fsource == nullptr)
throw FlycastException(std::string("Cannot open CDI file ") + file);
image_s image = { 0 };
track_s track = { 0 };
if (!CDI_init(fsource, &image, file))
{
std::fclose(fsource);
return nullptr;
throw FlycastException(std::string("Invalid CDI file ") + file);
}
CDI_get_sessions(fsource,&image);
@ -41,8 +40,6 @@ Disc* cdi_parse(const char* file)
image.header_position = std::ftell(fsource);
//printf("\nSession %d has %d track(s)\n",image.global_current_session,image.tracks);
if (image.tracks == 0)
INFO_LOG(GDROM, "Open session");
else
@ -96,8 +93,6 @@ Disc* cdi_parse(const char* file)
if (track.mode==0)
CD_DA=true;
t.ADDR=1;//hmm is that ok ?
t.CTRL=track.mode==0?0:4;
@ -107,55 +102,30 @@ Disc* cdi_parse(const char* file)
rv->tracks.push_back(t);
//printf("\n");
// if (track.pregap_length != 150) printf("Warning! This track seems to have a non-standard pregap...\n");
if (track.length < 0)
WARN_LOG(GDROM, "Negative track size found. You must extract image with /pregap option");
//if (!opts.showinfo)
std::fseek(fsource, track.position, SEEK_SET);
if (track.total_length < track.length + track.pregap_length)
{
if (track.total_length < track.length + track.pregap_length)
{
WARN_LOG(GDROM, "This track seems truncated. Skipping...");
std::fseek(fsource, track.position, SEEK_SET);
std::fseek(fsource, track.total_length, SEEK_CUR);
track.position = std::ftell(fsource);
}
else
{
//printf("Track position: %lu\n",track.position + track.pregap_length * track.sector_size);
std::fseek(fsource, track.position, SEEK_SET);
// fseek(fsource, track->pregap_length * track->sector_size, SEEK_CUR);
// fseek(fsource, track->length * track->sector_size, SEEK_CUR);
std::fseek(fsource, track.total_length * track.sector_size, SEEK_CUR);
//savetrack(fsource, &image, &track, &opts, &flags);
track.position = std::ftell(fsource);
rv->EndFAD=track.start_lba +track.total_length;
// Generate cuesheet entries
//if (flags.create_cuesheet && !(track.mode == 2 && flags.do_convert)) // Do not generate input if converted (obsolete)
// savecuesheet(fcuesheet, &image, &track, &opts, &flags);
}
WARN_LOG(GDROM, "This track seems truncated. Skipping...");
// FIXME that can't be right
std::fseek(fsource, track.total_length, SEEK_CUR);
}
else
{
std::fseek(fsource, track.total_length * track.sector_size, SEEK_CUR);
rv->EndFAD=track.start_lba +track.total_length;
}
track.position = std::ftell(fsource);
std::fseek(fsource, image.header_position, SEEK_SET);
// Close loops
image.remaining_tracks--;
}
//if (flags.create_cuesheet) fclose(fcuesheet);
}
CDI_skip_next_session (fsource, &image);
CDI_skip_next_session(fsource, &image);
image.remaining_sessions--;
}
@ -167,8 +137,6 @@ Disc* cdi_parse(const char* file)
rv->LeadOut.ADDR=0;
rv->LeadOut.CTRL=0;
return rv;
}

View File

@ -1,9 +1,10 @@
#include "common.h"
#include "stdclass.h"
#include <libchdr/chd.h>
/* tracks are padded to a multiple of this many frames */
const uint32_t CD_TRACK_PADDING = 4;
constexpr uint32_t CD_TRACK_PADDING = 4;
struct CHDDisc : Disc
{
@ -15,7 +16,7 @@ struct CHDDisc : Disc
u32 hunkbytes = 0;
u32 sph = 0;
bool TryOpen(const char* file);
void tryOpen(const char* file);
~CHDDisc() override
{
@ -38,20 +39,21 @@ struct CHDTrack : TrackFile
CHDTrack(CHDDisc* disc, u32 StartFAD, s32 Offset, u32 fmt, bool swap_bytes)
{
this->disc=disc;
this->StartFAD=StartFAD;
this->disc = disc;
this->StartFAD = StartFAD;
this->Offset = Offset;
this->fmt=fmt;
this->fmt = fmt;
this->swap_bytes = swap_bytes;
}
void Read(u32 FAD, u8* dst, SectorFormat* sector_type, u8* subcode, SubcodeFormat* subcode_type) override
bool Read(u32 FAD, u8* dst, SectorFormat* sector_type, u8* subcode, SubcodeFormat* subcode_type) override
{
u32 fad_offs = FAD + Offset;
u32 hunk=(fad_offs)/disc->sph;
if (disc->old_hunk!=hunk)
{
chd_read(disc->chd,hunk,disc->hunk_mem); //CHDERR_NONE
if (chd_read(disc->chd,hunk,disc->hunk_mem) != CHDERR_NONE)
return false;
disc->old_hunk = hunk;
}
@ -73,24 +75,21 @@ struct CHDTrack : TrackFile
//While space is reserved for it, the images contain no actual subcodes
//memcpy(subcode,disc->hunk_mem+hunk_ofs*(2352+96)+2352,96);
*subcode_type=SUBFMT_NONE;
return true;
}
};
bool CHDDisc::TryOpen(const char* file)
void CHDDisc::tryOpen(const char* file)
{
fp = nowide::fopen(file, "rb");
if (fp == nullptr)
{
INFO_LOG(GDROM, "chd: fopen failed for file %s: %d", file, errno);
return false;
}
throw FlycastException(std::string("Cannot open CHD file ") + file);
chd_error err = chd_open_file(fp, CHD_OPEN_READ, 0, &chd);
if (err != CHDERR_NONE)
{
INFO_LOG(GDROM, "chd: chd_open_file failed for file %s: %d", file, err);
return false;
}
throw FlycastException(std::string("Invalid CHD file ") + file);
INFO_LOG(GDROM, "chd: parsing file %s", file);
@ -102,11 +101,8 @@ bool CHDDisc::TryOpen(const char* file)
sph = hunkbytes/(2352+96);
if (hunkbytes%(2352+96)!=0)
{
INFO_LOG(GDROM, "chd: hunkbytes is invalid, %d\n",hunkbytes);
return false;
}
if (hunkbytes % (2352 + 96) != 0)
throw FlycastException(std::string("Invalid hunkbytes for CHD file ") + file);
u32 tag;
u8 flags;
@ -156,15 +152,13 @@ bool CHDDisc::TryOpen(const char* file)
|| pregap != 0
|| postgap != 0)
{
INFO_LOG(GDROM, "chd: track type %s is not supported", type);
return false;
throw FlycastException((std::string("chd: track type ") + type) + " is not supported");
}
DEBUG_LOG(GDROM, "%s", temp);
Track t;
t.StartFAD = total_frames;
total_frames += frames;
t.EndFAD = total_frames - 1;
t.ADDR = 0;
t.CTRL = strcmp(type,"AUDIO") == 0 ? 0 : 4;
t.file = new CHDTrack(this, t.StartFAD, Offset - t.StartFAD, strcmp(type, "MODE1") ? 2352 : 2048,
@ -182,25 +176,21 @@ bool CHDDisc::TryOpen(const char* file)
WARN_LOG(GDROM, "WARNING: chd: Total frames is wrong: %u frames (549300 expected) in %zu tracks", total_frames, tracks.size());
FillGDSession();
return true;
}
Disc* chd_parse(const char* file)
{
// Only try to open .chd files
size_t len = strlen(file);
if (len > 4 && stricmp( &file[len - 4], ".chd"))
if (get_file_extension(file) != "chd")
return nullptr;
CHDDisc* rv = new CHDDisc();
if (rv->TryOpen(file))
try {
rv->tryOpen(file);
return rv;
else
{
} catch (...) {
delete rv;
return 0;
throw;
}
}

View File

@ -87,37 +87,29 @@ struct Session
struct TrackFile
{
virtual void Read(u32 FAD,u8* dst,SectorFormat* sector_type,u8* subcode,SubcodeFormat* subcode_type)=0;
virtual ~TrackFile() = default;;
virtual bool Read(u32 FAD, u8 *dst, SectorFormat *sector_type, u8 *subcode, SubcodeFormat *subcode_type) = 0;
virtual ~TrackFile() = default;
};
struct Track
{
TrackFile* file; //handler for actual IO
u32 StartFAD; //Start FAD
u32 EndFAD; //End FAD
u8 CTRL;
u8 ADDR;
TrackFile* file = nullptr; // handler for actual IO
u32 StartFAD = 0; // Start FAD
u32 EndFAD = 0; // End FAD
u8 CTRL = 0;
u8 ADDR = 0;
Track()
bool Read(u32 FAD, u8 *dst, SectorFormat *sector_type, u8 *subcode, SubcodeFormat *subcode_type)
{
file = 0;
StartFAD = 0;
EndFAD = 0;
CTRL = 0;
ADDR = 0;
}
bool Read(u32 FAD,u8* dst,SectorFormat* sector_type,u8* subcode,SubcodeFormat* subcode_type)
{
if (FAD>=StartFAD && (FAD<=EndFAD || EndFAD==0) && file)
{
file->Read(FAD,dst,sector_type,subcode,subcode_type);
return true;
}
if (FAD >= StartFAD && (FAD <= EndFAD || EndFAD == 0) && file != nullptr)
return file->Read(FAD, dst, sector_type, subcode, subcode_type);
else
return false;
}
void Destroy() { delete file; file=0; }
void Destroy() {
delete file;
file = nullptr;
}
};
struct Disc
@ -196,7 +188,7 @@ struct Disc
}
else
{
INFO_LOG(GDROM, "Sector Read miss FAD: %d", FAD);
WARN_LOG(GDROM, "Sector Read miss FAD: %d", FAD);
}
dst+=fmt;
FAD++;
@ -261,18 +253,16 @@ struct RawTrackFile : TrackFile
FILE *file;
s32 offset;
u32 fmt;
bool cleanup;
RawTrackFile(FILE *file, u32 file_offs, u32 first_fad, u32 secfmt)
{
verify(file!=0);
this->file=file;
this->offset=file_offs-first_fad*secfmt;
this->fmt=secfmt;
this->cleanup=true;
verify(file != nullptr);
this->file = file;
this->offset = file_offs - first_fad * secfmt;
this->fmt = secfmt;
}
void Read(u32 FAD,u8* dst,SectorFormat* sector_type,u8* subcode,SubcodeFormat* subcode_type) override
bool Read(u32 FAD,u8* dst,SectorFormat* sector_type,u8* subcode,SubcodeFormat* subcode_type) override
{
//for now hackish
if (fmt==2352)
@ -290,12 +280,16 @@ struct RawTrackFile : TrackFile
std::fseek(file, offset + FAD * fmt, SEEK_SET);
if (std::fread(dst, 1, fmt, file) != fmt)
{
WARN_LOG(GDROM, "Failed or truncated GD-Rom read");
return false;
}
return true;
}
~RawTrackFile() override
{
if (cleanup && file)
std::fclose(file);
std::fclose(file);
}
};

View File

@ -18,6 +18,7 @@
*/
#include "common.h"
#include "stdclass.h"
#include <sstream>
extern std::string OS_dirname(std::string file);
@ -46,15 +47,13 @@ static u32 getSectorSize(const std::string& type) {
Disc* cue_parse(const char* file)
{
// Only try to open .cue files
size_t len = strlen(file);
if (len > 4 && stricmp( &file[len - 4], ".cue"))
if (get_file_extension(file) != "cue")
return nullptr;
FILE *fsource = nowide::fopen(file, "rb");
if (fsource == nullptr)
return nullptr;
throw FlycastException(std::string("Cannot open CUE file ") + file);
size_t cue_len = flycast::fsize(fsource);
@ -62,9 +61,8 @@ Disc* cue_parse(const char* file)
if (cue_len >= sizeof(cue_data))
{
WARN_LOG(GDROM, "CUE parse error: CUE file too big");
std::fclose(fsource);
return nullptr;
throw FlycastException("CUE parse error: CUE file too big");
}
if (std::fread(cue_data, 1, cue_len, fsource) != cue_len)
@ -163,24 +161,21 @@ Disc* cue_parse(const char* file)
if (index_num == 1)
{
Track t;
t.ADDR = 0;
t.StartFAD = current_fad;
t.CTRL = (track_type == "AUDIO" || track_type == "CDG") ? 0 : 4;
std::string path = basepath + normalize_path_separator(track_filename);
FILE *track_file = nowide::fopen(path.c_str(), "rb");
if (track_file == nullptr)
{
WARN_LOG(GDROM, "CUE file: cannot open track %d: %s", track_number, path.c_str());
delete disc;
return nullptr;
throw FlycastException("CUE file: cannot open track " + path);
}
u32 sector_size = getSectorSize(track_type);
if (sector_size == 0)
{
WARN_LOG(GDROM, "CUE file: track %d has unknown sector type: %s", track_number, track_type.c_str());
std::fclose(track_file);
delete disc;
return nullptr;
throw FlycastException("CUE file: track has unknown sector type: " + track_type);
}
if (flycast::fsize(track_file) % sector_size != 0)
WARN_LOG(GDROM, "Warning: Size of track %s is not multiple of sector size %d", track_filename.c_str(), sector_size);
@ -199,9 +194,8 @@ Disc* cue_parse(const char* file)
}
if (disc->tracks.empty())
{
WARN_LOG(GDROM, "CUE parse error: failed to parse or invalid file with 0 tracks");
delete disc;
return nullptr;
throw FlycastException("CUE parse error: failed to parse or invalid file with 0 tracks");
}
if (session_number == 0)

View File

@ -1,4 +1,5 @@
#include "common.h"
#include "stdclass.h"
#include <algorithm>
#include <sstream>
@ -62,8 +63,8 @@ namespace {
Disc* load_gdi(const char* file)
{
FILE *t = nowide::fopen(file, "rb");
if (!t)
return nullptr;
if (t == nullptr)
throw FlycastException(std::string("Cannot open GDI file ") + file);
size_t gdi_len = flycast::fsize(t);
@ -71,9 +72,8 @@ Disc* load_gdi(const char* file)
if (gdi_len >= sizeof(gdi_data))
{
WARN_LOG(GDROM, "GDI: file too big");
std::fclose(t);
return nullptr;
throw FlycastException("GDI file too big");
}
if (std::fread(gdi_data, 1, gdi_len, t) != gdi_len)
@ -85,10 +85,8 @@ Disc* load_gdi(const char* file)
u32 iso_tc = 0;
gdi >> iso_tc;
if (iso_tc == 0)
{
WARN_LOG(GDROM, "GDI: empty or invalid GDI file");
return nullptr;
}
throw FlycastException("GDI: empty or invalid GDI file");
INFO_LOG(GDROM, "GDI : %d tracks", iso_tc);
std::string basepath = OS_dirname(file);
@ -134,16 +132,19 @@ Disc* load_gdi(const char* file)
DEBUG_LOG(GDROM, "file[%d] \"%s\": FAD:%d, CTRL:%d, SSIZE:%d, OFFSET:%d", TRACK, track_filename.c_str(), FADS, CTRL, SSIZE, OFFSET);
Track t;
t.ADDR=0;
t.StartFAD=FADS+150;
t.EndFAD=0; //fill it in
t.file=0;
t.StartFAD = FADS + 150;
t.CTRL = CTRL;
if (SSIZE!=0)
{
std::string path = basepath + normalize_path_separator(track_filename);
t.file = new RawTrackFile(nowide::fopen(path.c_str(), "rb"), OFFSET, t.StartFAD,SSIZE);
FILE *file = nowide::fopen(path.c_str(), "rb");
if (file == nullptr)
{
delete disc;
throw FlycastException("GDI file: Cannot open track " + path);
}
t.file = new RawTrackFile(file, OFFSET, t.StartFAD, SSIZE);
}
if (!disc->tracks.empty())
disc->tracks.back().EndFAD = t.StartFAD - 1;
@ -158,13 +159,8 @@ Disc* load_gdi(const char* file)
Disc* gdi_parse(const char* file)
{
size_t len=strlen(file);
if (len>4)
{
if (stricmp( &file[len-4],".gdi")==0)
{
return load_gdi(file);
}
}
return 0;
if (get_file_extension(file) != "gdi")
return nullptr;
return load_gdi(file);
}

View File

@ -394,6 +394,7 @@ static void reios_sys_misc()
case 1: // Exit to BIOS menu
WARN_LOG(REIOS, "SYS_MISC 1");
throw FlycastException("Reboot to BIOS");
break;
case 2: // check disk
@ -645,9 +646,8 @@ static void reios_boot()
std::string extension = get_file_extension(settings.imgread.ImagePath);
if (extension == "elf")
{
if (!reios_loadElf(settings.imgread.ImagePath)) {
msgboxf("Failed to open %s", MBX_ICONERROR, settings.imgread.ImagePath);
}
if (!reios_loadElf(settings.imgread.ImagePath))
throw FlycastException(std::string("Failed to open ELF ") + settings.imgread.ImagePath);
reios_setup_state(0x8C010000);
}
else {
@ -656,7 +656,7 @@ static void reios_boot()
char bootfile[sizeof(ip_meta.boot_filename) + 1] = {0};
memcpy(bootfile, ip_meta.boot_filename, sizeof(ip_meta.boot_filename));
if (bootfile[0] == '\0' || !reios_locate_bootfile(bootfile))
msgboxf("Failed to locate bootfile %s", MBX_ICONERROR, bootfile);
throw FlycastException(std::string("Failed to locate bootfile ") + bootfile);
reios_setup_state(0xac008300);
}
else {
@ -668,14 +668,14 @@ static void reios_boot()
}
u32 data_size = 4;
u32* sz = (u32*)CurrentCartridge->GetPtr(0x368, data_size);
if (!sz || data_size != 4) {
msgboxf("Naomi boot failure", MBX_ICONERROR);
}
if (sz == nullptr || data_size != 4)
throw FlycastException("Naomi boot failure");
const u32 size = *sz;
data_size = 1;
verify(size < RAM_SIZE && CurrentCartridge->GetPtr(size - 1, data_size) && "Invalid cart size");
if (size > RAM_SIZE || CurrentCartridge->GetPtr(size - 1, data_size) == nullptr)
throw FlycastException("Invalid cart size");
data_size = size;
WriteMemBlock_nommu_ptr(0x0c020000, (u32*)CurrentCartridge->GetPtr(0, data_size), size);

View File

@ -432,6 +432,26 @@ static void gui_start_game(const std::string& path)
dc_load_game(path.empty() ? NULL : path_copy.c_str());
}
void gui_stop_game(const std::string& message)
{
if (!commandLineStart)
{
// Exit to main menu
dc_term_game();
gui_state = GuiState::Main;
game_started = false;
settings.imgread.ImagePath[0] = '\0';
reset_vmus();
if (!message.empty())
error_msg = "Flycast has stopped.\n\n" + message;
}
else
{
// Exit emulator
dc_exit();
}
}
static void gui_display_commands()
{
if (dc_is_running())
@ -515,20 +535,7 @@ static void gui_display_commands()
if (ImGui::Button("Exit", ImVec2(300 * scaling + ImGui::GetStyle().ColumnsMinSpacing + ImGui::GetStyle().FramePadding.x * 2 - 1,
50 * scaling)))
{
if (!commandLineStart)
{
// Exit to main menu
dc_term_game();
gui_state = GuiState::Main;
game_started = false;
settings.imgread.ImagePath[0] = '\0';
reset_vmus();
}
else
{
// Exit emulator
dc_exit();
}
gui_stop_game();
}
ImGui::End();
@ -909,6 +916,9 @@ static void error_popup()
{
if (!error_msg.empty())
{
ImVec2 padding = ImVec2(20 * scaling, 20 * scaling);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, padding);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, padding);
ImGui::OpenPopup("Error");
if (ImGui::BeginPopupModal("Error", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
{
@ -924,8 +934,11 @@ static void error_popup()
}
ImGui::SetItemDefaultFocus();
ImGui::PopStyleVar();
ImGui::PopTextWrapPos();
ImGui::EndPopup();
}
ImGui::PopStyleVar();
ImGui::PopStyleVar();
}
}
@ -1918,8 +1931,12 @@ static void gui_display_content()
if (gui_state == GuiState::SelectDisk)
{
strcpy(settings.imgread.ImagePath, game.path.c_str());
DiscSwap();
gui_state = GuiState::Closed;
try {
DiscSwap();
gui_state = GuiState::Closed;
} catch (const FlycastException& e) {
error_msg = e.what();
}
}
else
{

View File

@ -36,6 +36,7 @@ void gui_set_mouse_position(int x, int y);
void gui_set_mouse_button(int button, bool pressed);
void gui_set_mouse_wheel(float delta);
void gui_set_insets(int left, int right, int top, int bottom);
void gui_stop_game(const std::string& message = "");
extern int screen_dpi;
extern float scaling;

View File

@ -49,6 +49,11 @@ bool mainui_rend_frame()
if (!rend_single_frame(mainui_enabled))
{
UpdateInputState();
if (!dc_is_running())
{
dc_stop();
gui_stop_game(dc_get_last_error());
}
return false;
}
}

View File

@ -845,12 +845,26 @@ void retro_run()
// Render
is_dupe = true;
for (int i = 0; i < 5 && is_dupe; i++)
{
is_dupe = !rend_single_frame(true);
if (!dc_is_running()) {
std::string error = dc_get_last_error();
if (!error.empty())
gui_display_notification(error.c_str(), 5000);
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
}
}
}
else
{
startTime = sh4_sched_now64();
dc_run(nullptr);
try {
dc_run();
} catch (const FlycastException& e) {
ERROR_LOG(COMMON, "%s", e.what());
gui_display_notification(e.what(), 5000);
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
}
}
if (config::RendererType.isOpenGL())
@ -870,7 +884,7 @@ static bool loadGame(const char *path)
} catch (const FlycastException& e) {
ERROR_LOG(BOOT, "%s", e.what());
mute_messages = false;
gui_display_notification(e.what(), 2000);
gui_display_notification(e.what(), 5000);
return false;
}
mute_messages = false;
@ -2751,7 +2765,12 @@ static bool retro_set_eject_state(bool ejected)
}
else
{
return DiscSwap();
try {
return DiscSwap();
} catch (const FlycastException& e) {
ERROR_LOG(GDROM, "%s", e.what());
return false;
}
}
}
@ -2779,8 +2798,13 @@ static bool retro_set_image_index(unsigned index)
if (disc_tray_open)
return true;
else
try {
return DiscSwap();
} catch (const FlycastException& e) {
ERROR_LOG(GDROM, "%s", e.what());
return false;
}
}
static unsigned retro_get_num_images()