Rename h100 specific screenshots so they are used again
[kugel-rb.git] / apps / plugins / lib / grey_core.c
blob18b2716d4d4d0c3aaf987f8ba37c59fc442a5328
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 1, _timer_isr,
652 (_grey_info.flags & GREY_ON_COP) ? COP : CPU);
653 #else
654 rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE, 1,
655 _timer_isr);
656 #endif
657 #endif /* !SIMULATOR */
658 rb->screen_dump_set_hook(grey_screendump_hook);
660 else if (!enable && (_grey_info.flags & _GREY_RUNNING))
662 #ifdef SIMULATOR
663 rb->sim_lcd_ex_init(NULL);
664 #else /* !SIMULATOR */
665 rb->timer_unregister();
666 #if NUM_CORES > 1 /* Make sure the ISR has finished before calling lcd_update() */
667 rb->sleep(HZ/100);
668 #endif
669 #ifdef NEED_BOOST
670 rb->cpu_boost(false);
671 #endif
672 #endif /* !SIMULATOR */
673 _grey_info.flags &= ~_GREY_RUNNING;
674 rb->screen_dump_set_hook(NULL);
675 rb->lcd_update(); /* restore whatever there was before */
679 void grey_update_rect(int x, int y, int width, int height)
681 grey_ub_gray_bitmap_part(_grey_info.buffer, x, y, _grey_info.width,
682 x, y, width, height);
685 /* Update the whole greyscale overlay */
686 void grey_update(void)
688 grey_ub_gray_bitmap_part(_grey_info.buffer, 0, 0, _grey_info.width,
689 0, 0, _grey_info.width, _grey_info.height);
692 /* Do an lcd_update() to show changes done by rb->lcd_xxx() functions
693 (in areas of the screen not covered by the greyscale overlay). */
694 void grey_deferred_lcd_update(void)
696 if (_grey_info.flags & _GREY_RUNNING)
698 #ifdef SIMULATOR
699 _deferred_update();
700 #else
701 _grey_info.flags |= _GREY_DEFERRED_UPDATE;
702 #endif
704 else
705 rb->lcd_update();
708 /*** Screenshot ***/
710 #ifdef HAVE_LCD_SPLIT
711 #define NUM_SHADES 128
712 #define BMP_NUMCOLORS 256
713 #else
714 #define NUM_SHADES 129
715 #define BMP_NUMCOLORS 129
716 #endif
718 #define BMP_BPP 8
719 #define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
720 #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
721 #define BMP_DATASIZE (BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
722 #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
724 static const unsigned char bmpheader[] =
726 0x42, 0x4d, /* 'BM' */
727 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
728 0x00, 0x00, 0x00, 0x00, /* Reserved */
729 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
731 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
732 LE32_CONST(LCD_WIDTH), /* Width in pixels */
733 LE32_CONST(LCD_HEIGHT+LCD_SPLIT_LINES), /* Height in pixels */
734 0x01, 0x00, /* Number of planes (always 1) */
735 LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
736 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */
737 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
738 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
739 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
740 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
741 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
744 #if LCD_DEPTH == 2
745 /* Only defined for positive, non-split LCD for now */
746 static const unsigned char colorindex[4] = {128, 85, 43, 0};
747 #endif
749 /* Hook function for core screen_dump() to save the current display
750 content (b&w and greyscale overlay) to an 8-bit BMP file. */
751 static void grey_screendump_hook(int fd)
753 int i;
754 int y, gx, gy;
755 #if LCD_PIXELFORMAT == VERTICAL_PACKING
756 #if LCD_DEPTH == 1
757 unsigned val;
758 unsigned mask;
759 #elif LCD_DEPTH == 2
760 int shift;
761 #endif
762 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
763 unsigned data;
764 int shift;
765 #endif /* LCD_PIXELFORMAT */
766 fb_data *src;
767 unsigned char *gsrc;
768 unsigned char *dst, *dst_end;
769 unsigned char linebuf[MAX(4*NUM_SHADES,BMP_LINESIZE)];
771 rb->write(fd, bmpheader, sizeof(bmpheader)); /* write header */
773 /* build clut */
774 rb->memset(linebuf, 0, 4*NUM_SHADES);
775 dst = linebuf;
777 for (i = 0; i < NUM_SHADES; i++)
779 *dst++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR)
780 -BLUE_CMP(LCD_BL_DARKCOLOR), i) >> 7)
781 + BLUE_CMP(LCD_BL_DARKCOLOR);
782 *dst++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR)
783 -GREEN_CMP(LCD_BL_DARKCOLOR), i) >> 7)
784 + GREEN_CMP(LCD_BL_DARKCOLOR);
785 *dst++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR)
786 -RED_CMP(LCD_BL_DARKCOLOR), i) >> 7)
787 + RED_CMP(LCD_BL_DARKCOLOR);
788 dst++;
790 rb->write(fd, linebuf, 4*NUM_SHADES);
792 #ifdef HAVE_LCD_SPLIT
793 dst = linebuf;
795 for (i = 0; i <= NUM_SHADES; i++)
797 *dst++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR_2)
798 -BLUE_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
799 + BLUE_CMP(LCD_BL_DARKCOLOR_2);
800 *dst++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR_2)
801 -GREEN_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
802 + GREEN_CMP(LCD_BL_DARKCOLOR_2);
803 *dst++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR_2)
804 -RED_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
805 + RED_CMP(LCD_BL_DARKCOLOR_2);
806 dst++;
808 rb->write(fd, linebuf, 4*NUM_SHADES);
809 #endif
811 /* BMP image goes bottom -> top */
812 for (y = LCD_HEIGHT - 1; y >= 0; y--)
814 rb->memset(linebuf, 0, BMP_LINESIZE);
816 #if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
817 if (y == LCD_SPLIT_POS - 1)
819 rb->write(fd, linebuf, BMP_LINESIZE);
820 rb->write(fd, linebuf, BMP_LINESIZE);
822 #endif
824 dst = linebuf;
825 dst_end = dst + LCD_WIDTH;
826 gy = y - _grey_info.y;
827 gx = -_grey_info.x;
829 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
830 gsrc = _grey_info.values + _GREY_MULUQ(_grey_info.width, gy);
832 #if LCD_DEPTH == 2
833 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_FBWIDTH, y);
837 if (((unsigned)gy < (unsigned)_grey_info.height)
838 && ((unsigned)gx < (unsigned)_grey_info.width))
840 *dst++ = *gsrc++;
841 *dst++ = *gsrc++;
842 *dst++ = *gsrc++;
843 *dst++ = *gsrc++;
845 else
847 unsigned data = *src;
848 *dst++ = colorindex[(data >> 6) & 3];
849 *dst++ = colorindex[(data >> 4) & 3];
850 *dst++ = colorindex[(data >> 2) & 3];
851 *dst++ = colorindex[data & 3];
853 gx++, src++;
855 while (dst < dst_end);
857 #endif /* LCD_DEPTH */
858 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
859 gsrc = _grey_info.values + (~gy & _GREY_BMASK)
860 + _GREY_MULUQ(_grey_info.width, gy & ~_GREY_BMASK);
862 #if LCD_DEPTH == 1
863 mask = 1 << (y & 7);
864 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
868 if (((unsigned)gy < (unsigned)_grey_info.height)
869 && ((unsigned)gx < (unsigned)_grey_info.width))
871 val = *gsrc;
872 #ifdef HAVE_LCD_SPLIT
873 val -= val >> 7;
874 #endif
875 gsrc += _GREY_BSIZE;
877 else
879 #ifdef HAVE_NEGATIVE_LCD
880 val = (*src & mask) ? (NUM_SHADES-1) : 0;
881 #else
882 val = (*src & mask) ? 0 : (NUM_SHADES-1);
883 #endif
885 #ifdef HAVE_LCD_SPLIT
886 if (y < LCD_SPLIT_POS)
887 val |= 0x80;
888 #endif
889 *dst++ = val;
890 gx++, src++;
892 while (dst < dst_end);
894 #elif LCD_DEPTH == 2
895 shift = 2 * (y & 3);
896 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 2);
900 if (((unsigned)gy < (unsigned)_grey_info.height)
901 && ((unsigned)gx < (unsigned)_grey_info.width))
903 *dst++ = *gsrc;
904 gsrc += _GREY_BSIZE;
906 else
908 *dst++ = colorindex[(*src >> shift) & 3];
910 gx++, src++;
912 while (dst < dst_end);
914 #endif /* LCD_DEPTH */
915 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
916 gsrc = _grey_info.values + (~gy & _GREY_BMASK)
917 + _GREY_MULUQ(_grey_info.width, gy & ~_GREY_BMASK);
919 #if LCD_DEPTH == 2
920 shift = y & 7;
921 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
925 if (((unsigned)gy < (unsigned)_grey_info.height)
926 && ((unsigned)gx < (unsigned)_grey_info.width))
928 *dst++ = *gsrc;
929 gsrc += _GREY_BSIZE;
931 else
933 data = (*src >> shift) & 0x0101;
934 *dst++ = colorindex[((data >> 7) | data) & 3];
936 gx++, src++;
938 while (dst < dst_end);
940 #endif /* LCD_DEPTH */
941 #endif /* LCD_PIXELFORMAT */
943 rb->write(fd, linebuf, BMP_LINESIZE);