1 /*
2 * Copyright (c) 2020-2022 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 "draw/draw_utils.h"
17
18 #include "color_fill.h"
19 #include "draw/draw_triangle.h"
20 #include "engines/gfx/gfx_engine_manager.h"
21 #include "font/ui_font.h"
22 #include "gfx_utils/color.h"
23 #include "gfx_utils/graphic_log.h"
24 #include "gfx_utils/graphic_math.h"
25 #include "graphic_performance.h"
26 #include "securec.h"
27 #include "common/typed_text.h"
28 #ifdef ARM_NEON_OPT
29 #include "graphic_neon_pipeline.h"
30 #include "graphic_neon_utils.h"
31 #endif
32
33 #if ENABLE_ARM_MATH
34 #include "arm_math.h"
35 #endif
36
37 namespace OHOS {
38 // Preprocess operation for draw
39 #define DRAW_UTILS_PREPROCESS(gfxBufferInfo, opa) \
40 if ((opa) == OPA_TRANSPARENT) { \
41 return; \
42 } \
43 uint8_t* screenBuffer = static_cast<uint8_t*>(gfxBufferInfo.virAddr); \
44 if (screenBuffer == nullptr) { \
45 return; \
46 } \
47 ColorMode bufferMode = gfxBufferInfo.mode; \
48 uint8_t bufferPxSize = GetByteSizeByColorMode(bufferMode); \
49 uint16_t screenBufferWidth = gfxBufferInfo.width;
50
51 namespace {
52 static constexpr uint8_t OPACITY_STEP_A1 = 255;
53 static constexpr uint8_t OPACITY_STEP_A2 = 85;
54 static constexpr uint8_t OPACITY_STEP_A4 = 17;
55 } // namespace
56
TriangleEdge(int16_t x1,int16_t y1,int16_t x2,int16_t y2)57 TriangleEdge::TriangleEdge(int16_t x1, int16_t y1, int16_t x2, int16_t y2)
58 {
59 #if ENABLE_FIXED_POINT
60 curX = FO_TRANS_INTEGER_TO_FIXED(x1);
61 curY = FO_TRANS_INTEGER_TO_FIXED(y1);
62 du = FO_TRANS_INTEGER_TO_FIXED(x2 - x1);
63 dv = FO_TRANS_INTEGER_TO_FIXED(y2 - y1);
64 #else
65 curX = static_cast<float>(x1);
66 curY = static_cast<float>(y1);
67 du = static_cast<float>(x2 - x1);
68 dv = static_cast<float>(y2 - y1);
69 #endif
70 }
71
~TriangleEdge()72 TriangleEdge::~TriangleEdge() {}
73
GetInstance()74 DrawUtils* DrawUtils::GetInstance()
75 {
76 static DrawUtils instance;
77 return &instance;
78 }
79
DrawColorAreaBySides(BufferInfo & gfxDstBuffer,const Rect & mask,const ColorType & color,OpacityType opa,const EdgeSides & sides) const80 void DrawUtils::DrawColorAreaBySides(BufferInfo& gfxDstBuffer,
81 const Rect& mask,
82 const ColorType& color,
83 OpacityType opa,
84 const EdgeSides& sides) const
85 {
86 Rect area(sides.left, sides.top, sides.right, sides.bottom);
87 DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, area, mask, color, opa);
88 }
89
DrawColorArea(BufferInfo & gfxDstBuffer,const Rect & area,const Rect & mask,const ColorType & color,OpacityType opa) const90 void DrawUtils::DrawColorArea(BufferInfo& gfxDstBuffer,
91 const Rect& area,
92 const Rect& mask,
93 const ColorType& color,
94 OpacityType opa) const
95 {
96 if (opa == OPA_TRANSPARENT) {
97 return;
98 }
99
100 Rect maskedArea;
101 if (!maskedArea.Intersect(area, mask)) {
102 return;
103 }
104
105 BaseGfxEngine::GetInstance()->Fill(gfxDstBuffer, maskedArea, color, opa);
106 }
107
GetPxSizeByColorMode(uint8_t colorMode)108 uint8_t DrawUtils::GetPxSizeByColorMode(uint8_t colorMode)
109 {
110 switch (colorMode) {
111 case TSC6:
112 case TSC6A:
113 case ARGB8888:
114 case XRGB8888:
115 return 32; // 32: 32 bit
116 case RGB888:
117 return 24; // 24: 24 bit
118 case RGB565:
119 case ARGB1555:
120 case ARGB4444:
121 return 16; // 16: 16 bit
122 case L1:
123 case A1:
124 return 1; // 1: 1 bit
125 case L2:
126 case A2:
127 return 2; // 2: 2 bit
128 case L4:
129 case A4:
130 return 4; // 4: 4 bit
131 case L8:
132 case A8:
133 return 8; // 8: 8 bit
134 default:
135 return 0;
136 }
137 }
138
GetByteSizeByColorMode(uint8_t colorMode)139 uint8_t DrawUtils::GetByteSizeByColorMode(uint8_t colorMode)
140 {
141 switch (colorMode) {
142 case ARGB8888:
143 case XRGB8888:
144 return 4; // 4: 4 Byte
145 case RGB888:
146 return 3; // 3: 3 Byte
147 case RGB565:
148 case ARGB1555:
149 case ARGB4444:
150 return 2; // 2: 2 Byte
151 default:
152 return 0;
153 }
154 }
155
DrawPixel(BufferInfo & gfxDstBuffer,int16_t x,int16_t y,const Rect & mask,const ColorType & color,OpacityType opa) const156 void DrawUtils::DrawPixel(BufferInfo& gfxDstBuffer,
157 int16_t x,
158 int16_t y,
159 const Rect& mask,
160 const ColorType& color,
161 OpacityType opa) const
162 {
163 if ((x < mask.GetLeft()) || (x > mask.GetRight()) || (y < mask.GetTop()) || (y > mask.GetBottom())) {
164 return;
165 }
166
167 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
168
169 Color32 fillColor;
170 fillColor.full = Color::ColorTo32(color);
171
172 screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
173 COLOR_FILL_BLEND(screenBuffer, bufferMode, &fillColor, ARGB8888, opa);
174 }
175
DrawColorLetter(BufferInfo & gfxDstBuffer,const LabelLetterInfo & letterInfo,uint8_t * fontMap,GlyphNode node,int16_t lineHeight) const176 void DrawUtils::DrawColorLetter(BufferInfo& gfxDstBuffer,
177 const LabelLetterInfo& letterInfo,
178 uint8_t* fontMap,
179 GlyphNode node,
180 int16_t lineHeight) const
181 {
182 if (fontMap == nullptr) {
183 return;
184 }
185 UIFont* fontEngine = UIFont::GetInstance();
186 uint16_t letterW = node.cols;
187 uint16_t letterH = node.rows;
188 int16_t posX;
189 int16_t posY;
190 if (letterInfo.baseLine) {
191 // 2:Half the size between lineHeight and node.rows of emoji
192 posY = letterInfo.pos.y + (lineHeight - letterH) / 2 + letterInfo.offsetY;
193 } else {
194 FontHeader head;
195 if (fontEngine->GetFontHeader(head, letterInfo.fontId, letterInfo.fontSize) != 0) {
196 return;
197 }
198 posY = letterInfo.pos.y + head.ascender - letterInfo.offsetY;
199 }
200 if (letterInfo.direct == TEXT_DIRECT_RTL) {
201 /* RTL */
202 posX = letterInfo.pos.x- node.advance + letterInfo.offsetX;
203 } else {
204 /* LTR */
205 posX = letterInfo.pos.x;
206 }
207
208 uint16_t rowStart = (posY >= letterInfo.mask.GetTop()) ? 0 : (letterInfo.mask.GetTop() - posY);
209 uint16_t rowEnd =
210 (posY + letterH <= letterInfo.mask.GetBottom()) ? letterH : (letterInfo.mask.GetBottom() - posY + 1);
211 uint16_t colStart = (posX >= letterInfo.mask.GetLeft()) ? 0 : (letterInfo.mask.GetLeft() - posX);
212 uint16_t colEnd =
213 (posX + letterW <= letterInfo.mask.GetRight()) ? letterW : (letterInfo.mask.GetRight() - posX + 1);
214
215 Rect srcRect(posX, posY, posX + letterW - 1, posY + letterH - 1);
216 Rect subRect(posX + colStart, posY + rowStart, colEnd - 1 + posX, rowEnd - 1 + posY);
217
218 uint8_t pxSize = DrawUtils::GetPxSizeByColorMode(gfxDstBuffer.mode);
219 DrawImage(gfxDstBuffer, srcRect, letterInfo.mask, fontMap, letterInfo.opa, pxSize, ARGB8888);
220 }
221
DrawNormalLetter(BufferInfo & gfxDstBuffer,const LabelLetterInfo & letterInfo,uint8_t * fontMap,GlyphNode node,uint8_t maxLetterSize) const222 void DrawUtils::DrawNormalLetter(BufferInfo& gfxDstBuffer,
223 const LabelLetterInfo& letterInfo,
224 uint8_t* fontMap,
225 GlyphNode node,
226 uint8_t maxLetterSize) const
227 {
228 if (fontMap == nullptr) {
229 return;
230 }
231
232 UIFont* fontEngine = UIFont::GetInstance();
233 uint16_t letterW = node.cols;
234 uint16_t letterH = node.rows;
235 int16_t posX;
236 int16_t posY;
237
238 if (letterInfo.baseLine) {
239 posY = letterInfo.pos.y + maxLetterSize - node.top + letterInfo.offsetY;
240 } else {
241 FontHeader head;
242 if (fontEngine->GetFontHeader(head, letterInfo.fontId, letterInfo.fontSize) != 0) {
243 return;
244 }
245 posY = letterInfo.pos.y + head.ascender - node.top - letterInfo.offsetY;
246 }
247 if (letterInfo.direct == TEXT_DIRECT_RTL) {
248 /* RTL */
249 posX = letterInfo.pos.x - node.advance + node.left + letterInfo.offsetX;
250 } else {
251 /* LTR */
252 posX = letterInfo.pos.x + node.left + letterInfo.offsetX;
253 }
254 BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
255 if (letterInfo.haveLineBackgroundColor) {
256 Rect lineBackgroundRect(posX - node.left, letterInfo.mask.GetTop(),
257 posX + node.advance + letterInfo.letterSpace_ - node.left,
258 letterInfo.mask.GetBottom() - letterInfo.lineSpace_);
259 Style lineStyle;
260 lineStyle.bgColor_ = letterInfo.lineBackgroundColor;
261 baseGfxEngine->DrawRect(gfxDstBuffer, lineBackgroundRect,
262 lineBackgroundRect, lineStyle, lineStyle.bgColor_.alpha);
263 }
264 if (letterInfo.havebackgroundColor) {
265 Rect backgroundRect(posX, letterInfo.mask.GetTop(), posX + letterW + letterInfo.letterSpace_ - 1,
266 letterInfo.mask.GetBottom() - letterInfo.lineSpace_);
267 Style style;
268 style.bgColor_ = letterInfo.backgroundColor;
269 baseGfxEngine->DrawRect(gfxDstBuffer, backgroundRect,
270 backgroundRect, style, style.bgColor_.alpha);
271 }
272
273 if ((posX + letterW < letterInfo.mask.GetLeft()) || (posX > letterInfo.mask.GetRight()) ||
274 (posY + letterH < letterInfo.mask.GetTop()) || (posY > letterInfo.mask.GetBottom())) {
275 return;
276 }
277
278 uint16_t rowStart = (posY >= letterInfo.mask.GetTop()) ? 0 : (letterInfo.mask.GetTop() - posY);
279 uint16_t rowEnd =
280 (posY + letterH <= letterInfo.mask.GetBottom()) ? letterH : (letterInfo.mask.GetBottom() - posY + 1);
281 uint16_t colStart = (posX >= letterInfo.mask.GetLeft()) ? 0 : (letterInfo.mask.GetLeft() - posX);
282 uint16_t colEnd =
283 (posX + letterW <= letterInfo.mask.GetRight()) ? letterW : (letterInfo.mask.GetRight() - posX + 1);
284
285 Rect srcRect(posX, posY, posX + letterW - 1, posY + letterH - 1);
286 Rect subRect(posX + colStart, posY + rowStart, colEnd - 1 + posX, rowEnd - 1 + posY);
287
288 uint8_t fontWeight = fontEngine->GetFontWeight(letterInfo.fontId);
289 baseGfxEngine->DrawLetter(gfxDstBuffer, fontMap, srcRect, subRect,
290 fontWeight, letterInfo.color, letterInfo.opa);
291 }
292
DrawLetter(BufferInfo & gfxDstBuffer,const uint8_t * fontMap,const Rect & fontRect,const Rect & subRect,const uint8_t fontWeight,const ColorType & color,const OpacityType opa) const293 void DrawUtils::DrawLetter(BufferInfo& gfxDstBuffer,
294 const uint8_t* fontMap,
295 const Rect& fontRect,
296 const Rect& subRect,
297 const uint8_t fontWeight,
298 const ColorType& color,
299 const OpacityType opa) const
300 {
301 Color32 fillColor;
302 fillColor.full = Color::ColorTo32(color);
303 uint8_t opacityMask;
304 uint8_t opacityStep = 1;
305 switch (fontWeight) {
306 case FONT_WEIGHT_1:
307 opacityStep = OPACITY_STEP_A1;
308 opacityMask = 0x01;
309 break;
310 case FONT_WEIGHT_2:
311 opacityStep = OPACITY_STEP_A2;
312 opacityMask = 0x03;
313 break;
314 case FONT_WEIGHT_4:
315 opacityStep = OPACITY_STEP_A4;
316 opacityMask = 0x0F;
317 break;
318 case FONT_WEIGHT_8:
319 opacityMask = 0xFF;
320 break;
321 case FONT_WEIGHT_32:
322 opacityMask = 0xFF;
323 break;
324 default:
325 return;
326 }
327
328 uint8_t letterWidthInByte = (fontRect.GetWidth() * fontWeight) >> SHIFT_3;
329 if ((fontRect.GetWidth() * fontWeight) & 0x7) { // 0x7 : less than 1 byte is counted as 1 byte
330 letterWidthInByte++;
331 }
332 int16_t rowStart = subRect.GetY() - fontRect.GetY();
333 int16_t rowEnd = rowStart + subRect.GetHeight();
334 int16_t colStart = subRect.GetX() - fontRect.GetX();
335 int16_t colEnd = colStart + subRect.GetWidth();
336
337 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
338 screenBuffer += ((subRect.GetY() * screenBufferWidth) + subRect.GetX()) * bufferPxSize;
339 fontMap += (rowStart * letterWidthInByte) + ((colStart * fontWeight) >> SHIFT_3);
340
341 uint8_t offsetInFont = (colStart * fontWeight) % FONT_WEIGHT_8;
342 int16_t temp = subRect.GetWidth() * fontWeight - FONT_WEIGHT_8 + offsetInFont;
343 if (temp < 0) {
344 temp = 0;
345 }
346 int16_t validWidthInByte = temp / FONT_WEIGHT_8 + 1;
347 if (temp % FONT_WEIGHT_8 != 0) {
348 validWidthInByte++;
349 }
350 for (int16_t i = rowStart; i < rowEnd; i++) {
351 int16_t col = colStart;
352 uint8_t tempOffset = offsetInFont;
353 uint8_t tempFontByte = (*fontMap++) >> offsetInFont;
354 while (col < colEnd) {
355 while ((tempOffset < FONT_WEIGHT_8) && (col < colEnd)) {
356 uint8_t validOpacity = tempFontByte & opacityMask;
357 if (validOpacity != 0) {
358 validOpacity *= opacityStep;
359 if (opa != OPA_OPAQUE) {
360 validOpacity =
361 static_cast<OpacityType>((static_cast<uint16_t>(validOpacity) * opa) >> FONT_WEIGHT_8);
362 }
363 COLOR_FILL_BLEND(screenBuffer, bufferMode, &fillColor, ARGB8888, validOpacity);
364 }
365 screenBuffer += bufferPxSize;
366 tempFontByte = tempFontByte >> fontWeight;
367 tempOffset += fontWeight;
368 col++;
369 }
370 tempOffset = 0;
371 tempFontByte = *(fontMap++);
372 }
373 fontMap += letterWidthInByte - validWidthInByte - 1;
374 screenBuffer += (screenBufferWidth - (colEnd - colStart)) * bufferPxSize;
375 }
376 }
377
DrawImage(BufferInfo & gfxDstBuffer,const Rect & area,const Rect & mask,const uint8_t * image,OpacityType opa,uint8_t pxBitSize,ColorMode colorMode) const378 void DrawUtils::DrawImage(BufferInfo& gfxDstBuffer,
379 const Rect& area,
380 const Rect& mask,
381 const uint8_t* image,
382 OpacityType opa,
383 uint8_t pxBitSize,
384 ColorMode colorMode) const
385 {
386 if (image == nullptr) {
387 return;
388 }
389 Rect maskedArea;
390 if (!maskedArea.Intersect(area, mask)) {
391 return;
392 }
393 int16_t mapWidth = area.GetWidth();
394 int16_t imageX = maskedArea.GetLeft() - area.GetLeft();
395 int16_t imageY = maskedArea.GetTop() - area.GetTop();
396 uint32_t imageWidthInByte = (static_cast<uint32_t>(mapWidth) * pxBitSize) >> SHIFT_3;
397 if ((mapWidth * pxBitSize) & 0x7) { // 0x7 : less than 1 byte is counted as 1 byte
398 imageWidthInByte++;
399 }
400
401 BufferInfo src;
402 src.rect = {imageX, imageY, static_cast<int16_t>(imageX + maskedArea.GetWidth() - 1),
403 static_cast<int16_t>(imageY + maskedArea.GetHeight() - 1)};
404
405 src.virAddr = static_cast<void*>(const_cast<uint8_t*>(image));
406 src.stride = imageWidthInByte;
407 src.mode = colorMode;
408 src.color = 0;
409
410 Point dstPos = {maskedArea.GetLeft(), maskedArea.GetTop()};
411 BlendOption blendOption;
412 blendOption.opacity = opa;
413 blendOption.mode = BLEND_SRC_OVER;
414 BaseGfxEngine::GetInstance()->Blit(gfxDstBuffer, dstPos, src, maskedArea, blendOption);
415 }
416
FillAreaWithSoftWare(BufferInfo & gfxDstBuffer,const Rect & fillArea,const ColorType & color,const OpacityType & opa) const417 void DrawUtils::FillAreaWithSoftWare(BufferInfo& gfxDstBuffer,
418 const Rect& fillArea,
419 const ColorType& color,
420 const OpacityType& opa) const
421 {
422 if (gfxDstBuffer.virAddr == nullptr) {
423 return;
424 }
425 ColorMode mode = gfxDstBuffer.mode;
426 uint8_t destByteSize = GetByteSizeByColorMode(mode);
427 int16_t destWidth = gfxDstBuffer.width;
428 int32_t halBufferDeltaByteLen = static_cast<int32_t>(destWidth) * destByteSize;
429 int16_t width = fillArea.GetWidth();
430 int16_t height = fillArea.GetHeight();
431 uint8_t* dest = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
432 int32_t offset = static_cast<int32_t>(fillArea.GetTop()) * destWidth + fillArea.GetLeft();
433 dest += offset * destByteSize;
434
435 int32_t dstMaxSize = (gfxDstBuffer.width * gfxDstBuffer.height - offset) * destByteSize;
436 Color32 fillColor;
437 fillColor.full = Color::ColorTo32(color);
438 uint8_t* dstTmp = nullptr;
439
440 if ((fillColor.alpha == OPA_TRANSPARENT) || (opa == OPA_TRANSPARENT)) {
441 return;
442 }
443 /* cover mode */
444 if ((opa == OPA_OPAQUE) && (fillColor.alpha == OPA_OPAQUE)) {
445 for (int16_t col = 0; col < width; ++col) {
446 dstTmp = dest + (col * destByteSize);
447 COLOR_FILL_COVER(dstTmp, mode, fillColor.red, fillColor.green, fillColor.blue, ARGB8888);
448 }
449 uint8_t* memStart = dest;
450 int32_t memSize = static_cast<int32_t>(width) * destByteSize;
451 dest += halBufferDeltaByteLen;
452 dstMaxSize -= halBufferDeltaByteLen;
453 for (int16_t row = 1; row < height; ++row) {
454 #ifdef ARM_NEON_OPT
455 {
456 DEBUG_PERFORMANCE_TRACE("memcpy_neon");
457 NeonMemcpy(dest, dstMaxSize, memStart, memSize);
458 }
459 #else
460 {
461 DEBUG_PERFORMANCE_TRACE("memcpy");
462 if (memcpy_s(dest, dstMaxSize, memStart, memSize) != EOK) {
463 GRAPHIC_LOGE("DrawUtils::FillAreaWithSoftWare memcpy failed!\n");
464 return;
465 }
466 }
467 #endif
468 dest += halBufferDeltaByteLen;
469 dstMaxSize -= halBufferDeltaByteLen;
470 }
471 } else {
472 #ifdef ARM_NEON_OPT
473 {
474 DEBUG_PERFORMANCE_TRACE("FillAreaWithSoftWare_neon");
475 NeonBlendPipeLine pipeLine;
476 pipeLine.Construct(mode, ARGB8888, &fillColor, opa);
477 int16_t step = NEON_STEP_8 * GetByteSizeByColorMode(mode);
478 for (int16_t row = 0; row < height; ++row) {
479 uint8_t* buf = dest;
480 int16_t tmpWidth = width;
481 while (tmpWidth >= NEON_STEP_8) {
482 pipeLine.Invoke(buf);
483 buf += step;
484 tmpWidth -= NEON_STEP_8;
485 }
486 for (int16_t i = 0; i < tmpWidth; ++i) {
487 COLOR_FILL_BLEND(buf, mode, &fillColor, ARGB8888, opa);
488 buf += destByteSize;
489 }
490 dest += halBufferDeltaByteLen;
491 }
492 }
493 #else
494 {
495 DEBUG_PERFORMANCE_TRACE("FillAreaWithSoftWare");
496 for (int16_t row = 0; row < height; row++) {
497 for (int16_t col = 0; col < width; col++) {
498 dstTmp = dest + (col * destByteSize);
499 COLOR_FILL_BLEND(dstTmp, mode, &fillColor, ARGB8888, opa);
500 }
501 dest += destWidth * destByteSize;
502 }
503 }
504 #endif
505 }
506 }
507
508 #ifdef ARM_NEON_OPT
BlendLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t cover)509 void DrawUtils::BlendLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue,
510 uint8_t alpha, uint8_t cover)
511 {
512 NeonBlendPipeLine mNeonBlendPipeLine;
513 mNeonBlendPipeLine.NeonLerpARGB8888(color, red, green, blue, alpha, cover);
514 }
515
BlendLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha)516 void DrawUtils::BlendLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
517 {
518 NeonBlendPipeLine mNeonBlendPipeLine;
519 mNeonBlendPipeLine.NeonLerpARGB8888(color, red, green, blue, alpha);
520 }
521
BlendLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t srcCover)522 void DrawUtils::BlendLerpPix(uint8_t* dstColors, uint8_t* srcColors, uint8_t srcCover)
523 {
524 NeonBlendPipeLine mNeonBlendPipeLine;
525 mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCover);
526 }
527
BlendLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t * srcCovers)528 void DrawUtils::BlendLerpPix(uint8_t* dstColors, uint8_t* srcColors, uint8_t* srcCovers)
529 {
530 NeonBlendPipeLine mNeonBlendPipeLine;
531 mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCovers);
532 }
533
BlendLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t * covers)534 void DrawUtils::BlendLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue,
535 uint8_t alpha, uint8_t* covers)
536 {
537 NeonBlendPipeLine mNeonBlendPipeLine;
538 mNeonBlendPipeLine.NeonLerpARGB8888(color, red, green, blue, alpha, covers);
539 }
540
BlendPreLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t cover)541 void DrawUtils::BlendPreLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue,
542 uint8_t alpha, uint8_t cover)
543 {
544 NeonBlendPipeLine mNeonBlendPipeLine;
545 mNeonBlendPipeLine.NeonPrelerpARGB8888(color, red, green, blue, alpha, cover);
546 }
547
BlendPreLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha)548 void DrawUtils::BlendPreLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
549 {
550 NeonBlendPipeLine mNeonBlendPipeLine;
551 mNeonBlendPipeLine.NeonPrelerpARGB8888(color, red, green, blue, alpha);
552 }
BlendPreLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t srcCover)553 void DrawUtils::BlendPreLerpPix(uint8_t *dstColors, uint8_t *srcColors, uint8_t srcCover)
554 {
555 NeonBlendPipeLine mNeonBlendPipeLine;
556 mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCover);
557 }
558
BlendPreLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t * srcCovers)559 void DrawUtils::BlendPreLerpPix(uint8_t *dstColors, uint8_t *srcColors, uint8_t *srcCovers)
560 {
561 NeonBlendPipeLine mNeonBlendPipeLine;
562 mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCovers);
563 }
564
BlendPreLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t * covers)565 void DrawUtils::BlendPreLerpPix(uint8_t *color, uint8_t red, uint8_t green, uint8_t blue,
566 uint8_t alpha, uint8_t *covers)
567 {
568 NeonBlendPipeLine mNeonBlendPipeLine;
569 mNeonBlendPipeLine.NeonPreLerpARGB8888(color, red, green, blue, alpha, covers);
570 }
571 #endif
572
BlendWithSoftWare(const uint8_t * src1,const Rect & srcRect,uint32_t srcStride,uint32_t srcLineNumber,ColorMode srcMode,uint32_t color,OpacityType opa,uint8_t * dst,uint32_t destStride,ColorMode destMode,uint32_t x,uint32_t y) const573 void DrawUtils::BlendWithSoftWare(const uint8_t* src1,
574 const Rect& srcRect,
575 uint32_t srcStride,
576 uint32_t srcLineNumber,
577 ColorMode srcMode,
578 uint32_t color,
579 OpacityType opa,
580 uint8_t* dst,
581 uint32_t destStride,
582 ColorMode destMode,
583 uint32_t x,
584 uint32_t y) const
585 {
586 if ((dst == nullptr) || (src1 == nullptr)) {
587 return;
588 }
589 uint8_t destByteSize = GetByteSizeByColorMode(destMode);
590 uint8_t srcByteSize = GetByteSizeByColorMode(srcMode);
591
592 uint8_t* dest = dst + destStride * y;
593 dest += destByteSize * x;
594
595 uint8_t pxByteSize = GetPxSizeByColorMode(srcMode) >> 3; // 3 : right shift 3 bits
596 uint8_t* src = const_cast<uint8_t*>(src1) + srcStride * srcRect.GetY() + pxByteSize * srcRect.GetX();
597 uint32_t width = srcRect.GetWidth();
598 uint32_t height = srcRect.GetHeight();
599 #ifdef ARM_NEON_OPT
600 GetInstance()->SetDestAndSrc(srcMode, destMode, height, src, width, opa, dest,
601 destStride, srcStride, destByteSize, srcByteSize);
602 #else
603 {
604 DEBUG_PERFORMANCE_TRACE("BlendWithSoftWare");
605 for (uint32_t row = 0; row < height; ++row) {
606 uint8_t* destTmp = dest;
607 uint8_t* srcTmp = const_cast<uint8_t*>(src);
608 for (uint32_t col = 0; col < width; ++col) {
609 COLOR_FILL_BLEND(destTmp, destMode, srcTmp, srcMode, opa);
610 destTmp += destByteSize;
611 srcTmp += srcByteSize;
612 }
613 dest += destStride;
614 src += srcStride;
615 }
616 }
617 #endif
618 }
619
620 #ifdef ARM_NEON_OPT
SetDestAndSrc(ColorMode & srcMode,ColorMode & destMode,uint32_t height,uint8_t * src,uint32_t width,OpacityType opa,uint8_t * dest,uint32_t destStride,uint32_t srcStride,uint8_t destByteSize,uint8_t srcByteSize) const621 void DrawUtils::SetDestAndSrc(ColorMode& srcMode, ColorMode& destMode, uint32_t height, uint8_t* src,
622 uint32_t width, OpacityType opa, uint8_t* dest, uint32_t destStride,
623 uint32_t srcStride, uint8_t destByteSize, uint8_t srcByteSize) const
624 {
625 DEBUG_PERFORMANCE_TRACE("BlendWithSoftWare_neon");
626 NeonBlendPipeLine pipeLine;
627 pipeLine.Construct(destMode, srcMode);
628 int16_t dstStep = NEON_STEP_8 * GetByteSizeByColorMode(destMode);
629 int16_t srcStep = NEON_STEP_8 * GetByteSizeByColorMode(srcMode);
630 for (uint32_t row = 0; row < height; ++row) {
631 uint8_t* dstBuf = dest;
632 uint8_t* srcBuf = const_cast<uint8_t*>(src);
633 int16_t tmpWidth = width;
634 while (tmpWidth >= NEON_STEP_8) {
635 pipeLine.Invoke(dstBuf, srcBuf, opa);
636 dstBuf += dstStep;
637 srcBuf += srcStep;
638 tmpWidth -= NEON_STEP_8;
639 }
640 for (int16_t i = 0; i < tmpWidth; ++i) {
641 COLOR_FILL_BLEND(dstBuf, destMode, srcBuf, srcMode, opa);
642 dstBuf += destByteSize;
643 srcBuf += srcByteSize;
644 }
645 dest += destStride;
646 src += srcStride;
647 }
648 }
649 #endif
650
GetXAxisErrForJunctionLine(bool ignoreJunctionPoint,bool isRightPart,int16_t & xMinErr,int16_t & xMaxErr)651 void DrawUtils::GetXAxisErrForJunctionLine(bool ignoreJunctionPoint,
652 bool isRightPart,
653 int16_t& xMinErr,
654 int16_t& xMaxErr)
655 {
656 xMinErr = 0;
657 xMaxErr = 0;
658 if (ignoreJunctionPoint) {
659 if (isRightPart) {
660 xMinErr = 1;
661 } else {
662 xMaxErr = -1;
663 }
664 }
665 }
666
GetTransformInitState(const TransformMap & transMap,const Point & position,const Rect & trans,TransformInitState & init)667 void DrawUtils::GetTransformInitState(const TransformMap& transMap,
668 const Point& position,
669 const Rect& trans,
670 TransformInitState& init)
671 {
672 int16_t x = trans.GetLeft();
673 int16_t y = trans.GetTop();
674 #if ENABLE_FIXED_POINT
675 init.duHorizon = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[0]);
676 init.dvHorizon = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[1]);
677 init.duVertical = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[3]); // 3:RSxy
678 init.dvVertical = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[4]); // 4:RSyy
679 init.verticalU = (x - position.x) * init.duHorizon + (y - position.y) * init.duVertical +
680 FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[6]); // 6:TRSx
681 init.verticalV = (x - position.x) * init.dvHorizon + (y - position.y) * init.dvVertical +
682 FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[7]); // 7:TRSy
683 #else
684 init.duHorizon = transMap.invMatrix_.GetData()[0];
685 init.dvHorizon = transMap.invMatrix_.GetData()[1];
686 init.duVertical = transMap.invMatrix_.GetData()[3]; // 3:RSxy
687 init.dvVertical = transMap.invMatrix_.GetData()[4]; // 4:RSyy
688 init.verticalU = (x - position.x) * init.duHorizon + (y - position.y) * init.duVertical +
689 transMap.invMatrix_.GetData()[6]; // 6:TRSx
690 init.verticalV = (x - position.x) * init.dvHorizon + (y - position.y) * init.dvVertical +
691 transMap.invMatrix_.GetData()[7]; // 7:TRSy
692 #endif
693 }
694
StepToNextLine(TriangleEdge & edge1,TriangleEdge & edge2)695 inline void DrawUtils::StepToNextLine(TriangleEdge& edge1, TriangleEdge& edge2)
696 {
697 #if ENABLE_FIXED_POINT
698 edge1.curY += FIXED_NUM_1;
699 edge2.curY += FIXED_NUM_1;
700 edge1.curX += FO_DIV(edge1.du, edge1.dv);
701 edge2.curX += FO_DIV(edge2.du, edge2.dv);
702 #else
703 edge1.curY++;
704 edge2.curY++;
705 edge1.curX += edge1.du / edge1.dv;
706 edge2.curX += edge2.du / edge2.dv;
707 #endif
708 }
709
DrawTriangleAlphaBilinear(const TriangleScanInfo & in,const ColorMode bufferMode)710 void DrawUtils::DrawTriangleAlphaBilinear(const TriangleScanInfo& in, const ColorMode bufferMode)
711 {
712 int16_t maskLeft = in.mask.GetLeft();
713 int16_t maskRight = in.mask.GetRight();
714 for (int16_t y = in.yMin; y <= in.yMax; y++) {
715 #if ENABLE_FIXED_POINT
716 int16_t tempV = FO_TO_INTEGER(in.edge1.curX);
717 int16_t xMin = MATH_MAX(tempV, maskLeft);
718 tempV = FO_TO_INTEGER(in.edge2.curX);
719 int16_t xMax = MATH_MIN(tempV, maskRight);
720 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
721 #else
722 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX), maskLeft);
723 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX), maskRight);
724 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
725 #endif
726 in.init.verticalU += in.init.duHorizon * diffX;
727 in.init.verticalV += in.init.dvHorizon * diffX;
728 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
729
730 #if ENABLE_FIXED_POINT
731 // parameters below are Q15 fixed-point number
732 int64_t u = in.init.verticalU;
733 int64_t v = in.init.verticalV;
734 // parameters above are Q15 fixed-point number
735 #else
736 float u = in.init.verticalU;
737 float v = in.init.verticalV;
738 #endif
739 for (int16_t x = xMin; x <= xMax; x++) {
740 #if ENABLE_FIXED_POINT
741 int16_t intU = FO_TO_INTEGER(u);
742 int16_t intV = FO_TO_INTEGER(v);
743 if ((u >= 0) && (intU < (in.info.header.width - 1)) && (v >= 0) && (intV < (in.info.header.height - 1))) {
744 int16_t intUPlus1 = intU + 1;
745 int16_t intVPlus1 = intV + 1;
746 #else
747 const int16_t intU = static_cast<int16_t>(u);
748 const int16_t intV = static_cast<int16_t>(v);
749 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
750 const int16_t intUPlus1 = intU + 1;
751 const int16_t intVPlus1 = intV + 1;
752 #endif
753 OpacityType p1 = GetPxAlphaForAlphaImg(in.info, {intU, intV});
754 OpacityType p2 = GetPxAlphaForAlphaImg(in.info, {intUPlus1, intV});
755 OpacityType p3 = GetPxAlphaForAlphaImg(in.info, {intU, intVPlus1});
756 OpacityType p4 = GetPxAlphaForAlphaImg(in.info, {intUPlus1, intVPlus1});
757 #if ENABLE_FIXED_POINT
758 // parameters below are Q15 fixed-point number
759 int64_t decU = FO_DECIMAL(u);
760 int64_t decV = FO_DECIMAL(v);
761 int64_t decUMinus1 = FIXED_NUM_1 - decU;
762 int64_t decVMinus1 = FIXED_NUM_1 - decV;
763 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
764 int64_t w2 = FO_MUL(decU, decVMinus1);
765 int64_t w3 = FO_MUL(decUMinus1, decV);
766 int64_t w4 = FO_MUL(decU, decV);
767 // parameters above are Q15 fixed-point number
768 #else
769 const float decU = u - intU;
770 const float decV = v - intV;
771 const float decUMinus1 = 1.0f - decU;
772 const float decVMinus1 = 1.0f - decV;
773
774 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
775 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
776 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
777 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f); // 256:shift 8 bit left
778 #endif
779 #if ENABLE_ARM_MATH
780 const int64_t outA = __SMUAD(p1, w1) + __SMUAD(p2, w2) + __SMUAD(p3, w3) + __SMUAD(p4, w4);
781 #else
782 const int64_t outA = p1 * w1 + p2 * w2 + p3 * w3 + p4 * w4;
783 #endif
784 Color32 result;
785 result.full = Color::ColorTo32(in.color);
786 #if ENABLE_FIXED_POINT
787 result.alpha = FO_TO_INTEGER(outA);
788 #else
789 result.alpha = static_cast<uint8_t>(outA >> 8); // 8:shift 8 bit right
790 #endif
791 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
792 }
793 u += in.init.duHorizon;
794 v += in.init.dvHorizon;
795 screenBuffer += in.bufferPxSize;
796 }
797 StepToNextLine(in.edge1, in.edge2);
798 in.init.verticalU += in.init.duVertical;
799 in.init.verticalV += in.init.dvVertical;
800 #if ENABLE_FIXED_POINT
801 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
802 #else
803 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
804 #endif
805 in.init.verticalU += in.init.duHorizon * deltaX;
806 in.init.verticalV += in.init.dvHorizon * deltaX;
807 }
808 }
809
810 void DrawUtils::DrawTriangleTrueColorBilinear565(const TriangleScanInfo& in, const ColorMode bufferMode)
811 {
812 int16_t maskLeft = in.mask.GetLeft();
813 int16_t maskRight = in.mask.GetRight();
814 int16_t xMinErr = 0;
815 int16_t xMaxErr = 0;
816 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
817 for (int16_t y = in.yMin; y <= in.yMax; y++) {
818 #if ENABLE_FIXED_POINT
819 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
820 int16_t xMin = MATH_MAX(tempV, maskLeft);
821 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
822 int16_t xMax = MATH_MIN(tempV, maskRight);
823 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
824 #else
825 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
826 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
827 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
828 #endif
829 in.init.verticalU += in.init.duHorizon * diffX;
830 in.init.verticalV += in.init.dvHorizon * diffX;
831 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
832 #if ENABLE_FIXED_POINT
833 // parameters below are Q15 fixed-point number
834 int64_t u = in.init.verticalU;
835 int64_t v = in.init.verticalV;
836 // parameters above are Q15 fixed-point number
837 #else
838 float u = in.init.verticalU;
839 float v = in.init.verticalV;
840 #endif
841 for (int16_t x = xMin; x <= xMax; x++) {
842 #if ENABLE_FIXED_POINT
843 int16_t intU = FO_TO_INTEGER(u);
844 int16_t intV = FO_TO_INTEGER(v);
845 if ((u >= 0) && (intU < (in.info.header.width - 1)) && (v >= 0) && (intV < (in.info.header.height - 1))) {
846 #else
847 const int16_t intU = static_cast<int16_t>(u);
848 const int16_t intV = static_cast<int16_t>(v);
849 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
850 #endif
851 #if ENABLE_ARM_MATH
852 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
853 uint32_t val2 = __SMUAD(intU, in.pixelSize);
854 uint32_t px1 = val1 + val2;
855 #else
856 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
857 #endif
858 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
859 const Color16 p1 = *(reinterpret_cast<Color16*>(&imgHead[px1]));
860 const Color16 p2 = *(reinterpret_cast<Color16*>(&imgHead[px1 + in.pixelSize]));
861 const Color16 p3 = *(reinterpret_cast<Color16*>(&imgHead[px1 + in.srcLineWidth]));
862 const Color16 p4 = *(reinterpret_cast<Color16*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
863 #if ENABLE_FIXED_POINT
864 // parameters below are Q15 fixed-point number
865 int64_t decU = FO_DECIMAL(u);
866 int64_t decV = FO_DECIMAL(v);
867 int64_t decUMinus1 = FIXED_NUM_1 - decU;
868 int64_t decVMinus1 = FIXED_NUM_1 - decV;
869 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
870 int64_t w2 = FO_MUL(decU, decVMinus1);
871 int64_t w3 = FO_MUL(decUMinus1, decV);
872 int64_t w4 = FO_MUL(decU, decV);
873 // parameters above are Q15 fixed-point number
874 #else
875 const float decU = u - intU;
876 const float decV = v - intV;
877 const float decUMinus1 = 1 - decU;
878 const float decVMinus1 = 1 - decV;
879 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
880 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
881 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
882 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f); // 256:shift 8 bit left
883 #endif
884 #if ENABLE_ARM_MATH
885 const int64_t outR =
886 __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
887 const int64_t outG =
888 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
889 const int64_t outB =
890 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
891 #else
892 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
893 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
894 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
895 #endif
896
897 Color16 result;
898 #if ENABLE_FIXED_POINT
899 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
900 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
901 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
902 #else
903 result.red = static_cast<uint8_t>(outR >> 5); // 5:shift 5 bit right
904 result.green = static_cast<uint8_t>(outG >> 6); // 6:shift 6 bit right
905 result.blue = static_cast<uint8_t>(outB >> 5); // 5:shift 5 bit right
906 #endif
907 if (in.opaScale == OPA_OPAQUE) {
908 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, RGB565);
909 } else {
910 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, RGB565, in.opaScale);
911 }
912 }
913 u += in.init.duHorizon;
914 v += in.init.dvHorizon;
915 screenBuffer += in.bufferPxSize;
916 }
917 StepToNextLine(in.edge1, in.edge2);
918 in.init.verticalU += in.init.duVertical;
919 in.init.verticalV += in.init.dvVertical;
920 #if ENABLE_FIXED_POINT
921 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
922 #else
923 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
924 #endif
925 in.init.verticalU += in.init.duHorizon * deltaX;
926 in.init.verticalV += in.init.dvHorizon * deltaX;
927 }
928 }
929
930 void DrawUtils::DrawTriangleTrueColorBilinear888(const TriangleScanInfo& in, const ColorMode bufferMode)
931 {
932 int16_t maskLeft = in.mask.GetLeft();
933 int16_t maskRight = in.mask.GetRight();
934 int16_t xMinErr = 0;
935 int16_t xMaxErr = 0;
936 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
937 for (int16_t y = in.yMin; y <= in.yMax; y++) {
938 #if ENABLE_FIXED_POINT
939 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
940 int16_t xMin = MATH_MAX(tempV, maskLeft);
941 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
942 int16_t xMax = MATH_MIN(tempV, maskRight);
943 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
944 #else
945 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
946 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
947 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
948 #endif
949 in.init.verticalU += in.init.duHorizon * diffX;
950 in.init.verticalV += in.init.dvHorizon * diffX;
951 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
952 #if ENABLE_FIXED_POINT
953 // parameters below are Q15 fixed-point number
954 int64_t u = in.init.verticalU;
955 int64_t v = in.init.verticalV;
956 // parameters above are Q15 fixed-point number
957 #else
958 float u = in.init.verticalU;
959 float v = in.init.verticalV;
960 #endif
961 for (int16_t x = xMin; x <= xMax; x++) {
962 #if ENABLE_FIXED_POINT
963 int16_t intU = FO_TO_INTEGER(u);
964 int16_t intV = FO_TO_INTEGER(v);
965 #else
966 const int16_t intU = static_cast<int16_t>(u);
967 const int16_t intV = static_cast<int16_t>(v);
968 #endif
969 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
970 #if ENABLE_ARM_MATH
971 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
972 uint32_t val2 = __SMUAD(intU, in.pixelSize);
973 uint32_t px1 = val1 + val2;
974 #else
975 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
976 #endif
977 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
978 const Color24 p1 = *(reinterpret_cast<Color24*>(&imgHead[px1]));
979 const Color24 p2 = *(reinterpret_cast<Color24*>(&imgHead[px1 + in.pixelSize]));
980 const Color24 p3 = *(reinterpret_cast<Color24*>(&imgHead[px1 + in.srcLineWidth]));
981 const Color24 p4 = *(reinterpret_cast<Color24*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
982 #if ENABLE_FIXED_POINT
983 // parameters below are Q15 fixed-point number
984 int64_t decU = FO_DECIMAL(u);
985 int64_t decV = FO_DECIMAL(v);
986 int64_t decUMinus1 = FIXED_NUM_1 - decU;
987 int64_t decVMinus1 = FIXED_NUM_1 - decV;
988 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
989 int64_t w2 = FO_MUL(decU, decVMinus1);
990 int64_t w3 = FO_MUL(decUMinus1, decV);
991 int64_t w4 = FO_MUL(decU, decV);
992 // parameters above are Q15 fixed-point number
993 #else
994 const float decU = u - intU;
995 const float decV = v - intV;
996 const float decUMinus1 = 1 - decU;
997 const float decVMinus1 = 1 - decV;
998 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
999 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
1000 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
1001 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f); // 256:shift 8 bit left
1002 #endif
1003
1004 #if ENABLE_ARM_MATH
1005 const int64_t outR =
1006 __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1007 const int64_t outG =
1008 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1009 const int64_t outB =
1010 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1011 #else
1012 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1013 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1014 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1015 #endif
1016
1017 Color24 result;
1018 #if ENABLE_FIXED_POINT
1019 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
1020 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1021 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1022 #else
1023 result.red = static_cast<uint8_t>(outR >> 8); // 8:shift 8 bit right
1024 result.green = static_cast<uint8_t>(outG >> 8); // 8:shift 8 bit right
1025 result.blue = static_cast<uint8_t>(outB >> 8); // 8:shift 8 bit right
1026 #endif
1027 if (in.opaScale == OPA_OPAQUE) {
1028 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, RGB888);
1029 } else {
1030 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, RGB888, in.opaScale);
1031 }
1032 }
1033 u += in.init.duHorizon;
1034 v += in.init.dvHorizon;
1035 screenBuffer += in.bufferPxSize;
1036 }
1037 StepToNextLine(in.edge1, in.edge2);
1038 in.init.verticalU += in.init.duVertical;
1039 in.init.verticalV += in.init.dvVertical;
1040 #if ENABLE_FIXED_POINT
1041 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1042 #else
1043 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1044 #endif
1045 in.init.verticalU += in.init.duHorizon * deltaX;
1046 in.init.verticalV += in.init.dvHorizon * deltaX;
1047 }
1048 }
1049
1050 #if !ENABLE_FIXED_POINT
1051 static void DrawTriangleTrueColorBilinear8888Inner(const TriangleScanInfo& in,
1052 uint8_t* screenBuffer,
1053 int16_t len,
1054 const ColorMode bufferMode,
1055 float u,
1056 float v)
1057 {
1058 for (int16_t x = 0; x < len; ++x) {
1059 const int16_t intU = static_cast<int16_t>(u);
1060 const int16_t intV = static_cast<int16_t>(v);
1061 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1062 #if ENABLE_ARM_MATH
1063 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1064 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1065 uint32_t px1 = val1 + val2;
1066 #else
1067 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1068 #endif
1069 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1070 const ColorType p1 = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1071 const ColorType p2 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1072 const ColorType p3 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1073 const ColorType p4 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1074
1075 const float decU = u - intU;
1076 const float decV = v - intV;
1077 const float decUMinus1 = 1 - decU;
1078 const float decVMinus1 = 1 - decV;
1079
1080 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
1081 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
1082 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
1083 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f); // 256:shift 8 bit left
1084
1085 #if ENABLE_ARM_MATH
1086 const int32_t outR = __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1087 const int32_t outG =
1088 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1089 const int32_t outB =
1090 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1091 const int32_t outA =
1092 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1093 #else
1094 const int32_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1095 const int32_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1096 const int32_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1097 const int32_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1098 #endif
1099
1100 Color32 result;
1101 result.red = static_cast<uint8_t>(outR >> 8); // 8:shift 8 bit right
1102 result.green = static_cast<uint8_t>(outG >> 8); // 8:shift 8 bit right
1103 result.blue = static_cast<uint8_t>(outB >> 8); // 8:shift 8 bit right
1104 result.alpha = static_cast<uint8_t>(outA >> 8); // 8:shift 8 bit right
1105 if ((in.opaScale == OPA_OPAQUE) && (result.alpha == OPA_OPAQUE)) {
1106 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
1107 } else {
1108 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
1109 }
1110 }
1111 u += in.init.duHorizon;
1112 v += in.init.dvHorizon;
1113 screenBuffer += in.bufferPxSize;
1114 }
1115 }
1116 #endif
1117
1118 #if defined(ENABLE_FIXED_POINT) && ENABLE_FIXED_POINT
1119 static void DrawFixedTriangleTrueColorBilinear8888Inner(const TriangleScanInfo& in,
1120 uint8_t* screenBuffer,
1121 int16_t len,
1122 const ColorMode bufferMode,
1123 int64_t u,
1124 int64_t v)
1125 {
1126 for (int16_t x = 0; x < len; ++x) {
1127 int16_t intU = FO_TO_INTEGER(u);
1128 int16_t intV = FO_TO_INTEGER(v);
1129 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1130 #if ENABLE_ARM_MATH
1131 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1132 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1133 uint32_t px1 = val1 + val2;
1134 #else
1135 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1136 #endif
1137 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1138 const ColorType p1 = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1139 const ColorType p2 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1140 const ColorType p3 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1141 const ColorType p4 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1142
1143 // parameters below are Q15 fixed-point number
1144 int64_t decU = FO_DECIMAL(u);
1145 int64_t decV = FO_DECIMAL(v);
1146 int64_t decUMinus1 = FIXED_NUM_1 - decU;
1147 int64_t decVMinus1 = FIXED_NUM_1 - decV;
1148 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
1149 int64_t w2 = FO_MUL(decU, decVMinus1);
1150 int64_t w3 = FO_MUL(decUMinus1, decV);
1151 int64_t w4 = FO_MUL(decU, decV);
1152 // parameters above are Q15 fixed-point number
1153
1154 #if ENABLE_ARM_MATH
1155 const int64_t outR = __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1156 const int64_t outG =
1157 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1158 const int64_t outB =
1159 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1160 const int64_t outA =
1161 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1162 #else
1163 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1164 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1165 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1166 const int64_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1167 #endif
1168
1169 Color32 result;
1170 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
1171 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1172 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1173 result.alpha = static_cast<uint8_t>(outA >> FIXED_Q_NUM);
1174 if ((in.opaScale == OPA_OPAQUE) && (result.alpha == OPA_OPAQUE)) {
1175 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
1176 } else {
1177 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
1178 }
1179 }
1180 u += in.init.duHorizon;
1181 v += in.init.dvHorizon;
1182 screenBuffer += in.bufferPxSize;
1183 }
1184 }
1185 #endif
1186
1187 #ifdef ARM_NEON_OPT
1188 static void DrawTriangleTrueColorBilinear8888InnerNeon(const TriangleScanInfo& in,
1189 uint8_t* screenBuffer,
1190 int16_t len,
1191 float u,
1192 float v,
1193 NeonBlendPipeLine& pipeLine,
1194 const ColorMode bufferMode)
1195 {
1196 ColorType arrayp1[NEON_STEP_8] = {};
1197 ColorType arrayp2[NEON_STEP_8] = {};
1198 ColorType arrayp3[NEON_STEP_8] = {};
1199 ColorType arrayp4[NEON_STEP_8] = {};
1200 float arrayU[NEON_STEP_8] = {0};
1201 float arrayV[NEON_STEP_8] = {0};
1202 int32_t arrayPx1[NEON_STEP_8] = {0};
1203 int16_t step = in.bufferPxSize * NEON_STEP_8;
1204 #if ENABLE_FIXED_POINT
1205 float duHorizon = static_cast<float>(in.init.duHorizon) / FIXED_NUM_1;
1206 float dvHorizon = static_cast<float>(in.init.dvHorizon) / FIXED_NUM_1;
1207 #endif
1208 while (len >= NEON_STEP_8) {
1209 for (uint32_t i = 0; i < NEON_STEP_8; ++i) {
1210 arrayU[i] = u;
1211 arrayV[i] = v;
1212 #if ENABLE_FIXED_POINT
1213 u += duHorizon;
1214 v += dvHorizon;
1215 #else
1216 u += in.init.duHorizon;
1217 v += in.init.dvHorizon;
1218 #endif
1219 }
1220 // Monotonically increasing or decreasing, so only judge the beginning and end.
1221 if ((arrayU[0] >= 0) && (arrayU[0] < in.info.header.width - 1) && (arrayV[0] >= 0) &&
1222 (arrayV[0] < in.info.header.height - 1) && (arrayU[NEON_STEP_8 - 1] >= 0) &&
1223 (arrayU[NEON_STEP_8 - 1] < in.info.header.width - 1) && (arrayV[NEON_STEP_8 - 1] >= 0) &&
1224 (arrayV[NEON_STEP_8 - 1] < in.info.header.height - 1)) {
1225 // Process the lower half of arrayU and arrayV
1226 float32x4_t vU = vld1q_f32(arrayU);
1227 float32x4_t vV = vld1q_f32(arrayV);
1228 int32x4_t vIntU = vcvtq_s32_f32(vU);
1229 int32x4_t vIntV = vcvtq_s32_f32(vV);
1230 int32x4_t vPx1 =
1231 vaddq_s32(vmulq_s32(vIntV, vdupq_n_s32(in.srcLineWidth)), vmulq_s32(vIntU, vdupq_n_s32(in.pixelSize)));
1232 vst1q_s32(arrayPx1, vPx1);
1233 float32x4_t vDecU = vsubq_f32(vU, vcvtq_f32_s32(vIntU));
1234 float32x4_t vDecV = vsubq_f32(vV, vcvtq_f32_s32(vIntV));
1235 float32x4_t vDecUMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecU);
1236 float32x4_t vDecVMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecV);
1237 // 256:shift 8 bit left
1238 uint32x4_t vLowW1 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecVMinus1), vdupq_n_f32(256.0)));
1239 uint32x4_t vLowW2 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecVMinus1), vdupq_n_f32(256.0)));
1240 uint32x4_t vLowW3 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecV), vdupq_n_f32(256.0)));
1241 uint32x4_t vLowW4 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecV), vdupq_n_f32(256.0)));
1242 // Process the higher half of arrayU and arrayV
1243 vU = vld1q_f32(arrayU + NEON_STEP_4);
1244 vV = vld1q_f32(arrayV + NEON_STEP_4);
1245 vIntU = vcvtq_s32_f32(vU);
1246 vIntV = vcvtq_s32_f32(vV);
1247 vPx1 =
1248 vaddq_s32(vmulq_s32(vIntV, vdupq_n_s32(in.srcLineWidth)), vmulq_s32(vIntU, vdupq_n_s32(in.pixelSize)));
1249 vst1q_s32(arrayPx1 + NEON_STEP_4, vPx1);
1250 vDecU = vsubq_f32(vU, vcvtq_f32_s32(vIntU));
1251 vDecV = vsubq_f32(vV, vcvtq_f32_s32(vIntV));
1252 vDecUMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecU);
1253 vDecVMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecV);
1254 // 256:shift 8 bit left
1255 uint32x4_t vHighW1 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecVMinus1), vdupq_n_f32(256.0)));
1256 uint32x4_t vHighW2 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecVMinus1), vdupq_n_f32(256.0)));
1257 uint32x4_t vHighW3 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecV), vdupq_n_f32(256.0)));
1258 uint32x4_t vHighW4 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecV), vdupq_n_f32(256.0)));
1259
1260 // joins two uint32x4_t vectors into a uint16x8_t vector
1261 uint16x8_t vW1 = vcombine_u16(vmovn_u32(vLowW1), vmovn_u32(vHighW1));
1262 uint16x8_t vW2 = vcombine_u16(vmovn_u32(vLowW2), vmovn_u32(vHighW2));
1263 uint16x8_t vW3 = vcombine_u16(vmovn_u32(vLowW3), vmovn_u32(vHighW3));
1264 uint16x8_t vW4 = vcombine_u16(vmovn_u32(vLowW4), vmovn_u32(vHighW4));
1265
1266 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1267 for (uint32_t i = 0; i < NEON_STEP_8; ++i) {
1268 int32_t px1 = arrayPx1[i];
1269 arrayp1[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1270 arrayp2[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1271 arrayp3[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1272 arrayp4[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1273 }
1274
1275 uint8x8x4_t v4p1 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp1));
1276 uint8x8x4_t v4p2 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp2));
1277 uint8x8x4_t v4p3 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp3));
1278 uint8x8x4_t v4p4 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp4));
1279 uint8x8_t vOutB =
1280 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_B]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_B]), vW2) +
1281 vmulq_u16(vmovl_u8(v4p3.val[NEON_B]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_B]), vW4),
1282 8); // 8:shift 8 bit right
1283 uint8x8_t vOutG =
1284 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_G]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_G]), vW2) +
1285 vmulq_u16(vmovl_u8(v4p3.val[NEON_G]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_G]), vW4),
1286 8); // 8:shift 8 bit right
1287 uint8x8_t vOutR =
1288 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_R]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_R]), vW2) +
1289 vmulq_u16(vmovl_u8(v4p3.val[NEON_R]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_R]), vW4),
1290 8); // 8:shift 8 bit right
1291 uint8x8_t vOutA =
1292 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_A]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_A]), vW2) +
1293 vmulq_u16(vmovl_u8(v4p3.val[NEON_A]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_A]), vW4),
1294 8); // 8:shift 8 bit right
1295 vOutA = NeonMulDiv255(vdup_n_u8(in.opaScale), vOutA);
1296 pipeLine.Invoke(screenBuffer, vOutR, vOutG, vOutB, vOutA);
1297 } else {
1298 #if ENABLE_FIXED_POINT
1299 int64_t fixedU = FO_TRANS_FLOAT_TO_FIXED(arrayU[0]);
1300 int64_t fixedV = FO_TRANS_FLOAT_TO_FIXED(arrayV[0]);
1301 DrawFixedTriangleTrueColorBilinear8888Inner(in, screenBuffer, NEON_STEP_8, bufferMode, fixedU, fixedV);
1302 #else
1303 DrawTriangleTrueColorBilinear8888Inner(in, screenBuffer, NEON_STEP_8, bufferMode, arrayU[0], arrayV[0]);
1304 #endif
1305 }
1306 screenBuffer += step;
1307 len -= NEON_STEP_8;
1308 }
1309 if (len > 0) {
1310 #if ENABLE_FIXED_POINT
1311 int64_t fixedU = FO_TRANS_FLOAT_TO_FIXED(u);
1312 int64_t fixedV = FO_TRANS_FLOAT_TO_FIXED(v);
1313 DrawFixedTriangleTrueColorBilinear8888Inner(in, screenBuffer, len, bufferMode, fixedU, fixedV);
1314 #else
1315 DrawTriangleTrueColorBilinear8888Inner(in, screenBuffer, len, bufferMode, u, v);
1316 #endif
1317 }
1318 }
1319 #endif
1320
1321 void DrawUtils::Draw3DTriangleTrueColorBilinear8888(const TriangleScanInfo& in, const ColorMode bufferMode)
1322 {
1323 int16_t maskLeft = in.mask.GetLeft();
1324 int16_t maskRight = in.mask.GetRight();
1325 int16_t xMinErr = 0;
1326 int16_t xMaxErr = 0;
1327 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1328 #if ENABLE_FIXED_POINT
1329 int64_t invMatrix00 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[0]);
1330 int64_t invMatrix01 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[1]);
1331 int64_t invMatrix02 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[2]);
1332 int64_t invMatrix20 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[3]);
1333 int64_t invMatrix21 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[4]);
1334 int64_t invMatrix22 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[5]);
1335 int64_t invMatrix30 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[6]);
1336 int64_t invMatrix31 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[7]);
1337 int64_t invMatrix32 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[8]);
1338 #else // ENABLE_FIXED_POINT
1339 float invMatrix00 = in.matrix.GetData()[0];
1340 float invMatrix01 = in.matrix.GetData()[1];
1341 float invMatrix02 = in.matrix.GetData()[2];
1342 float invMatrix20 = in.matrix.GetData()[3];
1343 float invMatrix21 = in.matrix.GetData()[4];
1344 float invMatrix22 = in.matrix.GetData()[5];
1345 float invMatrix30 = in.matrix.GetData()[6];
1346 float invMatrix31 = in.matrix.GetData()[7];
1347 float invMatrix32 = in.matrix.GetData()[8];
1348 #endif // ENABLE_FIXED_POINT
1349 for (int16_t y = in.yMin; y <= in.yMax; ++y) {
1350 #if ENABLE_FIXED_POINT
1351 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1352 int16_t xMin = MATH_MAX(tempV, maskLeft);
1353 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1354 int16_t xMax = MATH_MIN(tempV, maskRight);
1355 #else // ENABLE_FIXED_POINT
1356 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1357 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1358 #endif // ENABLE_FIXED_POINT
1359 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1360 // move to current position
1361 for (int16_t x = xMin; x <= xMax; x++) {
1362 #if ENABLE_FIXED_POINT
1363 int64_t w = invMatrix02 * x + invMatrix22 * y + invMatrix32;
1364 int64_t u = FO_DIV((invMatrix00 * x + invMatrix20 * y + invMatrix30), w);
1365 int64_t v = FO_DIV((invMatrix01 * x + invMatrix21 * y + invMatrix31), w);
1366 int16_t intU = FO_TO_INTEGER(u);
1367 int16_t intV = FO_TO_INTEGER(v);
1368 #else // ENABLE_FIXED_POINT
1369 float w = invMatrix02 * x + invMatrix22 * y + invMatrix32;
1370 float u = (invMatrix00 * x + invMatrix20 * y + invMatrix30) / w;
1371 float v = (invMatrix01 * x + invMatrix21 * y + invMatrix31) / w;
1372 int16_t intU = static_cast<int16_t>(u);
1373 int16_t intV = static_cast<int16_t>(v);
1374 #endif // ENABLE_FIXED_POINT
1375 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1376 #if ENABLE_ARM_MATH
1377 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1378 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1379 uint32_t px1 = val1 + val2;
1380 #else // ENABLE_ARM_MATH
1381 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1382 #endif // ENABLE_ARM_MATH
1383 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1384 const ColorType p1 = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1385 const ColorType p2 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1386 const ColorType p3 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1387 const ColorType p4 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1388 #if ENABLE_FIXED_POINT
1389 int64_t decU = FO_DECIMAL(u);
1390 int64_t decV = FO_DECIMAL(v);
1391 int64_t decUMinus1 = FIXED_NUM_1 - decU;
1392 int64_t decVMinus1 = FIXED_NUM_1 - decV;
1393 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
1394 int64_t w2 = FO_MUL(decU, decVMinus1);
1395 int64_t w3 = FO_MUL(decUMinus1, decV);
1396 int64_t w4 = FO_MUL(decU, decV);
1397 #if ENABLE_ARM_MATH
1398 const int64_t outR =
1399 __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1400 const int64_t outG =
1401 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1402 const int64_t outB =
1403 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1404 const int64_t outA =
1405 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1406 #else
1407 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1408 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1409 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1410 const int64_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1411 #endif
1412 Color32 result;
1413 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
1414 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1415 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1416 result.alpha = static_cast<uint8_t>(outA >> FIXED_Q_NUM);
1417 #else // ENABLE_FIXED_POINT
1418 const float decU = u - intU;
1419 const float decV = v - intV;
1420 const float decUMinus1 = 1 - decU;
1421 const float decVMinus1 = 1 - decV;
1422 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
1423 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
1424 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
1425 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f);
1426 #if ENABLE_ARM_MATH
1427 const int32_t outR =
1428 __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1429 const int32_t outG =
1430 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1431 const int32_t outB =
1432 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1433 const int32_t outA =
1434 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1435 #else // ENABLE_ARM_MATH
1436 const int32_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1437 const int32_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1438 const int32_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1439 const int32_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1440 #endif // ENABLE_ARM_MATH
1441 Color32 result;
1442 result.red = static_cast<uint8_t>(outR >> 8); // 8:shift 8 bit right
1443 result.green = static_cast<uint8_t>(outG >> 8); // 8:shift 8 bit right
1444 result.blue = static_cast<uint8_t>(outB >> 8); // 8:shift 8 bit right
1445 result.alpha = static_cast<uint8_t>(outA >> 8); // 8:shift 8 bit right
1446 #endif // ENABLE_FIXED_POINT
1447 if ((in.opaScale == OPA_OPAQUE) && (result.alpha == OPA_OPAQUE)) {
1448 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
1449 } else {
1450 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
1451 }
1452 }
1453 screenBuffer += in.bufferPxSize;
1454 }
1455 StepToNextLine(in.edge1, in.edge2);
1456 }
1457 }
1458
1459 void DrawUtils::DrawTriangleTrueColorBilinear8888(const TriangleScanInfo& in, const ColorMode bufferMode)
1460 {
1461 int16_t maskLeft = in.mask.GetLeft();
1462 int16_t maskRight = in.mask.GetRight();
1463 int16_t xMinErr = 0;
1464 int16_t xMaxErr = 0;
1465 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1466 #ifdef ARM_NEON_OPT
1467 NeonBlendPipeLine pipeLine;
1468 pipeLine.Construct(bufferMode, ARGB8888);
1469 #endif
1470 for (int16_t y = in.yMin; y <= in.yMax; ++y) {
1471 #if ENABLE_FIXED_POINT
1472 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1473 int16_t xMin = MATH_MAX(tempV, maskLeft);
1474 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1475 int16_t xMax = MATH_MIN(tempV, maskRight);
1476 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
1477 #else
1478 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1479 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1480 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
1481 #endif
1482 in.init.verticalU += in.init.duHorizon * diffX;
1483 in.init.verticalV += in.init.dvHorizon * diffX;
1484 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1485 #ifdef ARM_NEON_OPT
1486 {
1487 #if ENABLE_FIXED_POINT
1488 float u = static_cast<float>(in.init.verticalU) / FIXED_NUM_1;
1489 float v = static_cast<float>(in.init.verticalV) / FIXED_NUM_1;
1490 #else
1491 float u = in.init.verticalU;
1492 float v = in.init.verticalV;
1493 #endif
1494 DEBUG_PERFORMANCE_TRACE("DrawTriangleTrueColorBilinear8888_neon");
1495 DrawTriangleTrueColorBilinear8888InnerNeon(in, screenBuffer, xMax - xMin + 1, u, v, pipeLine, bufferMode);
1496 }
1497 #else
1498 {
1499 DEBUG_PERFORMANCE_TRACE("DrawTriangleTrueColorBilinear8888");
1500 #if ENABLE_FIXED_POINT
1501 DrawFixedTriangleTrueColorBilinear8888Inner(in, screenBuffer, xMax - xMin + 1, bufferMode,
1502 in.init.verticalU, in.init.verticalV);
1503 #else
1504 DrawTriangleTrueColorBilinear8888Inner(in, screenBuffer, xMax - xMin + 1, bufferMode, in.init.verticalU,
1505 in.init.verticalV);
1506 #endif
1507 }
1508 #endif
1509 StepToNextLine(in.edge1, in.edge2);
1510 in.init.verticalU += in.init.duVertical;
1511 in.init.verticalV += in.init.dvVertical;
1512 #if ENABLE_FIXED_POINT
1513 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1514 #else
1515 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1516 #endif
1517 in.init.verticalU += in.init.duHorizon * deltaX;
1518 in.init.verticalV += in.init.dvHorizon * deltaX;
1519 }
1520 }
1521
1522 void DrawUtils::DrawTriangleTrueColorNearest(const TriangleScanInfo& in, const ColorMode bufferMode)
1523 {
1524 int16_t maskLeft = in.mask.GetLeft();
1525 int16_t maskRight = in.mask.GetRight();
1526 int16_t xMinErr = 0;
1527 int16_t xMaxErr = 0;
1528 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1529 for (int16_t y = in.yMin; y <= in.yMax; y++) {
1530 #if ENABLE_FIXED_POINT
1531 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1532 int16_t xMin = MATH_MAX(tempV, maskLeft);
1533 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1534 int16_t xMax = MATH_MIN(tempV, maskRight);
1535 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
1536 #else
1537 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1538 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1539 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
1540 #endif
1541 in.init.verticalU += in.init.duHorizon * diffX;
1542 in.init.verticalV += in.init.dvHorizon * diffX;
1543 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1544 #if ENABLE_FIXED_POINT
1545 // parameters below are Q15 fixed-point number
1546 int64_t u = in.init.verticalU;
1547 int64_t v = in.init.verticalV;
1548 // parameters above are Q15 fixed-point number
1549 #else
1550 float u = in.init.verticalU;
1551 float v = in.init.verticalV;
1552 #endif
1553 for (int16_t x = xMin; x <= xMax; x++) {
1554 #if ENABLE_FIXED_POINT
1555 int16_t intU = FO_TO_INTEGER(u);
1556 int16_t intV = FO_TO_INTEGER(v);
1557 if ((u >= 0) && (intU < (in.info.header.width - 1)) && (v >= 0) && (intV < (in.info.header.height - 1))) {
1558 #else
1559 const int16_t intU = static_cast<int16_t>(u);
1560 const int16_t intV = static_cast<int16_t>(v);
1561 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1562 #endif
1563 #if ENABLE_ARM_MATH
1564 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1565 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1566 uint32_t px1 = val1 + val2;
1567 #else
1568 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1569 #endif
1570 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1571 OpacityType opa = in.opaScale;
1572
1573 switch (in.info.header.colorMode) {
1574 case RGB888: {
1575 Color24 p24 = *(reinterpret_cast<Color24*>(&imgHead[px1]));
1576 if (opa == OPA_OPAQUE) {
1577 COLOR_FILL_COVER(screenBuffer, bufferMode, p24.red, p24.green, p24.blue, RGB888);
1578 } else {
1579 COLOR_FILL_BLEND(screenBuffer, bufferMode, &p24, RGB888, opa);
1580 }
1581 break;
1582 }
1583 case RGB565: {
1584 Color16 p16 = *(reinterpret_cast<Color16*>(&imgHead[px1]));
1585 if (opa == OPA_OPAQUE) {
1586 COLOR_FILL_COVER(screenBuffer, bufferMode, p16.red, p16.green, p16.blue, RGB565);
1587 } else {
1588 COLOR_FILL_BLEND(screenBuffer, bufferMode, &p16, RGB565, opa);
1589 }
1590 break;
1591 }
1592 case ARGB8888: {
1593 Color32 p32 = *(reinterpret_cast<Color32*>(&imgHead[px1]));
1594 if ((in.opaScale == OPA_OPAQUE) && (p32.alpha == OPA_OPAQUE)) {
1595 COLOR_FILL_COVER(screenBuffer, bufferMode, p32.red, p32.green, p32.blue, ARGB8888);
1596 } else {
1597 COLOR_FILL_BLEND(screenBuffer, bufferMode, &p32, ARGB8888, in.opaScale);
1598 }
1599 break;
1600 }
1601 case XRGB8888: {
1602 Color32 p32 = *(reinterpret_cast<Color32*>(&imgHead[px1]));
1603 if ((in.opaScale == OPA_OPAQUE) && (p32.alpha == OPA_OPAQUE)) {
1604 COLOR_FILL_COVER(screenBuffer, bufferMode, p32.red, p32.green, p32.blue, XRGB8888);
1605 } else {
1606 COLOR_FILL_BLEND(screenBuffer, bufferMode, &p32, XRGB8888, in.opaScale);
1607 }
1608 break;
1609 }
1610 default:
1611 return;
1612 }
1613 }
1614 u += in.init.duHorizon;
1615 v += in.init.dvHorizon;
1616 screenBuffer += in.bufferPxSize;
1617 }
1618 StepToNextLine(in.edge1, in.edge2);
1619 in.init.verticalU += in.init.duVertical;
1620 in.init.verticalV += in.init.dvVertical;
1621 #if ENABLE_FIXED_POINT
1622 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1623 #else
1624 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1625 #endif
1626 in.init.verticalU += in.init.duHorizon * deltaX;
1627 in.init.verticalV += in.init.dvHorizon * deltaX;
1628 }
1629 }
1630
1631 void DrawUtils::DrawTriangleTransformPart(BufferInfo& gfxDstBuffer, const TrianglePartInfo& part)
1632 {
1633 #if ENABLE_FIXED_POINT
1634 // parameters below are Q15 fixed-point number
1635 int64_t yMin = FO_TRANS_INTEGER_TO_FIXED(part.yMin);
1636 part.edge1.curX += (static_cast<int64_t>(part.edge1.du) * (yMin - part.edge1.curY) / part.edge1.dv);
1637 part.edge1.curY = yMin;
1638 part.edge2.curX += (static_cast<int64_t>(part.edge2.du) * (yMin - part.edge2.curY) / part.edge2.dv);
1639 part.edge2.curY = yMin;
1640 Rect line;
1641 line.SetLeft(FO_TO_INTEGER(part.edge1.curX));
1642 line.SetRight(FO_TO_INTEGER(part.edge1.curX));
1643 line.SetTop(FO_TO_INTEGER(part.edge1.curY));
1644 line.SetBottom(FO_TO_INTEGER(part.edge1.curY));
1645 // parameters above are Q15 fixed-point number
1646 #else
1647 part.edge1.curX += part.edge1.du * (part.yMin - part.edge1.curY) / part.edge1.dv;
1648 part.edge1.curY = part.yMin;
1649 part.edge2.curX += part.edge2.du * (part.yMin - part.edge2.curY) / part.edge2.dv;
1650 part.edge2.curY = part.yMin;
1651 Rect line;
1652 line.SetLeft(static_cast<int16_t>(part.edge1.curX));
1653 line.SetRight(static_cast<int16_t>(part.edge1.curX));
1654 line.SetTop(static_cast<int16_t>(part.edge1.curY));
1655 line.SetBottom(static_cast<int16_t>(part.edge1.curY));
1656 #endif
1657 TransformInitState init;
1658 GetTransformInitState(part.transMap, part.position, line, init);
1659
1660 uint8_t* screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
1661 if (screenBuffer == nullptr) {
1662 return;
1663 }
1664 GetInstance()->SetFucInfo(gfxDstBuffer, part, screenBuffer, init);
1665 }
1666
1667 void DrawUtils::SetFucInfo(BufferInfo& gfxDstBuffer, const TrianglePartInfo& part,
1668 uint8_t* screenBuffer, TransformInitState& init)
1669 {
1670 ColorMode bufferMode = gfxDstBuffer.mode;
1671 uint8_t bufferPxSize = GetByteSizeByColorMode(bufferMode);
1672
1673 uint8_t pixelSize;
1674 DrawTriangleTransformFuc fuc;
1675 bool isTrueColor = (part.info.header.colorMode == ARGB8888) || (part.info.header.colorMode == RGB888) ||
1676 (part.info.header.colorMode == RGB565) || (part.info.header.colorMode == XRGB8888);
1677 if (isTrueColor) {
1678 pixelSize = part.info.pxSize >> SHIFT_3;
1679 if (part.info.algorithm == TransformAlgorithm::NEAREST_NEIGHBOR) {
1680 fuc = DrawTriangleTrueColorNearest;
1681 } else if (part.info.header.colorMode == ARGB8888 || part.info.header.colorMode == XRGB8888) {
1682 if (part.transMap.Is3DTransform()) {
1683 fuc = Draw3DTriangleTrueColorBilinear8888;
1684 } else {
1685 fuc = DrawTriangleTrueColorBilinear8888;
1686 }
1687 } else if (part.info.header.colorMode == RGB888) {
1688 fuc = DrawTriangleTrueColorBilinear888;
1689 } else {
1690 fuc = DrawTriangleTrueColorBilinear565;
1691 }
1692 } else {
1693 pixelSize = part.info.pxSize;
1694 fuc = DrawTriangleAlphaBilinear;
1695 }
1696 const int32_t srcLineWidth = part.info.header.width * pixelSize;
1697 TriangleScanInfo input{part.yMin,
1698 part.yMax,
1699 part.edge1,
1700 part.edge2,
1701 screenBuffer,
1702 bufferPxSize,
1703 part.color,
1704 part.opaScale,
1705 init,
1706 gfxDstBuffer.width,
1707 pixelSize,
1708 srcLineWidth,
1709 part.info,
1710 part.mask,
1711 part.isRightPart,
1712 part.ignoreJunctionPoint,
1713 part.transMap.invMatrix_};
1714 fuc(input, gfxDstBuffer.mode);
1715 }
1716
1717 void DrawUtils::DrawTriangleTransform(BufferInfo& gfxDstBuffer,
1718 const Rect& mask,
1719 const Point& position,
1720 const ColorType& color,
1721 OpacityType opaScale,
1722 const TransformMap& transMap,
1723 const TriangleTransformDataInfo& triangleInfo)
1724 {
1725 bool p3IsInRight = ((triangleInfo.p1.y - triangleInfo.p2.y) * triangleInfo.p3.x +
1726 (triangleInfo.p2.x - triangleInfo.p1.x) * triangleInfo.p3.y +
1727 triangleInfo.p1.x * triangleInfo.p2.y - triangleInfo.p2.x * triangleInfo.p1.y) < 0;
1728 TriangleEdge edge1;
1729 TriangleEdge edge2;
1730 TrianglePartInfo part{
1731 mask,
1732 transMap,
1733 position,
1734 edge1,
1735 edge2,
1736 0,
1737 0,
1738 triangleInfo.info,
1739 color,
1740 opaScale,
1741 triangleInfo.isRightPart,
1742 triangleInfo.ignoreJunctionPoint,
1743 };
1744
1745 uint8_t yErr = 1;
1746 if (triangleInfo.p2.y == triangleInfo.p1.y) {
1747 yErr = 0;
1748 GetInstance()->SetPartEdge(gfxDstBuffer, triangleInfo, edge1, edge2, p3IsInRight, mask, yErr, part);
1749 return;
1750 }
1751 if (p3IsInRight) {
1752 edge1 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p2.x, triangleInfo.p2.y);
1753 edge2 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1754 } else {
1755 edge2 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p2.x, triangleInfo.p2.y);
1756 edge1 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1757 }
1758
1759 part.yMin = MATH_MAX(mask.GetTop(), triangleInfo.p1.y);
1760 part.yMax = MATH_MIN(mask.GetBottom(), triangleInfo.p2.y);
1761 part.edge1 = edge1;
1762 part.edge2 = edge2;
1763 DrawTriangleTransformPart(gfxDstBuffer, part);
1764 GetInstance()->SetPartEdge(gfxDstBuffer, triangleInfo, edge1, edge2, p3IsInRight, mask, yErr, part);
1765 }
1766
1767 void DrawUtils::SetPartEdge(BufferInfo& gfxDstBuffer, const TriangleTransformDataInfo& triangleInfo,
1768 TriangleEdge& edge1, TriangleEdge& edge2, bool p3IsInRight,
1769 const Rect& mask, uint8_t yErr, TrianglePartInfo& part) const
1770 {
1771 if (triangleInfo.p2.y == triangleInfo.p3.y) {
1772 return;
1773 }
1774
1775 if (triangleInfo.p2.y == triangleInfo.p1.y) {
1776 if (triangleInfo.p1.x < triangleInfo.p2.x) {
1777 edge1 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1778 edge2 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1779 } else {
1780 edge2 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1781 edge1 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1782 }
1783 } else {
1784 if (p3IsInRight) {
1785 edge1 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1786 } else {
1787 edge2 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1788 }
1789 }
1790
1791 part.yMin = MATH_MAX(mask.GetTop(), triangleInfo.p2.y + yErr);
1792 part.yMax = MATH_MIN(mask.GetBottom(), triangleInfo.p3.y);
1793 part.edge1 = edge1;
1794 part.edge2 = edge2;
1795 DrawTriangleTransformPart(gfxDstBuffer, part);
1796 }
1797
1798 void DrawUtils::AddBorderToImageData(TransformDataInfo& newDataInfo, ImageInfo& imageinfo)
1799 {
1800 int16_t border = 1; // 1 : border width
1801 int16_t offset = border * 2; // 2 : offset
1802 uint16_t width = newDataInfo.header.width;
1803 uint16_t height = newDataInfo.header.height;
1804 int16_t diff = 0;
1805 if (newDataInfo.pxSize > FONT_WEIGHT_8) {
1806 width += offset;
1807 height += offset;
1808 diff = border * newDataInfo.pxSize / FONT_WEIGHT_8;
1809 } else {
1810 width += offset * FONT_WEIGHT_8 / newDataInfo.pxSize;
1811 height += offset;
1812 diff = border;
1813 }
1814 uint16_t widthInByte = width * newDataInfo.pxSize / FONT_WEIGHT_8;
1815 if ((width * newDataInfo.pxSize) % FONT_WEIGHT_8 != 0) {
1816 widthInByte++;
1817 }
1818 imageinfo.header.width = newDataInfo.header.width;
1819 imageinfo.header.height = newDataInfo.header.height;
1820 imageinfo.dataSize = widthInByte * height;
1821 uint8_t* newData = static_cast<uint8_t*>(ImageCacheMalloc(imageinfo));
1822 if (newData == nullptr) {
1823 return;
1824 }
1825 imageinfo.data = newData;
1826 if (memset_s(newData, widthInByte * height, 0, widthInByte * height) != EOK) {
1827 ImageCacheFree(imageinfo);
1828 newData = nullptr;
1829 return;
1830 }
1831 uint8_t* tmp = newData;
1832 uint8_t* data = const_cast<uint8_t*>(newDataInfo.data);
1833 tmp += widthInByte * border + diff;
1834 for (int i = 0; i < newDataInfo.header.height; ++i) {
1835 // 2 : double
1836 if (memcpy_s(tmp, widthInByte - diff * 2, data, widthInByte - diff * 2) != EOK) {
1837 ImageCacheFree(imageinfo);
1838 newData = nullptr;
1839 return;
1840 }
1841 tmp += widthInByte;
1842 data += widthInByte - diff * 2; // 2 : double
1843 }
1844 newDataInfo.header.width = width;
1845 newDataInfo.header.height = height;
1846 newDataInfo.data = newData;
1847 }
1848
1849 void DrawUtils::UpdateTransMap(int16_t width, int16_t height, TransformMap& transMap)
1850 {
1851 Rect rect = transMap.GetTransMapRect();
1852 Matrix4<float> matrix = transMap.GetTransformMatrix();
1853 matrix = matrix * (Matrix4<float>::Translate(Vector3<float>(-rect.GetX(), -rect.GetY(), 0)));
1854 int16_t offsetX = (width - rect.GetWidth()) / 2; // 2 : half;
1855 int16_t offsetY = (height - rect.GetHeight()) / 2; // 2 : half;
1856 rect.SetPosition(rect.GetX() - offsetX, rect.GetY() - offsetY);
1857 rect.Resize(width, height);
1858 Polygon polygon = Polygon(rect);
1859 uint8_t vertexNum = transMap.GetPolygon().GetVertexNum();
1860 Vector4<float> imgPoint4;
1861 for (uint8_t i = 0; i < vertexNum; i++) {
1862 Vector4<float> point(polygon[i].x_, polygon[i].y_, 0, 1);
1863 imgPoint4 = matrix * point;
1864 if (imgPoint4.x_ < COORD_MIN) {
1865 polygon[i].x_ = COORD_MIN;
1866 } else if (imgPoint4.x_ > COORD_MAX) {
1867 polygon[i].x_ = COORD_MAX;
1868 } else {
1869 polygon[i].x_ = MATH_ROUND(imgPoint4.x_);
1870 }
1871
1872 if (imgPoint4.y_ < COORD_MIN) {
1873 polygon[i].y_ = COORD_MIN;
1874 } else if (imgPoint4.y_ > COORD_MAX) {
1875 polygon[i].y_ = COORD_MAX;
1876 } else {
1877 polygon[i].y_ = MATH_ROUND(imgPoint4.y_);
1878 }
1879 }
1880 transMap.SetPolygon(polygon);
1881 Matrix3<float> matrix3(matrix[0][0], matrix[0][1], matrix[0][3], matrix[1][0], matrix[1][1], matrix[1][3],
1882 matrix[3][0], matrix[3][1], matrix[3][3]);
1883 transMap.invMatrix_ = (matrix3 * (Matrix3<float>::Translate(Vector2<float>(rect.GetX(), rect.GetY())))).Inverse();
1884 }
1885
1886 void DrawUtils::DrawTransform(BufferInfo& gfxDstBuffer,
1887 const Rect& mask,
1888 const Point& position,
1889 const ColorType& color,
1890 OpacityType opaScale,
1891 const TransformMap& transMap,
1892 const TransformDataInfo& dataInfo) const
1893 {
1894 if (opaScale == OPA_TRANSPARENT) {
1895 return;
1896 }
1897 if ((gfxDstBuffer.virAddr == nullptr) || (dataInfo.data == nullptr)) {
1898 return;
1899 }
1900 ImageInfo imageinfo;
1901 TransformDataInfo newDataInfo = dataInfo;
1902 TransformMap newTransMap = transMap;
1903 // If the width and height of the rectangle of transMap are not equal to the width and height of the ImageHeader,
1904 // a border of transparency values to the data cannot be added.
1905 if ((transMap.GetTransMapRect().GetWidth() == dataInfo.header.width) &&
1906 (transMap.GetTransMapRect().GetHeight() == dataInfo.header.height)) {
1907 // Add a border of transparency values to the data
1908 AddBorderToImageData(newDataInfo, imageinfo);
1909 // Update the transMap according to new rect width and height
1910 UpdateTransMap(newDataInfo.header.width, newDataInfo.header.height, newTransMap);
1911 }
1912
1913 Rect trans = newTransMap.GetBoxRect();
1914 trans.SetX(trans.GetX() + position.x);
1915 trans.SetY(trans.GetY() + position.y);
1916 imageinfo.data = newDataInfo.data;
1917 if (!trans.Intersect(trans, mask)) {
1918 if (newDataInfo.data != dataInfo.data) {
1919 ImageCacheFree(imageinfo);
1920 }
1921 return;
1922 }
1923
1924 TriangleTransformDataInfo triangleInfo{
1925 newDataInfo,
1926 };
1927 Polygon polygon = newTransMap.GetPolygon();
1928 Point p1;
1929 p1.x = polygon[0].x_ + position.x; // 0:first point
1930 p1.y = polygon[0].y_ + position.y; // 0:first point
1931 Point p2;
1932 p2.x = polygon[1].x_ + position.x; // 1:second point
1933 p2.y = polygon[1].y_ + position.y; // 1:second point
1934 Point p3;
1935 p3.x = polygon[2].x_ + position.x; // 2:third point
1936 p3.y = polygon[2].y_ + position.y; // 2:third point
1937 triangleInfo.isRightPart = ((p1.y - p3.y) * p2.x + (p3.x - p1.x) * p2.y + p1.x * p3.y - p3.x * p1.y) < 0;
1938 triangleInfo.isRightPart = (p1.y < p3.y) ? triangleInfo.isRightPart : !triangleInfo.isRightPart;
1939 DrawTriangle::SortVertexs(p1, p2, p3);
1940 triangleInfo.ignoreJunctionPoint = false;
1941 triangleInfo.p1 = p1;
1942 triangleInfo.p2 = p2;
1943 triangleInfo.p3 = p3;
1944 if ((triangleInfo.p1.y <= mask.GetBottom()) && (triangleInfo.p3.y >= mask.GetTop())) {
1945 DrawTriangleTransform(gfxDstBuffer, mask, position, color, opaScale, newTransMap, triangleInfo);
1946 }
1947
1948 triangleInfo.ignoreJunctionPoint = true;
1949 triangleInfo.isRightPart = !triangleInfo.isRightPart;
1950 p1.x = polygon[0].x_ + position.x; // 0:first point
1951 p1.y = polygon[0].y_ + position.y; // 0:first point
1952 p3.x = polygon[2].x_ + position.x; // 2:third point
1953 p3.y = polygon[2].y_ + position.y; // 2:third point
1954 Point p4;
1955 p4.x = polygon[3].x_ + position.x; // 3:fourth point
1956 p4.y = polygon[3].y_ + position.y; // 3:fourth point
1957 DrawTriangle::SortVertexs(p1, p3, p4);
1958 triangleInfo.p1 = p1;
1959 triangleInfo.p2 = p3;
1960 triangleInfo.p3 = p4;
1961 if ((triangleInfo.p1.y <= mask.GetBottom()) && (triangleInfo.p3.y >= mask.GetTop())) {
1962 DrawTriangleTransform(gfxDstBuffer, mask, position, color, opaScale, newTransMap, triangleInfo);
1963 }
1964 if (newDataInfo.data != dataInfo.data) {
1965 ImageCacheFree(imageinfo);
1966 }
1967 }
1968
1969 OpacityType DrawUtils::GetPxAlphaForAlphaImg(const TransformDataInfo& dataInfo, const Point& point)
1970 {
1971 Point tmpPoint = point;
1972 const uint8_t* bufU8 = const_cast<uint8_t*>(dataInfo.data);
1973 #if ENABLE_SPEC_FONT
1974 if (dataInfo.header.colorMode == A1) {
1975 uint8_t bit = tmpPoint.x & 0x7; // 0x7: 1 byte is 8 bit,
1976 tmpPoint.x = tmpPoint.x >> SHIFT_3;
1977
1978 uint32_t px = (dataInfo.header.width >> SHIFT_3) * tmpPoint.y + tmpPoint.x;
1979 // 1: A1 means 1 bit, 7: maximum offset in bytes
1980 uint8_t pxOpa = (bufU8[px] & (1 << (7 - bit))) >> (7 - bit);
1981 return pxOpa ? OPA_TRANSPARENT : OPA_OPAQUE;
1982 } else if (dataInfo.header.colorMode == A2) {
1983 uint8_t bit = (tmpPoint.x & 0x3) * 2; // 0x3: 0b0011, 2: A2 color mode
1984 tmpPoint.x = tmpPoint.x >> SHIFT_2;
1985
1986 uint32_t px = (dataInfo.header.width >> SHIFT_2) * tmpPoint.y + tmpPoint.x;
1987 // 3: the value of 0b0011
1988 uint8_t pxOpa = (bufU8[px] & (3 << (SHIFT_6 - bit))) >> (SHIFT_6 - bit);
1989 return pxOpa * OPACITY_STEP_A2;
1990 } else if (dataInfo.header.colorMode == A8) {
1991 uint32_t px = dataInfo.header.width * tmpPoint.y + tmpPoint.x;
1992 return bufU8[px];
1993 }
1994 #else
1995 uint8_t letterWidthInByte = (dataInfo.header.width * dataInfo.pxSize) >> SHIFT_3;
1996 // 0x7: for rounding
1997 if ((dataInfo.header.width * dataInfo.pxSize) & 0x7) {
1998 letterWidthInByte++;
1999 }
2000 uint8_t bit = (tmpPoint.x & 0x1) << SHIFT_2;
2001 bufU8 += (tmpPoint.y * letterWidthInByte) + ((tmpPoint.x * dataInfo.pxSize) >> SHIFT_3);
2002 // 0xF: 0b1111, get the data of the A4 color mode
2003 uint8_t pxOpa = (*bufU8 & (0xF << bit)) >> (bit);
2004 return pxOpa * OPACITY_STEP_A4;
2005 #endif // ENABLE_SPEC_FONT
2006 }
2007
2008 void DrawUtils::DrawTranspantArea(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& mask)
2009 {
2010 FillArea(gfxDstBuffer, rect, mask, true, nullptr);
2011 }
2012
2013 void DrawUtils::DrawWithBuffer(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& mask, const ColorType* colorBuf)
2014 {
2015 FillArea(gfxDstBuffer, rect, mask, false, colorBuf);
2016 }
2017
2018 void DrawUtils::FillArea(BufferInfo& gfxDstBuffer,
2019 const Rect& rect,
2020 const Rect& mask,
2021 bool isTransparent,
2022 const ColorType* colorBuf)
2023 {
2024 Rect maskedArea;
2025 if (!maskedArea.Intersect(rect, mask)) {
2026 return;
2027 }
2028
2029 int16_t left = maskedArea.GetLeft();
2030 int16_t right = maskedArea.GetRight();
2031 int16_t top = maskedArea.GetTop();
2032 int16_t bottom = maskedArea.GetBottom();
2033
2034 DRAW_UTILS_PREPROCESS(gfxDstBuffer, OPA_OPAQUE);
2035 uint8_t* mem = screenBuffer;
2036 mem += top * screenBufferWidth * bufferPxSize;
2037 if (isTransparent) {
2038 uint16_t sz = (right - left + 1) * bufferPxSize;
2039 for (int16_t row = top; row <= bottom; row++) {
2040 if (memset_s(mem + (left * bufferPxSize), sz, 0, sz) != EOK) {
2041 return;
2042 }
2043 mem += screenBufferWidth * bufferPxSize;
2044 }
2045 } else {
2046 if (colorBuf == nullptr) {
2047 return;
2048 }
2049 for (int16_t row = top; row <= bottom; row++) {
2050 for (int16_t col = left; col <= right; col++) {
2051 #if COLOR_DEPTH == 32
2052 COLOR_FILL_COVER(mem[col * bufferPxSize], bufferMode, colorBuf[row * screenBufferWidth + col].red,
2053 colorBuf[row * screenBufferWidth + col].green,
2054 colorBuf[row * screenBufferWidth + col].blue, ARGB8888);
2055 #else
2056 COLOR_FILL_COVER(mem[col * bufferPxSize], bufferMode, colorBuf[row * screenBufferWidth + col].red,
2057 colorBuf[row * screenBufferWidth + col].green,
2058 colorBuf[row * screenBufferWidth + col].blue, RGB565);
2059 #endif
2060 }
2061 mem += screenBufferWidth * bufferPxSize;
2062 }
2063 }
2064 }
2065
2066 void DrawUtils::DrawAdjPixelInLine(BufferInfo& gfxDstBuffer,
2067 int16_t x1,
2068 int16_t y1,
2069 int16_t x2,
2070 int16_t y2,
2071 const Rect& mask,
2072 const ColorType& color,
2073 OpacityType opa,
2074 uint16_t weight) const
2075 {
2076 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2077 Color32 result;
2078 result.full = Color::ColorTo32(color);
2079 if ((x1 >= mask.GetLeft()) && (x1 <= mask.GetRight()) && (y1 >= mask.GetTop()) && (y1 <= mask.GetBottom())) {
2080 screenBuffer += (y1 * screenBufferWidth + x1) * bufferPxSize;
2081 OpacityType fillOpa = (weight ^ OPA_OPAQUE) * opa / OPA_OPAQUE;
2082 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2083 }
2084 if ((x2 >= mask.GetLeft()) && (x2 <= mask.GetRight()) && (y2 >= mask.GetTop()) && (y2 <= mask.GetBottom())) {
2085 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2086 screenBuffer += (y2 * screenBufferWidth + x2) * bufferPxSize;
2087 OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2088 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2089 }
2090 }
2091
2092 void DrawUtils::DrawPixelInLine(BufferInfo& gfxDstBuffer,
2093 int16_t x,
2094 int16_t y,
2095 const Rect& mask,
2096 const ColorType& color,
2097 OpacityType opa,
2098 uint16_t weight) const
2099 {
2100 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2101 Color32 result;
2102 result.full = Color::ColorTo32(color);
2103 if ((x >= mask.GetLeft()) && (x <= mask.GetRight()) && (y >= mask.GetTop()) && (y <= mask.GetBottom())) {
2104 screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
2105 OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2106 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2107 }
2108 }
2109
2110 void DrawUtils::DrawVerPixelInLine(BufferInfo& gfxDstBuffer,
2111 int16_t x,
2112 int16_t y,
2113 int8_t dir,
2114 const Rect& mask,
2115 const ColorType& color,
2116 OpacityType opa,
2117 uint16_t weight) const
2118 {
2119 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2120 if ((y < mask.GetTop()) || (y > mask.GetBottom())) {
2121 return;
2122 }
2123 Color32 result;
2124 result.full = Color::ColorTo32(color);
2125 int16_t x0 = x + dir;
2126 int16_t x1 = x - dir;
2127 if ((x0 >= mask.GetLeft()) && (x0 <= mask.GetRight())) {
2128 screenBuffer += (y * screenBufferWidth + x0) * bufferPxSize;
2129 OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2130 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2131 }
2132 if ((x >= mask.GetLeft()) && (x <= mask.GetRight())) {
2133 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2134 screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
2135 if (opa == OPA_OPAQUE) {
2136 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
2137 } else {
2138 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, opa);
2139 }
2140 }
2141 if ((x1 >= mask.GetLeft()) && (x1 <= mask.GetRight())) {
2142 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2143 screenBuffer += (y * screenBufferWidth + x1) * bufferPxSize;
2144 OpacityType fillOpa = (weight ^ OPA_OPAQUE) * opa / OPA_OPAQUE;
2145 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2146 }
2147 }
2148
2149 void DrawUtils::DrawHorPixelInLine(BufferInfo& gfxDstBuffer,
2150 int16_t x,
2151 int16_t y,
2152 int8_t dir,
2153 const Rect& mask,
2154 const ColorType& color,
2155 OpacityType opa,
2156 uint16_t weight) const
2157 {
2158 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2159 if ((x < mask.GetLeft()) || (x > mask.GetRight())) {
2160 return;
2161 }
2162 Color32 result;
2163 result.full = Color::ColorTo32(color);
2164 int16_t y0 = y + dir;
2165 int16_t y1 = y - dir;
2166 if ((y0 >= mask.GetTop()) && (y0 <= mask.GetBottom())) {
2167 screenBuffer += (y0 * screenBufferWidth + x) * bufferPxSize;
2168 OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2169 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2170 }
2171 if ((y >= mask.GetTop()) && (y <= mask.GetBottom())) {
2172 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2173 screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
2174 if (opa == OPA_OPAQUE) {
2175 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
2176 } else {
2177 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, opa);
2178 }
2179 }
2180 if ((y1 >= mask.GetTop()) && (y1 <= mask.GetBottom())) {
2181 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2182 screenBuffer += (y1 * screenBufferWidth + x) * bufferPxSize;
2183 OpacityType fillOpa = (weight ^ OPA_OPAQUE) * opa / OPA_OPAQUE;
2184 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2185 }
2186 }
2187 } // namespace OHOS
2188