Adapt the remaining plugins to put the greyscale isr on cop. Now they can be used...
[Rockbox.git] / apps / plugins / lib / grey_core.c
blobb4e7dfd1f4e42068d387aa8ed7125c9a7a175e99
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * New greyscale framework
11 * Core & miscellaneous functions
13 * This is a generic framework to display 129 shades of grey on low-depth
14 * bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins.
16 * Copyright (C) 2008 Jens Arnold
18 * All files in this archive are subject to the GNU General Public License.
19 * See the file COPYING in the source tree root for full license agreement.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
26 #include "plugin.h"
27 #include "grey.h"
29 #if defined(HAVE_ADJUSTABLE_CPU_FREQ) && \
30 (defined(CPU_PP) || (CONFIG_LCD == LCD_TL0350A))
31 #define NEED_BOOST
32 #endif
34 #ifndef SIMULATOR
36 #if defined ARCHOS_RECORDER /* verified */ \
37 || defined ARCHOS_FMRECORDER /* should be identical */ \
38 || defined ARCHOS_RECORDERV2 /* should be identical */ \
39 || defined ARCHOS_ONDIOFM /* verified */ \
40 || defined ARCHOS_ONDIOSP /* verified */
41 /* Average measurements of a Recorder v1, an Ondio FM, a backlight-modded
42 * Ondio FM, and an Ondio SP. */
43 static const unsigned char lcdlinear[256] = {
44 5, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 29, 31, 33, 35,
45 37, 39, 40, 42, 43, 45, 46, 48, 49, 50, 51, 53, 54, 55, 57, 58,
46 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 71, 72,
47 73, 74, 74, 75, 76, 77, 77, 78, 79, 79, 80, 80, 81, 81, 82, 82,
48 83, 84, 84, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91,
49 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
50 101, 101, 102, 103, 103, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109,
51 110, 110, 111, 112, 112, 113, 114, 114, 115, 115, 116, 117, 117, 118, 119, 119,
52 120, 120, 121, 122, 123, 123, 124, 125, 126, 126, 127, 128, 129, 129, 130, 131,
53 132, 132, 133, 134, 135, 135, 136, 137, 138, 138, 139, 140, 140, 141, 141, 142,
54 143, 144, 145, 146, 147, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 156,
55 157, 158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170,
56 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 184, 185, 186, 187,
57 188, 189, 191, 192, 194, 195, 197, 198, 199, 200, 202, 203, 204, 205, 207, 208,
58 209, 210, 212, 213, 215, 216, 218, 219, 220, 221, 222, 223, 225, 226, 227, 228,
59 229, 230, 232, 233, 234, 235, 237, 238, 239, 240, 242, 243, 244, 246, 247, 248
61 /* The actual LCD scanrate varies a lot with temperature on these targets */
62 #define LCD_SCANRATE 67 /* Hz */
64 #elif defined IAUDIO_M3 /* verified */
65 /* Average measurements of 2 iAudio remotes connected to an M3. */
66 static const unsigned char lcdlinear[256] = {
67 5, 9, 13, 17, 21, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66,
68 70, 73, 76, 78, 80, 82, 84, 86, 88, 90, 91, 92, 94, 95, 96, 97,
69 98, 99, 99, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108,
70 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
71 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 123, 123, 123,
72 124, 124, 124, 125, 125, 126, 126, 126, 127, 127, 127, 128, 128, 129, 129, 129,
73 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 134, 135, 135, 136, 136, 136,
74 137, 137, 137, 138, 138, 139, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143,
75 144, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 150, 151, 151, 152, 152,
76 153, 153, 154, 154, 155, 155, 156, 156, 157, 157, 158, 158, 159, 160, 160, 161,
77 162, 162, 163, 164, 164, 165, 166, 167, 168, 168, 169, 169, 170, 171, 171, 172,
78 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180, 181, 182, 182, 183, 184,
79 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201,
80 202, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219,
81 220, 221, 222, 223, 225, 226, 227, 228, 229, 230, 231, 232, 234, 235, 236, 237,
82 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 249, 250, 251, 252
84 /* The actual LCD scanrate is twice as high, but we cannot transfer fast enough
85 * for 150Hz. Even at 75Hz, greyscale display is very smooth. Average from
86 * 2 iAudio remotes. */
87 #define LCD_SCANRATE 75 /* Hz */
89 #elif defined IAUDIO_M5 /* verified */
90 /* Measurement of one iAudio M5L */
91 static const unsigned char lcdlinear[256] = {
92 4, 6, 8, 10, 11, 13, 15, 17, 19, 21, 22, 24, 25, 27, 28, 30,
93 32, 33, 35, 36, 37, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 51,
94 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63,
95 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 70, 70, 71, 72, 72,
96 73, 73, 74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81,
97 82, 82, 83, 84, 84, 85, 86, 86, 87, 87, 88, 89, 89, 90, 91, 91,
98 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
99 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
100 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
101 117, 117, 118, 119, 119, 120, 121, 121, 122, 122, 123, 124, 124, 125, 126, 126,
102 127, 127, 128, 129, 130, 130, 131, 132, 133, 133, 134, 135, 135, 136, 137, 137,
103 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151,
104 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 167, 168, 169,
105 170, 172, 173, 175, 177, 179, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198,
106 200, 202, 204, 205, 207, 209, 210, 212, 214, 216, 218, 219, 221, 223, 224, 226,
107 228, 230, 231, 233, 235, 236, 237, 239, 241, 243, 244, 246, 248, 249, 250, 252
109 #define LCD_SCANRATE 73 /* Hz */
111 #elif defined IPOD_1G2G /* verified */
112 /* Average measurements of an iPod 1st Gen (0x00010001) and an iPod 2nd Gen
113 * (0x00020000), measured with both backlight off & backlight on (flipped
114 * curves) and medium load (white background when measuring with backlight on),
115 * as the curve is load dependent (the controller's step-up converter doesn't
116 * provide enough juice). Table is for backlight_off state. */
117 static const unsigned char lcdlinear[256] = {
118 4, 6, 8, 9, 11, 13, 14, 16, 17, 18, 20, 21, 23, 24, 26, 27,
119 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 41, 42, 43, 44,
120 45, 45, 46, 47, 47, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53,
121 54, 54, 54, 55, 55, 56, 56, 56, 57, 57, 57, 58, 58, 59, 59, 59,
122 60, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 65, 65, 65,
123 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73,
124 74, 74, 74, 75, 75, 76, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80,
125 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88,
126 89, 89, 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 97, 98, 99, 99,
127 100, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108, 109, 109,
128 110, 110, 111, 112, 113, 113, 114, 115, 116, 116, 117, 118, 119, 119, 120, 121,
129 122, 122, 123, 124, 125, 125, 126, 127, 128, 129, 130, 131, 131, 132, 133, 134,
130 135, 137, 138, 139, 141, 142, 144, 145, 146, 147, 149, 150, 151, 152, 154, 155,
131 156, 158, 159, 161, 162, 164, 165, 167, 169, 171, 172, 174, 175, 177, 178, 180,
132 182, 184, 186, 188, 189, 191, 193, 195, 197, 199, 201, 203, 206, 208, 210, 212,
133 214, 217, 219, 221, 224, 226, 229, 231, 233, 236, 238, 240, 243, 245, 247, 250
135 /* Average from an iPod 1st Gen and an iPod 2nd Gen */
136 #define LCD_SCANRATE 96 /* Hz */
138 #elif defined IPOD_MINI2G /* verified */ \
139 || defined IPOD_MINI /* should be identical */ \
140 || defined IPOD_3G /* TODO: verify */ \
141 || defined IPOD_4G /* TODO: verify */
142 /* Measurement of one iPod Mini G2 */
143 static const unsigned char lcdlinear[256] = {
144 2, 5, 7, 10, 12, 15, 17, 20, 22, 24, 26, 28, 30, 32, 34, 36,
145 38, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 52, 53,
146 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 58, 59, 59, 60, 60, 60,
147 61, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65,
148 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69,
149 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 73, 73, 74, 74, 74,
150 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 78, 78, 79, 79, 79,
151 80, 80, 80, 81, 81, 82, 82, 82, 83, 83, 83, 84, 84, 85, 85, 85,
152 86, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92,
153 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 99, 99, 100, 101, 101,
154 102, 102, 103, 104, 104, 105, 106, 106, 107, 108, 109, 110, 110, 111, 112, 113,
155 114, 115, 115, 116, 117, 118, 118, 119, 120, 121, 121, 122, 123, 124, 124, 125,
156 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
157 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 153, 154, 155, 156, 158, 159,
158 160, 162, 163, 165, 166, 168, 169, 171, 172, 175, 177, 180, 182, 185, 187, 190,
159 192, 196, 199, 203, 206, 210, 213, 217, 220, 223, 227, 230, 234, 238, 242, 246
161 /* Average of an iPod Mini G2 and 2 3rd Gen iPods. */
162 #define LCD_SCANRATE 87 /* Hz */
164 #elif defined IRIVER_H100_SERIES /* verified */
165 /* Measurement of one Iriver H140 */
166 static const unsigned char lcdlinear[256] = {
167 5, 8, 12, 15, 18, 22, 25, 28, 31, 34, 36, 39, 42, 44, 47, 50,
168 53, 55, 57, 59, 62, 64, 66, 68, 70, 71, 72, 73, 75, 76, 77, 78,
169 79, 80, 80, 81, 82, 83, 83, 84, 85, 85, 86, 86, 87, 87, 88, 88,
170 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95,
171 96, 96, 96, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101,
172 102, 102, 102, 103, 103, 104, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
173 109, 109, 109, 110, 110, 111, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115,
174 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123,
175 124, 124, 125, 125, 126, 127, 127, 128, 129, 129, 130, 130, 131, 131, 132, 132,
176 133, 133, 134, 135, 135, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141,
177 142, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 148, 149, 150, 150, 151,
178 152, 152, 153, 153, 154, 155, 155, 156, 157, 157, 158, 159, 160, 160, 161, 162,
179 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
180 178, 179, 181, 182, 183, 184, 186, 187, 188, 189, 191, 192, 193, 194, 196, 197,
181 198, 200, 202, 203, 205, 207, 208, 210, 212, 214, 215, 217, 218, 220, 221, 223,
182 224, 226, 228, 229, 231, 233, 235, 236, 238, 240, 241, 242, 244, 245, 246, 248
184 #define LCD_SCANRATE 70 /* Hz */
186 #else /* not yet calibrated targets - generic linear mapping */
187 /* TODO: calibrate iFP7xx
188 * TODO: Olympus m:robe 100 */
189 static const unsigned char lcdlinear[256] = {
190 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
191 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
192 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
193 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
194 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
195 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
196 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
197 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
198 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
199 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
200 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
201 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
202 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
203 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
204 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
205 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
207 /* generic default */
208 #define LCD_SCANRATE 70 /* Hz */
210 #endif
211 #else /* SIMULATOR */
212 /* undo a (generic) PC display gamma of 2.0 to simulate target behaviour */
213 static const unsigned char lcdlinear[256] = {
214 0, 16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 58, 60, 62,
215 64, 66, 68, 70, 71, 73, 75, 77, 78, 80, 81, 83, 84, 86, 87, 89,
216 90, 92, 93, 94, 96, 97, 98, 100, 101, 102, 103, 105, 106, 107, 108, 109,
217 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127,
218 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 142,
219 143, 144, 145, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156,
220 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
221 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180,
222 181, 181, 182, 183, 183, 184, 185, 186, 186, 187, 188, 188, 189, 190, 190, 191,
223 192, 192, 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 201, 201,
224 202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
225 212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 220, 220, 221,
226 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 228, 228, 229, 229, 230,
227 230, 231, 231, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
228 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
229 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
231 #endif /* SIMULATOR */
233 /* Prototypes */
234 static inline void _deferred_update(void) __attribute__ ((always_inline));
235 static int exp_s16p16(int x);
236 static int log_s16p16(int x);
237 static void grey_screendump_hook(int fd);
238 static void fill_gvalues(void);
239 #ifdef SIMULATOR
240 static unsigned long _grey_get_pixel(int x, int y);
241 #else
242 static void _timer_isr(void);
243 #endif
246 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
247 static void invert_gvalues(void)
249 unsigned char *val, *end;
250 unsigned char rev_tab[256];
251 unsigned i;
252 unsigned last_i = 0;
253 unsigned x = 0;
254 unsigned last_x;
256 /* Step 1: Calculate a transposed table for undoing the old mapping */
257 for (i = 0; i < 256; i++)
259 last_x = x;
260 x = _grey_info.gvalue[i];
261 if (x > last_x)
263 rev_tab[last_x++] = (last_i + i) / 2;
264 while (x > last_x)
265 rev_tab[last_x++] = i;
266 last_i = i;
269 rev_tab[last_x++] = (last_i + 255) / 2;
270 while (256 > last_x)
271 rev_tab[last_x++] = 255;
273 /* Step 2: Calculate new mapping */
274 fill_gvalues();
276 /* Step 3: Transpose all pixel values */
277 val = _grey_info.values;
278 end = val + _GREY_MULUQ(_grey_info.width, _grey_info.height);
281 *val = _grey_info.gvalue[rev_tab[*val]];
282 while (++val < end);
284 #endif
286 /* Update LCD areas not covered by the greyscale overlay */
287 static inline void _deferred_update(void)
289 int x1 = MAX(_grey_info.x, 0);
290 int x2 = MIN(_grey_info.x + _grey_info.width, LCD_WIDTH);
291 int y1 = MAX(_grey_info.y, 0);
292 int y2 = MIN(_grey_info.y + _grey_info.height, LCD_HEIGHT);
294 if (y1 > 0) /* refresh part above overlay, full width */
295 _grey_info.rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
297 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
298 _grey_info.rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
300 if (x1 > 0) /* refresh part to the left of overlay */
301 _grey_info.rb->lcd_update_rect(0, y1, x1, y2 - y1);
303 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
304 _grey_info.rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
307 #ifdef SIMULATOR
309 /* Callback function for grey_ub_gray_bitmap_part() to read a pixel from the
310 * greybuffer. Note that x and y are in LCD coordinates, not greybuffer
311 * coordinates! */
312 static unsigned long _grey_get_pixel(int x, int y)
314 int xg = x - _grey_info.x;
315 int yg = y - _grey_info.y;
316 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
317 int idx = _grey_info.width * yg + xg;
318 #else /* vertical packing or vertical interleaved */
319 int idx = _grey_info.width * (yg & ~_GREY_BMASK)
320 + (xg << _GREY_BSHIFT) + (~yg & _GREY_BMASK);
321 #endif
323 return _grey_info.values[idx] + (1 << LCD_DEPTH);
326 #else /* !SIMULATOR */
328 /* Timer interrupt handler: display next frame */
329 static void _timer_isr(void)
331 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
332 unsigned long check = _grey_info.rb->is_backlight_on(true)
333 ? 0 : _GREY_BACKLIGHT_ON;
335 if ((_grey_info.flags & (_GREY_BACKLIGHT_ON|GREY_RAWMAPPED)) == check)
337 _grey_info.flags ^= _GREY_BACKLIGHT_ON;
338 invert_gvalues();
339 return; /* don't overload this timer slot */
341 #endif
342 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
343 _grey_info.rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
344 _grey_info.bx, _grey_info.y,
345 _grey_info.bwidth, _grey_info.height,
346 _grey_info.width);
347 #else /* vertical packing or vertical interleaved */
348 _grey_info.rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
349 _grey_info.x, _grey_info.by,
350 _grey_info.width, _grey_info.bheight,
351 _grey_info.width);
352 #endif
354 if (_grey_info.flags & _GREY_DEFERRED_UPDATE) /* lcd_update() requested? */
356 _deferred_update();
357 _grey_info.flags &= ~_GREY_DEFERRED_UPDATE; /* clear request */
361 #endif /* !SIMULATOR */
363 /* fixed point exp() */
364 static int exp_s16p16(int x)
366 int t;
367 int y = 0x00010000;
369 if (x < 0) x += 0xb1721, y >>= 16;
370 t = x - 0x58b91; if (t >= 0) x = t, y <<= 8;
371 t = x - 0x2c5c8; if (t >= 0) x = t, y <<= 4;
372 t = x - 0x162e4; if (t >= 0) x = t, y <<= 2;
373 t = x - 0x0b172; if (t >= 0) x = t, y <<= 1;
374 t = x - 0x067cd; if (t >= 0) x = t, y += y >> 1;
375 t = x - 0x03920; if (t >= 0) x = t, y += y >> 2;
376 t = x - 0x01e27; if (t >= 0) x = t, y += y >> 3;
377 t = x - 0x00f85; if (t >= 0) x = t, y += y >> 4;
378 t = x - 0x007e1; if (t >= 0) x = t, y += y >> 5;
379 t = x - 0x003f8; if (t >= 0) x = t, y += y >> 6;
380 t = x - 0x001fe; if (t >= 0) x = t, y += y >> 7;
381 y += ((y >> 8) * x) >> 8;
383 return y;
386 /* fixed point log() */
387 static int log_s16p16(int x)
389 int t;
390 int y = 0xa65af;
392 if (x < 0x00008000) x <<=16, y -= 0xb1721;
393 if (x < 0x00800000) x <<= 8, y -= 0x58b91;
394 if (x < 0x08000000) x <<= 4, y -= 0x2c5c8;
395 if (x < 0x20000000) x <<= 2, y -= 0x162e4;
396 if (x < 0x40000000) x <<= 1, y -= 0x0b172;
397 t = x + (x >> 1); if ((t & 0x80000000) == 0) x = t, y -= 0x067cd;
398 t = x + (x >> 2); if ((t & 0x80000000) == 0) x = t, y -= 0x03920;
399 t = x + (x >> 3); if ((t & 0x80000000) == 0) x = t, y -= 0x01e27;
400 t = x + (x >> 4); if ((t & 0x80000000) == 0) x = t, y -= 0x00f85;
401 t = x + (x >> 5); if ((t & 0x80000000) == 0) x = t, y -= 0x007e1;
402 t = x + (x >> 6); if ((t & 0x80000000) == 0) x = t, y -= 0x003f8;
403 t = x + (x >> 7); if ((t & 0x80000000) == 0) x = t, y -= 0x001fe;
404 x = 0x80000000 - x;
405 y -= x >> 15;
407 return y;
410 static void fill_gvalues(void)
412 int i;
413 unsigned data;
415 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
416 unsigned imask = (_grey_info.flags & _GREY_BACKLIGHT_ON) ? 0xff : 0;
417 #else
418 const unsigned imask = 0;
419 #endif
420 for (i = 0; i < 256; i++)
422 data = exp_s16p16((_GREY_GAMMA * log_s16p16(i * 257 + 1)) >> 8) + 128;
423 data = (data - (data >> 8)) >> 8; /* approx. data /= 257 */
424 data = ((lcdlinear[data ^ imask] ^ imask) << 7) + 127;
425 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
426 /* approx. data / 255 */
430 /* Initialise the framework and prepare the greyscale display buffer
432 arguments:
433 newrb = pointer to plugin api
434 gbuf = pointer to the memory area to use (e.g. plugin buffer)
435 gbuf_size = max usable size of the buffer
436 features = flags for requesting features
437 GREY_BUFFERED: use chunky pixel buffering
438 This allows to use all drawing functions, but needs more
439 memory. Unbuffered operation provides only a subset of
440 drawing functions. (only grey_bitmap drawing and scrolling)
441 GREY_RAWMAPPED: no LCD linearisation and gamma correction
442 width = width in pixels (1..LCD_WIDTH)
443 height = height in pixels (1..LCD_HEIGHT)
444 Note that depending on the target LCD, either height or
445 width are rounded up to a multiple of 4 or 8.
447 result:
448 true on success, false on failure
450 If you need info about the memory taken by the greyscale buffer, supply a
451 long* as the last parameter. This long will then contain the number of bytes
452 used. The total memory needed can be calculated as follows:
453 total_mem =
454 width * height * 2 [grey display data]
455 + buffered ? (width * height) : 0 [chunky buffer]
456 + 0..3 [alignment]
458 The function is authentic regarding memory usage on the simulator, even
459 if it doesn't use all of the allocated memory. */
460 bool grey_init(struct plugin_api* newrb, unsigned char *gbuf, long gbuf_size,
461 unsigned features, int width, int height, long *buf_taken)
463 int bdim, i;
464 long plane_size, buftaken;
465 unsigned data;
466 #ifndef SIMULATOR
467 unsigned *dst, *end;
468 #endif
470 _grey_info.rb = newrb;
472 if ((unsigned) width > LCD_WIDTH
473 || (unsigned) height > LCD_HEIGHT)
474 return false;
476 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
477 bdim = (width + 7) >> 3;
478 width = bdim << 3;
479 #else /* vertical packing or vertical interleaved */
480 #if (LCD_DEPTH == 1) || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
481 bdim = (height + 7) >> 3;
482 height = bdim << 3;
483 #elif LCD_DEPTH == 2
484 bdim = (height + 3) >> 2;
485 height = bdim << 2;
486 #endif
487 #endif
489 plane_size = _GREY_MULUQ(width, height);
490 #if defined(CPU_COLDFIRE) /* Buffers should be line aligned */ \
491 || defined(CPU_PP) && (NUM_CORES > 1) /* Buffers must be cache line aligned */
492 plane_size += (-plane_size) & 0xf;
493 buftaken = (-(long)gbuf) & 0xf;
494 #else /* Buffers must be 32 bit aligned. */
495 buftaken = (-(long)gbuf) & 3;
496 #endif
497 gbuf += buftaken;
499 if (features & GREY_BUFFERED) /* chunky buffer */
501 _grey_info.buffer = gbuf;
502 gbuf += plane_size;
503 buftaken += plane_size;
505 #if NUM_CORES > 1 /* Values and phases must be uncached when running on COP */
506 if (features & GREY_ON_COP)
507 gbuf = UNCACHED_ADDR(gbuf);
508 #endif
509 _grey_info.values = gbuf;
510 gbuf += plane_size;
511 _grey_info.phases = gbuf;
512 buftaken += 2 * plane_size;
514 if (buftaken > gbuf_size)
515 return false;
517 /* Init to white */
518 _grey_info.rb->memset(_grey_info.values, 0x80, plane_size);
520 #ifndef SIMULATOR
521 /* Init phases with random bits */
522 dst = (unsigned*)(_grey_info.phases);
523 end = (unsigned*)(_grey_info.phases + plane_size);
526 *dst++ = _grey_info.rb->rand();
527 while (dst < end);
528 #endif
530 _grey_info.x = 0;
531 _grey_info.y = 0;
532 _grey_info.width = width;
533 _grey_info.height = height;
534 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
535 _grey_info.bx = 0;
536 _grey_info.bwidth = bdim;
537 #else /* vertical packing or vertical interleaved */
538 _grey_info.by = 0;
539 _grey_info.bheight = bdim;
540 #endif
541 _grey_info.flags = features & 0xff;
542 _grey_info.fg_brightness = 0;
543 _grey_info.bg_brightness = 255;
544 _grey_info.drawmode = DRMODE_SOLID;
545 _grey_info.curfont = FONT_SYSFIXED;
547 /* precalculate the value -> pattern index conversion table, taking
548 linearisation and gamma correction into account */
549 if (features & GREY_RAWMAPPED)
551 for (i = 0; i < 256; i++)
553 data = i << 7;
554 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
557 else
559 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
560 if (_grey_info.rb->is_backlight_on(true))
561 _grey_info.flags |= _GREY_BACKLIGHT_ON;
562 #endif
563 fill_gvalues();
566 if (buf_taken) /* caller requested info about space taken */
567 *buf_taken = buftaken;
569 return true;
572 /* Release the greyscale display buffer and the library
573 DO CALL either this function or at least grey_show_display(false)
574 before you exit, otherwise nasty things may happen. */
575 void grey_release(void)
577 grey_show(false);
580 /* Switch the greyscale overlay on or off
581 DO NOT call lcd_update() or any other api function that directly accesses
582 the lcd while the greyscale overlay is running! If you need to do
583 lcd_update() to update something outside the greyscale overlay area, use
584 grey_deferred_update() instead.
586 Other functions to avoid are:
587 lcd_blit_mono(), lcd_update_rect(), lcd_set_contrast(),
588 lcd_set_invert_display(), lcd_set_flip() */
589 void grey_show(bool enable)
591 if (enable && !(_grey_info.flags & _GREY_RUNNING))
593 _grey_info.flags |= _GREY_RUNNING;
594 #ifdef SIMULATOR
595 _grey_info.rb->sim_lcd_ex_init(129, _grey_get_pixel);
596 _grey_info.rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
597 _grey_info.width, _grey_info.height);
598 #else /* !SIMULATOR */
599 #ifdef NEED_BOOST
600 _grey_info.rb->cpu_boost(true);
601 #endif
602 #if NUM_CORES > 1
603 _grey_info.rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE,
604 1, _timer_isr,
605 (_grey_info.flags & GREY_ON_COP) ? COP : CPU);
606 #else
607 _grey_info.rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE, 1,
608 _timer_isr);
609 #endif
610 #endif /* !SIMULATOR */
611 _grey_info.rb->screen_dump_set_hook(grey_screendump_hook);
613 else if (!enable && (_grey_info.flags & _GREY_RUNNING))
615 #ifdef SIMULATOR
616 _grey_info.rb->sim_lcd_ex_init(0, NULL);
617 #else /* !SIMULATOR */
618 _grey_info.rb->timer_unregister();
619 #if NUM_CORES > 1 /* Make sure the ISR has finished before calling lcd_update() */
620 _grey_info.rb->sleep(HZ/100);
621 #endif
622 #ifdef NEED_BOOST
623 _grey_info.rb->cpu_boost(false);
624 #endif
625 #endif /* !SIMULATOR */
626 _grey_info.flags &= ~_GREY_RUNNING;
627 _grey_info.rb->screen_dump_set_hook(NULL);
628 _grey_info.rb->lcd_update(); /* restore whatever there was before */
632 void grey_update_rect(int x, int y, int width, int height)
634 grey_ub_gray_bitmap_part(_grey_info.buffer, x, y, _grey_info.width,
635 x, y, width, height);
638 /* Update the whole greyscale overlay */
639 void grey_update(void)
641 grey_ub_gray_bitmap_part(_grey_info.buffer, 0, 0, _grey_info.width,
642 0, 0, _grey_info.width, _grey_info.height);
645 /* Do an lcd_update() to show changes done by rb->lcd_xxx() functions
646 (in areas of the screen not covered by the greyscale overlay). */
647 void grey_deferred_lcd_update(void)
649 if (_grey_info.flags & _GREY_RUNNING)
651 #ifdef SIMULATOR
652 _deferred_update();
653 #else
654 _grey_info.flags |= _GREY_DEFERRED_UPDATE;
655 #endif
657 else
658 _grey_info.rb->lcd_update();
661 /*** Screenshot ***/
663 #define BMP_FIXEDCOLORS (1 << LCD_DEPTH)
664 #define BMP_VARCOLORS 129
665 #define BMP_NUMCOLORS (BMP_FIXEDCOLORS + BMP_VARCOLORS)
666 #define BMP_BPP 8
667 #define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
668 #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
669 #define BMP_DATASIZE (BMP_LINESIZE * LCD_HEIGHT)
670 #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
672 #define LE16_CONST(x) (x)&0xff, ((x)>>8)&0xff
673 #define LE32_CONST(x) (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff
675 static const unsigned char bmpheader[] =
677 0x42, 0x4d, /* 'BM' */
678 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
679 0x00, 0x00, 0x00, 0x00, /* Reserved */
680 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
682 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
683 LE32_CONST(LCD_WIDTH), /* Width in pixels */
684 LE32_CONST(LCD_HEIGHT), /* Height in pixels */
685 0x01, 0x00, /* Number of planes (always 1) */
686 LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
687 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */
688 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
689 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
690 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
691 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
692 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
694 /* Fixed colours */
695 #if LCD_DEPTH == 1
696 0x90, 0xee, 0x90, 0x00, /* Colour #0 */
697 0x00, 0x00, 0x00, 0x00 /* Colour #1 */
698 #elif LCD_DEPTH == 2
699 0xe6, 0xd8, 0xad, 0x00, /* Colour #0 */
700 0x99, 0x90, 0x73, 0x00, /* Colour #1 */
701 0x4c, 0x48, 0x39, 0x00, /* Colour #2 */
702 0x00, 0x00, 0x00, 0x00 /* Colour #3 */
703 #endif
706 #if LCD_DEPTH == 1
707 #define BMP_RED 0x90
708 #define BMP_GREEN 0xee
709 #define BMP_BLUE 0x90
710 #elif LCD_DEPTH == 2
711 #define BMP_RED 0xad
712 #define BMP_GREEN 0xd8
713 #define BMP_BLUE 0xe6
714 #endif
716 /* Hook function for core screen_dump() to save the current display
717 content (b&w and greyscale overlay) to an 8-bit BMP file. */
718 static void grey_screendump_hook(int fd)
720 int i;
721 int x, y, gx, gy;
722 #if LCD_PIXELFORMAT == VERTICAL_PACKING
723 #if LCD_DEPTH == 1
724 unsigned mask;
725 #elif LCD_DEPTH == 2
726 int shift;
727 #endif
728 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
729 unsigned data;
730 int shift;
731 #endif /* LCD_PIXELFORMAT */
732 fb_data *lcdptr;
733 unsigned char *clut_entry;
734 unsigned char linebuf[MAX(4*BMP_VARCOLORS,BMP_LINESIZE)];
736 _grey_info.rb->write(fd, bmpheader, sizeof(bmpheader)); /* write header */
738 /* build clut */
739 _grey_info.rb->memset(linebuf, 0, 4*BMP_VARCOLORS);
740 clut_entry = linebuf;
742 for (i = 0; i <= 128; i++)
744 *clut_entry++ = _GREY_MULUQ(BMP_BLUE, i) >> 7;
745 *clut_entry++ = _GREY_MULUQ(BMP_GREEN, i) >> 7;
746 *clut_entry++ = _GREY_MULUQ(BMP_RED, i) >> 7;
747 clut_entry++;
749 _grey_info.rb->write(fd, linebuf, 4*BMP_VARCOLORS);
751 /* BMP image goes bottom -> top */
752 for (y = LCD_HEIGHT - 1; y >= 0; y--)
754 _grey_info.rb->memset(linebuf, 0, BMP_LINESIZE);
756 gy = y - _grey_info.y;
757 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
758 #if LCD_DEPTH == 2
759 lcdptr = _grey_info.rb->lcd_framebuffer + _GREY_MULUQ(LCD_FBWIDTH, y);
761 for (x = 0; x < LCD_WIDTH; x += 4)
763 gx = x - _grey_info.x;
765 if (((unsigned)gy < (unsigned)_grey_info.height)
766 && ((unsigned)gx < (unsigned)_grey_info.width))
768 unsigned char *src = _grey_info.values
769 + _GREY_MULUQ(_grey_info.width, gy) + gx;
770 for (i = 0; i < 4; i++)
771 linebuf[x + i] = BMP_FIXEDCOLORS + *src++;
773 else
775 unsigned data = *lcdptr;
776 linebuf[x] = (data >> 6) & 3;
777 linebuf[x + 1] = (data >> 4) & 3;
778 linebuf[x + 2] = (data >> 2) & 3;
779 linebuf[x + 3] = data & 3;
781 lcdptr++;
783 #endif /* LCD_DEPTH */
784 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
785 #if LCD_DEPTH == 1
786 mask = 1 << (y & 7);
787 lcdptr = _grey_info.rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
789 for (x = 0; x < LCD_WIDTH; x++)
791 gx = x - _grey_info.x;
793 if (((unsigned)gy < (unsigned)_grey_info.height)
794 && ((unsigned)gx < (unsigned)_grey_info.width))
796 linebuf[x] = BMP_FIXEDCOLORS
797 + _grey_info.values[_GREY_MULUQ(_grey_info.width,
798 gy & ~_GREY_BMASK)
799 + (gx << _GREY_BSHIFT)
800 + (~gy & _GREY_BMASK)];
802 else
804 linebuf[x] = (*lcdptr & mask) ? 1 : 0;
806 lcdptr++;
808 #elif LCD_DEPTH == 2
809 shift = 2 * (y & 3);
810 lcdptr = _grey_info.rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 2);
812 for (x = 0; x < LCD_WIDTH; x++)
814 gx = x - _grey_info.x;
816 if (((unsigned)gy < (unsigned)_grey_info.height)
817 && ((unsigned)gx < (unsigned)_grey_info.width))
819 linebuf[x] = BMP_FIXEDCOLORS
820 + _grey_info.values[_GREY_MULUQ(_grey_info.width,
821 gy & ~_GREY_BMASK)
822 + (gx << _GREY_BSHIFT)
823 + (~gy & _GREY_BMASK)];
825 else
827 linebuf[x] = (*lcdptr >> shift) & 3;
829 lcdptr++;
831 #endif /* LCD_DEPTH */
832 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
833 #if LCD_DEPTH == 2
834 shift = y & 7;
835 lcdptr = _grey_info.rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
837 for (x = 0; x < LCD_WIDTH; x++)
839 gx = x - _grey_info.x;
841 if (((unsigned)gy < (unsigned)_grey_info.height)
842 && ((unsigned)gx < (unsigned)_grey_info.width))
844 linebuf[x] = BMP_FIXEDCOLORS
845 + _grey_info.values[_GREY_MULUQ(_grey_info.width,
846 gy & ~_GREY_BMASK)
847 + (gx << _GREY_BSHIFT)
848 + (~gy & _GREY_BMASK)];
850 else
852 data = (*lcdptr >> shift) & 0x0101;
853 linebuf[x] = ((data >> 7) | data) & 3;
855 lcdptr++;
857 #endif /* LCD_DEPTH */
858 #endif /* LCD_PIXELFORMAT */
860 _grey_info.rb->write(fd, linebuf, BMP_LINESIZE);