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);
|
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
|
int
|
||||||
gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
|
gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
|
||||||
uint32_t SourceX, uint32_t SourceY,
|
uint32_t SourceX, uint32_t SourceY,
|
||||||
@ -764,6 +796,8 @@ gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
|
|||||||
tpl = BS->RaiseTPL(TPL_NOTIFY);
|
tpl = BS->RaiseTPL(TPL_NOTIFY);
|
||||||
switch (BltOperation) {
|
switch (BltOperation) {
|
||||||
case GfxFbBltVideoFill:
|
case GfxFbBltVideoFill:
|
||||||
|
gfxfb_shadow_fill(BltBuffer, DestinationX,
|
||||||
|
DestinationY, Width, Height);
|
||||||
status = gop->Blt(gop, BltBuffer, EfiBltVideoFill,
|
status = gop->Blt(gop, BltBuffer, EfiBltVideoFill,
|
||||||
SourceX, SourceY, DestinationX, DestinationY,
|
SourceX, SourceY, DestinationX, DestinationY,
|
||||||
Width, Height, Delta);
|
Width, Height, Delta);
|
||||||
@ -815,6 +849,8 @@ gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
|
|||||||
|
|
||||||
switch (BltOperation) {
|
switch (BltOperation) {
|
||||||
case GfxFbBltVideoFill:
|
case GfxFbBltVideoFill:
|
||||||
|
gfxfb_shadow_fill(BltBuffer, DestinationX, DestinationY,
|
||||||
|
Width, Height);
|
||||||
rv = gfxfb_blt_fill(BltBuffer, DestinationX, DestinationY,
|
rv = gfxfb_blt_fill(BltBuffer, DestinationX, DestinationY,
|
||||||
Width, Height);
|
Width, Height);
|
||||||
break;
|
break;
|
||||||
@ -984,7 +1020,6 @@ gfx_fb_fill(void *arg, const teken_rect_t *r, teken_char_t c,
|
|||||||
static void
|
static void
|
||||||
gfx_fb_cursor_draw(teken_gfx_t *state, const teken_pos_t *pos, bool on)
|
gfx_fb_cursor_draw(teken_gfx_t *state, const teken_pos_t *pos, bool on)
|
||||||
{
|
{
|
||||||
unsigned x, y, width, height;
|
|
||||||
const uint8_t *glyph;
|
const uint8_t *glyph;
|
||||||
teken_pos_t p;
|
teken_pos_t p;
|
||||||
int idx;
|
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)
|
if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
|
||||||
return;
|
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,
|
glyph = font_lookup(&state->tg_font, screen_buffer[idx].c,
|
||||||
&screen_buffer[idx].a);
|
&screen_buffer[idx].a);
|
||||||
gfx_bitblt_bitmap(state, glyph, &screen_buffer[idx].a, 0xff, on);
|
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)
|
const teken_pos_t *d)
|
||||||
{
|
{
|
||||||
uint32_t sx, sy, dx, dy, width, height;
|
uint32_t sx, sy, dx, dy, width, height;
|
||||||
|
uint32_t pitch, bytes;
|
||||||
|
int step;
|
||||||
|
|
||||||
width = state->tg_font.vf_width;
|
width = state->tg_font.vf_width;
|
||||||
height = state->tg_font.vf_height;
|
height = state->tg_font.vf_height;
|
||||||
|
|
||||||
sx = state->tg_origin.tp_col + s->tr_begin.tp_col * width;
|
sx = s->tr_begin.tp_col * width;
|
||||||
sy = state->tg_origin.tp_row + s->tr_begin.tp_row * height;
|
sy = s->tr_begin.tp_row * height;
|
||||||
dx = state->tg_origin.tp_col + d->tp_col * width;
|
dx = d->tp_col * width;
|
||||||
dy = state->tg_origin.tp_row + d->tp_row * height;
|
dy = d->tp_row * height;
|
||||||
|
|
||||||
width *= (s->tr_end.tp_col - s->tr_begin.tp_col + 1);
|
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);
|
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
|
static void
|
||||||
@ -1303,13 +1345,32 @@ gfx_fb_cons_display(uint32_t x, uint32_t y, uint32_t width, uint32_t height,
|
|||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
#if defined(EFI)
|
#if defined(EFI)
|
||||||
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf;
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf, *p;
|
||||||
#else
|
#else
|
||||||
struct paletteentry *buf;
|
struct paletteentry *buf, *p;
|
||||||
#endif
|
#endif
|
||||||
size_t size;
|
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
|
* 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)
|
if (gfx_state.tg_glyph_size != GlyphBufferSize)
|
||||||
(void) allocate_glyphbuffer(width, height);
|
(void) allocate_glyphbuffer(width, height);
|
||||||
|
|
||||||
|
size = width * height * sizeof(*buf);
|
||||||
if (size == GlyphBufferSize)
|
if (size == GlyphBufferSize)
|
||||||
buf = GlyphBuffer;
|
buf = GlyphBuffer;
|
||||||
else
|
else
|
||||||
|
@ -210,14 +210,13 @@ typedef struct teken_gfx {
|
|||||||
teken_t tg_teken; /* Teken core */
|
teken_t tg_teken; /* Teken core */
|
||||||
teken_pos_t tg_cursor; /* Where cursor was drawn */
|
teken_pos_t tg_cursor; /* Where cursor was drawn */
|
||||||
bool tg_cursor_visible;
|
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_tp; /* Terminal dimensions */
|
||||||
teken_pos_t tg_origin; /* Point of origin in pixels */
|
teken_pos_t tg_origin; /* Point of origin in pixels */
|
||||||
uint8_t *tg_glyph; /* Memory for glyph */
|
uint8_t *tg_glyph; /* Memory for glyph */
|
||||||
size_t tg_glyph_size;
|
size_t tg_glyph_size;
|
||||||
struct vt_font tg_font;
|
struct vt_font tg_font;
|
||||||
struct gen_fb tg_fb;
|
struct gen_fb tg_fb;
|
||||||
|
uint32_t *tg_shadow_fb; /* units of 4 bytes */
|
||||||
teken_funcs_t *tg_functions;
|
teken_funcs_t *tg_functions;
|
||||||
void *tg_private;
|
void *tg_private;
|
||||||
bool tg_kernel_supported; /* Loaded kernel is supported */
|
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 |
|
gfx_state->tg_fb.fb_bpp = fls(efifb.fb_mask_red | efifb.fb_mask_green |
|
||||||
efifb.fb_mask_blue | efifb.fb_mask_reserved);
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,6 +709,10 @@ vbe_set_mode(int modenum)
|
|||||||
gfx_state.tg_fb.fb_width = mi.XResolution;
|
gfx_state.tg_fb.fb_width = mi.XResolution;
|
||||||
gfx_state.tg_fb.fb_bpp = mi.BitsPerPixel;
|
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 */
|
/* Bytes per pixel */
|
||||||
bpp = roundup2(mi.BitsPerPixel, NBBY) / NBBY;
|
bpp = roundup2(mi.BitsPerPixel, NBBY) / NBBY;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user