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