From 70587527898345fdb7245be7c8723b338323fceb Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Sun, 15 Oct 2006 11:57:52 +0000 Subject: [PATCH] Removed ugly boosting solutions from playback code and let scheduler handle unboosting instead. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11226 a1c6a512-1295-4272-9138-f99709370657 --- apps/pcmbuf.c | 86 +++++++++++----------------------------- apps/pcmbuf.h | 1 - apps/playback.c | 32 +++------------ firmware/export/config.h | 1 + firmware/export/thread.h | 8 +++- firmware/thread.c | 32 ++++++++++++++- 6 files changed, 67 insertions(+), 93 deletions(-) diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index d8612a4fbc..44f175c67d 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -94,7 +94,6 @@ static size_t pcmbuf_mix_sample IDATA_ATTR; static bool low_latency_mode = false; static bool pcmbuf_flush; -static volatile bool output_completed = false; extern struct thread_entry *codec_thread_p; @@ -109,44 +108,6 @@ static bool prepare_insert(size_t length); static void pcmbuf_under_watermark(void); static bool pcmbuf_flush_fillpos(void); -#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && !defined(SIMULATOR) -void pcmbuf_boost(bool state) -{ - static bool boost_state = false; -#ifdef HAVE_PRIORITY_SCHEDULING - static bool priority_modified = false; -#endif - - if (crossfade_init || crossfade_active) - return; - - if (state != boost_state) - { - cpu_boost_id(state, CPUBOOSTID_PCMBUF); - boost_state = state; - } - -#ifdef HAVE_PRIORITY_SCHEDULING - if (state && LOW_DATA(2) && pcm_is_playing()) - { - if (!priority_modified) - { - /* Buffer is critically low so override UI priority. */ - priority_modified = true; - thread_set_priority(codec_thread_p, PRIORITY_REALTIME); - } - } - else if (priority_modified) - { - /* Set back the original priority. */ - thread_set_priority(codec_thread_p, PRIORITY_PLAYBACK); - priority_modified = false; - } - -#endif -} -#endif - #define CALL_IF_EXISTS(function, args...) if (function) function(args) /* This function has 2 major logical parts (separated by brackets both for * readability and variable scoping). The first part performs the @@ -204,7 +165,6 @@ process_new_buffer: *realsize = 0; *realstart = NULL; CALL_IF_EXISTS(pcmbuf_event_handler); - output_completed = true; } } } @@ -268,8 +228,25 @@ static inline void pcmbuf_add_chunk(void) static void pcmbuf_under_watermark(void) { +#ifdef HAVE_PRIORITY_SCHEDULING + static int old_priority = 0; + + if (LOW_DATA(2) && !old_priority && pcm_is_playing()) + { + /* Buffer is critically low so override UI priority. */ + old_priority = thread_set_priority(codec_thread_p, PRIORITY_REALTIME); + } + else if (old_priority) + { + /* Set back the original priority. */ + thread_set_priority(codec_thread_p, old_priority); + old_priority = 0; + } +#endif + /* Fill audio buffer by boosting cpu */ - pcmbuf_boost(true); + trigger_cpu_boost(); + /* Disable crossfade if < .5s of audio */ if (LOW_DATA(2)) { @@ -328,17 +305,16 @@ bool pcmbuf_crossfade_init(bool manual_skip) return false; } + trigger_cpu_boost(); + /* Not enough data, or crossfade disabled, flush the old data instead */ if (LOW_DATA(2) || !pcmbuf_is_crossfade_enabled() || low_latency_mode) { - pcmbuf_boost(true); pcmbuf_flush_fillpos(); pcmbuf_flush = true; return false; } - pcmbuf_boost(true); - /* Don't enable mix mode when skipping tracks manually. */ if (manual_skip) crossfade_mixmode = false; @@ -371,9 +347,6 @@ void pcmbuf_play_stop(void) crossfade_init = false; crossfade_active = false; pcmbuf_flush = false; - - pcmbuf_boost(false); - } int pcmbuf_used_descs(void) { @@ -433,7 +406,7 @@ void pcmbuf_pause(bool pause) { pcm_play_pause(!pause); if (!pause) pcm_mute(false); - pcmbuf_boost(!pause && pcm_is_playing()); + trigger_cpu_boost(); } /* Force playback. */ @@ -466,8 +439,6 @@ static bool pcmbuf_flush_fillpos(void) if (audiobuffer_fillpos) { /* Never use the last buffer descriptor */ while (pcmbuf_write == pcmbuf_write_end) { - /* Deboost to let the playback catchup */ - pcmbuf_boost(false); /* If this happens, something is being stupid */ if (!pcm_is_playing()) { logf("pcmbuf_flush_fillpos error"); @@ -762,14 +733,12 @@ static bool prepare_insert(size_t length) /* Need to save PCMBUF_MIN_CHUNK to prevent wrapping overwriting */ if (pcmbuf_free() < length + PCMBUF_MIN_CHUNK) - { - pcmbuf_boost(false); return false; - } if (!pcm_is_playing()) { - pcmbuf_boost(true); + trigger_cpu_boost(); + /* Pre-buffer 1s. */ #if MEM <= 1 if (!LOW_DATA(1)) @@ -1031,12 +1000,3 @@ bool pcmbuf_is_crossfade_enabled(void) return crossfade_enabled; } -bool pcmbuf_output_completed(void) -{ - if (output_completed) - { - output_completed = false; - return true; - } - return false; -} diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h index 2106968368..b5035f4405 100644 --- a/apps/pcmbuf.h +++ b/apps/pcmbuf.h @@ -46,7 +46,6 @@ size_t get_pcmbuf_descsize(void); void pcmbuf_pause(bool pause); void pcmbuf_play_stop(void); bool pcmbuf_is_crossfade_active(void); -bool pcmbuf_output_completed(void); /* These functions are for playing chained buffers of PCM data */ #if defined(HAVE_ADJUSTABLE_CPU_FREQ) && !defined(SIMULATOR) diff --git a/apps/playback.c b/apps/playback.c index 44aa8696fc..feba1d1c6c 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -292,11 +292,6 @@ struct voice_info { char *buf; }; -#ifdef HAVE_ADJUSTABLE_CPU_FREQ -static void voice_boost_cpu(bool state); -#else -#define voice_boost_cpu(state) do { } while(0) -#endif static void voice_thread(void); #endif /* PLAYBACK_VOICE */ @@ -316,7 +311,7 @@ void mp3_play_data(const unsigned char* start, int size, LOGFQUEUE("mp3 > voice Q_VOICE_PLAY"); queue_post(&voice_queue, Q_VOICE_PLAY, &voice_clip); voice_thread_start = true; - voice_boost_cpu(true); + trigger_cpu_boost(); #else (void) start; (void) size; @@ -815,19 +810,6 @@ static const char * get_codec_filename(int enc_spec) #ifdef PLAYBACK_VOICE -#ifdef HAVE_ADJUSTABLE_CPU_FREQ -static void voice_boost_cpu(bool state) -{ - static bool voice_cpu_boosted = false; - - if (state != voice_cpu_boosted) - { - voice_cpu_boosted = state; - cpu_boost_id(state, CPUBOOSTID_PLAYBACK_VOICE); - } -} -#endif - static bool voice_pcmbuf_insert_split_callback( const void *ch1, const void *ch2, size_t length) { @@ -976,7 +958,6 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) voice_getmore = NULL; voice_remaining = 0; voicebuf = NULL; - voice_boost_cpu(false); /* Force the codec to think it's changing tracks */ ci_voice.new_track = 1; @@ -1005,7 +986,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) /* Set up new voice data */ struct voice_info *voice_data; voice_is_playing = true; - voice_boost_cpu(true); + trigger_cpu_boost(); voice_data = ev.data; voice_remaining = voice_data->size; voicebuf = voice_data->buf; @@ -1666,7 +1647,7 @@ static bool codec_load_next_track(void) automatic_skip = true; } - cpu_boost_id(true, CPUBOOSTID_PLAYBACK_CODEC); + trigger_cpu_boost(); LOGFQUEUE("codec > audio Q_AUDIO_CHECK_NEW_TRACK"); queue_post(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0); while (1) @@ -1680,7 +1661,7 @@ static bool codec_load_next_track(void) else break; } - cpu_boost_id(false, CPUBOOSTID_PLAYBACK_CODEC); + switch (ev.id) { case Q_CODEC_REQUEST_COMPLETE: @@ -2153,7 +2134,7 @@ static void audio_read_file(bool quick) return ; } - cpu_boost_id(true, CPUBOOSTID_PLAYBACK_AUDIO); + trigger_cpu_boost(); while (tracks[track_widx].filerem > 0) { int overlap; @@ -2218,7 +2199,6 @@ static void audio_read_file(bool quick) logf("Partially buf:%dB", tracks[track_widx].filesize - tracks[track_widx].filerem); } - cpu_boost_id(false, CPUBOOSTID_PLAYBACK_AUDIO); } static bool audio_loadcodec(bool start_play) @@ -3338,8 +3318,6 @@ static void audio_thread(void) case SYS_TIMEOUT: LOGFQUEUE("audio < SYS_TIMEOUT"); - if (pcmbuf_output_completed()) - pcmbuf_play_stop(); /* Stop to ensure unboosted */ break; default: diff --git a/firmware/export/config.h b/firmware/export/config.h index 1b756cc6bd..6a3091de30 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -222,6 +222,7 @@ #if (CONFIG_CODEC == SWCODEC) && !defined(SIMULATOR) && !defined(BOOTLOADER) #define HAVE_PRIORITY_SCHEDULING +#define HAVE_SCHEDULER_BOOSTCTRL #endif /* define for all cpus from coldfire family */ diff --git a/firmware/export/thread.h b/firmware/export/thread.h index cd532c8968..17e6e3aa88 100644 --- a/firmware/export/thread.h +++ b/firmware/export/thread.h @@ -131,12 +131,18 @@ struct thread_entry* const char *name IF_PRIO(, int priority)); +#ifdef HAVE_SCHEDULER_BOOSTCTRL +void trigger_cpu_boost(void); +#else +#define trigger_cpu_boost() +#endif + void remove_thread(struct thread_entry *thread); void switch_thread(bool save_context, struct thread_entry **blocked_list); void sleep_thread(int ticks); void block_thread(struct thread_entry **thread, int timeout); void wakeup_thread(struct thread_entry **thread); -void thread_set_priority(struct thread_entry *thread, int priority); +int thread_set_priority(struct thread_entry *thread, int priority); void init_threads(void); int thread_stack_usage(const struct thread_entry *thread); int thread_get_status(const struct thread_entry *thread); diff --git a/firmware/thread.c b/firmware/thread.c index 205375a44d..6a94a52333 100644 --- a/firmware/thread.c +++ b/firmware/thread.c @@ -35,6 +35,9 @@ struct core_entry cores[NUM_CORES] IBSS_ATTR; #ifdef HAVE_PRIORITY_SCHEDULING static unsigned short highest_priority IBSS_ATTR; #endif +#ifdef HAVE_SCHEDULER_BOOSTCTRL +static bool cpu_boosted IBSS_ATTR; +#endif /* Define to enable additional checks for blocking violations etc. */ // #define THREAD_EXTRA_CHECKS @@ -332,6 +335,14 @@ static inline void sleep_core(void) if (cores[CURRENT_CORE].running != NULL) break; +#ifdef HAVE_SCHEDULER_BOOSTCTRL + if (cpu_boosted) + { + cpu_boost(false); + cpu_boosted = false; + } +#endif + /* Enter sleep mode to reduce power usage, woken up on interrupt */ #ifdef CPU_COLDFIRE asm volatile ("stop #0x2000"); @@ -646,6 +657,17 @@ struct thread_entry* return thread; } +#ifdef HAVE_SCHEDULER_BOOSTCTRL +void trigger_cpu_boost(void) +{ + if (!cpu_boosted) + { + cpu_boost(true); + cpu_boosted = true; + } +} +#endif + /*--------------------------------------------------------------------------- * Remove a thread on the current core from the scheduler. * Parameter is the ID as returned from create_thread(). @@ -676,13 +698,18 @@ void remove_thread(struct thread_entry *thread) } #ifdef HAVE_PRIORITY_SCHEDULING -void thread_set_priority(struct thread_entry *thread, int priority) +int thread_set_priority(struct thread_entry *thread, int priority) { + int old_priority; + if (thread == NULL) thread = cores[CURRENT_CORE].running; + old_priority = thread->priority; thread->priority = priority; highest_priority = 100; + + return old_priority; } #endif @@ -698,6 +725,9 @@ void init_threads(void) #ifdef HAVE_PRIORITY_SCHEDULING cores[core].threads[0].priority = PRIORITY_USER_INTERFACE; highest_priority = 100; +#endif +#ifdef HAVE_SCHEDULER_BOOSTCTRL + cpu_boosted = false; #endif add_to_list(&cores[core].running, &cores[core].threads[0]);