[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v1 1/3] dirty 2d
From: |
kbader94 |
Subject: |
[PATCH v1 1/3] dirty 2d |
Date: |
Mon, 17 Jun 2024 22:14:43 -0600 |
Modify the dirty function so it tracks and updates 2d regions. The current
dirty() implementation only tracks the y coordinate changes, and then updates
all the pixels in between the changed(dirty) y coordinates, such that the
entire screen's width is updated even if just a single 16x16 pixel character
was updated(dirtied). This patch modifies render_targets to use
grub_video_rects to track dirty regions instead of the previous dirty struct.
dirty callees are then modified appropriately using 2d coordinates. Finally the
doublebuf_*_update_screen functions are modified to update 2d regions by making
multiple grub_memcpy calls to the framebuffer, one for each row of pixels being
updated(instead of a single call for the contiguous block of framebuffer data
as was previously done).
Changes to be committed:
modified: grub-core/video/fb/video_fb.c
Signed-off-by: kbader94 <kyle.bader94@gmail.com>
---
grub-core/video/fb/video_fb.c | 199 +++++++++++++++++++++-------------
1 file changed, 122 insertions(+), 77 deletions(-)
diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c
index fa4ebde26..d17c47b11 100644
--- a/grub-core/video/fb/video_fb.c
+++ b/grub-core/video/fb/video_fb.c
@@ -31,13 +31,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
typedef grub_err_t (*grub_video_fb_doublebuf_update_screen_t) (void);
typedef volatile void *framebuf_t;
-
-struct dirty
-{
- int first_line;
- int last_line;
-};
-
static struct
{
struct grub_video_fbrender_target *render_target;
@@ -47,8 +40,8 @@ static struct
unsigned int palette_size;
- struct dirty current_dirty;
- struct dirty previous_dirty;
+ struct grub_video_rect current_dirty;
+ struct grub_video_rect previous_dirty;
/* For page flipping strategy. */
int displayed_page; /* The page # that is the front buffer. */
@@ -831,14 +824,36 @@ grub_video_fb_unmap_color_int (struct
grub_video_fbblit_info * source,
}
static void
-dirty (int y, int height)
+dirty (int x, int y, int width, int height)
{
+
+ grub_video_rect_t *current_dirty = &framebuffer.current_dirty;
+ grub_video_rect_t dirty_rect = {
+ .x = x,
+ .y = y,
+ .width = width,
+ .height = height
+ };
+
if (framebuffer.render_target != framebuffer.back_target)
return;
- if (framebuffer.current_dirty.first_line > y)
- framebuffer.current_dirty.first_line = y;
- if (framebuffer.current_dirty.last_line < y + height)
- framebuffer.current_dirty.last_line = y + height;
+
+ /* extend dirty_rect bounds if dirty x min is less than current x */
+ if (dirty_rect.x < current_dirty->x)
+ current_dirty->x = dirty_rect.x;
+
+ /* extend dirty_rect bounds if dirty x max is greater than current width */
+ if (dirty_rect.x + dirty_rect.width > current_dirty->x +
current_dirty->width)
+ current_dirty->width = (dirty_rect.x + dirty_rect.width) -
current_dirty->x;
+
+ /* extend dirty_rect bounds if dirty y min is less than current y */
+ if (dirty_rect.y < current_dirty->y)
+ current_dirty->y = dirty_rect.y;
+
+ /* extend dirty_rect bounds if dirty y max is greater than current height */
+ if (dirty_rect.y + dirty_rect.height > current_dirty->y +
current_dirty->height)
+ current_dirty->height = (dirty_rect.y + dirty_rect.height) -
current_dirty->y;
+
}
grub_err_t
@@ -896,7 +911,7 @@ grub_video_fb_fill_rect (grub_video_color_t color, int x,
int y,
x += area_x;
y += area_y;
- dirty (y, height);
+ dirty (x, y, width, height);
/* Use fbblit_info to encapsulate rendering. */
target.mode_info = &framebuffer.render_target->mode_info;
@@ -1008,8 +1023,7 @@ grub_video_fb_blit_source (struct grub_video_fbblit_info
*source,
target.mode_info = &framebuffer.render_target->mode_info;
target.data = framebuffer.render_target->data;
- /* Do actual blitting. */
- dirty (y, height);
+ dirty (x, y, width, height);
grub_video_fb_dispatch_blit (&target, source, oper, x, y, width, height,
offset_x, offset_y);
@@ -1061,7 +1075,9 @@ grub_video_fb_scroll (grub_video_color_t color, int dx,
int dy)
width = framebuffer.render_target->viewport.width - grub_abs (dx);
height = framebuffer.render_target->viewport.height - grub_abs (dy);
- dirty (framebuffer.render_target->viewport.y,
+ dirty (framebuffer.render_target->viewport.x,
+ framebuffer.render_target->viewport.y,
+ framebuffer.render_target->viewport.width,
framebuffer.render_target->viewport.height);
if (dx < 0)
@@ -1416,28 +1432,33 @@ grub_video_fb_get_active_render_target (struct
grub_video_fbrender_target **targ
static grub_err_t
doublebuf_blit_update_screen (void)
{
- if (framebuffer.current_dirty.first_line
- <= framebuffer.current_dirty.last_line)
- {
- grub_size_t copy_size;
-
- if (grub_sub (framebuffer.current_dirty.last_line,
- framebuffer.current_dirty.first_line, ©_size) ||
- grub_mul (framebuffer.back_target->mode_info.pitch, copy_size,
©_size))
- {
- /* Shouldn't happen, but if it does we've a bug. */
- return GRUB_ERR_BUG;
- }
-
- grub_memcpy ((char *) framebuffer.pages[0] +
framebuffer.current_dirty.first_line *
- framebuffer.back_target->mode_info.pitch,
- (char *) framebuffer.back_target->data +
framebuffer.current_dirty.first_line *
- framebuffer.back_target->mode_info.pitch,
- copy_size);
+ if (framebuffer.current_dirty.height > 0 || framebuffer.current_dirty.width
> 0) {
+ /* dirty row size in bytes */
+ grub_size_t row_size = framebuffer.current_dirty.width
+ *
framebuffer.back_target->mode_info.bytes_per_pixel;
+
+ /* address of dirty_rect origin on render target */
+ char *src_base = (char *)framebuffer.back_target->data +
framebuffer.current_dirty.y
+ * framebuffer.back_target->mode_info.pitch +
framebuffer.current_dirty.x
+ * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+ /* address of dirty_rect origin on display target */
+ char *dst_base = (char *)framebuffer.pages[0] + framebuffer.current_dirty.y
+ * framebuffer.back_target->mode_info.pitch +
framebuffer.current_dirty.x
+ * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+ /* blit each row from render_target to display */
+ grub_size_t pitch = framebuffer.back_target->mode_info.pitch;
+ for (unsigned int y = 0; y < framebuffer.current_dirty.height; y++) {
+ grub_memcpy(dst_base + y * pitch, src_base + y * pitch, row_size);
}
- framebuffer.current_dirty.first_line
- = framebuffer.back_target->mode_info.height;
- framebuffer.current_dirty.last_line = 0;
+ }
+
+ /* reset current_dirty rect */
+ framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.height = 0;
+ framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.width = 0;
return GRUB_ERR_NONE;
}
@@ -1470,8 +1491,10 @@ 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.first_line = mode_info.height;
- framebuffer.current_dirty.last_line = 0;
+ framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.height = 0;
+ framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.width = 0;
return GRUB_ERR_NONE;
}
@@ -1481,37 +1504,52 @@ doublebuf_pageflipping_update_screen (void)
{
int new_displayed_page;
grub_err_t err;
- int first_line, last_line;
-
- first_line = framebuffer.current_dirty.first_line;
- last_line = framebuffer.current_dirty.last_line;
- if (first_line > framebuffer.previous_dirty.first_line)
- first_line = framebuffer.previous_dirty.first_line;
- if (last_line < framebuffer.previous_dirty.last_line)
- last_line = framebuffer.previous_dirty.last_line;
- if (first_line <= last_line)
- {
- grub_size_t copy_size;
-
- if (grub_sub (last_line, first_line, ©_size) ||
- grub_mul (framebuffer.back_target->mode_info.pitch, copy_size,
©_size))
- {
- /* Shouldn't happen, but if it does we've a bug. */
- return GRUB_ERR_BUG;
- }
-
- grub_memcpy ((char *) framebuffer.pages[framebuffer.render_page] +
first_line *
- framebuffer.back_target->mode_info.pitch,
- (char *) framebuffer.back_target->data + first_line *
- framebuffer.back_target->mode_info.pitch,
- copy_size);
+ /* compare current and previous dirty_rects, and use greatest extents */
+ unsigned int min_x = framebuffer.current_dirty.x;
+ unsigned int min_y = framebuffer.current_dirty.y;
+ unsigned int max_x = framebuffer.current_dirty.x +
framebuffer.current_dirty.width;
+ unsigned int max_y = framebuffer.current_dirty.y +
framebuffer.current_dirty.height;
+ if (framebuffer.previous_dirty.x < min_x)
+ min_x = framebuffer.previous_dirty.x;
+ if (framebuffer.previous_dirty.y < min_y)
+ min_y = framebuffer.previous_dirty.y;
+ if (framebuffer.previous_dirty.x + framebuffer.previous_dirty.width > max_x)
+ max_x = framebuffer.previous_dirty.x + framebuffer.previous_dirty.width;
+ if (framebuffer.previous_dirty.y + framebuffer.previous_dirty.height > max_y)
+ max_y = framebuffer.previous_dirty.y + framebuffer.previous_dirty.height;
+ int dirty_width = max_x - min_x;
+ int dirty_height = max_y - min_y;
+
+ /* check if there is anything to do */
+ if (dirty_width > 0 && dirty_height > 0) {
+ /* byte size of dirty row */
+ grub_size_t row_size = dirty_width
+ * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+ /* render target base address */
+ char *src_base = (char *)framebuffer.back_target->data + min_y
+ * framebuffer.back_target->mode_info.pitch + min_x
+ * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+ /* display target base address */
+ char *dst_base = (char *)framebuffer.pages[framebuffer.render_page] +
min_y
+ * framebuffer.back_target->mode_info.pitch + min_x
+ * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+ /* blit each row from render_target to display */
+ grub_size_t pitch = framebuffer.back_target->mode_info.pitch;
+ for (int y = 0; y < dirty_height; y++) {
+ grub_memcpy(dst_base + y * pitch, src_base + y * pitch, row_size);
}
+ }
+ /* reset current_dirty rect */
framebuffer.previous_dirty = framebuffer.current_dirty;
- framebuffer.current_dirty.first_line
- = framebuffer.back_target->mode_info.height;
- framebuffer.current_dirty.last_line = 0;
+ framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.height = 0;
+ framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.width = 0;
/* Swap the page numbers in the framebuffer struct. */
new_displayed_page = framebuffer.render_page;
@@ -1570,12 +1608,17 @@ doublebuf_pageflipping_init (struct
grub_video_mode_info *mode_info,
framebuffer.pages[0] = page0_ptr;
framebuffer.pages[1] = page1_ptr;
- framebuffer.current_dirty.first_line
- = framebuffer.back_target->mode_info.height;
- framebuffer.current_dirty.last_line = 0;
- framebuffer.previous_dirty.first_line
- = framebuffer.back_target->mode_info.height;
- framebuffer.previous_dirty.last_line = 0;
+ /* reset current_dirty rect */
+ framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.height = 0;
+ framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.width = 0;
+
+ /* reset previous_dirty rect */
+ framebuffer.previous_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.previous_dirty.height = 0;
+ framebuffer.previous_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.previous_dirty.width = 0;
/* Set the framebuffer memory data pointer and display the right page. */
err = set_page_in (framebuffer.displayed_page);
@@ -1661,9 +1704,11 @@ grub_video_fb_setup (unsigned int mode_type, unsigned
int mode_mask,
framebuffer.displayed_page = 0;
framebuffer.render_page = 0;
framebuffer.set_page = 0;
- framebuffer.current_dirty.first_line
- = framebuffer.back_target->mode_info.height;
- framebuffer.current_dirty.last_line = 0;
+ /* reset transformed_add_rect */
+ framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+ framebuffer.current_dirty.height = 0;
+ framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+ framebuffer.current_dirty.width = 0;
mode_info->mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
--
2.34.1
- [PATCH v1 0/3] framebuffer rotation, kbader94, 2024/06/18
- [PATCH v1 1/3] dirty 2d,
kbader94 <=
- [PATCH v1 3/3] fb rotation - Add config option to grub-mkconfig to enable setting GRUB_FB_ROTATION in grub's config file. Setting GRUB_FB_ROTATION to 90, 180, 270, 'left', 'right', or 'inverted' will set the rotation for both grub AND linux. For linux, the changes are passed on to linux kernel entries if GRUB_GFXPAYLOAD_LINUX = 'keep'., kbader94, 2024/06/18
- [PATCH v1 2/3] framebuffer rotation, kbader94, 2024/06/18
- Prev by Date:
[PATCH v1 0/3] framebuffer rotation
- Next by Date:
[PATCH v1 3/3] fb rotation - Add config option to grub-mkconfig to enable setting GRUB_FB_ROTATION in grub's config file. Setting GRUB_FB_ROTATION to 90, 180, 270, 'left', 'right', or 'inverted' will set the rotation for both grub AND linux. For linux, the changes are passed on to linux kernel entries if GRUB_GFXPAYLOAD_LINUX = 'keep'.
- Previous by thread:
[PATCH v1 0/3] framebuffer rotation
- Next by thread:
[PATCH v1 3/3] fb rotation - Add config option to grub-mkconfig to enable setting GRUB_FB_ROTATION in grub's config file. Setting GRUB_FB_ROTATION to 90, 180, 270, 'left', 'right', or 'inverted' will set the rotation for both grub AND linux. For linux, the changes are passed on to linux kernel entries if GRUB_GFXPAYLOAD_LINUX = 'keep'.
- Index(es):