From d8b6a950c67f21d09898fe32d0917d0970dab738 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Wed, 4 Mar 2009 21:23:49 +0000 Subject: FS#9919 pictureflow cache rework, footprint reduction, buflib use git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20203 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/pictureflow.c | 622 ++++++++++++++++++++++++++++----------------- 1 file changed, 383 insertions(+), 239 deletions(-) diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c index 5613ce82bd..cead25c959 100644 --- a/apps/plugins/pictureflow.c +++ b/apps/plugins/pictureflow.c @@ -32,6 +32,7 @@ #include "pluginbitmaps/pictureflow_logo.h" #include "lib/grey.h" #include "lib/feature_wrappers.h" +#include "lib/buflib.h" PLUGIN_HEADER @@ -116,7 +117,7 @@ typedef fb_data pix_t; #define DISPLAY_LEFT_R (PFREAL_HALF - LCD_WIDTH * PFREAL_HALF) #define MAXSLIDE_LEFT_R (PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF) -#define SLIDE_CACHE_SIZE 100 +#define SLIDE_CACHE_SIZE 64 /* probably more than can be loaded */ #define MAX_SLIDES_COUNT 10 @@ -127,8 +128,6 @@ typedef fb_data pix_t; #define EV_WAKEUP 1337 /* maximum number of albums */ -#define MAX_ALBUMS 1024 -#define AVG_ALBUM_NAME_LENGTH 20 #define MAX_TRACKS 50 #define AVG_TRACK_NAME_LENGTH 20 @@ -161,7 +160,8 @@ struct slide_data { struct slide_cache { int index; /* index of the cached slide */ int hid; /* handle ID of the cached slide */ - long touched; /* last time the slide was touched */ + short next; /* "next" slide, with LRU last */ + short prev; /* "previous" slide */ }; struct album_data { @@ -196,7 +196,7 @@ const struct picture logos[]={ {pictureflow_logo, BMPWIDTH_pictureflow_logo, BMPHEIGHT_pictureflow_logo}, }; -enum show_album_name_values { album_name_hide = 0, album_name_bottom , +enum show_album_name_values { album_name_hide = 0, album_name_bottom, album_name_top }; static char* show_album_name_conf[] = { @@ -216,7 +216,8 @@ static int zoom = 100; static bool show_fps = false; static bool resize = true; static int cache_version = 0; -static int show_album_name = (LCD_HEIGHT > 100) ? album_name_top : album_name_bottom; +static int show_album_name = (LCD_HEIGHT > 100) + ? album_name_top : album_name_bottom; static struct configdata config[] = { @@ -239,7 +240,7 @@ static struct configdata config[] = /** below we allocate the memory we want to use **/ static pix_t *buffer; /* for now it always points to the lcd framebuffer */ -static uint16_t reflect_table[REFLECT_HEIGHT]; +static uint8_t reflect_table[REFLECT_HEIGHT]; static struct slide_data center_slide; static struct slide_data left_slides[MAX_SLIDES_COUNT]; static struct slide_data right_slides[MAX_SLIDES_COUNT]; @@ -247,32 +248,34 @@ static int slide_frame; static int step; static int target; static int fade; -static int center_index; /* index of the slide that is in the center */ +static int center_index = 0; /* index of the slide that is in the center */ static int itilt; static PFreal offsetX; static PFreal offsetY; static int number_of_slides; static struct slide_cache cache[SLIDE_CACHE_SIZE]; -static int slide_cache_in_use; +static int cache_free; +static int cache_used = -1; +static int cache_left_index = -1; +static int cache_right_index = -1; +static int cache_center_index = -1; /* use long for aligning */ unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)]; /* queue (as array) for scheduling load_surface */ -static int slide_cache_stack[SLIDE_CACHE_SIZE]; -static int slide_cache_stack_index; -struct mutex slide_cache_stack_lock; static int empty_slide_hid; unsigned int thread_id; struct event_queue thread_q; -static long uniqbuf[UNIQBUF_SIZE]; static struct tagcache_search tcs; -static struct album_data album[MAX_ALBUMS]; -static char album_names[MAX_ALBUMS*AVG_ALBUM_NAME_LENGTH]; +static struct buflib_context buf_ctx; + +static struct album_data *album; +static char *album_names; static int album_count; static char track_names[MAX_TRACKS * AVG_TRACK_NAME_LENGTH]; @@ -333,6 +336,7 @@ static int pf_state; /** code */ static inline pix_t fade_color(pix_t c, unsigned int a); bool save_pfraw(char* filename, struct bitmap *bm); +bool load_new_slide(void); int load_surface(int); static inline PFreal fmul(PFreal a, PFreal b) @@ -398,7 +402,7 @@ static inline int clz(uint32_t v) } #else static const char clz_lut[16] = { 4, 3, 2, 2, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0, 0 }; /* This clz is based on the log2(n) implementation at * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup * It is not any faster than the one above, but trades 16B in the lookup table @@ -472,7 +476,7 @@ static inline PFreal fdiv(PFreal n, PFreal m) #endif /* warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed! */ -static const PFreal sin_tab[] = { +static const short sin_tab[] = { 0, 100, 200, 297, 392, 483, 569, 650, 724, 792, 851, 903, 946, 980, 1004, 1019, 1024, 1019, 1004, 980, 946, 903, 851, 792, @@ -562,30 +566,43 @@ void init_reflect_table(void) */ int create_album_index(void) { + plugin_buf_size -= UNIQBUF_SIZE * sizeof(long); + long *uniqbuf = (long *)(plugin_buf_size + (char *)plugin_buf); + album = ((struct album_data *)uniqbuf) - 1; rb->memset(&tcs, 0, sizeof(struct tagcache_search) ); album_count = 0; rb->tagcache_search(&tcs, tag_album); rb->tagcache_search_set_uniqbuf(&tcs, uniqbuf, UNIQBUF_SIZE); - int l, old_l = 0; + unsigned int l, old_l = 0; + album_names = plugin_buf; album[0].name_idx = 0; - while (rb->tagcache_get_next(&tcs) && album_count < MAX_ALBUMS) + while (rb->tagcache_get_next(&tcs)) { + plugin_buf_size -= sizeof(struct album_data); l = rb->strlen(tcs.result) + 1; if ( album_count > 0 ) - album[album_count].name_idx = album[album_count-1].name_idx + old_l; + album[-album_count].name_idx = album[1-album_count].name_idx + old_l; - if ( (album[album_count].name_idx + l) > - MAX_ALBUMS*AVG_ALBUM_NAME_LENGTH ) + if ( l > plugin_buf_size ) /* not enough memory */ return ERROR_BUFFER_FULL; - rb->strcpy(album_names + album[album_count].name_idx, tcs.result); - album[album_count].seek = tcs.result_seek; + rb->strcpy(plugin_buf, tcs.result); + plugin_buf_size -= l; + plugin_buf = l + (char *)plugin_buf; + album[-album_count].seek = tcs.result_seek; old_l = l; album_count++; } rb->tagcache_search_finish(&tcs); - + ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4); + int i; + struct album_data* tmp_album = (struct album_data*)plugin_buf; + for (i = album_count - 1; i >= 0; i--) + tmp_album[i] = album[-i]; + album = tmp_album; + plugin_buf = album + album_count; + plugin_buf_size += UNIQBUF_SIZE * sizeof(long); return (album_count > 0) ? 0 : ERROR_NO_ALBUMS; } @@ -824,123 +841,6 @@ bool create_albumart_cache(void) return true; } -/** - Return the index on the stack of slide_index. - Return -1 if slide_index is not on the stack. - */ -static inline int slide_stack_get_index(const int slide_index) -{ - int i = slide_cache_stack_index + 1; - while (i--) { - if ( slide_cache_stack[i] == slide_index ) return i; - }; - return -1; -} - -/** - Push the slide_index on the stack so the image will be loaded. - The algorithm tries to keep the center_index on top and the - slide_index as high as possible (so second if center_index is - on the stack). - */ -void slide_stack_push(const int slide_index) -{ - rb->mutex_lock(&slide_cache_stack_lock); - - if ( slide_cache_stack_index == -1 ) { - /* empty stack, no checks at all */ - slide_cache_stack[ ++slide_cache_stack_index ] = slide_index; - rb->mutex_unlock(&slide_cache_stack_lock); - return; - } - - int i = slide_stack_get_index( slide_index ); - - if ( i == slide_cache_stack_index ) { - /* slide_index is on top, so we do not change anything */ - rb->mutex_unlock(&slide_cache_stack_lock); - return; - } - - if ( i >= 0 ) { - /* slide_index is already on the stack, but not on top */ - int tmp = slide_cache_stack[ slide_cache_stack_index ]; - if ( tmp == center_index ) { - /* the center_index is on top of the stack so do not touch that */ - if ( slide_cache_stack_index > 0 ) { - /* - but maybe it is possible to swap the given slide_index to - the second place - */ - tmp = slide_cache_stack[slide_cache_stack_index - 1]; - slide_cache_stack[slide_cache_stack_index - 1] = - slide_cache_stack[i]; - slide_cache_stack[i] = tmp; - } - } - else { - /* - if the center_index is not on top (i.e. already loaded) bring - the slide_index to the top - */ - slide_cache_stack[slide_cache_stack_index] = slide_cache_stack[i]; - slide_cache_stack[i] = tmp; - } - } - else { - /* slide_index is not on the stack */ - if ( slide_cache_stack_index >= SLIDE_CACHE_SIZE-1 ) { - /* - if we exceeded the stack size, clear the first half of the - stack - */ - slide_cache_stack_index = SLIDE_CACHE_SIZE/2; - for (i = 0; i <= slide_cache_stack_index ; i++) - slide_cache_stack[i] = slide_cache_stack[i + - slide_cache_stack_index]; - } - if ( slide_cache_stack[ slide_cache_stack_index ] == center_index ) { - /* if the center_index is on top leave it there */ - slide_cache_stack[ slide_cache_stack_index ] = slide_index; - slide_cache_stack[ ++slide_cache_stack_index ] = center_index; - } - else { - /* usual stack case: push the slide_index on top */ - slide_cache_stack[ ++slide_cache_stack_index ] = slide_index; - } - } - rb->mutex_unlock(&slide_cache_stack_lock); -} - - -/** - Pop the topmost item from the stack and decrease the stack size - */ -static inline int slide_stack_pop(void) -{ - rb->mutex_lock(&slide_cache_stack_lock); - int result; - if ( slide_cache_stack_index >= 0 ) - result = slide_cache_stack[ slide_cache_stack_index-- ]; - else - result = -1; - rb->mutex_unlock(&slide_cache_stack_lock); - return result; -} - - -/** - Load the slide into the cache. - Thus we have to queue the loading request in our thread while discarding the - oldest slide. - */ -static inline void request_surface(const int slide_index) -{ - slide_stack_push(slide_index); - rb->queue_post(&thread_q, EV_WAKEUP, 0); -} - - /** Thread used for loading and preparing bitmaps in the background */ @@ -957,10 +857,8 @@ void thread(void) /* we just woke up */ break; } - int slide_index; - while ( (slide_index = slide_stack_pop()) != -1 ) { - load_surface( slide_index ); - rb->queue_wait_w_tmo(&thread_q, &ev, HZ/10); + while ( load_new_slide() ) { + rb->yield(); switch (ev.id) { case EV_EXIT: return; @@ -999,13 +897,15 @@ bool create_pf_thread(void) sizeof(thread_stack), 0, "Picture load thread" - IF_PRIO(, PRIORITY_BACKGROUND) + IF_PRIO(, MAX(PRIORITY_USER_INTERFACE / 2, + PRIORITY_REALTIME + 1)) IF_COP(, CPU) ) ) == 0) { return false; } thread_is_running = true; + rb->queue_post(&thread_q, EV_WAKEUP, 0); return true; } @@ -1031,45 +931,201 @@ bool save_pfraw(char* filename, struct bitmap *bm) } +/* + * The following functions implement the linked-list-in-array used to manage + * the LRU cache of slides, and the list of free cache slots. + */ + +#define seek_right_while(start, cond) \ +({ \ + int ind_, next_ = (start); \ + do { \ + ind_ = next_; \ + next_ = cache[ind_].next; \ + } while (next_ != cache_used && (cond)); \ + ind_; \ +}) + +#define seek_left_while(start, cond) \ +({ \ + int ind_, next_ = (start); \ + do { \ + ind_ = next_; \ + next_ = cache[ind_].prev; \ + } while (ind_ != cache_used && (cond)); \ + ind_; \ +}) + +/** + Pop the given item from the linked list starting at *head, returning the next + item, or -1 if the list is now empty. +*/ +static inline int lla_pop_item (int *head, int i) +{ + int prev = cache[i].prev; + int next = cache[i].next; + if (i == next) + { + *head = -1; + return -1; + } + else if (i == *head) + *head = next; + cache[next].prev = prev; + cache[prev].next = next; + return next; +} + + +/** + Pop the head item from the list starting at *head, returning the index of the + item, or -1 if the list is already empty. +*/ +static inline int lla_pop_head (int *head) +{ + int i = *head; + if (i != -1) + lla_pop_item(head, i); + return i; +} + +/** + Insert the item at index i before the one at index p. +*/ +static inline void lla_insert (int i, int p) +{ + int next = p; + int prev = cache[next].prev; + cache[next].prev = i; + cache[prev].next = i; + cache[i].next = next; + cache[i].prev = prev; +} + + +/** + Insert the item at index i at the end of the list starting at *head. +*/ +static inline void lla_insert_tail (int *head, int i) +{ + if (*head == -1) + { + *head = i; + cache[i].next = i; + cache[i].prev = i; + } else + lla_insert(i, *head); +} + +/** + Insert the item at index i before the one at index p. +*/ +static inline void lla_insert_after(int i, int p) +{ + p = cache[p].next; + lla_insert(i, p); +} + + +/** + Insert the item at index i before the one at index p in the list starting at + *head +*/ +static inline void lla_insert_before(int *head, int i, int p) +{ + lla_insert(i, p); + if (*head == p) + *head = i; +} + + +/** + Free the used slide at index i, and its buffer, and move it to the free + slides list. +*/ +static inline void free_slide(int i) +{ + if (cache[i].hid != empty_slide_hid) + buflib_free(&buf_ctx, cache[i].hid); + cache[i].index = -1; + lla_pop_item(&cache_used, i); + lla_insert_tail(&cache_free, i); + if (cache_used == -1) + { + cache_right_index = -1; + cache_left_index = -1; + cache_center_index = -1; + } +} + + +/** + Free one slide ranked above the given priority. If no such slide can be found, + return false. +*/ +static inline int free_slide_prio(int prio) +{ + if (cache_used == -1) + return false; + int i, l = cache_used, r = cache[cache_used].prev, prio_max; + int prio_l = cache[l].index < center_index ? + center_index - cache[l].index : 0; + int prio_r = cache[r].index > center_index ? + cache[r].index - center_index : 0; + if (prio_l > prio_r) + { + i = l; + prio_max = prio_l; + } else { + i = r; + prio_max = prio_r; + } + if (prio_max > prio) + { + if (i == cache_left_index) + cache_left_index = cache[i].next; + if (i == cache_right_index) + cache_right_index = cache[i].prev; + free_slide(i); + return true; + } else + return false; +} + /** Read the pfraw image given as filename and return the hid of the buffer */ -int read_pfraw(char* filename) +int read_pfraw(char* filename, int prio) { struct pfraw_header bmph; int fh = rb->open(filename, O_RDONLY); - rb->read(fh, &bmph, sizeof(struct pfraw_header)); - if( fh < 0 ) { + if( fh < 0 ) return empty_slide_hid; - } + else + rb->read(fh, &bmph, sizeof(struct pfraw_header)); int size = sizeof(struct bitmap) + sizeof( pix_t ) * bmph.width * bmph.height; - int hid = rb->bufalloc(NULL, size, TYPE_BITMAP); - if (hid < 0) { - rb->close( fh ); - return -1; - } + int hid; + while (!(hid = buflib_alloc(&buf_ctx, size)) && free_slide_prio(prio)); - struct bitmap *bm; - if (rb->bufgetdata(hid, 0, (void *)&bm) < size) { + if (!hid) { rb->close( fh ); - return -1; + return 0; } + struct dim *bm = buflib_get_data(&buf_ctx, hid); + bm->width = bmph.width; bm->height = bmph.height; -#if LCD_DEPTH > 1 - bm->format = FORMAT_NATIVE; -#endif - bm->data = ((unsigned char *)bm + sizeof(struct bitmap)); + pix_t *data = (pix_t*)(sizeof(struct dim) + (char *)bm); int y; for( y = 0; y < bm->height; y++ ) { - pix_t *d = (pix_t*)( bm->data ) + (y*bm->width); - rb->read( fh, d , sizeof( pix_t ) * bm->width ); + rb->read( fh, data , sizeof( pix_t ) * bm->width ); + data += bm->width; } rb->close( fh ); return hid; @@ -1080,21 +1136,21 @@ int read_pfraw(char* filename) Load the surface for the given slide_index into the cache at cache_index. */ static inline bool load_and_prepare_surface(const int slide_index, - const int cache_index) + const int cache_index, + const int prio) { char tmp_path_name[MAX_PATH+1]; rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw", slide_index); - int hid = read_pfraw(tmp_path_name); - if (hid < 0) + int hid = read_pfraw(tmp_path_name, prio); + if (!hid) return false; cache[cache_index].hid = hid; if ( cache_index < SLIDE_CACHE_SIZE ) { cache[cache_index].index = slide_index; - cache[cache_index].touched = *rb->current_tick; } return true; @@ -1102,48 +1158,129 @@ static inline bool load_and_prepare_surface(const int slide_index, /** - Load the surface from a bmp and overwrite the oldest slide in the cache - if necessary. - */ -int load_surface(const int slide_index) + Load the "next" slide that we can load, freeing old slides if needed, provided + that they are further from center_index than the current slide +*/ +bool load_new_slide(void) { - long oldest_tick = *rb->current_tick; - int oldest_slide = 0; - int i; - if ( slide_cache_in_use < SLIDE_CACHE_SIZE ) { /* initial fill */ - oldest_slide = slide_cache_in_use; - load_and_prepare_surface(slide_index, slide_cache_in_use++); - } - else { - for (i = 0; i < SLIDE_CACHE_SIZE; i++) { /* look for oldest slide */ - if (cache[i].touched < oldest_tick) { - oldest_slide = i; - oldest_tick = cache[i].touched; + int i = -1; + if (cache_center_index != -1) + { + int next, prev; + if (cache[cache_center_index].index != center_index) + { + if (cache[cache_center_index].index < center_index) + { + cache_center_index = seek_right_while(cache_center_index, + cache[next_].index <= center_index); + prev = cache_center_index; + next = cache[cache_center_index].next; + } + else + { + cache_center_index = seek_left_while(cache_center_index, + cache[next_].index >= center_index); + next = cache_center_index; + prev = cache[cache_center_index].prev; + } + if (cache[cache_center_index].index != center_index) + { + if (cache_free == -1) + free_slide_prio(0); + i = lla_pop_head(&cache_free); + if (!load_and_prepare_surface(center_index, i, 0)) + goto fail_and_refree; + if (cache[next].index == -1) + { + if (cache[prev].index == -1) + goto insert_first_slide; + else + next = cache[prev].next; + } + lla_insert(i, next); + if (cache[i].index < cache[cache_used].index) + cache_used = i; + cache_center_index = i; + cache_left_index = i; + cache_right_index = i; + return true; + } + } + if (cache[cache_left_index].index > + cache[cache_center_index].index) + cache_left_index = cache_center_index; + if (cache[cache_right_index].index < + cache[cache_center_index].index) + cache_right_index = cache_center_index; + cache_left_index = seek_left_while(cache_left_index, + cache[ind_].index - 1 == cache[next_].index); + cache_right_index = seek_right_while(cache_right_index, + cache[ind_].index - 1 == cache[next_].index); + int prio_l = cache[cache_center_index].index - + cache[cache_left_index].index + 1; + int prio_r = cache[cache_right_index].index - + cache[cache_center_index].index + 1; + if ((prio_l < prio_r || + cache[cache_right_index].index >= number_of_slides) && + cache[cache_left_index].index > 0) + { + if (cache_free == -1) + free_slide_prio(prio_l); + i = lla_pop_head(&cache_free); + if (load_and_prepare_surface(cache[cache_left_index].index + - 1, i, prio_l)) + { + lla_insert_before(&cache_used, i, cache_left_index); + cache_left_index = i; + return true; + } + } else if(cache[cache_right_index].index < number_of_slides - 1) + { + if (cache_free == -1) + free_slide_prio(prio_l); + i = lla_pop_head(&cache_free); + if (load_and_prepare_surface(cache[cache_right_index].index + + 1, i, prio_r)) + { + lla_insert_after(i, cache_right_index); + cache_right_index = i; + return true; } } - if (cache[oldest_slide].hid != empty_slide_hid) { - rb->bufclose(cache[oldest_slide].hid); - cache[oldest_slide].hid = -1; + } else { + i = lla_pop_head(&cache_free); + if (load_and_prepare_surface(center_index, i, 0)) + { +insert_first_slide: + cache[i].next = i; + cache[i].prev = i; + cache_center_index = i; + cache_left_index = i; + cache_right_index = i; + cache_used = i; + return true; } - load_and_prepare_surface(slide_index, oldest_slide); } - return oldest_slide; +fail_and_refree: + if (i != -1) + { + lla_insert_tail(&cache_free, i); + } + return false; } /** Get a slide from the buffer */ -static inline struct bitmap *get_slide(const int hid) +static inline struct dim *get_slide(const int hid) { - if (hid < 0) + if (!hid) return NULL; - struct bitmap *bmp; + struct dim *bmp; - ssize_t ret = rb->bufgetdata(hid, 0, (void *)&bmp); - if (ret < 0) - return NULL; + bmp = buflib_get_data(&buf_ctx, hid); return bmp; } @@ -1152,23 +1289,21 @@ static inline struct bitmap *get_slide(const int hid) /** Return the requested surface */ -static inline struct bitmap *surface(const int slide_index) +static inline struct dim *surface(const int slide_index) { if (slide_index < 0) return 0; if (slide_index >= number_of_slides) return 0; - int i; - for (i = 0; i < slide_cache_in_use; i++) { - /* maybe do the inverse mapping => implies dynamic allocation? */ - if ( cache[i].index == slide_index ) { - /* We have already loaded our slide, so touch it and return it. */ - cache[i].touched = *rb->current_tick; - return get_slide(cache[i].hid); - } + if ((i = cache_used ) != -1) + { + do { + if (cache[i].index == slide_index) + return get_slide(cache[i].hid); + i = cache[i].next; + } while (i != cache_used); } - request_surface(slide_index); return get_slide(empty_slide_hid); } @@ -1293,13 +1428,13 @@ static inline pix_t fade_color(pix_t c, unsigned int a) */ void render_slide(struct slide_data *slide, const int alpha) { - struct bitmap *bmp = surface(slide->slide_index); + struct dim *bmp = surface(slide->slide_index); if (!bmp) { return; } if (slide->angle > 255 || slide->angle < -255) return; - pix_t *src = (pix_t *)bmp->data; + pix_t *src = (pix_t*)(sizeof(struct dim) + (char *)bmp); const int sw = bmp->width; const int sh = bmp->height; @@ -1329,7 +1464,7 @@ void render_slide(struct slide_data *slide, const int alpha) xsnum = CAM_DIST * (slide->cx - xp) - fmuln(xp, zo, PFREAL_SHIFT - 2, 0); xsden = fmuln(xp, sinr, PFREAL_SHIFT - 2, 0) - CAM_DIST * cosr; xs = fdiv(xsnum, xsden); - + xsnumi = -CAM_DIST_R - zo; xsdeni = sinr; int x; @@ -1411,11 +1546,10 @@ void render_slide(struct slide_data *slide, const int alpha) xs = fdiv(xsnum, xsden); } else xs += PFREAL_ONE; - + } /* let the music play... */ rb->yield(); - return; } @@ -1425,8 +1559,11 @@ void render_slide(struct slide_data *slide, const int alpha) */ static inline void set_current_slide(const int slide_index) { + int old_center_index = center_index; step = 0; center_index = fbound(slide_index, 0, number_of_slides - 1); + if (old_center_index != center_index) + rb->queue_post(&thread_q, EV_WAKEUP, 0); target = center_index; slide_frame = slide_index << 16; reset_slides(); @@ -1583,6 +1720,7 @@ void update_scroll_animation(void) index++; if (center_index != index) { center_index = index; + rb->queue_post(&thread_q, EV_WAKEUP, 0); slide_frame = index << 16; center_slide.slide_index = center_index; for (i = 0; i < num_slides; i++) @@ -1652,12 +1790,6 @@ void cleanup(void *parameter) /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); /* backlight control in lib/helper.c */ - int i; - for (i = 0; i < slide_cache_in_use; i++) { - rb->bufclose(cache[i].hid); - } - if ( empty_slide_hid != - 1) - rb->bufclose(empty_slide_hid); #ifdef USEGSLIB grey_release(); #endif @@ -1687,9 +1819,6 @@ int create_empty_slide(bool force) return false; } - empty_slide_hid = read_pfraw( EMPTY_SLIDE ); - if (empty_slide_hid == -1 ) return false; - return true; } @@ -2053,7 +2182,7 @@ void draw_album_text(void) int main(void) { int ret; - + rb->lcd_setfont(FONT_UI); draw_splashscreen(); @@ -2068,6 +2197,7 @@ int main(void) init_reflect_table(); + ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4); ret = create_album_index(); if (ret == ERROR_BUFFER_FULL) { rb->splash(HZ, "Not enough memory for album names"); @@ -2076,7 +2206,8 @@ int main(void) rb->splash(HZ, "No albums found. Please enable database"); return PLUGIN_ERROR; } - + + ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4); number_of_slides = album_count; if ((cache_version != CACHE_VERSION) && !create_albumart_cache()) { rb->splash(HZ, "Could not create album art cache"); @@ -2090,6 +2221,27 @@ int main(void) cache_version = CACHE_VERSION; configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); + +#ifdef USEGSLIB + long grey_buf_used; + if (!grey_init(plugin_buf, plugin_buf_size, GREY_BUFFERED|GREY_ON_COP, + LCD_WIDTH, LCD_HEIGHT, &grey_buf_used)) + { + rb->splash(HZ, "Greylib init failed!"); + return PLUGIN_ERROR; + } + grey_setfont(FONT_UI); + plugin_buf_size -= grey_buf_used; + plugin_buf = (void*)(grey_buf_used + (char*)plugin_buf); +#endif + buflib_init(&buf_ctx, (void *)plugin_buf, plugin_buf_size); + + if (!(empty_slide_hid = read_pfraw(EMPTY_SLIDE, 0))) + { + rb->splash(HZ, "Unable to load empty slide image"); + return PLUGIN_ERROR; + } + if (!create_pf_thread()) { rb->splash(HZ, "Cannot create thread!"); return PLUGIN_ERROR; @@ -2098,27 +2250,21 @@ int main(void) int i; /* initialize */ - int min_slide_cache = fmin(number_of_slides, SLIDE_CACHE_SIZE); - for (i = 0; i < min_slide_cache; i++) { - cache[i].hid = -1; - cache[i].touched = 0; - slide_cache_stack[i] = SLIDE_CACHE_SIZE-i-1; - } - slide_cache_stack_index = min_slide_cache-1; - slide_cache_in_use = 0; -#ifdef USEGSLIB - if (!grey_init(plugin_buf, plugin_buf_size, GREY_BUFFERED|GREY_ON_COP, - LCD_WIDTH, LCD_HEIGHT, NULL)) - rb->splash(HZ, "Greylib init failed!"); - grey_setfont(FONT_UI); -#endif + for (i = 0; i < SLIDE_CACHE_SIZE; i++) { + cache[i].hid = 0; + cache[i].index = 0; + cache[i].next = i + 1; + cache[i].prev = i - 1; + } + cache[0].prev = i - 1; + cache[i - 1].next = 0; + cache_free = 0; buffer = LCD_BUF; pf_state = pf_idle; track_index = -1; extra_fade = 0; - center_index = 0; slide_frame = 0; step = 0; target = 0; @@ -2289,7 +2435,6 @@ int main(void) enum plugin_status plugin_start(const void *parameter) { int ret; - (void) parameter; #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); @@ -2300,7 +2445,6 @@ enum plugin_status plugin_start(const void *parameter) rb->cpu_boost(true); #endif plugin_buf = rb->plugin_get_buffer(&plugin_buf_size); - ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4); ret = main(); #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(false); -- cgit v1.2.3