Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F159187646
D57373.id179027.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D57373.id179027.diff
View Options
diff --git a/stand/common/gfx_fb.h b/stand/common/gfx_fb.h
--- a/stand/common/gfx_fb.h
+++ b/stand/common/gfx_fb.h
@@ -216,6 +216,12 @@
struct gen_fb tg_fb;
uint32_t *tg_shadow_fb; /* units of 4 bytes */
size_t tg_shadow_sz; /* units of pages */
+ /* Dirty rectangle for double-buffered flush */
+ uint32_t tg_dirty_x1;
+ uint32_t tg_dirty_y1;
+ uint32_t tg_dirty_x2;
+ uint32_t tg_dirty_y2;
+ bool tg_dirty;
teken_funcs_t *tg_functions;
void *tg_private;
} teken_gfx_t;
@@ -264,6 +270,7 @@
bool gfx_get_edid_resolution(struct vesa_edid_info *, edid_res_list_t *);
void gfx_framework_init(void);
void gfx_fb_cons_display(uint32_t, uint32_t, uint32_t, uint32_t, void *);
+void gfx_fb_flush(void);
void gfx_fb_setpixel(uint32_t, uint32_t);
void gfx_fb_drawrect(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
void gfx_term_drawrect(uint32_t, uint32_t, uint32_t, uint32_t);
diff --git a/stand/common/gfx_fb.c b/stand/common/gfx_fb.c
--- a/stand/common/gfx_fb.c
+++ b/stand/common/gfx_fb.c
@@ -816,6 +816,27 @@
return (0);
}
+static void
+gfx_shadow_mark_dirty(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ if (gfx_state.tg_dirty) {
+ if (x < gfx_state.tg_dirty_x1)
+ gfx_state.tg_dirty_x1 = x;
+ if (y < gfx_state.tg_dirty_y1)
+ gfx_state.tg_dirty_y1 = y;
+ if (x + w > gfx_state.tg_dirty_x2)
+ gfx_state.tg_dirty_x2 = x + w;
+ if (y + h > gfx_state.tg_dirty_y2)
+ gfx_state.tg_dirty_y2 = y + h;
+ } else {
+ gfx_state.tg_dirty = true;
+ gfx_state.tg_dirty_x1 = x;
+ gfx_state.tg_dirty_y1 = y;
+ gfx_state.tg_dirty_x2 = x + w;
+ gfx_state.tg_dirty_y2 = y + h;
+ }
+}
+
static void
gfxfb_shadow_fill(uint32_t *BltBuffer,
uint32_t DestinationX, uint32_t DestinationY,
@@ -846,6 +867,86 @@
gfx_state.tg_shadow_fb[off + x] = *BltBuffer;
}
}
+
+ gfx_shadow_mark_dirty(DestinationX, DestinationY, Width, Height);
+}
+
+/*
+ * Write a pixel buffer into the shadow framebuffer.
+ */
+static void
+gfxfb_shadow_buf_write(void *BltBuffer, uint32_t SourceX, uint32_t SourceY,
+ uint32_t DestinationX, uint32_t DestinationY,
+ uint32_t Width, uint32_t Height, uint32_t Delta)
+{
+ uint32_t fbW = gfx_state.tg_fb.fb_width;
+ uint32_t sy, dy;
+
+ if (Delta == 0)
+ Delta = Width * sizeof(*gfx_state.tg_shadow_fb);
+
+ for (sy = SourceY, dy = DestinationY; sy < SourceY + Height; sy++, dy++) {
+ uint32_t *src = (uint32_t *)((uint8_t *)BltBuffer + sy * Delta) +
+ SourceX;
+ uint32_t *dst = gfx_state.tg_shadow_fb + dy * fbW + DestinationX;
+
+ bcopy(src, dst, Width * sizeof(*gfx_state.tg_shadow_fb));
+ }
+
+ gfx_shadow_mark_dirty(DestinationX, DestinationY, Width, Height);
+}
+
+/*
+ * Copy a region within the shadow framebuffer.
+ */
+static void
+gfxfb_shadow_vid_to_vid(uint32_t SourceX, uint32_t SourceY,
+ uint32_t DestinationX, uint32_t DestinationY,
+ uint32_t Width, uint32_t Height)
+{
+ uint32_t fbW = gfx_state.tg_fb.fb_width;
+ uint32_t h = Height;
+ int step = 1;
+ uint32_t sy = SourceY, dy = DestinationY;
+
+ if (dy * fbW + DestinationX > sy * fbW + SourceX) {
+ sy += Height - 1;
+ dy += Height - 1;
+ step = -1;
+ }
+
+ while (Height-- > 0) {
+ bcopy(gfx_state.tg_shadow_fb + sy * fbW + SourceX,
+ gfx_state.tg_shadow_fb + dy * fbW + DestinationX,
+ Width * sizeof(*gfx_state.tg_shadow_fb));
+ sy += step;
+ dy += step;
+ }
+
+ gfx_shadow_mark_dirty(DestinationX, DestinationY, Width, h);
+}
+
+/*
+ * Read a region from the shadow framebuffer into a pixel buffer.
+ */
+static void
+gfxfb_shadow_buf_read(void *BltBuffer, uint32_t SourceX, uint32_t SourceY,
+ uint32_t DestinationX, uint32_t DestinationY,
+ uint32_t Width, uint32_t Height, uint32_t Delta)
+{
+ uint32_t fbW = gfx_state.tg_fb.fb_width;
+ uint32_t sy, dy;
+
+ if (Delta == 0)
+ Delta = Width * sizeof(*gfx_state.tg_shadow_fb);
+
+ for (sy = SourceY, dy = DestinationY; sy < SourceY + Height; sy++, dy++) {
+ uint32_t *src = gfx_state.tg_shadow_fb + sy * fbW + SourceX;
+ uint32_t *dst = (uint32_t *)((uint8_t *)BltBuffer + dy * Delta) +
+ DestinationX;
+
+ bcopy(src, dst, Width * sizeof(*gfx_state.tg_shadow_fb));
+ }
}
int
@@ -855,6 +956,42 @@
uint32_t Width, uint32_t Height, uint32_t Delta)
{
int rv;
+
+ /*
+ * When a shadow framebuffer is present, redirect every blt operation
+ * into it regardless of the underlying display backend (EFI GOP or
+ * direct framebuffer). Reads are served from the shadow to avoid
+ * unreliable video readback. The real video is updated in bulk by
+ * gfx_fb_flush() once a logical output operation is complete.
+ */
+ if (gfx_state.tg_shadow_fb != NULL) {
+ switch (BltOperation) {
+ case GfxFbBltVideoFill:
+ gfxfb_shadow_fill(BltBuffer, DestinationX, DestinationY,
+ Width, Height);
+ break;
+
+ case GfxFbBltVideoToBltBuffer:
+ gfxfb_shadow_buf_read(BltBuffer, SourceX, SourceY,
+ DestinationX, DestinationY, Width, Height, Delta);
+ break;
+
+ case GfxFbBltBufferToVideo:
+ gfxfb_shadow_buf_write(BltBuffer, SourceX, SourceY,
+ DestinationX, DestinationY, Width, Height, Delta);
+ break;
+
+ case GfxFbBltVideoToVideo:
+ gfxfb_shadow_vid_to_vid(SourceX, SourceY,
+ DestinationX, DestinationY, Width, Height);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ return (0);
+ }
+
#if defined(EFI)
EFI_STATUS status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
@@ -874,8 +1011,6 @@
tpl = BS->RaiseTPL(TPL_NOTIFY);
switch (BltOperation) {
case GfxFbBltVideoFill:
- gfxfb_shadow_fill(BltBuffer, DestinationX,
- DestinationY, Width, Height);
status = gop->Blt(gop, BltBuffer, EfiBltVideoFill,
SourceX, SourceY, DestinationX, DestinationY,
Width, Height, Delta);
@@ -927,8 +1062,6 @@
switch (BltOperation) {
case GfxFbBltVideoFill:
- gfxfb_shadow_fill(BltBuffer, DestinationX, DestinationY,
- Width, Height);
rv = gfxfb_blt_fill(BltBuffer, DestinationX, DestinationY,
Width, Height);
break;
@@ -955,6 +1088,57 @@
return (rv);
}
+/*
+ * Flush the dirty region of the shadow framebuffer to the real framebuffer.
+ * Must be called after each logical output operation when shadow fb is in use.
+ */
+void
+gfx_fb_flush(void)
+{
+ uint32_t x, y, w, h, pitch;
+
+ if (gfx_state.tg_shadow_fb == NULL || !gfx_state.tg_dirty ||
+ gfx_state.tg_fb_type == FB_TEXT)
+ return;
+
+ x = gfx_state.tg_dirty_x1;
+ y = gfx_state.tg_dirty_y1;
+ pitch = gfx_state.tg_fb.fb_width;
+
+ if (x >= pitch || y >= gfx_state.tg_fb.fb_height)
+ goto done;
+
+ w = gfx_state.tg_dirty_x2 - x;
+ h = gfx_state.tg_dirty_y2 - y;
+
+ if (x + w > pitch)
+ w = pitch - x;
+ if (y + h > gfx_state.tg_fb.fb_height)
+ h = gfx_state.tg_fb.fb_height - y;
+
+#if defined(EFI)
+ if (gfx_state.tg_fb_type == FB_GOP && !ignore_gop_blt &&
+ boot_services_active) {
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = gfx_state.tg_private;
+ EFI_TPL tpl;
+
+ assert(gop != NULL);
+ tpl = BS->RaiseTPL(TPL_NOTIFY);
+ (void) gop->Blt(gop,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)gfx_state.tg_shadow_fb,
+ EfiBltBufferToVideo, x, y, x, y, w, h,
+ pitch * sizeof(*gfx_state.tg_shadow_fb));
+ BS->RestoreTPL(tpl);
+ goto done;
+ }
+#endif
+ (void) gfxfb_blt_buffer_to_video(gfx_state.tg_shadow_fb,
+ x, y, x, y, w, h, pitch * sizeof(*gfx_state.tg_shadow_fb));
+
+done:
+ gfx_state.tg_dirty = false;
+}
+
void
gfx_bitblt_bitmap(teken_gfx_t *state, const uint8_t *glyph,
const teken_attr_t *a, uint32_t alpha, bool cursor)
@@ -1057,6 +1241,8 @@
c = teken_get_cursor(&state->tg_teken);
gfx_fb_cursor_draw(state, c, true);
}
+
+ gfx_fb_flush();
}
void
@@ -1096,6 +1282,7 @@
gfx_fb_cursor_draw(state, c, true);
}
+ gfx_fb_flush();
TSEXIT();
}
@@ -1132,6 +1319,7 @@
if (state->tg_cursor_visible) {
gfx_fb_cursor_draw(state, &state->tg_cursor, false);
gfx_fb_cursor_draw(state, p, true);
+ gfx_fb_flush();
}
}
@@ -1158,6 +1346,7 @@
state->tg_cursor_visible = true;
else
state->tg_cursor_visible = false;
+ gfx_fb_flush();
break;
default:
/* Not yet implemented */
@@ -1205,7 +1394,7 @@
width *= (s->tr_end.tp_col - s->tr_begin.tp_col + 1);
/*
- * With no shadow fb, use video to video copy.
+ * With no shadow fb, use video to video copy directly.
*/
if (state->tg_shadow_fb == NULL) {
(void) gfxfb_blt(NULL, GfxFbBltVideoToVideo,
@@ -1218,14 +1407,17 @@
}
/*
- * With shadow fb, we need to copy data on both shadow and video,
- * to preserve the consistency. We only read data from shadow fb.
+ * With shadow fb, copy within shadow only. Mark the destination dirty
+ * so gfx_fb_flush() will push it to the real framebuffer.
*/
-
step = 1;
pitch = state->tg_fb.fb_width;
bytes = width * sizeof (*state->tg_shadow_fb);
+ uint32_t dst_x = dx + state->tg_origin.tp_col;
+ uint32_t dst_y = dy + state->tg_origin.tp_row;
+ uint32_t dst_h = height;
+
/*
* To handle overlapping areas, set up reverse copy here.
*/
@@ -1240,13 +1432,11 @@
uint32_t *destination = &state->tg_shadow_fb[dy * pitch + dx];
bcopy(source, destination, bytes);
- (void) gfxfb_blt(destination, GfxFbBltBufferToVideo,
- 0, 0, dx + state->tg_origin.tp_col,
- dy + state->tg_origin.tp_row, width, 1, 0);
-
sy += step;
dy += step;
}
+
+ gfx_shadow_mark_dirty(dst_x, dst_y, width, dst_h);
}
static void
@@ -1345,6 +1535,8 @@
c = teken_get_cursor(&state->tg_teken);
gfx_fb_cursor_draw(state, c, true);
}
+
+ gfx_fb_flush();
}
/*
@@ -1434,23 +1626,22 @@
size_t size;
/*
- * If we do have shadow fb, we will use shadow to render data,
- * and copy shadow to video.
+ * If we do have shadow fb, render into it only. The caller is
+ * responsible for flushing the dirty region to the real framebuffer
+ * via gfx_fb_flush() once a logical output operation is complete.
*/
if (gfx_state.tg_shadow_fb != NULL) {
uint32_t pitch = gfx_state.tg_fb.fb_width;
+ uint32_t sy = y - gfx_state.tg_origin.tp_row;
+ uint32_t sx = x - gfx_state.tg_origin.tp_col;
- /* Copy rectangle line by line. */
p = data;
- for (uint32_t sy = 0; sy < height; sy++) {
+ for (uint32_t row = 0; row < height; row++) {
buf = (void *)(gfx_state.tg_shadow_fb +
- (y - gfx_state.tg_origin.tp_row) * pitch +
- x - gfx_state.tg_origin.tp_col);
- bitmap_cpy(buf, &p[sy * width], width);
- (void) gfxfb_blt(buf, GfxFbBltBufferToVideo,
- 0, 0, x, y, width, 1, 0);
- y++;
+ (sy + row) * pitch + sx);
+ bitmap_cpy(buf, &p[row * width], width);
}
+ gfx_shadow_mark_dirty(x, y, width, height);
return;
}
@@ -1566,6 +1757,7 @@
gfxfb_blt(&c, GfxFbBltVideoFill, 0, 0, x1, y1, 1, y2 - y1, 0);
gfxfb_blt(&c, GfxFbBltVideoFill, 0, 0, x2, y1, 1, y2 - y1, 0);
}
+ gfx_fb_flush();
}
void
@@ -1618,6 +1810,7 @@
y0 += sy;
}
}
+ gfx_fb_flush();
}
/*
@@ -1690,6 +1883,7 @@
} while (dy < dx); /* gradient negates -> algorithm fails */
}
gfx_fb_line(x0, y0, x2, y2, width);
+ gfx_fb_flush();
}
/*
@@ -2042,6 +2236,7 @@
gfx_fb_cons_display(ux1, uy1, fwidth, fheight, data);
free(data);
+ gfx_fb_flush();
return (0);
}
diff --git a/stand/ficl/gfx_loader.c b/stand/ficl/gfx_loader.c
--- a/stand/ficl/gfx_loader.c
+++ b/stand/ficl/gfx_loader.c
@@ -156,9 +156,10 @@
vmCheckStack(pVM, 2, 0);
#endif
- y = stackPopUNS(pVM->pStack);
- x = stackPopUNS(pVM->pStack);
- gfx_fb_setpixel(x, y);
+ y = stackPopUNS(pVM->pStack);
+ x = stackPopUNS(pVM->pStack);
+ gfx_fb_setpixel(x, y);
+ gfx_fb_flush();
}
void
diff --git a/stand/liblua/gfx_utils.c b/stand/liblua/gfx_utils.c
--- a/stand/liblua/gfx_utils.c
+++ b/stand/liblua/gfx_utils.c
@@ -133,7 +133,8 @@
x = luaL_checknumber(L, 1);
y = luaL_checknumber(L, 2);
- gfx_fb_setpixel(x, y);
+ gfx_fb_setpixel(x, y);
+ gfx_fb_flush();
return 0;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jun 12, 2:26 AM (7 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33897558
Default Alt Text
D57373.id179027.diff (11 KB)
Attached To
Mode
D57373: stand: Bulk operations on each gfxfb_blt if shadow buffer enabled
Attached
Detach File
Event Timeline
Log In to Comment