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