Srcover for sprite blitters.
authorherb <herb@google.com>
Thu, 26 May 2016 17:56:17 +0000 (10:56 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 26 May 2016 17:56:18 +0000 (10:56 -0700)
In order for this code to run, the gDefaultProfileIsSRGB flag needs to be true.

min base     min exp    percent   name
5601856   4689911   0.837207  top25desk_espn.skp_1
3491515   3202806   0.917311  top25desk_facebook.skp_1
5110247   4865740   0.952154  top25desk_weather_com.skp_1
605445    585520    0.96709   top25desk_techcrunch_com.skp_1
1007151   986193    0.979191  top25desk_wikipedia__1_tab_.skp_1
5951286   5889979   0.989699  top25desk_sports_yahoo_com_.skp_1
2825583   2804853   0.992663  top25desk_plus_google_com_11003.skp_1
8839265   8823249   0.998188  top25desk_twitter.skp_1
4169125   4168882   0.999942  top25desk_docs___1_open_documen.skp_1
6615327   6620663   1.00081   top25desk_youtube_com.skp_1
4613903   4647583   1.0073    top25desk_wordpress.skp_1
2532280   2554154   1.00864   top25desk_ebay_com.skp_1
4015689   4063584   1.01193   top25desk_google_com__hl_en_q_b.skp_1
9427478   9579203   1.01609   top25desk_answers_yahoo_com.skp_1
7403901   7542770   1.01876   top25desk_booking_com.skp_1
12249953  12528353  1.02273   top25desk_google_com_search_q_c.skp_1
1078648   1111050   1.03004   top25desk_games_yahoo_com.skp_1
7232627   7481555   1.03442   top25desk_pinterest.skp_1
2996819   3112091   1.03846   top25desk_google_com_calendar_.skp_1
2181531   2271677   1.04132   top25desk_amazon_com.skp_1
925245    987545    1.06733   top25desk_blogger.skp_1
4143359   4442607   1.07222   top25desk_linkedin.skp_1
4370962   4744580   1.08548   top25desk_news_yahoo_com.skp_1
4284025   4735094   1.10529   top25desk_mail_google_com_mail_.skp_1

[mtklein] We measured the noise here to be [-5%, +8%], so most of these changes fall within the noise.  We manually confirmed the two above that noise window (yahoo and mail) are also noise... srcover_srgb_srgb() did not figure prominently in their profiles.  The espn and facebook improvements look real.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1996683003

Review-Url: https://codereview.chromium.org/1996683003

src/core/SkBlitter_Sprite.cpp

index c0b7430..2ddc5f4 100644 (file)
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "SkOpts.h"
 #include "SkSmallAllocator.h"
 #include "SkSpriteBlitter.h"
 
@@ -43,7 +44,7 @@ void SkSpriteBlitter::blitMask(const SkMask&, const SkIRect& clip) {
 //      2. paint has no modifiers (i.e. alpha, colorfilter, etc.)
 //      3. xfermode needs no blending: e.g. kSrc_Mode or kSrcOver_Mode + opaque src
 //
-class SkSpriteBlitter_memcpy : public SkSpriteBlitter {
+class SkSpriteBlitter_Src_SrcOver : public SkSpriteBlitter {
 public:
     static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) {
         if (dst.colorType() != src.colorType()) {
@@ -68,14 +69,32 @@ public:
         if (SkXfermode::kSrcOver_Mode == mode && src.isOpaque()) {
             return true;
         }
-        return false;
+
+        // At this point memcpy can't be used. The following check for using SrcOver.
+
+        if (dst.colorType() != kN32_SkColorType
+            || dst.info().profileType() != kSRGB_SkColorProfileType) {
+            return false;
+        }
+
+        return SkXfermode::kSrcOver_Mode == mode;
     }
 
-    SkSpriteBlitter_memcpy(const SkPixmap& src)  : INHERITED(src) {}
+    SkSpriteBlitter_Src_SrcOver(const SkPixmap& src)  : INHERITED(src) {}
 
     void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
         SkASSERT(Supports(dst, fSource, paint));
         this->INHERITED::setup(dst, left, top, paint);
+        SkXfermode::Mode mode;
+        if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
+            SkFAIL("Should never happen.");
+        }
+
+        SkASSERT(mode == SkXfermode::kSrcOver_Mode || mode == SkXfermode::kSrc_Mode);
+
+        if (mode == SkXfermode::kSrcOver_Mode && !fSource.isOpaque()) {
+            fUseMemcpy = false;
+        }
     }
 
     void blitRect(int x, int y, int width, int height) override {
@@ -83,22 +102,37 @@ public:
         SkASSERT(fDst.info().profileType() == fSource.info().profileType());
         SkASSERT(width > 0 && height > 0);
 
-        char* dst = (char*)fDst.writable_addr(x, y);
-        const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
-        const size_t dstRB = fDst.rowBytes();
-        const size_t srcRB = fSource.rowBytes();
-        const size_t bytesToCopy = width << fSource.shiftPerPixel();
-
-        while (--height >= 0) {
-            memcpy(dst, src, bytesToCopy);
-            dst += dstRB;
-            src += srcRB;
+        if (fUseMemcpy) {
+            char* dst = (char*)fDst.writable_addr(x, y);
+            const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
+            const size_t dstRB = fDst.rowBytes();
+            const size_t srcRB = fSource.rowBytes();
+            const size_t bytesToCopy = width << fSource.shiftPerPixel();
+
+            while (height --> 0) {
+                memcpy(dst, src, bytesToCopy);
+                dst += dstRB;
+                src += srcRB;
+            }
+        } else {
+            uint32_t* dst       = fDst.writable_addr32(x, y);
+            const uint32_t* src = fSource.addr32(x - fLeft, y - fTop);
+            const int dstStride = fDst.rowBytesAsPixels();
+            const int srcStride = fSource.rowBytesAsPixels();
+
+            while (height --> 0) {
+                SkOpts::srcover_srgb_srgb(dst, src, width, width);
+                dst += dstStride;
+                src += srcStride;
+            }
         }
     }
 
+private:
     typedef SkSpriteBlitter INHERITED;
-};
 
+    bool fUseMemcpy {true};
+};
 
 // returning null means the caller will call SkBlitter::Choose() and
 // have wrapped the source bitmap inside a shader
@@ -115,10 +149,10 @@ SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
     */
     SkASSERT(allocator != nullptr);
 
-    SkSpriteBlitter* blitter;
+    SkSpriteBlitter* blitter = nullptr;
 
-    if (SkSpriteBlitter_memcpy::Supports(dst, source, paint)) {
-        blitter = allocator->createT<SkSpriteBlitter_memcpy>(source);
+    if (SkSpriteBlitter_Src_SrcOver::Supports(dst, source, paint)) {
+        blitter = allocator->createT<SkSpriteBlitter_Src_SrcOver>(source);
     } else {
         switch (dst.colorType()) {
             case kRGB_565_SkColorType:
@@ -135,7 +169,6 @@ SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
                 blitter = SkSpriteBlitter::ChooseF16(source, paint, allocator);
                 break;
             default:
-                blitter = nullptr;
                 break;
         }
     }