diff --git a/core/dispframe.cpp b/core/dispframe.cpp index ef767517a..c68e0ddce 100755 --- a/core/dispframe.cpp +++ b/core/dispframe.cpp @@ -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 diff --git a/core/emulator.cpp b/core/emulator.cpp index 11fee2473..f206fb856 100644 --- a/core/emulator.cpp +++ b/core/emulator.cpp @@ -42,8 +42,10 @@ extern int screen_width, screen_height; std::atomic 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) diff --git a/core/emulator.h b/core/emulator.h index 4e2be7c72..9909760f2 100644 --- a/core/emulator.h +++ b/core/emulator.h @@ -31,7 +31,7 @@ extern std::atomic 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, diff --git a/core/imgread/cdi.cpp b/core/imgread/cdi.cpp index ae9547972..ae410c6d7 100644 --- a/core/imgread/cdi.cpp +++ b/core/imgread/cdi.cpp @@ -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; } diff --git a/core/imgread/chd.cpp b/core/imgread/chd.cpp index 2270c6cbb..645df2cb2 100644 --- a/core/imgread/chd.cpp +++ b/core/imgread/chd.cpp @@ -1,9 +1,10 @@ #include "common.h" +#include "stdclass.h" #include /* 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; } } diff --git a/core/imgread/common.h b/core/imgread/common.h index 2f5001732..d2fd16598 100644 --- a/core/imgread/common.h +++ b/core/imgread/common.h @@ -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); } }; diff --git a/core/imgread/cue.cpp b/core/imgread/cue.cpp index f026ee2ff..bf95f9673 100644 --- a/core/imgread/cue.cpp +++ b/core/imgread/cue.cpp @@ -18,6 +18,7 @@ */ #include "common.h" +#include "stdclass.h" #include 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) diff --git a/core/imgread/gdi.cpp b/core/imgread/gdi.cpp index b055c5235..3790be9c5 100644 --- a/core/imgread/gdi.cpp +++ b/core/imgread/gdi.cpp @@ -1,4 +1,5 @@ #include "common.h" +#include "stdclass.h" #include #include @@ -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); } diff --git a/core/reios/reios.cpp b/core/reios/reios.cpp index aa69ef13f..97dba83ee 100644 --- a/core/reios/reios.cpp +++ b/core/reios/reios.cpp @@ -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); diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 9ea1589ae..2f7f877ed 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -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 { diff --git a/core/rend/gui.h b/core/rend/gui.h index 4f4a9dadf..c6b2139e6 100644 --- a/core/rend/gui.h +++ b/core/rend/gui.h @@ -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; diff --git a/core/rend/mainui.cpp b/core/rend/mainui.cpp index a379847b7..6fa9ef791 100644 --- a/core/rend/mainui.cpp +++ b/core/rend/mainui.cpp @@ -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; } } diff --git a/shell/libretro/libretro.cpp b/shell/libretro/libretro.cpp index 9f6146d52..8db1484fc 100644 --- a/shell/libretro/libretro.cpp +++ b/shell/libretro/libretro.cpp @@ -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()