diff --git a/config.c b/config.c index 707f7d93..dda3c635 100644 --- a/config.c +++ b/config.c @@ -107,26 +107,28 @@ get_config_path(void) } 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) return false; errno = 0; 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); return false; } - if (*end != '\0') { - LOG_ERR("%s:%d: invalid color: %s", path, lineno, s); - return false; - } - - *color = res & 0xffffff; + *color = value & 0xffffff; return true; } @@ -149,6 +151,15 @@ parse_section_main(const char *key, const char *value, struct config *conf, 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 { LOG_WARN("%s:%u: invalid key: %s", path, lineno, key); return false; @@ -427,6 +438,8 @@ config_load(struct config *conf) .cursor = 0, }, }, + + .render_worker_count = sysconf(_SC_NPROCESSORS_ONLN), }; char *path = get_config_path(); diff --git a/config.h b/config.h index 68d6f0a1..e965f142 100644 --- a/config.h +++ b/config.h @@ -24,6 +24,8 @@ struct config { uint32_t cursor; } color; } cursor; + + size_t render_worker_count; }; bool config_load(struct config *conf); diff --git a/main.c b/main.c index 7d0fa355..0368c687 100644 --- a/main.c +++ b/main.c @@ -11,9 +11,9 @@ #include #include +#include #include -#include #include #include #include @@ -388,8 +388,18 @@ main(int argc, char *const *argv) .normal = {.damage = tll_init(), .scroll_damage = tll_init()}, .alt = {.damage = tll_init(), .scroll_damage = tll_init()}, .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 */ term.colors.fg = term.colors.default_fg; term.colors.bg = term.colors.default_bg; @@ -409,6 +419,18 @@ main(int argc, char *const *argv) thrd_t keyboard_repeater_id; 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])) goto out; @@ -827,6 +849,15 @@ out: cnd_signal(&term.kbd.repeat.cond); 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(); if (term.render.frame_callback != NULL) wl_callback_destroy(term.render.frame_callback); @@ -910,6 +941,17 @@ out: thrd_join(keyboard_repeater_id, NULL); cnd_destroy(&term.kbd.repeat.cond); 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_write_fd); diff --git a/render.c b/render.c index cf6c013e..123e5593 100644 --- a/render.c +++ b/render.c @@ -76,45 +76,52 @@ gseq_flush(struct terminal *term, struct buffer *buf) } 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 = attrs_to_font(term, &cell->attrs); double baseline = y + term->fextents.height - term->fextents.descent; double width = font->underline.thickness; 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_line_width(buf->cairo, width); - cairo_move_to(buf->cairo, x, round(y_under) + 0.5); - cairo_rel_line_to(buf->cairo, term->cell_width, 0); - cairo_stroke(buf->cairo); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb(cr, color.r, color.g, color.b); + cairo_set_line_width(cr, width); + cairo_move_to(cr, x, round(y_under) + 0.5); + cairo_rel_line_to(cr, term->cell_width, 0); + cairo_stroke(cr); } static void -draw_bar(const struct terminal *term, struct buffer *buf, struct rgb color, - double x, double y) +draw_bar(const struct terminal *term, struct buffer *buf, size_t buf_idx, + struct rgb color, double x, double y) { - cairo_set_source_rgb(buf->cairo, color.r, color.g, color.b); - cairo_set_line_width(buf->cairo, 1.0); - cairo_move_to(buf->cairo, x + 0.5, y); - cairo_rel_line_to(buf->cairo, 0, term->cell_height); - cairo_stroke(buf->cairo); + cairo_t *cr = buf->cairo[buf_idx]; + + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb(cr, color.r, color.g, color.b); + 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 -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) { double baseline = y + term->fextents.height - term->fextents.descent; double width = font->strikeout.thickness; 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_line_width(buf->cairo, width); - cairo_move_to(buf->cairo, x, round(y_strike) + 0.5); - cairo_rel_line_to(buf->cairo, term->cell_width, 0); - cairo_stroke(buf->cairo); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb(cr, color.r, color.g, color.b); + cairo_set_line_width(cr, width); + cairo_move_to(cr, x, round(y_strike) + 0.5); + cairo_rel_line_to(cr, term->cell_width, 0); + cairo_stroke(cr); } static bool @@ -166,9 +173,10 @@ arm_blink_timer(struct terminal *term) } static void -render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, - int col, int row, bool has_cursor) +render_cell(struct terminal *term, struct buffer *buf, size_t buf_idx, + const struct cell *cell, int col, int row, bool has_cursor) { + cairo_t *cr = buf->cairo[buf_idx]; double width = term->cell_width; double height = term->cell_height; double x = col * width; @@ -208,18 +216,19 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, } /* Background */ - cairo_set_source_rgb(buf->cairo, bg.r, bg.g, bg.b); - cairo_rectangle(buf->cairo, x, y, width, height); - cairo_fill(buf->cairo); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb(cr, bg.r, bg.g, bg.b); + cairo_rectangle(cr, x, y, width, height); + cairo_fill(cr); /* Non-block cursors */ if (has_cursor) { struct rgb cursor_color = color_hex_to_rgb(term->cursor_color.cursor); 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) 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) { @@ -232,10 +241,10 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, /* 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) - 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 @@ -268,15 +277,25 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, struct glyph _glyph; 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; + } glyph = &_glyph; } assert(glyph != NULL); - cairo_set_source_rgb(buf->cairo, fg.r, fg.g, fg.b); - cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER); - cairo_mask_surface(buf->cairo, glyph->surf, x + glyph->left, y + term->fextents.ascent - glyph->top); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb(cr, fg.r, fg.g, fg.b); + +#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) { cairo_surface_destroy(_glyph.surf); @@ -303,11 +322,11 @@ grid_render_scroll(struct terminal *term, struct buffer *buf, buf->size); if (height > 0) { - cairo_surface_flush(buf->cairo_surface); - uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface); + cairo_surface_flush(buf->cairo_surface[0]); + uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface[0]); 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); } @@ -332,26 +351,74 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf, buf->size); if (height > 0) { - cairo_surface_flush(buf->cairo_surface); - uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface); + cairo_surface_flush(buf->cairo_surface[0]); + uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface[0]); 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); } } 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++) - 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( term->wl.surface, 0, row_no * 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( @@ -374,8 +441,8 @@ grid_render(struct terminal *term) assert(term->width > 0); assert(term->height > 0); - struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height); - cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE); + struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height, 1 + term->render.workers.count); + cairo_set_operator(buf->cairo[0], CAIRO_OPERATOR_SOURCE); gseq.g = gseq.glyphs; gseq.count = 0; @@ -385,7 +452,7 @@ grid_render(struct terminal *term) /* Erase old cursor (if we rendered a cursor last time) */ if (term->render.last_cursor.cell != NULL) { render_cell( - term, buf, + term, buf, 0, term->render.last_cursor.cell, term->render.last_cursor.in_view.col, 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; 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, bmargin, term->width, bmargin_height); - cairo_fill(buf->cairo); + cairo_rectangle(buf->cairo[0], rmargin, 0, rmargin_width, term->height); + cairo_rectangle(buf->cairo[0], 0, bmargin, term->width, bmargin_height); + cairo_fill(buf->cairo[0]); wl_surface_damage_buffer( 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); } + 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++) { struct row *row = grid_row_in_view(term->grid, r); if (!row->dirty) 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; 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) { /* Check if there are still any visible blinking cells */ bool none_is_blinking = true; @@ -516,6 +601,10 @@ grid_render(struct terminal *term) 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) { /* Remember cursor coordinates so that we can erase it next * 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]; render_cell( - term, buf, term->render.last_cursor.cell, + term, buf, 0, term->render.last_cursor.cell, term->cursor.col, view_aligned_row, true); wl_surface_damage_buffer( @@ -549,10 +638,10 @@ grid_render(struct terminal *term) } if (term->flash.active) { - cairo_set_source_rgba(buf->cairo, 1.0, 1.0, 0.0, 0.5); - cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER); - cairo_rectangle(buf->cairo, 0, 0, term->width, term->height); - cairo_fill(buf->cairo); + cairo_set_source_rgba(buf->cairo[0], 1.0, 1.0, 0.0, 0.5); + cairo_set_operator(buf->cairo[0], CAIRO_OPERATOR_OVER); + cairo_rectangle(buf->cairo[0], 0, 0, term->width, term->height); + cairo_fill(buf->cairo[0]); wl_surface_damage_buffer( 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->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); assert(term->render.frame_callback == NULL); diff --git a/render.h b/render.h index fd923e7d..0b7a40ca 100644 --- a/render.h +++ b/render.h @@ -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_update_cursor_surface(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); diff --git a/shm.c b/shm.c index dd85ef3f..ca078544 100644 --- a/shm.c +++ b/shm.c @@ -27,8 +27,10 @@ static const struct wl_buffer_listener buffer_listener = { }; 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) { if (it->item.width != width || it->item.height != height) continue; @@ -57,8 +59,8 @@ shm_get_buffer(struct wl_shm *shm, int width, int height) struct wl_shm_pool *pool = NULL; struct wl_buffer *buf = NULL; - cairo_surface_t *cairo_surface = NULL; - cairo_t *cairo = NULL; + cairo_surface_t **cairo_surface = NULL; + cairo_t **cairo = NULL; /* Backing memory for SHM */ 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; /* Create a cairo surface around the mmapped memory */ - cairo_surface = cairo_image_surface_create_for_data( - mmapped, CAIRO_FORMAT_ARGB32, width, height, stride); - 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_surface = calloc(copies, sizeof(cairo_surface[0])); + cairo = calloc(copies, sizeof(cairo[0])); - cairo = cairo_create(cairo_surface); - if (cairo_status(cairo) != CAIRO_STATUS_SUCCESS) { - LOG_ERR("failed to create cairo context: %s", - cairo_status_to_string(cairo_status(cairo))); - goto err; + for (size_t i = 0; i < copies; i++) { + cairo_surface[i] = cairo_image_surface_create_for_data( + mmapped, CAIRO_FORMAT_ARGB32, width, height, stride); + + 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' */ @@ -124,6 +132,7 @@ shm_get_buffer(struct wl_shm *shm, int width, int height) .size = size, .mmapped = mmapped, .wl_buf = buf, + .copies = copies, .cairo_surface = cairo_surface, .cairo = cairo} ) @@ -134,10 +143,18 @@ shm_get_buffer(struct wl_shm *shm, int width, int height) return ret; err: - if (cairo != NULL) - cairo_destroy(cairo); - if (cairo_surface != NULL) - cairo_surface_destroy(cairo_surface); + if (cairo != NULL) { + for (size_t i = 0; i < copies; i++) + if (cairo[i] != NULL) + 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) wl_buffer_destroy(buf); if (pool != NULL) @@ -156,8 +173,18 @@ shm_fini(void) tll_foreach(buffers, it) { struct buffer *buf = &it->item; - cairo_destroy(buf->cairo); - cairo_surface_destroy(buf->cairo_surface); + if (buf->cairo != NULL) { + 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); munmap(buf->mmapped, buf->size); diff --git a/shm.h b/shm.h index 35360db6..9982cb8d 100644 --- a/shm.h +++ b/shm.h @@ -16,9 +16,10 @@ struct buffer { struct wl_buffer *wl_buf; - cairo_surface_t *cairo_surface; - cairo_t *cairo; + size_t copies; + 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); diff --git a/terminal.h b/terminal.h index 86b92d17..de359576 100644 --- a/terminal.h +++ b/terminal.h @@ -5,9 +5,11 @@ #include #include +#include #include #include FT_FREETYPE_H +#include FT_LCD_FILTER_H #include #include @@ -211,6 +213,11 @@ struct glyph { cairo_surface_t *surf; int left; int top; + + int format; + int width; + int height; + int stride; }; struct font { @@ -341,6 +348,17 @@ struct terminal { struct { 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 */ struct { struct coord actual; /* Absolute */