AC_SUBST(CAIRO_CFLAGS)
AC_SUBST(CAIRO_LIBS)
+PKG_CHECK_MODULES([PIXMAN], [pixman-1],
+ [have_pixman=yes], [have_pixman=no])
+AC_SUBST(PIXMAN_CFLAGS)
+AC_SUBST(PIXMAN_LIBS)
+
#
# Parse arguments
# This parses all arguments that are given via "--enable-XY" or "--with-XY" and
enable_renderer_bbulk="no"
enable_renderer_gltex="no"
enable_renderer_cairo="no"
+enable_renderer_pixman="no"
if test "x$with_renderers" = "x" ; then
enable_renderer_bbulk="yes (default)"
enable_renderer_gltex="yes (default)"
enable_renderer_cairo="no (default)"
+ enable_renderer_pixman="no (default)"
with_renderers="bbulk,gltex (default)"
else
SAVEIFS="$IFS"
enable_renderer_gltex="yes"
elif test "x$i" = "xcairo" ; then
enable_renderer_cairo="yes"
+ elif test "x$i" = "xpixman" ; then
+ enable_renderer_pixman="yes"
else
IFS="$SAVEIFS"
AC_ERROR([Unknown renderer $i])
renderer_cairo_missing="enable-renderer-cairo"
fi
+# renderer pixman
+renderer_pixman_avail=no
+renderer_pixman_missing=""
+if test ! "x$enable_renderer_pixman" = "xno" ; then
+ renderer_pixman_avail=yes
+ if test "x$have_pixman" = "xno" ; then
+ renderer_pixman_avail=no
+ renderer_pixman_missing="pixman"
+ fi
+
+ if test "x$renderer_pixman_avail" = "xno" ; then
+ if test "x$enable_renderer_pixman" = "xyes" ; then
+ AC_ERROR([missing for renderer-pixman: $renderer_pixman_missing])
+ fi
+ fi
+else
+ renderer_pixman_missing="enable-renderer-pixman"
+fi
+
# font unifont
font_unifont_avail=no
font_unifont_missing=""
fi
fi
+# renderer pixman
+renderer_pixman_enabled=no
+if test "x$renderer_pixman_avail" = "xyes" ; then
+ if test "x${enable_renderer_pixman% *}" = "xyes" ; then
+ renderer_pixman_enabled=yes
+ fi
+fi
+
# renderer bbulk
renderer_bbulk_enabled=no
if test "x$renderer_bbulk_avail" = "xyes" ; then
AM_CONDITIONAL([BUILD_ENABLE_RENDERER_CAIRO],
[test "x$renderer_cairo_enabled" = "xyes"])
+# renderer pixman
+if test "x$renderer_pixman_enabled" = "xyes" ; then
+ AC_DEFINE([BUILD_ENABLE_RENDERER_PIXMAN], [1],
+ [Build pixman rendering backend])
+fi
+
+AM_CONDITIONAL([BUILD_ENABLE_RENDERER_PIXMAN],
+ [test "x$renderer_pixman_enabled" = "xyes"])
+
# font unifont
if test "x$font_unifont_enabled" = "xyes" ; then
AC_DEFINE([BUILD_ENABLE_FONT_UNIFONT], [1],
bbulk: $renderer_bbulk_enabled ($renderer_bbulk_avail: $renderer_bbulk_missing)
gltex: $renderer_gltex_enabled ($renderer_gltex_avail: $renderer_gltex_missing)
cairo: $renderer_cairo_enabled ($renderer_cairo_avail: $renderer_cairo_missing)
+ pixman: $renderer_pixman_enabled ($renderer_pixman_avail: $renderer_pixman_missing)
Session Types:
dummy: $session_dummy_enabled ($session_dummy_avail: $session_dummy_missing)
--- /dev/null
+/*
+ * kmscon - Pixman based rendering backend module
+ *
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Pixman based rendering backend
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "text.h"
+#include "kmscon_module_interface.h"
+#include "log.h"
+
+#define LOG_SUBSYSTEM "mod_pixman"
+
+static int kmscon_pixman_load(void)
+{
+ int ret;
+
+ kmscon_text_pixman_ops.owner = KMSCON_THIS_MODULE;
+ ret = kmscon_text_register(&kmscon_text_pixman_ops);
+ if (ret) {
+ log_error("cannot register pixman renderer");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void kmscon_pixman_unload(void)
+{
+ kmscon_text_unregister(kmscon_text_pixman_ops.name);
+}
+
+KMSCON_MODULE(NULL, kmscon_pixman_load, kmscon_pixman_unload, NULL);
--- /dev/null
+/*
+ * kmscon - Pixman Text Renderer Backend
+ *
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Pixman based text renderer
+ */
+
+#include <errno.h>
+#include <pixman.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "log.h"
+#include "shl_hashtable.h"
+#include "text.h"
+#include "uterm_video.h"
+
+#define LOG_SUBSYSTEM "text_pixman"
+
+struct tp_glyph {
+ const struct kmscon_glyph *glyph;
+ pixman_image_t *surf;
+};
+
+struct tp_pixman {
+ struct shl_hashtable *glyphs;
+ struct shl_hashtable *bold_glyphs;
+
+ struct uterm_video_buffer buf[2];
+ pixman_image_t *surf[2];
+ unsigned int format[2];
+
+ bool use_indirect;
+ uint8_t *data[2];
+ struct uterm_video_buffer vbuf;
+
+ /* cache */
+ unsigned int cur;
+ unsigned int c_bpp;
+ uint32_t *c_data;
+ unsigned int c_stride;
+};
+
+static int tp_init(struct kmscon_text *txt)
+{
+ struct tp_pixman *tp;
+
+ tp = malloc(sizeof(*tp));
+ if (!tp)
+ return -ENOMEM;
+
+ txt->data = tp;
+ return 0;
+}
+
+static void tp_destroy(struct kmscon_text *txt)
+{
+ struct tp_pixman *tp = txt->data;
+
+ free(tp);
+}
+
+static void free_glyph(void *data)
+{
+ struct tp_glyph *glyph = data;
+
+ pixman_image_unref(glyph->surf);
+ free(glyph);
+}
+
+static unsigned int format_u2p(unsigned int f)
+{
+ switch (f) {
+ case UTERM_FORMAT_XRGB32:
+ return PIXMAN_x8r8g8b8;
+ case UTERM_FORMAT_RGB16:
+ return PIXMAN_r5g6b5;
+ case UTERM_FORMAT_GREY:
+ return PIXMAN_a8;
+ default:
+ return 0;
+ }
+}
+
+static int alloc_indirect(struct kmscon_text *txt,
+ unsigned int w, unsigned int h)
+{
+ struct tp_pixman *tp = txt->data;
+ unsigned int s, i, format;
+ int ret;
+
+ log_info("using blitting engine");
+
+ format = format_u2p(UTERM_FORMAT_XRGB32);
+ s = w * 4;
+
+ tp->data[0] = malloc(s * h);
+ tp->data[1] = malloc(s * h);
+ if (!tp->data[0] || !tp->data[1]) {
+ log_error("cannot allocate memory for render-buffer");
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ for (i = 0; i < 2; ++i) {
+ tp->format[i] = format;
+ tp->surf[i] = pixman_image_create_bits(format, w, h,
+ (void*)tp->data[i], s);
+ if (!tp->surf[i]) {
+ log_error("cannot create pixman surfaces");
+ goto err_pixman;
+ }
+ }
+
+ tp->vbuf.width = w;
+ tp->vbuf.height = h;
+ tp->vbuf.stride = s;
+ tp->vbuf.format = UTERM_FORMAT_XRGB32;
+ tp->use_indirect = true;
+ return 0;
+
+err_pixman:
+ if (tp->surf[1])
+ pixman_image_unref(tp->surf[1]);
+ tp->surf[1] = NULL;
+ if (tp->surf[0])
+ pixman_image_unref(tp->surf[0]);
+ tp->surf[0] = NULL;
+err_free:
+ free(tp->data[1]);
+ free(tp->data[0]);
+ tp->data[1] = NULL;
+ tp->data[0] = NULL;
+ return ret;
+}
+
+static int tp_set(struct kmscon_text *txt)
+{
+ struct tp_pixman *tp = txt->data;
+ int ret;
+ unsigned int w, h;
+ struct uterm_mode *m;
+
+ memset(tp, 0, sizeof(*tp));
+ m = uterm_display_get_current(txt->disp);
+ w = uterm_mode_get_width(m);
+ h = uterm_mode_get_height(m);
+
+ ret = shl_hashtable_new(&tp->glyphs, shl_direct_hash,
+ shl_direct_equal, NULL,
+ free_glyph);
+ if (ret)
+ return ret;
+
+ ret = shl_hashtable_new(&tp->bold_glyphs, shl_direct_hash,
+ shl_direct_equal, NULL,
+ free_glyph);
+ if (ret)
+ goto err_htable;
+
+ /*
+ * TODO: It is actually faster to use a local shadow buffer and then
+ * blit all data to the framebuffer afterwards. Reads seem to be
+ * horribly slow on some mmap'ed framebuffers. However, that's not true
+ * for all so we actually don't know which to use here.
+ */
+ ret = uterm_display_get_buffers(txt->disp, tp->buf,
+ UTERM_FORMAT_XRGB32);
+ if (true || ret) {
+ log_warning("cannot get buffers for display %p",
+ txt->disp);
+ ret = alloc_indirect(txt, w, h);
+ if (ret)
+ goto err_htable_bold;
+ } else {
+ tp->format[0] = format_u2p(tp->buf[0].format);
+ tp->surf[0] = pixman_image_create_bits_no_clear(tp->format[0],
+ tp->buf[0].width, tp->buf[0].height,
+ (void*)tp->buf[0].data,
+ tp->buf[0].stride);
+ tp->format[1] = format_u2p(tp->buf[1].format);
+ tp->surf[1] = pixman_image_create_bits_no_clear(tp->format[1],
+ tp->buf[1].width, tp->buf[1].height,
+ (void*)tp->buf[1].data,
+ tp->buf[1].stride);
+ if (!tp->surf[0] || !tp->surf[1]) {
+ log_error("cannot create pixman surfaces");
+ goto err_ctx;
+ }
+ }
+
+ txt->cols = w / txt->font->attr.width;
+ txt->rows = h / txt->font->attr.height;
+
+ return 0;
+
+err_ctx:
+ if (tp->surf[1])
+ pixman_image_unref(tp->surf[1]);
+ if (tp->surf[0])
+ pixman_image_unref(tp->surf[0]);
+ free(tp->data[1]);
+ free(tp->data[0]);
+err_htable_bold:
+ shl_hashtable_free(tp->bold_glyphs);
+err_htable:
+ shl_hashtable_free(tp->glyphs);
+ return ret;
+}
+
+static void tp_unset(struct kmscon_text *txt)
+{
+ struct tp_pixman *tp = txt->data;
+
+ pixman_image_unref(tp->surf[1]);
+ pixman_image_unref(tp->surf[0]);
+ free(tp->data[1]);
+ free(tp->data[0]);
+ shl_hashtable_free(tp->bold_glyphs);
+ shl_hashtable_free(tp->glyphs);
+}
+
+static int find_glyph(struct kmscon_text *txt, struct tp_glyph **out,
+ uint32_t id, const uint32_t *ch, size_t len, bool bold)
+{
+ struct tp_pixman *tp = txt->data;
+ struct tp_glyph *glyph;
+ struct shl_hashtable *gtable;
+ struct kmscon_font *font;
+ const struct uterm_video_buffer *buf;
+ unsigned int format;
+ int ret;
+ bool res;
+
+ if (bold) {
+ gtable = tp->bold_glyphs;
+ font = txt->bold_font;
+ } else {
+ gtable = tp->glyphs;
+ font = txt->font;
+ }
+
+ res = shl_hashtable_find(gtable, (void**)&glyph,
+ (void*)(unsigned long)id);
+ if (res) {
+ *out = glyph;
+ return 0;
+ }
+
+ glyph = malloc(sizeof(*glyph));
+ if (!glyph)
+ return -ENOMEM;
+ memset(glyph, 0, sizeof(*glyph));
+
+ if (!len)
+ ret = kmscon_font_render_empty(font, &glyph->glyph);
+ else
+ ret = kmscon_font_render(font, id, ch, len, &glyph->glyph);
+
+ if (ret) {
+ ret = kmscon_font_render_inval(font, &glyph->glyph);
+ if (ret)
+ goto err_free;
+ }
+
+ buf = &glyph->glyph->buf;
+ format = format_u2p(buf->format);
+ glyph->surf = pixman_image_create_bits_no_clear(format,
+ buf->width,
+ buf->height,
+ (void*)buf->data,
+ buf->stride);
+ if (!glyph->surf) {
+ log_error("cannot create pixman-glyph: %d %p %d %d %d %d",
+ ret, buf->data, format, buf->width, buf->height,
+ buf->stride);
+ ret = -EFAULT;
+ goto err_free;
+ }
+
+ ret = shl_hashtable_insert(gtable, (void*)(long)id, glyph);
+ if (ret)
+ goto err_pixman;
+
+ *out = glyph;
+ return 0;
+
+err_pixman:
+ pixman_image_unref(glyph->surf);
+err_free:
+ free(glyph);
+ return ret;
+}
+
+static int tp_prepare(struct kmscon_text *txt)
+{
+ struct tp_pixman *tp = txt->data;
+ int ret;
+ pixman_image_t *img;
+
+ ret = uterm_display_use(txt->disp, NULL);
+ if (ret < 0) {
+ log_error("cannot use display %p", txt->disp);
+ return ret;
+ }
+
+ tp->cur = ret;
+ img = tp->surf[tp->cur];
+ tp->c_bpp = PIXMAN_FORMAT_BPP(tp->format[tp->cur]);
+ tp->c_data = pixman_image_get_data(img);
+ tp->c_stride = pixman_image_get_stride(img);
+
+ return 0;
+}
+
+static int tp_draw(struct kmscon_text *txt,
+ uint32_t id, const uint32_t *ch, size_t len,
+ unsigned int width,
+ unsigned int posx, unsigned int posy,
+ const struct tsm_screen_attr *attr)
+{
+ struct tp_pixman *tp = txt->data;
+ struct tp_glyph *glyph;
+ int ret;
+ uint32_t bc;
+ pixman_color_t fc;
+ pixman_image_t *col;
+
+ if (!width)
+ return 0;
+
+ ret = find_glyph(txt, &glyph, id, ch, len, attr->bold);
+ if (ret)
+ return ret;
+
+ if (attr->inverse) {
+ bc = (attr->fr << 16) | (attr->fg << 8) | (attr->fb);
+ fc.red = attr->br << 8;
+ fc.green = attr->bg << 8;
+ fc.blue = attr->bb << 8;
+ fc.alpha = 0xffff;
+ } else {
+ bc = (attr->br << 16) | (attr->bg << 8) | (attr->bb);
+ fc.red = attr->fr << 8;
+ fc.green = attr->fg << 8;
+ fc.blue = attr->fb << 8;
+ fc.alpha = 0xffff;
+ }
+
+ pixman_fill(tp->c_data, tp->c_stride / 4, tp->c_bpp,
+ posx * txt->font->attr.width,
+ posy * txt->font->attr.height,
+ txt->font->attr.width,
+ txt->font->attr.height,
+ bc);
+
+ col = pixman_image_create_solid_fill(&fc);
+ if (!col) {
+ log_error("cannot create pixman color image");
+ return -ENOMEM;
+ }
+
+ pixman_image_composite(PIXMAN_OP_OVER,
+ col, /* src */
+ glyph->surf, /* mask */
+ tp->surf[tp->cur], /* dst */
+ 0, 0, 0, 0,
+ posx * txt->font->attr.width,
+ posy * txt->font->attr.height,
+ txt->font->attr.width,
+ txt->font->attr.height);
+
+ pixman_image_unref(col);
+
+ return 0;
+}
+
+static int tp_render(struct kmscon_text *txt)
+{
+ struct tp_pixman *tp = txt->data;
+ int ret;
+
+ if (!tp->use_indirect)
+ return 0;
+
+ tp->vbuf.data = tp->data[tp->cur];
+ ret = uterm_display_blit(txt->disp, &tp->vbuf, 0, 0);
+ if (ret) {
+ log_error("cannot blit back-buffer to display: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+struct kmscon_text_ops kmscon_text_pixman_ops = {
+ .name = "pixman",
+ .owner = NULL,
+ .init = tp_init,
+ .destroy = tp_destroy,
+ .set = tp_set,
+ .unset = tp_unset,
+ .prepare = tp_prepare,
+ .draw = tp_draw,
+ .render = tp_render,
+ .abort = NULL,
+};