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