Libretro: Add initial libretro version

This commit is contained in:
Jeffrey Pfau 2015-03-05 21:43:57 -08:00
parent eb21dd722f
commit cf71d39bf0
3 changed files with 2201 additions and 0 deletions

View File

@ -12,6 +12,7 @@ set(USE_BLIP ON CACHE BOOL "Whether or not to enable blip_buf support")
set(USE_LZMA ON CACHE BOOL "Whether or not to enable 7-Zip support")
set(BUILD_QT ON CACHE BOOL "Build Qt frontend")
set(BUILD_SDL ON CACHE BOOL "Build SDL frontend")
set(BUILD_LIBRETRO OFF CACHE BOOL "Build libretro core")
set(BUILD_PERF OFF CACHE BOOL "Build performance profiling tool")
set(BUILD_STATIC OFF CACHE BOOL "Build a static library")
set(BUILD_SHARED ON CACHE BOOL "Build a shared library")
@ -309,6 +310,12 @@ if(BUILD_QT)
add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/qt ${CMAKE_BINARY_DIR}/qt)
endif()
if(BUILD_LIBRETRO)
file(GLOB RETRO_SRC ${CMAKE_SOURCE_DIR}/src/platform/libretro/*.c)
add_library(${BINARY_NAME}-libretro SHARED ${RETRO_SRC})
target_link_libraries(${BINARY_NAME}-libretro ${BINARY_NAME} m ${DEBUGGER_LIB} ${OS_LIB} ${DEPENDENCY_LIB})
endif()
if(BUILD_PERF)
set(PERF_SRC ${CMAKE_SOURCE_DIR}/src/platform/perf-main.c)
if(UNIX AND NOT APPLE)
@ -355,6 +362,7 @@ message(STATUS " Better audio resampling: ${USE_BLIP}")
message(STATUS "Frontend summary:")
message(STATUS " Qt: ${BUILD_QT}")
message(STATUS " SDL (${SDL_VERSION}): ${BUILD_SDL}")
message(STATUS " Libretro core: ${BUILD_LIBRETRO}")
message(STATUS " Profiling: ${BUILD_PERF}")
message(STATUS "Library summary:")
message(STATUS " Static: ${BUILD_STATIC}")

View File

@ -0,0 +1,267 @@
#include "libretro.h"
#include "gba/gba.h"
#include "gba/renderers/video-software.h"
#include "gba/serialize.h"
#include "gba/video.h"
#include "util/vfs.h"
static retro_environment_t environCallback;
static retro_video_refresh_t videoCallback;
static retro_input_poll_t inputPollCallback;
static retro_input_state_t inputCallback;
static retro_log_printf_t logCallback;
static void GBARetroLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args);
static struct GBA gba;
static struct ARMCore cpu;
static struct GBAVideoSoftwareRenderer renderer;
static struct VFile* rom;
static struct VFile* save;
static void* savedata;
unsigned retro_api_version(void) {
return RETRO_API_VERSION;
}
void retro_set_environment(retro_environment_t environ) {
environCallback = environ;
}
void retro_set_video_refresh(retro_video_refresh_t video) {
videoCallback = video;
}
void retro_set_audio_sample(retro_audio_sample_t audio) {
UNUSED(audio);
}
void retro_set_audio_sample_batch(retro_audio_sample_batch_t audioBatch) {
UNUSED(audioBatch);
}
void retro_set_input_poll(retro_input_poll_t inputPoll) {
inputPollCallback = inputPoll;
}
void retro_set_input_state(retro_input_state_t input) {
inputCallback = input;
}
void retro_get_system_info(struct retro_system_info* info) {
info->need_fullpath = false;
info->valid_extensions = "gba";
info->library_version = PROJECT_VERSION;
info->library_name = PROJECT_NAME;
info->block_extract = false;
}
void retro_get_system_av_info(struct retro_system_av_info* info) {
info->geometry.base_width = VIDEO_HORIZONTAL_PIXELS;
info->geometry.base_height = VIDEO_VERTICAL_PIXELS;
info->geometry.max_width = VIDEO_HORIZONTAL_PIXELS;
info->geometry.max_height = VIDEO_VERTICAL_PIXELS;
info->timing.fps = GBA_ARM7TDMI_FREQUENCY / (float) VIDEO_TOTAL_LENGTH;
info->timing.sample_rate = 32768;
}
void retro_init(void) {
enum retro_pixel_format fmt;
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
fmt = RETRO_PIXEL_FORMAT_RGB565;
#else
fmt = RETRO_PIXEL_FORMAT_0RGB1555;
#endif
#else
fmt = RETRO_PIXEL_FORMAT_XRGB8888;
#endif
environCallback(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt);
struct retro_input_descriptor inputDescriptors[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }
};
environCallback(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, &inputDescriptors);
// TODO: RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME when BIOS booting is supported
// TODO: RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
struct retro_log_callback log;
if (environCallback(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) {
logCallback = log.log;
} else {
logCallback = 0;
}
GBACreate(&gba);
ARMSetComponents(&cpu, &gba.d, 0, 0);
ARMInit(&cpu);
gba.logLevel = 0; // TODO: Settings
gba.logHandler = GBARetroLog;
gba.idleOptimization = IDLE_LOOP_REMOVE; // TODO: Settings
rom = 0;
GBAVideoSoftwareRendererCreate(&renderer);
renderer.outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
renderer.outputBufferStride = 256;
GBAVideoAssociateRenderer(&gba.video, &renderer.d);
}
void retro_deinit(void) {
GBADestroy(&gba);
}
void retro_run(void) {
int keys;
gba.keySource = &keys;
inputPollCallback();
keys = 0;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A)) << 0;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B)) << 1;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT)) << 2;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START)) << 3;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT)) << 4;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT)) << 5;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP)) << 6;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN)) << 7;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R)) << 8;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L)) << 9;
int frameCount = gba.video.frameCounter;
while (gba.video.frameCounter == frameCount) {
ARMRunLoop(&cpu);
}
videoCallback(renderer.outputBuffer, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, BYTES_PER_PIXEL * 256);
}
void retro_reset(void) {
ARMReset(&cpu);
}
bool retro_load_game(const struct retro_game_info* game) {
if (game->data) {
rom = VFileFromMemory((void*) game->data, game->size); // TODO: readonly VFileMem
} else {
rom = VFileOpen(game->path, O_RDONLY);
}
if (!rom) {
return false;
}
if (!GBAIsROM(rom)) {
return false;
}
// TODO
save = 0;
savedata = 0;
GBALoadROM(&gba, rom, save, game->path);
ARMReset(&cpu);
return true;
}
void retro_unload_game(void) {
// TODO
}
size_t retro_serialize_size(void) {
return sizeof(struct GBASerializedState);
}
bool retro_serialize(void* data, size_t size) {
if (size != retro_serialize_size()) {
return false;
}
GBASerialize(&gba, data);
return true;
}
bool retro_unserialize(const void* data, size_t size) {
if (size != retro_serialize_size()) {
return false;
}
GBADeserialize(&gba, data);
return true;
}
void retro_cheat_reset(void) {
// TODO: Cheats
}
void retro_cheat_set(unsigned index, bool enabled, const char* code) {
// TODO: Cheats
UNUSED(index);
UNUSED(enabled);
UNUSED(code);
}
unsigned retro_get_region(void) {
return RETRO_REGION_NTSC; // TODO: This isn't strictly true
}
void retro_set_controller_port_device(unsigned port, unsigned device) {
UNUSED(port);
UNUSED(device);
}
bool retro_load_game_special(unsigned game_type, const struct retro_game_info* info, size_t num_info) {
UNUSED(game_type);
UNUSED(info);
UNUSED(num_info);
return false;
}
void* retro_get_memory_data(unsigned id) {
// TODO
UNUSED(id);
return 0;
}
size_t retro_get_memory_size(unsigned id) {
// TODO
UNUSED(id);
return 0;
}
void GBARetroLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) {
UNUSED(thread);
if (!logCallback) {
return;
}
char message[128];
vsnprintf(message, sizeof(message), format, args);
enum retro_log_level retroLevel = RETRO_LOG_INFO;
switch (level) {
case GBA_LOG_ALL:
case GBA_LOG_ERROR:
case GBA_LOG_FATAL:
retroLevel = RETRO_LOG_ERROR;
break;
case GBA_LOG_WARN:
retroLevel = RETRO_LOG_WARN;
break;
case GBA_LOG_INFO:
case GBA_LOG_GAME_ERROR:
case GBA_LOG_SWI:
retroLevel = RETRO_LOG_INFO;
break;
case GBA_LOG_DEBUG:
case GBA_LOG_STUB:
retroLevel = RETRO_LOG_DEBUG;
break;
}
logCallback(retroLevel, "%s\n", message);
}

File diff suppressed because it is too large Load Diff