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