blob: c4288c1d0b4820df880f69b7b231564f55bf8f72 [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include "base/container_of.h"
#include "base/xalloc.h"
#include "drivers/display/framebuffer.h"
static int fb_display_initialize(FbDisplay *display)
{
if (display->fb_info.buffer)
return 0;
if (framebuffer_prepare(display->framebuffer, &display->fb_info)) {
display->fb_info.buffer = NULL;
return 1;
}
if (display->monitor && monitor_enable(display->monitor))
return 1;
return 0;
}
static inline void fb_display_set_pixel(FbDisplay *display,
uint32_t x, uint32_t y, uint32_t color)
{
const uint32_t xres = display->fb_info.resolution.x;
const uint8_t bpp = display->fb_info.bits_per_pixel;
uint8_t *pixel = display->fb_info.buffer + (x + y * xres) * bpp / 8;
for (int i = 0; i < bpp / 8; i++)
pixel[i] = (color >> (i * 8));
}
static int fb_display_dimensions(DisplayOps *me,
uint32_t *height, uint32_t *width)
{
FbDisplay *display = container_of(me, FbDisplay, ops);
if (fb_display_initialize(display))
return 1;
*height = display->fb_info.resolution.y;
*width = display->fb_info.resolution.x;
return 0;
}
static int fb_display_fill(DisplayOps *me, uint32_t x, uint32_t y,
uint32_t height, uint32_t width,
const DcColor *color)
{
FbDisplay *display = container_of(me, FbDisplay, ops);
if (fb_display_initialize(display))
return 1;
if (height == 0 || width == 0)
return 0;
const uint32_t pval = framebuffer_pixel_value(&display->fb_info, color);
for (uint32_t offy = 0; offy < height; offy++) {
for (uint32_t offx = 0; offx < width; offx++) {
fb_display_set_pixel(display, x + offx,
y + offy, pval);
}
}
return 0;
}
static void fb_display_move_row(FbDisplay *display, uint32_t x, uint32_t y,
uint32_t new_x, uint32_t new_y, uint32_t width)
{
const uint32_t xres = display->fb_info.resolution.x;
const uint8_t bpp = display->fb_info.bits_per_pixel;
uint8_t *from = display->fb_info.buffer + (x + y * xres) * bpp / 8;
uint8_t *to = display->fb_info.buffer +
(new_x + new_y * xres) * bpp / 8;
memmove(to, from, width * bpp / 8);
}
static int fb_display_move(DisplayOps *me, uint32_t x, uint32_t y,
uint32_t new_x, uint32_t new_y,
uint32_t height, uint32_t width)
{
FbDisplay *display = container_of(me, FbDisplay, ops);
if (fb_display_initialize(display))
return 1;
if (height == 0 || width == 0)
return 0;
for (uint32_t y_idx = 0; y_idx < height; y_idx++) {
uint32_t offy = (new_y > y) ? (height - y_idx - 1) : y_idx;
fb_display_move_row(display, x, y + offy, new_x,
new_y + offy, width);
}
return 0;
}
static int fb_display_draw(DisplayOps *me, uint32_t x, uint32_t y,
const DcBitmap *bitmap)
{
FbDisplay *display = container_of(me, FbDisplay, ops);
if (fb_display_initialize(display))
return 1;
DcColor *pixel = bitmap->pixels;
for (uint32_t offy = 0; offy < bitmap->height; offy++) {
for (uint32_t offx = 0; offx < bitmap->width; offx++) {
uint32_t pval = framebuffer_pixel_value(
&display->fb_info, pixel++);
fb_display_set_pixel(display, x + offx,
y + offy, pval);
}
}
return 0;
}
FbDisplay *new_fb_display(FrameBufferOps *framebuffer, MonitorOps *monitor)
{
FbDisplay *display = xzalloc(sizeof(*display));
display->ops.dimensions = &fb_display_dimensions;
display->ops.fill = &fb_display_fill;
display->ops.move = &fb_display_move;
display->ops.draw = &fb_display_draw;
display->framebuffer = framebuffer;
display->monitor = monitor;
return display;
}