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