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 "include/private/chromium/GrSlug.h"
22 #include "src/core/SkCanvasPriv.h"
23 #include "src/core/SkClipStack.h"
24 #include "src/core/SkCustomMeshPriv.h"
25 #include "src/core/SkDraw.h"
26 #include "src/core/SkImageFilterCache.h"
27 #include "src/core/SkImageFilter_Base.h"
28 #include "src/core/SkLatticeIter.h"
29 #include "src/core/SkPictureData.h"
30 #include "src/core/SkRRectPriv.h"
31 #include "src/core/SkRasterClip.h"
32 #include "src/core/SkRecord.h"
33 #include "src/core/SkStroke.h"
34 #include "src/core/SkTLazy.h"
35 #include "src/core/SkVerticesPriv.h"
36 #include "src/gpu/GrBlurUtils.h"
37 #include "src/gpu/GrDirectContextPriv.h"
38 #include "src/gpu/GrGpu.h"
39 #include "src/gpu/GrRecordingContextPriv.h"
40 #include "src/gpu/GrStyle.h"
41 #include "src/gpu/GrSurfaceProxyPriv.h"
42 #include "src/gpu/GrTracing.h"
43 #include "src/gpu/SkGr.h"
44 #include "src/gpu/effects/GrDisableColorXP.h"
45 #include "src/gpu/effects/GrRRectEffect.h"
46 #include "src/gpu/geometry/GrStyledShape.h"
47 #include "src/image/SkImage_Base.h"
48 #include "src/image/SkReadPixelsRec.h"
49 #include "src/image/SkSurface_Gpu.h"
50 #include "src/utils/SkUTF.h"
51
52 #define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(fContext->priv().singleOwner())
53
54
55 ///////////////////////////////////////////////////////////////////////////////
56
57 namespace {
58
force_aa_clip(const skgpu::v1::SurfaceDrawContext * sdc)59 bool force_aa_clip(const skgpu::v1::SurfaceDrawContext* sdc) {
60 return sdc->numSamples() > 1 || sdc->alwaysAntialias();
61 }
62
point_mode_to_primitive_type(SkCanvas::PointMode mode)63 inline GrPrimitiveType point_mode_to_primitive_type(SkCanvas::PointMode mode) {
64 switch (mode) {
65 case SkCanvas::kPoints_PointMode:
66 return GrPrimitiveType::kPoints;
67 case SkCanvas::kLines_PointMode:
68 return GrPrimitiveType::kLines;
69 case SkCanvas::kPolygon_PointMode:
70 return GrPrimitiveType::kLineStrip;
71 }
72 SK_ABORT("Unexpected mode");
73 }
74
make_inverse_rrect_fp(const SkMatrix & viewMatrix,const SkRRect & rrect,GrAA aa,const GrShaderCaps & shaderCaps)75 std::unique_ptr<GrFragmentProcessor> make_inverse_rrect_fp(const SkMatrix& viewMatrix,
76 const SkRRect& rrect, GrAA aa,
77 const GrShaderCaps& shaderCaps) {
78 SkTCopyOnFirstWrite<SkRRect> devRRect(rrect);
79 if (viewMatrix.isIdentity() || rrect.transform(viewMatrix, devRRect.writable())) {
80 auto edgeType = (aa == GrAA::kYes) ? GrClipEdgeType::kInverseFillAA
81 : GrClipEdgeType::kInverseFillBW;
82 auto [success, fp] = GrRRectEffect::Make(/*inputFP=*/nullptr, edgeType, *devRRect,
83 shaderCaps);
84 return (success) ? std::move(fp) : nullptr;
85 }
86 return nullptr;
87 }
88
init_vertices_paint(GrRecordingContext * rContext,const GrColorInfo & colorInfo,const SkPaint & skPaint,const SkMatrixProvider & matrixProvider,sk_sp<SkBlender> blender,bool hasColors,GrPaint * grPaint)89 bool init_vertices_paint(GrRecordingContext* rContext,
90 const GrColorInfo& colorInfo,
91 const SkPaint& skPaint,
92 const SkMatrixProvider& matrixProvider,
93 sk_sp<SkBlender> blender,
94 bool hasColors,
95 GrPaint* grPaint) {
96 if (hasColors) {
97 return SkPaintToGrPaintWithBlend(rContext,
98 colorInfo,
99 skPaint,
100 matrixProvider,
101 blender.get(),
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 (count == 2 && mode == SkCanvas::kLines_PointMode) {
348 if (paint.getPathEffect()) {
349 // Probably a dashed line. Draw as a path.
350 GrPaint grPaint;
351 if (SkPaintToGrPaint(this->recordingContext(),
352 fSurfaceDrawContext->colorInfo(),
353 paint,
354 this->asMatrixProvider(),
355 &grPaint)) {
356 SkPath path;
357 path.setIsVolatile(true);
358 path.moveTo(pts[0]);
359 path.lineTo(pts[1]);
360 fSurfaceDrawContext->drawPath(this->clip(),
361 std::move(grPaint),
362 aa,
363 this->localToDevice(),
364 path,
365 GrStyle(paint, SkPaint::kStroke_Style));
366 }
367 return;
368 }
369 if (!paint.getMaskFilter() &&
370 paint.getStrokeWidth() > 0 && // drawStrokedLine doesn't support hairlines.
371 paint.getStrokeCap() != SkPaint::kRound_Cap) { // drawStrokedLine doesn't do round caps.
372 // Simple stroked line. Bypass path rendering.
373 GrPaint grPaint;
374 if (SkPaintToGrPaint(this->recordingContext(),
375 fSurfaceDrawContext->colorInfo(),
376 paint,
377 this->asMatrixProvider(),
378 &grPaint)) {
379 fSurfaceDrawContext->drawStrokedLine(this->clip(),
380 std::move(grPaint),
381 aa,
382 this->localToDevice(),
383 pts,
384 SkStrokeRec(paint, SkPaint::kStroke_Style));
385 }
386 return;
387 }
388 }
389
390 SkScalar scales[2];
391 bool isHairline = (0 == width) ||
392 (1 == width && this->localToDevice().getMinMaxScales(scales) &&
393 SkScalarNearlyEqual(scales[0], 1.f) && SkScalarNearlyEqual(scales[1], 1.f));
394 // we only handle non-coverage-aa hairlines and paints without path effects or mask filters,
395 // else we let the SkDraw call our drawPath()
396 if (!isHairline ||
397 paint.getPathEffect() ||
398 paint.getMaskFilter() ||
399 fSurfaceDrawContext->chooseAAType(aa) == GrAAType::kCoverage) {
400 SkRasterClip rc(this->devClipBounds());
401 SkDraw draw;
402 draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0);
403 draw.fMatrixProvider = this;
404 draw.fRC = &rc;
405 draw.drawPoints(mode, count, pts, paint, this);
406 return;
407 }
408
409 GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode);
410
411 const SkMatrixProvider* matrixProvider = this;
412
413 GrPaint grPaint;
414 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
415 *matrixProvider, &grPaint)) {
416 return;
417 }
418
419 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
420 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr,
421 nullptr);
422
423 fSurfaceDrawContext->drawVertices(this->clip(), std::move(grPaint), *matrixProvider,
424 std::move(vertices), &primitiveType);
425 }
426
427 ///////////////////////////////////////////////////////////////////////////////
428
drawRect(const SkRect & rect,const SkPaint & paint)429 void Device::drawRect(const SkRect& rect, const SkPaint& paint) {
430 ASSERT_SINGLE_OWNER
431 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRect", fContext.get());
432
433 GrStyle style(paint);
434
435 // A couple reasons we might need to call drawPath.
436 if (paint.getMaskFilter() || paint.getPathEffect()) {
437 GrStyledShape shape(rect, style);
438
439 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(),
440 this->clip(), paint, this->asMatrixProvider(), shape);
441 return;
442 }
443
444 GrPaint grPaint;
445 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
446 this->asMatrixProvider(), &grPaint)) {
447 return;
448 }
449
450 fSurfaceDrawContext->drawRect(this->clip(), std::move(grPaint),
451 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), rect,
452 &style);
453 }
454
drawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],SkCanvas::QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)455 void Device::drawEdgeAAQuad(const SkRect& rect,
456 const SkPoint clip[4],
457 SkCanvas::QuadAAFlags aaFlags,
458 const SkColor4f& color,
459 SkBlendMode mode) {
460 ASSERT_SINGLE_OWNER
461 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawEdgeAAQuad", fContext.get());
462
463 SkPMColor4f dstColor = SkColor4fPrepForDst(color, fSurfaceDrawContext->colorInfo()).premul();
464
465 GrPaint grPaint;
466 grPaint.setColor4f(dstColor);
467 if (mode != SkBlendMode::kSrcOver) {
468 grPaint.setXPFactory(SkBlendMode_AsXPFactory(mode));
469 }
470
471 // This is exclusively meant for tiling operations, so keep AA enabled to handle MSAA seaming
472 GrQuadAAFlags grAA = SkToGrQuadAAFlags(aaFlags);
473 if (clip) {
474 // Use fillQuadWithEdgeAA
475 fSurfaceDrawContext->fillQuadWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA,
476 this->localToDevice(), clip, nullptr);
477 } else {
478 // Use fillRectWithEdgeAA to preserve mathematical properties of dst being rectangular
479 fSurfaceDrawContext->fillRectWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA,
480 this->localToDevice(), rect);
481 }
482 }
483
484 ///////////////////////////////////////////////////////////////////////////////
485
drawRRect(const SkRRect & rrect,const SkPaint & paint)486 void Device::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
487 ASSERT_SINGLE_OWNER
488 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRRect", fContext.get());
489
490 SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter());
491 if (mf) {
492 if (mf->hasFragmentProcessor()) {
493 mf = nullptr; // already handled in SkPaintToGrPaint
494 }
495 }
496
497 GrStyle style(paint);
498
499 if (mf || style.pathEffect()) {
500 // A path effect will presumably transform this rrect into something else.
501 GrStyledShape shape(rrect, style);
502
503 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(),
504 this->clip(), paint, this->asMatrixProvider(), shape);
505 return;
506 }
507
508 SkASSERT(!style.pathEffect());
509
510 GrPaint grPaint;
511 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
512 this->asMatrixProvider(), &grPaint)) {
513 return;
514 }
515
516 fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint),
517 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
518 rrect, style);
519 }
520
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)521 void Device::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
522 ASSERT_SINGLE_OWNER
523 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDRRect", fContext.get());
524 if (outer.isEmpty()) {
525 return;
526 }
527
528 if (inner.isEmpty()) {
529 return this->drawRRect(outer, paint);
530 }
531
532 SkStrokeRec stroke(paint);
533
534 if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
535 // For axis-aligned filled DRRects, just draw a regular rrect with inner clipped out using a
536 // coverage FP instead of using path rendering.
537 if (auto fp = make_inverse_rrect_fp(this->localToDevice(), inner,
538 fSurfaceDrawContext->chooseAA(paint),
539 *fSurfaceDrawContext->caps()->shaderCaps())) {
540 GrPaint grPaint;
541 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
542 this->asMatrixProvider(), &grPaint)) {
543 return;
544 }
545 SkASSERT(!grPaint.hasCoverageFragmentProcessor());
546 grPaint.setCoverageFragmentProcessor(std::move(fp));
547 fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint),
548 fSurfaceDrawContext->chooseAA(paint),
549 this->localToDevice(), outer, GrStyle());
550 return;
551 }
552 }
553
554 SkPath path;
555 path.setIsVolatile(true);
556 path.addRRect(outer);
557 path.addRRect(inner);
558 path.setFillType(SkPathFillType::kEvenOdd);
559
560 // TODO: We are losing the possible mutability of the path here but this should probably be
561 // fixed by upgrading GrStyledShape to handle DRRects.
562 GrStyledShape shape(path, paint);
563
564 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(),
565 paint, this->asMatrixProvider(), shape);
566 }
567
568 /////////////////////////////////////////////////////////////////////////////
569
drawRegion(const SkRegion & region,const SkPaint & paint)570 void Device::drawRegion(const SkRegion& region, const SkPaint& paint) {
571 ASSERT_SINGLE_OWNER
572
573 if (paint.getMaskFilter()) {
574 SkPath path;
575 region.getBoundaryPath(&path);
576 path.setIsVolatile(true);
577 return this->drawPath(path, paint, true);
578 }
579
580 GrPaint grPaint;
581 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
582 this->asMatrixProvider(), &grPaint)) {
583 return;
584 }
585
586 fSurfaceDrawContext->drawRegion(this->clip(), std::move(grPaint),
587 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
588 region, GrStyle(paint));
589 }
590
drawOval(const SkRect & oval,const SkPaint & paint)591 void Device::drawOval(const SkRect& oval, const SkPaint& paint) {
592 ASSERT_SINGLE_OWNER
593 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawOval", fContext.get());
594
595 if (paint.getMaskFilter()) {
596 // The RRect path can handle special case blurring
597 SkRRect rr = SkRRect::MakeOval(oval);
598 return this->drawRRect(rr, paint);
599 }
600
601 GrPaint grPaint;
602 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
603 this->asMatrixProvider(), &grPaint)) {
604 return;
605 }
606
607 fSurfaceDrawContext->drawOval(this->clip(), std::move(grPaint),
608 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval,
609 GrStyle(paint));
610 }
611
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)612 void Device::drawArc(const SkRect& oval,
613 SkScalar startAngle,
614 SkScalar sweepAngle,
615 bool useCenter,
616 const SkPaint& paint) {
617 ASSERT_SINGLE_OWNER
618 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawArc", fContext.get());
619 if (paint.getMaskFilter()) {
620 this->INHERITED::drawArc(oval, startAngle, sweepAngle, useCenter, paint);
621 return;
622 }
623 GrPaint grPaint;
624 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
625 this->asMatrixProvider(), &grPaint)) {
626 return;
627 }
628
629 fSurfaceDrawContext->drawArc(this->clip(), std::move(grPaint),
630 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval,
631 startAngle, sweepAngle, useCenter, GrStyle(paint));
632 }
633
634 ///////////////////////////////////////////////////////////////////////////////
635
drawPath(const SkPath & origSrcPath,const SkPaint & paint,bool pathIsMutable)636 void Device::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool pathIsMutable) {
637 #if GR_TEST_UTILS
638 if (fContext->priv().options().fAllPathsVolatile && !origSrcPath.isVolatile()) {
639 this->drawPath(SkPath(origSrcPath).setIsVolatile(true), paint, true);
640 return;
641 }
642 #endif
643 ASSERT_SINGLE_OWNER
644 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPath", fContext.get());
645 if (!paint.getMaskFilter()) {
646 GrPaint grPaint;
647 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
648 this->asMatrixProvider(), &grPaint)) {
649 return;
650 }
651 fSurfaceDrawContext->drawPath(this->clip(), std::move(grPaint),
652 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
653 origSrcPath, GrStyle(paint));
654 return;
655 }
656
657 // TODO: losing possible mutability of 'origSrcPath' here
658 GrStyledShape shape(origSrcPath, paint);
659
660 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(),
661 paint, this->asMatrixProvider(), shape);
662 }
663
makeSpecial(const SkBitmap & bitmap)664 sk_sp<SkSpecialImage> Device::makeSpecial(const SkBitmap& bitmap) {
665 ASSERT_SINGLE_OWNER
666
667 // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's
668 // semantics). Since this is cached we would have to bake the fit into the cache key though.
669 auto view = std::get<0>(GrMakeCachedBitmapProxyView(fContext.get(), bitmap));
670 if (!view) {
671 return nullptr;
672 }
673
674 const SkIRect rect = SkIRect::MakeSize(view.proxy()->dimensions());
675
676 // GrMakeCachedBitmapProxyView creates a tight copy of 'bitmap' so we don't have to subset
677 // the special image
678 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
679 rect,
680 bitmap.getGenerationID(),
681 std::move(view),
682 SkColorTypeToGrColorType(bitmap.colorType()),
683 bitmap.refColorSpace(),
684 this->surfaceProps());
685 }
686
makeSpecial(const SkImage * image)687 sk_sp<SkSpecialImage> Device::makeSpecial(const SkImage* image) {
688 ASSERT_SINGLE_OWNER
689
690 SkPixmap pm;
691 if (image->isTextureBacked()) {
692 auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo);
693 SkASSERT(view);
694
695 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
696 SkIRect::MakeWH(image->width(), image->height()),
697 image->uniqueID(),
698 std::move(view),
699 ct,
700 image->refColorSpace(),
701 this->surfaceProps());
702 } else if (image->peekPixels(&pm)) {
703 SkBitmap bm;
704
705 bm.installPixels(pm);
706 return this->makeSpecial(bm);
707 } else {
708 return nullptr;
709 }
710 }
711
snapSpecial(const SkIRect & subset,bool forceCopy)712 sk_sp<SkSpecialImage> Device::snapSpecial(const SkIRect& subset, bool forceCopy) {
713 ASSERT_SINGLE_OWNER
714
715 auto sdc = fSurfaceDrawContext.get();
716
717 // If we are wrapping a vulkan secondary command buffer, then we can't snap off a special image
718 // since it would require us to make a copy of the underlying VkImage which we don't have access
719 // to. Additionaly we can't stop and start the render pass that is used with the secondary
720 // command buffer.
721 if (sdc->wrapsVkSecondaryCB()) {
722 return nullptr;
723 }
724
725 SkASSERT(sdc->asSurfaceProxy());
726
727 SkIRect finalSubset = subset;
728 GrSurfaceProxyView view = sdc->readSurfaceView();
729 if (forceCopy || !view.asTextureProxy()) {
730 // When the device doesn't have a texture, or a copy is requested, we create a temporary
731 // texture that matches the device contents
732 view = GrSurfaceProxyView::Copy(fContext.get(),
733 std::move(view),
734 GrMipmapped::kNo, // Don't auto generate mips
735 subset,
736 SkBackingFit::kApprox,
737 SkBudgeted::kYes); // Always budgeted
738 if (!view) {
739 return nullptr;
740 }
741 // Since this copied only the requested subset, the special image wrapping the proxy no
742 // longer needs the original subset.
743 finalSubset = SkIRect::MakeSize(view.dimensions());
744 }
745
746 GrColorType ct = SkColorTypeToGrColorType(this->imageInfo().colorType());
747
748 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
749 finalSubset,
750 kNeedNewImageUniqueID_SpecialImage,
751 std::move(view),
752 ct,
753 this->imageInfo().refColorSpace(),
754 this->surfaceProps());
755 }
756
drawDevice(SkBaseDevice * device,const SkSamplingOptions & sampling,const SkPaint & paint)757 void Device::drawDevice(SkBaseDevice* device,
758 const SkSamplingOptions& sampling,
759 const SkPaint& paint) {
760 ASSERT_SINGLE_OWNER
761 // clear of the source device must occur before CHECK_SHOULD_DRAW
762 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDevice", fContext.get());
763 this->INHERITED::drawDevice(device, sampling, paint);
764 }
765
drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)766 void Device::drawImageRect(const SkImage* image,
767 const SkRect* src,
768 const SkRect& dst,
769 const SkSamplingOptions& sampling,
770 const SkPaint& paint,
771 SkCanvas::SrcRectConstraint constraint) {
772 ASSERT_SINGLE_OWNER
773 GrAA aa = fSurfaceDrawContext->chooseAA(paint);
774 GrQuadAAFlags aaFlags = (aa == GrAA::kYes) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
775 this->drawImageQuad(image, src, &dst, nullptr, aa, aaFlags, nullptr, sampling, paint,
776 constraint);
777 }
778
drawViewLattice(GrSurfaceProxyView view,const GrColorInfo & info,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst,SkFilterMode filter,const SkPaint & origPaint)779 void Device::drawViewLattice(GrSurfaceProxyView view,
780 const GrColorInfo& info,
781 std::unique_ptr<SkLatticeIter> iter,
782 const SkRect& dst,
783 SkFilterMode filter,
784 const SkPaint& origPaint) {
785 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawViewLattice", fContext.get());
786 SkASSERT(view);
787
788 SkTCopyOnFirstWrite<SkPaint> paint(&origPaint);
789
790 if (!info.isAlphaOnly() && (paint->getColor() & 0x00FFFFFF) != 0x00FFFFFF) {
791 paint.writable()->setColor(SkColorSetARGB(origPaint.getAlpha(), 0xFF, 0xFF, 0xFF));
792 }
793 GrPaint grPaint;
794 // Passing null as shaderFP indicates that the GP will provide the shader.
795 if (!SkPaintToGrPaintReplaceShader(this->recordingContext(),
796 fSurfaceDrawContext->colorInfo(),
797 *paint,
798 this->asMatrixProvider(),
799 /*shaderFP=*/nullptr,
800 &grPaint)) {
801 return;
802 }
803
804 if (info.isAlphaOnly()) {
805 // If we were doing this with an FP graph we'd use a kDstIn blend between the texture and
806 // the paint color.
807 view.concatSwizzle(skgpu::Swizzle("aaaa"));
808 }
809 auto csxf = GrColorSpaceXform::Make(info, fSurfaceDrawContext->colorInfo());
810
811 fSurfaceDrawContext->drawImageLattice(this->clip(), std::move(grPaint), this->localToDevice(),
812 std::move(view), info.alphaType(), std::move(csxf),
813 filter, std::move(iter), dst);
814 }
815
drawImageLattice(const SkImage * image,const SkCanvas::Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint & paint)816 void Device::drawImageLattice(const SkImage* image,
817 const SkCanvas::Lattice& lattice,
818 const SkRect& dst,
819 SkFilterMode filter,
820 const SkPaint& paint) {
821 ASSERT_SINGLE_OWNER
822 auto iter = std::make_unique<SkLatticeIter>(lattice, dst);
823 if (auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo); view) {
824 GrColorInfo colorInfo(ct, image->alphaType(), image->refColorSpace());
825 this->drawViewLattice(std::move(view),
826 std::move(colorInfo),
827 std::move(iter),
828 dst,
829 filter,
830 paint);
831 }
832 }
833
drawVertices(const SkVertices * vertices,sk_sp<SkBlender> blender,const SkPaint & paint)834 void Device::drawVertices(const SkVertices* vertices,
835 sk_sp<SkBlender> blender,
836 const SkPaint& paint) {
837 ASSERT_SINGLE_OWNER
838 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawVertices", fContext.get());
839 SkASSERT(vertices);
840
841 #ifdef SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER
842 if (!paint.getShader()) {
843 blender = SkBlender::Mode(SkBlendMode::kDst);
844 }
845 #endif
846
847 SkVerticesPriv info(vertices->priv());
848
849 GrPaint grPaint;
850 if (!init_vertices_paint(fContext.get(),
851 fSurfaceDrawContext->colorInfo(),
852 paint,
853 this->asMatrixProvider(),
854 std::move(blender),
855 info.hasColors(),
856 &grPaint)) {
857 return;
858 }
859 fSurfaceDrawContext->drawVertices(this->clip(),
860 std::move(grPaint),
861 this->asMatrixProvider(),
862 sk_ref_sp(const_cast<SkVertices*>(vertices)),
863 nullptr);
864 }
865
drawCustomMesh(SkCustomMesh customMesh,sk_sp<SkBlender> blender,const SkPaint & paint)866 void Device::drawCustomMesh(SkCustomMesh customMesh,
867 sk_sp<SkBlender> blender,
868 const SkPaint& paint) {
869 ASSERT_SINGLE_OWNER
870 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawCustomMesh", fContext.get());
871 SkASSERT(customMesh.vb);
872
873 GrPaint grPaint;
874 if (!init_vertices_paint(fContext.get(),
875 fSurfaceDrawContext->colorInfo(),
876 paint,
877 this->asMatrixProvider(),
878 std::move(blender),
879 SkCustomMeshSpecificationPriv::HasColors(*customMesh.spec),
880 &grPaint)) {
881 return;
882 }
883 fSurfaceDrawContext->drawCustomMesh(this->clip(),
884 std::move(grPaint),
885 this->asMatrixProvider(),
886 std::move(customMesh));
887 }
888
889 ///////////////////////////////////////////////////////////////////////////////
890
drawShadow(const SkPath & path,const SkDrawShadowRec & rec)891 void Device::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
892 #if GR_TEST_UTILS
893 if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
894 this->drawShadow(SkPath(path).setIsVolatile(true), rec);
895 return;
896 }
897 #endif
898 ASSERT_SINGLE_OWNER
899 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawShadow", fContext.get());
900
901 if (!fSurfaceDrawContext->drawFastShadow(this->clip(), this->localToDevice(), path, rec)) {
902 // failed to find an accelerated case
903 this->INHERITED::drawShadow(path, rec);
904 }
905 }
906
907 ///////////////////////////////////////////////////////////////////////////////
908
drawAtlas(const SkRSXform xform[],const SkRect texRect[],const SkColor colors[],int count,sk_sp<SkBlender> blender,const SkPaint & paint)909 void Device::drawAtlas(const SkRSXform xform[],
910 const SkRect texRect[],
911 const SkColor colors[],
912 int count,
913 sk_sp<SkBlender> blender,
914 const SkPaint& paint) {
915 ASSERT_SINGLE_OWNER
916 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawAtlas", fContext.get());
917
918 GrPaint grPaint;
919 if (colors) {
920 if (!SkPaintToGrPaintWithBlend(this->recordingContext(),
921 fSurfaceDrawContext->colorInfo(),
922 paint,
923 this->asMatrixProvider(),
924 blender.get(),
925 &grPaint)) {
926 return;
927 }
928 } else {
929 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(),
930 paint, this->asMatrixProvider(), &grPaint)) {
931 return;
932 }
933 }
934
935 fSurfaceDrawContext->drawAtlas(this->clip(), std::move(grPaint), this->localToDevice(), count,
936 xform, texRect, colors);
937 }
938
939 ///////////////////////////////////////////////////////////////////////////////
940
onDrawGlyphRunList(SkCanvas * canvas,const SkGlyphRunList & glyphRunList,const SkPaint & paint)941 void Device::onDrawGlyphRunList(SkCanvas* canvas,
942 const SkGlyphRunList& glyphRunList,
943 const SkPaint& paint) {
944 ASSERT_SINGLE_OWNER
945 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawGlyphRunList", fContext.get());
946 SkASSERT(!glyphRunList.hasRSXForm());
947
948 #if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG)
949 auto slug = this->convertGlyphRunListToSlug(glyphRunList, paint);
950 if (slug != nullptr) {
951 this->drawSlug(slug.get());
952 }
953 return;
954 #endif
955
956 fSurfaceDrawContext->drawGlyphRunList(
957 canvas, this->clip(), this->asMatrixProvider(), glyphRunList, paint);
958 }
959
960 ///////////////////////////////////////////////////////////////////////////////
961
drawDrawable(SkCanvas * canvas,SkDrawable * drawable,const SkMatrix * matrix)962 void Device::drawDrawable(SkCanvas* canvas, SkDrawable* drawable, const SkMatrix* matrix) {
963 ASSERT_SINGLE_OWNER
964
965 GrBackendApi api = this->recordingContext()->backend();
966 if (GrBackendApi::kVulkan == api) {
967 const SkMatrix& ctm = this->localToDevice();
968 const SkMatrix& combinedMatrix = matrix ? SkMatrix::Concat(ctm, *matrix) : ctm;
969 std::unique_ptr<SkDrawable::GpuDrawHandler> gpuDraw =
970 drawable->snapGpuDrawHandler(api, combinedMatrix, this->devClipBounds(),
971 this->imageInfo());
972 if (gpuDraw) {
973 fSurfaceDrawContext->drawDrawable(
974 std::move(gpuDraw), combinedMatrix.mapRect(drawable->getBounds()));
975 return;
976 }
977 }
978 this->INHERITED::drawDrawable(canvas, drawable, matrix);
979 }
980
981
982 ///////////////////////////////////////////////////////////////////////////////
983
wait(int numSemaphores,const GrBackendSemaphore * waitSemaphores,bool deleteSemaphoresAfterWait)984 bool Device::wait(int numSemaphores,
985 const GrBackendSemaphore* waitSemaphores,
986 bool deleteSemaphoresAfterWait) {
987 ASSERT_SINGLE_OWNER
988
989 return fSurfaceDrawContext->waitOnSemaphores(numSemaphores, waitSemaphores,
990 deleteSemaphoresAfterWait);
991 }
992
replaceBackingProxy(SkSurface::ContentChangeMode mode,sk_sp<GrRenderTargetProxy> newRTP,GrColorType grColorType,sk_sp<SkColorSpace> colorSpace,GrSurfaceOrigin origin,const SkSurfaceProps & props)993 bool Device::replaceBackingProxy(SkSurface::ContentChangeMode mode,
994 sk_sp<GrRenderTargetProxy> newRTP,
995 GrColorType grColorType,
996 sk_sp<SkColorSpace> colorSpace,
997 GrSurfaceOrigin origin,
998 const SkSurfaceProps& props) {
999 auto sdc = SurfaceDrawContext::Make(fContext.get(), grColorType, std::move(newRTP),
1000 std::move(colorSpace), origin, props);
1001 if (!sdc) {
1002 return false;
1003 }
1004
1005 SkASSERT(sdc->dimensions() == fSurfaceDrawContext->dimensions());
1006 SkASSERT(sdc->numSamples() == fSurfaceDrawContext->numSamples());
1007 SkASSERT(sdc->asSurfaceProxy()->priv().isExact());
1008 if (mode == SkSurface::kRetain_ContentChangeMode) {
1009 if (fContext->abandoned()) {
1010 return false;
1011 }
1012
1013 SkASSERT(fSurfaceDrawContext->asTextureProxy());
1014 SkAssertResult(sdc->blitTexture(fSurfaceDrawContext->readSurfaceView(),
1015 SkIRect::MakeWH(this->width(), this->height()),
1016 SkIPoint::Make(0, 0)));
1017 }
1018
1019 fSurfaceDrawContext = std::move(sdc);
1020 return true;
1021 }
1022
asyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)1023 void Device::asyncRescaleAndReadPixels(const SkImageInfo& info,
1024 const SkIRect& srcRect,
1025 RescaleGamma rescaleGamma,
1026 RescaleMode rescaleMode,
1027 ReadPixelsCallback callback,
1028 ReadPixelsContext context) {
1029 auto* sdc = fSurfaceDrawContext.get();
1030 // Context TODO: Elevate direct context requirement to public API.
1031 auto dContext = sdc->recordingContext()->asDirectContext();
1032 if (!dContext) {
1033 return;
1034 }
1035 sdc->asyncRescaleAndReadPixels(dContext, info, srcRect, rescaleGamma, rescaleMode, callback,
1036 context);
1037 }
1038
asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,SkISize dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)1039 void Device::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
1040 sk_sp<SkColorSpace> dstColorSpace,
1041 const SkIRect& srcRect,
1042 SkISize dstSize,
1043 RescaleGamma rescaleGamma,
1044 RescaleMode rescaleMode,
1045 ReadPixelsCallback callback,
1046 ReadPixelsContext context) {
1047 auto* sdc = fSurfaceDrawContext.get();
1048 // Context TODO: Elevate direct context requirement to public API.
1049 auto dContext = sdc->recordingContext()->asDirectContext();
1050 if (!dContext) {
1051 return;
1052 }
1053 sdc->asyncRescaleAndReadPixelsYUV420(dContext,
1054 yuvColorSpace,
1055 std::move(dstColorSpace),
1056 srcRect,
1057 dstSize,
1058 rescaleGamma,
1059 rescaleMode,
1060 callback,
1061 context);
1062 }
1063
1064 ///////////////////////////////////////////////////////////////////////////////
1065
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)1066 SkBaseDevice* Device::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
1067 ASSERT_SINGLE_OWNER
1068
1069 SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry);
1070
1071 // layers are never drawn in repeat modes, so we can request an approx
1072 // match and ignore any padding.
1073 SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox
1074 : SkBackingFit::kExact;
1075
1076 SkASSERT(cinfo.fInfo.colorType() != kRGBA_1010102_SkColorType);
1077
1078 auto sdc = SurfaceDrawContext::MakeWithFallback(
1079 fContext.get(), SkColorTypeToGrColorType(cinfo.fInfo.colorType()),
1080 fSurfaceDrawContext->colorInfo().refColorSpace(), fit, cinfo.fInfo.dimensions(), props,
1081 fSurfaceDrawContext->numSamples(), GrMipmapped::kNo,
1082 fSurfaceDrawContext->asSurfaceProxy()->isProtected(),
1083 fSurfaceDrawContext->origin(),
1084 SkBudgeted::kYes);
1085 if (!sdc) {
1086 return nullptr;
1087 }
1088
1089 // Skia's convention is to only clear a device if it is non-opaque.
1090 InitContents init = cinfo.fInfo.isOpaque() ? InitContents::kUninit : InitContents::kClear;
1091
1092 return Device::Make(std::move(sdc), cinfo.fInfo.alphaType(), init).release();
1093 }
1094
makeSurface(const SkImageInfo & info,const SkSurfaceProps & props)1095 sk_sp<SkSurface> Device::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1096 ASSERT_SINGLE_OWNER
1097 // TODO: Change the signature of newSurface to take a budgeted parameter.
1098 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
1099 return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info,
1100 fSurfaceDrawContext->numSamples(),
1101 fSurfaceDrawContext->origin(), &props);
1102 }
1103
getImageFilterCache()1104 SkImageFilterCache* Device::getImageFilterCache() {
1105 ASSERT_SINGLE_OWNER
1106 // We always return a transient cache, so it is freed after each
1107 // filter traversal.
1108 return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
1109 }
1110
1111 ////////////////////////////////////////////////////////////////////////////////////
1112
android_utils_clipWithStencil()1113 bool Device::android_utils_clipWithStencil() {
1114 SkRegion clipRegion;
1115 this->onAsRgnClip(&clipRegion);
1116 if (clipRegion.isEmpty()) {
1117 return false;
1118 }
1119 auto sdc = fSurfaceDrawContext.get();
1120 SkASSERT(sdc);
1121 GrPaint grPaint;
1122 grPaint.setXPFactory(GrDisableColorXPFactory::Get());
1123 static constexpr GrUserStencilSettings kDrawToStencil(
1124 GrUserStencilSettings::StaticInit<
1125 0x1,
1126 GrUserStencilTest::kAlways,
1127 0x1,
1128 GrUserStencilOp::kReplace,
1129 GrUserStencilOp::kReplace,
1130 0x1>()
1131 );
1132 // Regions don't actually need AA, but in DMSAA mode everything is antialiased.
1133 GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias());
1134 sdc->drawRegion(nullptr, std::move(grPaint), aa, SkMatrix::I(), clipRegion,
1135 GrStyle::SimpleFill(), &kDrawToStencil);
1136 return true;
1137 }
1138
1139 } // namespace skgpu::v1
1140