kmscon: add pixman renderer

This is an experimental renderer based on pixman. It is only available for
testing-purposes and should not be used in production, yet. The bbulk
renderer is still the faster alternative and should be used instead.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2013-01-24 12:13:29 +01:00
parent d72e44e9a1
commit 79c5ba7185
5 changed files with 551 additions and 0 deletions

View File

@ -468,6 +468,24 @@ mod_cairo_la_LDFLAGS = \
-module \
-avoid-version
if BUILD_ENABLE_RENDERER_PIXMAN
module_LTLIBRARIES += mod-pixman.la
endif
mod_pixman_la_SOURCES = \
src/kmscon_module_interface.h \
src/githead.h \
src/text_pixman.c \
src/kmscon_mod_pixman.c
mod_pixman_la_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(PIXMAN_CFLAGS)
mod_pixman_la_LIBADD = \
$(PIXMAN_LIBS)
mod_pixman_la_LDFLAGS = \
-module \
-avoid-version
#
# Binaries
# These are the sources for the main binaries and test programs. They mostly

View File

@ -109,6 +109,11 @@ PKG_CHECK_MODULES([CAIRO], [cairo],
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
@ -256,10 +261,12 @@ AC_ARG_WITH([renderers],
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"
@ -271,6 +278,8 @@ else
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])
@ -569,6 +578,25 @@ else
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=""
@ -819,6 +847,14 @@ if test "x$renderer_cairo_avail" = "xyes" ; then
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
@ -1025,6 +1061,15 @@ fi
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],
@ -1195,6 +1240,7 @@ AC_MSG_NOTICE([Build configuration:
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)

57
src/kmscon_mod_pixman.c Normal file
View File

@ -0,0 +1,57 @@
/*
* 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);

View File

@ -114,5 +114,6 @@ extern struct kmscon_text_ops kmscon_text_bblit_ops;
extern struct kmscon_text_ops kmscon_text_bbulk_ops;
extern struct kmscon_text_ops kmscon_text_gltex_ops;
extern struct kmscon_text_ops kmscon_text_cairo_ops;
extern struct kmscon_text_ops kmscon_text_pixman_ops;
#endif /* KMSCON_TEXT_H */

429
src/text_pixman.c Normal file
View File

@ -0,0 +1,429 @@
/*
* 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,
};