diff --git a/commands/videotest.c b/commands/videotest.c index 6fe4b9b..22e6e8c 100644 --- a/commands/videotest.c +++ b/commands/videotest.c @@ -24,6 +24,105 @@ #include #include #include +#include +#include /*for some reason render target type is defined there */ +#include + +char leaf_data[] = { 0x00, 0x0f, 0xe0, 0x00, + 0x00, 0x7f, 0xfc, 0x00, + 0x01, 0xff, 0xff, 0x00, + 0x03, 0xff, 0xff, 0x80, + + 0x07, 0xff, 0xff, 0xe0, + 0x0f, 0xff, 0xff, 0xf0, + 0x1f, 0xff, 0xff, 0xf0, + 0x3f, 0xff, 0xff, 0xf8, + + 0x3f, 0xff, 0xff, 0xf8, + 0x7f, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xfe, + + 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xfe, + + 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xfe, + + 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xf8, + + 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xe0, + 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, + + 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xfc, 0x00, + 0xff, 0xff, 0xe0, 0x00, + 0xff, 0x00, 0x00, 0x00 }; +#define LEAF_SIZE 32 + +struct grub_video_bitmap leaves[4]; + +static void init_leaves(void) +{ + + leaves[0].mode_info.width = LEAF_SIZE; + leaves[0].mode_info.height = LEAF_SIZE; + leaves[0].mode_info.transform = FB_TRAN_EAST; + leaves[0].mode_info.mode_type = + (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) + | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP; + leaves[0].mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED; + leaves[0].mode_info.bpp = 1; + leaves[0].mode_info.bytes_per_pixel = 0; + leaves[0].mode_info.pitch = LEAF_SIZE; + leaves[0].mode_info.number_of_colors = 2; + leaves[0].mode_info.bg_red = 128; + leaves[0].mode_info.fg_red = 255; + leaves[0].mode_info.bg_green = 128; + leaves[0].mode_info.fg_green = 255; + leaves[0].mode_info.bg_blue = 128; + leaves[0].mode_info.fg_blue = 255; + leaves[0].data = leaf_data; + + grub_memcpy(&leaves[1], leaves, sizeof(leaves[0])); + grub_memcpy(&leaves[2], leaves, 2* sizeof(leaves[0])); + leaves[1].mode_info.transform = FB_TRAN_NORTH; + leaves[2].mode_info.transform = FB_TRAN_WEST; + leaves[3].mode_info.transform = FB_TRAN_SOUTH; + leaves[0].mode_info.fg_red = 0; + leaves[1].mode_info.fg_green = 0; + leaves[2].mode_info.fg_blue = 0; + leaves[3].mode_info.fg_blue = 0; + leaves[3].mode_info.fg_green = 0; + leaves[3].mode_info.fg_red = 0; +} + +#define BORDER 20 + +static void draw_leaves(void) +{ + grub_font_t sans; + grub_video_color_t color; + + sans = grub_font_get ("Helvetica Bold 14"); + color = grub_video_map_rgb (255, 255, 255); + + grub_video_blit_bitmap(leaves, GRUB_VIDEO_BLIT_REPLACE, BORDER, BORDER, 0, 0, LEAF_SIZE, LEAF_SIZE); + grub_video_blit_bitmap(leaves + 1, GRUB_VIDEO_BLIT_REPLACE, BORDER+LEAF_SIZE, BORDER, 0, 0, LEAF_SIZE, LEAF_SIZE); + grub_video_blit_bitmap(leaves + 2, GRUB_VIDEO_BLIT_REPLACE, BORDER+LEAF_SIZE, BORDER+LEAF_SIZE, 0, 0, LEAF_SIZE, LEAF_SIZE); + grub_video_blit_bitmap(leaves + 3, GRUB_VIDEO_BLIT_REPLACE, BORDER, BORDER+LEAF_SIZE, 0, 0, LEAF_SIZE, LEAF_SIZE); + grub_font_draw_string ("Leaves", sans, color, BORDER + LEAF_SIZE / 2, 4*LEAF_SIZE + BORDER); + +} static grub_err_t grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), @@ -34,10 +133,10 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), return grub_errno; grub_video_color_t color; - unsigned int x; - unsigned int y; - unsigned int width; - unsigned int height; + int x; + int y; + int width; + int height; int i; grub_font_t sansbig; grub_font_t sans; @@ -48,9 +147,47 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), grub_video_color_t palette[16]; const char *str; int texty; + struct grub_video_fbrender_target * tgt; + grub_video_fb_get_active_render_target(&tgt); + init_leaves(); grub_video_get_viewport (&x, &y, &width, &height); + draw_leaves(); + + tgt->mode_info.transform=FB_TRAN_MIRROR; + draw_leaves(); + + tgt->mode_info.transform=FB_TRAN_FLIP|FB_TRAN_MIRROR; + draw_leaves(); + + tgt->mode_info.transform=FB_TRAN_FLIP; + draw_leaves(); + + grub_getkey (); + + tgt->mode_info.transform=FB_TRAN_NORTH; + color = grub_video_map_rgb (0, 0, 0); + grub_video_fill_rect (color, 0, 0, width, height); + draw_leaves(); + + tgt->mode_info.transform=FB_TRAN_EAST; + grub_video_set_viewport (x, y, height, width); + draw_leaves(); + + tgt->mode_info.transform=FB_TRAN_SOUTH; + grub_video_set_viewport (x, y, width, height); + draw_leaves(); + + tgt->mode_info.transform=FB_TRAN_WEST; + grub_video_set_viewport (x, y, height, width); + draw_leaves(); + + tgt->mode_info.transform=FB_TRAN_NORTH; + grub_video_set_viewport (x, y, width, height); + + grub_getkey (); + grub_video_create_render_target (&text_layer, width, height, GRUB_VIDEO_MODE_TYPE_RGB | GRUB_VIDEO_MODE_TYPE_ALPHA); @@ -115,7 +252,8 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), str = "Unicode test: happy\xE2\x98\xBA \xC2\xA3 5.00" " \xC2\xA1\xCF\x84\xC3\xA4u! " - " \xE2\x84\xA4\xE2\x8A\x87\xE2\x84\x9D"; + " \xE2\x84\xA4\xE2\x8A\x87\xE2\x84\x9D " + " \343\201\202!" /* hiragana letter a */; color = grub_video_map_rgb (128, 128, 255); /* All characters in the string exist in the 'Fixed 20' (10x20) font. */ diff --git a/font/font.c b/font/font.c index a812919..176443a 100644 --- a/font/font.c +++ b/font/font.c @@ -987,8 +987,10 @@ grub_font_draw_glyph (struct grub_font_glyph *glyph, if (glyph->width == 0 || glyph->height == 0) return GRUB_ERR_NONE; + /* TODO: add support for bitmaps to create_bitmap */ glyph_bitmap.mode_info.width = glyph->width; glyph_bitmap.mode_info.height = glyph->height; + glyph_bitmap.mode_info.transform = 0; glyph_bitmap.mode_info.mode_type = (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP; diff --git a/include/grub/fbblit.h b/include/grub/fbblit.h index 664f508..ae77134 100644 --- a/include/grub/fbblit.h +++ b/include/grub/fbblit.h @@ -28,7 +28,7 @@ void grub_video_fbblit_replace (struct grub_video_fbblit_info *dst, struct grub_video_fbblit_info *src, int x, int y, int width, int height, - int offset_x, int offset_y); + int offset_x, int offset_y, int transform); void grub_video_fbblit_replace_directN (struct grub_video_fbblit_info *dst, @@ -94,7 +94,7 @@ void grub_video_fbblit_blend (struct grub_video_fbblit_info *dst, struct grub_video_fbblit_info *src, int x, int y, int width, int height, - int offset_x, int offset_y); + int offset_x, int offset_y, int transform); void grub_video_fbblit_blend_BGRA8888_RGBA8888 (struct grub_video_fbblit_info *dst, diff --git a/include/grub/fbfill.h b/include/grub/fbfill.h index c85fa12..b60a7ba 100644 --- a/include/grub/fbfill.h +++ b/include/grub/fbfill.h @@ -32,10 +32,10 @@ struct grub_video_fbrender_target struct { - unsigned int x; - unsigned int y; - unsigned int width; - unsigned int height; + int x; + int y; + int width; + int height; } viewport; /* Indicates whether the data has been allocated by us and must be freed diff --git a/include/grub/fbtran.h b/include/grub/fbtran.h new file mode 100644 index 0000000..d72be81 --- /dev/null +++ b/include/grub/fbtran.h @@ -0,0 +1,235 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + + +#ifndef GRUB_FBTRAN_HEADER +#define GRUB_FBTRAN_HEADER 1 + +#include +#include +#include + +/* NOTE: This header is private header for fb driver and should not be used + in other parts of the code. */ + +/* Supported operations are simple and easy to understand. + * MIRROR | swap image across (around) the vertical axis + * FLIP - swap image across the horizontal axis - upside down + * SWAP / swap image across the x=y axis - swap the x and y coordinates + * + * All the operations are self-negating. + * || = -- = // = 0 (identity) + * + * | and - are commutative. + * + * |- = -| + * + * The relationship between \ and |,- is more peculiar: + * + * \- = |\ + * \| = -\ + * + * The typical display operations used to adjust displayed picture for use with + * rotated display equipment and/or mirrors are FLIP, MIRROR, and rot90, + * rot180, rot270. + * + * The way this rotation works is somewhat confusing. If we say "rotate left" + * does that mean to rotate the screen left (and rotate the picture right to + * compensate) or the other way around? + * + * So I will try to explain in different terms for clarity. + * Let's say that what you normally get is "facing the north side of the + * screen" or "N" for short. If you turn the screen anti-clockwise you get E, + * etc. + * + * TODO: check that applying mirroring first works for non-square bitmaps ! + * If we apply the simple transforms (MIRROR, FLIP) first to get the corretct + * picture when facing the east side of the screen we need the -\ transform. + * + * E = -rot90 = -\ + * S = -rot180 = -\-\ = -|\\ = -| + * W = -rot270 = -|-\ = |\ + * + * Forward transform is from user visible cordinates to framebuffer memory coordinates. + */ + +#define FB_TRAN_SWAP 1 +#define FB_TRAN_FLIP 2 +#define FB_TRAN_MIRROR 4 +#define FB_TRAN_MASK 7 +#define FB_TRAN_SIMPLE 6 +#define FB_TRAN_NORTH 0 +#define FB_TRAN_EAST (FB_TRAN_FLIP | FB_TRAN_SWAP) +#define FB_TRAN_SOUTH (FB_TRAN_FLIP | FB_TRAN_MIRROR) +#define FB_TRAN_WEST (FB_TRAN_MIRROR | FB_TRAN_SWAP) + +/* internal function used for transforms */ +static inline int fb_tran_swap_tran(int transform) +{ + int old = transform; + transform &= FB_TRAN_SWAP; + if (old & FB_TRAN_MIRROR) + transform ^= FB_TRAN_FLIP; + if (old & FB_TRAN_FLIP) + transform ^= FB_TRAN_MIRROR; + return transform; +} + +/* Return a new bitmap for the transformation which is the result of applying + * the transformations present in the first bitmap, and then transformations in + * the second bitmap. Should work on modes that have the same width and height + * at the point the transfom is appended. In other words: don't use.*/ +static inline int fb_tran_append(int transform_first, int transform_second) +{ + return (transform_first & FB_TRAN_SWAP) ? + (transform_first ^ fb_tran_swap_tran(transform_second)) : + (transform_first ^ transform_second); +} + +/* Return a bitmap for transformation that negates the specified transformation. */ +static inline int fb_tran_invert(int transform) +{ + return (transform & FB_TRAN_SWAP) ? fb_tran_swap_tran(transform) : transform; +} + +/* Create a bitmap for transformation that has to be applied after the first + * transformation to obtain the second transformation. */ +static inline int fb_tran_diff(int transform_first, int transform_second) +{ + return fb_tran_append(fb_tran_invert(transform_first), transform_second); +} + +/* transform screen dimensions */ +static inline grub_err_t fb_tran_dim_back(int * width, int * height, int transform) +{ + if (transform & FB_TRAN_SWAP) + swap_int(width, height); + return GRUB_ERR_NONE; +} + +static inline grub_err_t fb_tran_dim(unsigned * width, unsigned * height, int transform) +{ + if (transform & FB_TRAN_SWAP) + swap_unsigned(width, height); + return GRUB_ERR_NONE; +} + +/* internal - apply coordinate transform to a point */ +static inline grub_err_t fb_tran_point_intern(int *x, int *y, int width, int height, int transform, int user_coordinates) +{ + if (user_coordinates && (transform & FB_TRAN_SWAP)) + swap_int(&width, &height); + if (transform & FB_TRAN_MIRROR) + *x = width -1 - *x; + if (transform & FB_TRAN_FLIP) + *y = height -1 - *y; + if (transform & FB_TRAN_SWAP) + swap_int(x, y); + return GRUB_ERR_NONE; +} + +/* apply coordinate transform to a point */ +static inline grub_err_t fb_tran_point(int *x, int *y, const struct grub_video_mode_info *mode) +{ + return fb_tran_point_intern(x, y, mode->width, mode->height, mode->transform, 1); +} + +/* apply reverse coordinate transform to a point */ +static inline grub_err_t fb_tran_point_back(int *x, int *y, const struct grub_video_mode_info *mode) +{ + return fb_tran_point_intern(x, y, mode->width, mode->height, fb_tran_invert(mode->transform), 0); +} + +/* internal - apply coordinate transform to a rectangle */ +static inline grub_err_t fb_tran_rect_intern(int *x, int *y, int *width, int *height, int mode_width, int mode_height, int transform, int user_coordinates) +{ + int x2, y2; + grub_fb_norm_rect(x, y, width, height); + x2 = *x + *width; + y2 = *y + *height; + fb_tran_point_intern(x, y, mode_width, mode_height, transform, user_coordinates); + fb_tran_point_intern(&x2, &y2, mode_width, mode_height, transform, user_coordinates); + if(*x > x2) + { + swap_int(x, &x2); + (*x)++; + x2++; + } + if(*y > y2) + { + swap_int(y, &y2); + (*y)++; + y2++; + } + *width = x2 - *x; + *height = y2 - *y; + return GRUB_ERR_NONE; +} + +/* apply coordinate transform to a rectangle */ +static inline grub_err_t fb_tran_rect(int *x, int *y, int *width, int *height, const struct grub_video_mode_info *mode) +{ + return fb_tran_rect_intern(x, y, width, height, mode->width, mode->height, mode->transform,1); +} + +/* apply reverse coordinate transform to a rectangle */ +static inline grub_err_t fb_tran_rect_back(int *x, int *y, int *width, int *height, const struct grub_video_mode_info *mode) +{ + return fb_tran_rect_intern(x, y, width, height, mode->width, mode->height, fb_tran_invert(mode->transform),0); +} + +/* requires a 4byte buffer */ +static inline void fb_tran_format(char * str, int transform) +{ + if (transform & FB_TRAN_MIRROR) + *str++ = 'M'; + if (transform & FB_TRAN_FLIP) + *str++ = 'F'; + if (transform & FB_TRAN_SWAP) + *str++ = 'X'; + *str=0; +} + +/* Return bitmap of transform that is to be applied during blit. + * The source and target point are transformed to the framebuffer coordinates + * so that src_x,src_y is copied to x,y. + */ +#include /* grub_getkey */ +static inline grub_err_t fb_tran_blit(int *src_x, int *src_y, int *width, int *height, + int *x, int *y, int *transform, + const struct grub_video_mode_info *source_mode, + const struct grub_video_mode_info *target_mode) +{ + int sx1 = *src_x; + int sy1 = *src_y; + int sx2, sy2; + + fb_tran_rect(src_x, src_y, width, height, source_mode); + sx2 = *src_x; + sy2 = *src_y; + fb_tran_point_back(&sx2, &sy2, source_mode); + *x += sx2 - sx1; + *y += sy2 - sy1; + fb_tran_point(x, y, target_mode); + /* TODO: define blitter transform and check that this does the right thing */ + *transform = fb_tran_diff(source_mode->transform, target_mode->transform); + return GRUB_ERR_NONE; +} + + +#endif /* ! GRUB_FBTRAN_HEADER */ diff --git a/include/grub/misc.h b/include/grub/misc.h index a63a0b4..3651046 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -212,6 +212,15 @@ grub_max (long x, long y) return y; } +static inline long +grub_min (long x, long y) +{ + if (x > y) + return y; + else + return x; +} + /* Rounded-up division */ static inline unsigned int grub_div_roundup (unsigned int x, unsigned int y) diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h index 6a93ab0..c7ebe2f 100644 --- a/include/grub/util/misc.h +++ b/include/grub/util/misc.h @@ -39,6 +39,9 @@ extern char *progname; extern int verbosity; +static inline void swap_int(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } +static inline void swap_unsigned(unsigned *a, unsigned *b) { unsigned tmp = *a; *a = *b; *b = tmp; } + void grub_util_warn (const char *fmt, ...); void grub_util_info (const char *fmt, ...); void grub_util_error (const char *fmt, ...) __attribute__ ((noreturn)); diff --git a/include/grub/video.h b/include/grub/video.h index 4145db4..c07de38 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -149,6 +149,8 @@ struct grub_video_mode_info grub_uint8_t fg_green; grub_uint8_t fg_blue; grub_uint8_t fg_alpha; + + int transform; }; struct grub_video_palette_data @@ -171,7 +173,7 @@ struct grub_video_adapter grub_err_t (*fini) (void); grub_err_t (*setup) (unsigned int width, unsigned int height, - unsigned int mode_type); + unsigned int mode_type, int transform); grub_err_t (*get_info) (struct grub_video_mode_info *mode_info); @@ -184,11 +186,9 @@ struct grub_video_adapter grub_err_t (*get_palette) (unsigned int start, unsigned int count, struct grub_video_palette_data *palette_data); - grub_err_t (*set_viewport) (unsigned int x, unsigned int y, - unsigned int width, unsigned int height); + grub_err_t (*set_viewport) (int x, int y, int width, int height); - grub_err_t (*get_viewport) (unsigned int *x, unsigned int *y, - unsigned int *width, unsigned int *height); + grub_err_t (*get_viewport) (int *x, int *y, int *width, int *height); grub_video_color_t (*map_color) (grub_uint32_t color_name); @@ -203,17 +203,17 @@ struct grub_video_adapter grub_uint8_t *blue, grub_uint8_t *alpha); grub_err_t (*fill_rect) (grub_video_color_t color, int x, int y, - unsigned int width, unsigned int height); + int width, int height); grub_err_t (*blit_bitmap) (struct grub_video_bitmap *bitmap, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height); + int width, int height); grub_err_t (*blit_render_target) (struct grub_video_render_target *source, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height); + int width, int height); grub_err_t (*scroll) (grub_video_color_t color, int dx, int dy); @@ -258,11 +258,11 @@ grub_err_t grub_video_set_palette (unsigned int start, unsigned int count, grub_err_t grub_video_get_palette (unsigned int start, unsigned int count, struct grub_video_palette_data *palette_data); -grub_err_t grub_video_set_viewport (unsigned int x, unsigned int y, - unsigned int width, unsigned int height); +grub_err_t grub_video_set_viewport (int x, int y, + int width, int height); -grub_err_t grub_video_get_viewport (unsigned int *x, unsigned int *y, - unsigned int *width, unsigned int *height); +grub_err_t grub_video_get_viewport (int *x, int *y, + int *width, int *height); grub_video_color_t grub_video_map_color (grub_uint32_t color_name); @@ -277,19 +277,18 @@ grub_err_t grub_video_unmap_color (grub_video_color_t color, grub_uint8_t *blue, grub_uint8_t *alpha); grub_err_t grub_video_fill_rect (grub_video_color_t color, int x, int y, - unsigned int width, unsigned int height); + int width, int height); grub_err_t grub_video_blit_bitmap (struct grub_video_bitmap *bitmap, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height); + int width, int height); grub_err_t grub_video_blit_render_target (struct grub_video_render_target *source, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, - unsigned int height); + int width, int height); grub_err_t grub_video_scroll (grub_video_color_t color, int dx, int dy); diff --git a/include/grub/video_fb.h b/include/grub/video_fb.h index 850946d..f1aa295 100644 --- a/include/grub/video_fb.h +++ b/include/grub/video_fb.h @@ -36,6 +36,22 @@ struct grub_video_fbblit_info; struct grub_video_fbrender_target; +/* make width and height of a rectangle non-negative */ +static inline grub_err_t grub_fb_norm_rect(int *x, int *y, int *width, int *height) +{ + if(*width < 0) + { + *width = -*width; + *x -= *width - 1; + } + if(*height < 0) + { + *height = -*height; + *y -= *height - 1; + } + return GRUB_ERR_NONE; +} + #define GRUB_VIDEO_FBSTD_NUMCOLORS 16 extern struct grub_video_palette_data grub_video_fbstd_colors[GRUB_VIDEO_FBSTD_NUMCOLORS]; @@ -55,11 +71,11 @@ grub_err_t grub_video_fb_set_palette (unsigned int start, unsigned int count, struct grub_video_palette_data *palette_data); grub_err_t -grub_video_fb_set_viewport (unsigned int x, unsigned int y, - unsigned int width, unsigned int height); +grub_video_fb_set_viewport (int x, int y, + int width, int height); grub_err_t -grub_video_fb_get_viewport (unsigned int *x, unsigned int *y, - unsigned int *width, unsigned int *height); +grub_video_fb_get_viewport (int *x, int *y, + int *width, int *height); grub_video_color_t grub_video_fb_map_color (grub_uint32_t color_name); @@ -85,19 +101,19 @@ grub_video_fb_unmap_color_int (struct grub_video_fbblit_info * source, grub_err_t grub_video_fb_fill_rect (grub_video_color_t color, int x, int y, - unsigned int width, unsigned int height); + int width, int height); grub_err_t grub_video_fb_blit_bitmap (struct grub_video_bitmap *bitmap, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height); + int width, int height); grub_err_t grub_video_fb_blit_render_target (struct grub_video_fbrender_target *source, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height); + int width, int height); grub_err_t grub_video_fb_scroll (grub_video_color_t color, int dx, int dy); diff --git a/video/bitmap.c b/video/bitmap.c index 7b135a5..88c7bfd 100644 --- a/video/bitmap.c +++ b/video/bitmap.c @@ -75,6 +75,7 @@ grub_video_bitmap_create (struct grub_video_bitmap **bitmap, mode_info->width = width; mode_info->height = height; mode_info->blit_format = blit_format; + mode_info->transform = 0; switch (blit_format) { diff --git a/video/fb/fbblit.c b/video/fb/fbblit.c index 705da83..abfab8c 100644 --- a/video/fb/fbblit.c +++ b/video/fb/fbblit.c @@ -27,16 +27,19 @@ #include #include #include +#include /* Generic replacing blitter (slow). Works for every supported format. */ void grub_video_fbblit_replace (struct grub_video_fbblit_info *dst, struct grub_video_fbblit_info *src, int x, int y, int width, int height, - int offset_x, int offset_y) + int offset_x, int offset_y, int transform) { int i; int j; + int dx = (transform & FB_TRAN_MIRROR) ? -1 : 1; + int dy = (transform & FB_TRAN_FLIP) ? -1 : 1; grub_uint8_t src_red; grub_uint8_t src_green; grub_uint8_t src_blue; @@ -56,8 +59,11 @@ grub_video_fbblit_replace (struct grub_video_fbblit_info *dst, dst_color = grub_video_fb_map_rgba (src_red, src_green, src_blue, src_alpha); - set_pixel (dst, x + i, y + j, dst_color); - } + if (transform & FB_TRAN_SWAP) + set_pixel (dst, x + j*dy, y + i*dx, dst_color); + else + set_pixel (dst, x + i*dx, y + j*dy, dst_color); + } } } @@ -409,10 +415,12 @@ void grub_video_fbblit_blend (struct grub_video_fbblit_info *dst, struct grub_video_fbblit_info *src, int x, int y, int width, int height, - int offset_x, int offset_y) + int offset_x, int offset_y, int transform) { int i; int j; + int dx = (transform & FB_TRAN_MIRROR) ? -1 : 1; + int dy = (transform & FB_TRAN_FLIP) ? -1 : 1; for (j = 0; j < height; j++) { @@ -460,7 +468,10 @@ grub_video_fbblit_blend (struct grub_video_fbblit_info *dst, dst_color = grub_video_fb_map_rgba (dst_red, dst_green, dst_blue, dst_alpha); - set_pixel (dst, x + i, y + j, dst_color); + if (transform & FB_TRAN_SWAP) + set_pixel (dst, x + j*dy, y + i*dx, dst_color); + else + set_pixel (dst, x + i*dx, y + j*dy, dst_color); } } } diff --git a/video/fb/video_fb.c b/video/fb/video_fb.c index a35dd7a..e8e7c93 100644 --- a/video/fb/video_fb.c +++ b/video/fb/video_fb.c @@ -23,6 +23,7 @@ #include #include #include +#include #include static struct grub_video_fbrender_target *render_target; @@ -117,27 +118,30 @@ grub_video_fb_set_palette (unsigned int start, unsigned int count, } grub_err_t -grub_video_fb_set_viewport (unsigned int x, unsigned int y, - unsigned int width, unsigned int height) +grub_video_fb_set_viewport (int x, int y, int width, int height) { + grub_fb_norm_rect(&x, &y, &width, &height); /* Make sure viewport is withing screen dimensions. If viewport was set to be out of the region, mark its size as zero. */ - if (x > render_target->mode_info.width) + int mode_width = render_target->mode_info.width; + int mode_height = render_target->mode_info.height; + fb_tran_dim_back(&mode_width, &mode_height, render_target->mode_info.transform); + if (x > mode_width) { x = 0; width = 0; } - if (y > render_target->mode_info.height) + if (y > mode_height) { y = 0; height = 0; } - if (x + width > render_target->mode_info.width) + if (x + width > mode_width) width = render_target->mode_info.width - x; - if (y + height > render_target->mode_info.height) + if (y + height > mode_height) height = render_target->mode_info.height - y; render_target->viewport.x = x; @@ -149,8 +153,7 @@ grub_video_fb_set_viewport (unsigned int x, unsigned int y, } grub_err_t -grub_video_fb_get_viewport (unsigned int *x, unsigned int *y, - unsigned int *width, unsigned int *height) +grub_video_fb_get_viewport (int *x, int *y, int *width, int *height) { if (x) *x = render_target->viewport.x; if (y) *y = render_target->viewport.y; @@ -399,14 +402,15 @@ grub_video_fb_unmap_color_int (struct grub_video_fbblit_info * source, grub_err_t grub_video_fb_fill_rect (grub_video_color_t color, int x, int y, - unsigned int width, unsigned int height) + int width, int height) { struct grub_video_fbblit_info target; + grub_fb_norm_rect(&x, &y, &width, &height); /* Make sure there is something to do. */ - if ((x >= (int)render_target->viewport.width) || (x + (int)width < 0)) + if ((x >= render_target->viewport.width) || (x + width < 0)) return GRUB_ERR_NONE; - if ((y >= (int)render_target->viewport.height) || (y + (int)height < 0)) + if ((y >= render_target->viewport.height) || (y + height < 0)) return GRUB_ERR_NONE; /* Do not allow drawing out of viewport. */ @@ -434,6 +438,9 @@ grub_video_fb_fill_rect (grub_video_color_t color, int x, int y, target.mode_info = &render_target->mode_info; target.data = render_target->data; + /* transform coordinates */ + fb_tran_rect(&x, &y, &width, &height, &render_target->mode_info); + /* Try to figure out more optimized version. Note that color is already mapped to target format so we can make assumptions based on that. */ if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888) @@ -481,15 +488,20 @@ grub_video_fb_fill_rect (grub_video_color_t color, int x, int y, /* NOTE: This function assumes that given coordinates are within bounds of handled data. */ +/* TODO: check transform */ static void common_blitter (struct grub_video_fbblit_info *target, struct grub_video_fbblit_info *source, enum grub_video_blit_operators oper, int x, int y, - unsigned int width, unsigned int height, + int width, int height, int offset_x, int offset_y) { + int transform; + fb_tran_blit(&offset_x, &offset_y, &width, &height, &x, &y, &transform, + source->mode_info, target->mode_info); if (oper == GRUB_VIDEO_BLIT_REPLACE) { + if (!transform) { /* Try to figure out more optimized version for replace operator. */ if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888) { @@ -587,13 +599,15 @@ common_blitter (struct grub_video_fbblit_info *target, return; } } + } /* !transform */ /* No optimized replace operator found, use default (slow) blitter. */ grub_video_fbblit_replace (target, source, x, y, width, height, - offset_x, offset_y); + offset_x, offset_y, transform); } else { + if (!transform) { /* Try to figure out more optimized blend operator. */ if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888) { @@ -674,10 +688,11 @@ common_blitter (struct grub_video_fbblit_info *target, return; } } + } /* !transform */ /* No optimized blend operation found, use default (slow) blitter. */ grub_video_fbblit_blend (target, source, x, y, width, height, - offset_x, offset_y); + offset_x, offset_y, transform); } } @@ -685,27 +700,34 @@ grub_err_t grub_video_fb_blit_bitmap (struct grub_video_bitmap *bitmap, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height) + int width, int height) { struct grub_video_fbblit_info source; struct grub_video_fbblit_info target; + int src_x = offset_x; + int src_y = offset_y; + + /* Normalize source rectangle and shift target insert point accordingly. */ + grub_fb_norm_rect(&offset_x, &offset_y, &width, &height); + x += offset_x - src_x; + y += offset_y - src_y; /* Make sure there is something to do. */ if ((width == 0) || (height == 0)) return GRUB_ERR_NONE; - if ((x >= (int)render_target->viewport.width) || (x + (int)width < 0)) + if ((x >= render_target->viewport.width) || (x + width < 0)) return GRUB_ERR_NONE; - if ((y >= (int)render_target->viewport.height) || (y + (int)height < 0)) + if ((y >= render_target->viewport.height) || (y + height < 0)) return GRUB_ERR_NONE; if ((x + (int)bitmap->mode_info.width) < 0) return GRUB_ERR_NONE; if ((y + (int)bitmap->mode_info.height) < 0) return GRUB_ERR_NONE; if ((offset_x >= (int)bitmap->mode_info.width) - || (offset_x + (int)width < 0)) + || (offset_x + width < 0)) return GRUB_ERR_NONE; if ((offset_y >= (int)bitmap->mode_info.height) - || (offset_y + (int)height < 0)) + || (offset_y + height < 0)) return GRUB_ERR_NONE; /* If we have negative coordinates, optimize drawing to minimum. */ @@ -743,16 +765,16 @@ grub_video_fb_blit_bitmap (struct grub_video_bitmap *bitmap, if ((y + height) > render_target->viewport.height) height = render_target->viewport.height - y; - if ((offset_x + width) > bitmap->mode_info.width) + if ((offset_x + width) > (int)bitmap->mode_info.width) width = bitmap->mode_info.width - offset_x; - if ((offset_y + height) > bitmap->mode_info.height) + if ((offset_y + height) > (int)bitmap->mode_info.height) height = bitmap->mode_info.height - offset_y; /* Limit drawing to source render target dimensions. */ - if (width > bitmap->mode_info.width) + if (width > (int)bitmap->mode_info.width) width = bitmap->mode_info.width; - if (height > bitmap->mode_info.height) + if (height > (int)bitmap->mode_info.height) height = bitmap->mode_info.height; /* Add viewport offset. */ @@ -776,27 +798,37 @@ grub_err_t grub_video_fb_blit_render_target (struct grub_video_fbrender_target *source, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height) + int width, int height) { struct grub_video_fbblit_info source_info; struct grub_video_fbblit_info target_info; + int source_width = source->mode_info.width; + int source_height = source->mode_info.height; + int src_x = offset_x; + int src_y = offset_y; + fb_tran_dim_back(&source_width, &source_height, source->mode_info.transform); + + /* Normalize source rectangle and shift target insert point accordingly. */ + grub_fb_norm_rect(&offset_x, &offset_y, &width, &height); + x += offset_x - src_x; + y += offset_y - src_y; /* Make sure there is something to do. */ if ((width == 0) || (height == 0)) return GRUB_ERR_NONE; - if ((x >= (int)render_target->viewport.width) || (x + (int)width < 0)) + if ((x >= render_target->viewport.width) || (x + width < 0)) return GRUB_ERR_NONE; - if ((y >= (int)render_target->viewport.height) || (y + (int)height < 0)) + if ((y >= render_target->viewport.height) || (y + height < 0)) return GRUB_ERR_NONE; - if ((x + (int)source->mode_info.width) < 0) + if ((x + source_width) < 0) return GRUB_ERR_NONE; - if ((y + (int)source->mode_info.height) < 0) + if ((y + source_height) < 0) return GRUB_ERR_NONE; - if ((offset_x >= (int)source->mode_info.width) - || (offset_x + (int)width < 0)) + if ((offset_x >= source_width) + || (offset_x + width < 0)) return GRUB_ERR_NONE; - if ((offset_y >= (int)source->mode_info.height) - || (offset_y + (int)height < 0)) + if ((offset_y >= source_height) + || (offset_y + height < 0)) return GRUB_ERR_NONE; /* If we have negative coordinates, optimize drawing to minimum. */ @@ -834,17 +866,17 @@ grub_video_fb_blit_render_target (struct grub_video_fbrender_target *source, if ((y + height) > render_target->viewport.height) height = render_target->viewport.height - y; - if ((offset_x + width) > source->mode_info.width) - width = source->mode_info.width - offset_x; - if ((offset_y + height) > source->mode_info.height) - height = source->mode_info.height - offset_y; + if ((offset_x + width) > source_width) + width = source_width - offset_x; + if ((offset_y + height) > source_height) + height = source_height - offset_y; /* Limit drawing to source render target dimensions. */ - if (width > source->mode_info.width) - width = source->mode_info.width; + if (width > source_width) + width = source_width; - if (height > source->mode_info.height) - height = source->mode_info.height; + if (height > source_height) + height = source_height; /* Add viewport offset. */ x += render_target->viewport.x; @@ -872,6 +904,7 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) int src_y; int dst_x; int dst_y; + int t_width, t_height; /* 1. Check if we have something to do. */ if ((dx == 0) && (dy == 0)) @@ -902,9 +935,16 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) dst_y = render_target->viewport.y + dy; } + t_width = width; + t_height = height; + fb_tran_rect(&src_x, &src_y, &t_width, &t_height, &render_target->mode_info); + t_width = width; + t_height = height; + fb_tran_rect(&dst_x, &dst_y, &t_width, &t_height, &render_target->mode_info); + /* 2. Check if there is need to copy data. */ - if ((grub_abs (dx) < render_target->viewport.width) - && (grub_abs (dy) < render_target->viewport.height)) + if (((int)grub_abs (dx) < render_target->viewport.width) + && ((int)grub_abs (dy) < render_target->viewport.height)) { /* 3. Move data in render target. */ struct grub_video_fbblit_info target; @@ -916,23 +956,23 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) target.data = render_target->data; /* Check vertical direction of the move. */ - if (dy <= 0) + if (dst_y <= src_y) /* 3a. Move data upwards. */ - for (j = 0; j < height; j++) + for (j = 0; j < t_height; j++) { dst = grub_video_fb_get_video_ptr (&target, dst_x, dst_y + j); src = grub_video_fb_get_video_ptr (&target, src_x, src_y + j); grub_memmove (dst, src, - width * target.mode_info->bytes_per_pixel); + t_width * target.mode_info->bytes_per_pixel); } else /* 3b. Move data downwards. */ - for (j = (height - 1); j >= 0; j--) + for (j = (t_height - 1); j >= 0; j--) { dst = grub_video_fb_get_video_ptr (&target, dst_x, dst_y + j); src = grub_video_fb_get_video_ptr (&target, src_x, src_y + j); grub_memmove (dst, src, - width * target.mode_info->bytes_per_pixel); + t_width * target.mode_info->bytes_per_pixel); } } @@ -945,7 +985,7 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) grub_video_fb_fill_rect (color, 0, 0, render_target->viewport.width, dy); else if (dy < 0) { - if (render_target->viewport.height < grub_abs (dy)) + if (render_target->viewport.height < (int)grub_abs (dy)) dy = -render_target->viewport.height; grub_video_fb_fill_rect (color, 0, render_target->viewport.height + dy, @@ -958,7 +998,7 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) dx, render_target->viewport.height); else if (dx < 0) { - if (render_target->viewport.width < grub_abs (dx)) + if (render_target->viewport.width < (int)grub_abs (dx)) dx = -render_target->viewport.width; grub_video_fb_fill_rect (color, render_target->viewport.width + dx, 0, @@ -976,6 +1016,7 @@ grub_video_fb_create_render_target (struct grub_video_fbrender_target **result, { struct grub_video_fbrender_target *target; unsigned int size; + int transform = render_target->mode_info.transform; /* Validate arguments. */ if ((! result) @@ -1001,7 +1042,12 @@ grub_video_fb_create_render_target (struct grub_video_fbrender_target **result, target->viewport.width = width; target->viewport.height = height; + /* Set up the target so that it has the same direction as the current target */ + /* TODO: Implement other directions, too */ + fb_tran_dim(&width, &height, transform); + /* Setup render target format. */ + target->mode_info.transform = transform; target->mode_info.width = width; target->mode_info.height = height; target->mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB @@ -1066,10 +1112,11 @@ grub_video_fb_create_render_target_from_pointer (struct grub_video_fbrender_targ target->viewport.y = 0; target->viewport.width = mode_info->width; target->viewport.height = mode_info->height; + fb_tran_dim_back(&(target->viewport.width), &(target->viewport.height), mode_info->transform); /* Clear render target with black and maximum transparency. */ for (y = 0; y < mode_info->height; y++) - grub_memset (target->data + mode_info->pitch * y, 0, + grub_memset ((char *)target->data + mode_info->pitch * y, 0, mode_info->bytes_per_pixel * mode_info->width); /* Save result to caller. */ diff --git a/video/i386/pc/vbe.c b/video/i386/pc/vbe.c index 3efcd56..b36d034 100644 --- a/video/i386/pc/vbe.c +++ b/video/i386/pc/vbe.c @@ -381,7 +381,7 @@ grub_video_vbe_fini (void) static grub_err_t grub_video_vbe_setup (unsigned int width, unsigned int height, - unsigned int mode_type) + unsigned int mode_type, int transform) { grub_uint16_t *p; struct grub_vbe_mode_info_block vbe_mode_info; @@ -499,6 +499,8 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, framebuffer.mode_info.blit_format = grub_video_get_blit_format (&framebuffer.mode_info); + framebuffer.mode_info.transform = transform; + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr); if (err) diff --git a/video/video.c b/video/video.c index 36ebfd1..14672b1 100644 --- a/video/video.c +++ b/video/video.c @@ -21,6 +21,7 @@ #include #include #include +#include /* The list of video adapters registered to system. */ static grub_video_adapter_t grub_video_adapter_list; @@ -225,8 +226,7 @@ grub_video_get_palette (unsigned int start, unsigned int count, /* Set viewport dimensions. */ grub_err_t -grub_video_set_viewport (unsigned int x, unsigned int y, - unsigned int width, unsigned int height) +grub_video_set_viewport (int x, int y, int width, int height) { if (! grub_video_adapter_active) return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); @@ -236,8 +236,7 @@ grub_video_set_viewport (unsigned int x, unsigned int y, /* Get viewport dimensions. */ grub_err_t -grub_video_get_viewport (unsigned int *x, unsigned int *y, - unsigned int *width, unsigned int *height) +grub_video_get_viewport (int *x, int *y, int *width, int *height) { if (! grub_video_adapter_active) return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); @@ -295,7 +294,7 @@ grub_video_unmap_color (grub_video_color_t color, grub_uint8_t *red, /* Fill rectangle using specified color. */ grub_err_t grub_video_fill_rect (grub_video_color_t color, int x, int y, - unsigned int width, unsigned int height) + int width, int height) { if (! grub_video_adapter_active) return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); @@ -308,7 +307,7 @@ grub_err_t grub_video_blit_bitmap (struct grub_video_bitmap *bitmap, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height) + int width, int height) { if (! grub_video_adapter_active) return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); @@ -323,7 +322,7 @@ grub_err_t grub_video_blit_render_target (struct grub_video_render_target *target, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height) + int width, int height) { if (! grub_video_adapter_active) return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); @@ -412,6 +411,10 @@ grub_video_set_mode (const char *modestring, int height = -1; int depth = -1; int flags = 0; + int transform = 0; + int flip = 0; + int mirror = 0; + int swap = 0; /* Take copy of env.var. as we don't want to modify that. */ modevar = grub_strdup (modestring); @@ -509,6 +512,10 @@ grub_video_set_mode (const char *modestring, current_mode = tmp; param = tmp; value = NULL; + transform = 0; + mirror = 0; + flip = 0; + swap = 0; /* XXX: we assume that we're in pure text mode if no video mode is initialized. Is it always true? */ @@ -532,7 +539,36 @@ grub_video_set_mode (const char *modestring, } } - /* Parse x[x]*/ + /* TODO: document direction */ + /* Parse [Dir]x[x]*/ + for (;;param++) + switch (*param) { + case 'N': + case 'n': transform = 0; + break; + case 'E': + case 'e': transform = FB_TRAN_EAST; + break; + case 'S': + case 's': transform = FB_TRAN_SOUTH; + break; + case 'W': + case 'w': transform = FB_TRAN_WEST; + break; + case 'M': + case 'm': mirror = 1; break; + case 'F': + case 'f': flip = 1; break; + case 'X': + case 'x': swap = 1; break; + default: goto end_direction_parse_loop; + } +end_direction_parse_loop: + + if (mirror) transform ^= FB_TRAN_MIRROR; + if (flip) transform ^= FB_TRAN_FLIP; + if (swap) transform ^= FB_TRAN_SWAP; + /* Find width value. */ value = param; @@ -668,7 +704,7 @@ grub_video_set_mode (const char *modestring, } /* Try to initialize video mode. */ - err = p->setup (width, height, flags); + err = p->setup (width, height, flags, transform); if (err != GRUB_ERR_NONE) { p->fini ();