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. Briefly, include:
 - pixman_image_composite: image compositing
 - pixman_fill_rect: use pixman_image_fill_rectangles to fill the image
   with retangles
 - pixman_image_fill_boxes: span is filled with the boxs

Close #6
  • Loading branch information
Bennctu committed Oct 1, 2024
1 parent 9530bc5 commit 6332572
Show file tree
Hide file tree
Showing 16 changed files with 332 additions and 14 deletions.
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ libtwin.a_includes-y := \
libtwin.a_files-$(CONFIG_LOGGING) += src/log.c
libtwin.a_files-$(CONFIG_CURSOR) += src/cursor.c

# Pixman
ifeq ($(CONFIG_PIXMAN), y)
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)
endif

# Image loaders

ifeq ($(CONFIG_LOADER_JPEG), y)
Expand Down Expand Up @@ -118,6 +125,10 @@ endif

CFLAGS += -include config.h

ifeq ($(CONFIG_PIXMAN), y)
CFLAGS += $(shell pkg-config --cflags pixman-1)
endif

check_goal := $(strip $(MAKECMDGOALS))
ifneq ($(check_goal), config)
include mk/common.mk
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
14 changes: 14 additions & 0 deletions apps/animation.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,27 @@ static void _apps_animation_paint(apps_animation_t *anim)
} else {
current_frame = anim->pix;
}
#if defined(CONFIG_PIXMAN)
pixman_image_t *src = create_pixman_image_from_twin_pixmap(current_frame);

pixman_image_t *dst =
create_pixman_image_from_twin_pixmap(_apps_animation_pixmap(anim));

twin_coord_t ox, oy;
twin_pixmap_get_origin(_apps_animation_pixmap(anim), &ox, &oy);
pixman_image_composite(PIXMAN_OP_SRC, src, NULL, dst, 0, 0, 0, 0, ox, oy,
current_frame->width, current_frame->height);

pixman_image_unref(src);
pixman_image_unref(dst);
#else
twin_operand_t srcop = {
.source_kind = TWIN_PIXMAP,
.u.pixmap = current_frame,
};
twin_composite(_apps_animation_pixmap(anim), 0, 0, &srcop, 0, 0, NULL, 0, 0,
TWIN_SOURCE, current_frame->width, current_frame->height);
#endif
}

static twin_time_t _apps_animation_timeout(twin_time_t maybe_unused now,
Expand Down
30 changes: 29 additions & 1 deletion apps/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@ static twin_pixmap_t *load_background(twin_screen_t *screen, const char *path)
twin_pixmap_destroy(raw_background);
return twin_make_pattern();
}
#if defined(CONFIG_PIXMAN)
pixman_image_t *srcop_pix =
create_pixman_image_from_twin_pixmap(raw_background);

pixman_transform_t transform;
pixman_transform_init_identity(&transform);

pixman_fixed_t sx, sy;
sx = twin_fixed_div(twin_int_to_fixed(raw_background->width),
twin_int_to_fixed(screen->width));
sy = twin_fixed_div(twin_int_to_fixed(raw_background->height),
twin_int_to_fixed(screen->height));

pixman_transform_scale(&transform, NULL, sx, sy);
pixman_image_set_transform(srcop_pix, &transform);

pixman_image_t *scaled_background_pix =
create_pixman_image_from_twin_pixmap(scaled_background);

twin_coord_t ox, oy;
twin_pixmap_get_origin(scaled_background, &ox, &oy);
pixman_image_composite(PIXMAN_OP_SRC, srcop_pix, NULL,
scaled_background_pix, 0, 0, 0, 0, ox, oy,
screen->width, screen->height);

pixman_image_unref(srcop_pix);
pixman_image_unref(scaled_background_pix);
#else
twin_fixed_t sx, sy;
sx = twin_fixed_div(twin_int_to_fixed(raw_background->width),
twin_int_to_fixed(screen->width));
Expand All @@ -60,7 +88,7 @@ static twin_pixmap_t *load_background(twin_screen_t *screen, const char *path)
};
twin_composite(scaled_background, 0, 0, &srcop, 0, 0, NULL, 0, 0,
TWIN_SOURCE, screen->width, screen->height);

#endif
twin_pixmap_destroy(raw_background);

return scaled_background;
Expand Down
91 changes: 85 additions & 6 deletions apps/multi.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ static void apps_line_start(twin_screen_t *screen, int x, int y, int w, int h)
twin_fixed_t fy;

twin_path_translate(stroke, D(200), D(200));
#if defined(CONFIG_PIXMAN)
pixman_fill_rect(pixmap, &(pixman_color_t){0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF},
pixmap->clip.left, pixmap->clip.top, w, h);
#else
twin_fill(pixmap, 0xffffffff, TWIN_SOURCE, 0, 0, w, h);
#endif

twin_window_set_name(window, "line");

Expand All @@ -41,21 +46,30 @@ static void apps_circletext_start(twin_screen_t *screen,
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
int wid = window->client.right - window->client.left;
int hei = window->client.bottom - window->client.top;
twin_pixmap_t *pixmap = window->pixmap;
twin_path_t *path = twin_path_create();
twin_path_t *pen = twin_path_create();

#if defined(CONFIG_PIXMAN)
twin_pixmap_t *alpha = twin_pixmap_create(TWIN_A8, wid, hei);
int s;
twin_operand_t source, mask;

twin_rect_t win_clip = twin_pixmap_get_clip(window->pixmap);
pixman_fill_rect(window->pixmap,
&(pixman_color_t){0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF},
win_clip.left, win_clip.top, wid, hei);
#else
twin_pixmap_t *alpha = twin_pixmap_create(TWIN_A8, wid, hei);
twin_pixmap_t *pixmap = window->pixmap;
twin_fill(pixmap, 0xffffffff, TWIN_SOURCE, 0, 0, wid, hei);
#endif

twin_window_set_name(window, "circletext");

twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
twin_path_circle(pen, 0, 0, D(1));

twin_path_translate(path, D(200), D(200));
twin_path_set_font_size(path, D(15));
int s;
for (s = 0; s < 41; s++) {
twin_state_t state = twin_path_save(path);
twin_path_rotate(path, twin_degrees_to_angle(9 * s));
Expand All @@ -66,12 +80,31 @@ static void apps_circletext_start(twin_screen_t *screen,
twin_fill_path(alpha, path, 0, 0);
twin_path_destroy(path);
twin_path_destroy(pen);

#if defined(CONFIG_PIXMAN)
pixman_image_t *mask = create_pixman_image_from_twin_pixmap(alpha);
pixman_image_t *source = pixman_image_create_solid_fill(
&(pixman_color_t){0x0000, 0x0000, 0x0000, 0xFFFF});
pixman_image_t *dst = create_pixman_image_from_twin_pixmap(window->pixmap);

twin_coord_t ox, oy;
twin_pixmap_get_origin(window->pixmap, &ox, &oy);
pixman_image_composite(PIXMAN_OP_OVER, source, mask, dst, 0, 0, 0, 0, ox,
oy, wid, hei);

pixman_image_unref(source);
pixman_image_unref(mask);
pixman_image_unref(dst);
#else
twin_operand_t source, mask;
source.source_kind = TWIN_SOLID;
source.u.argb = 0xff000000;
mask.source_kind = TWIN_PIXMAP;
mask.u.pixmap = alpha;
twin_composite(pixmap, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER, wid,
hei);
#endif

twin_pixmap_destroy(alpha);
twin_window_show(window);
}
Expand All @@ -90,13 +123,16 @@ static void apps_quickbrown_start(twin_screen_t *screen,
twin_path_t *path = twin_path_create();
twin_path_t *pen = twin_path_create();
twin_pixmap_t *alpha = twin_pixmap_create(TWIN_A8, wid, hei);
twin_operand_t source, mask;
twin_fixed_t fx, fy;
int s;

twin_window_set_name(window, "Quick Brown");

#if defined(CONFIG_PIXMAN)
pixman_fill_rect(pixmap, &(pixman_color_t){0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF},
pixmap->clip.left, pixmap->clip.top, w, h);
#else
twin_fill(pixmap, 0xffffffff, TWIN_SOURCE, 0, 0, wid, hei);
#endif

twin_path_circle(pen, 0, 0, D(1));

Expand All @@ -113,12 +149,29 @@ static void apps_quickbrown_start(twin_screen_t *screen,
twin_fill_path(alpha, path, 0, 0);
twin_path_destroy(path);
twin_path_destroy(pen);
#if defined(CONFIG_PIXMAN)
pixman_image_t *mask = create_pixman_image_from_twin_pixmap(alpha);
pixman_image_t *src = pixman_image_create_solid_fill(
&(pixman_color_t){0x0000, 0x0000, 0x0000, 0xFFFF});
pixman_image_t *dst = create_pixman_image_from_twin_pixmap(pixmap);

twin_coord_t ox, oy;
twin_pixmap_get_origin(pixmap, &ox, &oy);
pixman_image_composite(PIXMAN_OP_OVER, src, mask, dst, 0, 0, 0, 0, ox, oy,
wid, hei);

pixman_image_unref(src);
pixman_image_unref(mask);
pixman_image_unref(dst);
#else
twin_operand_t source, mask;
source.source_kind = TWIN_SOLID;
source.u.argb = 0xff000000;
mask.source_kind = TWIN_PIXMAP;
mask.u.pixmap = alpha;
twin_composite(pixmap, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER, wid,
hei);
#endif
twin_pixmap_destroy(alpha);
twin_window_show(window);
}
Expand All @@ -133,13 +186,17 @@ static void apps_ascii_start(twin_screen_t *screen, int x, int y, int w, int h)
twin_path_t *path = twin_path_create();
twin_path_t *pen = twin_path_create();
twin_pixmap_t *alpha = twin_pixmap_create(TWIN_A8, wid, hei);
twin_operand_t source, mask;
twin_fixed_t fx, fy;
int s;

twin_window_set_name(window, "ASCII");

#if defined(CONFIG_PIXMAN)
pixman_fill_rect(pixmap, &(pixman_color_t){0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF},
pixmap->clip.left, pixmap->clip.top, w, h);
#else
twin_fill(pixmap, 0xffffffff, TWIN_SOURCE, 0, 0, wid, hei);
#endif
twin_path_circle(pen, 0, 0, D(1));

fx = D(3);
Expand All @@ -161,12 +218,29 @@ static void apps_ascii_start(twin_screen_t *screen, int x, int y, int w, int h)
twin_fill_path(alpha, path, 0, 0);
twin_path_destroy(path);
twin_path_destroy(pen);
#if defined(CONFIG_PIXMAN)
pixman_image_t *mask = create_pixman_image_from_twin_pixmap(alpha);
pixman_image_t *src = pixman_image_create_solid_fill(
&(pixman_color_t){0x0000, 0x0000, 0x0000, 0xFFFF});
pixman_image_t *dst = create_pixman_image_from_twin_pixmap(pixmap);

twin_coord_t ox, oy;
twin_pixmap_get_origin(pixmap, &ox, &oy);
pixman_image_composite(PIXMAN_OP_OVER, src, mask, dst, 0, 0, 0, 0, ox, oy,
wid, hei);

pixman_image_unref(src);
pixman_image_unref(mask);
pixman_image_unref(dst);
#else
twin_operand_t source, mask;
source.source_kind = TWIN_SOLID;
source.u.argb = 0xff000000;
mask.source_kind = TWIN_PIXMAP;
mask.u.pixmap = alpha;
twin_composite(pixmap, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER, wid,
hei);
#endif
twin_pixmap_destroy(alpha);
twin_window_show(window);
}
Expand All @@ -184,7 +258,12 @@ static void apps_jelly_start(twin_screen_t *screen, int x, int y, int w, int h)

twin_window_set_name(window, "Jelly");

#if defined(CONFIG_PIXMAN)
pixman_fill_rect(pixmap, &(pixman_color_t){0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF},
pixmap->clip.left, pixmap->clip.top, wid, hei);
#else
twin_fill(pixmap, 0xffffffff, TWIN_SOURCE, 0, 0, wid, hei);
#endif

fx = D(3);
fy = D(8);
Expand Down
4 changes: 4 additions & 0 deletions configs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ config CURSOR
bool "Manipulate cursor"
default n

config PIXMAN
bool "Pixman to pixel manipulation"
default y

endmenu

menu "Image Loaders"
Expand Down
1 change: 1 addition & 0 deletions configs/defconfig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
CONFIG_BACKEND_SDL=y
CONFIG_PIXMAN=y
CONFIG_LOADER_PNG=y
CONFIG_LOADER_JPEG=y
CONFIG_LOADER_GIF=y
Expand Down
31 changes: 31 additions & 0 deletions include/twin.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
#include <stdbool.h>
#include <stdint.h>

#if defined(CONFIG_PIXMAN)
#include <pixman.h>
#endif

typedef uint8_t twin_a8_t;
typedef uint16_t twin_a16_t;
typedef uint16_t twin_rgb16_t;
Expand Down Expand Up @@ -984,6 +988,33 @@ bool twin_pixmap_transparent(twin_pixmap_t *pixmap,

bool twin_pixmap_dispatch(twin_pixmap_t *pixmap, twin_event_t *event);

/*
* pixman.c
*/

#if defined(CONFIG_PIXMAN)
void twin_argb32_to_pixman_color(twin_argb32_t argb, pixman_color_t *color);

pixman_format_code_t twin_to_pixman_format(twin_format_t twin_format);

pixman_op_t twin_to_pixman_op(twin_operator_t twin_op);

void pixman_fill_rect(twin_pixmap_t *pixmap,
const pixman_color_t *color,
int origin_x,
int origin_y,
int width,
int height);

#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); \
})
#endif

/*
* poly.c
*/
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
Loading

0 comments on commit 6332572

Please sign in to comment.