initial commit
[kugel-rb.git] / apps / gui / skin_engine / skin_buffer.c
blob56f095468585f375a7fb127780737eb298edf6c6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 * Copyright (C) 2009 Jonathan Gordon
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include "config.h"
27 #include "buffer.h"
28 #include "settings.h"
29 #include "screen_access.h"
30 #include "skin_engine.h"
31 #include "wps_internals.h"
32 #include "skin_tokens.h"
33 #include "skin_buffer.h"
34 #include "dir.h"
36 /* skin buffer management.
37 * This module is used to allocate space in a single global skin buffer for
38 * tokens for both/all screens.
40 * This is mostly just copy/paste from firmware/buffer.c
43 * MAIN_ and REMOTE_BUFFER are just for reasonable size calibration,
44 * both screens can use the whole buffer as they need; it's not split
45 * between screens
47 * Buffer can be allocated from either "end" of the global buffer.
48 * items with unknown sizes get allocated from the start (0->) (data)
49 * items with known sizes get allocated from the end (<-buf_size) (tokens)
50 * After loading 2 skins the buffer will look like this:
51 * |tokens skin1|images skin1|tokens s2|images s2|---SPACE---|data skin2|data skin1|
52 * Make sure to never start allocating from the beginning before letting us know
53 * how much was used. and RESPECT THE buf_free RETURN VALUES!
58 #ifdef HAVE_LCD_BITMAP
59 #define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
60 + (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES))
62 #if (NB_SCREENS > 1)
63 #define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \
64 + (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES))
65 #else
66 #define REMOTE_BUFFER 0
67 #endif
70 #define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER) + \
71 (WPS_MAX_TOKENS * sizeof(struct wps_token))
72 #endif
74 #ifdef HAVE_LCD_CHARCELLS
75 #define SKIN_BUFFER_SIZE (LCD_HEIGHT * LCD_WIDTH) * 64 + \
76 (WPS_MAX_TOKENS * sizeof(struct wps_token))
77 #endif
79 static unsigned char *buffer;
80 static unsigned char *buffer_front = NULL; /* start of the free space,
81 increases with allocation*/
82 static unsigned char *buffer_back = NULL; /* end of the free space
83 decreases with allocation */
84 static size_t buf_size = SKIN_BUFFER_SIZE;
85 #define SKIN_BUFFER_FILE_BASE ".skin_buffer_"
86 void skin_buffer_init(void)
88 #if 1 /* this will go in again later probably */
89 if (buffer == NULL)
91 DIR *dh;
92 struct dirent *file;
93 dh = opendir(ROCKBOX_DIR);
94 bool found = false;
95 /* traverse the rockbox dir for our skin file */
96 if (dh)
98 while(!found && (file = readdir(dh)))
100 /* the skin file is named .skin_buffer_XXXX, so don't
101 * compare the trailing \0 to get a match */
102 if (!strncmp(file->d_name, SKIN_BUFFER_FILE_BASE,
103 sizeof(SKIN_BUFFER_FILE_BASE)-1))
104 found = true;
107 if (found)
108 buf_size = atoi(file->d_name + sizeof(SKIN_BUFFER_FILE_BASE)-1);
109 else
110 buf_size = SKIN_BUFFER_SIZE;
112 buffer = buffer_alloc(buf_size);
113 buffer_front = buffer;
114 buffer_back = buffer + buf_size;
116 else
117 #endif
119 /* reset the buffer.... */
120 buffer_front = buffer;
121 buffer_back = buffer + buf_size;
126 void skin_buffer_dump_size(ssize_t size)
128 DIR *dh;
129 struct dirent *file;
130 dh = opendir(ROCKBOX_DIR);
131 char filename[MAX_PATH];
132 if (dh)
134 while((file = readdir(dh)))
136 /* the skin file is named .skin_buffer_XXXX, so don't
137 * compare the trailing \0 to get a match */
138 if (!strncmp(file->d_name, SKIN_BUFFER_FILE_BASE,
139 sizeof(SKIN_BUFFER_FILE_BASE)-1))
141 char f[MAX_PATH];
142 snprintf(f, sizeof f, ROCKBOX_DIR "/%s", file->d_name);
143 remove(f);
144 break;
148 if (size < 0)
150 /* add a 30k buffer to be safe */
151 size = skin_buffer_usage();
152 /* make sure at least a backdrop + extra skin data can be loaded
153 * to aid the first pass */
154 if (size < (LCD_BACKDROP_BYTES + (30<<10)))
155 size = (LCD_BACKDROP_BYTES + (30<<10));
157 snprintf(filename, sizeof(filename),
158 ROCKBOX_DIR "/" SKIN_BUFFER_FILE_BASE "%d", size + (30<<10));
159 creat(filename); /* what to do if it failed? */
162 /* get the number of bytes currently being used */
163 size_t skin_buffer_usage(void)
165 return buf_size - (buffer_back-buffer_front);
168 size_t skin_buffer_freespace(void)
170 return buffer_back-buffer_front;
173 /* Allocate size bytes from the buffer
174 * allocates from the back end (data end)
176 void* skin_buffer_alloc(size_t size)
178 if (skin_buffer_freespace() <= size)
180 return NULL;
182 buffer_back -= size;
183 /* 32-bit aligned */
184 buffer_back = (void *)(((unsigned long)buffer_back) & ~3);
186 memset(buffer_back, 0, size);
187 return buffer_back;
190 /* Get a pointer to the skin buffer and the count of how much is free
191 * used to do your own buffer management.
192 * Any memory used will be overwritten next time wps_buffer_alloc()
193 * is called unless skin_buffer_increment() is called first
195 * This is from the start of the buffer, it is YOUR responsility to make
196 * sure you dont ever use more then *freespace, and bear in mind this will only
197 * be valid untill skin_buffer_alloc() is next called...
198 * so call skin_buffer_increment() and skin_buffer_freespace() regularly
200 void* skin_buffer_grab(size_t *freespace)
202 *freespace = buf_size - skin_buffer_usage();
203 return buffer_front;
206 /* Use after skin_buffer_grab() to specify how much buffer was used */
207 void skin_buffer_increment(size_t used, bool align)
209 buffer_front += used;
210 if (align)
212 /* 32-bit aligned */
213 buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3);
217 /* free previously skin_buffer_increment()'ed space. This just moves the pointer
218 * back 'used' bytes so make sure you actually want to do this */
219 void skin_buffer_free_from_front(size_t used)
221 buffer_front -= used;
222 /* 32-bit aligned */
223 buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3);