Add optional framebuffer rotation, which allows the user to specify the
display output rotation
MODIFIED:
fbutil.h include/grub - Add function declarations. see below.
video.h include/grub
struct grub_video_mode_info - Add int original_width, int original_height,
enum grub_video_rotation rotation.
fbblit.c grub-core/video/fb
Modify grub_video_fb_dispatch_blit() to rotate blit coordinates.
TODO: currently only the generic(slow) blitting operation is used when
rotation is specified. This should be implementd for every blitting mode and
operation.
fbfill.c grub-core/video/fb
Modify grub_video_fb_fill_dispatch() to rotate fill coordinates.
fbutil.c grub-core/video/fb
Add functions trans_x and trans_y to translate coordinates depending on
mode_info.rotation
Add function grub_video_transform_rectangle to transform video_rect
depending on mode_info
video_fb.c grub-core/video/fb
Modify functions:
dirty() to rotate dirty video_rect
grub_video_fb_scroll() to rotate scroll
grub_video_fb_create_render_target - use no rotation via mode_info by
default. Render
target's(such as text_layers) get rotated on the final blit to the actual
framebuffer, thus we want a mode_info with NO rotation set to prevent
"double rotation's".
grub_video_fb_create_render_target_from_pointer - Check for rotation
grub_env_var and set mode_info rotation, viewport, area, width, and height for
render_target depending on the rotation specified.
Other functions - update to use original_width or original_height where
appropriate.
Signed-off-by: kbader94 <[email protected]>
---
grub-core/video/fb/fbblit.c | 71 ++++++++++++++++++++--
grub-core/video/fb/fbfill.c | 28 ++++++---
grub-core/video/fb/fbutil.c | 61 +++++++++++++++++++
grub-core/video/fb/video_fb.c | 107 +++++++++++++++++++++++-----------
include/grub/fbutil.h | 9 +++
include/grub/video.h | 20 ++++++-
6 files changed, 247 insertions(+), 49 deletions(-)
diff --git a/grub-core/video/fb/fbblit.c b/grub-core/video/fb/fbblit.c
index 1010ef393..5dda0ffdb 100644
--- a/grub-core/video/fb/fbblit.c
+++ b/grub-core/video/fb/fbblit.c
@@ -62,7 +62,8 @@ 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);
+ set_pixel (dst, x + trans_x(i, j, dst->mode_info),
+ y + trans_y(i,j, dst->mode_info), dst_color);
}
}
}
@@ -1195,11 +1196,11 @@ grub_video_fbblit_blend (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);
+ set_pixel (dst, x + trans_x(i, j, dst->mode_info), y +
trans_y(i,j, dst->mode_info), dst_color);
continue;
}
- dst_color = get_pixel (dst, x + i, y + j);
+ dst_color = get_pixel (dst, x + trans_x(i, j, dst->mode_info), y +
trans_y(i,j, dst->mode_info));
grub_video_fb_unmap_color_int (dst, dst_color, &dst_red,
&dst_green, &dst_blue, &dst_alpha);
@@ -1212,7 +1213,7 @@ 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);
+ set_pixel (dst, x + trans_x(i, j, dst->mode_info), y + trans_y(i,j,
dst->mode_info), dst_color);
}
}
}
@@ -1936,6 +1937,68 @@ grub_video_fb_dispatch_blit (struct
grub_video_fbblit_info *target,
unsigned int width, unsigned int height,
int offset_x, int offset_y)
{
+ if (target->mode_info->rotation == GRUB_VIDEO_ROTATE_90)
+ {
+ int nx = y;
+ int ny = target->mode_info->width - x - 1;
+ if (oper == GRUB_VIDEO_BLIT_REPLACE)
+ {
+ /* No optimized replace operator found, use default (slow) blitter.
*/
+ grub_video_fbblit_replace (target, source, nx, ny, width, height,
+ offset_x, offset_y);
+ return;
+ }
+ else
+ {
+ /* No optimized replace operator found, use default (slow) blitter.
*/
+ grub_video_fbblit_blend (target, source, nx, ny, width, height,
+ offset_x, offset_y);
+ return;
+ }
+ }
+
+ if (target->mode_info->rotation == GRUB_VIDEO_ROTATE_180)
+ {
+ int nx = target->mode_info->width - x - 1;
+ int ny = target->mode_info->height - y - 1;
+ if (oper == GRUB_VIDEO_BLIT_REPLACE)
+ {
+ /* No optimized replace operator found, use default (slow) blitter.
*/
+ grub_video_fbblit_replace (target, source, nx, ny, width, height,
+ offset_x, offset_y);
+ return;
+ }
+ else
+ {
+ /* No optimized replace operator found, use default (slow) blitter.
*/
+ grub_video_fbblit_blend (target, source, nx, ny, width, height,
+ offset_x, offset_y);
+ return;
+ }
+
+
+ }
+
+ if (target->mode_info->rotation == GRUB_VIDEO_ROTATE_270)
+ {
+ int nx = target->mode_info->height - y - 1;
+ int ny = x;
+ if (oper == GRUB_VIDEO_BLIT_REPLACE)
+ {
+ /* No optimized replace operator found, use default (slow) blitter.
*/
+ grub_video_fbblit_replace (target, source, nx, ny, width, height,
+ offset_x, offset_y);
+ return;
+ }
+ else
+ {
+ /* No optimized replace operator found, use default (slow) blitter.
*/
+ grub_video_fbblit_blend (target, source, nx, ny, width, height,
+ offset_x, offset_y);
+ return;
+ }
+ }
+
if (oper == GRUB_VIDEO_BLIT_REPLACE)
{
/* Try to figure out more optimized version for replace operator. */
diff --git a/grub-core/video/fb/fbfill.c b/grub-core/video/fb/fbfill.c
index 49fa16b92..cab4d8acc 100644
--- a/grub-core/video/fb/fbfill.c
+++ b/grub-core/video/fb/fbfill.c
@@ -185,28 +185,38 @@ grub_video_fb_fill_dispatch (struct
grub_video_fbblit_info *target,
grub_video_color_t color, int x, int y,
unsigned int width, unsigned int height)
{
+ grub_video_rect_t orig = {
+ .x = x,
+ .y = y,
+ .width = width,
+ .height = height
+ };
+ grub_video_rect_t tran = grub_video_transform_rectangle (orig,
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. */
switch (target->mode_info->bytes_per_pixel)
{
case 4:
- grub_video_fbfill_direct32 (target, color, x, y,
- width, height);
+ grub_video_fbfill_direct32 (target, color, tran.x, tran.y,
+ tran.width, tran.height);
return;
case 3:
- grub_video_fbfill_direct24 (target, color, x, y,
- width, height);
+ grub_video_fbfill_direct24 (target, color, tran.x, tran.y,
+ tran.width, tran.height);
+ return;
return;
case 2:
- grub_video_fbfill_direct16 (target, color, x, y,
- width, height);
+ grub_video_fbfill_direct16 (target, color, tran.x, tran.y,
+ tran.width, tran.height);
return;
case 1:
- grub_video_fbfill_direct8 (target, color, x, y,
- width, height);
+ grub_video_fbfill_direct8 (target, color, tran.x, tran.y,
+ tran.width, tran.height);
return;
}
/* No optimized version found, use default (slow) filler. */
- grub_video_fbfill (target, color, x, y, width, height);
+ grub_video_fbfill (target, color, tran.x, tran.y,
+ tran.width, tran.height);
}
diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c
index 25ef39f47..368356fd7 100644
--- a/grub-core/video/fb/fbutil.c
+++ b/grub-core/video/fb/fbutil.c
@@ -149,3 +149,64 @@ set_pixel (struct grub_video_fbblit_info *source,
break;
}
}
+
+int
+trans_x(int x,int y, struct grub_video_mode_info *mode_info)
+{
+ switch (mode_info->rotation) {
+ case GRUB_VIDEO_ROTATE_90:
+ return y;
+ case GRUB_VIDEO_ROTATE_180:
+ return -x;
+ case GRUB_VIDEO_ROTATE_270:
+ return -y;
+ case GRUB_VIDEO_ROTATE_NONE:
+ default:
+ return x;
+ }
+}
+
+int
+trans_y(int x, int y, struct grub_video_mode_info *mode_info)
+{
+ switch (mode_info->rotation) {
+ case GRUB_VIDEO_ROTATE_90:
+ return -x;
+ case GRUB_VIDEO_ROTATE_180:
+ return -y;
+ case GRUB_VIDEO_ROTATE_270:
+ return x;
+ case GRUB_VIDEO_ROTATE_NONE:
+ default:
+ return y;
+ }
+}
+
+grub_video_rect_t grub_video_transform_rectangle (grub_video_rect_t r, const
struct grub_video_mode_info *mode_info)
+{
+ grub_video_rect_t n;
+ switch (mode_info->rotation)
+ {
+ case GRUB_VIDEO_ROTATE_NONE:
+ return r;
+ case GRUB_VIDEO_ROTATE_90:
+ n.width = r.height;
+ n.height = r.width;
+ n.x = r.y;
+ n.y = mode_info->width - r.x - r.width;
+ return n;
+ case GRUB_VIDEO_ROTATE_180:
+ n.width = r.width;
+ n.height = r.height;
+ n.x = mode_info->width - r.x - r.width;
+ n.y = mode_info->height - r.y - r.height;
+ return n;
+ case GRUB_VIDEO_ROTATE_270:
+ n.width = r.height;
+ n.height = r.width;
+ n.x = mode_info->height - r.y - r.height;
+ n.y = r.x;
+ return n;
+ }
+ return r;
+}
\ No newline at end of file
diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c
index d17c47b11..377a9179d 100644
--- a/grub-core/video/fb/video_fb.c
+++ b/grub-core/video/fb/video_fb.c
@@ -26,6 +26,7 @@
#include <grub/bitmap.h>
#include <grub/dl.h>
#include <grub/safemath.h>
+#include <grub/env.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -826,15 +827,17 @@ grub_video_fb_unmap_color_int (struct
grub_video_fbblit_info * source,
static void
dirty (int x, int y, int width, int height)
{
-
+
grub_video_rect_t *current_dirty = &framebuffer.current_dirty;
- grub_video_rect_t dirty_rect = {
+ grub_video_rect_t additive_rect = {
.x = x,
.y = y,
.width = width,
.height = height
};
+ grub_video_rect_t dirty_rect = grub_video_transform_rectangle
(additive_rect, &framebuffer.render_target->mode_info);
+
if (framebuffer.render_target != framebuffer.back_target)
return;
@@ -1063,6 +1066,8 @@ grub_video_fb_scroll (grub_video_color_t color, int dx,
int dy)
{
int width;
int height;
+ int tx; /* transformed scroll coords */
+ int ty; /* transformed scroll coords */
int src_x;
int src_y;
int dst_x;
@@ -1072,39 +1077,41 @@ grub_video_fb_scroll (grub_video_color_t color, int dx,
int dy)
if ((dx == 0) && (dy == 0))
return GRUB_ERR_NONE;
- width = framebuffer.render_target->viewport.width - grub_abs (dx);
- height = framebuffer.render_target->viewport.height - grub_abs (dy);
+ tx = trans_x(dx,dy, &framebuffer.render_target->mode_info);
+ ty = trans_y(dx,dy, &framebuffer.render_target->mode_info);
+ width = framebuffer.render_target->mode_info.original_width - grub_abs (tx);
+ height = framebuffer.render_target->mode_info.original_height - grub_abs
(ty);
dirty (framebuffer.render_target->viewport.x,
framebuffer.render_target->viewport.y,
- framebuffer.render_target->viewport.width,
+ framebuffer.render_target->viewport.width,
framebuffer.render_target->viewport.height);
- if (dx < 0)
+ if (tx < 0)
{
- src_x = framebuffer.render_target->viewport.x - dx;
+ src_x = framebuffer.render_target->viewport.x - tx;
dst_x = framebuffer.render_target->viewport.x;
}
else
{
src_x = framebuffer.render_target->viewport.x;
- dst_x = framebuffer.render_target->viewport.x + dx;
+ dst_x = framebuffer.render_target->viewport.x + tx;
}
- if (dy < 0)
+ if (ty < 0)
{
- src_y = framebuffer.render_target->viewport.y - dy;
+ src_y = framebuffer.render_target->viewport.y - ty;
dst_y = framebuffer.render_target->viewport.y;
}
else
{
src_y = framebuffer.render_target->viewport.y;
- dst_y = framebuffer.render_target->viewport.y + dy;
+ dst_y = framebuffer.render_target->viewport.y + ty;
}
/* 2. Check if there is need to copy data. */
- if ((grub_abs (dx) < framebuffer.render_target->viewport.width)
- && (grub_abs (dy) < framebuffer.render_target->viewport.height))
+ if ((grub_abs (tx) < framebuffer.render_target->viewport.width)
+ && (grub_abs (ty) < framebuffer.render_target->viewport.height))
{
/* 3. Move data in render target. */
struct grub_video_fbblit_info target;
@@ -1119,7 +1126,7 @@ grub_video_fb_scroll (grub_video_color_t color, int dx,
int dy)
linelen = width * target.mode_info->bytes_per_pixel;
#define DO_SCROLL \
/* Check vertical direction of the move. */ \
- if (dy < 0 || (dy == 0 && dx < 0)) \
+ if (ty < 0 || (ty == 0 && tx < 0)) \
{ \
dst = (void *) grub_video_fb_get_video_ptr (&target, \
dst_x, dst_y); \
@@ -1245,6 +1252,9 @@ grub_video_fb_create_render_target (struct
grub_video_fbrender_target **result,
/* TODO: Implement other types too.
Currently only 32bit render targets are supported. */
+/* only used by text_layers, so do not rotate */
+ target->mode_info.rotation = GRUB_VIDEO_ROTATE_NONE;
+
/* Mark render target as allocated. */
target->is_allocated = 1;
@@ -1270,6 +1280,8 @@ grub_video_fb_create_render_target (struct
grub_video_fbrender_target **result,
/* Setup render target format. */
target->mode_info.width = width;
target->mode_info.height = height;
+ target->mode_info.original_width = width;
+ target->mode_info.original_height = height;
switch (mode_type)
{
case GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
@@ -1332,6 +1344,7 @@ grub_video_fb_create_render_target_from_pointer (struct
grub_video_fbrender_targ
{
struct grub_video_fbrender_target *target;
unsigned y;
+ const char *rot_env;
#ifndef GRUB_HAVE_UNALIGNED_ACCESS
if (!(mode_info->bytes_per_pixel & (mode_info->bytes_per_pixel - 1))
@@ -1352,30 +1365,53 @@ grub_video_fb_create_render_target_from_pointer (struct
grub_video_fbrender_targ
target->data = ptr;
grub_memcpy (&(target->mode_info), mode_info, sizeof (target->mode_info));
+ rot_env = grub_env_get("rotation");
+
+ if (!rot_env) {
+ target->mode_info.rotation = GRUB_VIDEO_ROTATE_NONE;
+ } else if (grub_strcmp(rot_env, "90") == 0) {
+ target->mode_info.rotation = GRUB_VIDEO_ROTATE_90;
+ } else if (grub_strcmp(rot_env, "180") == 0) {
+ target->mode_info.rotation = GRUB_VIDEO_ROTATE_180;
+ } else if (grub_strcmp(rot_env, "270") == 0) {
+ target->mode_info.rotation = GRUB_VIDEO_ROTATE_270;
+ } else {
+ target->mode_info.rotation = GRUB_VIDEO_ROTATE_NONE;
+ }
+
+ target->mode_info.original_width = mode_info->width;
+ target->mode_info.original_height = mode_info->height;
+
+ if (target->mode_info.rotation == GRUB_VIDEO_ROTATE_90
+ || target->mode_info.rotation == GRUB_VIDEO_ROTATE_270)
+ {
+ target->mode_info.width = target->mode_info.original_height;
+ target->mode_info.height = target->mode_info.original_width;
+ }
/* Reset viewport, region and area to match new mode. */
target->viewport.x = 0;
target->viewport.y = 0;
- target->viewport.width = mode_info->width;
- target->viewport.height = mode_info->height;
+ target->viewport.width = target->mode_info.width;
+ target->viewport.height = target->mode_info.height;
target->region.x = 0;
target->region.y = 0;
- target->region.width = mode_info->width;
- target->region.height = mode_info->height;
+ target->region.width = target->mode_info.width;
+ target->region.height = target->mode_info.height;
target->area_enabled = 0;
target->area.x = 0;
target->area.y = 0;
- target->area.width = mode_info->width;
- target->area.height = mode_info->height;
+ target->area.width = target->mode_info.width;
+ target->area.height = target->mode_info.height;
target->area_offset_x = 0;
target->area_offset_y = 0;
/* Clear render target with black and maximum transparency. */
- for (y = 0; y < mode_info->height; y++)
+ for (y = 0; y < target->mode_info.original_height; y++)
grub_memset (target->data + mode_info->pitch * y, 0,
- mode_info->bytes_per_pixel * mode_info->width);
+ mode_info->bytes_per_pixel * target->mode_info.original_width);
/* Save result to caller. */
*result = target;
@@ -1455,9 +1491,9 @@ doublebuf_blit_update_screen (void)
}
/* reset current_dirty rect */
- framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.y =
framebuffer.back_target->mode_info.original_height;
framebuffer.current_dirty.height = 0;
- framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.x =
framebuffer.back_target->mode_info.original_width;
framebuffer.current_dirty.width = 0;
return GRUB_ERR_NONE;
@@ -1491,9 +1527,9 @@ grub_video_fb_doublebuf_blit_init (struct
grub_video_fbrender_target **back,
framebuffer.pages[0] = framebuf;
framebuffer.displayed_page = 0;
framebuffer.render_page = 0;
- framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.y =
framebuffer.back_target->mode_info.original_height;
framebuffer.current_dirty.height = 0;
- framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.x =
framebuffer.back_target->mode_info.original_width;
framebuffer.current_dirty.width = 0;
return GRUB_ERR_NONE;
@@ -1546,9 +1582,9 @@ doublebuf_pageflipping_update_screen (void)
/* reset current_dirty rect */
framebuffer.previous_dirty = framebuffer.current_dirty;
- framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.y =
framebuffer.back_target->mode_info.original_height;
framebuffer.current_dirty.height = 0;
- framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.x =
framebuffer.back_target->mode_info.original_width;
framebuffer.current_dirty.width = 0;
/* Swap the page numbers in the framebuffer struct. */
@@ -1609,15 +1645,15 @@ doublebuf_pageflipping_init (struct
grub_video_mode_info *mode_info,
framebuffer.pages[1] = page1_ptr;
/* reset current_dirty rect */
- framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.y =
framebuffer.back_target->mode_info.original_height;
framebuffer.current_dirty.height = 0;
- framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.x =
framebuffer.back_target->mode_info.original_width;
framebuffer.current_dirty.width = 0;
/* reset previous_dirty rect */
- framebuffer.previous_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.previous_dirty.y =
framebuffer.back_target->mode_info.original_height;
framebuffer.previous_dirty.height = 0;
- framebuffer.previous_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.previous_dirty.x =
framebuffer.back_target->mode_info.original_width;
framebuffer.previous_dirty.width = 0;
/* Set the framebuffer memory data pointer and display the right page. */
@@ -1705,9 +1741,9 @@ grub_video_fb_setup (unsigned int mode_type, unsigned int
mode_mask,
framebuffer.render_page = 0;
framebuffer.set_page = 0;
/* reset transformed_add_rect */
- framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.y =
framebuffer.back_target->mode_info.original_height;
framebuffer.current_dirty.height = 0;
- framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.x =
framebuffer.back_target->mode_info.original_width;
framebuffer.current_dirty.width = 0;
mode_info->mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
@@ -1739,6 +1775,9 @@ grub_video_fb_get_info_and_fini (struct
grub_video_mode_info *mode_info,
grub_memcpy (mode_info, &(framebuffer.back_target->mode_info),
sizeof (*mode_info));
+ mode_info->width = framebuffer.back_target->mode_info.original_width;
+ mode_info->height = framebuffer.back_target->mode_info.original_height;
+
/* We are about to load a kernel. Switch back to page zero, since some
kernel drivers expect that. */
if (framebuffer.set_page && framebuffer.displayed_page != 0)
diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h
index 78a1ab3b4..ad625bff9 100644
--- a/include/grub/fbutil.h
+++ b/include/grub/fbutil.h
@@ -61,4 +61,13 @@ grub_video_color_t get_pixel (struct grub_video_fbblit_info
*source,
void set_pixel (struct grub_video_fbblit_info *source,
unsigned int x, unsigned int y, grub_video_color_t color);
+int
+trans_x(int x,int y, struct grub_video_mode_info *mode_info);
+
+int
+trans_y(int x, int y, struct grub_video_mode_info *mode_info);
+
+grub_video_rect_t grub_video_transform_rectangle (grub_video_rect_t r,
+ const struct
grub_video_mode_info *mode_info);
+
#endif /* ! GRUB_VBEUTIL_MACHINE_HEADER */
diff --git a/include/grub/video.h b/include/grub/video.h
index 9dac0f379..f05e70b26 100644
--- a/include/grub/video.h
+++ b/include/grub/video.h
@@ -75,6 +75,14 @@ typedef enum grub_video_mode_type
GRUB_VIDEO_MODE_TYPE_INFO_MASK = 0x00FF0000,
} grub_video_mode_type_t;
+enum grub_video_rotation
+ {
+ GRUB_VIDEO_ROTATE_NONE,
+ GRUB_VIDEO_ROTATE_90,
+ GRUB_VIDEO_ROTATE_180,
+ GRUB_VIDEO_ROTATE_270
+ };
+
/* The basic render target representing the whole display. This always
renders to the back buffer when double-buffering is in use. */
#define GRUB_VIDEO_RENDER_TARGET_DISPLAY \
@@ -122,12 +130,20 @@ enum grub_video_blit_operators
struct grub_video_mode_info
{
- /* Width of the screen. */
+ /* Width of the screen, before the rotation. */
+ unsigned int original_width;
+
+ /* Height of the screen, before the rotation. */
+ unsigned int original_height;
+
+ /* Width of the screen, after the rotation. */
unsigned int width;
- /* Height of the screen. */
+ /* Height of the screen, after the rotation. */
unsigned int height;
+ enum grub_video_rotation rotation;
+
/* Mode type bitmask. Contains information like is it Index color or
RGB mode. */
grub_video_mode_type_t mode_type;
--
2.34.1
_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel