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

View file

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

44
main.c
View file

@ -11,9 +11,9 @@
#include <errno.h>
#include <sys/timerfd.h>
#include <sys/sysinfo.h>
#include <freetype/tttables.h>
#include <cairo-ft.h>
#include <wayland-client.h>
#include <wayland-cursor.h>
#include <xdg-shell.h>
@ -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);

199
render.c
View file

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

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

69
shm.c
View file

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

7
shm.h
View file

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

View file

@ -5,9 +5,11 @@
#include <stddef.h>
#include <threads.h>
#include <semaphore.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_LCD_FILTER_H
#include <cairo.h>
#include <wayland-client.h>
@ -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 */