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