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