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/ganesh/GrBackendSurface.h"
43 #include "include/gpu/ganesh/GrContextOptions.h"
44 #include "include/gpu/ganesh/GrDirectContext.h"
45 #include "include/gpu/ganesh/GrRecordingContext.h"
46 #include "include/gpu/ganesh/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(GPU_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 , fSubRunControl(sdc->recordingContext()->priv().getSubRunControl(
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(GPU_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(GPU_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(GPU_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 rCtx->priv().options().fSharpenMipmappedTextures,
1043 cacheSize,
1044 maxTextureSize);
1045 #if defined(GPU_TEST_UTILS)
1046 gNumTilesDrawnGanesh.store(numTiles, std::memory_order_relaxed);
1047 #endif
1048 return wasTiled;
1049 }
1050
drawViewLattice(GrSurfaceProxyView view,const GrColorInfo & info,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst,SkFilterMode filter,const SkPaint & origPaint)1051 void Device::drawViewLattice(GrSurfaceProxyView view,
1052 const GrColorInfo& info,
1053 std::unique_ptr<SkLatticeIter> iter,
1054 const SkRect& dst,
1055 SkFilterMode filter,
1056 const SkPaint& origPaint) {
1057 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::ganesh::Device", "drawViewLattice", fContext.get());
1058 SkASSERT(view);
1059
1060 SkTCopyOnFirstWrite<SkPaint> paint(&origPaint);
1061
1062 if (!info.isAlphaOnly() && (paint->getColor() & 0x00FFFFFF) != 0x00FFFFFF) {
1063 paint.writable()->setColor(SkColorSetARGB(origPaint.getAlpha(), 0xFF, 0xFF, 0xFF));
1064 }
1065 GrPaint grPaint;
1066 // Passing null as shaderFP indicates that the GP will provide the shader.
1067 if (!SkPaintToGrPaintReplaceShader(this->recordingContext(),
1068 fSurfaceDrawContext->colorInfo(),
1069 *paint,
1070 this->localToDevice(),
1071 /*shaderFP=*/nullptr,
1072 fSurfaceDrawContext->surfaceProps(),
1073 &grPaint)) {
1074 return;
1075 }
1076
1077 if (info.isAlphaOnly()) {
1078 // If we were doing this with an FP graph we'd use a kDstIn blend between the texture
1079 // and the paint color.
1080 view.concatSwizzle(skgpu::Swizzle("aaaa"));
1081 }
1082 auto csxf = GrColorSpaceXform::Make(info, fSurfaceDrawContext->colorInfo());
1083
1084 fSurfaceDrawContext->drawImageLattice(this->clip(),
1085 std::move(grPaint),
1086 this->localToDevice(),
1087 std::move(view),
1088 info.alphaType(),
1089 std::move(csxf),
1090 filter,
1091 std::move(iter),
1092 dst);
1093 }
1094
drawImageLattice(const SkImage * image,const SkCanvas::Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint & paint)1095 void Device::drawImageLattice(const SkImage* image,
1096 const SkCanvas::Lattice& lattice,
1097 const SkRect& dst,
1098 SkFilterMode filter,
1099 const SkPaint& paint) {
1100 ASSERT_SINGLE_OWNER
1101 auto iter = std::make_unique<SkLatticeIter>(lattice, dst);
1102
1103 auto [view, ct] = skgpu::ganesh::AsView(this->recordingContext(), image, skgpu::Mipmapped::kNo);
1104 if (view) {
1105 GrColorInfo colorInfo(ct, image->alphaType(), image->refColorSpace());
1106 this->drawViewLattice(
1107 std::move(view), std::move(colorInfo), std::move(iter), dst, filter, paint);
1108 }
1109 }
1110
drawVertices(const SkVertices * vertices,sk_sp<SkBlender> blender,const SkPaint & paint,bool skipColorXform)1111 void Device::drawVertices(const SkVertices* vertices,
1112 sk_sp<SkBlender> blender,
1113 const SkPaint& paint,
1114 bool skipColorXform) {
1115 ASSERT_SINGLE_OWNER
1116 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::ganesh::Device", "drawVertices", fContext.get());
1117 SkASSERT(vertices);
1118
1119 #ifdef SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER
1120 if (!paint.getShader()) {
1121 blender = SkBlender::Mode(SkBlendMode::kDst);
1122 }
1123 #endif
1124
1125 SkVerticesPriv info(vertices->priv());
1126
1127 GrPaint grPaint;
1128 if (!init_vertices_paint(fContext.get(),
1129 fSurfaceDrawContext->colorInfo(),
1130 paint,
1131 this->localToDevice(),
1132 blender.get(),
1133 info.hasColors(),
1134 fSurfaceDrawContext->surfaceProps(),
1135 &grPaint)) {
1136 return;
1137 }
1138 fSurfaceDrawContext->drawVertices(this->clip(),
1139 std::move(grPaint),
1140 this->localToDevice(),
1141 sk_ref_sp(const_cast<SkVertices*>(vertices)),
1142 nullptr,
1143 skipColorXform);
1144 }
1145
drawMesh(const SkMesh & mesh,sk_sp<SkBlender> blender,const SkPaint & paint)1146 void Device::drawMesh(const SkMesh& mesh, sk_sp<SkBlender> blender, const SkPaint& paint) {
1147 ASSERT_SINGLE_OWNER
1148 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::ganesh::Device", "drawMesh", fContext.get());
1149 if (!mesh.isValid()) {
1150 return;
1151 }
1152
1153 GrPaint grPaint;
1154 if (!init_vertices_paint(fContext.get(),
1155 fSurfaceDrawContext->colorInfo(),
1156 paint,
1157 this->localToDevice(),
1158 blender.get(),
1159 SkMeshSpecificationPriv::HasColors(*mesh.spec()),
1160 fSurfaceDrawContext->surfaceProps(),
1161 &grPaint)) {
1162 return;
1163 }
1164
1165 TArray<std::unique_ptr<GrFragmentProcessor>> meshChildFPs;
1166 if (!init_mesh_child_effects(fContext.get(),
1167 fSurfaceDrawContext->colorInfo(),
1168 fSurfaceDrawContext->surfaceProps(),
1169 mesh,
1170 &meshChildFPs)) {
1171 return;
1172 }
1173 fSurfaceDrawContext->drawMesh(this->clip(), std::move(grPaint), this->localToDevice(), mesh,
1174 std::move(meshChildFPs));
1175 }
1176
1177 ///////////////////////////////////////////////////////////////////////////////
1178
1179 #if !defined(SK_ENABLE_OPTIMIZE_SIZE)
drawShadow(const SkPath & path,const SkDrawShadowRec & rec)1180 void Device::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
1181 #if defined(GPU_TEST_UTILS)
1182 if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
1183 this->drawShadow(SkPath(path).setIsVolatile(true), rec);
1184 return;
1185 }
1186 #endif
1187 ASSERT_SINGLE_OWNER
1188 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::ganesh::Device", "drawShadow", fContext.get());
1189
1190 if (!fSurfaceDrawContext->drawFastShadow(this->clip(), this->localToDevice(), path, rec)) {
1191 // failed to find an accelerated case
1192 this->SkDevice::drawShadow(path, rec);
1193 }
1194 }
1195 #endif // SK_ENABLE_OPTIMIZE_SIZE
1196
1197 ///////////////////////////////////////////////////////////////////////////////
1198
drawAtlas(const SkRSXform xform[],const SkRect texRect[],const SkColor colors[],int count,sk_sp<SkBlender> blender,const SkPaint & paint)1199 void Device::drawAtlas(const SkRSXform xform[],
1200 const SkRect texRect[],
1201 const SkColor colors[],
1202 int count,
1203 sk_sp<SkBlender> blender,
1204 const SkPaint& paint) {
1205 ASSERT_SINGLE_OWNER
1206 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::ganesh::Device", "drawAtlas", fContext.get());
1207
1208 GrPaint grPaint;
1209 if (colors) {
1210 if (!SkPaintToGrPaintWithBlend(this->recordingContext(),
1211 fSurfaceDrawContext->colorInfo(),
1212 paint,
1213 this->localToDevice(),
1214 blender.get(),
1215 fSurfaceDrawContext->surfaceProps(),
1216 &grPaint)) {
1217 return;
1218 }
1219 } else {
1220 if (!SkPaintToGrPaint(this->recordingContext(),
1221 fSurfaceDrawContext->colorInfo(),
1222 paint,
1223 this->localToDevice(),
1224 fSurfaceDrawContext->surfaceProps(),
1225 &grPaint)) {
1226 return;
1227 }
1228 }
1229
1230 fSurfaceDrawContext->drawAtlas(this->clip(), std::move(grPaint), this->localToDevice(), count,
1231 xform, texRect, colors);
1232 }
1233
1234 ///////////////////////////////////////////////////////////////////////////////
1235
onDrawGlyphRunList(SkCanvas * canvas,const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)1236 void Device::onDrawGlyphRunList(SkCanvas* canvas,
1237 const sktext::GlyphRunList& glyphRunList,
1238 const SkPaint& paint) {
1239 ASSERT_SINGLE_OWNER
1240 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::ganesh::Device", "drawGlyphRunList", fContext.get());
1241 SkASSERT(!glyphRunList.hasRSXForm());
1242
1243 if (glyphRunList.blob() == nullptr) {
1244 // If the glyphRunList does not have an associated text blob, then it was created by one of
1245 // the direct draw APIs (drawGlyphs, etc.). Use a Slug to draw the glyphs.
1246 auto slug = this->convertGlyphRunListToSlug(glyphRunList, paint);
1247 if (slug != nullptr) {
1248 this->drawSlug(canvas, slug.get(), paint);
1249 }
1250 } else {
1251 fSurfaceDrawContext->drawGlyphRunList(canvas,
1252 this->clip(),
1253 this->localToDevice(),
1254 glyphRunList,
1255 this->strikeDeviceInfo(),
1256 paint);
1257 }
1258 }
1259
1260 ///////////////////////////////////////////////////////////////////////////////
1261
drawDrawable(SkCanvas * canvas,SkDrawable * drawable,const SkMatrix * matrix)1262 void Device::drawDrawable(SkCanvas* canvas, SkDrawable* drawable, const SkMatrix* matrix) {
1263 ASSERT_SINGLE_OWNER
1264
1265 GrBackendApi api = this->recordingContext()->backend();
1266 if (GrBackendApi::kVulkan == api) {
1267 const SkMatrix& ctm = this->localToDevice();
1268 const SkMatrix& combinedMatrix = matrix ? SkMatrix::Concat(ctm, *matrix) : ctm;
1269 std::unique_ptr<SkDrawable::GpuDrawHandler> gpuDraw =
1270 drawable->snapGpuDrawHandler(api, combinedMatrix, this->devClipBounds(),
1271 this->imageInfo());
1272 if (gpuDraw) {
1273 fSurfaceDrawContext->drawDrawable(
1274 std::move(gpuDraw), combinedMatrix.mapRect(drawable->getBounds()));
1275 return;
1276 }
1277 }
1278 this->SkDevice::drawDrawable(canvas, drawable, matrix);
1279 }
1280
1281
1282 ///////////////////////////////////////////////////////////////////////////////
1283
readSurfaceView()1284 GrSurfaceProxyView Device::readSurfaceView() {
1285 return this->surfaceFillContext()->readSurfaceView();
1286 }
1287
targetProxy()1288 GrRenderTargetProxy* Device::targetProxy() {
1289 return this->readSurfaceView().asRenderTargetProxy();
1290 }
1291
wait(int numSemaphores,const GrBackendSemaphore * waitSemaphores,bool deleteSemaphoresAfterWait)1292 bool Device::wait(int numSemaphores,
1293 const GrBackendSemaphore* waitSemaphores,
1294 bool deleteSemaphoresAfterWait) {
1295 ASSERT_SINGLE_OWNER
1296
1297 return fSurfaceDrawContext->waitOnSemaphores(numSemaphores, waitSemaphores,
1298 deleteSemaphoresAfterWait);
1299 }
1300
discard()1301 void Device::discard() {
1302 fSurfaceDrawContext->discard();
1303 }
1304
resolveMSAA()1305 void Device::resolveMSAA() {
1306 fSurfaceDrawContext->resolveMSAA();
1307 }
1308
replaceBackingProxy(SkSurface::ContentChangeMode mode,sk_sp<GrRenderTargetProxy> newRTP,GrColorType grColorType,sk_sp<SkColorSpace> colorSpace,GrSurfaceOrigin origin,const SkSurfaceProps & props)1309 bool Device::replaceBackingProxy(SkSurface::ContentChangeMode mode,
1310 sk_sp<GrRenderTargetProxy> newRTP,
1311 GrColorType grColorType,
1312 sk_sp<SkColorSpace> colorSpace,
1313 GrSurfaceOrigin origin,
1314 const SkSurfaceProps& props) {
1315 auto sdc = SurfaceDrawContext::Make(fContext.get(), grColorType, std::move(newRTP),
1316 std::move(colorSpace), origin, props);
1317 if (!sdc) {
1318 return false;
1319 }
1320
1321 SkASSERT(sdc->dimensions() == fSurfaceDrawContext->dimensions());
1322 SkASSERT(sdc->numSamples() == fSurfaceDrawContext->numSamples());
1323 SkASSERT(sdc->asSurfaceProxy()->priv().isExact());
1324 if (mode == SkSurface::kRetain_ContentChangeMode) {
1325 if (fContext->abandoned()) {
1326 return false;
1327 }
1328
1329 SkASSERT(fSurfaceDrawContext->asTextureProxy());
1330 SkAssertResult(sdc->blitTexture(fSurfaceDrawContext->readSurfaceView(),
1331 SkIRect::MakeWH(this->width(), this->height()),
1332 SkIPoint::Make(0, 0)));
1333 }
1334
1335 fSurfaceDrawContext = std::move(sdc);
1336 return true;
1337 }
1338
replaceBackingProxy(SkSurface::ContentChangeMode mode)1339 bool Device::replaceBackingProxy(SkSurface::ContentChangeMode mode) {
1340 ASSERT_SINGLE_OWNER
1341
1342 const SkImageInfo& ii = this->imageInfo();
1343 GrRenderTargetProxy* oldRTP = this->targetProxy();
1344 GrSurfaceProxyView oldView = this->readSurfaceView();
1345
1346 auto grColorType = SkColorTypeToGrColorType(ii.colorType());
1347 auto format = fContext->priv().caps()->getDefaultBackendFormat(grColorType, GrRenderable::kYes);
1348 if (!format.isValid()) {
1349 return false;
1350 }
1351
1352 GrProxyProvider* proxyProvider = fContext->priv().proxyProvider();
1353 // This entry point is used by SkSurface_Ganesh::onCopyOnWrite so it must create a
1354 // kExact-backed render target proxy
1355 sk_sp<GrTextureProxy> proxy =
1356 proxyProvider->createProxy(format,
1357 ii.dimensions(),
1358 GrRenderable::kYes,
1359 oldRTP->numSamples(),
1360 oldView.mipmapped(),
1361 SkBackingFit::kExact,
1362 oldRTP->isBudgeted(),
1363 oldRTP->isProtected(),
1364 /*label=*/"BaseDevice_ReplaceBackingProxy");
1365 if (!proxy) {
1366 return false;
1367 }
1368
1369 return this->replaceBackingProxy(mode, sk_ref_sp(proxy->asRenderTargetProxy()),
1370 grColorType, ii.refColorSpace(), oldView.origin(),
1371 this->surfaceProps());
1372 }
1373
asyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)1374 void Device::asyncRescaleAndReadPixels(const SkImageInfo& info,
1375 const SkIRect& srcRect,
1376 RescaleGamma rescaleGamma,
1377 RescaleMode rescaleMode,
1378 ReadPixelsCallback callback,
1379 ReadPixelsContext context) {
1380 auto* sdc = fSurfaceDrawContext.get();
1381 // Context TODO: Elevate direct context requirement to public API.
1382 auto dContext = sdc->recordingContext()->asDirectContext();
1383 if (!dContext) {
1384 return;
1385 }
1386 sdc->asyncRescaleAndReadPixels(dContext, info, srcRect, rescaleGamma, rescaleMode, callback,
1387 context);
1388 }
1389
asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,bool readAlpha,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,SkISize dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)1390 void Device::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
1391 bool readAlpha,
1392 sk_sp<SkColorSpace> dstColorSpace,
1393 const SkIRect& srcRect,
1394 SkISize dstSize,
1395 RescaleGamma rescaleGamma,
1396 RescaleMode rescaleMode,
1397 ReadPixelsCallback callback,
1398 ReadPixelsContext context) {
1399 auto* sdc = fSurfaceDrawContext.get();
1400 // Context TODO: Elevate direct context requirement to public API.
1401 auto dContext = sdc->recordingContext()->asDirectContext();
1402 if (!dContext) {
1403 return;
1404 }
1405 sdc->asyncRescaleAndReadPixelsYUV420(dContext,
1406 yuvColorSpace,
1407 readAlpha,
1408 std::move(dstColorSpace),
1409 srcRect,
1410 dstSize,
1411 rescaleGamma,
1412 rescaleMode,
1413 callback,
1414 context);
1415 }
1416
1417 ///////////////////////////////////////////////////////////////////////////////
1418
createDevice(const CreateInfo & cinfo,const SkPaint *)1419 sk_sp<SkDevice> Device::createDevice(const CreateInfo& cinfo, const SkPaint*) {
1420 ASSERT_SINGLE_OWNER
1421
1422 SkSurfaceProps props =
1423 this->surfaceProps().cloneWithPixelGeometry(cinfo.fPixelGeometry);
1424
1425 SkASSERT(cinfo.fInfo.colorType() != kRGBA_1010102_SkColorType);
1426
1427 auto sdc = SurfaceDrawContext::MakeWithFallback(
1428 fContext.get(),
1429 SkColorTypeToGrColorType(cinfo.fInfo.colorType()),
1430 cinfo.fInfo.refColorSpace(),
1431 SkBackingFit::kApprox,
1432 cinfo.fInfo.dimensions(),
1433 props,
1434 fSurfaceDrawContext->numSamples(),
1435 skgpu::Mipmapped::kNo,
1436 fSurfaceDrawContext->asSurfaceProxy()->isProtected(),
1437 fSurfaceDrawContext->origin(),
1438 skgpu::Budgeted::kYes);
1439 if (!sdc) {
1440 return nullptr;
1441 }
1442
1443 // Skia's convention is to only clear a device if it is non-opaque.
1444 InitContents init = cinfo.fInfo.isOpaque() ? InitContents::kUninit : InitContents::kClear;
1445
1446 return Device::Make(std::move(sdc), cinfo.fInfo.alphaType(), init);
1447 }
1448
makeSurface(const SkImageInfo & info,const SkSurfaceProps & props)1449 sk_sp<SkSurface> Device::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1450 ASSERT_SINGLE_OWNER
1451 // TODO: Change the signature of newSurface to take a budgeted parameter.
1452 static const skgpu::Budgeted kBudgeted = skgpu::Budgeted::kNo;
1453 bool isProtected = this->targetProxy()->isProtected() == GrProtected::kYes;
1454 return SkSurfaces::RenderTarget(fContext.get(),
1455 kBudgeted,
1456 info,
1457 fSurfaceDrawContext->numSamples(),
1458 fSurfaceDrawContext->origin(),
1459 &props,
1460 /* shouldCreateWithMips= */ false,
1461 isProtected);
1462 }
1463
1464 ////////////////////////////////////////////////////////////////////////////////////
1465
android_utils_clipWithStencil()1466 bool Device::android_utils_clipWithStencil() {
1467 SkRegion clipRegion;
1468 this->android_utils_clipAsRgn(&clipRegion);
1469 if (clipRegion.isEmpty()) {
1470 return false;
1471 }
1472 auto sdc = fSurfaceDrawContext.get();
1473 SkASSERT(sdc);
1474 GrPaint grPaint;
1475 grPaint.setXPFactory(GrDisableColorXPFactory::Get());
1476 static constexpr GrUserStencilSettings kDrawToStencil(
1477 GrUserStencilSettings::StaticInit<
1478 0x1,
1479 GrUserStencilTest::kAlways,
1480 0x1,
1481 GrUserStencilOp::kReplace,
1482 GrUserStencilOp::kReplace,
1483 0x1>()
1484 );
1485 // Regions don't actually need AA, but in DMSAA mode everything is antialiased.
1486 GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias());
1487 sdc->drawRegion(nullptr, std::move(grPaint), aa, SkMatrix::I(), clipRegion,
1488 GrStyle::SimpleFill(), &kDrawToStencil);
1489 return true;
1490 }
1491
strikeDeviceInfo() const1492 SkStrikeDeviceInfo Device::strikeDeviceInfo() const {
1493 return {this->surfaceProps(), this->scalerContextFlags(), &fSubRunControl};
1494 }
1495
convertGlyphRunListToSlug(const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)1496 sk_sp<sktext::gpu::Slug> Device::convertGlyphRunListToSlug(const sktext::GlyphRunList& glyphRunList,
1497 const SkPaint& paint) {
1498 return sktext::gpu::SlugImpl::Make(this->localToDevice(),
1499 glyphRunList,
1500 paint,
1501 this->strikeDeviceInfo(),
1502 SkStrikeCache::GlobalStrikeCache());
1503 }
1504
1505 #if defined(SK_DEBUG)
valid_slug_matrices(const SkMatrix & creationMatrix,const SkMatrix & positionMatrix)1506 static bool valid_slug_matrices(const SkMatrix& creationMatrix, const SkMatrix& positionMatrix) {
1507 // A Slug can be drawn with:
1508 // The exact same matrix that was used for creation
1509 // - OR -
1510 // A non-perspective matrix that has the same 2x2 and a relative integer translation
1511 //
1512 // For the second case, calculate the translation in source space to a translation in
1513 // device space by mapping (0, 0) through both the creationMatrix and the positionMatrix;
1514 // take the difference.
1515 if (creationMatrix == positionMatrix) {
1516 return true;
1517 }
1518
1519 SkVector translation = positionMatrix.mapOrigin() - creationMatrix.mapOrigin();
1520 return creationMatrix.getScaleX() == positionMatrix.getScaleX() &&
1521 creationMatrix.getScaleY() == positionMatrix.getScaleY() &&
1522 creationMatrix.getSkewX() == positionMatrix.getSkewX() &&
1523 creationMatrix.getSkewY() == positionMatrix.getSkewY() &&
1524 !positionMatrix.hasPerspective() && !creationMatrix.hasPerspective() &&
1525 SkScalarIsInt(translation.x()) && SkScalarIsInt(translation.y());
1526 }
1527 #endif
1528
1529
drawSlug(SkCanvas * canvas,const sktext::gpu::Slug * slug,const SkPaint & paint)1530 void Device::drawSlug(SkCanvas* canvas, const sktext::gpu::Slug* slug, const SkPaint& paint) {
1531 SkASSERT(canvas);
1532 SkASSERT(slug);
1533 const sktext::gpu::SlugImpl* slugImpl = static_cast<const sktext::gpu::SlugImpl*>(slug);
1534 #if defined(SK_DEBUG)
1535 if (!fContext->priv().options().fSupportBilerpFromGlyphAtlas) {
1536 // We can draw a slug if the atlas has padding or if the creation matrix and the
1537 // drawing matrix are the same (up to integer translation).
1538 // If they are the same, then the Slug will use the direct drawing code and not use bi-lerp.
1539 SkMatrix slugMatrix = slugImpl->initialPositionMatrix();
1540 SkMatrix positionMatrix = this->localToDevice();
1541 positionMatrix.preTranslate(slugImpl->origin().x(), slugImpl->origin().y());
1542 SkASSERT(valid_slug_matrices(slugMatrix, positionMatrix));
1543 }
1544 #endif
1545 auto atlasDelegate = [&](const sktext::gpu::AtlasSubRun* subRun,
1546 SkPoint drawOrigin,
1547 const SkPaint& paint,
1548 sk_sp<SkRefCnt> subRunStorage,
1549 sktext::gpu::RendererData) {
1550 auto[drawingClip, op] = subRun->makeAtlasTextOp(
1551 this->clip(), this->localToDevice(), drawOrigin, paint,
1552 std::move(subRunStorage), fSurfaceDrawContext.get());
1553 if (op != nullptr) {
1554 fSurfaceDrawContext->addDrawOp(drawingClip, std::move(op));
1555 }
1556 };
1557
1558 slugImpl->subRuns()->draw(canvas, slugImpl->origin(), paint, slugImpl, atlasDelegate);
1559 }
1560
1561 } // namespace skgpu::ganesh
1562