2 * kmscon - Pixman Text Renderer Backend
4 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Pixman based text renderer
35 #include "shl_hashtable.h"
38 #include "uterm_video.h"
40 #define LOG_SUBSYSTEM "text_pixman"
43 const struct kmscon_glyph *glyph;
49 pixman_image_t *white;
50 struct shl_hashtable *glyphs;
51 struct shl_hashtable *bold_glyphs;
53 struct uterm_video_buffer buf[2];
54 pixman_image_t *surf[2];
55 unsigned int format[2];
60 struct uterm_video_buffer vbuf;
66 unsigned int c_stride;
69 static int tp_init(struct kmscon_text *txt)
73 tp = malloc(sizeof(*tp));
81 static void tp_destroy(struct kmscon_text *txt)
83 struct tp_pixman *tp = txt->data;
88 static void free_glyph(void *data)
90 struct tp_glyph *glyph = data;
92 pixman_image_unref(glyph->surf);
97 static unsigned int format_u2p(unsigned int f)
100 case UTERM_FORMAT_XRGB32:
101 return PIXMAN_x8r8g8b8;
102 case UTERM_FORMAT_RGB16:
103 return PIXMAN_r5g6b5;
104 case UTERM_FORMAT_GREY:
111 static int alloc_indirect(struct kmscon_text *txt,
112 unsigned int w, unsigned int h)
114 struct tp_pixman *tp = txt->data;
115 unsigned int s, i, format;
118 log_info("using blitting engine");
120 format = format_u2p(UTERM_FORMAT_XRGB32);
123 tp->data[0] = malloc(s * h);
124 tp->data[1] = malloc(s * h);
125 if (!tp->data[0] || !tp->data[1]) {
126 log_error("cannot allocate memory for render-buffer");
131 for (i = 0; i < 2; ++i) {
132 tp->format[i] = format;
133 tp->surf[i] = pixman_image_create_bits(format, w, h,
134 (void*)tp->data[i], s);
136 log_error("cannot create pixman surfaces");
144 tp->vbuf.format = UTERM_FORMAT_XRGB32;
145 tp->use_indirect = true;
150 pixman_image_unref(tp->surf[1]);
153 pixman_image_unref(tp->surf[0]);
163 static int tp_set(struct kmscon_text *txt)
165 struct tp_pixman *tp = txt->data;
168 struct uterm_mode *m;
169 pixman_color_t white;
171 memset(tp, 0, sizeof(*tp));
172 m = uterm_display_get_current(txt->disp);
173 w = uterm_mode_get_width(m);
174 h = uterm_mode_get_height(m);
177 white.green = 0xffff;
181 tp->white = pixman_image_create_solid_fill(&white);
183 log_error("cannot create pixman solid color buffer");
187 ret = shl_hashtable_new(&tp->glyphs, shl_direct_hash,
188 shl_direct_equal, NULL,
193 ret = shl_hashtable_new(&tp->bold_glyphs, shl_direct_hash,
194 shl_direct_equal, NULL,
200 * TODO: It is actually faster to use a local shadow buffer and then
201 * blit all data to the framebuffer afterwards. Reads seem to be
202 * horribly slow on some mmap'ed framebuffers. However, that's not true
203 * for all so we actually don't know which to use here.
205 ret = uterm_display_get_buffers(txt->disp, tp->buf,
206 UTERM_FORMAT_XRGB32);
208 log_warning("cannot get buffers for display %p",
210 ret = alloc_indirect(txt, w, h);
212 goto err_htable_bold;
214 tp->format[0] = format_u2p(tp->buf[0].format);
215 tp->surf[0] = pixman_image_create_bits_no_clear(tp->format[0],
216 tp->buf[0].width, tp->buf[0].height,
217 (void*)tp->buf[0].data,
219 tp->format[1] = format_u2p(tp->buf[1].format);
220 tp->surf[1] = pixman_image_create_bits_no_clear(tp->format[1],
221 tp->buf[1].width, tp->buf[1].height,
222 (void*)tp->buf[1].data,
224 if (!tp->surf[0] || !tp->surf[1]) {
225 log_error("cannot create pixman surfaces");
230 txt->cols = w / txt->font->attr.width;
231 txt->rows = h / txt->font->attr.height;
237 pixman_image_unref(tp->surf[1]);
239 pixman_image_unref(tp->surf[0]);
243 shl_hashtable_free(tp->bold_glyphs);
245 shl_hashtable_free(tp->glyphs);
247 pixman_image_unref(tp->white);
251 static void tp_unset(struct kmscon_text *txt)
253 struct tp_pixman *tp = txt->data;
255 pixman_image_unref(tp->surf[1]);
256 pixman_image_unref(tp->surf[0]);
259 shl_hashtable_free(tp->bold_glyphs);
260 shl_hashtable_free(tp->glyphs);
261 pixman_image_unref(tp->white);
264 static int find_glyph(struct kmscon_text *txt, struct tp_glyph **out,
265 uint32_t id, const uint32_t *ch, size_t len, bool bold)
267 struct tp_pixman *tp = txt->data;
268 struct tp_glyph *glyph;
269 struct shl_hashtable *gtable;
270 struct kmscon_font *font;
271 const struct uterm_video_buffer *buf;
273 unsigned int format, i;
278 gtable = tp->bold_glyphs;
279 font = txt->bold_font;
285 res = shl_hashtable_find(gtable, (void**)&glyph,
286 (void*)(unsigned long)id);
292 glyph = malloc(sizeof(*glyph));
295 memset(glyph, 0, sizeof(*glyph));
298 ret = kmscon_font_render_empty(font, &glyph->glyph);
300 ret = kmscon_font_render(font, id, ch, len, &glyph->glyph);
303 ret = kmscon_font_render_inval(font, &glyph->glyph);
308 buf = &glyph->glyph->buf;
309 stride = buf->stride;
310 format = format_u2p(buf->format);
311 glyph->surf = pixman_image_create_bits_no_clear(format,
317 stride = (buf->stride + 3) & ~0x3;
318 if (!tp->new_stride) {
319 tp->new_stride = true;
320 log_debug("wrong stride, copy buffer (%d => %d)",
321 buf->stride, stride);
324 glyph->data = malloc(stride * buf->height);
326 log_error("cannot allocate memory for glyph storage");
333 for (i = 0; i < buf->height; ++i) {
334 memcpy(dst, src, buf->width);
339 glyph->surf = pixman_image_create_bits_no_clear(format,
347 log_error("cannot create pixman-glyph: %d %p %d %d %d %d",
348 ret, glyph->data ? glyph->data : buf->data, format,
349 buf->width, buf->height, stride);
354 ret = shl_hashtable_insert(gtable, (void*)(long)id, glyph);
362 pixman_image_unref(glyph->surf);
368 static int tp_prepare(struct kmscon_text *txt)
370 struct tp_pixman *tp = txt->data;
374 ret = uterm_display_use(txt->disp, NULL);
376 log_error("cannot use display %p", txt->disp);
381 img = tp->surf[tp->cur];
382 tp->c_bpp = PIXMAN_FORMAT_BPP(tp->format[tp->cur]);
383 tp->c_data = pixman_image_get_data(img);
384 tp->c_stride = pixman_image_get_stride(img);
389 static int tp_draw(struct kmscon_text *txt,
390 uint32_t id, const uint32_t *ch, size_t len,
392 unsigned int posx, unsigned int posy,
393 const struct tsm_screen_attr *attr)
395 struct tp_pixman *tp = txt->data;
396 struct tp_glyph *glyph;
405 ret = find_glyph(txt, &glyph, id, ch, len, attr->bold);
410 bc = (attr->fr << 16) | (attr->fg << 8) | (attr->fb);
411 fc.red = attr->br << 8;
412 fc.green = attr->bg << 8;
413 fc.blue = attr->bb << 8;
416 bc = (attr->br << 16) | (attr->bg << 8) | (attr->bb);
417 fc.red = attr->fr << 8;
418 fc.green = attr->fg << 8;
419 fc.blue = attr->fb << 8;
423 /* TODO: We _really_ should fix pixman to allow something like
424 * pixman_image_set_solid_fill(img, &fc) to avoid allocating a pixman
425 * image for each glyph here.
426 * libc malloc() is pretty fast, but this still costs us a lot of
427 * rendering performance. */
428 if (!fc.red && !fc.green && !fc.blue) {
430 pixman_image_ref(col);
432 col = pixman_image_create_solid_fill(&fc);
434 log_error("cannot create pixman color image");
440 pixman_image_composite(PIXMAN_OP_SRC,
445 posx * txt->font->attr.width,
446 posy * txt->font->attr.height,
447 txt->font->attr.width,
448 txt->font->attr.height);
450 pixman_fill(tp->c_data, tp->c_stride / 4, tp->c_bpp,
451 posx * txt->font->attr.width,
452 posy * txt->font->attr.height,
453 txt->font->attr.width,
454 txt->font->attr.height,
457 pixman_image_composite(PIXMAN_OP_OVER,
462 posx * txt->font->attr.width,
463 posy * txt->font->attr.height,
464 txt->font->attr.width,
465 txt->font->attr.height);
468 pixman_image_unref(col);
473 static int tp_render(struct kmscon_text *txt)
475 struct tp_pixman *tp = txt->data;
478 if (!tp->use_indirect)
481 tp->vbuf.data = tp->data[tp->cur];
482 ret = uterm_display_blit(txt->disp, &tp->vbuf, 0, 0);
484 log_error("cannot blit back-buffer to display: %d", ret);
491 struct kmscon_text_ops kmscon_text_pixman_ops = {
495 .destroy = tp_destroy,
498 .prepare = tp_prepare,