wip: initial multithreaded renderer

This commit is contained in:
Daniel Eklöf 2019-07-29 20:13:26 +02:00
parent d1b88f67e4
commit c531795b83
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
8 changed files with 287 additions and 89 deletions

View file

@ -107,26 +107,28 @@ get_config_path(void)
} }
static bool static bool
str_to_color(const char *s, uint32_t *color, const char *path, int lineno) str_to_ulong(const char *s, int base, unsigned long *res)
{ {
if (s == NULL) if (s == NULL)
return false; return false;
errno = 0; errno = 0;
char *end = NULL; char *end = NULL;
unsigned long res = strtoul(s, &end, 16);
if (errno != 0) { *res = strtoul(s, &end, base);
return errno == 0 && *end == '\0';
}
static bool
str_to_color(const char *s, uint32_t *color, const char *path, int lineno)
{
unsigned long value;
if (!str_to_ulong(s, 16, &value)) {
LOG_ERRNO("%s:%d: invalid color: %s", path, lineno, s); LOG_ERRNO("%s:%d: invalid color: %s", path, lineno, s);
return false; return false;
} }
if (*end != '\0') { *color = value & 0xffffff;
LOG_ERR("%s:%d: invalid color: %s", path, lineno, s);
return false;
}
*color = res & 0xffffff;
return true; return true;
} }
@ -149,6 +151,15 @@ parse_section_main(const char *key, const char *value, struct config *conf,
conf->font = strdup(value); conf->font = strdup(value);
} }
else if (strcmp(key, "workers") == 0) {
unsigned long count;
if (!str_to_ulong(value, 10, &count)) {
LOG_ERR("%s:%d: expected an integer: %s", path, lineno, value);
return false;
}
conf->render_worker_count = count;
}
else { else {
LOG_WARN("%s:%u: invalid key: %s", path, lineno, key); LOG_WARN("%s:%u: invalid key: %s", path, lineno, key);
return false; return false;
@ -427,6 +438,8 @@ config_load(struct config *conf)
.cursor = 0, .cursor = 0,
}, },
}, },
.render_worker_count = sysconf(_SC_NPROCESSORS_ONLN),
}; };
char *path = get_config_path(); char *path = get_config_path();

View file

@ -24,6 +24,8 @@ struct config {
uint32_t cursor; uint32_t cursor;
} color; } color;
} cursor; } cursor;
size_t render_worker_count;
}; };
bool config_load(struct config *conf); bool config_load(struct config *conf);

44
main.c
View file

@ -11,9 +11,9 @@
#include <errno.h> #include <errno.h>
#include <sys/timerfd.h> #include <sys/timerfd.h>
#include <sys/sysinfo.h>
#include <freetype/tttables.h> #include <freetype/tttables.h>
#include <cairo-ft.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <wayland-cursor.h> #include <wayland-cursor.h>
#include <xdg-shell.h> #include <xdg-shell.h>
@ -388,8 +388,18 @@ main(int argc, char *const *argv)
.normal = {.damage = tll_init(), .scroll_damage = tll_init()}, .normal = {.damage = tll_init(), .scroll_damage = tll_init()},
.alt = {.damage = tll_init(), .scroll_damage = tll_init()}, .alt = {.damage = tll_init(), .scroll_damage = tll_init()},
.grid = &term.normal, .grid = &term.normal,
.render = {
.workers = {
.count = conf.render_worker_count,
.queue = tll_init(),
},
},
}; };
LOG_INFO("using %zu rendering threads", term.render.workers.count);
struct render_worker_context worker_context[term.render.workers.count];
/* Initialize 'current' colors from the default colors */ /* Initialize 'current' colors from the default colors */
term.colors.fg = term.colors.default_fg; term.colors.fg = term.colors.default_fg;
term.colors.bg = term.colors.default_bg; term.colors.bg = term.colors.default_bg;
@ -409,6 +419,18 @@ main(int argc, char *const *argv)
thrd_t keyboard_repeater_id; thrd_t keyboard_repeater_id;
thrd_create(&keyboard_repeater_id, &keyboard_repeater, &term); thrd_create(&keyboard_repeater_id, &keyboard_repeater, &term);
sem_init(&term.render.workers.start, 0, 0);
sem_init(&term.render.workers.done, 0, 0);
mtx_init(&term.render.workers.lock, mtx_plain);
cnd_init(&term.render.workers.cond);
term.render.workers.threads = calloc(term.render.workers.count, sizeof(term.render.workers.threads[0]));
for (size_t i = 0; i < term.render.workers.count; i++) {
worker_context[i].term = &term;
worker_context[i].my_id = 1 + i;
thrd_create(&term.render.workers.threads[i], &render_worker_thread, &worker_context[i]);
}
if (!font_from_name(conf.font, &term.fonts[0])) if (!font_from_name(conf.font, &term.fonts[0]))
goto out; goto out;
@ -827,6 +849,15 @@ out:
cnd_signal(&term.kbd.repeat.cond); cnd_signal(&term.kbd.repeat.cond);
mtx_unlock(&term.kbd.repeat.mutex); mtx_unlock(&term.kbd.repeat.mutex);
mtx_lock(&term.render.workers.lock);
assert(tll_length(term.render.workers.queue) == 0);
for (size_t i = 0; i < term.render.workers.count; i++) {
sem_post(&term.render.workers.start);
tll_push_back(term.render.workers.queue, -2);
}
cnd_broadcast(&term.render.workers.cond);
mtx_unlock(&term.render.workers.lock);
shm_fini(); shm_fini();
if (term.render.frame_callback != NULL) if (term.render.frame_callback != NULL)
wl_callback_destroy(term.render.frame_callback); wl_callback_destroy(term.render.frame_callback);
@ -910,6 +941,17 @@ out:
thrd_join(keyboard_repeater_id, NULL); thrd_join(keyboard_repeater_id, NULL);
cnd_destroy(&term.kbd.repeat.cond); cnd_destroy(&term.kbd.repeat.cond);
mtx_destroy(&term.kbd.repeat.mutex); mtx_destroy(&term.kbd.repeat.mutex);
for (size_t i = 0; i < term.render.workers.count; i++)
thrd_join(term.render.workers.threads[i], NULL);
free(term.render.workers.threads);
cnd_destroy(&term.render.workers.cond);
mtx_destroy(&term.render.workers.lock);
sem_destroy(&term.render.workers.start);
sem_destroy(&term.render.workers.done);
assert(tll_length(term.render.workers.queue) == 0);
tll_free(term.render.workers.queue);
close(term.kbd.repeat.pipe_read_fd); close(term.kbd.repeat.pipe_read_fd);
close(term.kbd.repeat.pipe_write_fd); close(term.kbd.repeat.pipe_write_fd);

199
render.c
View file

@ -76,45 +76,52 @@ gseq_flush(struct terminal *term, struct buffer *buf)
} }
static void static void
draw_underline(const struct terminal *term, struct buffer *buf, draw_underline(const struct terminal *term, struct buffer *buf, size_t buf_idx,
const struct font *font, struct rgb color, double x, double y) const struct font *font, struct rgb color, double x, double y)
{ {
//const struct font *font = attrs_to_font(term, &cell->attrs); //const struct font *font = attrs_to_font(term, &cell->attrs);
double baseline = y + term->fextents.height - term->fextents.descent; double baseline = y + term->fextents.height - term->fextents.descent;
double width = font->underline.thickness; double width = font->underline.thickness;
double y_under = baseline - font->underline.position - width / 2.; double y_under = baseline - font->underline.position - width / 2.;
cairo_t *cr = buf->cairo[buf_idx];
cairo_set_source_rgb(buf->cairo, color.r, color.g, color.b); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_line_width(buf->cairo, width); cairo_set_source_rgb(cr, color.r, color.g, color.b);
cairo_move_to(buf->cairo, x, round(y_under) + 0.5); cairo_set_line_width(cr, width);
cairo_rel_line_to(buf->cairo, term->cell_width, 0); cairo_move_to(cr, x, round(y_under) + 0.5);
cairo_stroke(buf->cairo); cairo_rel_line_to(cr, term->cell_width, 0);
cairo_stroke(cr);
} }
static void static void
draw_bar(const struct terminal *term, struct buffer *buf, struct rgb color, draw_bar(const struct terminal *term, struct buffer *buf, size_t buf_idx,
double x, double y) struct rgb color, double x, double y)
{ {
cairo_set_source_rgb(buf->cairo, color.r, color.g, color.b); cairo_t *cr = buf->cairo[buf_idx];
cairo_set_line_width(buf->cairo, 1.0);
cairo_move_to(buf->cairo, x + 0.5, y); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_rel_line_to(buf->cairo, 0, term->cell_height); cairo_set_source_rgb(cr, color.r, color.g, color.b);
cairo_stroke(buf->cairo); cairo_set_line_width(cr, 1.0);
cairo_move_to(cr, x + 0.5, y);
cairo_rel_line_to(cr, 0, term->cell_height);
cairo_stroke(cr);
} }
static void static void
draw_strikeout(const struct terminal *term, struct buffer *buf, draw_strikeout(const struct terminal *term, struct buffer *buf, size_t buf_idx,
const struct font *font, struct rgb color, double x, double y) const struct font *font, struct rgb color, double x, double y)
{ {
double baseline = y + term->fextents.height - term->fextents.descent; double baseline = y + term->fextents.height - term->fextents.descent;
double width = font->strikeout.thickness; double width = font->strikeout.thickness;
double y_strike = baseline - font->strikeout.position - width / 2.; double y_strike = baseline - font->strikeout.position - width / 2.;
cairo_t *cr = buf->cairo[buf_idx];
cairo_set_source_rgb(buf->cairo, color.r, color.g, color.b); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_line_width(buf->cairo, width); cairo_set_source_rgb(cr, color.r, color.g, color.b);
cairo_move_to(buf->cairo, x, round(y_strike) + 0.5); cairo_set_line_width(cr, width);
cairo_rel_line_to(buf->cairo, term->cell_width, 0); cairo_move_to(cr, x, round(y_strike) + 0.5);
cairo_stroke(buf->cairo); cairo_rel_line_to(cr, term->cell_width, 0);
cairo_stroke(cr);
} }
static bool static bool
@ -166,9 +173,10 @@ arm_blink_timer(struct terminal *term)
} }
static void static void
render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, render_cell(struct terminal *term, struct buffer *buf, size_t buf_idx,
int col, int row, bool has_cursor) const struct cell *cell, int col, int row, bool has_cursor)
{ {
cairo_t *cr = buf->cairo[buf_idx];
double width = term->cell_width; double width = term->cell_width;
double height = term->cell_height; double height = term->cell_height;
double x = col * width; double x = col * width;
@ -208,18 +216,19 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
} }
/* Background */ /* Background */
cairo_set_source_rgb(buf->cairo, bg.r, bg.g, bg.b); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(buf->cairo, x, y, width, height); cairo_set_source_rgb(cr, bg.r, bg.g, bg.b);
cairo_fill(buf->cairo); cairo_rectangle(cr, x, y, width, height);
cairo_fill(cr);
/* Non-block cursors */ /* Non-block cursors */
if (has_cursor) { if (has_cursor) {
struct rgb cursor_color = color_hex_to_rgb(term->cursor_color.cursor); struct rgb cursor_color = color_hex_to_rgb(term->cursor_color.cursor);
if (term->cursor_style == CURSOR_BAR) if (term->cursor_style == CURSOR_BAR)
draw_bar(term, buf, cursor_color, x, y); draw_bar(term, buf, buf_idx, cursor_color, x, y);
else if (term->cursor_style == CURSOR_UNDERLINE) else if (term->cursor_style == CURSOR_UNDERLINE)
draw_underline( draw_underline(
term, buf, attrs_to_font(term, &cell->attrs), cursor_color, x, y); term, buf, buf_idx, attrs_to_font(term, &cell->attrs), cursor_color, x, y);
} }
if (cell->attrs.blink && !term->blink.active) { if (cell->attrs.blink && !term->blink.active) {
@ -232,10 +241,10 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
/* Underline */ /* Underline */
if (cell->attrs.underline) if (cell->attrs.underline)
draw_underline(term, buf, attrs_to_font(term, &cell->attrs), fg, x, y); draw_underline(term, buf, buf_idx, attrs_to_font(term, &cell->attrs), fg, x, y);
if (cell->attrs.strikethrough) if (cell->attrs.strikethrough)
draw_strikeout(term, buf, attrs_to_font(term, &cell->attrs), fg, x, y); draw_strikeout(term, buf, buf_idx, attrs_to_font(term, &cell->attrs), fg, x, y);
/* /*
* cairo_show_glyphs() apparently works *much* faster when * cairo_show_glyphs() apparently works *much* faster when
@ -268,15 +277,25 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
struct glyph _glyph; struct glyph _glyph;
if (glyph == NULL) { if (glyph == NULL) {
if (!font_glyph_for_utf8(font, cell->c, &_glyph)) if (!font_glyph_for_utf8(font, cell->c, &_glyph)) {
LOG_ERR("FAILED: %.4s", cell->c);
return; return;
}
glyph = &_glyph; glyph = &_glyph;
} }
assert(glyph != NULL); assert(glyph != NULL);
cairo_set_source_rgb(buf->cairo, fg.r, fg.g, fg.b); cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER); cairo_set_source_rgb(cr, fg.r, fg.g, fg.b);
cairo_mask_surface(buf->cairo, glyph->surf, x + glyph->left, y + term->fextents.ascent - glyph->top);
#if 0
cairo_surface_t *surf = cairo_image_surface_create_for_data(
glyph->data, glyph->format, glyph->width, glyph->height, glyph->stride);
cairo_mask_surface(cr, surf, x + glyph->left, y + term->fextents.ascent - glyph->top);
cairo_surface_destroy(surf);
#else
cairo_mask_surface(cr, glyph->surf, x + glyph->left, y + term->fextents.ascent - glyph->top);
#endif
if (glyph == &_glyph) { if (glyph == &_glyph) {
cairo_surface_destroy(_glyph.surf); cairo_surface_destroy(_glyph.surf);
@ -303,11 +322,11 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
buf->size); buf->size);
if (height > 0) { if (height > 0) {
cairo_surface_flush(buf->cairo_surface); cairo_surface_flush(buf->cairo_surface[0]);
uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface); uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface[0]);
memmove(raw + dst_y * stride, raw + src_y * stride, height * stride); memmove(raw + dst_y * stride, raw + src_y * stride, height * stride);
cairo_surface_mark_dirty(buf->cairo_surface); cairo_surface_mark_dirty(buf->cairo_surface[0]);
wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height); wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height);
} }
@ -332,26 +351,74 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf,
buf->size); buf->size);
if (height > 0) { if (height > 0) {
cairo_surface_flush(buf->cairo_surface); cairo_surface_flush(buf->cairo_surface[0]);
uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface); uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface[0]);
memmove(raw + dst_y * stride, raw + src_y * stride, height * stride); memmove(raw + dst_y * stride, raw + src_y * stride, height * stride);
cairo_surface_mark_dirty(buf->cairo_surface); cairo_surface_mark_dirty(buf->cairo_surface[0]);
wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height); wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height);
} }
} }
static void static void
render_row(struct terminal *term, struct buffer *buf, struct row *row, int row_no) render_row(struct terminal *term, struct buffer *buf, size_t buf_idx, struct row *row, int row_no)
{ {
for (int col = 0; col < term->cols; col++) for (int col = 0; col < term->cols; col++)
render_cell(term, buf, &row->cells[col], col, row_no, false); render_cell(term, buf, buf_idx, &row->cells[col], col, row_no, false);
#if 0
wl_surface_damage_buffer( wl_surface_damage_buffer(
term->wl.surface, term->wl.surface,
0, row_no * term->cell_height, 0, row_no * term->cell_height,
term->width, term->cell_height); term->width, term->cell_height);
#endif
}
int
render_worker_thread(void *_ctx)
{
struct render_worker_context *ctx = _ctx;
struct terminal *term = ctx->term;
const int my_id = ctx->my_id;
sem_t *start = &term->render.workers.start;
sem_t *done = &term->render.workers.done;
mtx_t *lock = &term->render.workers.lock;
cnd_t *cond = &term->render.workers.cond;
while (true) {
sem_wait(start);
struct buffer *buf = term->render.workers.buf;
bool frame_done = false;
while (!frame_done) {
mtx_lock(lock);
while (tll_length(term->render.workers.queue) == 0)
cnd_wait(cond, lock);
int row_no = tll_pop_front(term->render.workers.queue);
mtx_unlock(lock);
switch (row_no) {
default:
assert(buf != NULL);
render_row(term, buf, my_id, grid_row_in_view(term->grid, row_no), row_no);
break;
case -1:
frame_done = true;
sem_post(done);
break;
case -2:
return 0;
}
}
};
return -1;
} }
static void frame_callback( static void frame_callback(
@ -374,8 +441,8 @@ grid_render(struct terminal *term)
assert(term->width > 0); assert(term->width > 0);
assert(term->height > 0); assert(term->height > 0);
struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height); struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height, 1 + term->render.workers.count);
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE); cairo_set_operator(buf->cairo[0], CAIRO_OPERATOR_SOURCE);
gseq.g = gseq.glyphs; gseq.g = gseq.glyphs;
gseq.count = 0; gseq.count = 0;
@ -385,7 +452,7 @@ grid_render(struct terminal *term)
/* Erase old cursor (if we rendered a cursor last time) */ /* Erase old cursor (if we rendered a cursor last time) */
if (term->render.last_cursor.cell != NULL) { if (term->render.last_cursor.cell != NULL) {
render_cell( render_cell(
term, buf, term, buf, 0,
term->render.last_cursor.cell, term->render.last_cursor.cell,
term->render.last_cursor.in_view.col, term->render.last_cursor.in_view.col,
term->render.last_cursor.in_view.row, false); term->render.last_cursor.in_view.row, false);
@ -424,11 +491,11 @@ grid_render(struct terminal *term)
uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg; uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg;
struct rgb bg = color_hex_to_rgb(_bg); struct rgb bg = color_hex_to_rgb(_bg);
cairo_set_source_rgb(buf->cairo, bg.r, bg.g, bg.b); cairo_set_source_rgb(buf->cairo[0], bg.r, bg.g, bg.b);
cairo_rectangle(buf->cairo, rmargin, 0, rmargin_width, term->height); cairo_rectangle(buf->cairo[0], rmargin, 0, rmargin_width, term->height);
cairo_rectangle(buf->cairo, 0, bmargin, term->width, bmargin_height); cairo_rectangle(buf->cairo[0], 0, bmargin, term->width, bmargin_height);
cairo_fill(buf->cairo); cairo_fill(buf->cairo[0]);
wl_surface_damage_buffer( wl_surface_damage_buffer(
term->wl.surface, rmargin, 0, rmargin_width, term->height); term->wl.surface, rmargin, 0, rmargin_width, term->height);
@ -456,20 +523,38 @@ grid_render(struct terminal *term)
tll_remove(term->grid->scroll_damage, it); tll_remove(term->grid->scroll_damage, it);
} }
term->render.workers.buf = buf;
for (size_t i = 0; i < term->render.workers.count; i++)
sem_post(&term->render.workers.start);
assert(tll_length(term->render.workers.queue) == 0);
for (int r = 0; r < term->rows; r++) { for (int r = 0; r < term->rows; r++) {
struct row *row = grid_row_in_view(term->grid, r); struct row *row = grid_row_in_view(term->grid, r);
if (!row->dirty) if (!row->dirty)
continue; continue;
//LOG_WARN("rendering line: %d", r); mtx_lock(&term->render.workers.lock);
tll_push_back(term->render.workers.queue, r);
cnd_signal(&term->render.workers.cond);
mtx_unlock(&term->render.workers.lock);
row->dirty = false; row->dirty = false;
all_clean = false; all_clean = false;
render_row(term, buf, row, r); wl_surface_damage_buffer(
term->wl.surface,
0, r * term->cell_height,
term->width, term->cell_height);
} }
mtx_lock(&term->render.workers.lock);
for (size_t i = 0; i < term->render.workers.count; i++)
tll_push_back(term->render.workers.queue, -1);
cnd_broadcast(&term->render.workers.cond);
mtx_unlock(&term->render.workers.lock);
if (term->blink.active) { if (term->blink.active) {
/* Check if there are still any visible blinking cells */ /* Check if there are still any visible blinking cells */
bool none_is_blinking = true; bool none_is_blinking = true;
@ -516,6 +601,10 @@ grid_render(struct terminal *term)
cursor_is_visible = true; cursor_is_visible = true;
} }
for (size_t i = 0; i < term->render.workers.count; i++)
sem_wait(&term->render.workers.done);
term->render.workers.buf = NULL;
if (cursor_is_visible && !term->hide_cursor) { if (cursor_is_visible && !term->hide_cursor) {
/* Remember cursor coordinates so that we can erase it next /* Remember cursor coordinates so that we can erase it next
* time. Note that we need to re-align it against the view. */ * time. Note that we need to re-align it against the view. */
@ -531,7 +620,7 @@ grid_render(struct terminal *term)
term->render.last_cursor.cell = &row->cells[term->cursor.col]; term->render.last_cursor.cell = &row->cells[term->cursor.col];
render_cell( render_cell(
term, buf, term->render.last_cursor.cell, term, buf, 0, term->render.last_cursor.cell,
term->cursor.col, view_aligned_row, true); term->cursor.col, view_aligned_row, true);
wl_surface_damage_buffer( wl_surface_damage_buffer(
@ -549,10 +638,10 @@ grid_render(struct terminal *term)
} }
if (term->flash.active) { if (term->flash.active) {
cairo_set_source_rgba(buf->cairo, 1.0, 1.0, 0.0, 0.5); cairo_set_source_rgba(buf->cairo[0], 1.0, 1.0, 0.0, 0.5);
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER); cairo_set_operator(buf->cairo[0], CAIRO_OPERATOR_OVER);
cairo_rectangle(buf->cairo, 0, 0, term->width, term->height); cairo_rectangle(buf->cairo[0], 0, 0, term->width, term->height);
cairo_fill(buf->cairo); cairo_fill(buf->cairo[0]);
wl_surface_damage_buffer( wl_surface_damage_buffer(
term->wl.surface, 0, 0, term->width, term->height); term->wl.surface, 0, 0, term->width, term->height);
@ -561,7 +650,7 @@ grid_render(struct terminal *term)
assert(term->grid->offset >= 0 && term->grid->offset < term->grid->num_rows); assert(term->grid->offset >= 0 && term->grid->offset < term->grid->num_rows);
assert(term->grid->view >= 0 && term->grid->view < term->grid->num_rows); assert(term->grid->view >= 0 && term->grid->view < term->grid->num_rows);
cairo_surface_flush(buf->cairo_surface); cairo_surface_flush(buf->cairo_surface[0]);
wl_surface_attach(term->wl.surface, buf->wl_buf, 0, 0); wl_surface_attach(term->wl.surface, buf->wl_buf, 0, 0);
assert(term->render.frame_callback == NULL); assert(term->render.frame_callback == NULL);

View file

@ -10,3 +10,9 @@ void render_resize(struct terminal *term, int width, int height);
void render_set_title(struct terminal *term, const char *title); void render_set_title(struct terminal *term, const char *title);
void render_update_cursor_surface(struct terminal *term); void render_update_cursor_surface(struct terminal *term);
void render_refresh(struct terminal *term); void render_refresh(struct terminal *term);
struct render_worker_context {
int my_id;
struct terminal *term;
};
int render_worker_thread(void *_ctx);

69
shm.c
View file

@ -27,8 +27,10 @@ static const struct wl_buffer_listener buffer_listener = {
}; };
struct buffer * struct buffer *
shm_get_buffer(struct wl_shm *shm, int width, int height) shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies)
{ {
assert(copies >= 1);
tll_foreach(buffers, it) { tll_foreach(buffers, it) {
if (it->item.width != width || it->item.height != height) if (it->item.width != width || it->item.height != height)
continue; continue;
@ -57,8 +59,8 @@ shm_get_buffer(struct wl_shm *shm, int width, int height)
struct wl_shm_pool *pool = NULL; struct wl_shm_pool *pool = NULL;
struct wl_buffer *buf = NULL; struct wl_buffer *buf = NULL;
cairo_surface_t *cairo_surface = NULL; cairo_surface_t **cairo_surface = NULL;
cairo_t *cairo = NULL; cairo_t **cairo = NULL;
/* Backing memory for SHM */ /* Backing memory for SHM */
pool_fd = memfd_create("f00sel-wayland-shm-buffer-pool", MFD_CLOEXEC); pool_fd = memfd_create("f00sel-wayland-shm-buffer-pool", MFD_CLOEXEC);
@ -99,19 +101,25 @@ shm_get_buffer(struct wl_shm *shm, int width, int height)
close(pool_fd); pool_fd = -1; close(pool_fd); pool_fd = -1;
/* Create a cairo surface around the mmapped memory */ /* Create a cairo surface around the mmapped memory */
cairo_surface = cairo_image_surface_create_for_data( cairo_surface = calloc(copies, sizeof(cairo_surface[0]));
mmapped, CAIRO_FORMAT_ARGB32, width, height, stride); cairo = calloc(copies, sizeof(cairo[0]));
if (cairo_surface_status(cairo_surface) != CAIRO_STATUS_SUCCESS) {
LOG_ERR("failed to create cairo surface: %s",
cairo_status_to_string(cairo_surface_status(cairo_surface)));
goto err;
}
cairo = cairo_create(cairo_surface); for (size_t i = 0; i < copies; i++) {
if (cairo_status(cairo) != CAIRO_STATUS_SUCCESS) { cairo_surface[i] = cairo_image_surface_create_for_data(
LOG_ERR("failed to create cairo context: %s", mmapped, CAIRO_FORMAT_ARGB32, width, height, stride);
cairo_status_to_string(cairo_status(cairo)));
goto err; if (cairo_surface_status(cairo_surface[i]) != CAIRO_STATUS_SUCCESS) {
LOG_ERR("failed to create cairo surface: %s",
cairo_status_to_string(cairo_surface_status(cairo_surface[i])));
goto err;
}
cairo[i] = cairo_create(cairo_surface[i]);
if (cairo_status(cairo[i]) != CAIRO_STATUS_SUCCESS) {
LOG_ERR("failed to create cairo context: %s",
cairo_status_to_string(cairo_status(cairo[i])));
goto err;
}
} }
/* Push to list of available buffers, but marked as 'busy' */ /* Push to list of available buffers, but marked as 'busy' */
@ -124,6 +132,7 @@ shm_get_buffer(struct wl_shm *shm, int width, int height)
.size = size, .size = size,
.mmapped = mmapped, .mmapped = mmapped,
.wl_buf = buf, .wl_buf = buf,
.copies = copies,
.cairo_surface = cairo_surface, .cairo_surface = cairo_surface,
.cairo = cairo} .cairo = cairo}
) )
@ -134,10 +143,18 @@ shm_get_buffer(struct wl_shm *shm, int width, int height)
return ret; return ret;
err: err:
if (cairo != NULL) if (cairo != NULL) {
cairo_destroy(cairo); for (size_t i = 0; i < copies; i++)
if (cairo_surface != NULL) if (cairo[i] != NULL)
cairo_surface_destroy(cairo_surface); cairo_destroy(cairo[i]);
free(cairo);
}
if (cairo_surface != NULL) {
for (size_t i = 0; i < copies; i++)
if (cairo_surface[i] != NULL)
cairo_surface_destroy(cairo_surface[i]);
free(cairo_surface);
}
if (buf != NULL) if (buf != NULL)
wl_buffer_destroy(buf); wl_buffer_destroy(buf);
if (pool != NULL) if (pool != NULL)
@ -156,8 +173,18 @@ shm_fini(void)
tll_foreach(buffers, it) { tll_foreach(buffers, it) {
struct buffer *buf = &it->item; struct buffer *buf = &it->item;
cairo_destroy(buf->cairo); if (buf->cairo != NULL) {
cairo_surface_destroy(buf->cairo_surface); for (size_t i = 0; i < buf->copies; i++)
if (buf->cairo[i] != NULL)
cairo_destroy(buf->cairo[i]);
free(buf->cairo);
}
if (buf->cairo_surface != NULL) {
for (size_t i = 0; i < buf->copies; i++)
if (buf->cairo_surface[i] != NULL)
cairo_surface_destroy(buf->cairo_surface[i]);
free(buf->cairo_surface);
}
wl_buffer_destroy(buf->wl_buf); wl_buffer_destroy(buf->wl_buf);
munmap(buf->mmapped, buf->size); munmap(buf->mmapped, buf->size);

7
shm.h
View file

@ -16,9 +16,10 @@ struct buffer {
struct wl_buffer *wl_buf; struct wl_buffer *wl_buf;
cairo_surface_t *cairo_surface; size_t copies;
cairo_t *cairo; cairo_surface_t **cairo_surface;
cairo_t **cairo;
}; };
struct buffer *shm_get_buffer(struct wl_shm *shm, int width, int height); struct buffer *shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies);
void shm_fini(void); void shm_fini(void);

View file

@ -5,9 +5,11 @@
#include <stddef.h> #include <stddef.h>
#include <threads.h> #include <threads.h>
#include <semaphore.h>
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include FT_LCD_FILTER_H
#include <cairo.h> #include <cairo.h>
#include <wayland-client.h> #include <wayland-client.h>
@ -211,6 +213,11 @@ struct glyph {
cairo_surface_t *surf; cairo_surface_t *surf;
int left; int left;
int top; int top;
int format;
int width;
int height;
int stride;
}; };
struct font { struct font {
@ -341,6 +348,17 @@ struct terminal {
struct { struct {
struct wl_callback *frame_callback; struct wl_callback *frame_callback;
struct {
size_t count;
sem_t start;
sem_t done;
cnd_t cond;
mtx_t lock;
tll(int) queue;
thrd_t *threads;
struct buffer *buf;
} workers;
/* Last rendered cursor position */ /* Last rendered cursor position */
struct { struct {
struct coord actual; /* Absolute */ struct coord actual; /* Absolute */