1 #ifndef _Painter_AlphaBlend_h_
2 #define _Painter_AlphaBlend_h_
3 
4 namespace Upp {
5 
6 void AlphaBlend(RGBA *t, const RGBA& c, int alpha);
7 void AlphaBlend(RGBA *t, const RGBA *s, int alpha, int len);
8 void AlphaBlend(RGBA *t, const RGBA& c, int alpha, int len);
9 
10 #ifdef CPU_SIMD
11 
12 force_inline
BroadcastAlpha(i16x8 x)13 i16x8 BroadcastAlpha(i16x8 x)
14 {
15 #ifdef PLATFORM_MACOS
16 	return BroadcastLH0(x);
17 #else
18 	return BroadcastLH3(x);
19 #endif
20 }
21 
22 force_inline
Mul8(i16x8 x,int alpha)23 i16x8 Mul8(i16x8 x, int alpha)
24 {
25 	return i16all(alpha) * x >> 8;
26 }
27 
28 force_inline
MakeAlpha(i16x8 x)29 i16x8 MakeAlpha(i16x8 x)
30 {
31 	x = BroadcastAlpha(x);
32 #ifdef PLATFORM_MACOS
33 	x = i16x8(129, 129, 129, 128, 129, 129, 129, 128) * x >> 7;
34 #else
35 	x = i16x8(128, 129, 129, 129, 128, 129, 129, 129) * x >> 7; // a for alpha, 256*a/255 for color
36 #endif
37 	return i16all(256) - x; // 256 - a for alpha, 256 - 256*a/255 for color;
38 }
39 
40 force_inline
AlphaBlendSIMD(i16x8 t,i16x8 s,i16x8 alpha)41 i16x8 AlphaBlendSIMD(i16x8 t, i16x8 s, i16x8 alpha)
42 {
43 	return s + (t * alpha >> 8);
44 }
45 
46 force_inline
AlphaBlend1(RGBA * t,i16x8 s,i16x8 alpha)47 void AlphaBlend1(RGBA *t, i16x8 s, i16x8 alpha)
48 {
49 	StoreRGBA(t, AlphaBlendSIMD(LoadRGBA(t), s, alpha));
50 }
51 
52 force_inline
AlphaBlend2(RGBA * t,i16x8 s,i16x8 alpha)53 void AlphaBlend2(RGBA *t, i16x8 s, i16x8 alpha)
54 {
55 	StoreRGBA2(t, AlphaBlendSIMD(LoadRGBA2(t), s, alpha));
56 }
57 
58 force_inline
AlphaBlend4(RGBA * t,i16x8 sl,i16x8 al,i16x8 sh,i16x8 ah)59 void AlphaBlend4(RGBA *t, i16x8 sl, i16x8 al, i16x8 sh, i16x8 ah)
60 {
61 	i16x8 t4(t);
62 	PackRGBA(
63 		AlphaBlendSIMD(LoadRGBAL(t4), sl, al),
64 		AlphaBlendSIMD(LoadRGBAH(t4), sh, ah)
65 	).Store(t);
66 }
67 
68 force_inline
AlphaBlend(RGBA * t,const RGBA & c)69 void AlphaBlend(RGBA *t, const RGBA& c)
70 {
71 	i16x8 s = LoadRGBA(&c);
72 	StoreRGBA(t, AlphaBlendSIMD(LoadRGBA(t), s, MakeAlpha(s)));
73 }
74 
75 force_inline
AlphaBlend(RGBA * t,const RGBA & c,int alpha)76 void AlphaBlend(RGBA *t, const RGBA& c, int alpha)
77 {
78 	i16x8 s = Mul8(LoadRGBA(&c), alpha);
79 	StoreRGBA(t, AlphaBlendSIMD(LoadRGBA(t), s, MakeAlpha(s)));
80 }
81 
82 force_inline
AlphaBlend(RGBA * t,const RGBA & c,int alpha,int len)83 void AlphaBlend(RGBA *t, const RGBA& c, int alpha, int len)
84 {
85 	i16x8 s = Mul8(LoadRGBA2(c), alpha);
86 	i16x8 a = MakeAlpha(s);
87 	while(len >= 4) {
88 		AlphaBlend4(t, s, a, s, a);
89 		t += 4;
90 		len -= 4;
91 	}
92 	if(len & 2) {
93 		AlphaBlend2(t, s, a);
94 		t += 2;
95 	}
96 	if(len & 1)
97 		AlphaBlend1(t, s, a);
98 }
99 
100 force_inline
AlphaBlend(RGBA * t,const RGBA * s,int alpha,int len)101 void AlphaBlend(RGBA *t, const RGBA *s, int alpha, int len)
102 {
103 	if(alpha == 256) {
104 		while(len >= 4) {
105 			i16x8 m(s);
106 			i16x8 s0 = LoadRGBAL(m);
107 			i16x8 s1 = LoadRGBAH(m);
108 			AlphaBlend4(t, s0, MakeAlpha(s0), s1, MakeAlpha(s1));
109 			t += 4;
110 			s += 4;
111 			len -= 4;
112 		}
113 		if(len & 2) {
114 			i16x8 s0 = LoadRGBA2(s);
115 			AlphaBlend2(t, s0, MakeAlpha(s0));
116 			t += 2;
117 			s += 2;
118 		}
119 		if(len & 1) {
120 			i16x8 s0 = LoadRGBA(s);
121 			AlphaBlend1(t, s0, MakeAlpha(s0));
122 		}
123 	}
124 	else {
125 		while(len >= 4) {
126 			i16x8 m(s);
127 			i16x8 s0 = Mul8(LoadRGBAL(m), alpha);
128 			i16x8 s1 = Mul8(LoadRGBAH(m), alpha);
129 			AlphaBlend4(t, s0, MakeAlpha(s0), s1, MakeAlpha(s1));
130 			t += 4;
131 			s += 4;
132 			len -= 4;
133 		}
134 		if(len & 2) {
135 			i16x8 s0 = Mul8(LoadRGBA2(s), alpha);
136 			AlphaBlend2(t, s0, MakeAlpha(s0));
137 			t += 2;
138 			s += 2;
139 		}
140 		if(len & 1) {
141 			i16x8 s0 = Mul8(LoadRGBA(s), alpha);
142 			AlphaBlend1(t, s0, MakeAlpha(s0));
143 		}
144 	}
145 }
146 
147 #else
148 
149 force_inline
AlphaBlend__(RGBA & t,const RGBA & c)150 void AlphaBlend__(RGBA& t, const RGBA& c)
151 {
152 	int alpha = 256 - (c.a + (c.a >> 7));
153 	t.r = c.r + (alpha * t.r >> 8);
154 	t.g = c.g + (alpha * t.g >> 8);
155 	t.b = c.b + (alpha * t.b >> 8);
156 	t.a = c.a + ((256 - c.a) * t.a >> 8);
157 }
158 
159 force_inline
AlphaBlend__(RGBA & t,const RGBA & c,int cover)160 void AlphaBlend__(RGBA& t, const RGBA& c, int cover)
161 {
162 	int a = c.a * cover >> 8;
163 	int alpha = 256 - a - (a >> 7);
164 	t.r = (c.r * cover >> 8) + (alpha * t.r >> 8);
165 	t.g = (c.g * cover >> 8) + (alpha * t.g >> 8);
166 	t.b = (c.b * cover >> 8) + (alpha * t.b >> 8);
167 	t.a = a + (alpha * t.a >> 8);
168 }
169 
170 force_inline
AlphaBlend(RGBA * t,const RGBA & c)171 void AlphaBlend(RGBA *t, const RGBA& c)
172 {
173 	AlphaBlend__(*t, c);
174 }
175 
176 force_inline
AlphaBlend(RGBA * t,const RGBA & c,int alpha)177 void AlphaBlend(RGBA *t, const RGBA& c, int alpha)
178 {
179 	AlphaBlend__(*t, c, alpha);
180 }
181 
182 force_inline
AlphaBlend(RGBA * t,const RGBA & c,int alpha,int len)183 void AlphaBlend(RGBA *t, const RGBA& c, int alpha, int len)
184 {
185 	RGBA c1;
186 	if(alpha != 256)
187 		c1 = Mul8(c, alpha);
188 	else
189 		c1 = c;
190 	RGBA *e = t + len;
191 	while(t < e)
192 		AlphaBlend__(*t++, c1);
193 }
194 
195 force_inline
AlphaBlend(RGBA * t,const RGBA * s,int alpha,int len)196 void AlphaBlend(RGBA *t, const RGBA *s, int alpha, int len)
197 {
198 	if(alpha == 256) {
199 		for(int i = 0; i < len; i++) {
200 			if(s[i].a == 255)
201 				t[i] = s[i];
202 			else
203 				AlphaBlend__(t[i], s[i]);
204 		}
205 	}
206 	else {
207 		const RGBA *e = t + len;
208 		while(t < e)
209 			AlphaBlend__(*t++, *s++, alpha);
210 	}
211 }
212 
213 #endif
214 
215 };
216 
217 #endif
218