From 2076846a5c272fcf9e8e150772e5300b37186059 Mon Sep 17 00:00:00 2001 From: aliaspider Date: Fri, 17 Apr 2015 19:45:07 +0100 Subject: [PATCH 1/2] (CTR/3DS) disable v-sync blocking after a missed vblank-start event. will prevent cores running under 60fps from slowing down even more. --- gfx/drivers/ctr_gfx.c | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/gfx/drivers/ctr_gfx.c b/gfx/drivers/ctr_gfx.c index a92bc5a408..8aa241e751 100644 --- a/gfx/drivers/ctr_gfx.c +++ b/gfx/drivers/ctr_gfx.c @@ -228,28 +228,37 @@ static bool ctr_frame(void* data, const void* frame, extern bool select_pressed; - RARCH_PERFORMANCE_INIT(ctrframe_f); - RARCH_PERFORMANCE_START(ctrframe_f); - if (!width || !height) { gspWaitForEvent(GSPEVENT_VBlank0, true); - goto end; + return true; } if(!aptMainLoop()) { event_command(EVENT_CMD_QUIT); - goto end; + return true; } if (select_pressed) { event_command(EVENT_CMD_QUIT); - goto end; + return true; } + svcWaitSynchronization(gspEvents[GSPEVENT_P3D], 20000000); + svcClearEvent(gspEvents[GSPEVENT_P3D]); + svcWaitSynchronization(gspEvents[GSPEVENT_PPF], 20000000); + svcClearEvent(gspEvents[GSPEVENT_PPF]); + + gfxSwapBuffersGpu(); frames++; + + if (ctr->vsync) + svcWaitSynchronization(gspEvents[GSPEVENT_VBlank0], U64_MAX); + + svcClearEvent(gspEvents[GSPEVENT_VBlank0]); + currentTick = svcGetSystemTick(); uint32_t diff = currentTick - lastTick; if(diff > CTR_CPU_TICKS_PER_SECOND) @@ -260,23 +269,10 @@ static bool ctr_frame(void* data, const void* frame, } printf("fps: %8.4f frames: %i\r", fps, total_frames++); -// fflush(stdout); + fflush(stdout); - /* enable this to profile the core without video output */ -#if 0 - if (!ctr->menu_texture_enable) - goto end; -#endif - - svcWaitSynchronization(gspEvents[GSPEVENT_P3D], 20000000); - svcClearEvent(gspEvents[GSPEVENT_P3D]); - svcWaitSynchronization(gspEvents[GSPEVENT_PPF], 20000000); - svcClearEvent(gspEvents[GSPEVENT_PPF]); - - gfxSwapBuffersGpu(); - - if (ctr->vsync) - gspWaitForEvent(GSPEVENT_VBlank0, true); + RARCH_PERFORMANCE_INIT(ctrframe_f); + RARCH_PERFORMANCE_START(ctrframe_f); ctrGuSetMemoryFill(true, (u32*)CTR_GPU_FRAMEBUFFER, 0x00000000, (u32*)(CTR_GPU_FRAMEBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), @@ -363,9 +359,6 @@ static bool ctr_frame(void* data, const void* frame, ctrGuDisplayTransfer(true, CTR_GPU_FRAMEBUFFER, 240,400, CTRGU_RGBA8, gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 240,400,CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE); - -end: -// gspWaitForEvent(GSPEVENT_VBlank0, true); RARCH_PERFORMANCE_STOP(ctrframe_f); return true; } From 1575b7e87f955291f55aaff6f1aa9695fde4556e Mon Sep 17 00:00:00 2001 From: aliaspider Date: Fri, 17 Apr 2015 19:50:36 +0100 Subject: [PATCH 2/2] (CTR/3DS) audio driver: use cpu tick count instead of csndGetState to determine the playback position. fixes a random lockup that can happen when calling csndGetState, and also removes the need to rely on samplePAddr since it doesn't seem to available on all systems. --- audio/drivers/ctr_audio.c | 123 +++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 54 deletions(-) diff --git a/audio/drivers/ctr_audio.c b/audio/drivers/ctr_audio.c index a82f15561c..3c3ba73333 100644 --- a/audio/drivers/ctr_audio.c +++ b/audio/drivers/ctr_audio.c @@ -21,20 +21,24 @@ typedef struct { bool nonblocking; + bool playing; int16_t* l; int16_t* r; - int16_t* silence; uint32_t l_paddr; uint32_t r_paddr; - uint32_t silence_paddr; uint32_t pos; + + uint32_t playpos; + uint32_t cpu_ticks_per_sample; + uint64_t cpu_ticks_last; + int rate; } ctr_audio_t; -#define CTR_AUDIO_COUNT (1u << 12u) +#define CTR_AUDIO_COUNT (1u << 11u) #define CTR_AUDIO_COUNT_MASK (CTR_AUDIO_COUNT - 1u) #define CTR_AUDIO_SIZE (CTR_AUDIO_COUNT * sizeof(int16_t)) #define CTR_AUDIO_SIZE_MASK (CTR_AUDIO_SIZE - 1u) @@ -52,31 +56,30 @@ static void *ctr_audio_init(const char *device, unsigned rate, unsigned latency) ctr_audio_t *ctr = (ctr_audio_t*)calloc(1, sizeof(ctr_audio_t)); - ctr->l = linearAlloc(CTR_AUDIO_SIZE); - ctr->r = linearAlloc(CTR_AUDIO_SIZE); - ctr->silence = linearAlloc(CTR_AUDIO_SIZE); + ctr->l = linearAlloc(CTR_AUDIO_SIZE); + ctr->r = linearAlloc(CTR_AUDIO_SIZE); - memset(ctr->l, 0, CTR_AUDIO_SIZE); - memset(ctr->r, 0, CTR_AUDIO_SIZE); - memset(ctr->silence, 0, CTR_AUDIO_SIZE); + memset(ctr->l, 0, CTR_AUDIO_SIZE); + memset(ctr->r, 0, CTR_AUDIO_SIZE); - ctr->l_paddr = osConvertVirtToPhys((u32)ctr->l); - ctr->r_paddr = osConvertVirtToPhys((u32)ctr->r); - ctr->silence_paddr = osConvertVirtToPhys((u32)ctr->silence); + ctr->l_paddr = osConvertVirtToPhys((u32)ctr->l); + ctr->r_paddr = osConvertVirtToPhys((u32)ctr->r); ctr->pos = 0; ctr->rate = rate; + ctr->cpu_ticks_per_sample = CSND_TIMER(rate) * 4; - GSPGPU_FlushDataCache(NULL, (u8*)ctr->silence, CTR_AUDIO_SIZE); + GSPGPU_FlushDataCache(NULL, (u8*)ctr->l_paddr, CTR_AUDIO_SIZE); + GSPGPU_FlushDataCache(NULL, (u8*)ctr->r_paddr, CTR_AUDIO_SIZE); csndPlaySound(0x8, SOUND_LOOPMODE(CSND_LOOPMODE_NORMAL)| SOUND_FORMAT(CSND_ENCODING_PCM16), - rate, ctr->silence, ctr->silence, CTR_AUDIO_SIZE); + rate, 1.0, -1.0, ctr->l, ctr->l, CTR_AUDIO_SIZE); csndPlaySound(0x9, SOUND_LOOPMODE(CSND_LOOPMODE_NORMAL)| SOUND_FORMAT(CSND_ENCODING_PCM16), - rate, ctr->silence, ctr->silence, CTR_AUDIO_SIZE); + rate, 1.0, 1.0, ctr->r, ctr->r, CTR_AUDIO_SIZE); - CSND_SetVol(0x8, 0xFFFF, 0); - CSND_SetVol(0x9, 0, 0xFFFF); - csndExecCmds(false); + ctr->playpos = 0; + ctr->cpu_ticks_last = svcGetSystemTick(); + ctr->playing = true; return ctr; } @@ -92,7 +95,6 @@ static void ctr_audio_free(void *data) linearFree(ctr->l); linearFree(ctr->r); - linearFree(ctr->silence); free(ctr); } @@ -107,45 +109,35 @@ static ssize_t ctr_audio_write(void *data, const void *buf, size_t size) int i; const uint16_t* src = buf; - RARCH_PERFORMANCE_INIT(ctraudio_f); + RARCH_PERFORMANCE_INIT(ctraudio_f); RARCH_PERFORMANCE_START(ctraudio_f); - CSND_ChnInfo channel_info; - csndGetState(0x8, &channel_info); + uint64_t current_tick = svcGetSystemTick(); + uint32_t samples_played = (current_tick - ctr->cpu_ticks_last) / ctr->cpu_ticks_per_sample; + ctr->playpos = (ctr->playpos + samples_played) & CTR_AUDIO_COUNT_MASK; + ctr->cpu_ticks_last += samples_played * ctr->cpu_ticks_per_sample; - uint32_t playpos; - if((channel_info.samplePAddr >= (ctr->l_paddr)) && - (channel_info.samplePAddr < (ctr->l_paddr + CTR_AUDIO_SIZE))) - { - playpos = (channel_info.samplePAddr - ctr->l_paddr) / sizeof(uint16_t); - } - else - { - CSND_SetBlock(0x8, 1, ctr->l_paddr, CTR_AUDIO_SIZE); - CSND_SetBlock(0x9, 1, ctr->r_paddr, CTR_AUDIO_SIZE); - csndExecCmds(false); - playpos = 0; - } - if((((playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 2)) || - (((ctr->pos - playpos ) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 4)) || - (((playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (size >> 2))) + if((((ctr->playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 2)) || + (((ctr->pos - ctr->playpos ) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 4)) || + (((ctr->playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (size >> 2))) { if (ctr->nonblocking) - ctr->pos = (playpos + (CTR_AUDIO_COUNT >> 1)) & CTR_AUDIO_COUNT_MASK; + ctr->pos = (ctr->playpos + (CTR_AUDIO_COUNT >> 1)) & CTR_AUDIO_COUNT_MASK; else { do{ + /* todo: compute the correct sleep period */ svcSleepThread(100000); -// svcSleepThread(((s64)(CTR_AUDIO_COUNT >> 8) * 1000000000) / ctr->rate); - csndGetState(0x8, &channel_info); - playpos = (channel_info.samplePAddr - ctr->l_paddr) / sizeof(uint16_t); - }while (((playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 1) - || (((ctr->pos - playpos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 4))); + current_tick = svcGetSystemTick(); + samples_played = (current_tick - ctr->cpu_ticks_last) / ctr->cpu_ticks_per_sample; + ctr->playpos = (ctr->playpos + samples_played) & CTR_AUDIO_COUNT_MASK; + ctr->cpu_ticks_last += samples_played * ctr->cpu_ticks_per_sample; + }while (((ctr->playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 1) + || (((ctr->pos - ctr->playpos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 4))); } } - for (i = 0; i < (size >> 1); i += 2) { ctr->l[ctr->pos] = src[i]; @@ -153,6 +145,9 @@ static ssize_t ctr_audio_write(void *data, const void *buf, size_t size) ctr->pos++; ctr->pos &= CTR_AUDIO_COUNT_MASK; } + GSPGPU_FlushDataCache(NULL, (u8*)ctr->l, CTR_AUDIO_SIZE); + GSPGPU_FlushDataCache(NULL, (u8*)ctr->r, CTR_AUDIO_SIZE); + RARCH_PERFORMANCE_STOP(ctraudio_f); @@ -163,31 +158,51 @@ static bool ctr_audio_stop(void *data) { ctr_audio_t* ctr = (ctr_audio_t*)data; - CSND_SetBlock(0x8, 1, ctr->silence_paddr, CTR_AUDIO_SIZE); - CSND_SetBlock(0x9, 1, ctr->silence_paddr, CTR_AUDIO_SIZE); + /* using SetPlayState would make tracking the playback + * position more difficult */ + +// CSND_SetPlayState(0x8, 0); +// CSND_SetPlayState(0x9, 0); + + /* setting the channel volume to 0 seems to make it + * impossible to set it back to full volume later */ + + CSND_SetVol(0x8, 0x00000001, 0); + CSND_SetVol(0x9, 0x00010000, 0); csndExecCmds(false); + ctr->playing = false; + return true; } static bool ctr_audio_alive(void *data) { - (void)data; - return true; + ctr_audio_t* ctr = (ctr_audio_t*)data; + return ctr->playing; } static bool ctr_audio_start(void *data) { ctr_audio_t* ctr = (ctr_audio_t*)data; + global_t *global = global_get_ptr(); -// csndPlaySound(0x8, SOUND_LOOPMODE(CSND_LOOPMODE_NORMAL)| SOUND_FORMAT(CSND_ENCODING_PCM16), -// ctr->rate, ctr->l_paddr + ((ctr->pos + (CTR_AUDIO_SIZE / 2)) & CTR_AUDIO_SIZE_MASK), -// (u32*)ctr->silence_paddr, CTR_AUDIO_SIZE); + /* prevents restarting audio when the menu + * is toggled off on shutdown */ + + if (global->system.shutdown) + return true; + +// CSND_SetPlayState(0x8, 1); +// CSND_SetPlayState(0x9, 1); + + CSND_SetVol(0x8, 0x00008000, 0); + CSND_SetVol(0x9, 0x80000000, 0); - CSND_SetBlock(0x8, 1, ctr->l_paddr, CTR_AUDIO_SIZE); - CSND_SetBlock(0x9, 1, ctr->r_paddr, CTR_AUDIO_SIZE); csndExecCmds(false); + ctr->playing = true; + return true; }