From 8a62d5ea9656061eae1101e729338d06998283dd Mon Sep 17 00:00:00 2001 From: FIX94 Date: Mon, 21 Nov 2016 03:18:48 +0100 Subject: [PATCH] (WiiU) massive changes in the audio driver, this should hopefully work better (WiiU) making sure the menu is properly drawn before swapping buffers, fixes visible menu drawing lines --- audio/drivers/wiiu_audio.c | 147 ++++++++++++++++++++++++++----------- gfx/drivers/wiiu_gfx.c | 4 +- 2 files changed, 106 insertions(+), 45 deletions(-) diff --git a/audio/drivers/wiiu_audio.c b/audio/drivers/wiiu_audio.c index 540126bbda..ea694a5cd8 100644 --- a/audio/drivers/wiiu_audio.c +++ b/audio/drivers/wiiu_audio.c @@ -25,7 +25,7 @@ #include #include #include - +#include #include "wiiu/wiiu_dbg.h" #include "wiiu/system/memory.h" @@ -44,16 +44,20 @@ typedef struct bool nonblocking; uint32_t pos; + uint32_t written; + OSSpinLock spinlock; } ax_audio_t; -#define AX_AUDIO_COUNT_SHIFT 13u +//4096 samples main buffer, 85ms total +#define AX_AUDIO_COUNT_SHIFT 12u #define AX_AUDIO_COUNT (1u << AX_AUDIO_COUNT_SHIFT) #define AX_AUDIO_COUNT_MASK (AX_AUDIO_COUNT - 1u) #define AX_AUDIO_SIZE (AX_AUDIO_COUNT << 1u) #define AX_AUDIO_SIZE_MASK (AX_AUDIO_SIZE - 1u) -//#define AX_AUDIO_FRAME_COUNT 144 -#define AX_AUDIO_FRAME_COUNT 160 +#define AX_AUDIO_SAMPLE_COUNT 144 //3ms +#define AX_AUDIO_SAMPLE_MIN (AX_AUDIO_SAMPLE_COUNT * 6) //18ms +#define AX_AUDIO_SAMPLE_LOAD (AX_AUDIO_SAMPLE_COUNT * 8) //24ms #define AX_AUDIO_RATE 48000 //#define ax_audio_ticks_to_samples(ticks) (((ticks) * 64) / 82875) //#define ax_audio_samples_to_ticks(samples) (((samples) * 82875) / 64) @@ -65,15 +69,16 @@ static inline int ax_diff(int v1, int v2) AXResult ax_aux_callback(void* data, ax_audio_t* ax) { - AXVoiceOffsets offsets; - AXGetVoiceOffsets(ax->voice_l, &offsets); - - if (ax_diff(offsets.currentOffset, ax->pos) < 0) + OSUninterruptibleSpinLock_Acquire(&ax->spinlock); + //buffer underrun, stop playback to let if fill up + if(ax->written < AX_AUDIO_SAMPLE_MIN) { AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_STOPPED); AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_STOPPED); } - + else //all good, play back frame + ax->written -= AX_AUDIO_SAMPLE_COUNT; + OSUninterruptibleSpinLock_Release(&ax->spinlock); return AX_RESULT_SUCCESS; } @@ -99,6 +104,10 @@ static void* ax_audio_init(const char* device, unsigned rate, unsigned latency) ax->buffer_l = MEM1_alloc(AX_AUDIO_SIZE, 0x100); ax->buffer_r = MEM1_alloc(AX_AUDIO_SIZE, 0x100); + memset(ax->buffer_l,0,AX_AUDIO_SIZE); + memset(ax->buffer_r,0,AX_AUDIO_SIZE); + DCFlushRange(ax->buffer_l,AX_AUDIO_SIZE); + DCFlushRange(ax->buffer_r,AX_AUDIO_SIZE); AXVoiceOffsets offsets; @@ -133,11 +142,14 @@ static void* ax_audio_init(const char* device, unsigned rate, unsigned latency) AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_STOPPED); ax->pos = 0; + ax->written = 0; config_get_ptr()->audio.out_rate = AX_AUDIO_RATE; AXRegisterAuxCallback(AX_DEVICE_TYPE_DRC, 0, 0, (AXAuxCallback)ax_aux_callback, ax); + OSInitSpinLock(&ax->spinlock); + return ax; } @@ -184,7 +196,7 @@ static void ax_audio_buffer_write(ax_audio_t* ax, const uint16_t* src, int count ax->pos &= AX_AUDIO_COUNT_MASK; } - +static bool ax_audio_start(void* data); static ssize_t ax_audio_write(void* data, const void* buf, size_t size) { static struct retro_perf_counter ax_audio_write_perf = {0}; @@ -196,48 +208,79 @@ static ssize_t ax_audio_write(void* data, const void* buf, size_t size) performance_counter_start(&ax_audio_write_perf); int count = size >> 2; - AXVoiceOffsets offsets; - AXGetVoiceOffsets(ax->voice_l, &offsets); - - if((((offsets.currentOffset - ax->pos) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 2)) || - (((ax->pos - offsets.currentOffset ) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 4)) || - (((offsets.currentOffset - ax->pos) & AX_AUDIO_COUNT_MASK) < (size >> 2))) + if(count == 0 || (size % 4)) { - if (ax->nonblocking) - ax->pos = (offsets.currentOffset + (AX_AUDIO_COUNT >> 1)) & AX_AUDIO_COUNT_MASK; - else - { - do{ - retro_sleep(1); - AXGetVoiceOffsets(ax->voice_l, &offsets); - }while(AXIsVoiceRunning(ax->voice_l) && - (((offsets.currentOffset - ax->pos) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 1) || - (((ax->pos - offsets.currentOffset) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 4)))); - } + count = 0; + goto wiiu_audio_end; } + size_t countAvail = AX_AUDIO_COUNT - ax->written; + if (ax->nonblocking) + { + if(countAvail < AX_AUDIO_SAMPLE_COUNT) + { + count = 0; + goto wiiu_audio_end; + } + if(count > countAvail) + count = countAvail; + } + else if(countAvail < count) + { + //sync, wait for free memory + do { + OSYieldThread(); + countAvail = AX_AUDIO_COUNT - ax->written; + } while(AXIsVoiceRunning(ax->voice_l) && countAvail < count && countAvail < AX_AUDIO_SAMPLE_COUNT); + } // ax_audio_buffer_write(ax, buf, count); - - for (i = 0; i < (size >> 1); i += 2) + //write in new data + size_t startPos = ax->pos; + int flushP2needed = 0; + int flushP2 = 0; + for (i = 0; i < (count << 1); i += 2) { ax->buffer_l[ax->pos] = src[i]; ax->buffer_r[ax->pos] = src[i + 1]; ax->pos++; ax->pos &= AX_AUDIO_COUNT_MASK; + //wrapped around, make sure to store cache + if(ax->pos == 0) + { + flushP2needed = 1; + flushP2 = ((count << 1) - i); + DCStoreRangeNoSync(ax->buffer_l+startPos, (AX_AUDIO_COUNT-startPos) << 1); + DCStoreRangeNoSync(ax->buffer_r+startPos, (AX_AUDIO_COUNT-startPos) << 1); + } } - DCFlushRange(ax->buffer_l, AX_AUDIO_SIZE); - DCFlushRange(ax->buffer_r, AX_AUDIO_SIZE); + //standard cache store case + if(!flushP2needed) + { + DCStoreRangeNoSync(ax->buffer_l+startPos, count << 1); + DCStoreRange(ax->buffer_r+startPos, count << 1); + } //store the rest after wrap + else if(flushP2 > 0) + { + DCStoreRangeNoSync(ax->buffer_l, flushP2); + DCStoreRange(ax->buffer_r, flushP2); + } + //add in new audio data + OSUninterruptibleSpinLock_Acquire(&ax->spinlock); + ax->written += count; + OSUninterruptibleSpinLock_Release(&ax->spinlock); -// if(!AXIsVoiceRunning(ax->voice_l) && (((ax->pos - offsets.currentOffset) & AX_AUDIO_COUNT_MASK) > AX_AUDIO_FRAME_COUNT)) -// { - AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_PLAYING); - AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_PLAYING); -// } + //possibly buffer underrun + if(!AXIsVoiceRunning(ax->voice_l)) + { + //checks if it can be started + ax_audio_start(ax); + } +wiiu_audio_end: performance_counter_stop(&ax_audio_write_perf); - return size; + return (count << 2); } static bool ax_audio_stop(void* data) @@ -265,8 +308,25 @@ static bool ax_audio_start(void* data) if (runloop_ctl(RUNLOOP_CTL_IS_SHUTDOWN, NULL)) return true; - AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_PLAYING); - AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_PLAYING); + //for safety first + ax_audio_stop(data); + + //reset offset to last load offset + AXVoiceOffsets offsets; + uint32_t lastOffset = ((ax->pos - ((ax->written)<<1)) & AX_AUDIO_COUNT_MASK); + AXGetVoiceOffsets(ax->voice_l, &offsets); + offsets.currentOffset = lastOffset; + AXSetVoiceOffsets(ax->voice_l, &offsets); + AXGetVoiceOffsets(ax->voice_r, &offsets); + offsets.currentOffset = lastOffset; + AXSetVoiceOffsets(ax->voice_r, &offsets); + + //set back to playing on enough buffered data + if(ax->written > AX_AUDIO_SAMPLE_MIN) + { + AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_PLAYING); + AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_PLAYING); + } return true; } @@ -276,7 +336,11 @@ static void ax_audio_set_nonblock_state(void* data, bool state) ax_audio_t* ax = (ax_audio_t*)data; if (ax) + { + if(state != ax->nonblocking) + ax_audio_start(data); ax->nonblocking = state; + } } static bool ax_audio_use_float(void* data) @@ -289,10 +353,9 @@ static size_t ax_audio_write_avail(void* data) { ax_audio_t* ax = (ax_audio_t*)data; - AXVoiceOffsets offsets; - AXGetVoiceOffsets(ax->voice_l, &offsets); + size_t ret = AX_AUDIO_COUNT - ax->written; - return (offsets.currentOffset - ax->pos) & AX_AUDIO_COUNT_MASK; + return (ret < AX_AUDIO_SAMPLE_COUNT ? 0 : ret); } static size_t ax_audio_buffer_size(void* data) diff --git a/gfx/drivers/wiiu_gfx.c b/gfx/drivers/wiiu_gfx.c index 465ae5a06f..ae98ff6cbf 100644 --- a/gfx/drivers/wiiu_gfx.c +++ b/gfx/drivers/wiiu_gfx.c @@ -582,16 +582,13 @@ static bool wiiu_gfx_frame(void* data, const void* frame, printf("\rfps: %8.8f frames : %5i", fps, wiiu->frames++); fflush(stdout); - if (wiiu->should_resize) wiiu_gfx_update_viewport(wiiu); - GX2ClearColor(&wiiu->color_buffer, 0.0f, 0.0f, 0.0f, 1.0f); /* can't call GX2ClearColor after GX2SetContextState for whatever reason */ GX2SetContextState(wiiu->ctx_state); - if(frame) { if (width > wiiu->texture.surface.width) @@ -655,6 +652,7 @@ static bool wiiu_gfx_frame(void* data, const void* frame, GX2SetPixelSampler(&wiiu->sampler_linear, wiiu->shader->sampler.location); GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, 4, 0, 1); + GX2DrawDone(); } GX2CopyColorBufferToScanBuffer(&wiiu->color_buffer, GX2_SCAN_TARGET_DRC);