diff --git a/bug_fixes_plan.md b/bug_fixes_plan.md new file mode 100644 index 0000000000..f6e7be3fa1 --- /dev/null +++ b/bug_fixes_plan.md @@ -0,0 +1,85 @@ +# Suyu Bug Fixes Plan + +## 1. Game-specific issues + +### Approach: +- Analyze logs and crash reports for the affected games (e.g., Echoes of Wisdom, Tears of the Kingdom, Shin Megami Tensei V). +- Identify common patterns or specific hardware/API calls causing issues. +- Implement game-specific workarounds if necessary. + +### TODO: +- [ ] Review game-specific issues in the issue tracker +- [ ] Analyze logs and crash reports +- [ ] Implement fixes for each game +- [ ] Test fixes thoroughly + +## 2. Crashes + +### Approach: +- Implement better error handling and logging throughout the codebase. +- Add more robust null checks and boundary checks. +- Review and optimize memory management. + +### TODO: +- [ ] Implement a centralized error handling system +- [ ] Add more detailed logging for crash-prone areas +- [ ] Review and improve memory management in core emulation components + +## 3. Shader caching and performance issues + +### Approach: +- Optimize shader compilation process. +- Implement background shader compilation to reduce stuttering. +- Review and optimize the caching mechanism. + +### TODO: +- [ ] Profile shader compilation and identify bottlenecks +- [ ] Implement asynchronous shader compilation +- [ ] Optimize shader cache storage and retrieval +- [ ] Implement shader pre-caching for known games + +## 4. Missing features + +### Approach: +- Prioritize missing features based on user demand and technical feasibility. +- Implement support for additional file formats (NSZ, XCZ). +- Add custom save data folder selection. + +### TODO: +- [ ] Implement NSZ and XCZ file format support +- [ ] Add UI option for custom save data folder selection +- [ ] Update relevant documentation + +## 5. Add-ons and mods issues + +### Approach: +- Review the current implementation of add-ons and mods support. +- Implement a more robust system for managing and applying mods. +- Improve compatibility checks for mods. + +### TODO: +- [ ] Review and refactor the current mod system +- [ ] Implement better mod management UI +- [ ] Add compatibility checks for mods +- [ ] Improve documentation for mod creators + +## 6. General optimization + +### Approach: +- Profile the emulator to identify performance bottlenecks. +- Optimize core emulation components. +- Implement multi-threading where appropriate. + +### TODO: +- [ ] Conduct thorough profiling of the emulator +- [ ] Optimize CPU-intensive operations +- [ ] Implement or improve multi-threading in suitable components +- [ ] Review and optimize memory usage + +## Testing and Quality Assurance + +- Implement a comprehensive test suite for core emulation components. +- Set up continuous integration to run tests automatically. +- Establish a structured QA process for testing game compatibility and performance. + +Remember to update the relevant documentation and changelog after implementing these fixes. Prioritize the issues based on their impact on user experience and the number of affected users. \ No newline at end of file diff --git a/src/core/libretro_wrapper.cpp b/src/core/libretro_wrapper.cpp index 8d5df1bd16..ba0472fe4d 100644 --- a/src/core/libretro_wrapper.cpp +++ b/src/core/libretro_wrapper.cpp @@ -1,11 +1,13 @@ #include "core/libretro_wrapper.h" +#include "nintendo_library/nintendo_library.h" #include #include #include +#include namespace Core { -LibretroWrapper::LibretroWrapper() : core_handle(nullptr) {} +LibretroWrapper::LibretroWrapper() : core_handle(nullptr), nintendo_library(std::make_unique()) {} LibretroWrapper::~LibretroWrapper() { Unload(); @@ -14,36 +16,42 @@ LibretroWrapper::~LibretroWrapper() { bool LibretroWrapper::LoadCore(const std::string& core_path) { core_handle = dlopen(core_path.c_str(), RTLD_LAZY); if (!core_handle) { + std::cerr << "Failed to load libretro core: " << dlerror() << std::endl; return false; } // Load libretro core functions - retro_init = reinterpret_cast(dlsym(core_handle, "retro_init")); - retro_deinit = reinterpret_cast(dlsym(core_handle, "retro_deinit")); - retro_api_version = reinterpret_cast(dlsym(core_handle, "retro_api_version")); - retro_get_system_info = reinterpret_cast(dlsym(core_handle, "retro_get_system_info")); - retro_get_system_av_info = reinterpret_cast(dlsym(core_handle, "retro_get_system_av_info")); - retro_set_environment = reinterpret_cast(dlsym(core_handle, "retro_set_environment")); - retro_set_video_refresh = reinterpret_cast(dlsym(core_handle, "retro_set_video_refresh")); - retro_set_audio_sample = reinterpret_cast(dlsym(core_handle, "retro_set_audio_sample")); - retro_set_audio_sample_batch = reinterpret_cast(dlsym(core_handle, "retro_set_audio_sample_batch")); - retro_set_input_poll = reinterpret_cast(dlsym(core_handle, "retro_set_input_poll")); - retro_set_input_state = reinterpret_cast(dlsym(core_handle, "retro_set_input_state")); - retro_set_controller_port_device = reinterpret_cast(dlsym(core_handle, "retro_set_controller_port_device")); - retro_reset = reinterpret_cast(dlsym(core_handle, "retro_reset")); - retro_run = reinterpret_cast(dlsym(core_handle, "retro_run")); - retro_serialize_size = reinterpret_cast(dlsym(core_handle, "retro_serialize_size")); - retro_serialize = reinterpret_cast(dlsym(core_handle, "retro_serialize")); - retro_unserialize = reinterpret_cast(dlsym(core_handle, "retro_unserialize")); - retro_load_game = reinterpret_cast(dlsym(core_handle, "retro_load_game")); - retro_unload_game = reinterpret_cast(dlsym(core_handle, "retro_unload_game")); + #define LOAD_SYMBOL(S) S = reinterpret_cast(dlsym(core_handle, #S)); \ + if (!S) { \ + std::cerr << "Failed to load symbol " #S ": " << dlerror() << std::endl; \ + Unload(); \ + return false; \ + } - if (!retro_init || !retro_deinit || !retro_api_version || !retro_get_system_info || - !retro_get_system_av_info || !retro_set_environment || !retro_set_video_refresh || - !retro_set_audio_sample || !retro_set_audio_sample_batch || !retro_set_input_poll || - !retro_set_input_state || !retro_set_controller_port_device || !retro_reset || - !retro_run || !retro_serialize_size || !retro_serialize || !retro_unserialize || - !retro_load_game || !retro_unload_game) { + LOAD_SYMBOL(retro_init) + LOAD_SYMBOL(retro_deinit) + LOAD_SYMBOL(retro_api_version) + LOAD_SYMBOL(retro_get_system_info) + LOAD_SYMBOL(retro_get_system_av_info) + LOAD_SYMBOL(retro_set_environment) + LOAD_SYMBOL(retro_set_video_refresh) + LOAD_SYMBOL(retro_set_audio_sample) + LOAD_SYMBOL(retro_set_audio_sample_batch) + LOAD_SYMBOL(retro_set_input_poll) + LOAD_SYMBOL(retro_set_input_state) + LOAD_SYMBOL(retro_set_controller_port_device) + LOAD_SYMBOL(retro_reset) + LOAD_SYMBOL(retro_run) + LOAD_SYMBOL(retro_serialize_size) + LOAD_SYMBOL(retro_serialize) + LOAD_SYMBOL(retro_unserialize) + LOAD_SYMBOL(retro_load_game) + LOAD_SYMBOL(retro_unload_game) + + #undef LOAD_SYMBOL + + if (!nintendo_library->Initialize()) { + std::cerr << "Failed to initialize Nintendo Library" << std::endl; Unload(); return false; } @@ -54,6 +62,7 @@ bool LibretroWrapper::LoadCore(const std::string& core_path) { bool LibretroWrapper::LoadGame(const std::string& game_path) { if (!core_handle) { + std::cerr << "Libretro core not loaded" << std::endl; return false; } @@ -62,18 +71,34 @@ bool LibretroWrapper::LoadGame(const std::string& game_path) { game_info.size = 0; game_info.meta = nullptr; - return retro_load_game(&game_info); + if (!retro_load_game(&game_info)) { + std::cerr << "Failed to load game through libretro" << std::endl; + return false; + } + + if (!nintendo_library->LoadROM(game_path)) { + std::cerr << "Failed to load ROM through Nintendo Library" << std::endl; + return false; + } + + return true; } void LibretroWrapper::Run() { if (core_handle) { retro_run(); + nintendo_library->RunFrame(); + } else { + std::cerr << "Cannot run: Libretro core not loaded" << std::endl; } } void LibretroWrapper::Reset() { if (core_handle) { retro_reset(); + // Add any necessary reset logic for Nintendo Library + } else { + std::cerr << "Cannot reset: Libretro core not loaded" << std::endl; } } @@ -84,6 +109,9 @@ void LibretroWrapper::Unload() { dlclose(core_handle); core_handle = nullptr; } + nintendo_library->Shutdown(); } +// Add implementations for other libretro functions as needed + } // namespace Core \ No newline at end of file diff --git a/src/core/libretro_wrapper.h b/src/core/libretro_wrapper.h new file mode 100644 index 0000000000..84e2aacd0c --- /dev/null +++ b/src/core/libretro_wrapper.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +// Forward declaration +namespace Nintendo { +class Library; +} + +struct retro_game_info; + +namespace Core { + +class LibretroWrapper { +public: + LibretroWrapper(); + ~LibretroWrapper(); + + bool LoadCore(const std::string& core_path); + bool LoadGame(const std::string& game_path); + void Run(); + void Reset(); + void Unload(); + +private: + void* core_handle; + retro_game_info game_info; + std::unique_ptr nintendo_library; + + // Libretro function pointers + void (*retro_init)(); + void (*retro_deinit)(); + unsigned (*retro_api_version)(); + void (*retro_get_system_info)(struct retro_system_info *info); + void (*retro_get_system_av_info)(struct retro_system_av_info *info); + void (*retro_set_environment)(void (*)(unsigned, const char*)); + void (*retro_set_video_refresh)(void (*)(const void*, unsigned, unsigned, size_t)); + void (*retro_set_audio_sample)(void (*)(int16_t, int16_t)); + void (*retro_set_audio_sample_batch)(size_t (*)(const int16_t*, size_t)); + void (*retro_set_input_poll)(void (*)()); + void (*retro_set_input_state)(int16_t (*)(unsigned, unsigned, unsigned, unsigned)); + void (*retro_set_controller_port_device)(unsigned, unsigned); + void (*retro_reset)(); + void (*retro_run)(); + size_t (*retro_serialize_size)(); + bool (*retro_serialize)(void*, size_t); + bool (*retro_unserialize)(const void*, size_t); + bool (*retro_load_game)(const struct retro_game_info*); + void (*retro_unload_game)(); +}; + +} // namespace Core \ No newline at end of file