From ac3fa529dccaa95e4e1d50535ec54e4717f8f61d Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 10 Aug 2012 11:42:00 +0200 Subject: [PATCH] text: rework text renderer system This reworks the text renderer system to make it easier to write backends. We also allow returning errors during rendering now. Signed-off-by: David Herrmann --- src/terminal.c | 4 +- src/text.c | 215 +++++++++++++++++++++++++++++++++++------------ src/text.h | 39 ++++----- src/text_bblit.c | 80 ++++++------------ 4 files changed, 206 insertions(+), 132 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index a135365..b0d41c1 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -184,9 +184,7 @@ static int add_display(struct kmscon_terminal *term, struct uterm_display *disp) goto err_font; } - kmscon_text_set_bgcolor(scr->txt, 0, 0, 0); - kmscon_text_set_font(scr->txt, scr->font); - kmscon_text_set_screen(scr->txt, scr->screen); + kmscon_text_set(scr->txt, scr->font, scr->screen); cols = kmscon_text_get_cols(scr->txt); rows = kmscon_text_get_rows(scr->txt); diff --git a/src/text.c b/src/text.c index 177f3f1..78411e4 100644 --- a/src/text.c +++ b/src/text.c @@ -214,7 +214,11 @@ int kmscon_text_new(struct kmscon_text **out, text->ref = 1; text->ops = be->ops; - ret = text->ops->init(text); + if (text->ops->init) + ret = text->ops->init(text); + else + ret = 0; + if (ret) { if (be == def) { log_error("default backend %s cannot create renderer", @@ -275,74 +279,99 @@ void kmscon_text_unref(struct kmscon_text *text) if (!text || !text->ref || --text->ref) return; - text_lock(); log_debug("freeing text renderer"); - text->ops->destroy(text); - kmscon_font_unref(text->font); - uterm_screen_unref(text->screen); + kmscon_text_unset(text); + + text_lock(); + + if (text->ops->destroy) + text->ops->destroy(text); free(text); + text_unlock(); } /** - * kmscon_text_set_font: + * kmscon_text_set: * @txt: Valid text-renderer object - * @font: Valid font object + * @font: font object + * @screen: screen object * - * This makes the text-renderer @txt use the font @font. You can drop your - * reference to @font after calling this. + * This makes the text-renderer @txt use the font @font and screen @screen. You + * can drop your reference to both after calling this. + * This calls kmscon_text_unset() first to remove all previous associations. + * None of the arguments can be NULL! + * If this function fails then you must assume that no font/screen will be set + * and the object is invalid. + * + * Returns: 0 on success, negative error code on failure. */ -void kmscon_text_set_font(struct kmscon_text *txt, - struct kmscon_font *font) +int kmscon_text_set(struct kmscon_text *txt, + struct kmscon_font *font, + struct uterm_screen *screen) { - if (!txt || !font) - return; + int ret; + + if (!txt || !font || !screen) + return -EINVAL; + + kmscon_text_unset(txt); - kmscon_font_unref(txt->font); txt->font = font; - kmscon_font_ref(txt->font); + txt->screen = screen; - txt->ops->new_font(txt); + if (txt->ops->set) { + ret = txt->ops->set(txt); + if (ret) { + txt->font = NULL; + txt->screen = NULL; + return ret; + } + } + + kmscon_font_ref(txt->font); + uterm_screen_ref(txt->screen); + + return 0; } /** - * kmscon_text_set_bgcolor: - * @txt: Valid text-renderer object - * @r: red value - * @g: green value - * @b: blue value + * kmscon_text_unset(): + * @txt: text renderer * - * This sets the background color to r/g/b. The background color is a solid - * color which is used for the whole background. You should give the same as the - * default background color of your characters as this will speed up the drawing - * operations. + * This redos kmscon_text_set() by dropping the internal references to the font + * and screen and invalidating the object. You need to call kmscon_text_set() + * again to make use of this text renderer. + * This is automatically called when the text renderer is destroyed. */ -void kmscon_text_set_bgcolor(struct kmscon_text *txt, - uint8_t r, uint8_t g, uint8_t b) +void kmscon_text_unset(struct kmscon_text *txt) { - if (!txt) + if (!txt || !txt->screen || !txt->font) return; - txt->bg_r = r; - txt->bg_g = g; - txt->bg_b = b; - - txt->ops->new_bgcolor(txt); -} - -void kmscon_text_set_screen(struct kmscon_text *txt, - struct uterm_screen *screen) -{ - if (!txt || !screen) - return; + if (txt->ops->unset) + txt->ops->unset(txt); + kmscon_font_unref(txt->font); uterm_screen_unref(txt->screen); - txt->screen = screen; - uterm_screen_ref(txt->screen); - - txt->ops->new_screen(txt); + txt->font = NULL; + txt->screen = NULL; + txt->cols = 0; + txt->rows = 0; + txt->rendering = false; } +/** + * kmscon_text_get_cols: + * @txt: valid text renderer + * + * After setting the arguments with kmscon_text_set(), the renderer will compute + * the number of columns/rows of the console that it can display on the screen. + * You can retrieve these values via these functions. + * If kmscon_text_set() hasn't been called, this will return 0. + * + * Returns: Number of columns or 0 if @txt is invalid + */ unsigned int kmscon_text_get_cols(struct kmscon_text *txt) { if (!txt) @@ -351,6 +380,17 @@ unsigned int kmscon_text_get_cols(struct kmscon_text *txt) return txt->cols; } +/** + * kmscon_text_get_rows: + * @txt: valid text renderer + * + * After setting the arguments with kmscon_text_set(), the renderer will compute + * the number of columns/rows of the console that it can display on the screen. + * You can retrieve these values via these functions. + * If kmscon_text_set() hasn't been called, this will return 0. + * + * Returns: Number of rows or 0 if @txt is invalid + */ unsigned int kmscon_text_get_rows(struct kmscon_text *txt) { if (!txt) @@ -359,32 +399,101 @@ unsigned int kmscon_text_get_rows(struct kmscon_text *txt) return txt->rows; } -void kmscon_text_prepare(struct kmscon_text *txt) +/** + * kmscon_text_prepare: + * @txt: valid text renderer + * + * This starts a rendering-round. When rendering a console via a text renderer, + * you have to call this first, then render all your glyphs via + * kmscon_text_draw() and finally use kmscon_text_render(). If you modify this + * renderer during rendering or if you activate different OpenGL contexts in + * between, you need to restart rendering by calling kmscon_text_prepare() again + * and redoing everything from the beginning. + * + * Returns: 0 on success, negative error code on failure. + */ +int kmscon_text_prepare(struct kmscon_text *txt) { + int ret = 0; + if (!txt || !txt->font || !txt->screen) - return; + return -EINVAL; txt->rendering = true; - txt->ops->prepare(txt); + if (txt->ops->prepare) + ret = txt->ops->prepare(txt); + if (ret) + txt->rendering = false; + + return ret; } -void kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch, +/** + * kmscon_text_draw: + * @txt: valid text renderer + * @ch: symbol you want to draw + * @posx: X-position of the glyph + * @posy: Y-position of the glyph + * @attr: glyph attributes + * + * This draws a single glyph at the requested position. The position is a + * console position, not a pixel position! You must precede this call with + * kmscon_text_prepare(). Use this function to feed all glyphs into the + * rendering pipeline and finally call kmscon_text_render(). + * + * Returns: 0 on success or negative error code if this glyph couldn't be drawn. + */ +int kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch, unsigned int posx, unsigned int posy, const struct font_char_attr *attr) { if (!txt || !txt->rendering) - return; + return -EINVAL; if (posx >= txt->cols || posy >= txt->rows || !attr) - return; + return -EINVAL; - txt->ops->draw(txt, ch, posx, posy, attr); + return txt->ops->draw(txt, ch, posx, posy, attr); } -void kmscon_text_render(struct kmscon_text *txt) +/** + * kmscon_text_render: + * @txt: valid text renderer + * + * This does the final rendering round after kmscon_text_prepare() has been + * called and all glyphs were sent to the renderer via kmscon_text_draw(). + * + * Returns: 0 on success, negative error on failure. + */ +int kmscon_text_render(struct kmscon_text *txt) +{ + int ret = 0; + + if (!txt || !txt->rendering) + return -EINVAL; + + if (txt->ops->render) + ret = txt->ops->render(txt); + txt->rendering = false; + + return ret; +} + +/** + * kmscon_text_abort: + * @txt: valid text renderer + * + * If you called kmscon_text_prepare() but you want to abort rendering instead + * of finishing it with kmscon_text_render(), you can safely call this to reset + * internal state. It is optional to call this or simply restart rendering. + * Especially if the other renderers return an error, then they probably already + * aborted rendering and it is not required to call this. + */ +void kmscon_text_abort(struct kmscon_text *txt) { if (!txt || !txt->rendering) return; - txt->ops->render(txt); + if (txt->ops->abort) + txt->ops->abort(txt); txt->rendering = false; } diff --git a/src/text.h b/src/text.h index e48bb69..0b612ae 100644 --- a/src/text.h +++ b/src/text.h @@ -133,29 +133,27 @@ struct kmscon_text_ops; struct kmscon_text { unsigned long ref; const struct kmscon_text_ops *ops; + void *data; + struct kmscon_font *font; struct uterm_screen *screen; - uint8_t bg_r; - uint8_t bg_g; - uint8_t bg_b; unsigned int cols; unsigned int rows; bool rendering; - void *data; }; struct kmscon_text_ops { const char *name; int (*init) (struct kmscon_text *txt); void (*destroy) (struct kmscon_text *txt); - void (*new_font) (struct kmscon_text *txt); - void (*new_bgcolor) (struct kmscon_text *txt); - void (*new_screen) (struct kmscon_text *txt); - void (*prepare) (struct kmscon_text *txt); - void (*draw) (struct kmscon_text *txt, kmscon_symbol_t ch, - unsigned int posx, unsigned int posy, - const struct font_char_attr *attr); - void (*render) (struct kmscon_text *txt); + int (*set) (struct kmscon_text *txt); + void (*unset) (struct kmscon_text *txt); + int (*prepare) (struct kmscon_text *txt); + int (*draw) (struct kmscon_text *txt, kmscon_symbol_t ch, + unsigned int posx, unsigned int posy, + const struct font_char_attr *attr); + int (*render) (struct kmscon_text *txt); + void (*abort) (struct kmscon_text *txt); }; int kmscon_text_register(const struct kmscon_text_ops *ops); @@ -165,20 +163,19 @@ int kmscon_text_new(struct kmscon_text **out, const char *backend); void kmscon_text_ref(struct kmscon_text *txt); void kmscon_text_unref(struct kmscon_text *txt); -void kmscon_text_set_font(struct kmscon_text *txt, - struct kmscon_font *font); -void kmscon_text_set_bgcolor(struct kmscon_text *txt, - uint8_t r, uint8_t g, uint8_t b); -void kmscon_text_set_screen(struct kmscon_text *txt, - struct uterm_screen *screen); +int kmscon_text_set(struct kmscon_text *txt, + struct kmscon_font *font, + struct uterm_screen *screen); +void kmscon_text_unset(struct kmscon_text *txt); unsigned int kmscon_text_get_cols(struct kmscon_text *txt); unsigned int kmscon_text_get_rows(struct kmscon_text *txt); -void kmscon_text_prepare(struct kmscon_text *txt); -void kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch, +int kmscon_text_prepare(struct kmscon_text *txt); +int kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch, unsigned int posx, unsigned int posy, const struct font_char_attr *attr); -void kmscon_text_render(struct kmscon_text *txt); +int kmscon_text_render(struct kmscon_text *txt); +void kmscon_text_abort(struct kmscon_text *txt); /* modularized backends */ diff --git a/src/text_bblit.c b/src/text_bblit.c index 50ebb2c..38adbd4 100644 --- a/src/text_bblit.c +++ b/src/text_bblit.c @@ -44,22 +44,10 @@ #define LOG_SUBSYSTEM "text_bblit" -static int bblit_init(struct kmscon_text *txt) -{ - return 0; -} - -static void bblit_destroy(struct kmscon_text *txt) -{ -} - -static void bblit_recalculate_size(struct kmscon_text *txt) +static int bblit_set(struct kmscon_text *txt) { unsigned int sw, sh, fw, fh; - if (!txt->font || !txt->screen) - return; - fw = txt->font->attr.width; fh = txt->font->attr.height; sw = uterm_screen_width(txt->screen); @@ -67,29 +55,13 @@ static void bblit_recalculate_size(struct kmscon_text *txt) txt->cols = sw / fw; txt->rows = sh / fh; + + return 0; } -static void bblit_new_font(struct kmscon_text *txt) -{ - bblit_recalculate_size(txt); -} - -static void bblit_new_bgcolor(struct kmscon_text *txt) -{ -} - -static void bblit_new_screen(struct kmscon_text *txt) -{ - bblit_recalculate_size(txt); -} - -static void bblit_prepare(struct kmscon_text *txt) -{ -} - -static void bblit_draw(struct kmscon_text *txt, kmscon_symbol_t ch, - unsigned int posx, unsigned int posy, - const struct font_char_attr *attr) +static int bblit_draw(struct kmscon_text *txt, kmscon_symbol_t ch, + unsigned int posx, unsigned int posy, + const struct font_char_attr *attr) { const struct kmscon_glyph *glyph; int ret; @@ -103,39 +75,37 @@ static void bblit_draw(struct kmscon_text *txt, kmscon_symbol_t ch, if (ret) { ret = kmscon_font_render_inval(txt->font, &glyph); if (ret) - return; + return ret; } /* draw glyph */ if (attr->inverse) { - uterm_screen_blend(txt->screen, &glyph->buf, - posx * txt->font->attr.width, - posy * txt->font->attr.height, - attr->br, attr->bg, attr->bb, - attr->fr, attr->fg, attr->fb); + ret = uterm_screen_blend(txt->screen, &glyph->buf, + posx * txt->font->attr.width, + posy * txt->font->attr.height, + attr->br, attr->bg, attr->bb, + attr->fr, attr->fg, attr->fb); } else { - uterm_screen_blend(txt->screen, &glyph->buf, - posx * txt->font->attr.width, - posy * txt->font->attr.height, - attr->fr, attr->fg, attr->fb, - attr->br, attr->bg, attr->bb); + ret = uterm_screen_blend(txt->screen, &glyph->buf, + posx * txt->font->attr.width, + posy * txt->font->attr.height, + attr->fr, attr->fg, attr->fb, + attr->br, attr->bg, attr->bb); } -} -static void bblit_render(struct kmscon_text *txt) -{ + return ret; } static const struct kmscon_text_ops kmscon_text_bblit_ops = { .name = "bblit", - .init = bblit_init, - .destroy = bblit_destroy, - .new_font = bblit_new_font, - .new_bgcolor = bblit_new_bgcolor, - .new_screen = bblit_new_screen, - .prepare = bblit_prepare, + .init = NULL, + .destroy = NULL, + .set = bblit_set, + .unset = NULL, + .prepare = NULL, .draw = bblit_draw, - .render = bblit_render, + .render = NULL, + .abort = NULL, }; int kmscon_text_bblit_load(void)