gfx/skia/trunk/src/gpu/SkGpuDevice.cpp

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

mercurial