CONFIG_VIDEO=y
CONFIG_VIDEO_FONT_SUN12X22=y
CONFIG_VIDEO_COPY=y
-CONFIG_VIDEO_DAMAGE=y
CONFIG_VIDEO_BRIDGE=y
CONFIG_VIDEO_BRIDGE_LVDS_CODEC=y
CONFIG_CONSOLE_ROTATION=y
config VIDEO_COPY
bool "Enable copying the frame buffer to a hardware copy"
+ select VIDEO_DAMAGE
help
On some machines (e.g. x86), reading from the frame buffer is very
slow because it is uncached. To improve performance, this feature
allows the frame buffer to be kept in cached memory (allocated by
U-Boot) and then copied to the hardware frame-buffer as needed.
+ It uses the VIDEO_DAMAGE feature to keep track of regions to copy
+ and will only copy actually touched regions.
To use this, your video driver must set @copy_base in
struct video_uc_plat.
regions of the frame buffer that were modified before, speeding up
screen refreshes significantly.
+ It is also used by VIDEO_COPY to identify which regions changed.
+
config BACKLIGHT_PWM
bool "Generic PWM based Backlight Driver"
depends on BACKLIGHT && DM_PWM
fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes);
end = dst;
- ret = vidconsole_sync_copy(dev, line, end);
- if (ret)
- return ret;
-
video_damage(dev->parent,
0,
fontdata->height * row,
void *dst;
void *src;
int size;
- int ret;
dst = vid_priv->fb + rowdst * fontdata->height * vid_priv->line_length;
src = vid_priv->fb + rowsrc * fontdata->height * vid_priv->line_length;
size = fontdata->height * vid_priv->line_length * count;
- ret = vidconsole_memmove(dev, dst, src, size);
- if (ret)
- return ret;
+ memmove(dst, src, size);
video_damage(dev->parent,
0,
fontdata->width,
fontdata->height);
- ret = vidconsole_sync_copy(dev, start, line);
- if (ret)
- return ret;
-
return VID_TO_POS(fontdata->width);
}
int pbytes = VNBYTES(vid_priv->bpix);
void *start, *dst, *line;
int i, j;
- int ret;
start = vid_priv->fb + vid_priv->line_length -
(row + 1) * fontdata->height * pbytes;
fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes);
line += vid_priv->line_length;
}
- ret = vidconsole_sync_copy(dev, start, line);
- if (ret)
- return ret;
video_damage(dev->parent,
vid_priv->xsize - ((row + 1) * fontdata->height),
int pbytes = VNBYTES(vid_priv->bpix);
void *dst;
void *src;
- int j, ret;
+ int j;
dst = vid_priv->fb + vid_priv->line_length -
(rowdst + count) * fontdata->height * pbytes;
(rowsrc + count) * fontdata->height * pbytes;
for (j = 0; j < vid_priv->ysize; j++) {
- ret = vidconsole_memmove(dev, dst, src,
- fontdata->height * pbytes * count);
- if (ret)
- return ret;
+ memmove(dst, src, fontdata->height * pbytes * count);
src += vid_priv->line_length;
dst += vid_priv->line_length;
}
return ret;
/* We draw backwards from 'start, so account for the first line */
- ret = vidconsole_sync_copy(dev, start - vid_priv->line_length, line);
- if (ret)
- return ret;
-
video_damage(dev->parent,
vid_priv->xsize - y - fontdata->height,
linenum - 1,
struct video_fontdata *fontdata = priv->fontdata;
void *start, *line, *dst, *end;
int pixels = fontdata->height * vid_priv->xsize;
- int i, ret;
+ int i;
int pbytes = VNBYTES(vid_priv->bpix);
start = vid_priv->fb + vid_priv->ysize * vid_priv->line_length -
for (i = 0; i < pixels; i++)
fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes);
end = dst;
- ret = vidconsole_sync_copy(dev, start, end);
- if (ret)
- return ret;
video_damage(dev->parent,
0,
vid_priv->line_length;
src = end - (rowsrc + count) * fontdata->height *
vid_priv->line_length;
- vidconsole_memmove(dev, dst, src,
- fontdata->height * vid_priv->line_length * count);
+ memmove(dst, src, fontdata->height * vid_priv->line_length * count);
video_damage(dev->parent,
0,
if (ret)
return ret;
- /* Add 4 bytes to allow for the first pixel writen */
- ret = vidconsole_sync_copy(dev, start + 4, line);
- if (ret)
- return ret;
-
video_damage(dev->parent,
x - fontdata->width + 1,
linenum - fontdata->height + 1,
struct video_fontdata *fontdata = priv->fontdata;
int pbytes = VNBYTES(vid_priv->bpix);
void *start, *dst, *line;
- int i, j, ret;
+ int i, j;
start = vid_priv->fb + row * fontdata->height * pbytes;
line = start;
fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes);
line += vid_priv->line_length;
}
- ret = vidconsole_sync_copy(dev, start, line);
- if (ret)
- return ret;
video_damage(dev->parent,
row * fontdata->height,
int pbytes = VNBYTES(vid_priv->bpix);
void *dst;
void *src;
- int j, ret;
+ int j;
dst = vid_priv->fb + rowdst * fontdata->height * pbytes;
src = vid_priv->fb + rowsrc * fontdata->height * pbytes;
for (j = 0; j < vid_priv->ysize; j++) {
- ret = vidconsole_memmove(dev, dst, src,
- fontdata->height * pbytes * count);
- if (ret)
- return ret;
+ memmove(dst, src, fontdata->height * pbytes * count);
src += vid_priv->line_length;
dst += vid_priv->line_length;
}
line = start;
ret = fill_char_horizontally(pfont, &line, vid_priv, fontdata, NORMAL_DIRECTION);
- if (ret)
- return ret;
- /* Add a line to allow for the first pixels writen */
- ret = vidconsole_sync_copy(dev, start + vid_priv->line_length, line);
if (ret)
return ret;
struct console_tt_priv *priv = dev_get_priv(dev);
struct console_tt_metrics *met = priv->cur_met;
void *end, *line;
- int ret;
line = vid_priv->fb + row * met->font_size * vid_priv->line_length;
end = line + met->font_size * vid_priv->line_length;
default:
return -ENOSYS;
}
- ret = vidconsole_sync_copy(dev, line, end);
- if (ret)
- return ret;
video_damage(dev->parent,
0,
struct console_tt_metrics *met = priv->cur_met;
void *dst;
void *src;
- int i, diff, ret;
+ int i, diff;
dst = vid_priv->fb + rowdst * met->font_size * vid_priv->line_length;
src = vid_priv->fb + rowsrc * met->font_size * vid_priv->line_length;
- ret = vidconsole_memmove(dev, dst, src, met->font_size *
- vid_priv->line_length * count);
- if (ret)
- return ret;
+ memmove(dst, src, met->font_size * vid_priv->line_length * count);
/* Scroll up our position history */
diff = (rowsrc - rowdst) * met->font_size;
u8 *bits, *data;
int advance;
void *start, *end, *line;
- int row, ret;
+ int row;
/* First get some basic metrics about this character */
stbtt_GetCodepointHMetrics(font, cp, &advance, &lsb);
width,
height);
- ret = vidconsole_sync_copy(dev, start, line);
- if (ret)
- return ret;
free(data);
return width_frac;
uint row, width, height, xoff;
void *start, *line;
uint out, val;
- int ret;
if (xpl_phase() <= PHASE_SPL)
return -ENOSYS;
line += vid_priv->line_length;
}
- ret = vidconsole_sync_copy(dev, start, line);
- if (ret)
- return ret;
+
+ video_damage(dev->parent, x, y, width, height);
return video_sync(vid, true);
}
.per_device_auto = sizeof(struct vidconsole_priv),
};
-#ifdef CONFIG_VIDEO_COPY
-int vidconsole_sync_copy(struct udevice *dev, void *from, void *to)
-{
- struct udevice *vid = dev_get_parent(dev);
-
- return video_sync_copy(vid, from, to);
-}
-
-int vidconsole_memmove(struct udevice *dev, void *dst, const void *src,
- int size)
-{
- memmove(dst, src, size);
- return vidconsole_sync_copy(dev, dst, dst + size);
-}
-#endif
-
int vidconsole_clear_and_reset(struct udevice *dev)
{
int ret;
struct video_priv *priv = dev_get_uclass_priv(dev);
void *start, *line;
int pixels = xend - xstart;
- int row, i, ret;
+ int row, i;
start = priv->fb + ystart * priv->line_length;
start += xstart * VNBYTES(priv->bpix);
}
line += priv->line_length;
}
- ret = video_sync_copy(dev, start, line);
- if (ret)
- return ret;
video_damage(dev, xstart, ystart, xend - xstart, yend - ystart);
int video_fill(struct udevice *dev, u32 colour)
{
struct video_priv *priv = dev_get_uclass_priv(dev);
- int ret;
switch (priv->bpix) {
case VIDEO_BPP16:
memset(priv->fb, colour, priv->fb_size);
break;
}
- ret = video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
- if (ret)
- return ret;
video_damage(dev, 0, 0, priv->xsize, priv->ysize);
}
#endif
+static void video_flush_copy(struct udevice *vid)
+{
+ struct video_priv *priv = dev_get_uclass_priv(vid);
+
+ if (!priv->copy_fb)
+ return;
+
+ if (priv->damage.xend && priv->damage.yend) {
+ int lstart = priv->damage.xstart * VNBYTES(priv->bpix);
+ int lend = priv->damage.xend * VNBYTES(priv->bpix);
+ int y;
+
+ for (y = priv->damage.ystart; y < priv->damage.yend; y++) {
+ ulong offset = (y * priv->line_length) + lstart;
+ ulong len = lend - lstart;
+
+ memcpy(priv->copy_fb + offset, priv->fb + offset, len);
+ }
+ }
+}
+
/* Flush video activity to the caches */
int video_sync(struct udevice *vid, bool force)
{
struct video_ops *ops = video_get_ops(vid);
int ret;
+ if (IS_ENABLED(CONFIG_VIDEO_COPY))
+ video_flush_copy(vid);
+
if (ops && ops->video_sync) {
ret = ops->video_sync(vid);
if (ret)
return priv->ysize;
}
-#ifdef CONFIG_VIDEO_COPY
-int video_sync_copy(struct udevice *dev, void *from, void *to)
-{
- struct video_priv *priv = dev_get_uclass_priv(dev);
-
- if (priv->copy_fb) {
- long offset, size;
-
- /* Find the offset of the first byte to copy */
- if ((ulong)to > (ulong)from) {
- size = to - from;
- offset = from - priv->fb;
- } else {
- size = from - to;
- offset = to - priv->fb;
- }
-
- /*
- * Allow a bit of leeway for valid requests somewhere near the
- * frame buffer
- */
- if (offset < -priv->fb_size || offset > 2 * priv->fb_size) {
-#ifdef DEBUG
- char str[120];
-
- snprintf(str, sizeof(str),
- "[** FAULT sync_copy fb=%p, from=%p, to=%p, offset=%lx]",
- priv->fb, from, to, offset);
- console_puts_select_stderr(true, str);
-#endif
- return -EFAULT;
- }
-
- /*
- * Silently crop the memcpy. This allows callers to avoid doing
- * this themselves. It is common for the end pointer to go a
- * few lines after the end of the frame buffer, since most of
- * the update algorithms terminate a line after their last write
- */
- if (offset + size > priv->fb_size) {
- size = priv->fb_size - offset;
- } else if (offset < 0) {
- size += offset;
- offset = 0;
- }
-
- memcpy(priv->copy_fb + offset, priv->fb + offset, size);
- }
-
- return 0;
-}
-
-int video_sync_copy_all(struct udevice *dev)
-{
- struct video_priv *priv = dev_get_uclass_priv(dev);
-
- video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
-
- return 0;
-}
-
-#endif
-
#define SPLASH_DECL(_name) \
extern u8 __splash_ ## _name ## _begin[]; \
extern u8 __splash_ ## _name ## _end[]
enum video_format eformat;
struct bmp_color_table_entry *palette;
int hdr_size;
- int ret;
if (!bmp || !(bmp->header.signature[0] == 'B' &&
bmp->header.signature[1] == 'M')) {
video_damage(dev, x, y, width, height);
- /* Find the position of the top left of the image in the framebuffer */
- fb = (uchar *)(priv->fb + y * priv->line_length + x * bpix / 8);
- ret = video_sync_copy(dev, start, fb);
- if (ret)
- return log_ret(ret);
-
return video_sync(dev, false);
}
*/
int video_default_font_height(struct udevice *dev);
-#ifdef CONFIG_VIDEO_COPY
-/**
- * vidconsole_sync_copy() - Sync back to the copy framebuffer
- *
- * This ensures that the copy framebuffer has the same data as the framebuffer
- * for a particular region. It should be called after the framebuffer is updated
- *
- * @from and @to can be in either order. The region between them is synced.
- *
- * @dev: Vidconsole device being updated
- * @from: Start/end address within the framebuffer (->fb)
- * @to: Other address within the frame buffer
- * Return: 0 if OK, -EFAULT if the start address is before the start of the
- * frame buffer start
- */
-int video_sync_copy(struct udevice *dev, void *from, void *to);
-
-/**
- * video_sync_copy_all() - Sync the entire framebuffer to the copy
- *
- * @dev: Vidconsole device being updated
- * Return: 0 (always)
- */
-int video_sync_copy_all(struct udevice *dev);
-#else
-static inline int video_sync_copy(struct udevice *dev, void *from, void *to)
-{
- return 0;
-}
-
-static inline int video_sync_copy_all(struct udevice *dev)
-{
- return 0;
-}
-
-#endif
-
#ifdef CONFIG_VIDEO_DAMAGE
/**
* video_damage() - Notify the video subsystem about screen updates.
*/
int vidconsole_get_font_size(struct udevice *dev, const char **name, uint *sizep);
-#ifdef CONFIG_VIDEO_COPY
-/**
- * vidconsole_sync_copy() - Sync back to the copy framebuffer
- *
- * This ensures that the copy framebuffer has the same data as the framebuffer
- * for a particular region. It should be called after the framebuffer is updated
- *
- * @from and @to can be in either order. The region between them is synced.
- *
- * @dev: Vidconsole device being updated
- * @from: Start/end address within the framebuffer (->fb)
- * @to: Other address within the frame buffer
- * Return: 0 if OK, -EFAULT if the start address is before the start of the
- * frame buffer start
- */
-int vidconsole_sync_copy(struct udevice *dev, void *from, void *to);
-
-/**
- * vidconsole_memmove() - Perform a memmove() within the frame buffer
- *
- * This handles a memmove(), e.g. for scrolling. It also updates the copy
- * framebuffer.
- *
- * @dev: Vidconsole device being updated
- * @dst: Destination address within the framebuffer (->fb)
- * @src: Source address within the framebuffer (->fb)
- * @size: Number of bytes to transfer
- * Return: 0 if OK, -EFAULT if the start address is before the start of the
- * frame buffer start
- */
-int vidconsole_memmove(struct udevice *dev, void *dst, const void *src,
- int size);
-#else
-
-#include <string.h>
-
-static inline int vidconsole_sync_copy(struct udevice *dev, void *from,
- void *to)
-{
- return 0;
-}
-
-static inline int vidconsole_memmove(struct udevice *dev, void *dst,
- const void *src, int size)
-{
- memmove(dst, src, size);
-
- return 0;
-}
-
-#endif
-
#endif
if (!IS_ENABLED(CONFIG_VIDEO_COPY))
return 0;
+ video_sync(dev, false);
ut_assertf(!memcmp(priv->fb, priv->copy_fb, priv->fb_size),
"Copy framebuffer does not match fb");
/*
* We should have the full content on the main buffer, but only
- * the new content should have been copied to the copy buffer.
+ * 'damage' should have been copied to the copy buffer. This consists
+ * of a while rectangle with the Denx logo and four lines of text. The
+ * rest of the display is black.
+ *
+ * An easy way to try this is by changing video_sync() to call
+ * sandbox_sdl_sync(priv->copy_fb) instead of priv->fb then running the
+ * unit test:
+ *
+ * ./u-boot -Tl
+ * ut dm dm_test_video_copy
*/
vidconsole_put_string(con, test_string);
vidconsole_put_string(con, test_string);
+ video_sync(dev, true);
ut_asserteq(7589, compress_frame_buffer(uts, dev, false));
- ut_asserteq(5278, compress_frame_buffer(uts, dev, true));
+ ut_asserteq(7704, compress_frame_buffer(uts, dev, true));
return 0;
}