summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-color-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-color-common.c')
-rw-r--r--firmware/drivers/lcd-color-common.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/firmware/drivers/lcd-color-common.c b/firmware/drivers/lcd-color-common.c
index cce0bbbf4e..ae0fe519bc 100644
--- a/firmware/drivers/lcd-color-common.c
+++ b/firmware/drivers/lcd-color-common.c
@@ -220,6 +220,195 @@ static inline int clamp(int val, int min, int max)
220 return val; 220 return val;
221} 221}
222 222
223#ifndef _WIN32
224/*
225 * weak attribute doesn't work for win32 as of gcc 4.6.2 and binutils 2.21.52
226 * When building win32 simulators, we won't be using an optimized version of
227 * lcd_blit_yuv(), so just don't use the weak attribute.
228 */
229__attribute__((weak))
230#endif
231void lcd_yuv_set_options(unsigned options)
232{
233 (void)options;
234}
235
236/* Draw a partial YUV colour bitmap */
237#ifndef _WIN32
238__attribute__((weak))
239#endif
240void lcd_blit_yuv(unsigned char * const src[3],
241 int src_x, int src_y, int stride,
242 int x, int y, int width, int height)
243{
244 const unsigned char *ysrc, *usrc, *vsrc;
245 int linecounter;
246 fb_data *dst, *row_end;
247 long z;
248
249 /* width and height must be >= 2 and an even number */
250 width &= ~1;
251 linecounter = height >> 1;
252
253#if LCD_WIDTH >= LCD_HEIGHT
254 dst = FBADDR(x, y);
255 row_end = dst + width;
256#else
257 dst = FBADDR(LCD_WIDTH - y - 1, x);
258 row_end = dst + LCD_WIDTH * width;
259#endif
260
261 z = stride * src_y;
262 ysrc = src[0] + z + src_x;
263 usrc = src[1] + (z >> 2) + (src_x >> 1);
264 vsrc = src[2] + (usrc - src[1]);
265
266 /* stride => amount to jump from end of last row to start of next */
267 stride -= width;
268
269 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
270
271 do
272 {
273 do
274 {
275 int y, cb, cr, rv, guv, bu, r, g, b;
276
277 y = YFAC*(*ysrc++ - 16);
278 cb = *usrc++ - 128;
279 cr = *vsrc++ - 128;
280
281 rv = RVFAC*cr;
282 guv = GUFAC*cb + GVFAC*cr;
283 bu = BUFAC*cb;
284
285 r = y + rv;
286 g = y + guv;
287 b = y + bu;
288
289 if ((unsigned)(r | g | b) > 64*256-1)
290 {
291 r = clamp(r, 0, 64*256-1);
292 g = clamp(g, 0, 64*256-1);
293 b = clamp(b, 0, 64*256-1);
294 }
295
296 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
297
298#if LCD_WIDTH >= LCD_HEIGHT
299 dst++;
300#else
301 dst += LCD_WIDTH;
302#endif
303
304 y = YFAC*(*ysrc++ - 16);
305 r = y + rv;
306 g = y + guv;
307 b = y + bu;
308
309 if ((unsigned)(r | g | b) > 64*256-1)
310 {
311 r = clamp(r, 0, 64*256-1);
312 g = clamp(g, 0, 64*256-1);
313 b = clamp(b, 0, 64*256-1);
314 }
315
316 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
317
318#if LCD_WIDTH >= LCD_HEIGHT
319 dst++;
320#else
321 dst += LCD_WIDTH;
322#endif
323 }
324 while (dst < row_end);
325
326 ysrc += stride;
327 usrc -= width >> 1;
328 vsrc -= width >> 1;
329
330#if LCD_WIDTH >= LCD_HEIGHT
331 row_end += LCD_WIDTH;
332 dst += LCD_WIDTH - width;
333#else
334 row_end -= 1;
335 dst -= LCD_WIDTH*width + 1;
336#endif
337
338 do
339 {
340 int y, cb, cr, rv, guv, bu, r, g, b;
341
342 y = YFAC*(*ysrc++ - 16);
343 cb = *usrc++ - 128;
344 cr = *vsrc++ - 128;
345
346 rv = RVFAC*cr;
347 guv = GUFAC*cb + GVFAC*cr;
348 bu = BUFAC*cb;
349
350 r = y + rv;
351 g = y + guv;
352 b = y + bu;
353
354 if ((unsigned)(r | g | b) > 64*256-1)
355 {
356 r = clamp(r, 0, 64*256-1);
357 g = clamp(g, 0, 64*256-1);
358 b = clamp(b, 0, 64*256-1);
359 }
360
361 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
362
363#if LCD_WIDTH >= LCD_HEIGHT
364 dst++;
365#else
366 dst += LCD_WIDTH;
367#endif
368
369 y = YFAC*(*ysrc++ - 16);
370 r = y + rv;
371 g = y + guv;
372 b = y + bu;
373
374 if ((unsigned)(r | g | b) > 64*256-1)
375 {
376 r = clamp(r, 0, 64*256-1);
377 g = clamp(g, 0, 64*256-1);
378 b = clamp(b, 0, 64*256-1);
379 }
380
381 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
382
383#if LCD_WIDTH >= LCD_HEIGHT
384 dst++;
385#else
386 dst += LCD_WIDTH;
387#endif
388 }
389 while (dst < row_end);
390
391 ysrc += stride;
392 usrc += stride >> 1;
393 vsrc += stride >> 1;
394
395#if LCD_WIDTH >= LCD_HEIGHT
396 row_end += LCD_WIDTH;
397 dst += LCD_WIDTH - width;
398#else
399 row_end -= 1;
400 dst -= LCD_WIDTH*width + 1;
401#endif
402 }
403 while (--linecounter > 0);
404
405#if LCD_WIDTH >= LCD_HEIGHT
406 lcd_update_rect(x, y, width, height);
407#else
408 lcd_update_rect(LCD_WIDTH - y - height, x, height, width);
409#endif
410}
411
223/* Fill a rectangle with a gradient. This function draws only the partial 412/* Fill a rectangle with a gradient. This function draws only the partial
224 * gradient. It assumes the original gradient is src_height high and skips 413 * gradient. It assumes the original gradient is src_height high and skips
225 * the first few rows. This is useful for drawing only the bottom half of 414 * the first few rows. This is useful for drawing only the bottom half of