Merge pull request #81 from jdgleaver/libco-alt
Add build-time option to run the emulator in a thread instead of libco (fixes OpenDingux target)
This commit is contained in:
commit
f5eae17f5a
17
Makefile
17
Makefile
|
@ -4,6 +4,7 @@ FRONTEND_SUPPORTS_RGB565=1
|
||||||
FORCE_32BIT_ARCH=0
|
FORCE_32BIT_ARCH=0
|
||||||
HAVE_MMAP=0
|
HAVE_MMAP=0
|
||||||
HAVE_MMAP_WIN32=0
|
HAVE_MMAP_WIN32=0
|
||||||
|
USE_LIBCO=1
|
||||||
|
|
||||||
UNAME=$(shell uname -a)
|
UNAME=$(shell uname -a)
|
||||||
|
|
||||||
|
@ -400,13 +401,13 @@ else ifeq ($(platform), emscripten)
|
||||||
# GCW0
|
# GCW0
|
||||||
else ifeq ($(platform), gcw0)
|
else ifeq ($(platform), gcw0)
|
||||||
TARGET := $(TARGET_NAME)_libretro.so
|
TARGET := $(TARGET_NAME)_libretro.so
|
||||||
CC ?= /opt/gcw0-toolchain/usr/bin/mipsel-linux-gcc
|
CC = /opt/gcw0-toolchain/usr/bin/mipsel-linux-gcc
|
||||||
CXX ?= /opt/gcw0-toolchain/usr/bin/mipsel-linux-g++
|
CXX = /opt/gcw0-toolchain/usr/bin/mipsel-linux-g++
|
||||||
AR ?= /opt/gcw0-toolchain/usr/bin/mipsel-linux-ar
|
AR = /opt/gcw0-toolchain/usr/bin/mipsel-linux-ar
|
||||||
SHARED := -shared -nostdlib -Wl,--version-script=link.T
|
SHARED := -shared -nostdlib -Wl,--version-script=link.T
|
||||||
fpic := -fPIC
|
fpic := -fPIC
|
||||||
CFLAGS += $(PTHREAD_FLAGS) -DHAVE_MKDIR
|
CFLAGS += -fomit-frame-pointer -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float
|
||||||
CFLAGS += -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float
|
USE_LIBCO = 0
|
||||||
|
|
||||||
# Windows
|
# Windows
|
||||||
else
|
else
|
||||||
|
@ -445,6 +446,12 @@ OBJECTS := $(SOURCES_C:.c=.o) $(SOURCES_ASM:.S=.o)
|
||||||
|
|
||||||
DEFINES := -DHAVE_STRINGS_H -DHAVE_STDINT_H -DHAVE_INTTYPES_H -D__LIBRETRO__ -DINLINE=inline -Wall
|
DEFINES := -DHAVE_STRINGS_H -DHAVE_STDINT_H -DHAVE_INTTYPES_H -D__LIBRETRO__ -DINLINE=inline -Wall
|
||||||
|
|
||||||
|
ifeq ($(USE_LIBCO), 1)
|
||||||
|
DEFINES += -DUSE_LIBCO
|
||||||
|
else
|
||||||
|
LDFLAGS += -lpthread
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_DYNAREC), 1)
|
ifeq ($(HAVE_DYNAREC), 1)
|
||||||
DEFINES += -DHAVE_DYNAREC
|
DEFINES += -DHAVE_DYNAREC
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -13,9 +13,13 @@ SOURCES_C := $(CORE_DIR)/main.c \
|
||||||
$(CORE_DIR)/sound.c \
|
$(CORE_DIR)/sound.c \
|
||||||
$(CORE_DIR)/cheats.c \
|
$(CORE_DIR)/cheats.c \
|
||||||
$(CORE_DIR)/libretro.c \
|
$(CORE_DIR)/libretro.c \
|
||||||
$(CORE_DIR)/libco/libco.c \
|
|
||||||
$(CORE_DIR)/gba_cc_lut.c
|
$(CORE_DIR)/gba_cc_lut.c
|
||||||
|
|
||||||
|
ifeq ($(USE_LIBCO), 1)
|
||||||
|
SOURCES_C += $(CORE_DIR)/libco/libco.c
|
||||||
|
else
|
||||||
|
SOURCES_C += $(CORE_DIR)/retro_emu_thread.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_DYNAREC), 1)
|
ifeq ($(HAVE_DYNAREC), 1)
|
||||||
SOURCES_C += $(CORE_DIR)/cpu_threaded.c
|
SOURCES_C += $(CORE_DIR)/cpu_threaded.c
|
||||||
|
|
39
libretro.c
39
libretro.c
|
@ -5,6 +5,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "libco.h"
|
#include "libco.h"
|
||||||
|
#include "retro_emu_thread.h"
|
||||||
#include "libretro.h"
|
#include "libretro.h"
|
||||||
#include "libretro_core_options.h"
|
#include "libretro_core_options.h"
|
||||||
#include "memmap.h"
|
#include "memmap.h"
|
||||||
|
@ -73,8 +74,10 @@ static retro_environment_t environ_cb;
|
||||||
|
|
||||||
struct retro_perf_callback perf_cb;
|
struct retro_perf_callback perf_cb;
|
||||||
|
|
||||||
|
#if defined(USE_LIBCO)
|
||||||
static cothread_t main_thread;
|
static cothread_t main_thread;
|
||||||
static cothread_t cpu_thread;
|
static cothread_t cpu_thread;
|
||||||
|
#endif
|
||||||
int dynarec_enable;
|
int dynarec_enable;
|
||||||
int use_libretro_save_method = 0;
|
int use_libretro_save_method = 0;
|
||||||
|
|
||||||
|
@ -92,14 +95,23 @@ static bool post_process_mix = false;
|
||||||
|
|
||||||
void switch_to_main_thread(void)
|
void switch_to_main_thread(void)
|
||||||
{
|
{
|
||||||
|
#if defined(USE_LIBCO)
|
||||||
co_switch(main_thread);
|
co_switch(main_thread);
|
||||||
|
#else
|
||||||
|
retro_switch_thread();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void switch_to_cpu_thread(void)
|
static inline void switch_to_cpu_thread(void)
|
||||||
{
|
{
|
||||||
|
#if defined(USE_LIBCO)
|
||||||
co_switch(cpu_thread);
|
co_switch(cpu_thread);
|
||||||
|
#else
|
||||||
|
retro_switch_thread();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(USE_LIBCO)
|
||||||
static void cpu_thread_entry(void)
|
static void cpu_thread_entry(void)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DYNAREC
|
#ifdef HAVE_DYNAREC
|
||||||
|
@ -108,16 +120,29 @@ static void cpu_thread_entry(void)
|
||||||
#endif
|
#endif
|
||||||
execute_arm(execute_cycles);
|
execute_arm(execute_cycles);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void init_context_switch(void)
|
static inline void init_context_switch(void)
|
||||||
{
|
{
|
||||||
|
#if defined(USE_LIBCO)
|
||||||
main_thread = co_active();
|
main_thread = co_active();
|
||||||
cpu_thread = co_create(0x20000, cpu_thread_entry);
|
cpu_thread = co_create(0x20000, cpu_thread_entry);
|
||||||
|
#else
|
||||||
|
if (!retro_init_emu_thread(dynarec_enable, execute_cycles))
|
||||||
|
if (log_cb)
|
||||||
|
log_cb(RETRO_LOG_ERROR, "[gpSP]: Failed to initialize emulation thread!\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void deinit_context_switch(void)
|
static inline void deinit_context_switch(void)
|
||||||
{
|
{
|
||||||
|
#if defined(USE_LIBCO)
|
||||||
co_delete(cpu_thread);
|
co_delete(cpu_thread);
|
||||||
|
#else
|
||||||
|
retro_cancel_emu_thread();
|
||||||
|
retro_join_emu_thread();
|
||||||
|
retro_deinit_emu_thread();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(PSP)
|
#if defined(PSP)
|
||||||
|
@ -933,6 +958,20 @@ void retro_run(void)
|
||||||
{
|
{
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
|
|
||||||
|
#if !defined(USE_LIBCO)
|
||||||
|
if (!retro_is_emu_thread_initialized())
|
||||||
|
{
|
||||||
|
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (retro_emu_thread_exited())
|
||||||
|
{
|
||||||
|
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
|
||||||
|
retro_join_emu_thread();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
update_input();
|
update_input();
|
||||||
|
|
||||||
input_poll_cb();
|
input_poll_cb();
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
// This is copyrighted software. More information is at the end of this file.
|
||||||
|
#include "retro_emu_thread.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
static pthread_t main_thread;
|
||||||
|
static pthread_t emu_thread;
|
||||||
|
static pthread_mutex_t emu_mutex;
|
||||||
|
static pthread_mutex_t main_mutex;
|
||||||
|
static pthread_cond_t emu_cv;
|
||||||
|
static pthread_cond_t main_cv;
|
||||||
|
static bool emu_keep_waiting = true;
|
||||||
|
static bool main_keep_waiting = true;
|
||||||
|
static bool emu_has_exited = false;
|
||||||
|
static bool emu_thread_canceled = false;
|
||||||
|
static bool emu_thread_initialized = false;
|
||||||
|
|
||||||
|
static void* retro_run_emulator(void *args)
|
||||||
|
{
|
||||||
|
char *args_str = (char *)args;
|
||||||
|
bool dynarec = (*args_str++ == 1) ? true : false;
|
||||||
|
u32 cycles = strtol(args_str, NULL, 10);
|
||||||
|
|
||||||
|
emu_has_exited = false;
|
||||||
|
emu_thread_canceled = false;
|
||||||
|
|
||||||
|
#if defined(HAVE_DYNAREC)
|
||||||
|
if (dynarec)
|
||||||
|
execute_arm_translate(cycles);
|
||||||
|
#endif
|
||||||
|
execute_arm(cycles);
|
||||||
|
|
||||||
|
emu_has_exited = true;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void retro_switch_to_emu_thread()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&emu_mutex);
|
||||||
|
emu_keep_waiting = false;
|
||||||
|
pthread_mutex_unlock(&emu_mutex);
|
||||||
|
pthread_mutex_lock(&main_mutex);
|
||||||
|
pthread_cond_signal(&emu_cv);
|
||||||
|
|
||||||
|
main_keep_waiting = true;
|
||||||
|
while (main_keep_waiting)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&main_cv, &main_mutex);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&main_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void retro_switch_to_main_thread()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&main_mutex);
|
||||||
|
main_keep_waiting = false;
|
||||||
|
pthread_mutex_unlock(&main_mutex);
|
||||||
|
pthread_mutex_lock(&emu_mutex);
|
||||||
|
pthread_cond_signal(&main_cv);
|
||||||
|
|
||||||
|
emu_keep_waiting = true;
|
||||||
|
while (emu_keep_waiting)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&emu_cv, &emu_mutex);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&emu_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void retro_switch_thread()
|
||||||
|
{
|
||||||
|
if (pthread_self() == main_thread)
|
||||||
|
retro_switch_to_emu_thread();
|
||||||
|
else
|
||||||
|
retro_switch_to_main_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool retro_init_emu_thread(bool dynarec, u32 cycles)
|
||||||
|
{
|
||||||
|
char args[256];
|
||||||
|
args[0] = '\0';
|
||||||
|
|
||||||
|
if (emu_thread_initialized)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Keep this very simple:
|
||||||
|
* - First character: dynarec, 0/1
|
||||||
|
* - Remaining characters: cycles */
|
||||||
|
snprintf(args, sizeof(args), " %u", cycles);
|
||||||
|
args[0] = dynarec ? 1 : 0;
|
||||||
|
|
||||||
|
main_thread = pthread_self();
|
||||||
|
if (pthread_mutex_init(&main_mutex, NULL))
|
||||||
|
goto main_mutex_error;
|
||||||
|
if (pthread_mutex_init(&emu_mutex, NULL))
|
||||||
|
goto emu_mutex_error;
|
||||||
|
if (pthread_cond_init(&main_cv, NULL))
|
||||||
|
goto main_cv_error;
|
||||||
|
if (pthread_cond_init(&emu_cv, NULL))
|
||||||
|
goto emu_cv_error;
|
||||||
|
if (pthread_create(&emu_thread, NULL, retro_run_emulator, args))
|
||||||
|
goto emu_thread_error;
|
||||||
|
|
||||||
|
emu_thread_initialized = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
emu_thread_error:
|
||||||
|
pthread_cond_destroy(&emu_cv);
|
||||||
|
emu_cv_error:
|
||||||
|
pthread_cond_destroy(&main_cv);
|
||||||
|
main_cv_error:
|
||||||
|
pthread_mutex_destroy(&emu_mutex);
|
||||||
|
emu_mutex_error:
|
||||||
|
pthread_mutex_destroy(&main_mutex);
|
||||||
|
main_mutex_error:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void retro_deinit_emu_thread()
|
||||||
|
{
|
||||||
|
if (!emu_thread_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&main_mutex);
|
||||||
|
pthread_mutex_destroy(&emu_mutex);
|
||||||
|
pthread_cond_destroy(&main_cv);
|
||||||
|
pthread_cond_destroy(&emu_cv);
|
||||||
|
emu_thread_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool retro_is_emu_thread_initialized()
|
||||||
|
{
|
||||||
|
return emu_thread_initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void retro_join_emu_thread()
|
||||||
|
{
|
||||||
|
static bool is_joined = false;
|
||||||
|
if (is_joined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pthread_join(emu_thread, NULL);
|
||||||
|
is_joined = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void retro_cancel_emu_thread()
|
||||||
|
{
|
||||||
|
if (emu_thread_canceled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pthread_cancel(emu_thread);
|
||||||
|
emu_thread_canceled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool retro_emu_thread_exited()
|
||||||
|
{
|
||||||
|
return emu_has_exited;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (C) 2020 Nikos Chantziaras <realnc@gmail.com>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation, either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef EMU_THREAD_H
|
||||||
|
#define EMU_THREAD_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/* gpSP doesn't have a top-level main loop that we can use, so instead we run it in its own thread
|
||||||
|
* and switch between it and the main thread. Calling this function will block the current thread
|
||||||
|
* and unblock the other.
|
||||||
|
*
|
||||||
|
* This function can be called from either the main or the emulation thread.
|
||||||
|
*/
|
||||||
|
void retro_switch_thread(void);
|
||||||
|
|
||||||
|
/* Initialize the emulation thread and any related resources.
|
||||||
|
*
|
||||||
|
* Only call this function from the main thread.
|
||||||
|
*/
|
||||||
|
bool retro_init_emu_thread(bool dynarec, u32 cycles);
|
||||||
|
|
||||||
|
/* Destroy the emulation thread and any related resources. Only call this after the emulation thread
|
||||||
|
* has finished (or canceled) and joined.
|
||||||
|
*
|
||||||
|
* Only call this function from the main thread.
|
||||||
|
*/
|
||||||
|
void retro_deinit_emu_thread(void);
|
||||||
|
|
||||||
|
/* Returns true if the emulation thread was initialized successfully.
|
||||||
|
*
|
||||||
|
* This function can be called from either the main or the emulation thread.
|
||||||
|
*/
|
||||||
|
bool retro_is_emu_thread_initialized(void);
|
||||||
|
|
||||||
|
/* Join the emulation thread. The thread must have exited naturally or been canceled.
|
||||||
|
*
|
||||||
|
* Only call this function from the main thread.
|
||||||
|
*/
|
||||||
|
void retro_join_emu_thread(void);
|
||||||
|
|
||||||
|
/* Cancel the emulation thread.
|
||||||
|
*
|
||||||
|
* Only call this function from the main thread.
|
||||||
|
*/
|
||||||
|
void retro_cancel_emu_thread(void);
|
||||||
|
|
||||||
|
/* Returns true if the emulation thread has exited naturally.
|
||||||
|
*
|
||||||
|
* This function can be called from either the main or the emulation thread.
|
||||||
|
*/
|
||||||
|
bool retro_emu_thread_exited(void);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue