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