loader: framebuffer should only be written into
Reading from Write Combining memory can be very-very slow. Try to use shadow buffer to avoid such reads. MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D33305
This commit is contained in:
parent
faa3605705
commit
6102f43cf0
@ -741,6 +741,38 @@ gfxfb_blt_video_to_video(uint32_t SourceX, uint32_t SourceY,
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
gfxfb_shadow_fill(uint32_t *BltBuffer,
|
||||
uint32_t DestinationX, uint32_t DestinationY,
|
||||
uint32_t Width, uint32_t Height)
|
||||
{
|
||||
uint32_t fbX, fbY;
|
||||
|
||||
if (gfx_state.tg_shadow_fb == NULL)
|
||||
return;
|
||||
|
||||
fbX = gfx_state.tg_fb.fb_width;
|
||||
fbY = gfx_state.tg_fb.fb_height;
|
||||
|
||||
if (BltBuffer == NULL)
|
||||
return;
|
||||
|
||||
if (DestinationX + Width > fbX)
|
||||
Width = fbX - DestinationX;
|
||||
|
||||
if (DestinationY + Height > fbY)
|
||||
Height = fbY - DestinationY;
|
||||
|
||||
uint32_t y2 = Height + DestinationY;
|
||||
for (uint32_t y1 = DestinationY; y1 < y2; y1++) {
|
||||
uint32_t off = y1 * fbX + DestinationX;
|
||||
|
||||
for (uint32_t x = 0; x < Width; x++) {
|
||||
gfx_state.tg_shadow_fb[off + x] = *BltBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
|
||||
uint32_t SourceX, uint32_t SourceY,
|
||||
@ -764,6 +796,8 @@ gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
|
||||
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);
|
||||
@ -815,6 +849,8 @@ gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
|
||||
|
||||
switch (BltOperation) {
|
||||
case GfxFbBltVideoFill:
|
||||
gfxfb_shadow_fill(BltBuffer, DestinationX, DestinationY,
|
||||
Width, Height);
|
||||
rv = gfxfb_blt_fill(BltBuffer, DestinationX, DestinationY,
|
||||
Width, Height);
|
||||
break;
|
||||
@ -984,7 +1020,6 @@ gfx_fb_fill(void *arg, const teken_rect_t *r, teken_char_t c,
|
||||
static void
|
||||
gfx_fb_cursor_draw(teken_gfx_t *state, const teken_pos_t *pos, bool on)
|
||||
{
|
||||
unsigned x, y, width, height;
|
||||
const uint8_t *glyph;
|
||||
teken_pos_t p;
|
||||
int idx;
|
||||
@ -998,42 +1033,6 @@ gfx_fb_cursor_draw(teken_gfx_t *state, const teken_pos_t *pos, bool on)
|
||||
if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
|
||||
return;
|
||||
|
||||
width = state->tg_font.vf_width;
|
||||
height = state->tg_font.vf_height;
|
||||
x = state->tg_origin.tp_col + p.tp_col * width;
|
||||
y = state->tg_origin.tp_row + p.tp_row * height;
|
||||
|
||||
/*
|
||||
* Save original display content to preserve image data.
|
||||
*/
|
||||
if (on) {
|
||||
if (state->tg_cursor_image == NULL ||
|
||||
state->tg_cursor_size != width * height * 4) {
|
||||
free(state->tg_cursor_image);
|
||||
state->tg_cursor_size = width * height * 4;
|
||||
state->tg_cursor_image = malloc(state->tg_cursor_size);
|
||||
}
|
||||
if (state->tg_cursor_image != NULL) {
|
||||
if (gfxfb_blt(state->tg_cursor_image,
|
||||
GfxFbBltVideoToBltBuffer, x, y, 0, 0,
|
||||
width, height, 0) != 0) {
|
||||
free(state->tg_cursor_image);
|
||||
state->tg_cursor_image = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Restore display from tg_cursor_image.
|
||||
* If there is no image, restore char from screen_buffer.
|
||||
*/
|
||||
if (state->tg_cursor_image != NULL &&
|
||||
gfxfb_blt(state->tg_cursor_image, GfxFbBltBufferToVideo,
|
||||
0, 0, x, y, width, height, 0) == 0) {
|
||||
state->tg_cursor = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
glyph = font_lookup(&state->tg_font, screen_buffer[idx].c,
|
||||
&screen_buffer[idx].a);
|
||||
gfx_bitblt_bitmap(state, glyph, &screen_buffer[idx].a, 0xff, on);
|
||||
@ -1110,19 +1109,62 @@ gfx_fb_copy_area(teken_gfx_t *state, const teken_rect_t *s,
|
||||
const teken_pos_t *d)
|
||||
{
|
||||
uint32_t sx, sy, dx, dy, width, height;
|
||||
uint32_t pitch, bytes;
|
||||
int step;
|
||||
|
||||
width = state->tg_font.vf_width;
|
||||
height = state->tg_font.vf_height;
|
||||
|
||||
sx = state->tg_origin.tp_col + s->tr_begin.tp_col * width;
|
||||
sy = state->tg_origin.tp_row + s->tr_begin.tp_row * height;
|
||||
dx = state->tg_origin.tp_col + d->tp_col * width;
|
||||
dy = state->tg_origin.tp_row + d->tp_row * height;
|
||||
sx = s->tr_begin.tp_col * width;
|
||||
sy = s->tr_begin.tp_row * height;
|
||||
dx = d->tp_col * width;
|
||||
dy = d->tp_row * height;
|
||||
|
||||
width *= (s->tr_end.tp_col - s->tr_begin.tp_col + 1);
|
||||
|
||||
(void) gfxfb_blt(NULL, GfxFbBltVideoToVideo, sx, sy, dx, dy,
|
||||
/*
|
||||
* With no shadow fb, use video to video copy.
|
||||
*/
|
||||
if (state->tg_shadow_fb == NULL) {
|
||||
(void) gfxfb_blt(NULL, GfxFbBltVideoToVideo,
|
||||
sx + state->tg_origin.tp_col,
|
||||
sy + state->tg_origin.tp_row,
|
||||
dx + state->tg_origin.tp_col,
|
||||
dy + state->tg_origin.tp_row,
|
||||
width, height, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* With shadow fb, we need to copy data on both shadow and video,
|
||||
* to preserve the consistency. We only read data from shadow fb.
|
||||
*/
|
||||
|
||||
step = 1;
|
||||
pitch = state->tg_fb.fb_width;
|
||||
bytes = width * sizeof (*state->tg_shadow_fb);
|
||||
|
||||
/*
|
||||
* To handle overlapping areas, set up reverse copy here.
|
||||
*/
|
||||
if (dy * pitch + dx > sy * pitch + sx) {
|
||||
sy += height;
|
||||
dy += height;
|
||||
step = -step;
|
||||
}
|
||||
|
||||
while (height-- > 0) {
|
||||
uint32_t *source = &state->tg_shadow_fb[sy * pitch + sx];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1303,13 +1345,32 @@ gfx_fb_cons_display(uint32_t x, uint32_t y, uint32_t width, uint32_t height,
|
||||
void *data)
|
||||
{
|
||||
#if defined(EFI)
|
||||
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf;
|
||||
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf, *p;
|
||||
#else
|
||||
struct paletteentry *buf;
|
||||
struct paletteentry *buf, *p;
|
||||
#endif
|
||||
size_t size;
|
||||
|
||||
size = width * height * sizeof(*buf);
|
||||
/*
|
||||
* If we do have shadow fb, we will use shadow to render data,
|
||||
* and copy shadow to video.
|
||||
*/
|
||||
if (gfx_state.tg_shadow_fb != NULL) {
|
||||
uint32_t pitch = gfx_state.tg_fb.fb_width;
|
||||
|
||||
/* Copy rectangle line by line. */
|
||||
p = data;
|
||||
for (uint32_t sy = 0; sy < height; sy++) {
|
||||
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++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common data to display is glyph, use preallocated
|
||||
@ -1318,6 +1379,7 @@ gfx_fb_cons_display(uint32_t x, uint32_t y, uint32_t width, uint32_t height,
|
||||
if (gfx_state.tg_glyph_size != GlyphBufferSize)
|
||||
(void) allocate_glyphbuffer(width, height);
|
||||
|
||||
size = width * height * sizeof(*buf);
|
||||
if (size == GlyphBufferSize)
|
||||
buf = GlyphBuffer;
|
||||
else
|
||||
|
@ -210,14 +210,13 @@ typedef struct teken_gfx {
|
||||
teken_t tg_teken; /* Teken core */
|
||||
teken_pos_t tg_cursor; /* Where cursor was drawn */
|
||||
bool tg_cursor_visible;
|
||||
uint8_t *tg_cursor_image; /* Memory for cursor */
|
||||
size_t tg_cursor_size;
|
||||
teken_pos_t tg_tp; /* Terminal dimensions */
|
||||
teken_pos_t tg_origin; /* Point of origin in pixels */
|
||||
uint8_t *tg_glyph; /* Memory for glyph */
|
||||
size_t tg_glyph_size;
|
||||
struct vt_font tg_font;
|
||||
struct gen_fb tg_fb;
|
||||
uint32_t *tg_shadow_fb; /* units of 4 bytes */
|
||||
teken_funcs_t *tg_functions;
|
||||
void *tg_private;
|
||||
bool tg_kernel_supported; /* Loaded kernel is supported */
|
||||
|
@ -622,6 +622,9 @@ efi_find_framebuffer(teken_gfx_t *gfx_state)
|
||||
gfx_state->tg_fb.fb_bpp = fls(efifb.fb_mask_red | efifb.fb_mask_green |
|
||||
efifb.fb_mask_blue | efifb.fb_mask_reserved);
|
||||
|
||||
free(gfx_state->tg_shadow_fb);
|
||||
gfx_state->tg_shadow_fb = malloc(efifb.fb_height * efifb.fb_width *
|
||||
sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -709,6 +709,10 @@ vbe_set_mode(int modenum)
|
||||
gfx_state.tg_fb.fb_width = mi.XResolution;
|
||||
gfx_state.tg_fb.fb_bpp = mi.BitsPerPixel;
|
||||
|
||||
free(gfx_state.tg_shadow_fb);
|
||||
gfx_state.tg_shadow_fb = malloc(mi.YResolution * mi.XResolution *
|
||||
sizeof(struct paletteentry));
|
||||
|
||||
/* Bytes per pixel */
|
||||
bpp = roundup2(mi.BitsPerPixel, NBBY) / NBBY;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user