Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2011 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 "SkGpuDevice.h"
      9 
     10 #include "effects/GrBicubicEffect.h"
     11 #include "effects/GrDashingEffect.h"
     12 #include "effects/GrTextureDomain.h"
     13 #include "effects/GrSimpleTextureEffect.h"
     14 
     15 #include "GrContext.h"
     16 #include "GrBitmapTextContext.h"
     17 #include "GrDistanceFieldTextContext.h"
     18 #include "GrLayerCache.h"
     19 #include "GrPictureUtils.h"
     20 #include "GrStrokeInfo.h"
     21 #include "GrTracing.h"
     22 
     23 #include "SkGrTexturePixelRef.h"
     24 
     25 #include "SkDeviceImageFilterProxy.h"
     26 #include "SkDrawProcs.h"
     27 #include "SkGlyphCache.h"
     28 #include "SkImageFilter.h"
     29 #include "SkMaskFilter.h"
     30 #include "SkPathEffect.h"
     31 #include "SkPicture.h"
     32 #include "SkPicturePlayback.h"
     33 #include "SkRRect.h"
     34 #include "SkStroke.h"
     35 #include "SkSurface.h"
     36 #include "SkTLazy.h"
     37 #include "SkUtils.h"
     38 #include "SkVertState.h"
     39 #include "SkErrorInternals.h"
     40 
     41 #define CACHE_COMPATIBLE_DEVICE_TEXTURES 1
     42 
     43 #if 0
     44     extern bool (*gShouldDrawProc)();
     45     #define CHECK_SHOULD_DRAW(draw, forceI)                     \
     46         do {                                                    \
     47             if (gShouldDrawProc && !gShouldDrawProc()) return;  \
     48             this->prepareDraw(draw, forceI);                    \
     49         } while (0)
     50 #else
     51     #define CHECK_SHOULD_DRAW(draw, forceI) this->prepareDraw(draw, forceI)
     52 #endif
     53 
     54 // This constant represents the screen alignment criterion in texels for
     55 // requiring texture domain clamping to prevent color bleeding when drawing
     56 // a sub region of a larger source image.
     57 #define COLOR_BLEED_TOLERANCE 0.001f
     58 
     59 #define DO_DEFERRED_CLEAR()             \
     60     do {                                \
     61         if (fNeedClear) {               \
     62             this->clear(SK_ColorTRANSPARENT); \
     63         }                               \
     64     } while (false)                     \
     65 
     66 ///////////////////////////////////////////////////////////////////////////////
     67 
     68 #define CHECK_FOR_ANNOTATION(paint) \
     69     do { if (paint.getAnnotation()) { return; } } while (0)
     70 
     71 ///////////////////////////////////////////////////////////////////////////////
     72 
     73 
     74 class SkGpuDevice::SkAutoCachedTexture : public ::SkNoncopyable {
     75 public:
     76     SkAutoCachedTexture()
     77         : fDevice(NULL)
     78         , fTexture(NULL) {
     79     }
     80 
     81     SkAutoCachedTexture(SkGpuDevice* device,
     82                         const SkBitmap& bitmap,
     83                         const GrTextureParams* params,
     84                         GrTexture** texture)
     85         : fDevice(NULL)
     86         , fTexture(NULL) {
     87         SkASSERT(NULL != texture);
     88         *texture = this->set(device, bitmap, params);
     89     }
     90 
     91     ~SkAutoCachedTexture() {
     92         if (NULL != fTexture) {
     93             GrUnlockAndUnrefCachedBitmapTexture(fTexture);
     94         }
     95     }
     96 
     97     GrTexture* set(SkGpuDevice* device,
     98                    const SkBitmap& bitmap,
     99                    const GrTextureParams* params) {
    100         if (NULL != fTexture) {
    101             GrUnlockAndUnrefCachedBitmapTexture(fTexture);
    102             fTexture = NULL;
    103         }
    104         fDevice = device;
    105         GrTexture* result = (GrTexture*)bitmap.getTexture();
    106         if (NULL == result) {
    107             // Cannot return the native texture so look it up in our cache
    108             fTexture = GrLockAndRefCachedBitmapTexture(device->context(), bitmap, params);
    109             result = fTexture;
    110         }
    111         return result;
    112     }
    113 
    114 private:
    115     SkGpuDevice* fDevice;
    116     GrTexture*   fTexture;
    117 };
    118 
    119 ///////////////////////////////////////////////////////////////////////////////
    120 
    121 struct GrSkDrawProcs : public SkDrawProcs {
    122 public:
    123     GrContext* fContext;
    124     GrTextContext* fTextContext;
    125     GrFontScaler* fFontScaler;  // cached in the skia glyphcache
    126 };
    127 
    128 ///////////////////////////////////////////////////////////////////////////////
    129 
    130 /*
    131  * GrRenderTarget does not know its opaqueness, only its config, so we have
    132  * to make conservative guesses when we return an "equivalent" bitmap.
    133  */
    134 static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
    135     SkBitmap bitmap;
    136     bitmap.setInfo(renderTarget->info());
    137     return bitmap;
    138 }
    139 
    140 SkGpuDevice* SkGpuDevice::Create(GrSurface* surface, unsigned flags) {
    141     SkASSERT(NULL != surface);
    142     if (NULL == surface->asRenderTarget() || NULL == surface->getContext()) {
    143         return NULL;
    144     }
    145     if (surface->asTexture()) {
    146         return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asTexture(), flags));
    147     } else {
    148         return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asRenderTarget(), flags));
    149     }
    150 }
    151 
    152 SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture, unsigned flags)
    153     : SkBitmapDevice(make_bitmap(context, texture->asRenderTarget())) {
    154     this->initFromRenderTarget(context, texture->asRenderTarget(), flags);
    155 }
    156 
    157 SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget, unsigned flags)
    158     : SkBitmapDevice(make_bitmap(context, renderTarget)) {
    159     this->initFromRenderTarget(context, renderTarget, flags);
    160 }
    161 
    162 void SkGpuDevice::initFromRenderTarget(GrContext* context,
    163                                        GrRenderTarget* renderTarget,
    164                                        unsigned flags) {
    165     fDrawProcs = NULL;
    166 
    167     fContext = context;
    168     fContext->ref();
    169 
    170     bool useDFFonts = !!(flags & kDFFonts_Flag);
    171     fMainTextContext = SkNEW_ARGS(GrDistanceFieldTextContext, (fContext, fLeakyProperties,
    172                                                                useDFFonts));
    173     fFallbackTextContext = SkNEW_ARGS(GrBitmapTextContext, (fContext, fLeakyProperties));
    174 
    175     fRenderTarget = NULL;
    176     fNeedClear = flags & kNeedClear_Flag;
    177 
    178     SkASSERT(NULL != renderTarget);
    179     fRenderTarget = renderTarget;
    180     fRenderTarget->ref();
    181 
    182     // Hold onto to the texture in the pixel ref (if there is one) because the texture holds a ref
    183     // on the RT but not vice-versa.
    184     // TODO: Remove this trickery once we figure out how to make SkGrPixelRef do this without
    185     // busting chrome (for a currently unknown reason).
    186     GrSurface* surface = fRenderTarget->asTexture();
    187     if (NULL == surface) {
    188         surface = fRenderTarget;
    189     }
    190 
    191     SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef,
    192                                 (surface->info(), surface, SkToBool(flags & kCached_Flag)));
    193 
    194     this->setPixelRef(pr)->unref();
    195 }
    196 
    197 SkGpuDevice* SkGpuDevice::Create(GrContext* context, const SkImageInfo& origInfo,
    198                                  int sampleCount) {
    199     if (kUnknown_SkColorType == origInfo.colorType() ||
    200         origInfo.width() < 0 || origInfo.height() < 0) {
    201         return NULL;
    202     }
    203 
    204     SkImageInfo info = origInfo;
    205     // TODO: perhas we can loosen this check now that colortype is more detailed
    206     // e.g. can we support both RGBA and BGRA here?
    207     if (kRGB_565_SkColorType == info.colorType()) {
    208         info.fAlphaType = kOpaque_SkAlphaType;  // force this setting
    209     } else {
    210         info.fColorType = kN32_SkColorType;
    211         if (kOpaque_SkAlphaType != info.alphaType()) {
    212             info.fAlphaType = kPremul_SkAlphaType;  // force this setting
    213         }
    214     }
    215 
    216     GrTextureDesc desc;
    217     desc.fFlags = kRenderTarget_GrTextureFlagBit;
    218     desc.fWidth = info.width();
    219     desc.fHeight = info.height();
    220     desc.fConfig = SkImageInfo2GrPixelConfig(info);
    221     desc.fSampleCnt = sampleCount;
    222 
    223     SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0));
    224     if (!texture.get()) {
    225         return NULL;
    226     }
    227 
    228     return SkNEW_ARGS(SkGpuDevice, (context, texture.get()));
    229 }
    230 
    231 SkGpuDevice::~SkGpuDevice() {
    232     if (fDrawProcs) {
    233         delete fDrawProcs;
    234     }
    235 
    236     delete fMainTextContext;
    237     delete fFallbackTextContext;
    238 
    239     // The GrContext takes a ref on the target. We don't want to cause the render
    240     // target to be unnecessarily kept alive.
    241     if (fContext->getRenderTarget() == fRenderTarget) {
    242         fContext->setRenderTarget(NULL);
    243     }
    244 
    245     if (fContext->getClip() == &fClipData) {
    246         fContext->setClip(NULL);
    247     }
    248 
    249     SkSafeUnref(fRenderTarget);
    250     fContext->unref();
    251 }
    252 
    253 ///////////////////////////////////////////////////////////////////////////////
    254 
    255 void SkGpuDevice::makeRenderTargetCurrent() {
    256     DO_DEFERRED_CLEAR();
    257     fContext->setRenderTarget(fRenderTarget);
    258 }
    259 
    260 ///////////////////////////////////////////////////////////////////////////////
    261 
    262 bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
    263                                int x, int y) {
    264     DO_DEFERRED_CLEAR();
    265 
    266     // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
    267     GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo);
    268     if (kUnknown_GrPixelConfig == config) {
    269         return false;
    270     }
    271 
    272     uint32_t flags = 0;
    273     if (kUnpremul_SkAlphaType == dstInfo.alphaType()) {
    274         flags = GrContext::kUnpremul_PixelOpsFlag;
    275     }
    276     return fContext->readRenderTargetPixels(fRenderTarget, x, y, dstInfo.width(), dstInfo.height(),
    277                                             config, dstPixels, dstRowBytes, flags);
    278 }
    279 
    280 bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
    281                                 int x, int y) {
    282     // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
    283     GrPixelConfig config = SkImageInfo2GrPixelConfig(info);
    284     if (kUnknown_GrPixelConfig == config) {
    285         return false;
    286     }
    287     uint32_t flags = 0;
    288     if (kUnpremul_SkAlphaType == info.alphaType()) {
    289         flags = GrContext::kUnpremul_PixelOpsFlag;
    290     }
    291     fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags);
    292 
    293     // need to bump our genID for compatibility with clients that "know" we have a bitmap
    294     this->onAccessBitmap().notifyPixelsChanged();
    295 
    296     return true;
    297 }
    298 
    299 const SkBitmap& SkGpuDevice::onAccessBitmap() {
    300     DO_DEFERRED_CLEAR();
    301     return INHERITED::onAccessBitmap();
    302 }
    303 
    304 void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
    305     INHERITED::onAttachToCanvas(canvas);
    306 
    307     // Canvas promises that this ptr is valid until onDetachFromCanvas is called
    308     fClipData.fClipStack = canvas->getClipStack();
    309 }
    310 
    311 void SkGpuDevice::onDetachFromCanvas() {
    312     INHERITED::onDetachFromCanvas();
    313     fClipData.fClipStack = NULL;
    314 }
    315 
    316 // call this every draw call, to ensure that the context reflects our state,
    317 // and not the state from some other canvas/device
    318 void SkGpuDevice::prepareDraw(const SkDraw& draw, bool forceIdentity) {
    319     SkASSERT(NULL != fClipData.fClipStack);
    320 
    321     fContext->setRenderTarget(fRenderTarget);
    322 
    323     SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack);
    324 
    325     if (forceIdentity) {
    326         fContext->setIdentityMatrix();
    327     } else {
    328         fContext->setMatrix(*draw.fMatrix);
    329     }
    330     fClipData.fOrigin = this->getOrigin();
    331 
    332     fContext->setClip(&fClipData);
    333 
    334     DO_DEFERRED_CLEAR();
    335 }
    336 
    337 GrRenderTarget* SkGpuDevice::accessRenderTarget() {
    338     DO_DEFERRED_CLEAR();
    339     return fRenderTarget;
    340 }
    341 
    342 ///////////////////////////////////////////////////////////////////////////////
    343 
    344 SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
    345 SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
    346 SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
    347 SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
    348 SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
    349                   shader_type_mismatch);
    350 SK_COMPILE_ASSERT(SkShader::kTwoPointConical_BitmapType == 5,
    351                   shader_type_mismatch);
    352 SK_COMPILE_ASSERT(SkShader::kLinear_BitmapType == 6, shader_type_mismatch);
    353 SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 6, shader_type_mismatch);
    354 
    355 ///////////////////////////////////////////////////////////////////////////////
    356 
    357 void SkGpuDevice::clear(SkColor color) {
    358     SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
    359     fContext->clear(&rect, SkColor2GrColor(color), true, fRenderTarget);
    360     fNeedClear = false;
    361 }
    362 
    363 void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
    364     CHECK_SHOULD_DRAW(draw, false);
    365 
    366     GrPaint grPaint;
    367     SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
    368 
    369     fContext->drawPaint(grPaint);
    370 }
    371 
    372 // must be in SkCanvas::PointMode order
    373 static const GrPrimitiveType gPointMode2PrimtiveType[] = {
    374     kPoints_GrPrimitiveType,
    375     kLines_GrPrimitiveType,
    376     kLineStrip_GrPrimitiveType
    377 };
    378 
    379 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
    380                              size_t count, const SkPoint pts[], const SkPaint& paint) {
    381     CHECK_FOR_ANNOTATION(paint);
    382     CHECK_SHOULD_DRAW(draw, false);
    383 
    384     SkScalar width = paint.getStrokeWidth();
    385     if (width < 0) {
    386         return;
    387     }
    388 
    389     if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
    390         GrStrokeInfo strokeInfo(paint, SkPaint::kStroke_Style);
    391         GrPaint grPaint;
    392         SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
    393         SkPath path;
    394         path.moveTo(pts[0]);
    395         path.lineTo(pts[1]);
    396         fContext->drawPath(grPaint, path, strokeInfo);
    397         return;
    398     }
    399 
    400     // we only handle hairlines and paints without path effects or mask filters,
    401     // else we let the SkDraw call our drawPath()
    402     if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) {
    403         draw.drawPoints(mode, count, pts, paint, true);
    404         return;
    405     }
    406 
    407     GrPaint grPaint;
    408     SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
    409 
    410     fContext->drawVertices(grPaint,
    411                            gPointMode2PrimtiveType[mode],
    412                            SkToS32(count),
    413                            (SkPoint*)pts,
    414                            NULL,
    415                            NULL,
    416                            NULL,
    417                            0);
    418 }
    419 
    420 ///////////////////////////////////////////////////////////////////////////////
    421 
    422 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
    423                            const SkPaint& paint) {
    424     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawRect", fContext);
    425 
    426     CHECK_FOR_ANNOTATION(paint);
    427     CHECK_SHOULD_DRAW(draw, false);
    428 
    429     bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
    430     SkScalar width = paint.getStrokeWidth();
    431 
    432     /*
    433         We have special code for hairline strokes, miter-strokes, bevel-stroke
    434         and fills. Anything else we just call our path code.
    435      */
    436     bool usePath = doStroke && width > 0 &&
    437                    (paint.getStrokeJoin() == SkPaint::kRound_Join ||
    438                     (paint.getStrokeJoin() == SkPaint::kBevel_Join && rect.isEmpty()));
    439     // another two reasons we might need to call drawPath...
    440 
    441     if (paint.getMaskFilter()) {
    442         usePath = true;
    443     }
    444 
    445     if (!usePath && paint.isAntiAlias() && !fContext->getMatrix().rectStaysRect()) {
    446 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
    447         if (doStroke) {
    448 #endif
    449             usePath = true;
    450 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
    451         } else {
    452             usePath = !fContext->getMatrix().preservesRightAngles();
    453         }
    454 #endif
    455     }
    456     // until we can both stroke and fill rectangles
    457     if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
    458         usePath = true;
    459     }
    460 
    461     GrStrokeInfo strokeInfo(paint);
    462 
    463     const SkPathEffect* pe = paint.getPathEffect();
    464     if (!usePath && NULL != pe && !strokeInfo.isDashed()) {
    465         usePath = true;
    466     }
    467 
    468     if (usePath) {
    469         SkPath path;
    470         path.addRect(rect);
    471         this->drawPath(draw, path, paint, NULL, true);
    472         return;
    473     }
    474 
    475     GrPaint grPaint;
    476     SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
    477 
    478     fContext->drawRect(grPaint, rect, &strokeInfo);
    479 }
    480 
    481 ///////////////////////////////////////////////////////////////////////////////
    482 
    483 void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
    484                            const SkPaint& paint) {
    485     CHECK_FOR_ANNOTATION(paint);
    486     CHECK_SHOULD_DRAW(draw, false);
    487 
    488     GrPaint grPaint;
    489     SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
    490 
    491     GrStrokeInfo strokeInfo(paint);
    492     if (paint.getMaskFilter()) {
    493         // try to hit the fast path for drawing filtered round rects
    494 
    495         SkRRect devRRect;
    496         if (rect.transform(fContext->getMatrix(), &devRRect)) {
    497             if (devRRect.allCornersCircular()) {
    498                 SkRect maskRect;
    499                 if (paint.getMaskFilter()->canFilterMaskGPU(devRRect.rect(),
    500                                             draw.fClip->getBounds(),
    501                                             fContext->getMatrix(),
    502                                             &maskRect)) {
    503                     SkIRect finalIRect;
    504                     maskRect.roundOut(&finalIRect);
    505                     if (draw.fClip->quickReject(finalIRect)) {
    506                         // clipped out
    507                         return;
    508                     }
    509                     if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext, &grPaint,
    510                                                                         strokeInfo.getStrokeRec(),
    511                                                                         devRRect)) {
    512                         return;
    513                     }
    514                 }
    515 
    516             }
    517         }
    518 
    519     }
    520 
    521     bool usePath = false;
    522 
    523     if (paint.getMaskFilter()) {
    524         usePath = true;
    525     } else {
    526         const SkPathEffect* pe = paint.getPathEffect();
    527         if (NULL != pe && !strokeInfo.isDashed()) {
    528             usePath = true;
    529         }
    530     }
    531 
    532 
    533     if (usePath) {
    534         SkPath path;
    535         path.addRRect(rect);
    536         this->drawPath(draw, path, paint, NULL, true);
    537         return;
    538     }
    539 
    540     fContext->drawRRect(grPaint, rect, strokeInfo);
    541 }
    542 
    543 void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
    544                               const SkRRect& inner, const SkPaint& paint) {
    545     SkStrokeRec stroke(paint);
    546     if (stroke.isFillStyle()) {
    547 
    548         CHECK_FOR_ANNOTATION(paint);
    549         CHECK_SHOULD_DRAW(draw, false);
    550 
    551         GrPaint grPaint;
    552         SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
    553 
    554         if (NULL == paint.getMaskFilter() && NULL == paint.getPathEffect()) {
    555             fContext->drawDRRect(grPaint, outer, inner);
    556             return;
    557         }
    558     }
    559 
    560     SkPath path;
    561     path.addRRect(outer);
    562     path.addRRect(inner);
    563     path.setFillType(SkPath::kEvenOdd_FillType);
    564 
    565     this->drawPath(draw, path, paint, NULL, true);
    566 }
    567 
    568 
    569 /////////////////////////////////////////////////////////////////////////////
    570 
    571 void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval,
    572                            const SkPaint& paint) {
    573     CHECK_FOR_ANNOTATION(paint);
    574     CHECK_SHOULD_DRAW(draw, false);
    575 
    576     GrStrokeInfo strokeInfo(paint);
    577 
    578     bool usePath = false;
    579     // some basic reasons we might need to call drawPath...
    580     if (paint.getMaskFilter()) {
    581         usePath = true;
    582     } else {
    583         const SkPathEffect* pe = paint.getPathEffect();
    584         if (NULL != pe && !strokeInfo.isDashed()) {
    585             usePath = true;
    586         }
    587     }
    588 
    589     if (usePath) {
    590         SkPath path;
    591         path.addOval(oval);
    592         this->drawPath(draw, path, paint, NULL, true);
    593         return;
    594     }
    595 
    596     GrPaint grPaint;
    597     SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
    598 
    599     fContext->drawOval(grPaint, oval, strokeInfo);
    600 }
    601 
    602 #include "SkMaskFilter.h"
    603 
    604 ///////////////////////////////////////////////////////////////////////////////
    605 
    606 // helpers for applying mask filters
    607 namespace {
    608 
    609 // Draw a mask using the supplied paint. Since the coverage/geometry
    610 // is already burnt into the mask this boils down to a rect draw.
    611 // Return true if the mask was successfully drawn.
    612 bool draw_mask(GrContext* context, const SkRect& maskRect,
    613                GrPaint* grp, GrTexture* mask) {
    614     GrContext::AutoMatrix am;
    615     if (!am.setIdentity(context, grp)) {
    616         return false;
    617     }
    618 
    619     SkMatrix matrix;
    620     matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop);
    621     matrix.postIDiv(mask->width(), mask->height());
    622 
    623     grp->addCoverageEffect(GrSimpleTextureEffect::Create(mask, matrix))->unref();
    624     context->drawRect(*grp, maskRect);
    625     return true;
    626 }
    627 
    628 bool draw_with_mask_filter(GrContext* context, const SkPath& devPath,
    629                            SkMaskFilter* filter, const SkRegion& clip,
    630                            GrPaint* grp, SkPaint::Style style) {
    631     SkMask  srcM, dstM;
    632 
    633     if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), filter, &context->getMatrix(), &srcM,
    634                             SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
    635         return false;
    636     }
    637     SkAutoMaskFreeImage autoSrc(srcM.fImage);
    638 
    639     if (!filter->filterMask(&dstM, srcM, context->getMatrix(), NULL)) {
    640         return false;
    641     }
    642     // this will free-up dstM when we're done (allocated in filterMask())
    643     SkAutoMaskFreeImage autoDst(dstM.fImage);
    644 
    645     if (clip.quickReject(dstM.fBounds)) {
    646         return false;
    647     }
    648 
    649     // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
    650     // the current clip (and identity matrix) and GrPaint settings
    651     GrTextureDesc desc;
    652     desc.fWidth = dstM.fBounds.width();
    653     desc.fHeight = dstM.fBounds.height();
    654     desc.fConfig = kAlpha_8_GrPixelConfig;
    655 
    656     GrAutoScratchTexture ast(context, desc);
    657     GrTexture* texture = ast.texture();
    658 
    659     if (NULL == texture) {
    660         return false;
    661     }
    662     texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
    663                                dstM.fImage, dstM.fRowBytes);
    664 
    665     SkRect maskRect = SkRect::Make(dstM.fBounds);
    666 
    667     return draw_mask(context, maskRect, grp, texture);
    668 }
    669 
    670 // Create a mask of 'devPath' and place the result in 'mask'. Return true on
    671 // success; false otherwise.
    672 bool create_mask_GPU(GrContext* context,
    673                      const SkRect& maskRect,
    674                      const SkPath& devPath,
    675                      const GrStrokeInfo& strokeInfo,
    676                      bool doAA,
    677                      GrAutoScratchTexture* mask) {
    678     GrTextureDesc desc;
    679     desc.fFlags = kRenderTarget_GrTextureFlagBit;
    680     desc.fWidth = SkScalarCeilToInt(maskRect.width());
    681     desc.fHeight = SkScalarCeilToInt(maskRect.height());
    682     // We actually only need A8, but it often isn't supported as a
    683     // render target so default to RGBA_8888
    684     desc.fConfig = kRGBA_8888_GrPixelConfig;
    685     if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
    686         desc.fConfig = kAlpha_8_GrPixelConfig;
    687     }
    688 
    689     mask->set(context, desc);
    690     if (NULL == mask->texture()) {
    691         return false;
    692     }
    693 
    694     GrTexture* maskTexture = mask->texture();
    695     SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
    696 
    697     GrContext::AutoRenderTarget art(context, maskTexture->asRenderTarget());
    698     GrContext::AutoClip ac(context, clipRect);
    699 
    700     context->clear(NULL, 0x0, true);
    701 
    702     GrPaint tempPaint;
    703     if (doAA) {
    704         tempPaint.setAntiAlias(true);
    705         // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
    706         // blend coeff of zero requires dual source blending support in order
    707         // to properly blend partially covered pixels. This means the AA
    708         // code path may not be taken. So we use a dst blend coeff of ISA. We
    709         // could special case AA draws to a dst surface with known alpha=0 to
    710         // use a zero dst coeff when dual source blending isn't available.
    711         tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
    712     }
    713 
    714     GrContext::AutoMatrix am;
    715 
    716     // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint.
    717     SkMatrix translate;
    718     translate.setTranslate(-maskRect.fLeft, -maskRect.fTop);
    719     am.set(context, translate);
    720     context->drawPath(tempPaint, devPath, strokeInfo);
    721     return true;
    722 }
    723 
    724 SkBitmap wrap_texture(GrTexture* texture) {
    725     SkBitmap result;
    726     result.setInfo(texture->info());
    727     result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unref();
    728     return result;
    729 }
    730 
    731 };
    732 
    733 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
    734                            const SkPaint& paint, const SkMatrix* prePathMatrix,
    735                            bool pathIsMutable) {
    736     CHECK_FOR_ANNOTATION(paint);
    737     CHECK_SHOULD_DRAW(draw, false);
    738 
    739     GrPaint grPaint;
    740     SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
    741 
    742     // If we have a prematrix, apply it to the path, optimizing for the case
    743     // where the original path can in fact be modified in place (even though
    744     // its parameter type is const).
    745     SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
    746     SkTLazy<SkPath> tmpPath;
    747     SkTLazy<SkPath> effectPath;
    748 
    749     if (prePathMatrix) {
    750         SkPath* result = pathPtr;
    751 
    752         if (!pathIsMutable) {
    753             result = tmpPath.init();
    754             pathIsMutable = true;
    755         }
    756         // should I push prePathMatrix on our MV stack temporarily, instead
    757         // of applying it here? See SkDraw.cpp
    758         pathPtr->transform(*prePathMatrix, result);
    759         pathPtr = result;
    760     }
    761     // at this point we're done with prePathMatrix
    762     SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
    763 
    764     GrStrokeInfo strokeInfo(paint);
    765     SkPathEffect* pathEffect = paint.getPathEffect();
    766     const SkRect* cullRect = NULL;  // TODO: what is our bounds?
    767     SkStrokeRec* strokePtr = strokeInfo.getStrokeRecPtr();
    768     if (pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr, strokePtr,
    769                                              cullRect)) {
    770         pathPtr = effectPath.get();
    771         pathIsMutable = true;
    772         strokeInfo.removeDash();
    773     }
    774 
    775     const SkStrokeRec& stroke = strokeInfo.getStrokeRec();
    776     if (paint.getMaskFilter()) {
    777         if (!stroke.isHairlineStyle()) {
    778             SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
    779             if (stroke.applyToPath(strokedPath, *pathPtr)) {
    780                 pathPtr = strokedPath;
    781                 pathIsMutable = true;
    782                 strokeInfo.setFillStyle();
    783             }
    784         }
    785 
    786         // avoid possibly allocating a new path in transform if we can
    787         SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init();
    788 
    789         // transform the path into device space
    790         pathPtr->transform(fContext->getMatrix(), devPathPtr);
    791 
    792         SkRect maskRect;
    793         if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(),
    794                                                     draw.fClip->getBounds(),
    795                                                     fContext->getMatrix(),
    796                                                     &maskRect)) {
    797             // The context's matrix may change while creating the mask, so save the CTM here to
    798             // pass to filterMaskGPU.
    799             const SkMatrix ctm = fContext->getMatrix();
    800 
    801             SkIRect finalIRect;
    802             maskRect.roundOut(&finalIRect);
    803             if (draw.fClip->quickReject(finalIRect)) {
    804                 // clipped out
    805                 return;
    806             }
    807 
    808             if (paint.getMaskFilter()->directFilterMaskGPU(fContext, &grPaint,
    809                                                            stroke, *devPathPtr)) {
    810                 // the mask filter was able to draw itself directly, so there's nothing
    811                 // left to do.
    812                 return;
    813             }
    814 
    815             GrAutoScratchTexture mask;
    816 
    817             if (create_mask_GPU(fContext, maskRect, *devPathPtr, strokeInfo,
    818                                 grPaint.isAntiAlias(), &mask)) {
    819                 GrTexture* filtered;
    820 
    821                 if (paint.getMaskFilter()->filterMaskGPU(mask.texture(),
    822                                                          ctm, maskRect, &filtered, true)) {
    823                     // filterMaskGPU gives us ownership of a ref to the result
    824                     SkAutoTUnref<GrTexture> atu(filtered);
    825 
    826                     // If the scratch texture that we used as the filter src also holds the filter
    827                     // result then we must detach so that this texture isn't recycled for a later
    828                     // draw.
    829                     if (filtered == mask.texture()) {
    830                         mask.detach();
    831                         filtered->unref(); // detach transfers GrAutoScratchTexture's ref to us.
    832                     }
    833 
    834                     if (draw_mask(fContext, maskRect, &grPaint, filtered)) {
    835                         // This path is completely drawn
    836                         return;
    837                     }
    838                 }
    839             }
    840         }
    841 
    842         // draw the mask on the CPU - this is a fallthrough path in case the
    843         // GPU path fails
    844         SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_Style :
    845                                                           SkPaint::kFill_Style;
    846         draw_with_mask_filter(fContext, *devPathPtr, paint.getMaskFilter(),
    847                               *draw.fClip, &grPaint, style);
    848         return;
    849     }
    850 
    851     fContext->drawPath(grPaint, *pathPtr, strokeInfo);
    852 }
    853 
    854 static const int kBmpSmallTileSize = 1 << 10;
    855 
    856 static inline int get_tile_count(const SkIRect& srcRect, int tileSize)  {
    857     int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
    858     int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
    859     return tilesX * tilesY;
    860 }
    861 
    862 static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int maxTileSize) {
    863     if (maxTileSize <= kBmpSmallTileSize) {
    864         return maxTileSize;
    865     }
    866 
    867     size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
    868     size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
    869 
    870     maxTileTotalTileSize *= maxTileSize * maxTileSize;
    871     smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
    872 
    873     if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
    874         return kBmpSmallTileSize;
    875     } else {
    876         return maxTileSize;
    877     }
    878 }
    879 
    880 // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
    881 // pixels from the bitmap are necessary.
    882 static void determine_clipped_src_rect(const GrContext* context,
    883                                        const SkBitmap& bitmap,
    884                                        const SkRect* srcRectPtr,
    885                                        SkIRect* clippedSrcIRect) {
    886     const GrClipData* clip = context->getClip();
    887     clip->getConservativeBounds(context->getRenderTarget(), clippedSrcIRect, NULL);
    888     SkMatrix inv;
    889     if (!context->getMatrix().invert(&inv)) {
    890         clippedSrcIRect->setEmpty();
    891         return;
    892     }
    893     SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect);
    894     inv.mapRect(&clippedSrcRect);
    895     if (NULL != srcRectPtr) {
    896         // we've setup src space 0,0 to map to the top left of the src rect.
    897         clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop);
    898         if (!clippedSrcRect.intersect(*srcRectPtr)) {
    899             clippedSrcIRect->setEmpty();
    900             return;
    901         }
    902     }
    903     clippedSrcRect.roundOut(clippedSrcIRect);
    904     SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
    905     if (!clippedSrcIRect->intersect(bmpBounds)) {
    906         clippedSrcIRect->setEmpty();
    907     }
    908 }
    909 
    910 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
    911                                    const GrTextureParams& params,
    912                                    const SkRect* srcRectPtr,
    913                                    int maxTileSize,
    914                                    int* tileSize,
    915                                    SkIRect* clippedSrcRect) const {
    916     // if bitmap is explictly texture backed then just use the texture
    917     if (NULL != bitmap.getTexture()) {
    918         return false;
    919     }
    920 
    921     // if it's larger than the max tile size, then we have no choice but tiling.
    922     if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) {
    923         determine_clipped_src_rect(fContext, bitmap, srcRectPtr, clippedSrcRect);
    924         *tileSize = determine_tile_size(bitmap, *clippedSrcRect, maxTileSize);
    925         return true;
    926     }
    927 
    928     if (bitmap.width() * bitmap.height() < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
    929         return false;
    930     }
    931 
    932     // if the entire texture is already in our cache then no reason to tile it
    933     if (GrIsBitmapInCache(fContext, bitmap, &params)) {
    934         return false;
    935     }
    936 
    937     // At this point we know we could do the draw by uploading the entire bitmap
    938     // as a texture. However, if the texture would be large compared to the
    939     // cache size and we don't require most of it for this draw then tile to
    940     // reduce the amount of upload and cache spill.
    941 
    942     // assumption here is that sw bitmap size is a good proxy for its size as
    943     // a texture
    944     size_t bmpSize = bitmap.getSize();
    945     size_t cacheSize;
    946     fContext->getResourceCacheLimits(NULL, &cacheSize);
    947     if (bmpSize < cacheSize / 2) {
    948         return false;
    949     }
    950 
    951     // Figure out how much of the src we will need based on the src rect and clipping.
    952     determine_clipped_src_rect(fContext, bitmap, srcRectPtr, clippedSrcRect);
    953     *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
    954     size_t usedTileBytes = get_tile_count(*clippedSrcRect, kBmpSmallTileSize) *
    955                            kBmpSmallTileSize * kBmpSmallTileSize;
    956 
    957     return usedTileBytes < 2 * bmpSize;
    958 }
    959 
    960 void SkGpuDevice::drawBitmap(const SkDraw& origDraw,
    961                              const SkBitmap& bitmap,
    962                              const SkMatrix& m,
    963                              const SkPaint& paint) {
    964     SkMatrix concat;
    965     SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
    966     if (!m.isIdentity()) {
    967         concat.setConcat(*draw->fMatrix, m);
    968         draw.writable()->fMatrix = &concat;
    969     }
    970     this->drawBitmapCommon(*draw, bitmap, NULL, NULL, paint, SkCanvas::kNone_DrawBitmapRectFlag);
    971 }
    972 
    973 // This method outsets 'iRect' by 'outset' all around and then clamps its extents to
    974 // 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
    975 // of 'iRect' for all possible outsets/clamps.
    976 static inline void clamped_outset_with_offset(SkIRect* iRect,
    977                                               int outset,
    978                                               SkPoint* offset,
    979                                               const SkIRect& clamp) {
    980     iRect->outset(outset, outset);
    981 
    982     int leftClampDelta = clamp.fLeft - iRect->fLeft;
    983     if (leftClampDelta > 0) {
    984         offset->fX -= outset - leftClampDelta;
    985         iRect->fLeft = clamp.fLeft;
    986     } else {
    987         offset->fX -= outset;
    988     }
    989 
    990     int topClampDelta = clamp.fTop - iRect->fTop;
    991     if (topClampDelta > 0) {
    992         offset->fY -= outset - topClampDelta;
    993         iRect->fTop = clamp.fTop;
    994     } else {
    995         offset->fY -= outset;
    996     }
    997 
    998     if (iRect->fRight > clamp.fRight) {
    999         iRect->fRight = clamp.fRight;
   1000     }
   1001     if (iRect->fBottom > clamp.fBottom) {
   1002         iRect->fBottom = clamp.fBottom;
   1003     }
   1004 }
   1005 
   1006 static bool has_aligned_samples(const SkRect& srcRect,
   1007                                 const SkRect& transformedRect) {
   1008     // detect pixel disalignment
   1009     if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) -
   1010             transformedRect.left()) < COLOR_BLEED_TOLERANCE &&
   1011         SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) -
   1012             transformedRect.top()) < COLOR_BLEED_TOLERANCE &&
   1013         SkScalarAbs(transformedRect.width() - srcRect.width()) <
   1014             COLOR_BLEED_TOLERANCE &&
   1015         SkScalarAbs(transformedRect.height() - srcRect.height()) <
   1016             COLOR_BLEED_TOLERANCE) {
   1017         return true;
   1018     }
   1019     return false;
   1020 }
   1021 
   1022 static bool may_color_bleed(const SkRect& srcRect,
   1023                             const SkRect& transformedRect,
   1024                             const SkMatrix& m) {
   1025     // Only gets called if has_aligned_samples returned false.
   1026     // So we can assume that sampling is axis aligned but not texel aligned.
   1027     SkASSERT(!has_aligned_samples(srcRect, transformedRect));
   1028     SkRect innerSrcRect(srcRect), innerTransformedRect,
   1029         outerTransformedRect(transformedRect);
   1030     innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
   1031     m.mapRect(&innerTransformedRect, innerSrcRect);
   1032 
   1033     // The gap between outerTransformedRect and innerTransformedRect
   1034     // represents the projection of the source border area, which is
   1035     // problematic for color bleeding.  We must check whether any
   1036     // destination pixels sample the border area.
   1037     outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
   1038     innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
   1039     SkIRect outer, inner;
   1040     outerTransformedRect.round(&outer);
   1041     innerTransformedRect.round(&inner);
   1042     // If the inner and outer rects round to the same result, it means the
   1043     // border does not overlap any pixel centers. Yay!
   1044     return inner != outer;
   1045 }
   1046 
   1047 static bool needs_texture_domain(const SkBitmap& bitmap,
   1048                                  const SkRect& srcRect,
   1049                                  GrTextureParams &params,
   1050                                  const SkMatrix& contextMatrix,
   1051                                  bool bicubic) {
   1052     bool needsTextureDomain = false;
   1053 
   1054     if (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode) {
   1055         // Need texture domain if drawing a sub rect
   1056         needsTextureDomain = srcRect.width() < bitmap.width() ||
   1057                              srcRect.height() < bitmap.height();
   1058         if (!bicubic && needsTextureDomain && contextMatrix.rectStaysRect()) {
   1059             // sampling is axis-aligned
   1060             SkRect transformedRect;
   1061             contextMatrix.mapRect(&transformedRect, srcRect);
   1062 
   1063             if (has_aligned_samples(srcRect, transformedRect)) {
   1064                 params.setFilterMode(GrTextureParams::kNone_FilterMode);
   1065                 needsTextureDomain = false;
   1066             } else {
   1067                 needsTextureDomain = may_color_bleed(srcRect, transformedRect, contextMatrix);
   1068             }
   1069         }
   1070     }
   1071     return needsTextureDomain;
   1072 }
   1073 
   1074 void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
   1075                                    const SkBitmap& bitmap,
   1076                                    const SkRect* srcRectPtr,
   1077                                    const SkSize* dstSizePtr,
   1078                                    const SkPaint& paint,
   1079                                    SkCanvas::DrawBitmapRectFlags flags) {
   1080     CHECK_SHOULD_DRAW(draw, false);
   1081 
   1082     SkRect srcRect;
   1083     SkSize dstSize;
   1084     // If there is no src rect, or the src rect contains the entire bitmap then we're effectively
   1085     // in the (easier) bleed case, so update flags.
   1086     if (NULL == srcRectPtr) {
   1087         SkScalar w = SkIntToScalar(bitmap.width());
   1088         SkScalar h = SkIntToScalar(bitmap.height());
   1089         dstSize.fWidth = w;
   1090         dstSize.fHeight = h;
   1091         srcRect.set(0, 0, w, h);
   1092         flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
   1093     } else {
   1094         SkASSERT(NULL != dstSizePtr);
   1095         srcRect = *srcRectPtr;
   1096         dstSize = *dstSizePtr;
   1097         if (srcRect.fLeft <= 0 && srcRect.fTop <= 0 &&
   1098             srcRect.fRight >= bitmap.width() && srcRect.fBottom >= bitmap.height()) {
   1099             flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
   1100         }
   1101     }
   1102 
   1103     if (paint.getMaskFilter()){
   1104         // Convert the bitmap to a shader so that the rect can be drawn
   1105         // through drawRect, which supports mask filters.
   1106         SkBitmap        tmp;    // subset of bitmap, if necessary
   1107         const SkBitmap* bitmapPtr = &bitmap;
   1108         SkMatrix localM;
   1109         if (NULL != srcRectPtr) {
   1110             localM.setTranslate(-srcRectPtr->fLeft, -srcRectPtr->fTop);
   1111             localM.postScale(dstSize.fWidth / srcRectPtr->width(),
   1112                              dstSize.fHeight / srcRectPtr->height());
   1113             // In bleed mode we position and trim the bitmap based on the src rect which is
   1114             // already accounted for in 'm' and 'srcRect'. In clamp mode we need to chop out
   1115             // the desired portion of the bitmap and then update 'm' and 'srcRect' to
   1116             // compensate.
   1117             if (!(SkCanvas::kBleed_DrawBitmapRectFlag & flags)) {
   1118                 SkIRect iSrc;
   1119                 srcRect.roundOut(&iSrc);
   1120 
   1121                 SkPoint offset = SkPoint::Make(SkIntToScalar(iSrc.fLeft),
   1122                                                SkIntToScalar(iSrc.fTop));
   1123 
   1124                 if (!bitmap.extractSubset(&tmp, iSrc)) {
   1125                     return;     // extraction failed
   1126                 }
   1127                 bitmapPtr = &tmp;
   1128                 srcRect.offset(-offset.fX, -offset.fY);
   1129 
   1130                 // The source rect has changed so update the matrix
   1131                 localM.preTranslate(offset.fX, offset.fY);
   1132             }
   1133         } else {
   1134             localM.reset();
   1135         }
   1136 
   1137         SkPaint paintWithShader(paint);
   1138         paintWithShader.setShader(SkShader::CreateBitmapShader(*bitmapPtr,
   1139             SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &localM))->unref();
   1140         SkRect dstRect = {0, 0, dstSize.fWidth, dstSize.fHeight};
   1141         this->drawRect(draw, dstRect, paintWithShader);
   1142 
   1143         return;
   1144     }
   1145 
   1146     // If there is no mask filter than it is OK to handle the src rect -> dst rect scaling using
   1147     // the view matrix rather than a local matrix.
   1148     SkMatrix m;
   1149     m.setScale(dstSize.fWidth / srcRect.width(),
   1150                dstSize.fHeight / srcRect.height());
   1151     fContext->concatMatrix(m);
   1152 
   1153     GrTextureParams params;
   1154     SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
   1155     GrTextureParams::FilterMode textureFilterMode;
   1156 
   1157     bool doBicubic = false;
   1158 
   1159     switch(paintFilterLevel) {
   1160         case SkPaint::kNone_FilterLevel:
   1161             textureFilterMode = GrTextureParams::kNone_FilterMode;
   1162             break;
   1163         case SkPaint::kLow_FilterLevel:
   1164             textureFilterMode = GrTextureParams::kBilerp_FilterMode;
   1165             break;
   1166         case SkPaint::kMedium_FilterLevel:
   1167             if (fContext->getMatrix().getMinScale() < SK_Scalar1) {
   1168                 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
   1169             } else {
   1170                 // Don't trigger MIP level generation unnecessarily.
   1171                 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
   1172             }
   1173             break;
   1174         case SkPaint::kHigh_FilterLevel:
   1175             // Minification can look bad with the bicubic effect.
   1176             doBicubic =
   1177                 GrBicubicEffect::ShouldUseBicubic(fContext->getMatrix(), &textureFilterMode);
   1178             break;
   1179         default:
   1180             SkErrorInternals::SetError( kInvalidPaint_SkError,
   1181                                         "Sorry, I don't understand the filtering "
   1182                                         "mode you asked for.  Falling back to "
   1183                                         "MIPMaps.");
   1184             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
   1185             break;
   1186     }
   1187 
   1188     int tileFilterPad;
   1189     if (doBicubic) {
   1190         tileFilterPad = GrBicubicEffect::kFilterTexelPad;
   1191     } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
   1192         tileFilterPad = 0;
   1193     } else {
   1194         tileFilterPad = 1;
   1195     }
   1196     params.setFilterMode(textureFilterMode);
   1197 
   1198     int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad;
   1199     int tileSize;
   1200 
   1201     SkIRect clippedSrcRect;
   1202     if (this->shouldTileBitmap(bitmap, params, srcRectPtr, maxTileSize, &tileSize,
   1203                                &clippedSrcRect)) {
   1204         this->drawTiledBitmap(bitmap, srcRect, clippedSrcRect, params, paint, flags, tileSize,
   1205                               doBicubic);
   1206     } else {
   1207         // take the simple case
   1208         bool needsTextureDomain = needs_texture_domain(bitmap,
   1209                                                        srcRect,
   1210                                                        params,
   1211                                                        fContext->getMatrix(),
   1212                                                        doBicubic);
   1213         this->internalDrawBitmap(bitmap,
   1214                                  srcRect,
   1215                                  params,
   1216                                  paint,
   1217                                  flags,
   1218                                  doBicubic,
   1219                                  needsTextureDomain);
   1220     }
   1221 }
   1222 
   1223 // Break 'bitmap' into several tiles to draw it since it has already
   1224 // been determined to be too large to fit in VRAM
   1225 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
   1226                                   const SkRect& srcRect,
   1227                                   const SkIRect& clippedSrcIRect,
   1228                                   const GrTextureParams& params,
   1229                                   const SkPaint& paint,
   1230                                   SkCanvas::DrawBitmapRectFlags flags,
   1231                                   int tileSize,
   1232                                   bool bicubic) {
   1233     // The following pixel lock is technically redundant, but it is desirable
   1234     // to lock outside of the tile loop to prevent redecoding the whole image
   1235     // at each tile in cases where 'bitmap' holds an SkDiscardablePixelRef that
   1236     // is larger than the limit of the discardable memory pool.
   1237     SkAutoLockPixels alp(bitmap);
   1238     SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
   1239 
   1240     int nx = bitmap.width() / tileSize;
   1241     int ny = bitmap.height() / tileSize;
   1242     for (int x = 0; x <= nx; x++) {
   1243         for (int y = 0; y <= ny; y++) {
   1244             SkRect tileR;
   1245             tileR.set(SkIntToScalar(x * tileSize),
   1246                       SkIntToScalar(y * tileSize),
   1247                       SkIntToScalar((x + 1) * tileSize),
   1248                       SkIntToScalar((y + 1) * tileSize));
   1249 
   1250             if (!SkRect::Intersects(tileR, clippedSrcRect)) {
   1251                 continue;
   1252             }
   1253 
   1254             if (!tileR.intersect(srcRect)) {
   1255                 continue;
   1256             }
   1257 
   1258             SkBitmap tmpB;
   1259             SkIRect iTileR;
   1260             tileR.roundOut(&iTileR);
   1261             SkPoint offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
   1262                                            SkIntToScalar(iTileR.fTop));
   1263 
   1264             // Adjust the context matrix to draw at the right x,y in device space
   1265             SkMatrix tmpM;
   1266             GrContext::AutoMatrix am;
   1267             tmpM.setTranslate(offset.fX - srcRect.fLeft, offset.fY - srcRect.fTop);
   1268             am.setPreConcat(fContext, tmpM);
   1269 
   1270             if (SkPaint::kNone_FilterLevel != paint.getFilterLevel() || bicubic) {
   1271                 SkIRect iClampRect;
   1272 
   1273                 if (SkCanvas::kBleed_DrawBitmapRectFlag & flags) {
   1274                     // In bleed mode we want to always expand the tile on all edges
   1275                     // but stay within the bitmap bounds
   1276                     iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
   1277                 } else {
   1278                     // In texture-domain/clamp mode we only want to expand the
   1279                     // tile on edges interior to "srcRect" (i.e., we want to
   1280                     // not bleed across the original clamped edges)
   1281                     srcRect.roundOut(&iClampRect);
   1282                 }
   1283                 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
   1284                 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
   1285             }
   1286 
   1287             if (bitmap.extractSubset(&tmpB, iTileR)) {
   1288                 // now offset it to make it "local" to our tmp bitmap
   1289                 tileR.offset(-offset.fX, -offset.fY);
   1290                 GrTextureParams paramsTemp = params;
   1291                 bool needsTextureDomain = needs_texture_domain(bitmap,
   1292                                                                srcRect,
   1293                                                                paramsTemp,
   1294                                                                fContext->getMatrix(),
   1295                                                                bicubic);
   1296                 this->internalDrawBitmap(tmpB,
   1297                                          tileR,
   1298                                          paramsTemp,
   1299                                          paint,
   1300                                          flags,
   1301                                          bicubic,
   1302                                          needsTextureDomain);
   1303             }
   1304         }
   1305     }
   1306 }
   1307 
   1308 
   1309 /*
   1310  *  This is called by drawBitmap(), which has to handle images that may be too
   1311  *  large to be represented by a single texture.
   1312  *
   1313  *  internalDrawBitmap assumes that the specified bitmap will fit in a texture
   1314  *  and that non-texture portion of the GrPaint has already been setup.
   1315  */
   1316 void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
   1317                                      const SkRect& srcRect,
   1318                                      const GrTextureParams& params,
   1319                                      const SkPaint& paint,
   1320                                      SkCanvas::DrawBitmapRectFlags flags,
   1321                                      bool bicubic,
   1322                                      bool needsTextureDomain) {
   1323     SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
   1324              bitmap.height() <= fContext->getMaxTextureSize());
   1325 
   1326     GrTexture* texture;
   1327     SkAutoCachedTexture act(this, bitmap, &params, &texture);
   1328     if (NULL == texture) {
   1329         return;
   1330     }
   1331 
   1332     SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() };
   1333     SkRect paintRect;
   1334     SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width()));
   1335     SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height()));
   1336     paintRect.setLTRB(SkScalarMul(srcRect.fLeft,   wInv),
   1337                       SkScalarMul(srcRect.fTop,    hInv),
   1338                       SkScalarMul(srcRect.fRight,  wInv),
   1339                       SkScalarMul(srcRect.fBottom, hInv));
   1340 
   1341     SkRect textureDomain = SkRect::MakeEmpty();
   1342     SkAutoTUnref<GrEffectRef> effect;
   1343     if (needsTextureDomain && !(flags & SkCanvas::kBleed_DrawBitmapRectFlag)) {
   1344         // Use a constrained texture domain to avoid color bleeding
   1345         SkScalar left, top, right, bottom;
   1346         if (srcRect.width() > SK_Scalar1) {
   1347             SkScalar border = SK_ScalarHalf / texture->width();
   1348             left = paintRect.left() + border;
   1349             right = paintRect.right() - border;
   1350         } else {
   1351             left = right = SkScalarHalf(paintRect.left() + paintRect.right());
   1352         }
   1353         if (srcRect.height() > SK_Scalar1) {
   1354             SkScalar border = SK_ScalarHalf / texture->height();
   1355             top = paintRect.top() + border;
   1356             bottom = paintRect.bottom() - border;
   1357         } else {
   1358             top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom());
   1359         }
   1360         textureDomain.setLTRB(left, top, right, bottom);
   1361         if (bicubic) {
   1362             effect.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), textureDomain));
   1363         } else {
   1364             effect.reset(GrTextureDomainEffect::Create(texture,
   1365                                                        SkMatrix::I(),
   1366                                                        textureDomain,
   1367                                                        GrTextureDomain::kClamp_Mode,
   1368                                                        params.filterMode()));
   1369         }
   1370     } else if (bicubic) {
   1371         SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode());
   1372         SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
   1373         effect.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), tileModes));
   1374     } else {
   1375         effect.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params));
   1376     }
   1377 
   1378     // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
   1379     // the rest from the SkPaint.
   1380     GrPaint grPaint;
   1381     grPaint.addColorEffect(effect);
   1382     bool alphaOnly = !(kAlpha_8_SkColorType == bitmap.colorType());
   1383     GrColor grColor = (alphaOnly) ? SkColor2GrColorJustAlpha(paint.getColor()) :
   1384                                     SkColor2GrColor(paint.getColor());
   1385     SkPaint2GrPaintNoShader(this->context(), paint, grColor, false, &grPaint);
   1386 
   1387     fContext->drawRectToRect(grPaint, dstRect, paintRect, NULL);
   1388 }
   1389 
   1390 static bool filter_texture(SkBaseDevice* device, GrContext* context,
   1391                            GrTexture* texture, const SkImageFilter* filter,
   1392                            int w, int h, const SkImageFilter::Context& ctx,
   1393                            SkBitmap* result, SkIPoint* offset) {
   1394     SkASSERT(filter);
   1395     SkDeviceImageFilterProxy proxy(device);
   1396 
   1397     if (filter->canFilterImageGPU()) {
   1398         // Save the render target and set it to NULL, so we don't accidentally draw to it in the
   1399         // filter.  Also set the clip wide open and the matrix to identity.
   1400         GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
   1401         return filter->filterImageGPU(&proxy, wrap_texture(texture), ctx, result, offset);
   1402     } else {
   1403         return false;
   1404     }
   1405 }
   1406 
   1407 void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
   1408                              int left, int top, const SkPaint& paint) {
   1409     // drawSprite is defined to be in device coords.
   1410     CHECK_SHOULD_DRAW(draw, true);
   1411 
   1412     SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
   1413     if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
   1414         return;
   1415     }
   1416 
   1417     int w = bitmap.width();
   1418     int h = bitmap.height();
   1419 
   1420     GrTexture* texture;
   1421     // draw sprite uses the default texture params
   1422     SkAutoCachedTexture act(this, bitmap, NULL, &texture);
   1423 
   1424     SkImageFilter* filter = paint.getImageFilter();
   1425     // This bitmap will own the filtered result as a texture.
   1426     SkBitmap filteredBitmap;
   1427 
   1428     if (NULL != filter) {
   1429         SkIPoint offset = SkIPoint::Make(0, 0);
   1430         SkMatrix matrix(*draw.fMatrix);
   1431         matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
   1432         SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
   1433         SkImageFilter::Cache* cache = SkImageFilter::Cache::Create();
   1434         SkAutoUnref aur(cache);
   1435         SkImageFilter::Context ctx(matrix, clipBounds, cache);
   1436         if (filter_texture(this, fContext, texture, filter, w, h, ctx, &filteredBitmap,
   1437                            &offset)) {
   1438             texture = (GrTexture*) filteredBitmap.getTexture();
   1439             w = filteredBitmap.width();
   1440             h = filteredBitmap.height();
   1441             left += offset.x();
   1442             top += offset.y();
   1443         } else {
   1444             return;
   1445         }
   1446     }
   1447 
   1448     GrPaint grPaint;
   1449     grPaint.addColorTextureEffect(texture, SkMatrix::I());
   1450 
   1451     SkPaint2GrPaintNoShader(this->context(), paint, SkColor2GrColorJustAlpha(paint.getColor()),
   1452                             false, &grPaint);
   1453 
   1454     fContext->drawRectToRect(grPaint,
   1455                              SkRect::MakeXYWH(SkIntToScalar(left),
   1456                                               SkIntToScalar(top),
   1457                                               SkIntToScalar(w),
   1458                                               SkIntToScalar(h)),
   1459                              SkRect::MakeXYWH(0,
   1460                                               0,
   1461                                               SK_Scalar1 * w / texture->width(),
   1462                                               SK_Scalar1 * h / texture->height()));
   1463 }
   1464 
   1465 void SkGpuDevice::drawBitmapRect(const SkDraw& origDraw, const SkBitmap& bitmap,
   1466                                  const SkRect* src, const SkRect& dst,
   1467                                  const SkPaint& paint,
   1468                                  SkCanvas::DrawBitmapRectFlags flags) {
   1469     SkMatrix    matrix;
   1470     SkRect      bitmapBounds, tmpSrc;
   1471 
   1472     bitmapBounds.set(0, 0,
   1473                      SkIntToScalar(bitmap.width()),
   1474                      SkIntToScalar(bitmap.height()));
   1475 
   1476     // Compute matrix from the two rectangles
   1477     if (NULL != src) {
   1478         tmpSrc = *src;
   1479     } else {
   1480         tmpSrc = bitmapBounds;
   1481     }
   1482 
   1483     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
   1484 
   1485     // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null.
   1486     if (NULL != src) {
   1487         if (!bitmapBounds.contains(tmpSrc)) {
   1488             if (!tmpSrc.intersect(bitmapBounds)) {
   1489                 return; // nothing to draw
   1490             }
   1491         }
   1492     }
   1493 
   1494     SkRect tmpDst;
   1495     matrix.mapRect(&tmpDst, tmpSrc);
   1496 
   1497     SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
   1498     if (0 != tmpDst.fLeft || 0 != tmpDst.fTop) {
   1499         // Translate so that tempDst's top left is at the origin.
   1500         matrix = *origDraw.fMatrix;
   1501         matrix.preTranslate(tmpDst.fLeft, tmpDst.fTop);
   1502         draw.writable()->fMatrix = &matrix;
   1503     }
   1504     SkSize dstSize;
   1505     dstSize.fWidth = tmpDst.width();
   1506     dstSize.fHeight = tmpDst.height();
   1507 
   1508     this->drawBitmapCommon(*draw, bitmap, &tmpSrc, &dstSize, paint, flags);
   1509 }
   1510 
   1511 void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
   1512                              int x, int y, const SkPaint& paint) {
   1513     // clear of the source device must occur before CHECK_SHOULD_DRAW
   1514     SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
   1515     if (dev->fNeedClear) {
   1516         // TODO: could check here whether we really need to draw at all
   1517         dev->clear(0x0);
   1518     }
   1519 
   1520     // drawDevice is defined to be in device coords.
   1521     CHECK_SHOULD_DRAW(draw, true);
   1522 
   1523     GrRenderTarget* devRT = dev->accessRenderTarget();
   1524     GrTexture* devTex;
   1525     if (NULL == (devTex = devRT->asTexture())) {
   1526         return;
   1527     }
   1528 
   1529     const SkBitmap& bm = dev->accessBitmap(false);
   1530     int w = bm.width();
   1531     int h = bm.height();
   1532 
   1533     SkImageFilter* filter = paint.getImageFilter();
   1534     // This bitmap will own the filtered result as a texture.
   1535     SkBitmap filteredBitmap;
   1536 
   1537     if (NULL != filter) {
   1538         SkIPoint offset = SkIPoint::Make(0, 0);
   1539         SkMatrix matrix(*draw.fMatrix);
   1540         matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
   1541         SkIRect clipBounds = SkIRect::MakeWH(devTex->width(), devTex->height());
   1542         SkImageFilter::Cache* cache = SkImageFilter::Cache::Create();
   1543         SkAutoUnref aur(cache);
   1544         SkImageFilter::Context ctx(matrix, clipBounds, cache);
   1545         if (filter_texture(this, fContext, devTex, filter, w, h, ctx, &filteredBitmap,
   1546                            &offset)) {
   1547             devTex = filteredBitmap.getTexture();
   1548             w = filteredBitmap.width();
   1549             h = filteredBitmap.height();
   1550             x += offset.fX;
   1551             y += offset.fY;
   1552         } else {
   1553             return;
   1554         }
   1555     }
   1556 
   1557     GrPaint grPaint;
   1558     grPaint.addColorTextureEffect(devTex, SkMatrix::I());
   1559 
   1560     SkPaint2GrPaintNoShader(this->context(), paint, SkColor2GrColorJustAlpha(paint.getColor()),
   1561                             false, &grPaint);
   1562 
   1563     SkRect dstRect = SkRect::MakeXYWH(SkIntToScalar(x),
   1564                                       SkIntToScalar(y),
   1565                                       SkIntToScalar(w),
   1566                                       SkIntToScalar(h));
   1567 
   1568     // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate
   1569     // scratch texture).
   1570     SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(),
   1571                                     SK_Scalar1 * h / devTex->height());
   1572 
   1573     fContext->drawRectToRect(grPaint, dstRect, srcRect);
   1574 }
   1575 
   1576 bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) {
   1577     return filter->canFilterImageGPU();
   1578 }
   1579 
   1580 bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
   1581                               const SkImageFilter::Context& ctx,
   1582                               SkBitmap* result, SkIPoint* offset) {
   1583     // want explicitly our impl, so guard against a subclass of us overriding it
   1584     if (!this->SkGpuDevice::canHandleImageFilter(filter)) {
   1585         return false;
   1586     }
   1587 
   1588     SkAutoLockPixels alp(src, !src.getTexture());
   1589     if (!src.getTexture() && !src.readyToDraw()) {
   1590         return false;
   1591     }
   1592 
   1593     GrTexture* texture;
   1594     // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup
   1595     // must be pushed upstack.
   1596     SkAutoCachedTexture act(this, src, NULL, &texture);
   1597 
   1598     return filter_texture(this, fContext, texture, filter, src.width(), src.height(), ctx,
   1599                           result, offset);
   1600 }
   1601 
   1602 ///////////////////////////////////////////////////////////////////////////////
   1603 
   1604 // must be in SkCanvas::VertexMode order
   1605 static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
   1606     kTriangles_GrPrimitiveType,
   1607     kTriangleStrip_GrPrimitiveType,
   1608     kTriangleFan_GrPrimitiveType,
   1609 };
   1610 
   1611 void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
   1612                               int vertexCount, const SkPoint vertices[],
   1613                               const SkPoint texs[], const SkColor colors[],
   1614                               SkXfermode* xmode,
   1615                               const uint16_t indices[], int indexCount,
   1616                               const SkPaint& paint) {
   1617     CHECK_SHOULD_DRAW(draw, false);
   1618 
   1619     // If both textures and vertex-colors are NULL, strokes hairlines with the paint's color.
   1620     if ((NULL == texs || NULL == paint.getShader()) && NULL == colors) {
   1621         texs = NULL;
   1622         SkPaint copy(paint);
   1623         copy.setStyle(SkPaint::kStroke_Style);
   1624         copy.setStrokeWidth(0);
   1625 
   1626         VertState       state(vertexCount, indices, indexCount);
   1627         VertState::Proc vertProc = state.chooseProc(vmode);
   1628 
   1629         SkPoint* pts = new SkPoint[vertexCount * 6];
   1630         int i = 0;
   1631         while (vertProc(&state)) {
   1632             pts[i] = vertices[state.f0];
   1633             pts[i + 1] = vertices[state.f1];
   1634             pts[i + 2] = vertices[state.f1];
   1635             pts[i + 3] = vertices[state.f2];
   1636             pts[i + 4] = vertices[state.f2];
   1637             pts[i + 5] = vertices[state.f0];
   1638             i += 6;
   1639         }
   1640         draw.drawPoints(SkCanvas::kLines_PointMode, i, pts, copy, true);
   1641         return;
   1642     }
   1643 
   1644     GrPaint grPaint;
   1645     // we ignore the shader if texs is null.
   1646     if (NULL == texs) {
   1647         SkPaint2GrPaintNoShader(this->context(), paint, SkColor2GrColor(paint.getColor()),
   1648                                 NULL == colors, &grPaint);
   1649     } else {
   1650         SkPaint2GrPaintShader(this->context(), paint, NULL == colors, &grPaint);
   1651     }
   1652 
   1653 #if 0
   1654     if (NULL != xmode && NULL != texs && NULL != colors) {
   1655         if (!SkXfermode::IsMode(xmode, SkXfermode::kModulate_Mode)) {
   1656             SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
   1657             return;
   1658         }
   1659     }
   1660 #endif
   1661 
   1662     SkAutoSTMalloc<128, GrColor> convertedColors(0);
   1663     if (NULL != colors) {
   1664         // need to convert byte order and from non-PM to PM
   1665         convertedColors.reset(vertexCount);
   1666         SkColor color;
   1667         for (int i = 0; i < vertexCount; ++i) {
   1668             color = colors[i];
   1669             if (paint.getAlpha() != 255) {
   1670                 color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paint.getAlpha()));
   1671             }
   1672             convertedColors[i] = SkColor2GrColor(color);
   1673         }
   1674         colors = convertedColors.get();
   1675     }
   1676     fContext->drawVertices(grPaint,
   1677                            gVertexMode2PrimitiveType[vmode],
   1678                            vertexCount,
   1679                            vertices,
   1680                            texs,
   1681                            colors,
   1682                            indices,
   1683                            indexCount);
   1684 }
   1685 
   1686 ///////////////////////////////////////////////////////////////////////////////
   1687 
   1688 void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
   1689                           size_t byteLength, SkScalar x, SkScalar y,
   1690                           const SkPaint& paint) {
   1691     CHECK_SHOULD_DRAW(draw, false);
   1692 
   1693     if (fMainTextContext->canDraw(paint)) {
   1694         GrPaint grPaint;
   1695         SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
   1696 
   1697         SkDEBUGCODE(this->validate();)
   1698 
   1699         fMainTextContext->drawText(grPaint, paint, (const char *)text, byteLength, x, y);
   1700     } else if (fFallbackTextContext && fFallbackTextContext->canDraw(paint)) {
   1701         GrPaint grPaint;
   1702         SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
   1703 
   1704         SkDEBUGCODE(this->validate();)
   1705 
   1706         fFallbackTextContext->drawText(grPaint, paint, (const char *)text, byteLength, x, y);
   1707     } else {
   1708         // this guy will just call our drawPath()
   1709         draw.drawText_asPaths((const char*)text, byteLength, x, y, paint);
   1710     }
   1711 }
   1712 
   1713 void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
   1714                              size_t byteLength, const SkScalar pos[],
   1715                              SkScalar constY, int scalarsPerPos,
   1716                              const SkPaint& paint) {
   1717     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPosText", fContext);
   1718     CHECK_SHOULD_DRAW(draw, false);
   1719 
   1720     if (fMainTextContext->canDraw(paint)) {
   1721         GrPaint grPaint;
   1722         SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
   1723 
   1724         SkDEBUGCODE(this->validate();)
   1725 
   1726         fMainTextContext->drawPosText(grPaint, paint, (const char *)text, byteLength, pos,
   1727                                       constY, scalarsPerPos);
   1728     } else if (fFallbackTextContext && fFallbackTextContext->canDraw(paint)) {
   1729         GrPaint grPaint;
   1730         SkPaint2GrPaintShader(this->context(), paint, true, &grPaint);
   1731 
   1732         SkDEBUGCODE(this->validate();)
   1733 
   1734         fFallbackTextContext->drawPosText(grPaint, paint, (const char *)text, byteLength, pos,
   1735                                           constY, scalarsPerPos);
   1736     } else {
   1737         draw.drawPosText_asPaths((const char*)text, byteLength, pos, constY,
   1738                                  scalarsPerPos, paint);
   1739     }
   1740 }
   1741 
   1742 void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
   1743                                 size_t len, const SkPath& path,
   1744                                 const SkMatrix* m, const SkPaint& paint) {
   1745     CHECK_SHOULD_DRAW(draw, false);
   1746 
   1747     SkASSERT(draw.fDevice == this);
   1748     draw.drawTextOnPath((const char*)text, len, path, m, paint);
   1749 }
   1750 
   1751 ///////////////////////////////////////////////////////////////////////////////
   1752 
   1753 bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
   1754     if (!paint.isLCDRenderText()) {
   1755         // we're cool with the paint as is
   1756         return false;
   1757     }
   1758 
   1759     if (paint.getShader() ||
   1760         paint.getXfermode() || // unless its srcover
   1761         paint.getMaskFilter() ||
   1762         paint.getRasterizer() ||
   1763         paint.getColorFilter() ||
   1764         paint.getPathEffect() ||
   1765         paint.isFakeBoldText() ||
   1766         paint.getStyle() != SkPaint::kFill_Style) {
   1767         // turn off lcd
   1768         flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
   1769         flags->fHinting = paint.getHinting();
   1770         return true;
   1771     }
   1772     // we're cool with the paint as is
   1773     return false;
   1774 }
   1775 
   1776 void SkGpuDevice::flush() {
   1777     DO_DEFERRED_CLEAR();
   1778     fContext->resolveRenderTarget(fRenderTarget);
   1779 }
   1780 
   1781 ///////////////////////////////////////////////////////////////////////////////
   1782 
   1783 SkBaseDevice* SkGpuDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
   1784     GrTextureDesc desc;
   1785     desc.fConfig = fRenderTarget->config();
   1786     desc.fFlags = kRenderTarget_GrTextureFlagBit;
   1787     desc.fWidth = info.width();
   1788     desc.fHeight = info.height();
   1789     desc.fSampleCnt = fRenderTarget->numSamples();
   1790 
   1791     SkAutoTUnref<GrTexture> texture;
   1792     // Skia's convention is to only clear a device if it is non-opaque.
   1793     unsigned flags = info.isOpaque() ? 0 : kNeedClear_Flag;
   1794 
   1795 #if CACHE_COMPATIBLE_DEVICE_TEXTURES
   1796     // layers are never draw in repeat modes, so we can request an approx
   1797     // match and ignore any padding.
   1798     flags |= kCached_Flag;
   1799     const GrContext::ScratchTexMatch match = (kSaveLayer_Usage == usage) ?
   1800                                                 GrContext::kApprox_ScratchTexMatch :
   1801                                                 GrContext::kExact_ScratchTexMatch;
   1802     texture.reset(fContext->lockAndRefScratchTexture(desc, match));
   1803 #else
   1804     texture.reset(fContext->createUncachedTexture(desc, NULL, 0));
   1805 #endif
   1806     if (NULL != texture.get()) {
   1807         return SkGpuDevice::Create(texture, flags);
   1808     } else {
   1809         GrPrintf("---- failed to create compatible device texture [%d %d]\n",
   1810                  info.width(), info.height());
   1811         return NULL;
   1812     }
   1813 }
   1814 
   1815 SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info) {
   1816     return SkSurface::NewRenderTarget(fContext, info, fRenderTarget->numSamples());
   1817 }
   1818 
   1819 void SkGpuDevice::EXPERIMENTAL_optimize(const SkPicture* picture) {
   1820     SkPicture::AccelData::Key key = GPUAccelData::ComputeAccelDataKey();
   1821 
   1822     const SkPicture::AccelData* existing = picture->EXPERIMENTAL_getAccelData(key);
   1823     if (NULL != existing) {
   1824         return;
   1825     }
   1826 
   1827     SkAutoTUnref<GPUAccelData> data(SkNEW_ARGS(GPUAccelData, (key)));
   1828 
   1829     picture->EXPERIMENTAL_addAccelData(data);
   1830 
   1831     GatherGPUInfo(picture, data);
   1832 }
   1833 
   1834 static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* result) {
   1835     SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
   1836     result->setInfo(info);
   1837     result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
   1838 }
   1839 
   1840 void SkGpuDevice::EXPERIMENTAL_purge(const SkPicture* picture) {
   1841 
   1842 }
   1843 
   1844 bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* canvas, const SkPicture* picture) {
   1845 
   1846     SkPicture::AccelData::Key key = GPUAccelData::ComputeAccelDataKey();
   1847 
   1848     const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key);
   1849     if (NULL == data) {
   1850         return false;
   1851     }
   1852 
   1853     const GPUAccelData *gpuData = static_cast<const GPUAccelData*>(data);
   1854 
   1855     if (0 == gpuData->numSaveLayers()) {
   1856         return false;
   1857     }
   1858 
   1859     SkAutoTArray<bool> pullForward(gpuData->numSaveLayers());
   1860     for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
   1861         pullForward[i] = false;
   1862     }
   1863 
   1864     SkRect clipBounds;
   1865     if (!canvas->getClipBounds(&clipBounds)) {
   1866         return true;
   1867     }
   1868     SkIRect query;
   1869     clipBounds.roundOut(&query);
   1870 
   1871     const SkPicture::OperationList& ops = picture->EXPERIMENTAL_getActiveOps(query);
   1872 
   1873     // This code pre-renders the entire layer since it will be cached and potentially
   1874     // reused with different clips (e.g., in different tiles). Because of this the
   1875     // clip will not be limiting the size of the pre-rendered layer. kSaveLayerMaxSize
   1876     // is used to limit which clips are pre-rendered.
   1877     static const int kSaveLayerMaxSize = 256;
   1878 
   1879     if (ops.valid()) {
   1880         // In this case the picture has been generated with a BBH so we use
   1881         // the BBH to limit the pre-rendering to just the layers needed to cover
   1882         // the region being drawn
   1883         for (int i = 0; i < ops.numOps(); ++i) {
   1884             uint32_t offset = ops.offset(i);
   1885 
   1886             // For now we're saving all the layers in the GPUAccelData so they
   1887             // can be nested. Additionally, the nested layers appear before
   1888             // their parent in the list.
   1889             for (int j = 0 ; j < gpuData->numSaveLayers(); ++j) {
   1890                 const GPUAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(j);
   1891 
   1892                 if (pullForward[j]) {
   1893                     continue;            // already pulling forward
   1894                 }
   1895 
   1896                 if (offset < info.fSaveLayerOpID || offset > info.fRestoreOpID) {
   1897                     continue;            // the op isn't in this range
   1898                 }
   1899 
   1900                 // TODO: once this code is more stable unsuitable layers can
   1901                 // just be omitted during the optimization stage
   1902                 if (!info.fValid ||
   1903                     kSaveLayerMaxSize < info.fSize.fWidth ||
   1904                     kSaveLayerMaxSize < info.fSize.fHeight ||
   1905                     info.fIsNested) {
   1906                     continue;            // this layer is unsuitable
   1907                 }
   1908 
   1909                 pullForward[j] = true;
   1910             }
   1911         }
   1912     } else {
   1913         // In this case there is no BBH associated with the picture. Pre-render
   1914         // all the layers that intersect the drawn region
   1915         for (int j = 0; j < gpuData->numSaveLayers(); ++j) {
   1916             const GPUAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(j);
   1917 
   1918             SkIRect layerRect = SkIRect::MakeXYWH(info.fOffset.fX,
   1919                                                   info.fOffset.fY,
   1920                                                   info.fSize.fWidth,
   1921                                                   info.fSize.fHeight);
   1922 
   1923             if (!SkIRect::Intersects(query, layerRect)) {
   1924                 continue;
   1925             }
   1926 
   1927             // TODO: once this code is more stable unsuitable layers can
   1928             // just be omitted during the optimization stage
   1929             if (!info.fValid ||
   1930                 kSaveLayerMaxSize < info.fSize.fWidth ||
   1931                 kSaveLayerMaxSize < info.fSize.fHeight ||
   1932                 info.fIsNested) {
   1933                 continue;
   1934             }
   1935 
   1936             pullForward[j] = true;
   1937         }
   1938     }
   1939 
   1940     SkPicturePlayback::PlaybackReplacements replacements;
   1941 
   1942     for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
   1943         if (pullForward[i]) {
   1944             GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture, i);
   1945 
   1946             const GPUAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
   1947 
   1948             if (NULL != picture->fPlayback) {
   1949                 SkPicturePlayback::PlaybackReplacements::ReplacementInfo* layerInfo =
   1950                                                                         replacements.push();
   1951                 layerInfo->fStart = info.fSaveLayerOpID;
   1952                 layerInfo->fStop = info.fRestoreOpID;
   1953                 layerInfo->fPos = info.fOffset;
   1954 
   1955                 GrTextureDesc desc;
   1956                 desc.fFlags = kRenderTarget_GrTextureFlagBit;
   1957                 desc.fWidth = info.fSize.fWidth;
   1958                 desc.fHeight = info.fSize.fHeight;
   1959                 desc.fConfig = kSkia8888_GrPixelConfig;
   1960                 // TODO: need to deal with sample count
   1961 
   1962                 bool bNeedsRendering = true;
   1963 
   1964                 // This just uses scratch textures and doesn't cache the texture.
   1965                 // This can yield a lot of re-rendering
   1966                 if (NULL == layer->getTexture()) {
   1967                     layer->setTexture(fContext->lockAndRefScratchTexture(desc,
   1968                                                         GrContext::kApprox_ScratchTexMatch));
   1969                     if (NULL == layer->getTexture()) {
   1970                         continue;
   1971                     }
   1972                 } else {
   1973                     bNeedsRendering = false;
   1974                 }
   1975 
   1976                 layerInfo->fBM = SkNEW(SkBitmap);
   1977                 wrap_texture(layer->getTexture(), desc.fWidth, desc.fHeight, layerInfo->fBM);
   1978 
   1979                 SkASSERT(info.fPaint);
   1980                 layerInfo->fPaint = info.fPaint;
   1981 
   1982                 if (bNeedsRendering) {
   1983                     SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
   1984                                                         layer->getTexture()->asRenderTarget()));
   1985 
   1986                     SkCanvas* canvas = surface->getCanvas();
   1987 
   1988                     canvas->setMatrix(info.fCTM);
   1989                     canvas->clear(SK_ColorTRANSPARENT);
   1990 
   1991                     picture->fPlayback->setDrawLimits(info.fSaveLayerOpID, info.fRestoreOpID);
   1992                     picture->fPlayback->draw(*canvas, NULL);
   1993                     picture->fPlayback->setDrawLimits(0, 0);
   1994                     canvas->flush();
   1995                 }
   1996             }
   1997         }
   1998     }
   1999 
   2000     // Playback using new layers
   2001     picture->fPlayback->setReplacements(&replacements);
   2002     picture->fPlayback->draw(*canvas, NULL);
   2003     picture->fPlayback->setReplacements(NULL);
   2004 
   2005     for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
   2006         GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture, i);
   2007 
   2008         if (NULL != layer->getTexture()) {
   2009             fContext->unlockScratchTexture(layer->getTexture());
   2010             layer->setTexture(NULL);
   2011         }
   2012     }
   2013 
   2014     return true;
   2015 }
   2016