LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkRasterPipelineBlitter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 93 169 55.0 %
Date: 2017-07-14 16:53:18 Functions: 11 13 84.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkArenaAlloc.h"
       9             : #include "SkBlitter.h"
      10             : #include "SkBlendModePriv.h"
      11             : #include "SkColor.h"
      12             : #include "SkColorFilter.h"
      13             : #include "SkOpts.h"
      14             : #include "SkPM4f.h"
      15             : #include "SkPM4fPriv.h"
      16             : #include "SkRasterPipeline.h"
      17             : #include "SkShader.h"
      18             : #include "SkUtils.h"
      19             : 
      20             : 
      21         312 : class SkRasterPipelineBlitter : public SkBlitter {
      22             : public:
      23             :     static SkBlitter* Create(const SkPixmap&, const SkPaint&, const SkMatrix& ctm,
      24             :                              SkArenaAlloc*);
      25             : 
      26         312 :     SkRasterPipelineBlitter(SkPixmap dst, SkBlendMode blend, SkPM4f paintColor)
      27         312 :         : fDst(dst)
      28             :         , fBlend(blend)
      29         312 :         , fPaintColor(paintColor)
      30         312 :     {}
      31             : 
      32             :     void blitH    (int x, int y, int w)                            override;
      33             :     void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override;
      34             :     void blitMask (const SkMask&, const SkIRect& clip)             override;
      35             : 
      36             :     // TODO: The default implementations of the other blits look fine,
      37             :     // but some of them like blitV could probably benefit from custom
      38             :     // blits using something like a SkRasterPipeline::runFew() method.
      39             : 
      40             : private:
      41             :     void append_load_d(SkRasterPipeline*) const;
      42             :     void append_blend (SkRasterPipeline*) const;
      43             :     void maybe_clamp  (SkRasterPipeline*) const;
      44             :     void append_store (SkRasterPipeline*) const;
      45             : 
      46             :     SkPixmap         fDst;
      47             :     SkBlendMode      fBlend;
      48             :     SkPM4f           fPaintColor;
      49             :     SkRasterPipeline fShader;
      50             : 
      51             :     // We may be able to specialize blitH() into a memset.
      52             :     bool     fCanMemsetInBlitH = false;
      53             :     uint64_t fMemsetColor      = 0;     // Big enough for largest dst format, F16.
      54             : 
      55             :     // Built lazily on first use.
      56             :     SkRasterPipeline fBlitH,
      57             :                      fBlitAntiH,
      58             :                      fBlitMaskA8,
      59             :                      fBlitMaskLCD16;
      60             : 
      61             :     // These values are pointed to by the blit pipelines above,
      62             :     // which allows us to adjust them from call to call.
      63             :     void*       fDstPtr          = nullptr;
      64             :     const void* fMaskPtr         = nullptr;
      65             :     float       fCurrentCoverage = 0.0f;
      66             :     int         fCurrentY        = 0;
      67             : 
      68             :     typedef SkBlitter INHERITED;
      69             : };
      70             : 
      71         312 : SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
      72             :                                          const SkPaint& paint,
      73             :                                          const SkMatrix& ctm,
      74             :                                          SkArenaAlloc* alloc) {
      75         312 :     return SkRasterPipelineBlitter::Create(dst, paint, ctm, alloc);
      76             : }
      77             : 
      78         316 : static bool supported(const SkImageInfo& info) {
      79         316 :     switch (info.colorType()) {
      80           8 :         case kAlpha_8_SkColorType:  return true;
      81           0 :         case kRGB_565_SkColorType:  return true;
      82         308 :         case kN32_SkColorType:      return info.gammaCloseToSRGB();
      83           0 :         case kRGBA_F16_SkColorType: return true;
      84           0 :         default:                    return false;
      85             :     }
      86             : }
      87             : 
      88         312 : SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
      89             :                                            const SkPaint& paint,
      90             :                                            const SkMatrix& ctm,
      91             :                                            SkArenaAlloc* alloc) {
      92             :     auto blitter = alloc->make<SkRasterPipelineBlitter>(
      93             :             dst,
      94         624 :             paint.getBlendMode(),
      95         936 :             SkPM4f_from_SkColor(paint.getColor(), dst.colorSpace()));
      96             : 
      97             : 
      98         312 :     SkBlendMode*      blend       = &blitter->fBlend;
      99         312 :     SkPM4f*           paintColor  = &blitter->fPaintColor;
     100         312 :     SkRasterPipeline* pipeline    = &blitter->fShader;
     101             : 
     102         312 :     SkShader*      shader      = paint.getShader();
     103         312 :     SkColorFilter* colorFilter = paint.getColorFilter();
     104             : 
     105             :     // TODO: all temporary
     106         312 :     if (!supported(dst.info()) || !SkBlendMode_AppendStages(*blend)) {
     107         308 :         return nullptr;
     108             :     }
     109             : 
     110           4 :     bool is_opaque   = paintColor->a() == 1.0f,
     111           4 :          is_constant = true;
     112           4 :     if (shader) {
     113           2 :         pipeline->append(SkRasterPipeline::seed_shader, &blitter->fCurrentY);
     114           2 :         if (!shader->appendStages(pipeline, dst.colorSpace(), alloc, ctm, paint)) {
     115           2 :             return nullptr;
     116             :         }
     117           0 :         if (!is_opaque) {
     118             :             pipeline->append(SkRasterPipeline::scale_1_float,
     119           0 :                              &paintColor->fVec[SkPM4f::A]);
     120             :         }
     121             : 
     122           0 :         is_opaque   = is_opaque && shader->isOpaque();
     123           0 :         is_constant = shader->isConstant();
     124             :     } else {
     125           2 :         pipeline->append(SkRasterPipeline::constant_color, paintColor);
     126             :     }
     127             : 
     128           2 :     if (colorFilter) {
     129           0 :         if (!colorFilter->appendStages(pipeline, dst.colorSpace(), alloc, is_opaque)) {
     130           0 :             return nullptr;
     131             :         }
     132           0 :         is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
     133             :     }
     134             : 
     135           2 :     if (is_constant) {
     136           2 :         pipeline->append(SkRasterPipeline::store_f32, &paintColor);
     137           2 :         pipeline->run(0,1);
     138             : 
     139           2 :         *pipeline = SkRasterPipeline();
     140           2 :         pipeline->append(SkRasterPipeline::constant_color, paintColor);
     141             : 
     142           2 :         is_opaque = paintColor->a() == 1.0f;
     143             :     }
     144             : 
     145           2 :     if (is_opaque && *blend == SkBlendMode::kSrcOver) {
     146           2 :         *blend = SkBlendMode::kSrc;
     147             :     }
     148             : 
     149           2 :     if (is_constant && *blend == SkBlendMode::kSrc) {
     150           4 :         SkRasterPipeline p;
     151           2 :         p.extend(*pipeline);
     152           2 :         blitter->fDstPtr = &blitter->fMemsetColor;
     153           2 :         blitter->append_store(&p);
     154           2 :         p.run(0,1);
     155             : 
     156           2 :         blitter->fCanMemsetInBlitH = true;
     157             :     }
     158             : 
     159           2 :     return blitter;
     160             : }
     161             : 
     162           1 : void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p) const {
     163           1 :     SkASSERT(supported(fDst.info()));
     164             : 
     165           1 :     p->append(SkRasterPipeline::move_src_dst);
     166           1 :     switch (fDst.info().colorType()) {
     167           1 :         case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::load_a8,   &fDstPtr); break;
     168           0 :         case kRGB_565_SkColorType:   p->append(SkRasterPipeline::load_565,  &fDstPtr); break;
     169             :         case kBGRA_8888_SkColorType:
     170           0 :         case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::load_8888, &fDstPtr); break;
     171           0 :         case kRGBA_F16_SkColorType:  p->append(SkRasterPipeline::load_f16,  &fDstPtr); break;
     172           0 :         default: break;
     173             :     }
     174           1 :     if (fDst.info().colorType() == kBGRA_8888_SkColorType) {
     175           0 :         p->append(SkRasterPipeline::swap_rb);
     176             :     }
     177           1 :     if (fDst.info().gammaCloseToSRGB()) {
     178           0 :         p->append_from_srgb(fDst.info().alphaType());
     179             :     }
     180           1 :     p->append(SkRasterPipeline::swap);
     181           1 : }
     182             : 
     183           3 : void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p) const {
     184           3 :     if (fDst.info().gammaCloseToSRGB()) {
     185           0 :         p->append(SkRasterPipeline::to_srgb);
     186             :     }
     187           3 :     if (fDst.info().colorType() == kBGRA_8888_SkColorType) {
     188           0 :         p->append(SkRasterPipeline::swap_rb);
     189             :     }
     190             : 
     191           3 :     SkASSERT(supported(fDst.info()));
     192           3 :     switch (fDst.info().colorType()) {
     193           3 :         case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::store_a8,   &fDstPtr); break;
     194           0 :         case kRGB_565_SkColorType:   p->append(SkRasterPipeline::store_565,  &fDstPtr); break;
     195             :         case kBGRA_8888_SkColorType:
     196           0 :         case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::store_8888, &fDstPtr); break;
     197           0 :         case kRGBA_F16_SkColorType:  p->append(SkRasterPipeline::store_f16,  &fDstPtr); break;
     198           0 :         default: break;
     199             :     }
     200           3 : }
     201             : 
     202           1 : void SkRasterPipelineBlitter::append_blend(SkRasterPipeline* p) const {
     203           1 :     SkAssertResult(SkBlendMode_AppendStages(fBlend, p));
     204           1 : }
     205             : 
     206           1 : void SkRasterPipelineBlitter::maybe_clamp(SkRasterPipeline* p) const {
     207           1 :     if (SkBlendMode_CanOverflow(fBlend)) {
     208           0 :         p->append(SkRasterPipeline::clamp_a);
     209             :     }
     210           1 : }
     211             : 
     212          29 : void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
     213          29 :     fDstPtr = fDst.writable_addr(0,y);
     214          29 :     fCurrentY = y;
     215             : 
     216          29 :     if (fCanMemsetInBlitH) {
     217          29 :         switch (fDst.shiftPerPixel()) {
     218          29 :             case 0:    memset  ((uint8_t *)fDstPtr + x, fMemsetColor, w); return;
     219           0 :             case 1: sk_memset16((uint16_t*)fDstPtr + x, fMemsetColor, w); return;
     220           0 :             case 2: sk_memset32((uint32_t*)fDstPtr + x, fMemsetColor, w); return;
     221           0 :             case 3: sk_memset64((uint64_t*)fDstPtr + x, fMemsetColor, w); return;
     222           0 :             default: break;
     223             :         }
     224             :     }
     225             : 
     226           0 :     auto& p = fBlitH;
     227           0 :     if (p.empty()) {
     228           0 :         p.extend(fShader);
     229           0 :         if (fBlend != SkBlendMode::kSrc) {
     230           0 :             this->append_load_d(&p);
     231           0 :             this->append_blend(&p);
     232           0 :             this->maybe_clamp(&p);
     233             :         }
     234           0 :         this->append_store(&p);
     235             :     }
     236           0 :     p.run(x,w);
     237             : }
     238             : 
     239           0 : void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
     240           0 :     auto& p = fBlitAntiH;
     241           0 :     if (p.empty()) {
     242           0 :         p.extend(fShader);
     243           0 :         if (fBlend == SkBlendMode::kSrcOver) {
     244           0 :             p.append(SkRasterPipeline::scale_1_float, &fCurrentCoverage);
     245           0 :             this->append_load_d(&p);
     246           0 :             this->append_blend(&p);
     247             :         } else {
     248           0 :             this->append_load_d(&p);
     249           0 :             this->append_blend(&p);
     250           0 :             p.append(SkRasterPipeline::lerp_1_float, &fCurrentCoverage);
     251             :         }
     252           0 :         this->maybe_clamp(&p);
     253           0 :         this->append_store(&p);
     254             :     }
     255             : 
     256           0 :     fDstPtr = fDst.writable_addr(0,y);
     257           0 :     fCurrentY = y;
     258           0 :     for (int16_t run = *runs; run > 0; run = *runs) {
     259           0 :         switch (*aa) {
     260           0 :             case 0x00:                       break;
     261           0 :             case 0xff: this->blitH(x,y,run); break;
     262             :             default:
     263           0 :                 fCurrentCoverage = *aa * (1/255.0f);
     264           0 :                 p.run(x,run);
     265             :         }
     266           0 :         x    += run;
     267           0 :         runs += run;
     268           0 :         aa   += run;
     269             :     }
     270           0 : }
     271             : 
     272           1 : void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
     273           1 :     if (mask.fFormat == SkMask::kBW_Format) {
     274             :         // TODO: native BW masks?
     275           0 :         return INHERITED::blitMask(mask, clip);
     276             :     }
     277             : 
     278           1 :     if (mask.fFormat == SkMask::kA8_Format && fBlitMaskA8.empty()) {
     279           1 :         auto& p = fBlitMaskA8;
     280           1 :         p.extend(fShader);
     281           1 :         if (fBlend == SkBlendMode::kSrcOver) {
     282           0 :             p.append(SkRasterPipeline::scale_u8, &fMaskPtr);
     283           0 :             this->append_load_d(&p);
     284           0 :             this->append_blend(&p);
     285             :         } else {
     286           1 :             this->append_load_d(&p);
     287           1 :             this->append_blend(&p);
     288           1 :             p.append(SkRasterPipeline::lerp_u8, &fMaskPtr);
     289             :         }
     290           1 :         this->maybe_clamp(&p);
     291           1 :         this->append_store(&p);
     292             :     }
     293             : 
     294           1 :     if (mask.fFormat == SkMask::kLCD16_Format && fBlitMaskLCD16.empty()) {
     295           0 :         auto& p = fBlitMaskLCD16;
     296           0 :         p.extend(fShader);
     297           0 :         this->append_load_d(&p);
     298           0 :         this->append_blend(&p);
     299           0 :         p.append(SkRasterPipeline::lerp_565, &fMaskPtr);
     300           0 :         this->maybe_clamp(&p);
     301           0 :         this->append_store(&p);
     302             :     }
     303             : 
     304           1 :     int x = clip.left();
     305          28 :     for (int y = clip.top(); y < clip.bottom(); y++) {
     306          27 :         fDstPtr = fDst.writable_addr(0,y);
     307          27 :         fCurrentY = y;
     308             : 
     309          27 :         switch (mask.fFormat) {
     310             :             case SkMask::kA8_Format:
     311          27 :                 fMaskPtr = mask.getAddr8(x,y)-x;
     312          27 :                 fBlitMaskA8.run(x,clip.width());
     313          27 :                 break;
     314             :             case SkMask::kLCD16_Format:
     315           0 :                 fMaskPtr = mask.getAddrLCD16(x,y)-x;
     316           0 :                 fBlitMaskLCD16.run(x,clip.width());
     317           0 :                 break;
     318             :             default:
     319             :                 // TODO
     320           0 :                 break;
     321             :         }
     322             :     }
     323             : }

Generated by: LCOV version 1.13