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/v1/Device_v1.h"
9
10 #include "include/core/SkImageFilter.h"
11 #include "include/core/SkMaskFilter.h"
12 #include "include/core/SkPathEffect.h"
13 #include "include/core/SkPicture.h"
14 #include "include/core/SkSurface.h"
15 #include "include/core/SkVertices.h"
16 #include "include/effects/SkRuntimeEffect.h"
17 #include "include/gpu/GrDirectContext.h"
18 #include "include/gpu/GrRecordingContext.h"
19 #include "include/private/SkShadowFlags.h"
20 #include "include/private/SkTo.h"
21 #include "src/core/SkCanvasPriv.h"
22 #include "src/core/SkClipStack.h"
23 #include "src/core/SkDraw.h"
24 #include "src/core/SkImageFilterCache.h"
25 #include "src/core/SkImageFilter_Base.h"
26 #include "src/core/SkLatticeIter.h"
27 #include "src/core/SkPictureData.h"
28 #include "src/core/SkRRectPriv.h"
29 #include "src/core/SkRasterClip.h"
30 #include "src/core/SkRecord.h"
31 #include "src/core/SkStroke.h"
32 #include "src/core/SkTLazy.h"
33 #include "src/core/SkVerticesPriv.h"
34 #include "src/gpu/GrBlurUtils.h"
35 #include "src/gpu/GrDirectContextPriv.h"
36 #include "src/gpu/GrGpu.h"
37 #include "src/gpu/GrRecordingContextPriv.h"
38 #include "src/gpu/GrStyle.h"
39 #include "src/gpu/GrSurfaceProxyPriv.h"
40 #include "src/gpu/GrTracing.h"
41 #include "src/gpu/SkGr.h"
42 #include "src/gpu/effects/GrDisableColorXP.h"
43 #include "src/gpu/effects/GrRRectEffect.h"
44 #include "src/gpu/geometry/GrStyledShape.h"
45 #include "src/image/SkImage_Base.h"
46 #include "src/image/SkReadPixelsRec.h"
47 #include "src/image/SkSurface_Gpu.h"
48 #include "src/utils/SkUTF.h"
49
50 #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fContext->priv().singleOwner())
51
52
53 ///////////////////////////////////////////////////////////////////////////////
54
55 namespace {
56
force_aa_clip(const skgpu::v1::SurfaceDrawContext * sdc)57 bool force_aa_clip(const skgpu::v1::SurfaceDrawContext* sdc) {
58 return sdc->numSamples() > 1 || sdc->alwaysAntialias();
59 }
60
point_mode_to_primitive_type(SkCanvas::PointMode mode)61 inline GrPrimitiveType point_mode_to_primitive_type(SkCanvas::PointMode mode) {
62 switch (mode) {
63 case SkCanvas::kPoints_PointMode:
64 return GrPrimitiveType::kPoints;
65 case SkCanvas::kLines_PointMode:
66 return GrPrimitiveType::kLines;
67 case SkCanvas::kPolygon_PointMode:
68 return GrPrimitiveType::kLineStrip;
69 }
70 SK_ABORT("Unexpected mode");
71 }
72
make_inverse_rrect_fp(const SkMatrix & viewMatrix,const SkRRect & rrect,GrAA aa,const GrShaderCaps & shaderCaps)73 std::unique_ptr<GrFragmentProcessor> make_inverse_rrect_fp(const SkMatrix& viewMatrix,
74 const SkRRect& rrect, GrAA aa,
75 const GrShaderCaps& shaderCaps) {
76 SkTCopyOnFirstWrite<SkRRect> devRRect(rrect);
77 if (viewMatrix.isIdentity() || rrect.transform(viewMatrix, devRRect.writable())) {
78 auto edgeType = (aa == GrAA::kYes) ? GrClipEdgeType::kInverseFillAA
79 : GrClipEdgeType::kInverseFillBW;
80 auto [success, fp] = GrRRectEffect::Make(/*inputFP=*/nullptr, edgeType, *devRRect,
81 shaderCaps);
82 return (success) ? std::move(fp) : nullptr;
83 }
84 return nullptr;
85 }
86
init_vertices_paint(GrRecordingContext * rContext,const GrColorInfo & colorInfo,const SkPaint & skPaint,const SkMatrixProvider & matrixProvider,SkBlendMode bmode,bool hasColors,GrPaint * grPaint)87 bool init_vertices_paint(GrRecordingContext* rContext,
88 const GrColorInfo& colorInfo,
89 const SkPaint& skPaint,
90 const SkMatrixProvider& matrixProvider,
91 SkBlendMode bmode,
92 bool hasColors,
93 GrPaint* grPaint) {
94 if (hasColors) {
95 // When there are colors and a shader, the shader and colors are combined using bmode.
96 // With no shader, we just use the colors (kDst).
97 return SkPaintToGrPaintWithBlend(rContext,
98 colorInfo,
99 skPaint,
100 matrixProvider,
101 skPaint.getShader() ? bmode : SkBlendMode::kDst,
102 grPaint);
103 } else {
104 return SkPaintToGrPaint(rContext, colorInfo, skPaint, matrixProvider, grPaint);
105 }
106 }
107
108 } // anonymous namespace
109
110 namespace skgpu::v1 {
111
Make(GrRecordingContext * rContext,GrColorType colorType,sk_sp<GrSurfaceProxy> proxy,sk_sp<SkColorSpace> colorSpace,GrSurfaceOrigin origin,const SkSurfaceProps & surfaceProps,InitContents init)112 sk_sp<BaseDevice> Device::Make(GrRecordingContext* rContext,
113 GrColorType colorType,
114 sk_sp<GrSurfaceProxy> proxy,
115 sk_sp<SkColorSpace> colorSpace,
116 GrSurfaceOrigin origin,
117 const SkSurfaceProps& surfaceProps,
118 InitContents init) {
119 auto sdc = SurfaceDrawContext::Make(rContext,
120 colorType,
121 std::move(proxy),
122 std::move(colorSpace),
123 origin,
124 surfaceProps);
125
126 return Device::Make(std::move(sdc), kPremul_SkAlphaType, init);
127 }
128
Make(std::unique_ptr<SurfaceDrawContext> sdc,SkAlphaType alphaType,InitContents init)129 sk_sp<BaseDevice> Device::Make(std::unique_ptr<SurfaceDrawContext> sdc,
130 SkAlphaType alphaType,
131 InitContents init) {
132 if (!sdc) {
133 return nullptr;
134 }
135
136 GrRecordingContext* rContext = sdc->recordingContext();
137 if (rContext->abandoned()) {
138 return nullptr;
139 }
140
141 SkColorType ct = GrColorTypeToSkColorType(sdc->colorInfo().colorType());
142
143 DeviceFlags flags;
144 if (!rContext->colorTypeSupportedAsSurface(ct) ||
145 !CheckAlphaTypeAndGetFlags(alphaType, init, &flags)) {
146 return nullptr;
147 }
148 return sk_sp<Device>(new Device(std::move(sdc), flags));
149 }
150
Make(GrRecordingContext * rContext,SkBudgeted budgeted,const SkImageInfo & ii,SkBackingFit fit,int sampleCount,GrMipmapped mipMapped,GrProtected isProtected,GrSurfaceOrigin origin,const SkSurfaceProps & props,InitContents init)151 sk_sp<BaseDevice> Device::Make(GrRecordingContext* rContext,
152 SkBudgeted budgeted,
153 const SkImageInfo& ii,
154 SkBackingFit fit,
155 int sampleCount,
156 GrMipmapped mipMapped,
157 GrProtected isProtected,
158 GrSurfaceOrigin origin,
159 const SkSurfaceProps& props,
160 InitContents init) {
161 if (!rContext) {
162 return nullptr;
163 }
164
165 auto sdc = SurfaceDrawContext::Make(rContext,
166 SkColorTypeToGrColorType(ii.colorType()),
167 ii.refColorSpace(),
168 fit,
169 ii.dimensions(),
170 props,
171 sampleCount,
172 mipMapped,
173 isProtected,
174 origin,
175 budgeted);
176
177 return Device::Make(std::move(sdc), ii.alphaType(), init);
178 }
179
Device(std::unique_ptr<SurfaceDrawContext> sdc,DeviceFlags flags)180 Device::Device(std::unique_ptr<SurfaceDrawContext> sdc, DeviceFlags flags)
181 : INHERITED(sk_ref_sp(sdc->recordingContext()),
182 MakeInfo(sdc.get(), flags),
183 sdc->surfaceProps())
184 , fSurfaceDrawContext(std::move(sdc))
185 , fClip(SkIRect::MakeSize(fSurfaceDrawContext->dimensions()),
186 &this->asMatrixProvider(),
187 force_aa_clip(fSurfaceDrawContext.get())) {
188 if (flags & DeviceFlags::kNeedClear) {
189 this->clearAll();
190 }
191 }
192
193 ///////////////////////////////////////////////////////////////////////////////
194
onReadPixels(const SkPixmap & pm,int x,int y)195 bool Device::onReadPixels(const SkPixmap& pm, int x, int y) {
196 ASSERT_SINGLE_OWNER
197
198 // Context TODO: Elevate direct context requirement to public API
199 auto dContext = fContext->asDirectContext();
200 if (!dContext || !SkImageInfoValidConversion(pm.info(), this->imageInfo())) {
201 return false;
202 }
203
204 return fSurfaceDrawContext->readPixels(dContext, pm, {x, y});
205 }
206
onWritePixels(const SkPixmap & pm,int x,int y)207 bool Device::onWritePixels(const SkPixmap& pm, int x, int y) {
208 ASSERT_SINGLE_OWNER
209
210 // Context TODO: Elevate direct context requirement to public API
211 auto dContext = fContext->asDirectContext();
212 if (!dContext || !SkImageInfoValidConversion(this->imageInfo(), pm.info())) {
213 return false;
214 }
215
216 return fSurfaceDrawContext->writePixels(dContext, pm, {x, y});
217 }
218
onAccessPixels(SkPixmap * pmap)219 bool Device::onAccessPixels(SkPixmap* pmap) {
220 ASSERT_SINGLE_OWNER
221 return false;
222 }
223
surfaceDrawContext()224 SurfaceDrawContext* Device::surfaceDrawContext() {
225 ASSERT_SINGLE_OWNER
226 return fSurfaceDrawContext.get();
227 }
228
surfaceDrawContext() const229 const SurfaceDrawContext* Device::surfaceDrawContext() const {
230 ASSERT_SINGLE_OWNER
231 return fSurfaceDrawContext.get();
232 }
233
surfaceFillContext()234 skgpu::SurfaceFillContext* Device::surfaceFillContext() {
235 ASSERT_SINGLE_OWNER
236 return fSurfaceDrawContext.get();
237 }
238
clearAll()239 void Device::clearAll() {
240 ASSERT_SINGLE_OWNER
241 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "clearAll", fContext.get());
242
243 SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
244 fSurfaceDrawContext->clearAtLeast(rect, SK_PMColor4fTRANSPARENT);
245 }
246
247 ///////////////////////////////////////////////////////////////////////////////
248
onClipPath(const SkPath & path,SkClipOp op,bool aa)249 void Device::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
250 #if GR_TEST_UTILS
251 if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
252 this->onClipPath(SkPath(path).setIsVolatile(true), op, aa);
253 return;
254 }
255 #endif
256 SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
257 fClip.clipPath(this->localToDevice(), path, GrAA(aa), op);
258 }
259
onClipRegion(const SkRegion & globalRgn,SkClipOp op)260 void Device::onClipRegion(const SkRegion& globalRgn, SkClipOp op) {
261 SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
262
263 // Regions don't actually need AA, but in DMSAA mode every clip element is antialiased.
264 GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias());
265
266 if (globalRgn.isEmpty()) {
267 fClip.clipRect(SkMatrix::I(), SkRect::MakeEmpty(), aa, op);
268 } else if (globalRgn.isRect()) {
269 fClip.clipRect(this->globalToDevice().asM33(), SkRect::Make(globalRgn.getBounds()), aa, op);
270 } else {
271 SkPath path;
272 globalRgn.getBoundaryPath(&path);
273 fClip.clipPath(this->globalToDevice().asM33(), path, aa, op);
274 }
275 }
276
onAsRgnClip(SkRegion * region) const277 void Device::onAsRgnClip(SkRegion* region) const {
278 SkIRect bounds = fClip.getConservativeBounds();
279 // Assume wide open and then perform intersect/difference operations reducing the region
280 region->setRect(bounds);
281 const SkRegion deviceBounds(bounds);
282 for (const ClipStack::Element& e : fClip) {
283 SkRegion tmp;
284 if (e.fShape.isRect() && e.fLocalToDevice.isIdentity()) {
285 tmp.setRect(e.fShape.rect().roundOut());
286 } else {
287 SkPath tmpPath;
288 e.fShape.asPath(&tmpPath);
289 tmpPath.transform(e.fLocalToDevice);
290 tmp.setPath(tmpPath, deviceBounds);
291 }
292
293 region->op(tmp, (SkRegion::Op) e.fOp);
294 }
295 }
296
onClipIsAA() const297 bool Device::onClipIsAA() const {
298 for (const ClipStack::Element& e : fClip) {
299 if (e.fAA == GrAA::kYes) {
300 return true;
301 }
302 SkASSERT(!fSurfaceDrawContext->alwaysAntialias());
303 }
304 return false;
305 }
306
onGetClipType() const307 SkBaseDevice::ClipType Device::onGetClipType() const {
308 ClipStack::ClipState state = fClip.clipState();
309 if (state == ClipStack::ClipState::kEmpty) {
310 return ClipType::kEmpty;
311 } else if (state == ClipStack::ClipState::kDeviceRect ||
312 state == ClipStack::ClipState::kWideOpen) {
313 return ClipType::kRect;
314 } else {
315 return ClipType::kComplex;
316 }
317 }
318
319 ///////////////////////////////////////////////////////////////////////////////
320
drawPaint(const SkPaint & paint)321 void Device::drawPaint(const SkPaint& paint) {
322 ASSERT_SINGLE_OWNER
323 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPaint", fContext.get());
324
325 GrPaint grPaint;
326 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
327 this->asMatrixProvider(), &grPaint)) {
328 return;
329 }
330
331 fSurfaceDrawContext->drawPaint(this->clip(), std::move(grPaint), this->localToDevice());
332 }
333
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)334 void Device::drawPoints(SkCanvas::PointMode mode,
335 size_t count,
336 const SkPoint pts[],
337 const SkPaint& paint) {
338 ASSERT_SINGLE_OWNER
339 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPoints", fContext.get());
340 SkScalar width = paint.getStrokeWidth();
341 if (width < 0) {
342 return;
343 }
344
345 GrAA aa = fSurfaceDrawContext->chooseAA(paint);
346
347 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
348 GrStyle style(paint, SkPaint::kStroke_Style);
349 GrPaint grPaint;
350 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
351 this->asMatrixProvider(), &grPaint)) {
352 return;
353 }
354 SkPath path;
355 path.setIsVolatile(true);
356 path.moveTo(pts[0]);
357 path.lineTo(pts[1]);
358 fSurfaceDrawContext->drawPath(this->clip(), std::move(grPaint), aa, this->localToDevice(),
359 path, style);
360 return;
361 }
362
363 SkScalar scales[2];
364 bool isHairline = (0 == width) ||
365 (1 == width && this->localToDevice().getMinMaxScales(scales) &&
366 SkScalarNearlyEqual(scales[0], 1.f) && SkScalarNearlyEqual(scales[1], 1.f));
367 // we only handle non-coverage-aa hairlines and paints without path effects or mask filters,
368 // else we let the SkDraw call our drawPath()
369 if (!isHairline ||
370 paint.getPathEffect() ||
371 paint.getMaskFilter() ||
372 fSurfaceDrawContext->chooseAAType(aa) == GrAAType::kCoverage) {
373 SkRasterClip rc(this->devClipBounds());
374 SkDraw draw;
375 draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0);
376 draw.fMatrixProvider = this;
377 draw.fRC = &rc;
378 draw.drawPoints(mode, count, pts, paint, this);
379 return;
380 }
381
382 GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode);
383
384 const SkMatrixProvider* matrixProvider = this;
385 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
386 SkTLazy<SkPostTranslateMatrixProvider> postTranslateMatrixProvider;
387 // This offsetting in device space matches the expectations of the Android framework for non-AA
388 // points and lines.
389 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
390 static const SkScalar kOffset = 0.063f; // Just greater than 1/16.
391 matrixProvider = postTranslateMatrixProvider.init(*matrixProvider, kOffset, kOffset);
392 }
393 #endif
394
395 GrPaint grPaint;
396 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
397 *matrixProvider, &grPaint)) {
398 return;
399 }
400
401 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
402 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr,
403 nullptr);
404
405 fSurfaceDrawContext->drawVertices(this->clip(), std::move(grPaint), *matrixProvider,
406 std::move(vertices), &primitiveType);
407 }
408
409 ///////////////////////////////////////////////////////////////////////////////
410
drawRect(const SkRect & rect,const SkPaint & paint)411 void Device::drawRect(const SkRect& rect, const SkPaint& paint) {
412 ASSERT_SINGLE_OWNER
413 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRect", fContext.get());
414
415 GrStyle style(paint);
416
417 // A couple reasons we might need to call drawPath.
418 if (paint.getMaskFilter() || paint.getPathEffect()) {
419 GrStyledShape shape(rect, style);
420
421 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(),
422 this->clip(), paint, this->asMatrixProvider(), shape);
423 return;
424 }
425
426 GrPaint grPaint;
427 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
428 this->asMatrixProvider(), &grPaint)) {
429 return;
430 }
431
432 fSurfaceDrawContext->drawRect(this->clip(), std::move(grPaint),
433 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), rect,
434 &style);
435 }
436
drawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],SkCanvas::QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)437 void Device::drawEdgeAAQuad(const SkRect& rect,
438 const SkPoint clip[4],
439 SkCanvas::QuadAAFlags aaFlags,
440 const SkColor4f& color,
441 SkBlendMode mode) {
442 ASSERT_SINGLE_OWNER
443 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawEdgeAAQuad", fContext.get());
444
445 SkPMColor4f dstColor = SkColor4fPrepForDst(color, fSurfaceDrawContext->colorInfo()).premul();
446
447 GrPaint grPaint;
448 grPaint.setColor4f(dstColor);
449 if (mode != SkBlendMode::kSrcOver) {
450 grPaint.setXPFactory(SkBlendMode_AsXPFactory(mode));
451 }
452
453 // This is exclusively meant for tiling operations, so keep AA enabled to handle MSAA seaming
454 GrQuadAAFlags grAA = SkToGrQuadAAFlags(aaFlags);
455 if (clip) {
456 // Use fillQuadWithEdgeAA
457 fSurfaceDrawContext->fillQuadWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA,
458 this->localToDevice(), clip, nullptr);
459 } else {
460 // Use fillRectWithEdgeAA to preserve mathematical properties of dst being rectangular
461 fSurfaceDrawContext->fillRectWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA,
462 this->localToDevice(), rect);
463 }
464 }
465
466 ///////////////////////////////////////////////////////////////////////////////
467
drawRRect(const SkRRect & rrect,const SkPaint & paint)468 void Device::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
469 ASSERT_SINGLE_OWNER
470 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRRect", fContext.get());
471
472 SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter());
473 if (mf) {
474 if (mf->hasFragmentProcessor()) {
475 mf = nullptr; // already handled in SkPaintToGrPaint
476 }
477 }
478
479 GrStyle style(paint);
480
481 if (mf || style.pathEffect()) {
482 // A path effect will presumably transform this rrect into something else.
483 GrStyledShape shape(rrect, style);
484
485 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(),
486 this->clip(), paint, this->asMatrixProvider(), shape);
487 return;
488 }
489
490 SkASSERT(!style.pathEffect());
491
492 GrPaint grPaint;
493 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
494 this->asMatrixProvider(), &grPaint)) {
495 return;
496 }
497
498 fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint),
499 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
500 rrect, style);
501 }
502
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)503 void Device::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
504 ASSERT_SINGLE_OWNER
505 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDRRect", fContext.get());
506 if (outer.isEmpty()) {
507 return;
508 }
509
510 if (inner.isEmpty()) {
511 return this->drawRRect(outer, paint);
512 }
513
514 SkStrokeRec stroke(paint);
515
516 if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
517 // For axis-aligned filled DRRects, just draw a regular rrect with inner clipped out using a
518 // coverage FP instead of using path rendering.
519 if (auto fp = make_inverse_rrect_fp(this->localToDevice(), inner,
520 fSurfaceDrawContext->chooseAA(paint),
521 *fSurfaceDrawContext->caps()->shaderCaps())) {
522 GrPaint grPaint;
523 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
524 this->asMatrixProvider(), &grPaint)) {
525 return;
526 }
527 SkASSERT(!grPaint.hasCoverageFragmentProcessor());
528 grPaint.setCoverageFragmentProcessor(std::move(fp));
529 fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint),
530 fSurfaceDrawContext->chooseAA(paint),
531 this->localToDevice(), outer, GrStyle());
532 return;
533 }
534 }
535
536 SkPath path;
537 path.setIsVolatile(true);
538 path.addRRect(outer);
539 path.addRRect(inner);
540 path.setFillType(SkPathFillType::kEvenOdd);
541
542 // TODO: We are losing the possible mutability of the path here but this should probably be
543 // fixed by upgrading GrStyledShape to handle DRRects.
544 GrStyledShape shape(path, paint);
545
546 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(),
547 paint, this->asMatrixProvider(), shape);
548 }
549
550 /////////////////////////////////////////////////////////////////////////////
551
drawRegion(const SkRegion & region,const SkPaint & paint)552 void Device::drawRegion(const SkRegion& region, const SkPaint& paint) {
553 ASSERT_SINGLE_OWNER
554
555 if (paint.getMaskFilter()) {
556 SkPath path;
557 region.getBoundaryPath(&path);
558 path.setIsVolatile(true);
559 return this->drawPath(path, paint, true);
560 }
561
562 GrPaint grPaint;
563 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
564 this->asMatrixProvider(), &grPaint)) {
565 return;
566 }
567
568 fSurfaceDrawContext->drawRegion(this->clip(), std::move(grPaint),
569 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
570 region, GrStyle(paint));
571 }
572
drawOval(const SkRect & oval,const SkPaint & paint)573 void Device::drawOval(const SkRect& oval, const SkPaint& paint) {
574 ASSERT_SINGLE_OWNER
575 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawOval", fContext.get());
576
577 if (paint.getMaskFilter()) {
578 // The RRect path can handle special case blurring
579 SkRRect rr = SkRRect::MakeOval(oval);
580 return this->drawRRect(rr, paint);
581 }
582
583 GrPaint grPaint;
584 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
585 this->asMatrixProvider(), &grPaint)) {
586 return;
587 }
588
589 fSurfaceDrawContext->drawOval(this->clip(), std::move(grPaint),
590 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval,
591 GrStyle(paint));
592 }
593
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)594 void Device::drawArc(const SkRect& oval,
595 SkScalar startAngle,
596 SkScalar sweepAngle,
597 bool useCenter,
598 const SkPaint& paint) {
599 ASSERT_SINGLE_OWNER
600 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawArc", fContext.get());
601 if (paint.getMaskFilter()) {
602 this->INHERITED::drawArc(oval, startAngle, sweepAngle, useCenter, paint);
603 return;
604 }
605 GrPaint grPaint;
606 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
607 this->asMatrixProvider(), &grPaint)) {
608 return;
609 }
610
611 fSurfaceDrawContext->drawArc(this->clip(), std::move(grPaint),
612 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval,
613 startAngle, sweepAngle, useCenter, GrStyle(paint));
614 }
615
616 ///////////////////////////////////////////////////////////////////////////////
617
drawPath(const SkPath & origSrcPath,const SkPaint & paint,bool pathIsMutable)618 void Device::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool pathIsMutable) {
619 #if GR_TEST_UTILS
620 if (fContext->priv().options().fAllPathsVolatile && !origSrcPath.isVolatile()) {
621 this->drawPath(SkPath(origSrcPath).setIsVolatile(true), paint, true);
622 return;
623 }
624 #endif
625 ASSERT_SINGLE_OWNER
626 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPath", fContext.get());
627 if (!paint.getMaskFilter()) {
628 GrPaint grPaint;
629 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
630 this->asMatrixProvider(), &grPaint)) {
631 return;
632 }
633 fSurfaceDrawContext->drawPath(this->clip(), std::move(grPaint),
634 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
635 origSrcPath, GrStyle(paint));
636 return;
637 }
638
639 // TODO: losing possible mutability of 'origSrcPath' here
640 GrStyledShape shape(origSrcPath, paint);
641
642 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(),
643 paint, this->asMatrixProvider(), shape);
644 }
645
makeSpecial(const SkBitmap & bitmap)646 sk_sp<SkSpecialImage> Device::makeSpecial(const SkBitmap& bitmap) {
647 ASSERT_SINGLE_OWNER
648
649 // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's
650 // semantics). Since this is cached we would have to bake the fit into the cache key though.
651 auto view = std::get<0>(GrMakeCachedBitmapProxyView(fContext.get(), bitmap));
652 if (!view) {
653 return nullptr;
654 }
655
656 const SkIRect rect = SkIRect::MakeSize(view.proxy()->dimensions());
657
658 // GrMakeCachedBitmapProxyView creates a tight copy of 'bitmap' so we don't have to subset
659 // the special image
660 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
661 rect,
662 bitmap.getGenerationID(),
663 std::move(view),
664 SkColorTypeToGrColorType(bitmap.colorType()),
665 bitmap.refColorSpace(),
666 this->surfaceProps());
667 }
668
makeSpecial(const SkImage * image)669 sk_sp<SkSpecialImage> Device::makeSpecial(const SkImage* image) {
670 ASSERT_SINGLE_OWNER
671
672 SkPixmap pm;
673 if (image->isTextureBacked()) {
674 auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo);
675 SkASSERT(view);
676
677 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
678 SkIRect::MakeWH(image->width(), image->height()),
679 image->uniqueID(),
680 std::move(view),
681 ct,
682 image->refColorSpace(),
683 this->surfaceProps());
684 } else if (image->peekPixels(&pm)) {
685 SkBitmap bm;
686
687 bm.installPixels(pm);
688 return this->makeSpecial(bm);
689 } else {
690 return nullptr;
691 }
692 }
693
snapSpecial(const SkIRect & subset,bool forceCopy)694 sk_sp<SkSpecialImage> Device::snapSpecial(const SkIRect& subset, bool forceCopy) {
695 ASSERT_SINGLE_OWNER
696
697 auto sdc = fSurfaceDrawContext.get();
698
699 // If we are wrapping a vulkan secondary command buffer, then we can't snap off a special image
700 // since it would require us to make a copy of the underlying VkImage which we don't have access
701 // to. Additionaly we can't stop and start the render pass that is used with the secondary
702 // command buffer.
703 if (sdc->wrapsVkSecondaryCB()) {
704 return nullptr;
705 }
706
707 SkASSERT(sdc->asSurfaceProxy());
708
709 SkIRect finalSubset = subset;
710 GrSurfaceProxyView view = sdc->readSurfaceView();
711 if (forceCopy || !view.asTextureProxy()) {
712 // When the device doesn't have a texture, or a copy is requested, we create a temporary
713 // texture that matches the device contents
714 view = GrSurfaceProxyView::Copy(fContext.get(),
715 std::move(view),
716 GrMipmapped::kNo, // Don't auto generate mips
717 subset,
718 SkBackingFit::kApprox,
719 SkBudgeted::kYes); // Always budgeted
720 if (!view) {
721 return nullptr;
722 }
723 // Since this copied only the requested subset, the special image wrapping the proxy no
724 // longer needs the original subset.
725 finalSubset = SkIRect::MakeSize(view.dimensions());
726 }
727
728 GrColorType ct = SkColorTypeToGrColorType(this->imageInfo().colorType());
729
730 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
731 finalSubset,
732 kNeedNewImageUniqueID_SpecialImage,
733 std::move(view),
734 ct,
735 this->imageInfo().refColorSpace(),
736 this->surfaceProps());
737 }
738
drawDevice(SkBaseDevice * device,const SkSamplingOptions & sampling,const SkPaint & paint)739 void Device::drawDevice(SkBaseDevice* device,
740 const SkSamplingOptions& sampling,
741 const SkPaint& paint) {
742 ASSERT_SINGLE_OWNER
743 // clear of the source device must occur before CHECK_SHOULD_DRAW
744 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDevice", fContext.get());
745 this->INHERITED::drawDevice(device, sampling, paint);
746 }
747
drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)748 void Device::drawImageRect(const SkImage* image,
749 const SkRect* src,
750 const SkRect& dst,
751 const SkSamplingOptions& sampling,
752 const SkPaint& paint,
753 SkCanvas::SrcRectConstraint constraint) {
754 ASSERT_SINGLE_OWNER
755 GrAA aa = fSurfaceDrawContext->chooseAA(paint);
756 GrQuadAAFlags aaFlags = (aa == GrAA::kYes) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
757 this->drawImageQuad(image, src, &dst, nullptr, aa, aaFlags, nullptr, sampling, paint,
758 constraint);
759 }
760
drawViewLattice(GrSurfaceProxyView view,const GrColorInfo & info,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst,SkFilterMode filter,const SkPaint & origPaint)761 void Device::drawViewLattice(GrSurfaceProxyView view,
762 const GrColorInfo& info,
763 std::unique_ptr<SkLatticeIter> iter,
764 const SkRect& dst,
765 SkFilterMode filter,
766 const SkPaint& origPaint) {
767 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawViewLattice", fContext.get());
768 SkASSERT(view);
769
770 SkTCopyOnFirstWrite<SkPaint> paint(&origPaint);
771
772 if (!info.isAlphaOnly() && (paint->getColor() & 0x00FFFFFF) != 0x00FFFFFF) {
773 paint.writable()->setColor(SkColorSetARGB(origPaint.getAlpha(), 0xFF, 0xFF, 0xFF));
774 }
775 GrPaint grPaint;
776 if (!SkPaintToGrPaintWithPrimitiveColor(this->recordingContext(),
777 fSurfaceDrawContext->colorInfo(), *paint,
778 this->asMatrixProvider(), &grPaint)) {
779 return;
780 }
781
782 if (info.isAlphaOnly()) {
783 // If we were doing this with an FP graph we'd use a kDstIn blend between the texture and
784 // the paint color.
785 view.concatSwizzle(GrSwizzle("aaaa"));
786 }
787 auto csxf = GrColorSpaceXform::Make(info, fSurfaceDrawContext->colorInfo());
788
789 fSurfaceDrawContext->drawImageLattice(this->clip(), std::move(grPaint), this->localToDevice(),
790 std::move(view), info.alphaType(), std::move(csxf),
791 filter, std::move(iter), dst);
792 }
793
drawImageLattice(const SkImage * image,const SkCanvas::Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint & paint)794 void Device::drawImageLattice(const SkImage* image,
795 const SkCanvas::Lattice& lattice,
796 const SkRect& dst,
797 SkFilterMode filter,
798 const SkPaint& paint) {
799 ASSERT_SINGLE_OWNER
800 auto iter = std::make_unique<SkLatticeIter>(lattice, dst);
801 if (auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo); view) {
802 GrColorInfo colorInfo(ct, image->alphaType(), image->refColorSpace());
803 this->drawViewLattice(std::move(view),
804 std::move(colorInfo),
805 std::move(iter),
806 dst,
807 filter,
808 paint);
809 }
810 }
811
drawVertices(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)812 void Device::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
813 ASSERT_SINGLE_OWNER
814 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawVertices", fContext.get());
815 SkASSERT(vertices);
816
817 SkVerticesPriv info(vertices->priv());
818
819 GrPaint grPaint;
820 if (!init_vertices_paint(fContext.get(), fSurfaceDrawContext->colorInfo(), paint,
821 this->asMatrixProvider(), mode, info.hasColors(), &grPaint)) {
822 return;
823 }
824 fSurfaceDrawContext->drawVertices(this->clip(),
825 std::move(grPaint),
826 this->asMatrixProvider(),
827 sk_ref_sp(const_cast<SkVertices*>(vertices)),
828 nullptr);
829 }
830
831 ///////////////////////////////////////////////////////////////////////////////
832
drawShadow(const SkPath & path,const SkDrawShadowRec & rec)833 void Device::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
834 #if GR_TEST_UTILS
835 if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
836 this->drawShadow(SkPath(path).setIsVolatile(true), rec);
837 return;
838 }
839 #endif
840 ASSERT_SINGLE_OWNER
841 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawShadow", fContext.get());
842
843 if (!fSurfaceDrawContext->drawFastShadow(this->clip(), this->localToDevice(), path, rec)) {
844 // failed to find an accelerated case
845 this->INHERITED::drawShadow(path, rec);
846 }
847 }
848
849 ///////////////////////////////////////////////////////////////////////////////
850
drawAtlas(const SkRSXform xform[],const SkRect texRect[],const SkColor colors[],int count,SkBlendMode mode,const SkPaint & paint)851 void Device::drawAtlas(const SkRSXform xform[],
852 const SkRect texRect[],
853 const SkColor colors[],
854 int count,
855 SkBlendMode mode,
856 const SkPaint& paint) {
857 ASSERT_SINGLE_OWNER
858 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawAtlas", fContext.get());
859
860 GrPaint grPaint;
861 if (colors) {
862 if (!SkPaintToGrPaintWithBlend(this->recordingContext(), fSurfaceDrawContext->colorInfo(),
863 paint, this->asMatrixProvider(), mode, &grPaint)) {
864 return;
865 }
866 } else {
867 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(),
868 paint, this->asMatrixProvider(), &grPaint)) {
869 return;
870 }
871 }
872
873 fSurfaceDrawContext->drawAtlas(this->clip(), std::move(grPaint), this->localToDevice(), count,
874 xform, texRect, colors);
875 }
876
877 ///////////////////////////////////////////////////////////////////////////////
878
onDrawGlyphRunList(const SkGlyphRunList & glyphRunList,const SkPaint & paint)879 void Device::onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) {
880 ASSERT_SINGLE_OWNER
881 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawGlyphRunList", fContext.get());
882 SkASSERT(!glyphRunList.hasRSXForm());
883
884 fSurfaceDrawContext->drawGlyphRunList(
885 this->clip(), this->asMatrixProvider(), glyphRunList, paint);
886 }
887
888 ///////////////////////////////////////////////////////////////////////////////
889
drawDrawable(SkDrawable * drawable,const SkMatrix * matrix,SkCanvas * canvas)890 void Device::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, SkCanvas* canvas) {
891 ASSERT_SINGLE_OWNER
892
893 GrBackendApi api = this->recordingContext()->backend();
894 if (GrBackendApi::kVulkan == api) {
895 const SkMatrix& ctm = this->localToDevice();
896 const SkMatrix& combinedMatrix = matrix ? SkMatrix::Concat(ctm, *matrix) : ctm;
897 std::unique_ptr<SkDrawable::GpuDrawHandler> gpuDraw =
898 drawable->snapGpuDrawHandler(api, combinedMatrix, this->devClipBounds(),
899 this->imageInfo());
900 if (gpuDraw) {
901 fSurfaceDrawContext->drawDrawable(
902 std::move(gpuDraw), combinedMatrix.mapRect(drawable->getBounds()));
903 return;
904 }
905 }
906 this->INHERITED::drawDrawable(drawable, matrix, canvas);
907 }
908
909
910 ///////////////////////////////////////////////////////////////////////////////
911
wait(int numSemaphores,const GrBackendSemaphore * waitSemaphores,bool deleteSemaphoresAfterWait)912 bool Device::wait(int numSemaphores,
913 const GrBackendSemaphore* waitSemaphores,
914 bool deleteSemaphoresAfterWait) {
915 ASSERT_SINGLE_OWNER
916
917 return fSurfaceDrawContext->waitOnSemaphores(numSemaphores, waitSemaphores,
918 deleteSemaphoresAfterWait);
919 }
920
replaceBackingProxy(SkSurface::ContentChangeMode mode,sk_sp<GrRenderTargetProxy> newRTP,GrColorType grColorType,sk_sp<SkColorSpace> colorSpace,GrSurfaceOrigin origin,const SkSurfaceProps & props)921 bool Device::replaceBackingProxy(SkSurface::ContentChangeMode mode,
922 sk_sp<GrRenderTargetProxy> newRTP,
923 GrColorType grColorType,
924 sk_sp<SkColorSpace> colorSpace,
925 GrSurfaceOrigin origin,
926 const SkSurfaceProps& props) {
927 auto sdc = SurfaceDrawContext::Make(fContext.get(), grColorType, std::move(newRTP),
928 std::move(colorSpace), origin, props);
929 if (!sdc) {
930 return false;
931 }
932
933 SkASSERT(sdc->dimensions() == fSurfaceDrawContext->dimensions());
934 SkASSERT(sdc->numSamples() == fSurfaceDrawContext->numSamples());
935 SkASSERT(sdc->asSurfaceProxy()->priv().isExact());
936 if (mode == SkSurface::kRetain_ContentChangeMode) {
937 if (fContext->abandoned()) {
938 return false;
939 }
940
941 SkASSERT(fSurfaceDrawContext->asTextureProxy());
942 SkAssertResult(sdc->blitTexture(fSurfaceDrawContext->readSurfaceView(),
943 SkIRect::MakeWH(this->width(), this->height()),
944 SkIPoint::Make(0, 0)));
945 }
946
947 fSurfaceDrawContext = std::move(sdc);
948 return true;
949 }
950
asyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)951 void Device::asyncRescaleAndReadPixels(const SkImageInfo& info,
952 const SkIRect& srcRect,
953 RescaleGamma rescaleGamma,
954 RescaleMode rescaleMode,
955 ReadPixelsCallback callback,
956 ReadPixelsContext context) {
957 auto* sdc = fSurfaceDrawContext.get();
958 // Context TODO: Elevate direct context requirement to public API.
959 auto dContext = sdc->recordingContext()->asDirectContext();
960 if (!dContext) {
961 return;
962 }
963 sdc->asyncRescaleAndReadPixels(dContext, info, srcRect, rescaleGamma, rescaleMode, callback,
964 context);
965 }
966
asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,SkISize dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)967 void Device::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
968 sk_sp<SkColorSpace> dstColorSpace,
969 const SkIRect& srcRect,
970 SkISize dstSize,
971 RescaleGamma rescaleGamma,
972 RescaleMode rescaleMode,
973 ReadPixelsCallback callback,
974 ReadPixelsContext context) {
975 auto* sdc = fSurfaceDrawContext.get();
976 // Context TODO: Elevate direct context requirement to public API.
977 auto dContext = sdc->recordingContext()->asDirectContext();
978 if (!dContext) {
979 return;
980 }
981 sdc->asyncRescaleAndReadPixelsYUV420(dContext,
982 yuvColorSpace,
983 std::move(dstColorSpace),
984 srcRect,
985 dstSize,
986 rescaleGamma,
987 rescaleMode,
988 callback,
989 context);
990 }
991
992 ///////////////////////////////////////////////////////////////////////////////
993
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)994 SkBaseDevice* Device::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
995 ASSERT_SINGLE_OWNER
996
997 SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry);
998
999 // layers are never drawn in repeat modes, so we can request an approx
1000 // match and ignore any padding.
1001 SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox
1002 : SkBackingFit::kExact;
1003
1004 SkASSERT(cinfo.fInfo.colorType() != kRGBA_1010102_SkColorType);
1005
1006 auto sdc = SurfaceDrawContext::MakeWithFallback(
1007 fContext.get(), SkColorTypeToGrColorType(cinfo.fInfo.colorType()),
1008 fSurfaceDrawContext->colorInfo().refColorSpace(), fit, cinfo.fInfo.dimensions(), props,
1009 fSurfaceDrawContext->numSamples(), GrMipmapped::kNo,
1010 fSurfaceDrawContext->asSurfaceProxy()->isProtected(), kBottomLeft_GrSurfaceOrigin,
1011 SkBudgeted::kYes);
1012 if (!sdc) {
1013 return nullptr;
1014 }
1015
1016 // Skia's convention is to only clear a device if it is non-opaque.
1017 InitContents init = cinfo.fInfo.isOpaque() ? InitContents::kUninit : InitContents::kClear;
1018
1019 return Device::Make(std::move(sdc), cinfo.fInfo.alphaType(), init).release();
1020 }
1021
makeSurface(const SkImageInfo & info,const SkSurfaceProps & props)1022 sk_sp<SkSurface> Device::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1023 ASSERT_SINGLE_OWNER
1024 // TODO: Change the signature of newSurface to take a budgeted parameter.
1025 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
1026 return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info,
1027 fSurfaceDrawContext->numSamples(),
1028 fSurfaceDrawContext->origin(), &props);
1029 }
1030
getImageFilterCache()1031 SkImageFilterCache* Device::getImageFilterCache() {
1032 ASSERT_SINGLE_OWNER
1033 // We always return a transient cache, so it is freed after each
1034 // filter traversal.
1035 return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
1036 }
1037
1038 ////////////////////////////////////////////////////////////////////////////////////
1039
android_utils_clipWithStencil()1040 bool Device::android_utils_clipWithStencil() {
1041 SkRegion clipRegion;
1042 this->onAsRgnClip(&clipRegion);
1043 if (clipRegion.isEmpty()) {
1044 return false;
1045 }
1046 auto sdc = fSurfaceDrawContext.get();
1047 SkASSERT(sdc);
1048 GrPaint grPaint;
1049 grPaint.setXPFactory(GrDisableColorXPFactory::Get());
1050 static constexpr GrUserStencilSettings kDrawToStencil(
1051 GrUserStencilSettings::StaticInit<
1052 0x1,
1053 GrUserStencilTest::kAlways,
1054 0x1,
1055 GrUserStencilOp::kReplace,
1056 GrUserStencilOp::kReplace,
1057 0x1>()
1058 );
1059 // Regions don't actually need AA, but in DMSAA mode everything is antialiased.
1060 GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias());
1061 sdc->drawRegion(nullptr, std::move(grPaint), aa, SkMatrix::I(), clipRegion,
1062 GrStyle::SimpleFill(), &kDrawToStencil);
1063 return true;
1064 }
1065
drawBlurImage(const SkImage * image,const SkBlurArg & blurArg)1066 bool Device::drawBlurImage(const SkImage* image, const SkBlurArg& blurArg)
1067 {
1068 if (image == nullptr) {
1069 return false;
1070 }
1071 if (auto[view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo); view) {
1072 return fSurfaceDrawContext->drawBlurImage(std::move(view), blurArg);
1073 }
1074 }
1075
1076 } // namespace skgpu::v1
1077