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 "src/gpu/SkGpuDevice.h"
9
10#include "include/core/SkImageFilter.h"
11#include "include/core/SkPathEffect.h"
12#include "include/core/SkPicture.h"
13#include "include/core/SkSurface.h"
14#include "include/core/SkVertices.h"
15#include "include/effects/SkRuntimeEffect.h"
16#include "include/gpu/GrDirectContext.h"
17#include "include/gpu/GrRecordingContext.h"
18#include "include/private/SkShadowFlags.h"
19#include "include/private/SkTo.h"
20#include "src/core/SkCanvasPriv.h"
21#include "src/core/SkClipStack.h"
22#include "src/core/SkDraw.h"
23#include "src/core/SkImageFilterCache.h"
24#include "src/core/SkImageFilter_Base.h"
25#include "src/core/SkLatticeIter.h"
26#include "src/core/SkPictureData.h"
27#include "src/core/SkRRectPriv.h"
28#include "src/core/SkRasterClip.h"
29#include "src/core/SkRecord.h"
30#include "src/core/SkSpecialImage.h"
31#include "src/core/SkStroke.h"
32#include "src/core/SkTLazy.h"
33#include "src/core/SkVerticesPriv.h"
34#include "src/gpu/GrBitmapTextureMaker.h"
35#include "src/gpu/GrBlurUtils.h"
36#include "src/gpu/GrGpu.h"
37#include "src/gpu/GrImageTextureMaker.h"
38#include "src/gpu/GrRecordingContextPriv.h"
39#include "src/gpu/GrRenderTargetContextPriv.h"
40#include "src/gpu/GrStyle.h"
41#include "src/gpu/GrSurfaceProxyPriv.h"
42#include "src/gpu/GrTextureAdjuster.h"
43#include "src/gpu/GrTracing.h"
44#include "src/gpu/SkGr.h"
45#include "src/gpu/geometry/GrStyledShape.h"
46#include "src/image/SkImage_Base.h"
47#include "src/image/SkReadPixelsRec.h"
48#include "src/image/SkSurface_Gpu.h"
49#include "src/utils/SkUTF.h"
50
51#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fContext->priv().singleOwner())
52
53
54///////////////////////////////////////////////////////////////////////////////
55
56/** Checks that the alpha type is legal and gets constructor flags. Returns false if device creation
57 should fail. */
58bool SkGpuDevice::CheckAlphaTypeAndGetFlags(
59 const SkImageInfo* info, SkGpuDevice::InitContents init, unsigned* flags) {
60 *flags = 0;
61 if (info) {
62 switch (info->alphaType()) {
63 case kPremul_SkAlphaType:
64 break;
65 case kOpaque_SkAlphaType:
66 *flags |= SkGpuDevice::kIsOpaque_Flag;
67 break;
68 default: // If it is unpremul or unknown don't try to render
69 return false;
70 }
71 }
72 if (kClear_InitContents == init) {
73 *flags |= kNeedClear_Flag;
74 }
75 return true;
76}
77
78sk_sp<SkGpuDevice> SkGpuDevice::Make(GrRecordingContext* context,
79 std::unique_ptr<GrRenderTargetContext> renderTargetContext,
80 InitContents init) {
81 if (!renderTargetContext || context->abandoned()) {
82 return nullptr;
83 }
84
85 SkColorType ct = GrColorTypeToSkColorType(renderTargetContext->colorInfo().colorType());
86
87 unsigned flags;
88 if (!context->colorTypeSupportedAsSurface(ct) ||
89 !CheckAlphaTypeAndGetFlags(nullptr, init, &flags)) {
90 return nullptr;
91 }
92 return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext), flags));
93}
94
95sk_sp<SkGpuDevice> SkGpuDevice::Make(GrRecordingContext* context, SkBudgeted budgeted,
96 const SkImageInfo& info, int sampleCount,
97 GrSurfaceOrigin origin, const SkSurfaceProps* props,
98 GrMipmapped mipMapped, InitContents init) {
99 unsigned flags;
100 if (!context->colorTypeSupportedAsSurface(info.colorType()) ||
101 !CheckAlphaTypeAndGetFlags(&info, init, &flags)) {
102 return nullptr;
103 }
104
105 auto renderTargetContext =
106 MakeRenderTargetContext(context, budgeted, info, sampleCount, origin, props, mipMapped);
107 if (!renderTargetContext) {
108 return nullptr;
109 }
110
111 return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext), flags));
112}
113
114GrContext* SkGpuDevice::context() const {
115 // CONTEXT TODO: remove this use of 'backdoor'. Short term, we need to use it to support the
116 // SkCanvas::getGrContext and SkSurface::getContext calls.
117 return fContext->priv().backdoor();
118}
119
120static SkImageInfo make_info(GrRenderTargetContext* context, bool opaque) {
121 SkColorType colorType = GrColorTypeToSkColorType(context->colorInfo().colorType());
122 return SkImageInfo::Make(context->width(), context->height(), colorType,
123 opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
124 context->colorInfo().refColorSpace());
125}
126
127SkGpuDevice::SkGpuDevice(GrRecordingContext* context,
128 std::unique_ptr<GrRenderTargetContext> renderTargetContext,
129 unsigned flags)
130 : INHERITED(make_info(renderTargetContext.get(), SkToBool(flags & kIsOpaque_Flag)),
131 renderTargetContext->surfaceProps())
132 , fContext(SkRef(context))
133 , fRenderTargetContext(std::move(renderTargetContext))
134 , fClip(fRenderTargetContext->dimensions(), &this->cs(), &this->asMatrixProvider()) {
135 if (flags & kNeedClear_Flag) {
136 this->clearAll();
137 }
138}
139
140std::unique_ptr<GrRenderTargetContext> SkGpuDevice::MakeRenderTargetContext(
141 GrRecordingContext* context,
142 SkBudgeted budgeted,
143 const SkImageInfo& origInfo,
144 int sampleCount,
145 GrSurfaceOrigin origin,
146 const SkSurfaceProps* surfaceProps,
147 GrMipmapped mipMapped) {
148 if (!context) {
149 return nullptr;
150 }
151
152 // This method is used to create SkGpuDevice's for SkSurface_Gpus. In this case
153 // they need to be exact.
154 return GrRenderTargetContext::Make(
155 context, SkColorTypeToGrColorType(origInfo.colorType()), origInfo.refColorSpace(),
156 SkBackingFit::kExact, origInfo.dimensions(), sampleCount, mipMapped, GrProtected::kNo,
157 origin, budgeted, surfaceProps);
158}
159
160sk_sp<SkSpecialImage> SkGpuDevice::filterTexture(SkSpecialImage* srcImg,
161 int left, int top,
162 SkIPoint* offset,
163 const SkImageFilter* filter) {
164 SkASSERT(srcImg->isTextureBacked());
165 SkASSERT(filter);
166
167 SkMatrix matrix = this->localToDevice();
168 matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
169 const SkIRect clipBounds = this->devClipBounds().makeOffset(-left, -top);
170 sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
171 SkColorType colorType = GrColorTypeToSkColorType(fRenderTargetContext->colorInfo().colorType());
172 if (colorType == kUnknown_SkColorType) {
173 colorType = kRGBA_8888_SkColorType;
174 }
175 SkImageFilter_Base::Context ctx(matrix, clipBounds, cache.get(), colorType,
176 fRenderTargetContext->colorInfo().colorSpace(), srcImg);
177
178 return as_IFB(filter)->filterImage(ctx).imageAndOffset(offset);
179}
180
181///////////////////////////////////////////////////////////////////////////////
182
183bool SkGpuDevice::onReadPixels(const SkPixmap& pm, int x, int y) {
184 ASSERT_SINGLE_OWNER
185
186 // Context TODO: Elevate direct context requirement to public API
187 auto dContext = fContext->asDirectContext();
188 if (!dContext || !SkImageInfoValidConversion(pm.info(), this->imageInfo())) {
189 return false;
190 }
191
192 return fRenderTargetContext->readPixels(dContext, pm.info(), pm.writable_addr(), pm.rowBytes(),
193 {x, y});
194}
195
196bool SkGpuDevice::onWritePixels(const SkPixmap& pm, int x, int y) {
197 ASSERT_SINGLE_OWNER
198
199 // Context TODO: Elevate direct context requirement to public API
200 auto dContext = fContext->asDirectContext();
201 if (!dContext || !SkImageInfoValidConversion(this->imageInfo(), pm.info())) {
202 return false;
203 }
204
205 return fRenderTargetContext->writePixels(dContext, pm.info(), pm.addr(), pm.rowBytes(), {x, y});
206}
207
208bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) {
209 ASSERT_SINGLE_OWNER
210 return false;
211}
212
213GrRenderTargetContext* SkGpuDevice::accessRenderTargetContext() {
214 ASSERT_SINGLE_OWNER
215 return fRenderTargetContext.get();
216}
217
218void SkGpuDevice::clearAll() {
219 ASSERT_SINGLE_OWNER
220 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext.get());
221
222 SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
223 fRenderTargetContext->priv().clearAtLeast(rect, SK_PMColor4fTRANSPARENT);
224}
225
226void SkGpuDevice::replaceRenderTargetContext(std::unique_ptr<GrRenderTargetContext> rtc,
227 SkSurface::ContentChangeMode mode) {
228 SkASSERT(rtc->width() == this->width());
229 SkASSERT(rtc->height() == this->height());
230 SkASSERT(rtc->numSamples() == fRenderTargetContext->numSamples());
231 SkASSERT(rtc->asSurfaceProxy()->priv().isExact());
232 if (mode == SkSurface::kRetain_ContentChangeMode) {
233 if (this->recordingContext()->abandoned()) {
234 return;
235 }
236
237 SkASSERT(fRenderTargetContext->asTextureProxy());
238 SkAssertResult(rtc->blitTexture(fRenderTargetContext->readSurfaceView(),
239 SkIRect::MakeWH(this->width(), this->height()),
240 SkIPoint::Make(0,0)));
241 }
242
243 fRenderTargetContext = std::move(rtc);
244}
245
246void SkGpuDevice::replaceRenderTargetContext(SkSurface::ContentChangeMode mode) {
247 ASSERT_SINGLE_OWNER
248
249 SkBudgeted budgeted = fRenderTargetContext->priv().isBudgeted();
250
251 // This entry point is used by SkSurface_Gpu::onCopyOnWrite so it must create a
252 // kExact-backed render target context.
253 auto newRTC = MakeRenderTargetContext(this->recordingContext(),
254 budgeted,
255 this->imageInfo(),
256 fRenderTargetContext->numSamples(),
257 fRenderTargetContext->origin(),
258 &this->surfaceProps(),
259 fRenderTargetContext->mipmapped());
260 if (!newRTC) {
261 return;
262 }
263 this->replaceRenderTargetContext(std::move(newRTC), mode);
264}
265
266///////////////////////////////////////////////////////////////////////////////
267
268void SkGpuDevice::drawPaint(const SkPaint& paint) {
269 ASSERT_SINGLE_OWNER
270 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext.get());
271
272 GrPaint grPaint;
273 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), paint,
274 this->asMatrixProvider(), &grPaint)) {
275 return;
276 }
277
278 fRenderTargetContext->drawPaint(this->clip(), std::move(grPaint), this->localToDevice());
279}
280
281static inline GrPrimitiveType point_mode_to_primitive_type(SkCanvas::PointMode mode) {
282 switch (mode) {
283 case SkCanvas::kPoints_PointMode:
284 return GrPrimitiveType::kPoints;
285 case SkCanvas::kLines_PointMode:
286 return GrPrimitiveType::kLines;
287 case SkCanvas::kPolygon_PointMode:
288 return GrPrimitiveType::kLineStrip;
289 }
290 SK_ABORT("Unexpected mode");
291}
292
293void SkGpuDevice::drawPoints(SkCanvas::PointMode mode,
294 size_t count, const SkPoint pts[], const SkPaint& paint) {
295 ASSERT_SINGLE_OWNER
296 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext.get());
297 SkScalar width = paint.getStrokeWidth();
298 if (width < 0) {
299 return;
300 }
301
302 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
303 GrStyle style(paint, SkPaint::kStroke_Style);
304 GrPaint grPaint;
305 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), paint,
306 this->asMatrixProvider(), &grPaint)) {
307 return;
308 }
309 SkPath path;
310 path.setIsVolatile(true);
311 path.moveTo(pts[0]);
312 path.lineTo(pts[1]);
313 fRenderTargetContext->drawPath(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()),
314 this->localToDevice(), path, style);
315 return;
316 }
317
318 SkScalar scales[2];
319 bool isHairline = (0 == width) ||
320 (1 == width && this->localToDevice().getMinMaxScales(scales) &&
321 SkScalarNearlyEqual(scales[0], 1.f) && SkScalarNearlyEqual(scales[1], 1.f));
322 // we only handle non-antialiased hairlines and paints without path effects or mask filters,
323 // else we let the SkDraw call our drawPath()
324 if (!isHairline || paint.getPathEffect() || paint.getMaskFilter() || paint.isAntiAlias()) {
325 SkRasterClip rc(this->devClipBounds());
326 SkDraw draw;
327 draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0);
328 draw.fMatrixProvider = this;
329 draw.fRC = &rc;
330 draw.drawPoints(mode, count, pts, paint, this);
331 return;
332 }
333
334 GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode);
335
336 const SkMatrixProvider* matrixProvider = this;
337#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
338 SkTLazy<SkPostTranslateMatrixProvider> postTranslateMatrixProvider;
339 // This offsetting in device space matches the expectations of the Android framework for non-AA
340 // points and lines.
341 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
342 static const SkScalar kOffset = 0.063f; // Just greater than 1/16.
343 matrixProvider = postTranslateMatrixProvider.init(*matrixProvider, kOffset, kOffset);
344 }
345#endif
346
347 GrPaint grPaint;
348 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), paint,
349 *matrixProvider, &grPaint)) {
350 return;
351 }
352
353 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
354 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr,
355 nullptr);
356
357 fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), *matrixProvider,
358 std::move(vertices), &primitiveType);
359}
360
361///////////////////////////////////////////////////////////////////////////////
362
363void SkGpuDevice::drawRect(const SkRect& rect, const SkPaint& paint) {
364 ASSERT_SINGLE_OWNER
365 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext.get());
366
367 GrStyle style(paint);
368
369 // A couple reasons we might need to call drawPath.
370 if (paint.getMaskFilter() || paint.getPathEffect()) {
371 GrStyledShape shape(rect, style);
372
373 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fRenderTargetContext.get(),
374 this->clip(), paint, this->asMatrixProvider(), shape);
375 return;
376 }
377
378 GrPaint grPaint;
379 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), paint,
380 this->asMatrixProvider(), &grPaint)) {
381 return;
382 }
383
384 fRenderTargetContext->drawRect(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()),
385 this->localToDevice(), rect, &style);
386}
387
388void SkGpuDevice::drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
389 SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color,
390 SkBlendMode mode) {
391 ASSERT_SINGLE_OWNER
392 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawEdgeAAQuad", fContext.get());
393
394 SkPMColor4f dstColor = SkColor4fPrepForDst(color, fRenderTargetContext->colorInfo()).premul();
395
396 GrPaint grPaint;
397 grPaint.setColor4f(dstColor);
398 if (mode != SkBlendMode::kSrcOver) {
399 grPaint.setXPFactory(SkBlendMode_AsXPFactory(mode));
400 }
401
402 // This is exclusively meant for tiling operations, so keep AA enabled to handle MSAA seaming
403 GrQuadAAFlags grAA = SkToGrQuadAAFlags(aaFlags);
404 if (clip) {
405 // Use fillQuadWithEdgeAA
406 fRenderTargetContext->fillQuadWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA,
407 this->localToDevice(), clip, nullptr);
408 } else {
409 // Use fillRectWithEdgeAA to preserve mathematical properties of dst being rectangular
410 fRenderTargetContext->fillRectWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA,
411 this->localToDevice(), rect);
412 }
413}
414
415///////////////////////////////////////////////////////////////////////////////
416
417void SkGpuDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
418 ASSERT_SINGLE_OWNER
419 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext.get());
420
421 SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter());
422 if (mf) {
423 if (mf->hasFragmentProcessor()) {
424 mf = nullptr; // already handled in SkPaintToGrPaint
425 }
426 }
427
428 GrStyle style(paint);
429
430 if (mf || style.pathEffect()) {
431 // A path effect will presumably transform this rrect into something else.
432 GrStyledShape shape(rrect, style);
433
434 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fRenderTargetContext.get(),
435 this->clip(), paint, this->asMatrixProvider(), shape);
436 return;
437 }
438
439 SkASSERT(!style.pathEffect());
440
441 GrPaint grPaint;
442 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), paint,
443 this->asMatrixProvider(), &grPaint)) {
444 return;
445 }
446
447 fRenderTargetContext->drawRRect(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()),
448 this->localToDevice(), rrect, style);
449}
450
451
452void SkGpuDevice::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
453 ASSERT_SINGLE_OWNER
454 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext.get());
455 if (outer.isEmpty()) {
456 return;
457 }
458
459 if (inner.isEmpty()) {
460 return this->drawRRect(outer, paint);
461 }
462
463 SkStrokeRec stroke(paint);
464
465 if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
466 GrPaint grPaint;
467 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), paint,
468 this->asMatrixProvider(), &grPaint)) {
469 return;
470 }
471
472 fRenderTargetContext->drawDRRect(this->clip(), std::move(grPaint),
473 GrAA(paint.isAntiAlias()), this->localToDevice(),
474 outer, inner);
475 return;
476 }
477
478 SkPath path;
479 path.setIsVolatile(true);
480 path.addRRect(outer);
481 path.addRRect(inner);
482 path.setFillType(SkPathFillType::kEvenOdd);
483
484 // TODO: We are losing the possible mutability of the path here but this should probably be
485 // fixed by upgrading GrStyledShape to handle DRRects.
486 GrStyledShape shape(path, paint);
487
488 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(),
489 paint, this->asMatrixProvider(), shape);
490}
491
492/////////////////////////////////////////////////////////////////////////////
493
494void SkGpuDevice::drawRegion(const SkRegion& region, const SkPaint& paint) {
495 if (paint.getMaskFilter()) {
496 SkPath path;
497 region.getBoundaryPath(&path);
498 path.setIsVolatile(true);
499 return this->drawPath(path, paint, true);
500 }
501
502 GrPaint grPaint;
503 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), paint,
504 this->asMatrixProvider(), &grPaint)) {
505 return;
506 }
507
508 fRenderTargetContext->drawRegion(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()),
509 this->localToDevice(), region, GrStyle(paint));
510}
511
512void 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->recordingContext(), fRenderTargetContext->colorInfo(), paint,
524 this->asMatrixProvider(), &grPaint)) {
525 return;
526 }
527
528 fRenderTargetContext->drawOval(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()),
529 this->localToDevice(), oval, GrStyle(paint));
530}
531
532void 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->recordingContext(), fRenderTargetContext->colorInfo(), paint,
542 this->asMatrixProvider(), &grPaint)) {
543 return;
544 }
545
546 fRenderTargetContext->drawArc(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()),
547 this->localToDevice(), oval, startAngle, sweepAngle, useCenter,
548 GrStyle(paint));
549}
550
551#include "include/core/SkMaskFilter.h"
552
553///////////////////////////////////////////////////////////////////////////////
554void 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 local;
590 local.setSinCos(v.fX, -v.fY, mid.fX, mid.fY);
591
592 SkPreConcatMatrixProvider matrixProvider(this->asMatrixProvider(), local);
593
594 GrPaint grPaint;
595 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), newPaint,
596 matrixProvider, &grPaint)) {
597 return;
598 }
599
600 fRenderTargetContext->fillRectWithLocalMatrix(this->clip(), std::move(grPaint),
601 GrAA(newPaint.isAntiAlias()),
602 matrixProvider.localToDevice(), rect, local);
603}
604
605void SkGpuDevice::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool pathIsMutable) {
606 ASSERT_SINGLE_OWNER
607 if (!origSrcPath.isInverseFillType() && !paint.getPathEffect()) {
608 SkPoint points[2];
609 if (SkPaint::kStroke_Style == paint.getStyle() && paint.getStrokeWidth() > 0 &&
610 !paint.getMaskFilter() && SkPaint::kRound_Cap != paint.getStrokeCap() &&
611 this->localToDevice().preservesRightAngles() && origSrcPath.isLine(points)) {
612 // Path-based stroking looks better for thin rects
613 SkScalar strokeWidth = this->localToDevice().getMaxScale() * paint.getStrokeWidth();
614 if (strokeWidth >= 1.0f) {
615 // Round capping support is currently disabled b.c. it would require a RRect
616 // GrDrawOp that takes a localMatrix.
617 this->drawStrokedLine(points, paint);
618 return;
619 }
620 }
621 }
622
623 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext.get());
624 if (!paint.getMaskFilter()) {
625 GrPaint grPaint;
626 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), paint,
627 this->asMatrixProvider(), &grPaint)) {
628 return;
629 }
630 fRenderTargetContext->drawPath(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()),
631 this->localToDevice(), origSrcPath, GrStyle(paint));
632 return;
633 }
634
635 // TODO: losing possible mutability of 'origSrcPath' here
636 GrStyledShape shape(origSrcPath, paint);
637
638 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(),
639 paint, this->asMatrixProvider(), shape);
640}
641
642void SkGpuDevice::drawSpecial(SkSpecialImage* special, int left, int top, const SkPaint& paint) {
643 SkASSERT(!paint.getMaskFilter());
644
645 ASSERT_SINGLE_OWNER
646 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSpecial", fContext.get());
647
648 sk_sp<SkSpecialImage> result;
649 if (paint.getImageFilter()) {
650 SkIPoint offset = { 0, 0 };
651
652 result = this->filterTexture(special, left, top, &offset, paint.getImageFilter());
653 if (!result) {
654 return;
655 }
656
657 left += offset.fX;
658 top += offset.fY;
659 } else {
660 result = sk_ref_sp(special);
661 }
662
663 SkASSERT(result->isTextureBacked());
664 GrSurfaceProxyView view = result->view(this->recordingContext());
665 if (!view) {
666 return;
667 }
668
669 SkMatrix ctm = this->localToDevice();
670 ctm.postTranslate(-SkIntToScalar(left), -SkIntToScalar(top));
671
672 SkPaint tmpUnfiltered(paint);
673 tmpUnfiltered.setImageFilter(nullptr);
674
675 auto fp = GrTextureEffect::Make(std::move(view), special->alphaType());
676 fp = GrColorSpaceXformEffect::Make(
677 std::move(fp),
678 result->getColorSpace(), result->alphaType(),
679 fRenderTargetContext->colorInfo().colorSpace(), kPremul_SkAlphaType);
680 if (GrColorTypeIsAlphaOnly(SkColorTypeToGrColorType(result->colorType()))) {
681 fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
682 } else {
683 if (paint.getColor4f().isOpaque()) {
684 fp = GrFragmentProcessor::OverrideInput(std::move(fp), SK_PMColor4fWHITE, false);
685 } else {
686 fp = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
687 }
688 }
689
690 GrPaint grPaint;
691 if (!SkPaintToGrPaintReplaceShader(this->recordingContext(), fRenderTargetContext->colorInfo(),
692 tmpUnfiltered, this->asMatrixProvider(), std::move(fp),
693 &grPaint)) {
694 return;
695 }
696
697 const SkIRect& subset = result->subset();
698 SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(left, top, subset.width(), subset.height()));
699 SkRect srcRect = SkRect::Make(subset);
700
701 // Draw directly in screen space, possibly with an extra coverage processor
702 fRenderTargetContext->fillRectToRect(this->clip(), std::move(grPaint),
703 GrAA(paint.isAntiAlias()), SkMatrix::I(), dstRect, srcRect);
704}
705
706sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkBitmap& bitmap) {
707 // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's
708 // semantics). Since this is cached we would have to bake the fit into the cache key though.
709 auto view = GrMakeCachedBitmapProxyView(fContext.get(), bitmap);
710 if (!view) {
711 return nullptr;
712 }
713
714 const SkIRect rect = SkIRect::MakeSize(view.proxy()->dimensions());
715
716 // GrMakeCachedBitmapProxyView creates a tight copy of 'bitmap' so we don't have to subset
717 // the special image
718 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
719 rect,
720 bitmap.getGenerationID(),
721 std::move(view),
722 SkColorTypeToGrColorType(bitmap.colorType()),
723 bitmap.refColorSpace(),
724 &this->surfaceProps());
725}
726
727sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkImage* image) {
728 SkPixmap pm;
729 if (image->isTextureBacked()) {
730 const GrSurfaceProxyView* view = as_IB(image)->view(this->recordingContext());
731 SkASSERT(view);
732
733 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
734 SkIRect::MakeWH(image->width(), image->height()),
735 image->uniqueID(),
736 *view,
737 SkColorTypeToGrColorType(image->colorType()),
738 image->refColorSpace(),
739 &this->surfaceProps());
740 } else if (image->peekPixels(&pm)) {
741 SkBitmap bm;
742
743 bm.installPixels(pm);
744 return this->makeSpecial(bm);
745 } else {
746 return nullptr;
747 }
748}
749
750sk_sp<SkSpecialImage> SkGpuDevice::snapSpecial(const SkIRect& subset, bool forceCopy) {
751 GrRenderTargetContext* rtc = this->accessRenderTargetContext();
752
753 // If we are wrapping a vulkan secondary command buffer, then we can't snap off a special image
754 // since it would require us to make a copy of the underlying VkImage which we don't have access
755 // to. Additionaly we can't stop and start the render pass that is used with the secondary
756 // command buffer.
757 if (rtc->wrapsVkSecondaryCB()) {
758 return nullptr;
759 }
760
761 SkASSERT(rtc->asSurfaceProxy());
762
763 SkIRect finalSubset = subset;
764 GrSurfaceProxyView view = rtc->readSurfaceView();
765 if (forceCopy || !view.asTextureProxy()) {
766 // When the device doesn't have a texture, or a copy is requested, we create a temporary
767 // texture that matches the device contents
768 view = GrSurfaceProxyView::Copy(fContext.get(),
769 std::move(view),
770 GrMipmapped::kNo, // Don't auto generate mips
771 subset,
772 SkBackingFit::kApprox,
773 SkBudgeted::kYes); // Always budgeted
774 if (!view) {
775 return nullptr;
776 }
777 // Since this copied only the requested subset, the special image wrapping the proxy no
778 // longer needs the original subset.
779 finalSubset = SkIRect::MakeSize(view.dimensions());
780 }
781
782 GrColorType ct = SkColorTypeToGrColorType(this->imageInfo().colorType());
783
784 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
785 finalSubset,
786 kNeedNewImageUniqueID_SpecialImage,
787 std::move(view),
788 ct,
789 this->imageInfo().refColorSpace(),
790 &this->surfaceProps());
791}
792
793void SkGpuDevice::drawDevice(SkBaseDevice* device,
794 int left, int top, const SkPaint& paint) {
795 SkASSERT(!paint.getImageFilter());
796 SkASSERT(!paint.getMaskFilter());
797
798 ASSERT_SINGLE_OWNER
799 // clear of the source device must occur before CHECK_SHOULD_DRAW
800 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext.get());
801
802 // drawDevice is defined to be in device coords.
803 SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
804 sk_sp<SkSpecialImage> srcImg(dev->snapSpecial(SkIRect::MakeWH(dev->width(), dev->height())));
805 if (!srcImg) {
806 return;
807 }
808
809 this->drawSpecial(srcImg.get(), left, top, paint);
810}
811
812void SkGpuDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
813 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
814 ASSERT_SINGLE_OWNER
815 GrQuadAAFlags aaFlags = paint.isAntiAlias() ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
816 this->drawImageQuad(image, src, &dst, nullptr, GrAA(paint.isAntiAlias()), aaFlags, nullptr,
817 paint, constraint);
818}
819
820// When drawing nine-patches or n-patches, cap the filter quality at kLinear.
821static GrSamplerState::Filter compute_lattice_filter_mode(const SkPaint& paint) {
822 if (paint.getFilterQuality() == kNone_SkFilterQuality) {
823 return GrSamplerState::Filter::kNearest;
824 }
825 return GrSamplerState::Filter::kLinear;
826}
827
828void SkGpuDevice::drawImageNine(const SkImage* image,
829 const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
830 ASSERT_SINGLE_OWNER
831 uint32_t pinnedUniqueID;
832 auto iter = std::make_unique<SkLatticeIter>(image->width(), image->height(), center, dst);
833 if (GrSurfaceProxyView view = as_IB(image)->refPinnedView(this->recordingContext(),
834 &pinnedUniqueID)) {
835 GrTextureAdjuster adjuster(this->recordingContext(), std::move(view),
836 image->imageInfo().colorInfo(), pinnedUniqueID);
837 this->drawProducerLattice(&adjuster, std::move(iter), dst, paint);
838 } else {
839 SkBitmap bm;
840 if (image->isLazyGenerated()) {
841 GrImageTextureMaker maker(fContext.get(), image, GrImageTexGenPolicy::kDraw);
842 this->drawProducerLattice(&maker, std::move(iter), dst, paint);
843 } else if (as_IB(image)->getROPixels(&bm)) {
844 GrBitmapTextureMaker maker(fContext.get(), bm, GrImageTexGenPolicy::kDraw);
845 this->drawProducerLattice(&maker, std::move(iter), dst, paint);
846 }
847 }
848}
849
850void SkGpuDevice::drawProducerLattice(GrTextureProducer* producer,
851 std::unique_ptr<SkLatticeIter> iter, const SkRect& dst,
852 const SkPaint& origPaint) {
853 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerLattice", fContext.get());
854 SkTCopyOnFirstWrite<SkPaint> paint(&origPaint);
855
856 if (!producer->isAlphaOnly() && (paint->getColor() & 0x00FFFFFF) != 0x00FFFFFF) {
857 paint.writable()->setColor(SkColorSetARGB(origPaint.getAlpha(), 0xFF, 0xFF, 0xFF));
858 }
859 GrPaint grPaint;
860 if (!SkPaintToGrPaintWithPrimitiveColor(this->recordingContext(),
861 fRenderTargetContext->colorInfo(),
862 *paint, this->asMatrixProvider(), &grPaint)) {
863 return;
864 }
865
866 auto dstColorSpace = fRenderTargetContext->colorInfo().colorSpace();
867 const GrSamplerState::Filter filter = compute_lattice_filter_mode(*paint);
868 auto view = producer->view(GrMipmapped::kNo);
869 if (!view) {
870 return;
871 }
872 auto csxf = GrColorSpaceXform::Make(producer->colorSpace(), producer->alphaType(),
873 dstColorSpace, kPremul_SkAlphaType);
874
875 fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->localToDevice(),
876 std::move(view), producer->alphaType(), std::move(csxf),
877 filter, std::move(iter), dst);
878}
879
880void SkGpuDevice::drawImageLattice(const SkImage* image,
881 const SkCanvas::Lattice& lattice, const SkRect& dst,
882 const SkPaint& paint) {
883 ASSERT_SINGLE_OWNER
884 uint32_t pinnedUniqueID;
885 auto iter = std::make_unique<SkLatticeIter>(lattice, dst);
886 if (GrSurfaceProxyView view = as_IB(image)->refPinnedView(this->recordingContext(),
887 &pinnedUniqueID)) {
888 GrTextureAdjuster adjuster(this->recordingContext(), std::move(view),
889 image->imageInfo().colorInfo(), pinnedUniqueID);
890 this->drawProducerLattice(&adjuster, std::move(iter), dst, paint);
891 } else {
892 SkBitmap bm;
893 if (image->isLazyGenerated()) {
894 GrImageTextureMaker maker(fContext.get(), image, GrImageTexGenPolicy::kDraw);
895 this->drawProducerLattice(&maker, std::move(iter), dst, paint);
896 } else if (as_IB(image)->getROPixels(&bm)) {
897 GrBitmapTextureMaker maker(fContext.get(), bm, GrImageTexGenPolicy::kDraw);
898 this->drawProducerLattice(&maker, std::move(iter), dst, paint);
899 }
900 }
901}
902
903static bool init_vertices_paint(GrRecordingContext* context,
904 const GrColorInfo& colorInfo,
905 const SkPaint& skPaint,
906 const SkMatrixProvider& matrixProvider,
907 SkBlendMode bmode,
908 bool hasColors,
909 GrPaint* grPaint) {
910 if (skPaint.getShader()) {
911 if (hasColors) {
912 // When there are colors and a shader, the shader and colors are combined using bmode.
913 return SkPaintToGrPaintWithBlend(context, colorInfo, skPaint, matrixProvider, bmode,
914 grPaint);
915 } else {
916 // We have a shader, but no colors to blend it against.
917 return SkPaintToGrPaint(context, colorInfo, skPaint, matrixProvider, grPaint);
918 }
919 } else {
920 if (hasColors) {
921 // We have colors, but no shader.
922 return SkPaintToGrPaintWithPrimitiveColor(context, colorInfo, skPaint, matrixProvider,
923 grPaint);
924 } else {
925 // No colors and no shader. Just draw with the paint color.
926 return SkPaintToGrPaintNoShader(context, colorInfo, skPaint, matrixProvider, grPaint);
927 }
928 }
929}
930
931void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
932 ASSERT_SINGLE_OWNER
933 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get());
934 SkASSERT(vertices);
935
936 SkVerticesPriv info(vertices->priv());
937
938 const SkRuntimeEffect* effect =
939 paint.getShader() ? as_SB(paint.getShader())->asRuntimeEffect() : nullptr;
940
941 GrPaint grPaint;
942 if (!init_vertices_paint(fContext.get(), fRenderTargetContext->colorInfo(), paint,
943 this->asMatrixProvider(), mode, info.hasColors(), &grPaint)) {
944 return;
945 }
946 fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->asMatrixProvider(),
947 sk_ref_sp(const_cast<SkVertices*>(vertices)), nullptr,
948 effect);
949}
950
951///////////////////////////////////////////////////////////////////////////////
952
953void SkGpuDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
954
955 ASSERT_SINGLE_OWNER
956 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawShadow", fContext.get());
957
958 if (!fRenderTargetContext->drawFastShadow(this->clip(), this->localToDevice(), path, rec)) {
959 // failed to find an accelerated case
960 this->INHERITED::drawShadow(path, rec);
961 }
962}
963
964///////////////////////////////////////////////////////////////////////////////
965
966void SkGpuDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[],
967 const SkRect texRect[], const SkColor colors[], int count,
968 SkBlendMode mode, const SkPaint& paint) {
969 ASSERT_SINGLE_OWNER
970 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawAtlas", fContext.get());
971
972 SkPaint p(paint);
973 p.setShader(atlas->makeShader());
974
975 GrPaint grPaint;
976 if (colors) {
977 if (!SkPaintToGrPaintWithBlend(this->recordingContext(), fRenderTargetContext->colorInfo(),
978 p, this->asMatrixProvider(), (SkBlendMode)mode, &grPaint)) {
979 return;
980 }
981 } else {
982 if (!SkPaintToGrPaint(this->recordingContext(), fRenderTargetContext->colorInfo(), p,
983 this->asMatrixProvider(), &grPaint)) {
984 return;
985 }
986 }
987
988 fRenderTargetContext->drawAtlas(
989 this->clip(), std::move(grPaint), this->localToDevice(), count, xform, texRect, colors);
990}
991
992///////////////////////////////////////////////////////////////////////////////
993
994void SkGpuDevice::drawGlyphRunList(const SkGlyphRunList& glyphRunList) {
995 ASSERT_SINGLE_OWNER
996 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawGlyphRunList", fContext.get());
997
998 // Check for valid input
999 if (!this->localToDevice().isFinite() || !glyphRunList.allFontsFinite()) {
1000 return;
1001 }
1002
1003 fRenderTargetContext->drawGlyphRunList(this->clip(), this->asMatrixProvider(), glyphRunList);
1004}
1005
1006///////////////////////////////////////////////////////////////////////////////
1007
1008void SkGpuDevice::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, SkCanvas* canvas) {
1009 GrBackendApi api = this->recordingContext()->backend();
1010 if (GrBackendApi::kVulkan == api) {
1011 const SkMatrix& ctm = canvas->getTotalMatrix();
1012 const SkMatrix& combinedMatrix = matrix ? SkMatrix::Concat(ctm, *matrix) : ctm;
1013 std::unique_ptr<SkDrawable::GpuDrawHandler> gpuDraw =
1014 drawable->snapGpuDrawHandler(api, combinedMatrix, canvas->getDeviceClipBounds(),
1015 this->imageInfo());
1016 if (gpuDraw) {
1017 fRenderTargetContext->drawDrawable(std::move(gpuDraw), drawable->getBounds());
1018 return;
1019 }
1020 }
1021 this->INHERITED::drawDrawable(drawable, matrix, canvas);
1022}
1023
1024
1025///////////////////////////////////////////////////////////////////////////////
1026
1027void SkGpuDevice::flush() {
1028 auto direct = fContext->asDirectContext();
1029 if (!direct) {
1030 return;
1031 }
1032
1033 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo(), nullptr);
1034 direct->submit();
1035}
1036
1037GrSemaphoresSubmitted SkGpuDevice::flush(SkSurface::BackendSurfaceAccess access,
1038 const GrFlushInfo& info,
1039 const GrBackendSurfaceMutableState* newState) {
1040 ASSERT_SINGLE_OWNER
1041
1042 return fRenderTargetContext->flush(access, info, newState);
1043}
1044
1045bool SkGpuDevice::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores,
1046 bool deleteSemaphoresAfterWait) {
1047 ASSERT_SINGLE_OWNER
1048
1049 return fRenderTargetContext->waitOnSemaphores(numSemaphores, waitSemaphores,
1050 deleteSemaphoresAfterWait);
1051}
1052
1053///////////////////////////////////////////////////////////////////////////////
1054
1055SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
1056 ASSERT_SINGLE_OWNER
1057
1058 SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry);
1059
1060 // layers are never drawn in repeat modes, so we can request an approx
1061 // match and ignore any padding.
1062 SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox
1063 : SkBackingFit::kExact;
1064
1065 SkASSERT(cinfo.fInfo.colorType() != kRGBA_1010102_SkColorType);
1066
1067 auto rtc = GrRenderTargetContext::MakeWithFallback(
1068 fContext.get(), SkColorTypeToGrColorType(cinfo.fInfo.colorType()),
1069 fRenderTargetContext->colorInfo().refColorSpace(), fit, cinfo.fInfo.dimensions(),
1070 fRenderTargetContext->numSamples(), GrMipmapped::kNo,
1071 fRenderTargetContext->asSurfaceProxy()->isProtected(), kBottomLeft_GrSurfaceOrigin,
1072 SkBudgeted::kYes, &props);
1073 if (!rtc) {
1074 return nullptr;
1075 }
1076
1077 // Skia's convention is to only clear a device if it is non-opaque.
1078 InitContents init = cinfo.fInfo.isOpaque() ? kUninit_InitContents : kClear_InitContents;
1079
1080 return SkGpuDevice::Make(fContext.get(), std::move(rtc), init).release();
1081}
1082
1083sk_sp<SkSurface> SkGpuDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1084 ASSERT_SINGLE_OWNER
1085 // TODO: Change the signature of newSurface to take a budgeted parameter.
1086 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
1087 return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info,
1088 fRenderTargetContext->numSamples(),
1089 fRenderTargetContext->origin(), &props);
1090}
1091
1092SkImageFilterCache* SkGpuDevice::getImageFilterCache() {
1093 ASSERT_SINGLE_OWNER
1094 // We always return a transient cache, so it is freed after each
1095 // filter traversal.
1096 return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
1097}
1098
1099////////////////////////////////////////////////////////////////////////////////////
1100
1101bool SkGpuDevice::android_utils_clipWithStencil() {
1102 SkRegion clipRegion;
1103 this->onAsRgnClip(&clipRegion);
1104 if (clipRegion.isEmpty()) {
1105 return false;
1106 }
1107 GrRenderTargetContext* rtc = this->accessRenderTargetContext();
1108 if (!rtc) {
1109 return false;
1110 }
1111 GrPaint grPaint;
1112 grPaint.setXPFactory(GrDisableColorXPFactory::Get());
1113 static constexpr GrUserStencilSettings kDrawToStencil(
1114 GrUserStencilSettings::StaticInit<
1115 0x1,
1116 GrUserStencilTest::kAlways,
1117 0x1,
1118 GrUserStencilOp::kReplace,
1119 GrUserStencilOp::kReplace,
1120 0x1>()
1121 );
1122 rtc->drawRegion(nullptr, std::move(grPaint), GrAA::kNo, SkMatrix::I(), clipRegion,
1123 GrStyle::SimpleFill(), &kDrawToStencil);
1124 return true;
1125}
1126