Skip to content

Commit 54b51b5

Browse files
committed
Utilize pixman for efficient pixel manipulation
According to issue #6, I replace original image compositing with Pixman function. Breifly, include: - pixman_image_composite: image compositing - pixman_image_fill_rectangles: fill the image with rectangles 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.
1 parent 980bd4c commit 54b51b5

File tree

5 files changed

+226
-5
lines changed

5 files changed

+226
-5
lines changed

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ libtwin.a_files-y = \
4545
src/pattern.c \
4646
src/spline.c \
4747
src/work.c \
48-
src/draw.c \
4948
src/hull.c \
5049
src/icon.c \
5150
src/pixmap.c \
@@ -61,6 +60,15 @@ libtwin.a_includes-y := \
6160
# Features
6261
libtwin.a_files-$(CONFIG_LOGGING) += src/log.c
6362
libtwin.a_files-$(CONFIG_CURSOR) += src/cursor.c
63+
libtwin.a_files-$(CONFIG_RENDERER_BUILTIN) += src/draw.c
64+
65+
## Pixman
66+
libtwin.a_files-$(CONFIG_RENDERER_PIXMAN) += src/pixman.c
67+
libtwin.a_cflags-$(CONFIG_RENDERER_PIXMAN) += $(shell pkg-config --cflags pixman-1)
68+
ifeq ($(CONFIG_RENDERER_PIXMAN), y)
69+
TARGET_LIBS += $(shell pkg-config --libs pixman-1)
70+
CFLAGS += $(shell pkg-config --cflags pixman-1)
71+
endif
6472

6573
# Image loaders
6674

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ benefiting the entire application stack.
6565
`Mado` is built with a minimalist design in mind. However, its verification
6666
relies on certain third-party packages for full functionality and access to all
6767
its features. We encourage the development environment to be installed with all optional
68-
packages, including [libjpeg](https://www.ijg.org/), [libpng](https://github.com/pnggroup/libpng),
69-
and the [SDL2 library](https://www.libsdl.org/).
70-
* macOS: `brew install sdl2 jpeg libpng`
71-
* Ubuntu Linux / Debian: `sudo apt install libsdl2-dev libjpeg-dev libpng-dev`
68+
packages, including [libjpeg](https://www.ijg.org/), [libpng](https://github.com/pnggroup/libpng),
69+
[pixman](https://pixman.org/), and the [SDL2 library](https://www.libsdl.org/).
70+
* macOS: `brew install sdl2 jpeg libpng pixman`
71+
* Ubuntu Linux / Debian: `sudo apt install libsdl2-dev libjpeg-dev libpng-dev libpixman-1-dev`
7272

7373
### Configuration
7474

configs/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ config BACKEND_SDL
1717

1818
endchoice
1919

20+
choice
21+
prompt "Renderer Selection"
22+
default RENDERER_BUILTIN
23+
24+
config RENDERER_BUILTIN
25+
bool "Built-in pixel manipulation"
26+
27+
config RENDERER_PIXMAN
28+
bool "Pixman based rendering"
29+
30+
endchoice
31+
2032
menu "Features"
2133

2234
config LOGGING

src/pixman.c

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/*
2+
* Twin - A Tiny Window System
3+
* Copyright (c) 2024 National Cheng Kung University, Taiwan
4+
* All rights reserved.
5+
*/
6+
7+
#include <pixman.h>
8+
#include "twin_private.h"
9+
10+
static void twin_argb32_to_pixman_color(twin_argb32_t argb,
11+
pixman_color_t *color)
12+
{
13+
/* Extract ARGB every Byte */
14+
uint16_t a = (argb >> 24) & 0xFF;
15+
uint16_t r = (argb >> 16) & 0xFF;
16+
uint16_t g = (argb >> 8) & 0xFF;
17+
uint16_t b = argb & 0xFF;
18+
19+
/* 8bits -> 16bits (255 -> 65535) */
20+
color->alpha = (a << 8) + a;
21+
color->red = (r << 8) + r;
22+
color->green = (g << 8) + g;
23+
color->blue = (b << 8) + b;
24+
}
25+
26+
static const pixman_format_code_t twin_pixman_format[3] = {
27+
[TWIN_A8] = PIXMAN_a8,
28+
[TWIN_RGB16] = PIXMAN_r5g6b5,
29+
[TWIN_ARGB32] = PIXMAN_a8r8g8b8};
30+
31+
static pixman_format_code_t twin_to_pixman_format(
32+
const twin_format_t twin_format)
33+
{
34+
return twin_pixman_format[twin_format];
35+
}
36+
37+
static const pixman_op_t twin_pixman_op[2] =
38+
{[TWIN_OVER] = PIXMAN_OP_OVER, [TWIN_SOURCE] = PIXMAN_OP_SRC};
39+
40+
static pixman_op_t twin_to_pixman_op(const twin_operator_t twin_op)
41+
{
42+
return twin_pixman_op[twin_op];
43+
}
44+
45+
#define create_pixman_image_from_twin_pixmap(pixmap) \
46+
({ \
47+
typeof(pixmap) _pixmap = (pixmap); \
48+
pixman_image_create_bits(twin_to_pixman_format((_pixmap)->format), \
49+
(_pixmap)->width, (_pixmap)->height, \
50+
(_pixmap)->p.argb32, (_pixmap)->stride); \
51+
})
52+
53+
static void pixmap_matrix_scale(pixman_image_t *src, twin_matrix_t *matrix)
54+
{
55+
pixman_transform_t transform;
56+
pixman_transform_init_identity(&transform);
57+
58+
pixman_fixed_t sx = matrix->m[0][0], sy = matrix->m[1][1];
59+
60+
pixman_transform_scale(&transform, NULL, sx, sy);
61+
pixman_image_set_transform(src, &transform);
62+
}
63+
64+
void twin_composite(twin_pixmap_t *_dst,
65+
twin_coord_t dst_x,
66+
twin_coord_t dst_y,
67+
twin_operand_t *_src,
68+
twin_coord_t src_x,
69+
twin_coord_t src_y,
70+
twin_operand_t *_msk,
71+
twin_coord_t msk_x,
72+
twin_coord_t msk_y,
73+
twin_operator_t operator,
74+
twin_coord_t width,
75+
twin_coord_t height)
76+
{
77+
pixman_image_t *src;
78+
if (_src->source_kind == TWIN_SOLID) {
79+
pixman_color_t source_pixel;
80+
twin_argb32_to_pixman_color(_src->u.argb, &source_pixel);
81+
src = pixman_image_create_solid_fill(&source_pixel);
82+
} else {
83+
twin_pixmap_t *src_pixmap = _src->u.pixmap;
84+
src = create_pixman_image_from_twin_pixmap(src_pixmap);
85+
86+
if (!twin_matrix_is_identity(&(src_pixmap->transform)))
87+
pixmap_matrix_scale(src, &(src_pixmap->transform));
88+
}
89+
90+
pixman_image_t *dst = create_pixman_image_from_twin_pixmap(_dst);
91+
92+
/* Set origin */
93+
twin_coord_t ox, oy;
94+
twin_pixmap_get_origin(_dst, &ox, &oy);
95+
ox += dst_x;
96+
oy += dst_y;
97+
98+
if (!_msk) {
99+
pixman_image_composite(twin_to_pixman_op(operator), src, NULL, dst,
100+
src_x, src_y, 0, 0, ox, oy, width, height);
101+
} else {
102+
pixman_image_t *msk =
103+
create_pixman_image_from_twin_pixmap(_msk->u.pixmap);
104+
pixman_image_composite(twin_to_pixman_op(operator), src, msk, dst,
105+
src_x, src_y, msk_x, msk_y, ox, oy, width,
106+
height);
107+
pixman_image_unref(msk);
108+
}
109+
110+
pixman_image_unref(src);
111+
pixman_image_unref(dst);
112+
}
113+
114+
void twin_fill(twin_pixmap_t *_dst,
115+
twin_argb32_t pixel,
116+
twin_operator_t operator,
117+
twin_coord_t left,
118+
twin_coord_t top,
119+
twin_coord_t right,
120+
twin_coord_t bottom)
121+
{
122+
/* offset */
123+
left += _dst->origin_x;
124+
top += _dst->origin_y;
125+
right += _dst->origin_x;
126+
bottom += _dst->origin_y;
127+
128+
/* clip */
129+
if (left < _dst->clip.left)
130+
left = _dst->clip.left;
131+
if (right > _dst->clip.right)
132+
right = _dst->clip.right;
133+
if (top < _dst->clip.top)
134+
top = _dst->clip.top;
135+
if (bottom > _dst->clip.bottom)
136+
bottom = _dst->clip.bottom;
137+
138+
pixman_image_t *dst = create_pixman_image_from_twin_pixmap(_dst);
139+
pixman_color_t color;
140+
twin_argb32_to_pixman_color(pixel, &color);
141+
pixman_image_fill_rectangles(
142+
twin_to_pixman_op(operator), dst, &color, 1,
143+
&(pixman_rectangle16_t){left, top, right - left, bottom - top});
144+
145+
twin_pixmap_damage(_dst, left, top, right, bottom);
146+
147+
pixman_image_unref(dst);
148+
}
149+
150+
/* Same function in draw.c */
151+
static twin_argb32_t _twin_apply_alpha(twin_argb32_t v)
152+
{
153+
uint16_t t1, t2, t3;
154+
twin_a8_t alpha = twin_get_8(v,
155+
#if __BYTE_ORDER == __BIG_ENDIAN
156+
0
157+
#else
158+
24
159+
#endif
160+
);
161+
162+
/* clear RGB data if alpha is zero */
163+
if (!alpha)
164+
return 0;
165+
166+
#if __BYTE_ORDER == __BIG_ENDIAN
167+
/* twin needs ARGB format */
168+
return alpha << 24 | twin_int_mult(twin_get_8(v, 24), alpha, t1) << 16 |
169+
twin_int_mult(twin_get_8(v, 16), alpha, t2) << 8 |
170+
twin_int_mult(twin_get_8(v, 8), alpha, t3) << 0;
171+
#else
172+
return alpha << 24 | twin_int_mult(twin_get_8(v, 0), alpha, t1) << 16 |
173+
twin_int_mult(twin_get_8(v, 8), alpha, t2) << 8 |
174+
twin_int_mult(twin_get_8(v, 16), alpha, t3) << 0;
175+
#endif
176+
}
177+
178+
void twin_premultiply_alpha(twin_pixmap_t *px)
179+
{
180+
int x, y;
181+
twin_pointer_t p;
182+
183+
if (px->format != TWIN_ARGB32)
184+
return;
185+
186+
for (y = 0; y < px->height; y++) {
187+
p.b = px->p.b + y * px->stride;
188+
189+
for (x = 0; x < px->width; x++)
190+
p.argb32[x] = _twin_apply_alpha(p.argb32[x]);
191+
}
192+
}

src/pixmap.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,20 @@
88

99
#include "twin_private.h"
1010

11+
#define IS_ALIGNED(p, alignment) ((p % alignment) == 0)
12+
#define ALIGN_UP(sz, alignment) \
13+
(((alignment) & ((alignment) - 1)) == 0 \
14+
? (((sz) + (alignment) - 1) & ~((alignment) - 1)) \
15+
: ((((sz) + (alignment) - 1) / (alignment)) * (alignment)))
1116
twin_pixmap_t *twin_pixmap_create(twin_format_t format,
1217
twin_coord_t width,
1318
twin_coord_t height)
1419
{
1520
twin_coord_t stride = twin_bytes_per_pixel(format) * width;
21+
/* Align stride to 4 bytes for proper uint32_t access in Pixman. */
22+
if (!IS_ALIGNED(stride, 4))
23+
stride = ALIGN_UP(stride, 4);
24+
1625
twin_area_t space = (twin_area_t) stride * height;
1726
twin_area_t size = sizeof(twin_pixmap_t) + space;
1827
twin_pixmap_t *pixmap = malloc(size);

0 commit comments

Comments
 (0)