1
0
Fork 0
forked from len0rd/rockbox

FS#9919 pictureflow cache rework, footprint reduction, buflib use

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20203 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Andrew Mahone 2009-03-04 21:23:49 +00:00
parent b727de604d
commit d8b6a950c6

View file

@ -32,6 +32,7 @@
#include "pluginbitmaps/pictureflow_logo.h" #include "pluginbitmaps/pictureflow_logo.h"
#include "lib/grey.h" #include "lib/grey.h"
#include "lib/feature_wrappers.h" #include "lib/feature_wrappers.h"
#include "lib/buflib.h"
PLUGIN_HEADER PLUGIN_HEADER
@ -116,7 +117,7 @@ typedef fb_data pix_t;
#define DISPLAY_LEFT_R (PFREAL_HALF - LCD_WIDTH * PFREAL_HALF) #define DISPLAY_LEFT_R (PFREAL_HALF - LCD_WIDTH * PFREAL_HALF)
#define MAXSLIDE_LEFT_R (PFREAL_HALF - DISPLAY_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 #define MAX_SLIDES_COUNT 10
@ -127,8 +128,6 @@ typedef fb_data pix_t;
#define EV_WAKEUP 1337 #define EV_WAKEUP 1337
/* maximum number of albums */ /* maximum number of albums */
#define MAX_ALBUMS 1024
#define AVG_ALBUM_NAME_LENGTH 20
#define MAX_TRACKS 50 #define MAX_TRACKS 50
#define AVG_TRACK_NAME_LENGTH 20 #define AVG_TRACK_NAME_LENGTH 20
@ -161,7 +160,8 @@ struct slide_data {
struct slide_cache { struct slide_cache {
int index; /* index of the cached slide */ int index; /* index of the cached slide */
int hid; /* handle ID 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 { struct album_data {
@ -196,7 +196,7 @@ const struct picture logos[]={
{pictureflow_logo, BMPWIDTH_pictureflow_logo, BMPHEIGHT_pictureflow_logo}, {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 }; album_name_top };
static char* show_album_name_conf[] = static char* show_album_name_conf[] =
{ {
@ -216,7 +216,8 @@ static int zoom = 100;
static bool show_fps = false; static bool show_fps = false;
static bool resize = true; static bool resize = true;
static int cache_version = 0; 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[] = static struct configdata config[] =
{ {
@ -239,7 +240,7 @@ static struct configdata config[] =
/** below we allocate the memory we want to use **/ /** below we allocate the memory we want to use **/
static pix_t *buffer; /* for now it always points to the lcd framebuffer */ 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 center_slide;
static struct slide_data left_slides[MAX_SLIDES_COUNT]; static struct slide_data left_slides[MAX_SLIDES_COUNT];
static struct slide_data right_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 step;
static int target; static int target;
static int fade; 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 int itilt;
static PFreal offsetX; static PFreal offsetX;
static PFreal offsetY; static PFreal offsetY;
static int number_of_slides; static int number_of_slides;
static struct slide_cache cache[SLIDE_CACHE_SIZE]; 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 */ /* use long for aligning */
unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)]; unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)];
/* queue (as array) for scheduling load_surface */ /* 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; static int empty_slide_hid;
unsigned int thread_id; unsigned int thread_id;
struct event_queue thread_q; struct event_queue thread_q;
static long uniqbuf[UNIQBUF_SIZE];
static struct tagcache_search tcs; static struct tagcache_search tcs;
static struct album_data album[MAX_ALBUMS]; static struct buflib_context buf_ctx;
static char album_names[MAX_ALBUMS*AVG_ALBUM_NAME_LENGTH];
static struct album_data *album;
static char *album_names;
static int album_count; static int album_count;
static char track_names[MAX_TRACKS * AVG_TRACK_NAME_LENGTH]; static char track_names[MAX_TRACKS * AVG_TRACK_NAME_LENGTH];
@ -333,6 +336,7 @@ static int pf_state;
/** code */ /** code */
static inline pix_t fade_color(pix_t c, unsigned int a); static inline pix_t fade_color(pix_t c, unsigned int a);
bool save_pfraw(char* filename, struct bitmap *bm); bool save_pfraw(char* filename, struct bitmap *bm);
bool load_new_slide(void);
int load_surface(int); int load_surface(int);
static inline PFreal fmul(PFreal a, PFreal b) static inline PFreal fmul(PFreal a, PFreal b)
@ -398,7 +402,7 @@ static inline int clz(uint32_t v)
} }
#else #else
static const char clz_lut[16] = { 4, 3, 2, 2, 1, 1, 1, 1, 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 /* This clz is based on the log2(n) implementation at
* http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
* It is not any faster than the one above, but trades 16B in the lookup table * 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 #endif
/* warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed! */ /* 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, 0, 100, 200, 297, 392, 483, 569, 650,
724, 792, 851, 903, 946, 980, 1004, 1019, 724, 792, 851, 903, 946, 980, 1004, 1019,
1024, 1019, 1004, 980, 946, 903, 851, 792, 1024, 1019, 1004, 980, 946, 903, 851, 792,
@ -562,30 +566,43 @@ void init_reflect_table(void)
*/ */
int create_album_index(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) ); rb->memset(&tcs, 0, sizeof(struct tagcache_search) );
album_count = 0; album_count = 0;
rb->tagcache_search(&tcs, tag_album); rb->tagcache_search(&tcs, tag_album);
rb->tagcache_search_set_uniqbuf(&tcs, uniqbuf, UNIQBUF_SIZE); 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; 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; l = rb->strlen(tcs.result) + 1;
if ( album_count > 0 ) 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) > if ( l > plugin_buf_size )
MAX_ALBUMS*AVG_ALBUM_NAME_LENGTH )
/* not enough memory */ /* not enough memory */
return ERROR_BUFFER_FULL; return ERROR_BUFFER_FULL;
rb->strcpy(album_names + album[album_count].name_idx, tcs.result); rb->strcpy(plugin_buf, tcs.result);
album[album_count].seek = tcs.result_seek; plugin_buf_size -= l;
plugin_buf = l + (char *)plugin_buf;
album[-album_count].seek = tcs.result_seek;
old_l = l; old_l = l;
album_count++; album_count++;
} }
rb->tagcache_search_finish(&tcs); 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; return (album_count > 0) ? 0 : ERROR_NO_ALBUMS;
} }
@ -824,123 +841,6 @@ bool create_albumart_cache(void)
return true; 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 Thread used for loading and preparing bitmaps in the background
*/ */
@ -957,10 +857,8 @@ void thread(void)
/* we just woke up */ /* we just woke up */
break; break;
} }
int slide_index; while ( load_new_slide() ) {
while ( (slide_index = slide_stack_pop()) != -1 ) { rb->yield();
load_surface( slide_index );
rb->queue_wait_w_tmo(&thread_q, &ev, HZ/10);
switch (ev.id) { switch (ev.id) {
case EV_EXIT: case EV_EXIT:
return; return;
@ -999,13 +897,15 @@ bool create_pf_thread(void)
sizeof(thread_stack), sizeof(thread_stack),
0, 0,
"Picture load thread" "Picture load thread"
IF_PRIO(, PRIORITY_BACKGROUND) IF_PRIO(, MAX(PRIORITY_USER_INTERFACE / 2,
PRIORITY_REALTIME + 1))
IF_COP(, CPU) IF_COP(, CPU)
) )
) == 0) { ) == 0) {
return false; return false;
} }
thread_is_running = true; thread_is_running = true;
rb->queue_post(&thread_q, EV_WAKEUP, 0);
return true; 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 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; struct pfraw_header bmph;
int fh = rb->open(filename, O_RDONLY); 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; return empty_slide_hid;
} else
rb->read(fh, &bmph, sizeof(struct pfraw_header));
int size = sizeof(struct bitmap) + sizeof( pix_t ) * int size = sizeof(struct bitmap) + sizeof( pix_t ) *
bmph.width * bmph.height; bmph.width * bmph.height;
int hid = rb->bufalloc(NULL, size, TYPE_BITMAP); int hid;
if (hid < 0) { while (!(hid = buflib_alloc(&buf_ctx, size)) && free_slide_prio(prio));
if (!hid) {
rb->close( fh ); rb->close( fh );
return -1; return 0;
} }
struct bitmap *bm; struct dim *bm = buflib_get_data(&buf_ctx, hid);
if (rb->bufgetdata(hid, 0, (void *)&bm) < size) {
rb->close( fh );
return -1;
}
bm->width = bmph.width; bm->width = bmph.width;
bm->height = bmph.height; bm->height = bmph.height;
#if LCD_DEPTH > 1 pix_t *data = (pix_t*)(sizeof(struct dim) + (char *)bm);
bm->format = FORMAT_NATIVE;
#endif
bm->data = ((unsigned char *)bm + sizeof(struct bitmap));
int y; int y;
for( y = 0; y < bm->height; y++ ) for( y = 0; y < bm->height; y++ )
{ {
pix_t *d = (pix_t*)( bm->data ) + (y*bm->width); rb->read( fh, data , sizeof( pix_t ) * bm->width );
rb->read( fh, d , sizeof( pix_t ) * bm->width ); data += bm->width;
} }
rb->close( fh ); rb->close( fh );
return hid; 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. 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, 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]; char tmp_path_name[MAX_PATH+1];
rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw", rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw",
slide_index); slide_index);
int hid = read_pfraw(tmp_path_name); int hid = read_pfraw(tmp_path_name, prio);
if (hid < 0) if (!hid)
return false; return false;
cache[cache_index].hid = hid; cache[cache_index].hid = hid;
if ( cache_index < SLIDE_CACHE_SIZE ) { if ( cache_index < SLIDE_CACHE_SIZE ) {
cache[cache_index].index = slide_index; cache[cache_index].index = slide_index;
cache[cache_index].touched = *rb->current_tick;
} }
return true; 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 Load the "next" slide that we can load, freeing old slides if needed, provided
if necessary. that they are further from center_index than the current slide
*/ */
int load_surface(const int slide_index) bool load_new_slide(void)
{ {
long oldest_tick = *rb->current_tick; int i = -1;
int oldest_slide = 0; if (cache_center_index != -1)
int i; {
if ( slide_cache_in_use < SLIDE_CACHE_SIZE ) { /* initial fill */ int next, prev;
oldest_slide = slide_cache_in_use; if (cache[cache_center_index].index != center_index)
load_and_prepare_surface(slide_index, slide_cache_in_use++); {
} if (cache[cache_center_index].index < center_index)
else { {
for (i = 0; i < SLIDE_CACHE_SIZE; i++) { /* look for oldest slide */ cache_center_index = seek_right_while(cache_center_index,
if (cache[i].touched < oldest_tick) { cache[next_].index <= center_index);
oldest_slide = i; prev = cache_center_index;
oldest_tick = cache[i].touched; 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[oldest_slide].hid != empty_slide_hid) { if (cache[cache_left_index].index >
rb->bufclose(cache[oldest_slide].hid); cache[cache_center_index].index)
cache[oldest_slide].hid = -1; 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;
}
}
} 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 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; return NULL;
struct bitmap *bmp; struct dim *bmp;
ssize_t ret = rb->bufgetdata(hid, 0, (void *)&bmp); bmp = buflib_get_data(&buf_ctx, hid);
if (ret < 0)
return NULL;
return bmp; return bmp;
} }
@ -1152,23 +1289,21 @@ static inline struct bitmap *get_slide(const int hid)
/** /**
Return the requested surface 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) if (slide_index < 0)
return 0; return 0;
if (slide_index >= number_of_slides) if (slide_index >= number_of_slides)
return 0; return 0;
int i; int i;
for (i = 0; i < slide_cache_in_use; i++) { if ((i = cache_used ) != -1)
/* maybe do the inverse mapping => implies dynamic allocation? */ {
if ( cache[i].index == slide_index ) { do {
/* We have already loaded our slide, so touch it and return it. */ if (cache[i].index == slide_index)
cache[i].touched = *rb->current_tick; return get_slide(cache[i].hid);
return get_slide(cache[i].hid); i = cache[i].next;
} } while (i != cache_used);
} }
request_surface(slide_index);
return get_slide(empty_slide_hid); 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) 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) { if (!bmp) {
return; return;
} }
if (slide->angle > 255 || slide->angle < -255) if (slide->angle > 255 || slide->angle < -255)
return; 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 sw = bmp->width;
const int sh = bmp->height; 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); xsnum = CAM_DIST * (slide->cx - xp) - fmuln(xp, zo, PFREAL_SHIFT - 2, 0);
xsden = fmuln(xp, sinr, PFREAL_SHIFT - 2, 0) - CAM_DIST * cosr; xsden = fmuln(xp, sinr, PFREAL_SHIFT - 2, 0) - CAM_DIST * cosr;
xs = fdiv(xsnum, xsden); xs = fdiv(xsnum, xsden);
xsnumi = -CAM_DIST_R - zo; xsnumi = -CAM_DIST_R - zo;
xsdeni = sinr; xsdeni = sinr;
int x; int x;
@ -1411,11 +1546,10 @@ void render_slide(struct slide_data *slide, const int alpha)
xs = fdiv(xsnum, xsden); xs = fdiv(xsnum, xsden);
} else } else
xs += PFREAL_ONE; xs += PFREAL_ONE;
} }
/* let the music play... */ /* let the music play... */
rb->yield(); rb->yield();
return; 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) static inline void set_current_slide(const int slide_index)
{ {
int old_center_index = center_index;
step = 0; step = 0;
center_index = fbound(slide_index, 0, number_of_slides - 1); 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; target = center_index;
slide_frame = slide_index << 16; slide_frame = slide_index << 16;
reset_slides(); reset_slides();
@ -1583,6 +1720,7 @@ void update_scroll_animation(void)
index++; index++;
if (center_index != index) { if (center_index != index) {
center_index = index; center_index = index;
rb->queue_post(&thread_q, EV_WAKEUP, 0);
slide_frame = index << 16; slide_frame = index << 16;
center_slide.slide_index = center_index; center_slide.slide_index = center_index;
for (i = 0; i < num_slides; i++) for (i = 0; i < num_slides; i++)
@ -1652,12 +1790,6 @@ void cleanup(void *parameter)
/* Turn on backlight timeout (revert to settings) */ /* Turn on backlight timeout (revert to settings) */
backlight_use_settings(); /* backlight control in lib/helper.c */ 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 #ifdef USEGSLIB
grey_release(); grey_release();
#endif #endif
@ -1687,9 +1819,6 @@ int create_empty_slide(bool force)
return false; return false;
} }
empty_slide_hid = read_pfraw( EMPTY_SLIDE );
if (empty_slide_hid == -1 ) return false;
return true; return true;
} }
@ -2053,7 +2182,7 @@ void draw_album_text(void)
int main(void) int main(void)
{ {
int ret; int ret;
rb->lcd_setfont(FONT_UI); rb->lcd_setfont(FONT_UI);
draw_splashscreen(); draw_splashscreen();
@ -2068,6 +2197,7 @@ int main(void)
init_reflect_table(); init_reflect_table();
ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4);
ret = create_album_index(); ret = create_album_index();
if (ret == ERROR_BUFFER_FULL) { if (ret == ERROR_BUFFER_FULL) {
rb->splash(HZ, "Not enough memory for album names"); 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"); rb->splash(HZ, "No albums found. Please enable database");
return PLUGIN_ERROR; return PLUGIN_ERROR;
} }
ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4);
number_of_slides = album_count; number_of_slides = album_count;
if ((cache_version != CACHE_VERSION) && !create_albumart_cache()) { if ((cache_version != CACHE_VERSION) && !create_albumart_cache()) {
rb->splash(HZ, "Could not create album art cache"); rb->splash(HZ, "Could not create album art cache");
@ -2090,6 +2221,27 @@ int main(void)
cache_version = CACHE_VERSION; cache_version = CACHE_VERSION;
configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_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()) { if (!create_pf_thread()) {
rb->splash(HZ, "Cannot create thread!"); rb->splash(HZ, "Cannot create thread!");
return PLUGIN_ERROR; return PLUGIN_ERROR;
@ -2098,27 +2250,21 @@ int main(void)
int i; int i;
/* initialize */ /* initialize */
int min_slide_cache = fmin(number_of_slides, SLIDE_CACHE_SIZE); for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
for (i = 0; i < min_slide_cache; i++) { cache[i].hid = 0;
cache[i].hid = -1; cache[i].index = 0;
cache[i].touched = 0; cache[i].next = i + 1;
slide_cache_stack[i] = SLIDE_CACHE_SIZE-i-1; cache[i].prev = i - 1;
} }
slide_cache_stack_index = min_slide_cache-1; cache[0].prev = i - 1;
slide_cache_in_use = 0; cache[i - 1].next = 0;
#ifdef USEGSLIB cache_free = 0;
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
buffer = LCD_BUF; buffer = LCD_BUF;
pf_state = pf_idle; pf_state = pf_idle;
track_index = -1; track_index = -1;
extra_fade = 0; extra_fade = 0;
center_index = 0;
slide_frame = 0; slide_frame = 0;
step = 0; step = 0;
target = 0; target = 0;
@ -2289,7 +2435,6 @@ int main(void)
enum plugin_status plugin_start(const void *parameter) enum plugin_status plugin_start(const void *parameter)
{ {
int ret; int ret;
(void) parameter; (void) parameter;
#if LCD_DEPTH > 1 #if LCD_DEPTH > 1
rb->lcd_set_backdrop(NULL); rb->lcd_set_backdrop(NULL);
@ -2300,7 +2445,6 @@ enum plugin_status plugin_start(const void *parameter)
rb->cpu_boost(true); rb->cpu_boost(true);
#endif #endif
plugin_buf = rb->plugin_get_buffer(&plugin_buf_size); plugin_buf = rb->plugin_get_buffer(&plugin_buf_size);
ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4);
ret = main(); ret = main();
#ifdef HAVE_ADJUSTABLE_CPU_FREQ #ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false); rb->cpu_boost(false);