rockbox/firmware/drivers/lcd-memframe.c
Jonathan Gordon b37e6bc8c1 lcd drivers: Convert lcd_[remote_]framebuffer to a pointer
Change all lcd drivers to using a pointer to the static framebuffer
instead of directly accessing the static array. This will let us
later do fun things like dynamic framebuffer sizes (RaaA) or
ability to use different buffers for different layers (dynamic
skin backdrops!)

Change-Id: I0a4d58a9d7b55e6c932131b929e5d4c9f9414b06
2012-02-28 11:44:59 +11:00

211 lines
6.6 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (c) 2007, 2011 Michael Sevakis
*
* Shared C code for memory framebuffer LCDs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include "lcd.h"
#include "lcd-target.h"
/*** Misc. functions ***/
bool lcd_on SHAREDBSS_ATTR = false;
#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
bool lcd_active(void)
{
return lcd_on;
}
/* For use by target driver only! */
void lcd_set_active(bool active)
{
lcd_on = active;
}
#else
#define lcd_on true
#endif
#ifndef lcd_write_enabled
#define lcd_write_enabled() lcd_on
#endif
/*** Blitting functions ***/
/* Copies a rectangle from one framebuffer to another. Can be used in
single transfer mode with width = num pixels, and height = 1 which
allows a full-width rectangle to be copied more efficiently. */
extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src,
int width, int height);
#ifndef LCD_OPTIMIZED_UPDATE
/* Update the display.
This must be called after all other LCD functions that change the display. */
void lcd_update(void)
{
if (!lcd_write_enabled())
return;
/* Copy the Rockbox framebuffer to the second framebuffer */
lcd_copy_buffer_rect(LCD_FRAMEBUF_ADDR(0, 0), FBADDR(0,0),
LCD_WIDTH*LCD_HEIGHT, 1);
}
#endif /* LCD_OPTIMIZED_UPDATE */
#ifndef LCD_OPTIMIZED_UPDATE_RECT
/* Update a fraction of the display. */
void lcd_update_rect(int x, int y, int width, int height)
{
fb_data *dst, *src;
if (!lcd_write_enabled())
return;
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x; /* Clip right */
if (x < 0)
width += x, x = 0; /* Clip left */
if (width <= 0)
return; /* nothing left to do */
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y; /* Clip bottom */
if (y < 0)
height += y, y = 0; /* Clip top */
if (height <= 0)
return; /* nothing left to do */
dst = LCD_FRAMEBUF_ADDR(x, y);
src = FBADDR(x,y);
/* Copy part of the Rockbox framebuffer to the second framebuffer */
if (width < LCD_WIDTH)
{
/* Not full width - do line-by-line */
lcd_copy_buffer_rect(dst, src, width, height);
}
else
{
/* Full width - copy as one line */
lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1);
}
}
#endif /* LCD_OPTIMIZED_UPDATE_RECT */
/*** YUV functions ***/
static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
extern void lcd_write_yuv420_lines(fb_data *dst,
unsigned char const * const src[3],
int width,
int stride);
extern void lcd_write_yuv420_lines_odither(fb_data *dst,
unsigned char const * const src[3],
int width,
int stride,
int x_screen, /* To align dither pattern */
int y_screen);
void lcd_yuv_set_options(unsigned options)
{
lcd_yuv_options = options;
}
#ifndef LCD_OPTIMIZED_BLIT_YUV
/* Performance function to blit a YUV bitmap directly to the LCD
* src_x, src_y, width and height should be even and within the LCD's
* boundaries.
*
* For portrait LCDs, show it rotated counterclockwise by 90 degrees
*/
void lcd_blit_yuv(unsigned char * const src[3],
int src_x, int src_y, int stride,
int x, int y, int width, int height)
{
/* Macrofy the bits that change between orientations */
#if CONFIG_ORIENTATION == SCREEN_PORTRAIT
#define LCD_FRAMEBUF_ADDR_ORIENTED(col, row) \
LCD_FRAMEBUF_ADDR(row, col)
#define lcd_write_yuv420_lines_odither_oriented(dst, src, w, s, col, row) \
lcd_write_yuv420_lines_odither(dst, src, w, s, row, col)
#define YUV_NEXTLINE() dst -= 2
#define YUV_DITHER_NEXTLINE() dst -= 2, y -= 2
#else
#define LCD_FRAMEBUF_ADDR_ORIENTED(col, row) \
LCD_FRAMEBUF_ADDR(col, row)
#define lcd_write_yuv420_lines_odither_oriented(dst, src, w, s, col, row) \
lcd_write_yuv420_lines_odither(dst, src, w, s, col, row)
#define YUV_NEXTLINE() dst += 2*LCD_FBWIDTH
#define YUV_DITHER_NEXTLINE() dst += 2*LCD_FBWIDTH, y += 2
#endif
if (!lcd_write_enabled())
return;
/* Sorry, but width and height must be >= 2 or else */
width &= ~1;
height >>= 1;
#if CONFIG_ORIENTATION == SCREEN_PORTRAIT
/* Adjust portrait coordinates to make (0, 0) the upper right corner */
y = LCD_WIDTH - 1 - y;
#endif
fb_data *dst = LCD_FRAMEBUF_ADDR_ORIENTED(x, y);
int z = stride*src_y;
unsigned char const * yuv_src[3];
yuv_src[0] = src[0] + z + src_x;
yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
if (lcd_yuv_options & LCD_YUV_DITHER)
{
do
{
lcd_write_yuv420_lines_odither_oriented(dst, yuv_src, width,
stride, x, y);
yuv_src[0] += stride << 1; /* Skip down two luma lines */
yuv_src[1] += stride >> 1; /* Skip down one chroma line */
yuv_src[2] += stride >> 1;
YUV_DITHER_NEXTLINE();
}
while (--height > 0);
}
else
{
do
{
lcd_write_yuv420_lines(dst, yuv_src, width, stride);
yuv_src[0] += stride << 1; /* Skip down two luma lines */
yuv_src[1] += stride >> 1; /* Skip down one chroma line */
yuv_src[2] += stride >> 1;
YUV_NEXTLINE();
}
while (--height > 0);
}
}
#endif /* LCD_OPTIMIZED_BLIT_YUV */