mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-04 23:07:46 -04:00
Merge branch 'irixxxx/ps2-merge'
This commit is contained in:
commit
f3ae9cb900
13 changed files with 1597 additions and 4 deletions
24
.github/workflows/ci.yml
vendored
24
.github/workflows/ci.yml
vendored
|
@ -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
|
||||
|
|
8
Makefile
8
Makefile
|
@ -235,6 +235,14 @@ 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
|
||||
OBJS += platform/ps2/emu.o
|
||||
OBJS += platform/ps2/in_ps2.o
|
||||
USE_FRONTEND = 1
|
||||
endif
|
||||
ifeq "$(PLATFORM)" "libretro"
|
||||
OBJS += platform/libretro/libretro.o
|
||||
ifneq ($(STATIC_LINKING), 1)
|
||||
|
|
13
configure
vendored
13
configure
vendored
|
@ -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${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"
|
||||
;;
|
||||
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <pico/pico_int.h>
|
||||
#include <pico/patch.h>
|
||||
|
||||
#ifdef PANDORA
|
||||
#if defined(PANDORA) || defined(__PS2__)
|
||||
#define MENU_X2 1
|
||||
#else
|
||||
#define MENU_X2 0
|
||||
|
@ -72,6 +72,8 @@ static int menu_w, menu_h;
|
|||
#include <platform/gp2x/menu.c>
|
||||
#elif defined(__PSP__)
|
||||
#include <platform/psp/menu.c>
|
||||
#elif defined(__PS2__)
|
||||
#include <platform/ps2/menu.c>
|
||||
#elif defined(PANDORA)
|
||||
#include <platform/pandora/menu.c>
|
||||
#else
|
||||
|
|
27
platform/ps2/Makefile
Normal file
27
platform/ps2/Makefile
Normal file
|
@ -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
|
||||
|
||||
|
985
platform/ps2/emu.c
Normal file
985
platform/ps2/emu.c
Normal file
|
@ -0,0 +1,985 @@
|
|||
#include <stddef.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <kernel.h>
|
||||
#include <ps2_joystick_driver.h>
|
||||
#include <ps2_audio_driver.h>
|
||||
#include <libpad.h>
|
||||
#include <gsKit.h>
|
||||
#include <dmaKit.h>
|
||||
#include <gsToolkit.h>
|
||||
#include <gsInline.h>
|
||||
#include <audsrv.h>
|
||||
|
||||
#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"
|
||||
|
||||
#include <pico/pico_int.h>
|
||||
|
||||
#define OSD_FPS_X (gsGlobal->Width - 80)
|
||||
|
||||
/* 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;
|
||||
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 },
|
||||
{ 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 }
|
||||
};
|
||||
|
||||
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;
|
||||
static GSPRIMUVPOINT *osd_vertices;
|
||||
|
||||
static GSTEXTURE *cdleds;
|
||||
static GSPRIMUVPOINT *cdleds_vertices;
|
||||
|
||||
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_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, 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;
|
||||
|
||||
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;
|
||||
|
||||
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("ovrn %d %d\n", len, PicoIn.sndOut - sndBuffer);
|
||||
if (l > samples_block * (SOUND_BLOCK_COUNT-2)) {
|
||||
sndBuffer_endptr = PicoIn.sndOut;
|
||||
PicoIn.sndOut = sndBuffer;
|
||||
}
|
||||
|
||||
// signal the snd thread
|
||||
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)
|
||||
{
|
||||
lprintf("sthr: start\n");
|
||||
|
||||
while (!sound_thread_exit)
|
||||
{
|
||||
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 samples, queue silence
|
||||
int queued = audsrv_queued()/2;
|
||||
while (queued < 2*samples_block) {
|
||||
short *sndOut = PicoIn.sndOut, *sndEnd = sndBuffer_endptr;
|
||||
|
||||
// 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 > 3*samples_block - queued)
|
||||
buflen = 3*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) & ~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 < 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 sound failed (%d)\n", ret);
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
thread.stack = stack;
|
||||
thread.stack_size = sizeof(stack);
|
||||
thread.gp_reg = &_gp;
|
||||
thread.option = (u32) "sndthread";
|
||||
thread.initial_priority = 40;
|
||||
thid = CreateThread(&thread);
|
||||
|
||||
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);
|
||||
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 mp3_init_done;
|
||||
int ret, stereo;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
resetSound();
|
||||
PicoIn.writeSound = writeSound;
|
||||
snd_playptr = PicoIn.sndOut = sndBuffer_endptr = sndBuffer;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) || is_bg_frame)
|
||||
|
||||
static int vsync_handler(void)
|
||||
{
|
||||
iSignalSema(vsync_sema_id);
|
||||
if (sound_stopped)
|
||||
iSignalSema(sound_sem);
|
||||
|
||||
ExitHandler();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void set_g_screen_values() {
|
||||
size_t g_screenSize = gsKit_texture_size_ee(328, 256, GS_PSM_CT16);
|
||||
int i;
|
||||
|
||||
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_screens[i]->Width = 328;
|
||||
g_screens[i]->Height = 256;
|
||||
|
||||
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;
|
||||
|
||||
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() {
|
||||
size_t cdledsSize = gsKit_texture_size_ee(14, 5, GS_PSM_CT16);
|
||||
|
||||
cdleds = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE));
|
||||
cdleds->Mem = (uint32_t *)malloc(cdledsSize);
|
||||
cdleds_vertices = (GSPRIMUVPOINT *)calloc(2, sizeof(GSPRIMUVPOINT));
|
||||
|
||||
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() {
|
||||
size_t osdSize = gsKit_texture_size_ee(gsGlobal->Width, 8, GS_PSM_CT16);
|
||||
int num_osds = 4, i;
|
||||
|
||||
osd = (GSTEXTURE *)calloc(1, sizeof(GSTEXTURE));
|
||||
osd->Mem = (uint32_t *)malloc(osdSize);
|
||||
|
||||
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;
|
||||
|
||||
sema.init_count = 0;
|
||||
sema.max_count = 1;
|
||||
sema.option = 0;
|
||||
|
||||
vsync_sema_id = CreateSema(&sema);
|
||||
|
||||
gsGlobal = gsKit_init_global();
|
||||
// gsGlobal->Mode = GS_MODE_NTSC;
|
||||
// gsGlobal->Height = 448;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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_screens[0]->Mem);
|
||||
free(g_screens[0]);
|
||||
free(g_screens[1]->Mem);
|
||||
free(g_screens[1]);
|
||||
free(g_screen_vertices);
|
||||
free(g_screen_palette);
|
||||
|
||||
free(g_menuscreen->Mem);
|
||||
free(g_menuscreen);
|
||||
free(g_menuscreen_vertices);
|
||||
free(g_menubg_ptr);
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
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 blit_screen(void)
|
||||
{
|
||||
if (!is_16bit_mode() && Pico.m.dirtyPal)
|
||||
make_ps2_palette();
|
||||
|
||||
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;
|
||||
|
||||
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 += 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;
|
||||
}
|
||||
|
||||
static void blit_cdleds(void)
|
||||
{
|
||||
if (!osd_cdleds) return;
|
||||
|
||||
gsKit_TexManager_bind(gsGlobal, cdleds);
|
||||
gskit_prim_list_sprite_texture_uv_3d(gsGlobal, cdleds, 2, cdleds_vertices);
|
||||
}
|
||||
|
||||
static void draw_pico_ptr(void)
|
||||
{
|
||||
int x = pico_pen_x, y = pico_pen_y, offs;
|
||||
int pp = g_screen_ppitch;
|
||||
|
||||
x = (x * out_w * ((1ULL<<32) / 320)) >> 32;
|
||||
y = (y * out_h * ((1ULL<<32) / 224)) >> 32;
|
||||
|
||||
offs = g_screen_ppitch * (out_y+y) + (out_x+x);
|
||||
|
||||
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)
|
||||
{
|
||||
set_scaling_params();
|
||||
|
||||
Pico.m.dirtyPal = 1;
|
||||
}
|
||||
|
||||
/* finalize rendering a frame */
|
||||
void pemu_finalize_frame(const char *fps, const char *notice)
|
||||
{
|
||||
int emu_opt = currentConfig.EmuOpt;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
/* display a completed frame buffer and prepare a new render buffer */
|
||||
void plat_video_flip(void)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
/* 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 gskit_clear
|
||||
}
|
||||
|
||||
/* 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)gsGlobal->Height/line_count;
|
||||
break;
|
||||
case EOPT_VSCALE_NOBORDER:
|
||||
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 = (hscale*h43)/col_count;
|
||||
break;
|
||||
case EOPT_SCALE_STRETCH:
|
||||
hscale = (hscale*h43/2 + gsGlobal->Width/2)/col_count;
|
||||
break;
|
||||
case EOPT_SCALE_WIDE:
|
||||
hscale = (float)gsGlobal->Width/col_count;
|
||||
break;
|
||||
default:
|
||||
// hscale = vscale, computed before switch
|
||||
break;
|
||||
}
|
||||
|
||||
vidResetMode();
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
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()]);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
apply_renderer();
|
||||
vidResetMode();
|
||||
}
|
||||
|
||||
/* prepare for entering the emulator loop */
|
||||
void pemu_loop_prep(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* terminate the emulator loop */
|
||||
void pemu_loop_end(void)
|
||||
{
|
||||
pemu_sound_stop();
|
||||
pemu_forced_frame(0, 1);
|
||||
}
|
268
platform/ps2/in_ps2.c
Normal file
268
platform/ps2/in_ps2.c
Normal file
|
@ -0,0 +1,268 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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<<i))
|
||||
break;
|
||||
|
||||
old_val ^= 1 << i;
|
||||
|
||||
if (is_down)
|
||||
*is_down = !!(val & (1<<i));
|
||||
return i;
|
||||
}
|
||||
|
||||
static struct {
|
||||
unsigned key;
|
||||
int pbtn;
|
||||
} key_pbtn_map[] =
|
||||
{
|
||||
{ PAD_UP, PBTN_UP },
|
||||
{ PAD_DOWN, PBTN_DOWN },
|
||||
{ PAD_LEFT, PBTN_LEFT },
|
||||
{ PAD_RIGHT, PBTN_RIGHT },
|
||||
{ PAD_CIRCLE, PBTN_MOK },
|
||||
{ PAD_CROSS, PBTN_MBACK },
|
||||
{ PAD_TRIANGLE, PBTN_MA2 },
|
||||
{ PAD_SQUARE, PBTN_MA3 },
|
||||
{ PAD_L1, PBTN_L },
|
||||
{ PAD_R1, PBTN_R },
|
||||
};
|
||||
|
||||
#define KEY_PBTN_MAP_SIZE (sizeof(key_pbtn_map) / sizeof(key_pbtn_map[0]))
|
||||
|
||||
static int in_ps2_menu_translate(void *drv_data, int keycode, char *charcode)
|
||||
{
|
||||
int i;
|
||||
if (keycode < 0)
|
||||
{
|
||||
/* menu -> 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);
|
||||
}
|
||||
|
6
platform/ps2/in_ps2.h
Normal file
6
platform/ps2/in_ps2.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
struct in_default_bind;
|
||||
|
||||
void in_ps2_init(struct in_default_bind *defbinds);
|
||||
|
||||
void in_ps2_deinit();
|
21
platform/ps2/menu.c
Normal file
21
platform/ps2/menu.c
Normal file
|
@ -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);
|
||||
}
|
10
platform/ps2/menu.h
Normal file
10
platform/ps2/menu.h
Normal file
|
@ -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)
|
||||
|
231
platform/ps2/plat.c
Normal file
231
platform/ps2/plat.c
Normal file
|
@ -0,0 +1,231 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <kernel.h>
|
||||
#include <iopcontrol.h>
|
||||
#include <sbv_patches.h>
|
||||
#include <sifrpc.h>
|
||||
#include <loadfile.h>
|
||||
#include <ps2_filesystem_driver.h>
|
||||
#include <ps2_joystick_driver.h>
|
||||
#include <ps2_audio_driver.h>
|
||||
|
||||
#include "../libpicofe/plat.h"
|
||||
|
||||
static int sound_rates[] = { 11025, 22050, 44100, -1 };
|
||||
struct plat_target plat_target = { .sound_rates = sound_rates };
|
||||
|
||||
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
|
||||
|
||||
while (!SifIopSync()) {};
|
||||
SifInitRpc(0);
|
||||
sbv_patch_enable_lmb();
|
||||
sbv_patch_disable_prefix_check();
|
||||
}
|
||||
|
||||
static void init_drivers() {
|
||||
init_ps2_filesystem_driver();
|
||||
}
|
||||
|
||||
static void deinit_drivers() {
|
||||
deinit_ps2_filesystem_driver();
|
||||
}
|
||||
|
||||
int plat_target_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* System level deinitialization */
|
||||
void plat_target_finish(void)
|
||||
{
|
||||
deinit_drivers();
|
||||
}
|
||||
|
||||
int plat_parse_arg(int argc, char *argv[], int *x)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Preliminary initialization needed at program start */
|
||||
void plat_early_init(void) {
|
||||
reset_IOP();
|
||||
init_drivers();
|
||||
#if defined(LOG_TO_FILE)
|
||||
log_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* top directory for rom images */
|
||||
int plat_get_data_dir(char *dst, int len)
|
||||
{
|
||||
getcwd(dst, len);
|
||||
return strlen(dst);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* current time in ms */
|
||||
unsigned int plat_get_ticks_ms(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
unsigned int ret;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
ret = (unsigned)tv.tv_sec * 1000;
|
||||
/* approximate /= 1000 */
|
||||
ret += ((unsigned)tv.tv_usec * 4194) >> 22;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* current time in us */
|
||||
unsigned int plat_get_ticks_us(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
unsigned int ret;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
ret = (unsigned)tv.tv_sec * 1000000;
|
||||
ret += (unsigned)tv.tv_usec;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
iWakeupThread((s32)arg);
|
||||
}
|
||||
|
||||
/* sleep for some time in us */
|
||||
void plat_wait_till_us(unsigned int us_to)
|
||||
{
|
||||
// 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 */
|
||||
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, ...)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, fmt);
|
||||
#if defined(LOG_TO_FILE)
|
||||
vfprintf(logFile, fmt, vl);
|
||||
#else
|
||||
vprintf(fmt, vl);
|
||||
#endif
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
void plat_debug_cat(char *str) {}
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue