diff --git a/Makefile.common b/Makefile.common index c0e54a63c0..7d5f843015 100644 --- a/Makefile.common +++ b/Makefile.common @@ -685,7 +685,8 @@ endif ifeq ($(TARGET), retroarch_3ds) OBJ += audio/drivers/ctr_csnd_audio.o \ - audio/drivers/ctr_dsp_audio.o + audio/drivers/ctr_dsp_audio.o \ + audio/drivers/ctr_dsp_thread_audio.o endif ifeq ($(HAVE_ALSA), 1) diff --git a/Makefile.ctr b/Makefile.ctr index bde79c9f5f..1e72406204 100644 --- a/Makefile.ctr +++ b/Makefile.ctr @@ -8,6 +8,7 @@ BUILD_3DSX = 1 BUILD_3DS = 0 BUILD_CIA = 1 LIBCTRU_NO_DEPRECATION = 1 +USE_CTRULIB_2 = 0 APP_TITLE = RetroArch 3DS APP_DESCRIPTION = RetroArch 3DS @@ -35,8 +36,7 @@ OBJ += ctr/exec-3dsx/exec_cia.o \ ctr/exec-3dsx/exec_3dsx.o \ ctr/exec-3dsx/mini-hb-menu/launch.o \ ctr/exec-3dsx/mini-hb-menu/loaders/rosalina.o \ - ctr/exec-3dsx/mini-hb-menu/loaders/hax2.o \ - ctr/exec-3dsx/mini-hb-menu/loaders/ninjhax1.o + ctr/exec-3dsx/mini-hb-menu/loaders/hax2.o ifeq ($(APP_BIG_TEXT_SECTION), 1) APP_USE_SVCHAX = 1 @@ -56,7 +56,8 @@ ifeq ($(GRIFFIN_BUILD), 1) DEFINES += -DHAVE_PATCH -DHAVE_RWAV DEFINES += -DHAVE_SCREENSHOTS DEFINES += -DHAVE_REWIND - #DEFINES += -DHAVE_SOCKET_LEGACY -DHAVE_THREADS + DEFINES += -DHAVE_THREADS + #DEFINES += -DHAVE_SOCKET_LEGACY #-DHAVE_SSL -DHAVE_BUILTINMBEDTLS -DMBEDTLS_SSL_DEBUG_ALL #ssl is currently incompatible with griffin due to use of the "static" flag on repeating functions that will conflict when included in one file else @@ -84,7 +85,7 @@ else #HAVE_NETWORKING = 1 #HAVE_CHEEVOS = 1 #HAVE_SOCKET_LEGACY = 1 - #HAVE_THREADS = 1 + HAVE_THREADS = 1 #HAVE_SSL = 1 #HAVE_BUILTINMBEDTLS = 1 @@ -104,6 +105,18 @@ ifeq ($(strip $(CTRULIB)),) CTRULIB = $(DEVKITPRO)/libctru endif +ifeq ($(strip $(USE_CTRULIB_2)),1) + CFLAGS += -DUSE_CTRULIB_2 +endif + +ifeq ($(strip $(DEVKITTOOLS)),) + ifeq ($(strip $(USE_CTRULIB_2)),1) + DEVKITTOOLS = $(DEVKITPRO)/tools + else + DEVKITTOOLS = $(DEVKITARM) + endif +endif + APP_TITLE := $(shell echo "$(APP_TITLE)" | cut -c1-128) APP_DESCRIPTION := $(shell echo "$(APP_DESCRIPTION)" | cut -c1-256) APP_AUTHOR := $(shell echo "$(APP_AUTHOR)" | cut -c1-128) @@ -225,13 +238,13 @@ else endif %.o: %.vsh %.gsh - $(DEVKITARM)/bin/picasso $^ -o $*.shbin - $(DEVKITARM)/bin/bin2s $*.shbin | $(PREFIX)as -o $@ + $(DEVKITTOOLS)/bin/picasso $^ -o $*.shbin + $(DEVKITTOOLS)/bin/bin2s $*.shbin | $(PREFIX)as -o $@ rm $*.shbin %.o: %.vsh - $(DEVKITARM)/bin/picasso $^ -o $*.shbin - $(DEVKITARM)/bin/bin2s $*.shbin | $(PREFIX)as -o $@ + $(DEVKITTOOLS)/bin/picasso $^ -o $*.shbin + $(DEVKITTOOLS)/bin/bin2s $*.shbin | $(PREFIX)as -o $@ rm $*.shbin %.o: %.cpp @@ -252,7 +265,7 @@ endif %.vsh: $(TARGET).smdh: $(APP_ICON) - $(DEVKITARM)/bin/smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@ + $(DEVKITTOOLS)/bin/smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@ $(TARGET).3dsx: $(TARGET).elf ifeq ($(APP_BIG_TEXT_SECTION), 1) @@ -260,7 +273,7 @@ ifeq ($(APP_BIG_TEXT_SECTION), 1) else rm -f $(TARGET).xml endif - $(DEVKITARM)/bin/3dsxtool $< $@ $(_3DSXFLAGS) + $(DEVKITTOOLS)/bin/3dsxtool $< $@ $(_3DSXFLAGS) $(TARGET).elf: ctr/3dsx_custom_crt0.o $(LD) $(LDFLAGS) $(OBJ) $(LIBDIRS) $(LIBS) -o $@ diff --git a/Makefile.ctr.salamander b/Makefile.ctr.salamander index 2e1bfc7e86..692350d905 100644 --- a/Makefile.ctr.salamander +++ b/Makefile.ctr.salamander @@ -5,6 +5,7 @@ DEBUG = 0 BUILD_3DSX = 1 BUILD_3DS = 0 BUILD_CIA = 1 +USE_CTRULIB_2 = 0 APP_TITLE = RetroArch 3DS APP_DESCRIPTION = RetroArch 3DS @@ -45,13 +46,24 @@ OBJ += ctr/exec-3dsx/exec_cia.o \ ctr/exec-3dsx/exec_3dsx.o \ ctr/exec-3dsx/mini-hb-menu/launch.o \ ctr/exec-3dsx/mini-hb-menu/loaders/rosalina.o \ - ctr/exec-3dsx/mini-hb-menu/loaders/hax2.o \ - ctr/exec-3dsx/mini-hb-menu/loaders/ninjhax1.o + ctr/exec-3dsx/mini-hb-menu/loaders/hax2.o ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitpro") endif +ifeq ($(strip $(USE_CTRULIB_2)),1) + CFLAGS += -DUSE_CTRULIB_2 +endif + +ifeq ($(strip $(DEVKITTOOLS)),) + ifeq ($(strip $(USE_CTRULIB_2)),1) + DEVKITTOOLS = $(DEVKITPRO)/tools + else + DEVKITTOOLS = $(DEVKITARM) + endif +endif + ifeq ($(strip $(CTRULIB)),) CTRULIB = $(DEVKITPRO)/libctru endif @@ -153,13 +165,13 @@ else endif %.o: %.vsh %.gsh - $(DEVKITARM)/bin/picasso $^ -o $*.shbin - $(DEVKITARM)/bin/bin2s $*.shbin | $(PREFIX)as -o $@ + $(DEVKITTOOLS)/bin/picasso $^ -o $*.shbin + $(DEVKITTOOLS)/bin/bin2s $*.shbin | $(PREFIX)as -o $@ rm $*.shbin %.o: %.vsh - $(DEVKITARM)/bin/picasso $^ -o $*.shbin - $(DEVKITARM)/bin/bin2s $*.shbin | $(PREFIX)as -o $@ + $(DEVKITTOOLS)/bin/picasso $^ -o $*.shbin + $(DEVKITTOOLS)/bin/bin2s $*.shbin | $(PREFIX)as -o $@ rm $*.shbin %.o: %.cpp @@ -180,7 +192,7 @@ endif %.vsh: $(TARGET).smdh: $(APP_ICON) - $(DEVKITARM)/bin/smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@ + $(DEVKITTOOLS)/bin/smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@ $(TARGET).3dsx: $(TARGET).elf ifeq ($(APP_BIG_TEXT_SECTION), 1) @@ -188,7 +200,7 @@ ifeq ($(APP_BIG_TEXT_SECTION), 1) else rm -f $(TARGET).xml endif - $(DEVKITARM)/bin/3dsxtool $< $@ $(_3DSXFLAGS) + $(DEVKITTOOLS)/bin/3dsxtool $< $@ $(_3DSXFLAGS) $(TARGET).elf: ctr/3dsx_custom_crt0.o $(LD) $(LDFLAGS) $(OBJ) $(LIBDIRS) $(LIBS) -o $@ diff --git a/audio/drivers/ctr_dsp_audio.c b/audio/drivers/ctr_dsp_audio.c index 68d8121cca..02b52773b8 100644 --- a/audio/drivers/ctr_dsp_audio.c +++ b/audio/drivers/ctr_dsp_audio.c @@ -107,6 +107,15 @@ static ssize_t ctr_dsp_audio_write(void *data, const void *buf, size_t size) { do{ svcSleepThread(100000); + + /* Run aptMainLoop to update APT state if DSP state + * changed, this prevents a hang on sleep. */ + if(!aptMainLoop()) + { + command_event(CMD_EVENT_QUIT, NULL); + return true; + } + sample_pos = ndspChnGetSamplePos(ctr->channel); }while (((sample_pos - (ctr->pos + (size >>2))) & CTR_DSP_AUDIO_COUNT_MASK) > (CTR_DSP_AUDIO_COUNT >> 1) || (((ctr->pos - (CTR_DSP_AUDIO_COUNT >> 4) - sample_pos) & CTR_DSP_AUDIO_COUNT_MASK) > (CTR_DSP_AUDIO_COUNT >> 1))); diff --git a/audio/drivers/ctr_dsp_thread_audio.c b/audio/drivers/ctr_dsp_thread_audio.c new file mode 100644 index 0000000000..08dad28654 --- /dev/null +++ b/audio/drivers/ctr_dsp_thread_audio.c @@ -0,0 +1,339 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2020 - Justin Weiss + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include <3ds.h> +#include +#include +#include +#include + +#include "../../retroarch.h" +#include "../../ctr/ctr_debug.h" + +typedef struct +{ + fifo_buffer_t* fifo; + size_t fifo_size; + + slock_t* fifo_lock; + scond_t* fifo_avail; + scond_t* fifo_done; + sthread_t* thread; + + volatile bool running; + + bool nonblocking; + bool playing; + retro_time_t frame_time; + int channel; + ndspWaveBuf dsp_buf; + + uint32_t pos; +} ctr_dsp_thread_audio_t; + +// PCM16 stereo +#define DSP_BYTES_TO_SAMPLES(bytes) (bytes / (2 * sizeof(uint16_t))) +#define DSP_SAMPLES_TO_BYTES(samples) (samples * 2 * sizeof(uint16_t)) + +static void ctr_dsp_audio_loop(void* data) +{ + uint32_t pos, buf_pos; + ctr_dsp_thread_audio_t *ctr = (ctr_dsp_thread_audio_t*)data; + + if (!ctr) + return; + + while (1) + { + size_t buf_avail, avail, to_write; + slock_lock(ctr->fifo_lock); + + do { + avail = FIFO_READ_AVAIL(ctr->fifo); + + if (!avail) { + scond_wait(ctr->fifo_avail, ctr->fifo_lock); + } + } while (!avail && ctr->running); + + slock_unlock(ctr->fifo_lock); + + if (!ctr->running) + break; + + pos = ctr->pos; + buf_pos = DSP_SAMPLES_TO_BYTES(ndspChnGetSamplePos(ctr->channel)); + + buf_avail = buf_pos >= pos ? buf_pos - pos : ctr->fifo_size - pos; + to_write = MIN(avail, buf_avail); + + slock_lock(ctr->fifo_lock); + + if (to_write > 0) { + fifo_read(ctr->fifo, ctr->dsp_buf.data_pcm8 + pos, to_write); + DSP_FlushDataCache(ctr->dsp_buf.data_pcm8 + pos, to_write); + scond_signal(ctr->fifo_done); + } + + slock_unlock(ctr->fifo_lock); + + if (buf_pos == pos) { + svcSleepThread(100000); + } + + ctr->pos = (pos + to_write) % ctr->fifo_size; + } +} + +static void ctr_dsp_thread_audio_free(void *data); + +static void *ctr_dsp_thread_audio_init(const char *device, unsigned rate, unsigned latency, + unsigned block_frames, + unsigned *new_rate) +{ + ctr_dsp_thread_audio_t *ctr = NULL; + + (void)device; + (void)rate; + + if (ndspInit() < 0) + return NULL; + + ctr = (ctr_dsp_thread_audio_t*)calloc(1, sizeof(ctr_dsp_thread_audio_t)); + + if (!ctr) + return NULL; + + *new_rate = 32728; + + ctr->running = true; + ctr->channel = 0; + + ndspSetOutputMode(NDSP_OUTPUT_STEREO); + ndspSetClippingMode(NDSP_CLIP_SOFT); /* ?? */ + ndspSetOutputCount(2); + ndspChnReset(ctr->channel); + ndspChnSetFormat(ctr->channel, NDSP_FORMAT_STEREO_PCM16); + ndspChnSetInterp(ctr->channel, NDSP_INTERP_NONE); + ndspChnSetRate(ctr->channel, 32728.0f); + ndspChnWaveBufClear(ctr->channel); + + ctr->fifo_size = DSP_SAMPLES_TO_BYTES((*new_rate * MAX(latency, 8)) / 1000); + + ctr->dsp_buf.data_pcm16 = linearAlloc(ctr->fifo_size); + memset(ctr->dsp_buf.data_pcm16, 0, ctr->fifo_size); + DSP_FlushDataCache(ctr->dsp_buf.data_pcm16, ctr->fifo_size); + + ctr->dsp_buf.looping = true; + ctr->dsp_buf.nsamples = DSP_BYTES_TO_SAMPLES(ctr->fifo_size); + ndspChnWaveBufAdd(ctr->channel, &ctr->dsp_buf); + + ctr->fifo = fifo_new(ctr->fifo_size); + + if (!(ctr->fifo_lock = slock_new()) || + !(ctr->fifo_avail = scond_new()) || + !(ctr->fifo_done = scond_new()) || + !(ctr->thread = sthread_create(ctr_dsp_audio_loop, ctr))) + { + RARCH_LOG("[Audio]: thread creation failed.\n"); + ctr->running = false; + ctr_dsp_thread_audio_free(ctr); + return NULL; + } + + ctr->pos = 0; + ctr->playing = true; + + ctr->frame_time = (retro_time_t)roundf(1000000 * 4481134.0 / (*new_rate * 8192.0)); + + ndspSetMasterVol(1.0); + + return ctr; +} + +static void ctr_dsp_thread_audio_free(void *data) +{ + ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data; + if (!ctr) + return; + + if (ctr->running) + { + ctr->running = false; + scond_signal(ctr->fifo_avail); + } + + if (ctr->thread) + sthread_join(ctr->thread); + + scond_free(ctr->fifo_avail); + scond_free(ctr->fifo_done); + slock_free(ctr->fifo_lock); + + if (ctr->fifo) + { + fifo_free(ctr->fifo); + ctr->fifo = NULL; + } + + ndspChnWaveBufClear(ctr->channel); + + linearFree(ctr->dsp_buf.data_pcm16); + + free(ctr); + ndspExit(); + ctr = NULL; +} + +static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t size) +{ + size_t avail, written; + ctr_dsp_thread_audio_t * ctr = (ctr_dsp_thread_audio_t*)data; + + if (!ctr || !ctr->running) + return 0; + + if (ctr->nonblocking) + { + slock_lock(ctr->fifo_lock); + avail = FIFO_WRITE_AVAIL(ctr->fifo); + written = MIN(avail, size); + if (written > 0) + { + fifo_write(ctr->fifo, buf, written); + scond_signal(ctr->fifo_avail); + } + slock_unlock(ctr->fifo_lock); + } + else + { + written = 0; + while (written < size && ctr->running) + { + slock_lock(ctr->fifo_lock); + avail = FIFO_WRITE_AVAIL(ctr->fifo); + if (avail == 0) + { + if (ctr->running) + { + /* Wait a maximum of one frame, skip the write if the thread is still busy */ + if (!scond_wait_timeout(ctr->fifo_done, ctr->fifo_lock, ctr->frame_time)) { + slock_unlock(ctr->fifo_lock); + break; + } + } + slock_unlock(ctr->fifo_lock); + } + else + { + size_t write_amt = MIN(size - written, avail); + fifo_write(ctr->fifo, (const char*)buf + written, write_amt); + scond_signal(ctr->fifo_avail); + slock_unlock(ctr->fifo_lock); + written += write_amt; + } + } + } + + return written; +} + +static bool ctr_dsp_thread_audio_stop(void *data) +{ + ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data; + + if (!ctr) + return false; + + ndspSetMasterVol(0.0); + ctr->playing = false; + + return true; +} + +static bool ctr_dsp_thread_audio_alive(void *data) +{ + ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data; + + if (!ctr) + return false; + + return ctr->playing; +} + +static bool ctr_dsp_thread_audio_start(void *data, bool is_shutdown) +{ + ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data; + + if (!ctr) + return false; + + /* Prevents restarting audio when the menu + * is toggled off on shutdown */ + if (is_shutdown) + return true; + + ndspSetMasterVol(1.0); + ctr->playing = true; + + return true; +} + +static void ctr_dsp_thread_audio_set_nonblock_state(void *data, bool state) +{ + ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data; + if (ctr) + ctr->nonblocking = state; +} + +static bool ctr_dsp_thread_audio_use_float(void *data) +{ + (void)data; + return false; +} + +static size_t ctr_dsp_thread_audio_write_avail(void *data) +{ + size_t val; + ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data; + + slock_lock(ctr->fifo_lock); + val = FIFO_WRITE_AVAIL(ctr->fifo); + slock_unlock(ctr->fifo_lock); + + return val; +} + +static size_t ctr_dsp_thread_audio_buffer_size(void *data) +{ + ctr_dsp_thread_audio_t* ctr = (ctr_dsp_thread_audio_t*)data; + return ctr->fifo_size; +} + +audio_driver_t audio_ctr_dsp_thread = { + ctr_dsp_thread_audio_init, + ctr_dsp_thread_audio_write, + ctr_dsp_thread_audio_stop, + ctr_dsp_thread_audio_start, + ctr_dsp_thread_audio_alive, + ctr_dsp_thread_audio_set_nonblock_state, + ctr_dsp_thread_audio_free, + ctr_dsp_thread_audio_use_float, + "dsp_thread", + NULL, + NULL, + ctr_dsp_thread_audio_write_avail, + ctr_dsp_thread_audio_buffer_size +}; diff --git a/ctr/ctr_linear.cpp b/ctr/ctr_linear.cpp index 2dc6f80c2a..f73a4b7723 100644 --- a/ctr/ctr_linear.cpp +++ b/ctr/ctr_linear.cpp @@ -201,8 +201,7 @@ void* linearMemAlign(size_t size, size_t alignment) void* linearAlloc(size_t size) { #if 0 - extern PrintConsole* currentConsole; - if(currentConsole->consoleInitialised) + if(ctrConsole && ctrConsole->consoleInitialised) { printf("linearAlloc : 0x%08X\n", size); DEBUG_HOLD(); diff --git a/ctr/ctr_svchax.c b/ctr/ctr_svchax.c index 53f96d367a..7614417c31 100644 --- a/ctr/ctr_svchax.c +++ b/ctr/ctr_svchax.c @@ -44,7 +44,9 @@ typedef struct bool isNew3DS; u32 kernel_fcram_mapping_offset; +#ifndef USE_CTRULIB_2 Handle arbiter; +#endif volatile u32 alloc_address; volatile u32 alloc_size; u8* flush_buffer; @@ -263,7 +265,9 @@ static void do_memchunkhax2(void) svcCloseHandle(mch2.dummy_threads_lock); +#ifndef USE_CTRULIB_2 mch2.arbiter = __sync_get_arbiter(); +#endif svcControlMemory(&linear_buffer, 0, 0, 0x1000, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); @@ -327,9 +331,14 @@ static void do_memchunkhax2(void) (ThreadFunc)alloc_thread_entry, (u32)&mch2, mch2.threads[MCH2_THREAD_COUNT_MAX - 1].stack_top, 0x3F, 1); +#ifdef USE_CTRULIB_2 + while ((u32) syncArbitrateAddress((s32 *)mch2.alloc_address, + ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, 0) == 0xD9001814); +#else while ((u32) svcArbitrateAddress(mch2.arbiter, mch2.alloc_address, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, 0, 0) == 0xD9001814); +#endif GX_TextureCopy((void*)linear_buffer, 0, (void*)dst_memchunk, 0, 16, 8); memcpy(flush_buffer, flush_buffer + 0x4000, 0x4000); diff --git a/ctr/ctr_system.c b/ctr/ctr_system.c index 4f690d6eaa..544a6ae327 100644 --- a/ctr/ctr_system.c +++ b/ctr/ctr_system.c @@ -21,6 +21,8 @@ u32 __heapBase; u32 __stack_bottom; u32 __stack_size_extra; +u32 __saved_stack; + extern u32 __linear_heap_size_hbl; extern u32 __heap_size_hbl; extern void* __service_ptr; @@ -74,6 +76,11 @@ void __system_allocateHeaps(void) /* Allocate the linear heap */ svcControlMemory(&__linear_heap, 0x0, 0x0, __linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); +#ifdef USE_CTRULIB_2 + /* Mappable allocator init */ + mappableInit(OS_MAP_AREA_BEGIN, OS_MAP_AREA_END); +#endif + /* Set up newlib heap */ fake_heap_end = (char*)0x13F00000; } @@ -240,6 +247,9 @@ void __system_initArgv(void) void initSystem(void (*retAddr)(void)) { + register u32 sp_val __asm__("sp"); + __saved_stack = sp_val; + __libctru_init(retAddr); __appInit(); __system_initArgv(); @@ -250,6 +260,7 @@ void __attribute__((noreturn)) __ctru_exit(int rc) { __libc_fini_array(); __appExit(); + asm ("mov sp, %[saved_stack] \n\t" : : [saved_stack] "r" (__saved_stack) : "sp"); __libctru_exit(rc); } diff --git a/ctr/exec-3dsx/exec_3dsx.c b/ctr/exec-3dsx/exec_3dsx.c index c23c990904..39fa80511e 100644 --- a/ctr/exec-3dsx/exec_3dsx.c +++ b/ctr/exec-3dsx/exec_3dsx.c @@ -5,7 +5,6 @@ #include "mini-hb-menu/common.h" -extern const loaderFuncs_s loader_Ninjhax1; extern const loaderFuncs_s loader_Ninjhax2; extern const loaderFuncs_s loader_Rosalina; @@ -69,12 +68,6 @@ static int exec_3dsx_actual(const char* path, launch_3dsx = loader_Ninjhax2.launchFile; } - if (!inited) - { - inited = loader_Ninjhax1.init(); - launch_3dsx = loader_Ninjhax1.launchFile; - } - if (inited) { osSetSpeedupEnable(false); diff --git a/ctr/exec-3dsx/mini-hb-menu/loaders/ninjhax1.c b/ctr/exec-3dsx/mini-hb-menu/loaders/ninjhax1.c deleted file mode 100644 index 8fd05663d3..0000000000 --- a/ctr/exec-3dsx/mini-hb-menu/loaders/ninjhax1.c +++ /dev/null @@ -1,43 +0,0 @@ -#include "../common.h" - -static void (*callBootloader_1x)(Handle hb, Handle file); -static void (*setArgs_1x)(u32* src, u32 length); -static Handle fileHandle; - -static bool init(void) -{ - Result res = hbInit(); - if (R_FAILED(res)) - return false; - - HB_GetBootloaderAddresses((void**)&callBootloader_1x, (void**)&setArgs_1x); - return true; -} - -static void deinit(void) -{ - hbExit(); -} - -static void bootloaderJump(void) -{ - callBootloader_1x(0x00000000, fileHandle); -} - -static void launchFile(const char* path, argData_s* args, executableMetadata_s* em) -{ - fileHandle = launchOpenFile(path); - if (fileHandle==0) - return; - setArgs_1x(args->buf, sizeof(args->buf)); - __system_retAddr = bootloaderJump; -} - -const loaderFuncs_s loader_Ninjhax1 = -{ - .name = "ninjhax 1.x", - .flags = LOADER_SHOW_REBOOT, - .init = init, - .deinit = deinit, - .launchFile = launchFile, -}; diff --git a/frontend/drivers/platform_ctr.c b/frontend/drivers/platform_ctr.c index dc61bdb496..d77d681712 100644 --- a/frontend/drivers/platform_ctr.c +++ b/frontend/drivers/platform_ctr.c @@ -60,6 +60,8 @@ static enum frontend_fork ctr_fork_mode = FRONTEND_FORK_NONE; static const char* elf_path_cst = "sdmc:/retroarch/retroarch.3dsx"; +extern bool ctr_bottom_screen_enabled; + #ifdef IS_SALAMANDER static void get_first_valid_core(char* path_return, size_t len) { @@ -135,8 +137,6 @@ static void frontend_ctr_deinit(void* data) u8 not_2DS; u8 device_model = 0xFF; - extern PrintConsole* currentConsole; - (void)data; #ifndef IS_SALAMANDER @@ -153,8 +153,7 @@ static void frontend_ctr_deinit(void* data) verbosity_enable(); retro_main_log_file_init(NULL, false); - if ((gfxBottomFramebuffers[0] == (u8*)currentConsole->frameBuffer) - && (ctr_fork_mode == FRONTEND_FORK_NONE)) + if (ctr_bottom_screen_enabled && (ctr_fork_mode == FRONTEND_FORK_NONE)) wait_for_input(); CFGU_GetModelNintendo2DS(¬_2DS); @@ -394,6 +393,36 @@ __attribute__((weak)) u32 __ctr_patch_services; void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id); +#ifdef USE_CTRULIB_2 +u8* gfxTopLeftFramebuffers[2]; +u8* gfxTopRightFramebuffers[2]; +u8* gfxBottomFramebuffers[2]; + +void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id) +{ + if(screen==GFX_TOP) + { + u8 enable3d = 0; + u8 bit5=(enable3d != 0); + gspPresentBuffer(GFX_TOP, + id, + (u32*)gfxTopLeftFramebuffers[id], + enable3d ? (u32*)gfxTopRightFramebuffers[id] : (u32*)gfxTopLeftFramebuffers[id], + 240 * 3, + ((1)<<8)|((1^bit5)<<6)|((bit5)<<5)|GSP_BGR8_OES); + } else { + gspPresentBuffer(GFX_BOTTOM, + id, + (u32*)gfxBottomFramebuffers[id], + (u32*)gfxBottomFramebuffers[id], + 240 * 2, + GSP_RGB565_OES); + } +} +#endif + +PrintConsole* ctrConsole; + static void frontend_ctr_init(void* data) { #ifndef IS_SALAMANDER @@ -407,12 +436,25 @@ static void frontend_ctr_init(void* data) u32 topSize = 400 * 240 * 3; u32 bottomSize = 320 * 240 * 2; + +#ifdef USE_CTRULIB_2 + linearFree(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL)); + linearFree(gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL)); + linearFree(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL)); + gfxSwapBuffers(); + + linearFree(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL)); + linearFree(gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL)); + linearFree(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL)); + gfxSwapBuffers(); +#else linearFree(gfxTopLeftFramebuffers [0]); linearFree(gfxTopLeftFramebuffers [1]); linearFree(gfxBottomFramebuffers [0]); linearFree(gfxBottomFramebuffers [1]); linearFree(gfxTopRightFramebuffers[0]); linearFree(gfxTopRightFramebuffers[1]); +#endif gfxTopLeftFramebuffers [0] = linearAlloc(topSize * 2); gfxTopRightFramebuffers[0] = gfxTopLeftFramebuffers[0] + topSize; @@ -427,7 +469,7 @@ static void frontend_ctr_init(void* data) gfxSetFramebufferInfo(GFX_BOTTOM, 0); gfxSet3D(true); - consoleInit(GFX_BOTTOM, NULL); + ctrConsole = consoleInit(GFX_BOTTOM, NULL); /* enable access to all service calls when possible. */ if (svchax_init) @@ -440,8 +482,10 @@ static void frontend_ctr_init(void* data) if (csndInit() != 0) audio_ctr_csnd = audio_null; ctr_check_dspfirm(); - if (ndspInit() != 0) + if (ndspInit() != 0) { audio_ctr_dsp = audio_null; + audio_ctr_dsp_thread = audio_null; + } cfguInit(); ptmuInit(); mcuHwcInit(); @@ -518,7 +562,11 @@ static enum frontend_powerstate frontend_ctr_get_powerstate( u8 battery_percent = 0; u8 charging = 0; +#ifdef USE_CTRULIB_2 + MCUHWC_GetBatteryLevel(&battery_percent); +#else mcuHwcGetBatteryLevel(&battery_percent); +#endif *percent = battery_percent; /* 3DS does not support seconds of charge remaining */ diff --git a/gfx/common/ctr_common.h b/gfx/common/ctr_common.h index 17ce294a2b..8bd3547150 100644 --- a/gfx/common/ctr_common.h +++ b/gfx/common/ctr_common.h @@ -24,6 +24,14 @@ #define CTR_TOP_FRAMEBUFFER_WIDTH 400 #define CTR_TOP_FRAMEBUFFER_HEIGHT 240 +#ifdef USE_CTRULIB_2 +extern u8* gfxTopLeftFramebuffers[2]; +extern u8* gfxTopRightFramebuffers[2]; +extern u8* gfxBottomFramebuffers[2]; +#endif + +extern PrintConsole* ctrConsole; + extern const u8 ctr_sprite_shbin[]; extern const u32 ctr_sprite_shbin_size; diff --git a/gfx/drivers/ctr_gfx.c b/gfx/drivers/ctr_gfx.c index 10f909183b..d9506c4216 100644 --- a/gfx/drivers/ctr_gfx.c +++ b/gfx/drivers/ctr_gfx.c @@ -51,7 +51,7 @@ * Have to keep track of bottom screen enable state * externally, otherwise cannot detect current state * when reinitialising... */ -static bool ctr_bottom_screen_enabled = true; +bool ctr_bottom_screen_enabled = true; static INLINE void ctr_check_3D_slider(ctr_video_t* ctr, ctr_video_mode_enum video_mode) { @@ -325,13 +325,12 @@ static void ctr_set_bottom_screen_enable(void* data, bool enabled) { Handle lcd_handle; u8 not_2DS; - extern PrintConsole* currentConsole; ctr_video_t *ctr = (ctr_video_t*)data; - if (!ctr) - return; + if (!ctr) + return; - gfxBottomFramebuffers[0] = enabled ? (u8*)currentConsole->frameBuffer: + gfxBottomFramebuffers[0] = enabled ? (u8*)ctrConsole->frameBuffer: (u8*)ctr->empty_framebuffer; CFGU_GetModelNintendo2DS(¬_2DS); @@ -568,12 +567,6 @@ static bool ctr_frame(void* data, const void* frame, return true; } - if(!aptMainLoop()) - { - command_event(CMD_EVENT_QUIT, NULL); - return true; - } - state_tmp = hidKeysDown(); hidTouchRead(&state_tmp_touch); if((state_tmp & KEY_TOUCH) && (state_tmp_touch.py < 120)) @@ -916,6 +909,32 @@ static bool ctr_frame(void* data, const void* frame, /* Swap buffers : */ +#ifdef USE_CTRULIB_2 + u32 *buf0, *buf1; + u32 stride; + + buf0 = (u32*)gfxTopLeftFramebuffers[ctr->current_buffer_top]; + + if(ctr->video_mode == CTR_VIDEO_MODE_2D_800X240) + { + buf1 = (u32*)(gfxTopLeftFramebuffers[ctr->current_buffer_top] + 240 * 3); + stride = 240 * 3 * 2; + } + else + { + if (ctr->enable_3d) + buf1 = (u32*)gfxTopRightFramebuffers[ctr->current_buffer_top]; + else + buf1 = buf0; + + stride = 240 * 3; + } + + u8 bit5 = (ctr->enable_3d != 0); + + gspPresentBuffer(GFX_TOP, ctr->current_buffer_top, buf0, buf1, + stride, (1<<8)|((1^bit5)<<6)|((bit5)<<5)|GSP_BGR8_OES); +#else topFramebufferInfo. active_framebuf = ctr->current_buffer_top; topFramebufferInfo. @@ -953,6 +972,7 @@ static bool ctr_frame(void* data, const void* frame, framebufferInfoHeader[0x0] ^= 1; framebufferInfo[framebufferInfoHeader[0x0]] = topFramebufferInfo; framebufferInfoHeader[0x1] = 1; +#endif ctr->current_buffer_top ^= 1; ctr->p3d_event_pending = true; diff --git a/gfx/drivers/ctr_gu.h b/gfx/drivers/ctr_gu.h index 0307604ddd..317f2b8753 100644 --- a/gfx/drivers/ctr_gu.h +++ b/gfx/drivers/ctr_gu.h @@ -58,6 +58,20 @@ extern u32 gpuCmdBufOffset; extern u32 __linear_heap_size; extern u32 __linear_heap; +#ifdef USE_CTRULIB_2 +__attribute__((always_inline)) +static INLINE Result ctrGspSubmitGxCommand(u32 gxCommand[0x8]) +{ + return gspSubmitGxCommand(gxCommand); +} +#else +__attribute__((always_inline)) +static INLINE Result ctrGspSubmitGxCommand(u32 gxCommand[0x8]) +{ + return gspSubmitGxCommand(gxCmdBuf, gxCommand); +} +#endif + __attribute__((always_inline)) static INLINE Result ctr_set_parallax_layer(bool state) { @@ -107,7 +121,7 @@ static INLINE Result ctrGuSetCommandList_First(bool queued, u32* buf0a, u32 buf0 gxCommand[6]=(u32)buf2s; //buf2 size gxCommand[7]=0x0; - return gspSubmitGxCommand(gxCmdBuf, gxCommand); + return ctrGspSubmitGxCommand(gxCommand); } __attribute__((always_inline)) @@ -121,7 +135,7 @@ static INLINE Result ctrGuSetCommandList_Last(bool queued, u32* buf0a, u32 buf0s gxCommand[4]=gxCommand[5]=gxCommand[6]=0x0; gxCommand[7]=(flags>>1)&1; //when non-zero, call svcFlushProcessDataCache() with the specified buffer - return gspSubmitGxCommand(gxCmdBuf, gxCommand); + return ctrGspSubmitGxCommand(gxCommand); } __attribute__((always_inline)) @@ -145,7 +159,7 @@ static INLINE Result ctrGuSetMemoryFill(bool queued, u32* buf0a, u32 buf0v, u32* gxCommand[6]=(u32)buf1e; //buf1 end addr gxCommand[7]=(width0)|(width1<<16); - return gspSubmitGxCommand(gxCmdBuf, gxCommand); + return ctrGspSubmitGxCommand(gxCommand); } __attribute__((always_inline)) @@ -167,7 +181,7 @@ static INLINE Result ctrGuCopyImage | ((dst_w > src_w) ? CTRGU_DMA_TRUNCATE : 0); gxCommand[6]=gxCommand[7]=0x0; - return gspSubmitGxCommand(gxCmdBuf, gxCommand); + return ctrGspSubmitGxCommand(gxCommand); } @@ -186,7 +200,7 @@ static INLINE Result ctrGuDisplayTransfer gxCommand[5]=(src_fmt << 8) | (dst_fmt << 12) | multisample_lvl; gxCommand[6]=gxCommand[7]=0x0; - return gspSubmitGxCommand(gxCmdBuf, gxCommand); + return ctrGspSubmitGxCommand(gxCommand); } diff --git a/gfx/video_thread_wrapper.c b/gfx/video_thread_wrapper.c index faeaf028eb..1a9e47dac0 100644 --- a/gfx/video_thread_wrapper.c +++ b/gfx/video_thread_wrapper.c @@ -829,7 +829,11 @@ static bool video_thread_init(thread_video_t *thr, max_size = info.input_scale * RARCH_SCALE_BASE; max_size *= max_size; max_size *= info.rgb32 ? sizeof(uint32_t) : sizeof(uint16_t); +#ifdef _3DS + thr->frame.buffer = linearMemAlign(max_size, 0x80); +#else thr->frame.buffer = (uint8_t*)malloc(max_size); +#endif if (!thr->frame.buffer) return false; @@ -949,7 +953,11 @@ static void video_thread_free(void *data) #if defined(HAVE_MENU) free(thr->texture.frame); #endif +#ifdef _3DS + linearFree(thr->frame.buffer); +#else free(thr->frame.buffer); +#endif slock_free(thr->frame.lock); slock_free(thr->lock); scond_free(thr->cond_cmd); diff --git a/griffin/griffin.c b/griffin/griffin.c index 9d8c02a606..969f75f4d8 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -897,6 +897,7 @@ AUDIO #elif defined(_3DS) #include "../audio/drivers/ctr_csnd_audio.c" #include "../audio/drivers/ctr_dsp_audio.c" +#include "../audio/drivers/ctr_dsp_thread_audio.c" #endif #ifdef HAVE_XAUDIO diff --git a/libretro-common/features/features_cpu.c b/libretro-common/features/features_cpu.c index a0dda815d2..0ad815e2a0 100644 --- a/libretro-common/features/features_cpu.c +++ b/libretro-common/features/features_cpu.c @@ -234,6 +234,8 @@ retro_time_t cpu_features_get_time_usec(void) return ticks_to_us(OSGetSystemTime()); #elif defined(SWITCH) || defined(HAVE_LIBNX) return (svcGetSystemTick() * 10) / 192; +#elif defined(_3DS) + return osGetTime() * 1000; #elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__) || defined(DJGPP) struct timespec tv = {0}; if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0) @@ -245,8 +247,6 @@ retro_time_t cpu_features_get_time_usec(void) return ps2_clock() / PS2_CLOCKS_PER_MSEC * 1000; #elif defined(VITA) || defined(PSP) return sceKernelGetSystemTimeWide(); -#elif defined(_3DS) - return osGetTime() * 1000; #else #error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue." #endif diff --git a/libretro-common/rthreads/ctr_pthread.h b/libretro-common/rthreads/ctr_pthread.h index 41e0fc2513..985a3648ef 100644 --- a/libretro-common/rthreads/ctr_pthread.h +++ b/libretro-common/rthreads/ctr_pthread.h @@ -30,14 +30,24 @@ #include #include -#define STACKSIZE (4 * 1024) +#define STACKSIZE (32 * 1024) + +#ifndef PTHREAD_SCOPE_PROCESS +/* An earlier version of devkitARM does not define the pthread types. Can remove in r54+. */ typedef Thread pthread_t; typedef LightLock pthread_mutex_t; typedef void* pthread_mutexattr_t; typedef int pthread_attr_t; -typedef LightEvent pthread_cond_t; +typedef uint32_t pthread_cond_t; typedef int pthread_condattr_t; +#endif + +typedef struct { + uint32_t semaphore; + LightLock lock; + uint32_t waiting; +} cond_t; /* libctru threads return void but pthreads return void pointer */ static bool mutex_inited = false; @@ -56,11 +66,18 @@ static INLINE int pthread_create(pthread_t *thread, { s32 prio = 0; Thread new_ctr_thread; + int procnum = -2; // use default cpu + bool isNew3DS; + + APT_CheckNew3DS(&isNew3DS); + + if (isNew3DS) + procnum = 2; if (!mutex_inited) { - LightLock_Init(&safe_double_thread_launch); - mutex_inited = true; + LightLock_Init(&safe_double_thread_launch); + mutex_inited = true; } /*Must wait if attempting to launch 2 threads at once to prevent corruption of function pointer*/ @@ -69,27 +86,27 @@ static INLINE int pthread_create(pthread_t *thread, svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); start_routine_jump = start_routine; - new_ctr_thread = threadCreate(ctr_thread_launcher, arg, STACKSIZE, prio - 1, -1/*No affinity, use any CPU*/, false); + new_ctr_thread = threadCreate(ctr_thread_launcher, arg, STACKSIZE, prio - 1, procnum, false); if (!new_ctr_thread) { - LightLock_Unlock(&safe_double_thread_launch); - return EAGAIN; + LightLock_Unlock(&safe_double_thread_launch); + return EAGAIN; } - *thread = new_ctr_thread; + *thread = (pthread_t)new_ctr_thread; return 0; } static INLINE pthread_t pthread_self(void) { - return threadGetCurrent(); + return (pthread_t)threadGetCurrent(); } static INLINE int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) { - LightLock_Init(mutex); + LightLock_Init((LightLock *)mutex); return 0; } @@ -101,12 +118,13 @@ static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex) static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex) { - return LightLock_TryLock(mutex); + LightLock_Lock((LightLock *)mutex); + return 0; } static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex) { - LightLock_Unlock(mutex); + LightLock_Unlock((LightLock *)mutex); return 0; } @@ -115,6 +133,8 @@ static INLINE void pthread_exit(void *retval) /*Yes the pointer to int cast is not ideal*/ /*threadExit((int)retval);*/ (void)retval; + + threadExit(0); } static INLINE int pthread_detach(pthread_t thread) @@ -127,68 +147,131 @@ static INLINE int pthread_detach(pthread_t thread) static INLINE int pthread_join(pthread_t thread, void **retval) { /*retval is ignored*/ - return threadJoin(thread, U64_MAX); + if(threadJoin((Thread)thread, INT64_MAX)) + return -1; + + threadFree((Thread)thread); + + return 0; } static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex) { - return LightLock_TryLock(mutex); + return LightLock_TryLock((LightLock *)mutex); } static INLINE int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { - LightEvent_Wait(cond); + cond_t *cond_data = (cond_t *)*cond; + LightLock_Lock(&cond_data->lock); + cond_data->waiting++; + LightLock_Unlock(mutex); + LightLock_Unlock(&cond_data->lock); + svcWaitSynchronization(cond_data->semaphore, INT64_MAX); + LightLock_Lock(mutex); return 0; } static INLINE int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { - for (;;) - { - struct timespec now = {0}; - /* Missing clock_gettime*/ - struct timeval tm; + struct timespec now = {0}; + /* Missing clock_gettime*/ + struct timeval tm; + int retval = 0; - gettimeofday(&tm, NULL); - now.tv_sec = tm.tv_sec; - now.tv_nsec = tm.tv_usec * 1000; - if (LightEvent_TryWait(cond) != 0 || now.tv_sec > abstime->tv_sec || (now.tv_sec == abstime->tv_sec && now.tv_nsec > abstime->tv_nsec)) - break; + cond_t *cond_data = (cond_t *)*cond; + LightLock_Lock(&cond_data->lock); + cond_data->waiting++; + + gettimeofday(&tm, NULL); + now.tv_sec = tm.tv_sec; + now.tv_nsec = tm.tv_usec * 1000; + s64 timeout = (abstime->tv_sec - now.tv_sec) * 1000000000 + (abstime->tv_nsec - now.tv_nsec); + + if (timeout >= 0) { + LightLock_Unlock(mutex); + LightLock_Unlock(&cond_data->lock); + if (svcWaitSynchronization(cond_data->semaphore, timeout)) + retval = ETIMEDOUT; + + LightLock_Lock(mutex); + } else { + retval = ETIMEDOUT; } - return 0; + return retval; } static INLINE int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) { - LightEvent_Init(cond, RESET_ONESHOT); + cond_t *cond_data = calloc(1, sizeof(cond_t)); + if (!cond_data) + goto error; + + if (svcCreateSemaphore(&cond_data->semaphore, 0, 1)) + goto error; + + LightLock_Init(&cond_data->lock); + cond_data->waiting = 0; + *cond = (pthread_cond_t)cond_data; return 0; + + error: + svcCloseHandle(cond_data->semaphore); + if (cond_data) + free(cond_data); + return -1; } static INLINE int pthread_cond_signal(pthread_cond_t *cond) { - LightEvent_Signal(cond); + int32_t count; + cond_t *cond_data = (cond_t *)*cond; + LightLock_Lock(&cond_data->lock); + if (cond_data->waiting) { + cond_data->waiting--; + LightLock_Unlock(&cond_data->lock); + svcReleaseSemaphore(&count, cond_data->semaphore, 1); + } else { + LightLock_Unlock(&cond_data->lock); + } return 0; } static INLINE int pthread_cond_broadcast(pthread_cond_t *cond) { - LightEvent_Signal(cond); + int32_t count; + cond_t *cond_data = (cond_t *)*cond; + LightLock_Lock(&cond_data->lock); + while (cond_data->waiting) { + cond_data->waiting--; + LightLock_Unlock(&cond_data->lock); + svcReleaseSemaphore(&count, cond_data->semaphore, 1); + LightLock_Lock(&cond_data->lock); + } + LightLock_Unlock(&cond_data->lock); + return 0; } static INLINE int pthread_cond_destroy(pthread_cond_t *cond) { - /*nothing to destroy*/ + if (*cond) { + cond_t *cond_data = (cond_t *)*cond; + + svcCloseHandle(cond_data->semaphore); + free(cond_data); + } + *cond = 0; return 0; } static INLINE int pthread_equal(pthread_t t1, pthread_t t2) { - if (threadGetHandle(t1) == threadGetHandle(t2)) + if (threadGetHandle((Thread)t1) == threadGetHandle((Thread)t2)) return 1; return 0; } diff --git a/libretro-common/vfs/vfs_implementation.c b/libretro-common/vfs/vfs_implementation.c index 96390a1d1c..637b873d99 100644 --- a/libretro-common/vfs/vfs_implementation.c +++ b/libretro-common/vfs/vfs_implementation.c @@ -446,7 +446,14 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl( */ /* TODO: this is only useful for a few platforms, * find which and add ifdef */ -#if !defined(PSP) +#if defined(_3DS) + if (stream->scheme != VFS_SCHEME_CDROM) + { + stream->buf = (char*)calloc(1, 0x10000); + if (stream->fp) + setvbuf(stream->fp, stream->buf, _IOFBF, 0x10000); + } +#elif !defined(PSP) if (stream->scheme != VFS_SCHEME_CDROM) { stream->buf = (char*)calloc(1, 0x4000); diff --git a/pkg/ctr/tools/makerom-linux b/pkg/ctr/tools/makerom-linux index f3f6cd5469..b9580da614 100755 Binary files a/pkg/ctr/tools/makerom-linux and b/pkg/ctr/tools/makerom-linux differ diff --git a/pkg/ctr/tools/makerom-mac b/pkg/ctr/tools/makerom-mac index 8d246131bd..d95560721c 100755 Binary files a/pkg/ctr/tools/makerom-mac and b/pkg/ctr/tools/makerom-mac differ diff --git a/pkg/ctr/tools/makerom.exe b/pkg/ctr/tools/makerom.exe index b8741b7f75..6073c403d7 100755 Binary files a/pkg/ctr/tools/makerom.exe and b/pkg/ctr/tools/makerom.exe differ diff --git a/retroarch.c b/retroarch.c index 3a6907b8d4..f183993631 100644 --- a/retroarch.c +++ b/retroarch.c @@ -379,6 +379,7 @@ static const audio_driver_t *audio_drivers[] = { #ifdef _3DS &audio_ctr_csnd, &audio_ctr_dsp, + &audio_ctr_dsp_thread, #endif #ifdef SWITCH &audio_switch, @@ -38776,6 +38777,13 @@ static enum runloop_state runloop_check_state( return RUNLOOP_STATE_QUIT; #endif +#ifdef _3DS + /* Should be called once per frame */ + if (!aptMainLoop()) + return RUNLOOP_STATE_QUIT; +#endif + + BIT256_CLEAR_ALL_PTR(¤t_bits); p_rarch->input_driver_block_libretro_input = false; diff --git a/retroarch.h b/retroarch.h index 4021f75847..d4005c5eff 100644 --- a/retroarch.h +++ b/retroarch.h @@ -605,6 +605,7 @@ extern audio_driver_t audio_psp; extern audio_driver_t audio_ps2; extern audio_driver_t audio_ctr_csnd; extern audio_driver_t audio_ctr_dsp; +extern audio_driver_t audio_ctr_dsp_thread; extern audio_driver_t audio_switch; extern audio_driver_t audio_switch_thread; extern audio_driver_t audio_switch_libnx_audren; diff --git a/tasks/task_save.c b/tasks/task_save.c index 7e95caba7d..d46b39ce2b 100644 --- a/tasks/task_save.c +++ b/tasks/task_save.c @@ -58,7 +58,7 @@ #include "../managers/cheat_manager.h" #endif -#ifdef HAVE_LIBNX +#if defined(HAVE_LIBNX) || defined(_3DS) #define SAVE_STATE_CHUNK 4096 * 10 #else #define SAVE_STATE_CHUNK 4096