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