diff options
author | Andrew Mahone <andrew.mahone@gmail.com> | 2008-12-26 07:03:22 +0000 |
---|---|---|
committer | Andrew Mahone <andrew.mahone@gmail.com> | 2008-12-26 07:03:22 +0000 |
commit | f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04 (patch) | |
tree | ea469e428a756e4f4979be1b6f5a84179a2cc80f /apps/recorder/bmp.h | |
parent | 7428c7cc5b8462ed95683f707fe78609ce8208bf (diff) | |
download | rockbox-f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04.tar.gz rockbox-f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04.zip |
Latest work on the bmp on-load scaler:
Macros for calculating size needed for bitmap load and scaling, so that
these can be compile-time constant when their inputs are.
Reduce size of bayer dither by chopping all but first row of dither
matrix, and replacing 2D lookup with 1D lookup and small calculation.
Move some functions not related to actual bmp file loading out of bmp.c.
A smaller brightness() for mono targets, and a higher-quality one for
greyscale targets, both replacing the division by 10 with a shift.
Port of the linear and area scalers to greyscale targets, this costs
some binsize but produces better output even when dithered to 2bpp.
Move duplicated row output code from inside vertical scalers to a
separate row output function.
Move some multiplies out of the line scaler, for a small speedup and
code size reduction, as well as a small improvement in accuracy for the
upscaling case.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19592 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/recorder/bmp.h')
-rw-r--r-- | apps/recorder/bmp.h | 221 |
1 files changed, 116 insertions, 105 deletions
diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h index d1b1d7f3ed..273e178bc9 100644 --- a/apps/recorder/bmp.h +++ b/apps/recorder/bmp.h | |||
@@ -32,11 +32,7 @@ | |||
32 | 32 | ||
33 | #define IMG_NORESIZE 0 | 33 | #define IMG_NORESIZE 0 |
34 | #define IMG_RESIZE 1 | 34 | #define IMG_RESIZE 1 |
35 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | 35 | #define BM_MAX_WIDTH (((LCD_WIDTH) + 7) & ~7) |
36 | #define MAX_WIDTH 8 | ||
37 | #else | ||
38 | #define MAX_WIDTH LCD_WIDTH | ||
39 | #endif | ||
40 | 36 | ||
41 | struct uint8_rgb { | 37 | struct uint8_rgb { |
42 | uint8_t blue; | 38 | uint8_t blue; |
@@ -56,129 +52,144 @@ struct rowset { | |||
56 | }; | 52 | }; |
57 | 53 | ||
58 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | 54 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) |
59 | extern const unsigned char dither_matrix[16][16]; | 55 | extern const unsigned char dither_table[16]; |
60 | static inline unsigned char dither_mat(unsigned int x, unsigned int y) | 56 | #define DITHERY(y) (dither_table[(y) & 15] & 0xAA) |
61 | { | 57 | #define DITHERX(x) (dither_table[(x) & 15]) |
62 | return dither_matrix[y][x]; | 58 | #define DITHERXDY(x,dy) (DITHERX(x) ^ dy) |
63 | } | 59 | #define DITHERDXY(dx,y) (dx ^ DITHERY(y)) |
60 | #define DITHERXY(x,y) (DITHERX(x) ^ DITHERY(y)) | ||
64 | #endif | 61 | #endif |
65 | 62 | ||
63 | /* The /256 version has a mean squared variance from YUV luma of <1 grey level. | ||
64 | The /8 version is a good deal less accurate, but sufficient on mono as we | ||
65 | don't support HQ output or dithering there, yet. | ||
66 | */ | ||
66 | static inline unsigned brightness(struct uint8_rgb color) | 67 | static inline unsigned brightness(struct uint8_rgb color) |
67 | { | 68 | { |
68 | return (3 * (unsigned)color.red + 6 * (unsigned)color.green | 69 | #if LCD_DEPTH > 1 |
69 | + (unsigned)color.blue) / 10; | 70 | return (77 * (unsigned)color.red + 150 * (unsigned)color.green |
71 | + 29 * (unsigned)color.blue) / 256; | ||
72 | #else | ||
73 | return (2 * (unsigned)color.red + 5 * (unsigned)color.green | ||
74 | + (unsigned)color.blue) / 8; | ||
75 | #endif | ||
70 | } | 76 | } |
71 | 77 | ||
72 | #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ | 78 | #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ |
73 | || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ | 79 | || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ |
74 | && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) | 80 | && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) |
75 | extern const unsigned short vi_pattern[4]; | 81 | extern const unsigned short vi_pattern[4]; |
76 | static inline unsigned short vi_pat(unsigned int bright) | ||
77 | { | ||
78 | return vi_pattern[bright]; | ||
79 | } | ||
80 | #endif | 82 | #endif |
81 | 83 | ||
82 | static inline int get_fb_height(struct bitmap *bm, bool remote) | 84 | /* Number of rows of data in a mono bitmap height pixels tall */ |
83 | { | 85 | #define MONO_BM_HEIGHT(height) (((height) + 7) >> 3) |
84 | const int height = bm->height; | 86 | |
85 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | 87 | /* Number of rows of datain a LCD native bitmap height pixels tall */ |
86 | const int format = bm->format; | 88 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) |
89 | #if LCD_DEPTH == 1 || \ | ||
90 | (LCD_DEPTH == 2 && LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) | ||
91 | #define LCD_BM_HEIGHT(height) (((height) + 7) >> 3) | ||
92 | #elif LCD_DEPTH == 2 && LCD_PIXELFORMAT == VERTICAL_PACKING | ||
93 | #define LCD_BM_HEIGHT(height) (((height) + 3) >> 2) | ||
94 | #else | ||
95 | #define LCD_BM_HEIGHT(height) (height) | ||
87 | #endif | 96 | #endif |
88 | int dst_height; | ||
89 | 97 | ||
90 | #if !defined(HAVE_REMOTE_LCD) || \ | 98 | /* Number of rows of data in a remote native bitmap height pixels tall. */ |
91 | (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) | 99 | #ifdef HAVE_REMOTE_LCD |
92 | (void) remote; | 100 | #if LCD_REMOTE_DEPTH == 1 || \ |
101 | (LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) | ||
102 | #define LCD_REMOTE_BM_HEIGHT(height) (((height) + 7) >> 3) | ||
103 | #elif LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING | ||
104 | #define LCD_REMOTE_BM_HEIGHT(height) (((height) + 3) >> 2) | ||
105 | #else | ||
106 | #define LCD_REMOTE_BM_HEIGHT(height) (height) | ||
107 | #endif | ||
108 | #define NATIVE_BM_HEIGHT(height,remote) ((remote) ? \ | ||
109 | LCD_REMOTE_BM_HEIGHT(height) : LCD_BM_HEIGHT(height)) | ||
110 | #else | ||
111 | #define NATIVE_BM_HEIGHT(height,remote) LCD_BM_HEIGHT(height) | ||
93 | #endif | 112 | #endif |
94 | 113 | ||
95 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | 114 | /* Convenience macro to calculate rows based on height, remote vs main LCD, |
96 | if (format == FORMAT_NATIVE) { | 115 | and format |
97 | #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 | 116 | */ |
98 | if (remote) { | 117 | #define BM_HEIGHT(height,format,remote) ((format) == FORMAT_MONO ? \ |
99 | #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) | 118 | MONO_BM_HEIGHT(height) : NATIVE_BM_HEIGHT(height,remote)) |
100 | dst_height = (height + 7) >> 3; | 119 | #else |
101 | #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ | 120 | #define BM_HEIGHT(height,format,remote) MONO_BM_HEIGHT(height) |
102 | } else | 121 | #endif |
103 | #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ | ||
104 | { | ||
105 | #if LCD_DEPTH == 2 | ||
106 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
107 | dst_height = height; | ||
108 | #elif LCD_PIXELFORMAT == VERTICAL_PACKING | ||
109 | dst_height = (height + 3) >> 2; | ||
110 | #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED | ||
111 | dst_height = (height + 7) >> 3; | ||
112 | #endif /* LCD_PIXELFORMAT */ | ||
113 | #elif LCD_DEPTH == 16 | ||
114 | dst_height = height; | ||
115 | #endif /* LCD_DEPTH */ | ||
116 | } | ||
117 | } else | ||
118 | #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ | ||
119 | { | ||
120 | dst_height = (height + 7) >> 3; | ||
121 | } | ||
122 | |||
123 | return dst_height; | ||
124 | } | ||
125 | 122 | ||
126 | static inline int get_fb_width(struct bitmap *bm, bool remote) | 123 | /* Number of data elements in a mono bitmap width pixels wide */ |
127 | { | 124 | #define MONO_BM_WIDTH(width) (width) |
128 | const int width = bm->width; | 125 | |
129 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | 126 | /* Number of data elements in a LCD native bitmap width pixels wide */ |
130 | const int format = bm->format; | 127 | #if LCD_DEPTH > 1 |
128 | #if LCD_DEPTH == 2 && LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
129 | #define LCD_BM_WIDTH(width) (((width) + 3) >> 2) | ||
130 | #else | ||
131 | #define LCD_BM_WIDTH(width) (width) | ||
131 | #endif | 132 | #endif |
132 | int dst_width; | ||
133 | 133 | ||
134 | #if !defined(HAVE_REMOTE_LCD) || \ | 134 | /* Number of data elements in a remote native bitmap width pixels wide */ |
135 | (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) | 135 | #ifdef HAVE_LCD_REMOTE |
136 | (void) remote; | 136 | #if LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING |
137 | #define LCD_REMOTE_BM_WIDTH(width) (((width) + 3) >> 2) | ||
138 | #else | ||
139 | #define LCD_REMOTE_BM_WIDTH(width) (width) | ||
140 | #endif | ||
141 | #define NATIVE_BM_WIDTH(width,remote) ((remote) ? \ | ||
142 | LCD_REMOTE_BM_WIDTH(width) : LCD_BM_WIDTH(width)) | ||
143 | #else | ||
144 | #define NATIVE_BM_WIDTH(width,remote) LCD_BM_WIDTH(width) | ||
137 | #endif | 145 | #endif |
138 | 146 | ||
139 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | 147 | /* Convenience macro to calculate elements based on height, remote vs native |
140 | if (format == FORMAT_NATIVE) { | 148 | main LCD, and format |
141 | #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 | 149 | */ |
142 | if (remote) { | 150 | #define BM_WIDTH(width,format,remote) ((format) == FORMAT_MONO ? \ |
143 | #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) | 151 | MONO_BM_WIDTH(width) : NATIVE_BM_WIDTH(width,remote)) |
144 | dst_width = width; | 152 | #else |
145 | #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ | 153 | #define BM_WIDTH(width,format,remote) MONO_BM_WIDTH(width) |
146 | } else | 154 | #endif |
147 | #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ | ||
148 | { | ||
149 | #if LCD_DEPTH == 2 | ||
150 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
151 | dst_width = (width + 3) >> 2; | ||
152 | #elif LCD_PIXELFORMAT == VERTICAL_PACKING | ||
153 | dst_width = width; | ||
154 | #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED | ||
155 | dst_width = width; | ||
156 | #endif /* LCD_PIXELFORMAT */ | ||
157 | #elif LCD_DEPTH == 16 | ||
158 | dst_width = width; | ||
159 | #endif /* LCD_DEPTH */ | ||
160 | } | ||
161 | } else | ||
162 | #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ | ||
163 | { | ||
164 | dst_width = width; | ||
165 | } | ||
166 | |||
167 | return dst_width; | ||
168 | } | ||
169 | 155 | ||
170 | static inline int get_totalsize(struct bitmap *bm, bool remote) | 156 | /* Size in bytes of a mono bitmap of dimensions width*height */ |
171 | { | 157 | #define MONO_BM_SIZE(width,height) (MONO_BM_WIDTH(width) * \ |
172 | int sz; | 158 | MONO_BM_HEIGHT(height) * FB_DATA_SZ) |
173 | #ifdef HAVE_REMOTE_LCD | ||
174 | if (remote && sizeof(fb_data) != sizeof(fb_remote_data)) | ||
175 | sz = sizeof(fb_remote_data); | ||
176 | else | ||
177 | #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ | ||
178 | sz = sizeof(fb_data); | ||
179 | 159 | ||
180 | return get_fb_width(bm, remote) * get_fb_height(bm, remote) * sz; | 160 | /* Size in bytes of a native bitmap of dimensions width*height */ |
181 | } | 161 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) |
162 | #if defined(HAVE_REMOTE_LCD) && FB_DATA_SZ != FB_RDATA_SZ | ||
163 | #define NATIVE_BM_SIZE(width,height,format,remote) \ | ||
164 | (((remote) ? FB_RDATA_SZ : FB_DATA_SZ) * BM_WIDTH(width,format,remote) \ | ||
165 | * BM_HEIGHT(height,format,remote)) | ||
166 | #else | ||
167 | #define NATIVE_BM_SIZE(width,height,format,remote) \ | ||
168 | (FB_DATA_SZ * BM_WIDTH(width,format,remote) * \ | ||
169 | BM_HEIGHT(height,format,remote)) | ||
170 | #endif | ||
171 | |||
172 | /* Convenience macro to calculate size in bytes based on height, remote vs | ||
173 | main LCD, and format | ||
174 | */ | ||
175 | #define BM_SIZE(width,height,format,remote) (((format) == FORMAT_MONO) ? \ | ||
176 | MONO_BM_SIZE(width,height) : NATIVE_BM_SIZE(width,height,format,remote)) | ||
177 | #else | ||
178 | #define BM_SIZE(width,height,format,remote) MONO_BM_SIZE(width,height) | ||
179 | #endif | ||
180 | |||
181 | /* Size in bytes needed to load and scale a bitmap with target size up to | ||
182 | width*height, including overhead to allow for buffer alignment. | ||
183 | */ | ||
184 | #ifdef HAVE_LCD_COLOR | ||
185 | #define BM_SCALED_SIZE(width,height,format,remote) \ | ||
186 | (BM_SIZE(width,height,format,remote) + \ | ||
187 | (remote ? 0 : BM_WIDTH(width,format,remote) * sizeof(uint32_t) * 9 + 3)) | ||
188 | #else | ||
189 | #define BM_SCALED_SIZE(width,height,format,remote) \ | ||
190 | (BM_SIZE(width,height,format,remote) + \ | ||
191 | (width * sizeof(uint32_t) * 3 + 3)) | ||
192 | #endif | ||
182 | 193 | ||
183 | /********************************************************************* | 194 | /********************************************************************* |
184 | * read_bmp_file() | 195 | * read_bmp_file() |