From 64c6e038ebf396d2bc65fae21533458355fd6b90 Mon Sep 17 00:00:00 2001 From: Julian Harnath Date: Sat, 15 Aug 2015 12:50:32 +0200 Subject: [PATCH] app_server: bilinear bitmap painting: alpha overlay support * Add support for pixel alpha overlay mode in the optimized bilinear- scaled bitmap drawing code of BitmapPainter. For now, only BilinearDefault supports this. DrawBitmapBilinear gets the colour type and draw mode as template parameters to minimize code duplication and allow simple extension with further pixel formats and modes. Avoids, for this mode, fallback to the slower generic AGG-pipeline-based version. --- .../Painter/bitmap_painter/BitmapPainter.cpp | 16 +- .../bitmap_painter/DrawBitmapBilinear.h | 191 +++++++++++++++--- 2 files changed, 172 insertions(+), 35 deletions(-) diff --git a/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.cpp b/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.cpp index 813f291e90..d22e8c0e62 100644 --- a/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.cpp +++ b/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.cpp @@ -138,17 +138,27 @@ Painter::BitmapPainter::Draw(const BRect& sourceRect, if (fPainter->fDrawingMode == B_OP_COPY && !_HasAffineTransform() && !_HasAlphaMask()) { if ((fOptions & B_FILTER_BITMAP_BILINEAR) != 0) { - DrawBitmapBilinearCopy drawBilinear; + DrawBitmapBilinear drawBilinear; drawBilinear.Draw(fPainter, fPainter->fInternal, fBitmap, fOffset, fScaleX, fScaleY, fDestinationRect); - } - else { + } else { DrawBitmapNearestNeighborCopy::Draw(fPainter, fPainter->fInternal, fBitmap, fOffset, fScaleX, fScaleY, fDestinationRect); } return; } + if (fPainter->fDrawingMode == B_OP_ALPHA + && fPainter->fAlphaSrcMode == B_PIXEL_ALPHA + && fPainter->fAlphaFncMode == B_ALPHA_OVERLAY + && !_HasAffineTransform() && !_HasAlphaMask() + && (fOptions & B_FILTER_BITMAP_BILINEAR) != 0) { + DrawBitmapBilinear drawBilinear; + drawBilinear.Draw(fPainter, fPainter->fInternal, + fBitmap, fOffset, fScaleX, fScaleY, fDestinationRect); + return; + } + // for all other cases (non-optimized drawing mode or scaled drawing) DrawBitmapGeneric::Draw(fPainter, fPainter->fInternal, fBitmap, fOffset, fScaleX, fScaleY, fDestinationRect, fOptions); diff --git a/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapBilinear.h b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapBilinear.h index 5dc75257a1..5268a6b2d4 100644 --- a/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapBilinear.h +++ b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapBilinear.h @@ -10,6 +10,8 @@ #include "Painter.h" +#include + // Prototypes for assembler routines extern "C" { @@ -83,8 +85,8 @@ struct DrawBitmapBilinearOptimized { //printf("x: %ld - %ld\n", xIndexL, xIndexR); //printf("y: %ld - %ld\n", y1, y2); - OptimizedVersion optimizedVersion; - optimizedVersion.DrawToClipRect(xIndexL, xIndexR, y1, y2); + static_cast(this)->DrawToClipRect( + xIndexL, xIndexR, y1, y2); } while (baseRenderer.next_clip_box()); } @@ -99,7 +101,134 @@ protected: }; -struct BilinearDefault : DrawBitmapBilinearOptimized { +struct ColorTypeRgb { + static void + Interpolate(uint32* t, const uint8* s, uint32 sourceBytesPerRow, + uint16 wLeft, uint16 wTop, uint16 wRight, uint16 wBottom) + { + // left and right of top row + t[0] = (s[0] * wLeft + s[4] * wRight) * wTop; + t[1] = (s[1] * wLeft + s[5] * wRight) * wTop; + t[2] = (s[2] * wLeft + s[6] * wRight) * wTop; + + // left and right of bottom row + s += sourceBytesPerRow; + t[0] += (s[0] * wLeft + s[4] * wRight) * wBottom; + t[1] += (s[1] * wLeft + s[5] * wRight) * wBottom; + t[2] += (s[2] * wLeft + s[6] * wRight) * wBottom; + + t[0] >>= 16; + t[1] >>= 16; + t[2] >>= 16; + } + + static void + InterpolateLastColumn(uint32* t, const uint8* s, const uint8* sBottom, + uint16 wTop, uint16 wBottom) + { + t[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; + t[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; + t[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; + } + + static void + InterpolateLastRow(uint32* t, const uint8* s, uint16 wLeft, + uint16 wRight) + { + t[0] = (s[0] * wLeft + s[4] * wRight) >> 8; + t[1] = (s[1] * wLeft + s[5] * wRight) >> 8; + t[2] = (s[2] * wLeft + s[6] * wRight) >> 8; + } +}; + + +struct ColorTypeRgba { + static void + Interpolate(uint32* t, const uint8* s, uint32 sourceBytesPerRow, + uint16 wLeft, uint16 wTop, uint16 wRight, uint16 wBottom) + { + // left and right of top row + t[0] = (s[0] * wLeft + s[4] * wRight) * wTop; + t[1] = (s[1] * wLeft + s[5] * wRight) * wTop; + t[2] = (s[2] * wLeft + s[6] * wRight) * wTop; + t[3] = (s[3] * wLeft + s[7] * wRight) * wTop; + + // left and right of bottom row + s += sourceBytesPerRow; + + t[0] += (s[0] * wLeft + s[4] * wRight) * wBottom; + t[1] += (s[1] * wLeft + s[5] * wRight) * wBottom; + t[2] += (s[2] * wLeft + s[6] * wRight) * wBottom; + t[3] += (s[3] * wLeft + s[7] * wRight) * wBottom; + + t[0] >>= 16; + t[1] >>= 16; + t[2] >>= 16; + t[3] >>= 16; + } + + static void + InterpolateLastColumn(uint32* t, const uint8* s, const uint8* sBottom, + uint16 wTop, uint16 wBottom) + { + t[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; + t[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; + t[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; + t[3] = (s[3] * wTop + sBottom[3] * wBottom) >> 8; + } + + static void + InterpolateLastRow(uint32* t, const uint8* s, uint16 wLeft, + uint16 wRight) + { + t[0] = (s[0] * wLeft + s[4] * wRight) >> 8; + t[1] = (s[1] * wLeft + s[5] * wRight) >> 8; + t[2] = (s[2] * wLeft + s[6] * wRight) >> 8; + t[3] = (s[3] * wLeft + s[7] * wRight) >> 8; + } +}; + + +struct DrawModeCopy { + static void + Blend(uint8*& d, uint32* t) + { + d[0] = t[0]; + d[1] = t[1]; + d[2] = t[2]; + d += 4; + } +}; + + +struct DrawModeAlphaOverlay { + static void + Blend(uint8*& d, uint32* t) + { + uint8 t0 = t[0]; + uint8 t1 = t[1]; + uint8 t2 = t[2]; + uint8 t3 = t[3]; + + if (t3 == 255) { + d[0] = t0; + d[1] = t1; + d[2] = t2; + } else { + d[0] = ((t0 - d[0]) * t3 + (d[0] << 8)) >> 8; + d[1] = ((t1 - d[1]) * t3 + (d[1] << 8)) >> 8; + d[2] = ((t2 - d[2]) * t3 + (d[2] << 8)) >> 8; + } + + d += 4; + } +}; + + +template +struct BilinearDefault : + DrawBitmapBilinearOptimized > { + void DrawToClipRect(int32 xIndexL, int32 xIndexR, int32 y1, int32 y2) { // In this mode we anticipate many pixels wich need filtering, @@ -122,38 +251,33 @@ struct BilinearDefault : DrawBitmapBilinearOptimized { // buffer offset into source (top row) register const uint8* src = fSource->row_ptr(fWeightsY[y1].index); + // buffer handle for destination to be incremented per // pixel register uint8* d = fDestination; for (int32 x = xIndexL; x <= xIndexMax; x++) { const uint8* s = src + fWeightsX[x].index; + // calculate the weighted sum of all four // interpolated pixels const uint16 wLeft = fWeightsX[x].weight; const uint16 wRight = 255 - wLeft; - // left and right of top row - uint32 t0 = (s[0] * wLeft + s[4] * wRight) * wTop; - uint32 t1 = (s[1] * wLeft + s[5] * wRight) * wTop; - uint32 t2 = (s[2] * wLeft + s[6] * wRight) * wTop; - // left and right of bottom row - s += fSourceBytesPerRow; - t0 += (s[0] * wLeft + s[4] * wRight) * wBottom; - t1 += (s[1] * wLeft + s[5] * wRight) * wBottom; - t2 += (s[2] * wLeft + s[6] * wRight) * wBottom; - d[0] = t0 >> 16; - d[1] = t1 >> 16; - d[2] = t2 >> 16; - d += 4; + uint32 t[4]; + ColorType::Interpolate(&t[0], s, fSourceBytesPerRow, + wLeft, wTop, wRight, wBottom); + DrawMode::Blend(d, &t[0]); } // last column of pixels if necessary if (xIndexMax < xIndexR) { const uint8* s = src + fWeightsX[xIndexR].index; const uint8* sBottom = s + fSourceBytesPerRow; - d[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; - d[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; - d[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; + + uint32 t[4]; + ColorType::InterpolateLastColumn(&t[0], s, sBottom, wTop, + wBottom); + DrawMode::Blend(d, &t[0]); } fDestination += fDestinationBytesPerRow; @@ -171,10 +295,9 @@ struct BilinearDefault : DrawBitmapBilinearOptimized { const uint8* s = src + fWeightsX[x].index; const uint16 wLeft = fWeightsX[x].weight; const uint16 wRight = 255 - wLeft; - d[0] = (s[0] * wLeft + s[4] * wRight) >> 8; - d[1] = (s[1] * wLeft + s[5] * wRight) >> 8; - d[2] = (s[2] * wLeft + s[6] * wRight) >> 8; - d += 4; + uint32 t[4]; + ColorType::InterpolateLastRow(&t[0], s, wLeft, wRight); + DrawMode::Blend(d, &t[0]); } } @@ -349,7 +472,8 @@ struct BilinearSimd : DrawBitmapBilinearOptimized { #endif // __INTEL__ -struct DrawBitmapBilinearCopy { +template +struct DrawBitmapBilinear { void Draw(const Painter* painter, PainterAggInterface& aggInterface, agg::rendering_buffer& bitmap, BPoint offset, @@ -466,20 +590,23 @@ struct DrawBitmapBilinearCopy { int codeSelect = kUseDefaultVersion; - uint32 neededSIMDFlags = APPSERVER_SIMD_MMX | APPSERVER_SIMD_SSE; - if ((gSIMDFlags & neededSIMDFlags) == neededSIMDFlags) - codeSelect = kUseSIMDVersion; - else { - if (scaleX == scaleY && (scaleX == 1.5 || scaleX == 2.0 - || scaleX == 2.5 || scaleX == 3.0)) { - codeSelect = kOptimizeForLowFilterRatio; + if (typeid(ColorType) == typeid(ColorTypeRgb) + && typeid(DrawMode) == typeid(DrawModeCopy)) { + uint32 neededSIMDFlags = APPSERVER_SIMD_MMX | APPSERVER_SIMD_SSE; + if ((gSIMDFlags & neededSIMDFlags) == neededSIMDFlags) + codeSelect = kUseSIMDVersion; + else { + if (scaleX == scaleY && (scaleX == 1.5 || scaleX == 2.0 + || scaleX == 2.5 || scaleX == 3.0)) { + codeSelect = kOptimizeForLowFilterRatio; + } } } switch (codeSelect) { case kUseDefaultVersion: { - BilinearDefault bilinearPainter; + BilinearDefault bilinearPainter; bilinearPainter.Draw(aggInterface, destinationRect, &bitmap, filterData); break;