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