Merge branch 'for-next/video'
This commit is contained in:
commit
ca95c2bab9
|
@ -1417,6 +1417,15 @@ config CMD_SPLASH
|
|||
-b COLOR background color in 0xttrrggbb
|
||||
-o render offscreen
|
||||
|
||||
config CMD_FBTEST
|
||||
bool
|
||||
depends on VIDEO
|
||||
select 2D_PRIMITIVES
|
||||
prompt "FB test"
|
||||
help
|
||||
Framebuffer test command that allows to produce a number of
|
||||
test patterns on a screen.
|
||||
|
||||
config CMD_READLINE
|
||||
tristate
|
||||
prompt "readline"
|
||||
|
|
|
@ -57,6 +57,7 @@ obj-$(CONFIG_CMD_HELP) += help.o
|
|||
obj-$(CONFIG_CMD_LSMOD) += lsmod.o
|
||||
obj-$(CONFIG_CMD_INSMOD) += insmod.o
|
||||
obj-$(CONFIG_CMD_SPLASH) += splash.o
|
||||
obj-$(CONFIG_CMD_FBTEST) += fbtest.o
|
||||
obj-$(CONFIG_USB_GADGET_DFU) += dfu.o
|
||||
obj-$(CONFIG_USB_GADGET_SERIAL) += usbserial.o
|
||||
obj-$(CONFIG_CMD_GPIO) += gpio.o
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <getopt.h>
|
||||
#include <fb.h>
|
||||
#include <gui/graphic_utils.h>
|
||||
#include <gui/2d-primitives.h>
|
||||
#include <linux/gcd.h>
|
||||
#include <int_sqrt.h>
|
||||
|
||||
static void fbtest_pattern_bars(struct screen *sc, u32 unused)
|
||||
{
|
||||
int i;
|
||||
|
||||
const u32 xres = sc->info->xres;
|
||||
|
||||
const u32 colors[] = {
|
||||
0xFFFFFF, /* white */
|
||||
0xFFFF00, /* yellow */
|
||||
0x00FFFF, /* cyan */
|
||||
0x00FF00, /* green */
|
||||
0xFF00FF, /* magenta */
|
||||
0xFF0000, /* red */
|
||||
0x0000FF, /* blue */
|
||||
0x000000, /* black */
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(colors); i++) {
|
||||
const u8 r = (colors[i] >> 16) & 0xff;
|
||||
const u8 g = (colors[i] >> 8) & 0xff;
|
||||
const u8 b = (colors[i] >> 0) & 0xff;
|
||||
const int dx = xres / ARRAY_SIZE(colors);
|
||||
|
||||
gu_fill_rectangle(sc,
|
||||
i * dx, -1, (i + 1) * dx - 1, -1,
|
||||
r, g, b, 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
static void fbtest_pattern_geometry(struct screen *sc, u32 color)
|
||||
{
|
||||
int i;
|
||||
|
||||
const u8 r = (color >> 16) & 0xff;
|
||||
const u8 g = (color >> 8) & 0xff;
|
||||
const u8 b = (color >> 0) & 0xff;
|
||||
|
||||
const u32 xres = sc->info->xres;
|
||||
const u32 yres = sc->info->yres;
|
||||
|
||||
const u8 xcount = xres / gcd(xres, yres);
|
||||
const u8 ycount = yres / gcd(xres, yres);
|
||||
|
||||
const struct {
|
||||
int x1, y1, x2, y2;
|
||||
} borders[] = {
|
||||
{ 0, 0, xres - 1, 0 },
|
||||
{ xres - 1, 0, xres - 1, yres - 1 },
|
||||
{ 0, yres - 1, xres - 1, yres - 1 },
|
||||
{ 0, 0, 0, yres - 1 },
|
||||
};
|
||||
|
||||
const int R1 = min(xres, yres) / 2;
|
||||
const int h = xres * xres + yres * yres;
|
||||
const int R2 = (int_sqrt(h) / 2 - R1) * 5 / 12;
|
||||
|
||||
const struct {
|
||||
int x0, y0, radius;
|
||||
} circles[] = {
|
||||
{ xres / 2, yres / 2, R1 - 1 },
|
||||
{ R2, R2, R2 - 1 },
|
||||
{ xres - R2, R2, R2 - 1 },
|
||||
{ xres - R2, yres - R2, R2 - 1 },
|
||||
{ R2, yres - R2, R2 - 1 }
|
||||
};
|
||||
|
||||
void *buf = gui_screen_render_buffer(sc);
|
||||
|
||||
gu_memset_pixel(sc->info, buf, ~color,
|
||||
sc->s.width * sc->s.height);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(borders); i++)
|
||||
gu_draw_line(sc,
|
||||
borders[i].x1, borders[i].y1,
|
||||
borders[i].x2, borders[i].y2,
|
||||
r, g, b, 0xff, 10);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(circles); i++)
|
||||
gu_draw_circle(sc,
|
||||
circles[i].x0, circles[i].y0,
|
||||
circles[i].radius,
|
||||
r, g, b, 0xff);
|
||||
|
||||
for (i = 1; i < ycount; i++) {
|
||||
const int y = (yres - 1) * i / ycount;
|
||||
gu_draw_line(sc,
|
||||
0, y, xres - 1, y,
|
||||
r, g, b, 0xff, 0);
|
||||
}
|
||||
|
||||
|
||||
for (i = 1; i < xcount; i++) {
|
||||
const int x = (xres - 1) * i / xcount;
|
||||
gu_draw_line(sc,
|
||||
x, 0, x, yres - 1,
|
||||
r, g, b, 0xff, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int do_fbtest(int argc, char *argv[])
|
||||
{
|
||||
struct screen *sc;
|
||||
int opt;
|
||||
unsigned int i;
|
||||
const char *pattern_name = NULL;
|
||||
char *fbdev = "/dev/fb0";
|
||||
void (*pattern) (struct screen *sc, u32 color) = NULL;
|
||||
u32 color = 0xffffff;
|
||||
|
||||
struct {
|
||||
const char *name;
|
||||
void (*func) (struct screen *sc, u32 color);
|
||||
} patterns[] = {
|
||||
{ "geometry", fbtest_pattern_geometry },
|
||||
{ "bars", fbtest_pattern_bars }
|
||||
};
|
||||
|
||||
while((opt = getopt(argc, argv, "d:p:c:")) > 0) {
|
||||
switch(opt) {
|
||||
case 'd':
|
||||
fbdev = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
pattern_name = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
color = simple_strtoul(optarg, NULL, 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern_name) {
|
||||
for (i = 0; i < ARRAY_SIZE(patterns); i++)
|
||||
if (!strcmp(pattern_name, patterns[i].name))
|
||||
pattern = patterns[i].func;
|
||||
|
||||
if (!pattern) {
|
||||
printf("Unknown pattern: %s\n", pattern_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
sc = fb_open(fbdev);
|
||||
if (IS_ERR(sc)) {
|
||||
perror("fd_open");
|
||||
return PTR_ERR(sc);
|
||||
}
|
||||
|
||||
if (!pattern_name) {
|
||||
printf("No pattern selected. Cycling through all of them.\n");
|
||||
printf("Press Ctrl-C to stop\n");
|
||||
|
||||
i = 0;
|
||||
for (;;) {
|
||||
uint64_t start;
|
||||
pattern = patterns[i++ % ARRAY_SIZE(patterns)].func;
|
||||
pattern(sc, color);
|
||||
gu_screen_blit(sc);
|
||||
|
||||
start = get_time_ns();
|
||||
while (!is_timeout(start, 2 * SECOND))
|
||||
if (ctrlc())
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
pattern(sc, color);
|
||||
gu_screen_blit(sc);
|
||||
}
|
||||
done:
|
||||
fb_close(sc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAREBOX_CMD_HELP_START(fbtest)
|
||||
BAREBOX_CMD_HELP_TEXT("This command displays a test pattern on a screen")
|
||||
BAREBOX_CMD_HELP_TEXT("")
|
||||
BAREBOX_CMD_HELP_TEXT("Options:")
|
||||
BAREBOX_CMD_HELP_OPT ("-d <fbdev>\t", "framebuffer device (default /dev/fb0)")
|
||||
BAREBOX_CMD_HELP_OPT ("-c color\t", "color")
|
||||
BAREBOX_CMD_HELP_OPT ("-p pattern\t", "pattern name (geometry, bars)")
|
||||
BAREBOX_CMD_HELP_END
|
||||
|
||||
BAREBOX_CMD_START(fbtest)
|
||||
.cmd = do_fbtest,
|
||||
BAREBOX_CMD_DESC("display a test pattern")
|
||||
BAREBOX_CMD_OPTS("[-dcp]")
|
||||
BAREBOX_CMD_GROUP(CMD_GRP_CONSOLE)
|
||||
BAREBOX_CMD_HELP(cmd_fbtest_help)
|
||||
BAREBOX_CMD_END
|
|
@ -320,35 +320,6 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
|
|||
return (hblank);
|
||||
}
|
||||
|
||||
/**
|
||||
* int_sqrt - rough approximation to sqrt
|
||||
* @x: integer of which to calculate the sqrt
|
||||
*
|
||||
* A very rough approximation to the sqrt() function.
|
||||
*/
|
||||
unsigned long int_sqrt(unsigned long x)
|
||||
{
|
||||
unsigned long b, m, y = 0;
|
||||
|
||||
if (x <= 1)
|
||||
return x;
|
||||
|
||||
m = 1UL << (BITS_PER_LONG - 2);
|
||||
while (m != 0) {
|
||||
b = y + m;
|
||||
y >>= 1;
|
||||
|
||||
if (x >= b) {
|
||||
x -= b;
|
||||
y += m;
|
||||
}
|
||||
m >>= 2;
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
EXPORT_SYMBOL(int_sqrt);
|
||||
|
||||
/**
|
||||
* fb_get_hfreq - estimate hsync
|
||||
* @vfreq: vertical refresh rate
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef __2D_PRIMITIVES__
|
||||
#define __2D_PRIMITIVES__
|
||||
|
||||
#include <fb.h>
|
||||
|
||||
void gu_draw_line(struct screen *sc,
|
||||
int x1, int y1, int x2, int y2,
|
||||
u8 r, u8 g, u8 b, u8 a,
|
||||
unsigned int dash);
|
||||
|
||||
void gu_draw_circle(struct screen *sc,
|
||||
int x0, int y0, int radius,
|
||||
u8 r, u8 g, u8 b, u8 a);
|
||||
|
||||
#endif
|
|
@ -28,4 +28,7 @@ void gu_invert_area(struct fb_info *info, void *buf, int startx, int starty, int
|
|||
void gu_screen_blit_area(struct screen *sc, int startx, int starty, int width,
|
||||
int height);
|
||||
|
||||
void gu_fill_rectangle(struct screen *sc,
|
||||
int x1, int y1, int x2, int y2,
|
||||
u8 r, u8 g, u8 b, u8 a);
|
||||
#endif /* __GRAPHIC_UTILS_H__ */
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INT_SQRT__
|
||||
#define __INT_SQRT__
|
||||
|
||||
unsigned long int_sqrt(unsigned long x);
|
||||
|
||||
#endif
|
|
@ -58,3 +58,4 @@ obj-$(CONFIG_BAREBOX_LOGO) += logo/
|
|||
obj-y += reed_solomon/
|
||||
obj-$(CONFIG_RATP) += ratp.o
|
||||
obj-y += list_sort.o
|
||||
obj-y += int_sqrt.o
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
#include <common.h>
|
||||
#include <fb.h>
|
||||
#include <gui/graphic_utils.h>
|
||||
#include <linux/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <fs.h>
|
||||
#include <malloc.h>
|
||||
|
||||
static void __illuminate(struct fb_info *info,
|
||||
int x, int y,
|
||||
u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
void *pixel;
|
||||
|
||||
pixel = fb_get_screen_base(info);
|
||||
pixel += y * info->line_length + x * (info->bits_per_pixel >> 3);
|
||||
|
||||
gu_set_rgba_pixel(info, pixel, r, g, b, a);
|
||||
}
|
||||
|
||||
static void illuminate(struct fb_info *info,
|
||||
bool invert,
|
||||
int x, int y,
|
||||
u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
if (invert)
|
||||
__illuminate(info, y, x,
|
||||
r, g, b, a);
|
||||
else
|
||||
__illuminate(info, x, y,
|
||||
r, g, b, a);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void draw_simple_line(struct screen *sc,
|
||||
int x1, int y1,
|
||||
int x2, int y2,
|
||||
u8 r, u8 g, u8 b, u8 a,
|
||||
unsigned int dash)
|
||||
{
|
||||
int x;
|
||||
bool invert = false;
|
||||
unsigned int pixel = 0;
|
||||
|
||||
BUG_ON(x1 != x2 &&
|
||||
y1 != y2);
|
||||
|
||||
if (x1 == x2) {
|
||||
swap(x1, y1);
|
||||
swap(x2, y2);
|
||||
invert = true;
|
||||
}
|
||||
|
||||
if (x1 > x2) {
|
||||
swap(x1, x2);
|
||||
swap(y1, y2);
|
||||
}
|
||||
|
||||
for (x = x1; x < x2 - 1; x++) {
|
||||
if (!dash ||
|
||||
(++pixel % (2 * dash)) < dash)
|
||||
illuminate(sc->info,
|
||||
invert,
|
||||
x, y1,
|
||||
r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gl_draw_line - draw a 2D dashed line between (x1, y1) and (x2,y2)
|
||||
*
|
||||
* @sc: screen to draw on
|
||||
* @x1, @y1: first point defining the line
|
||||
* @x2, @y2: second point defining the line
|
||||
* @r, @g, @b, @a: line's color
|
||||
* @dash: dash length (0 denotes solid line)
|
||||
*
|
||||
* gl_draw_line() implements integer version of Bresenham's algoritm
|
||||
* as can be found here:
|
||||
*
|
||||
* http://www.idav.ucdavis.edu/education/GraphicsNotes/Bresenhams-Algorithm.pdf
|
||||
*/
|
||||
void gu_draw_line(struct screen *sc,
|
||||
int x1, int y1,
|
||||
int x2, int y2,
|
||||
u8 r, u8 g, u8 b, u8 a,
|
||||
unsigned int dash)
|
||||
{
|
||||
int dx;
|
||||
int dy;
|
||||
int i, j, eps;
|
||||
bool invert = false;
|
||||
unsigned int pixel = 0;
|
||||
|
||||
BUG_ON(x1 < 0 || y1 < 0 ||
|
||||
x2 < 0 || y2 < 0);
|
||||
|
||||
if (x1 == x2 || y1 == y2) {
|
||||
draw_simple_line(sc,
|
||||
x1, y1,
|
||||
x2, y2,
|
||||
r, g, b, a, dash);
|
||||
return;
|
||||
}
|
||||
|
||||
dx = abs(x2 - x1);
|
||||
dy = abs(y2 - y1);
|
||||
|
||||
/*
|
||||
* First thing we need to determine "Driving Axis", as can be
|
||||
* seen below if Y-axis projection of the line is bigger than
|
||||
* X-axis projection we swap axes and pretend the X is Y and
|
||||
* vice versa
|
||||
*/
|
||||
if (dy > dx) {
|
||||
swap(x1, y1);
|
||||
swap(x2, y2);
|
||||
swap(dx, dy);
|
||||
invert = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Second, we need to make sure that we will be traversing
|
||||
* driving axis in the direction of increment so we swap point
|
||||
* 1 with point 2 if x1 is greater than x2
|
||||
*/
|
||||
if (x1 > x2) {
|
||||
swap(x1, x2);
|
||||
swap(y1, y2);
|
||||
}
|
||||
|
||||
j = y1;
|
||||
eps = dy - dx;
|
||||
|
||||
for (i = x1; i <= x2 - 1; i++) {
|
||||
if (!dash ||
|
||||
(++pixel % (2 * dash)) > dash) {
|
||||
illuminate(sc->info,
|
||||
invert,
|
||||
j, i,
|
||||
r, g, b, a);
|
||||
} else {
|
||||
printf("NOT illuminating pixel: %d\n", pixel);
|
||||
}
|
||||
|
||||
if (eps >= 0) {
|
||||
j += 1;
|
||||
eps -= dx;
|
||||
}
|
||||
|
||||
eps += dy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gl_draw_circle - draw a 2D circle with center at (x0, y0)
|
||||
*
|
||||
* @sc: screen to draw on
|
||||
* @x0, @y0: coordinates of circle's center
|
||||
* @radius: circle's radius
|
||||
* @r, @g, @b, @a: circle's color
|
||||
|
||||
*
|
||||
* gu_draw_circle() implements midpoint circle algorithm as can be
|
||||
* found here:
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
|
||||
*/
|
||||
void gu_draw_circle(struct screen *sc,
|
||||
int x0, int y0, int radius,
|
||||
u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
int x = radius;
|
||||
int y = 0;
|
||||
int e = 0;
|
||||
|
||||
BUG_ON(x0 < 0 || y0 < 0 || radius < 0);
|
||||
|
||||
while (x >= y) {
|
||||
__illuminate(sc->info, x0 + x, y0 + y, r, g, b, a);
|
||||
__illuminate(sc->info, x0 + y, y0 + x, r, g, b, a);
|
||||
__illuminate(sc->info, x0 - y, y0 + x, r, g, b, a);
|
||||
__illuminate(sc->info, x0 - x, y0 + y, r, g, b, a);
|
||||
__illuminate(sc->info, x0 - x, y0 - y, r, g, b, a);
|
||||
__illuminate(sc->info, x0 - y, y0 - x, r, g, b, a);
|
||||
__illuminate(sc->info, x0 + y, y0 - x, r, g, b, a);
|
||||
__illuminate(sc->info, x0 + x, y0 - y, r, g, b, a);
|
||||
|
||||
y += 1;
|
||||
e += 1 + 2 * y;
|
||||
|
||||
if (2 * (e - x) + 1 > 0) {
|
||||
x -= 1;
|
||||
e += 1 - 2 * x;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,9 @@ config IMAGE_RENDERER
|
|||
|
||||
if IMAGE_RENDERER
|
||||
|
||||
config 2D_PRIMITIVES
|
||||
bool
|
||||
|
||||
config BMP
|
||||
bool "bmp"
|
||||
|
||||
|
|
|
@ -3,3 +3,4 @@ obj-$(CONFIG_IMAGE_RENDERER) += image_renderer.o graphic_utils.o
|
|||
obj-$(CONFIG_PNG) += png.o
|
||||
obj-$(CONFIG_LODEPNG) += png_lode.o lodepng.o
|
||||
obj-$(CONFIG_PICOPNG) += png_pico.o picopng.o
|
||||
obj-$(CONFIG_2D_PRIMITIVES) += 2d-primitives.o
|
||||
|
|
|
@ -336,3 +336,32 @@ void gu_screen_blit(struct screen *sc)
|
|||
if (info->screen_base_shadow)
|
||||
memcpy(info->screen_base, info->screen_base_shadow, sc->fbsize);
|
||||
}
|
||||
|
||||
void gu_fill_rectangle(struct screen *sc,
|
||||
int x1, int y1, int x2, int y2,
|
||||
u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
int y;
|
||||
void *buf = gui_screen_render_buffer(sc);
|
||||
|
||||
x1 = max(0, x1);
|
||||
y1 = max(0, y1);
|
||||
|
||||
x2 = (x2 < 0) ? sc->info->xres - 1 : x2;
|
||||
y2 = (y2 < 0) ? sc->info->yres - 1 : y2;
|
||||
|
||||
if (x2 < x1)
|
||||
swap(x1, x2);
|
||||
if (y2 < y1)
|
||||
swap(y1, y2);
|
||||
|
||||
for(y = y1; y <= y2; y++) {
|
||||
int x;
|
||||
unsigned char *pixel = buf + y * sc->info->line_length +
|
||||
x1 * (sc->info->bits_per_pixel / 8);
|
||||
for(x = x1; x <= x2; x++) {
|
||||
gu_set_rgba_pixel(sc->info, pixel, r, g, b, a);
|
||||
pixel += sc->info->bits_per_pixel / 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
/**
|
||||
* int_sqrt - rough approximation to sqrt
|
||||
* @x: integer of which to calculate the sqrt
|
||||
*
|
||||
* A very rough approximation to the sqrt() function.
|
||||
*/
|
||||
unsigned long int_sqrt(unsigned long x)
|
||||
{
|
||||
unsigned long b, m, y = 0;
|
||||
|
||||
if (x <= 1)
|
||||
return x;
|
||||
|
||||
m = 1UL << (BITS_PER_LONG - 2);
|
||||
while (m != 0) {
|
||||
b = y + m;
|
||||
y >>= 1;
|
||||
|
||||
if (x >= b) {
|
||||
x -= b;
|
||||
y += m;
|
||||
}
|
||||
m >>= 2;
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
EXPORT_SYMBOL(int_sqrt);
|
Loading…
Reference in New Issue