evas/map: support aa in basic c computation.

This commit is contained in:
ChunEon Park 2014-11-26 15:12:25 +09:00
parent 215b52ecc1
commit a3b3e1ecad
5 changed files with 327 additions and 13 deletions

View File

@ -350,6 +350,7 @@ lib/evas/common/evas_font_compress_draw.c \
lib/evas/common/evas_map_image_internal.c \
lib/evas/common/evas_map_image_core.c \
lib/evas/common/evas_map_image_loop.c \
lib/evas/common/evas_map_image_aa.c \
lib/evas/common/evas_scale_smooth_scaler.c \
lib/evas/common/evas_scale_smooth_scaler_down.c \
lib/evas/common/evas_scale_smooth_scaler_downx.c \

View File

@ -30,6 +30,8 @@ struct _Span
struct _Line
{
Span span[2];
int aa_cov[2];
int aa_len[2];
};
static inline FPc
@ -82,6 +84,8 @@ _interpolated_clip_span(Span *s, int c1, int c2, Eina_Bool interp_col)
}
}
#include "evas_map_image_aa.c"
// 12.63 % of time - this can improve
static void
_calc_spans(RGBA_Map_Point *p, Line *spans, int ystart, int yend, int cx, int cy EINA_UNUSED, int cw, int ch EINA_UNUSED)

View File

@ -0,0 +1,297 @@
/*
* evas_map_image_aa.c
*
* Created on: Nov 21, 2014
* Author: hermet
*/
#define READY_TX() \
{ \
if (eidx == 0) \
{ \
tx[0] = edge2.x; \
tx[1] = spans[y].span[0].x[0]; \
} \
else \
{ \
tx[0] = spans[y].span[0].x[1]; \
tx[1] = edge2.x; \
} \
}
#define READY_TX2() \
{ \
if (eidx == 0) \
{ \
tx2[0] = edge2.x; \
tx2[1] = edge1.x; \
} \
else \
{ \
tx2[0] = edge1.x; \
tx2[1] = edge2.x; \
} \
}
#define PUSH_EDGES(xx) \
{ \
if (!leftover) \
{ \
edge1.x = edge2.x; \
edge1.y = edge2.y; \
edge2.x = (xx); \
edge2.y = y; \
} \
else \
{ \
edge1.y = edge2.y; \
edge2.y = y; \
} \
reset_tx2 = EINA_TRUE; \
}
//Vertical Inside Direction
#define VERT_INSIDE(rewind, y_advance) \
{ \
int cov_range = edge2.y - edge1.y; \
int coverage = (256 / (cov_range + 1)); \
int ry; \
int val; \
for (ry = 1; ry < ((rewind) + 1); ry++) \
{ \
int ridx = (y - ry) + (y_advance); \
if (spans[ridx].aa_len[eidx] > 1) continue; \
if (eidx == 1) \
val = (256 - (coverage * (ry + (cov_range - (rewind))))); \
else \
val = (coverage * (ry + (cov_range - (rewind)))); \
if ((spans[ridx].aa_len[eidx] == 0) || \
(val < spans[ridx].aa_cov[eidx])) \
spans[ridx].aa_cov[eidx] = val; \
spans[ridx].aa_len[eidx] = 1; \
} \
prev_aa = 4; \
}
//Vertical Outside Direction
#define VERT_OUTSIDE(rewind, y_advance, cov_range) \
{ \
int coverage = (256 / ((cov_range) + 1)); \
int ry = 1; \
for (; ry < ((rewind) + 1); ry++) \
{ \
int ridx = (y - ry) + (y_advance); \
if (spans[ridx].aa_len[(eidx)] > 1) continue; \
spans[ridx].aa_len[(eidx)] = 1; \
if (eidx == 1) \
{ \
spans[ridx].aa_cov[(eidx)] = \
(coverage * (ry + (cov_range - (rewind)))); \
} \
else \
{ \
spans[ridx].aa_cov[(eidx)] = \
(256 - (coverage * (ry + ((cov_range) - (rewind))))); \
} \
} \
prev_aa = 2; \
}
//Horizontal Inside Direction
#define HORIZ_INSIDE(yy, xx, xx2) \
{ \
if (((xx) - (xx2)) > spans[(yy)].aa_len[(eidx)]) \
{ \
spans[(yy)].aa_len[(eidx)] = ((xx) - (xx2)); \
spans[(yy)].aa_cov[(eidx)] = (256 / (spans[(yy)].aa_len[(eidx)] + 1)); \
} \
}
//Horizontal Outside Direction
#define HORIZ_OUTSIDE(yy, xx, xx2) \
{ \
if (((xx) - (xx2)) > spans[(yy)].aa_len[(eidx)]) \
{ \
spans[(yy)].aa_len[(eidx)] = ((xx) - (xx2)); \
spans[(yy)].aa_cov[(eidx)] = (256 / (spans[(yy)].aa_len[(eidx)] + 1)); \
} \
}
static inline DATA32
_aa_coverage_apply(Line *line, int ww, int w, DATA32 val)
{
//Left Edge Anti Anliasing
if ((w - line->aa_len[0]) < ww)
{
return MUL_256((line->aa_cov[0] * (w - ww + 1)), val);
}
//Right Edge Anti Aliasing
if (line->aa_len[1] >= ww)
{
return MUL_256(256 - (line->aa_cov[1] * (line->aa_len[1] - ww + 1)),
val);
}
return val;
}
void
_calc_aa_edges_internal(Line *spans, int eidx, int ystart, int yend)
{
int y;
Evas_Coord_Point edge1 = { -1, -1 }; //prev-previous edge pixel
Evas_Coord_Point edge2 = { -1, -1 }; //previous edge pixel
/* store larger to tx[0] between prev and current edge's x positions. */
int tx[2] = {0, 0};
/* store lager to tx2[0] between edge1 and edge2's x positions. */
int tx2[2] = {0, 0};
/* previous edge anti-aliased type.
2: vertical outside
4: vertical inside */
int prev_aa = 0;
Eina_Bool reset_tx2 = EINA_TRUE;
yend -= ystart;
//Find Start Edge
for (y = 0; y < yend; y++)
{
if (spans[y].span[0].x[0] == -1) continue;
edge1.x = edge2.x = spans[y].span[0].x[eidx];
edge1.y = edge2.y = y;
break;
}
//Calculates AA Edges
for (y++; y <= yend; y++)
{
Eina_Bool leftover = EINA_FALSE;
if (spans[y].span[0].x[eidx] == -1) leftover = EINA_TRUE;
if (!leftover) READY_TX()
//Case1. Outside Incremental
if (tx[0] > tx[1])
{
//Horizontal Edge
if ((y - edge2.y) == 1)
{
HORIZ_OUTSIDE(y, tx[0], tx[1])
}
//Vertical Edge
else if (tx[0] > tx[1])
{
VERT_OUTSIDE((y - edge2.y), 0, (y - edge2.y))
//Just in case: 1 pixel alias next to vertical edge?
if (abs(spans[(y + 1)].span[0].x[eidx] -
spans[y].span[0].x[eidx]) >= 1)
{
HORIZ_OUTSIDE(y, tx[0], tx[1])
}
}
PUSH_EDGES(spans[y].span[0].x[eidx])
}
//Case2. Inside Incremental
else if (tx[1] > tx[0])
{
//Just in case: direction is reversed at the outside vertical edge?
if (prev_aa == 2)
{
VERT_OUTSIDE((y - edge2.y), 0, (y - edge2.y))
edge1.x = spans[y - 1].span[0].x[eidx];
edge1.y = y - 1;
edge2.x = spans[y].span[0].x[eidx];
edge2.y = y;
}
else
PUSH_EDGES(spans[y].span[0].x[eidx])
/* Find next edge. We go forward 2 more index since this logic
computes aa edges by looking back in advance 2 spans. */
for (y++; y <= (yend + 2); y++)
{
leftover = EINA_FALSE;
if ((spans[y].span[0].x[eidx] == -1) || (y > yend))
leftover = EINA_TRUE;
if (!leftover) READY_TX()
if (reset_tx2) READY_TX2()
//Case 1. Inside Direction
if (tx[1] > tx[0])
{
//Horizontal Edge
if ((edge2.y - edge1.y) == 1)
{
HORIZ_INSIDE(edge1.y, tx2[0], tx2[1]);
}
//Vertical Edge
else if ((tx2[0] - tx2[1]) == 1)
{
VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y))
}
//Just in case: Right Side Square Edge...?
else if (prev_aa == 4)
{
VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y))
if ((y - edge2.y) == 1)
{
HORIZ_INSIDE((edge2.y - 1), edge2.x,
spans[y].span[0].x[eidx]);
}
}
PUSH_EDGES(spans[y].span[0].x[eidx])
}
//Case 2. Reversed. Outside Direction
else if (tx[1] < tx[0])
{
//Horizontal Edge
if ((edge2.y - edge1.y) == 1)
HORIZ_INSIDE(edge1.y, tx2[0], tx2[1])
//Vertical Edge
else
VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y))
PUSH_EDGES(spans[y].span[0].x[eidx])
break;
}
}
}
}
y = yend;
//Leftovers for verticals.
if (prev_aa == 2)
{
if (((eidx == 0) && (edge1.x > edge2.x)) ||
((eidx == 1) && (edge1.x < edge2.x)))
VERT_OUTSIDE((y - edge2.y + 1), 1, (edge2.y - edge1.y));
}
else if (prev_aa == 4)
{
if (((eidx == 0) && (edge1.x < edge2.x)) ||
((eidx == 1) && (edge1.x > edge2.x)))
{
VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y))
VERT_INSIDE((y - edge2.y) + 1, 1);
}
}
}
static void
_calc_aa_edges(Line *spans, int ystart, int yend)
{
//FIXME: support 2 span case.
//left side
_calc_aa_edges_internal(spans, 0, ystart, yend);
//right side
_calc_aa_edges_internal(spans, 1, ystart, yend);
}

View File

@ -76,12 +76,20 @@ FUNC_NAME(RGBA_Image *src, RGBA_Image *dst,
// calculate the spans list
_calc_spans(p, spans, ystart, yend, cx, cy, cw, ch);
// calculate anti alias edges
if (anti_alias) _calc_aa_edges(spans, ystart, yend);
// walk through spans and render
// if operation is solid, bypass buf and draw func and draw direct to dst
direct = 0;
/* FIXME: even if anti-alias is enabled, only edges may require the
pixels composition. we can optimize it. */
if ((!src->cache_entry.flags.alpha) && (!dst->cache_entry.flags.alpha) &&
(mul_col == 0xffffffff) && (!havea))
(mul_col == 0xffffffff) && (!havea) && (!anti_alias))
{
direct = 1;
}
@ -96,9 +104,10 @@ FUNC_NAME(RGBA_Image *src, RGBA_Image *dst,
func = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, mul_col, dst->cache_entry.flags.alpha, cw, render_op);
else
func = evas_common_gfx_func_composite_pixel_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, cw, render_op);
src->cache_entry.flags.alpha = pa;
}
if (anti_alias) src->cache_entry.flags.alpha = EINA_TRUE;
else src->cache_entry.flags.alpha = pa;
}
if (havecol == 0)
{
#undef COLMUL

View File

@ -31,12 +31,13 @@
while (ww > 0)
{
DATA32 val1 = 0x00000000;
# ifdef COLBLACK
*d = 0xff000000; // col
# else //COLBLACK
FPc uu1, vv1, uu2, vv2;
FPc rv, ru;
DATA32 val1, val2, val3, val4;
DATA32 val2, val3, val4;
uu1 = u;
if (uu1 < 0) uu1 = 0;
@ -156,19 +157,19 @@
val1 = INTERP_256(rv, val3, val1); // col
# ifdef COLMUL
# ifdef COLSAME
*d = MUL4_SYM(c1, val1);
val1 = MUL4_SYM(c1, val1);
# else //COLSAME
val2 = INTERP_256((cv >> 16), c2, c1); // col
*d = MUL4_SYM(val2, val1); // col
val1 = MUL4_SYM(val2, val1); // col
cv += cd; // col
# endif //COLSAME
# else
*d = val1;
# endif //COLMUL
# endif //SCALE_USING_MMX
u += ud;
v += vd;
# endif //COLBLACK
if (anti_alias) val1 = _aa_coverage_apply(line, ww, w, val1);
*d = val1;
d++;
ww--;
}
@ -200,9 +201,9 @@
while (ww > 0)
{
DATA32 val1 = 0x00000000;
# ifdef COLMUL
# ifndef COLBLACK
DATA32 val1;
# ifdef COLSAME
# else
DATA32 cval; // col
@ -211,7 +212,7 @@
# endif //COLMUL
# ifdef COLBLACK
*d = 0xff000000; // col
val1 = 0xff000000; // col
# else //COLBLACK
s = sp + ((v >> (FP + FPI)) * sw) + (u >> (FP + FPI));
# ifdef COLMUL
@ -225,7 +226,7 @@
MUL4_SYM_NEON(d0, d1, d4)
VMOV_R2M_NEON(q0, d0, d);
# else
*d = MUL4_SYM(c1, val1);
val1 = MUL4_SYM(c1, val1);
# endif //SCALE_USING_NEON
# else //COLSAME
/* XXX: this neon is broken! :( FIXME
@ -242,18 +243,20 @@
# else
*/
cval = INTERP_256((cv >> 16), c2, c1); // col
*d = MUL4_SYM(cval, val1);
val1 = MUL4_SYM(cval, val1);
cv += cd; // col
/*
# endif
*/
# endif //COLSAME
# else //COLMUL
*d = *s;
val1 = *s;
# endif //COLMUL
u += ud;
v += vd;
# endif //COLBLACK
if (anti_alias) val1 = _aa_coverage_apply(line, ww, w, val1);
*d = val1;
d++;
ww--;
}