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