-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Utilize pixman for efficient pixel manipulation #55
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
/* | ||
* Twin - A Tiny Window System | ||
* Copyright (c) 2024 National Cheng Kung University, Taiwan | ||
* 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]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See if the function can be accelerated by Pixman.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Observing the difference between using (left image) and not using (right image) _twin_apply_alpha, we know that _twin_apply_alpha performs the conversion from ABGR to ARGB.
According to the implementation in _twin_apply_alpha,
it also multiplies RBG channels with alpha value.
However, the public API in pixman.h doesn't provide the functions about ABGR to ARGB conversion and alpha premultiplication for user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check the inner function
_convertBGRtoARGB
in filesrc/image-png.c
which was a workaround for macOS.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran mado with gdb. The function _convertBGRtoARGB isn't executed because my operating system is not macOS.
/src/pixman.c#L172 is executed because my computer is a little-endian machine. The PNG data is originally in RGBA format as the following image, but it becomes ABGR format on a little-endian machine. In /src/pixman.c#L172, mado has already performed the ABGR-to-ARGB conversion for the requirement of the pixmap's pixel data.