1 /* 2 * Copyright 2009, Christian Packmann. 3 * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>. 4 * Copyright 2005-2014, Stephan Aßmus <superstippi@gmx.de>. 5 * Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de> 6 * All rights reserved. Distributed under the terms of the MIT License. 7 */ 8 #ifndef DRAW_BITMAP_BILINEAR_H 9 #define DRAW_BITMAP_BILINEAR_H 10 11 #include "Painter.h" 12 13 #include <typeinfo> 14 15 16 // Prototypes for assembler routines 17 extern "C" { 18 void bilinear_scale_xloop_mmxsse(const uint8* src, void* dst, 19 void* xWeights, uint32 xmin, uint32 xmax, uint32 wTop, uint32 srcBPR); 20 } 21 22 23 extern uint32 gSIMDFlags; 24 25 26 namespace BitmapPainterPrivate { 27 28 29 struct FilterInfo { 30 uint16 index; // index into source bitmap row/column 31 uint16 weight; // weight of the pixel at index [0..255] 32 }; 33 34 35 struct FilterData { 36 FilterInfo* fWeightsX; 37 FilterInfo* fWeightsY; 38 uint32 fIndexOffsetX; 39 uint32 fIndexOffsetY; 40 }; 41 42 43 template<class OptimizedVersion> 44 struct DrawBitmapBilinearOptimized { 45 void Draw(PainterAggInterface& aggInterface, const BRect& destinationRect, 46 agg::rendering_buffer* bitmap, const FilterData& filterData) 47 { 48 fSource = bitmap; 49 fSourceBytesPerRow = bitmap->stride(); 50 fDestination = NULL; 51 fDestinationBytesPerRow = aggInterface.fBuffer.stride(); 52 fWeightsX = filterData.fWeightsX; 53 fWeightsY = filterData.fWeightsY; 54 55 const int32 left = (int32)destinationRect.left; 56 const int32 top = (int32)destinationRect.top; 57 const int32 right = (int32)destinationRect.right; 58 const int32 bottom = (int32)destinationRect.bottom; 59 60 renderer_base& baseRenderer = aggInterface.fBaseRenderer; 61 62 // iterate over clipping boxes 63 baseRenderer.first_clip_box(); 64 do { 65 const int32 x1 = max_c(baseRenderer.xmin(), left); 66 const int32 x2 = min_c(baseRenderer.xmax(), right); 67 if (x1 > x2) 68 continue; 69 70 int32 y1 = max_c(baseRenderer.ymin(), top); 71 int32 y2 = min_c(baseRenderer.ymax(), bottom); 72 if (y1 > y2) 73 continue; 74 75 // buffer offset into destination 76 fDestination = aggInterface.fBuffer.row_ptr(y1) + x1 * 4; 77 78 // x and y are needed as indices into the weight arrays, so the 79 // offset into the target buffer needs to be compensated 80 const int32 xIndexL = x1 - left - filterData.fIndexOffsetX; 81 const int32 xIndexR = x2 - left - filterData.fIndexOffsetX; 82 y1 -= top + filterData.fIndexOffsetY; 83 y2 -= top + filterData.fIndexOffsetY; 84 85 //printf("x: %ld - %ld\n", xIndexL, xIndexR); 86 //printf("y: %ld - %ld\n", y1, y2); 87 88 static_cast<OptimizedVersion*>(this)->DrawToClipRect( 89 xIndexL, xIndexR, y1, y2); 90 91 } while (baseRenderer.next_clip_box()); 92 } 93 94 protected: 95 agg::rendering_buffer* fSource; 96 uint32 fSourceBytesPerRow; 97 uint8* fDestination; 98 uint32 fDestinationBytesPerRow; 99 FilterInfo* fWeightsX; 100 FilterInfo* fWeightsY; 101 }; 102 103 104 struct ColorTypeRgb { 105 static void 106 Interpolate(uint32* t, const uint8* s, uint32 sourceBytesPerRow, 107 uint16 wLeft, uint16 wTop, uint16 wRight, uint16 wBottom) 108 { 109 // left and right of top row 110 t[0] = (s[0] * wLeft + s[4] * wRight) * wTop; 111 t[1] = (s[1] * wLeft + s[5] * wRight) * wTop; 112 t[2] = (s[2] * wLeft + s[6] * wRight) * wTop; 113 114 // left and right of bottom row 115 s += sourceBytesPerRow; 116 t[0] += (s[0] * wLeft + s[4] * wRight) * wBottom; 117 t[1] += (s[1] * wLeft + s[5] * wRight) * wBottom; 118 t[2] += (s[2] * wLeft + s[6] * wRight) * wBottom; 119 120 t[0] >>= 16; 121 t[1] >>= 16; 122 t[2] >>= 16; 123 } 124 125 static void 126 InterpolateLastColumn(uint32* t, const uint8* s, const uint8* sBottom, 127 uint16 wTop, uint16 wBottom) 128 { 129 t[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; 130 t[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; 131 t[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; 132 } 133 134 static void 135 InterpolateLastRow(uint32* t, const uint8* s, uint16 wLeft, 136 uint16 wRight) 137 { 138 t[0] = (s[0] * wLeft + s[4] * wRight) >> 8; 139 t[1] = (s[1] * wLeft + s[5] * wRight) >> 8; 140 t[2] = (s[2] * wLeft + s[6] * wRight) >> 8; 141 } 142 }; 143 144 145 struct ColorTypeRgba { 146 static void 147 Interpolate(uint32* t, const uint8* s, uint32 sourceBytesPerRow, 148 uint16 wLeft, uint16 wTop, uint16 wRight, uint16 wBottom) 149 { 150 // left and right of top row 151 t[0] = (s[0] * wLeft + s[4] * wRight) * wTop; 152 t[1] = (s[1] * wLeft + s[5] * wRight) * wTop; 153 t[2] = (s[2] * wLeft + s[6] * wRight) * wTop; 154 t[3] = (s[3] * wLeft + s[7] * wRight) * wTop; 155 156 // left and right of bottom row 157 s += sourceBytesPerRow; 158 159 t[0] += (s[0] * wLeft + s[4] * wRight) * wBottom; 160 t[1] += (s[1] * wLeft + s[5] * wRight) * wBottom; 161 t[2] += (s[2] * wLeft + s[6] * wRight) * wBottom; 162 t[3] += (s[3] * wLeft + s[7] * wRight) * wBottom; 163 164 t[0] >>= 16; 165 t[1] >>= 16; 166 t[2] >>= 16; 167 t[3] >>= 16; 168 } 169 170 static void 171 InterpolateLastColumn(uint32* t, const uint8* s, const uint8* sBottom, 172 uint16 wTop, uint16 wBottom) 173 { 174 t[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; 175 t[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; 176 t[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; 177 t[3] = (s[3] * wTop + sBottom[3] * wBottom) >> 8; 178 } 179 180 static void 181 InterpolateLastRow(uint32* t, const uint8* s, uint16 wLeft, 182 uint16 wRight) 183 { 184 t[0] = (s[0] * wLeft + s[4] * wRight) >> 8; 185 t[1] = (s[1] * wLeft + s[5] * wRight) >> 8; 186 t[2] = (s[2] * wLeft + s[6] * wRight) >> 8; 187 t[3] = (s[3] * wLeft + s[7] * wRight) >> 8; 188 } 189 }; 190 191 192 struct DrawModeCopy { 193 static void 194 Blend(uint8*& d, uint32* t) 195 { 196 d[0] = t[0]; 197 d[1] = t[1]; 198 d[2] = t[2]; 199 d += 4; 200 } 201 }; 202 203 204 struct DrawModeAlphaOverlay { 205 static void 206 Blend(uint8*& d, uint32* t) 207 { 208 uint8 t0 = t[0]; 209 uint8 t1 = t[1]; 210 uint8 t2 = t[2]; 211 uint8 t3 = t[3]; 212 213 if (t3 == 255) { 214 d[0] = t0; 215 d[1] = t1; 216 d[2] = t2; 217 } else { 218 d[0] = ((t0 - d[0]) * t3 + (d[0] << 8)) >> 8; 219 d[1] = ((t1 - d[1]) * t3 + (d[1] << 8)) >> 8; 220 d[2] = ((t2 - d[2]) * t3 + (d[2] << 8)) >> 8; 221 } 222 223 d += 4; 224 } 225 }; 226 227 228 template<class ColorType, class DrawMode> 229 struct BilinearDefault : 230 DrawBitmapBilinearOptimized<BilinearDefault<ColorType, DrawMode> > { 231 232 void DrawToClipRect(int32 xIndexL, int32 xIndexR, int32 y1, int32 y2) 233 { 234 // In this mode we anticipate many pixels wich need filtering, 235 // there are no special cases for direct hit pixels except for 236 // the last column/row and the right/bottom corner pixel. 237 238 // The last column/row handling does not need to be performed 239 // for all clipping rects! 240 int32 yMax = y2; 241 if (this->fWeightsY[yMax].weight == 255) 242 yMax--; 243 int32 xIndexMax = xIndexR; 244 if (this->fWeightsX[xIndexMax].weight == 255) 245 xIndexMax--; 246 247 for (; y1 <= yMax; y1++) { 248 // cache the weight of the top and bottom row 249 const uint16 wTop = this->fWeightsY[y1].weight; 250 const uint16 wBottom = 255 - this->fWeightsY[y1].weight; 251 252 // buffer offset into source (top row) 253 const uint8* src = this->fSource->row_ptr( 254 this->fWeightsY[y1].index); 255 256 // buffer handle for destination to be incremented per 257 // pixel 258 uint8* d = this->fDestination; 259 260 for (int32 x = xIndexL; x <= xIndexMax; x++) { 261 const uint8* s = src + this->fWeightsX[x].index; 262 263 // calculate the weighted sum of all four 264 // interpolated pixels 265 const uint16 wLeft = this->fWeightsX[x].weight; 266 const uint16 wRight = 255 - wLeft; 267 268 uint32 t[4]; 269 270 if (this->fSource->height() > 1) { 271 ColorType::Interpolate(&t[0], s, this->fSourceBytesPerRow, 272 wLeft, wTop, wRight, wBottom); 273 } else { 274 ColorType::InterpolateLastRow(&t[0], s, wLeft, wRight); 275 } 276 DrawMode::Blend(d, &t[0]); 277 } 278 // last column of pixels if necessary 279 if (xIndexMax < xIndexR && this->fSource->height() > 1) { 280 const uint8* s = src + this->fWeightsX[xIndexR].index; 281 const uint8* sBottom = s + this->fSourceBytesPerRow; 282 283 uint32 t[4]; 284 ColorType::InterpolateLastColumn(&t[0], s, sBottom, wTop, 285 wBottom); 286 DrawMode::Blend(d, &t[0]); 287 } 288 289 this->fDestination += this->fDestinationBytesPerRow; 290 } 291 292 // last row of pixels if necessary 293 // buffer offset into source (bottom row) 294 const uint8* src 295 = this->fSource->row_ptr(this->fWeightsY[y2].index); 296 // buffer handle for destination to be incremented per pixel 297 uint8* d = this->fDestination; 298 299 if (yMax < y2) { 300 for (int32 x = xIndexL; x <= xIndexMax; x++) { 301 const uint8* s = src + this->fWeightsX[x].index; 302 const uint16 wLeft = this->fWeightsX[x].weight; 303 const uint16 wRight = 255 - wLeft; 304 uint32 t[4]; 305 ColorType::InterpolateLastRow(&t[0], s, wLeft, wRight); 306 DrawMode::Blend(d, &t[0]); 307 } 308 } 309 310 // pixel in bottom right corner if necessary 311 if (yMax < y2 && xIndexMax < xIndexR) { 312 const uint8* s = src + this->fWeightsX[xIndexR].index; 313 *(uint32*)d = *(uint32*)s; 314 } 315 } 316 }; 317 318 319 struct BilinearLowFilterRatio : 320 DrawBitmapBilinearOptimized<BilinearLowFilterRatio> { 321 void DrawToClipRect(int32 xIndexL, int32 xIndexR, int32 y1, int32 y2) 322 { 323 // In this mode, we anticipate to hit many destination pixels 324 // that map directly to a source pixel, we have more branches 325 // in the inner loop but save time because of the special 326 // cases. If there are too few direct hit pixels, the branches 327 // only waste time. 328 329 for (; y1 <= y2; y1++) { 330 // cache the weight of the top and bottom row 331 const uint16 wTop = fWeightsY[y1].weight; 332 const uint16 wBottom = 255 - fWeightsY[y1].weight; 333 334 // buffer offset into source (top row) 335 const uint8* src = fSource->row_ptr(fWeightsY[y1].index); 336 // buffer handle for destination to be incremented per 337 // pixel 338 uint8* d = fDestination; 339 340 if (wTop == 255) { 341 for (int32 x = xIndexL; x <= xIndexR; x++) { 342 const uint8* s = src + fWeightsX[x].index; 343 // This case is important to prevent out 344 // of bounds access at bottom edge of the source 345 // bitmap. If the scale is low and integer, it will 346 // also help the speed. 347 if (fWeightsX[x].weight == 255) { 348 // As above, but to prevent out of bounds 349 // on the right edge. 350 *(uint32*)d = *(uint32*)s; 351 } else { 352 // Only the left and right pixels are 353 // interpolated, since the top row has 100% 354 // weight. 355 const uint16 wLeft = fWeightsX[x].weight; 356 const uint16 wRight = 255 - wLeft; 357 d[0] = (s[0] * wLeft + s[4] * wRight) >> 8; 358 d[1] = (s[1] * wLeft + s[5] * wRight) >> 8; 359 d[2] = (s[2] * wLeft + s[6] * wRight) >> 8; 360 } 361 d += 4; 362 } 363 } else { 364 for (int32 x = xIndexL; x <= xIndexR; x++) { 365 const uint8* s = src + fWeightsX[x].index; 366 if (fWeightsX[x].weight == 255) { 367 // Prevent out of bounds access on the right 368 // edge or simply speed up. 369 const uint8* sBottom = s + fSourceBytesPerRow; 370 d[0] = (s[0] * wTop + sBottom[0] * wBottom) 371 >> 8; 372 d[1] = (s[1] * wTop + sBottom[1] * wBottom) 373 >> 8; 374 d[2] = (s[2] * wTop + sBottom[2] * wBottom) 375 >> 8; 376 } else { 377 // calculate the weighted sum of all four 378 // interpolated pixels 379 const uint16 wLeft = fWeightsX[x].weight; 380 const uint16 wRight = 255 - wLeft; 381 // left and right of top row 382 uint32 t0 = (s[0] * wLeft + s[4] * wRight) 383 * wTop; 384 uint32 t1 = (s[1] * wLeft + s[5] * wRight) 385 * wTop; 386 uint32 t2 = (s[2] * wLeft + s[6] * wRight) 387 * wTop; 388 389 // left and right of bottom row 390 s += fSourceBytesPerRow; 391 t0 += (s[0] * wLeft + s[4] * wRight) * wBottom; 392 t1 += (s[1] * wLeft + s[5] * wRight) * wBottom; 393 t2 += (s[2] * wLeft + s[6] * wRight) * wBottom; 394 395 d[0] = t0 >> 16; 396 d[1] = t1 >> 16; 397 d[2] = t2 >> 16; 398 } 399 d += 4; 400 } 401 } 402 fDestination += fDestinationBytesPerRow; 403 } 404 } 405 }; 406 407 408 #ifdef __i386__ 409 410 struct BilinearSimd : DrawBitmapBilinearOptimized<BilinearSimd> { 411 void DrawToClipRect(int32 xIndexL, int32 xIndexR, int32 y1, int32 y2) 412 { 413 // Basically the same as the "standard" mode, but we use SIMD 414 // routines for the processing of the single display lines. 415 416 // The last column/row handling does not need to be performed 417 // for all clipping rects! 418 int32 yMax = y2; 419 if (fWeightsY[yMax].weight == 255) 420 yMax--; 421 int32 xIndexMax = xIndexR; 422 if (fWeightsX[xIndexMax].weight == 255) 423 xIndexMax--; 424 425 for (; y1 <= yMax; y1++) { 426 // cache the weight of the top and bottom row 427 const uint16 wTop = fWeightsY[y1].weight; 428 const uint16 wBottom = 255 - fWeightsY[y1].weight; 429 430 // buffer offset into source (top row) 431 const uint8* src = fSource->row_ptr(fWeightsY[y1].index); 432 // buffer handle for destination to be incremented per 433 // pixel 434 uint8* d = fDestination; 435 bilinear_scale_xloop_mmxsse(src, fDestination, fWeightsX, xIndexL, 436 xIndexMax, wTop, fSourceBytesPerRow); 437 // increase pointer by processed pixels 438 d += (xIndexMax - xIndexL + 1) * 4; 439 440 // last column of pixels if necessary 441 if (xIndexMax < xIndexR) { 442 const uint8* s = src + fWeightsX[xIndexR].index; 443 const uint8* sBottom = s + fSourceBytesPerRow; 444 d[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; 445 d[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; 446 d[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; 447 } 448 449 fDestination += fDestinationBytesPerRow; 450 } 451 452 // last row of pixels if necessary 453 // buffer offset into source (bottom row) 454 const uint8* src = fSource->row_ptr(fWeightsY[y2].index); 455 // buffer handle for destination to be incremented per pixel 456 uint8* d = fDestination; 457 458 if (yMax < y2) { 459 for (int32 x = xIndexL; x <= xIndexMax; x++) { 460 const uint8* s = src + fWeightsX[x].index; 461 const uint16 wLeft = fWeightsX[x].weight; 462 const uint16 wRight = 255 - wLeft; 463 d[0] = (s[0] * wLeft + s[4] * wRight) >> 8; 464 d[1] = (s[1] * wLeft + s[5] * wRight) >> 8; 465 d[2] = (s[2] * wLeft + s[6] * wRight) >> 8; 466 d += 4; 467 } 468 } 469 470 // pixel in bottom right corner if necessary 471 if (yMax < y2 && xIndexMax < xIndexR) { 472 const uint8* s = src + fWeightsX[xIndexR].index; 473 *(uint32*)d = *(uint32*)s; 474 } 475 } 476 }; 477 478 #endif // __i386__ 479 480 481 template<class ColorType, class DrawMode> 482 struct DrawBitmapBilinear { 483 void 484 Draw(const Painter* painter, PainterAggInterface& aggInterface, 485 agg::rendering_buffer& bitmap, BPoint offset, 486 double scaleX, double scaleY, BRect destinationRect) 487 { 488 //bigtime_t now = system_time(); 489 uint32 dstWidth = destinationRect.IntegerWidth() + 1; 490 uint32 dstHeight = destinationRect.IntegerHeight() + 1; 491 uint32 srcWidth = bitmap.width(); 492 uint32 srcHeight = bitmap.height(); 493 494 // Do not calculate more filter weights than necessary and also 495 // keep the stack based allocations reasonably sized 496 const BRegion& clippingRegion = *painter->ClippingRegion(); 497 if (clippingRegion.Frame().IntegerWidth() + 1 < (int32)dstWidth) 498 dstWidth = clippingRegion.Frame().IntegerWidth() + 1; 499 if (clippingRegion.Frame().IntegerHeight() + 1 < (int32)dstHeight) 500 dstHeight = clippingRegion.Frame().IntegerHeight() + 1; 501 502 // When calculating less filter weights than specified by 503 // destinationRect, we need to compensate the offset. 504 FilterData filterData; 505 filterData.fIndexOffsetX = 0; 506 filterData.fIndexOffsetY = 0; 507 if (clippingRegion.Frame().left > destinationRect.left) { 508 filterData.fIndexOffsetX = (int32)(clippingRegion.Frame().left 509 - destinationRect.left); 510 } 511 if (clippingRegion.Frame().top > destinationRect.top) { 512 filterData.fIndexOffsetY = (int32)(clippingRegion.Frame().top 513 - destinationRect.top); 514 } 515 516 //#define FILTER_INFOS_ON_HEAP 517 #ifdef FILTER_INFOS_ON_HEAP 518 filterData.fWeightsX = new (nothrow) FilterInfo[dstWidth]; 519 filterData.fWeightsY = new (nothrow) FilterInfo[dstHeight]; 520 if (filterData.fWeightsX == NULL || filterData.fWeightsY == NULL) { 521 delete[] filterData.fWeightsX; 522 delete[] filterData.fWeightsY; 523 return; 524 } 525 #else 526 // stack based saves about 200µs on 1.85 GHz Core 2 Duo 527 // should not pose a problem with stack overflows 528 // (needs around 12Kb for 1920x1200) 529 FilterInfo xWeights[dstWidth]; 530 FilterInfo yWeights[dstHeight]; 531 filterData.fWeightsX = &xWeights[0]; 532 filterData.fWeightsY = &yWeights[0]; 533 #endif 534 535 // Extract the cropping information for the source bitmap, 536 // If only a part of the source bitmap is to be drawn with scale, 537 // the offset will be different from the destinationRect left top 538 // corner. 539 const int32 xBitmapShift = (int32)(destinationRect.left - offset.x); 540 const int32 yBitmapShift = (int32)(destinationRect.top - offset.y); 541 542 for (uint32 i = 0; i < dstWidth; i++) { 543 // fractional index into source 544 // NOTE: It is very important to calculate the fractional index 545 // into the source pixel grid like this to prevent out of bounds 546 // access! It will result in the rightmost pixel of the destination 547 // to access the rightmost pixel of the source with a weighting 548 // of 255. This in turn will trigger an optimization in the loop 549 // that also prevents out of bounds access. 550 float index = (i + filterData.fIndexOffsetX) * (srcWidth - 1) 551 / (srcWidth * scaleX - 1); 552 // round down to get the left pixel 553 filterData.fWeightsX[i].index = (uint16)index; 554 filterData.fWeightsX[i].weight = 555 255 - (uint16)((index - filterData.fWeightsX[i].index) * 255); 556 // handle cropped source bitmap 557 filterData.fWeightsX[i].index += xBitmapShift; 558 // precompute index for 32 bit pixels 559 filterData.fWeightsX[i].index *= 4; 560 } 561 562 for (uint32 i = 0; i < dstHeight; i++) { 563 // fractional index into source 564 // NOTE: It is very important to calculate the fractional index 565 // into the source pixel grid like this to prevent out of bounds 566 // access! It will result in the bottommost pixel of the 567 // destination to access the bottommost pixel of the source with a 568 // weighting of 255. This in turn will trigger an optimization in 569 // the loop that also prevents out of bounds access. 570 float index = (i + filterData.fIndexOffsetY) * (srcHeight - 1) 571 / (srcHeight * scaleY - 1); 572 // round down to get the top pixel 573 filterData.fWeightsY[i].index = (uint16)index; 574 filterData.fWeightsY[i].weight = 575 255 - (uint16)((index - filterData.fWeightsY[i].index) * 255); 576 // handle cropped source bitmap 577 filterData.fWeightsY[i].index += yBitmapShift; 578 } 579 //printf("X: %d/%d ... %d/%d, %d/%d (%ld)\n", 580 // xWeights[0].index, xWeights[0].weight, 581 // xWeights[dstWidth - 2].index, xWeights[dstWidth - 2].weight, 582 // xWeights[dstWidth - 1].index, xWeights[dstWidth - 1].weight, 583 // dstWidth); 584 //printf("Y: %d/%d ... %d/%d, %d/%d (%ld)\n", 585 // yWeights[0].index, yWeights[0].weight, 586 // yWeights[dstHeight - 2].index, yWeights[dstHeight - 2].weight, 587 // yWeights[dstHeight - 1].index, yWeights[dstHeight - 1].weight, 588 // dstHeight); 589 590 // Figure out which version of the code we want to use... 591 enum { 592 kOptimizeForLowFilterRatio = 0, 593 kUseDefaultVersion, 594 kUseSIMDVersion 595 }; 596 597 int codeSelect = kUseDefaultVersion; 598 599 if (typeid(ColorType) == typeid(ColorTypeRgb) 600 && typeid(DrawMode) == typeid(DrawModeCopy)) { 601 uint32 neededSIMDFlags = APPSERVER_SIMD_MMX | APPSERVER_SIMD_SSE; 602 if ((gSIMDFlags & neededSIMDFlags) == neededSIMDFlags) 603 codeSelect = kUseSIMDVersion; 604 else { 605 if (scaleX == scaleY && (scaleX == 1.5 || scaleX == 2.0 606 || scaleX == 2.5 || scaleX == 3.0)) { 607 codeSelect = kOptimizeForLowFilterRatio; 608 } 609 } 610 } 611 612 switch (codeSelect) { 613 case kUseDefaultVersion: 614 { 615 BilinearDefault<ColorType, DrawMode> bilinearPainter; 616 bilinearPainter.Draw(aggInterface, destinationRect, &bitmap, 617 filterData); 618 break; 619 } 620 621 case kOptimizeForLowFilterRatio: 622 { 623 BilinearLowFilterRatio bilinearPainter; 624 bilinearPainter.Draw(aggInterface, destinationRect, 625 &bitmap, filterData); 626 break; 627 } 628 629 #ifdef __i386__ 630 case kUseSIMDVersion: 631 { 632 BilinearSimd bilinearPainter; 633 bilinearPainter.Draw(aggInterface, destinationRect, &bitmap, 634 filterData); 635 break; 636 } 637 #endif // __i386__ 638 } 639 640 #ifdef FILTER_INFOS_ON_HEAP 641 delete[] filterData.fWeightsX; 642 delete[] filterData.fWeightsY; 643 #endif 644 //printf("draw bitmap %.5fx%.5f: %lld\n", scaleX, scaleY, 645 // system_time() - now); 646 } 647 }; 648 649 650 } // namespace BitmapPainterPrivate 651 652 653 #endif // DRAW_BITMAP_BILINEAR_H 654