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 <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-08-10 11:42:00 +02:00
parent 4ee5c05b57
commit ac3fa529dc
4 changed files with 206 additions and 132 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */

View File

@ -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)