mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-02 04:52:44 +01:00
added
This commit is contained in:
parent
e018a2875c
commit
6c81b5b067
3 changed files with 193 additions and 27 deletions
85
bug_fixes_plan.md
Normal file
85
bug_fixes_plan.md
Normal file
|
@ -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.
|
|
@ -1,11 +1,13 @@
|
||||||
#include "core/libretro_wrapper.h"
|
#include "core/libretro_wrapper.h"
|
||||||
|
#include "nintendo_library/nintendo_library.h"
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
LibretroWrapper::LibretroWrapper() : core_handle(nullptr) {}
|
LibretroWrapper::LibretroWrapper() : core_handle(nullptr), nintendo_library(std::make_unique<Nintendo::Library>()) {}
|
||||||
|
|
||||||
LibretroWrapper::~LibretroWrapper() {
|
LibretroWrapper::~LibretroWrapper() {
|
||||||
Unload();
|
Unload();
|
||||||
|
@ -14,36 +16,42 @@ LibretroWrapper::~LibretroWrapper() {
|
||||||
bool LibretroWrapper::LoadCore(const std::string& core_path) {
|
bool LibretroWrapper::LoadCore(const std::string& core_path) {
|
||||||
core_handle = dlopen(core_path.c_str(), RTLD_LAZY);
|
core_handle = dlopen(core_path.c_str(), RTLD_LAZY);
|
||||||
if (!core_handle) {
|
if (!core_handle) {
|
||||||
|
std::cerr << "Failed to load libretro core: " << dlerror() << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load libretro core functions
|
// Load libretro core functions
|
||||||
retro_init = reinterpret_cast<void (*)()>(dlsym(core_handle, "retro_init"));
|
#define LOAD_SYMBOL(S) S = reinterpret_cast<decltype(S)>(dlsym(core_handle, #S)); \
|
||||||
retro_deinit = reinterpret_cast<void (*)()>(dlsym(core_handle, "retro_deinit"));
|
if (!S) { \
|
||||||
retro_api_version = reinterpret_cast<unsigned (*)()>(dlsym(core_handle, "retro_api_version"));
|
std::cerr << "Failed to load symbol " #S ": " << dlerror() << std::endl; \
|
||||||
retro_get_system_info = reinterpret_cast<void (*)(struct retro_system_info*)>(dlsym(core_handle, "retro_get_system_info"));
|
Unload(); \
|
||||||
retro_get_system_av_info = reinterpret_cast<void (*)(struct retro_system_av_info*)>(dlsym(core_handle, "retro_get_system_av_info"));
|
return false; \
|
||||||
retro_set_environment = reinterpret_cast<void (*)(retro_environment_t)>(dlsym(core_handle, "retro_set_environment"));
|
}
|
||||||
retro_set_video_refresh = reinterpret_cast<void (*)(retro_video_refresh_t)>(dlsym(core_handle, "retro_set_video_refresh"));
|
|
||||||
retro_set_audio_sample = reinterpret_cast<void (*)(retro_audio_sample_t)>(dlsym(core_handle, "retro_set_audio_sample"));
|
|
||||||
retro_set_audio_sample_batch = reinterpret_cast<void (*)(retro_audio_sample_batch_t)>(dlsym(core_handle, "retro_set_audio_sample_batch"));
|
|
||||||
retro_set_input_poll = reinterpret_cast<void (*)(retro_input_poll_t)>(dlsym(core_handle, "retro_set_input_poll"));
|
|
||||||
retro_set_input_state = reinterpret_cast<void (*)(retro_input_state_t)>(dlsym(core_handle, "retro_set_input_state"));
|
|
||||||
retro_set_controller_port_device = reinterpret_cast<void (*)(unsigned, unsigned)>(dlsym(core_handle, "retro_set_controller_port_device"));
|
|
||||||
retro_reset = reinterpret_cast<void (*)()>(dlsym(core_handle, "retro_reset"));
|
|
||||||
retro_run = reinterpret_cast<void (*)()>(dlsym(core_handle, "retro_run"));
|
|
||||||
retro_serialize_size = reinterpret_cast<size_t (*)()>(dlsym(core_handle, "retro_serialize_size"));
|
|
||||||
retro_serialize = reinterpret_cast<bool (*)(void*, size_t)>(dlsym(core_handle, "retro_serialize"));
|
|
||||||
retro_unserialize = reinterpret_cast<bool (*)(const void*, size_t)>(dlsym(core_handle, "retro_unserialize"));
|
|
||||||
retro_load_game = reinterpret_cast<bool (*)(const struct retro_game_info*)>(dlsym(core_handle, "retro_load_game"));
|
|
||||||
retro_unload_game = reinterpret_cast<void (*)()>(dlsym(core_handle, "retro_unload_game"));
|
|
||||||
|
|
||||||
if (!retro_init || !retro_deinit || !retro_api_version || !retro_get_system_info ||
|
LOAD_SYMBOL(retro_init)
|
||||||
!retro_get_system_av_info || !retro_set_environment || !retro_set_video_refresh ||
|
LOAD_SYMBOL(retro_deinit)
|
||||||
!retro_set_audio_sample || !retro_set_audio_sample_batch || !retro_set_input_poll ||
|
LOAD_SYMBOL(retro_api_version)
|
||||||
!retro_set_input_state || !retro_set_controller_port_device || !retro_reset ||
|
LOAD_SYMBOL(retro_get_system_info)
|
||||||
!retro_run || !retro_serialize_size || !retro_serialize || !retro_unserialize ||
|
LOAD_SYMBOL(retro_get_system_av_info)
|
||||||
!retro_load_game || !retro_unload_game) {
|
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();
|
Unload();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +62,7 @@ bool LibretroWrapper::LoadCore(const std::string& core_path) {
|
||||||
|
|
||||||
bool LibretroWrapper::LoadGame(const std::string& game_path) {
|
bool LibretroWrapper::LoadGame(const std::string& game_path) {
|
||||||
if (!core_handle) {
|
if (!core_handle) {
|
||||||
|
std::cerr << "Libretro core not loaded" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,18 +71,34 @@ bool LibretroWrapper::LoadGame(const std::string& game_path) {
|
||||||
game_info.size = 0;
|
game_info.size = 0;
|
||||||
game_info.meta = nullptr;
|
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() {
|
void LibretroWrapper::Run() {
|
||||||
if (core_handle) {
|
if (core_handle) {
|
||||||
retro_run();
|
retro_run();
|
||||||
|
nintendo_library->RunFrame();
|
||||||
|
} else {
|
||||||
|
std::cerr << "Cannot run: Libretro core not loaded" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibretroWrapper::Reset() {
|
void LibretroWrapper::Reset() {
|
||||||
if (core_handle) {
|
if (core_handle) {
|
||||||
retro_reset();
|
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);
|
dlclose(core_handle);
|
||||||
core_handle = nullptr;
|
core_handle = nullptr;
|
||||||
}
|
}
|
||||||
|
nintendo_library->Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add implementations for other libretro functions as needed
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
53
src/core/libretro_wrapper.h
Normal file
53
src/core/libretro_wrapper.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// 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> 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
|
Loading…
Reference in a new issue