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