Skip to content

Commit

Permalink
Utilize pixman for efficient pixel manipulation
Browse files Browse the repository at this point in the history
According to issue #6, I replace original image compositing and
trapezoid rasterization with Pixman function. Breifly, include:
 - pixman_image_composite: image compositing
 - pixman_image_fill_rectangles: fill the image with rectangles
 - pixman_image_fill_boxes: span is filled with the boxs

For the implementation changes:
 1. add a configurable option to build. It will reduce the code bloat.
 2. use the same public interface to maintain the source-level
    compatibility.

Close #6
  • Loading branch information
Bennctu committed Oct 5, 2024
1 parent 7a1d138 commit 9a9b5de
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 3 deletions.
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ libtwin.a_files-y = \
src/pattern.c \
src/spline.c \
src/work.c \
src/draw.c \
src/hull.c \
src/icon.c \
src/pixmap.c \
Expand All @@ -62,6 +61,16 @@ libtwin.a_includes-y := \
libtwin.a_files-$(CONFIG_LOGGING) += src/log.c
libtwin.a_files-$(CONFIG_CURSOR) += src/cursor.c

# Rendering
ifeq ($(CONFIG_RENDERER_BUILTIN), y) ## Builtin
libtwin.a_files-y += src/draw.c
else ifeq ($(CONFIG_RENDERER_PIXMAN), y) ## Pixman
libtwin.a_files-y += src/pixman.c
libtwin.a_cflags-y += $(shell pkg-config --cflags pixman-1)
TARGET_LIBS += $(shell pkg-config --libs pixman-1)
CFLAGS += $(shell pkg-config --cflags pixman-1)
endif

# Image loaders

ifeq ($(CONFIG_LOADER_JPEG), y)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ benefiting the entire application stack.
`Mado` is built with a minimalist design in mind. However, its verification
relies on certain third-party packages for full functionality and access to all
its features. To ensure proper operation, the development environment should
have the [SDL2 library](https://www.libsdl.org/), [libjpeg](https://www.ijg.org/), and [libpng](https://github.com/pnggroup/libpng) installed.
have the [SDL2 library](https://www.libsdl.org/), [libjpeg](https://www.ijg.org/), [libpng](https://github.com/pnggroup/libpng), and [libpixman-1](https://pixman.org/) installed.
* macOS: `brew install sdl2 jpeg libpng`
* Ubuntu Linux / Debian: `sudo apt install libsdl2-dev libjpeg-dev libpng-dev`
* Ubuntu Linux / Debian: `sudo apt install libsdl2-dev libjpeg-dev libpng-dev libpixman-1-dev`

Configure via [Kconfiglib](https://pypi.org/project/kconfiglib/)
```shell
Expand Down
12 changes: 12 additions & 0 deletions configs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ config BACKEND_SDL

endchoice

choice
prompt "Renderer Selection"
default RENDERER_BUILTIN

config RENDERER_BUILTIN
bool "Built-in pixel manipulation"

config RENDERER_PIXMAN
bool "Pixman based rendering"

endchoice

menu "Features"

config LOGGING
Expand Down
17 changes: 17 additions & 0 deletions include/twin_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ typedef int8_t twin_gfixed_t;
#define twin_sfixed_mod(f) ((f) & 0xf)

#define twin_int_to_sfixed(i) ((twin_sfixed_t) ((i) * 16))
#define twin_sfixed_to_int(i) ((int32_t) ((i) >> 4))

#define twin_sfixed_to_fixed(s) (((twin_fixed_t) (s)) << 12)
#define twin_fixed_to_sfixed(f) ((twin_sfixed_t) ((f) >> 12))
Expand Down Expand Up @@ -168,6 +169,22 @@ typedef int8_t twin_gfixed_t;
((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \
((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)) | 0xff000000)

#define min(x, y) \
({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; \
})

#define max(x, y) \
({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x > _y ? _x : _y; \
})

typedef union {
twin_pointer_t p;
twin_argb32_t c;
Expand Down
212 changes: 212 additions & 0 deletions src/pixman.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/*
* Twin - A Tiny Window System
* Copyright (c) 2004 Keith Packard <keithp@keithp.com>
* All rights reserved.
*/

#include <pixman.h>
#include "twin_private.h"

static void twin_argb32_to_pixman_color(twin_argb32_t argb,
pixman_color_t *color)
{
/* Extract ARGB every Byte */
uint16_t a = (argb >> 24) & 0xFF;
uint16_t r = (argb >> 16) & 0xFF;
uint16_t g = (argb >> 8) & 0xFF;
uint16_t b = argb & 0xFF;

/* 8bits -> 16bits (255 -> 65535) */
color->alpha = (a << 8) + a;
color->red = (r << 8) + r;
color->green = (g << 8) + g;
color->blue = (b << 8) + b;
}

static const pixman_format_code_t twin_pixman_format[3] = {
[TWIN_A8] = PIXMAN_a8,
[TWIN_RGB16] = PIXMAN_r5g6b5,
[TWIN_ARGB32] = PIXMAN_a8r8g8b8};

static pixman_format_code_t twin_to_pixman_format(
const twin_format_t twin_format)
{
return twin_pixman_format[twin_format];
}

static const pixman_op_t twin_pixman_op[2] =
{[TWIN_OVER] = PIXMAN_OP_OVER, [TWIN_SOURCE] = PIXMAN_OP_SRC};

static pixman_op_t twin_to_pixman_op(const twin_operator_t twin_op)
{
return twin_pixman_op[twin_op];
}

#define create_pixman_image_from_twin_pixmap(pixmap) \
({ \
typeof(pixmap) _pixmap = (pixmap); \
pixman_image_create_bits(twin_to_pixman_format((_pixmap)->format), \
(_pixmap)->width, (_pixmap)->height, \
(_pixmap)->p.argb32, (_pixmap)->stride); \
})

static void pixmap_matrix_scale(pixman_image_t *src, twin_matrix_t *matrix)
{
pixman_transform_t transform;
pixman_transform_init_identity(&transform);

pixman_fixed_t sx = matrix->m[0][0], sy = matrix->m[1][1];

pixman_transform_scale(&transform, NULL, sx, sy);
pixman_image_set_transform(src, &transform);
}

void twin_composite(twin_pixmap_t *_dst,
twin_coord_t dst_x,
twin_coord_t dst_y,
twin_operand_t *_src,
twin_coord_t src_x,
twin_coord_t src_y,
twin_operand_t *_msk,
twin_coord_t msk_x,
twin_coord_t msk_y,
twin_operator_t operator,
twin_coord_t width,
twin_coord_t height)
{
pixman_image_t *src;
if (_src->source_kind == TWIN_SOLID) {
pixman_color_t source_pixel;
twin_argb32_to_pixman_color(_src->u.argb, &source_pixel);
src = pixman_image_create_solid_fill(&source_pixel);
} else {
twin_pixmap_t *src_pixmap = _src->u.pixmap;
src = create_pixman_image_from_twin_pixmap(src_pixmap);

if (!twin_matrix_is_identity(&(src_pixmap->transform)))
pixmap_matrix_scale(src, &(src_pixmap->transform));
}

pixman_image_t *dst = create_pixman_image_from_twin_pixmap(_dst);

/* Set origin */
twin_coord_t ox, oy;
twin_pixmap_get_origin(_dst, &ox, &oy);
ox += dst_x;
oy += dst_y;

if (!_msk) {
pixman_image_composite(twin_to_pixman_op(operator), src, NULL, dst,
src_x, src_y, 0, 0, ox, oy, width, height);
} else {
pixman_image_t *msk =
create_pixman_image_from_twin_pixmap(_msk->u.pixmap);
pixman_image_composite(twin_to_pixman_op(operator), src, msk, dst,
src_x, src_y, msk_x, msk_y, ox, oy, width,
height);
pixman_image_unref(msk);
}

pixman_image_unref(src);
pixman_image_unref(dst);
}

void twin_fill(twin_pixmap_t *_dst,
twin_argb32_t pixel,
twin_operator_t operator,
twin_coord_t left,
twin_coord_t top,
twin_coord_t right,
twin_coord_t bottom)
{
/* offset */
left += _dst->origin_x;
top += _dst->origin_y;
right += _dst->origin_x;
bottom += _dst->origin_y;

/* clip */
if (left < _dst->clip.left)
left = _dst->clip.left;
if (right > _dst->clip.right)
right = _dst->clip.right;
if (top < _dst->clip.top)
top = _dst->clip.top;
if (bottom > _dst->clip.bottom)
bottom = _dst->clip.bottom;

pixman_image_t *dst = create_pixman_image_from_twin_pixmap(_dst);
pixman_color_t color;
twin_argb32_to_pixman_color(pixel, &color);
pixman_image_fill_rectangles(
twin_to_pixman_op(operator), dst, &color, 1,
&(pixman_rectangle16_t){left, top, right - left, bottom - top});

twin_pixmap_damage(_dst, left, top, right, bottom);

pixman_image_unref(dst);
}

/* Same function in draw.c */
static twin_argb32_t _twin_apply_alpha(twin_argb32_t v)
{
uint16_t t1, t2, t3;
twin_a8_t alpha = twin_get_8(v,
#if __BYTE_ORDER == __BIG_ENDIAN
0
#else
24
#endif
);

/* clear RGB data if alpha is zero */
if (!alpha)
return 0;

#if __BYTE_ORDER == __BIG_ENDIAN
/* twin needs ARGB format */
return alpha << 24 | twin_int_mult(twin_get_8(v, 24), alpha, t1) << 16 |
twin_int_mult(twin_get_8(v, 16), alpha, t2) << 8 |
twin_int_mult(twin_get_8(v, 8), alpha, t3) << 0;
#else
return alpha << 24 | twin_int_mult(twin_get_8(v, 0), alpha, t1) << 16 |
twin_int_mult(twin_get_8(v, 8), alpha, t2) << 8 |
twin_int_mult(twin_get_8(v, 16), alpha, t3) << 0;
#endif
}

void twin_premultiply_alpha(twin_pixmap_t *px)
{
int x, y;
twin_pointer_t p;

if (px->format != TWIN_ARGB32)
return;

for (y = 0; y < px->height; y++) {
p.b = px->p.b + y * px->stride;

for (x = 0; x < px->width; x++)
p.argb32[x] = _twin_apply_alpha(p.argb32[x]);
}
}

void _span_fill(twin_pixmap_t *pixmap,
twin_sfixed_t y,
twin_sfixed_t left,
twin_sfixed_t right)
{
pixman_image_t *mask = create_pixman_image_from_twin_pixmap(pixmap);

left = min(left, twin_int_to_sfixed(pixmap->width - 1));
right = min(right, twin_int_to_sfixed(pixmap->width - 1));

pixman_box32_t box = {.x1 = twin_sfixed_to_int(left),
.x2 = twin_sfixed_to_int(right),
.y1 = twin_sfixed_to_int(y),
.y2 = twin_sfixed_to_int(y) + 1};
pixman_color_t white = {0xffff, 0xffff, 0xffff, 0xffff};
pixman_image_fill_boxes(PIXMAN_OP_SRC, mask, &white, 1, &box);

pixman_image_unref(mask);
}
4 changes: 4 additions & 0 deletions src/pixmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ twin_pixmap_t *twin_pixmap_create(twin_format_t format,
twin_coord_t height)
{
twin_coord_t stride = twin_bytes_per_pixel(format) * width;
/* Padding the stride to a multiple of 4 bytes */
if (stride % 4 != 0)
stride += (4 - stride % 4);

twin_area_t space = (twin_area_t) stride * height;
twin_area_t size = sizeof(twin_pixmap_t) + space;
twin_pixmap_t *pixmap = malloc(size);
Expand Down
2 changes: 2 additions & 0 deletions src/poly.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ static int _twin_edge_build(twin_spoint_t *vertices,
return e;
}

#ifdef CONFIG_RENDERER_BUILTIN
static void _span_fill(twin_pixmap_t *pixmap,
twin_sfixed_t y,
twin_sfixed_t left,
Expand Down Expand Up @@ -224,6 +225,7 @@ static void _span_fill(twin_pixmap_t *pixmap,
*s = twin_sat(a);
}
}
#endif

static void _twin_edge_fill(twin_pixmap_t *pixmap,
twin_edge_t *edges,
Expand Down

0 comments on commit 9a9b5de

Please sign in to comment.