Home | History | Annotate | Download | only in core
      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 "SkColorSpaceXformer.h"
     14 #include "SkOpts.h"
     15 #include "SkPM4f.h"
     16 #include "SkPM4fPriv.h"
     17 #include "SkRasterPipeline.h"
     18 #include "SkShader.h"
     19 #include "SkShaderBase.h"
     20 #include "SkUtils.h"
     21 #include "../jumper/SkJumper.h"
     22 
     23 class SkRasterPipelineBlitter final : public SkBlitter {
     24 public:
     25     // This is our common entrypoint for creating the blitter once we've sorted out shaders.
     26     static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkArenaAlloc*,
     27                              const SkRasterPipeline& shaderPipeline,
     28                              SkShaderBase::Context*,
     29                              bool is_opaque, bool is_constant);
     30 
     31     SkRasterPipelineBlitter(SkPixmap dst,
     32                             SkBlendMode blend,
     33                             SkArenaAlloc* alloc,
     34                             SkShaderBase::Context* burstCtx)
     35         : fDst(dst)
     36         , fBlend(blend)
     37         , fAlloc(alloc)
     38         , fBurstCtx(burstCtx)
     39         , fColorPipeline(alloc)
     40     {}
     41 
     42     void blitH     (int x, int y, int w)                            override;
     43     void blitAntiH (int x, int y, const SkAlpha[], const int16_t[]) override;
     44     void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1)               override;
     45     void blitAntiV2(int x, int y, U8CPU a0, U8CPU a1)               override;
     46     void blitMask  (const SkMask&, const SkIRect& clip)             override;
     47     void blitRect  (int x, int y, int width, int height)            override;
     48     void blitV     (int x, int y, int height, SkAlpha alpha)        override;
     49 
     50 private:
     51     void append_load_dst(SkRasterPipeline*) const;
     52     void append_store   (SkRasterPipeline*) const;
     53 
     54     // If we have an burst context, use it to fill our shader buffer.
     55     void burst_shade(int x, int y, int w);
     56 
     57     SkPixmap               fDst;
     58     SkBlendMode            fBlend;
     59     SkArenaAlloc*          fAlloc;
     60     SkShaderBase::Context* fBurstCtx;
     61     SkRasterPipeline       fColorPipeline;
     62 
     63     SkJumper_MemoryCtx fShaderOutput = {nullptr,0},  // Possibly updated each call to burst_shade().
     64                        fDstPtr       = {nullptr,0},  // Always points to the top-left of fDst.
     65                        fMaskPtr      = {nullptr,0};  // Updated each call to blitMask().
     66 
     67     // We may be able to specialize blitH() or blitRect() into a memset.
     68     bool     fCanMemsetInBlitRect = false;
     69     uint64_t fMemsetColor      = 0;     // Big enough for largest dst format, F16.
     70 
     71     // Built lazily on first use.
     72     std::function<void(size_t, size_t, size_t, size_t)> fBlitRect,
     73                                                         fBlitAntiH,
     74                                                         fBlitMaskA8,
     75                                                         fBlitMaskLCD16;
     76 
     77     // These values are pointed to by the blit pipelines above,
     78     // which allows us to adjust them from call to call.
     79     float fCurrentCoverage = 0.0f;
     80     float fDitherRate      = 0.0f;
     81 
     82     std::vector<SkPM4f> fShaderBuffer;
     83 
     84     typedef SkBlitter INHERITED;
     85 };
     86 
     87 SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
     88                                          const SkPaint& paint,
     89                                          const SkMatrix& ctm,
     90                                          SkArenaAlloc* alloc) {
     91     SkColorSpace* dstCS = dst.colorSpace();
     92     SkPM4f paintColor = SkPM4f_from_SkColor(paint.getColor(), dstCS);
     93     auto shader = as_SB(paint.getShader());
     94 
     95     SkRasterPipeline_<256> shaderPipeline;
     96     if (!shader) {
     97         // Having no shader makes things nice and easy... just use the paint color.
     98         shaderPipeline.append_constant_color(alloc, paintColor);
     99         bool is_opaque    = paintColor.a() == 1.0f,
    100              is_constant  = true;
    101         return SkRasterPipelineBlitter::Create(dst, paint, alloc,
    102                                                shaderPipeline, nullptr,
    103                                                is_opaque, is_constant);
    104     }
    105 
    106     bool is_opaque    = shader->isOpaque() && paintColor.a() == 1.0f;
    107     bool is_constant  = shader->isConstant();
    108 
    109     // Check whether the shader prefers to run in burst mode.
    110     if (auto* burstCtx = shader->makeBurstPipelineContext(
    111         SkShaderBase::ContextRec(paint, ctm, nullptr, SkShaderBase::ContextRec::kPM4f_DstType,
    112                                  dstCS), alloc)) {
    113         return SkRasterPipelineBlitter::Create(dst, paint, alloc,
    114                                                shaderPipeline, burstCtx,
    115                                                is_opaque, is_constant);
    116     }
    117 
    118     if (shader->appendStages({&shaderPipeline, alloc, dstCS, paint, nullptr, ctm})) {
    119         if (paintColor.a() != 1.0f) {
    120             shaderPipeline.append(SkRasterPipeline::scale_1_float,
    121                                   alloc->make<float>(paintColor.a()));
    122         }
    123         return SkRasterPipelineBlitter::Create(dst, paint, alloc, shaderPipeline, nullptr,
    124                                                is_opaque, is_constant);
    125     }
    126 
    127     // The shader has opted out of drawing anything.
    128     return alloc->make<SkNullBlitter>();
    129 }
    130 
    131 SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
    132                                          const SkPaint& paint,
    133                                          const SkRasterPipeline& shaderPipeline,
    134                                          bool is_opaque,
    135                                          SkArenaAlloc* alloc) {
    136     bool is_constant = false;  // If this were the case, it'd be better to just set a paint color.
    137     return SkRasterPipelineBlitter::Create(dst, paint, alloc, shaderPipeline, nullptr,
    138                                            is_opaque, is_constant);
    139 }
    140 
    141 SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
    142                                            const SkPaint& paint,
    143                                            SkArenaAlloc* alloc,
    144                                            const SkRasterPipeline& shaderPipeline,
    145                                            SkShaderBase::Context* burstCtx,
    146                                            bool is_opaque,
    147                                            bool is_constant) {
    148     auto blitter = alloc->make<SkRasterPipelineBlitter>(dst,
    149                                                         paint.getBlendMode(),
    150                                                         alloc,
    151                                                         burstCtx);
    152 
    153     // Our job in this factory is to fill out the blitter's color pipeline.
    154     // This is the common front of the full blit pipelines, each constructed lazily on first use.
    155     // The full blit pipelines handle reading and writing the dst, blending, coverage, dithering.
    156     auto colorPipeline = &blitter->fColorPipeline;
    157 
    158     // Let's get the shader in first.
    159     if (burstCtx) {
    160         colorPipeline->append(SkRasterPipeline::load_f32, &blitter->fShaderOutput);
    161     } else {
    162         colorPipeline->extend(shaderPipeline);
    163     }
    164 
    165     // If there's a color filter it comes next.
    166     if (auto colorFilter = paint.getColorFilter()) {
    167         colorFilter->appendStages(colorPipeline, dst.colorSpace(), alloc, is_opaque);
    168         is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
    169     }
    170 
    171     // Not all formats make sense to dither (think, F16).  We set their dither rate
    172     // to zero.  We need to decide if we're going to dither now to keep is_constant accurate.
    173     if (paint.isDither()) {
    174         switch (dst.info().colorType()) {
    175             default:                        blitter->fDitherRate =      0.0f; break;
    176             case kARGB_4444_SkColorType:    blitter->fDitherRate =   1/15.0f; break;
    177             case   kRGB_565_SkColorType:    blitter->fDitherRate =   1/63.0f; break;
    178             case    kGray_8_SkColorType:
    179             case  kRGB_888x_SkColorType:
    180             case kRGBA_8888_SkColorType:
    181             case kBGRA_8888_SkColorType:    blitter->fDitherRate =  1/255.0f; break;
    182             case kRGB_101010x_SkColorType:
    183             case kRGBA_1010102_SkColorType: blitter->fDitherRate = 1/1023.0f; break;
    184         }
    185         // TODO: for constant colors, we could try to measure the effect of dithering, and if
    186         //       it has no value (i.e. all variations result in the same 32bit color, then we
    187         //       could disable it (for speed, by not adding the stage).
    188     }
    189     is_constant = is_constant && (blitter->fDitherRate == 0.0f);
    190 
    191     // We're logically done here.  The code between here and return blitter is all optimization.
    192 
    193     // A pipeline that's still constant here can collapse back into a constant color.
    194     if (is_constant) {
    195         SkPM4f constantColor;
    196         SkJumper_MemoryCtx constantColorPtr = { &constantColor, 0 };
    197         colorPipeline->append(SkRasterPipeline::store_f32, &constantColorPtr);
    198         colorPipeline->run(0,0,1,1);
    199         colorPipeline->reset();
    200         colorPipeline->append_constant_color(alloc, constantColor);
    201 
    202         is_opaque = constantColor.a() == 1.0f;
    203     }
    204 
    205     // We can strength-reduce SrcOver into Src when opaque.
    206     if (is_opaque && blitter->fBlend == SkBlendMode::kSrcOver) {
    207         blitter->fBlend = SkBlendMode::kSrc;
    208     }
    209 
    210     // When we're drawing a constant color in Src mode, we can sometimes just memset.
    211     // (The previous two optimizations help find more opportunities for this one.)
    212     if (is_constant && blitter->fBlend == SkBlendMode::kSrc) {
    213         // Run our color pipeline all the way through to produce what we'd memset when we can.
    214         // Not all blits can memset, so we need to keep colorPipeline too.
    215         SkRasterPipeline_<256> p;
    216         p.extend(*colorPipeline);
    217         blitter->fDstPtr = SkJumper_MemoryCtx{&blitter->fMemsetColor, 0};
    218         blitter->append_store(&p);
    219         p.run(0,0,1,1);
    220 
    221         blitter->fCanMemsetInBlitRect = true;
    222     }
    223 
    224     blitter->fDstPtr = SkJumper_MemoryCtx{
    225         blitter->fDst.writable_addr(),
    226         blitter->fDst.rowBytesAsPixels(),
    227     };
    228 
    229     return blitter;
    230 }
    231 
    232 void SkRasterPipelineBlitter::append_load_dst(SkRasterPipeline* p) const {
    233     const void* ctx = &fDstPtr;
    234     switch (fDst.info().colorType()) {
    235         default: break;
    236 
    237         case kGray_8_SkColorType:       p->append(SkRasterPipeline::load_g8_dst,      ctx); break;
    238         case kAlpha_8_SkColorType:      p->append(SkRasterPipeline::load_a8_dst,      ctx); break;
    239         case kRGB_565_SkColorType:      p->append(SkRasterPipeline::load_565_dst,     ctx); break;
    240         case kARGB_4444_SkColorType:    p->append(SkRasterPipeline::load_4444_dst,    ctx); break;
    241         case kBGRA_8888_SkColorType:    p->append(SkRasterPipeline::load_bgra_dst,    ctx); break;
    242         case kRGBA_8888_SkColorType:    p->append(SkRasterPipeline::load_8888_dst,    ctx); break;
    243         case kRGBA_1010102_SkColorType: p->append(SkRasterPipeline::load_1010102_dst, ctx); break;
    244         case kRGBA_F16_SkColorType:     p->append(SkRasterPipeline::load_f16_dst,     ctx); break;
    245 
    246         case kRGB_888x_SkColorType:     p->append(SkRasterPipeline::load_8888_dst,    ctx);
    247                                         p->append(SkRasterPipeline::force_opaque_dst     ); break;
    248         case kRGB_101010x_SkColorType:  p->append(SkRasterPipeline::load_1010102_dst, ctx);
    249                                         p->append(SkRasterPipeline::force_opaque_dst     ); break;
    250     }
    251     if (fDst.info().gammaCloseToSRGB()) {
    252         p->append(SkRasterPipeline::from_srgb_dst);
    253     }
    254     if (fDst.info().alphaType() == kUnpremul_SkAlphaType) {
    255         p->append(SkRasterPipeline::premul_dst);
    256     }
    257 }
    258 
    259 void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p) const {
    260     if (fDst.info().alphaType() == kUnpremul_SkAlphaType) {
    261         p->append(SkRasterPipeline::unpremul);
    262     }
    263     if (fDst.info().gammaCloseToSRGB()) {
    264         p->append(SkRasterPipeline::to_srgb);
    265     }
    266     if (fDitherRate > 0.0f) {
    267         // We dither after any sRGB transfer function to make sure our 1/255.0f is sensible
    268         // over the whole range.  If we did it before, 1/255.0f is too big a rate near zero.
    269         p->append(SkRasterPipeline::dither, &fDitherRate);
    270     }
    271 
    272     const void* ctx = &fDstPtr;
    273     switch (fDst.info().colorType()) {
    274         default: break;
    275 
    276         case kGray_8_SkColorType:       p->append(SkRasterPipeline::luminance_to_alpha);
    277                                         p->append(SkRasterPipeline::store_a8,      ctx); break;
    278         case kAlpha_8_SkColorType:      p->append(SkRasterPipeline::store_a8,      ctx); break;
    279         case kRGB_565_SkColorType:      p->append(SkRasterPipeline::store_565,     ctx); break;
    280         case kARGB_4444_SkColorType:    p->append(SkRasterPipeline::store_4444,    ctx); break;
    281         case kBGRA_8888_SkColorType:    p->append(SkRasterPipeline::store_bgra,    ctx); break;
    282         case kRGBA_8888_SkColorType:    p->append(SkRasterPipeline::store_8888,    ctx); break;
    283         case kRGBA_1010102_SkColorType: p->append(SkRasterPipeline::store_1010102, ctx); break;
    284         case kRGBA_F16_SkColorType:     p->append(SkRasterPipeline::store_f16,     ctx); break;
    285 
    286         case kRGB_888x_SkColorType:     p->append(SkRasterPipeline::force_opaque         );
    287                                         p->append(SkRasterPipeline::store_8888,       ctx); break;
    288         case kRGB_101010x_SkColorType:  p->append(SkRasterPipeline::force_opaque         );
    289                                         p->append(SkRasterPipeline::store_1010102,    ctx); break;
    290     }
    291 }
    292 
    293 void SkRasterPipelineBlitter::burst_shade(int x, int y, int w) {
    294     SkASSERT(fBurstCtx);
    295     if (w > SkToInt(fShaderBuffer.size())) {
    296         fShaderBuffer.resize(w);
    297     }
    298     fBurstCtx->shadeSpan4f(x,y, fShaderBuffer.data(), w);
    299     // We'll be reading from fShaderOutput.pixels + x, so back up by x.
    300     fShaderOutput = SkJumper_MemoryCtx{ fShaderBuffer.data() - x, 0 };
    301 }
    302 
    303 void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
    304     this->blitRect(x,y,w,1);
    305 }
    306 
    307 void SkRasterPipelineBlitter::blitRect(int x, int y, int w, int h) {
    308     if (fCanMemsetInBlitRect) {
    309         for (int ylimit = y+h; y < ylimit; y++) {
    310             switch (fDst.shiftPerPixel()) {
    311                 case 0:    memset  (fDst.writable_addr8 (x,y), fMemsetColor, w); break;
    312                 case 1: sk_memset16(fDst.writable_addr16(x,y), fMemsetColor, w); break;
    313                 case 2: sk_memset32(fDst.writable_addr32(x,y), fMemsetColor, w); break;
    314                 case 3: sk_memset64(fDst.writable_addr64(x,y), fMemsetColor, w); break;
    315                 default: break;
    316             }
    317         }
    318         return;
    319     }
    320 
    321     if (!fBlitRect) {
    322         SkRasterPipeline p(fAlloc);
    323         p.extend(fColorPipeline);
    324         if (fBlend == SkBlendMode::kSrcOver
    325                 && (fDst.info().colorType() == kRGBA_8888_SkColorType ||
    326                     fDst.info().colorType() == kBGRA_8888_SkColorType)
    327                 && !fDst.colorSpace()
    328                 && fDst.info().alphaType() != kUnpremul_SkAlphaType
    329                 && fDitherRate == 0.0f) {
    330             auto stage = fDst.info().colorType() == kRGBA_8888_SkColorType
    331                        ? SkRasterPipeline::srcover_rgba_8888
    332                        : SkRasterPipeline::srcover_bgra_8888;
    333             p.append(stage, &fDstPtr);
    334         } else {
    335             if (fBlend != SkBlendMode::kSrc) {
    336                 this->append_load_dst(&p);
    337                 SkBlendMode_AppendStages(fBlend, &p);
    338             }
    339             this->append_store(&p);
    340         }
    341         fBlitRect = p.compile();
    342     }
    343 
    344     if (fBurstCtx) {
    345         // We can only burst shade one row at a time.
    346         for (int ylimit = y+h; y < ylimit; y++) {
    347             this->burst_shade(x,y,w);
    348             fBlitRect(x,y, w,1);
    349         }
    350     } else {
    351         // If not bursting we can blit the entire rect at once.
    352         fBlitRect(x,y,w,h);
    353     }
    354 }
    355 
    356 void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
    357     if (!fBlitAntiH) {
    358         SkRasterPipeline p(fAlloc);
    359         p.extend(fColorPipeline);
    360         if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/false)) {
    361             p.append(SkRasterPipeline::scale_1_float, &fCurrentCoverage);
    362             this->append_load_dst(&p);
    363             SkBlendMode_AppendStages(fBlend, &p);
    364         } else {
    365             this->append_load_dst(&p);
    366             SkBlendMode_AppendStages(fBlend, &p);
    367             p.append(SkRasterPipeline::lerp_1_float, &fCurrentCoverage);
    368         }
    369 
    370         this->append_store(&p);
    371         fBlitAntiH = p.compile();
    372     }
    373 
    374     for (int16_t run = *runs; run > 0; run = *runs) {
    375         switch (*aa) {
    376             case 0x00:                       break;
    377             case 0xff: this->blitH(x,y,run); break;
    378             default:
    379                 fCurrentCoverage = *aa * (1/255.0f);
    380                 if (fBurstCtx) {
    381                     this->burst_shade(x,y,run);
    382                 }
    383                 fBlitAntiH(x,y,run,1);
    384         }
    385         x    += run;
    386         runs += run;
    387         aa   += run;
    388     }
    389 }
    390 
    391 void SkRasterPipelineBlitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
    392     SkIRect clip = {x,y, x+2,y+1};
    393     uint8_t coverage[] = { (uint8_t)a0, (uint8_t)a1 };
    394 
    395     SkMask mask;
    396     mask.fImage    = coverage;
    397     mask.fBounds   = clip;
    398     mask.fRowBytes = 2;
    399     mask.fFormat   = SkMask::kA8_Format;
    400 
    401     this->blitMask(mask, clip);
    402 }
    403 
    404 void SkRasterPipelineBlitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
    405     SkIRect clip = {x,y, x+1,y+2};
    406     uint8_t coverage[] = { (uint8_t)a0, (uint8_t)a1 };
    407 
    408     SkMask mask;
    409     mask.fImage    = coverage;
    410     mask.fBounds   = clip;
    411     mask.fRowBytes = 1;
    412     mask.fFormat   = SkMask::kA8_Format;
    413 
    414     this->blitMask(mask, clip);
    415 }
    416 
    417 void SkRasterPipelineBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
    418     SkIRect clip = {x,y, x+1,y+height};
    419 
    420     SkMask mask;
    421     mask.fImage    = &alpha;
    422     mask.fBounds   = clip;
    423     mask.fRowBytes = 0;     // so we reuse the 1 "row" for all of height
    424     mask.fFormat   = SkMask::kA8_Format;
    425 
    426     this->blitMask(mask, clip);
    427 }
    428 
    429 void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
    430     if (mask.fFormat == SkMask::kBW_Format) {
    431         // TODO: native BW masks?
    432         return INHERITED::blitMask(mask, clip);
    433     }
    434 
    435     // We'll use the first (A8) plane of any mask and ignore the other two, just like Ganesh.
    436     SkMask::Format effectiveMaskFormat = mask.fFormat == SkMask::k3D_Format ? SkMask::kA8_Format
    437                                                                             : mask.fFormat;
    438 
    439 
    440     // Lazily build whichever pipeline we need, specialized for each mask format.
    441     if (effectiveMaskFormat == SkMask::kA8_Format && !fBlitMaskA8) {
    442         SkRasterPipeline p(fAlloc);
    443         p.extend(fColorPipeline);
    444         if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/false)) {
    445             p.append(SkRasterPipeline::scale_u8, &fMaskPtr);
    446             this->append_load_dst(&p);
    447             SkBlendMode_AppendStages(fBlend, &p);
    448         } else {
    449             this->append_load_dst(&p);
    450             SkBlendMode_AppendStages(fBlend, &p);
    451             p.append(SkRasterPipeline::lerp_u8, &fMaskPtr);
    452         }
    453         this->append_store(&p);
    454         fBlitMaskA8 = p.compile();
    455     }
    456     if (effectiveMaskFormat == SkMask::kLCD16_Format && !fBlitMaskLCD16) {
    457         SkRasterPipeline p(fAlloc);
    458         p.extend(fColorPipeline);
    459         if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/true)) {
    460             // Somewhat unusually, scale_565 needs dst loaded first.
    461             this->append_load_dst(&p);
    462             p.append(SkRasterPipeline::scale_565, &fMaskPtr);
    463             SkBlendMode_AppendStages(fBlend, &p);
    464         } else {
    465             this->append_load_dst(&p);
    466             SkBlendMode_AppendStages(fBlend, &p);
    467             p.append(SkRasterPipeline::lerp_565, &fMaskPtr);
    468         }
    469         this->append_store(&p);
    470         fBlitMaskLCD16 = p.compile();
    471     }
    472 
    473     std::function<void(size_t,size_t,size_t,size_t)>* blitter = nullptr;
    474     // Update fMaskPtr to point "into" this current mask, but lined up with fDstPtr at (0,0).
    475     switch (effectiveMaskFormat) {
    476         case SkMask::kA8_Format:
    477             fMaskPtr.stride = mask.fRowBytes;
    478             fMaskPtr.pixels = (uint8_t*)mask.fImage - mask.fBounds.left()
    479                                                     - mask.fBounds.top() * fMaskPtr.stride;
    480             blitter = &fBlitMaskA8;
    481             break;
    482         case SkMask::kLCD16_Format:
    483             fMaskPtr.stride = mask.fRowBytes / 2;
    484             fMaskPtr.pixels = (uint16_t*)mask.fImage - mask.fBounds.left()
    485                                                      - mask.fBounds.top() * fMaskPtr.stride;
    486             blitter = &fBlitMaskLCD16;
    487             break;
    488         default:
    489             return;
    490     }
    491 
    492     SkASSERT(blitter);
    493     if (fBurstCtx) {
    494         // We can only burst shade one row at a time.
    495         int x = clip.left();
    496         for (int y = clip.top(); y < clip.bottom(); y++) {
    497             this->burst_shade(x,y,clip.width());
    498             (*blitter)(x,y, clip.width(),1);
    499         }
    500     } else {
    501         // If not bursting we can blit the entire mask at once.
    502         (*blitter)(clip.left(),clip.top(), clip.width(),clip.height());
    503     }
    504 }
    505