From cb774958736c62c637eab56c6aab1887d29a10fa Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sat, 30 Dec 2023 21:56:14 +0100 Subject: [PATCH 01/19] First PS2 compilation --- .github/workflows/ci.yml | 24 +++++++++ Makefile | 6 +++ configure | 13 ++++- platform/ps2/Makefile | 27 ++++++++++ platform/ps2/plat.c | 108 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 platform/ps2/Makefile create mode 100644 platform/ps2/plat.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af1f4392..fe8d360e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,6 +94,30 @@ jobs: name: PSP path: PicoDrive_psp_*.zip + build-ps2: + runs-on: ubuntu-latest + container: ps2dev/ps2dev + steps: + - name: build environment + run: | + apk add build-base cmake git zip make + - uses: actions/checkout@v3 + with: + submodules: true + - name: build + run: | + export CROSS_COMPILE=mips64r5900el-ps2-elf- + git config --global --add safe.directory $PWD + ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD) + ./configure --platform=ps2 + make -j2 + make -C platform/ps2 rel VER=$ver + - name: artifacts + uses: actions/upload-artifact@v3 + with: + name: PS2 + path: PicoDrive_ps2_*.zip + build-dingux: runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index d8f7cae0..4174c294 100644 --- a/Makefile +++ b/Makefile @@ -235,6 +235,12 @@ OBJS += platform/psp/asm_utils.o OBJS += platform/psp/mp3.o USE_FRONTEND = 1 endif +ifeq "$(PLATFORM)" "ps2" +CFLAGS += -DUSE_BGR555 # -DLOG_TO_FILE +LDLIBS += -lpatches -lgskit -ldmakit -lps2_drivers +OBJS += platform/ps2/plat.o +USE_FRONTEND = 1 +endif ifeq "$(PLATFORM)" "libretro" OBJS += platform/libretro/libretro.o ifneq ($(STATIC_LINKING), 1) diff --git a/configure b/configure index fd2d9a7e..dc887617 100755 --- a/configure +++ b/configure @@ -39,7 +39,7 @@ check_define() # "" means "autodetect". # TODO this is annoyingly messy. should have platform and device -platform_list="generic pandora gph dingux retrofw opendingux[-gcw0] odbeta[-gcw0] miyoo rpi1 rpi2 psp" +platform_list="generic pandora gph dingux retrofw opendingux[-gcw0] odbeta[-gcw0] miyoo rpi1 rpi2 ps2 psp" platform="generic" sound_driver_list="oss alsa sdl" sound_drivers="" @@ -59,6 +59,7 @@ CC="${CC-${CROSS_COMPILE}gcc}" CXX="${CXX-${CROSS_COMPILE}g++}" AS="${AS-${CROSS_COMPILE}as}" STRIP="${STRIP-${CROSS_COMPILE}strip}" +LD="${LD-${CROSS_COMPILE}gcc}" # Use better gcc for linking SYSROOT=`$CC $CFLAGS $LDFLAGS --print-sysroot 2> /dev/null || true` config_mak="config.mak" @@ -150,6 +151,15 @@ set_platform() MFLAGS="-march=allegrex" ARCH=mipsel ;; + ps2) + # use newlib + SYSLIBS="" + MFLAGS="" + ARCH=mips64r5900el + ASFLAGS="$ASFLAGS -G0 -call_shared" + CFLAGS="$CFLAGS -D_EE -G0 -I${PS2SDK}/ee/include -I${PS2SDK}/common/include -I${PS2SDK}/ports/include" + LDFLAGS="$LDFLAGS -Wl,-zmax-page-size=128 -T${PS2SDK}/ee/startup/linkfile -L${PS2SDK}/ee/lib -L${PS2SDK}/ports/lib" + ;; *) fail "unsupported platform: $platform" ;; @@ -457,6 +467,7 @@ echo "CC = $CC" >> $config_mak echo "CXX = $CXX" >> $config_mak echo "AS = $AS" >> $config_mak echo "STRIP = $STRIP" >> $config_mak +echo "LD = $LD" >> $config_mak echo "CFLAGS += $MFLAGS $CFLAGS" >> $config_mak echo "ASFLAGS += $MFLAGS $ASFLAGS" >> $config_mak echo "LDFLAGS += $LDFLAGS" >> $config_mak diff --git a/platform/ps2/Makefile b/platform/ps2/Makefile new file mode 100644 index 00000000..42ba39d6 --- /dev/null +++ b/platform/ps2/Makefile @@ -0,0 +1,27 @@ + +# ----------- release ----------- +ifneq ($(findstring rel,$(MAKECMDGOALS)),) +ifeq ($(VER),) +$(error need VER) +endif +endif + +../../tools/textfilter: ../../tools/textfilter.c + make -C ../../tools/ textfilter + +readme.txt: ../../tools/textfilter ../base_readme.txt ../../ChangeLog + ../../tools/textfilter ../base_readme.txt $@ PS2 + +# ? +rel: ../../PicoDrive readme.txt ../game_def.cfg + mkdir -p PicoDrive/skin/ + cp $^ PicoDrive/ + cp ../../skin/* PicoDrive/skin/ + zip -9 -r ../../PicoDrive_ps2_$(VER).zip PicoDrive + rm -rf PicoDrive + mkdir bin_to_cso_mp3 + cp ../../tools/bin_to_cso_mp3/* bin_to_cso_mp3/ + zip -9 -r ../../PicoDrive_ps2_$(VER).zip bin_to_cso_mp3 + rm -rf bin_to_cso_mp3 + + diff --git a/platform/ps2/plat.c b/platform/ps2/plat.c new file mode 100644 index 00000000..02681734 --- /dev/null +++ b/platform/ps2/plat.c @@ -0,0 +1,108 @@ +#include +#include + +#include "../libpicofe/plat.h" + +const char *renderer_names[] = { "Software", "Hardware" }; +const char *renderer_names32x[] = { "Software", "Hardware", "Hardware (fast)" }; + +struct plat_target plat_target = {}; + +int plat_parse_arg(int argc, char *argv[], int *x) { return 1; } + +void plat_early_init(void) {} + +int plat_target_init(void) { return 0; } + +void plat_init(void) {} + +void plat_video_menu_enter(int is_rom_loaded) {} + +void plat_video_menu_leave(void) {} + +void plat_finish(void) {} + +void plat_target_finish(void) {} + +void plat_video_menu_begin(void) {} + +void plat_video_menu_end(void) {} + +int plat_get_root_dir(char *dst, int len) { return 0; } + + +unsigned int plat_get_ticks_ms(void) { return 0; } + +unsigned int plat_get_ticks_us(void) { return 0; } + +void plat_sleep_ms(int ms) {} + +void plat_video_toggle_renderer(int change, int menu_call) {} + +void plat_update_volume(int has_changed, int is_up) {} + +int plat_is_dir(const char *path) { return 0; } + +void plat_status_msg_busy_first(const char *msg) {} + +void pemu_prep_defconfig(void) {} + +void pemu_validate_config(void) {} + +void plat_status_msg_clear(void) {} + +void plat_status_msg_busy_next(const char *msg) {} + +void plat_video_loop_prepare(void) {} + +int plat_get_data_dir(char *dst, int len) { return 0; } + +void plat_video_flip(void) {} + +void plat_video_wait_vsync(void) {} + +void plat_wait_till_us(unsigned int us) {} + +int plat_get_skin_dir(char *dst, int len) { return 0; } + +void plat_debug_cat(char *str) {} + +int plat_wait_event(int *fds_hnds, int count, int timeout_ms) { return 0; } + +void pemu_loop_prep(void) {} + +void pemu_sound_start(void) {} + +void pemu_loop_end(void) {} + +void *plat_mem_get_for_drc(size_t size) { return NULL; } + +void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed) { return NULL; } + +void *plat_mremap(void *ptr, size_t oldsize, size_t newsize) { return NULL; } + +void plat_munmap(void *ptr, size_t size) {} + +int plat_mem_set_exec(void *ptr, size_t size) { return 0; } + +void emu_video_mode_change(int start_line, int line_count, int start_col, int col_count) {} + +void pemu_forced_frame(int no_scale, int do_emu) {} + +void pemu_finalize_frame(const char *fps, const char *notice_msg) {} + +int _flush_cache (char *addr, const int size, const int op) { return 0; } + +/* lprintf */ +void lprintf(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); +#if defined(LOG_TO_FILE) + vfprintf(logFile, fmt, vl); +#else + vprintf(fmt, vl); +#endif + va_end(vl); +} \ No newline at end of file From 936f164b559ccec173d7beed43049bd20f8bcd0f Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 31 Dec 2023 00:38:09 +0100 Subject: [PATCH 02/19] Starting to boot --- platform/ps2/plat.c | 276 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 227 insertions(+), 49 deletions(-) diff --git a/platform/ps2/plat.c b/platform/ps2/plat.c index 02681734..c3585dff 100644 --- a/platform/ps2/plat.c +++ b/platform/ps2/plat.c @@ -1,5 +1,21 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include "../libpicofe/plat.h" @@ -8,90 +24,222 @@ const char *renderer_names32x[] = { "Software", "Hardware", "Hardware (fast)" }; struct plat_target plat_target = {}; -int plat_parse_arg(int argc, char *argv[], int *x) { return 1; } +static void reset_IOP() { + SifInitRpc(0); +#if !defined(DEBUG) || defined(BUILD_FOR_PCSX2) + /* Comment this line if you don't wanna debug the output */ + while (!SifIopReset(NULL, 0)) {}; +#endif -void plat_early_init(void) {} + while (!SifIopSync()) {}; + SifInitRpc(0); + sbv_patch_enable_lmb(); + sbv_patch_disable_prefix_check(); +} -int plat_target_init(void) { return 0; } +static void init_drivers() { + init_ps2_filesystem_driver(); +} -void plat_init(void) {} +static void deinit_drivers() { + deinit_ps2_filesystem_driver(); +} -void plat_video_menu_enter(int is_rom_loaded) {} - -void plat_video_menu_leave(void) {} - -void plat_finish(void) {} - -void plat_target_finish(void) {} - -void plat_video_menu_begin(void) {} - -void plat_video_menu_end(void) {} - -int plat_get_root_dir(char *dst, int len) { return 0; } +void plat_init(void) +{ + init_joystick_driver(false); + init_audio_driver(); +} -unsigned int plat_get_ticks_ms(void) { return 0; } +void plat_finish(void) { + deinit_audio_driver(); + deinit_joystick_driver(false); +} -unsigned int plat_get_ticks_us(void) { return 0; } +int plat_target_init(void) +{ + return 0; +} -void plat_sleep_ms(int ms) {} +/* System level deinitialization */ +void plat_target_finish(void) +{ + deinit_drivers(); +} -void plat_video_toggle_renderer(int change, int menu_call) {} +/* display a completed frame buffer and prepare a new render buffer */ +void plat_video_flip(void) +{ -void plat_update_volume(int has_changed, int is_up) {} +} -int plat_is_dir(const char *path) { return 0; } +/* wait for start of vertical blanking */ +void plat_video_wait_vsync(void) +{ +} -void plat_status_msg_busy_first(const char *msg) {} +/* switch from emulation display to menu display */ +void plat_video_menu_enter(int is_rom_loaded) +{ -void pemu_prep_defconfig(void) {} +} -void pemu_validate_config(void) {} +/* start rendering a menu screen */ +void plat_video_menu_begin(void) +{ -void plat_status_msg_clear(void) {} +} -void plat_status_msg_busy_next(const char *msg) {} +/* display a completed menu screen */ +void plat_video_menu_end(void) +{ -void plat_video_loop_prepare(void) {} +} -int plat_get_data_dir(char *dst, int len) { return 0; } +/* terminate menu display */ +void plat_video_menu_leave(void) +{ -void plat_video_flip(void) {} +} -void plat_video_wait_vsync(void) {} +int plat_parse_arg(int argc, char *argv[], int *x) +{ + return 1; +} -void plat_wait_till_us(unsigned int us) {} +/* Preliminary initialization needed at program start */ +void plat_early_init(void) { + reset_IOP(); + init_drivers(); +#if defined(LOG_TO_FILE) + log_init(); +#endif +} -int plat_get_skin_dir(char *dst, int len) { return 0; } +/* base directory for configuration and save files */ +int plat_get_root_dir(char *dst, int len) +{ + getcwd(dst, len); + // We need to append / at the end + strcat(dst, "/"); + return strlen(dst); +} -void plat_debug_cat(char *str) {} +/* base directory for emulator resources */ +int plat_get_skin_dir(char *dst, int len) +{ + if (len > 5) + strcpy(dst, "skin/"); + else if (len > 0) + *dst = 0; + return strlen(dst); +} -int plat_wait_event(int *fds_hnds, int count, int timeout_ms) { return 0; } +/* top directory for rom images */ +int plat_get_data_dir(char *dst, int len) +{ + getcwd(dst, len); + return strlen(dst); +} -void pemu_loop_prep(void) {} +/* check if path is a directory */ +int plat_is_dir(const char *path) +{ + DIR *dir; + if ((dir = opendir(path))) { + closedir(dir); + return 1; + } + return 0; +} -void pemu_sound_start(void) {} +/* current time in ms */ +unsigned int plat_get_ticks_ms(void) +{ + struct timeval tv; + unsigned int ret; -void pemu_loop_end(void) {} + gettimeofday(&tv, NULL); -void *plat_mem_get_for_drc(size_t size) { return NULL; } + ret = (unsigned)tv.tv_sec * 1000; + /* approximate /= 1000 */ + ret += ((unsigned)tv.tv_usec * 4195) >> 22; -void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed) { return NULL; } + return ret; +} -void *plat_mremap(void *ptr, size_t oldsize, size_t newsize) { return NULL; } +/* current time in us */ +unsigned int plat_get_ticks_us(void) +{ + struct timeval tv; + unsigned int ret; -void plat_munmap(void *ptr, size_t size) {} + gettimeofday(&tv, NULL); -int plat_mem_set_exec(void *ptr, size_t size) { return 0; } + ret = (unsigned)tv.tv_sec * 1000000; + ret += (unsigned)tv.tv_usec; -void emu_video_mode_change(int start_line, int line_count, int start_col, int col_count) {} + return ret; +} -void pemu_forced_frame(int no_scale, int do_emu) {} +/* sleep for some time in ms */ +void plat_sleep_ms(int ms) +{ + usleep(ms * 1000); +} -void pemu_finalize_frame(const char *fps, const char *notice_msg) {} +/* sleep for some time in us */ +void plat_wait_till_us(unsigned int us_to) +{ + usleep(us_to - plat_get_ticks_us()); +} -int _flush_cache (char *addr, const int size, const int op) { return 0; } +/* wait until some event occurs, or timeout */ +int plat_wait_event(int *fds_hnds, int count, int timeout_ms) +{ + return 0; // unused +} + +/* memory mapping functions */ +void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed) +{ + return malloc(size); +} + +void *plat_mremap(void *ptr, size_t oldsize, size_t newsize) +{ + return realloc(ptr, newsize); +} + +void plat_munmap(void *ptr, size_t size) +{ + free(ptr); +} + +void *plat_mem_get_for_drc(size_t size) +{ + return NULL; +} + +int plat_mem_set_exec(void *ptr, size_t size) +{ + return 0; +} + +int _flush_cache (char *addr, const int size, const int op) +{ + FlushCache(WRITEBACK_DCACHE); /* WRITEBACK_DCACHE */ + FlushCache(INVALIDATE_ICACHE); /* INVALIDATE_ICACHE */ + return 0; +} + +int posix_memalign(void **p, size_t align, size_t size) +{ + if (p) + *p = memalign(align, size); + return (p ? *p ? 0 : ENOMEM : EINVAL); +} /* lprintf */ void lprintf(const char *fmt, ...) @@ -105,4 +253,34 @@ void lprintf(const char *fmt, ...) vprintf(fmt, vl); #endif va_end(vl); -} \ No newline at end of file +} + +void plat_video_toggle_renderer(int change, int menu_call) {} + +void plat_update_volume(int has_changed, int is_up) {} + +void plat_status_msg_busy_first(const char *msg) {} + +void pemu_prep_defconfig(void) {} + +void pemu_validate_config(void) {} + +void plat_status_msg_clear(void) {} + +void plat_status_msg_busy_next(const char *msg) {} + +void plat_video_loop_prepare(void) {} + +void plat_debug_cat(char *str) {} + +void pemu_loop_prep(void) {} + +void pemu_sound_start(void) {} + +void pemu_loop_end(void) {} + +void emu_video_mode_change(int start_line, int line_count, int start_col, int col_count) {} + +void pemu_forced_frame(int no_scale, int do_emu) {} + +void pemu_finalize_frame(const char *fps, const char *notice_msg) {} \ No newline at end of file From 9b4c95a951f87a2169952d1017253e273ca71ffb Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 31 Dec 2023 00:51:49 +0100 Subject: [PATCH 03/19] Fix folder creation --- platform/common/emu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/common/emu.c b/platform/common/emu.c index 92375ea5..5e51d934 100644 --- a/platform/common/emu.c +++ b/platform/common/emu.c @@ -1243,7 +1243,7 @@ static void mkdir_path(char *path_with_reserve, int pos, const char *name) strcpy(path_with_reserve + pos, name); if (plat_is_dir(path_with_reserve)) return; - if (mkdir(path_with_reserve, 0777) < 0) + if (mkdir(path_with_reserve, 0755) < 0) lprintf("failed to create: %s\n", path_with_reserve); } From 8b65c92f1f7084212fbebed4a9465c79f1dcc582 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 31 Dec 2023 00:52:01 +0100 Subject: [PATCH 04/19] Use MenuX2 in PS2 --- platform/common/menu_pico.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index e48fa402..a9fc7900 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -19,7 +19,7 @@ #include #include -#ifdef PANDORA +#if defined(PANDORA) || defined(__PS2__) #define MENU_X2 1 #else #define MENU_X2 0 From e22b24b81ae63f29596eeae2fb2112e75e424f5b Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 31 Dec 2023 17:00:46 +0100 Subject: [PATCH 05/19] First dummy input implementation --- Makefile | 2 + platform/ps2/emu.c | 41 +++++++ platform/ps2/in_ps2.c | 268 ++++++++++++++++++++++++++++++++++++++++++ platform/ps2/in_ps2.h | 6 + platform/ps2/plat.c | 12 -- 5 files changed, 317 insertions(+), 12 deletions(-) create mode 100644 platform/ps2/emu.c create mode 100644 platform/ps2/in_ps2.c create mode 100644 platform/ps2/in_ps2.h diff --git a/Makefile b/Makefile index 4174c294..cbed7900 100644 --- a/Makefile +++ b/Makefile @@ -239,6 +239,8 @@ ifeq "$(PLATFORM)" "ps2" CFLAGS += -DUSE_BGR555 # -DLOG_TO_FILE LDLIBS += -lpatches -lgskit -ldmakit -lps2_drivers OBJS += platform/ps2/plat.o +OBJS += platform/ps2/emu.o +OBJS += platform/ps2/in_ps2.o USE_FRONTEND = 1 endif ifeq "$(PLATFORM)" "libretro" diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c new file mode 100644 index 00000000..4ff7f16a --- /dev/null +++ b/platform/ps2/emu.c @@ -0,0 +1,41 @@ +#include + +#include +#include +#include + +#include "in_ps2.h" +#include "../libpicofe/input.h" +#include "../common/input_pico.h" +#include "../common/emu.h" + +static struct in_default_bind in_ps2_defbinds[] = +{ + { PAD_UP, IN_BINDTYPE_PLAYER12, GBTN_UP }, + { PAD_DOWN, IN_BINDTYPE_PLAYER12, GBTN_DOWN }, + { PAD_LEFT, IN_BINDTYPE_PLAYER12, GBTN_LEFT }, + { PAD_RIGHT, IN_BINDTYPE_PLAYER12, GBTN_RIGHT }, + { PAD_SQUARE, IN_BINDTYPE_PLAYER12, GBTN_A }, + { PAD_CROSS, IN_BINDTYPE_PLAYER12, GBTN_B }, + { PAD_CIRCLE, IN_BINDTYPE_PLAYER12, GBTN_C }, + { PAD_START, IN_BINDTYPE_PLAYER12, GBTN_START }, + { PAD_TRIANGLE, IN_BINDTYPE_EMU, PEVB_SWITCH_RND }, + { PAD_L1, IN_BINDTYPE_EMU, PEVB_STATE_SAVE }, + { PAD_R1, IN_BINDTYPE_EMU, PEVB_STATE_LOAD }, + { PAD_SELECT, IN_BINDTYPE_EMU, PEVB_MENU }, + { 0, 0, 0 } +}; + +void plat_init(void) +{ + init_joystick_driver(false); + in_ps2_init(in_ps2_defbinds); + in_probe(); + init_audio_driver(); + // plat_get_data_dir(rom_fname_loaded, sizeof(rom_fname_loaded)); +} + +void plat_finish(void) { + deinit_audio_driver(); + deinit_joystick_driver(false); +} \ No newline at end of file diff --git a/platform/ps2/in_ps2.c b/platform/ps2/in_ps2.c new file mode 100644 index 00000000..d58d514c --- /dev/null +++ b/platform/ps2/in_ps2.c @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "libpad.h" +#include "libmtap.h" + +#include "../libpicofe/input.h" +#include "in_ps2.h" + +#define IN_PS2_PREFIX "ps2:" +#define IN_PS2_NBUTTONS 32 +#define ANALOG_DEADZONE 80 + +/* note: in_ps2 handles combos (if 2 btns have the same bind, + * both must be pressed for action to happen) */ +static int in_ps2_combo_keys = 0; +static int in_ps2_combo_acts = 0; + +static uintptr_t padBuf[2][4]; +static uint32_t padConnected[2][4]; // 2 ports, 4 slots +static uint32_t padOpen[2][4]; +static uint32_t maxslot[2]; + + +static const char *in_ps2_keys[IN_PS2_NBUTTONS] = { + [0 ... IN_PS2_NBUTTONS-1] = NULL, +}; + + +/* calculate bit number from bit mask (logarithm to the basis 2) */ +static int lg2(unsigned v) +{ + /* credits to https://graphics.stanford.edu/~seander/bithacks.html */ + int r, s; + + r = (v > 0xFFFF) << 4; v >>= r; + s = (v > 0xFF ) << 3; v >>= s; r |= s; + s = (v > 0xF ) << 2; v >>= s; r |= s; + s = (v > 0x3 ) << 1; v >>= s; r |= s; + r |= (v >> 1); + return r; +} + +static unsigned int ps2_pad_read() +{ + unsigned int paddata; + struct padButtonStatus buttons; + int32_t ret, port, slot; + + + // Using for now port 0, slot 0 + port = 0; + slot = 0; + + ret = padRead(port, slot, &buttons); + + if (ret != 0) { + paddata = 0xffff ^ buttons.btns; + } + + // analog.. + // buttons &= ~(PS2_NUB_UP|PS2_NUB_DOWN|PS2_NUB_LEFT|PS2_NUB_RIGHT); + // if (pad.Lx < 128 - ANALOG_DEADZONE) buttons |= PS2_NUB_LEFT; + // if (pad.Lx > 128 + ANALOG_DEADZONE) buttons |= PS2_NUB_RIGHT; + // if (pad.Ly < 128 - ANALOG_DEADZONE) buttons |= PS2_NUB_UP; + // if (pad.Ly > 128 + ANALOG_DEADZONE) buttons |= PS2_NUB_DOWN; + + return paddata; +} + +static unsigned in_ps2_get_bits(void) +{ + unsigned mask = + PAD_UP|PAD_DOWN|PAD_LEFT|PAD_RIGHT | + PAD_CIRCLE|PAD_CROSS|PAD_TRIANGLE|PAD_SQUARE | + PAD_L1|PAD_R1|PAD_SELECT|PAD_START; + // PS2_NUB_UP|PS2_NUB_DOWN|PS2_NUB_LEFT|PS2_NUB_RIGHT | + + return ps2_pad_read() & mask; +} + +static void in_ps2_probe(const in_drv_t *drv) +{ + in_register(IN_PS2_PREFIX "PS2 pad", -1, NULL, + IN_PS2_NBUTTONS, in_ps2_keys, 1); +} + +static void in_ps2_free(void *drv_data) +{ + +} + +static const char * const * +in_ps2_get_key_names(const in_drv_t *drv, int *count) +{ + *count = IN_PS2_NBUTTONS; + return in_ps2_keys; +} + +/* ORs result with pressed buttons */ +static int in_ps2_update(void *drv_data, const int *binds, int *result) +{ + int type_start = 0; + int i, t; + unsigned keys; + + keys = in_ps2_get_bits(); + + if (keys & in_ps2_combo_keys) { + result[IN_BINDTYPE_EMU] = in_combos_do(keys, binds, IN_PS2_NBUTTONS, + in_ps2_combo_keys, in_ps2_combo_acts); + type_start = IN_BINDTYPE_PLAYER12; + } + + for (i = 0; keys; i++, keys >>= 1) { + if (!(keys & 1)) + continue; + + for (t = type_start; t < IN_BINDTYPE_COUNT; t++) + result[t] |= binds[IN_BIND_OFFS(i, t)]; + } + + return 0; +} + +int in_ps2_update_keycode(void *data, int *is_down) +{ + static unsigned old_val = 0; + unsigned val, diff, i; + + val = in_ps2_get_bits(); + diff = val ^ old_val; + if (diff == 0) + return -1; + + /* take one bit only */ + for (i = 0; i < sizeof(diff)*8; i++) + if (diff & (1< kc */ + keycode = -keycode; + for (i = 0; i < KEY_PBTN_MAP_SIZE; i++) + if (key_pbtn_map[i].pbtn == keycode) + return key_pbtn_map[i].key; + } + else + { + for (i = 0; i < KEY_PBTN_MAP_SIZE; i++) + if (key_pbtn_map[i].key == keycode) + return key_pbtn_map[i].pbtn; + } + + return 0; +} + +/* remove binds of missing keys, count remaining ones */ +static int in_ps2_clean_binds(void *drv_data, int *binds, int *def_binds) +{ + int i, count = 0; + + for (i = 0; i < IN_PS2_NBUTTONS; i++) { + int t, offs; + for (t = 0; t < IN_BINDTYPE_COUNT; t++) { + offs = IN_BIND_OFFS(i, t); + if (in_ps2_keys[i] == NULL) + binds[offs] = def_binds[offs] = 0; + if (binds[offs]) + count++; + } + } + + in_combos_find(binds, IN_PS2_NBUTTONS, &in_ps2_combo_keys, &in_ps2_combo_acts); + + return count; +} + +static const in_drv_t in_ps2_drv = { + .prefix = IN_PS2_PREFIX, + .probe = in_ps2_probe, + .free = in_ps2_free, + .get_key_names = in_ps2_get_key_names, + .clean_binds = in_ps2_clean_binds, + .update = in_ps2_update, + .update_keycode = in_ps2_update_keycode, + .menu_translate = in_ps2_menu_translate, +}; + +void in_ps2_init(struct in_default_bind *defbinds) +{ + int i, j; + + for (j = 0; j < 2; j++) { + mtapPortOpen(j); + + for (i = 0; i < 4; i++) { + padConnected[j][i] = 0; + padOpen[j][i] = 0; + padBuf[j][i] = memalign(64, 256); + padPortOpen(j, i, padBuf[j][i]); + } + } + + /* PS2 keys have bit masks, Picodrive wants bit numbers */ + for (i = 0; defbinds[i].code; i++) + defbinds[i].code = lg2(defbinds[i].code); + for (i = 0; i < KEY_PBTN_MAP_SIZE; i++) + key_pbtn_map[i].key = lg2(key_pbtn_map[i].key); + + in_ps2_combo_keys = in_ps2_combo_acts = 0; + + /* fill keys array, converting key bitmasks to bit numbers */ + in_ps2_keys[lg2(PAD_UP)] = "Up"; + in_ps2_keys[lg2(PAD_LEFT)] = "Left"; + in_ps2_keys[lg2(PAD_DOWN)] = "Down"; + in_ps2_keys[lg2(PAD_RIGHT)] = "Right"; + in_ps2_keys[lg2(PAD_START)] = "Start"; + in_ps2_keys[lg2(PAD_SELECT)] = "Select"; + in_ps2_keys[lg2(PAD_L1)] = "L1"; + in_ps2_keys[lg2(PAD_R1)] = "R1"; + in_ps2_keys[lg2(PAD_TRIANGLE)] = "Triangle"; + in_ps2_keys[lg2(PAD_CIRCLE)] = "Circle"; + in_ps2_keys[lg2(PAD_CROSS)] = "Cross"; + in_ps2_keys[lg2(PAD_SQUARE)] = "Square"; + // in_ps2_keys[lg2(PS2_NUB_UP)] = "Analog up"; + // in_ps2_keys[lg2(PS2_NUB_LEFT)] = "Analog left"; + // in_ps2_keys[lg2(PS2_NUB_DOWN)] = "Analog down"; + // in_ps2_keys[lg2(PS2_NUB_RIGHT)] = "Analog right"; + + in_register_driver(&in_ps2_drv, defbinds, NULL); +} + diff --git a/platform/ps2/in_ps2.h b/platform/ps2/in_ps2.h new file mode 100644 index 00000000..0f9bc8df --- /dev/null +++ b/platform/ps2/in_ps2.h @@ -0,0 +1,6 @@ + +struct in_default_bind; + +void in_ps2_init(struct in_default_bind *defbinds); + +void in_ps2_deinit(); diff --git a/platform/ps2/plat.c b/platform/ps2/plat.c index c3585dff..02b3d73d 100644 --- a/platform/ps2/plat.c +++ b/platform/ps2/plat.c @@ -45,18 +45,6 @@ static void deinit_drivers() { deinit_ps2_filesystem_driver(); } -void plat_init(void) -{ - init_joystick_driver(false); - init_audio_driver(); -} - - -void plat_finish(void) { - deinit_audio_driver(); - deinit_joystick_driver(false); -} - int plat_target_init(void) { return 0; From ebf2b007d1a8b04e3d2fed4147727245758a484f Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 31 Dec 2023 18:10:25 +0100 Subject: [PATCH 06/19] Starting to copy some logic for emu from PSP --- platform/ps2/emu.c | 265 ++++++++++++++++++++++++++++++++++++++++++++ platform/ps2/plat.c | 35 +----- 2 files changed, 267 insertions(+), 33 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index 4ff7f16a..c0dd7d25 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -1,14 +1,26 @@ #include +#include #include #include #include #include "in_ps2.h" #include "../libpicofe/input.h" +#include "../libpicofe/plat.h" #include "../common/input_pico.h" #include "../common/emu.h" +#include + +#define OSD_FPS_X 220 + +static int osd_buf_cnt, osd_cdleds; + +static int out_x, out_y; +static int out_w, out_h; +static float hscale, vscale; + static struct in_default_bind in_ps2_defbinds[] = { { PAD_UP, IN_BINDTYPE_PLAYER12, GBTN_UP }, @@ -26,6 +38,145 @@ static struct in_default_bind in_ps2_defbinds[] = { 0, 0, 0 } }; +const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast", NULL }; +const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL }; +enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT }; + +#define is_16bit_mode() \ + (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X)) + +static int get_renderer(void) +{ + if (PicoIn.AHW & PAHW_32X) + return currentConfig.renderer32x; + else + return currentConfig.renderer; +} + +static void change_renderer(int diff) +{ + int *r; + if (PicoIn.AHW & PAHW_32X) + r = ¤tConfig.renderer32x; + else + r = ¤tConfig.renderer; + *r += diff; + + if (*r >= RT_COUNT) + *r = 0; + else if (*r < 0) + *r = RT_COUNT - 1; +} + +static void apply_renderer(void) +{ + PicoIn.opt &= ~(POPT_ALT_RENDERER|POPT_EN_SOFTSCALE); + PicoIn.opt |= POPT_DIS_32C_BORDER; + + switch (get_renderer()) { + case RT_16BIT: + PicoDrawSetOutFormat(PDF_RGB555, 0); + break; + case RT_8BIT_ACC: + PicoDrawSetOutFormat(PDF_8BIT, 0); + break; + case RT_8BIT_FAST: + PicoIn.opt |= POPT_ALT_RENDERER; + PicoDrawSetOutFormat(PDF_NONE, 0); + break; + } +} + +static void osd_text(int x, const char *text) +{ + +} + +static void blit_osd(void) +{ + +} + +static void cd_leds(void) +{ + +} + +static void blit_cdleds(void) +{ + +} + +void blitscreen_clut(void) +{ + + blit_osd(); + blit_cdleds(); +} + +static void draw_pico_ptr(void) +{ + // unsigned char *p = (unsigned char *)g_screen_ptr + 8; + + // // only if pen enabled and for 8bit mode + // if (pico_inp_mode == 0 || is_16bit_mode()) return; + + // p += 512 * (pico_pen_y + PICO_PEN_ADJUST_Y); + // p += pico_pen_x + PICO_PEN_ADJUST_X; + // if (!(Pico.video.reg[12]&1) && !(PicoIn.opt & POPT_DIS_32C_BORDER)) + // p += 32; + + // p[ -1] = 0xe0; p[ 0] = 0xf0; p[ 1] = 0xe0; + // p[ 511] = 0xf0; p[ 512] = 0xf0; p[ 513] = 0xf0; + // p[1023] = 0xe0; p[1024] = 0xf0; p[1025] = 0xe0; +} + +static void vidResetMode(void) {} + +void pemu_sound_start(void) {} +void pemu_sound_stop(void) {} + +/* set default configuration values */ +void pemu_prep_defconfig(void) +{ + defaultConfig.s_PsndRate = 44100; + defaultConfig.s_PicoCDBuffers = 64; + defaultConfig.filter = EOPT_FILTER_BILINEAR; // bilinear filtering + defaultConfig.scaling = EOPT_SCALE_43; + defaultConfig.vscaling = EOPT_VSCALE_FULL; + defaultConfig.renderer = RT_8BIT_ACC; + defaultConfig.renderer32x = RT_8BIT_ACC; + defaultConfig.EmuOpt |= EOPT_SHOW_RTC; +} + +/* check configuration for inconsistencies */ +void pemu_validate_config(void) +{ + if (currentConfig.gamma < -4 || currentConfig.gamma > 16) + currentConfig.gamma = 0; + if (currentConfig.gamma2 < 0 || currentConfig.gamma2 > 2) + currentConfig.gamma2 = 0; +} + +/* finalize rendering a frame */ +void pemu_finalize_frame(const char *fps, const char *notice) +{ + int emu_opt = currentConfig.EmuOpt; + + if (PicoIn.AHW & PAHW_PICO) + draw_pico_ptr(); + + osd_buf_cnt = 0; + if (notice) osd_text(4, notice); + if (emu_opt & 2) osd_text(OSD_FPS_X, fps); + + osd_cdleds = 0; + if ((emu_opt & 0x400) && (PicoIn.AHW & PAHW_MCD)) + cd_leds(); + + FlushCache(WRITEBACK_DCACHE); +} + void plat_init(void) { init_joystick_driver(false); @@ -38,4 +189,118 @@ void plat_init(void) void plat_finish(void) { deinit_audio_driver(); deinit_joystick_driver(false); +} + +/* display emulator status messages before holding emulation */ +void plat_status_msg_busy_first(const char *msg) +{ + plat_status_msg_busy_next(msg); +} + +void plat_status_msg_busy_next(const char *msg) +{ + plat_status_msg_clear(); + pemu_finalize_frame("", msg); + plat_video_flip(); + emu_status_msg(""); + reset_timing = 1; +} + +/* clear status message area */ +void plat_status_msg_clear(void) +{ + // not needed since the screen buf is cleared through the GU +} + +/* change the audio volume setting */ +void plat_update_volume(int has_changed, int is_up) +{ +} + +/* prepare for MD screen mode change */ +void emu_video_mode_change(int start_line, int line_count, int start_col, int col_count) +{ + int h43 = (col_count >= 192 ? 320 : col_count); // ugh, mind GG... + int v43 = (line_count >= 192 ? Pico.m.pal ? 240 : 224 : line_count); + + out_y = start_line; out_x = start_col; + out_h = line_count; out_w = col_count; + + if (col_count == 248) // mind aspect ratio when blanking 1st column + col_count = 256; + + switch (currentConfig.vscaling) { + case EOPT_VSCALE_FULL: + line_count = v43; + vscale = (float)270/line_count; + break; + case EOPT_VSCALE_NOBORDER: + vscale = (float)270/line_count; + break; + default: + vscale = 1; + break; + } + + switch (currentConfig.scaling) { + case EOPT_SCALE_43: + hscale = (vscale*h43)/col_count; + break; + case EOPT_SCALE_STRETCH: + hscale = (vscale*h43/2 + 480/2)/col_count; + break; + case EOPT_SCALE_WIDE: + hscale = (float)480/col_count; + break; + default: + hscale = vscale; + break; + } + + vidResetMode(); +} + +/* render one frame in RGB */ +void pemu_forced_frame(int no_scale, int do_emu) +{ + Pico.m.dirtyPal = 1; + + if (!no_scale) + no_scale = currentConfig.scaling == EOPT_SCALE_NONE; + emu_cmn_forced_frame(no_scale, do_emu, g_screen_ptr); +} + +/* change the platform output rendering */ +void plat_video_toggle_renderer(int change, int is_menu_call) +{ + change_renderer(change); + + if (is_menu_call) + return; + + apply_renderer(); + vidResetMode(); + rendstatus_old = -1; + + if (PicoIn.AHW & PAHW_32X) + emu_status_msg(renderer_names32x[get_renderer()]); + else + emu_status_msg(renderer_names[get_renderer()]); +} + +/* prepare for emulator output rendering */ +void plat_video_loop_prepare(void) +{ + apply_renderer(); + vidResetMode(); +} + +/* prepare for entering the emulator loop */ +void pemu_loop_prep(void) +{ +} + +/* terminate the emulator loop */ +void pemu_loop_end(void) +{ } \ No newline at end of file diff --git a/platform/ps2/plat.c b/platform/ps2/plat.c index 02b3d73d..418e5310 100644 --- a/platform/ps2/plat.c +++ b/platform/ps2/plat.c @@ -19,9 +19,6 @@ #include "../libpicofe/plat.h" -const char *renderer_names[] = { "Software", "Hardware" }; -const char *renderer_names32x[] = { "Software", "Hardware", "Hardware (fast)" }; - struct plat_target plat_target = {}; static void reset_IOP() { @@ -59,7 +56,7 @@ void plat_target_finish(void) /* display a completed frame buffer and prepare a new render buffer */ void plat_video_flip(void) { - + blitscreen_clut(); } /* wait for start of vertical blanking */ @@ -243,32 +240,4 @@ void lprintf(const char *fmt, ...) va_end(vl); } -void plat_video_toggle_renderer(int change, int menu_call) {} - -void plat_update_volume(int has_changed, int is_up) {} - -void plat_status_msg_busy_first(const char *msg) {} - -void pemu_prep_defconfig(void) {} - -void pemu_validate_config(void) {} - -void plat_status_msg_clear(void) {} - -void plat_status_msg_busy_next(const char *msg) {} - -void plat_video_loop_prepare(void) {} - -void plat_debug_cat(char *str) {} - -void pemu_loop_prep(void) {} - -void pemu_sound_start(void) {} - -void pemu_loop_end(void) {} - -void emu_video_mode_change(int start_line, int line_count, int start_col, int col_count) {} - -void pemu_forced_frame(int no_scale, int do_emu) {} - -void pemu_finalize_frame(const char *fps, const char *notice_msg) {} \ No newline at end of file +void plat_debug_cat(char *str) {} \ No newline at end of file From 888ca0b83ba33424a7ecd242f4fb23c402aade30 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 31 Dec 2023 18:27:46 +0100 Subject: [PATCH 07/19] Adding gskit dependency --- configure | 4 +-- platform/ps2/emu.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/configure b/configure index dc887617..e73c6959 100755 --- a/configure +++ b/configure @@ -157,8 +157,8 @@ set_platform() MFLAGS="" ARCH=mips64r5900el ASFLAGS="$ASFLAGS -G0 -call_shared" - CFLAGS="$CFLAGS -D_EE -G0 -I${PS2SDK}/ee/include -I${PS2SDK}/common/include -I${PS2SDK}/ports/include" - LDFLAGS="$LDFLAGS -Wl,-zmax-page-size=128 -T${PS2SDK}/ee/startup/linkfile -L${PS2SDK}/ee/lib -L${PS2SDK}/ports/lib" + CFLAGS="$CFLAGS -D_EE -G0 -I${PS2SDK}/ee/include -I${PS2SDK}/common/include -I${PS2DEV}/gsKit/include -I${PS2SDK}/ports/include" + LDFLAGS="$LDFLAGS -Wl,-zmax-page-size=128 -T${PS2SDK}/ee/startup/linkfile -L${PS2SDK}/ee/lib -L${PS2DEV}/gsKit/lib -L${PS2SDK}/ports/lib" ;; *) fail "unsupported platform: $platform" diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index c0dd7d25..a2562f45 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -1,9 +1,14 @@ #include +#include #include #include #include #include +#include +#include +#include +#include #include "in_ps2.h" #include "../libpicofe/input.h" @@ -15,6 +20,11 @@ #define OSD_FPS_X 220 +/* turn black GS Screen */ +#define GS_BLACK GS_SETREG_RGBA(0x00, 0x00, 0x00, 0x80) +/* Generic tint color */ +#define GS_TEXT GS_SETREG_RGBA(0x80, 0x80, 0x80, 0x80) + static int osd_buf_cnt, osd_cdleds; static int out_x, out_y; @@ -42,9 +52,70 @@ const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL }; enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT }; +typedef struct ps2_video { + GSGLOBAL *gsGlobal; + + GSTEXTURE *scrbitmap; + GSTEXTURE *tex_spr0; + GSTEXTURE *tex_spr1; + GSTEXTURE *tex_spr2; + GSTEXTURE *tex_fix; + uint32_t offset; + uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ + uint8_t pixel_format; +} ps2_video_t; + +ps2_video_t *ps2_video = NULL; + #define is_16bit_mode() \ (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X)) +static void video_init(void) +{ + ps2_video = (ps2_video_t*)calloc(1, sizeof(ps2_video_t)); + + GSGLOBAL *gsGlobal; + + gsGlobal = gsKit_init_global(); + + gsGlobal->Mode = GS_MODE_NTSC; + gsGlobal->Height = 448; + + gsGlobal->PSM = GS_PSM_CT24; + gsGlobal->PSMZ = GS_PSMZ_16S; + gsGlobal->ZBuffering = GS_SETTING_OFF; + gsGlobal->DoubleBuffering = GS_SETTING_ON; + gsGlobal->PrimAlphaEnable = GS_SETTING_ON; + gsGlobal->Dithering = GS_SETTING_OFF; + + gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0, 1, 0, 1, 0), 0); + + dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF); + dmaKit_chan_init(DMA_CHANNEL_GIF); + + gsKit_set_clamp(gsGlobal, GS_CMODE_REPEAT); + + gsKit_vram_clear(gsGlobal); + + gsKit_init_screen(gsGlobal); + + gsKit_TexManager_init(gsGlobal); + + gsKit_mode_switch(gsGlobal, GS_ONESHOT); + gsKit_clear(gsGlobal, GS_BLACK); + ps2_video->gsGlobal = gsGlobal; +} + +static void video_deinit(void) +{ + if (!ps2_video) return; + + gsKit_clear(ps2_video->gsGlobal, GS_BLACK); + gsKit_vram_clear(ps2_video->gsGlobal); + gsKit_deinit_global(ps2_video->gsGlobal); + free(ps2_video); +} + static int get_renderer(void) { if (PicoIn.AHW & PAHW_32X) @@ -179,6 +250,7 @@ void pemu_finalize_frame(const char *fps, const char *notice) void plat_init(void) { + video_init(); init_joystick_driver(false); in_ps2_init(in_ps2_defbinds); in_probe(); @@ -189,6 +261,7 @@ void plat_init(void) void plat_finish(void) { deinit_audio_driver(); deinit_joystick_driver(false); + video_deinit(); } /* display emulator status messages before holding emulation */ From 862e969bab60a74cc94e45bef46aa419e21940b2 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Mon, 1 Jan 2024 12:24:10 +0100 Subject: [PATCH 08/19] Adding background objects --- platform/ps2/emu.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index a2562f45..c25fc2bd 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -55,11 +55,8 @@ enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT }; typedef struct ps2_video { GSGLOBAL *gsGlobal; - GSTEXTURE *scrbitmap; - GSTEXTURE *tex_spr0; - GSTEXTURE *tex_spr1; - GSTEXTURE *tex_spr2; - GSTEXTURE *tex_fix; + GSTEXTURE *g_menuscreen; + uint8_t *g_menubg_ptr; uint32_t offset; uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ uint8_t pixel_format; @@ -70,6 +67,29 @@ ps2_video_t *ps2_video = NULL; #define is_16bit_mode() \ (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X)) +static void set_g_menuscreen_values(ps2_video_t *ps2_video) +{ + GSTEXTURE *g_menuscreen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); + size_t g_menuscreenSize = gsKit_texture_size_ee(ps2_video->gsGlobal->Width, ps2_video->gsGlobal->Height, GS_PSM_CT16); + g_menuscreen->Width = ps2_video->gsGlobal->Width; + g_menuscreen->Height = ps2_video->gsGlobal->Height; + g_menuscreen->PSM = GS_PSM_CT16; + g_menuscreen->Mem = (uint32_t *)malloc(g_menuscreenSize); + + ps2_video->g_menuscreen = g_menuscreen; + ps2_video->g_menubg_ptr = (uint8_t *)malloc(g_menuscreenSize);; + + g_menuscreen_w = g_menuscreen->Width; + g_menuscreen_h = g_menuscreen->Height; + g_menuscreen_pp = g_menuscreen->Width; + g_menuscreen_ptr = g_menuscreen->Mem; + + g_menubg_src_w = g_menuscreen->Width; + g_menubg_src_h = g_menuscreen->Height; + g_menubg_src_pp = g_menuscreen->Width; + g_menubg_ptr = ps2_video->g_menubg_ptr; +} + static void video_init(void) { ps2_video = (ps2_video_t*)calloc(1, sizeof(ps2_video_t)); @@ -104,12 +124,19 @@ static void video_init(void) gsKit_mode_switch(gsGlobal, GS_ONESHOT); gsKit_clear(gsGlobal, GS_BLACK); ps2_video->gsGlobal = gsGlobal; + + set_g_menuscreen_values(ps2_video); } static void video_deinit(void) { if (!ps2_video) return; + free(ps2_video->g_menuscreen->Mem); + free(ps2_video->g_menuscreen); + + free(ps2_video->g_menubg_ptr); + gsKit_clear(ps2_video->gsGlobal, GS_BLACK); gsKit_vram_clear(ps2_video->gsGlobal); gsKit_deinit_global(ps2_video->gsGlobal); From 8633b583f0bddb3401470387939df964c246df30 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Mon, 1 Jan 2024 13:08:17 +0100 Subject: [PATCH 09/19] Starting to see the menu in the screen --- platform/ps2/emu.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ platform/ps2/plat.c | 35 ---------------------- 2 files changed, 71 insertions(+), 35 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index c25fc2bd..15a0e304 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -13,6 +13,7 @@ #include "in_ps2.h" #include "../libpicofe/input.h" #include "../libpicofe/plat.h" +#include "../libpicofe/menu.h" #include "../common/input_pico.h" #include "../common/emu.h" @@ -56,6 +57,8 @@ typedef struct ps2_video { GSGLOBAL *gsGlobal; GSTEXTURE *g_menuscreen; + uint32_t g_menuscreen_vertices_count; + GSPRIMUVPOINT *g_menuscreen_vertices; uint8_t *g_menubg_ptr; uint32_t offset; uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ @@ -88,6 +91,20 @@ static void set_g_menuscreen_values(ps2_video_t *ps2_video) g_menubg_src_h = g_menuscreen->Height; g_menubg_src_pp = g_menuscreen->Width; g_menubg_ptr = ps2_video->g_menubg_ptr; + + uint32_t g_menuscreen_vertices_count = 2; + GSPRIMUVPOINT *g_menuscreen_vertices = (GSPRIMUVPOINT *)calloc(g_menuscreen_vertices_count, sizeof(GSPRIMUVPOINT)); + + g_menuscreen_vertices[0].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, 0, 0, 0); + g_menuscreen_vertices[0].uv = vertex_to_UV(g_menuscreen, 0, 0); + g_menuscreen_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + g_menuscreen_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, g_menuscreen->Width, g_menuscreen->Height, 0); + g_menuscreen_vertices[1].uv = vertex_to_UV(g_menuscreen, g_menuscreen->Width, g_menuscreen->Height); + g_menuscreen_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + ps2_video->g_menuscreen_vertices_count = g_menuscreen_vertices_count; + ps2_video->g_menuscreen_vertices = g_menuscreen_vertices; } static void video_init(void) @@ -231,6 +248,60 @@ static void draw_pico_ptr(void) static void vidResetMode(void) {} +static void flipScreen(void *data, bool vsync) +{ + ps2_video_t *ps2 = (ps2_video_t*)data; + + gsKit_queue_exec(ps2->gsGlobal); + gsKit_finish(); + + if (vsync) gsKit_sync_flip(ps2->gsGlobal); + + gsKit_TexManager_nextFrame(ps2->gsGlobal); + gsKit_clear(ps2->gsGlobal, GS_BLACK); +} + + +/* display a completed frame buffer and prepare a new render buffer */ +void plat_video_flip(void) +{ + blitscreen_clut(); +} + +/* wait for start of vertical blanking */ +void plat_video_wait_vsync(void) +{ +} + +/* switch from emulation display to menu display */ +void plat_video_menu_enter(int is_rom_loaded) +{ +} + +/* start rendering a menu screen */ +void plat_video_menu_begin(void) +{ + gsKit_TexManager_invalidate(ps2_video->gsGlobal, ps2_video->g_menuscreen); +} + +/* display a completed menu screen */ +void plat_video_menu_end(void) +{ + gsKit_TexManager_bind(ps2_video->gsGlobal, ps2_video->g_menuscreen); + gskit_prim_list_sprite_texture_uv_3d( + ps2_video->gsGlobal, + ps2_video->g_menuscreen, + ps2_video->g_menuscreen_vertices_count, + ps2_video->g_menuscreen_vertices + ); + flipScreen(ps2_video, 1); +} + +/* terminate menu display */ +void plat_video_menu_leave(void) +{ +} + void pemu_sound_start(void) {} void pemu_sound_stop(void) {} diff --git a/platform/ps2/plat.c b/platform/ps2/plat.c index 418e5310..7b6d2267 100644 --- a/platform/ps2/plat.c +++ b/platform/ps2/plat.c @@ -53,41 +53,6 @@ void plat_target_finish(void) deinit_drivers(); } -/* display a completed frame buffer and prepare a new render buffer */ -void plat_video_flip(void) -{ - blitscreen_clut(); -} - -/* wait for start of vertical blanking */ -void plat_video_wait_vsync(void) -{ -} - -/* switch from emulation display to menu display */ -void plat_video_menu_enter(int is_rom_loaded) -{ - -} - -/* start rendering a menu screen */ -void plat_video_menu_begin(void) -{ - -} - -/* display a completed menu screen */ -void plat_video_menu_end(void) -{ - -} - -/* terminate menu display */ -void plat_video_menu_leave(void) -{ - -} - int plat_parse_arg(int argc, char *argv[], int *x) { return 1; From 1107e618f5e3e9eb7cffb866fa3d6c25d32cea85 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Tue, 2 Jan 2024 00:10:21 +0100 Subject: [PATCH 10/19] Starting to see the emulator on the screen --- platform/ps2/emu.c | 168 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 159 insertions(+), 9 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index 15a0e304..862d9187 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -59,6 +59,19 @@ typedef struct ps2_video { GSTEXTURE *g_menuscreen; uint32_t g_menuscreen_vertices_count; GSPRIMUVPOINT *g_menuscreen_vertices; + + GSTEXTURE *g_screen; + uint32_t g_screen_vertices_count; + GSPRIMUVPOINT *g_screen_vertices; + + GSTEXTURE *osd; + uint32_t osd_vertices_count; + GSPRIMUVPOINT *osd_vertices; + + GSTEXTURE *cdleds; + uint32_t cdleds_vertices_count; + GSPRIMUVPOINT *cdleds_vertices; + uint8_t *g_menubg_ptr; uint32_t offset; uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ @@ -107,6 +120,91 @@ static void set_g_menuscreen_values(ps2_video_t *ps2_video) ps2_video->g_menuscreen_vertices = g_menuscreen_vertices; } +void set_g_screen_values(ps2_video_t *ps2_video) { + GSTEXTURE *g_screen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); + size_t g_screenSize = gsKit_texture_size_ee(328, 256, GS_PSM_CT16); + g_screen->Width = 328; + g_screen->Height = 256; + g_screen->PSM = GS_PSM_CT16; + g_screen->Mem = (uint32_t *)malloc(g_screenSize); + + g_screen_width = 328; + g_screen_height = 256; + g_screen_ppitch = 328; + g_screen_ptr = g_screen->Mem; + + ps2_video->g_screen = g_screen; + + uint32_t g_screen_vertices_count = 2; + GSPRIMUVPOINT *g_screen_vertices = (GSPRIMUVPOINT *)calloc(g_screen_vertices_count, sizeof(GSPRIMUVPOINT)); + + g_screen_vertices[0].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, 0, 0, 2); + g_screen_vertices[0].uv = vertex_to_UV(g_screen, 0, 0); + g_screen_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + g_screen_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, g_screen->Width, g_screen->Height, 2); + g_screen_vertices[1].uv = vertex_to_UV(g_screen, g_screen->Width, g_screen->Height); + g_screen_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + ps2_video->g_screen_vertices_count = g_screen_vertices_count; + ps2_video->g_screen_vertices = g_screen_vertices; + + if (is_16bit_mode()) + PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2); + else + PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch); +} + +void set_cdleds_values(ps2_video_t *ps2_video) { + GSTEXTURE *cdleds = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); + size_t cdledsSize = gsKit_texture_size_ee(14, 5, GS_PSM_CT16); + cdleds->Width = 14; + cdleds->Height = 5; + cdleds->PSM = GS_PSM_CT16; + cdleds->Mem = (uint32_t *)malloc(cdledsSize); + + ps2_video->cdleds = cdleds; + + uint32_t cdleds_vertices_count = 2; + GSPRIMUVPOINT *cdleds_vertices = (GSPRIMUVPOINT *)calloc(cdleds_vertices_count, sizeof(GSPRIMUVPOINT)); + + cdleds_vertices[0].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, 4, 1, 2); + cdleds_vertices[0].uv = vertex_to_UV(cdleds, 0, 0); + cdleds_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + cdleds_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, cdleds->Width, cdleds->Height, 0); + cdleds_vertices[1].uv = vertex_to_UV(cdleds, cdleds->Width, cdleds->Height); + cdleds_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + ps2_video->cdleds_vertices_count = cdleds_vertices_count; + ps2_video->cdleds_vertices = cdleds_vertices; +} + +void set_osd_values(ps2_video_t *ps2_video) { + GSTEXTURE *osd = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); + size_t osdSize = gsKit_texture_size_ee(512, 8, GS_PSM_CT16); + osd->Width = 512; + osd->Height = 8; + osd->PSM = GS_PSM_CT16; + osd->Mem = (uint32_t *)malloc(osdSize); + + ps2_video->osd = osd; + + uint32_t osd_vertices_count = 2; + GSPRIMUVPOINT *osd_vertices = (GSPRIMUVPOINT *)calloc(osd_vertices_count, sizeof(GSPRIMUVPOINT)); + + osd_vertices[0].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, 0, 0, 0); + osd_vertices[0].uv = vertex_to_UV(osd, 0, 0); + osd_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + osd_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, osd->Width, osd->Height, 0); + osd_vertices[1].uv = vertex_to_UV(osd, osd->Width, osd->Height); + osd_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + ps2_video->osd_vertices_count = osd_vertices_count; + ps2_video->osd_vertices = osd_vertices; +} + static void video_init(void) { ps2_video = (ps2_video_t*)calloc(1, sizeof(ps2_video_t)); @@ -141,6 +239,7 @@ static void video_init(void) gsKit_mode_switch(gsGlobal, GS_ONESHOT); gsKit_clear(gsGlobal, GS_BLACK); ps2_video->gsGlobal = gsGlobal; + ps2_video->vsync = 0; set_g_menuscreen_values(ps2_video); } @@ -151,6 +250,7 @@ static void video_deinit(void) free(ps2_video->g_menuscreen->Mem); free(ps2_video->g_menuscreen); + free(ps2_video->g_menuscreen_vertices); free(ps2_video->g_menubg_ptr); @@ -204,7 +304,36 @@ static void apply_renderer(void) static void osd_text(int x, const char *text) { + // int len = strlen(text) * 8; + // int *p, h; + // void *tmp = g_screen_ptr; + // printf("osd_text, text: %s\n", text); + // g_screen_ptr = osd_buf; + // for (h = 0; h < 8; h++) { + // p = (int *) (osd_buf+x+512*h); + // p = (int *) ((int)p & ~3); // align + // memset32_uncached(p, 0, len/2); + // } + // emu_text_out16(x, 0, text); + // g_screen_ptr = tmp; + + // osd_buf_x[osd_buf_cnt] = x; + // osd_buf_l[osd_buf_cnt] = len; + // osd_buf_cnt ++; +} + +static void blit_screen(void) +{ + gsKit_TexManager_invalidate(ps2_video->gsGlobal, ps2_video->g_screen); + + gsKit_TexManager_bind(ps2_video->gsGlobal, ps2_video->g_screen); + gskit_prim_list_sprite_texture_uv_3d( + ps2_video->gsGlobal, + ps2_video->g_screen, + ps2_video->g_screen_vertices_count, + ps2_video->g_screen_vertices + ); } static void blit_osd(void) @@ -214,19 +343,32 @@ static void blit_osd(void) static void cd_leds(void) { + unsigned int reg, col_g, col_r, *p; + gsKit_TexManager_invalidate(ps2_video->gsGlobal, ps2_video->cdleds); + reg = Pico_mcd->s68k_regs[0]; + + p = (unsigned int *)ps2_video->cdleds->Mem; + col_g = (reg & 2) ? 0x06000600 : 0; + col_r = (reg & 1) ? 0x00180018 : 0; + *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 512/2 - 12/2; + *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 512/2 - 12/2; + *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; + + osd_cdleds = 1; } static void blit_cdleds(void) { + if (!osd_cdleds) return; -} - -void blitscreen_clut(void) -{ - - blit_osd(); - blit_cdleds(); + gsKit_TexManager_bind(ps2_video->gsGlobal, ps2_video->cdleds); + gskit_prim_list_sprite_texture_uv_3d( + ps2_video->gsGlobal, + ps2_video->cdleds, + ps2_video->cdleds_vertices_count, + ps2_video->cdleds_vertices + ); } static void draw_pico_ptr(void) @@ -265,7 +407,12 @@ static void flipScreen(void *data, bool vsync) /* display a completed frame buffer and prepare a new render buffer */ void plat_video_flip(void) { - blitscreen_clut(); + blit_screen(); + blit_osd(); + blit_cdleds(); + + // flipScreen(ps2_video, ps2_video->vsync); + flipScreen(ps2_video, 1); } /* wait for start of vertical blanking */ @@ -313,7 +460,7 @@ void pemu_prep_defconfig(void) defaultConfig.filter = EOPT_FILTER_BILINEAR; // bilinear filtering defaultConfig.scaling = EOPT_SCALE_43; defaultConfig.vscaling = EOPT_VSCALE_FULL; - defaultConfig.renderer = RT_8BIT_ACC; + defaultConfig.renderer = RT_16BIT; defaultConfig.renderer32x = RT_8BIT_ACC; defaultConfig.EmuOpt |= EOPT_SHOW_RTC; } @@ -469,9 +616,12 @@ void plat_video_loop_prepare(void) /* prepare for entering the emulator loop */ void pemu_loop_prep(void) { + set_g_screen_values(ps2_video); + set_cdleds_values(ps2_video); } /* terminate the emulator loop */ void pemu_loop_end(void) { + pemu_sound_stop(); } \ No newline at end of file From 30f7602e65fc887b84e2c2f3f1754940e08f0ad1 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Fri, 5 Jan 2024 18:02:51 +0100 Subject: [PATCH 11/19] Disable alpha and improve vsync logic --- platform/ps2/emu.c | 67 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index 862d9187..0c38260c 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -53,6 +53,8 @@ const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL }; enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT }; +static int vsync_sema_id; + typedef struct ps2_video { GSGLOBAL *gsGlobal; @@ -72,8 +74,9 @@ typedef struct ps2_video { uint32_t cdleds_vertices_count; GSPRIMUVPOINT *cdleds_vertices; - uint8_t *g_menubg_ptr; uint32_t offset; + int32_t vsync_callback_id; + uint8_t *g_menubg_ptr; uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ uint8_t pixel_format; } ps2_video_t; @@ -83,6 +86,14 @@ ps2_video_t *ps2_video = NULL; #define is_16bit_mode() \ (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X)) +static int vsync_handler(void) +{ + iSignalSema(vsync_sema_id); + + ExitHandler(); + return 0; +} + static void set_g_menuscreen_values(ps2_video_t *ps2_video) { GSTEXTURE *g_menuscreen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); @@ -142,7 +153,7 @@ void set_g_screen_values(ps2_video_t *ps2_video) { g_screen_vertices[0].uv = vertex_to_UV(g_screen, 0, 0); g_screen_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - g_screen_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, g_screen->Width, g_screen->Height, 2); + g_screen_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, ps2_video->gsGlobal->Width, ps2_video->gsGlobal->Height, 2); g_screen_vertices[1].uv = vertex_to_UV(g_screen, g_screen->Width, g_screen->Height); g_screen_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); @@ -207,8 +218,15 @@ void set_osd_values(ps2_video_t *ps2_video) { static void video_init(void) { + ee_sema_t sema; + + sema.init_count = 0; + sema.max_count = 1; + sema.option = 0; ps2_video = (ps2_video_t*)calloc(1, sizeof(ps2_video_t)); + vsync_sema_id = CreateSema(&sema); + GSGLOBAL *gsGlobal; gsGlobal = gsKit_init_global(); @@ -220,15 +238,17 @@ static void video_init(void) gsGlobal->PSMZ = GS_PSMZ_16S; gsGlobal->ZBuffering = GS_SETTING_OFF; gsGlobal->DoubleBuffering = GS_SETTING_ON; - gsGlobal->PrimAlphaEnable = GS_SETTING_ON; + gsGlobal->PrimAlphaEnable = GS_SETTING_OFF; gsGlobal->Dithering = GS_SETTING_OFF; - gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0, 1, 0, 1, 0), 0); + // gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0, 1, 0, 1, 0), 0); dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF); dmaKit_chan_init(DMA_CHANNEL_GIF); gsKit_set_clamp(gsGlobal, GS_CMODE_REPEAT); + // gsKit_set_test(gsGlobal, GS_ZTEST_OFF); + // gsKit_set_test(gsGlobal, GS_ATEST_OFF); gsKit_vram_clear(gsGlobal); @@ -240,6 +260,7 @@ static void video_init(void) gsKit_clear(gsGlobal, GS_BLACK); ps2_video->gsGlobal = gsGlobal; ps2_video->vsync = 0; + ps2_video->vsync_callback_id = gsKit_add_vsync_handler(vsync_handler); set_g_menuscreen_values(ps2_video); } @@ -257,6 +278,11 @@ static void video_deinit(void) gsKit_clear(ps2_video->gsGlobal, GS_BLACK); gsKit_vram_clear(ps2_video->gsGlobal); gsKit_deinit_global(ps2_video->gsGlobal); + gsKit_remove_vsync_handler(ps2_video->vsync_callback_id); + + if (vsync_sema_id >= 0) + DeleteSema(vsync_sema_id); + free(ps2_video); } @@ -390,6 +416,32 @@ static void draw_pico_ptr(void) static void vidResetMode(void) {} +/* Copy of gsKit_sync_flip, but without the 'flip' */ +static void gsKit_sync(GSGLOBAL *gsGlobal) +{ + if (!gsGlobal->FirstFrame) + WaitSema(vsync_sema_id); + + while (PollSema(vsync_sema_id) >= 0); +} + +/* Copy of gsKit_sync_flip, but without the 'sync' */ +static void gsKit_flip(GSGLOBAL *gsGlobal) +{ + if (!gsGlobal->FirstFrame) + { + if (gsGlobal->DoubleBuffering == GS_SETTING_ON) + { + GS_SET_DISPFB2(gsGlobal->ScreenBuffer[gsGlobal->ActiveBuffer & 1] / 8192, + gsGlobal->Width / 64, gsGlobal->PSM, 0, 0); + + gsGlobal->ActiveBuffer ^= 1; + } + } + + gsKit_setactive(gsGlobal); +} + static void flipScreen(void *data, bool vsync) { ps2_video_t *ps2 = (ps2_video_t*)data; @@ -397,7 +449,9 @@ static void flipScreen(void *data, bool vsync) gsKit_queue_exec(ps2->gsGlobal); gsKit_finish(); - if (vsync) gsKit_sync_flip(ps2->gsGlobal); + if (ps2->vsync) + gsKit_sync(ps2->gsGlobal); + gsKit_flip(ps2->gsGlobal); gsKit_TexManager_nextFrame(ps2->gsGlobal); gsKit_clear(ps2->gsGlobal, GS_BLACK); @@ -411,8 +465,7 @@ void plat_video_flip(void) blit_osd(); blit_cdleds(); - // flipScreen(ps2_video, ps2_video->vsync); - flipScreen(ps2_video, 1); + flipScreen(ps2_video, ps2_video->vsync); } /* wait for start of vertical blanking */ From 6724ae42f3b85050e54977785ae03ab382c22c00 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Fri, 5 Jan 2024 18:59:21 +0100 Subject: [PATCH 12/19] Some clean up around emu.c --- platform/ps2/emu.c | 244 +++++++++++++++++++-------------------------- 1 file changed, 105 insertions(+), 139 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index 0c38260c..98d2ed06 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -53,35 +53,24 @@ const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL }; enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT }; +static GSGLOBAL *gsGlobal; + +static GSTEXTURE *g_menuscreen; +static GSPRIMUVPOINT *g_menuscreen_vertices; + +static GSTEXTURE *g_screen; +static GSPRIMUVPOINT *g_screen_vertices; + +static GSTEXTURE *osd; +static uint32_t osd_vertices_count; +static GSPRIMUVPOINT *osd_vertices; + +static GSTEXTURE *cdleds; +static GSPRIMUVPOINT *cdleds_vertices; + static int vsync_sema_id; - -typedef struct ps2_video { - GSGLOBAL *gsGlobal; - - GSTEXTURE *g_menuscreen; - uint32_t g_menuscreen_vertices_count; - GSPRIMUVPOINT *g_menuscreen_vertices; - - GSTEXTURE *g_screen; - uint32_t g_screen_vertices_count; - GSPRIMUVPOINT *g_screen_vertices; - - GSTEXTURE *osd; - uint32_t osd_vertices_count; - GSPRIMUVPOINT *osd_vertices; - - GSTEXTURE *cdleds; - uint32_t cdleds_vertices_count; - GSPRIMUVPOINT *cdleds_vertices; - - uint32_t offset; - int32_t vsync_callback_id; - uint8_t *g_menubg_ptr; - uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ - uint8_t pixel_format; -} ps2_video_t; - -ps2_video_t *ps2_video = NULL; +static int32_t vsync_callback_id; +static uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ #define is_16bit_mode() \ (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X)) @@ -94,17 +83,22 @@ static int vsync_handler(void) return 0; } -static void set_g_menuscreen_values(ps2_video_t *ps2_video) +static void set_g_menuscreen_values() { - GSTEXTURE *g_menuscreen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); - size_t g_menuscreenSize = gsKit_texture_size_ee(ps2_video->gsGlobal->Width, ps2_video->gsGlobal->Height, GS_PSM_CT16); - g_menuscreen->Width = ps2_video->gsGlobal->Width; - g_menuscreen->Height = ps2_video->gsGlobal->Height; + if (g_menuscreen != NULL) { + free(g_menuscreen->Mem); + free(g_menuscreen); + free(g_menubg_ptr); + free(g_menuscreen_vertices); + } + g_menuscreen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); + size_t g_menuscreenSize = gsKit_texture_size_ee(gsGlobal->Width, gsGlobal->Height, GS_PSM_CT16); + g_menuscreen->Width = gsGlobal->Width; + g_menuscreen->Height = gsGlobal->Height; g_menuscreen->PSM = GS_PSM_CT16; - g_menuscreen->Mem = (uint32_t *)malloc(g_menuscreenSize); + g_menuscreen->Mem = malloc(g_menuscreenSize); - ps2_video->g_menuscreen = g_menuscreen; - ps2_video->g_menubg_ptr = (uint8_t *)malloc(g_menuscreenSize);; + g_menubg_ptr = (uint8_t *)malloc(g_menuscreenSize); g_menuscreen_w = g_menuscreen->Width; g_menuscreen_h = g_menuscreen->Height; @@ -114,25 +108,25 @@ static void set_g_menuscreen_values(ps2_video_t *ps2_video) g_menubg_src_w = g_menuscreen->Width; g_menubg_src_h = g_menuscreen->Height; g_menubg_src_pp = g_menuscreen->Width; - g_menubg_ptr = ps2_video->g_menubg_ptr; - uint32_t g_menuscreen_vertices_count = 2; - GSPRIMUVPOINT *g_menuscreen_vertices = (GSPRIMUVPOINT *)calloc(g_menuscreen_vertices_count, sizeof(GSPRIMUVPOINT)); + g_menuscreen_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT)); - g_menuscreen_vertices[0].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, 0, 0, 0); + g_menuscreen_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 0, 0, 2); g_menuscreen_vertices[0].uv = vertex_to_UV(g_menuscreen, 0, 0); g_menuscreen_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - g_menuscreen_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, g_menuscreen->Width, g_menuscreen->Height, 0); + g_menuscreen_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, g_menuscreen->Width, g_menuscreen->Height, 2); g_menuscreen_vertices[1].uv = vertex_to_UV(g_menuscreen, g_menuscreen->Width, g_menuscreen->Height); g_menuscreen_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - - ps2_video->g_menuscreen_vertices_count = g_menuscreen_vertices_count; - ps2_video->g_menuscreen_vertices = g_menuscreen_vertices; } -void set_g_screen_values(ps2_video_t *ps2_video) { - GSTEXTURE *g_screen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); +void set_g_screen_values() { + if (g_screen != NULL) { + free(g_screen->Mem); + free(g_screen); + free(g_screen_vertices); + } + g_screen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); size_t g_screenSize = gsKit_texture_size_ee(328, 256, GS_PSM_CT16); g_screen->Width = 328; g_screen->Height = 256; @@ -144,76 +138,69 @@ void set_g_screen_values(ps2_video_t *ps2_video) { g_screen_ppitch = 328; g_screen_ptr = g_screen->Mem; - ps2_video->g_screen = g_screen; - - uint32_t g_screen_vertices_count = 2; - GSPRIMUVPOINT *g_screen_vertices = (GSPRIMUVPOINT *)calloc(g_screen_vertices_count, sizeof(GSPRIMUVPOINT)); + g_screen_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT)); - g_screen_vertices[0].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, 0, 0, 2); + g_screen_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 0, 0, 0); g_screen_vertices[0].uv = vertex_to_UV(g_screen, 0, 0); g_screen_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - g_screen_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, ps2_video->gsGlobal->Width, ps2_video->gsGlobal->Height, 2); + g_screen_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, gsGlobal->Width, gsGlobal->Height, 0); g_screen_vertices[1].uv = vertex_to_UV(g_screen, g_screen->Width, g_screen->Height); g_screen_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - ps2_video->g_screen_vertices_count = g_screen_vertices_count; - ps2_video->g_screen_vertices = g_screen_vertices; - if (is_16bit_mode()) PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2); else PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch); } -void set_cdleds_values(ps2_video_t *ps2_video) { - GSTEXTURE *cdleds = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); +void set_cdleds_values() { + if (cdleds != NULL) { + free(cdleds->Mem); + free(cdleds); + free(cdleds_vertices); + } + cdleds = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); size_t cdledsSize = gsKit_texture_size_ee(14, 5, GS_PSM_CT16); cdleds->Width = 14; cdleds->Height = 5; cdleds->PSM = GS_PSM_CT16; cdleds->Mem = (uint32_t *)malloc(cdledsSize); - ps2_video->cdleds = cdleds; - - uint32_t cdleds_vertices_count = 2; - GSPRIMUVPOINT *cdleds_vertices = (GSPRIMUVPOINT *)calloc(cdleds_vertices_count, sizeof(GSPRIMUVPOINT)); + cdleds_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT)); - cdleds_vertices[0].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, 4, 1, 2); + cdleds_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 4, 1, 1); cdleds_vertices[0].uv = vertex_to_UV(cdleds, 0, 0); cdleds_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - cdleds_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, cdleds->Width, cdleds->Height, 0); + cdleds_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, cdleds->Width, cdleds->Height, 1); cdleds_vertices[1].uv = vertex_to_UV(cdleds, cdleds->Width, cdleds->Height); cdleds_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - - ps2_video->cdleds_vertices_count = cdleds_vertices_count; - ps2_video->cdleds_vertices = cdleds_vertices; } -void set_osd_values(ps2_video_t *ps2_video) { - GSTEXTURE *osd = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); +void set_osd_values() { + if (osd != NULL) { + free(osd->Mem); + free(osd); + free(osd_vertices); + } + osd = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); size_t osdSize = gsKit_texture_size_ee(512, 8, GS_PSM_CT16); osd->Width = 512; osd->Height = 8; osd->PSM = GS_PSM_CT16; osd->Mem = (uint32_t *)malloc(osdSize); - ps2_video->osd = osd; - - uint32_t osd_vertices_count = 2; - GSPRIMUVPOINT *osd_vertices = (GSPRIMUVPOINT *)calloc(osd_vertices_count, sizeof(GSPRIMUVPOINT)); + osd_vertices_count = 2; + osd_vertices = (GSPRIMUVPOINT *)calloc(osd_vertices_count, sizeof(GSPRIMUVPOINT)); - osd_vertices[0].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, 0, 0, 0); + osd_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 0, 0, 1); osd_vertices[0].uv = vertex_to_UV(osd, 0, 0); osd_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - osd_vertices[1].xyz2 = vertex_to_XYZ2(ps2_video->gsGlobal, osd->Width, osd->Height, 0); + osd_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, osd->Width, osd->Height, 1); osd_vertices[1].uv = vertex_to_UV(osd, osd->Width, osd->Height); osd_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - - ps2_video->osd_vertices_count = osd_vertices_count; - ps2_video->osd_vertices = osd_vertices; } static void video_init(void) @@ -223,14 +210,10 @@ static void video_init(void) sema.init_count = 0; sema.max_count = 1; sema.option = 0; - ps2_video = (ps2_video_t*)calloc(1, sizeof(ps2_video_t)); vsync_sema_id = CreateSema(&sema); - GSGLOBAL *gsGlobal; - gsGlobal = gsKit_init_global(); - gsGlobal->Mode = GS_MODE_NTSC; gsGlobal->Height = 448; @@ -241,49 +224,37 @@ static void video_init(void) gsGlobal->PrimAlphaEnable = GS_SETTING_OFF; gsGlobal->Dithering = GS_SETTING_OFF; - // gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0, 1, 0, 1, 0), 0); dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF); dmaKit_chan_init(DMA_CHANNEL_GIF); gsKit_set_clamp(gsGlobal, GS_CMODE_REPEAT); - // gsKit_set_test(gsGlobal, GS_ZTEST_OFF); - // gsKit_set_test(gsGlobal, GS_ATEST_OFF); gsKit_vram_clear(gsGlobal); - gsKit_init_screen(gsGlobal); - gsKit_TexManager_init(gsGlobal); - gsKit_mode_switch(gsGlobal, GS_ONESHOT); gsKit_clear(gsGlobal, GS_BLACK); - ps2_video->gsGlobal = gsGlobal; - ps2_video->vsync = 0; - ps2_video->vsync_callback_id = gsKit_add_vsync_handler(vsync_handler); + vsync = 0; + vsync_callback_id = gsKit_add_vsync_handler(vsync_handler); - set_g_menuscreen_values(ps2_video); + set_g_menuscreen_values(); } static void video_deinit(void) { - if (!ps2_video) return; + free(g_menuscreen->Mem); + free(g_menuscreen); + free(g_menuscreen_vertices); + free(g_menubg_ptr); - free(ps2_video->g_menuscreen->Mem); - free(ps2_video->g_menuscreen); - free(ps2_video->g_menuscreen_vertices); - - free(ps2_video->g_menubg_ptr); - - gsKit_clear(ps2_video->gsGlobal, GS_BLACK); - gsKit_vram_clear(ps2_video->gsGlobal); - gsKit_deinit_global(ps2_video->gsGlobal); - gsKit_remove_vsync_handler(ps2_video->vsync_callback_id); + gsKit_clear(gsGlobal, GS_BLACK); + gsKit_vram_clear(gsGlobal); + gsKit_deinit_global(gsGlobal); + gsKit_remove_vsync_handler(vsync_callback_id); if (vsync_sema_id >= 0) DeleteSema(vsync_sema_id); - - free(ps2_video); } static int get_renderer(void) @@ -351,14 +322,14 @@ static void osd_text(int x, const char *text) static void blit_screen(void) { - gsKit_TexManager_invalidate(ps2_video->gsGlobal, ps2_video->g_screen); + gsKit_TexManager_invalidate(gsGlobal, g_screen); - gsKit_TexManager_bind(ps2_video->gsGlobal, ps2_video->g_screen); + gsKit_TexManager_bind(gsGlobal, g_screen); gskit_prim_list_sprite_texture_uv_3d( - ps2_video->gsGlobal, - ps2_video->g_screen, - ps2_video->g_screen_vertices_count, - ps2_video->g_screen_vertices + gsGlobal, + g_screen, + 2, + g_screen_vertices ); } @@ -370,11 +341,11 @@ static void blit_osd(void) static void cd_leds(void) { unsigned int reg, col_g, col_r, *p; - gsKit_TexManager_invalidate(ps2_video->gsGlobal, ps2_video->cdleds); + gsKit_TexManager_invalidate(gsGlobal, cdleds); reg = Pico_mcd->s68k_regs[0]; - p = (unsigned int *)ps2_video->cdleds->Mem; + p = (unsigned int *)cdleds->Mem; col_g = (reg & 2) ? 0x06000600 : 0; col_r = (reg & 1) ? 0x00180018 : 0; *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 512/2 - 12/2; @@ -388,12 +359,12 @@ static void blit_cdleds(void) { if (!osd_cdleds) return; - gsKit_TexManager_bind(ps2_video->gsGlobal, ps2_video->cdleds); + gsKit_TexManager_bind(gsGlobal, cdleds); gskit_prim_list_sprite_texture_uv_3d( - ps2_video->gsGlobal, - ps2_video->cdleds, - ps2_video->cdleds_vertices_count, - ps2_video->cdleds_vertices + gsGlobal, + cdleds, + 2, + cdleds_vertices ); } @@ -442,19 +413,14 @@ static void gsKit_flip(GSGLOBAL *gsGlobal) gsKit_setactive(gsGlobal); } -static void flipScreen(void *data, bool vsync) +static void flipScreen() { - ps2_video_t *ps2 = (ps2_video_t*)data; - - gsKit_queue_exec(ps2->gsGlobal); + gsKit_queue_exec(gsGlobal); gsKit_finish(); + gsKit_flip(gsGlobal); - if (ps2->vsync) - gsKit_sync(ps2->gsGlobal); - gsKit_flip(ps2->gsGlobal); - - gsKit_TexManager_nextFrame(ps2->gsGlobal); - gsKit_clear(ps2->gsGlobal, GS_BLACK); + gsKit_TexManager_nextFrame(gsGlobal); + gsKit_clear(gsGlobal, GS_BLACK); } @@ -464,13 +430,13 @@ void plat_video_flip(void) blit_screen(); blit_osd(); blit_cdleds(); - - flipScreen(ps2_video, ps2_video->vsync); + flipScreen(); } /* wait for start of vertical blanking */ void plat_video_wait_vsync(void) { + gsKit_sync(gsGlobal); } /* switch from emulation display to menu display */ @@ -481,20 +447,20 @@ void plat_video_menu_enter(int is_rom_loaded) /* start rendering a menu screen */ void plat_video_menu_begin(void) { - gsKit_TexManager_invalidate(ps2_video->gsGlobal, ps2_video->g_menuscreen); + gsKit_TexManager_invalidate(gsGlobal, g_menuscreen); } /* display a completed menu screen */ void plat_video_menu_end(void) { - gsKit_TexManager_bind(ps2_video->gsGlobal, ps2_video->g_menuscreen); + gsKit_TexManager_bind(gsGlobal, g_menuscreen); gskit_prim_list_sprite_texture_uv_3d( - ps2_video->gsGlobal, - ps2_video->g_menuscreen, - ps2_video->g_menuscreen_vertices_count, - ps2_video->g_menuscreen_vertices + gsGlobal, + g_menuscreen, + 2, + g_menuscreen_vertices ); - flipScreen(ps2_video, 1); + flipScreen(1); } /* terminate menu display */ @@ -553,7 +519,7 @@ void plat_init(void) in_ps2_init(in_ps2_defbinds); in_probe(); init_audio_driver(); - // plat_get_data_dir(rom_fname_loaded, sizeof(rom_fname_loaded)); + plat_get_data_dir(rom_fname_loaded, sizeof(rom_fname_loaded)); } void plat_finish(void) { @@ -669,8 +635,8 @@ void plat_video_loop_prepare(void) /* prepare for entering the emulator loop */ void pemu_loop_prep(void) { - set_g_screen_values(ps2_video); - set_cdleds_values(ps2_video); + set_g_screen_values(); + set_cdleds_values(); } /* terminate the emulator loop */ From b4a8b47113362738e86b661dc2a9ee7abc6a617c Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sat, 6 Jan 2024 00:01:22 +0100 Subject: [PATCH 13/19] Some progress about centering image --- platform/ps2/emu.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index 98d2ed06..cd5302c3 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -28,8 +28,6 @@ static int osd_buf_cnt, osd_cdleds; -static int out_x, out_y; -static int out_w, out_h; static float hscale, vscale; static struct in_default_bind in_ps2_defbinds[] = @@ -546,13 +544,11 @@ void plat_status_msg_busy_next(const char *msg) /* clear status message area */ void plat_status_msg_clear(void) { - // not needed since the screen buf is cleared through the GU + // not needed since the screen buf is cleared through the gskit_clear } /* change the audio volume setting */ -void plat_update_volume(int has_changed, int is_up) -{ -} +void plat_update_volume(int has_changed, int is_up) {} /* prepare for MD screen mode change */ void emu_video_mode_change(int start_line, int line_count, int start_col, int col_count) @@ -560,11 +556,11 @@ void emu_video_mode_change(int start_line, int line_count, int start_col, int co int h43 = (col_count >= 192 ? 320 : col_count); // ugh, mind GG... int v43 = (line_count >= 192 ? Pico.m.pal ? 240 : 224 : line_count); - out_y = start_line; out_x = start_col; - out_h = line_count; out_w = col_count; - if (col_count == 248) // mind aspect ratio when blanking 1st column col_count = 256; + + g_screen_vertices[0].uv = vertex_to_UV(g_screen, start_col, start_line); + g_screen_vertices[1].uv = vertex_to_UV(g_screen, col_count, line_count); switch (currentConfig.vscaling) { case EOPT_VSCALE_FULL: From 455cecf973706ef7a6538859ca0d542ef9fe4512 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sat, 6 Jan 2024 12:43:23 +0100 Subject: [PATCH 14/19] Sound almost working --- platform/ps2/emu.c | 204 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 3 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index cd5302c3..05d7d8dd 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "in_ps2.h" #include "../libpicofe/input.h" @@ -70,6 +71,204 @@ static int vsync_sema_id; static int32_t vsync_callback_id; static uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ +/* sound stuff */ +#define SOUND_BLOCK_SIZE_NTSC (1470*2) // 1024 // 1152 +#define SOUND_BLOCK_SIZE_PAL (1764*2) +#define SOUND_BLOCK_COUNT 8 + +static short __attribute__((aligned(4))) sndBuffer[SOUND_BLOCK_SIZE_PAL*SOUND_BLOCK_COUNT + 54000/50*2]; +static short *snd_playptr = NULL, *sndBuffer_endptr = NULL; +static int samples_made = 0, samples_done = 0, samples_block = 0; +static int sound_thread_exit = 0; +static int32_t sound_sem = -1; +static uint8_t stack[0x10000] __attribute__((aligned(16))); +extern void *_gp; + +static int mp3_init(void) { return 0; } + +static void writeSound(int len) +{ + int ret; + + // printf("writeSound, len: %i\n", len); + + PicoIn.sndOut += len / 2; + /*if (PicoIn.sndOut > sndBuffer_endptr) { + memcpy((int *)(void *)sndBuffer, (int *)endptr, (PicoIn.sndOut - endptr + 1) * 2); + PicoIn.sndOut = &sndBuffer[PicoIn.sndOut - endptr]; + lprintf("mov\n"); + } + else*/ + if (PicoIn.sndOut > sndBuffer_endptr) lprintf("snd oflow %i!\n", PicoIn.sndOut - sndBuffer_endptr); + if (PicoIn.sndOut >= sndBuffer_endptr) + PicoIn.sndOut = sndBuffer; + + // signal the snd thread + samples_made += len / 2; + if (samples_made - samples_done > samples_block*2) { + lprintf("signal, %i/%i\n", samples_done, samples_made); + ret = SignalSema(sound_sem); + //if (ret < 0) lprintf("snd signal ret %08x\n", ret); + } +} + +static int sound_thread(void *argp) +{ + int ret = 0; + + while (!sound_thread_exit) + { + if (samples_made - samples_done < samples_block) { + // wait for data (use at least 2 blocks) + //lprintf("sthr: wait... (%i)\n", samples_made - samples_done); + while (samples_made - samples_done <= samples_block*2 && !sound_thread_exit) { + printf("sthr: WaitSema\n"); + ret = WaitSema(sound_sem); + } + if (ret < 0) lprintf("sthr: WaitSema: %i\n", ret); + continue; + } + + // lprintf("sthr: got data: %i\n", samples_made - samples_done); + int buflen = samples_block * 2; + ret = (audsrv_play_audio((char *)snd_playptr, buflen) != buflen) ? -1 : 0; + printf("audsrv_play_audio ret: %i, buflen: %i\n", ret, buflen); + // ret = sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, snd_playptr); + + samples_done += samples_block; + snd_playptr += samples_block; + if (snd_playptr >= sndBuffer_endptr) + snd_playptr = sndBuffer; + // 1.5 kernel returns 0, newer ones return # of samples queued + if (ret < 0) + lprintf("sthr: audsrv_play_audio: %08x; pos %i/%i\n", ret, samples_done, samples_made); + + // shouln't happen, but just in case + if (samples_made - samples_done >= samples_block*3) { + //lprintf("sthr: block skip (%i)\n", samples_made - samples_done); + samples_done += samples_block; // skip + snd_playptr += samples_block; + } + + } + + lprintf("sthr: exit\n"); + ExitDeleteThread(); + return 0; +} + +static void sound_init(void) +{ + int thid; + int ret; + ee_sema_t sema; + ee_thread_t thread; + + sema.max_count = 1; + sema.init_count = 0; + sema.option = (u32) "sndsem"; + if ((sound_sem = CreateSema(&sema)) < 0) + return; + + thread.func = &sound_thread; + thread.stack = stack; + thread.stack_size = sizeof(stack); + thread.gp_reg = &_gp; + thread.option = (u32) "sndthread"; + thread.initial_priority = 0x12; + thid = CreateThread(&thread); + + if (thid >= 0) { + ret = StartThread(thid, NULL); + if (ret < 0) lprintf("sound_init: StartThread returned %08x\n", ret); + }else { + DeleteSema(sound_sem); + lprintf("CreateThread failed: %i\n", thid); + } +} + +void pemu_sound_start(void) { + static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0; + static int mp3_init_done; + int ret, stereo; + struct audsrv_fmt_t format; + + samples_made = samples_done = 0; + + if (!(currentConfig.EmuOpt & EOPT_EN_SOUND)) + return; + + if (PicoIn.AHW & PAHW_MCD) { + // mp3... + if (!mp3_init_done) { + ret = mp3_init(); + mp3_init_done = 1; + if (ret) emu_status_msg("mp3 init failed (%i)", ret); + } + } + + if (PicoIn.sndRate > 52000 && PicoIn.sndRate < 54000) + PicoIn.sndRate = YM2612_NATIVE_RATE(); + ret = POPT_EN_FM|POPT_EN_PSG|POPT_EN_STEREO; + if (PicoIn.sndRate != PsndRate_old || (PicoIn.opt&ret) != (PicoOpt_old&ret) || Pico.m.pal != pal_old) { + PsndRerate(Pico.m.frame_count ? 1 : 0); + } + stereo=(PicoIn.opt&8)>>3; + + samples_block = Pico.m.pal ? SOUND_BLOCK_SIZE_PAL : SOUND_BLOCK_SIZE_NTSC; + printf("samples_block: %i\n", samples_block); + if (PicoIn.sndRate <= 22050) samples_block /= 2; + sndBuffer_endptr = &sndBuffer[samples_block*SOUND_BLOCK_COUNT]; + + lprintf("starting audio: %i, len: %i, stereo: %i, pal: %i, block samples: %i\n", + PicoIn.sndRate, Pico.snd.len, stereo, Pico.m.pal, samples_block); + + format.bits = 16; + format.freq = PicoIn.sndRate; + format.channels = 2; + ret = audsrv_set_format(&format); + audsrv_set_volume(MAX_VOLUME); + if (ret < 0) { + lprintf("audsrv_set_format() failed: %i\n", ret); + emu_status_msg("sound init failed (%i), snd disabled", ret); + currentConfig.EmuOpt &= ~EOPT_EN_SOUND; + } else { + PicoIn.writeSound = writeSound; + memset32((int *)(void *)sndBuffer, 0, sizeof(sndBuffer)/4); + snd_playptr = sndBuffer_endptr - samples_block; + samples_made = samples_block; // send 1 empty block first.. + PicoIn.sndOut = sndBuffer; + PsndRate_old = PicoIn.sndRate; + PicoOpt_old = PicoIn.opt; + pal_old = Pico.m.pal; + } +} + +void pemu_sound_stop(void) +{ + int i; + if (samples_done == 0) + { + // if no data is written between sceAudioSRCChReserve and sceAudioSRCChRelease calls, + // we get a deadlock on next sceAudioSRCChReserve call + // so this is yet another workaround: + memset32((int *)(void *)sndBuffer, 0, samples_block*4/4); + samples_made = samples_block * 3; + SignalSema(sound_sem); + } + plat_sleep_ms(100); + samples_made = samples_done = 0; + audsrv_stop_audio(); +} + +static void sound_deinit(void) +{ + sound_thread_exit = 1; + SignalSema(sound_sem); + DeleteSema(sound_sem); + sound_sem = -1; +} + #define is_16bit_mode() \ (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X)) @@ -466,9 +665,6 @@ void plat_video_menu_leave(void) { } -void pemu_sound_start(void) {} -void pemu_sound_stop(void) {} - /* set default configuration values */ void pemu_prep_defconfig(void) { @@ -517,10 +713,12 @@ void plat_init(void) in_ps2_init(in_ps2_defbinds); in_probe(); init_audio_driver(); + sound_init(); plat_get_data_dir(rom_fname_loaded, sizeof(rom_fname_loaded)); } void plat_finish(void) { + sound_deinit(); deinit_audio_driver(); deinit_joystick_driver(false); video_deinit(); From 4abc40d56b2f9d6bb3246b8a07925262abc55557 Mon Sep 17 00:00:00 2001 From: kub Date: Mon, 5 Feb 2024 20:14:06 +0100 Subject: [PATCH 15/19] fixes for audio and video, add psp-like scaling --- platform/common/menu_pico.c | 2 + platform/ps2/emu.c | 891 ++++++++++++++++++++---------------- platform/ps2/menu.c | 21 + platform/ps2/menu.h | 10 + platform/ps2/plat.c | 5 +- 5 files changed, 527 insertions(+), 402 deletions(-) create mode 100644 platform/ps2/menu.c create mode 100644 platform/ps2/menu.h diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index a9fc7900..78dfcc33 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -72,6 +72,8 @@ static int menu_w, menu_h; #include #elif defined(__PSP__) #include +#elif defined(__PS2__) +#include #elif defined(PANDORA) #include #else diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index 05d7d8dd..a5de6493 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -20,7 +20,7 @@ #include -#define OSD_FPS_X 220 +#define OSD_FPS_X (gsGlobal->Width - 80) /* turn black GS Screen */ #define GS_BLACK GS_SETREG_RGBA(0x00, 0x00, 0x00, 0x80) @@ -29,6 +29,8 @@ static int osd_buf_cnt, osd_cdleds; +static int out_x, out_y; +static int out_w, out_h; static float hscale, vscale; static struct in_default_bind in_ps2_defbinds[] = @@ -51,14 +53,18 @@ static struct in_default_bind in_ps2_defbinds[] = const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast", NULL }; const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL }; enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT }; +static int is_bg_frame; static GSGLOBAL *gsGlobal; static GSTEXTURE *g_menuscreen; static GSPRIMUVPOINT *g_menuscreen_vertices; +static GSTEXTURE *g_screens[2]; +static int g_screen_index; static GSTEXTURE *g_screen; static GSPRIMUVPOINT *g_screen_vertices; +static u16 *g_screen_palette; static GSTEXTURE *osd; static uint32_t osd_vertices_count; @@ -72,84 +78,73 @@ static int32_t vsync_callback_id; static uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ /* sound stuff */ -#define SOUND_BLOCK_SIZE_NTSC (1470*2) // 1024 // 1152 -#define SOUND_BLOCK_SIZE_PAL (1764*2) #define SOUND_BLOCK_COUNT 8 +#define SOUND_BUFFER_SIZE (2*54000/50*SOUND_BLOCK_COUNT) // max.rate/min.frames -static short __attribute__((aligned(4))) sndBuffer[SOUND_BLOCK_SIZE_PAL*SOUND_BLOCK_COUNT + 54000/50*2]; +static short __attribute__((aligned(4))) sndBuffer[SOUND_BUFFER_SIZE]; static short *snd_playptr = NULL, *sndBuffer_endptr = NULL; static int samples_made = 0, samples_done = 0, samples_block = 0; static int sound_thread_exit = 0; static int32_t sound_sem = -1; -static uint8_t stack[0x10000] __attribute__((aligned(16))); +static uint8_t stack[0x4000] __attribute__((aligned(16))); extern void *_gp; static int mp3_init(void) { return 0; } static void writeSound(int len) { - int ret; - - // printf("writeSound, len: %i\n", len); + int ret, l; PicoIn.sndOut += len / 2; - /*if (PicoIn.sndOut > sndBuffer_endptr) { - memcpy((int *)(void *)sndBuffer, (int *)endptr, (PicoIn.sndOut - endptr + 1) * 2); - PicoIn.sndOut = &sndBuffer[PicoIn.sndOut - endptr]; - lprintf("mov\n"); - } - else*/ - if (PicoIn.sndOut > sndBuffer_endptr) lprintf("snd oflow %i!\n", PicoIn.sndOut - sndBuffer_endptr); - if (PicoIn.sndOut >= sndBuffer_endptr) + + l = PicoIn.sndOut - sndBuffer; + if (l > sizeof(sndBuffer)/2) + lprintf("ovfl %d %d\n", len, PicoIn.sndOut - sndBuffer); + if (l > samples_block * 6) { + sndBuffer_endptr = PicoIn.sndOut; PicoIn.sndOut = sndBuffer; + } + if (sndBuffer_endptr < PicoIn.sndOut) + sndBuffer_endptr = PicoIn.sndOut; // signal the snd thread samples_made += len / 2; - if (samples_made - samples_done > samples_block*2) { - lprintf("signal, %i/%i\n", samples_done, samples_made); - ret = SignalSema(sound_sem); - //if (ret < 0) lprintf("snd signal ret %08x\n", ret); - } +// lprintf("signal, %i/%i\n", samples_done, samples_made); + ret = SignalSema(sound_sem); +// if (ret < 0) lprintf("snd signal ret %08x\n", ret); } static int sound_thread(void *argp) { - int ret = 0; - while (!sound_thread_exit) { + int ret = 0; + if (samples_made - samples_done < samples_block) { // wait for data (use at least 2 blocks) - //lprintf("sthr: wait... (%i)\n", samples_made - samples_done); - while (samples_made - samples_done <= samples_block*2 && !sound_thread_exit) { - printf("sthr: WaitSema\n"); +// lprintf("sthr: wait... (%i)\n", samples_made - samples_done); + while (samples_made - samples_done < samples_block*2 && !sound_thread_exit) ret = WaitSema(sound_sem); - } if (ret < 0) lprintf("sthr: WaitSema: %i\n", ret); continue; } +// lprintf("sthr: got data: %i\n", samples_made - samples_done); + short *sndOut = PicoIn.sndOut, *sndEnd = sndBuffer_endptr; + int buflen = samples_block * 2; + if (sndOut >= snd_playptr) + buflen = sndOut - snd_playptr; + else buflen = sndEnd - snd_playptr; + if (buflen > samples_block) + buflen = samples_block; + ret = audsrv_play_audio((char *)snd_playptr, buflen*2); +// if (ret != buflen*2 && ret >= 0) lprintf("sthr: play ret: %i, buflen: %i\n", ret, buflen*2); + if (ret < 0) lprintf("sthr: play: ret %08x; pos %i/%i\n", ret, samples_done, samples_made); - // lprintf("sthr: got data: %i\n", samples_made - samples_done); - int buflen = samples_block * 2; - ret = (audsrv_play_audio((char *)snd_playptr, buflen) != buflen) ? -1 : 0; - printf("audsrv_play_audio ret: %i, buflen: %i\n", ret, buflen); - // ret = sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, snd_playptr); + samples_done += buflen; + snd_playptr += buflen; - samples_done += samples_block; - snd_playptr += samples_block; if (snd_playptr >= sndBuffer_endptr) snd_playptr = sndBuffer; - // 1.5 kernel returns 0, newer ones return # of samples queued - if (ret < 0) - lprintf("sthr: audsrv_play_audio: %08x; pos %i/%i\n", ret, samples_done, samples_made); - - // shouln't happen, but just in case - if (samples_made - samples_done >= samples_block*3) { - //lprintf("sthr: block skip (%i)\n", samples_made - samples_done); - samples_done += samples_block; // skip - snd_playptr += samples_block; - } - } lprintf("sthr: exit\n"); @@ -162,36 +157,39 @@ static void sound_init(void) int thid; int ret; ee_sema_t sema; - ee_thread_t thread; + ee_thread_t thread; - sema.max_count = 1; - sema.init_count = 0; - sema.option = (u32) "sndsem"; - if ((sound_sem = CreateSema(&sema)) < 0) - return; + sema.max_count = 1; + sema.init_count = 0; + sema.option = (u32) "sndsem"; + if ((sound_sem = CreateSema(&sema)) < 0) + return; + audsrv_init(); - thread.func = &sound_thread; - thread.stack = stack; - thread.stack_size = sizeof(stack); - thread.gp_reg = &_gp; - thread.option = (u32) "sndthread"; - thread.initial_priority = 0x12; - thid = CreateThread(&thread); + thread.func = &sound_thread; + thread.stack = stack; + thread.stack_size = sizeof(stack); + thread.gp_reg = &_gp; + thread.option = (u32) "sndthread"; + thread.initial_priority = 40; + thid = CreateThread(&thread); - if (thid >= 0) { + samples_block = 22050/50; // needs to be initialized before thread start + if (thid >= 0) { ret = StartThread(thid, NULL); if (ret < 0) lprintf("sound_init: StartThread returned %08x\n", ret); - }else { - DeleteSema(sound_sem); + ChangeThreadPriority(0, 64); + } else { + DeleteSema(sound_sem); lprintf("CreateThread failed: %i\n", thid); - } + } } void pemu_sound_start(void) { - static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0; + static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0; static int mp3_init_done; int ret, stereo; - struct audsrv_fmt_t format; + struct audsrv_fmt_t format; samples_made = samples_done = 0; @@ -215,49 +213,35 @@ void pemu_sound_start(void) { } stereo=(PicoIn.opt&8)>>3; - samples_block = Pico.m.pal ? SOUND_BLOCK_SIZE_PAL : SOUND_BLOCK_SIZE_NTSC; - printf("samples_block: %i\n", samples_block); - if (PicoIn.sndRate <= 22050) samples_block /= 2; - sndBuffer_endptr = &sndBuffer[samples_block*SOUND_BLOCK_COUNT]; + samples_block = PicoIn.sndRate * (stereo ? 2 : 1) / (Pico.m.pal ? 50 : 60); lprintf("starting audio: %i, len: %i, stereo: %i, pal: %i, block samples: %i\n", PicoIn.sndRate, Pico.snd.len, stereo, Pico.m.pal, samples_block); format.bits = 16; - format.freq = PicoIn.sndRate; - format.channels = 2; + format.freq = PicoIn.sndRate; + format.channels = 2; ret = audsrv_set_format(&format); - audsrv_set_volume(MAX_VOLUME); + audsrv_set_volume(MAX_VOLUME); if (ret < 0) { lprintf("audsrv_set_format() failed: %i\n", ret); emu_status_msg("sound init failed (%i), snd disabled", ret); currentConfig.EmuOpt &= ~EOPT_EN_SOUND; } else { PicoIn.writeSound = writeSound; - memset32((int *)(void *)sndBuffer, 0, sizeof(sndBuffer)/4); - snd_playptr = sndBuffer_endptr - samples_block; - samples_made = samples_block; // send 1 empty block first.. - PicoIn.sndOut = sndBuffer; + snd_playptr = PicoIn.sndOut = sndBuffer_endptr = sndBuffer; + PsndRate_old = PicoIn.sndRate; PicoOpt_old = PicoIn.opt; pal_old = Pico.m.pal; } + ret = audsrv_play_audio((char *)snd_playptr, 4); } void pemu_sound_stop(void) { - int i; - if (samples_done == 0) - { - // if no data is written between sceAudioSRCChReserve and sceAudioSRCChRelease calls, - // we get a deadlock on next sceAudioSRCChReserve call - // so this is yet another workaround: - memset32((int *)(void *)sndBuffer, 0, samples_block*4/4); - samples_made = samples_block * 3; - SignalSema(sound_sem); - } - plat_sleep_ms(100); samples_made = samples_done = 0; + plat_sleep_ms(100); audsrv_stop_audio(); } @@ -270,192 +254,297 @@ static void sound_deinit(void) } #define is_16bit_mode() \ - (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X)) + (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X) || is_bg_frame) static int vsync_handler(void) { - iSignalSema(vsync_sema_id); + iSignalSema(vsync_sema_id); - ExitHandler(); - return 0; + ExitHandler(); + return 0; } -static void set_g_menuscreen_values() +/* Copy of gsKit_sync_flip, but without the 'flip' */ +static void gsKit_sync(GSGLOBAL *gsGlobal) { - if (g_menuscreen != NULL) { - free(g_menuscreen->Mem); - free(g_menuscreen); - free(g_menubg_ptr); - free(g_menuscreen_vertices); - } - g_menuscreen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); - size_t g_menuscreenSize = gsKit_texture_size_ee(gsGlobal->Width, gsGlobal->Height, GS_PSM_CT16); - g_menuscreen->Width = gsGlobal->Width; - g_menuscreen->Height = gsGlobal->Height; - g_menuscreen->PSM = GS_PSM_CT16; - g_menuscreen->Mem = malloc(g_menuscreenSize); + if (!gsGlobal->FirstFrame) + WaitSema(vsync_sema_id); - g_menubg_ptr = (uint8_t *)malloc(g_menuscreenSize); + while (PollSema(vsync_sema_id) >= 0); +} - g_menuscreen_w = g_menuscreen->Width; - g_menuscreen_h = g_menuscreen->Height; - g_menuscreen_pp = g_menuscreen->Width; - g_menuscreen_ptr = g_menuscreen->Mem; +/* Copy of gsKit_sync_flip, but without the 'sync' */ +static void gsKit_flip(GSGLOBAL *gsGlobal) +{ + if (!gsGlobal->FirstFrame) + { + if (gsGlobal->DoubleBuffering == GS_SETTING_ON) + { + GS_SET_DISPFB2(gsGlobal->ScreenBuffer[gsGlobal->ActiveBuffer & 1] / 8192, + gsGlobal->Width / 64, gsGlobal->PSM, 0, 0); - g_menubg_src_w = g_menuscreen->Width; - g_menubg_src_h = g_menuscreen->Height; - g_menubg_src_pp = g_menuscreen->Width; + gsGlobal->ActiveBuffer ^= 1; + } + } - g_menuscreen_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT)); - - g_menuscreen_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 0, 0, 2); + gsKit_setactive(gsGlobal); +} + +static void flipScreen() +{ + gsKit_flip(gsGlobal); + + gsKit_TexManager_nextFrame(gsGlobal); +} + + +static void set_g_menuscreen_values(void) +{ + size_t g_menuscreenSize = gsKit_texture_size_ee(gsGlobal->Width, gsGlobal->Height, GS_PSM_CT16); + + g_menuscreen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); + g_menuscreen->Mem = malloc(g_menuscreenSize); + g_menuscreen_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT)); + + g_menuscreen->Width = gsGlobal->Width; + g_menuscreen->Height = gsGlobal->Height; + g_menuscreen->PSM = GS_PSM_CT16; + + g_menuscreen_w = g_menuscreen->Width; + g_menuscreen_h = g_menuscreen->Height; + g_menuscreen_pp = g_menuscreen->Width; + g_menuscreen_ptr = g_menuscreen->Mem; + + g_menuscreen_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 0, 0, 2); g_menuscreen_vertices[0].uv = vertex_to_UV(g_menuscreen, 0, 0); g_menuscreen_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); - g_menuscreen_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, g_menuscreen->Width, g_menuscreen->Height, 2); - g_menuscreen_vertices[1].uv = vertex_to_UV(g_menuscreen, g_menuscreen->Width, g_menuscreen->Height); - g_menuscreen_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + g_menuscreen_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, g_menuscreen->Width, g_menuscreen->Height, 2); + g_menuscreen_vertices[1].uv = vertex_to_UV(g_menuscreen, g_menuscreen->Width, g_menuscreen->Height); + g_menuscreen_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); } void set_g_screen_values() { - if (g_screen != NULL) { - free(g_screen->Mem); - free(g_screen); - free(g_screen_vertices); - } - g_screen = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); - size_t g_screenSize = gsKit_texture_size_ee(328, 256, GS_PSM_CT16); - g_screen->Width = 328; - g_screen->Height = 256; - g_screen->PSM = GS_PSM_CT16; - g_screen->Mem = (uint32_t *)malloc(g_screenSize); + size_t g_screenSize = gsKit_texture_size_ee(328, 256, GS_PSM_CT16); + int i; - g_screen_width = 328; - g_screen_height = 256; - g_screen_ppitch = 328; - g_screen_ptr = g_screen->Mem; + g_screen_palette = malloc(gsKit_texture_size_ee(16, 16, GS_PSM_CT16)); + g_screen_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT)); + for (i = 0; i < 2; i++) { + g_screens[i] = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); + g_screens[i]->Mem = (uint32_t *)malloc(g_screenSize); - g_screen_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT)); - - g_screen_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 0, 0, 0); - g_screen_vertices[0].uv = vertex_to_UV(g_screen, 0, 0); - g_screen_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + g_screens[i]->Width = 328; + g_screens[i]->Height = 256; + g_screens[i]->PSM = GS_PSM_CT16; + g_screens[i]->Filter = GS_FILTER_LINEAR; - g_screen_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, gsGlobal->Width, gsGlobal->Height, 0); - g_screen_vertices[1].uv = vertex_to_UV(g_screen, g_screen->Width, g_screen->Height); - g_screen_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + g_screens[i]->Clut = g_screen_palette; + g_screens[i]->ClutPSM = GS_PSM_CT16; + } + g_screen = g_screens[g_screen_index]; + g_screen_ptr = g_screen->Mem; - if (is_16bit_mode()) - PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2); - else - PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch); + g_screen_width = 328; + g_screen_height = 256; + g_screen_ppitch = 328; + + g_screen_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 0, 0, 0); + g_screen_vertices[0].uv = vertex_to_UV(g_screen, 0, 0); + g_screen_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + g_screen_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, gsGlobal->Width, gsGlobal->Height, 0); + g_screen_vertices[1].uv = vertex_to_UV(g_screen, g_screen->Width, g_screen->Height); + g_screen_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); } void set_cdleds_values() { - if (cdleds != NULL) { - free(cdleds->Mem); - free(cdleds); - free(cdleds_vertices); - } - cdleds = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); - size_t cdledsSize = gsKit_texture_size_ee(14, 5, GS_PSM_CT16); - cdleds->Width = 14; - cdleds->Height = 5; - cdleds->PSM = GS_PSM_CT16; - cdleds->Mem = (uint32_t *)malloc(cdledsSize); + size_t cdledsSize = gsKit_texture_size_ee(14, 5, GS_PSM_CT16); - cdleds_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT)); - - cdleds_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 4, 1, 1); - cdleds_vertices[0].uv = vertex_to_UV(cdleds, 0, 0); - cdleds_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + cdleds = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); + cdleds->Mem = (uint32_t *)malloc(cdledsSize); + cdleds_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT)); - cdleds_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, cdleds->Width, cdleds->Height, 1); - cdleds_vertices[1].uv = vertex_to_UV(cdleds, cdleds->Width, cdleds->Height); - cdleds_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + cdleds->Width = 14; + cdleds->Height = 5; + cdleds->PSM = GS_PSM_CT16; + + cdleds_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 4, 1, 1); + cdleds_vertices[0].uv = vertex_to_UV(cdleds, 0, 0); + cdleds_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + cdleds_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, cdleds->Width, cdleds->Height, 1); + cdleds_vertices[1].uv = vertex_to_UV(cdleds, cdleds->Width, cdleds->Height); + cdleds_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); } void set_osd_values() { - if (osd != NULL) { - free(osd->Mem); - free(osd); - free(osd_vertices); - } - osd = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); - size_t osdSize = gsKit_texture_size_ee(512, 8, GS_PSM_CT16); - osd->Width = 512; - osd->Height = 8; - osd->PSM = GS_PSM_CT16; - osd->Mem = (uint32_t *)malloc(osdSize); + size_t osdSize = gsKit_texture_size_ee(gsGlobal->Width, 8, GS_PSM_CT16); + int num_osds = 4, i; - osd_vertices_count = 2; - osd_vertices = (GSPRIMUVPOINT *)calloc(osd_vertices_count, sizeof(GSPRIMUVPOINT)); - - osd_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, 0, 0, 1); - osd_vertices[0].uv = vertex_to_UV(osd, 0, 0); - osd_vertices[0].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + osd = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE)); + osd->Mem = (uint32_t *)malloc(osdSize); - osd_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, osd->Width, osd->Height, 1); - osd_vertices[1].uv = vertex_to_UV(osd, osd->Width, osd->Height); - osd_vertices[1].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + osd_vertices_count = 2*num_osds; + osd_vertices = (GSPRIMUVPOINT *)calloc(osd_vertices_count, sizeof(GSPRIMUVPOINT)); + + osd->Width = gsGlobal->Width; + osd->Height = 8; + osd->PSM = GS_PSM_CT16; + + for (i = 0; i < 2*num_osds; i++) + osd_vertices[i].rgbaq = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); } static void video_init(void) { - ee_sema_t sema; + ee_sema_t sema; - sema.init_count = 0; - sema.max_count = 1; - sema.option = 0; + sema.init_count = 0; + sema.max_count = 1; + sema.option = 0; - vsync_sema_id = CreateSema(&sema); + vsync_sema_id = CreateSema(&sema); - gsGlobal = gsKit_init_global(); - gsGlobal->Mode = GS_MODE_NTSC; - gsGlobal->Height = 448; + gsGlobal = gsKit_init_global(); +// gsGlobal->Mode = GS_MODE_NTSC; +// gsGlobal->Height = 448; - gsGlobal->PSM = GS_PSM_CT24; - gsGlobal->PSMZ = GS_PSMZ_16S; - gsGlobal->ZBuffering = GS_SETTING_OFF; - gsGlobal->DoubleBuffering = GS_SETTING_ON; - gsGlobal->PrimAlphaEnable = GS_SETTING_OFF; - gsGlobal->Dithering = GS_SETTING_OFF; + gsGlobal->PSM = GS_PSM_CT16; + gsGlobal->PSMZ = GS_PSMZ_16S; + gsGlobal->ZBuffering = GS_SETTING_OFF; + gsGlobal->DoubleBuffering = GS_SETTING_ON; + gsGlobal->PrimAlphaEnable = GS_SETTING_OFF; + gsGlobal->Dithering = GS_SETTING_OFF; - dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF); - dmaKit_chan_init(DMA_CHANNEL_GIF); + dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF); + dmaKit_chan_init(DMA_CHANNEL_GIF); - gsKit_set_clamp(gsGlobal, GS_CMODE_REPEAT); + gsKit_set_clamp(gsGlobal, GS_CMODE_REPEAT); - gsKit_vram_clear(gsGlobal); - gsKit_init_screen(gsGlobal); - gsKit_TexManager_init(gsGlobal); - gsKit_mode_switch(gsGlobal, GS_ONESHOT); - gsKit_clear(gsGlobal, GS_BLACK); - vsync = 0; - vsync_callback_id = gsKit_add_vsync_handler(vsync_handler); + gsKit_vram_clear(gsGlobal); + gsKit_init_screen(gsGlobal); + gsKit_TexManager_init(gsGlobal); + gsKit_mode_switch(gsGlobal, GS_ONESHOT); + gsKit_clear(gsGlobal, GS_BLACK); + vsync = 0; + vsync_callback_id = gsKit_add_vsync_handler(vsync_handler); - set_g_menuscreen_values(); + set_g_screen_values(); + set_g_menuscreen_values(); + set_osd_values(); + set_cdleds_values(); + + g_menubg_ptr = (uint8_t *)malloc(2 * g_menuscreen_pp * g_menuscreen_h); + g_menubg_src_w = g_screen->Width; + g_menubg_src_h = g_screen->Height; + g_menubg_src_pp = g_screen->Width; } static void video_deinit(void) { - free(g_menuscreen->Mem); - free(g_menuscreen); - free(g_menuscreen_vertices); - free(g_menubg_ptr); + free(g_screens[0]->Mem); + free(g_screens[0]); + free(g_screens[1]->Mem); + free(g_screens[1]); + free(g_screen_vertices); + free(g_screen_palette); - gsKit_clear(gsGlobal, GS_BLACK); - gsKit_vram_clear(gsGlobal); - gsKit_deinit_global(gsGlobal); - gsKit_remove_vsync_handler(vsync_callback_id); + free(g_menuscreen->Mem); + free(g_menuscreen); + free(g_menuscreen_vertices); + free(g_menubg_ptr); - if (vsync_sema_id >= 0) - DeleteSema(vsync_sema_id); + free(osd->Mem); + free(osd); + free(osd_vertices); + + free(cdleds->Mem); + free(cdleds); + free(cdleds_vertices); + + gsKit_clear(gsGlobal, GS_BLACK); + gsKit_vram_clear(gsGlobal); + gsKit_deinit_global(gsGlobal); + gsKit_remove_vsync_handler(vsync_callback_id); + + if (vsync_sema_id >= 0) + DeleteSema(vsync_sema_id); +} + +static void set_scaling_params(void) +{ + int width, height, xoffs, yoffs; + int u[2], v[2]; + + height = (int)(out_h * vscale + 0.5); + width = (int)(out_w * hscale + 0.5); + + if (width & 1) width++; // make even + if (height & 1) height++; + + if (width >= gsGlobal->Width) { + u[0] = out_x + (width-gsGlobal->Width)/2; + u[1] = out_x + out_w - (width-gsGlobal->Width)/2 - 1; + width = gsGlobal->Width; + xoffs = 0; + } else { + u[0] = out_x; + u[1] = out_x + out_w; + xoffs = gsGlobal->Width/2 - width/2; + } + + if (height >= gsGlobal->Height) { + v[0] = out_y + (height-gsGlobal->Height)/2; + v[1] = out_y + out_h - (height-gsGlobal->Height)/2; + height = gsGlobal->Height; + yoffs = 0; + } else { + v[0] = out_y; + v[1] = out_y + out_h; + yoffs = gsGlobal->Height/2 - height/2; + } + + if (xoffs < 0) xoffs = 0; + if (yoffs < 0) yoffs = 0; + g_screen_vertices[0].xyz2 = vertex_to_XYZ2(gsGlobal, xoffs, yoffs, 0); + g_screen_vertices[1].xyz2 = vertex_to_XYZ2(gsGlobal, xoffs + width, yoffs + height, 0); + + if (!is_16bit_mode()) { + // 8-bit modes have an 8 px overlap area on the left + u[0] += 8; u[1] += 8; + } + g_screen_vertices[0].uv = vertex_to_UV(g_screen, u[0], v[0]); + g_screen_vertices[1].uv = vertex_to_UV(g_screen, u[1], v[1]); + +// lprintf("set_scaling_params: wxh = %ix%i\n",gsGlobal->Width,gsGlobal->Height); +// lprintf("offs: %i, %i wh: %i, %i\n", xoffs, yoffs, width, height); +// lprintf("uv0, uv1: %i, %i; %i, %i\n", u[0], v[0], u[1], v[1]); +} + +static void make_ps2_palette(void) +{ + PicoDrawUpdateHighPal(); + + // Rotate CLUT. PS2 is special since entries in CLUT are not in sequence. + unsigned short int *pal=(void *)g_screen_palette; + int i; + + for (i = 0; i < 256; i+=8) { + if ((i&0x18) == 0x08) + memcpy(pal+i,Pico.est.HighPal+i+8,16); + else if ((i&0x18) == 0x10) + memcpy(pal+i,Pico.est.HighPal+i-8,16); + else + memcpy(pal+i,Pico.est.HighPal+i,16); + } } static int get_renderer(void) { + if (is_bg_frame) + return RT_16BIT; if (PicoIn.AHW & PAHW_32X) return currentConfig.renderer32x; else @@ -480,7 +569,6 @@ static void change_renderer(int diff) static void apply_renderer(void) { PicoIn.opt &= ~(POPT_ALT_RENDERER|POPT_EN_SOFTSCALE); - PicoIn.opt |= POPT_DIS_32C_BORDER; switch (get_renderer()) { case RT_16BIT: @@ -496,57 +584,65 @@ static void apply_renderer(void) } } -static void osd_text(int x, const char *text) -{ - // int len = strlen(text) * 8; - // int *p, h; - // void *tmp = g_screen_ptr; - // printf("osd_text, text: %s\n", text); - - // g_screen_ptr = osd_buf; - // for (h = 0; h < 8; h++) { - // p = (int *) (osd_buf+x+512*h); - // p = (int *) ((int)p & ~3); // align - // memset32_uncached(p, 0, len/2); - // } - // emu_text_out16(x, 0, text); - // g_screen_ptr = tmp; - - // osd_buf_x[osd_buf_cnt] = x; - // osd_buf_l[osd_buf_cnt] = len; - // osd_buf_cnt ++; -} - static void blit_screen(void) { - gsKit_TexManager_invalidate(gsGlobal, g_screen); + if (!is_16bit_mode() && Pico.m.dirtyPal) + make_ps2_palette(); - gsKit_TexManager_bind(gsGlobal, g_screen); - gskit_prim_list_sprite_texture_uv_3d( - gsGlobal, - g_screen, - 2, - g_screen_vertices - ); + g_screen->PSM = is_16bit_mode() ? GS_PSM_CT16 : GS_PSM_T8; + g_screen->Filter = (currentConfig.filter ? GS_FILTER_LINEAR : GS_FILTER_NEAREST); + + gsKit_TexManager_bind(gsGlobal, g_screen); + gskit_prim_list_sprite_texture_uv_3d(gsGlobal, g_screen, 2, g_screen_vertices); +} + +static void osd_text(int x, const char *text) +{ + void *old_ptr = g_screen_ptr; + int old_pitch = g_screen_ppitch; + + int len = strlen(text) * 8; + u16 *osd_buf = osd->Mem; + int *p, h; + + g_screen_ptr = osd_buf; + g_screen_ppitch = gsGlobal->Width; + for (h = 0; h < 8; h++) { + p = (int *) (osd_buf + x + gsGlobal->Width*h); + p = (int *) ((int)p & ~3); // align + memset32_uncached(p, 0, len/2); + } + emu_text_out16(x, 0, text); + g_screen_ptr = old_ptr; + g_screen_ppitch = old_pitch; + + osd_vertices[osd_buf_cnt].xyz2 = vertex_to_XYZ2(gsGlobal, x, gsGlobal->Height-8, 1); + osd_vertices[osd_buf_cnt].uv = vertex_to_UV(osd, x, 0); + osd_vertices[osd_buf_cnt+1].xyz2 = vertex_to_XYZ2(gsGlobal, x+len, gsGlobal->Height, 1); + osd_vertices[osd_buf_cnt+1].uv = vertex_to_UV(osd, x+len, 8); + osd_buf_cnt += 2; } static void blit_osd(void) { - + gsKit_TexManager_bind(gsGlobal, osd); + while (osd_buf_cnt > 0) { + osd_buf_cnt -= 2; + gskit_prim_list_sprite_texture_uv_3d(gsGlobal, osd, 2, osd_vertices+osd_buf_cnt); + } } static void cd_leds(void) { - unsigned int reg, col_g, col_r, *p; - gsKit_TexManager_invalidate(gsGlobal, cdleds); + unsigned int reg, col_g, col_r, *p; reg = Pico_mcd->s68k_regs[0]; p = (unsigned int *)cdleds->Mem; col_g = (reg & 2) ? 0x06000600 : 0; col_r = (reg & 1) ? 0x00180018 : 0; - *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 512/2 - 12/2; - *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 512/2 - 12/2; + *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += gsGlobal->Width/2 - 12/2; + *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += gsGlobal->Width/2 - 12/2; *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; osd_cdleds = 1; @@ -554,137 +650,42 @@ static void cd_leds(void) static void blit_cdleds(void) { - if (!osd_cdleds) return; + if (!osd_cdleds) return; - gsKit_TexManager_bind(gsGlobal, cdleds); - gskit_prim_list_sprite_texture_uv_3d( - gsGlobal, - cdleds, - 2, - cdleds_vertices - ); + gsKit_TexManager_bind(gsGlobal, cdleds); + gskit_prim_list_sprite_texture_uv_3d(gsGlobal, cdleds, 2, cdleds_vertices); } static void draw_pico_ptr(void) { - // unsigned char *p = (unsigned char *)g_screen_ptr + 8; + int x = pico_pen_x, y = pico_pen_y, offs; + int pp = g_screen_ppitch; - // // only if pen enabled and for 8bit mode - // if (pico_inp_mode == 0 || is_16bit_mode()) return; + x = (x * out_w * ((1ULL<<32) / 320)) >> 32; + y = (y * out_h * ((1ULL<<32) / 224)) >> 32; - // p += 512 * (pico_pen_y + PICO_PEN_ADJUST_Y); - // p += pico_pen_x + PICO_PEN_ADJUST_X; - // if (!(Pico.video.reg[12]&1) && !(PicoIn.opt & POPT_DIS_32C_BORDER)) - // p += 32; + offs = g_screen_ppitch * (out_y+y) + (out_x+x); - // p[ -1] = 0xe0; p[ 0] = 0xf0; p[ 1] = 0xe0; - // p[ 511] = 0xf0; p[ 512] = 0xf0; p[ 513] = 0xf0; - // p[1023] = 0xe0; p[1024] = 0xf0; p[1025] = 0xe0; + if (is_16bit_mode()) { + unsigned short *p = (unsigned short *)g_screen_ptr + offs; + + p[ -1] = 0x0000; p[ 0] = 0x001f; p[ 1] = 0x0000; + p[ pp-1] = 0x001f; p[ pp] = 0x001f; p[ pp+1] = 0x001f; + p[2*pp-1] = 0x0000; p[2*pp] = 0x001f; p[2*pp+1] = 0x0000; + } else { + unsigned char *p = (unsigned char *)g_screen_ptr + offs + 8; + + p[ -1] = 0xe0; p[ 0] = 0xf0; p[ 1] = 0xe0; + p[ pp-1] = 0xf0; p[ pp] = 0xf0; p[ pp+1] = 0xf0; + p[2*pp-1] = 0xe0; p[2*pp] = 0xf0; p[2*pp+1] = 0xe0; + } } -static void vidResetMode(void) {} - -/* Copy of gsKit_sync_flip, but without the 'flip' */ -static void gsKit_sync(GSGLOBAL *gsGlobal) +static void vidResetMode(void) { - if (!gsGlobal->FirstFrame) - WaitSema(vsync_sema_id); + set_scaling_params(); - while (PollSema(vsync_sema_id) >= 0); -} - -/* Copy of gsKit_sync_flip, but without the 'sync' */ -static void gsKit_flip(GSGLOBAL *gsGlobal) -{ - if (!gsGlobal->FirstFrame) - { - if (gsGlobal->DoubleBuffering == GS_SETTING_ON) - { - GS_SET_DISPFB2(gsGlobal->ScreenBuffer[gsGlobal->ActiveBuffer & 1] / 8192, - gsGlobal->Width / 64, gsGlobal->PSM, 0, 0); - - gsGlobal->ActiveBuffer ^= 1; - } - } - - gsKit_setactive(gsGlobal); -} - -static void flipScreen() -{ - gsKit_queue_exec(gsGlobal); - gsKit_finish(); - gsKit_flip(gsGlobal); - - gsKit_TexManager_nextFrame(gsGlobal); - gsKit_clear(gsGlobal, GS_BLACK); -} - - -/* display a completed frame buffer and prepare a new render buffer */ -void plat_video_flip(void) -{ - blit_screen(); - blit_osd(); - blit_cdleds(); - flipScreen(); -} - -/* wait for start of vertical blanking */ -void plat_video_wait_vsync(void) -{ - gsKit_sync(gsGlobal); -} - -/* switch from emulation display to menu display */ -void plat_video_menu_enter(int is_rom_loaded) -{ -} - -/* start rendering a menu screen */ -void plat_video_menu_begin(void) -{ - gsKit_TexManager_invalidate(gsGlobal, g_menuscreen); -} - -/* display a completed menu screen */ -void plat_video_menu_end(void) -{ - gsKit_TexManager_bind(gsGlobal, g_menuscreen); - gskit_prim_list_sprite_texture_uv_3d( - gsGlobal, - g_menuscreen, - 2, - g_menuscreen_vertices - ); - flipScreen(1); -} - -/* terminate menu display */ -void plat_video_menu_leave(void) -{ -} - -/* set default configuration values */ -void pemu_prep_defconfig(void) -{ - defaultConfig.s_PsndRate = 44100; - defaultConfig.s_PicoCDBuffers = 64; - defaultConfig.filter = EOPT_FILTER_BILINEAR; // bilinear filtering - defaultConfig.scaling = EOPT_SCALE_43; - defaultConfig.vscaling = EOPT_VSCALE_FULL; - defaultConfig.renderer = RT_16BIT; - defaultConfig.renderer32x = RT_8BIT_ACC; - defaultConfig.EmuOpt |= EOPT_SHOW_RTC; -} - -/* check configuration for inconsistencies */ -void pemu_validate_config(void) -{ - if (currentConfig.gamma < -4 || currentConfig.gamma > 16) - currentConfig.gamma = 0; - if (currentConfig.gamma2 < 0 || currentConfig.gamma2 > 2) - currentConfig.gamma2 = 0; + Pico.m.dirtyPal = 1; } /* finalize rendering a frame */ @@ -692,8 +693,8 @@ void pemu_finalize_frame(const char *fps, const char *notice) { int emu_opt = currentConfig.EmuOpt; - if (PicoIn.AHW & PAHW_PICO) - draw_pico_ptr(); + if ((PicoIn.AHW & PAHW_PICO) && (currentConfig.EmuOpt & EOPT_PICO_PEN)) + if (pico_inp_mode) draw_pico_ptr(); osd_buf_cnt = 0; if (notice) osd_text(4, notice); @@ -706,22 +707,99 @@ void pemu_finalize_frame(const char *fps, const char *notice) FlushCache(WRITEBACK_DCACHE); } -void plat_init(void) +/* display a completed frame buffer and prepare a new render buffer */ +void plat_video_flip(void) { - video_init(); - init_joystick_driver(false); - in_ps2_init(in_ps2_defbinds); - in_probe(); - init_audio_driver(); - sound_init(); - plat_get_data_dir(rom_fname_loaded, sizeof(rom_fname_loaded)); + gsKit_TexManager_invalidate(gsGlobal, osd); + gsKit_TexManager_invalidate(gsGlobal, cdleds); + gsKit_TexManager_invalidate(gsGlobal, g_screen); + + gsKit_finish(); + flipScreen(); + + gsKit_clear(gsGlobal, GS_BLACK); + blit_screen(); + blit_osd(); + blit_cdleds(); + gsKit_queue_exec(gsGlobal); + + g_screen_index ^= 1; + g_screen = g_screens[g_screen_index]; + g_screen_ptr = g_screen->Mem; + + plat_video_set_buffer(g_screen_ptr); +} + +/* wait for start of vertical blanking */ +void plat_video_wait_vsync(void) +{ + gsKit_sync(gsGlobal); +} + +/* switch from emulation display to menu display */ +void plat_video_menu_enter(int is_rom_loaded) +{ + g_screen_ptr = NULL; +} + +/* start rendering a menu screen */ +void plat_video_menu_begin(void) +{ +} + +/* display a completed menu screen */ +void plat_video_menu_end(void) +{ + gsKit_TexManager_bind(gsGlobal, g_menuscreen); + gskit_prim_list_sprite_texture_uv_3d( gsGlobal, g_menuscreen, 2, g_menuscreen_vertices); + gsKit_queue_exec(gsGlobal); + gsKit_finish(); + gsKit_TexManager_invalidate(gsGlobal, g_menuscreen); + + flipScreen(); +} + +/* terminate menu display */ +void plat_video_menu_leave(void) +{ + g_screen_ptr = g_screen->Mem; + plat_video_set_buffer(g_screen_ptr); +} + +/* set default configuration values */ +void pemu_prep_defconfig(void) +{ + defaultConfig.s_PsndRate = 22050; + defaultConfig.s_PicoCDBuffers = 64; + defaultConfig.filter = EOPT_FILTER_BILINEAR; // bilinear filtering + defaultConfig.scaling = EOPT_SCALE_43; + defaultConfig.vscaling = EOPT_VSCALE_FULL; + defaultConfig.renderer = RT_8BIT_ACC; + defaultConfig.renderer32x = RT_8BIT_ACC; + defaultConfig.EmuOpt |= EOPT_SHOW_RTC; +} + +/* check configuration for inconsistencies */ +void pemu_validate_config(void) +{ +} + +void plat_init(void) +{ + video_init(); + init_joystick_driver(false); + in_ps2_init(in_ps2_defbinds); + in_probe(); + init_audio_driver(); + sound_init(); + plat_get_data_dir(rom_fname_loaded, sizeof(rom_fname_loaded)); } void plat_finish(void) { - sound_deinit(); - deinit_audio_driver(); - deinit_joystick_driver(false); - video_deinit(); + sound_deinit(); + deinit_audio_driver(); + deinit_joystick_driver(false); + video_deinit(); } /* display emulator status messages before holding emulation */ @@ -754,37 +832,38 @@ void emu_video_mode_change(int start_line, int line_count, int start_col, int co int h43 = (col_count >= 192 ? 320 : col_count); // ugh, mind GG... int v43 = (line_count >= 192 ? Pico.m.pal ? 240 : 224 : line_count); + out_y = start_line; out_x = start_col; + out_h = line_count; out_w = col_count; + if (col_count == 248) // mind aspect ratio when blanking 1st column col_count = 256; - - g_screen_vertices[0].uv = vertex_to_UV(g_screen, start_col, start_line); - g_screen_vertices[1].uv = vertex_to_UV(g_screen, col_count, line_count); switch (currentConfig.vscaling) { case EOPT_VSCALE_FULL: line_count = v43; - vscale = (float)270/line_count; + vscale = (float)gsGlobal->Height/line_count; break; case EOPT_VSCALE_NOBORDER: - vscale = (float)270/line_count; + vscale = (float)gsGlobal->Height/line_count; break; default: vscale = 1; break; } + hscale = vscale * (gsGlobal->Aspect == GS_ASPECT_16_9 ? (4./3)/(16./9) : 1); switch (currentConfig.scaling) { case EOPT_SCALE_43: - hscale = (vscale*h43)/col_count; + hscale = (hscale*h43)/col_count; break; case EOPT_SCALE_STRETCH: - hscale = (vscale*h43/2 + 480/2)/col_count; + hscale = (hscale*h43/2 + gsGlobal->Width/2)/col_count; break; case EOPT_SCALE_WIDE: - hscale = (float)480/col_count; + hscale = (float)gsGlobal->Width/col_count; break; default: - hscale = vscale; + // hscale = vscale, computed before switch break; } @@ -794,11 +873,15 @@ void emu_video_mode_change(int start_line, int line_count, int start_col, int co /* render one frame in RGB */ void pemu_forced_frame(int no_scale, int do_emu) { + is_bg_frame = 1; Pico.m.dirtyPal = 1; if (!no_scale) no_scale = currentConfig.scaling == EOPT_SCALE_NONE; emu_cmn_forced_frame(no_scale, do_emu, g_screen_ptr); + + g_menubg_src_ptr = g_screen_ptr; + is_bg_frame = 0; } /* change the platform output rendering */ @@ -819,8 +902,17 @@ void plat_video_toggle_renderer(int change, int is_menu_call) emu_status_msg(renderer_names[get_renderer()]); } +/* set the buffer for emulator output rendering */ +void plat_video_set_buffer(void *buf) +{ + if (is_16bit_mode()) + PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2); + else + PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch); +} + /* prepare for emulator output rendering */ -void plat_video_loop_prepare(void) +void plat_video_loop_prepare(void) { apply_renderer(); vidResetMode(); @@ -829,12 +921,11 @@ void plat_video_loop_prepare(void) /* prepare for entering the emulator loop */ void pemu_loop_prep(void) { - set_g_screen_values(); - set_cdleds_values(); } /* terminate the emulator loop */ void pemu_loop_end(void) { - pemu_sound_stop(); -} \ No newline at end of file + pemu_sound_stop(); + pemu_forced_frame(0, 1); +} diff --git a/platform/ps2/menu.c b/platform/ps2/menu.c new file mode 100644 index 00000000..c4416448 --- /dev/null +++ b/platform/ps2/menu.c @@ -0,0 +1,21 @@ + +static const char *men_vscaling_opts[] = { "OFF", "fullscreen", "borderless", NULL }; +static const char *men_hscaling_opts[] = { "1:1", "4:3", "extended", "fullwidth", NULL }; +static const char *men_filter_opts[] = { "nearest", "bilinear", NULL }; + +#define MENU_OPTIONS_GFX \ + mee_enum ("Vertical scaling", MA_OPT_VSCALING, currentConfig.vscaling, men_vscaling_opts), \ + mee_enum ("Aspect ratio", MA_OPT_SCALING, currentConfig.scaling, men_hscaling_opts), \ + mee_enum ("Scaler type", MA_OPT3_FILTERING, currentConfig.filter, men_filter_opts), \ + mee_onoff ("Wait for vsync", MA_OPT3_VSYNC, currentConfig.EmuOpt, EOPT_VSYNC), \ + +#define MENU_OPTIONS_ADV + +static menu_entry e_menu_sms_options[]; +static menu_entry e_menu_keyconfig[]; + +void psp_menu_init(void) +{ + me_enable(e_menu_sms_options, MA_SMSOPT_GHOSTING, 0); + me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0); +} diff --git a/platform/ps2/menu.h b/platform/ps2/menu.h new file mode 100644 index 00000000..d5aa6082 --- /dev/null +++ b/platform/ps2/menu.h @@ -0,0 +1,10 @@ + +void menu_loop(void); +int menu_loop_tray(void); +void menu_romload_prepare(const char *rom_name); +void menu_romload_end(void); + + +#define CONFIGURABLE_KEYS (PBTN_UP|PBTN_LEFT|PBTN_RIGHT|PBTN_DOWN|PBTN_L|PBTN_R|PBTN_TRIANGLE|PBTN_CIRCLE|PBTN_X|PBTN_SQUARE|PBTN_START| \ + PBTN_NUB_UP|PBTN_NUB_RIGHT|PBTN_NUB_DOWN|PBTN_NUB_LEFT|PBTN_NOTE) + diff --git a/platform/ps2/plat.c b/platform/ps2/plat.c index 7b6d2267..d645b5ef 100644 --- a/platform/ps2/plat.c +++ b/platform/ps2/plat.c @@ -19,7 +19,8 @@ #include "../libpicofe/plat.h" -struct plat_target plat_target = {}; +static int sound_rates[] = { 11025, 22050, 44100, -1 }; +struct plat_target plat_target = { .sound_rates = sound_rates }; static void reset_IOP() { SifInitRpc(0); @@ -205,4 +206,4 @@ void lprintf(const char *fmt, ...) va_end(vl); } -void plat_debug_cat(char *str) {} \ No newline at end of file +void plat_debug_cat(char *str) {} From 3eb1d645852e3142d30b7bf1ce2b00d8d3b35041 Mon Sep 17 00:00:00 2001 From: kub Date: Wed, 14 Feb 2024 23:41:24 +0100 Subject: [PATCH 16/19] ps2, minor audio and gfx fixes --- platform/ps2/emu.c | 16 +++++++--------- platform/ps2/plat.c | 2 +- platform/psp/plat.c | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index a5de6493..a423f6ec 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -78,7 +78,7 @@ static int32_t vsync_callback_id; static uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ /* sound stuff */ -#define SOUND_BLOCK_COUNT 8 +#define SOUND_BLOCK_COUNT 6 #define SOUND_BUFFER_SIZE (2*54000/50*SOUND_BLOCK_COUNT) // max.rate/min.frames static short __attribute__((aligned(4))) sndBuffer[SOUND_BUFFER_SIZE]; @@ -100,7 +100,7 @@ static void writeSound(int len) l = PicoIn.sndOut - sndBuffer; if (l > sizeof(sndBuffer)/2) lprintf("ovfl %d %d\n", len, PicoIn.sndOut - sndBuffer); - if (l > samples_block * 6) { + if (l > samples_block * (SOUND_BLOCK_COUNT-2)) { sndBuffer_endptr = PicoIn.sndOut; PicoIn.sndOut = sndBuffer; } @@ -111,11 +111,12 @@ static void writeSound(int len) samples_made += len / 2; // lprintf("signal, %i/%i\n", samples_done, samples_made); ret = SignalSema(sound_sem); -// if (ret < 0) lprintf("snd signal ret %08x\n", ret); + if (ret < 0) lprintf("snd signal ret %08x\n", ret); } static int sound_thread(void *argp) { + lprintf("sthr: start\n"); while (!sound_thread_exit) { int ret = 0; @@ -130,14 +131,13 @@ static int sound_thread(void *argp) } // lprintf("sthr: got data: %i\n", samples_made - samples_done); short *sndOut = PicoIn.sndOut, *sndEnd = sndBuffer_endptr; - int buflen = samples_block * 2; + int buflen = sndEnd - snd_playptr; if (sndOut >= snd_playptr) buflen = sndOut - snd_playptr; - else buflen = sndEnd - snd_playptr; if (buflen > samples_block) buflen = samples_block; ret = audsrv_play_audio((char *)snd_playptr, buflen*2); -// if (ret != buflen*2 && ret >= 0) lprintf("sthr: play ret: %i, buflen: %i\n", ret, buflen*2); + if (ret != buflen*2 && ret >= 0) lprintf("sthr: play ret: %i, buflen: %i\n", ret, buflen*2); if (ret < 0) lprintf("sthr: play: ret %08x; pos %i/%i\n", ret, samples_done, samples_made); samples_done += buflen; @@ -241,7 +241,7 @@ void pemu_sound_start(void) { void pemu_sound_stop(void) { samples_made = samples_done = 0; - plat_sleep_ms(100); + plat_sleep_ms(200); audsrv_stop_audio(); } @@ -336,8 +336,6 @@ void set_g_screen_values() { g_screens[i]->Width = 328; g_screens[i]->Height = 256; - g_screens[i]->PSM = GS_PSM_CT16; - g_screens[i]->Filter = GS_FILTER_LINEAR; g_screens[i]->Clut = g_screen_palette; g_screens[i]->ClutPSM = GS_PSM_CT16; diff --git a/platform/ps2/plat.c b/platform/ps2/plat.c index d645b5ef..17cfdc08 100644 --- a/platform/ps2/plat.c +++ b/platform/ps2/plat.c @@ -115,7 +115,7 @@ unsigned int plat_get_ticks_ms(void) ret = (unsigned)tv.tv_sec * 1000; /* approximate /= 1000 */ - ret += ((unsigned)tv.tv_usec * 4195) >> 22; + ret += ((unsigned)tv.tv_usec * 4194) >> 22; return ret; } diff --git a/platform/psp/plat.c b/platform/psp/plat.c index b23bc386..64ae0432 100644 --- a/platform/psp/plat.c +++ b/platform/psp/plat.c @@ -181,7 +181,7 @@ unsigned int plat_get_ticks_ms(void) ret = (unsigned)tv.tv_sec * 1000; /* approximate /= 1000 */ - ret += ((unsigned)tv.tv_usec * 4195) >> 22; + ret += ((unsigned)tv.tv_usec * 4194) >> 22; return ret; } From dedf7fa7d5577577f8029ccdd5aceb6207488355 Mon Sep 17 00:00:00 2001 From: kub Date: Wed, 14 Feb 2024 23:42:50 +0100 Subject: [PATCH 17/19] ps2, kludge for timer bugs in ps2sdk --- platform/ps2/plat.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/platform/ps2/plat.c b/platform/ps2/plat.c index 17cfdc08..253e1878 100644 --- a/platform/ps2/plat.c +++ b/platform/ps2/plat.c @@ -134,16 +134,38 @@ unsigned int plat_get_ticks_us(void) return ret; } -/* sleep for some time in ms */ -void plat_sleep_ms(int ms) +/* Unfortunately the SetTimerAlarm function in ps2sdk has a bug which makes it + * waiting much too long in some cases. For now, replaced by SetAlarm and a + * polling loop with RotateThreadReadyQueue for yielding to other threads. + */ + +static void alarm_cb(int id, unsigned short time, void *arg) { - usleep(ms * 1000); + iWakeupThread((s32)arg); } /* sleep for some time in us */ void plat_wait_till_us(unsigned int us_to) { - usleep(us_to - plat_get_ticks_us()); + // TODO hsync depends on NTSC/PAL (15750/15625 Hz), it however doesn't + // matter if it falls a bit short, the while loop will catch the rest + unsigned hsyncs = (us_to - plat_get_ticks_us()) * 15620 / 1000000; + + if (hsyncs && SetAlarm(hsyncs, alarm_cb, (void *)GetThreadId()) >= 0) + SleepThread(); + while ((int)(us_to - plat_get_ticks_us()) > 0) + RotateThreadReadyQueue(0); + +// unsigned int ticks = plat_get_ticks_us(); +// if ((int)(us_to - ticks) > 0) +// usleep(us_to - ticks); +} + +/* sleep for some time in ms */ +void plat_sleep_ms(int ms) +{ + plat_wait_till_us(plat_get_ticks_us() + ms*1000); +// usleep(ms * 1000); } /* wait until some event occurs, or timeout */ From fd604aa720093043caa374b0d8a3404e3b3cbe5f Mon Sep 17 00:00:00 2001 From: kub Date: Thu, 15 Feb 2024 23:08:24 +0100 Subject: [PATCH 18/19] ps2, kludge for handling audsrv shortcomings --- platform/ps2/emu.c | 103 ++++++++++++++++++++++++++++++++------------- 1 file changed, 74 insertions(+), 29 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index a423f6ec..8632fc06 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -79,9 +79,10 @@ static uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ /* sound stuff */ #define SOUND_BLOCK_COUNT 6 -#define SOUND_BUFFER_SIZE (2*54000/50*SOUND_BLOCK_COUNT) // max.rate/min.frames +#define SOUND_BUFFER_CHUNK (2*54000/50) // max.rate/min.frames, stereo -static short __attribute__((aligned(4))) sndBuffer[SOUND_BUFFER_SIZE]; +static short __attribute__((aligned(4))) sndBuffer[SOUND_BUFFER_CHUNK*SOUND_BLOCK_COUNT]; +static short __attribute__((aligned(4))) nulBuffer[SOUND_BUFFER_CHUNK]; static short *snd_playptr = NULL, *sndBuffer_endptr = NULL; static int samples_made = 0, samples_done = 0, samples_block = 0; static int sound_thread_exit = 0; @@ -91,6 +92,23 @@ extern void *_gp; static int mp3_init(void) { return 0; } +/* audsrv in ps2sdk has shortcomings: + * - it has a bug which prevents it from discerning "ringbuffer empty" from + * "ringbuffer full", which leads to audio not stopped if all queued samples + * have been played. Hence, it repeats the complete ringbuffer over and again. + * - on audsrv_set_format the ringbuffer is preset to be about 40% filled, + * regardless of the data in the buffer at that moment. Old data is played out + * if audio play is started. + * - stopping audio play is keeping any remaining samples in the buffer, which + * are played first after the next audio play. There's no method to clear the + * ringbuffer. + * + * To cope with this, audio samples are always pushed to audsrv to prevent the + * ringbuffer from emptying, even in the menu. This also avoids stopping audio. + * Since silence is played in the menu, the behaviour of set_format when leaving + * the menu is covered since the buffer is filled with silence at that time. + */ + static void writeSound(int len) { int ret, l; @@ -106,45 +124,72 @@ static void writeSound(int len) } if (sndBuffer_endptr < PicoIn.sndOut) sndBuffer_endptr = PicoIn.sndOut; + samples_made += len / 2; // signal the snd thread - samples_made += len / 2; -// lprintf("signal, %i/%i\n", samples_done, samples_made); - ret = SignalSema(sound_sem); - if (ret < 0) lprintf("snd signal ret %08x\n", ret); +// ret = SignalSema(sound_sem); +// if (ret < 0) lprintf("snd signal ret %08x\n", ret); } static int sound_thread(void *argp) { lprintf("sthr: start\n"); + while (!sound_thread_exit) { int ret = 0; - if (samples_made - samples_done < samples_block) { - // wait for data (use at least 2 blocks) -// lprintf("sthr: wait... (%i)\n", samples_made - samples_done); - while (samples_made - samples_done < samples_block*2 && !sound_thread_exit) - ret = WaitSema(sound_sem); - if (ret < 0) lprintf("sthr: WaitSema: %i\n", ret); - continue; + // curb the sample queue to prevent it from filling + while (samples_made - samples_done > 4*samples_block) { + short *sndOut = PicoIn.sndOut, *sndEnd = sndBuffer_endptr; + + int buflen = sndEnd - snd_playptr; + if (sndOut > snd_playptr) + buflen = sndOut - snd_playptr; + if (buflen > samples_made - samples_done - 4*samples_block) + buflen = samples_made - samples_done - 4*samples_block; + + samples_done += buflen; + snd_playptr += buflen; + if (snd_playptr >= sndBuffer_endptr) + snd_playptr -= sndBuffer_endptr - sndBuffer; } -// lprintf("sthr: got data: %i\n", samples_made - samples_done); - short *sndOut = PicoIn.sndOut, *sndEnd = sndBuffer_endptr; - int buflen = sndEnd - snd_playptr; - if (sndOut >= snd_playptr) - buflen = sndOut - snd_playptr; - if (buflen > samples_block) - buflen = samples_block; - ret = audsrv_play_audio((char *)snd_playptr, buflen*2); - if (ret != buflen*2 && ret >= 0) lprintf("sthr: play ret: %i, buflen: %i\n", ret, buflen*2); - if (ret < 0) lprintf("sthr: play: ret %08x; pos %i/%i\n", ret, samples_done, samples_made); - samples_done += buflen; - snd_playptr += buflen; + // queue samples to audsrv, minimum 2 frames + // if there aren't enough samlpes, queue silence + int queued = audsrv_queued()/2; + while (queued < 2*samples_block) { + short *sndOut = PicoIn.sndOut, *sndEnd = sndBuffer_endptr; - if (snd_playptr >= sndBuffer_endptr) - snd_playptr = sndBuffer; + // compute sample chunk size + int buflen = sndEnd - snd_playptr; + if (sndOut > snd_playptr) + buflen = sndOut - snd_playptr; + if (buflen > samples_made - samples_done) + buflen = samples_made - samples_done; + if (buflen > 4*samples_block - queued) + buflen = 4*samples_block - queued; + + // play audio + if (buflen > 0) { + ret = audsrv_play_audio((char *)snd_playptr, buflen*2); + + samples_done += buflen; + snd_playptr += buflen; + if (snd_playptr >= sndBuffer_endptr) + snd_playptr -= sndBuffer_endptr - sndBuffer; + } else { + buflen = 3*samples_block - queued; + ret = audsrv_play_audio((char *)nulBuffer, buflen*2); + } + if (ret != buflen*2 && ret >= 0) lprintf("sthr: play ret: %i, buflen: %i\n", ret, buflen*2); + if (ret < 0) lprintf("sthr: play: ret %08x; pos %i/%i\n", ret, samples_done, samples_made); + + queued = audsrv_queued()/2; + } + + ret = WaitSema(sound_sem); + if (ret < 0) lprintf("sthr: WaitSema failed (%d)\n", ret); } lprintf("sthr: exit\n"); @@ -235,14 +280,13 @@ void pemu_sound_start(void) { PicoOpt_old = PicoIn.opt; pal_old = Pico.m.pal; } - ret = audsrv_play_audio((char *)snd_playptr, 4); + audsrv_play_audio((char *)snd_playptr, 2*2); } void pemu_sound_stop(void) { samples_made = samples_done = 0; plat_sleep_ms(200); - audsrv_stop_audio(); } static void sound_deinit(void) @@ -259,6 +303,7 @@ static void sound_deinit(void) static int vsync_handler(void) { iSignalSema(vsync_sema_id); + iSignalSema(sound_sem); ExitHandler(); return 0; From e2b9687b3f3130a1d8c3ef54b5042f610f95f28f Mon Sep 17 00:00:00 2001 From: kub Date: Sat, 17 Feb 2024 19:37:11 +0100 Subject: [PATCH 19/19] ps2, more audio fixes --- platform/ps2/emu.c | 123 ++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 56 deletions(-) diff --git a/platform/ps2/emu.c b/platform/ps2/emu.c index 8632fc06..d5385930 100644 --- a/platform/ps2/emu.c +++ b/platform/ps2/emu.c @@ -78,15 +78,16 @@ static int32_t vsync_callback_id; static uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ /* sound stuff */ -#define SOUND_BLOCK_COUNT 6 -#define SOUND_BUFFER_CHUNK (2*54000/50) // max.rate/min.frames, stereo +#define SOUND_BLOCK_COUNT 7 +#define SOUND_BUFFER_CHUNK (2*54000/50) // max.rate/min.frames in stereo static short __attribute__((aligned(4))) sndBuffer[SOUND_BUFFER_CHUNK*SOUND_BLOCK_COUNT]; static short __attribute__((aligned(4))) nulBuffer[SOUND_BUFFER_CHUNK]; static short *snd_playptr = NULL, *sndBuffer_endptr = NULL; -static int samples_made = 0, samples_done = 0, samples_block = 0; -static int sound_thread_exit = 0; -static int32_t sound_sem = -1; +static int samples_made, samples_done, samples_block; + +static int sound_thread_exit = 0, sound_stopped = 1; +static int32_t sound_sem = -1, sound_mutex = -1; static uint8_t stack[0x4000] __attribute__((aligned(16))); extern void *_gp; @@ -113,22 +114,41 @@ static void writeSound(int len) { int ret, l; - PicoIn.sndOut += len / 2; + if (samples_made - samples_done < samples_block * (SOUND_BLOCK_COUNT-3)) { + samples_made += len / 2; + PicoIn.sndOut += len / 2; + } else + lprintf("ovfl %d\n", samples_made - samples_done); + if (sndBuffer_endptr < PicoIn.sndOut) + sndBuffer_endptr = PicoIn.sndOut; l = PicoIn.sndOut - sndBuffer; if (l > sizeof(sndBuffer)/2) - lprintf("ovfl %d %d\n", len, PicoIn.sndOut - sndBuffer); + lprintf("ovrn %d %d\n", len, PicoIn.sndOut - sndBuffer); if (l > samples_block * (SOUND_BLOCK_COUNT-2)) { sndBuffer_endptr = PicoIn.sndOut; PicoIn.sndOut = sndBuffer; } - if (sndBuffer_endptr < PicoIn.sndOut) - sndBuffer_endptr = PicoIn.sndOut; - samples_made += len / 2; // signal the snd thread -// ret = SignalSema(sound_sem); -// if (ret < 0) lprintf("snd signal ret %08x\n", ret); + SignalSema(sound_sem); +} + +static void resetSound() +{ + struct audsrv_fmt_t format; + int stereo = (PicoIn.opt&8)>>3; + int ret; + + format.bits = 16; + format.freq = PicoIn.sndRate; + format.channels = stereo ? 2 : 1; + ret = audsrv_set_format(&format); + if (ret < 0) { + lprintf("audsrv_set_format() failed: %i\n", ret); + emu_status_msg("sound init failed (%i), snd disabled", ret); + currentConfig.EmuOpt &= ~EOPT_EN_SOUND; + } } static int sound_thread(void *argp) @@ -137,26 +157,11 @@ static int sound_thread(void *argp) while (!sound_thread_exit) { - int ret = 0; - - // curb the sample queue to prevent it from filling - while (samples_made - samples_done > 4*samples_block) { - short *sndOut = PicoIn.sndOut, *sndEnd = sndBuffer_endptr; - - int buflen = sndEnd - snd_playptr; - if (sndOut > snd_playptr) - buflen = sndOut - snd_playptr; - if (buflen > samples_made - samples_done - 4*samples_block) - buflen = samples_made - samples_done - 4*samples_block; - - samples_done += buflen; - snd_playptr += buflen; - if (snd_playptr >= sndBuffer_endptr) - snd_playptr -= sndBuffer_endptr - sndBuffer; - } + int ret = WaitSema(sound_mutex); + if (ret < 0) lprintf("sthr: WaitSema mutex failed (%d)\n", ret); // queue samples to audsrv, minimum 2 frames - // if there aren't enough samlpes, queue silence + // if there aren't enough samples, queue silence int queued = audsrv_queued()/2; while (queued < 2*samples_block) { short *sndOut = PicoIn.sndOut, *sndEnd = sndBuffer_endptr; @@ -167,8 +172,8 @@ static int sound_thread(void *argp) buflen = sndOut - snd_playptr; if (buflen > samples_made - samples_done) buflen = samples_made - samples_done; - if (buflen > 4*samples_block - queued) - buflen = 4*samples_block - queued; + if (buflen > 3*samples_block - queued) + buflen = 3*samples_block - queued; // play audio if (buflen > 0) { @@ -179,17 +184,23 @@ static int sound_thread(void *argp) if (snd_playptr >= sndBuffer_endptr) snd_playptr -= sndBuffer_endptr - sndBuffer; } else { - buflen = 3*samples_block - queued; + buflen = (3*samples_block - queued) & ~1; + while (buflen > sizeof(nulBuffer)/2) { + audsrv_play_audio((char *)nulBuffer, sizeof(nulBuffer)); + buflen -= sizeof(nulBuffer)/2; + } ret = audsrv_play_audio((char *)nulBuffer, buflen*2); } - if (ret != buflen*2 && ret >= 0) lprintf("sthr: play ret: %i, buflen: %i\n", ret, buflen*2); + if (ret != buflen*2 && ret > 0) lprintf("sthr: play ret: %i, buflen: %i\n", ret, buflen*2); if (ret < 0) lprintf("sthr: play: ret %08x; pos %i/%i\n", ret, samples_done, samples_made); + if (ret == 0) resetSound(); queued = audsrv_queued()/2; } + SignalSema(sound_mutex); ret = WaitSema(sound_sem); - if (ret < 0) lprintf("sthr: WaitSema failed (%d)\n", ret); + if (ret < 0) lprintf("sthr: WaitSema sound failed (%d)\n", ret); } lprintf("sthr: exit\n"); @@ -209,6 +220,11 @@ static void sound_init(void) sema.option = (u32) "sndsem"; if ((sound_sem = CreateSema(&sema)) < 0) return; + sema.max_count = 1; + sema.init_count = 1; + sema.option = (u32) "sndmutex"; + if ((sound_mutex = CreateSema(&sema)) < 0) + return; audsrv_init(); thread.func = &sound_thread; @@ -234,7 +250,6 @@ void pemu_sound_start(void) { static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0; static int mp3_init_done; int ret, stereo; - struct audsrv_fmt_t format; samples_made = samples_done = 0; @@ -250,43 +265,38 @@ void pemu_sound_start(void) { } } + ret = WaitSema(sound_mutex); + if (ret < 0) lprintf("WaitSema mutex failed (%d)\n", ret); + if (PicoIn.sndRate > 52000 && PicoIn.sndRate < 54000) PicoIn.sndRate = YM2612_NATIVE_RATE(); ret = POPT_EN_FM|POPT_EN_PSG|POPT_EN_STEREO; if (PicoIn.sndRate != PsndRate_old || (PicoIn.opt&ret) != (PicoOpt_old&ret) || Pico.m.pal != pal_old) { PsndRerate(Pico.m.frame_count ? 1 : 0); } - stereo=(PicoIn.opt&8)>>3; - + stereo = (PicoIn.opt&8)>>3; samples_block = PicoIn.sndRate * (stereo ? 2 : 1) / (Pico.m.pal ? 50 : 60); lprintf("starting audio: %i, len: %i, stereo: %i, pal: %i, block samples: %i\n", PicoIn.sndRate, Pico.snd.len, stereo, Pico.m.pal, samples_block); - format.bits = 16; - format.freq = PicoIn.sndRate; - format.channels = 2; - ret = audsrv_set_format(&format); - audsrv_set_volume(MAX_VOLUME); - if (ret < 0) { - lprintf("audsrv_set_format() failed: %i\n", ret); - emu_status_msg("sound init failed (%i), snd disabled", ret); - currentConfig.EmuOpt &= ~EOPT_EN_SOUND; - } else { - PicoIn.writeSound = writeSound; - snd_playptr = PicoIn.sndOut = sndBuffer_endptr = sndBuffer; + resetSound(); + PicoIn.writeSound = writeSound; + snd_playptr = PicoIn.sndOut = sndBuffer_endptr = sndBuffer; - PsndRate_old = PicoIn.sndRate; - PicoOpt_old = PicoIn.opt; - pal_old = Pico.m.pal; - } + PsndRate_old = PicoIn.sndRate; + PicoOpt_old = PicoIn.opt; + pal_old = Pico.m.pal; + + sound_stopped = 0; audsrv_play_audio((char *)snd_playptr, 2*2); + SignalSema(sound_mutex); } void pemu_sound_stop(void) { + sound_stopped = 1; samples_made = samples_done = 0; - plat_sleep_ms(200); } static void sound_deinit(void) @@ -303,7 +313,8 @@ static void sound_deinit(void) static int vsync_handler(void) { iSignalSema(vsync_sema_id); - iSignalSema(sound_sem); + if (sound_stopped) + iSignalSema(sound_sem); ExitHandler(); return 0;