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/GrTextureDomainEffect.h"
     11 #include "effects/GrSimpleTextureEffect.h"
     12 
     13 #include "GrContext.h"
     14 #include "GrTextContext.h"
     15 
     16 #include "SkGrTexturePixelRef.h"
     17 
     18 #include "SkColorFilter.h"
     19 #include "SkDeviceImageFilterProxy.h"
     20 #include "SkDrawProcs.h"
     21 #include "SkGlyphCache.h"
     22 #include "SkImageFilter.h"
     23 #include "SkPathEffect.h"
     24 #include "SkRRect.h"
     25 #include "SkStroke.h"
     26 #include "SkUtils.h"
     27 #include "SkErrorInternals.h"
     28 
     29 #define CACHE_COMPATIBLE_DEVICE_TEXTURES 1
     30 
     31 #if 0
     32     extern bool (*gShouldDrawProc)();
     33     #define CHECK_SHOULD_DRAW(draw, forceI)                     \
     34         do {                                                    \
     35             if (gShouldDrawProc && !gShouldDrawProc()) return;  \
     36             this->prepareDraw(draw, forceI);                    \
     37         } while (0)
     38 #else
     39     #define CHECK_SHOULD_DRAW(draw, forceI) this->prepareDraw(draw, forceI)
     40 #endif
     41 
     42 // This constant represents the screen alignment criterion in texels for
     43 // requiring texture domain clamping to prevent color bleeding when drawing
     44 // a sub region of a larger source image.
     45 #define COLOR_BLEED_TOLERANCE SkFloatToScalar(0.001f)
     46 
     47 #define DO_DEFERRED_CLEAR()             \
     48     do {                                \
     49         if (fNeedClear) {               \
     50             this->clear(SK_ColorTRANSPARENT); \
     51         }                               \
     52     } while (false)                     \
     53 
     54 ///////////////////////////////////////////////////////////////////////////////
     55 
     56 #define CHECK_FOR_NODRAW_ANNOTATION(paint) \
     57     do { if (paint.isNoDrawAnnotation()) { return; } } while (0)
     58 
     59 ///////////////////////////////////////////////////////////////////////////////
     60 
     61 
     62 class SkGpuDevice::SkAutoCachedTexture : public ::SkNoncopyable {
     63 public:
     64     SkAutoCachedTexture()
     65         : fDevice(NULL)
     66         , fTexture(NULL) {
     67     }
     68 
     69     SkAutoCachedTexture(SkGpuDevice* device,
     70                         const SkBitmap& bitmap,
     71                         const GrTextureParams* params,
     72                         GrTexture** texture)
     73         : fDevice(NULL)
     74         , fTexture(NULL) {
     75         GrAssert(NULL != texture);
     76         *texture = this->set(device, bitmap, params);
     77     }
     78 
     79     ~SkAutoCachedTexture() {
     80         if (NULL != fTexture) {
     81             GrUnlockAndUnrefCachedBitmapTexture(fTexture);
     82         }
     83     }
     84 
     85     GrTexture* set(SkGpuDevice* device,
     86                    const SkBitmap& bitmap,
     87                    const GrTextureParams* params) {
     88         if (NULL != fTexture) {
     89             GrUnlockAndUnrefCachedBitmapTexture(fTexture);
     90             fTexture = NULL;
     91         }
     92         fDevice = device;
     93         GrTexture* result = (GrTexture*)bitmap.getTexture();
     94         if (NULL == result) {
     95             // Cannot return the native texture so look it up in our cache
     96             fTexture = GrLockAndRefCachedBitmapTexture(device->context(), bitmap, params);
     97             result = fTexture;
     98         }
     99         return result;
    100     }
    101 
    102 private:
    103     SkGpuDevice* fDevice;
    104     GrTexture*   fTexture;
    105 };
    106 
    107 ///////////////////////////////////////////////////////////////////////////////
    108 
    109 struct GrSkDrawProcs : public SkDrawProcs {
    110 public:
    111     GrContext* fContext;
    112     GrTextContext* fTextContext;
    113     GrFontScaler* fFontScaler;  // cached in the skia glyphcache
    114 };
    115 
    116 ///////////////////////////////////////////////////////////////////////////////
    117 
    118 static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
    119     switch (config) {
    120         case kAlpha_8_GrPixelConfig:
    121             *isOpaque = false;
    122             return SkBitmap::kA8_Config;
    123         case kRGB_565_GrPixelConfig:
    124             *isOpaque = true;
    125             return SkBitmap::kRGB_565_Config;
    126         case kRGBA_4444_GrPixelConfig:
    127             *isOpaque = false;
    128             return SkBitmap::kARGB_4444_Config;
    129         case kSkia8888_GrPixelConfig:
    130             // we don't currently have a way of knowing whether
    131             // a 8888 is opaque based on the config.
    132             *isOpaque = false;
    133             return SkBitmap::kARGB_8888_Config;
    134         default:
    135             *isOpaque = false;
    136             return SkBitmap::kNo_Config;
    137     }
    138 }
    139 
    140 static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
    141     GrPixelConfig config = renderTarget->config();
    142 
    143     bool isOpaque;
    144     SkBitmap bitmap;
    145     bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
    146                      renderTarget->width(), renderTarget->height());
    147     bitmap.setIsOpaque(isOpaque);
    148     return bitmap;
    149 }
    150 
    151 SkGpuDevice* SkGpuDevice::Create(GrSurface* surface) {
    152     GrAssert(NULL != surface);
    153     if (NULL == surface->asRenderTarget() || NULL == surface->getContext()) {
    154         return NULL;
    155     }
    156     if (surface->asTexture()) {
    157         return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asTexture()));
    158     } else {
    159         return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asRenderTarget()));
    160     }
    161 }
    162 
    163 SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
    164 : SkDevice(make_bitmap(context, texture->asRenderTarget())) {
    165     this->initFromRenderTarget(context, texture->asRenderTarget(), false);
    166 }
    167 
    168 SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
    169 : SkDevice(make_bitmap(context, renderTarget)) {
    170     this->initFromRenderTarget(context, renderTarget, false);
    171 }
    172 
    173 void SkGpuDevice::initFromRenderTarget(GrContext* context,
    174                                        GrRenderTarget* renderTarget,
    175                                        bool cached) {
    176     fDrawProcs = NULL;
    177 
    178     fContext = context;
    179     fContext->ref();
    180 
    181     fRenderTarget = NULL;
    182     fNeedClear = false;
    183 
    184     GrAssert(NULL != renderTarget);
    185     fRenderTarget = renderTarget;
    186     fRenderTarget->ref();
    187 
    188     // Hold onto to the texture in the pixel ref (if there is one) because the texture holds a ref
    189     // on the RT but not vice-versa.
    190     // TODO: Remove this trickery once we figure out how to make SkGrPixelRef do this without
    191     // busting chrome (for a currently unknown reason).
    192     GrSurface* surface = fRenderTarget->asTexture();
    193     if (NULL == surface) {
    194         surface = fRenderTarget;
    195     }
    196     SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (surface, cached));
    197 
    198     this->setPixelRef(pr, 0)->unref();
    199 }
    200 
    201 SkGpuDevice::SkGpuDevice(GrContext* context,
    202                          SkBitmap::Config config,
    203                          int width,
    204                          int height,
    205                          int sampleCount)
    206     : SkDevice(config, width, height, false /*isOpaque*/) {
    207 
    208     fDrawProcs = NULL;
    209 
    210     fContext = context;
    211     fContext->ref();
    212 
    213     fRenderTarget = NULL;
    214     fNeedClear = false;
    215 
    216     if (config != SkBitmap::kRGB_565_Config) {
    217         config = SkBitmap::kARGB_8888_Config;
    218     }
    219 
    220     GrTextureDesc desc;
    221     desc.fFlags = kRenderTarget_GrTextureFlagBit;
    222     desc.fWidth = width;
    223     desc.fHeight = height;
    224     desc.fConfig = SkBitmapConfig2GrPixelConfig(config);
    225     desc.fSampleCnt = sampleCount;
    226 
    227     SkAutoTUnref<GrTexture> texture(fContext->createUncachedTexture(desc, NULL, 0));
    228 
    229     if (NULL != texture) {
    230         fRenderTarget = texture->asRenderTarget();
    231         fRenderTarget->ref();
    232 
    233         GrAssert(NULL != fRenderTarget);
    234 
    235         // wrap the bitmap with a pixelref to expose our texture
    236         SkGrPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (texture));
    237         this->setPixelRef(pr, 0)->unref();
    238     } else {
    239         GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
    240                  width, height);
    241         GrAssert(false);
    242     }
    243 }
    244 
    245 SkGpuDevice::~SkGpuDevice() {
    246     if (fDrawProcs) {
    247         delete fDrawProcs;
    248     }
    249 
    250     // The GrContext takes a ref on the target. We don't want to cause the render
    251     // target to be unnecessarily kept alive.
    252     if (fContext->getRenderTarget() == fRenderTarget) {
    253         fContext->setRenderTarget(NULL);
    254     }
    255 
    256     if (fContext->getClip() == &fClipData) {
    257         fContext->setClip(NULL);
    258     }
    259 
    260     SkSafeUnref(fRenderTarget);
    261     fContext->unref();
    262 }
    263 
    264 ///////////////////////////////////////////////////////////////////////////////
    265 
    266 void SkGpuDevice::makeRenderTargetCurrent() {
    267     DO_DEFERRED_CLEAR();
    268     fContext->setRenderTarget(fRenderTarget);
    269 }
    270 
    271 ///////////////////////////////////////////////////////////////////////////////
    272 
    273 namespace {
    274 GrPixelConfig config8888_to_grconfig_and_flags(SkCanvas::Config8888 config8888, uint32_t* flags) {
    275     switch (config8888) {
    276         case SkCanvas::kNative_Premul_Config8888:
    277             *flags = 0;
    278             return kSkia8888_GrPixelConfig;
    279         case SkCanvas::kNative_Unpremul_Config8888:
    280             *flags = GrContext::kUnpremul_PixelOpsFlag;
    281             return kSkia8888_GrPixelConfig;
    282         case SkCanvas::kBGRA_Premul_Config8888:
    283             *flags = 0;
    284             return kBGRA_8888_GrPixelConfig;
    285         case SkCanvas::kBGRA_Unpremul_Config8888:
    286             *flags = GrContext::kUnpremul_PixelOpsFlag;
    287             return kBGRA_8888_GrPixelConfig;
    288         case SkCanvas::kRGBA_Premul_Config8888:
    289             *flags = 0;
    290             return kRGBA_8888_GrPixelConfig;
    291         case SkCanvas::kRGBA_Unpremul_Config8888:
    292             *flags = GrContext::kUnpremul_PixelOpsFlag;
    293             return kRGBA_8888_GrPixelConfig;
    294         default:
    295             GrCrash("Unexpected Config8888.");
    296             *flags = 0; // suppress warning
    297             return kSkia8888_GrPixelConfig;
    298     }
    299 }
    300 }
    301 
    302 bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap,
    303                                int x, int y,
    304                                SkCanvas::Config8888 config8888) {
    305     DO_DEFERRED_CLEAR();
    306     SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
    307     SkASSERT(!bitmap.isNull());
    308     SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
    309 
    310     SkAutoLockPixels alp(bitmap);
    311     GrPixelConfig config;
    312     uint32_t flags;
    313     config = config8888_to_grconfig_and_flags(config8888, &flags);
    314     return fContext->readRenderTargetPixels(fRenderTarget,
    315                                             x, y,
    316                                             bitmap.width(),
    317                                             bitmap.height(),
    318                                             config,
    319                                             bitmap.getPixels(),
    320                                             bitmap.rowBytes(),
    321                                             flags);
    322 }
    323 
    324 void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
    325                               SkCanvas::Config8888 config8888) {
    326     SkAutoLockPixels alp(bitmap);
    327     if (!bitmap.readyToDraw()) {
    328         return;
    329     }
    330 
    331     GrPixelConfig config;
    332     uint32_t flags;
    333     if (SkBitmap::kARGB_8888_Config == bitmap.config()) {
    334         config = config8888_to_grconfig_and_flags(config8888, &flags);
    335     } else {
    336         flags = 0;
    337         config= SkBitmapConfig2GrPixelConfig(bitmap.config());
    338     }
    339 
    340     fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(),
    341                                config, bitmap.getPixels(), bitmap.rowBytes(), flags);
    342 }
    343 
    344 namespace {
    345 void purgeClipCB(int genID, void* ) {
    346 
    347     if (SkClipStack::kInvalidGenID == genID ||
    348         SkClipStack::kEmptyGenID == genID ||
    349         SkClipStack::kWideOpenGenID == genID) {
    350         // none of these cases will have a cached clip mask
    351         return;
    352     }
    353 
    354 }
    355 };
    356 
    357 void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
    358     INHERITED::onAttachToCanvas(canvas);
    359 
    360     // Canvas promises that this ptr is valid until onDetachFromCanvas is called
    361     fClipData.fClipStack = canvas->getClipStack();
    362 
    363     fClipData.fClipStack->addPurgeClipCallback(purgeClipCB, fContext);
    364 }
    365 
    366 void SkGpuDevice::onDetachFromCanvas() {
    367     INHERITED::onDetachFromCanvas();
    368 
    369     // TODO: iterate through the clip stack and clean up any cached clip masks
    370     fClipData.fClipStack->removePurgeClipCallback(purgeClipCB, fContext);
    371 
    372     fClipData.fClipStack = NULL;
    373 }
    374 
    375 #ifdef SK_DEBUG
    376 static void check_bounds(const GrClipData& clipData,
    377                          const SkRegion& clipRegion,
    378                          int renderTargetWidth,
    379                          int renderTargetHeight) {
    380 
    381     SkIRect devBound;
    382 
    383     devBound.setLTRB(0, 0, renderTargetWidth, renderTargetHeight);
    384 
    385     SkClipStack::BoundsType boundType;
    386     SkRect canvTemp;
    387 
    388     clipData.fClipStack->getBounds(&canvTemp, &boundType);
    389     if (SkClipStack::kNormal_BoundsType == boundType) {
    390         SkIRect devTemp;
    391 
    392         canvTemp.roundOut(&devTemp);
    393 
    394         devTemp.offset(-clipData.fOrigin.fX, -clipData.fOrigin.fY);
    395 
    396         if (!devBound.intersect(devTemp)) {
    397             devBound.setEmpty();
    398         }
    399     }
    400 
    401     GrAssert(devBound.contains(clipRegion.getBounds()));
    402 }
    403 #endif
    404 
    405 ///////////////////////////////////////////////////////////////////////////////
    406 
    407 // call this every draw call, to ensure that the context reflects our state,
    408 // and not the state from some other canvas/device
    409 void SkGpuDevice::prepareDraw(const SkDraw& draw, bool forceIdentity) {
    410     GrAssert(NULL != fClipData.fClipStack);
    411 
    412     fContext->setRenderTarget(fRenderTarget);
    413 
    414     SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack);
    415 
    416     if (forceIdentity) {
    417         fContext->setIdentityMatrix();
    418     } else {
    419         fContext->setMatrix(*draw.fMatrix);
    420     }
    421     fClipData.fOrigin = this->getOrigin();
    422 
    423 #ifdef SK_DEBUG
    424     check_bounds(fClipData, *draw.fClip, fRenderTarget->width(), fRenderTarget->height());
    425 #endif
    426 
    427     fContext->setClip(&fClipData);
    428 
    429     DO_DEFERRED_CLEAR();
    430 }
    431 
    432 GrRenderTarget* SkGpuDevice::accessRenderTarget() {
    433     DO_DEFERRED_CLEAR();
    434     return fRenderTarget;
    435 }
    436 
    437 ///////////////////////////////////////////////////////////////////////////////
    438 
    439 SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
    440 SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
    441 SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
    442 SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
    443 SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
    444                   shader_type_mismatch);
    445 SK_COMPILE_ASSERT(SkShader::kTwoPointConical_BitmapType == 5,
    446                   shader_type_mismatch);
    447 SK_COMPILE_ASSERT(SkShader::kLinear_BitmapType == 6, shader_type_mismatch);
    448 SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 6, shader_type_mismatch);
    449 
    450 namespace {
    451 
    452 // converts a SkPaint to a GrPaint, ignoring the skPaint's shader
    453 // justAlpha indicates that skPaint's alpha should be used rather than the color
    454 // Callers may subsequently modify the GrPaint. Setting constantColor indicates
    455 // that the final paint will draw the same color at every pixel. This allows
    456 // an optimization where the the color filter can be applied to the skPaint's
    457 // color once while converting to GrPaint and then ignored.
    458 inline bool skPaint2GrPaintNoShader(SkGpuDevice* dev,
    459                                     const SkPaint& skPaint,
    460                                     bool justAlpha,
    461                                     bool constantColor,
    462                                     GrPaint* grPaint) {
    463 
    464     grPaint->setDither(skPaint.isDither());
    465     grPaint->setAntiAlias(skPaint.isAntiAlias());
    466 
    467     SkXfermode::Coeff sm;
    468     SkXfermode::Coeff dm;
    469 
    470     SkXfermode* mode = skPaint.getXfermode();
    471     GrEffectRef* xferEffect = NULL;
    472     if (SkXfermode::AsNewEffectOrCoeff(mode, dev->context(), &xferEffect, &sm, &dm)) {
    473         if (NULL != xferEffect) {
    474             grPaint->addColorEffect(xferEffect)->unref();
    475             sm = SkXfermode::kOne_Coeff;
    476             dm = SkXfermode::kZero_Coeff;
    477         }
    478     } else {
    479         //SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
    480 #if 0
    481         return false;
    482 #else
    483         // Fall back to src-over
    484         sm = SkXfermode::kOne_Coeff;
    485         dm = SkXfermode::kISA_Coeff;
    486 #endif
    487     }
    488     grPaint->setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm));
    489 
    490     if (justAlpha) {
    491         uint8_t alpha = skPaint.getAlpha();
    492         grPaint->setColor(GrColorPackRGBA(alpha, alpha, alpha, alpha));
    493         // justAlpha is currently set to true only if there is a texture,
    494         // so constantColor should not also be true.
    495         GrAssert(!constantColor);
    496     } else {
    497         grPaint->setColor(SkColor2GrColor(skPaint.getColor()));
    498     }
    499 
    500     SkColorFilter* colorFilter = skPaint.getColorFilter();
    501     if (NULL != colorFilter) {
    502         // if the source color is a constant then apply the filter here once rather than per pixel
    503         // in a shader.
    504         if (constantColor) {
    505             SkColor filtered = colorFilter->filterColor(skPaint.getColor());
    506             grPaint->setColor(SkColor2GrColor(filtered));
    507         } else {
    508             SkAutoTUnref<GrEffectRef> effect(colorFilter->asNewEffect(dev->context()));
    509             if (NULL != effect.get()) {
    510                 grPaint->addColorEffect(effect);
    511             } else {
    512                 // TODO: rewrite this using asNewEffect()
    513                 SkColor color;
    514                 SkXfermode::Mode filterMode;
    515                 if (colorFilter->asColorMode(&color, &filterMode)) {
    516                     grPaint->setXfermodeColorFilter(filterMode, SkColor2GrColor(color));
    517                 }
    518             }
    519         }
    520     }
    521 
    522     return true;
    523 }
    524 
    525 // This function is similar to skPaint2GrPaintNoShader but also converts
    526 // skPaint's shader to a GrTexture/GrEffectStage if possible. The texture to
    527 // be used is set on grPaint and returned in param act. constantColor has the
    528 // same meaning as in skPaint2GrPaintNoShader.
    529 inline bool skPaint2GrPaintShader(SkGpuDevice* dev,
    530                                   const SkPaint& skPaint,
    531                                   bool constantColor,
    532                                   GrPaint* grPaint) {
    533     SkShader* shader = skPaint.getShader();
    534     if (NULL == shader) {
    535         return skPaint2GrPaintNoShader(dev, skPaint, false, constantColor, grPaint);
    536     }
    537 
    538     // setup the shader as the first color effect on the paint
    539     SkAutoTUnref<GrEffectRef> effect(shader->asNewEffect(dev->context(), skPaint));
    540     if (NULL != effect.get()) {
    541         grPaint->addColorEffect(effect);
    542         // Now setup the rest of the paint.
    543         return skPaint2GrPaintNoShader(dev, skPaint, true, false, grPaint);
    544     } else {
    545         // We still don't have SkColorShader::asNewEffect() implemented.
    546         SkShader::GradientInfo info;
    547         SkColor                color;
    548 
    549         info.fColors = &color;
    550         info.fColorOffsets = NULL;
    551         info.fColorCount = 1;
    552         if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
    553             SkPaint copy(skPaint);
    554             copy.setShader(NULL);
    555             // modulate the paint alpha by the shader's solid color alpha
    556             U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
    557             copy.setColor(SkColorSetA(color, newA));
    558             return skPaint2GrPaintNoShader(dev, copy, false, constantColor, grPaint);
    559         } else {
    560             return false;
    561         }
    562     }
    563 }
    564 }
    565 
    566 ///////////////////////////////////////////////////////////////////////////////
    567 void SkGpuDevice::clear(SkColor color) {
    568     SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
    569     fContext->clear(&rect, SkColor2GrColor(color), fRenderTarget);
    570     fNeedClear = false;
    571 }
    572 
    573 void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
    574     CHECK_SHOULD_DRAW(draw, false);
    575 
    576     GrPaint grPaint;
    577     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
    578         return;
    579     }
    580 
    581     fContext->drawPaint(grPaint);
    582 }
    583 
    584 // must be in SkCanvas::PointMode order
    585 static const GrPrimitiveType gPointMode2PrimtiveType[] = {
    586     kPoints_GrPrimitiveType,
    587     kLines_GrPrimitiveType,
    588     kLineStrip_GrPrimitiveType
    589 };
    590 
    591 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
    592                              size_t count, const SkPoint pts[], const SkPaint& paint) {
    593     CHECK_FOR_NODRAW_ANNOTATION(paint);
    594     CHECK_SHOULD_DRAW(draw, false);
    595 
    596     SkScalar width = paint.getStrokeWidth();
    597     if (width < 0) {
    598         return;
    599     }
    600 
    601     // we only handle hairlines and paints without path effects or mask filters,
    602     // else we let the SkDraw call our drawPath()
    603     if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) {
    604         draw.drawPoints(mode, count, pts, paint, true);
    605         return;
    606     }
    607 
    608     GrPaint grPaint;
    609     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
    610         return;
    611     }
    612 
    613     fContext->drawVertices(grPaint,
    614                            gPointMode2PrimtiveType[mode],
    615                            count,
    616                            (GrPoint*)pts,
    617                            NULL,
    618                            NULL,
    619                            NULL,
    620                            0);
    621 }
    622 
    623 ///////////////////////////////////////////////////////////////////////////////
    624 
    625 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
    626                            const SkPaint& paint) {
    627     CHECK_FOR_NODRAW_ANNOTATION(paint);
    628     CHECK_SHOULD_DRAW(draw, false);
    629 
    630     bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
    631     SkScalar width = paint.getStrokeWidth();
    632 
    633     /*
    634         We have special code for hairline strokes, miter-strokes, and fills.
    635         Anything else we just call our path code.
    636      */
    637     bool usePath = doStroke && width > 0 &&
    638                     paint.getStrokeJoin() != SkPaint::kMiter_Join;
    639     // another two reasons we might need to call drawPath...
    640     if (paint.getMaskFilter() || paint.getPathEffect()) {
    641         usePath = true;
    642     }
    643     if (!usePath && paint.isAntiAlias() && !fContext->getMatrix().rectStaysRect()) {
    644 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
    645         if (doStroke) {
    646 #endif
    647             usePath = true;
    648 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
    649         } else {
    650             usePath = !fContext->getMatrix().preservesRightAngles();
    651         }
    652 #endif
    653     }
    654     // small miter limit means right angles show bevel...
    655     if (SkPaint::kMiter_Join == paint.getStrokeJoin() &&
    656         paint.getStrokeMiter() < SK_ScalarSqrt2)
    657     {
    658         usePath = true;
    659     }
    660     // until we can both stroke and fill rectangles
    661     if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
    662         usePath = true;
    663     }
    664 
    665     if (usePath) {
    666         SkPath path;
    667         path.addRect(rect);
    668         this->drawPath(draw, path, paint, NULL, true);
    669         return;
    670     }
    671 
    672     GrPaint grPaint;
    673     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
    674         return;
    675     }
    676     fContext->drawRect(grPaint, rect, doStroke ? width : -1);
    677 }
    678 
    679 ///////////////////////////////////////////////////////////////////////////////
    680 
    681 void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
    682                            const SkPaint& paint) {
    683     CHECK_FOR_NODRAW_ANNOTATION(paint);
    684     CHECK_SHOULD_DRAW(draw, false);
    685 
    686     bool usePath = !rect.isSimple();
    687     // another two reasons we might need to call drawPath...
    688     if (paint.getMaskFilter() || paint.getPathEffect()) {
    689         usePath = true;
    690     }
    691     // until we can rotate rrects...
    692     if (!usePath && !fContext->getMatrix().rectStaysRect()) {
    693         usePath = true;
    694     }
    695 
    696     if (usePath) {
    697         SkPath path;
    698         path.addRRect(rect);
    699         this->drawPath(draw, path, paint, NULL, true);
    700         return;
    701     }
    702 
    703     GrPaint grPaint;
    704     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
    705         return;
    706     }
    707 
    708     SkStrokeRec stroke(paint);
    709     fContext->drawRRect(grPaint, rect, stroke);
    710 }
    711 
    712 ///////////////////////////////////////////////////////////////////////////////
    713 
    714 void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval,
    715                            const SkPaint& paint) {
    716     CHECK_FOR_NODRAW_ANNOTATION(paint);
    717     CHECK_SHOULD_DRAW(draw, false);
    718 
    719     bool usePath = false;
    720     // some basic reasons we might need to call drawPath...
    721     if (paint.getMaskFilter() || paint.getPathEffect()) {
    722         usePath = true;
    723     }
    724 
    725     if (usePath) {
    726         SkPath path;
    727         path.addOval(oval);
    728         this->drawPath(draw, path, paint, NULL, true);
    729         return;
    730     }
    731 
    732     GrPaint grPaint;
    733     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
    734         return;
    735     }
    736     SkStrokeRec stroke(paint);
    737 
    738     fContext->drawOval(grPaint, oval, stroke);
    739 }
    740 
    741 #include "SkMaskFilter.h"
    742 #include "SkBounder.h"
    743 
    744 ///////////////////////////////////////////////////////////////////////////////
    745 
    746 // helpers for applying mask filters
    747 namespace {
    748 
    749 // Draw a mask using the supplied paint. Since the coverage/geometry
    750 // is already burnt into the mask this boils down to a rect draw.
    751 // Return true if the mask was successfully drawn.
    752 bool draw_mask(GrContext* context, const SkRect& maskRect,
    753                GrPaint* grp, GrTexture* mask) {
    754     GrContext::AutoMatrix am;
    755     if (!am.setIdentity(context, grp)) {
    756         return false;
    757     }
    758 
    759     SkMatrix matrix;
    760     matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop);
    761     matrix.postIDiv(mask->width(), mask->height());
    762 
    763     grp->addCoverageEffect(GrSimpleTextureEffect::Create(mask, matrix))->unref();
    764     context->drawRect(*grp, maskRect);
    765     return true;
    766 }
    767 
    768 bool draw_with_mask_filter(GrContext* context, const SkPath& devPath,
    769                            SkMaskFilter* filter, const SkRegion& clip, SkBounder* bounder,
    770                            GrPaint* grp, SkPaint::Style style) {
    771     SkMask  srcM, dstM;
    772 
    773     if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), filter, &context->getMatrix(), &srcM,
    774                             SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
    775         return false;
    776     }
    777     SkAutoMaskFreeImage autoSrc(srcM.fImage);
    778 
    779     if (!filter->filterMask(&dstM, srcM, context->getMatrix(), NULL)) {
    780         return false;
    781     }
    782     // this will free-up dstM when we're done (allocated in filterMask())
    783     SkAutoMaskFreeImage autoDst(dstM.fImage);
    784 
    785     if (clip.quickReject(dstM.fBounds)) {
    786         return false;
    787     }
    788     if (bounder && !bounder->doIRect(dstM.fBounds)) {
    789         return false;
    790     }
    791 
    792     // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
    793     // the current clip (and identity matrix) and GrPaint settings
    794     GrTextureDesc desc;
    795     desc.fWidth = dstM.fBounds.width();
    796     desc.fHeight = dstM.fBounds.height();
    797     desc.fConfig = kAlpha_8_GrPixelConfig;
    798 
    799     GrAutoScratchTexture ast(context, desc);
    800     GrTexture* texture = ast.texture();
    801 
    802     if (NULL == texture) {
    803         return false;
    804     }
    805     texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
    806                                dstM.fImage, dstM.fRowBytes);
    807 
    808     SkRect maskRect = SkRect::MakeFromIRect(dstM.fBounds);
    809 
    810     return draw_mask(context, maskRect, grp, texture);
    811 }
    812 
    813 // Create a mask of 'devPath' and place the result in 'mask'. Return true on
    814 // success; false otherwise.
    815 bool create_mask_GPU(GrContext* context,
    816                      const SkRect& maskRect,
    817                      const SkPath& devPath,
    818                      const SkStrokeRec& stroke,
    819                      bool doAA,
    820                      GrAutoScratchTexture* mask) {
    821     GrTextureDesc desc;
    822     desc.fFlags = kRenderTarget_GrTextureFlagBit;
    823     desc.fWidth = SkScalarCeilToInt(maskRect.width());
    824     desc.fHeight = SkScalarCeilToInt(maskRect.height());
    825     // We actually only need A8, but it often isn't supported as a
    826     // render target so default to RGBA_8888
    827     desc.fConfig = kRGBA_8888_GrPixelConfig;
    828     if (context->isConfigRenderable(kAlpha_8_GrPixelConfig)) {
    829         desc.fConfig = kAlpha_8_GrPixelConfig;
    830     }
    831 
    832     mask->set(context, desc);
    833     if (NULL == mask->texture()) {
    834         return false;
    835     }
    836 
    837     GrTexture* maskTexture = mask->texture();
    838     SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
    839 
    840     GrContext::AutoRenderTarget art(context, maskTexture->asRenderTarget());
    841     GrContext::AutoClip ac(context, clipRect);
    842 
    843     context->clear(NULL, 0x0);
    844 
    845     GrPaint tempPaint;
    846     if (doAA) {
    847         tempPaint.setAntiAlias(true);
    848         // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
    849         // blend coeff of zero requires dual source blending support in order
    850         // to properly blend partially covered pixels. This means the AA
    851         // code path may not be taken. So we use a dst blend coeff of ISA. We
    852         // could special case AA draws to a dst surface with known alpha=0 to
    853         // use a zero dst coeff when dual source blending isn't available.
    854         tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
    855     }
    856 
    857     GrContext::AutoMatrix am;
    858 
    859     // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint.
    860     SkMatrix translate;
    861     translate.setTranslate(-maskRect.fLeft, -maskRect.fTop);
    862     am.set(context, translate);
    863     context->drawPath(tempPaint, devPath, stroke);
    864     return true;
    865 }
    866 
    867 SkBitmap wrap_texture(GrTexture* texture) {
    868     SkBitmap result;
    869     bool dummy;
    870     SkBitmap::Config config = grConfig2skConfig(texture->config(), &dummy);
    871     result.setConfig(config, texture->width(), texture->height());
    872     result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (texture)))->unref();
    873     return result;
    874 }
    875 
    876 };
    877 
    878 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
    879                            const SkPaint& paint, const SkMatrix* prePathMatrix,
    880                            bool pathIsMutable) {
    881     CHECK_FOR_NODRAW_ANNOTATION(paint);
    882     CHECK_SHOULD_DRAW(draw, false);
    883 
    884     GrPaint grPaint;
    885     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
    886         return;
    887     }
    888 
    889     // can we cheat, and treat a thin stroke as a hairline w/ coverage
    890     // if we can, we draw lots faster (raster device does this same test)
    891     SkScalar hairlineCoverage;
    892     bool doHairLine = SkDrawTreatAsHairline(paint, fContext->getMatrix(), &hairlineCoverage);
    893     if (doHairLine) {
    894         grPaint.setCoverage(SkScalarRoundToInt(hairlineCoverage * grPaint.getCoverage()));
    895     }
    896 
    897     // If we have a prematrix, apply it to the path, optimizing for the case
    898     // where the original path can in fact be modified in place (even though
    899     // its parameter type is const).
    900     SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
    901     SkPath  tmpPath, effectPath;
    902 
    903     if (prePathMatrix) {
    904         SkPath* result = pathPtr;
    905 
    906         if (!pathIsMutable) {
    907             result = &tmpPath;
    908             pathIsMutable = true;
    909         }
    910         // should I push prePathMatrix on our MV stack temporarily, instead
    911         // of applying it here? See SkDraw.cpp
    912         pathPtr->transform(*prePathMatrix, result);
    913         pathPtr = result;
    914     }
    915     // at this point we're done with prePathMatrix
    916     SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
    917 
    918     SkStrokeRec stroke(paint);
    919     SkPathEffect* pathEffect = paint.getPathEffect();
    920     const SkRect* cullRect = NULL;  // TODO: what is our bounds?
    921     if (pathEffect && pathEffect->filterPath(&effectPath, *pathPtr, &stroke,
    922                                              cullRect)) {
    923         pathPtr = &effectPath;
    924     }
    925 
    926     if (!pathEffect && doHairLine) {
    927         stroke.setHairlineStyle();
    928     }
    929 
    930     if (paint.getMaskFilter()) {
    931         if (!stroke.isHairlineStyle()) {
    932             if (stroke.applyToPath(&tmpPath, *pathPtr)) {
    933                 pathPtr = &tmpPath;
    934                 pathIsMutable = true;
    935                 stroke.setFillStyle();
    936             }
    937         }
    938 
    939         // avoid possibly allocating a new path in transform if we can
    940         SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
    941 
    942         // transform the path into device space
    943         pathPtr->transform(fContext->getMatrix(), devPathPtr);
    944 
    945         SkRect maskRect;
    946         if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(),
    947                                                     draw.fClip->getBounds(),
    948                                                     fContext->getMatrix(),
    949                                                     &maskRect)) {
    950             SkIRect finalIRect;
    951             maskRect.roundOut(&finalIRect);
    952             if (draw.fClip->quickReject(finalIRect)) {
    953                 // clipped out
    954                 return;
    955             }
    956             if (NULL != draw.fBounder && !draw.fBounder->doIRect(finalIRect)) {
    957                 // nothing to draw
    958                 return;
    959             }
    960 
    961             GrAutoScratchTexture mask;
    962 
    963             if (create_mask_GPU(fContext, maskRect, *devPathPtr, stroke,
    964                                 grPaint.isAntiAlias(), &mask)) {
    965                 GrTexture* filtered;
    966 
    967                 if (paint.getMaskFilter()->filterMaskGPU(mask.texture(), maskRect, &filtered, true)) {
    968                     SkAutoTUnref<GrTexture> atu(filtered);
    969 
    970                     if (draw_mask(fContext, maskRect, &grPaint, filtered)) {
    971                         // This path is completely drawn
    972                         return;
    973                     }
    974                 }
    975             }
    976         }
    977 
    978         // draw the mask on the CPU - this is a fallthrough path in case the
    979         // GPU path fails
    980         SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_Style :
    981                                                           SkPaint::kFill_Style;
    982         draw_with_mask_filter(fContext, *devPathPtr, paint.getMaskFilter(),
    983                               *draw.fClip, draw.fBounder, &grPaint, style);
    984         return;
    985     }
    986 
    987     fContext->drawPath(grPaint, *pathPtr, stroke);
    988 }
    989 
    990 namespace {
    991 
    992 inline int get_tile_count(int l, int t, int r, int b, int tileSize)  {
    993     int tilesX = (r / tileSize) - (l / tileSize) + 1;
    994     int tilesY = (b / tileSize) - (t / tileSize) + 1;
    995     return tilesX * tilesY;
    996 }
    997 
    998 inline int determine_tile_size(const SkBitmap& bitmap,
    999                                const SkRect& src,
   1000                                int maxTextureSize) {
   1001     static const int kSmallTileSize = 1 << 10;
   1002     if (maxTextureSize <= kSmallTileSize) {
   1003         return maxTextureSize;
   1004     }
   1005 
   1006     size_t maxTexTotalTileSize;
   1007     size_t smallTotalTileSize;
   1008 
   1009     SkIRect iSrc;
   1010     src.roundOut(&iSrc);
   1011 
   1012     maxTexTotalTileSize = get_tile_count(iSrc.fLeft,
   1013                                          iSrc.fTop,
   1014                                          iSrc.fRight,
   1015                                          iSrc.fBottom,
   1016                                          maxTextureSize);
   1017     smallTotalTileSize = get_tile_count(iSrc.fLeft,
   1018                                         iSrc.fTop,
   1019                                         iSrc.fRight,
   1020                                         iSrc.fBottom,
   1021                                         kSmallTileSize);
   1022 
   1023     maxTexTotalTileSize *= maxTextureSize * maxTextureSize;
   1024     smallTotalTileSize *= kSmallTileSize * kSmallTileSize;
   1025 
   1026     if (maxTexTotalTileSize > 2 * smallTotalTileSize) {
   1027         return kSmallTileSize;
   1028     } else {
   1029         return maxTextureSize;
   1030     }
   1031 }
   1032 }
   1033 
   1034 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
   1035                                    const GrTextureParams& params,
   1036                                    const SkRect* srcRectPtr) const {
   1037     // if bitmap is explictly texture backed then just use the texture
   1038     if (NULL != bitmap.getTexture()) {
   1039         return false;
   1040     }
   1041     // if it's larger than the max texture size, then we have no choice but
   1042     // tiling
   1043     const int maxTextureSize = fContext->getMaxTextureSize();
   1044     if (bitmap.width() > maxTextureSize ||
   1045         bitmap.height() > maxTextureSize) {
   1046         return true;
   1047     }
   1048     // if we are going to have to draw the whole thing, then don't tile
   1049     if (NULL == srcRectPtr) {
   1050         return false;
   1051     }
   1052     // if the entire texture is already in our cache then no reason to tile it
   1053     if (GrIsBitmapInCache(fContext, bitmap, &params)) {
   1054         return false;
   1055     }
   1056 
   1057     // At this point we know we could do the draw by uploading the entire bitmap
   1058     // as a texture. However, if the texture would be large compared to the
   1059     // cache size and we don't require most of it for this draw then tile to
   1060     // reduce the amount of upload and cache spill.
   1061 
   1062     // assumption here is that sw bitmap size is a good proxy for its size as
   1063     // a texture
   1064     size_t bmpSize = bitmap.getSize();
   1065     size_t cacheSize;
   1066     fContext->getTextureCacheLimits(NULL, &cacheSize);
   1067     if (bmpSize < cacheSize / 2) {
   1068         return false;
   1069     }
   1070 
   1071     SkScalar fracUsed = SkScalarMul(srcRectPtr->width() / bitmap.width(),
   1072                                     srcRectPtr->height() / bitmap.height());
   1073     if (fracUsed <= SK_ScalarHalf) {
   1074         return true;
   1075     } else {
   1076         return false;
   1077     }
   1078 }
   1079 
   1080 void SkGpuDevice::drawBitmap(const SkDraw& draw,
   1081                              const SkBitmap& bitmap,
   1082                              const SkMatrix& m,
   1083                              const SkPaint& paint) {
   1084     // We cannot call drawBitmapRect here since 'm' could be anything
   1085     this->drawBitmapCommon(draw, bitmap, NULL, m, paint);
   1086 }
   1087 
   1088 void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
   1089                                    const SkBitmap& bitmap,
   1090                                    const SkRect* srcRectPtr,
   1091                                    const SkMatrix& m,
   1092                                    const SkPaint& paint) {
   1093     CHECK_SHOULD_DRAW(draw, false);
   1094 
   1095     SkRect srcRect;
   1096     if (NULL == srcRectPtr) {
   1097         srcRect.set(0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
   1098     } else {
   1099         srcRect = *srcRectPtr;
   1100     }
   1101 
   1102     if (paint.getMaskFilter()){
   1103         // Convert the bitmap to a shader so that the rect can be drawn
   1104         // through drawRect, which supports mask filters.
   1105         SkMatrix        newM(m);
   1106         SkBitmap        tmp;    // subset of bitmap, if necessary
   1107         const SkBitmap* bitmapPtr = &bitmap;
   1108         if (NULL != srcRectPtr) {
   1109             SkIRect iSrc;
   1110             srcRect.roundOut(&iSrc);
   1111             if (!bitmap.extractSubset(&tmp, iSrc)) {
   1112                 return;     // extraction failed
   1113             }
   1114             bitmapPtr = &tmp;
   1115             srcRect.offset(SkIntToScalar(-iSrc.fLeft), SkIntToScalar(-iSrc.fTop));
   1116             // The source rect has changed so update the matrix
   1117             newM.preTranslate(SkIntToScalar(iSrc.fLeft), SkIntToScalar(iSrc.fTop));
   1118         }
   1119 
   1120         SkPaint paintWithTexture(paint);
   1121         paintWithTexture.setShader(SkShader::CreateBitmapShader(*bitmapPtr,
   1122             SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
   1123 
   1124         // Transform 'newM' needs to be concatenated to the current matrix,
   1125         // rather than transforming the primitive directly, so that 'newM' will
   1126         // also affect the behavior of the mask filter.
   1127         SkMatrix drawMatrix;
   1128         drawMatrix.setConcat(fContext->getMatrix(), newM);
   1129         SkDraw transformedDraw(draw);
   1130         transformedDraw.fMatrix = &drawMatrix;
   1131 
   1132         this->drawRect(transformedDraw, srcRect, paintWithTexture);
   1133 
   1134         return;
   1135     }
   1136 
   1137     GrTextureParams params;
   1138     SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
   1139     GrTextureParams::FilterMode textureFilterMode;
   1140     switch(paintFilterLevel) {
   1141         case SkPaint::kNone_FilterLevel:
   1142             textureFilterMode = GrTextureParams::kNone_FilterMode;
   1143             break;
   1144         case SkPaint::kLow_FilterLevel:
   1145             textureFilterMode = GrTextureParams::kBilerp_FilterMode;
   1146             break;
   1147         case SkPaint::kMedium_FilterLevel:
   1148             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
   1149             break;
   1150         case SkPaint::kHigh_FilterLevel:
   1151             SkErrorInternals::SetError( kInvalidPaint_SkError,
   1152                                         "Sorry, I don't yet support high quality "
   1153                                         "filtering on the GPU.  Falling back to "
   1154                                         "MIPMaps.");
   1155             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
   1156             break;
   1157         default:
   1158             SkErrorInternals::SetError( kInvalidPaint_SkError,
   1159                                         "Sorry, I don't understand the filtering "
   1160                                         "mode you asked for.  Falling back to "
   1161                                         "MIPMaps.");
   1162             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
   1163             break;
   1164 
   1165     }
   1166 
   1167     params.setFilterMode(textureFilterMode);
   1168 
   1169     if (!this->shouldTileBitmap(bitmap, params, srcRectPtr)) {
   1170         // take the simple case
   1171         this->internalDrawBitmap(bitmap, srcRect, m, params, paint);
   1172     } else {
   1173         this->drawTiledBitmap(bitmap, srcRect, m, params, paint);
   1174     }
   1175 }
   1176 
   1177 // Break 'bitmap' into several tiles to draw it since it has already
   1178 // been determined to be too large to fit in VRAM
   1179 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
   1180                                   const SkRect& srcRect,
   1181                                   const SkMatrix& m,
   1182                                   const GrTextureParams& params,
   1183                                   const SkPaint& paint) {
   1184     const int maxTextureSize = fContext->getMaxTextureSize();
   1185 
   1186     int tileSize = determine_tile_size(bitmap, srcRect, maxTextureSize);
   1187 
   1188     // compute clip bounds in local coordinates
   1189     SkRect clipRect;
   1190     {
   1191         const GrRenderTarget* rt = fContext->getRenderTarget();
   1192         clipRect.setWH(SkIntToScalar(rt->width()), SkIntToScalar(rt->height()));
   1193         if (!fContext->getClip()->fClipStack->intersectRectWithClip(&clipRect)) {
   1194             return;
   1195         }
   1196         SkMatrix matrix, inverse;
   1197         matrix.setConcat(fContext->getMatrix(), m);
   1198         if (!matrix.invert(&inverse)) {
   1199             return;
   1200         }
   1201         inverse.mapRect(&clipRect);
   1202     }
   1203 
   1204     int nx = bitmap.width() / tileSize;
   1205     int ny = bitmap.height() / tileSize;
   1206     for (int x = 0; x <= nx; x++) {
   1207         for (int y = 0; y <= ny; y++) {
   1208             SkRect tileR;
   1209             tileR.set(SkIntToScalar(x * tileSize),
   1210                       SkIntToScalar(y * tileSize),
   1211                       SkIntToScalar((x + 1) * tileSize),
   1212                       SkIntToScalar((y + 1) * tileSize));
   1213 
   1214             if (!SkRect::Intersects(tileR, clipRect)) {
   1215                 continue;
   1216             }
   1217 
   1218             if (!tileR.intersect(srcRect)) {
   1219                 continue;
   1220             }
   1221 
   1222             SkBitmap tmpB;
   1223             SkIRect iTileR;
   1224             tileR.roundOut(&iTileR);
   1225             if (bitmap.extractSubset(&tmpB, iTileR)) {
   1226                 // now offset it to make it "local" to our tmp bitmap
   1227                 tileR.offset(SkIntToScalar(-iTileR.fLeft), SkIntToScalar(-iTileR.fTop));
   1228                 SkMatrix tmpM(m);
   1229                 tmpM.preTranslate(SkIntToScalar(iTileR.fLeft),
   1230                                   SkIntToScalar(iTileR.fTop));
   1231 
   1232                 this->internalDrawBitmap(tmpB, tileR, tmpM, params, paint);
   1233             }
   1234         }
   1235     }
   1236 }
   1237 
   1238 static bool has_aligned_samples(const SkRect& srcRect,
   1239                                 const SkRect& transformedRect) {
   1240     // detect pixel disalignment
   1241     if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) -
   1242             transformedRect.left()) < COLOR_BLEED_TOLERANCE &&
   1243         SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) -
   1244             transformedRect.top()) < COLOR_BLEED_TOLERANCE &&
   1245         SkScalarAbs(transformedRect.width() - srcRect.width()) <
   1246             COLOR_BLEED_TOLERANCE &&
   1247         SkScalarAbs(transformedRect.height() - srcRect.height()) <
   1248             COLOR_BLEED_TOLERANCE) {
   1249         return true;
   1250     }
   1251     return false;
   1252 }
   1253 
   1254 static bool may_color_bleed(const SkRect& srcRect,
   1255                             const SkRect& transformedRect,
   1256                             const SkMatrix& m) {
   1257     // Only gets called if has_aligned_samples returned false.
   1258     // So we can assume that sampling is axis aligned but not texel aligned.
   1259     GrAssert(!has_aligned_samples(srcRect, transformedRect));
   1260     SkRect innerSrcRect(srcRect), innerTransformedRect,
   1261         outerTransformedRect(transformedRect);
   1262     innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
   1263     m.mapRect(&innerTransformedRect, innerSrcRect);
   1264 
   1265     // The gap between outerTransformedRect and innerTransformedRect
   1266     // represents the projection of the source border area, which is
   1267     // problematic for color bleeding.  We must check whether any
   1268     // destination pixels sample the border area.
   1269     outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
   1270     innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
   1271     SkIRect outer, inner;
   1272     outerTransformedRect.round(&outer);
   1273     innerTransformedRect.round(&inner);
   1274     // If the inner and outer rects round to the same result, it means the
   1275     // border does not overlap any pixel centers. Yay!
   1276     return inner != outer;
   1277 }
   1278 
   1279 
   1280 /*
   1281  *  This is called by drawBitmap(), which has to handle images that may be too
   1282  *  large to be represented by a single texture.
   1283  *
   1284  *  internalDrawBitmap assumes that the specified bitmap will fit in a texture
   1285  *  and that non-texture portion of the GrPaint has already been setup.
   1286  */
   1287 void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
   1288                                      const SkRect& srcRect,
   1289                                      const SkMatrix& m,
   1290                                      const GrTextureParams& params,
   1291                                      const SkPaint& paint) {
   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(srcRect);
   1302     SkRect paintRect;
   1303     SkScalar wInv = SkScalarInvert(SkIntToScalar(bitmap.width()));
   1304     SkScalar hInv = SkScalarInvert(SkIntToScalar(bitmap.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     bool needsTextureDomain = false;
   1311     if (params.filterMode() != GrTextureParams::kNone_FilterMode) {
   1312         // Need texture domain if drawing a sub rect.
   1313         needsTextureDomain = srcRect.width() < bitmap.width() ||
   1314                              srcRect.height() < bitmap.height();
   1315         if (needsTextureDomain && m.rectStaysRect() && fContext->getMatrix().rectStaysRect()) {
   1316             // sampling is axis-aligned
   1317             SkRect transformedRect;
   1318             SkMatrix srcToDeviceMatrix(m);
   1319             srcToDeviceMatrix.postConcat(fContext->getMatrix());
   1320             srcToDeviceMatrix.mapRect(&transformedRect, srcRect);
   1321 
   1322             if (has_aligned_samples(srcRect, transformedRect)) {
   1323                 // We could also turn off filtering here (but we already did a cache lookup with
   1324                 // params).
   1325                 needsTextureDomain = false;
   1326             } else {
   1327                 needsTextureDomain = may_color_bleed(srcRect, transformedRect, m);
   1328             }
   1329         }
   1330     }
   1331 
   1332     SkRect textureDomain = SkRect::MakeEmpty();
   1333     SkAutoTUnref<GrEffectRef> effect;
   1334     if (needsTextureDomain) {
   1335         // Use a constrained texture domain to avoid color bleeding
   1336         SkScalar left, top, right, bottom;
   1337         if (srcRect.width() > SK_Scalar1) {
   1338             SkScalar border = SK_ScalarHalf / bitmap.width();
   1339             left = paintRect.left() + border;
   1340             right = paintRect.right() - border;
   1341         } else {
   1342             left = right = SkScalarHalf(paintRect.left() + paintRect.right());
   1343         }
   1344         if (srcRect.height() > SK_Scalar1) {
   1345             SkScalar border = SK_ScalarHalf / bitmap.height();
   1346             top = paintRect.top() + border;
   1347             bottom = paintRect.bottom() - border;
   1348         } else {
   1349             top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom());
   1350         }
   1351         textureDomain.setLTRB(left, top, right, bottom);
   1352         effect.reset(GrTextureDomainEffect::Create(texture,
   1353                                                    SkMatrix::I(),
   1354                                                    textureDomain,
   1355                                                    GrTextureDomainEffect::kClamp_WrapMode,
   1356                                                    params.filterMode()));
   1357     } else {
   1358         effect.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params));
   1359     }
   1360 
   1361     // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
   1362     // the rest from the SkPaint.
   1363     GrPaint grPaint;
   1364     grPaint.addColorEffect(effect);
   1365     bool alphaOnly = !(SkBitmap::kA8_Config == bitmap.config());
   1366     if (!skPaint2GrPaintNoShader(this, paint, alphaOnly, false, &grPaint)) {
   1367         return;
   1368     }
   1369 
   1370     fContext->drawRectToRect(grPaint, dstRect, paintRect, &m);
   1371 }
   1372 
   1373 static bool filter_texture(SkDevice* device, GrContext* context,
   1374                            GrTexture* texture, SkImageFilter* filter,
   1375                            int w, int h, const SkMatrix& ctm, SkBitmap* result,
   1376                            SkIPoint* offset) {
   1377     GrAssert(filter);
   1378     SkDeviceImageFilterProxy proxy(device);
   1379 
   1380     if (filter->canFilterImageGPU()) {
   1381         // Save the render target and set it to NULL, so we don't accidentally draw to it in the
   1382         // filter.  Also set the clip wide open and the matrix to identity.
   1383         GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
   1384         return filter->filterImageGPU(&proxy, wrap_texture(texture), ctm, result, offset);
   1385     } else {
   1386         return false;
   1387     }
   1388 }
   1389 
   1390 void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
   1391                              int left, int top, const SkPaint& paint) {
   1392     // drawSprite is defined to be in device coords.
   1393     CHECK_SHOULD_DRAW(draw, true);
   1394 
   1395     SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
   1396     if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
   1397         return;
   1398     }
   1399 
   1400     int w = bitmap.width();
   1401     int h = bitmap.height();
   1402 
   1403     GrTexture* texture;
   1404     // draw sprite uses the default texture params
   1405     SkAutoCachedTexture act(this, bitmap, NULL, &texture);
   1406 
   1407     SkImageFilter* filter = paint.getImageFilter();
   1408     SkIPoint offset = SkIPoint::Make(left, top);
   1409     // This bitmap will own the filtered result as a texture.
   1410     SkBitmap filteredBitmap;
   1411 
   1412     if (NULL != filter) {
   1413         if (filter_texture(this, fContext, texture, filter, w, h, SkMatrix::I(), &filteredBitmap,
   1414                            &offset)) {
   1415             texture = (GrTexture*) filteredBitmap.getTexture();
   1416             w = filteredBitmap.width();
   1417             h = filteredBitmap.height();
   1418         } else {
   1419             return;
   1420         }
   1421     }
   1422 
   1423     GrPaint grPaint;
   1424     grPaint.addColorTextureEffect(texture, SkMatrix::I());
   1425 
   1426     if(!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
   1427         return;
   1428     }
   1429 
   1430     fContext->drawRectToRect(grPaint,
   1431                              SkRect::MakeXYWH(SkIntToScalar(offset.fX),
   1432                                               SkIntToScalar(offset.fY),
   1433                                               SkIntToScalar(w),
   1434                                               SkIntToScalar(h)),
   1435                              SkRect::MakeXYWH(0,
   1436                                               0,
   1437                                               SK_Scalar1 * w / texture->width(),
   1438                                               SK_Scalar1 * h / texture->height()));
   1439 }
   1440 
   1441 void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
   1442                                  const SkRect* src, const SkRect& dst,
   1443                                  const SkPaint& paint) {
   1444     SkMatrix    matrix;
   1445     SkRect      bitmapBounds, tmpSrc;
   1446 
   1447     bitmapBounds.set(0, 0,
   1448                      SkIntToScalar(bitmap.width()),
   1449                      SkIntToScalar(bitmap.height()));
   1450 
   1451     // Compute matrix from the two rectangles
   1452     if (NULL != src) {
   1453         tmpSrc = *src;
   1454     } else {
   1455         tmpSrc = bitmapBounds;
   1456     }
   1457     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
   1458 
   1459     // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null.
   1460     if (NULL != src) {
   1461         if (!bitmapBounds.contains(tmpSrc)) {
   1462             if (!tmpSrc.intersect(bitmapBounds)) {
   1463                 return; // nothing to draw
   1464             }
   1465         }
   1466     }
   1467 
   1468     this->drawBitmapCommon(draw, bitmap, &tmpSrc, matrix, paint);
   1469 }
   1470 
   1471 void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
   1472                              int x, int y, const SkPaint& paint) {
   1473     // clear of the source device must occur before CHECK_SHOULD_DRAW
   1474     SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
   1475     if (dev->fNeedClear) {
   1476         // TODO: could check here whether we really need to draw at all
   1477         dev->clear(0x0);
   1478     }
   1479 
   1480     // drawDevice is defined to be in device coords.
   1481     CHECK_SHOULD_DRAW(draw, true);
   1482 
   1483     GrRenderTarget* devRT = device->accessRenderTarget();
   1484     GrTexture* devTex;
   1485     if (NULL == (devTex = devRT->asTexture())) {
   1486         return;
   1487     }
   1488 
   1489     const SkBitmap& bm = dev->accessBitmap(false);
   1490     int w = bm.width();
   1491     int h = bm.height();
   1492 
   1493     SkImageFilter* filter = paint.getImageFilter();
   1494     // This bitmap will own the filtered result as a texture.
   1495     SkBitmap filteredBitmap;
   1496 
   1497     if (NULL != filter) {
   1498         SkIPoint offset = SkIPoint::Make(0, 0);
   1499         if (filter_texture(this, fContext, devTex, filter, w, h, SkMatrix::I(), &filteredBitmap,
   1500                            &offset)) {
   1501             devTex = filteredBitmap.getTexture();
   1502             w = filteredBitmap.width();
   1503             h = filteredBitmap.height();
   1504             x += offset.fX;
   1505             y += offset.fY;
   1506         } else {
   1507             return;
   1508         }
   1509     }
   1510 
   1511     GrPaint grPaint;
   1512     grPaint.addColorTextureEffect(devTex, SkMatrix::I());
   1513 
   1514     if (!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
   1515         return;
   1516     }
   1517 
   1518     SkRect dstRect = SkRect::MakeXYWH(SkIntToScalar(x),
   1519                                       SkIntToScalar(y),
   1520                                       SkIntToScalar(w),
   1521                                       SkIntToScalar(h));
   1522 
   1523     // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate
   1524     // scratch texture).
   1525     SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(),
   1526                                     SK_Scalar1 * h / devTex->height());
   1527 
   1528     fContext->drawRectToRect(grPaint, dstRect, srcRect);
   1529 }
   1530 
   1531 bool SkGpuDevice::canHandleImageFilter(SkImageFilter* filter) {
   1532     return filter->canFilterImageGPU();
   1533 }
   1534 
   1535 bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
   1536                               const SkMatrix& ctm,
   1537                               SkBitmap* result, SkIPoint* offset) {
   1538     // want explicitly our impl, so guard against a subclass of us overriding it
   1539     if (!this->SkGpuDevice::canHandleImageFilter(filter)) {
   1540         return false;
   1541     }
   1542 
   1543     SkAutoLockPixels alp(src, !src.getTexture());
   1544     if (!src.getTexture() && !src.readyToDraw()) {
   1545         return false;
   1546     }
   1547 
   1548     GrTexture* texture;
   1549     // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup
   1550     // must be pushed upstack.
   1551     SkAutoCachedTexture act(this, src, NULL, &texture);
   1552 
   1553     return filter_texture(this, fContext, texture, filter, src.width(), src.height(), ctm, result,
   1554                           offset);
   1555 }
   1556 
   1557 ///////////////////////////////////////////////////////////////////////////////
   1558 
   1559 // must be in SkCanvas::VertexMode order
   1560 static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
   1561     kTriangles_GrPrimitiveType,
   1562     kTriangleStrip_GrPrimitiveType,
   1563     kTriangleFan_GrPrimitiveType,
   1564 };
   1565 
   1566 void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
   1567                               int vertexCount, const SkPoint vertices[],
   1568                               const SkPoint texs[], const SkColor colors[],
   1569                               SkXfermode* xmode,
   1570                               const uint16_t indices[], int indexCount,
   1571                               const SkPaint& paint) {
   1572     CHECK_SHOULD_DRAW(draw, false);
   1573 
   1574     GrPaint grPaint;
   1575     // we ignore the shader if texs is null.
   1576     if (NULL == texs) {
   1577         if (!skPaint2GrPaintNoShader(this, paint, false, NULL == colors, &grPaint)) {
   1578             return;
   1579         }
   1580     } else {
   1581         if (!skPaint2GrPaintShader(this, paint, NULL == colors, &grPaint)) {
   1582             return;
   1583         }
   1584     }
   1585 
   1586     if (NULL != xmode && NULL != texs && NULL != colors) {
   1587         if (!SkXfermode::IsMode(xmode, SkXfermode::kModulate_Mode)) {
   1588             SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
   1589 #if 0
   1590             return
   1591 #endif
   1592         }
   1593     }
   1594 
   1595     SkAutoSTMalloc<128, GrColor> convertedColors(0);
   1596     if (NULL != colors) {
   1597         // need to convert byte order and from non-PM to PM
   1598         convertedColors.reset(vertexCount);
   1599         for (int i = 0; i < vertexCount; ++i) {
   1600             convertedColors[i] = SkColor2GrColor(colors[i]);
   1601         }
   1602         colors = convertedColors.get();
   1603     }
   1604     fContext->drawVertices(grPaint,
   1605                            gVertexMode2PrimitiveType[vmode],
   1606                            vertexCount,
   1607                            (GrPoint*) vertices,
   1608                            (GrPoint*) texs,
   1609                            colors,
   1610                            indices,
   1611                            indexCount);
   1612 }
   1613 
   1614 ///////////////////////////////////////////////////////////////////////////////
   1615 
   1616 static void GlyphCacheAuxProc(void* data) {
   1617     GrFontScaler* scaler = (GrFontScaler*)data;
   1618     SkSafeUnref(scaler);
   1619 }
   1620 
   1621 static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
   1622     void* auxData;
   1623     GrFontScaler* scaler = NULL;
   1624     if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
   1625         scaler = (GrFontScaler*)auxData;
   1626     }
   1627     if (NULL == scaler) {
   1628         scaler = SkNEW_ARGS(SkGrFontScaler, (cache));
   1629         cache->setAuxProc(GlyphCacheAuxProc, scaler);
   1630     }
   1631     return scaler;
   1632 }
   1633 
   1634 static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
   1635                              SkFixed fx, SkFixed fy,
   1636                              const SkGlyph& glyph) {
   1637     SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
   1638 
   1639     GrSkDrawProcs* procs = static_cast<GrSkDrawProcs*>(state.fDraw->fProcs);
   1640 
   1641     if (NULL == procs->fFontScaler) {
   1642         procs->fFontScaler = get_gr_font_scaler(state.fCache);
   1643     }
   1644 
   1645     procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
   1646                                                        glyph.getSubXFixed(),
   1647                                                        glyph.getSubYFixed()),
   1648                                          SkFixedFloorToFixed(fx),
   1649                                          SkFixedFloorToFixed(fy),
   1650                                          procs->fFontScaler);
   1651 }
   1652 
   1653 SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
   1654 
   1655     // deferred allocation
   1656     if (NULL == fDrawProcs) {
   1657         fDrawProcs = SkNEW(GrSkDrawProcs);
   1658         fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
   1659         fDrawProcs->fContext = fContext;
   1660     }
   1661 
   1662     // init our (and GL's) state
   1663     fDrawProcs->fTextContext = context;
   1664     fDrawProcs->fFontScaler = NULL;
   1665     return fDrawProcs;
   1666 }
   1667 
   1668 void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
   1669                           size_t byteLength, SkScalar x, SkScalar y,
   1670                           const SkPaint& paint) {
   1671     CHECK_SHOULD_DRAW(draw, false);
   1672 
   1673     if (fContext->getMatrix().hasPerspective()) {
   1674         // this guy will just call our drawPath()
   1675         draw.drawText((const char*)text, byteLength, x, y, paint);
   1676     } else {
   1677         SkDraw myDraw(draw);
   1678 
   1679         GrPaint grPaint;
   1680         if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   1681             return;
   1682         }
   1683         GrTextContext context(fContext, grPaint);
   1684         myDraw.fProcs = this->initDrawForText(&context);
   1685         this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
   1686     }
   1687 }
   1688 
   1689 void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
   1690                              size_t byteLength, const SkScalar pos[],
   1691                              SkScalar constY, int scalarsPerPos,
   1692                              const SkPaint& paint) {
   1693     CHECK_SHOULD_DRAW(draw, false);
   1694 
   1695     if (fContext->getMatrix().hasPerspective()) {
   1696         // this guy will just call our drawPath()
   1697         draw.drawPosText((const char*)text, byteLength, pos, constY,
   1698                          scalarsPerPos, paint);
   1699     } else {
   1700         SkDraw myDraw(draw);
   1701 
   1702         GrPaint grPaint;
   1703         if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   1704             return;
   1705         }
   1706         GrTextContext context(fContext, grPaint);
   1707         myDraw.fProcs = this->initDrawForText(&context);
   1708         this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
   1709                                      scalarsPerPos, paint);
   1710     }
   1711 }
   1712 
   1713 void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
   1714                                 size_t len, const SkPath& path,
   1715                                 const SkMatrix* m, const SkPaint& paint) {
   1716     CHECK_SHOULD_DRAW(draw, false);
   1717 
   1718     SkASSERT(draw.fDevice == this);
   1719     draw.drawTextOnPath((const char*)text, len, path, m, paint);
   1720 }
   1721 
   1722 ///////////////////////////////////////////////////////////////////////////////
   1723 
   1724 bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
   1725     if (!paint.isLCDRenderText()) {
   1726         // we're cool with the paint as is
   1727         return false;
   1728     }
   1729 
   1730     if (paint.getShader() ||
   1731         paint.getXfermode() || // unless its srcover
   1732         paint.getMaskFilter() ||
   1733         paint.getRasterizer() ||
   1734         paint.getColorFilter() ||
   1735         paint.getPathEffect() ||
   1736         paint.isFakeBoldText() ||
   1737         paint.getStyle() != SkPaint::kFill_Style) {
   1738         // turn off lcd
   1739         flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
   1740         flags->fHinting = paint.getHinting();
   1741         return true;
   1742     }
   1743     // we're cool with the paint as is
   1744     return false;
   1745 }
   1746 
   1747 void SkGpuDevice::flush() {
   1748     DO_DEFERRED_CLEAR();
   1749     fContext->resolveRenderTarget(fRenderTarget);
   1750 }
   1751 
   1752 ///////////////////////////////////////////////////////////////////////////////
   1753 
   1754 SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
   1755                                                 int width, int height,
   1756                                                 bool isOpaque,
   1757                                                 Usage usage) {
   1758     GrTextureDesc desc;
   1759     desc.fConfig = fRenderTarget->config();
   1760     desc.fFlags = kRenderTarget_GrTextureFlagBit;
   1761     desc.fWidth = width;
   1762     desc.fHeight = height;
   1763     desc.fSampleCnt = fRenderTarget->numSamples();
   1764 
   1765     SkAutoTUnref<GrTexture> texture;
   1766     // Skia's convention is to only clear a device if it is non-opaque.
   1767     bool needClear = !isOpaque;
   1768 
   1769 #if CACHE_COMPATIBLE_DEVICE_TEXTURES
   1770     // layers are never draw in repeat modes, so we can request an approx
   1771     // match and ignore any padding.
   1772     const GrContext::ScratchTexMatch match = (kSaveLayer_Usage == usage) ?
   1773                                                 GrContext::kApprox_ScratchTexMatch :
   1774                                                 GrContext::kExact_ScratchTexMatch;
   1775     texture.reset(fContext->lockAndRefScratchTexture(desc, match));
   1776 #else
   1777     texture.reset(fContext->createUncachedTexture(desc, NULL, 0));
   1778 #endif
   1779     if (NULL != texture.get()) {
   1780         return SkNEW_ARGS(SkGpuDevice,(fContext, texture, needClear));
   1781     } else {
   1782         GrPrintf("---- failed to create compatible device texture [%d %d]\n", width, height);
   1783         return NULL;
   1784     }
   1785 }
   1786 
   1787 SkGpuDevice::SkGpuDevice(GrContext* context,
   1788                          GrTexture* texture,
   1789                          bool needClear)
   1790     : SkDevice(make_bitmap(context, texture->asRenderTarget())) {
   1791 
   1792     GrAssert(texture && texture->asRenderTarget());
   1793     // This constructor is called from onCreateCompatibleDevice. It has locked the RT in the texture
   1794     // cache. We pass true for the third argument so that it will get unlocked.
   1795     this->initFromRenderTarget(context, texture->asRenderTarget(), true);
   1796     fNeedClear = needClear;
   1797 }
   1798