• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ganesh/Device_v1.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkBlendMode.h"
13 #include "include/core/SkBlender.h"
14 #include "include/core/SkCanvas.h"
15 #include "include/core/SkClipOp.h"
16 #include "include/core/SkColor.h"
17 #include "include/core/SkColorSpace.h"
18 #include "include/core/SkColorType.h"
19 #include "include/core/SkDrawable.h"
20 #include "include/core/SkImage.h"
21 #include "include/core/SkImageInfo.h"
22 #include "include/core/SkM44.h"
23 #include "include/core/SkMatrix.h"
24 #include "include/core/SkMesh.h"
25 #include "include/core/SkPaint.h"
26 #include "include/core/SkPath.h"
27 #include "include/core/SkPathTypes.h"
28 #include "include/core/SkPixmap.h"
29 #include "include/core/SkPoint.h"
30 #include "include/core/SkRRect.h"
31 #include "include/core/SkRSXform.h"
32 #include "include/core/SkRect.h"
33 #include "include/core/SkRefCnt.h"
34 #include "include/core/SkRegion.h"
35 #include "include/core/SkScalar.h"
36 #include "include/core/SkSize.h"
37 #include "include/core/SkStrokeRec.h"
38 #include "include/core/SkSurface.h"
39 #include "include/core/SkSurfaceProps.h"
40 #include "include/core/SkVertices.h"
41 #include "include/gpu/GpuTypes.h"
42 #include "include/gpu/GrBackendSurface.h"
43 #include "include/gpu/GrContextOptions.h"
44 #include "include/gpu/GrRecordingContext.h"
45 #include "include/gpu/GrTypes.h"
46 #include "include/private/SkColorData.h"
47 #include "include/private/base/SingleOwner.h"
48 #include "include/private/base/SkAssert.h"
49 #include "include/private/base/SkTo.h"
50 #include "include/private/chromium/Slug.h"  // IWYU pragma: keep
51 #include "include/private/gpu/ganesh/GrTypesPriv.h"
52 #include "src/base/SkTLazy.h"
53 #include "src/core/SkBlendModePriv.h"
54 #include "src/core/SkDevice.h"
55 #include "src/core/SkDraw.h"
56 #include "src/core/SkImageFilterCache.h"
57 #include "src/core/SkImageInfoPriv.h"
58 #include "src/core/SkLatticeIter.h"
59 #include "src/core/SkMaskFilterBase.h"
60 #include "src/core/SkMatrixProvider.h"
61 #include "src/core/SkMeshPriv.h"
62 #include "src/core/SkRasterClip.h"
63 #include "src/core/SkSpecialImage.h"
64 #include "src/core/SkTraceEvent.h"
65 #include "src/core/SkVerticesPriv.h"
66 #include "src/gpu/SkBackingFit.h"
67 #include "src/gpu/Swizzle.h"
68 #include "src/gpu/ganesh/ClipStack.h"
69 #include "src/gpu/ganesh/GrAuditTrail.h"
70 #include "src/gpu/ganesh/GrBlurUtils.h"
71 #include "src/gpu/ganesh/GrCaps.h"
72 #include "src/gpu/ganesh/GrColorInfo.h"
73 #include "src/gpu/ganesh/GrColorSpaceXform.h"
74 #include "src/gpu/ganesh/GrFragmentProcessor.h"
75 #include "src/gpu/ganesh/GrImageInfo.h"
76 #include "src/gpu/ganesh/GrPaint.h"
77 #include "src/gpu/ganesh/GrProxyProvider.h"
78 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
79 #include "src/gpu/ganesh/GrRenderTargetProxy.h"
80 #include "src/gpu/ganesh/GrStyle.h"
81 #include "src/gpu/ganesh/GrSurfaceProxy.h"
82 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
83 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
84 #include "src/gpu/ganesh/GrTextureProxy.h"
85 #include "src/gpu/ganesh/GrTracing.h"
86 #include "src/gpu/ganesh/GrUserStencilSettings.h"
87 #include "src/gpu/ganesh/SkGr.h"
88 #include "src/gpu/ganesh/SurfaceContext.h"
89 #include "src/gpu/ganesh/SurfaceDrawContext.h"
90 #include "src/gpu/ganesh/SurfaceFillContext.h"
91 #include "src/gpu/ganesh/effects/GrDisableColorXP.h"
92 #include "src/gpu/ganesh/effects/GrRRectEffect.h"
93 #include "src/gpu/ganesh/geometry/GrShape.h"
94 #include "src/gpu/ganesh/geometry/GrStyledShape.h"
95 #include "src/image/SkImage_Base.h"
96 #include "src/text/GlyphRun.h"
97 
98 #include <atomic>
99 #include <cstddef>
100 #include <cstdint>
101 #include <memory>
102 #include <tuple>
103 #include <utility>
104 
105 class GrBackendSemaphore;
106 enum class SkFilterMode;
107 struct GrShaderCaps;
108 struct SkDrawShadowRec;
109 struct SkSamplingOptions;
110 
111 #if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE)
112     #include "include/private/chromium/SkChromeRemoteGlyphCache.h"
113 #endif
114 
115 #define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(fContext->priv().singleOwner())
116 
117 ///////////////////////////////////////////////////////////////////////////////
118 
119 namespace {
120 
force_aa_clip(const skgpu::v1::SurfaceDrawContext * sdc)121 bool force_aa_clip(const skgpu::v1::SurfaceDrawContext* sdc) {
122     return sdc->numSamples() > 1 || sdc->alwaysAntialias();
123 }
124 
point_mode_to_primitive_type(SkCanvas::PointMode mode)125 inline GrPrimitiveType point_mode_to_primitive_type(SkCanvas::PointMode mode) {
126     switch (mode) {
127         case SkCanvas::kPoints_PointMode:
128             return GrPrimitiveType::kPoints;
129         case SkCanvas::kLines_PointMode:
130             return GrPrimitiveType::kLines;
131         case SkCanvas::kPolygon_PointMode:
132             return GrPrimitiveType::kLineStrip;
133     }
134     SK_ABORT("Unexpected mode");
135 }
136 
make_inverse_rrect_fp(const SkMatrix & viewMatrix,const SkRRect & rrect,GrAA aa,const GrShaderCaps & shaderCaps)137 std::unique_ptr<GrFragmentProcessor> make_inverse_rrect_fp(const SkMatrix& viewMatrix,
138                                                            const SkRRect& rrect, GrAA aa,
139                                                            const GrShaderCaps& shaderCaps) {
140     SkTCopyOnFirstWrite<SkRRect> devRRect(rrect);
141     if (viewMatrix.isIdentity() || rrect.transform(viewMatrix, devRRect.writable())) {
142         auto edgeType = (aa == GrAA::kYes) ? GrClipEdgeType::kInverseFillAA
143                                            : GrClipEdgeType::kInverseFillBW;
144         auto [success, fp] = GrRRectEffect::Make(/*inputFP=*/nullptr, edgeType, *devRRect,
145                                                  shaderCaps);
146         return (success) ? std::move(fp) : nullptr;
147     }
148     return nullptr;
149 }
150 
init_vertices_paint(GrRecordingContext * rContext,const GrColorInfo & colorInfo,const SkPaint & skPaint,const SkMatrix & ctm,sk_sp<SkBlender> blender,bool hasColors,const SkSurfaceProps & props,GrPaint * grPaint)151 bool init_vertices_paint(GrRecordingContext* rContext,
152                          const GrColorInfo& colorInfo,
153                          const SkPaint& skPaint,
154                          const SkMatrix& ctm,
155                          sk_sp<SkBlender> blender,
156                          bool hasColors,
157                          const SkSurfaceProps& props,
158                          GrPaint* grPaint) {
159     if (hasColors) {
160         return SkPaintToGrPaintWithBlend(rContext,
161                                          colorInfo,
162                                          skPaint,
163                                          ctm,
164                                          blender.get(),
165                                          props,
166                                          grPaint);
167     } else {
168         return SkPaintToGrPaint(rContext, colorInfo, skPaint, ctm, props, grPaint);
169     }
170 }
171 
172 } // anonymous namespace
173 
174 namespace skgpu::v1 {
175 
Make(GrRecordingContext * rContext,GrColorType colorType,sk_sp<GrSurfaceProxy> proxy,sk_sp<SkColorSpace> colorSpace,GrSurfaceOrigin origin,const SkSurfaceProps & surfaceProps,InitContents init)176 sk_sp<Device> Device::Make(GrRecordingContext* rContext,
177                            GrColorType colorType,
178                            sk_sp<GrSurfaceProxy> proxy,
179                            sk_sp<SkColorSpace> colorSpace,
180                            GrSurfaceOrigin origin,
181                            const SkSurfaceProps& surfaceProps,
182                            InitContents init) {
183     auto sdc = SurfaceDrawContext::Make(rContext,
184                                         colorType,
185                                         std::move(proxy),
186                                         std::move(colorSpace),
187                                         origin,
188                                         surfaceProps);
189 
190     return Device::Make(std::move(sdc), kPremul_SkAlphaType, init);
191 }
192 
MakeInfo(SurfaceContext * sc,DeviceFlags flags)193 SkImageInfo Device::MakeInfo(SurfaceContext* sc, DeviceFlags flags) {
194     SkColorType colorType = GrColorTypeToSkColorType(sc->colorInfo().colorType());
195     return SkImageInfo::Make(sc->width(), sc->height(), colorType,
196                              flags & DeviceFlags::kIsOpaque ? kOpaque_SkAlphaType
197                                                             : kPremul_SkAlphaType,
198                              sc->colorInfo().refColorSpace());
199 }
200 
201 
202 /** Checks that the alpha type is legal and gets constructor flags. Returns false if device creation
203     should fail. */
CheckAlphaTypeAndGetFlags(SkAlphaType alphaType,InitContents init,DeviceFlags * flags)204 bool Device::CheckAlphaTypeAndGetFlags(SkAlphaType alphaType,
205                                        InitContents init,
206                                        DeviceFlags* flags) {
207     *flags = DeviceFlags::kNone;
208     switch (alphaType) {
209         case kPremul_SkAlphaType:
210             break;
211         case kOpaque_SkAlphaType:
212             *flags |= DeviceFlags::kIsOpaque;
213             break;
214         default: // If it is unpremul or unknown don't try to render
215             return false;
216     }
217     if (InitContents::kClear == init) {
218         *flags |= DeviceFlags::kNeedClear;
219     }
220     return true;
221 }
222 
Make(std::unique_ptr<SurfaceDrawContext> sdc,SkAlphaType alphaType,InitContents init)223 sk_sp<Device> Device::Make(std::unique_ptr<SurfaceDrawContext> sdc,
224                            SkAlphaType alphaType,
225                            InitContents init) {
226     if (!sdc) {
227         return nullptr;
228     }
229 
230     GrRecordingContext* rContext = sdc->recordingContext();
231     if (rContext->abandoned()) {
232         return nullptr;
233     }
234 
235     SkColorType ct = GrColorTypeToSkColorType(sdc->colorInfo().colorType());
236 
237     DeviceFlags flags;
238     if (!rContext->colorTypeSupportedAsSurface(ct) ||
239         !CheckAlphaTypeAndGetFlags(alphaType, init, &flags)) {
240         return nullptr;
241     }
242     return sk_sp<Device>(new Device(std::move(sdc), flags));
243 }
244 
Make(GrRecordingContext * rContext,skgpu::Budgeted budgeted,const SkImageInfo & ii,SkBackingFit fit,int sampleCount,GrMipmapped mipmapped,GrProtected isProtected,GrSurfaceOrigin origin,const SkSurfaceProps & props,InitContents init)245 sk_sp<Device> Device::Make(GrRecordingContext* rContext,
246                            skgpu::Budgeted budgeted,
247                            const SkImageInfo& ii,
248                            SkBackingFit fit,
249                            int sampleCount,
250                            GrMipmapped mipmapped,
251                            GrProtected isProtected,
252                            GrSurfaceOrigin origin,
253                            const SkSurfaceProps& props,
254                            InitContents init) {
255     if (!rContext) {
256         return nullptr;
257     }
258 
259     auto sdc = SurfaceDrawContext::Make(rContext,
260                                         SkColorTypeToGrColorType(ii.colorType()),
261                                         ii.refColorSpace(),
262                                         fit,
263                                         ii.dimensions(),
264                                         props,
265                                         /*label=*/"MakeDevice",
266                                         sampleCount,
267                                         mipmapped,
268                                         isProtected,
269                                         origin,
270                                         budgeted);
271 
272     return Device::Make(std::move(sdc), ii.alphaType(), init);
273 }
274 
Device(std::unique_ptr<SurfaceDrawContext> sdc,DeviceFlags flags)275 Device::Device(std::unique_ptr<SurfaceDrawContext> sdc, DeviceFlags flags)
276         : SkBaseDevice(MakeInfo(sdc.get(), flags), sdc->surfaceProps())
277         , fContext(sk_ref_sp(sdc->recordingContext()))
278         , fSDFTControl(sdc->recordingContext()->priv().getSDFTControl(
279                        sdc->surfaceProps().isUseDeviceIndependentFonts()))
280         , fSurfaceDrawContext(std::move(sdc))
281         , fClip(SkIRect::MakeSize(fSurfaceDrawContext->dimensions()),
282                 &this->asMatrixProvider(),
283                 force_aa_clip(fSurfaceDrawContext.get())) {
284     if (flags & DeviceFlags::kNeedClear) {
285         this->clearAll();
286     }
287 }
288 
289 Device::~Device() = default;
290 
291 ///////////////////////////////////////////////////////////////////////////////
292 
onReadPixels(const SkPixmap & pm,int x,int y)293 bool Device::onReadPixels(const SkPixmap& pm, int x, int y) {
294     ASSERT_SINGLE_OWNER
295 
296     // Context TODO: Elevate direct context requirement to public API
297     auto dContext = fContext->asDirectContext();
298     if (!dContext || !SkImageInfoValidConversion(pm.info(), this->imageInfo())) {
299         return false;
300     }
301 
302     return fSurfaceDrawContext->readPixels(dContext, pm, {x, y});
303 }
304 
onWritePixels(const SkPixmap & pm,int x,int y)305 bool Device::onWritePixels(const SkPixmap& pm, int x, int y) {
306     ASSERT_SINGLE_OWNER
307 
308     // Context TODO: Elevate direct context requirement to public API
309     auto dContext = fContext->asDirectContext();
310     if (!dContext || !SkImageInfoValidConversion(this->imageInfo(), pm.info())) {
311         return false;
312     }
313 
314     return fSurfaceDrawContext->writePixels(dContext, pm, {x, y});
315 }
316 
onAccessPixels(SkPixmap * pmap)317 bool Device::onAccessPixels(SkPixmap* pmap) {
318     ASSERT_SINGLE_OWNER
319     return false;
320 }
321 
surfaceDrawContext()322 SurfaceDrawContext* Device::surfaceDrawContext() {
323     ASSERT_SINGLE_OWNER
324     return fSurfaceDrawContext.get();
325 }
326 
surfaceDrawContext() const327 const SurfaceDrawContext* Device::surfaceDrawContext() const {
328     ASSERT_SINGLE_OWNER
329     return fSurfaceDrawContext.get();
330 }
331 
surfaceFillContext()332 SurfaceFillContext* Device::surfaceFillContext() {
333     ASSERT_SINGLE_OWNER
334     return fSurfaceDrawContext.get();
335 }
336 
clearAll()337 void Device::clearAll() {
338     ASSERT_SINGLE_OWNER
339     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "clearAll", fContext.get());
340 
341     SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
342     fSurfaceDrawContext->clearAtLeast(rect, SK_PMColor4fTRANSPARENT);
343 }
344 
345 ///////////////////////////////////////////////////////////////////////////////
346 
onClipPath(const SkPath & path,SkClipOp op,bool aa)347 void Device::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
348 #if GR_TEST_UTILS
349     if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
350         this->onClipPath(SkPath(path).setIsVolatile(true), op, aa);
351         return;
352     }
353 #endif
354     SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
355     fClip.clipPath(this->localToDevice(), path, GrAA(aa), op);
356 }
357 
onClipRegion(const SkRegion & globalRgn,SkClipOp op)358 void Device::onClipRegion(const SkRegion& globalRgn, SkClipOp op) {
359     SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
360 
361     // Regions don't actually need AA, but in DMSAA mode every clip element is antialiased.
362     GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias());
363 
364     if (globalRgn.isEmpty()) {
365         fClip.clipRect(SkMatrix::I(), SkRect::MakeEmpty(), aa, op);
366     } else if (globalRgn.isRect()) {
367         fClip.clipRect(this->globalToDevice().asM33(), SkRect::Make(globalRgn.getBounds()), aa, op);
368     } else {
369         SkPath path;
370         globalRgn.getBoundaryPath(&path);
371         fClip.clipPath(this->globalToDevice().asM33(), path, aa, op);
372     }
373 }
374 
onAsRgnClip(SkRegion * region) const375 void Device::onAsRgnClip(SkRegion* region) const {
376     SkIRect bounds = fClip.getConservativeBounds();
377     // Assume wide open and then perform intersect/difference operations reducing the region
378     region->setRect(bounds);
379     const SkRegion deviceBounds(bounds);
380     for (const ClipStack::Element& e : fClip) {
381         SkRegion tmp;
382         if (e.fShape.isRect() && e.fLocalToDevice.isIdentity()) {
383             tmp.setRect(e.fShape.rect().roundOut());
384         } else {
385             SkPath tmpPath;
386             e.fShape.asPath(&tmpPath);
387             tmpPath.transform(e.fLocalToDevice);
388             tmp.setPath(tmpPath, deviceBounds);
389         }
390 
391         region->op(tmp, (SkRegion::Op) e.fOp);
392     }
393 }
394 
onClipIsAA() const395 bool Device::onClipIsAA() const {
396     for (const ClipStack::Element& e : fClip) {
397         if (e.fAA == GrAA::kYes) {
398             return true;
399         }
400         SkASSERT(!fSurfaceDrawContext->alwaysAntialias());
401     }
402     return false;
403 }
404 
onGetClipType() const405 SkBaseDevice::ClipType Device::onGetClipType() const {
406     ClipStack::ClipState state = fClip.clipState();
407     if (state == ClipStack::ClipState::kEmpty) {
408         return ClipType::kEmpty;
409     } else if (state == ClipStack::ClipState::kDeviceRect ||
410                state == ClipStack::ClipState::kWideOpen) {
411         return ClipType::kRect;
412     } else {
413         return ClipType::kComplex;
414     }
415 }
416 
417 ///////////////////////////////////////////////////////////////////////////////
418 
drawPaint(const SkPaint & paint)419 void Device::drawPaint(const SkPaint& paint) {
420     ASSERT_SINGLE_OWNER
421     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPaint", fContext.get());
422 
423     GrPaint grPaint;
424     if (!SkPaintToGrPaint(this->recordingContext(),
425                           fSurfaceDrawContext->colorInfo(),
426                           paint,
427                           this->localToDevice(),
428                           fSurfaceDrawContext->surfaceProps(),
429                           &grPaint)) {
430         return;
431     }
432 
433     fSurfaceDrawContext->drawPaint(this->clip(), std::move(grPaint), this->localToDevice());
434 }
435 
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)436 void Device::drawPoints(SkCanvas::PointMode mode,
437                         size_t count,
438                         const SkPoint pts[],
439                         const SkPaint& paint) {
440     ASSERT_SINGLE_OWNER
441     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPoints", fContext.get());
442     SkScalar width = paint.getStrokeWidth();
443     if (width < 0) {
444         return;
445     }
446 
447     GrAA aa = fSurfaceDrawContext->chooseAA(paint);
448 
449     if (count == 2 && mode == SkCanvas::kLines_PointMode) {
450         if (paint.getPathEffect()) {
451             // Probably a dashed line. Draw as a path.
452             GrPaint grPaint;
453             if (SkPaintToGrPaint(this->recordingContext(),
454                                  fSurfaceDrawContext->colorInfo(),
455                                  paint,
456                                  this->localToDevice(),
457                                  fSurfaceDrawContext->surfaceProps(),
458                                  &grPaint)) {
459                 SkPath path;
460                 path.setIsVolatile(true);
461                 path.moveTo(pts[0]);
462                 path.lineTo(pts[1]);
463                 fSurfaceDrawContext->drawPath(this->clip(),
464                                               std::move(grPaint),
465                                               aa,
466                                               this->localToDevice(),
467                                               path,
468                                               GrStyle(paint, SkPaint::kStroke_Style));
469             }
470             return;
471         }
472         if (!paint.getMaskFilter() &&
473             paint.getStrokeWidth() > 0 &&  // drawStrokedLine doesn't support hairlines.
474             paint.getStrokeCap() != SkPaint::kRound_Cap) { // drawStrokedLine doesn't do round caps.
475             // Simple stroked line. Bypass path rendering.
476             GrPaint grPaint;
477             if (SkPaintToGrPaint(this->recordingContext(),
478                                  fSurfaceDrawContext->colorInfo(),
479                                  paint,
480                                  this->localToDevice(),
481                                  fSurfaceDrawContext->surfaceProps(),
482                                  &grPaint)) {
483                 fSurfaceDrawContext->drawStrokedLine(this->clip(),
484                                                      std::move(grPaint),
485                                                      aa,
486                                                      this->localToDevice(),
487                                                      pts,
488                                                      SkStrokeRec(paint, SkPaint::kStroke_Style));
489             }
490             return;
491         }
492     }
493 
494     SkScalar scales[2];
495     bool isHairline = (0 == width) ||
496                        (1 == width && this->localToDevice().getMinMaxScales(scales) &&
497                         SkScalarNearlyEqual(scales[0], 1.f) && SkScalarNearlyEqual(scales[1], 1.f));
498     // we only handle non-coverage-aa hairlines and paints without path effects or mask filters,
499     // else we let the SkDraw call our drawPath()
500     if (!isHairline ||
501         paint.getPathEffect() ||
502         paint.getMaskFilter() ||
503         fSurfaceDrawContext->chooseAAType(aa) == GrAAType::kCoverage) {
504         SkRasterClip rc(this->devClipBounds());
505         SkDraw draw;
506         draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0);
507         draw.fMatrixProvider = this;
508         draw.fRC = &rc;
509         draw.drawPoints(mode, count, pts, paint, this);
510         return;
511     }
512 
513     const SkMatrixProvider* matrixProvider = this;
514     GrPaint grPaint;
515     if (!SkPaintToGrPaint(this->recordingContext(),
516                           fSurfaceDrawContext->colorInfo(),
517                           paint,
518                           matrixProvider->localToDevice(),
519                           fSurfaceDrawContext->surfaceProps(),
520                           &grPaint)) {
521         return;
522     }
523 
524     static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
525     sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr,
526                                                       nullptr);
527 
528     GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode);
529     fSurfaceDrawContext->drawVertices(this->clip(), std::move(grPaint), *matrixProvider,
530                                       std::move(vertices), &primitiveType);
531 }
532 
533 ///////////////////////////////////////////////////////////////////////////////
534 
drawRect(const SkRect & rect,const SkPaint & paint)535 void Device::drawRect(const SkRect& rect, const SkPaint& paint) {
536     ASSERT_SINGLE_OWNER
537     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRect", fContext.get());
538 
539     GrStyle style(paint);
540 
541     // A couple reasons we might need to call drawPath.
542     if (paint.getMaskFilter() || paint.getPathEffect()) {
543         GrStyledShape shape(rect, style);
544 
545         GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(),
546                                              this->clip(), paint, this->asMatrixProvider(), shape);
547         return;
548     }
549 
550     GrPaint grPaint;
551     if (!SkPaintToGrPaint(this->recordingContext(),
552                           fSurfaceDrawContext->colorInfo(),
553                           paint,
554                           this->localToDevice(),
555                           fSurfaceDrawContext->surfaceProps(),
556                           &grPaint)) {
557         return;
558     }
559 
560     fSurfaceDrawContext->drawRect(this->clip(), std::move(grPaint),
561                                   fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), rect,
562                                   &style);
563 }
564 
drawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],SkCanvas::QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)565 void Device::drawEdgeAAQuad(const SkRect& rect,
566                             const SkPoint clip[4],
567                             SkCanvas::QuadAAFlags aaFlags,
568                             const SkColor4f& color,
569                             SkBlendMode mode) {
570     ASSERT_SINGLE_OWNER
571     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawEdgeAAQuad", fContext.get());
572 
573     SkPMColor4f dstColor = SkColor4fPrepForDst(color, fSurfaceDrawContext->colorInfo()).premul();
574 
575     GrPaint grPaint;
576     grPaint.setColor4f(dstColor);
577     if (mode != SkBlendMode::kSrcOver) {
578         grPaint.setXPFactory(SkBlendMode_AsXPFactory(mode));
579     }
580 
581     if (clip) {
582         // Use fillQuadWithEdgeAA
583         fSurfaceDrawContext->fillQuadWithEdgeAA(this->clip(),
584                                                 std::move(grPaint),
585                                                 SkToGrQuadAAFlags(aaFlags),
586                                                 this->localToDevice(),
587                                                 clip,
588                                                 nullptr);
589     } else {
590         // Use fillRectWithEdgeAA to preserve mathematical properties of dst being rectangular
591         fSurfaceDrawContext->fillRectWithEdgeAA(this->clip(),
592                                                 std::move(grPaint),
593                                                 SkToGrQuadAAFlags(aaFlags),
594                                                 this->localToDevice(),
595                                                 rect);
596     }
597 }
598 
599 ///////////////////////////////////////////////////////////////////////////////
600 
drawRRect(const SkRRect & rrect,const SkPaint & paint)601 void Device::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
602     ASSERT_SINGLE_OWNER
603     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRRect", fContext.get());
604 
605     SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter());
606     if (mf) {
607         if (mf->hasFragmentProcessor()) {
608             mf = nullptr; // already handled in SkPaintToGrPaint
609         }
610     }
611 
612     GrStyle style(paint);
613 
614     if (mf || style.pathEffect()) {
615         // A path effect will presumably transform this rrect into something else.
616         GrStyledShape shape(rrect, style);
617 
618         GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(),
619                                              this->clip(), paint, this->asMatrixProvider(), shape);
620         return;
621     }
622 
623     SkASSERT(!style.pathEffect());
624 
625     GrPaint grPaint;
626     if (!SkPaintToGrPaint(this->recordingContext(),
627                           fSurfaceDrawContext->colorInfo(),
628                           paint,
629                           this->localToDevice(),
630                           fSurfaceDrawContext->surfaceProps(),
631                           &grPaint)) {
632         return;
633     }
634 
635     fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint),
636                                    fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
637                                    rrect, style);
638 }
639 
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)640 void Device::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
641     ASSERT_SINGLE_OWNER
642     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDRRect", fContext.get());
643     if (outer.isEmpty()) {
644        return;
645     }
646 
647     if (inner.isEmpty()) {
648         return this->drawRRect(outer, paint);
649     }
650 
651     SkStrokeRec stroke(paint);
652 
653     if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
654         // For axis-aligned filled DRRects, just draw a regular rrect with inner clipped out using a
655         // coverage FP instead of using path rendering.
656         if (auto fp = make_inverse_rrect_fp(this->localToDevice(), inner,
657                                             fSurfaceDrawContext->chooseAA(paint),
658                                             *fSurfaceDrawContext->caps()->shaderCaps())) {
659             GrPaint grPaint;
660             if (!SkPaintToGrPaint(this->recordingContext(),
661                                   fSurfaceDrawContext->colorInfo(),
662                                   paint,
663                                   this->localToDevice(),
664                                   fSurfaceDrawContext->surfaceProps(),
665                                   &grPaint)) {
666                 return;
667             }
668             SkASSERT(!grPaint.hasCoverageFragmentProcessor());
669             grPaint.setCoverageFragmentProcessor(std::move(fp));
670             fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint),
671                                            fSurfaceDrawContext->chooseAA(paint),
672                                            this->localToDevice(), outer, GrStyle());
673             return;
674         }
675     }
676 
677     SkPath path;
678     path.setIsVolatile(true);
679     path.addRRect(outer);
680     path.addRRect(inner);
681     path.setFillType(SkPathFillType::kEvenOdd);
682 
683     // TODO: We are losing the possible mutability of the path here but this should probably be
684     // fixed by upgrading GrStyledShape to handle DRRects.
685     GrStyledShape shape(path, paint);
686 
687     GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(),
688                                          paint, this->asMatrixProvider(), shape);
689 }
690 
691 /////////////////////////////////////////////////////////////////////////////
692 
drawRegion(const SkRegion & region,const SkPaint & paint)693 void Device::drawRegion(const SkRegion& region, const SkPaint& paint) {
694     ASSERT_SINGLE_OWNER
695 
696     if (paint.getMaskFilter()) {
697         SkPath path;
698         region.getBoundaryPath(&path);
699         path.setIsVolatile(true);
700         return this->drawPath(path, paint, true);
701     }
702 
703     GrPaint grPaint;
704     if (!SkPaintToGrPaint(this->recordingContext(),
705                           fSurfaceDrawContext->colorInfo(),
706                           paint,
707                           this->localToDevice(),
708                           fSurfaceDrawContext->surfaceProps(),
709                           &grPaint)) {
710         return;
711     }
712 
713     fSurfaceDrawContext->drawRegion(this->clip(), std::move(grPaint),
714                                     fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
715                                     region, GrStyle(paint));
716 }
717 
drawOval(const SkRect & oval,const SkPaint & paint)718 void Device::drawOval(const SkRect& oval, const SkPaint& paint) {
719     ASSERT_SINGLE_OWNER
720     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawOval", fContext.get());
721 
722     if (paint.getMaskFilter()) {
723         // The RRect path can handle special case blurring
724         SkRRect rr = SkRRect::MakeOval(oval);
725         return this->drawRRect(rr, paint);
726     }
727 
728     GrPaint grPaint;
729     if (!SkPaintToGrPaint(this->recordingContext(),
730                           fSurfaceDrawContext->colorInfo(),
731                           paint,
732                           this->localToDevice(),
733                           fSurfaceDrawContext->surfaceProps(),
734                           &grPaint)) {
735         return;
736     }
737 
738     fSurfaceDrawContext->drawOval(this->clip(), std::move(grPaint),
739                                   fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval,
740                                   GrStyle(paint));
741 }
742 
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)743 void Device::drawArc(const SkRect& oval,
744                      SkScalar startAngle,
745                      SkScalar sweepAngle,
746                      bool useCenter,
747                      const SkPaint& paint) {
748     ASSERT_SINGLE_OWNER
749     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawArc", fContext.get());
750     if (paint.getMaskFilter()) {
751         this->SkBaseDevice::drawArc(oval, startAngle, sweepAngle, useCenter, paint);
752         return;
753     }
754     GrPaint grPaint;
755     if (!SkPaintToGrPaint(this->recordingContext(),
756                           fSurfaceDrawContext->colorInfo(),
757                           paint,
758                           this->localToDevice(),
759                           fSurfaceDrawContext->surfaceProps(),
760                           &grPaint)) {
761         return;
762     }
763 
764     fSurfaceDrawContext->drawArc(this->clip(), std::move(grPaint),
765                                  fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval,
766                                  startAngle, sweepAngle, useCenter, GrStyle(paint));
767 }
768 
769 ///////////////////////////////////////////////////////////////////////////////
770 
drawPath(const SkPath & origSrcPath,const SkPaint & paint,bool pathIsMutable)771 void Device::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool pathIsMutable) {
772 #if GR_TEST_UTILS
773     if (fContext->priv().options().fAllPathsVolatile && !origSrcPath.isVolatile()) {
774         this->drawPath(SkPath(origSrcPath).setIsVolatile(true), paint, true);
775         return;
776     }
777 #endif
778     ASSERT_SINGLE_OWNER
779     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPath", fContext.get());
780     if (!paint.getMaskFilter()) {
781         GrPaint grPaint;
782         if (!SkPaintToGrPaint(this->recordingContext(),
783                               fSurfaceDrawContext->colorInfo(),
784                               paint,
785                               this->localToDevice(),
786                               fSurfaceDrawContext->surfaceProps(),
787                               &grPaint)) {
788             return;
789         }
790         fSurfaceDrawContext->drawPath(this->clip(), std::move(grPaint),
791                                       fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
792                                       origSrcPath, GrStyle(paint));
793         return;
794     }
795 
796     // TODO: losing possible mutability of 'origSrcPath' here
797     GrStyledShape shape(origSrcPath, paint);
798 
799     GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(),
800                                          paint, this->asMatrixProvider(), shape);
801 }
802 
makeSpecial(const SkBitmap & bitmap)803 sk_sp<SkSpecialImage> Device::makeSpecial(const SkBitmap& bitmap) {
804     ASSERT_SINGLE_OWNER
805 
806     // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's
807     // semantics). Since this is cached we would have to bake the fit into the cache key though.
808     auto view = std::get<0>(
809             GrMakeCachedBitmapProxyView(fContext.get(), bitmap, /*label=*/"Device_MakeSpecial"));
810     if (!view) {
811         return nullptr;
812     }
813 
814     const SkIRect rect = SkIRect::MakeSize(view.proxy()->dimensions());
815 
816     // GrMakeCachedBitmapProxyView creates a tight copy of 'bitmap' so we don't have to subset
817     // the special image
818     return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
819                                                rect,
820                                                bitmap.getGenerationID(),
821                                                std::move(view),
822                                                { SkColorTypeToGrColorType(bitmap.colorType()),
823                                                  kPremul_SkAlphaType,
824                                                  bitmap.refColorSpace() },
825                                                this->surfaceProps());
826 }
827 
makeSpecial(const SkImage * image)828 sk_sp<SkSpecialImage> Device::makeSpecial(const SkImage* image) {
829     ASSERT_SINGLE_OWNER
830 
831     SkPixmap pm;
832     if (image->isTextureBacked()) {
833         auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo);
834         SkASSERT(view);
835 
836         return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
837                                                    SkIRect::MakeWH(image->width(), image->height()),
838                                                    image->uniqueID(),
839                                                    std::move(view),
840                                                    { ct, kPremul_SkAlphaType,
841                                                      image->refColorSpace() },
842                                                    this->surfaceProps());
843     } else if (image->peekPixels(&pm)) {
844         SkBitmap bm;
845 
846         bm.installPixels(pm);
847         return this->makeSpecial(bm);
848     } else {
849         return nullptr;
850     }
851 }
852 
snapSpecial(const SkIRect & subset,bool forceCopy)853 sk_sp<SkSpecialImage> Device::snapSpecial(const SkIRect& subset, bool forceCopy) {
854     ASSERT_SINGLE_OWNER
855 
856     auto sdc = fSurfaceDrawContext.get();
857 
858     // If we are wrapping a vulkan secondary command buffer, then we can't snap off a special image
859     // since it would require us to make a copy of the underlying VkImage which we don't have access
860     // to. Additionaly we can't stop and start the render pass that is used with the secondary
861     // command buffer.
862     if (sdc->wrapsVkSecondaryCB()) {
863         return nullptr;
864     }
865 
866     SkASSERT(sdc->asSurfaceProxy());
867 
868     SkIRect finalSubset = subset;
869     GrSurfaceProxyView view = sdc->readSurfaceView();
870     if (forceCopy || !view.asTextureProxy()) {
871         // When the device doesn't have a texture, or a copy is requested, we create a temporary
872         // texture that matches the device contents
873         view = GrSurfaceProxyView::Copy(fContext.get(),
874                                         std::move(view),
875                                         GrMipmapped::kNo,  // Don't auto generate mips
876                                         subset,
877                                         SkBackingFit::kApprox,
878                                         skgpu::Budgeted::kYes,
879                                         /*label=*/"Device_SnapSpecial");  // Always budgeted
880         if (!view) {
881             return nullptr;
882         }
883         // Since this copied only the requested subset, the special image wrapping the proxy no
884         // longer needs the original subset.
885         finalSubset = SkIRect::MakeSize(view.dimensions());
886     }
887 
888     return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
889                                                finalSubset,
890                                                kNeedNewImageUniqueID_SpecialImage,
891                                                std::move(view),
892                                                GrColorInfo(this->imageInfo().colorInfo()),
893                                                this->surfaceProps());
894 }
895 
snapSpecialScaled(const SkIRect & subset,const SkISize & dstDims)896 sk_sp<SkSpecialImage> Device::snapSpecialScaled(const SkIRect& subset, const SkISize& dstDims) {
897      ASSERT_SINGLE_OWNER
898 
899     auto sdc = fSurfaceDrawContext.get();
900 
901     // If we are wrapping a vulkan secondary command buffer, then we can't snap off a special image
902     // since it would require us to make a copy of the underlying VkImage which we don't have access
903     // to. Additionaly we can't stop and start the render pass that is used with the secondary
904     // command buffer.
905     if (sdc->wrapsVkSecondaryCB()) {
906         return nullptr;
907     }
908 
909     SkASSERT(sdc->asSurfaceProxy());
910 
911     auto scaledContext = sdc->rescale(sdc->imageInfo().makeDimensions(dstDims),
912                                       sdc->origin(),
913                                       subset,
914                                       RescaleGamma::kSrc,
915                                       RescaleMode::kLinear);
916     if (!scaledContext) {
917         return nullptr;
918     }
919 
920     return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
921                                                SkIRect::MakeSize(dstDims),
922                                                kNeedNewImageUniqueID_SpecialImage,
923                                                scaledContext->readSurfaceView(),
924                                                GrColorInfo(this->imageInfo().colorInfo()),
925                                                this->surfaceProps());
926 }
927 
drawDevice(SkBaseDevice * device,const SkSamplingOptions & sampling,const SkPaint & paint)928 void Device::drawDevice(SkBaseDevice* device,
929                         const SkSamplingOptions& sampling,
930                         const SkPaint& paint) {
931     ASSERT_SINGLE_OWNER
932     // clear of the source device must occur before CHECK_SHOULD_DRAW
933     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDevice", fContext.get());
934     this->SkBaseDevice::drawDevice(device, sampling, paint);
935 }
936 
drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)937 void Device::drawImageRect(const SkImage* image,
938                            const SkRect* src,
939                            const SkRect& dst,
940                            const SkSamplingOptions& sampling,
941                            const SkPaint& paint,
942                            SkCanvas::SrcRectConstraint constraint) {
943     ASSERT_SINGLE_OWNER
944     GrAA aa = fSurfaceDrawContext->chooseAA(paint);
945     GrQuadAAFlags aaFlags = (aa == GrAA::kYes) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
946     this->drawImageQuad(image, src, &dst, nullptr, aaFlags, nullptr, sampling, paint, constraint);
947 }
948 
drawViewLattice(GrSurfaceProxyView view,const GrColorInfo & info,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst,SkFilterMode filter,const SkPaint & origPaint)949 void Device::drawViewLattice(GrSurfaceProxyView view,
950                              const GrColorInfo& info,
951                              std::unique_ptr<SkLatticeIter> iter,
952                              const SkRect& dst,
953                              SkFilterMode filter,
954                              const SkPaint& origPaint) {
955     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawViewLattice", fContext.get());
956     SkASSERT(view);
957 
958     SkTCopyOnFirstWrite<SkPaint> paint(&origPaint);
959 
960     if (!info.isAlphaOnly() && (paint->getColor() & 0x00FFFFFF) != 0x00FFFFFF) {
961         paint.writable()->setColor(SkColorSetARGB(origPaint.getAlpha(), 0xFF, 0xFF, 0xFF));
962     }
963     GrPaint grPaint;
964     // Passing null as shaderFP indicates that the GP will provide the shader.
965     if (!SkPaintToGrPaintReplaceShader(this->recordingContext(),
966                                        fSurfaceDrawContext->colorInfo(),
967                                        *paint,
968                                        this->localToDevice(),
969                                        /*shaderFP=*/nullptr,
970                                        fSurfaceDrawContext->surfaceProps(),
971                                        &grPaint)) {
972         return;
973     }
974 
975     if (info.isAlphaOnly()) {
976         // If we were doing this with an FP graph we'd use a kDstIn blend between the texture and
977         // the paint color.
978         view.concatSwizzle(skgpu::Swizzle("aaaa"));
979     }
980     auto csxf = GrColorSpaceXform::Make(info, fSurfaceDrawContext->colorInfo());
981 
982     fSurfaceDrawContext->drawImageLattice(this->clip(), std::move(grPaint), this->localToDevice(),
983                                           std::move(view), info.alphaType(), std::move(csxf),
984                                           filter, std::move(iter), dst);
985 }
986 
drawImageLattice(const SkImage * image,const SkCanvas::Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint & paint)987 void Device::drawImageLattice(const SkImage* image,
988                               const SkCanvas::Lattice& lattice,
989                               const SkRect& dst,
990                               SkFilterMode filter,
991                               const SkPaint& paint) {
992     ASSERT_SINGLE_OWNER
993     auto iter = std::make_unique<SkLatticeIter>(lattice, dst);
994     if (auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo); view) {
995         GrColorInfo colorInfo(ct, image->alphaType(), image->refColorSpace());
996         this->drawViewLattice(std::move(view),
997                               std::move(colorInfo),
998                               std::move(iter),
999                               dst,
1000                               filter,
1001                               paint);
1002     }
1003 }
1004 
drawVertices(const SkVertices * vertices,sk_sp<SkBlender> blender,const SkPaint & paint,bool skipColorXform)1005 void Device::drawVertices(const SkVertices* vertices,
1006                           sk_sp<SkBlender> blender,
1007                           const SkPaint& paint,
1008                           bool skipColorXform) {
1009     ASSERT_SINGLE_OWNER
1010     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawVertices", fContext.get());
1011     SkASSERT(vertices);
1012 
1013 #ifdef SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER
1014     if (!paint.getShader()) {
1015         blender = SkBlender::Mode(SkBlendMode::kDst);
1016     }
1017 #endif
1018 
1019     SkVerticesPriv info(vertices->priv());
1020 
1021     GrPaint grPaint;
1022     if (!init_vertices_paint(fContext.get(),
1023                              fSurfaceDrawContext->colorInfo(),
1024                              paint,
1025                              this->localToDevice(),
1026                              std::move(blender),
1027                              info.hasColors(),
1028                              fSurfaceDrawContext->surfaceProps(),
1029                              &grPaint)) {
1030         return;
1031     }
1032     fSurfaceDrawContext->drawVertices(this->clip(),
1033                                       std::move(grPaint),
1034                                       this->asMatrixProvider(),
1035                                       sk_ref_sp(const_cast<SkVertices*>(vertices)),
1036                                       nullptr,
1037                                       skipColorXform);
1038 }
1039 
drawMesh(const SkMesh & mesh,sk_sp<SkBlender> blender,const SkPaint & paint)1040 void Device::drawMesh(const SkMesh& mesh, sk_sp<SkBlender> blender, const SkPaint& paint) {
1041     ASSERT_SINGLE_OWNER
1042     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawMesh", fContext.get());
1043     SkASSERT(mesh.isValid());
1044 
1045     GrPaint grPaint;
1046     if (!init_vertices_paint(fContext.get(),
1047                              fSurfaceDrawContext->colorInfo(),
1048                              paint,
1049                              this->localToDevice(),
1050                              std::move(blender),
1051                              SkMeshSpecificationPriv::HasColors(*mesh.spec()),
1052                              fSurfaceDrawContext->surfaceProps(),
1053                              &grPaint)) {
1054         return;
1055     }
1056     fSurfaceDrawContext->drawMesh(this->clip(), std::move(grPaint), this->asMatrixProvider(), mesh);
1057 }
1058 
1059 ///////////////////////////////////////////////////////////////////////////////
1060 
1061 #if !defined(SK_ENABLE_OPTIMIZE_SIZE)
drawShadow(const SkPath & path,const SkDrawShadowRec & rec)1062 void Device::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
1063 #if GR_TEST_UTILS
1064     if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
1065         this->drawShadow(SkPath(path).setIsVolatile(true), rec);
1066         return;
1067     }
1068 #endif
1069     ASSERT_SINGLE_OWNER
1070     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawShadow", fContext.get());
1071 
1072     if (!fSurfaceDrawContext->drawFastShadow(this->clip(), this->localToDevice(), path, rec)) {
1073         // failed to find an accelerated case
1074         this->SkBaseDevice::drawShadow(path, rec);
1075     }
1076 }
1077 #endif  // SK_ENABLE_OPTIMIZE_SIZE
1078 
1079 ///////////////////////////////////////////////////////////////////////////////
1080 
drawAtlas(const SkRSXform xform[],const SkRect texRect[],const SkColor colors[],int count,sk_sp<SkBlender> blender,const SkPaint & paint)1081 void Device::drawAtlas(const SkRSXform xform[],
1082                        const SkRect texRect[],
1083                        const SkColor colors[],
1084                        int count,
1085                        sk_sp<SkBlender> blender,
1086                        const SkPaint& paint) {
1087     ASSERT_SINGLE_OWNER
1088     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawAtlas", fContext.get());
1089 
1090     GrPaint grPaint;
1091     if (colors) {
1092         if (!SkPaintToGrPaintWithBlend(this->recordingContext(),
1093                                        fSurfaceDrawContext->colorInfo(),
1094                                        paint,
1095                                        this->localToDevice(),
1096                                        blender.get(),
1097                                        fSurfaceDrawContext->surfaceProps(),
1098                                        &grPaint)) {
1099             return;
1100         }
1101     } else {
1102         if (!SkPaintToGrPaint(this->recordingContext(),
1103                               fSurfaceDrawContext->colorInfo(),
1104                               paint,
1105                               this->localToDevice(),
1106                               fSurfaceDrawContext->surfaceProps(),
1107                               &grPaint)) {
1108             return;
1109         }
1110     }
1111 
1112     fSurfaceDrawContext->drawAtlas(this->clip(), std::move(grPaint), this->localToDevice(), count,
1113                                    xform, texRect, colors);
1114 }
1115 
1116 ///////////////////////////////////////////////////////////////////////////////
1117 
1118 #if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG)
testingOnly_drawGlyphRunListWithSlug(SkCanvas * canvas,const sktext::GlyphRunList & glyphRunList,const SkPaint & initialPaint,const SkPaint & drawingPaint)1119 void Device::testingOnly_drawGlyphRunListWithSlug(SkCanvas* canvas,
1120                                                   const sktext::GlyphRunList& glyphRunList,
1121                                                   const SkPaint& initialPaint,
1122                                                   const SkPaint& drawingPaint) {
1123     auto slug = this->convertGlyphRunListToSlug(glyphRunList, initialPaint, drawingPaint);
1124     if (slug != nullptr) {
1125         this->drawSlug(canvas, slug.get(), drawingPaint);
1126     }
1127 }
1128 #endif
1129 
1130 #if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_SERIALIZE)
testingOnly_drawGlyphRunListWithSerializedSlug(SkCanvas * canvas,const sktext::GlyphRunList & glyphRunList,const SkPaint & initialPaint,const SkPaint & drawingPaint)1131 void Device::testingOnly_drawGlyphRunListWithSerializedSlug(
1132         SkCanvas* canvas,
1133         const sktext::GlyphRunList& glyphRunList,
1134         const SkPaint& initialPaint,
1135         const SkPaint& drawingPaint) {
1136     // This is not a text blob draw. Handle using glyphRunList conversion.
1137     if (glyphRunList.blob() == nullptr) {
1138         auto slug = this->convertGlyphRunListToSlug(glyphRunList, initialPaint, drawingPaint);
1139         if (slug != nullptr) {
1140             this->drawSlug(canvas, slug.get(), drawingPaint);
1141         }
1142         return;
1143     }
1144     auto srcSlug = Slug::ConvertBlob(
1145             canvas, *glyphRunList.blob(), glyphRunList.origin(), initialPaint);
1146 
1147     // There is nothing to draw.
1148     if (srcSlug == nullptr) {
1149         return;
1150     }
1151 
1152     auto dstSlugData = srcSlug->serialize();
1153 
1154     auto dstSlug = Slug::Deserialize(dstSlugData->data(), dstSlugData->size());
1155     SkASSERT(dstSlug != nullptr);
1156     if (dstSlug != nullptr) {
1157         this->drawSlug(canvas, dstSlug.get(), drawingPaint);
1158     }
1159 }
1160 #endif
1161 
1162 // This testing method draws a blob by analyzing it to create strike cache
1163 // differences and then serializing the Blob to a Slug. This creates a hard
1164 // break between the original glyph data, and the proxied glyph data - and
1165 // closely mimics how Chrome draws text.
1166 #if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE)
1167 namespace {
1168 class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
1169                            public SkStrikeClient::DiscardableHandleManager {
1170 public:
DiscardableManager()1171     DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
1172     ~DiscardableManager() override = default;
1173 
1174     // Server implementation.
createHandle()1175     SkDiscardableHandleId createHandle() override SK_EXCLUDES(fLock) {
1176         SkAutoMutexExclusive l(fLock);
1177 
1178         // Handles starts as locked.
1179         fLockedHandles.add(++fNextHandleId);
1180         return fNextHandleId;
1181     }
lockHandle(SkDiscardableHandleId id)1182     bool lockHandle(SkDiscardableHandleId id) override SK_EXCLUDES(fLock) {
1183         SkAutoMutexExclusive l(fLock);
1184 
1185         fLockedHandles.add(id);
1186         return true;
1187     }
1188 
1189     // Client implementation.
deleteHandle(SkDiscardableHandleId id)1190     bool deleteHandle(SkDiscardableHandleId id) override SK_EXCLUDES(fLock) {
1191         return false;
1192     }
1193 
notifyCacheMiss(SkStrikeClient::CacheMissType type,int fontSize)1194     void notifyCacheMiss(
1195             SkStrikeClient::CacheMissType type, int fontSize) override SK_EXCLUDES(fLock) {
1196         SkAutoMutexExclusive l(fLock);
1197 
1198         fCacheMissCount[type]++;
1199     }
isHandleDeleted(SkDiscardableHandleId id)1200     bool isHandleDeleted(SkDiscardableHandleId id) override SK_EXCLUDES(fLock) {
1201         return false;
1202     }
1203 
1204 private:
1205     // The tests below run in parallel on multiple threads and use the same
1206     // process global SkStrikeCache. So the implementation needs to be
1207     // thread-safe.
1208     mutable SkMutex fLock;
1209 
1210     SkDiscardableHandleId fNextHandleId SK_GUARDED_BY(fLock) = 0u;
1211     SkTHashSet<SkDiscardableHandleId> fLockedHandles SK_GUARDED_BY(fLock);
1212     int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u] SK_GUARDED_BY(fLock);
1213 };
1214 }  // namespace
1215 
testingOnly_drawGlyphRunListWithSerializedSlugAndStrike(SkCanvas * canvas,const sktext::GlyphRunList & glyphRunList,const SkPaint & initialPaint,const SkPaint & drawingPaint)1216 void Device::testingOnly_drawGlyphRunListWithSerializedSlugAndStrike(
1217         SkCanvas* canvas,
1218         const sktext::GlyphRunList& glyphRunList,
1219         const SkPaint& initialPaint,
1220         const SkPaint& drawingPaint) {
1221     if (glyphRunList.blob() == nullptr) {
1222         auto slug = this->convertGlyphRunListToSlug(glyphRunList, initialPaint, drawingPaint);
1223         if (slug != nullptr) {
1224             this->drawSlug(canvas, slug.get(), drawingPaint);
1225         }
1226         return;
1227     }
1228 
1229     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
1230     SkStrikeServer server{discardableManager.get()};
1231 
1232     SkStrikeClient client{discardableManager, false};
1233     SkSurfaceProps surfaceProps;
1234     if (!canvas->getProps(&surfaceProps)) {
1235         SK_ABORT("Ahhhhh! can't get the surface props.");
1236     }
1237     sk_sp<SkColorSpace> colorSpace = canvas->imageInfo().refColorSpace();
1238     bool useDFT = this->recordingContext()->asDirectContext()->supportsDistanceFieldText();
1239     auto analysisCanvas = server.makeAnalysisCanvas(
1240             canvas->getBaseLayerSize().width(), canvas->getBaseLayerSize().width(),
1241             surfaceProps,
1242             std::move(colorSpace),
1243             useDFT
1244     );
1245 
1246     analysisCanvas->setMatrix(canvas->getTotalMatrix());
1247     auto srcSlug = Slug::ConvertBlob(analysisCanvas.get(),
1248                                        *glyphRunList.blob(),
1249                                        glyphRunList.origin(),
1250                                        initialPaint);
1251 
1252     if (srcSlug == nullptr) {
1253         return;
1254     }
1255 
1256     std::vector<uint8_t> serverStrikeData;
1257     server.writeStrikeData(&serverStrikeData);
1258 
1259     if (!client.readStrikeData(serverStrikeData.data(), serverStrikeData.size())) {
1260         SK_ABORT("Problem reading the strike cache updates");
1261     }
1262 
1263     auto dstSlugData = srcSlug->serialize();
1264     auto dstSlug = client.deserializeSlug(dstSlugData->data(), dstSlugData->size());
1265     this->drawSlug(canvas, dstSlug.get(), drawingPaint);
1266 }
1267 #endif
1268 
onDrawGlyphRunList(SkCanvas * canvas,const sktext::GlyphRunList & glyphRunList,const SkPaint & initialPaint,const SkPaint & drawingPaint)1269 void Device::onDrawGlyphRunList(SkCanvas* canvas,
1270                                 const sktext::GlyphRunList& glyphRunList,
1271                                 const SkPaint& initialPaint,
1272                                 const SkPaint& drawingPaint) {
1273     ASSERT_SINGLE_OWNER
1274     GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawGlyphRunList", fContext.get());
1275     SkASSERT(!glyphRunList.hasRSXForm());
1276 
1277 #if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG)
1278     this->testingOnly_drawGlyphRunListWithSlug(canvas, glyphRunList, initialPaint, drawingPaint);
1279 #elif defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_SERIALIZE)
1280     this->testingOnly_drawGlyphRunListWithSerializedSlug(
1281             canvas, glyphRunList, initialPaint, drawingPaint);
1282 #elif defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE)
1283     this->testingOnly_drawGlyphRunListWithSerializedSlugAndStrike(
1284             canvas, glyphRunList, initialPaint, drawingPaint);
1285 #else
1286     if (glyphRunList.blob() == nullptr) {
1287         // If the glyphRunList does not have an associated text blob, then it was created by one of
1288         // the direct draw APIs (drawGlyphs, etc.). Use a Slug to draw the glyphs.
1289         auto slug = this->convertGlyphRunListToSlug(glyphRunList, initialPaint, drawingPaint);
1290         if (slug != nullptr) {
1291             this->drawSlug(canvas, slug.get(), drawingPaint);
1292         }
1293     } else {
1294         fSurfaceDrawContext->drawGlyphRunList(canvas,
1295                                               this->clip(),
1296                                               this->asMatrixProvider(),
1297                                               glyphRunList,
1298                                               this->strikeDeviceInfo(),
1299                                               drawingPaint);
1300     }
1301 #endif
1302 }
1303 
1304 ///////////////////////////////////////////////////////////////////////////////
1305 
drawDrawable(SkCanvas * canvas,SkDrawable * drawable,const SkMatrix * matrix)1306 void Device::drawDrawable(SkCanvas* canvas, SkDrawable* drawable, const SkMatrix* matrix) {
1307     ASSERT_SINGLE_OWNER
1308 
1309     GrBackendApi api = this->recordingContext()->backend();
1310     if (GrBackendApi::kVulkan == api) {
1311         const SkMatrix& ctm = this->localToDevice();
1312         const SkMatrix& combinedMatrix = matrix ? SkMatrix::Concat(ctm, *matrix) : ctm;
1313         std::unique_ptr<SkDrawable::GpuDrawHandler> gpuDraw =
1314                 drawable->snapGpuDrawHandler(api, combinedMatrix, this->devClipBounds(),
1315                                              this->imageInfo());
1316         if (gpuDraw) {
1317             fSurfaceDrawContext->drawDrawable(
1318                     std::move(gpuDraw), combinedMatrix.mapRect(drawable->getBounds()));
1319             return;
1320         }
1321     }
1322     this->SkBaseDevice::drawDrawable(canvas, drawable, matrix);
1323 }
1324 
1325 
1326 ///////////////////////////////////////////////////////////////////////////////
1327 
readSurfaceView()1328 GrSurfaceProxyView Device::readSurfaceView() {
1329     return this->surfaceFillContext()->readSurfaceView();
1330 }
1331 
targetProxy()1332 GrRenderTargetProxy* Device::targetProxy() {
1333     return this->readSurfaceView().asRenderTargetProxy();
1334 }
1335 
wait(int numSemaphores,const GrBackendSemaphore * waitSemaphores,bool deleteSemaphoresAfterWait)1336 bool Device::wait(int numSemaphores,
1337                   const GrBackendSemaphore* waitSemaphores,
1338                   bool deleteSemaphoresAfterWait) {
1339     ASSERT_SINGLE_OWNER
1340 
1341     return fSurfaceDrawContext->waitOnSemaphores(numSemaphores, waitSemaphores,
1342                                                  deleteSemaphoresAfterWait);
1343 }
1344 
discard()1345 void Device::discard() {
1346     fSurfaceDrawContext->discard();
1347 }
1348 
resolveMSAA()1349 void Device::resolveMSAA() {
1350     fSurfaceDrawContext->resolveMSAA();
1351 }
1352 
replaceBackingProxy(SkSurface::ContentChangeMode mode,sk_sp<GrRenderTargetProxy> newRTP,GrColorType grColorType,sk_sp<SkColorSpace> colorSpace,GrSurfaceOrigin origin,const SkSurfaceProps & props)1353 bool Device::replaceBackingProxy(SkSurface::ContentChangeMode mode,
1354                                  sk_sp<GrRenderTargetProxy> newRTP,
1355                                  GrColorType grColorType,
1356                                  sk_sp<SkColorSpace> colorSpace,
1357                                  GrSurfaceOrigin origin,
1358                                  const SkSurfaceProps& props) {
1359     auto sdc = SurfaceDrawContext::Make(fContext.get(), grColorType, std::move(newRTP),
1360                                         std::move(colorSpace), origin, props);
1361     if (!sdc) {
1362         return false;
1363     }
1364 
1365     SkASSERT(sdc->dimensions() == fSurfaceDrawContext->dimensions());
1366     SkASSERT(sdc->numSamples() == fSurfaceDrawContext->numSamples());
1367     SkASSERT(sdc->asSurfaceProxy()->priv().isExact());
1368     if (mode == SkSurface::kRetain_ContentChangeMode) {
1369         if (fContext->abandoned()) {
1370             return false;
1371         }
1372 
1373         SkASSERT(fSurfaceDrawContext->asTextureProxy());
1374         SkAssertResult(sdc->blitTexture(fSurfaceDrawContext->readSurfaceView(),
1375                                         SkIRect::MakeWH(this->width(), this->height()),
1376                                         SkIPoint::Make(0, 0)));
1377     }
1378 
1379     fSurfaceDrawContext = std::move(sdc);
1380     return true;
1381 }
1382 
replaceBackingProxy(SkSurface::ContentChangeMode mode)1383 bool Device::replaceBackingProxy(SkSurface::ContentChangeMode mode) {
1384     ASSERT_SINGLE_OWNER
1385 
1386     const SkImageInfo& ii = this->imageInfo();
1387     GrRenderTargetProxy* oldRTP = this->targetProxy();
1388     GrSurfaceProxyView oldView = this->readSurfaceView();
1389 
1390     auto grColorType = SkColorTypeToGrColorType(ii.colorType());
1391     auto format = fContext->priv().caps()->getDefaultBackendFormat(grColorType, GrRenderable::kYes);
1392     if (!format.isValid()) {
1393         return false;
1394     }
1395 
1396     GrProxyProvider* proxyProvider = fContext->priv().proxyProvider();
1397     // This entry point is used by SkSurface_Gpu::onCopyOnWrite so it must create a
1398     // kExact-backed render target proxy
1399     sk_sp<GrTextureProxy> proxy =
1400             proxyProvider->createProxy(format,
1401                                        ii.dimensions(),
1402                                        GrRenderable::kYes,
1403                                        oldRTP->numSamples(),
1404                                        oldView.mipmapped(),
1405                                        SkBackingFit::kExact,
1406                                        oldRTP->isBudgeted(),
1407                                        GrProtected::kNo,
1408                                        /*label=*/"BaseDevice_ReplaceBackingProxy");
1409     if (!proxy) {
1410         return false;
1411     }
1412 
1413     return this->replaceBackingProxy(mode, sk_ref_sp(proxy->asRenderTargetProxy()),
1414                                      grColorType, ii.refColorSpace(), oldView.origin(),
1415                                      this->surfaceProps());
1416 }
1417 
asyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)1418 void Device::asyncRescaleAndReadPixels(const SkImageInfo& info,
1419                                        const SkIRect& srcRect,
1420                                        RescaleGamma rescaleGamma,
1421                                        RescaleMode rescaleMode,
1422                                        ReadPixelsCallback callback,
1423                                        ReadPixelsContext context) {
1424     auto* sdc = fSurfaceDrawContext.get();
1425     // Context TODO: Elevate direct context requirement to public API.
1426     auto dContext = sdc->recordingContext()->asDirectContext();
1427     if (!dContext) {
1428         return;
1429     }
1430     sdc->asyncRescaleAndReadPixels(dContext, info, srcRect, rescaleGamma, rescaleMode, callback,
1431                                    context);
1432 }
1433 
asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,SkISize dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)1434 void Device::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
1435                                              sk_sp<SkColorSpace> dstColorSpace,
1436                                              const SkIRect& srcRect,
1437                                              SkISize dstSize,
1438                                              RescaleGamma rescaleGamma,
1439                                              RescaleMode rescaleMode,
1440                                              ReadPixelsCallback callback,
1441                                              ReadPixelsContext context) {
1442     auto* sdc = fSurfaceDrawContext.get();
1443     // Context TODO: Elevate direct context requirement to public API.
1444     auto dContext = sdc->recordingContext()->asDirectContext();
1445     if (!dContext) {
1446         return;
1447     }
1448     sdc->asyncRescaleAndReadPixelsYUV420(dContext,
1449                                          yuvColorSpace,
1450                                          std::move(dstColorSpace),
1451                                          srcRect,
1452                                          dstSize,
1453                                          rescaleGamma,
1454                                          rescaleMode,
1455                                          callback,
1456                                          context);
1457 }
1458 
1459 ///////////////////////////////////////////////////////////////////////////////
1460 
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)1461 SkBaseDevice* Device::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
1462     ASSERT_SINGLE_OWNER
1463 
1464     SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry);
1465 
1466     // layers are never drawn in repeat modes, so we can request an approx
1467     // match and ignore any padding.
1468     SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox
1469                                                             : SkBackingFit::kExact;
1470 
1471     SkASSERT(cinfo.fInfo.colorType() != kRGBA_1010102_SkColorType);
1472 
1473     auto sdc = SurfaceDrawContext::MakeWithFallback(
1474             fContext.get(),
1475             SkColorTypeToGrColorType(cinfo.fInfo.colorType()),
1476             fSurfaceDrawContext->colorInfo().refColorSpace(),
1477             fit,
1478             cinfo.fInfo.dimensions(),
1479             props,
1480             fSurfaceDrawContext->numSamples(),
1481             GrMipmapped::kNo,
1482             fSurfaceDrawContext->asSurfaceProxy()->isProtected(),
1483             fSurfaceDrawContext->origin(),
1484             skgpu::Budgeted::kYes);
1485     if (!sdc) {
1486         return nullptr;
1487     }
1488 
1489     // Skia's convention is to only clear a device if it is non-opaque.
1490     InitContents init = cinfo.fInfo.isOpaque() ? InitContents::kUninit : InitContents::kClear;
1491 
1492     return Device::Make(std::move(sdc), cinfo.fInfo.alphaType(), init).release();
1493 }
1494 
makeSurface(const SkImageInfo & info,const SkSurfaceProps & props)1495 sk_sp<SkSurface> Device::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1496     ASSERT_SINGLE_OWNER
1497     // TODO: Change the signature of newSurface to take a budgeted parameter.
1498     static const skgpu::Budgeted kBudgeted = skgpu::Budgeted::kNo;
1499     return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info,
1500                                        fSurfaceDrawContext->numSamples(),
1501                                        fSurfaceDrawContext->origin(), &props);
1502 }
1503 
getImageFilterCache()1504 SkImageFilterCache* Device::getImageFilterCache() {
1505     ASSERT_SINGLE_OWNER
1506     // We always return a transient cache, so it is freed after each
1507     // filter traversal.
1508     return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
1509 }
1510 
1511 ////////////////////////////////////////////////////////////////////////////////////
1512 
android_utils_clipWithStencil()1513 bool Device::android_utils_clipWithStencil() {
1514     SkRegion clipRegion;
1515     this->onAsRgnClip(&clipRegion);
1516     if (clipRegion.isEmpty()) {
1517         return false;
1518     }
1519     auto sdc = fSurfaceDrawContext.get();
1520     SkASSERT(sdc);
1521     GrPaint grPaint;
1522     grPaint.setXPFactory(GrDisableColorXPFactory::Get());
1523     static constexpr GrUserStencilSettings kDrawToStencil(
1524         GrUserStencilSettings::StaticInit<
1525             0x1,
1526             GrUserStencilTest::kAlways,
1527             0x1,
1528             GrUserStencilOp::kReplace,
1529             GrUserStencilOp::kReplace,
1530             0x1>()
1531     );
1532     // Regions don't actually need AA, but in DMSAA mode everything is antialiased.
1533     GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias());
1534     sdc->drawRegion(nullptr, std::move(grPaint), aa, SkMatrix::I(), clipRegion,
1535                     GrStyle::SimpleFill(), &kDrawToStencil);
1536     return true;
1537 }
1538 
strikeDeviceInfo() const1539 SkStrikeDeviceInfo Device::strikeDeviceInfo() const {
1540     return {this->surfaceProps(), this->scalerContextFlags(), &fSDFTControl};
1541 }
1542 
1543 } // namespace skgpu::v1
1544