Files
emulate/app/src/main/cpp/libretro_frontend.h

132 lines
4.4 KiB
C
Raw Normal View History

#pragma once
#include "libretro.h"
#include "audio_engine.h"
#include <android/native_window.h>
#include <atomic>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
enum class DisplayMode : int {
STRETCH = 0,
ASPECT_RATIO = 1,
INTEGER_SCALE = 2
};
class LibretroFrontend {
public:
static LibretroFrontend& instance();
bool loadCore(const char* soPath);
bool loadGame(const char* romPath);
void start();
void pause();
void resume();
void stop();
void reset();
void setWindow(ANativeWindow* window);
void releaseWindow();
void setButtonState(uint16_t state);
void setAnalogState(int stick, int16_t x, int16_t y);
bool saveState(const char* path);
bool loadState(const char* path);
void setAudioEnabled(bool enabled);
void setFrameSkip(int skip);
void setDisplayMode(int mode);
void setSystemDir(const char* dir);
void setSaveDir(const char* dir);
void setControllerPortDevice(unsigned port, unsigned device);
void setCoreOption(const char* key, const char* value);
bool isRunning() const { return running_.load(); }
private:
LibretroFrontend() = default;
~LibretroFrontend();
void runLoop();
void unloadCore();
// Libretro callbacks (static because libretro uses C function pointers)
static bool environmentCallback(unsigned cmd, void* data);
static void videoRefreshCallback(const void* data, unsigned width, unsigned height, size_t pitch);
static size_t audioSampleBatchCallback(const int16_t* data, size_t frames);
static void audioSampleCallback(int16_t left, int16_t right);
static void inputPollCallback();
static int16_t inputStateCallback(unsigned port, unsigned device, unsigned index, unsigned id);
static void logCallback(enum retro_log_level level, const char* fmt, ...);
// Core function pointers (resolved via dlsym)
void* core_handle_ = nullptr;
retro_init_t core_init_ = nullptr;
retro_deinit_t core_deinit_ = nullptr;
retro_api_version_t core_api_version_ = nullptr;
retro_get_system_info_t core_get_system_info_ = nullptr;
retro_get_system_av_info_t core_get_system_av_info_ = nullptr;
retro_set_environment_t core_set_environment_ = nullptr;
retro_set_video_refresh_t core_set_video_refresh_ = nullptr;
retro_set_audio_sample_t core_set_audio_sample_ = nullptr;
retro_set_audio_sample_batch_t core_set_audio_sample_batch_ = nullptr;
retro_set_input_poll_t core_set_input_poll_ = nullptr;
retro_set_input_state_t core_set_input_state_ = nullptr;
retro_set_controller_port_device_t core_set_controller_port_device_ = nullptr;
retro_load_game_t core_load_game_ = nullptr;
retro_unload_game_t core_unload_game_ = nullptr;
retro_run_t core_run_ = nullptr;
retro_reset_t core_reset_ = nullptr;
retro_serialize_size_t core_serialize_size_ = nullptr;
retro_serialize_t core_serialize_ = nullptr;
retro_unserialize_t core_unserialize_ = nullptr;
retro_get_memory_data_t core_get_memory_data_ = nullptr;
retro_get_memory_size_t core_get_memory_size_ = nullptr;
// State
std::atomic<bool> running_{false};
std::atomic<bool> paused_{false};
std::atomic<bool> game_loaded_{false};
std::thread emu_thread_;
// Video
ANativeWindow* window_ = nullptr;
std::mutex window_mutex_;
unsigned pixel_format_ = RETRO_PIXEL_FORMAT_RGB565;
std::atomic<DisplayMode> display_mode_{DisplayMode::STRETCH};
float core_aspect_ratio_ = 0.0f;
unsigned core_base_width_ = 0;
unsigned core_base_height_ = 0;
// Audio
AudioEngine audio_engine_;
// Input
std::atomic<uint16_t> button_state_{0};
std::atomic<int16_t> analog_lx_{0}, analog_ly_{0};
std::atomic<int16_t> analog_rx_{0}, analog_ry_{0};
// Paths
std::string system_dir_;
std::string save_dir_;
// ROM data (kept alive for cores with need_fullpath=false)
std::vector<uint8_t> rom_data_;
bool need_fullpath_ = true;
// Frame timing
double target_fps_ = 60.0;
int frame_skip_ = 0;
// Core options
std::unordered_map<std::string, std::string> core_options_;
std::atomic<bool> options_updated_{false};
};