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
37namespace 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
51namespace {
52static constexpr uint8_t OPACITY_STEP_A1 = 255;
53static constexpr uint8_t OPACITY_STEP_A2 = 85;
54static constexpr uint8_t OPACITY_STEP_A4 = 17;
55} // namespace
56
57TriangleEdge::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
72TriangleEdge::~TriangleEdge() {}
73
74DrawUtils* DrawUtils::GetInstance()
75{
76    static DrawUtils instance;
77    return &instance;
78}
79
80void 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
90void 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
108uint8_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
139uint8_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
156void 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
176void 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
222void 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
293void 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
378void 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
417void 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
509void 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
516void 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
522void DrawUtils::BlendLerpPix(uint8_t* dstColors, uint8_t* srcColors, uint8_t srcCover)
523{
524    NeonBlendPipeLine mNeonBlendPipeLine;
525    mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCover);
526}
527
528void DrawUtils::BlendLerpPix(uint8_t* dstColors, uint8_t* srcColors, uint8_t* srcCovers)
529{
530    NeonBlendPipeLine mNeonBlendPipeLine;
531    mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCovers);
532}
533
534void 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
541void 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
548void 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}
553void DrawUtils::BlendPreLerpPix(uint8_t *dstColors, uint8_t *srcColors, uint8_t srcCover)
554{
555    NeonBlendPipeLine mNeonBlendPipeLine;
556    mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCover);
557}
558
559void DrawUtils::BlendPreLerpPix(uint8_t *dstColors, uint8_t *srcColors, uint8_t *srcCovers)
560{
561    NeonBlendPipeLine mNeonBlendPipeLine;
562    mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCovers);
563}
564
565void 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
573void 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
621void 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
651void 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
667void 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
695inline 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
710void 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
810void 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
930void 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
1051static 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
1119static 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
1188static 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
1321void 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
1459void 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
1522void 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
1631void 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
1667void 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
1717void 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
1767void 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
1798void 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
1849void 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
1886void 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
1969OpacityType 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
2008void DrawUtils::DrawTranspantArea(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& mask)
2009{
2010    FillArea(gfxDstBuffer, rect, mask, true, nullptr);
2011}
2012
2013void DrawUtils::DrawWithBuffer(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& mask, const ColorType* colorBuf)
2014{
2015    FillArea(gfxDstBuffer, rect, mask, false, colorBuf);
2016}
2017
2018void 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
2066void 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
2092void 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
2110void 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
2149void 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