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 "GrBitmapTextureMaker.h"
11 #include "GrBlurUtils.h"
12 #include "GrContext.h"
13 #include "GrGpu.h"
14 #include "GrImageTextureMaker.h"
15 #include "GrRenderTargetContextPriv.h"
16 #include "GrStyle.h"
17 #include "GrSurfaceProxyPriv.h"
18 #include "GrTextureAdjuster.h"
19 #include "GrTextureProxy.h"
20 #include "GrTracing.h"
21 #include "SkCanvasPriv.h"
22 #include "SkDraw.h"
23 #include "SkGlyphCache.h"
24 #include "SkGr.h"
25 #include "SkImageFilter.h"
26 #include "SkImageFilterCache.h"
27 #include "SkImageInfoPriv.h"
28 #include "SkImage_Base.h"
29 #include "SkLatticeIter.h"
30 #include "SkMaskFilter.h"
31 #include "SkPathEffect.h"
32 #include "SkPicture.h"
33 #include "SkPictureData.h"
34 #include "SkRRect.h"
35 #include "SkRasterClip.h"
36 #include "SkReadPixelsRec.h"
37 #include "SkRecord.h"
38 #include "SkSpecialImage.h"
39 #include "SkStroke.h"
40 #include "SkSurface.h"
41 #include "SkSurface_Gpu.h"
42 #include "SkTLazy.h"
43 #include "SkUtils.h"
44 #include "SkVertState.h"
45 #include "SkVertices.h"
46 #include "SkWritePixelsRec.h"
47 #include "effects/GrBicubicEffect.h"
48 #include "effects/GrSimpleTextureEffect.h"
49 #include "effects/GrTextureDomain.h"
50 #include "../private/SkShadowFlags.h"
51 #include "text/GrTextUtils.h"
52
53 #if SK_SUPPORT_GPU
54
55 #define ASSERT_SINGLE_OWNER \
56 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->debugSingleOwner());)
57
58 #if 0
59 extern bool (*gShouldDrawProc)();
60 #define CHECK_SHOULD_DRAW() \
61 do { \
62 if (gShouldDrawProc && !gShouldDrawProc()) return; \
63 } while (0)
64 #else
65 #define CHECK_SHOULD_DRAW()
66 #endif
67
68 ///////////////////////////////////////////////////////////////////////////////
69
70 /** Checks that the alpha type is legal and gets constructor flags. Returns false if device creation
71 should fail. */
CheckAlphaTypeAndGetFlags(const SkImageInfo * info,SkGpuDevice::InitContents init,unsigned * flags)72 bool SkGpuDevice::CheckAlphaTypeAndGetFlags(
73 const SkImageInfo* info, SkGpuDevice::InitContents init, unsigned* flags) {
74 *flags = 0;
75 if (info) {
76 switch (info->alphaType()) {
77 case kPremul_SkAlphaType:
78 break;
79 case kOpaque_SkAlphaType:
80 *flags |= SkGpuDevice::kIsOpaque_Flag;
81 break;
82 default: // If it is unpremul or unknown don't try to render
83 return false;
84 }
85 }
86 if (kClear_InitContents == init) {
87 *flags |= kNeedClear_Flag;
88 }
89 return true;
90 }
91
Make(GrContext * context,sk_sp<GrRenderTargetContext> renderTargetContext,int width,int height,InitContents init)92 sk_sp<SkGpuDevice> SkGpuDevice::Make(GrContext* context,
93 sk_sp<GrRenderTargetContext> renderTargetContext,
94 int width, int height,
95 InitContents init) {
96 if (!renderTargetContext || renderTargetContext->wasAbandoned()) {
97 return nullptr;
98 }
99 unsigned flags;
100 if (!CheckAlphaTypeAndGetFlags(nullptr, init, &flags)) {
101 return nullptr;
102 }
103 return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext),
104 width, height, flags));
105 }
106
Make(GrContext * context,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,InitContents init)107 sk_sp<SkGpuDevice> SkGpuDevice::Make(GrContext* context, SkBudgeted budgeted,
108 const SkImageInfo& info, int sampleCount,
109 GrSurfaceOrigin origin,
110 const SkSurfaceProps* props, InitContents init) {
111 unsigned flags;
112 if (!CheckAlphaTypeAndGetFlags(&info, init, &flags)) {
113 return nullptr;
114 }
115
116 sk_sp<GrRenderTargetContext> renderTargetContext(MakeRenderTargetContext(context, budgeted,
117 info, sampleCount,
118 origin, props));
119 if (!renderTargetContext) {
120 return nullptr;
121 }
122
123 return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext),
124 info.width(), info.height(), flags));
125 }
126
make_info(GrRenderTargetContext * context,int w,int h,bool opaque)127 static SkImageInfo make_info(GrRenderTargetContext* context, int w, int h, bool opaque) {
128 SkColorType colorType;
129 if (!GrPixelConfigToColorType(context->config(), &colorType)) {
130 colorType = kUnknown_SkColorType;
131 }
132 return SkImageInfo::Make(w, h, colorType,
133 opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
134 context->refColorSpace());
135 }
136
SkGpuDevice(GrContext * context,sk_sp<GrRenderTargetContext> renderTargetContext,int width,int height,unsigned flags)137 SkGpuDevice::SkGpuDevice(GrContext* context, sk_sp<GrRenderTargetContext> renderTargetContext,
138 int width, int height, unsigned flags)
139 : INHERITED(make_info(renderTargetContext.get(), width, height,
140 SkToBool(flags & kIsOpaque_Flag)), renderTargetContext->surfaceProps())
141 , fContext(SkRef(context))
142 , fRenderTargetContext(std::move(renderTargetContext))
143 {
144 fSize.set(width, height);
145 fOpaque = SkToBool(flags & kIsOpaque_Flag);
146
147 if (flags & kNeedClear_Flag) {
148 this->clearAll();
149 }
150 }
151
MakeRenderTargetContext(GrContext * context,SkBudgeted budgeted,const SkImageInfo & origInfo,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * surfaceProps)152 sk_sp<GrRenderTargetContext> SkGpuDevice::MakeRenderTargetContext(
153 GrContext* context,
154 SkBudgeted budgeted,
155 const SkImageInfo& origInfo,
156 int sampleCount,
157 GrSurfaceOrigin origin,
158 const SkSurfaceProps* surfaceProps) {
159 if (kUnknown_SkColorType == origInfo.colorType() ||
160 origInfo.width() < 0 || origInfo.height() < 0) {
161 return nullptr;
162 }
163
164 if (!context) {
165 return nullptr;
166 }
167
168 GrPixelConfig config = SkImageInfo2GrPixelConfig(origInfo, *context->caps());
169 // This method is used to create SkGpuDevice's for SkSurface_Gpus. In this case
170 // they need to be exact.
171 return context->makeDeferredRenderTargetContext(
172 SkBackingFit::kExact,
173 origInfo.width(), origInfo.height(),
174 config, origInfo.refColorSpace(), sampleCount,
175 origin, surfaceProps, budgeted);
176 }
177
filterTexture(SkSpecialImage * srcImg,int left,int top,SkIPoint * offset,const SkImageFilter * filter)178 sk_sp<SkSpecialImage> SkGpuDevice::filterTexture(SkSpecialImage* srcImg,
179 int left, int top,
180 SkIPoint* offset,
181 const SkImageFilter* filter) {
182 SkASSERT(srcImg->isTextureBacked());
183 SkASSERT(filter);
184
185 SkMatrix matrix = this->ctm();
186 matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
187 const SkIRect clipBounds = this->devClipBounds().makeOffset(-left, -top);
188 sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
189 SkImageFilter::OutputProperties outputProperties(fRenderTargetContext->getColorSpace());
190 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
191
192 return filter->filterImage(srcImg, ctx, offset);
193 }
194
195 ///////////////////////////////////////////////////////////////////////////////
196
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int x,int y)197 bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
198 int x, int y) {
199 ASSERT_SINGLE_OWNER
200
201 if (!SkImageInfoValidConversion(dstInfo, this->imageInfo())) {
202 return false;
203 }
204
205 SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, x, y);
206 if (!rec.trim(this->width(), this->height())) {
207 return false;
208 }
209
210 return fRenderTargetContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
211 }
212
onWritePixels(const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRowBytes,int x,int y)213 bool SkGpuDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
214 size_t srcRowBytes, int x, int y) {
215 ASSERT_SINGLE_OWNER
216
217 if (!SkImageInfoValidConversion(this->imageInfo(), srcInfo)) {
218 return false;
219 }
220
221 SkWritePixelsRec rec(srcInfo, srcPixels, srcRowBytes, x, y);
222 if (!rec.trim(this->width(), this->height())) {
223 return false;
224 }
225
226 return fRenderTargetContext->writePixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
227 }
228
onAccessPixels(SkPixmap * pmap)229 bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) {
230 ASSERT_SINGLE_OWNER
231 return false;
232 }
233
accessRenderTargetContext()234 GrRenderTargetContext* SkGpuDevice::accessRenderTargetContext() {
235 ASSERT_SINGLE_OWNER
236 return fRenderTargetContext.get();
237 }
238
clearAll()239 void SkGpuDevice::clearAll() {
240 ASSERT_SINGLE_OWNER
241 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext.get());
242
243 SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
244 fRenderTargetContext->clear(&rect, 0x0, true);
245 }
246
replaceRenderTargetContext(bool shouldRetainContent)247 void SkGpuDevice::replaceRenderTargetContext(bool shouldRetainContent) {
248 ASSERT_SINGLE_OWNER
249
250 SkBudgeted budgeted = fRenderTargetContext->priv().isBudgeted();
251
252 // This entry point is used by SkSurface_Gpu::onCopyOnWrite so it must create a
253 // kExact-backed render target context.
254 sk_sp<GrRenderTargetContext> newRTC(MakeRenderTargetContext(
255 this->context(),
256 budgeted,
257 this->imageInfo(),
258 fRenderTargetContext->numColorSamples(),
259 fRenderTargetContext->origin(),
260 &this->surfaceProps()));
261 if (!newRTC) {
262 return;
263 }
264 SkASSERT(newRTC->asSurfaceProxy()->priv().isExact());
265
266 if (shouldRetainContent) {
267 if (fRenderTargetContext->wasAbandoned()) {
268 return;
269 }
270 newRTC->copy(fRenderTargetContext->asSurfaceProxy());
271 }
272
273 fRenderTargetContext = newRTC;
274 }
275
276 ///////////////////////////////////////////////////////////////////////////////
277
drawPaint(const SkPaint & paint)278 void SkGpuDevice::drawPaint(const SkPaint& paint) {
279 ASSERT_SINGLE_OWNER
280 CHECK_SHOULD_DRAW();
281 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext.get());
282
283 GrPaint grPaint;
284 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
285 &grPaint)) {
286 return;
287 }
288
289 fRenderTargetContext->drawPaint(this->clip(), std::move(grPaint), this->ctm());
290 }
291
292 // must be in SkCanvas::PointMode order
293 static const GrPrimitiveType gPointMode2PrimitiveType[] = {
294 GrPrimitiveType::kPoints,
295 GrPrimitiveType::kLines,
296 GrPrimitiveType::kLineStrip
297 };
298
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)299 void SkGpuDevice::drawPoints(SkCanvas::PointMode mode,
300 size_t count, const SkPoint pts[], const SkPaint& paint) {
301 ASSERT_SINGLE_OWNER
302 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext.get());
303 CHECK_SHOULD_DRAW();
304
305 SkScalar width = paint.getStrokeWidth();
306 if (width < 0) {
307 return;
308 }
309
310 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
311 GrStyle style(paint, SkPaint::kStroke_Style);
312 GrPaint grPaint;
313 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
314 &grPaint)) {
315 return;
316 }
317 SkPath path;
318 path.setIsVolatile(true);
319 path.moveTo(pts[0]);
320 path.lineTo(pts[1]);
321 fRenderTargetContext->drawPath(this->clip(), std::move(grPaint),
322 GrBoolToAA(paint.isAntiAlias()), this->ctm(), path, style);
323 return;
324 }
325
326 SkScalar scales[2];
327 bool isHairline = (0 == width) || (1 == width && this->ctm().getMinMaxScales(scales) &&
328 SkScalarNearlyEqual(scales[0], 1.f) &&
329 SkScalarNearlyEqual(scales[1], 1.f));
330 // we only handle non-antialiased hairlines and paints without path effects or mask filters,
331 // else we let the SkDraw call our drawPath()
332 if (!isHairline || paint.getPathEffect() || paint.getMaskFilter() || paint.isAntiAlias()) {
333 SkRasterClip rc(this->devClipBounds());
334 SkDraw draw;
335 draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0);
336 draw.fMatrix = &this->ctm();
337 draw.fRC = &rc;
338 draw.drawPoints(mode, count, pts, paint, this);
339 return;
340 }
341
342 GrPrimitiveType primitiveType = gPointMode2PrimitiveType[mode];
343
344 const SkMatrix* viewMatrix = &this->ctm();
345 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
346 // This offsetting in device space matches the expectations of the Android framework for non-AA
347 // points and lines.
348 SkMatrix tempMatrix;
349 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
350 tempMatrix = *viewMatrix;
351 static const SkScalar kOffset = 0.063f; // Just greater than 1/16.
352 tempMatrix.postTranslate(kOffset, kOffset);
353 viewMatrix = &tempMatrix;
354 }
355 #endif
356
357 GrPaint grPaint;
358 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, *viewMatrix,
359 &grPaint)) {
360 return;
361 }
362
363 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
364 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr,
365 nullptr);
366
367 fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), *viewMatrix,
368 std::move(vertices), &primitiveType);
369 }
370
371 ///////////////////////////////////////////////////////////////////////////////
372
drawRect(const SkRect & rect,const SkPaint & paint)373 void SkGpuDevice::drawRect(const SkRect& rect, const SkPaint& paint) {
374 ASSERT_SINGLE_OWNER
375 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext.get());
376 CHECK_SHOULD_DRAW();
377
378
379 // A couple reasons we might need to call drawPath.
380 if (paint.getMaskFilter() || paint.getPathEffect()) {
381 SkPath path;
382 path.setIsVolatile(true);
383 path.addRect(rect);
384 GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(),
385 this->clip(), path, paint, this->ctm(), nullptr,
386 this->devClipBounds(), true);
387 return;
388 }
389
390 GrPaint grPaint;
391 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
392 &grPaint)) {
393 return;
394 }
395
396 GrStyle style(paint);
397 fRenderTargetContext->drawRect(this->clip(), std::move(grPaint),
398 GrBoolToAA(paint.isAntiAlias()), this->ctm(), rect, &style);
399 }
400
401 ///////////////////////////////////////////////////////////////////////////////
402
drawRRect(const SkRRect & rrect,const SkPaint & paint)403 void SkGpuDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
404 ASSERT_SINGLE_OWNER
405 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext.get());
406 CHECK_SHOULD_DRAW();
407
408 GrPaint grPaint;
409 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
410 &grPaint)) {
411 return;
412 }
413
414 SkMaskFilter* mf = paint.getMaskFilter();
415 if (mf && mf->asFragmentProcessor(nullptr)) {
416 mf = nullptr; // already handled in SkPaintToGrPaint
417 }
418
419 GrStyle style(paint);
420 if (mf) {
421 // try to hit the fast path for drawing filtered round rects
422
423 SkRRect devRRect;
424 if (rrect.transform(this->ctm(), &devRRect)) {
425 if (devRRect.allCornersCircular()) {
426 SkRect maskRect;
427 if (mf->canFilterMaskGPU(devRRect, this->devClipBounds(),
428 this->ctm(), &maskRect)) {
429 SkIRect finalIRect;
430 maskRect.roundOut(&finalIRect);
431
432 // we used to test finalIRect for quickReject, but that seems unlikely
433 // given that the original shape was not rejected...
434
435 if (mf->directFilterRRectMaskGPU(this->context(), fRenderTargetContext.get(),
436 std::move(grPaint), this->clip(), this->ctm(),
437 style.strokeRec(), rrect, devRRect)) {
438 return;
439 }
440 }
441
442 }
443 }
444 }
445
446 if (mf || style.pathEffect()) {
447 // The only mask filter the native rrect drawing code could've handle was taken
448 // care of above.
449 // A path effect will presumably transform this rrect into something else.
450 SkPath path;
451 path.setIsVolatile(true);
452 path.addRRect(rrect);
453 GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(),
454 this->clip(), path, paint, this->ctm(), nullptr,
455 this->devClipBounds(), true);
456 return;
457 }
458
459 SkASSERT(!style.pathEffect());
460
461 fRenderTargetContext->drawRRect(this->clip(), std::move(grPaint),
462 GrBoolToAA(paint.isAntiAlias()), this->ctm(), rrect, style);
463 }
464
465
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)466 void SkGpuDevice::drawDRRect(const SkRRect& outer,
467 const SkRRect& inner, const SkPaint& paint) {
468 ASSERT_SINGLE_OWNER
469 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext.get());
470 CHECK_SHOULD_DRAW();
471
472 if (outer.isEmpty()) {
473 return;
474 }
475
476 if (inner.isEmpty()) {
477 return this->drawRRect(outer, paint);
478 }
479
480 SkStrokeRec stroke(paint);
481
482 if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
483 GrPaint grPaint;
484 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
485 &grPaint)) {
486 return;
487 }
488
489 fRenderTargetContext->drawDRRect(this->clip(), std::move(grPaint),
490 GrBoolToAA(paint.isAntiAlias()), this->ctm(), outer,
491 inner);
492 return;
493 }
494
495 SkPath path;
496 path.setIsVolatile(true);
497 path.addRRect(outer);
498 path.addRRect(inner);
499 path.setFillType(SkPath::kEvenOdd_FillType);
500
501 GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(),
502 path, paint, this->ctm(), nullptr, this->devClipBounds(),
503 true);
504 }
505
506
507 /////////////////////////////////////////////////////////////////////////////
508
drawRegion(const SkRegion & region,const SkPaint & paint)509 void SkGpuDevice::drawRegion(const SkRegion& region, const SkPaint& paint) {
510 if (paint.getMaskFilter()) {
511 SkPath path;
512 region.getBoundaryPath(&path);
513 return this->drawPath(path, paint, nullptr, false);
514 }
515
516 GrPaint grPaint;
517 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
518 &grPaint)) {
519 return;
520 }
521
522 fRenderTargetContext->drawRegion(this->clip(), std::move(grPaint),
523 GrBoolToAA(paint.isAntiAlias()), this->ctm(), region,
524 GrStyle(paint));
525 }
526
drawOval(const SkRect & oval,const SkPaint & paint)527 void SkGpuDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
528 ASSERT_SINGLE_OWNER
529 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext.get());
530 CHECK_SHOULD_DRAW();
531
532 // Presumably the path effect warps this to something other than an oval
533 if (paint.getPathEffect()) {
534 SkPath path;
535 path.setIsVolatile(true);
536 path.addOval(oval);
537 this->drawPath(path, paint, nullptr, true);
538 return;
539 }
540
541 if (paint.getMaskFilter()) {
542 // The RRect path can handle special case blurring
543 SkRRect rr = SkRRect::MakeOval(oval);
544 return this->drawRRect(rr, paint);
545 }
546
547 GrPaint grPaint;
548 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
549 &grPaint)) {
550 return;
551 }
552
553 fRenderTargetContext->drawOval(this->clip(), std::move(grPaint),
554 GrBoolToAA(paint.isAntiAlias()), this->ctm(), oval,
555 GrStyle(paint));
556 }
557
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)558 void SkGpuDevice::drawArc(const SkRect& oval, SkScalar startAngle,
559 SkScalar sweepAngle, bool useCenter, const SkPaint& paint) {
560 ASSERT_SINGLE_OWNER
561 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawArc", fContext.get());
562 CHECK_SHOULD_DRAW();
563
564 if (paint.getMaskFilter()) {
565 this->INHERITED::drawArc(oval, startAngle, sweepAngle, useCenter, paint);
566 return;
567 }
568 GrPaint grPaint;
569 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
570 &grPaint)) {
571 return;
572 }
573
574 fRenderTargetContext->drawArc(this->clip(), std::move(grPaint), GrBoolToAA(paint.isAntiAlias()),
575 this->ctm(), oval, startAngle, sweepAngle, useCenter,
576 GrStyle(paint));
577 }
578
579 #include "SkMaskFilter.h"
580
581 ///////////////////////////////////////////////////////////////////////////////
drawStrokedLine(const SkPoint points[2],const SkPaint & origPaint)582 void SkGpuDevice::drawStrokedLine(const SkPoint points[2],
583 const SkPaint& origPaint) {
584 ASSERT_SINGLE_OWNER
585 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawStrokedLine", fContext.get());
586 CHECK_SHOULD_DRAW();
587
588 // Adding support for round capping would require a
589 // GrRenderTargetContext::fillRRectWithLocalMatrix entry point
590 SkASSERT(SkPaint::kRound_Cap != origPaint.getStrokeCap());
591 SkASSERT(SkPaint::kStroke_Style == origPaint.getStyle());
592 SkASSERT(!origPaint.getPathEffect());
593 SkASSERT(!origPaint.getMaskFilter());
594
595 const SkScalar halfWidth = 0.5f * origPaint.getStrokeWidth();
596 SkASSERT(halfWidth > 0);
597
598 SkVector v = points[1] - points[0];
599
600 SkScalar length = SkPoint::Normalize(&v);
601 if (!length) {
602 v.fX = 1.0f;
603 v.fY = 0.0f;
604 }
605
606 SkPaint newPaint(origPaint);
607 newPaint.setStyle(SkPaint::kFill_Style);
608
609 SkScalar xtraLength = 0.0f;
610 if (SkPaint::kButt_Cap != origPaint.getStrokeCap()) {
611 xtraLength = halfWidth;
612 }
613
614 SkPoint mid = points[0] + points[1];
615 mid.scale(0.5f);
616
617 SkRect rect = SkRect::MakeLTRB(mid.fX-halfWidth, mid.fY - 0.5f*length - xtraLength,
618 mid.fX+halfWidth, mid.fY + 0.5f*length + xtraLength);
619 SkMatrix m;
620 m.setSinCos(v.fX, -v.fY, mid.fX, mid.fY);
621
622 SkMatrix local = m;
623
624 m.postConcat(this->ctm());
625
626 GrPaint grPaint;
627 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), newPaint, m, &grPaint)) {
628 return;
629 }
630
631 fRenderTargetContext->fillRectWithLocalMatrix(
632 this->clip(), std::move(grPaint), GrBoolToAA(newPaint.isAntiAlias()), m, rect, local);
633 }
634
drawPath(const SkPath & origSrcPath,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)635 void SkGpuDevice::drawPath(const SkPath& origSrcPath,
636 const SkPaint& paint, const SkMatrix* prePathMatrix,
637 bool pathIsMutable) {
638 ASSERT_SINGLE_OWNER
639 if (!origSrcPath.isInverseFillType() && !paint.getPathEffect() && !prePathMatrix) {
640 SkPoint points[2];
641 if (SkPaint::kStroke_Style == paint.getStyle() && paint.getStrokeWidth() > 0 &&
642 !paint.getMaskFilter() && SkPaint::kRound_Cap != paint.getStrokeCap() &&
643 this->ctm().preservesRightAngles() && origSrcPath.isLine(points)) {
644 // Path-based stroking looks better for thin rects
645 SkScalar strokeWidth = this->ctm().getMaxScale() * paint.getStrokeWidth();
646 if (strokeWidth >= 1.0f) {
647 // Round capping support is currently disabled b.c. it would require a RRect
648 // GrDrawOp that takes a localMatrix.
649 this->drawStrokedLine(points, paint);
650 return;
651 }
652 }
653 bool isClosed;
654 SkRect rect;
655 if (origSrcPath.isRect(&rect, &isClosed) && isClosed) {
656 this->drawRect(rect, paint);
657 return;
658 }
659 if (origSrcPath.isOval(&rect)) {
660 this->drawOval(rect, paint);
661 return;
662 }
663 SkRRect rrect;
664 if (origSrcPath.isRRect(&rrect)) {
665 this->drawRRect(rrect, paint);
666 return;
667 }
668 }
669
670 CHECK_SHOULD_DRAW();
671 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext.get());
672
673 GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(),
674 origSrcPath, paint, this->ctm(), prePathMatrix,
675 this->devClipBounds(), pathIsMutable);
676 }
677
678 static const int kBmpSmallTileSize = 1 << 10;
679
get_tile_count(const SkIRect & srcRect,int tileSize)680 static inline int get_tile_count(const SkIRect& srcRect, int tileSize) {
681 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
682 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
683 return tilesX * tilesY;
684 }
685
determine_tile_size(const SkIRect & src,int maxTileSize)686 static int determine_tile_size(const SkIRect& src, int maxTileSize) {
687 if (maxTileSize <= kBmpSmallTileSize) {
688 return maxTileSize;
689 }
690
691 size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
692 size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
693
694 maxTileTotalTileSize *= maxTileSize * maxTileSize;
695 smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
696
697 if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
698 return kBmpSmallTileSize;
699 } else {
700 return maxTileSize;
701 }
702 }
703
704 // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
705 // pixels from the bitmap are necessary.
determine_clipped_src_rect(int width,int height,const GrClip & clip,const SkMatrix & viewMatrix,const SkMatrix & srcToDstRect,const SkISize & imageSize,const SkRect * srcRectPtr,SkIRect * clippedSrcIRect)706 static void determine_clipped_src_rect(int width, int height,
707 const GrClip& clip,
708 const SkMatrix& viewMatrix,
709 const SkMatrix& srcToDstRect,
710 const SkISize& imageSize,
711 const SkRect* srcRectPtr,
712 SkIRect* clippedSrcIRect) {
713 clip.getConservativeBounds(width, height, clippedSrcIRect, nullptr);
714 SkMatrix inv = SkMatrix::Concat(viewMatrix, srcToDstRect);
715 if (!inv.invert(&inv)) {
716 clippedSrcIRect->setEmpty();
717 return;
718 }
719 SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect);
720 inv.mapRect(&clippedSrcRect);
721 if (srcRectPtr) {
722 if (!clippedSrcRect.intersect(*srcRectPtr)) {
723 clippedSrcIRect->setEmpty();
724 return;
725 }
726 }
727 clippedSrcRect.roundOut(clippedSrcIRect);
728 SkIRect bmpBounds = SkIRect::MakeSize(imageSize);
729 if (!clippedSrcIRect->intersect(bmpBounds)) {
730 clippedSrcIRect->setEmpty();
731 }
732 }
733
shouldTileImageID(uint32_t imageID,const SkIRect & imageRect,const SkMatrix & viewMatrix,const SkMatrix & srcToDstRect,const GrSamplerParams & params,const SkRect * srcRectPtr,int maxTileSize,int * tileSize,SkIRect * clippedSubset) const734 bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect,
735 const SkMatrix& viewMatrix,
736 const SkMatrix& srcToDstRect,
737 const GrSamplerParams& params,
738 const SkRect* srcRectPtr,
739 int maxTileSize,
740 int* tileSize,
741 SkIRect* clippedSubset) const {
742 ASSERT_SINGLE_OWNER
743 // if it's larger than the max tile size, then we have no choice but tiling.
744 if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) {
745 determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(),
746 this->clip(), viewMatrix, srcToDstRect, imageRect.size(),
747 srcRectPtr, clippedSubset);
748 *tileSize = determine_tile_size(*clippedSubset, maxTileSize);
749 return true;
750 }
751
752 // If the image would only produce 4 tiles of the smaller size, don't bother tiling it.
753 const size_t area = imageRect.width() * imageRect.height();
754 if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
755 return false;
756 }
757
758 // At this point we know we could do the draw by uploading the entire bitmap
759 // as a texture. However, if the texture would be large compared to the
760 // cache size and we don't require most of it for this draw then tile to
761 // reduce the amount of upload and cache spill.
762
763 // assumption here is that sw bitmap size is a good proxy for its size as
764 // a texture
765 size_t bmpSize = area * sizeof(SkPMColor); // assume 32bit pixels
766 size_t cacheSize;
767 fContext->getResourceCacheLimits(nullptr, &cacheSize);
768 if (bmpSize < cacheSize / 2) {
769 return false;
770 }
771
772 // Figure out how much of the src we will need based on the src rect and clipping. Reject if
773 // tiling memory savings would be < 50%.
774 determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(),
775 this->clip(), viewMatrix, srcToDstRect, imageRect.size(), srcRectPtr,
776 clippedSubset);
777 *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
778 size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) *
779 kBmpSmallTileSize * kBmpSmallTileSize *
780 sizeof(SkPMColor); // assume 32bit pixels;
781
782 return usedTileBytes * 2 < bmpSize;
783 }
784
shouldTileImage(const SkImage * image,const SkRect * srcRectPtr,SkCanvas::SrcRectConstraint constraint,SkFilterQuality quality,const SkMatrix & viewMatrix,const SkMatrix & srcToDstRect) const785 bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr,
786 SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality,
787 const SkMatrix& viewMatrix,
788 const SkMatrix& srcToDstRect) const {
789 ASSERT_SINGLE_OWNER
790 // if image is explictly texture backed then just use the texture
791 if (image->isTextureBacked()) {
792 return false;
793 }
794
795 GrSamplerParams params;
796 bool doBicubic;
797 GrSamplerParams::FilterMode textureFilterMode =
798 GrSkFilterQualityToGrFilterMode(quality, viewMatrix, srcToDstRect, &doBicubic);
799
800 int tileFilterPad;
801 if (doBicubic) {
802 tileFilterPad = GrBicubicEffect::kFilterTexelPad;
803 } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
804 tileFilterPad = 0;
805 } else {
806 tileFilterPad = 1;
807 }
808 params.setFilterMode(textureFilterMode);
809
810 int maxTileSize = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
811
812 // these are output, which we safely ignore, as we just want to know the predicate
813 int outTileSize;
814 SkIRect outClippedSrcRect;
815
816 return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, srcToDstRect,
817 params, srcRectPtr, maxTileSize, &outTileSize,
818 &outClippedSrcRect);
819 }
820
drawBitmap(const SkBitmap & bitmap,SkScalar x,SkScalar y,const SkPaint & paint)821 void SkGpuDevice::drawBitmap(const SkBitmap& bitmap,
822 SkScalar x,
823 SkScalar y,
824 const SkPaint& paint) {
825 SkMatrix m = SkMatrix::MakeTrans(x, y);
826 ASSERT_SINGLE_OWNER
827 CHECK_SHOULD_DRAW();
828 SkMatrix viewMatrix;
829 viewMatrix.setConcat(this->ctm(), m);
830
831 int maxTileSize = fContext->caps()->maxTileSize();
832
833 // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
834 // draw untiled, then we bypass checking for tiling purely for optimization reasons.
835 bool drawAA = GrFSAAType::kUnifiedMSAA != fRenderTargetContext->fsaaType() &&
836 paint.isAntiAlias() && bitmap.width() <= maxTileSize &&
837 bitmap.height() <= maxTileSize;
838
839 bool skipTileCheck = drawAA || paint.getMaskFilter();
840
841 if (!skipTileCheck) {
842 SkRect srcRect = SkRect::MakeIWH(bitmap.width(), bitmap.height());
843 int tileSize;
844 SkIRect clippedSrcRect;
845
846 GrSamplerParams params;
847 bool doBicubic;
848 GrSamplerParams::FilterMode textureFilterMode =
849 GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, SkMatrix::I(),
850 &doBicubic);
851
852 int tileFilterPad;
853
854 if (doBicubic) {
855 tileFilterPad = GrBicubicEffect::kFilterTexelPad;
856 } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
857 tileFilterPad = 0;
858 } else {
859 tileFilterPad = 1;
860 }
861 params.setFilterMode(textureFilterMode);
862
863 int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
864 if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), viewMatrix,
865 SkMatrix::I(), params, &srcRect, maxTileSizeForFilter,
866 &tileSize, &clippedSrcRect)) {
867 this->drawTiledBitmap(bitmap, viewMatrix, SkMatrix::I(), srcRect, clippedSrcRect,
868 params, paint, SkCanvas::kStrict_SrcRectConstraint, tileSize,
869 doBicubic);
870 return;
871 }
872 }
873 GrBitmapTextureMaker maker(fContext.get(), bitmap);
874 this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kStrict_SrcRectConstraint,
875 viewMatrix, this->clip(), paint);
876 }
877
878 // This method outsets 'iRect' by 'outset' all around and then clamps its extents to
879 // 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
880 // of 'iRect' for all possible outsets/clamps.
clamped_outset_with_offset(SkIRect * iRect,int outset,SkPoint * offset,const SkIRect & clamp)881 static inline void clamped_outset_with_offset(SkIRect* iRect,
882 int outset,
883 SkPoint* offset,
884 const SkIRect& clamp) {
885 iRect->outset(outset, outset);
886
887 int leftClampDelta = clamp.fLeft - iRect->fLeft;
888 if (leftClampDelta > 0) {
889 offset->fX -= outset - leftClampDelta;
890 iRect->fLeft = clamp.fLeft;
891 } else {
892 offset->fX -= outset;
893 }
894
895 int topClampDelta = clamp.fTop - iRect->fTop;
896 if (topClampDelta > 0) {
897 offset->fY -= outset - topClampDelta;
898 iRect->fTop = clamp.fTop;
899 } else {
900 offset->fY -= outset;
901 }
902
903 if (iRect->fRight > clamp.fRight) {
904 iRect->fRight = clamp.fRight;
905 }
906 if (iRect->fBottom > clamp.fBottom) {
907 iRect->fBottom = clamp.fBottom;
908 }
909 }
910
911 // Break 'bitmap' into several tiles to draw it since it has already
912 // been determined to be too large to fit in VRAM
drawTiledBitmap(const SkBitmap & bitmap,const SkMatrix & viewMatrix,const SkMatrix & dstMatrix,const SkRect & srcRect,const SkIRect & clippedSrcIRect,const GrSamplerParams & params,const SkPaint & origPaint,SkCanvas::SrcRectConstraint constraint,int tileSize,bool bicubic)913 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
914 const SkMatrix& viewMatrix,
915 const SkMatrix& dstMatrix,
916 const SkRect& srcRect,
917 const SkIRect& clippedSrcIRect,
918 const GrSamplerParams& params,
919 const SkPaint& origPaint,
920 SkCanvas::SrcRectConstraint constraint,
921 int tileSize,
922 bool bicubic) {
923 ASSERT_SINGLE_OWNER
924
925 // This is the funnel for all paths that draw tiled bitmaps/images. Log histogram entries.
926 SK_HISTOGRAM_BOOLEAN("DrawTiled", true);
927 LogDrawScaleFactor(viewMatrix, origPaint.getFilterQuality());
928
929 const SkPaint* paint = &origPaint;
930 SkPaint tempPaint;
931 if (origPaint.isAntiAlias() && GrFSAAType::kUnifiedMSAA != fRenderTargetContext->fsaaType()) {
932 // Drop antialiasing to avoid seams at tile boundaries.
933 tempPaint = origPaint;
934 tempPaint.setAntiAlias(false);
935 paint = &tempPaint;
936 }
937 SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
938
939 int nx = bitmap.width() / tileSize;
940 int ny = bitmap.height() / tileSize;
941 for (int x = 0; x <= nx; x++) {
942 for (int y = 0; y <= ny; y++) {
943 SkRect tileR;
944 tileR.set(SkIntToScalar(x * tileSize),
945 SkIntToScalar(y * tileSize),
946 SkIntToScalar((x + 1) * tileSize),
947 SkIntToScalar((y + 1) * tileSize));
948
949 if (!SkRect::Intersects(tileR, clippedSrcRect)) {
950 continue;
951 }
952
953 if (!tileR.intersect(srcRect)) {
954 continue;
955 }
956
957 SkIRect iTileR;
958 tileR.roundOut(&iTileR);
959 SkVector offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
960 SkIntToScalar(iTileR.fTop));
961 SkRect rectToDraw = tileR;
962 dstMatrix.mapRect(&rectToDraw);
963 if (GrSamplerParams::kNone_FilterMode != params.filterMode() || bicubic) {
964 SkIRect iClampRect;
965
966 if (SkCanvas::kFast_SrcRectConstraint == constraint) {
967 // In bleed mode we want to always expand the tile on all edges
968 // but stay within the bitmap bounds
969 iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
970 } else {
971 // In texture-domain/clamp mode we only want to expand the
972 // tile on edges interior to "srcRect" (i.e., we want to
973 // not bleed across the original clamped edges)
974 srcRect.roundOut(&iClampRect);
975 }
976 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
977 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
978 }
979
980 SkBitmap tmpB;
981 if (bitmap.extractSubset(&tmpB, iTileR)) {
982 // now offset it to make it "local" to our tmp bitmap
983 tileR.offset(-offset.fX, -offset.fY);
984 // de-optimized this determination
985 bool needsTextureDomain = true;
986 this->drawBitmapTile(tmpB,
987 viewMatrix,
988 rectToDraw,
989 tileR,
990 params,
991 *paint,
992 constraint,
993 bicubic,
994 needsTextureDomain);
995 }
996 }
997 }
998 }
999
drawBitmapTile(const SkBitmap & bitmap,const SkMatrix & viewMatrix,const SkRect & dstRect,const SkRect & srcRect,const GrSamplerParams & params,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint,bool bicubic,bool needsTextureDomain)1000 void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap,
1001 const SkMatrix& viewMatrix,
1002 const SkRect& dstRect,
1003 const SkRect& srcRect,
1004 const GrSamplerParams& params,
1005 const SkPaint& paint,
1006 SkCanvas::SrcRectConstraint constraint,
1007 bool bicubic,
1008 bool needsTextureDomain) {
1009 // We should have already handled bitmaps larger than the max texture size.
1010 SkASSERT(bitmap.width() <= fContext->caps()->maxTextureSize() &&
1011 bitmap.height() <= fContext->caps()->maxTextureSize());
1012 // We should be respecting the max tile size by the time we get here.
1013 SkASSERT(bitmap.width() <= fContext->caps()->maxTileSize() &&
1014 bitmap.height() <= fContext->caps()->maxTileSize());
1015
1016 SkASSERT(SkShader::kClamp_TileMode == params.getTileModeX() &&
1017 SkShader::kClamp_TileMode == params.getTileModeY());
1018
1019 sk_sp<GrTextureProxy> proxy = GrRefCachedBitmapTextureProxy(fContext.get(), bitmap,
1020 params, nullptr);
1021 if (!proxy) {
1022 return;
1023 }
1024 sk_sp<GrColorSpaceXform> colorSpaceXform =
1025 GrColorSpaceXform::Make(bitmap.colorSpace(), fRenderTargetContext->getColorSpace());
1026
1027 // Compute a matrix that maps the rect we will draw to the src rect.
1028 const SkMatrix texMatrix = SkMatrix::MakeRectToRect(dstRect, srcRect,
1029 SkMatrix::kFill_ScaleToFit);
1030
1031 // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
1032 // the rest from the SkPaint.
1033 sk_sp<GrFragmentProcessor> fp;
1034
1035 if (needsTextureDomain && (SkCanvas::kStrict_SrcRectConstraint == constraint)) {
1036 // Use a constrained texture domain to avoid color bleeding
1037 SkRect domain;
1038 if (srcRect.width() > SK_Scalar1) {
1039 domain.fLeft = srcRect.fLeft + 0.5f;
1040 domain.fRight = srcRect.fRight - 0.5f;
1041 } else {
1042 domain.fLeft = domain.fRight = srcRect.centerX();
1043 }
1044 if (srcRect.height() > SK_Scalar1) {
1045 domain.fTop = srcRect.fTop + 0.5f;
1046 domain.fBottom = srcRect.fBottom - 0.5f;
1047 } else {
1048 domain.fTop = domain.fBottom = srcRect.centerY();
1049 }
1050 if (bicubic) {
1051 fp = GrBicubicEffect::Make(std::move(proxy),
1052 std::move(colorSpaceXform), texMatrix, domain);
1053 } else {
1054 fp = GrTextureDomainEffect::Make(std::move(proxy),
1055 std::move(colorSpaceXform), texMatrix,
1056 domain, GrTextureDomain::kClamp_Mode,
1057 params.filterMode());
1058 }
1059 } else if (bicubic) {
1060 SkASSERT(GrSamplerParams::kNone_FilterMode == params.filterMode());
1061 SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
1062 fp = GrBicubicEffect::Make(std::move(proxy),
1063 std::move(colorSpaceXform), texMatrix, tileModes);
1064 } else {
1065 fp = GrSimpleTextureEffect::Make(std::move(proxy),
1066 std::move(colorSpaceXform), texMatrix, params);
1067 }
1068
1069 GrPaint grPaint;
1070 if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint, viewMatrix,
1071 std::move(fp), kAlpha_8_SkColorType == bitmap.colorType(),
1072 &grPaint)) {
1073 return;
1074 }
1075
1076 // Coverage-based AA would cause seams between tiles.
1077 GrAA aa = GrBoolToAA(paint.isAntiAlias() &&
1078 GrFSAAType::kNone != fRenderTargetContext->fsaaType());
1079 fRenderTargetContext->drawRect(this->clip(), std::move(grPaint), aa, viewMatrix, dstRect);
1080 }
1081
drawSprite(const SkBitmap & bitmap,int left,int top,const SkPaint & paint)1082 void SkGpuDevice::drawSprite(const SkBitmap& bitmap,
1083 int left, int top, const SkPaint& paint) {
1084 ASSERT_SINGLE_OWNER
1085 CHECK_SHOULD_DRAW();
1086 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSprite", fContext.get());
1087
1088 if (fContext->abandoned()) {
1089 return;
1090 }
1091
1092 sk_sp<SkSpecialImage> srcImg = this->makeSpecial(bitmap);
1093 if (!srcImg) {
1094 return;
1095 }
1096
1097 this->drawSpecial(srcImg.get(), left, top, paint, nullptr, SkMatrix::I());
1098 }
1099
1100
drawSpecial(SkSpecialImage * special1,int left,int top,const SkPaint & paint,SkImage * clipImage,const SkMatrix & clipMatrix)1101 void SkGpuDevice::drawSpecial(SkSpecialImage* special1, int left, int top, const SkPaint& paint,
1102 SkImage* clipImage,const SkMatrix& clipMatrix) {
1103 ASSERT_SINGLE_OWNER
1104 CHECK_SHOULD_DRAW();
1105 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSpecial", fContext.get());
1106
1107 // TODO: clipImage support.
1108
1109 SkIPoint offset = { 0, 0 };
1110
1111 sk_sp<SkSpecialImage> result;
1112 if (paint.getImageFilter()) {
1113 result = this->filterTexture(special1, left, top,
1114 &offset,
1115 paint.getImageFilter());
1116 if (!result) {
1117 return;
1118 }
1119 } else {
1120 result = sk_ref_sp(special1);
1121 }
1122
1123 SkASSERT(result->isTextureBacked());
1124 sk_sp<GrTextureProxy> proxy = result->asTextureProxyRef(this->context());
1125 if (!proxy) {
1126 return;
1127 }
1128
1129 const GrPixelConfig config = proxy->config();
1130
1131 SkPaint tmpUnfiltered(paint);
1132 tmpUnfiltered.setImageFilter(nullptr);
1133
1134 sk_sp<GrColorSpaceXform> colorSpaceXform =
1135 GrColorSpaceXform::Make(result->getColorSpace(), fRenderTargetContext->getColorSpace());
1136
1137 sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(std::move(proxy),
1138 std::move(colorSpaceXform),
1139 SkMatrix::I()));
1140 if (GrPixelConfigIsAlphaOnly(config)) {
1141 fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
1142 } else {
1143 fp = GrFragmentProcessor::MulOutputByInputAlpha(std::move(fp));
1144 }
1145
1146 GrPaint grPaint;
1147 if (!SkPaintToGrPaintReplaceShader(this->context(), fRenderTargetContext.get(), tmpUnfiltered,
1148 std::move(fp), &grPaint)) {
1149 return;
1150 }
1151
1152 const SkIRect& subset = result->subset();
1153
1154 fRenderTargetContext->fillRectToRect(
1155 this->clip(),
1156 std::move(grPaint),
1157 GrBoolToAA(paint.isAntiAlias()),
1158 SkMatrix::I(),
1159 SkRect::Make(SkIRect::MakeXYWH(left + offset.fX, top + offset.fY, subset.width(),
1160 subset.height())),
1161 SkRect::Make(subset));
1162 }
1163
drawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & origDst,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)1164 void SkGpuDevice::drawBitmapRect(const SkBitmap& bitmap,
1165 const SkRect* src, const SkRect& origDst,
1166 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
1167 ASSERT_SINGLE_OWNER
1168 CHECK_SHOULD_DRAW();
1169
1170 // The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must
1171 // be clipped to the bmp bounds. To determine tiling parameters we need the filter mode which
1172 // in turn requires knowing the src-to-dst mapping. If the src was clipped to the bmp bounds
1173 // then we use the src-to-dst mapping to compute a new clipped dst rect.
1174 const SkRect* dst = &origDst;
1175 const SkRect bmpBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1176 // Compute matrix from the two rectangles
1177 if (!src) {
1178 src = &bmpBounds;
1179 }
1180
1181 SkMatrix srcToDstMatrix;
1182 if (!srcToDstMatrix.setRectToRect(*src, *dst, SkMatrix::kFill_ScaleToFit)) {
1183 return;
1184 }
1185 SkRect tmpSrc, tmpDst;
1186 if (src != &bmpBounds) {
1187 if (!bmpBounds.contains(*src)) {
1188 tmpSrc = *src;
1189 if (!tmpSrc.intersect(bmpBounds)) {
1190 return; // nothing to draw
1191 }
1192 src = &tmpSrc;
1193 srcToDstMatrix.mapRect(&tmpDst, *src);
1194 dst = &tmpDst;
1195 }
1196 }
1197
1198 int maxTileSize = fContext->caps()->maxTileSize();
1199
1200 // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
1201 // draw untiled, then we bypass checking for tiling purely for optimization reasons.
1202 bool useCoverageAA = GrFSAAType::kUnifiedMSAA != fRenderTargetContext->fsaaType() &&
1203 paint.isAntiAlias() && bitmap.width() <= maxTileSize &&
1204 bitmap.height() <= maxTileSize;
1205
1206 bool skipTileCheck = useCoverageAA || paint.getMaskFilter();
1207
1208 if (!skipTileCheck) {
1209 int tileSize;
1210 SkIRect clippedSrcRect;
1211
1212 GrSamplerParams params;
1213 bool doBicubic;
1214 GrSamplerParams::FilterMode textureFilterMode =
1215 GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), srcToDstMatrix,
1216 &doBicubic);
1217
1218 int tileFilterPad;
1219
1220 if (doBicubic) {
1221 tileFilterPad = GrBicubicEffect::kFilterTexelPad;
1222 } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
1223 tileFilterPad = 0;
1224 } else {
1225 tileFilterPad = 1;
1226 }
1227 params.setFilterMode(textureFilterMode);
1228
1229 int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
1230 if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), this->ctm(),
1231 srcToDstMatrix, params, src, maxTileSizeForFilter, &tileSize,
1232 &clippedSrcRect)) {
1233 this->drawTiledBitmap(bitmap, this->ctm(), srcToDstMatrix, *src, clippedSrcRect,
1234 params, paint, constraint, tileSize, doBicubic);
1235 return;
1236 }
1237 }
1238 GrBitmapTextureMaker maker(fContext.get(), bitmap);
1239 this->drawTextureProducer(&maker, src, dst, constraint, this->ctm(), this->clip(), paint);
1240 }
1241
makeSpecial(const SkBitmap & bitmap)1242 sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkBitmap& bitmap) {
1243 // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's
1244 // semantics). Since this is cached we would have to bake the fit into the cache key though.
1245 sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(fContext->resourceProvider(), bitmap);
1246 if (!proxy) {
1247 return nullptr;
1248 }
1249
1250 const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height());
1251
1252 // GrMakeCachedBitmapProxy creates a tight copy of 'bitmap' so we don't have to subset
1253 // the special image
1254 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
1255 rect,
1256 bitmap.getGenerationID(),
1257 std::move(proxy),
1258 bitmap.refColorSpace(),
1259 &this->surfaceProps());
1260 }
1261
makeSpecial(const SkImage * image)1262 sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkImage* image) {
1263 SkPixmap pm;
1264 if (image->isTextureBacked()) {
1265 sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef();
1266
1267 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
1268 SkIRect::MakeWH(image->width(), image->height()),
1269 image->uniqueID(),
1270 std::move(proxy),
1271 as_IB(image)->onImageInfo().refColorSpace(),
1272 &this->surfaceProps());
1273 } else if (image->peekPixels(&pm)) {
1274 SkBitmap bm;
1275
1276 bm.installPixels(pm);
1277 return this->makeSpecial(bm);
1278 } else {
1279 return nullptr;
1280 }
1281 }
1282
snapSpecial()1283 sk_sp<SkSpecialImage> SkGpuDevice::snapSpecial() {
1284 sk_sp<GrTextureProxy> proxy(this->accessRenderTargetContext()->asTextureProxyRef());
1285 if (!proxy) {
1286 // When the device doesn't have a texture, we create a temporary texture.
1287 // TODO: we should actually only copy the portion of the source needed to apply the image
1288 // filter
1289 proxy = GrSurfaceProxy::Copy(fContext.get(),
1290 this->accessRenderTargetContext()->asSurfaceProxy(),
1291 SkBudgeted::kYes);
1292 if (!proxy) {
1293 return nullptr;
1294 }
1295 }
1296
1297 const SkImageInfo ii = this->imageInfo();
1298 const SkIRect srcRect = SkIRect::MakeWH(ii.width(), ii.height());
1299
1300 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
1301 srcRect,
1302 kNeedNewImageUniqueID_SpecialImage,
1303 std::move(proxy),
1304 ii.refColorSpace(),
1305 &this->surfaceProps());
1306 }
1307
drawDevice(SkBaseDevice * device,int left,int top,const SkPaint & paint)1308 void SkGpuDevice::drawDevice(SkBaseDevice* device,
1309 int left, int top, const SkPaint& paint) {
1310 SkASSERT(!paint.getImageFilter());
1311
1312 ASSERT_SINGLE_OWNER
1313 // clear of the source device must occur before CHECK_SHOULD_DRAW
1314 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext.get());
1315
1316 // drawDevice is defined to be in device coords.
1317 CHECK_SHOULD_DRAW();
1318
1319 SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
1320 sk_sp<SkSpecialImage> srcImg(dev->snapSpecial());
1321 if (!srcImg) {
1322 return;
1323 }
1324
1325 this->drawSpecial(srcImg.get(), left, top, paint, nullptr, SkMatrix::I());
1326 }
1327
drawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint & paint)1328 void SkGpuDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y,
1329 const SkPaint& paint) {
1330 ASSERT_SINGLE_OWNER
1331 SkMatrix viewMatrix = this->ctm();
1332 viewMatrix.preTranslate(x, y);
1333 uint32_t pinnedUniqueID;
1334
1335 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
1336 CHECK_SHOULD_DRAW();
1337 GrTextureAdjuster adjuster(this->context(), std::move(proxy),
1338 image->alphaType(), image->bounds(),
1339 pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
1340 this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint,
1341 viewMatrix, this->clip(), paint);
1342 return;
1343 } else {
1344 SkBitmap bm;
1345 if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint,
1346 paint.getFilterQuality(), this->ctm(), SkMatrix::I())) {
1347 // only support tiling as bitmap at the moment, so force raster-version
1348 if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1349 return;
1350 }
1351 this->drawBitmap(bm, x, y, paint);
1352 } else if (image->isLazyGenerated()) {
1353 CHECK_SHOULD_DRAW();
1354 GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
1355 this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint,
1356 viewMatrix, this->clip(), paint);
1357 } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1358 this->drawBitmap(bm, x, y, paint);
1359 }
1360 }
1361 }
1362
drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)1363 void SkGpuDevice::drawImageRect(const SkImage* image, const SkRect* src,
1364 const SkRect& dst, const SkPaint& paint,
1365 SkCanvas::SrcRectConstraint constraint) {
1366 ASSERT_SINGLE_OWNER
1367 uint32_t pinnedUniqueID;
1368 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
1369 CHECK_SHOULD_DRAW();
1370 GrTextureAdjuster adjuster(this->context(), std::move(proxy),
1371 image->alphaType(), image->bounds(), pinnedUniqueID,
1372 as_IB(image)->onImageInfo().colorSpace());
1373 this->drawTextureProducer(&adjuster, src, &dst, constraint, this->ctm(), this->clip(),
1374 paint);
1375 return;
1376 }
1377 SkBitmap bm;
1378 SkMatrix srcToDstRect;
1379 srcToDstRect.setRectToRect((src ? *src : SkRect::MakeIWH(image->width(), image->height())),
1380 dst, SkMatrix::kFill_ScaleToFit);
1381 if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), this->ctm(),
1382 srcToDstRect)) {
1383 // only support tiling as bitmap at the moment, so force raster-version
1384 if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1385 return;
1386 }
1387 this->drawBitmapRect(bm, src, dst, paint, constraint);
1388 } else if (image->isLazyGenerated()) {
1389 CHECK_SHOULD_DRAW();
1390 GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
1391 this->drawTextureProducer(&maker, src, &dst, constraint, this->ctm(), this->clip(), paint);
1392 } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1393 this->drawBitmapRect(bm, src, dst, paint, constraint);
1394 }
1395 }
1396
drawProducerNine(GrTextureProducer * producer,const SkIRect & center,const SkRect & dst,const SkPaint & paint)1397 void SkGpuDevice::drawProducerNine(GrTextureProducer* producer,
1398 const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
1399 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext.get());
1400
1401 CHECK_SHOULD_DRAW();
1402
1403 bool useFallback = paint.getMaskFilter() || paint.isAntiAlias() ||
1404 GrFSAAType::kUnifiedMSAA == fRenderTargetContext->fsaaType();
1405 bool doBicubic;
1406 GrSamplerParams::FilterMode textureFilterMode =
1407 GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), SkMatrix::I(),
1408 &doBicubic);
1409 if (useFallback || doBicubic || GrSamplerParams::kNone_FilterMode != textureFilterMode) {
1410 SkLatticeIter iter(producer->width(), producer->height(), center, dst);
1411
1412 SkRect srcR, dstR;
1413 while (iter.next(&srcR, &dstR)) {
1414 this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint,
1415 this->ctm(), this->clip(), paint);
1416 }
1417 return;
1418 }
1419
1420 static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode;
1421 sk_sp<GrFragmentProcessor> fp(
1422 producer->createFragmentProcessor(SkMatrix::I(),
1423 SkRect::MakeIWH(producer->width(), producer->height()),
1424 GrTextureProducer::kNo_FilterConstraint, true,
1425 &kMode, fRenderTargetContext->getColorSpace()));
1426 if (!fp) {
1427 return;
1428 }
1429 GrPaint grPaint;
1430 if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint,
1431 this->ctm(), std::move(fp), producer->isAlphaOnly(),
1432 &grPaint)) {
1433 return;
1434 }
1435
1436 std::unique_ptr<SkLatticeIter> iter(
1437 new SkLatticeIter(producer->width(), producer->height(), center, dst));
1438 fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->ctm(),
1439 producer->width(), producer->height(), std::move(iter),
1440 dst);
1441 }
1442
drawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint & paint)1443 void SkGpuDevice::drawImageNine(const SkImage* image,
1444 const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
1445 ASSERT_SINGLE_OWNER
1446 uint32_t pinnedUniqueID;
1447 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
1448 CHECK_SHOULD_DRAW();
1449 GrTextureAdjuster adjuster(this->context(), std::move(proxy),
1450 image->alphaType(), image->bounds(),
1451 pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
1452 this->drawProducerNine(&adjuster, center, dst, paint);
1453 } else {
1454 SkBitmap bm;
1455 if (image->isLazyGenerated()) {
1456 GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
1457 this->drawProducerNine(&maker, center, dst, paint);
1458 } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1459 this->drawBitmapNine(bm, center, dst, paint);
1460 }
1461 }
1462 }
1463
drawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint & paint)1464 void SkGpuDevice::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1465 const SkRect& dst, const SkPaint& paint) {
1466 ASSERT_SINGLE_OWNER
1467 GrBitmapTextureMaker maker(fContext.get(), bitmap);
1468 this->drawProducerNine(&maker, center, dst, paint);
1469 }
1470
drawProducerLattice(GrTextureProducer * producer,const SkCanvas::Lattice & lattice,const SkRect & dst,const SkPaint & paint)1471 void SkGpuDevice::drawProducerLattice(GrTextureProducer* producer,
1472 const SkCanvas::Lattice& lattice, const SkRect& dst,
1473 const SkPaint& paint) {
1474 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerLattice", fContext.get());
1475
1476 CHECK_SHOULD_DRAW();
1477
1478 static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode;
1479 sk_sp<GrFragmentProcessor> fp(
1480 producer->createFragmentProcessor(SkMatrix::I(),
1481 SkRect::MakeIWH(producer->width(), producer->height()),
1482 GrTextureProducer::kNo_FilterConstraint, true,
1483 &kMode, fRenderTargetContext->getColorSpace()));
1484 if (!fp) {
1485 return;
1486 }
1487 GrPaint grPaint;
1488 if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint,
1489 this->ctm(), std::move(fp), producer->isAlphaOnly(),
1490 &grPaint)) {
1491 return;
1492 }
1493
1494 std::unique_ptr<SkLatticeIter> iter(
1495 new SkLatticeIter(lattice, dst));
1496 fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->ctm(),
1497 producer->width(), producer->height(), std::move(iter),
1498 dst);
1499 }
1500
drawImageLattice(const SkImage * image,const SkCanvas::Lattice & lattice,const SkRect & dst,const SkPaint & paint)1501 void SkGpuDevice::drawImageLattice(const SkImage* image,
1502 const SkCanvas::Lattice& lattice, const SkRect& dst,
1503 const SkPaint& paint) {
1504 ASSERT_SINGLE_OWNER
1505 uint32_t pinnedUniqueID;
1506 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
1507 CHECK_SHOULD_DRAW();
1508 GrTextureAdjuster adjuster(this->context(), std::move(proxy),
1509 image->alphaType(), image->bounds(),
1510 pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
1511 this->drawProducerLattice(&adjuster, lattice, dst, paint);
1512 } else {
1513 SkBitmap bm;
1514 if (image->isLazyGenerated()) {
1515 GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
1516 this->drawProducerLattice(&maker, lattice, dst, paint);
1517 } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1518 this->drawBitmapLattice(bm, lattice, dst, paint);
1519 }
1520 }
1521 }
1522
drawBitmapLattice(const SkBitmap & bitmap,const SkCanvas::Lattice & lattice,const SkRect & dst,const SkPaint & paint)1523 void SkGpuDevice::drawBitmapLattice(const SkBitmap& bitmap,
1524 const SkCanvas::Lattice& lattice, const SkRect& dst,
1525 const SkPaint& paint) {
1526 ASSERT_SINGLE_OWNER
1527 GrBitmapTextureMaker maker(fContext.get(), bitmap);
1528 this->drawProducerLattice(&maker, lattice, dst, paint);
1529 }
1530
init_vertices_paint(GrContext * context,GrRenderTargetContext * rtc,const SkPaint & skPaint,const SkMatrix & matrix,SkBlendMode bmode,bool hasTexs,bool hasColors,GrPaint * grPaint)1531 static bool init_vertices_paint(GrContext* context, GrRenderTargetContext* rtc,
1532 const SkPaint& skPaint,
1533 const SkMatrix& matrix, SkBlendMode bmode,
1534 bool hasTexs, bool hasColors, GrPaint* grPaint) {
1535 if (hasTexs && skPaint.getShader()) {
1536 if (hasColors) {
1537 // When there are texs and colors the shader and colors are combined using bmode.
1538 return SkPaintToGrPaintWithXfermode(context, rtc, skPaint, matrix, bmode, grPaint);
1539 } else {
1540 // We have a shader, but no colors to blend it against.
1541 return SkPaintToGrPaint(context, rtc, skPaint, matrix, grPaint);
1542 }
1543 } else {
1544 if (hasColors) {
1545 // We have colors, but either have no shader or no texture coords (which implies that
1546 // we should ignore the shader).
1547 return SkPaintToGrPaintWithPrimitiveColor(context, rtc, skPaint, grPaint);
1548 } else {
1549 // No colors and no shaders. Just draw with the paint color.
1550 return SkPaintToGrPaintNoShader(context, rtc, skPaint, grPaint);
1551 }
1552 }
1553 }
1554
wireframeVertices(SkVertices::VertexMode vmode,int vertexCount,const SkPoint vertices[],SkBlendMode bmode,const uint16_t indices[],int indexCount,const SkPaint & paint)1555 void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCount,
1556 const SkPoint vertices[], SkBlendMode bmode,
1557 const uint16_t indices[], int indexCount,
1558 const SkPaint& paint) {
1559 ASSERT_SINGLE_OWNER
1560 CHECK_SHOULD_DRAW();
1561 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "wireframeVertices", fContext.get());
1562
1563 SkPaint copy(paint);
1564 copy.setStyle(SkPaint::kStroke_Style);
1565 copy.setStrokeWidth(0);
1566
1567 GrPaint grPaint;
1568 // we ignore the shader since we have no texture coordinates.
1569 if (!SkPaintToGrPaintNoShader(this->context(), fRenderTargetContext.get(), copy, &grPaint)) {
1570 return;
1571 }
1572
1573 int triangleCount = 0;
1574 int n = (nullptr == indices) ? vertexCount : indexCount;
1575 switch (vmode) {
1576 case SkVertices::kTriangles_VertexMode:
1577 triangleCount = n / 3;
1578 break;
1579 case SkVertices::kTriangleStrip_VertexMode:
1580 case SkVertices::kTriangleFan_VertexMode:
1581 triangleCount = n - 2;
1582 break;
1583 }
1584
1585 VertState state(vertexCount, indices, indexCount);
1586 VertState::Proc vertProc = state.chooseProc(vmode);
1587
1588 //number of indices for lines per triangle with kLines
1589 indexCount = triangleCount * 6;
1590
1591 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
1592 SkVertices::Builder builder(kIgnoredMode, vertexCount, indexCount, 0);
1593 memcpy(builder.positions(), vertices, vertexCount * sizeof(SkPoint));
1594
1595 uint16_t* lineIndices = builder.indices();
1596 int i = 0;
1597 while (vertProc(&state)) {
1598 lineIndices[i] = state.f0;
1599 lineIndices[i + 1] = state.f1;
1600 lineIndices[i + 2] = state.f1;
1601 lineIndices[i + 3] = state.f2;
1602 lineIndices[i + 4] = state.f2;
1603 lineIndices[i + 5] = state.f0;
1604 i += 6;
1605 }
1606
1607 GrPrimitiveType primitiveType = GrPrimitiveType::kLines;
1608 fRenderTargetContext->drawVertices(this->clip(),
1609 std::move(grPaint),
1610 this->ctm(),
1611 builder.detach(),
1612 &primitiveType);
1613 }
1614
drawVertices(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)1615 void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1616 ASSERT_SINGLE_OWNER
1617 CHECK_SHOULD_DRAW();
1618 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get());
1619
1620 SkASSERT(vertices);
1621 GrPaint grPaint;
1622 bool hasColors = vertices->hasColors();
1623 bool hasTexs = vertices->hasTexCoords();
1624 if ((!hasTexs || !paint.getShader()) && !hasColors) {
1625 // The dreaded wireframe mode. Fallback to drawVertices and go so slooooooow.
1626 this->wireframeVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
1627 mode, vertices->indices(), vertices->indexCount(), paint);
1628 return;
1629 }
1630 if (!init_vertices_paint(fContext.get(), fRenderTargetContext.get(), paint, this->ctm(),
1631 mode, hasTexs, hasColors, &grPaint)) {
1632 return;
1633 }
1634 fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->ctm(),
1635 sk_ref_sp(const_cast<SkVertices*>(vertices)));
1636 }
1637
1638 ///////////////////////////////////////////////////////////////////////////////
1639
drawShadow(const SkPath & path,const SkDrawShadowRec & rec)1640 void SkGpuDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
1641
1642 ASSERT_SINGLE_OWNER
1643 CHECK_SHOULD_DRAW();
1644 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawShadow", fContext.get());
1645
1646 GrColor color = SkColorToPremulGrColor(rec.fColor);
1647 if (!fRenderTargetContext->drawFastShadow(this->clip(), color, this->ctm(), path, rec)) {
1648 // failed to find an accelerated case
1649 this->INHERITED::drawShadow(path, rec);
1650 }
1651 }
1652
1653 ///////////////////////////////////////////////////////////////////////////////
1654
drawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect texRect[],const SkColor colors[],int count,SkBlendMode mode,const SkPaint & paint)1655 void SkGpuDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[],
1656 const SkRect texRect[], const SkColor colors[], int count,
1657 SkBlendMode mode, const SkPaint& paint) {
1658 ASSERT_SINGLE_OWNER
1659 if (paint.isAntiAlias()) {
1660 this->INHERITED::drawAtlas(atlas, xform, texRect, colors, count, mode, paint);
1661 return;
1662 }
1663
1664 CHECK_SHOULD_DRAW();
1665 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get());
1666
1667 SkPaint p(paint);
1668 p.setShader(atlas->makeShader());
1669
1670 GrPaint grPaint;
1671 if (colors) {
1672 if (!SkPaintToGrPaintWithXfermode(this->context(), fRenderTargetContext.get(), p,
1673 this->ctm(), (SkBlendMode)mode, &grPaint)) {
1674 return;
1675 }
1676 } else {
1677 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), p, this->ctm(),
1678 &grPaint)) {
1679 return;
1680 }
1681 }
1682
1683 SkDEBUGCODE(this->validate();)
1684 fRenderTargetContext->drawAtlas(
1685 this->clip(), std::move(grPaint), this->ctm(), count, xform, texRect, colors);
1686 }
1687
1688 ///////////////////////////////////////////////////////////////////////////////
1689
drawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)1690 void SkGpuDevice::drawText(const void* text,
1691 size_t byteLength, SkScalar x, SkScalar y,
1692 const SkPaint& paint) {
1693 ASSERT_SINGLE_OWNER
1694 CHECK_SHOULD_DRAW();
1695 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get());
1696 SkDEBUGCODE(this->validate();)
1697
1698 fRenderTargetContext->drawText(this->clip(), paint, this->ctm(), (const char*)text, byteLength,
1699 x, y, this->devClipBounds());
1700 }
1701
drawPosText(const void * text,size_t byteLength,const SkScalar pos[],int scalarsPerPos,const SkPoint & offset,const SkPaint & paint)1702 void SkGpuDevice::drawPosText(const void* text, size_t byteLength,
1703 const SkScalar pos[], int scalarsPerPos,
1704 const SkPoint& offset, const SkPaint& paint) {
1705 ASSERT_SINGLE_OWNER
1706 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPosText", fContext.get());
1707 CHECK_SHOULD_DRAW();
1708 SkDEBUGCODE(this->validate();)
1709
1710 fRenderTargetContext->drawPosText(this->clip(), paint, this->ctm(), (const char*)text,
1711 byteLength, pos, scalarsPerPos, offset,
1712 this->devClipBounds());
1713 }
1714
drawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint,SkDrawFilter * drawFilter)1715 void SkGpuDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
1716 const SkPaint& paint, SkDrawFilter* drawFilter) {
1717 ASSERT_SINGLE_OWNER
1718 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawTextBlob", fContext.get());
1719 CHECK_SHOULD_DRAW();
1720
1721 SkDEBUGCODE(this->validate();)
1722
1723 fRenderTargetContext->drawTextBlob(this->clip(), paint, this->ctm(), blob, x, y, drawFilter,
1724 this->devClipBounds());
1725 }
1726
1727 ///////////////////////////////////////////////////////////////////////////////
1728
onShouldDisableLCD(const SkPaint & paint) const1729 bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const {
1730 return GrTextUtils::ShouldDisableLCD(paint);
1731 }
1732
1733 ///////////////////////////////////////////////////////////////////////////////
1734
flush()1735 void SkGpuDevice::flush() {
1736 this->flushAndSignalSemaphores(0, nullptr);
1737 }
1738
flushAndSignalSemaphores(int numSemaphores,GrBackendSemaphore * signalSemaphores)1739 bool SkGpuDevice::flushAndSignalSemaphores(int numSemaphores,
1740 GrBackendSemaphore* signalSemaphores) {
1741 ASSERT_SINGLE_OWNER
1742
1743 return fRenderTargetContext->prepareForExternalIO(numSemaphores, signalSemaphores);
1744 }
1745
wait(int numSemaphores,const GrBackendSemaphore * waitSemaphores)1746 bool SkGpuDevice::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
1747 ASSERT_SINGLE_OWNER
1748
1749 return fRenderTargetContext->waitOnSemaphores(numSemaphores, waitSemaphores);
1750 }
1751
1752 ///////////////////////////////////////////////////////////////////////////////
1753
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)1754 SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
1755 ASSERT_SINGLE_OWNER
1756
1757 SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry);
1758
1759 // layers are never drawn in repeat modes, so we can request an approx
1760 // match and ignore any padding.
1761 SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox
1762 : SkBackingFit::kExact;
1763
1764 sk_sp<GrRenderTargetContext> rtc(fContext->makeDeferredRenderTargetContext(
1765 fit,
1766 cinfo.fInfo.width(), cinfo.fInfo.height(),
1767 fRenderTargetContext->config(),
1768 fRenderTargetContext->refColorSpace(),
1769 fRenderTargetContext->numStencilSamples(),
1770 kBottomLeft_GrSurfaceOrigin,
1771 &props));
1772 if (!rtc) {
1773 return nullptr;
1774 }
1775
1776 // Skia's convention is to only clear a device if it is non-opaque.
1777 InitContents init = cinfo.fInfo.isOpaque() ? kUninit_InitContents : kClear_InitContents;
1778
1779 return SkGpuDevice::Make(fContext.get(), std::move(rtc),
1780 cinfo.fInfo.width(), cinfo.fInfo.height(), init).release();
1781 }
1782
makeSurface(const SkImageInfo & info,const SkSurfaceProps & props)1783 sk_sp<SkSurface> SkGpuDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1784 ASSERT_SINGLE_OWNER
1785 // TODO: Change the signature of newSurface to take a budgeted parameter.
1786 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
1787 return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info,
1788 fRenderTargetContext->numStencilSamples(),
1789 fRenderTargetContext->origin(), &props);
1790 }
1791
getImageFilterCache()1792 SkImageFilterCache* SkGpuDevice::getImageFilterCache() {
1793 ASSERT_SINGLE_OWNER
1794 // We always return a transient cache, so it is freed after each
1795 // filter traversal.
1796 return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
1797 }
1798
1799 #endif
1800