Correct beast manual install instructions in Windows.
[kugel-rb.git] / apps / plugins / lib / grey_core.c
blob6fa422be05bd4362f45bb63e09408406466fd730
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 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
26 ****************************************************************************/
28 #include "plugin.h"
29 #include "grey.h"
31 #if defined(HAVE_ADJUSTABLE_CPU_FREQ) && \
32 (defined(CPU_PP) || (CONFIG_LCD == LCD_TL0350A))
33 #define NEED_BOOST
34 #endif
36 #ifndef SIMULATOR
38 #if defined ARCHOS_RECORDER /* verified */ \
39 || defined ARCHOS_FMRECORDER /* should be identical */ \
40 || defined ARCHOS_RECORDERV2 /* should be identical */ \
41 || defined ARCHOS_ONDIOFM /* verified */ \
42 || defined ARCHOS_ONDIOSP /* verified */
43 /* Average measurements of a Recorder v1, an Ondio FM, a backlight-modded
44 * Ondio FM, and an Ondio SP. */
45 static const unsigned char lcdlinear[256] = {
46 5, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 29, 31, 33, 35,
47 37, 39, 40, 42, 43, 45, 46, 48, 49, 50, 51, 53, 54, 55, 57, 58,
48 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 71, 72,
49 73, 74, 74, 75, 76, 77, 77, 78, 79, 79, 80, 80, 81, 81, 82, 82,
50 83, 84, 84, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91,
51 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
52 101, 101, 102, 103, 103, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109,
53 110, 110, 111, 112, 112, 113, 114, 114, 115, 115, 116, 117, 117, 118, 119, 119,
54 120, 120, 121, 122, 123, 123, 124, 125, 126, 126, 127, 128, 129, 129, 130, 131,
55 132, 132, 133, 134, 135, 135, 136, 137, 138, 138, 139, 140, 140, 141, 141, 142,
56 143, 144, 145, 146, 147, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 156,
57 157, 158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170,
58 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 184, 185, 186, 187,
59 188, 189, 191, 192, 194, 195, 197, 198, 199, 200, 202, 203, 204, 205, 207, 208,
60 209, 210, 212, 213, 215, 216, 218, 219, 220, 221, 222, 223, 225, 226, 227, 228,
61 229, 230, 232, 233, 234, 235, 237, 238, 239, 240, 242, 243, 244, 246, 247, 248
63 /* The actual LCD scanrate varies a lot with temperature on these targets */
64 #define LCD_SCANRATE 67 /* Hz */
66 #elif defined IAUDIO_M3 /* verified */
67 /* Average measurements of 2 iAudio remotes connected to an M3. */
68 static const unsigned char lcdlinear[256] = {
69 5, 9, 13, 17, 21, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66,
70 70, 73, 76, 78, 80, 82, 84, 86, 88, 90, 91, 92, 94, 95, 96, 97,
71 98, 99, 99, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108,
72 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
73 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 123, 123, 123,
74 124, 124, 124, 125, 125, 126, 126, 126, 127, 127, 127, 128, 128, 129, 129, 129,
75 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 134, 135, 135, 136, 136, 136,
76 137, 137, 137, 138, 138, 139, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143,
77 144, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 150, 151, 151, 152, 152,
78 153, 153, 154, 154, 155, 155, 156, 156, 157, 157, 158, 158, 159, 160, 160, 161,
79 162, 162, 163, 164, 164, 165, 166, 167, 168, 168, 169, 169, 170, 171, 171, 172,
80 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180, 181, 182, 182, 183, 184,
81 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201,
82 202, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219,
83 220, 221, 222, 223, 225, 226, 227, 228, 229, 230, 231, 232, 234, 235, 236, 237,
84 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 249, 250, 251, 252
86 /* The actual LCD scanrate is 3x as high, but 150 Hz or 75 Hz cause a too high
87 * CPU load (> 50 %). Even at 50Hz, greyscale display is rather smooth. Average
88 * from 2 iAudio remotes. */
89 #define LCD_SCANRATE 50 /* Hz */
91 #elif defined IAUDIO_M5 /* verified */
92 /* Measurement of one iAudio M5L */
93 static const unsigned char lcdlinear[256] = {
94 4, 6, 8, 10, 11, 13, 15, 17, 19, 21, 22, 24, 25, 27, 28, 30,
95 32, 33, 35, 36, 37, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 51,
96 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63,
97 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 70, 70, 71, 72, 72,
98 73, 73, 74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81,
99 82, 82, 83, 84, 84, 85, 86, 86, 87, 87, 88, 89, 89, 90, 91, 91,
100 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
101 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
102 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
103 117, 117, 118, 119, 119, 120, 121, 121, 122, 122, 123, 124, 124, 125, 126, 126,
104 127, 127, 128, 129, 130, 130, 131, 132, 133, 133, 134, 135, 135, 136, 137, 137,
105 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151,
106 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 167, 168, 169,
107 170, 172, 173, 175, 177, 179, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198,
108 200, 202, 204, 205, 207, 209, 210, 212, 214, 216, 218, 219, 221, 223, 224, 226,
109 228, 230, 231, 233, 235, 236, 237, 239, 241, 243, 244, 246, 248, 249, 250, 252
111 #define LCD_SCANRATE 73 /* Hz */
113 #elif defined IPOD_1G2G /* verified */
114 /* Average measurements of an iPod 1st Gen (0x00010001) and an iPod 2nd Gen
115 * (0x00020000), measured with both backlight off & backlight on (flipped
116 * curves) and medium load (white background when measuring with backlight on),
117 * as the curve is load dependent (the controller's step-up converter doesn't
118 * provide enough juice). Table is for backlight_off state. */
119 static const unsigned char lcdlinear[256] = {
120 4, 6, 8, 9, 11, 13, 14, 16, 17, 18, 20, 21, 23, 24, 26, 27,
121 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 41, 42, 43, 44,
122 45, 45, 46, 47, 47, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53,
123 54, 54, 54, 55, 55, 56, 56, 56, 57, 57, 57, 58, 58, 59, 59, 59,
124 60, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 65, 65, 65,
125 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73,
126 74, 74, 74, 75, 75, 76, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80,
127 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88,
128 89, 89, 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 97, 98, 99, 99,
129 100, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108, 109, 109,
130 110, 110, 111, 112, 113, 113, 114, 115, 116, 116, 117, 118, 119, 119, 120, 121,
131 122, 122, 123, 124, 125, 125, 126, 127, 128, 129, 130, 131, 131, 132, 133, 134,
132 135, 137, 138, 139, 141, 142, 144, 145, 146, 147, 149, 150, 151, 152, 154, 155,
133 156, 158, 159, 161, 162, 164, 165, 167, 169, 171, 172, 174, 175, 177, 178, 180,
134 182, 184, 186, 188, 189, 191, 193, 195, 197, 199, 201, 203, 206, 208, 210, 212,
135 214, 217, 219, 221, 224, 226, 229, 231, 233, 236, 238, 240, 243, 245, 247, 250
137 /* Average from an iPod 1st Gen and an iPod 2nd Gen */
138 #define LCD_SCANRATE 96 /* Hz */
140 #elif defined IPOD_MINI2G /* verified */ \
141 || defined IPOD_MINI /* should be identical */ \
142 || defined IPOD_3G /* TODO: verify */ \
143 || defined IPOD_4G /* TODO: verify */
144 /* Measurement of one iPod Mini G2 */
145 static const unsigned char lcdlinear[256] = {
146 2, 5, 7, 10, 12, 15, 17, 20, 22, 24, 26, 28, 30, 32, 34, 36,
147 38, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 52, 53,
148 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 58, 59, 59, 60, 60, 60,
149 61, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65,
150 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69,
151 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 73, 73, 74, 74, 74,
152 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 78, 78, 79, 79, 79,
153 80, 80, 80, 81, 81, 82, 82, 82, 83, 83, 83, 84, 84, 85, 85, 85,
154 86, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92,
155 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 99, 99, 100, 101, 101,
156 102, 102, 103, 104, 104, 105, 106, 106, 107, 108, 109, 110, 110, 111, 112, 113,
157 114, 115, 115, 116, 117, 118, 118, 119, 120, 121, 121, 122, 123, 124, 124, 125,
158 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
159 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 153, 154, 155, 156, 158, 159,
160 160, 162, 163, 165, 166, 168, 169, 171, 172, 175, 177, 180, 182, 185, 187, 190,
161 192, 196, 199, 203, 206, 210, 213, 217, 220, 223, 227, 230, 234, 238, 242, 246
163 /* Average of an iPod Mini G2 and 2 3rd Gen iPods. */
164 #define LCD_SCANRATE 87 /* Hz */
166 #elif defined IRIVER_H100_SERIES /* verified */
167 /* Measurement of one Iriver H140 */
168 static const unsigned char lcdlinear[256] = {
169 5, 8, 12, 15, 18, 22, 25, 28, 31, 34, 36, 39, 42, 44, 47, 50,
170 53, 55, 57, 59, 62, 64, 66, 68, 70, 71, 72, 73, 75, 76, 77, 78,
171 79, 80, 80, 81, 82, 83, 83, 84, 85, 85, 86, 86, 87, 87, 88, 88,
172 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95,
173 96, 96, 96, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101,
174 102, 102, 102, 103, 103, 104, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
175 109, 109, 109, 110, 110, 111, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115,
176 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123,
177 124, 124, 125, 125, 126, 127, 127, 128, 129, 129, 130, 130, 131, 131, 132, 132,
178 133, 133, 134, 135, 135, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141,
179 142, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 148, 149, 150, 150, 151,
180 152, 152, 153, 153, 154, 155, 155, 156, 157, 157, 158, 159, 160, 160, 161, 162,
181 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
182 178, 179, 181, 182, 183, 184, 186, 187, 188, 189, 191, 192, 193, 194, 196, 197,
183 198, 200, 202, 203, 205, 207, 208, 210, 212, 214, 215, 217, 218, 220, 221, 223,
184 224, 226, 228, 229, 231, 233, 235, 236, 238, 240, 241, 242, 244, 245, 246, 248
186 #define LCD_SCANRATE 70 /* Hz */
188 #elif defined MROBE_100 /* verified */
189 /* Average measurements of 2 m:robe 100 s */
190 static const unsigned char lcdlinear[256] = {
191 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 49, 53, 56, 60, 63, 67,
192 70, 73, 76, 79, 81, 84, 87, 90, 92, 95, 97, 100, 102, 105, 107, 110,
193 112, 114, 116, 118, 119, 121, 123, 125, 126, 128, 130, 131, 133, 135, 136, 138,
194 139, 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156, 157,
195 158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170, 171,
196 172, 172, 173, 173, 174, 174, 175, 175, 176, 176, 177, 178, 178, 179, 180, 180,
197 181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188,
198 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 193, 194, 194, 195, 195, 195,
199 196, 196, 197, 197, 198, 198, 199, 199, 200, 200, 200, 201, 201, 202, 202, 202,
200 203, 203, 204, 204, 205, 205, 206, 206, 207, 207, 207, 208, 208, 209, 209, 209,
201 210, 210, 210, 211, 211, 212, 212, 212, 213, 213, 213, 214, 214, 215, 215, 215,
202 216, 216, 216, 217, 217, 218, 218, 218, 219, 219, 219, 220, 220, 221, 221, 221,
203 222, 222, 222, 223, 223, 224, 224, 224, 225, 225, 225, 226, 226, 227, 227, 227,
204 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234, 234,
205 235, 235, 235, 236, 236, 237, 237, 237, 238, 238, 238, 239, 239, 240, 240, 240,
206 241, 241, 242, 242, 243, 243, 244, 244, 247, 248, 248, 249, 250, 250, 251, 252
208 #define LCD_SCANRATE 51 /* Hz */
210 #elif defined SANSA_CLIP /* NOT verified */
211 static const unsigned char lcdlinear[256] = {
212 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
213 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
214 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
215 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
216 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
217 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
218 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
219 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
220 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
221 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
222 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
223 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
224 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
225 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
226 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
227 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
229 #define LCD_SCANRATE 78 /* Hz */
231 #else /* not yet calibrated targets - generic linear mapping */
232 /* TODO: calibrate iFP7xx */
233 static const unsigned char lcdlinear[256] = {
234 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
235 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
236 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
237 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
238 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
239 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
240 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
241 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
242 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
243 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
244 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
245 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
246 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
247 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
248 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
249 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
251 /* generic default */
252 #define LCD_SCANRATE 70 /* Hz */
254 #endif
255 #else /* SIMULATOR */
256 /* undo a (generic) PC display gamma of 2.0 to simulate target behaviour */
257 static const unsigned char lcdlinear[256] = {
258 0, 16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 58, 60, 62,
259 64, 66, 68, 70, 71, 73, 75, 77, 78, 80, 81, 83, 84, 86, 87, 89,
260 90, 92, 93, 94, 96, 97, 98, 100, 101, 102, 103, 105, 106, 107, 108, 109,
261 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127,
262 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 142,
263 143, 144, 145, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156,
264 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
265 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180,
266 181, 181, 182, 183, 183, 184, 185, 186, 186, 187, 188, 188, 189, 190, 190, 191,
267 192, 192, 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 201, 201,
268 202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
269 212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 220, 220, 221,
270 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 228, 228, 229, 229, 230,
271 230, 231, 231, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
272 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
273 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
275 #endif /* SIMULATOR */
277 /* Prototypes */
278 static inline void _deferred_update(void) __attribute__ ((always_inline));
279 static int exp_s16p16(int x);
280 static int log_s16p16(int x);
281 static void grey_screendump_hook(int fd);
282 static void fill_gvalues(void);
283 #ifdef SIMULATOR
284 static unsigned long _grey_get_pixel(int x, int y);
285 #else
286 static void _timer_isr(void);
287 #endif
290 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
291 static void invert_gvalues(void)
293 unsigned char *val, *end;
294 unsigned char rev_tab[256];
295 unsigned i;
296 unsigned last_i = 0;
297 unsigned x = 0;
298 unsigned last_x;
300 /* Step 1: Calculate a transposed table for undoing the old mapping */
301 for (i = 0; i < 256; i++)
303 last_x = x;
304 x = _grey_info.gvalue[i];
305 if (x > last_x)
307 rev_tab[last_x++] = (last_i + i) / 2;
308 while (x > last_x)
309 rev_tab[last_x++] = i;
310 last_i = i;
313 rev_tab[last_x++] = (last_i + 255) / 2;
314 while (256 > last_x)
315 rev_tab[last_x++] = 255;
317 /* Step 2: Calculate new mapping */
318 fill_gvalues();
320 /* Step 3: Transpose all pixel values */
321 val = _grey_info.values;
322 end = val + _GREY_MULUQ(_grey_info.width, _grey_info.height);
325 *val = _grey_info.gvalue[rev_tab[*val]];
326 while (++val < end);
328 #endif
330 /* Update LCD areas not covered by the greyscale overlay */
331 static inline void _deferred_update(void)
333 int x1 = MAX(_grey_info.x, 0);
334 int x2 = MIN(_grey_info.x + _grey_info.width, LCD_WIDTH);
335 int y1 = MAX(_grey_info.y, 0);
336 int y2 = MIN(_grey_info.y + _grey_info.height, LCD_HEIGHT);
338 if (y1 > 0) /* refresh part above overlay, full width */
339 rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
341 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
342 rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
344 if (x1 > 0) /* refresh part to the left of overlay */
345 rb->lcd_update_rect(0, y1, x1, y2 - y1);
347 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
348 rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
351 #ifdef SIMULATOR
353 /* Callback function for grey_ub_gray_bitmap_part() to read a pixel from the
354 * greybuffer. Note that x and y are in LCD coordinates, not greybuffer
355 * coordinates! */
356 static unsigned long _grey_get_pixel(int x, int y)
358 long val;
359 int xg = x - _grey_info.x;
360 int yg = y - _grey_info.y;
361 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
362 int idx = _grey_info.width * yg + xg;
363 #else /* vertical packing or vertical interleaved */
364 int idx = _grey_info.width * (yg & ~_GREY_BMASK)
365 + (xg << _GREY_BSHIFT) + (~yg & _GREY_BMASK);
366 #endif
368 val = _grey_info.values[idx];
369 #ifdef HAVE_LCD_SPLIT
370 val -= val >> 7;
371 #endif
372 return val;
375 #else /* !SIMULATOR */
377 /* Timer interrupt handler: display next frame */
378 static void _timer_isr(void)
380 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
381 unsigned long check = rb->is_backlight_on(true)
382 ? 0 : _GREY_BACKLIGHT_ON;
384 if ((_grey_info.flags & (_GREY_BACKLIGHT_ON|GREY_RAWMAPPED)) == check)
386 _grey_info.flags ^= _GREY_BACKLIGHT_ON;
387 invert_gvalues();
388 return; /* don't overload this timer slot */
390 #endif
391 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
392 rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
393 _grey_info.bx, _grey_info.y,
394 _grey_info.bwidth, _grey_info.height,
395 _grey_info.width);
396 #else /* vertical packing or vertical interleaved */
397 rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
398 _grey_info.x, _grey_info.by,
399 _grey_info.width, _grey_info.bheight,
400 _grey_info.width);
401 #endif
403 if (_grey_info.flags & _GREY_DEFERRED_UPDATE) /* lcd_update() requested? */
405 _deferred_update();
406 _grey_info.flags &= ~_GREY_DEFERRED_UPDATE; /* clear request */
410 #endif /* !SIMULATOR */
412 /* fixed point exp() */
413 static int exp_s16p16(int x)
415 int t;
416 int y = 0x00010000;
418 if (x < 0) x += 0xb1721, y >>= 16;
419 t = x - 0x58b91; if (t >= 0) x = t, y <<= 8;
420 t = x - 0x2c5c8; if (t >= 0) x = t, y <<= 4;
421 t = x - 0x162e4; if (t >= 0) x = t, y <<= 2;
422 t = x - 0x0b172; if (t >= 0) x = t, y <<= 1;
423 t = x - 0x067cd; if (t >= 0) x = t, y += y >> 1;
424 t = x - 0x03920; if (t >= 0) x = t, y += y >> 2;
425 t = x - 0x01e27; if (t >= 0) x = t, y += y >> 3;
426 t = x - 0x00f85; if (t >= 0) x = t, y += y >> 4;
427 t = x - 0x007e1; if (t >= 0) x = t, y += y >> 5;
428 t = x - 0x003f8; if (t >= 0) x = t, y += y >> 6;
429 t = x - 0x001fe; if (t >= 0) x = t, y += y >> 7;
430 y += ((y >> 8) * x) >> 8;
432 return y;
435 /* fixed point log() */
436 static int log_s16p16(int x)
438 int t;
439 int y = 0xa65af;
441 if (x < 0x00008000) x <<=16, y -= 0xb1721;
442 if (x < 0x00800000) x <<= 8, y -= 0x58b91;
443 if (x < 0x08000000) x <<= 4, y -= 0x2c5c8;
444 if (x < 0x20000000) x <<= 2, y -= 0x162e4;
445 if (x < 0x40000000) x <<= 1, y -= 0x0b172;
446 t = x + (x >> 1); if ((t & 0x80000000) == 0) x = t, y -= 0x067cd;
447 t = x + (x >> 2); if ((t & 0x80000000) == 0) x = t, y -= 0x03920;
448 t = x + (x >> 3); if ((t & 0x80000000) == 0) x = t, y -= 0x01e27;
449 t = x + (x >> 4); if ((t & 0x80000000) == 0) x = t, y -= 0x00f85;
450 t = x + (x >> 5); if ((t & 0x80000000) == 0) x = t, y -= 0x007e1;
451 t = x + (x >> 6); if ((t & 0x80000000) == 0) x = t, y -= 0x003f8;
452 t = x + (x >> 7); if ((t & 0x80000000) == 0) x = t, y -= 0x001fe;
453 x = 0x80000000 - x;
454 y -= x >> 15;
456 return y;
459 static void fill_gvalues(void)
461 int i;
462 unsigned data;
464 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
465 unsigned imask = (_grey_info.flags & _GREY_BACKLIGHT_ON) ? 0xff : 0;
466 #else
467 const unsigned imask = 0;
468 #endif
469 for (i = 0; i < 256; i++)
471 data = exp_s16p16((_GREY_GAMMA * log_s16p16(i * 257 + 1)) >> 8) + 128;
472 data = (data - (data >> 8)) >> 8; /* approx. data /= 257 */
473 data = ((lcdlinear[data ^ imask] ^ imask) << 7) + 127;
474 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
475 /* approx. data / 255 */
479 /* Initialise the framework and prepare the greyscale display buffer
481 arguments:
482 newrb = pointer to plugin api
483 gbuf = pointer to the memory area to use (e.g. plugin buffer)
484 gbuf_size = max usable size of the buffer
485 features = flags for requesting features
486 GREY_BUFFERED: use chunky pixel buffering
487 This allows to use all drawing functions, but needs more
488 memory. Unbuffered operation provides only a subset of
489 drawing functions. (only grey_bitmap drawing and scrolling)
490 GREY_RAWMAPPED: no LCD linearisation and gamma correction
491 width = width in pixels (1..LCD_WIDTH)
492 height = height in pixels (1..LCD_HEIGHT)
493 Note that depending on the target LCD, either height or
494 width are rounded up to a multiple of 4 or 8.
496 result:
497 true on success, false on failure
499 If you need info about the memory taken by the greyscale buffer, supply a
500 long* as the last parameter. This long will then contain the number of bytes
501 used. The total memory needed can be calculated as follows:
502 total_mem =
503 width * height * 2 [grey display data]
504 + buffered ? (width * height) : 0 [chunky buffer]
505 + 0..3 [alignment]
507 The function is authentic regarding memory usage on the simulator, even
508 if it doesn't use all of the allocated memory. */
509 bool grey_init(unsigned char *gbuf, long gbuf_size,
510 unsigned features, int width, int height, long *buf_taken)
512 int bdim, i;
513 long plane_size, buftaken;
514 unsigned data;
515 #ifndef SIMULATOR
516 unsigned *dst, *end;
517 #endif
519 if ((unsigned) width > LCD_WIDTH
520 || (unsigned) height > LCD_HEIGHT)
521 return false;
523 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
524 bdim = (width + 7) >> 3;
525 width = bdim << 3;
526 #else /* vertical packing or vertical interleaved */
527 #if (LCD_DEPTH == 1) || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
528 bdim = (height + 7) >> 3;
529 height = bdim << 3;
530 #elif LCD_DEPTH == 2
531 bdim = (height + 3) >> 2;
532 height = bdim << 2;
533 #endif
534 #endif
536 plane_size = _GREY_MULUQ(width, height);
537 #if defined(CPU_COLDFIRE) /* Buffers should be line aligned */ \
538 || defined(CPU_PP) && (NUM_CORES > 1) /* Buffers must be cache line aligned */
539 plane_size += (-plane_size) & 0xf;
540 buftaken = (-(long)gbuf) & 0xf;
541 #else /* Buffers must be 32 bit aligned. */
542 buftaken = (-(long)gbuf) & 3;
543 #endif
544 gbuf += buftaken;
546 if (features & GREY_BUFFERED) /* chunky buffer */
548 _grey_info.buffer = gbuf;
549 gbuf += plane_size;
550 buftaken += plane_size;
552 #if NUM_CORES > 1 /* Values and phases must be uncached when running on COP */
553 if (features & GREY_ON_COP)
554 gbuf = UNCACHED_ADDR(gbuf);
555 #endif
556 _grey_info.values = gbuf;
557 gbuf += plane_size;
558 _grey_info.phases = gbuf;
559 buftaken += 2 * plane_size;
561 if (buftaken > gbuf_size)
562 return false;
564 /* Init to white */
565 rb->memset(_grey_info.values, 0x80, plane_size);
567 #ifndef SIMULATOR
568 /* Init phases with random bits */
569 dst = (unsigned*)(_grey_info.phases);
570 end = (unsigned*)(_grey_info.phases + plane_size);
573 *dst++ = rb->rand();
574 while (dst < end);
575 #endif
577 _grey_info.x = 0;
578 _grey_info.y = 0;
579 _grey_info.width = width;
580 _grey_info.height = height;
581 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
582 _grey_info.bx = 0;
583 _grey_info.bwidth = bdim;
584 #else /* vertical packing or vertical interleaved */
585 _grey_info.by = 0;
586 _grey_info.bheight = bdim;
587 #endif
588 _grey_info.flags = features & 0xff;
589 _grey_info.fg_brightness = 0;
590 _grey_info.bg_brightness = 255;
591 _grey_info.drawmode = DRMODE_SOLID;
592 _grey_info.curfont = FONT_SYSFIXED;
594 /* precalculate the value -> pattern index conversion table, taking
595 linearisation and gamma correction into account */
596 if (features & GREY_RAWMAPPED)
598 for (i = 0; i < 256; i++)
600 data = i << 7;
601 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
604 else
606 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
607 if (rb->is_backlight_on(true))
608 _grey_info.flags |= _GREY_BACKLIGHT_ON;
609 #endif
610 fill_gvalues();
613 if (buf_taken) /* caller requested info about space taken */
614 *buf_taken = buftaken;
616 return true;
619 /* Release the greyscale display buffer and the library
620 DO CALL either this function or at least grey_show_display(false)
621 before you exit, otherwise nasty things may happen. */
622 void grey_release(void)
624 grey_show(false);
627 /* Switch the greyscale overlay on or off
628 DO NOT call lcd_update() or any other api function that directly accesses
629 the lcd while the greyscale overlay is running! If you need to do
630 lcd_update() to update something outside the greyscale overlay area, use
631 grey_deferred_update() instead.
633 Other functions to avoid are:
634 lcd_blit_mono(), lcd_update_rect(), lcd_set_contrast(),
635 lcd_set_invert_display(), lcd_set_flip() */
636 void grey_show(bool enable)
638 if (enable && !(_grey_info.flags & _GREY_RUNNING))
640 _grey_info.flags |= _GREY_RUNNING;
641 #ifdef SIMULATOR
642 rb->sim_lcd_ex_init(_grey_get_pixel);
643 rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
644 _grey_info.width, _grey_info.height);
645 #else /* !SIMULATOR */
646 #ifdef NEED_BOOST
647 rb->cpu_boost(true);
648 #endif
649 #if NUM_CORES > 1
650 rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE,
651 _timer_isr,
652 (_grey_info.flags & GREY_ON_COP) ? COP : CPU);
653 #else
654 rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE, _timer_isr);
655 #endif
656 #endif /* !SIMULATOR */
657 rb->screen_dump_set_hook(grey_screendump_hook);
659 else if (!enable && (_grey_info.flags & _GREY_RUNNING))
661 #ifdef SIMULATOR
662 rb->sim_lcd_ex_init(NULL);
663 #else /* !SIMULATOR */
664 rb->timer_unregister();
665 #if NUM_CORES > 1 /* Make sure the ISR has finished before calling lcd_update() */
666 rb->sleep(HZ/100);
667 #endif
668 #ifdef NEED_BOOST
669 rb->cpu_boost(false);
670 #endif
671 #endif /* !SIMULATOR */
672 _grey_info.flags &= ~_GREY_RUNNING;
673 rb->screen_dump_set_hook(NULL);
674 rb->lcd_update(); /* restore whatever there was before */
678 void grey_update_rect(int x, int y, int width, int height)
680 grey_ub_gray_bitmap_part(_grey_info.buffer, x, y, _grey_info.width,
681 x, y, width, height);
684 /* Update the whole greyscale overlay */
685 void grey_update(void)
687 grey_ub_gray_bitmap_part(_grey_info.buffer, 0, 0, _grey_info.width,
688 0, 0, _grey_info.width, _grey_info.height);
691 /* Do an lcd_update() to show changes done by rb->lcd_xxx() functions
692 (in areas of the screen not covered by the greyscale overlay). */
693 void grey_deferred_lcd_update(void)
695 if (_grey_info.flags & _GREY_RUNNING)
697 #ifdef SIMULATOR
698 _deferred_update();
699 #else
700 _grey_info.flags |= _GREY_DEFERRED_UPDATE;
701 #endif
703 else
704 rb->lcd_update();
707 /*** Screenshot ***/
709 #ifdef HAVE_LCD_SPLIT
710 #define NUM_SHADES 128
711 #define BMP_NUMCOLORS 256
712 #else
713 #define NUM_SHADES 129
714 #define BMP_NUMCOLORS 129
715 #endif
717 #define BMP_BPP 8
718 #define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
719 #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
720 #define BMP_DATASIZE (BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
721 #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
723 static const unsigned char bmpheader[] =
725 0x42, 0x4d, /* 'BM' */
726 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
727 0x00, 0x00, 0x00, 0x00, /* Reserved */
728 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
730 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
731 LE32_CONST(LCD_WIDTH), /* Width in pixels */
732 LE32_CONST(LCD_HEIGHT+LCD_SPLIT_LINES), /* Height in pixels */
733 0x01, 0x00, /* Number of planes (always 1) */
734 LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
735 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */
736 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
737 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
738 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
739 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
740 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
743 #if LCD_DEPTH == 2
744 /* Only defined for positive, non-split LCD for now */
745 static const unsigned char colorindex[4] = {128, 85, 43, 0};
746 #endif
748 /* Hook function for core screen_dump() to save the current display
749 content (b&w and greyscale overlay) to an 8-bit BMP file. */
750 static void grey_screendump_hook(int fd)
752 int i;
753 int y, gx, gy;
754 #if LCD_PIXELFORMAT == VERTICAL_PACKING
755 #if LCD_DEPTH == 1
756 unsigned val;
757 unsigned mask;
758 #elif LCD_DEPTH == 2
759 int shift;
760 #endif
761 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
762 unsigned data;
763 int shift;
764 #endif /* LCD_PIXELFORMAT */
765 fb_data *src;
766 unsigned char *gsrc;
767 unsigned char *dst, *dst_end;
768 unsigned char linebuf[MAX(4*NUM_SHADES,BMP_LINESIZE)];
770 rb->write(fd, bmpheader, sizeof(bmpheader)); /* write header */
772 /* build clut */
773 rb->memset(linebuf, 0, 4*NUM_SHADES);
774 dst = linebuf;
776 for (i = 0; i < NUM_SHADES; i++)
778 *dst++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR)
779 -BLUE_CMP(LCD_BL_DARKCOLOR), i) >> 7)
780 + BLUE_CMP(LCD_BL_DARKCOLOR);
781 *dst++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR)
782 -GREEN_CMP(LCD_BL_DARKCOLOR), i) >> 7)
783 + GREEN_CMP(LCD_BL_DARKCOLOR);
784 *dst++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR)
785 -RED_CMP(LCD_BL_DARKCOLOR), i) >> 7)
786 + RED_CMP(LCD_BL_DARKCOLOR);
787 dst++;
789 rb->write(fd, linebuf, 4*NUM_SHADES);
791 #ifdef HAVE_LCD_SPLIT
792 dst = linebuf;
794 for (i = 0; i <= NUM_SHADES; i++)
796 *dst++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR_2)
797 -BLUE_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
798 + BLUE_CMP(LCD_BL_DARKCOLOR_2);
799 *dst++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR_2)
800 -GREEN_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
801 + GREEN_CMP(LCD_BL_DARKCOLOR_2);
802 *dst++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR_2)
803 -RED_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
804 + RED_CMP(LCD_BL_DARKCOLOR_2);
805 dst++;
807 rb->write(fd, linebuf, 4*NUM_SHADES);
808 #endif
810 /* BMP image goes bottom -> top */
811 for (y = LCD_HEIGHT - 1; y >= 0; y--)
813 rb->memset(linebuf, 0, BMP_LINESIZE);
815 #if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
816 if (y == LCD_SPLIT_POS - 1)
818 rb->write(fd, linebuf, BMP_LINESIZE);
819 rb->write(fd, linebuf, BMP_LINESIZE);
821 #endif
823 dst = linebuf;
824 dst_end = dst + LCD_WIDTH;
825 gy = y - _grey_info.y;
826 gx = -_grey_info.x;
828 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
829 gsrc = _grey_info.values + _GREY_MULUQ(_grey_info.width, gy);
831 #if LCD_DEPTH == 2
832 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_FBWIDTH, y);
836 if (((unsigned)gy < (unsigned)_grey_info.height)
837 && ((unsigned)gx < (unsigned)_grey_info.width))
839 *dst++ = *gsrc++;
840 *dst++ = *gsrc++;
841 *dst++ = *gsrc++;
842 *dst++ = *gsrc++;
844 else
846 unsigned data = *src;
847 *dst++ = colorindex[(data >> 6) & 3];
848 *dst++ = colorindex[(data >> 4) & 3];
849 *dst++ = colorindex[(data >> 2) & 3];
850 *dst++ = colorindex[data & 3];
852 gx++, src++;
854 while (dst < dst_end);
856 #endif /* LCD_DEPTH */
857 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
858 gsrc = _grey_info.values + (~gy & _GREY_BMASK)
859 + _GREY_MULUQ(_grey_info.width, gy & ~_GREY_BMASK);
861 #if LCD_DEPTH == 1
862 mask = BIT_N(y & 7);
863 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
867 if (((unsigned)gy < (unsigned)_grey_info.height)
868 && ((unsigned)gx < (unsigned)_grey_info.width))
870 val = *gsrc;
871 #ifdef HAVE_LCD_SPLIT
872 val -= val >> 7;
873 #endif
874 gsrc += _GREY_BSIZE;
876 else
878 #ifdef HAVE_NEGATIVE_LCD
879 val = (*src & mask) ? (NUM_SHADES-1) : 0;
880 #else
881 val = (*src & mask) ? 0 : (NUM_SHADES-1);
882 #endif
884 #ifdef HAVE_LCD_SPLIT
885 if (y < LCD_SPLIT_POS)
886 val |= 0x80;
887 #endif
888 *dst++ = val;
889 gx++, src++;
891 while (dst < dst_end);
893 #elif LCD_DEPTH == 2
894 shift = 2 * (y & 3);
895 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 2);
899 if (((unsigned)gy < (unsigned)_grey_info.height)
900 && ((unsigned)gx < (unsigned)_grey_info.width))
902 *dst++ = *gsrc;
903 gsrc += _GREY_BSIZE;
905 else
907 *dst++ = colorindex[(*src >> shift) & 3];
909 gx++, src++;
911 while (dst < dst_end);
913 #endif /* LCD_DEPTH */
914 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
915 gsrc = _grey_info.values + (~gy & _GREY_BMASK)
916 + _GREY_MULUQ(_grey_info.width, gy & ~_GREY_BMASK);
918 #if LCD_DEPTH == 2
919 shift = y & 7;
920 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
924 if (((unsigned)gy < (unsigned)_grey_info.height)
925 && ((unsigned)gx < (unsigned)_grey_info.width))
927 *dst++ = *gsrc;
928 gsrc += _GREY_BSIZE;
930 else
932 data = (*src >> shift) & 0x0101;
933 *dst++ = colorindex[((data >> 7) | data) & 3];
935 gx++, src++;
937 while (dst < dst_end);
939 #endif /* LCD_DEPTH */
940 #endif /* LCD_PIXELFORMAT */
942 rb->write(fd, linebuf, BMP_LINESIZE);