All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] Framebuffer rotation patch
@ 2009-08-28  8:03 Michal Suchanek
  2009-08-29 10:24 ` Michal Suchanek
  2010-02-11  2:46 ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 2 replies; 24+ messages in thread
From: Michal Suchanek @ 2009-08-28  8:03 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 569 bytes --]

Hello

Sending a preliminary framebuffer rotation patch.

You can use videotest to see 4 tiles rotated from the same bitmap data.

Known issues:

- font glyphs and terminal do not rotate properly
- no accelerated blitters for rotated modes, at least the 1bit blitter
should work

To be done

- split out signed rectangle patch that changes graphics coordinates
from unsigned to signed
- make up some naming scheme and rename functions and macros accordingly
- make up some acceptable way to specify framebnuffer rotation in the
environment like gfxmode

Thanks

Michal

[-- Attachment #2: grub-fbtran.patch --]
[-- Type: text/x-diff, Size: 46950 bytes --]

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 <grub/font.h>
 #include <grub/term.h>
 #include <grub/command.h>
+#include <grub/fbtran.h>
+#include <grub/fbfill.h> /*for some reason render target type is defined there */
+#include <grub/bitmap.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef GRUB_FBTRAN_HEADER
+#define GRUB_FBTRAN_HEADER	1
+
+#include <grub/video.h>
+#include <grub/video_fb.h>
+#include <grub/util/misc.h>
+
+/* 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/term.h> /* 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 <grub/misc.h>
 #include <grub/types.h>
 #include <grub/video.h>
+#include <grub/fbtran.h>
 
 /* 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 <grub/fbblit.h>
 #include <grub/fbfill.h>
 #include <grub/fbutil.h>
+#include <grub/fbtran.h>
 #include <grub/bitmap.h>
 
 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 <grub/dl.h>
 #include <grub/misc.h>
 #include <grub/mm.h>
+#include <grub/fbtran.h>
 
 /* 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 <width>x<height>[x<depth>]*/
+      /* TODO: document direction */
+      /* Parse [Dir]<width>x<height>[x<depth>]*/
+      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 ();

^ permalink raw reply related	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2010-02-16 23:20 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-28  8:03 [RFC] Framebuffer rotation patch Michal Suchanek
2009-08-29 10:24 ` Michal Suchanek
2010-02-11  2:46 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-11 10:19   ` Michal Suchanek
2010-02-11 10:52     ` Michal Suchanek
2010-02-11 16:11       ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-11 16:08     ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-13 17:29       ` Michal Suchanek
2010-02-15 17:05         ` [RFC] Framebuffer rotation patch, or why 'unsigned' fails us Colin D Bennett
2010-02-15 18:14           ` Michal Suchanek
2010-02-15 18:35             ` Colin D Bennett
2010-02-16 12:35             ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-16 20:53               ` Michal Suchanek
2010-02-16 12:32         ` [RFC] Framebuffer rotation patch Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-16 15:52           ` Michal Suchanek
2010-02-16 18:03             ` Isaac Dupree
2010-02-16 18:15               ` richardvoigt
2010-02-16 18:47                 ` [Off-topic] C++ enums Isaac Dupree
2010-02-16 16:08   ` [RFC] Framebuffer rotation patch Michal Suchanek
2010-02-16 16:21     ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-16 21:05       ` Michal Suchanek
2010-02-16 21:14         ` richardvoigt
2010-02-16 23:19           ` Michal Suchanek
2010-02-16 21:53         ` Michal Suchanek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.