diff options
author | Hung-Te Lin <hungte@chromium.org> | 2020-08-17 16:22:21 +0800 |
---|---|---|
committer | Julius Werner <jwerner@chromium.org> | 2020-08-28 21:40:58 +0000 |
commit | d04b3883815e898ebd81dd426437964f87cfd6af (patch) | |
tree | 6ae2163590ed98b0ba7539d5e32651cdd7b1bd20 | |
parent | 6d7996439f71feb1ed041f0d6bcc809c585a7cfd (diff) | |
download | coreboot-d04b3883815e898ebd81dd426437964f87cfd6af.tar.xz |
libpayload: cbgfx: Support buffered I/O
For payloads with UI based on CBGFX, they usually start by calling
clear_canvas or clear_screen and then draw the UI elements. However,
that makes the screen flicker.
A typical solution is to identify and minimize the area to redraw.
However for payloads with complicated UI and do not care about latency,
an alternative is to enable buffered I/O.
The new enable_graphics_buffer() will redirect all graphics I/O
into an invisible working buffer. To flush (redraw) the buffer to the
real screen, call flush_graphics_buffer(). To stop buffering, call
disable_graphics_buffer().
BUG=None
TEST=Add the enable, flush and disable calls to payload 'depthcharge',
built a firmware and boots into Chrome OS recover UI. No more
flickering. The average rendering time on x86 platform is 1.2ms.
Change-Id: Id60a2824fd9e164feae16b92b68b003beabea8d3
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/44654
Reviewed-by: Julius Werner <jwerner@chromium.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r-- | payloads/libpayload/drivers/video/graphics.c | 39 | ||||
-rw-r--r-- | payloads/libpayload/include/cbgfx.h | 23 |
2 files changed, 61 insertions, 1 deletions
diff --git a/payloads/libpayload/drivers/video/graphics.c b/payloads/libpayload/drivers/video/graphics.c index 2d2ea030ba..2bf5e19d88 100644 --- a/payloads/libpayload/drivers/video/graphics.c +++ b/payloads/libpayload/drivers/video/graphics.c @@ -41,6 +41,8 @@ static struct rect canvas; static struct rect screen; +static uint8_t *gfx_buffer; + /* * Framebuffer is assumed to assign a higher coordinate (larger x, y) to * a higher address @@ -48,7 +50,8 @@ static struct rect screen; static const struct cb_framebuffer *fbinfo; /* Shorthand for up-to-date virtual framebuffer address */ -#define FB ((unsigned char *)phys_to_virt(fbinfo->physical_address)) +#define REAL_FB ((unsigned char *)phys_to_virt(fbinfo->physical_address)) +#define FB (gfx_buffer ? gfx_buffer : REAL_FB) #define LOG(x...) printf("CBGFX: " x) #define PIVOT_H_MASK (PIVOT_H_LEFT|PIVOT_H_CENTER|PIVOT_H_RIGHT) @@ -1257,3 +1260,37 @@ int get_bitmap_dimension(const void *bitmap, size_t sz, struct scale *dim_rel) return CBGFX_SUCCESS; } + +int enable_graphics_buffer(void) +{ + if (gfx_buffer) + return CBGFX_SUCCESS; + + if (cbgfx_init()) + return CBGFX_ERROR_INIT; + + size_t buffer_size = fbinfo->y_resolution * fbinfo->bytes_per_line; + gfx_buffer = malloc(buffer_size); + if (!gfx_buffer) { + LOG("%s: Failed to create graphics buffer (%zu bytes).\n", + __func__, buffer_size); + return CBGFX_ERROR_GRAPHICS_BUFFER; + } + + return CBGFX_SUCCESS; +} + +int flush_graphics_buffer(void) +{ + if (!gfx_buffer) + return CBGFX_ERROR_GRAPHICS_BUFFER; + + memcpy(REAL_FB, gfx_buffer, fbinfo->y_resolution * fbinfo->bytes_per_line); + return CBGFX_SUCCESS; +} + +void disable_graphics_buffer(void) +{ + free(gfx_buffer); + gfx_buffer = NULL; +} diff --git a/payloads/libpayload/include/cbgfx.h b/payloads/libpayload/include/cbgfx.h index 85b61a7b10..72e512267a 100644 --- a/payloads/libpayload/include/cbgfx.h +++ b/payloads/libpayload/include/cbgfx.h @@ -56,6 +56,8 @@ #define CBGFX_ERROR_FRAMEBUFFER_ADDR 0x15 /* portrait screen not supported */ #define CBGFX_ERROR_PORTRAIT_SCREEN 0x16 +/* cannot use buffered I/O */ +#define CBGFX_ERROR_GRAPHICS_BUFFER 0x17 struct fraction { int32_t n; @@ -272,3 +274,24 @@ void clear_blend(void); * 0 = min alpha argument, 0% opacity */ #define ALPHA(percentage) MIN(255, (256 * percentage / 100)) + +/** + * Enable buffered I/O. All CBGFX operations will be redirected to a working + * buffer, and only updated (redrawn) when flush_graphics_buffer() is called. + * + * @return CBGFX_* error codes + */ +int enable_graphics_buffer(void); + +/** + * Redraw buffered graphics data to real screen if graphics buffer is already + * enabled. + * + * @return CBGFX_* error codes + */ +int flush_graphics_buffer(void); + +/** + * Stop using buffered I/O and release allocated memory. + */ +void disable_graphics_buffer(void); |