X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=frontend%2Flibretro.c;h=4c285cfbc26f83b34cc7f8e92cabb4ff3668a00c;hp=cf875beb4bf16c2b90b91d5b13b93ec85a24c79c;hb=HEAD;hpb=91da8e32287f181a870140fdcc8fcdac7bafdebe diff --git a/frontend/libretro.c b/frontend/libretro.c index cf875beb..407253e3 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -8,13 +8,16 @@ #define _GNU_SOURCE 1 // strcasestr #include #include +#include #include #include +#include #ifdef __MACH__ #include #include #endif +#include "retro_miscellaneous.h" #ifdef SWITCH #include #endif @@ -24,6 +27,7 @@ #include "../libpcsxcore/psxmem_map.h" #include "../libpcsxcore/new_dynarec/new_dynarec.h" #include "../libpcsxcore/cdrom.h" +#include "../libpcsxcore/cdrom-async.h" #include "../libpcsxcore/cdriso.h" #include "../libpcsxcore/cheat.h" #include "../libpcsxcore/r3000a.h" @@ -47,9 +51,16 @@ #endif #ifdef _3DS +#include <3ds/svc.h> +#include <3ds/services/apt.h> +#include <3ds/allocator/linear.h> #include "3ds/3ds_utils.h" #endif +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)(intptr_t)-1) +#endif + #define PORTS_NUMBER 8 #ifndef MIN @@ -62,8 +73,6 @@ #define ISHEXDEC ((buf[cursor] >= '0') && (buf[cursor] <= '9')) || ((buf[cursor] >= 'a') && (buf[cursor] <= 'f')) || ((buf[cursor] >= 'A') && (buf[cursor] <= 'F')) -#define INTERNAL_FPS_SAMPLE_PERIOD 64 - //hack to prevent retroarch freezing when reseting in the menu but not while running with the hot key static int rebootemu = 0; @@ -76,18 +85,23 @@ static retro_set_rumble_state_t rumble_cb; static struct retro_log_callback logging; static retro_log_printf_t log_cb; +#define LogWarn(fmt, ...) do { \ + if (log_cb) log_cb(RETRO_LOG_WARN, fmt, ##__VA_ARGS__); \ +} while (0) +#define LogErr(fmt, ...) do { \ + if (log_cb) log_cb(RETRO_LOG_ERROR, fmt, ##__VA_ARGS__); \ +} while (0) + static unsigned msg_interface_version = 0; static void *vout_buf; static void *vout_buf_ptr; -static int vout_width = 256, vout_height = 240, vout_pitch = 256; +static int vout_width = 256, vout_height = 240, vout_pitch_b = 256*2; static int vout_fb_dirty; static int psx_w, psx_h; static bool vout_can_dupe; -static bool duping_enable; static bool found_bios; -static bool display_internal_fps = false; -static unsigned frame_count = 0; +static int display_internal_fps; static bool libretro_supports_bitmasks = false; static bool libretro_supports_option_categories = false; static bool show_input_settings = true; @@ -120,11 +134,13 @@ static int retro_audio_buff_underrun = false; static unsigned retro_audio_latency = 0; static int update_audio_latency = false; -static unsigned previous_width = 0; -static unsigned previous_height = 0; +static unsigned int current_width; +static unsigned int current_height; +static enum retro_pixel_format current_fmt; static int plugins_opened; -static int is_pal_mode; + +#define is_pal_mode Config.PsxType /* memory card data */ extern char Mcd1Data[MCD_SIZE]; @@ -145,7 +161,9 @@ int in_mouse[8][2]; int multitap1 = 0; int multitap2 = 0; int in_enable_vibration = 1; -int in_enable_crosshair[2] = { 0, 0 }; +static int in_enable_crosshair[2] = { 0, 0 }; +static int in_dualshock_analog_combo = 0; +static bool in_dualshock_toggling = false; // NegCon adjustment parameters // > The NegCon 'twist' action is somewhat awkward when mapped @@ -169,7 +187,11 @@ static int negcon_linearity = 1; static bool axis_bounds_modifier; /* PSX max resolution is 640x512, but with enhancement it's 1024x512 */ +#ifdef GPU_NEON #define VOUT_MAX_WIDTH 1024 +#else +#define VOUT_MAX_WIDTH 640 +#endif #define VOUT_MAX_HEIGHT 512 //Dummy functions @@ -226,23 +248,60 @@ static void init_memcard(char *mcd_data) } } -static void set_vout_fb() +static void bgr_to_fb_empty(void *dst, const void *src, int bytes) +{ +} + +typedef void (bgr_to_fb_func)(void *dst, const void *src, int bytes); +static bgr_to_fb_func *g_bgr_to_fb = bgr_to_fb_empty; + +static void set_bgr_to_fb_func(int bgr24) +{ + switch (current_fmt) + { + case RETRO_PIXEL_FORMAT_XRGB8888: + g_bgr_to_fb = bgr24 ? bgr888_to_xrgb8888 : bgr555_to_xrgb8888; + break; + case RETRO_PIXEL_FORMAT_RGB565: + g_bgr_to_fb = bgr24 ? bgr888_to_rgb565 : bgr555_to_rgb565; + break; + default: + LogErr("unsupported current_fmt: %d\n", current_fmt); + g_bgr_to_fb = bgr_to_fb_empty; + break; + } +} + +static void set_vout_fb(void) { struct retro_framebuffer fb = { 0 }; + bool ret; fb.width = vout_width; fb.height = vout_height; fb.access_flags = RETRO_MEMORY_ACCESS_WRITE; - vout_pitch = vout_width; - if (environ_cb(RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER, &fb) && fb.format == RETRO_PIXEL_FORMAT_RGB565) { + ret = environ_cb(RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER, &fb); + if (ret && vout_can_dupe && + (fb.format == RETRO_PIXEL_FORMAT_RGB565 || fb.format == RETRO_PIXEL_FORMAT_XRGB8888)) + { + int bytes_pp = (fb.format == RETRO_PIXEL_FORMAT_XRGB8888) ? 4 : 2; + if (current_fmt != fb.format) { + LogWarn("fb.format changed: %d->%d\n", current_fmt, fb.format); + current_fmt = fb.format; + } vout_buf_ptr = fb.data; - if (fb.pitch / 2 != vout_pitch && fb.pitch != vout_width * 2) - SysPrintf("got unusual pitch %zd for resolution %dx%d\n", fb.pitch, vout_width, vout_height); - vout_pitch = fb.pitch / 2; + vout_pitch_b = fb.pitch; + if (fb.pitch != vout_width * bytes_pp) + LogWarn("got unusual pitch %zd for fmt %d resolution %dx%d\n", + fb.pitch, fb.format, vout_width, vout_height); } else + { + int bytes_pp = (current_fmt == RETRO_PIXEL_FORMAT_XRGB8888) ? 4 : 2; vout_buf_ptr = vout_buf; + vout_pitch_b = vout_width * bytes_pp; + } } static void vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp) @@ -252,10 +311,15 @@ static void vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp) psx_w = raw_w; psx_h = raw_h; - if (previous_width != vout_width || previous_height != vout_height) + /* it may seem like we could do RETRO_ENVIRONMENT_SET_PIXEL_FORMAT here to + * switch to something that can accommodate bgr24 for FMVs, but although it + * succeeds it doesn't actually change the format at least on Linux, and the + * docs say only retro_load_game() can do it */ + + if (current_width != vout_width || current_height != vout_height) { - previous_width = vout_width; - previous_height = vout_height; + current_width = vout_width; + current_height = vout_height; struct retro_system_av_info info; retro_get_system_av_info(&info); @@ -263,35 +327,25 @@ static void vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp) } set_vout_fb(); + set_bgr_to_fb_func(bpp == 24); } -#ifndef FRONTEND_SUPPORTS_RGB565 -static void convert(void *buf, size_t bytes) -{ - unsigned int i, v, *p = buf; - - for (i = 0; i < bytes / 4; i++) - { - v = p[i]; - p[i] = (v & 0x001f001f) | ((v >> 1) & 0x7fe07fe0); - } -} -#endif - // Function to add crosshairs -static void addCrosshair(int port, int crosshair_color, unsigned short *buffer, int bufferStride, int pos_x, int pos_y, int thickness, int size_x, int size_y) { +static void addCrosshair(int port, int crosshair_color, unsigned short *buffer, int bufferStride, int pos_x, int pos_y, int thickness, int size_x, int size_y) +{ for (port = 0; port < 2; port++) { // Draw the horizontal line of the crosshair - for (int i = pos_y - thickness / 2; i <= pos_y + thickness / 2; i++) { - for (int j = pos_x - size_x / 2; j <= pos_x + size_x / 2; j++) { + int i, j; + for (i = pos_y - thickness / 2; i <= pos_y + thickness / 2; i++) { + for (j = pos_x - size_x / 2; j <= pos_x + size_x / 2; j++) { if ((i + vout_height) >= 0 && (i + vout_height) < bufferStride && j >= 0 && j < bufferStride && in_enable_crosshair[port] > 0) buffer[i * bufferStride + j] = crosshair_color; - } } + } // Draw the vertical line of the crosshair - for (int i = pos_x - thickness / 2; i <= pos_x + thickness / 2; i++) { - for (int j = pos_y - size_y / 2; j <= pos_y + size_y / 2; j++) { + for (i = pos_x - thickness / 2; i <= pos_x + thickness / 2; i++) { + for (j = pos_y - size_y / 2; j <= pos_y + size_y / 2; j++) { if (i >= 0 && i < bufferStride && (j + vout_height) >= 0 && (j + vout_height) < bufferStride && in_enable_crosshair[port] > 0) buffer[j * bufferStride + i] = crosshair_color; } @@ -317,130 +371,174 @@ static void CrosshairDimensions(int port, struct CrosshairInfo *info) { info->size_y = psx_h * (pl_rearmed_cbs.gpu_neon.enhancement_enable ? 2 : 1) * (4.0f / 3.0f) / 40.0f; } -static void vout_flip(const void *vram, int stride, int bgr24, +static void vout_flip(const void *vram_, int vram_ofs, int bgr24, int x, int y, int w, int h, int dims_changed) { - unsigned short *dest = vout_buf_ptr; - const unsigned short *src = vram; - int dstride = vout_pitch, h1 = h; - int port = 0; + int bytes_pp = (current_fmt == RETRO_PIXEL_FORMAT_XRGB8888) ? 4 : 2; + int bytes_pp_s = bgr24 ? 3 : 2; + bgr_to_fb_func *bgr_to_fb = g_bgr_to_fb; + unsigned char *dest = vout_buf_ptr; + const unsigned char *vram = vram_; + int dstride = vout_pitch_b, h1 = h; + int enhres = w > psx_w; + u32 vram_mask = enhres ? ~0 : 0xfffff; + int port = 0, hwrapped; if (vram == NULL || dims_changed || (in_enable_crosshair[0] + in_enable_crosshair[1]) > 0) { - memset(vout_buf_ptr, 0, dstride * vout_height * 2); + unsigned char *dest2 = dest; + int h2 = h, ll = vout_width * bytes_pp; + if (dstride == ll) + memset(dest2, 0, dstride * vout_height); + else + for (; h2-- > 0; dest2 += dstride) + memset(dest2, 0, ll); // blanking if (vram == NULL) goto out; } - dest += x + y * dstride; + dest += x * bytes_pp + y * dstride; - if (bgr24) - { - // XXX: could we switch to RETRO_PIXEL_FORMAT_XRGB8888 here? - for (; h1-- > 0; dest += dstride, src += stride) - { - bgr888_to_rgb565(dest, src, w * 3); - } + for (; h1-- > 0; dest += dstride) { + bgr_to_fb(dest, vram + vram_ofs, w * bytes_pp_s); + vram_ofs = (vram_ofs + 2048) & vram_mask; } - else - { - for (; h1-- > 0; dest += dstride, src += stride) - { - bgr555_to_rgb565(dest, src, w * 2); + + hwrapped = (vram_ofs & 2047) + w * bytes_pp_s - 2048; + if (!enhres && hwrapped > 0) { + // this is super-rare so just fix-up + vram_ofs = (vram_ofs - h * 2048) & 0xff800; + dest -= dstride * h; + dest += (w - hwrapped / bytes_pp_s) * bytes_pp; + for (h1 = h; h1-- > 0; dest += dstride) { + bgr_to_fb(dest, vram + vram_ofs, hwrapped); + vram_ofs = (vram_ofs + 2048) & 0xfffff; } } + if (current_fmt == RETRO_PIXEL_FORMAT_RGB565) for (port = 0; port < 2; port++) { if (in_enable_crosshair[port] > 0 && (in_type[port] == PSE_PAD_TYPE_GUNCON || in_type[port] == PSE_PAD_TYPE_GUN)) { - struct CrosshairInfo crosshairInfo; - CrosshairDimensions(port, &crosshairInfo); - addCrosshair(port, in_enable_crosshair[port], dest, dstride, crosshairInfo.pos_x, crosshairInfo.pos_y, crosshairInfo.thickness, crosshairInfo.size_x, crosshairInfo.size_y); + struct CrosshairInfo crosshairInfo; + CrosshairDimensions(port, &crosshairInfo); + addCrosshair(port, in_enable_crosshair[port], (unsigned short *)dest, + dstride / 2, crosshairInfo.pos_x, crosshairInfo.pos_y, + crosshairInfo.thickness, crosshairInfo.size_x, crosshairInfo.size_y); } } out: -#ifndef FRONTEND_SUPPORTS_RGB565 - convert(vout_buf_ptr, vout_pitch * vout_height * 2); -#endif vout_fb_dirty = 1; pl_rearmed_cbs.flip_cnt++; } #ifdef _3DS -typedef struct -{ - void *buffer; - uint32_t target_map; - size_t size; - enum psxMapTag tag; -} psx_map_t; - -psx_map_t custom_psx_maps[] = { - { NULL, 0x13000000, 0x210000, MAP_TAG_RAM }, // 0x80000000 - { NULL, 0x12800000, 0x010000, MAP_TAG_OTHER }, // 0x1f800000 - { NULL, 0x12c00000, 0x080000, MAP_TAG_OTHER }, // 0x1fc00000 - { NULL, 0x11000000, 0x800000, MAP_TAG_LUTS }, // 0x08000000 - { NULL, 0x12000000, 0x201000, MAP_TAG_VRAM }, // 0x00000000 -}; +static u32 mapped_addrs[8]; +static u32 mapped_ram, mapped_ram_src; +static void *vram_mem; -void *pl_3ds_mmap(unsigned long addr, size_t size, int is_fixed, - enum psxMapTag tag) +// http://3dbrew.org/wiki/Memory_layout#ARM11_User-land_memory_regions +static void *pl_3ds_mmap(unsigned long addr, size_t size, + enum psxMapTag tag, int *can_retry_addr) { - (void)is_fixed; + void *ret = MAP_FAILED; + *can_retry_addr = 0; (void)addr; - if (__ctr_svchax) + if (tag == MAP_TAG_VRAM && vram_mem) + return vram_mem; + + if (__ctr_svchax) do { - psx_map_t *custom_map = custom_psx_maps; + // idea from fbalpha2012_neogeo + s32 addr = 0x10000000 - 0x1000; + u32 found_addr = 0; + MemInfo mem_info; + PageInfo page_info; + size_t i; + int r; - for (; custom_map->size; custom_map++) + for (i = 0; i < sizeof(mapped_addrs) / sizeof(mapped_addrs[0]); i++) + if (mapped_addrs[i] == 0) + break; + if (i == sizeof(mapped_addrs) / sizeof(mapped_addrs[0])) + break; + + size = (size + 0xfff) & ~0xfff; + + while (addr >= 0x08000000) { - if ((custom_map->size == size) && (custom_map->tag == tag)) - { - uint32_t ptr_aligned, tmp; - void *ret; + if ((r = svcQueryMemory(&mem_info, &page_info, addr)) < 0) { + LogErr("svcQueryMemory failed: %d\n", r); + break; + } - custom_map->buffer = malloc(size + 0x1000); - ptr_aligned = (((u32)custom_map->buffer) + 0xFFF) & ~0xFFF; + if (mem_info.state == MEMSTATE_FREE && mem_info.size >= size) { + found_addr = mem_info.base_addr + mem_info.size - size; + break; + } - if (svcControlMemory(&tmp, (void *)custom_map->target_map, (void *)ptr_aligned, size, MEMOP_MAP, 0x3) < 0) - { - SysPrintf("could not map memory @0x%08X\n", custom_map->target_map); - exit(1); - } + addr = mem_info.base_addr - 0x1000; + } + if (found_addr == 0) { + LogErr("no addr space for %u bytes\n", size); + break; + } - ret = (void *)custom_map->target_map; - memset(ret, 0, size); - return ret; + // https://libctru.devkitpro.org/svc_8h.html#a8046e9b23b1b209a4e278cb1c19c7a5a + if ((r = svcControlMemory(&mapped_addrs[i], found_addr, 0, size, MEMOP_ALLOC, MEMPERM_READWRITE)) < 0) { + LogErr("svcControlMemory failed for %08x %u: %d\n", found_addr, size, r); + break; + } + if (mapped_addrs[i] == 0) // needed? + mapped_addrs[i] = found_addr; + ret = (void *)mapped_addrs[i]; + + // "round" address helps the dynarec slightly, map ram at 0x13000000 + if (tag == MAP_TAG_RAM && !mapped_ram) { + u32 target = 0x13000000; + if ((r = svcControlMemory(&mapped_ram, target, mapped_addrs[i], size, MEMOP_MAP, MEMPERM_READWRITE)) < 0) + LogErr("could not map ram %08x -> %08x: %d\n", mapped_addrs[i], target, r); + else { + mapped_ram_src = mapped_addrs[i]; + mapped_ram = target; + ret = (void *)mapped_ram; } } + memset(ret, 0, size); + return ret; } + while (0); - return calloc(size, 1); + ret = calloc(size, 1); + return ret ? ret : MAP_FAILED; } -void pl_3ds_munmap(void *ptr, size_t size, enum psxMapTag tag) +static void pl_3ds_munmap(void *ptr, size_t size, enum psxMapTag tag) { (void)tag; - if (__ctr_svchax) - { - psx_map_t *custom_map = custom_psx_maps; - - for (; custom_map->size; custom_map++) - { - if ((custom_map->target_map == (uint32_t)ptr)) - { - uint32_t ptr_aligned, tmp; + if (ptr && ptr == vram_mem) + return; - ptr_aligned = (((u32)custom_map->buffer) + 0xFFF) & ~0xFFF; + if (ptr && __ctr_svchax) + { + size_t i; + u32 tmp; - svcControlMemory(&tmp, (void *)custom_map->target_map, (void *)ptr_aligned, size, MEMOP_UNMAP, 0x3); + size = (size + 0xfff) & ~0xfff; - free(custom_map->buffer); - custom_map->buffer = NULL; + if (ptr == (void *)mapped_ram) { + svcControlMemory(&tmp, mapped_ram, mapped_ram_src, size, MEMOP_UNMAP, 0); + ptr = (void *)mapped_ram_src; + mapped_ram = mapped_ram_src = 0; + } + for (i = 0; i < sizeof(mapped_addrs) / sizeof(mapped_addrs[0]); i++) { + if (ptr == (void *)mapped_addrs[i]) { + svcControlMemory(&tmp, mapped_addrs[i], 0, size, MEMOP_FREE, 0); + mapped_addrs[i] = 0; return; } } @@ -448,6 +546,51 @@ void pl_3ds_munmap(void *ptr, size_t size, enum psxMapTag tag) free(ptr); } + +// debug +static int ctr_get_tlbe_k(u32 ptr) +{ + u32 tlb_base = -1, tlb_ctl = -1, *l1; + s32 tlb_mask = 0xffffc000; + + asm volatile("mrc p15, 0, %0, c2, c0, 0" : "=r"(tlb_base)); + asm volatile("mrc p15, 0, %0, c2, c0, 2" : "=r"(tlb_ctl)); + tlb_mask >>= tlb_ctl & 7; + l1 = (u32 *)((tlb_base & tlb_mask) | 0xe0000000); + return l1[ptr >> 20]; +} + +static int ctr_get_tlbe(void *ptr) +{ + if (svcConvertVAToPA((void *)0xe0000000, 0) != 0x20000000) + return -1; + return svcCustomBackdoor(ctr_get_tlbe_k, ptr, NULL, NULL); +} +#endif + +#ifdef HAVE_LIBNX +static void *pl_switch_mmap(unsigned long addr, size_t size, + enum psxMapTag tag, int *can_retry_addr) +{ + void *ret = MAP_FAILED; + *can_retry_addr = 0; + (void)addr; + + // there's svcMapPhysicalMemory() but user logs show it doesn't hand out + // any desired addresses, so don't even bother + ret = aligned_alloc(0x1000, size); + if (!ret) + return MAP_FAILED; + memset(ret, 0, size); + return ret; +} + +static void pl_switch_munmap(void *ptr, size_t size, enum psxMapTag tag) +{ + (void)size; + (void)tag; + free(ptr); +} #endif #ifdef VITA @@ -461,7 +604,7 @@ typedef struct static void *addr = NULL; -psx_map_t custom_psx_maps[] = { +static psx_map_t custom_psx_maps[] = { { NULL, 0x800000, MAP_TAG_LUTS }, { NULL, 0x080000, MAP_TAG_OTHER }, { NULL, 0x010000, MAP_TAG_OTHER }, @@ -470,9 +613,8 @@ psx_map_t custom_psx_maps[] = { { NULL, 0x210000, MAP_TAG_RAM }, }; -int init_vita_mmap() +static int init_vita_mmap() { - int n; void *tmpaddr; addr = malloc(64 * 1024 * 1024); if (addr == NULL) @@ -486,6 +628,7 @@ int init_vita_mmap() custom_psx_maps[5].buffer = tmpaddr + 0x2000000; memset(tmpaddr, 0, 0x2210000); #if 0 + int n; for(n = 0; n < 5; n++){ sceClibPrintf("addr reserved %x\n",custom_psx_maps[n].buffer); } @@ -493,7 +636,7 @@ int init_vita_mmap() return 0; } -void deinit_vita_mmap() +static void deinit_vita_mmap() { size_t i; for (i = 0; i < sizeof(custom_psx_maps) / sizeof(custom_psx_maps[0]); i++) { @@ -503,11 +646,12 @@ void deinit_vita_mmap() free(addr); } -void *pl_vita_mmap(unsigned long addr, size_t size, int is_fixed, - enum psxMapTag tag) +static void *pl_vita_mmap(unsigned long addr, size_t size, + enum psxMapTag tag, int *can_retry_addr) { - (void)is_fixed; + void *ret; (void)addr; + *can_retry_addr = 0; psx_map_t *custom_map = custom_psx_maps; @@ -520,10 +664,11 @@ void *pl_vita_mmap(unsigned long addr, size_t size, int is_fixed, } } - return calloc(size, 1); + ret = calloc(size, 1); + return ret ? ret : MAP_FAILED; } -void pl_vita_munmap(void *ptr, size_t size, enum psxMapTag tag) +static void pl_vita_munmap(void *ptr, size_t size, enum psxMapTag tag) { (void)tag; @@ -542,6 +687,22 @@ void pl_vita_munmap(void *ptr, size_t size, enum psxMapTag tag) } #endif +static void log_mem_usage(void) +{ +#ifdef _3DS + extern u32 __heap_size, __linear_heap_size, __stacksize__; + extern char __end__; // 3dsx.ld + u32 app_memory = *((volatile u32 *)0x1FF80040); + s64 mem_used = 0; + if (__ctr_svchax) + svcGetSystemInfo(&mem_used, 0, 1); + + SysPrintf("mem: %d/%d heap: %d linear: %d/%d stack: %d exe: %d\n", + (int)mem_used, app_memory, __heap_size, __linear_heap_size - linearSpaceFree(), + __linear_heap_size, __stacksize__, (int)&__end__ - 0x100000); +#endif +} + static void *pl_mmap(unsigned int size) { return psxMap(0, size, 0, MAP_TAG_VRAM); @@ -568,12 +729,11 @@ struct rearmed_cbs pl_rearmed_cbs = { void pl_frame_limit(void) { /* called once per frame, make psxCpu->Execute() above return */ - stop++; + psxRegs.stop++; } void pl_timing_prepare(int is_pal) { - is_pal_mode = is_pal; } void plat_trigger_vibrate(int pad, int low, int high) @@ -715,8 +875,8 @@ static bool update_option_visibility(void) "pcsx_rearmed_negcon_deadzone", "pcsx_rearmed_negcon_response", "pcsx_rearmed_input_sensitivity", - "pcsx_rearmed_crosshair1", - "pcsx_rearmed_crosshair2", + "pcsx_rearmed_crosshair1", + "pcsx_rearmed_crosshair2", "pcsx_rearmed_konamigunadjustx", "pcsx_rearmed_konamigunadjusty", "pcsx_rearmed_gunconadjustx", @@ -805,6 +965,7 @@ static bool update_option_visibility(void) struct retro_core_option_display option_display; char gpu_unai_option[][40] = { "pcsx_rearmed_gpu_unai_blending", + "pcsx_rearmed_gpu_unai_skipline", "pcsx_rearmed_gpu_unai_lighting", "pcsx_rearmed_gpu_unai_fast_lighting", "pcsx_rearmed_gpu_unai_scale_hires", @@ -978,7 +1139,7 @@ void retro_get_system_info(struct retro_system_info *info) #endif memset(info, 0, sizeof(*info)); info->library_name = "PCSX-ReARMed"; - info->library_version = "r23l" GIT_VERSION; + info->library_version = "r25" GIT_VERSION; info->valid_extensions = "bin|cue|img|mdf|pbp|toc|cbn|m3u|chd|iso|exe"; info->need_fullpath = true; } @@ -989,7 +1150,7 @@ void retro_get_system_av_info(struct retro_system_av_info *info) unsigned geom_width = vout_width; memset(info, 0, sizeof(*info)); - info->timing.fps = is_pal_mode ? 50.0 : 60.0; + info->timing.fps = psxGetFps(); info->timing.sample_rate = 44100.0; info->geometry.base_width = geom_width; info->geometry.base_height = geom_height; @@ -1080,7 +1241,7 @@ static void save_close(void *file) return; if (fp->pos > r_size) - SysPrintf("ERROR: save buffer overflow detected\n"); + LogErr("ERROR: save buffer overflow detected\n"); else if (fp->is_write && fp->pos < r_size) // make sure we don't save trash in leftover space memset(fp->buf + fp->pos, 0, r_size - fp->pos); @@ -1151,7 +1312,7 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code) finish: if (ret != 0) - SysPrintf("Failed to set cheat %#u\n", index); + LogErr("Failed to set cheat %#u\n", index); else if (index < NumCheats) Cheats[index].Enabled = enabled; free(buf); @@ -1228,10 +1389,23 @@ static void disk_init(void) static bool disk_set_eject_state(bool ejected) { - // weird PCSX API.. + if (ejected != disk_ejected) + SysPrintf("new eject_state: %d\n", ejected); + + // weird PCSX API... SetCdOpenCaseTime(ejected ? -1 : (time(NULL) + 2)); LidInterrupt(); +#ifdef HAVE_CDROM + if (cdra_is_physical() && ejected != disk_ejected) { + cdra_stop_thread(); + if (!ejected) { + // likely the real cd was also changed - rescan + cdra_close(); + cdra_open(); + } + } +#endif disk_ejected = ejected; return true; } @@ -1257,8 +1431,8 @@ static bool disk_set_image_index(unsigned int index) if (disks[index].fname == NULL) { - SysPrintf("missing disk #%u\n", index); - CDR_shutdown(); + LogErr("missing disk #%u\n", index); + cdra_shutdown(); // RetroArch specifies "no disk" with index == count, // so don't fail here.. @@ -1266,26 +1440,25 @@ static bool disk_set_image_index(unsigned int index) return true; } - SysPrintf("switching to disk %u: \"%s\" #%d\n", index, + LogErr("switching to disk %u: \"%s\" #%d\n", index, disks[index].fname, disks[index].internal_index); cdrIsoMultidiskSelect = disks[index].internal_index; set_cd_image(disks[index].fname); if (ReloadCdromPlugin() < 0) { - SysPrintf("failed to load cdr plugin\n"); + LogErr("failed to load cdr plugin\n"); return false; } - if (CDR_open() < 0) + if (cdra_open() < 0) { - SysPrintf("failed to open cdr plugin\n"); + LogErr("failed to open cdr plugin\n"); return false; } if (!disk_ejected) { - SetCdOpenCaseTime(time(NULL) + 2); - LidInterrupt(); + disk_set_eject_state(disk_ejected); } disk_current_index = index; @@ -1518,17 +1691,21 @@ strcasestr(const char *s, const char *find) static void set_retro_memmap(void) { -#ifndef NDEBUG + uint64_t flags_ram = RETRO_MEMDESC_SYSTEM_RAM; struct retro_memory_map retromap = { 0 }; - struct retro_memory_descriptor mmap = { - 0, psxM, 0, 0, 0, 0, 0x200000 + struct retro_memory_descriptor descs[] = { + { flags_ram, psxM, 0, 0x00000000, 0x5fe00000, 0, 0x200000 }, + { flags_ram, psxH, 0, 0x1f800000, 0x7ffffc00, 0, 0x000400 }, + // not ram but let the frontend patch it if it wants; should be last + { flags_ram, psxR, 0, 0x1fc00000, 0x5ff80000, 0, 0x080000 }, }; - retromap.descriptors = &mmap; - retromap.num_descriptors = 1; + retromap.descriptors = descs; + retromap.num_descriptors = sizeof(descs) / sizeof(descs[0]); + if (Config.HLE) + retromap.num_descriptors--; environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &retromap); -#endif } static void show_notification(const char *msg_str, @@ -1613,12 +1790,25 @@ static void retro_set_audio_buff_status_cb(void) } static void update_variables(bool in_flight); + +static int get_bool_variable(const char *key) +{ + struct retro_variable var = { NULL, }; + + var.key = key; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "enabled") == 0) + return 1; + } + return 0; +} + bool retro_load_game(const struct retro_game_info *info) { size_t i; unsigned int cd_index = 0; - bool is_m3u = (strcasestr(info->path, ".m3u") != NULL); - bool is_exe = (strcasestr(info->path, ".exe") != NULL); + bool is_m3u, is_exe; int ret; struct retro_input_descriptor desc[] = { @@ -1661,23 +1851,24 @@ bool retro_load_game(const struct retro_game_info *info) { 0 }, }; - frame_count = 0; - environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); -#ifdef FRONTEND_SUPPORTS_RGB565 - enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565; + enum retro_pixel_format fmt = get_bool_variable("pcsx_rearmed_rgb32_output") + ? RETRO_PIXEL_FORMAT_XRGB8888 : RETRO_PIXEL_FORMAT_RGB565; if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) - { - SysPrintf("RGB565 supported, using it\n"); - } -#endif + current_fmt = fmt; + else + LogErr("SET_PIXEL_FORMAT failed\n"); + SysPrintf("Using PIXEL_FORMAT %d\n", current_fmt); + set_bgr_to_fb_func(0); if (info == NULL || info->path == NULL) { - SysPrintf("info->path required\n"); + LogErr("info->path required\n"); return false; } + is_m3u = (strcasestr(info->path, ".m3u") != NULL); + is_exe = (strcasestr(info->path, ".exe") != NULL); update_variables(false); @@ -1695,7 +1886,7 @@ bool retro_load_game(const struct retro_game_info *info) { if (!read_m3u(info->path)) { - log_cb(RETRO_LOG_INFO, "failed to read m3u file\n"); + LogErr("failed to read m3u file\n"); return false; } } @@ -1728,16 +1919,24 @@ bool retro_load_game(const struct retro_game_info *info) /* have to reload after set_cd_image for correct cdr plugin */ if (LoadPlugins() == -1) { - log_cb(RETRO_LOG_INFO, "failed to load plugins\n"); + LogErr("failed to load plugins\n"); return false; } + if (!strncmp(info->path, "cdrom:", 6)) + { +#if !defined(HAVE_CDROM) && !defined(USE_LIBRETRO_VFS) + ReleasePlugins(); + LogErr("%s\n", "Physical CD-ROM support is not compiled in."); + show_notification("Physical CD-ROM support is not compiled in.", 6000, 3); + return false; +#endif + } plugins_opened = 1; - NetOpened = 0; if (OpenPlugins() == -1) { - log_cb(RETRO_LOG_INFO, "failed to open plugins\n"); + LogErr("failed to open plugins\n"); return false; } @@ -1796,12 +1995,12 @@ bool retro_load_game(const struct retro_game_info *info) if (ReloadCdromPlugin() < 0) { - log_cb(RETRO_LOG_INFO, "failed to reload cdr plugins\n"); + LogErr("failed to reload cdr plugins\n"); return false; } - if (CDR_open() < 0) + if (cdra_open() < 0) { - log_cb(RETRO_LOG_INFO, "failed to open cdr plugin\n"); + LogErr("failed to open cdr plugin\n"); return false; } } @@ -1811,15 +2010,13 @@ bool retro_load_game(const struct retro_game_info *info) for (i = 0; i < 8; ++i) in_type[i] = PSE_PAD_TYPE_STANDARD; - plugin_call_rearmed_cbs(); - /* dfinput_activate(); */ - if (!is_exe && CheckCdrom() == -1) { - log_cb(RETRO_LOG_INFO, "unsupported/invalid CD image: %s\n", info->path); + LogErr("unsupported/invalid CD image: %s\n", info->path); return false; } + plugin_call_rearmed_cbs(); SysReset(); if (is_exe) @@ -1828,16 +2025,19 @@ bool retro_load_game(const struct retro_game_info *info) ret = LoadCdrom(); if (ret != 0) { - log_cb(RETRO_LOG_INFO, "could not load %s (%d)\n", is_exe ? "exe" : "CD", ret); + LogErr("could not load %s (%d)\n", is_exe ? "exe" : "CD", ret); return false; } emu_on_new_cd(0); set_retro_memmap(); retro_set_audio_buff_status_cb(); + log_mem_usage(); if (check_unsatisfied_libcrypt()) show_notification("LibCrypt protected game with missing SBI detected", 3000, 3); + if (Config.TurboCD) + show_notification("TurboCD is ON", 700, 2); return true; } @@ -1912,6 +2112,7 @@ static void update_variables(bool in_flight) int gpu_peops_fix = GPU_PEOPS_OLD_FRAME_SKIP; #endif frameskip_type_t prev_frameskip_type; + double old_fps = psxGetFps(); var.value = NULL; var.key = "pcsx_rearmed_frameskip_type"; @@ -1994,7 +2195,7 @@ static void update_variables(bool in_flight) { axis_bounds_modifier = true; } - else if (strcmp(var.value, "circle") == 0) + else { axis_bounds_modifier = false; } @@ -2011,28 +2212,49 @@ static void update_variables(bool in_flight) in_enable_vibration = 1; } + var.value = NULL; + var.key = "pcsx_rearmed_analog_combo"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "l1+r1+select") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L) | + (1 << RETRO_DEVICE_ID_JOYPAD_R) | (1 << RETRO_DEVICE_ID_JOYPAD_SELECT); + else if (strcmp(var.value, "l1+r1+start") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L) | + (1 << RETRO_DEVICE_ID_JOYPAD_R) | (1 << RETRO_DEVICE_ID_JOYPAD_START); + else if (strcmp(var.value, "l1+r1+l3") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L) | + (1 << RETRO_DEVICE_ID_JOYPAD_R) | (1 << RETRO_DEVICE_ID_JOYPAD_L3); + else if (strcmp(var.value, "l1+r1+r3") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L) | + (1 << RETRO_DEVICE_ID_JOYPAD_R) | (1 << RETRO_DEVICE_ID_JOYPAD_R3); + else if (strcmp(var.value, "l3+r3") == 0) + in_dualshock_analog_combo = (1 << RETRO_DEVICE_ID_JOYPAD_L3) | + (1 << RETRO_DEVICE_ID_JOYPAD_R3); + else + in_dualshock_analog_combo = 0; + } + var.value = NULL; var.key = "pcsx_rearmed_dithering"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - if (strcmp(var.value, "disabled") == 0) + if (strcmp(var.value, "force") == 0) { - pl_rearmed_cbs.gpu_peops.iUseDither = 0; + pl_rearmed_cbs.dithering = 2; + pl_rearmed_cbs.gpu_peopsgl.bDrawDither = 1; + } + else if (strcmp(var.value, "disabled") == 0) + { + pl_rearmed_cbs.dithering = 0; pl_rearmed_cbs.gpu_peopsgl.bDrawDither = 0; - pl_rearmed_cbs.gpu_unai.dithering = 0; -#ifdef GPU_NEON - pl_rearmed_cbs.gpu_neon.allow_dithering = 0; -#endif } - else if (strcmp(var.value, "enabled") == 0) + else { - pl_rearmed_cbs.gpu_peops.iUseDither = 1; + pl_rearmed_cbs.dithering = 1; pl_rearmed_cbs.gpu_peopsgl.bDrawDither = 1; - pl_rearmed_cbs.gpu_unai.dithering = 1; -#ifdef GPU_NEON - pl_rearmed_cbs.gpu_neon.allow_dithering = 1; -#endif } } @@ -2066,34 +2288,55 @@ static void update_variables(bool in_flight) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - if (strcmp(var.value, "disabled") == 0) - pl_rearmed_cbs.gpu_neon.enhancement_no_main = 0; - else if (strcmp(var.value, "enabled") == 0) + if (strcmp(var.value, "enabled") == 0) pl_rearmed_cbs.gpu_neon.enhancement_no_main = 1; + else + pl_rearmed_cbs.gpu_neon.enhancement_no_main = 0; + } + + var.value = NULL; + var.key = "pcsx_rearmed_neon_enhancement_tex_adj_v2"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "enabled") == 0) + pl_rearmed_cbs.gpu_neon.enhancement_tex_adj = 1; + else + pl_rearmed_cbs.gpu_neon.enhancement_tex_adj = 0; } #endif var.value = NULL; - var.key = "pcsx_rearmed_duping_enable"; + var.key = "pcsx_rearmed_display_fps_v2"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - if (strcmp(var.value, "disabled") == 0) - duping_enable = false; + if (strcmp(var.value, "extra") == 0) + display_internal_fps = 2; else if (strcmp(var.value, "enabled") == 0) - duping_enable = true; + display_internal_fps = 1; + else + display_internal_fps = 0; } var.value = NULL; - var.key = "pcsx_rearmed_display_internal_fps"; + var.key = "pcsx_rearmed_cd_turbo"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "enabled") == 0) + Config.TurboCD = true; + else + Config.TurboCD = false; + } +#if defined(HAVE_CDROM) || defined(USE_ASYNC_CDROM) + var.value = NULL; + var.key = "pcsx_rearmed_cd_readahead"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - if (strcmp(var.value, "disabled") == 0) - display_internal_fps = false; - else if (strcmp(var.value, "enabled") == 0) - display_internal_fps = true; + cdra_set_buf_count(strtol(var.value, NULL, 10)); } +#endif // // CPU emulation related config @@ -2123,29 +2366,45 @@ static void update_variables(bool in_flight) prev_cpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL); prev_cpu->Shutdown(); psxCpu->Init(); - psxCpu->Reset(); psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL); } } -#endif /* !DRC_DISABLE */ +#endif // !DRC_DISABLE var.value = NULL; var.key = "pcsx_rearmed_psxclock"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { int psxclock = atoi(var.value); - Config.cycle_multiplier = 10000 / psxclock; + if (strcmp(var.value, "auto") == 0 || psxclock == 0) + Config.cycle_multiplier = CYCLE_MULT_DEFAULT; + else + Config.cycle_multiplier = 10000 / psxclock; } #if !defined(DRC_DISABLE) && !defined(LIGHTREC) +#ifdef NDRC_THREAD + var.value = NULL; + var.key = "pcsx_rearmed_drc_thread"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + ndrc_g.hacks &= ~(NDHACK_THREAD_FORCE | NDHACK_THREAD_FORCE_ON); + if (strcmp(var.value, "disabled") == 0) + ndrc_g.hacks |= NDHACK_THREAD_FORCE; + else if (strcmp(var.value, "enabled") == 0) + ndrc_g.hacks |= NDHACK_THREAD_FORCE | NDHACK_THREAD_FORCE_ON; + // psxCpu->ApplyConfig(); will start/stop the thread + } +#endif + var.value = NULL; var.key = "pcsx_rearmed_nosmccheck"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (strcmp(var.value, "enabled") == 0) - new_dynarec_hacks |= NDHACK_NO_SMC_CHECK; + ndrc_g.hacks |= NDHACK_NO_SMC_CHECK; else - new_dynarec_hacks &= ~NDHACK_NO_SMC_CHECK; + ndrc_g.hacks &= ~NDHACK_NO_SMC_CHECK; } var.value = NULL; @@ -2153,9 +2412,9 @@ static void update_variables(bool in_flight) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (strcmp(var.value, "enabled") == 0) - new_dynarec_hacks |= NDHACK_GTE_UNNEEDED; + ndrc_g.hacks |= NDHACK_GTE_UNNEEDED; else - new_dynarec_hacks &= ~NDHACK_GTE_UNNEEDED; + ndrc_g.hacks &= ~NDHACK_GTE_UNNEEDED; } var.value = NULL; @@ -2163,9 +2422,9 @@ static void update_variables(bool in_flight) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (strcmp(var.value, "enabled") == 0) - new_dynarec_hacks |= NDHACK_GTE_NO_FLAGS; + ndrc_g.hacks |= NDHACK_GTE_NO_FLAGS; else - new_dynarec_hacks &= ~NDHACK_GTE_NO_FLAGS; + ndrc_g.hacks &= ~NDHACK_GTE_NO_FLAGS; } var.value = NULL; @@ -2173,9 +2432,9 @@ static void update_variables(bool in_flight) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (strcmp(var.value, "enabled") == 0) - new_dynarec_hacks |= NDHACK_NO_COMPAT_HACKS; + ndrc_g.hacks |= NDHACK_NO_COMPAT_HACKS; else - new_dynarec_hacks &= ~NDHACK_NO_COMPAT_HACKS; + ndrc_g.hacks &= ~NDHACK_NO_COMPAT_HACKS; } #endif /* !DRC_DISABLE && !LIGHTREC */ @@ -2240,6 +2499,7 @@ static void update_variables(bool in_flight) spu_config.iUseInterpolation = 0; } +#if P_HAVE_PTHREAD var.value = NULL; var.key = "pcsx_rearmed_spu_thread"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) @@ -2249,29 +2509,7 @@ static void update_variables(bool in_flight) else spu_config.iUseThread = 0; } - - if (P_HAVE_PTHREAD) { - var.value = NULL; - var.key = "pcsx_rearmed_async_cd"; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (strcmp(var.value, "async") == 0) - { - Config.AsyncCD = 1; - Config.CHD_Precache = 0; - } - else if (strcmp(var.value, "sync") == 0) - { - Config.AsyncCD = 0; - Config.CHD_Precache = 0; - } - else if (strcmp(var.value, "precache") == 0) - { - Config.AsyncCD = 0; - Config.CHD_Precache = 1; - } - } - } +#endif var.value = NULL; var.key = "pcsx_rearmed_noxadecoding"; @@ -2305,6 +2543,18 @@ static void update_variables(bool in_flight) Config.GpuListWalking = -1; } + var.value = NULL; + var.key = "pcsx_rearmed_fractional_framerate"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "disabled") == 0) + Config.FractionalFramerate = 0; + else if (strcmp(var.value, "enabled") == 0) + Config.FractionalFramerate = 1; + else // auto + Config.FractionalFramerate = -1; + } + var.value = NULL; var.key = "pcsx_rearmed_screen_centering"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) @@ -2333,6 +2583,25 @@ static void update_variables(bool in_flight) pl_rearmed_cbs.screen_centering_y = atoi(var.value); } + var.value = NULL; + var.key = "pcsx_rearmed_screen_centering_h_adj"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + pl_rearmed_cbs.screen_centering_h_adj = atoi(var.value); + } + + var.value = NULL; + var.key = "pcsx_rearmed_show_overscan"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "auto") == 0) + pl_rearmed_cbs.show_overscan = 1; + else if (strcmp(var.value, "hack") == 0) + pl_rearmed_cbs.show_overscan = 2; + else + pl_rearmed_cbs.show_overscan = 0; + } + #ifdef THREAD_RENDERING var.key = "pcsx_rearmed_gpu_thread_rendering"; var.value = NULL; @@ -2431,10 +2700,28 @@ static void update_variables(bool in_flight) * (480i, 512i) and has been obsoleted by * pcsx_rearmed_gpu_unai_scale_hires */ pl_rearmed_cbs.gpu_unai.ilace_force = 0; - /* Note: This used to be an option, but it has no - * discernable effect and has been obsoleted by - * pcsx_rearmed_gpu_unai_scale_hires */ - pl_rearmed_cbs.gpu_unai.pixel_skip = 0; + + var.key = "pcsx_rearmed_gpu_unai_old_renderer"; + var.value = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "enabled") == 0) + pl_rearmed_cbs.gpu_unai.old_renderer = 1; + else + pl_rearmed_cbs.gpu_unai.old_renderer = 0; + } + + var.key = "pcsx_rearmed_gpu_unai_skipline"; + var.value = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "disabled") == 0) + pl_rearmed_cbs.gpu_unai.ilace_force = 0; + else if (strcmp(var.value, "enabled") == 0) + pl_rearmed_cbs.gpu_unai.ilace_force = 1; + } var.key = "pcsx_rearmed_gpu_unai_lighting"; var.value = NULL; @@ -2573,6 +2860,27 @@ static void update_variables(bool in_flight) mouse_sensitivity = atof(var.value); } +#ifdef _3DS + var.value = NULL; + var.key = "pcsx_rearmed_3ds_appcputime"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + APT_SetAppCpuTimeLimit(strtol(var.value, NULL, 10)); + } +#endif + + if (found_bios) + { + var.value = NULL; + var.key = "pcsx_rearmed_show_bios_bootlogo"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + Config.SlowBoot = 0; + if (strcmp(var.value, "enabled") == 0) + Config.SlowBoot = 1; + } + } + if (in_flight) { // inform core things about possible config changes @@ -2590,29 +2898,15 @@ static void update_variables(bool in_flight) /* dfinput_activate(); */ } - else - { - //not yet running - - //bootlogo display hack - if (found_bios) - { - var.value = NULL; - var.key = "pcsx_rearmed_show_bios_bootlogo"; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - Config.SlowBoot = 0; - rebootemu = 0; - if (strcmp(var.value, "enabled") == 0) - { - Config.SlowBoot = 1; - rebootemu = 1; - } - } - } - } update_option_visibility(); + + if (in_flight && old_fps != psxGetFps()) + { + struct retro_system_av_info info; + retro_get_system_av_info(&info); + environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &info); + } } // Taken from beetle-psx-libretro @@ -2642,26 +2936,19 @@ static uint16_t get_analog_button(int16_t ret, retro_input_state_t input_state_c return button; } -unsigned char axis_range_modifier(int16_t axis_value, bool is_square) +static unsigned char axis_range_modifier(int axis_value, bool is_square) { - float modifier_axis_range = 0; + int modifier_axis_range; if (is_square) - { - modifier_axis_range = round((axis_value >> 8) / 0.785) + 128; - if (modifier_axis_range < 0) - { - modifier_axis_range = 0; - } - else if (modifier_axis_range > 255) - { - modifier_axis_range = 255; - } - } + modifier_axis_range = roundf((axis_value >> 8) / 0.785f) + 128; else - { - modifier_axis_range = MIN(((axis_value >> 8) + 128), 255); - } + modifier_axis_range = (axis_value >> 8) + 128; + + if (modifier_axis_range < 0) + modifier_axis_range = 0; + else if (modifier_axis_range > 255) + modifier_axis_range = 255; return modifier_axis_range; } @@ -2868,13 +3155,13 @@ static void update_input_mouse(int port, int ret) static void update_input(void) { - // reset all keystate, query libretro for keystate int i; int j; + // reset all keystate, query libretro for keystate for (i = 0; i < PORTS_NUMBER; i++) { - int16_t ret = 0; + int32_t ret = 0; int type = in_type[i]; in_keystate[i] = 0; @@ -2883,7 +3170,11 @@ static void update_input(void) continue; if (libretro_supports_bitmasks) + { ret = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); + // undo int16 sign extension (why input_state_cb returns int16 in the first place?) + ret &= (1 << (RETRO_DEVICE_ID_JOYPAD_R3 + 1)) - 1; + } else { for (j = 0; j < (RETRO_DEVICE_ID_JOYPAD_R3 + 1); j++) @@ -2908,7 +3199,23 @@ static void update_input(void) update_input_mouse(i, ret); break; default: - // Query digital inputs + // dualshock ANALOG toggle? + if (type == PSE_PAD_TYPE_ANALOGPAD && in_dualshock_analog_combo != 0 + && ret == in_dualshock_analog_combo) + { + if (!in_dualshock_toggling) + { + int state = padToggleAnalog(i); + char msg[32]; + snprintf(msg, sizeof(msg), "ANALOG %s", state ? "ON" : "OFF"); + show_notification(msg, 800, 1); + in_dualshock_toggling = true; + } + return; + } + in_dualshock_toggling = false; + + // Set digital inputs for (j = 0; j < RETRO_PSX_MAP_LEN; j++) if (ret & (1 << j)) in_keystate[i] |= retro_psx_map[j]; @@ -2929,24 +3236,50 @@ static void print_internal_fps(void) { if (display_internal_fps) { - frame_count++; + static u32 fps, frame_count_s; + static time_t last_time; + static u32 psx_vsync_count; + u32 psx_vsync_rate = is_pal_mode ? 50 : 60; + time_t now; - if (frame_count % INTERNAL_FPS_SAMPLE_PERIOD == 0) + psx_vsync_count++; + frame_count_s++; + now = time(NULL); + if (now != last_time) { - unsigned internal_fps = pl_rearmed_cbs.flip_cnt * (is_pal_mode ? 50 : 60) / INTERNAL_FPS_SAMPLE_PERIOD; - char str[64]; - const char *strc = (const char *)str; + fps = frame_count_s; + frame_count_s = 0; + last_time = now; + } - str[0] = '\0'; + if (psx_vsync_count >= psx_vsync_rate) + { + int pos = 0, cd_count; + char str[64]; - snprintf(str, sizeof(str), "Internal FPS: %2d", internal_fps); + if (display_internal_fps > 1) { +#if !defined(DRC_DISABLE) && !defined(LIGHTREC) + if (ndrc_g.did_compile) { + pos = snprintf(str, sizeof(str), "DRC: %d ", ndrc_g.did_compile); + ndrc_g.did_compile = 0; + } +#endif + cd_count = cdra_get_buf_count(); + if (cd_count) { + pos += snprintf(str + pos, sizeof(str) - pos, "CD: %2d/%d ", + cdra_get_buf_cached_approx(), cd_count); + } + } + snprintf(str + pos, sizeof(str) - pos, "FPS: %2d/%2d", + pl_rearmed_cbs.flip_cnt, fps); pl_rearmed_cbs.flip_cnt = 0; + psx_vsync_count = 0; if (msg_interface_version >= 1) { struct retro_message_ext msg = { - strc, + str, 3000, 1, RETRO_LOG_INFO, @@ -2959,15 +3292,13 @@ static void print_internal_fps(void) else { struct retro_message msg = { - strc, + str, 180 }; environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg); } } } - else - frame_count = 0; } void retro_run(void) @@ -3032,8 +3363,8 @@ void retro_run(void) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) update_variables(true); - stop = 0; - psxCpu->Execute(); + psxRegs.stop = 0; + psxCpu->Execute(&psxRegs); if (pl_rearmed_cbs.fskip_dirty == 1) { if (frameskip_counter < frameskip_interval) @@ -3042,9 +3373,18 @@ void retro_run(void) frameskip_counter = 0; } - video_cb((vout_fb_dirty || !vout_can_dupe || !duping_enable) ? vout_buf_ptr : NULL, - vout_width, vout_height, vout_pitch * 2); + video_cb((vout_fb_dirty || !vout_can_dupe) ? vout_buf_ptr : NULL, + vout_width, vout_height, vout_pitch_b); vout_fb_dirty = 0; + +#ifdef HAVE_CDROM + int inserted; + if (cdra_check_eject(&inserted) > 0) { + bool media_inserted = inserted != 0; + if (!media_inserted != disk_ejected) + disk_set_eject_state(!media_inserted); + } +#endif } static bool try_use_bios(const char *path, bool preferred_only) @@ -3166,7 +3506,7 @@ static int init_memcards(void) { if (strlen(dir) + strlen(CARD2_FILE) + 2 > sizeof(Config.Mcd2)) { - SysPrintf("Path '%s' is too long. Cannot use memcard 2. Use a shorter path.\n", dir); + LogErr("Path '%s' is too long. Cannot use memcard 2. Use a shorter path.\n", dir); ret = -1; } else @@ -3178,7 +3518,7 @@ static int init_memcards(void) } else { - SysPrintf("Could not get save directory! Could not create memcard 2."); + LogErr("Could not get save directory! Could not create memcard 2."); ret = -1; } } @@ -3264,6 +3604,8 @@ void retro_init(void) struct retro_rumble_interface rumble; int ret; + log_mem_usage(); + msg_interface_version = 0; environ_cb(RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION, &msg_interface_version); @@ -3272,11 +3614,13 @@ void retro_init(void) syscall(SYS_ptrace, 0 /*PTRACE_TRACEME*/, 0, 0, 0); #endif -#ifdef _3DS +#if defined(_3DS) psxMapHook = pl_3ds_mmap; psxUnmapHook = pl_3ds_munmap; -#endif -#ifdef VITA +#elif defined(HAVE_LIBNX) + psxMapHook = pl_switch_mmap; + psxUnmapHook = pl_switch_munmap; +#elif defined(VITA) if (init_vita_mmap() < 0) abort(); psxMapHook = pl_vita_mmap; @@ -3293,26 +3637,44 @@ void retro_init(void) ret |= emu_core_init(); if (ret != 0) { - SysPrintf("PCSX init failed.\n"); + LogErr("PCSX init failed.\n"); exit(1); } + // alloc enough for RETRO_PIXEL_FORMAT_XRGB8888 + size_t vout_buf_size = VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 4; #ifdef _3DS - vout_buf = linearMemAlign(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2, 0x80); + // Place psx vram in linear mem to take advantage of it's supersection mapping. + // The emu allocs 2x (0x201000 to be exact) but doesn't really need that much, + // so place vout_buf below to also act as an overdraw guard. + vram_mem = linearMemAlign(1024*1024 + 4096 + vout_buf_size, 4096); + if (vram_mem) { + vout_buf = (char *)vram_mem + 1024*1024 + 4096; + if (__ctr_svchax) + SysPrintf("vram: %p PA %08x tlb %08x\n", vram_mem, + svcConvertVAToPA(vram_mem, 0), ctr_get_tlbe(vram_mem)); + } #elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) && P_HAVE_POSIX_MEMALIGN - if (posix_memalign(&vout_buf, 16, VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2) != 0) - vout_buf = (void *) 0; + if (posix_memalign(&vout_buf, 16, vout_buf_size) != 0) + vout_buf = NULL; else - memset(vout_buf, 0, VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2); + memset(vout_buf, 0, vout_buf_size); #else - vout_buf = calloc(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT, 2); + vout_buf = calloc(vout_buf_size, 1); #endif + if (vout_buf == NULL) + { + LogErr("OOM for vout_buf.\n"); + // may be able to continue if we get retro_framebuffer access + } vout_buf_ptr = vout_buf; loadPSXBios(); environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &vout_can_dupe); + if (!vout_can_dupe) + LogWarn("CAN_DUPE reports false\n"); disk_initial_index = 0; disk_initial_path[0] = '\0'; @@ -3325,14 +3687,6 @@ void retro_init(void) if (environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble)) rumble_cb = rumble.set_rumble_state; - /* Set how much slower PSX CPU runs * 100 (so that 200 is 2 times) - * we have to do this because cache misses and some IO penalties - * are not emulated. Warning: changing this may break compatibility. */ - Config.cycle_multiplier = CYCLE_MULT_DEFAULT; -#if defined(HAVE_PRE_ARMV7) && !defined(_3DS) - Config.cycle_multiplier = 200; -#endif - pl_rearmed_cbs.gpu_peops.iUseDither = 1; pl_rearmed_cbs.gpu_peops.dwActFixes = GPU_PEOPS_OLD_FRAME_SKIP; SaveFuncs.open = save_open; @@ -3356,7 +3710,8 @@ void retro_deinit(void) } SysClose(); #ifdef _3DS - linearFree(vout_buf); + linearFree(vram_mem); + vram_mem = NULL; #else free(vout_buf); #endif @@ -3390,14 +3745,6 @@ void retro_deinit(void) update_audio_latency = false; } -#ifdef VITA -#include -int usleep(unsigned long us) -{ - sceKernelDelayThread(us); -} -#endif - void SysPrintf(const char *fmt, ...) { va_list list;