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