1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "soft_blit.h"
17 #include <string>
18 #include <unordered_map>
19 #include <algorithm>
20 #include "display_test.h"
21
22 #define R_PIX_OFFSET 0
23 #define G_PIX_OFFSET 8
24 #define B_PIX_OFFSET 16
25 #define A_PIX_OFFSET 24
26
27 namespace {
28 const int MAX_FLOAT_TO_INT32 = 2147483520;
29 const int MIN_FLOAT_TO_INT32 = -2147483520;
30
31 using BlendFunction = void (*)(ColorRGBAf &src, ColorRGBAf &dst);
32
RgbaGetR(uint32_t color)33 static inline uint32_t RgbaGetR(uint32_t color)
34 {
35 return ((color >> 0) & 0xFF);
36 }
37
RgbaGetG(uint32_t color)38 static inline uint32_t RgbaGetG(uint32_t color)
39 {
40 const uint32_t shift = 8;
41 const uint32_t mask = 0xFF;
42 return ((color >> shift) & mask);
43 }
44
RgbaGetB(uint32_t color)45 static inline uint32_t RgbaGetB(uint32_t color)
46 {
47 const uint32_t shift = 16;
48 const uint32_t mask = 0xFF;
49 return ((color >> shift) & mask);
50 }
51
RgbaGetA(uint32_t color)52 static inline uint32_t RgbaGetA(uint32_t color)
53 {
54 const uint32_t shift = 24;
55 const uint32_t mask = 0xFF;
56 return ((color >> shift) & mask);
57 }
58
ColorSetARGB(uint8_t r,uint8_t g,uint8_t b,uint8_t a)59 static constexpr inline uint32_t ColorSetARGB(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
60 {
61 return (r << R_PIX_OFFSET) | (g << G_PIX_OFFSET) | (b << B_PIX_OFFSET) | (a << A_PIX_OFFSET);
62 }
63
64 // blend none
65 /*
66 fs: sa fd: 1.0-sa
67 pixel = (foreground x fs + background x fd)
68 */
BlendNone(const ColorRGBAf & src,ColorRGBAf & dst)69 static inline void BlendNone(const ColorRGBAf &src, ColorRGBAf &dst)
70 {
71 dst.mR = src.mR * src.mA + dst.mR * (1 - src.mA);
72 dst.mG = src.mG * src.mA + dst.mG * (1 - src.mA);
73 dst.mB = src.mB * src.mA + dst.mB * (1 - src.mA);
74 dst.mA = src.mA * src.mA + dst.mA * (1 - src.mA);
75 }
76
77 // blend clear
BlendClear(ColorRGBAf & src,ColorRGBAf & dst)78 static inline void BlendClear(ColorRGBAf &src, ColorRGBAf &dst)
79 {
80 (void)src;
81 dst.mA = 0;
82 dst.mR = 0;
83 dst.mG = 0;
84 dst.mB = 0;
85 }
86
87 // blend src
BlendSrc(const ColorRGBAf & src,ColorRGBAf & dst)88 static inline void BlendSrc(const ColorRGBAf &src, ColorRGBAf &dst)
89 {
90 dst = src;
91 }
92
93 // blend src over
BlendSrcOver(ColorRGBAf & src,ColorRGBAf & dst)94 static inline void BlendSrcOver(ColorRGBAf &src, ColorRGBAf &dst)
95 {
96 // the display_gfx has Premultiplied
97 src.mR *= src.mA;
98 src.mG *= src.mA;
99 src.mB *= src.mA;
100
101 dst.mR = src.mR + (1 - src.mA) * dst.mR;
102 dst.mG = src.mG + (1 - src.mA) * dst.mG;
103 dst.mB = src.mB + (1 - src.mA) * dst.mB;
104 dst.mA = src.mA + (1 - src.mA) * dst.mA;
105 }
106
107 // blend src in
BlendSrcIn(const ColorRGBAf & src,ColorRGBAf & dst)108 static inline void BlendSrcIn(const ColorRGBAf &src, ColorRGBAf &dst)
109 {
110 dst.mR = src.mR * dst.mA;
111 dst.mG = src.mG * dst.mA;
112 dst.mB = src.mB * dst.mA;
113 dst.mA = src.mA * dst.mA;
114 }
115
116 // blend src out
BlendSrcOut(const ColorRGBAf & src,ColorRGBAf & dst)117 static inline void BlendSrcOut(const ColorRGBAf &src, ColorRGBAf &dst)
118 {
119 dst.mR = (1 - dst.mA) * src.mR;
120 dst.mG = (1 - dst.mA) * src.mG;
121 dst.mB = (1 - dst.mA) * src.mB;
122 dst.mA = (1 - dst.mA) * src.mA;
123 }
124
125 // blend src Atop
BlendAtop(const ColorRGBAf & src,ColorRGBAf & dst)126 static inline void BlendAtop(const ColorRGBAf &src, ColorRGBAf &dst)
127 {
128 dst.mR = dst.mA * src.mR + (1 - src.mA) * dst.mR;
129 dst.mG = dst.mA * src.mG + (1 - src.mA) * dst.mG;
130 dst.mB = dst.mA * src.mB + (1 - src.mA) * dst.mB;
131 dst.mA = dst.mA;
132 }
133
134 // blend dst
BlendDst(ColorRGBAf & src,ColorRGBAf & dst)135 static inline void BlendDst(ColorRGBAf &src, ColorRGBAf &dst)
136 {
137 (void)src;
138 (void)dst;
139 }
140
141 // blend dst atop
BlendDstAtop(const ColorRGBAf & src,ColorRGBAf & dst)142 static inline void BlendDstAtop(const ColorRGBAf &src, ColorRGBAf &dst)
143 {
144 dst.mR = src.mA * dst.mR + (1 - dst.mA) * src.mR;
145 dst.mG = src.mA * dst.mG + (1 - dst.mA) * src.mG;
146 dst.mB = src.mA * dst.mB + (1 - dst.mA) * src.mB;
147 dst.mA = src.mA;
148 }
149
150 // blend dst in
BlendDstIn(const ColorRGBAf & src,ColorRGBAf & dst)151 static inline void BlendDstIn(const ColorRGBAf &src, ColorRGBAf &dst)
152 {
153 dst.mR = dst.mR * src.mA;
154 dst.mG = dst.mG * src.mA;
155 dst.mB = dst.mB * src.mA;
156 dst.mA = src.mA * dst.mA;
157 }
158
159 // blend dst out
BlendDstOut(const ColorRGBAf & src,ColorRGBAf & dst)160 static inline void BlendDstOut(const ColorRGBAf &src, ColorRGBAf &dst)
161 {
162 dst.mR = (1 - src.mA) * dst.mR;
163 dst.mG = (1 - src.mA) * dst.mG;
164 dst.mB = (1 - src.mA) * dst.mB;
165 dst.mA = (1 - src.mA) * dst.mA;
166 }
167
168 // blend dst over
BlendDstOver(const ColorRGBAf & src,ColorRGBAf & dst)169 static inline void BlendDstOver(const ColorRGBAf &src, ColorRGBAf &dst)
170 {
171 // the display_gfx has Premultiplied
172 dst.mR *= dst.mA;
173 dst.mG *= dst.mA;
174 dst.mB *= dst.mA;
175
176 dst.mR = dst.mR + (1 - dst.mA) * src.mR;
177 dst.mG = dst.mG + (1 - dst.mA) * src.mG;
178 dst.mB = dst.mB + (1 - dst.mA) * src.mB;
179 dst.mA = dst.mA + (1 - dst.mA) * src.mA;
180 }
181
182 // blend xor
BlendXor(const ColorRGBAf & src,ColorRGBAf & dst)183 static inline void BlendXor(const ColorRGBAf &src, ColorRGBAf &dst)
184 {
185 dst.mR = (1 - dst.mA) * src.mR + (1 - src.mA) * dst.mR;
186 dst.mG = (1 - dst.mA) * src.mG + (1 - src.mA) * dst.mG;
187 dst.mB = (1 - dst.mA) * src.mB + (1 - src.mA) * dst.mB;
188 dst.mA = (1 - dst.mA) * src.mA + (1 - src.mA) * dst.mA;
189 }
190
191 // blend add
BlendAdd(const ColorRGBAf & src,ColorRGBAf & dst)192 static inline void BlendAdd(const ColorRGBAf &src, ColorRGBAf &dst)
193 {
194 dst.mR = std::max(0.0f, std::min(src.mR + dst.mR, 1.0f));
195 dst.mG = std::max(0.0f, std::min(src.mG + dst.mG, 1.0f));
196 dst.mB = std::max(0.0f, std::min(src.mB + dst.mB, 1.0f));
197 dst.mA = std::max(0.0f, std::min(src.mA + dst.mA, 1.0f));
198 }
199
GetBlendFunc(BlendType type)200 static BlendFunction GetBlendFunc(BlendType type)
201 {
202 std::unordered_map<BlendType, BlendFunction> maps = {
203 { BLEND_CLEAR, BlendClear }, { BLEND_SRC, BlendSrc }, { BLEND_DST, BlendDst },
204 { BLEND_SRCOVER, BlendSrcOver }, { BLEND_SRCIN, BlendSrcIn }, { BLEND_SRCOUT, BlendSrcOut },
205 { BLEND_SRCATOP, BlendAtop }, { BLEND_DSTIN, BlendDstIn }, { BLEND_DSTOUT, BlendDstOut },
206 { BLEND_DSTATOP, BlendDstAtop }, { BLEND_DSTOVER, BlendDstOver }, { BLEND_XOR, BlendXor },
207 { BLEND_ADD, BlendAdd }, { BLEND_NONE, BlendNone },
208 };
209 if (maps.find(type) != maps.end()) {
210 return maps[type];
211 } else {
212 DISPLAY_TEST_LOGE("has no function for blend type %d maps.size() %zd", type, maps.size());
213 return nullptr;
214 }
215 }
216
ConvertFloatToint(float f)217 static inline int32_t ConvertFloatToint(float f)
218 {
219 if (f > MAX_FLOAT_TO_INT32) {
220 return MAX_FLOAT_TO_INT32;
221 }
222 if (f < MIN_FLOAT_TO_INT32) {
223 return MIN_FLOAT_TO_INT32;
224 }
225 return static_cast<int32_t>(f);
226 }
227
GetPixelFormatBpp(PixelFormat format)228 static int32_t GetPixelFormatBpp(PixelFormat format)
229 {
230 const int32_t bppRgba8888 = 32;
231 switch (format) {
232 case PIXEL_FMT_RGBA_8888:
233 return bppRgba8888;
234 default:
235 return -1;
236 }
237 }
238
GetPixelRGBA32(const BufferHandle & handle,int x,int y)239 static uint32_t GetPixelRGBA32(const BufferHandle &handle, int x, int y)
240 {
241 const int32_t pixelBytes = 4;
242 int32_t bpp = GetPixelFormatBpp((PixelFormat)handle.format);
243 DISPLAY_TEST_CHK_RETURN((bpp <= 0), 0, DISPLAY_TEST_LOGE("CheckPixel do not support format %d", handle.format));
244 DISPLAY_TEST_CHK_RETURN((handle.virAddr == nullptr), 0,
245 DISPLAY_TEST_LOGE("CheckPixel viraddr is null must map it"));
246 DISPLAY_TEST_CHK_RETURN((x < 0 || x >= handle.width), 0,
247 DISPLAY_TEST_LOGE("CheckPixel invalid parameter x:%d width:%d", x, handle.width));
248 DISPLAY_TEST_CHK_RETURN((y < 0 || y >= handle.height), 0,
249 DISPLAY_TEST_LOGE("CheckPixel invalid parameter y:%d height:%d", y, handle.height));
250
251 int32_t position = y * handle.width + x;
252 if ((position * pixelBytes) > handle.size) {
253 DISPLAY_TEST_LOGE("the pixel position outside\n");
254 }
255 uint32_t *pixel = reinterpret_cast<uint32_t *>(handle.virAddr) + position;
256 return *pixel;
257 }
258
ColorRGBAf(uint32_t r,uint32_t g,uint32_t b,uint32_t a)259 ColorRGBAf::ColorRGBAf(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
260 {
261 const float inv = 1.0f / 255.0f;
262 mA = a * inv;
263 mR = r * inv;
264 mG = g * inv;
265 mB = b * inv;
266 }
267
Compare(ColorRGBA32 & other)268 bool ColorRGBA32::Compare(ColorRGBA32 &other)
269 {
270 const int endure = 1;
271 if ((std::abs(other.mA - mA) > endure) || (std::abs(other.mR - mR) > endure) ||
272 (std::abs(other.mG - mG) > endure) || (std::abs(other.mB - mB) > endure)) {
273 DISPLAY_TEST_LOGE("compare failed mC %x other.mC %x ", mC, other.mC);
274 return false;
275 }
276 return true;
277 }
278
ColorRGBA32(uint32_t pixel)279 ColorRGBA32::ColorRGBA32(uint32_t pixel)
280 {
281 mA = RgbaGetA(pixel);
282 mR = RgbaGetR(pixel);
283 mG = RgbaGetG(pixel);
284 mB = RgbaGetB(pixel);
285 mC = pixel;
286 }
287
ColorRGBA32(ColorRGBAf colorF)288 ColorRGBA32::ColorRGBA32(ColorRGBAf colorF)
289 {
290 const uint8_t rgbMax = 255;
291 const float round = 0.5;
292 mA = static_cast<uint8_t>(ConvertFloatToint(colorF.mA * rgbMax + round));
293 mR = static_cast<uint8_t>(ConvertFloatToint(colorF.mR * rgbMax + round));
294 mG = static_cast<uint8_t>(ConvertFloatToint(colorF.mG * rgbMax + round));
295 mB = static_cast<uint8_t>(ConvertFloatToint(colorF.mB * rgbMax + round));
296 mC = ColorSetARGB(mR, mG, mB, mA);
297 }
298 }
299
RunAndCheck(const BufferHandle & exBuffer)300 bool SoftBlit::RunAndCheck(const BufferHandle &exBuffer)
301 {
302 BlendFunction blendFunc = GetBlendFunc(mType);
303 if (blendFunc == nullptr) {
304 return false;
305 }
306 DISPLAY_TEST_LOGD("blend RunAndCheck begin");
307 for (int x = mSrcRect.x; x < mSrcRect.w; x++) {
308 for (int y = mSrcRect.y; y < mSrcRect.h; y++) {
309 uint32_t srcPixel = GetPixelRGBA32(mSrcBuffer, x, y);
310 uint32_t dstPixel = GetPixelRGBA32(mDstBuffer, x, y);
311 uint32_t exPixel = GetPixelRGBA32(exBuffer, x, y);
312 ColorRGBAf srcColorF =
313 ColorRGBAf(RgbaGetR(srcPixel), RgbaGetG(srcPixel), RgbaGetB(srcPixel), RgbaGetA(srcPixel));
314 ColorRGBAf dstColorF =
315 ColorRGBAf(RgbaGetR(dstPixel), RgbaGetG(dstPixel), RgbaGetB(dstPixel), RgbaGetA(dstPixel));
316 blendFunc(srcColorF, dstColorF);
317 ColorRGBA32 dstColrRGBA = ColorRGBA32(dstColorF);
318 ColorRGBA32 exRGBA = ColorRGBA32(exPixel);
319 if (!dstColrRGBA.Compare(exRGBA)) {
320 DISPLAY_TEST_LOGE(
321 "blend check failed x %d, y %d, srcPixel %x, dstPixel %x , exPixel %x, blendResult %x blendtype %d",
322 x, y, srcPixel, dstPixel, exPixel, dstColrRGBA.mC, mType);
323 return false;
324 }
325 }
326 }
327 DISPLAY_TEST_LOGD("blend RunAndCheck end");
328 return true;
329 }
330
SoftBlit(const BufferHandle & srcBuffer,const IRect & srcRect,const BufferHandle & dstBuffer,const IRect & dstRect,const BlendType type)331 SoftBlit::SoftBlit(const BufferHandle &srcBuffer, const IRect &srcRect, const BufferHandle &dstBuffer,
332 const IRect &dstRect, const BlendType type)
333 : mSrcRect(srcRect),
334 mDstRect(dstRect),
335 mSrcBuffer(srcBuffer),
336 mDstBuffer(dstBuffer),
337 mType(type)
338 {}
339