diff --git a/PKGBUILD b/PKGBUILD index b3b4352c..9ddead79 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -9,7 +9,7 @@ makedepends=('meson' 'ninja' 'scdoc') depends=( 'libxkbcommon' 'wayland' - 'freetype2' 'fontconfig' 'cairo') + 'freetype2' 'fontconfig' 'pixman') source=() pkgver() { @@ -25,4 +25,3 @@ build() { package() { DESTDIR="${pkgdir}/" ninja install } - diff --git a/README.md b/README.md index d8656f0d..e338c51a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ * fontconfig * freetype -* cairo +* pixman * wayland (_client_ and _cursor_ libraries) * wayland protocols * xkbcommon diff --git a/config.c b/config.c index 2bb04a65..eb9031ed 100644 --- a/config.c +++ b/config.c @@ -224,7 +224,7 @@ parse_section_colors(const char *key, const char *value, struct config *conf, return false; } - conf->colors.alpha = alpha; + conf->colors.alpha = alpha * 65535.; return true; } @@ -466,7 +466,7 @@ config_load(struct config *conf) default_bright[6], default_bright[7], }, - .alpha = 1., + .alpha = 0xffff, }, .cursor = { diff --git a/config.h b/config.h index cc17c8e2..e7158688 100644 --- a/config.h +++ b/config.h @@ -18,7 +18,7 @@ struct config { uint32_t bg; uint32_t regular[8]; uint32_t bright[8]; - double alpha; + uint16_t alpha; } colors; struct { diff --git a/font.c b/font.c index ca9d4464..df1581ac 100644 --- a/font.c +++ b/font.c @@ -367,19 +367,26 @@ glyph_for_wchar(struct font *font, wchar_t wc, struct glyph *glyph) if (bitmap->width == 0) goto err; - /* Map FT pixel format to cairo surface format */ - cairo_format_t cr_format = - bitmap->pixel_mode == FT_PIXEL_MODE_MONO ? CAIRO_FORMAT_A1 : - bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ? CAIRO_FORMAT_A8 : - bitmap->pixel_mode == FT_PIXEL_MODE_BGRA ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_INVALID; + /* Map FT pixel format to pixman format */ + pixman_format_code_t pix_format = + bitmap->pixel_mode == FT_PIXEL_MODE_MONO ? PIXMAN_a1 : + bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ? PIXMAN_a8 : + bitmap->pixel_mode == FT_PIXEL_MODE_BGRA ? PIXMAN_a8r8g8b8 : -1; - int stride = cairo_format_stride_for_width(cr_format, bitmap->width); + /* Calculate stride. Copied from cairoint.h:CAIRO_STRIDE_FOR_WIDTH_BPP */ + int bpp = + pix_format == PIXMAN_a1 ? 1 : + pix_format == PIXMAN_a8 ? 8 : + pix_format == PIXMAN_a8r8g8b8 ? 32 : -1; + assert(bpp >= 0); + + int stride = (((bpp * bitmap->width + 7) / 8 + 4 - 1) & -4); assert(stride >= bitmap->pitch); uint8_t *data = malloc(bitmap->rows * stride); assert(bitmap->pitch >= 0); - /* Convert FT bitmap to cairo surface (well, the backing image) */ + /* Convert FT bitmap to pixman image */ switch (bitmap->pixel_mode) { case FT_PIXEL_MODE_MONO: for (size_t r = 0; r < bitmap->rows; r++) { @@ -413,22 +420,31 @@ glyph_for_wchar(struct font *font, wchar_t wc, struct glyph *glyph) goto err; } - cairo_surface_t *surf = cairo_image_surface_create_for_data( - data, cr_format, bitmap->width, bitmap->rows, stride); + pixman_image_t *pix = pixman_image_create_bits_no_clear( + pix_format, bitmap->width, bitmap->rows, (uint32_t *)data, stride); - if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) { + if (pix == NULL) { free(data); - cairo_surface_destroy(surf); goto err; } + if (font->pixel_size_fixup != 1.) { + struct pixman_transform scale; + pixman_transform_init_scale( + &scale, + pixman_double_to_fixed(1. / font->pixel_size_fixup), + pixman_double_to_fixed(1. / font->pixel_size_fixup)); + pixman_image_set_transform(pix, &scale); + } + *glyph = (struct glyph){ .wc = wc, - .width = wcwidth(wc), - .surf = surf, - .left = font->face->glyph->bitmap_left, - .top = font->face->glyph->bitmap_top, - .pixel_size_fixup = font->pixel_size_fixup, + .cols = wcwidth(wc), + .pix = pix, + .x = font->face->glyph->bitmap_left / font->pixel_size_fixup, + .y = font->face->glyph->bitmap_top * font->pixel_size_fixup, + .width = bitmap->width, + .height = bitmap->rows, .valid = true, }; @@ -506,10 +522,8 @@ font_destroy(struct font *font) if (!it->item.valid) continue; - cairo_surface_flush(it->item.surf); - void *image = cairo_image_surface_get_data(it->item.surf); - - cairo_surface_destroy(it->item.surf); + void *image = pixman_image_get_data(it->item.pix); + pixman_image_unref(it->item.pix); free(image); } diff --git a/font.h b/font.h index 1450f5f9..97c3ec5f 100644 --- a/font.h +++ b/font.h @@ -7,7 +7,7 @@ #include FT_FREETYPE_H #include FT_LCD_FILTER_H #include -#include +#include #include "tllist.h" //#include "terminal.h" @@ -16,13 +16,14 @@ typedef tll(const char *) font_list_t; struct glyph { wchar_t wc; + int cols; + + pixman_image_t *pix; + int x; + int y; int width; + int height; - cairo_surface_t *surf; - int left; - int top; - - double pixel_size_fixup; bool valid; }; @@ -40,13 +41,13 @@ struct font { double pixel_size_fixup; /* Scale factor - should only be used with ARGB32 glyphs */ struct { - double position; - double thickness; + int position; + int thickness; } underline; struct { - double position; - double thickness; + int position; + int thickness; } strikeout; bool is_fallback; diff --git a/main.c b/main.c index 943a3d32..9f90caf8 100644 --- a/main.c +++ b/main.c @@ -555,8 +555,8 @@ main(int argc, char *const *argv) LOG_DBG("ft: x-scale: %f, height: %f, descent: %f", x_scale, height, descent); - f->underline.position = ft_face->underline_position * x_scale / 64.; - f->underline.thickness = ft_face->underline_thickness * x_scale / 64.; + f->underline.position = round(ft_face->underline_position * x_scale / 64.); + f->underline.thickness = ceil(ft_face->underline_thickness * x_scale / 64.); if (f->underline.position == 0.) { f->underline.position = descent / 2.; @@ -1085,8 +1085,6 @@ out: tll_free(term.render.workers.queue); config_free(conf); - - cairo_debug_reset_static_data(); return ret; } diff --git a/meson.build b/meson.build index 7fb661fc..cc344a87 100644 --- a/meson.build +++ b/meson.build @@ -42,8 +42,9 @@ cc = meson.get_compiler('c') math = cc.find_library('m') threads = dependency('threads') +freetype = dependency('freetype2') fontconfig = dependency('fontconfig') -cairo = dependency('cairo') +pixman = dependency('pixman-1') wayland_protocols = dependency('wayland-protocols') wayland_client = dependency('wayland-client') wayland_cursor = dependency('wayland-cursor') @@ -99,7 +100,7 @@ executable( 'tllist.h', 'vt.c', 'vt.h', wl_proto_src + wl_proto_headers, - dependencies: [threads, math, cairo, fontconfig, wayland_client, wayland_cursor, xkb], + dependencies: [threads, math, freetype, fontconfig, pixman, wayland_client, wayland_cursor, xkb], install: true) custom_target( diff --git a/render.c b/render.c index 5ed69d6e..e2ed46b1 100644 --- a/render.c +++ b/render.c @@ -37,6 +37,25 @@ color_hex_to_rgb(uint32_t color) }; } +static inline pixman_color_t +color_hex_to_pixman_with_alpha(uint32_t color, uint16_t alpha) +{ + int alpha_div = 0xffff / alpha; + return (pixman_color_t){ + .red = ((color >> 16 & 0xff) | (color >> 8 & 0xff00)) / alpha_div, + .green = ((color >> 8 & 0xff) | (color >> 0 & 0xff00)) / alpha_div, + .blue = ((color >> 0 & 0xff) | (color << 8 & 0xff00)) / alpha_div, + .alpha = alpha, + }; +} + +static inline pixman_color_t +color_hex_to_pixman(uint32_t color) +{ + /* Count on the compiler optimizing this */ + return color_hex_to_pixman_with_alpha(color, 0xffff); +} + static inline void color_dim(struct rgb *rgb) { @@ -45,48 +64,50 @@ color_dim(struct rgb *rgb) rgb->b /= 2.; } -static void -draw_underline(const struct terminal *term, cairo_t *cr, const struct font *font, - struct rgb color, double x, double y, int cols) +static inline void +pixman_color_dim(pixman_color_t *color) { - double baseline = y + term->fextents.height - term->fextents.descent; - double width = font->underline.thickness; - double y_under = baseline - font->underline.position - width / 2.; - - 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, cols * term->cell_width, 0); - cairo_stroke(cr); + color->red /= 2; + color->green /= 2; + color->blue /= 2; } static void -draw_bar(const struct terminal *term, cairo_t *cr, struct rgb color, - double x, double y) +draw_bar(const struct terminal *term, pixman_image_t *pix, + const pixman_color_t *color, int x, int y) { - 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); + /* TODO: investigate if this is the best way */ + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, color, + 1, &(pixman_rectangle16_t){x, y, 1, term->cell_height}); } static void -draw_strikeout(const struct terminal *term, cairo_t *cr, const struct font *font, - struct rgb color, double x, double y, int cols) +draw_underline(const struct terminal *term, pixman_image_t *pix, + const struct font *font, + const pixman_color_t *color, int x, int y, int cols) { - double baseline = y + term->fextents.height - term->fextents.descent; - double width = font->strikeout.thickness; - double y_strike = baseline - font->strikeout.position - width / 2.; + int baseline = y + term->fextents.height - term->fextents.descent; + int width = font->underline.thickness; + int y_under = baseline - font->underline.position - width / 2; - 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, cols * term->cell_width, 0); - cairo_stroke(cr); + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, color, + 1, &(pixman_rectangle16_t){x, y_under, cols * term->cell_width, width}); +} + +static void +draw_strikeout(const struct terminal *term, pixman_image_t *pix, + const struct font *font, + const pixman_color_t *color, int x, int y, int cols) +{ + int baseline = y + term->fextents.height - term->fextents.descent; + int width = font->strikeout.thickness; + int y_strike = baseline - font->strikeout.position - width / 2; + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, color, + 1, &(pixman_rectangle16_t){x, y_strike, cols * term->cell_width, width}); } static bool @@ -136,7 +157,7 @@ arm_blink_timer(struct terminal *term) } static int -render_cell(struct terminal *term, cairo_t *cr, +render_cell(struct terminal *term, pixman_image_t *pix, struct cell *cell, int col, int row, bool has_cursor) { if (cell->attrs.clean) @@ -144,10 +165,10 @@ render_cell(struct terminal *term, cairo_t *cr, cell->attrs.clean = 1; - double width = term->cell_width; - double height = term->cell_height; - double x = col * width; - double y = row * height; + int width = term->cell_width; + int height = term->cell_height; + int x = col * width; + int y = row * height; bool block_cursor = has_cursor && term->cursor_style == CURSOR_BLOCK; bool is_selected = coord_is_selected(term, col, row); @@ -169,41 +190,42 @@ render_cell(struct terminal *term, cairo_t *cr, if (cell->attrs.blink && term->blink.state == BLINK_OFF) _fg = _bg; - struct rgb fg = color_hex_to_rgb(_fg); - struct rgb bg = color_hex_to_rgb(_bg); + pixman_color_t fg = color_hex_to_pixman(_fg); + pixman_color_t bg = color_hex_to_pixman_with_alpha( + _bg, block_cursor ? 0xffff : term->colors.alpha); if (cell->attrs.dim) - color_dim(&fg); + pixman_color_dim(&fg); if (block_cursor && term->cursor_color.text >> 31) { /* User configured cursor color overrides all attributes */ assert(term->cursor_color.cursor >> 31); - fg = color_hex_to_rgb(term->cursor_color.text); - bg = color_hex_to_rgb(term->cursor_color.cursor); + fg = color_hex_to_pixman(term->cursor_color.text); + bg = color_hex_to_pixman(term->cursor_color.cursor); } struct font *font = attrs_to_font(term, &cell->attrs); const struct glyph *glyph = font_glyph_for_wc(font, cell->wc); - int cell_cols = glyph != NULL ? max(1, glyph->width) : 1; + int cell_cols = glyph != NULL ? max(1, glyph->cols) : 1; /* Background */ - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgba(cr, bg.r, bg.g, bg.b, block_cursor ? 1.0 : term->colors.alpha); - cairo_rectangle(cr, x, y, cell_cols * width, height); - cairo_fill(cr); + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, &bg, 1, + &(pixman_rectangle16_t){x, y, cell_cols * width, height}); /* Non-block cursors */ if (has_cursor) { - struct rgb cursor_color = term->cursor_color.text >> 31 - ? color_hex_to_rgb(term->cursor_color.cursor) - : fg; + pixman_color_t cursor_color = term->cursor_color.text >> 31 + ? color_hex_to_pixman(term->cursor_color.cursor) + : color_hex_to_pixman(_fg); if (term->cursor_style == CURSOR_BAR) - draw_bar(term, cr, cursor_color, x, y); + draw_bar(term, pix, &cursor_color, x, y); else if (term->cursor_style == CURSOR_UNDERLINE) draw_underline( - term, cr, attrs_to_font(term, &cell->attrs), cursor_color, x, y, cell_cols); + term, pix, attrs_to_font(term, &cell->attrs), &cursor_color, + x, y, cell_cols); } if (cell->attrs.blink && !term->blink.active) { @@ -215,36 +237,38 @@ render_cell(struct terminal *term, cairo_t *cr, return cell_cols; if (glyph != NULL) { - cairo_save(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - double fixup = glyph->pixel_size_fixup; - cairo_translate( - cr, - x + glyph->left / fixup, - y + term->fextents.ascent - glyph->top * fixup); - cairo_scale(cr, fixup, fixup); - - if (cairo_image_surface_get_format(glyph->surf) == CAIRO_FORMAT_ARGB32) { + if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) { /* Glyph surface is a pre-rendered image (typically a color emoji...) */ if (!(cell->attrs.blink && term->blink.state == BLINK_OFF)) { - cairo_set_source_surface(cr, glyph->surf, 0, 0); - cairo_paint(cr); + pixman_image_composite( + PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0, + x + glyph->x, y + term->fextents.ascent - glyph->y, + glyph->width, glyph->height); } } else { /* Glyph surface is an alpha mask */ - cairo_set_source_rgb(cr, fg.r, fg.g, fg.b); - cairo_mask_surface(cr, glyph->surf, 0, 0); + /* TODO: cache */ + pixman_image_t *src = pixman_image_create_solid_fill(&fg); + pixman_image_composite( + PIXMAN_OP_OVER, src, glyph->pix, pix, 0, 0, 0, 0, + x + glyph->x, y + term->fextents.ascent - glyph->y, + glyph->width, glyph->height); + pixman_image_unref(src); } - cairo_restore(cr); } /* Underline */ - if (cell->attrs.underline) - draw_underline(term, cr, attrs_to_font(term, &cell->attrs), fg, x, y, cell_cols); + if (cell->attrs.underline) { + pixman_color_t color = color_hex_to_pixman(_fg); + draw_underline(term, pix, attrs_to_font(term, &cell->attrs), + &color, x, y, cell_cols); + } - if (cell->attrs.strikethrough) - draw_strikeout(term, cr, attrs_to_font(term, &cell->attrs), fg, x, y, cell_cols); + if (cell->attrs.strikethrough) { + pixman_color_t color = color_hex_to_pixman(_fg); + draw_strikeout(term, pix, attrs_to_font(term, &cell->attrs), + &color, x, y, cell_cols); + } return cell_cols; } @@ -258,21 +282,18 @@ grid_render_scroll(struct terminal *term, struct buffer *buf, int width = buf->width; int height = (dmg->scroll.region.end - dmg->scroll.region.start - dmg->scroll.lines) * term->cell_height; - const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); - LOG_DBG("damage: SCROLL: %d-%d by %d lines (dst-y: %d, src-y: %d, " "height: %d, stride: %d, mmap-size: %zu)", dmg->scroll.region.start, dmg->scroll.region.end, dmg->scroll.lines, - dst_y, src_y, height, stride, + dst_y, src_y, height, buf->stride, buf->size); if (height > 0) { - 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[0]); + uint8_t *raw = buf->mmapped; + memmove(raw + dst_y * buf->stride, + raw + src_y * buf->stride, + height * buf->stride); wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height); } @@ -287,31 +308,28 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf, int width = buf->width; int height = (dmg->scroll.region.end - dmg->scroll.region.start - dmg->scroll.lines) * term->cell_height; - const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); - LOG_DBG("damage: SCROLL REVERSE: %d-%d by %d lines (dst-y: %d, src-y: %d, " "height: %d, stride: %d, mmap-size: %zu)", dmg->scroll.region.start, dmg->scroll.region.end, dmg->scroll.lines, - dst_y, src_y, height, stride, + dst_y, src_y, height, buf->stride, buf->size); if (height > 0) { - 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[0]); + uint8_t *raw = buf->mmapped; + memmove(raw + dst_y * buf->stride, + raw + src_y * buf->stride, + height * buf->stride); wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height); } } static void -render_row(struct terminal *term, cairo_t *cr, struct row *row, int row_no) +render_row(struct terminal *term, pixman_image_t *pix, struct row *row, int row_no) { for (int col = term->cols - 1; col >= 0; col--) - render_cell(term, cr, &row->cells[col], col, row_no, false); + render_cell(term, pix, &row->cells[col], col, row_no, false); } int @@ -349,7 +367,7 @@ render_worker_thread(void *_ctx) switch (row_no) { default: assert(buf != NULL); - render_row(term, buf->cairo[my_id], grid_row_in_view(term->grid, row_no), row_no); + render_row(term, buf->pix, grid_row_in_view(term->grid, row_no), row_no); break; case -1: @@ -387,8 +405,7 @@ grid_render(struct terminal *term) assert(term->height > 0); struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height, 1 + term->render.workers.count); - cairo_t *cr = buf->cairo[0]; - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + pixman_image_t *pix = buf->pix; bool all_clean = tll_length(term->grid->scroll_damage) == 0; @@ -399,7 +416,7 @@ grid_render(struct terminal *term) if (cell->attrs.clean) { cell->attrs.clean = 0; - render_cell(term, cr, cell, at.col, at.row, false); + render_cell(term, pix, cell, at.col, at.row, false); wl_surface_damage_buffer( term->wl.surface, @@ -431,12 +448,15 @@ grid_render(struct terminal *term) int bmargin_height = term->height - bmargin; uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg; - struct rgb bg = color_hex_to_rgb(_bg); - cairo_set_source_rgba(buf->cairo[0], bg.r, bg.g, bg.b, term->colors.alpha); - 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]); + pixman_color_t bg = color_hex_to_pixman_with_alpha(_bg, term->colors.alpha); + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, &bg, 1, + &(pixman_rectangle16_t){rmargin, 0, rmargin_width, term->height}); + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, &bg, 1, + &(pixman_rectangle16_t){0, bmargin, term->width, bmargin_height}); wl_surface_damage_buffer( term->wl.surface, rmargin, 0, rmargin_width, term->height); @@ -504,7 +524,7 @@ grid_render(struct terminal *term) if (!row->dirty) continue; - render_row(term, cr, row, r); + render_row(term, pix, row, r); row->dirty = false; all_clean = false; @@ -590,7 +610,7 @@ grid_render(struct terminal *term) cell->attrs.clean = 0; term->render.last_cursor.cell = cell; int cols_updated = render_cell( - term, cr, cell, term->cursor.col, view_aligned_row, true); + term, pix, cell, term->cursor.col, view_aligned_row, true); wl_surface_damage_buffer( term->wl.surface, @@ -605,10 +625,11 @@ grid_render(struct terminal *term) } if (term->flash.active) { - 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]); + /* Note: alpha is pre-computed in each color component */ + pixman_image_fill_rectangles( + PIXMAN_OP_OVER, pix, + &(pixman_color_t){.red=0x7fff, .green=0x7fff, .blue=0, .alpha=0x7fff}, + 1, &(pixman_rectangle16_t){0, 0, term->width, term->height}); wl_surface_damage_buffer( term->wl.surface, 0, 0, term->width, term->height); @@ -617,7 +638,6 @@ 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[0]); wl_surface_attach(term->wl.surface, buf->wl_buf, 0, 0); assert(term->render.frame_callback == NULL); diff --git a/shm.c b/shm.c index ca078544..ebff8a1a 100644 --- a/shm.c +++ b/shm.c @@ -7,6 +7,8 @@ #include #include +#include + #define LOG_MODULE "shm" #include "log.h" #include "tllist.h" @@ -45,11 +47,10 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies) * No existing buffer available. Create a new one by: * * 1. open a memory backed "file" with memfd_create() - * 2. mmap() the memory file, to be used by the cairo surface + * 2. mmap() the memory file, to be used by the pixman image * 3. create a wayland shm buffer for the same memory file * - * The cairo surface and the wayland buffer are now sharing - * memory. + * The pixman image and the wayland buffer are now sharing memory. */ int pool_fd = -1; @@ -59,8 +60,7 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies) struct wl_shm_pool *pool = NULL; struct wl_buffer *buf = NULL; - cairo_surface_t **cairo_surface = NULL; - cairo_t **cairo = NULL; + pixman_image_t *pix = NULL; /* Backing memory for SHM */ pool_fd = memfd_create("f00sel-wayland-shm-buffer-pool", MFD_CLOEXEC); @@ -69,8 +69,12 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies) goto err; } + /* TODO: copied from font.c */ + /* Calculate stride. Copied from cairoint.h:CAIRO_STRIDE_FOR_WIDTH_BPP */ + int bpp = 32; + const int stride = (((bpp * width + 7) / 8 + 4 - 1) & -4); + /* Total size */ - const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); size = stride * height; if (ftruncate(pool_fd, size) == -1) { LOG_ERRNO("failed to truncate SHM pool"); @@ -100,27 +104,9 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies) wl_shm_pool_destroy(pool); pool = NULL; close(pool_fd); pool_fd = -1; - /* Create a cairo surface around the mmapped memory */ - cairo_surface = calloc(copies, sizeof(cairo_surface[0])); - cairo = calloc(copies, sizeof(cairo[0])); - - 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; - } - } + /* One pixman image for each worker thread (do we really need multiple?) */ + pix = pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, width, height, (uint32_t *)mmapped, stride); /* Push to list of available buffers, but marked as 'busy' */ tll_push_back( @@ -128,13 +114,12 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies) ((struct buffer){ .width = width, .height = height, + .stride = stride, .busy = true, .size = size, .mmapped = mmapped, .wl_buf = buf, - .copies = copies, - .cairo_surface = cairo_surface, - .cairo = cairo} + .pix = pix} ) ); @@ -143,18 +128,8 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies) return ret; err: - 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 (pix != NULL) + pixman_image_unref(pix); if (buf != NULL) wl_buffer_destroy(buf); if (pool != NULL) @@ -173,18 +148,8 @@ shm_fini(void) tll_foreach(buffers, it) { struct buffer *buf = &it->item; - 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); - } + if (buf->pix != NULL) + pixman_image_unref(buf->pix); wl_buffer_destroy(buf->wl_buf); munmap(buf->mmapped, buf->size); diff --git a/shm.h b/shm.h index 9982cb8d..68013888 100644 --- a/shm.h +++ b/shm.h @@ -3,23 +3,22 @@ #include #include -#include +#include #include struct buffer { int width; int height; + int stride; bool busy; size_t size; void *mmapped; struct wl_buffer *wl_buf; - - size_t copies; - cairo_surface_t **cairo_surface; - cairo_t **cairo; + pixman_image_t *pix; }; -struct buffer *shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies); +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 2baa5f59..fde5ba7d 100644 --- a/terminal.h +++ b/terminal.h @@ -8,7 +8,6 @@ #include #include -#include #include #include #include