summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-memframe.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-memframe.c')
-rw-r--r--firmware/drivers/lcd-memframe.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/firmware/drivers/lcd-memframe.c b/firmware/drivers/lcd-memframe.c
index 357b4af32a..bb1682b074 100644
--- a/firmware/drivers/lcd-memframe.c
+++ b/firmware/drivers/lcd-memframe.c
@@ -110,3 +110,101 @@ void lcd_update_rect(int x, int y, int width, int height)
110 } 110 }
111} 111}
112#endif /* LCD_OPTIMIZED_UPDATE_RECT */ 112#endif /* LCD_OPTIMIZED_UPDATE_RECT */
113
114
115/*** YUV functions ***/
116static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
117
118
119/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
120extern void lcd_write_yuv420_lines(fb_data *dst,
121 unsigned char const * const src[3],
122 int width,
123 int stride);
124extern void lcd_write_yuv420_lines_odither(fb_data *dst,
125 unsigned char const * const src[3],
126 int width,
127 int stride,
128 int x_screen, /* To align dither pattern */
129 int y_screen);
130
131void lcd_yuv_set_options(unsigned options)
132{
133 lcd_yuv_options = options;
134}
135
136#ifndef LCD_OPTIMIZED_BLIT_YUV
137/* Performance function to blit a YUV bitmap directly to the LCD
138 * src_x, src_y, width and height should be even and within the LCD's
139 * boundaries.
140 *
141 * For portrait LCDs, show it rotated counterclockwise by 90 degrees
142 */
143void lcd_blit_yuv(unsigned char * const src[3],
144 int src_x, int src_y, int stride,
145 int x, int y, int width, int height)
146{
147 /* Macrofy the bits that change between orientations */
148#if CONFIG_ORIENTATION == SCREEN_PORTRAIT
149 #define LCD_FRAMEBUF_ADDR_ORIENTED(col, row) \
150 LCD_FRAMEBUF_ADDR(row, col)
151 #define lcd_write_yuv420_lines_odither_oriented(dst, src, w, s, col, row) \
152 lcd_write_yuv420_lines_odither(dst, src, w, s, row, col)
153 #define YUV_NEXTLINE() dst -= 2
154 #define YUV_DITHER_NEXTLINE() dst -= 2, y -= 2
155#else
156 #define LCD_FRAMEBUF_ADDR_ORIENTED(col, row) \
157 LCD_FRAMEBUF_ADDR(col, row)
158 #define lcd_write_yuv420_lines_odither_oriented(dst, src, w, s, col, row) \
159 lcd_write_yuv420_lines_odither(dst, src, w, s, col, row)
160 #define YUV_NEXTLINE() dst += 2*LCD_FBWIDTH
161 #define YUV_DITHER_NEXTLINE() dst += 2*LCD_FBWIDTH, y += 2
162#endif
163
164 if (!lcd_write_enabled())
165 return;
166
167 /* Sorry, but width and height must be >= 2 or else */
168 width &= ~1;
169 height >>= 1;
170
171#if CONFIG_ORIENTATION == SCREEN_PORTRAIT
172 /* Adjust portrait coordinates to make (0, 0) the upper right corner */
173 y = LCD_WIDTH - 1 - y;
174#endif
175
176 fb_data *dst = LCD_FRAMEBUF_ADDR_ORIENTED(x, y);
177 int z = stride*src_y;
178
179 unsigned char const * yuv_src[3];
180 yuv_src[0] = src[0] + z + src_x;
181 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
182 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
183
184 if (lcd_yuv_options & LCD_YUV_DITHER)
185 {
186 do
187 {
188 lcd_write_yuv420_lines_odither_oriented(dst, yuv_src, width,
189 stride, x, y);
190 yuv_src[0] += stride << 1; /* Skip down two luma lines */
191 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
192 yuv_src[2] += stride >> 1;
193 YUV_DITHER_NEXTLINE();
194 }
195 while (--height > 0);
196 }
197 else
198 {
199 do
200 {
201 lcd_write_yuv420_lines(dst, yuv_src, width, stride);
202 yuv_src[0] += stride << 1; /* Skip down two luma lines */
203 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
204 yuv_src[2] += stride >> 1;
205 YUV_NEXTLINE();
206 }
207 while (--height > 0);
208 }
209}
210#endif /* LCD_OPTIMIZED_BLIT_YUV */