1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/v1/Device_v1.h"
9
10 #include "include/core/SkImageFilter.h"
11 #include "include/core/SkMaskFilter.h"
12 #include "include/core/SkPathEffect.h"
13 #include "include/core/SkPicture.h"
14 #include "include/core/SkSurface.h"
15 #include "include/core/SkVertices.h"
16 #include "include/effects/SkRuntimeEffect.h"
17 #include "include/gpu/GrDirectContext.h"
18 #include "include/gpu/GrRecordingContext.h"
19 #include "include/private/SkShadowFlags.h"
20 #include "include/private/SkTo.h"
21 #include "src/core/SkCanvasPriv.h"
22 #include "src/core/SkClipStack.h"
23 #include "src/core/SkDraw.h"
24 #include "src/core/SkImageFilterCache.h"
25 #include "src/core/SkImageFilter_Base.h"
26 #include "src/core/SkLatticeIter.h"
27 #include "src/core/SkPictureData.h"
28 #include "src/core/SkRRectPriv.h"
29 #include "src/core/SkRasterClip.h"
30 #include "src/core/SkRecord.h"
31 #include "src/core/SkStroke.h"
32 #include "src/core/SkTLazy.h"
33 #include "src/core/SkVerticesPriv.h"
34 #include "src/gpu/GrBlurUtils.h"
35 #include "src/gpu/GrDirectContextPriv.h"
36 #include "src/gpu/GrGpu.h"
37 #include "src/gpu/GrRecordingContextPriv.h"
38 #include "src/gpu/GrStyle.h"
39 #include "src/gpu/GrSurfaceProxyPriv.h"
40 #include "src/gpu/GrTracing.h"
41 #include "src/gpu/SkGr.h"
42 #include "src/gpu/effects/GrDisableColorXP.h"
43 #include "src/gpu/effects/GrRRectEffect.h"
44 #include "src/gpu/geometry/GrStyledShape.h"
45 #include "src/image/SkImage_Base.h"
46 #include "src/image/SkReadPixelsRec.h"
47 #include "src/image/SkSurface_Gpu.h"
48 #include "src/utils/SkUTF.h"
49
50 #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fContext->priv().singleOwner())
51
52
53 ///////////////////////////////////////////////////////////////////////////////
54
55 namespace {
56
force_aa_clip(const skgpu::v1::SurfaceDrawContext * sdc)57 bool force_aa_clip(const skgpu::v1::SurfaceDrawContext* sdc) {
58 return sdc->numSamples() > 1 || sdc->alwaysAntialias();
59 }
60
point_mode_to_primitive_type(SkCanvas::PointMode mode)61 inline GrPrimitiveType point_mode_to_primitive_type(SkCanvas::PointMode mode) {
62 switch (mode) {
63 case SkCanvas::kPoints_PointMode:
64 return GrPrimitiveType::kPoints;
65 case SkCanvas::kLines_PointMode:
66 return GrPrimitiveType::kLines;
67 case SkCanvas::kPolygon_PointMode:
68 return GrPrimitiveType::kLineStrip;
69 }
70 SK_ABORT("Unexpected mode");
71 }
72
make_inverse_rrect_fp(const SkMatrix & viewMatrix,const SkRRect & rrect,GrAA aa,const GrShaderCaps & shaderCaps)73 std::unique_ptr<GrFragmentProcessor> make_inverse_rrect_fp(const SkMatrix& viewMatrix,
74 const SkRRect& rrect, GrAA aa,
75 const GrShaderCaps& shaderCaps) {
76 SkTCopyOnFirstWrite<SkRRect> devRRect(rrect);
77 if (viewMatrix.isIdentity() || rrect.transform(viewMatrix, devRRect.writable())) {
78 auto edgeType = (aa == GrAA::kYes) ? GrClipEdgeType::kInverseFillAA
79 : GrClipEdgeType::kInverseFillBW;
80 auto [success, fp] = GrRRectEffect::Make(/*inputFP=*/nullptr, edgeType, *devRRect,
81 shaderCaps);
82 return (success) ? std::move(fp) : nullptr;
83 }
84 return nullptr;
85 }
86
init_vertices_paint(GrRecordingContext * rContext,const GrColorInfo & colorInfo,const SkPaint & skPaint,const SkMatrixProvider & matrixProvider,SkBlendMode bmode,bool hasColors,GrPaint * grPaint)87 bool init_vertices_paint(GrRecordingContext* rContext,
88 const GrColorInfo& colorInfo,
89 const SkPaint& skPaint,
90 const SkMatrixProvider& matrixProvider,
91 SkBlendMode bmode,
92 bool hasColors,
93 GrPaint* grPaint) {
94 if (hasColors) {
95 // When there are colors and a shader, the shader and colors are combined using bmode.
96 // With no shader, we just use the colors (kDst).
97 return SkPaintToGrPaintWithBlend(rContext,
98 colorInfo,
99 skPaint,
100 matrixProvider,
101 skPaint.getShader() ? bmode : SkBlendMode::kDst,
102 grPaint);
103 } else {
104 return SkPaintToGrPaint(rContext, colorInfo, skPaint, matrixProvider, grPaint);
105 }
106 }
107
108 } // anonymous namespace
109
110 namespace skgpu::v1 {
111
Make(GrRecordingContext * rContext,GrColorType colorType,sk_sp<GrSurfaceProxy> proxy,sk_sp<SkColorSpace> colorSpace,GrSurfaceOrigin origin,const SkSurfaceProps & surfaceProps,InitContents init)112 sk_sp<BaseDevice> Device::Make(GrRecordingContext* rContext,
113 GrColorType colorType,
114 sk_sp<GrSurfaceProxy> proxy,
115 sk_sp<SkColorSpace> colorSpace,
116 GrSurfaceOrigin origin,
117 const SkSurfaceProps& surfaceProps,
118 InitContents init) {
119 auto sdc = SurfaceDrawContext::Make(rContext,
120 colorType,
121 std::move(proxy),
122 std::move(colorSpace),
123 origin,
124 surfaceProps);
125
126 return Device::Make(std::move(sdc), kPremul_SkAlphaType, init);
127 }
128
Make(std::unique_ptr<SurfaceDrawContext> sdc,SkAlphaType alphaType,InitContents init)129 sk_sp<BaseDevice> Device::Make(std::unique_ptr<SurfaceDrawContext> sdc,
130 SkAlphaType alphaType,
131 InitContents init) {
132 if (!sdc) {
133 return nullptr;
134 }
135
136 GrRecordingContext* rContext = sdc->recordingContext();
137 if (rContext->abandoned()) {
138 return nullptr;
139 }
140
141 SkColorType ct = GrColorTypeToSkColorType(sdc->colorInfo().colorType());
142
143 DeviceFlags flags;
144 if (!rContext->colorTypeSupportedAsSurface(ct) ||
145 !CheckAlphaTypeAndGetFlags(alphaType, init, &flags)) {
146 return nullptr;
147 }
148 return sk_sp<Device>(new Device(std::move(sdc), flags));
149 }
150
Make(GrRecordingContext * rContext,SkBudgeted budgeted,const SkImageInfo & ii,SkBackingFit fit,int sampleCount,GrMipmapped mipMapped,GrProtected isProtected,GrSurfaceOrigin origin,const SkSurfaceProps & props,InitContents init)151 sk_sp<BaseDevice> Device::Make(GrRecordingContext* rContext,
152 SkBudgeted budgeted,
153 const SkImageInfo& ii,
154 SkBackingFit fit,
155 int sampleCount,
156 GrMipmapped mipMapped,
157 GrProtected isProtected,
158 GrSurfaceOrigin origin,
159 const SkSurfaceProps& props,
160 InitContents init) {
161 if (!rContext) {
162 return nullptr;
163 }
164
165 auto sdc = SurfaceDrawContext::Make(rContext,
166 SkColorTypeToGrColorType(ii.colorType()),
167 ii.refColorSpace(),
168 fit,
169 ii.dimensions(),
170 props,
171 sampleCount,
172 mipMapped,
173 isProtected,
174 origin,
175 budgeted);
176
177 return Device::Make(std::move(sdc), ii.alphaType(), init);
178 }
179
Device(std::unique_ptr<SurfaceDrawContext> sdc,DeviceFlags flags)180 Device::Device(std::unique_ptr<SurfaceDrawContext> sdc, DeviceFlags flags)
181 : INHERITED(sk_ref_sp(sdc->recordingContext()),
182 MakeInfo(sdc.get(), flags),
183 sdc->surfaceProps())
184 , fSurfaceDrawContext(std::move(sdc))
185 , fClip(SkIRect::MakeSize(fSurfaceDrawContext->dimensions()),
186 &this->asMatrixProvider(),
187 force_aa_clip(fSurfaceDrawContext.get())) {
188 if (flags & DeviceFlags::kNeedClear) {
189 this->clearAll();
190 }
191 }
192
193 ///////////////////////////////////////////////////////////////////////////////
194
onReadPixels(const SkPixmap & pm,int x,int y)195 bool Device::onReadPixels(const SkPixmap& pm, int x, int y) {
196 ASSERT_SINGLE_OWNER
197
198 // Context TODO: Elevate direct context requirement to public API
199 auto dContext = fContext->asDirectContext();
200 if (!dContext || !SkImageInfoValidConversion(pm.info(), this->imageInfo())) {
201 return false;
202 }
203
204 return fSurfaceDrawContext->readPixels(dContext, pm, {x, y});
205 }
206
onWritePixels(const SkPixmap & pm,int x,int y)207 bool Device::onWritePixels(const SkPixmap& pm, int x, int y) {
208 ASSERT_SINGLE_OWNER
209
210 // Context TODO: Elevate direct context requirement to public API
211 auto dContext = fContext->asDirectContext();
212 if (!dContext || !SkImageInfoValidConversion(this->imageInfo(), pm.info())) {
213 return false;
214 }
215
216 return fSurfaceDrawContext->writePixels(dContext, pm, {x, y});
217 }
218
onAccessPixels(SkPixmap * pmap)219 bool Device::onAccessPixels(SkPixmap* pmap) {
220 ASSERT_SINGLE_OWNER
221 return false;
222 }
223
surfaceDrawContext()224 SurfaceDrawContext* Device::surfaceDrawContext() {
225 ASSERT_SINGLE_OWNER
226 return fSurfaceDrawContext.get();
227 }
228
surfaceDrawContext() const229 const SurfaceDrawContext* Device::surfaceDrawContext() const {
230 ASSERT_SINGLE_OWNER
231 return fSurfaceDrawContext.get();
232 }
233
surfaceFillContext()234 skgpu::SurfaceFillContext* Device::surfaceFillContext() {
235 ASSERT_SINGLE_OWNER
236 return fSurfaceDrawContext.get();
237 }
238
clearAll()239 void Device::clearAll() {
240 ASSERT_SINGLE_OWNER
241 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "clearAll", fContext.get());
242
243 SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
244 fSurfaceDrawContext->clearAtLeast(rect, SK_PMColor4fTRANSPARENT);
245 }
246
247 ///////////////////////////////////////////////////////////////////////////////
248
onClipPath(const SkPath & path,SkClipOp op,bool aa)249 void Device::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
250 #if GR_TEST_UTILS
251 if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
252 this->onClipPath(SkPath(path).setIsVolatile(true), op, aa);
253 return;
254 }
255 #endif
256 SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
257 fClip.clipPath(this->localToDevice(), path, GrAA(aa), op);
258 }
259
260 #ifdef SK_ENABLE_STENCIL_CULLING_OHOS
clearStencil(const SkIRect & rect,uint32_t stencilVal)261 void Device::clearStencil(const SkIRect& rect, uint32_t stencilVal) {
262 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "clearStencil", fContext.get());
263 fSurfaceDrawContext->clearStencil(rect, stencilVal);
264 }
265 #endif
266
onClipRegion(const SkRegion & globalRgn,SkClipOp op)267 void Device::onClipRegion(const SkRegion& globalRgn, SkClipOp op) {
268 SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
269
270 // Regions don't actually need AA, but in DMSAA mode every clip element is antialiased.
271 GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias());
272
273 if (globalRgn.isEmpty()) {
274 fClip.clipRect(SkMatrix::I(), SkRect::MakeEmpty(), aa, op);
275 } else if (globalRgn.isRect()) {
276 fClip.clipRect(this->globalToDevice().asM33(), SkRect::Make(globalRgn.getBounds()), aa, op);
277 } else {
278 SkPath path;
279 globalRgn.getBoundaryPath(&path);
280 fClip.clipPath(this->globalToDevice().asM33(), path, aa, op);
281 }
282 }
283
onAsRgnClip(SkRegion * region) const284 void Device::onAsRgnClip(SkRegion* region) const {
285 SkIRect bounds = fClip.getConservativeBounds();
286 // Assume wide open and then perform intersect/difference operations reducing the region
287 region->setRect(bounds);
288 const SkRegion deviceBounds(bounds);
289 for (const ClipStack::Element& e : fClip) {
290 SkRegion tmp;
291 if (e.fShape.isRect() && e.fLocalToDevice.isIdentity()) {
292 tmp.setRect(e.fShape.rect().roundOut());
293 } else {
294 SkPath tmpPath;
295 e.fShape.asPath(&tmpPath);
296 tmpPath.transform(e.fLocalToDevice);
297 tmp.setPath(tmpPath, deviceBounds);
298 }
299
300 region->op(tmp, (SkRegion::Op) e.fOp);
301 }
302 }
303
onClipIsAA() const304 bool Device::onClipIsAA() const {
305 for (const ClipStack::Element& e : fClip) {
306 if (e.fAA == GrAA::kYes) {
307 return true;
308 }
309 SkASSERT(!fSurfaceDrawContext->alwaysAntialias());
310 }
311 return false;
312 }
313
onGetClipType() const314 SkBaseDevice::ClipType Device::onGetClipType() const {
315 ClipStack::ClipState state = fClip.clipState();
316 if (state == ClipStack::ClipState::kEmpty) {
317 return ClipType::kEmpty;
318 } else if (state == ClipStack::ClipState::kDeviceRect ||
319 state == ClipStack::ClipState::kWideOpen) {
320 return ClipType::kRect;
321 } else {
322 return ClipType::kComplex;
323 }
324 }
325
326 ///////////////////////////////////////////////////////////////////////////////
327
drawPaint(const SkPaint & paint)328 void Device::drawPaint(const SkPaint& paint) {
329 ASSERT_SINGLE_OWNER
330 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPaint", fContext.get());
331
332 GrPaint grPaint;
333 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
334 this->asMatrixProvider(), &grPaint)) {
335 return;
336 }
337
338 fSurfaceDrawContext->drawPaint(this->clip(), std::move(grPaint), this->localToDevice());
339 }
340
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)341 void Device::drawPoints(SkCanvas::PointMode mode,
342 size_t count,
343 const SkPoint pts[],
344 const SkPaint& paint) {
345 ASSERT_SINGLE_OWNER
346 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPoints", fContext.get());
347 SkScalar width = paint.getStrokeWidth();
348 if (width < 0) {
349 return;
350 }
351
352 GrAA aa = fSurfaceDrawContext->chooseAA(paint);
353
354 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
355 GrStyle style(paint, SkPaint::kStroke_Style);
356 GrPaint grPaint;
357 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
358 this->asMatrixProvider(), &grPaint)) {
359 return;
360 }
361 SkPath path;
362 path.setIsVolatile(true);
363 path.moveTo(pts[0]);
364 path.lineTo(pts[1]);
365 fSurfaceDrawContext->drawPath(this->clip(), std::move(grPaint), aa, this->localToDevice(),
366 path, style);
367 return;
368 }
369
370 SkScalar scales[2];
371 bool isHairline = (0 == width) ||
372 (1 == width && this->localToDevice().getMinMaxScales(scales) &&
373 SkScalarNearlyEqual(scales[0], 1.f) && SkScalarNearlyEqual(scales[1], 1.f));
374 // we only handle non-coverage-aa hairlines and paints without path effects or mask filters,
375 // else we let the SkDraw call our drawPath()
376 if (!isHairline ||
377 paint.getPathEffect() ||
378 paint.getMaskFilter() ||
379 fSurfaceDrawContext->chooseAAType(aa) == GrAAType::kCoverage) {
380 SkRasterClip rc(this->devClipBounds());
381 SkDraw draw;
382 draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0);
383 draw.fMatrixProvider = this;
384 draw.fRC = &rc;
385 draw.drawPoints(mode, count, pts, paint, this);
386 return;
387 }
388
389 GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode);
390
391 const SkMatrixProvider* matrixProvider = this;
392 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
393 SkTLazy<SkPostTranslateMatrixProvider> postTranslateMatrixProvider;
394 // This offsetting in device space matches the expectations of the Android framework for non-AA
395 // points and lines.
396 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
397 static const SkScalar kOffset = 0.063f; // Just greater than 1/16.
398 matrixProvider = postTranslateMatrixProvider.init(*matrixProvider, kOffset, kOffset);
399 }
400 #endif
401
402 GrPaint grPaint;
403 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
404 *matrixProvider, &grPaint)) {
405 return;
406 }
407
408 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
409 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr,
410 nullptr);
411
412 fSurfaceDrawContext->drawVertices(this->clip(), std::move(grPaint), *matrixProvider,
413 std::move(vertices), &primitiveType);
414 }
415
416 ///////////////////////////////////////////////////////////////////////////////
417
drawRect(const SkRect & rect,const SkPaint & paint)418 void Device::drawRect(const SkRect& rect, const SkPaint& paint) {
419 ASSERT_SINGLE_OWNER
420 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRect", fContext.get());
421
422 GrStyle style(paint);
423
424 // A couple reasons we might need to call drawPath.
425 if (paint.getMaskFilter() || paint.getPathEffect()) {
426 GrStyledShape shape(rect, style);
427
428 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(),
429 this->clip(), paint, this->asMatrixProvider(), shape);
430 return;
431 }
432
433 GrPaint grPaint;
434 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
435 this->asMatrixProvider(), &grPaint)) {
436 return;
437 }
438
439 fSurfaceDrawContext->drawRect(this->clip(), std::move(grPaint),
440 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), rect,
441 &style);
442 }
443
drawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],SkCanvas::QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)444 void Device::drawEdgeAAQuad(const SkRect& rect,
445 const SkPoint clip[4],
446 SkCanvas::QuadAAFlags aaFlags,
447 const SkColor4f& color,
448 SkBlendMode mode) {
449 ASSERT_SINGLE_OWNER
450 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawEdgeAAQuad", fContext.get());
451
452 SkPMColor4f dstColor = SkColor4fPrepForDst(color, fSurfaceDrawContext->colorInfo()).premul();
453
454 GrPaint grPaint;
455 grPaint.setColor4f(dstColor);
456 if (mode != SkBlendMode::kSrcOver) {
457 grPaint.setXPFactory(SkBlendMode_AsXPFactory(mode));
458 }
459
460 // This is exclusively meant for tiling operations, so keep AA enabled to handle MSAA seaming
461 GrQuadAAFlags grAA = SkToGrQuadAAFlags(aaFlags);
462 if (clip) {
463 // Use fillQuadWithEdgeAA
464 fSurfaceDrawContext->fillQuadWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA,
465 this->localToDevice(), clip, nullptr);
466 } else {
467 // Use fillRectWithEdgeAA to preserve mathematical properties of dst being rectangular
468 fSurfaceDrawContext->fillRectWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA,
469 this->localToDevice(), rect);
470 }
471 }
472
473 ///////////////////////////////////////////////////////////////////////////////
474
drawRRect(const SkRRect & rrect,const SkPaint & paint)475 void Device::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
476 ASSERT_SINGLE_OWNER
477 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRRect", fContext.get());
478
479 SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter());
480 if (mf) {
481 if (mf->hasFragmentProcessor()) {
482 mf = nullptr; // already handled in SkPaintToGrPaint
483 }
484 }
485
486 GrStyle style(paint);
487
488 if (mf || style.pathEffect()) {
489 // A path effect will presumably transform this rrect into something else.
490 GrStyledShape shape(rrect, style);
491
492 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(),
493 this->clip(), paint, this->asMatrixProvider(), shape);
494 return;
495 }
496
497 SkASSERT(!style.pathEffect());
498
499 GrPaint grPaint;
500 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
501 this->asMatrixProvider(), &grPaint)) {
502 return;
503 }
504
505 fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint),
506 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
507 rrect, style);
508 }
509
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)510 void Device::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
511 ASSERT_SINGLE_OWNER
512 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDRRect", fContext.get());
513 if (outer.isEmpty()) {
514 return;
515 }
516
517 if (inner.isEmpty()) {
518 return this->drawRRect(outer, paint);
519 }
520
521 SkStrokeRec stroke(paint);
522
523 if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
524 // For axis-aligned filled DRRects, just draw a regular rrect with inner clipped out using a
525 // coverage FP instead of using path rendering.
526 if (auto fp = make_inverse_rrect_fp(this->localToDevice(), inner,
527 fSurfaceDrawContext->chooseAA(paint),
528 *fSurfaceDrawContext->caps()->shaderCaps())) {
529 GrPaint grPaint;
530 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
531 this->asMatrixProvider(), &grPaint)) {
532 return;
533 }
534 SkASSERT(!grPaint.hasCoverageFragmentProcessor());
535 grPaint.setCoverageFragmentProcessor(std::move(fp));
536 fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint),
537 fSurfaceDrawContext->chooseAA(paint),
538 this->localToDevice(), outer, GrStyle());
539 return;
540 }
541 }
542
543 SkPath path;
544 path.setIsVolatile(true);
545 path.addRRect(outer);
546 path.addRRect(inner);
547 path.setFillType(SkPathFillType::kEvenOdd);
548
549 // TODO: We are losing the possible mutability of the path here but this should probably be
550 // fixed by upgrading GrStyledShape to handle DRRects.
551 GrStyledShape shape(path, paint);
552
553 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(),
554 paint, this->asMatrixProvider(), shape);
555 }
556
557 /////////////////////////////////////////////////////////////////////////////
558
drawRegion(const SkRegion & region,const SkPaint & paint)559 void Device::drawRegion(const SkRegion& region, const SkPaint& paint) {
560 ASSERT_SINGLE_OWNER
561
562 if (paint.getMaskFilter()) {
563 SkPath path;
564 region.getBoundaryPath(&path);
565 path.setIsVolatile(true);
566 return this->drawPath(path, paint, true);
567 }
568
569 GrPaint grPaint;
570 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
571 this->asMatrixProvider(), &grPaint)) {
572 return;
573 }
574
575 fSurfaceDrawContext->drawRegion(this->clip(), std::move(grPaint),
576 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
577 region, GrStyle(paint));
578 }
579
drawOval(const SkRect & oval,const SkPaint & paint)580 void Device::drawOval(const SkRect& oval, const SkPaint& paint) {
581 ASSERT_SINGLE_OWNER
582 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawOval", fContext.get());
583
584 if (paint.getMaskFilter()) {
585 // The RRect path can handle special case blurring
586 SkRRect rr = SkRRect::MakeOval(oval);
587 return this->drawRRect(rr, paint);
588 }
589
590 GrPaint grPaint;
591 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
592 this->asMatrixProvider(), &grPaint)) {
593 return;
594 }
595
596 fSurfaceDrawContext->drawOval(this->clip(), std::move(grPaint),
597 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval,
598 GrStyle(paint));
599 }
600
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)601 void Device::drawArc(const SkRect& oval,
602 SkScalar startAngle,
603 SkScalar sweepAngle,
604 bool useCenter,
605 const SkPaint& paint) {
606 ASSERT_SINGLE_OWNER
607 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawArc", fContext.get());
608 if (paint.getMaskFilter()) {
609 this->INHERITED::drawArc(oval, startAngle, sweepAngle, useCenter, paint);
610 return;
611 }
612 GrPaint grPaint;
613 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
614 this->asMatrixProvider(), &grPaint)) {
615 return;
616 }
617
618 fSurfaceDrawContext->drawArc(this->clip(), std::move(grPaint),
619 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval,
620 startAngle, sweepAngle, useCenter, GrStyle(paint));
621 }
622
623 ///////////////////////////////////////////////////////////////////////////////
624
drawPath(const SkPath & origSrcPath,const SkPaint & paint,bool pathIsMutable)625 void Device::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool pathIsMutable) {
626 #if GR_TEST_UTILS
627 if (fContext->priv().options().fAllPathsVolatile && !origSrcPath.isVolatile()) {
628 this->drawPath(SkPath(origSrcPath).setIsVolatile(true), paint, true);
629 return;
630 }
631 #endif
632 ASSERT_SINGLE_OWNER
633 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPath", fContext.get());
634 if (!paint.getMaskFilter()) {
635 GrPaint grPaint;
636 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
637 this->asMatrixProvider(), &grPaint)) {
638 return;
639 }
640 fSurfaceDrawContext->drawPath(this->clip(), std::move(grPaint),
641 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(),
642 origSrcPath, GrStyle(paint));
643 return;
644 }
645
646 // TODO: losing possible mutability of 'origSrcPath' here
647 GrStyledShape shape(origSrcPath, paint);
648
649 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(),
650 paint, this->asMatrixProvider(), shape);
651 }
652
653 #ifdef SK_ENABLE_STENCIL_CULLING_OHOS
drawPathWithStencil(const SkPath & origSrcPath,const SkPaint & paint,uint32_t stencilRef,bool pathIsMutable)654 void Device::drawPathWithStencil(const SkPath& origSrcPath, const SkPaint& paint, uint32_t stencilRef,
655 bool pathIsMutable) {
656 fSurfaceDrawContext->setStencilRef(stencilRef);
657 this->drawPath(origSrcPath, paint, false);
658 fSurfaceDrawContext->resetStencilRef();
659 }
660 #endif
661
makeSpecial(const SkBitmap & bitmap)662 sk_sp<SkSpecialImage> Device::makeSpecial(const SkBitmap& bitmap) {
663 ASSERT_SINGLE_OWNER
664
665 // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's
666 // semantics). Since this is cached we would have to bake the fit into the cache key though.
667 auto view = std::get<0>(GrMakeCachedBitmapProxyView(fContext.get(), bitmap));
668 if (!view) {
669 return nullptr;
670 }
671
672 const SkIRect rect = SkIRect::MakeSize(view.proxy()->dimensions());
673
674 // GrMakeCachedBitmapProxyView creates a tight copy of 'bitmap' so we don't have to subset
675 // the special image
676 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
677 rect,
678 bitmap.getGenerationID(),
679 std::move(view),
680 SkColorTypeToGrColorType(bitmap.colorType()),
681 bitmap.refColorSpace(),
682 this->surfaceProps());
683 }
684
makeSpecial(const SkImage * image)685 sk_sp<SkSpecialImage> Device::makeSpecial(const SkImage* image) {
686 ASSERT_SINGLE_OWNER
687
688 SkPixmap pm;
689 if (image->isTextureBacked()) {
690 auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo);
691 SkASSERT(view);
692
693 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
694 SkIRect::MakeWH(image->width(), image->height()),
695 image->uniqueID(),
696 std::move(view),
697 ct,
698 image->refColorSpace(),
699 this->surfaceProps());
700 } else if (image->peekPixels(&pm)) {
701 SkBitmap bm;
702
703 bm.installPixels(pm);
704 return this->makeSpecial(bm);
705 } else {
706 return nullptr;
707 }
708 }
709
snapSpecial(const SkIRect & subset,bool forceCopy)710 sk_sp<SkSpecialImage> Device::snapSpecial(const SkIRect& subset, bool forceCopy) {
711 ASSERT_SINGLE_OWNER
712
713 auto sdc = fSurfaceDrawContext.get();
714
715 // If we are wrapping a vulkan secondary command buffer, then we can't snap off a special image
716 // since it would require us to make a copy of the underlying VkImage which we don't have access
717 // to. Additionaly we can't stop and start the render pass that is used with the secondary
718 // command buffer.
719 if (sdc->wrapsVkSecondaryCB()) {
720 return nullptr;
721 }
722
723 SkASSERT(sdc->asSurfaceProxy());
724
725 SkIRect finalSubset = subset;
726 GrSurfaceProxyView view = sdc->readSurfaceView();
727 if (forceCopy || !view.asTextureProxy()) {
728 // When the device doesn't have a texture, or a copy is requested, we create a temporary
729 // texture that matches the device contents
730 view = GrSurfaceProxyView::Copy(fContext.get(),
731 std::move(view),
732 GrMipmapped::kNo, // Don't auto generate mips
733 subset,
734 SkBackingFit::kApprox,
735 SkBudgeted::kYes); // Always budgeted
736 if (!view) {
737 return nullptr;
738 }
739 // Since this copied only the requested subset, the special image wrapping the proxy no
740 // longer needs the original subset.
741 finalSubset = SkIRect::MakeSize(view.dimensions());
742 }
743
744 GrColorType ct = SkColorTypeToGrColorType(this->imageInfo().colorType());
745
746 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
747 finalSubset,
748 kNeedNewImageUniqueID_SpecialImage,
749 std::move(view),
750 ct,
751 this->imageInfo().refColorSpace(),
752 this->surfaceProps());
753 }
754
drawDevice(SkBaseDevice * device,const SkSamplingOptions & sampling,const SkPaint & paint)755 void Device::drawDevice(SkBaseDevice* device,
756 const SkSamplingOptions& sampling,
757 const SkPaint& paint) {
758 ASSERT_SINGLE_OWNER
759 // clear of the source device must occur before CHECK_SHOULD_DRAW
760 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDevice", fContext.get());
761 this->INHERITED::drawDevice(device, sampling, paint);
762 }
763
764 #ifdef SK_ENABLE_STENCIL_CULLING_OHOS
drawImageRectWithStencil(const SkImage * image,const SkRect * src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint,uint32_t stencilRef)765 void Device::drawImageRectWithStencil(const SkImage* image,
766 const SkRect* src,
767 const SkRect& dst,
768 const SkSamplingOptions& sampling,
769 const SkPaint& paint,
770 SkCanvas::SrcRectConstraint constraint,
771 uint32_t stencilRef) {
772 fSurfaceDrawContext->setStencilRef(stencilRef);
773 this->drawImageRect(image, src, dst, sampling, paint, constraint);
774 fSurfaceDrawContext->resetStencilRef();
775 }
776 #endif
777
drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)778 void Device::drawImageRect(const SkImage* image,
779 const SkRect* src,
780 const SkRect& dst,
781 const SkSamplingOptions& sampling,
782 const SkPaint& paint,
783 SkCanvas::SrcRectConstraint constraint) {
784 ASSERT_SINGLE_OWNER
785 GrAA aa = fSurfaceDrawContext->chooseAA(paint);
786 GrQuadAAFlags aaFlags = (aa == GrAA::kYes) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
787 this->drawImageQuad(image, src, &dst, nullptr, aa, aaFlags, nullptr, sampling, paint,
788 constraint);
789 }
790
drawViewLattice(GrSurfaceProxyView view,const GrColorInfo & info,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst,SkFilterMode filter,const SkPaint & origPaint)791 void Device::drawViewLattice(GrSurfaceProxyView view,
792 const GrColorInfo& info,
793 std::unique_ptr<SkLatticeIter> iter,
794 const SkRect& dst,
795 SkFilterMode filter,
796 const SkPaint& origPaint) {
797 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawViewLattice", fContext.get());
798 SkASSERT(view);
799
800 SkTCopyOnFirstWrite<SkPaint> paint(&origPaint);
801
802 if (!info.isAlphaOnly() && (paint->getColor() & 0x00FFFFFF) != 0x00FFFFFF) {
803 paint.writable()->setColor(SkColorSetARGB(origPaint.getAlpha(), 0xFF, 0xFF, 0xFF));
804 }
805 GrPaint grPaint;
806 if (!SkPaintToGrPaintWithPrimitiveColor(this->recordingContext(),
807 fSurfaceDrawContext->colorInfo(), *paint,
808 this->asMatrixProvider(), &grPaint)) {
809 return;
810 }
811
812 if (info.isAlphaOnly()) {
813 // If we were doing this with an FP graph we'd use a kDstIn blend between the texture and
814 // the paint color.
815 view.concatSwizzle(GrSwizzle("aaaa"));
816 }
817 auto csxf = GrColorSpaceXform::Make(info, fSurfaceDrawContext->colorInfo());
818
819 fSurfaceDrawContext->drawImageLattice(this->clip(), std::move(grPaint), this->localToDevice(),
820 std::move(view), info.alphaType(), std::move(csxf),
821 filter, std::move(iter), dst);
822 }
823
drawImageLattice(const SkImage * image,const SkCanvas::Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint & paint)824 void Device::drawImageLattice(const SkImage* image,
825 const SkCanvas::Lattice& lattice,
826 const SkRect& dst,
827 SkFilterMode filter,
828 const SkPaint& paint) {
829 ASSERT_SINGLE_OWNER
830 auto iter = std::make_unique<SkLatticeIter>(lattice, dst);
831 if (auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo); view) {
832 GrColorInfo colorInfo(ct, image->alphaType(), image->refColorSpace());
833 this->drawViewLattice(std::move(view),
834 std::move(colorInfo),
835 std::move(iter),
836 dst,
837 filter,
838 paint);
839 }
840 }
841
drawVertices(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)842 void Device::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
843 ASSERT_SINGLE_OWNER
844 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawVertices", fContext.get());
845 SkASSERT(vertices);
846
847 SkVerticesPriv info(vertices->priv());
848
849 GrPaint grPaint;
850 if (!init_vertices_paint(fContext.get(), fSurfaceDrawContext->colorInfo(), paint,
851 this->asMatrixProvider(), mode, info.hasColors(), &grPaint)) {
852 return;
853 }
854 fSurfaceDrawContext->drawVertices(this->clip(),
855 std::move(grPaint),
856 this->asMatrixProvider(),
857 sk_ref_sp(const_cast<SkVertices*>(vertices)),
858 nullptr);
859 }
860
861 ///////////////////////////////////////////////////////////////////////////////
862
drawShadow(const SkPath & path,const SkDrawShadowRec & rec)863 void Device::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
864 #if GR_TEST_UTILS
865 if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
866 this->drawShadow(SkPath(path).setIsVolatile(true), rec);
867 return;
868 }
869 #endif
870 ASSERT_SINGLE_OWNER
871 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawShadow", fContext.get());
872
873 if (!fSurfaceDrawContext->drawFastShadow(this->clip(), this->localToDevice(), path, rec)) {
874 // failed to find an accelerated case
875 this->INHERITED::drawShadow(path, rec);
876 }
877 }
878
879 ///////////////////////////////////////////////////////////////////////////////
880
drawAtlas(const SkRSXform xform[],const SkRect texRect[],const SkColor colors[],int count,SkBlendMode mode,const SkPaint & paint)881 void Device::drawAtlas(const SkRSXform xform[],
882 const SkRect texRect[],
883 const SkColor colors[],
884 int count,
885 SkBlendMode mode,
886 const SkPaint& paint) {
887 ASSERT_SINGLE_OWNER
888 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawAtlas", fContext.get());
889
890 GrPaint grPaint;
891 if (colors) {
892 if (!SkPaintToGrPaintWithBlend(this->recordingContext(), fSurfaceDrawContext->colorInfo(),
893 paint, this->asMatrixProvider(), mode, &grPaint)) {
894 return;
895 }
896 } else {
897 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(),
898 paint, this->asMatrixProvider(), &grPaint)) {
899 return;
900 }
901 }
902
903 fSurfaceDrawContext->drawAtlas(this->clip(), std::move(grPaint), this->localToDevice(), count,
904 xform, texRect, colors);
905 }
906
907 ///////////////////////////////////////////////////////////////////////////////
908
onDrawGlyphRunList(const SkGlyphRunList & glyphRunList,const SkPaint & paint)909 void Device::onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) {
910 ASSERT_SINGLE_OWNER
911 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawGlyphRunList", fContext.get());
912 SkASSERT(!glyphRunList.hasRSXForm());
913
914 fSurfaceDrawContext->drawGlyphRunList(
915 this->clip(), this->asMatrixProvider(), glyphRunList, paint);
916 }
917
918 ///////////////////////////////////////////////////////////////////////////////
919
drawDrawable(SkDrawable * drawable,const SkMatrix * matrix,SkCanvas * canvas)920 void Device::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, SkCanvas* canvas) {
921 ASSERT_SINGLE_OWNER
922
923 GrBackendApi api = this->recordingContext()->backend();
924 if (GrBackendApi::kVulkan == api) {
925 const SkMatrix& ctm = this->localToDevice();
926 const SkMatrix& combinedMatrix = matrix ? SkMatrix::Concat(ctm, *matrix) : ctm;
927 std::unique_ptr<SkDrawable::GpuDrawHandler> gpuDraw =
928 drawable->snapGpuDrawHandler(api, combinedMatrix, this->devClipBounds(),
929 this->imageInfo());
930 if (gpuDraw) {
931 fSurfaceDrawContext->drawDrawable(
932 std::move(gpuDraw), combinedMatrix.mapRect(drawable->getBounds()));
933 return;
934 }
935 }
936 this->INHERITED::drawDrawable(drawable, matrix, canvas);
937 }
938
939
940 ///////////////////////////////////////////////////////////////////////////////
941
wait(int numSemaphores,const GrBackendSemaphore * waitSemaphores,bool deleteSemaphoresAfterWait)942 bool Device::wait(int numSemaphores,
943 const GrBackendSemaphore* waitSemaphores,
944 bool deleteSemaphoresAfterWait) {
945 ASSERT_SINGLE_OWNER
946
947 return fSurfaceDrawContext->waitOnSemaphores(numSemaphores, waitSemaphores,
948 deleteSemaphoresAfterWait);
949 }
950
replaceBackingProxy(SkSurface::ContentChangeMode mode,sk_sp<GrRenderTargetProxy> newRTP,GrColorType grColorType,sk_sp<SkColorSpace> colorSpace,GrSurfaceOrigin origin,const SkSurfaceProps & props)951 bool Device::replaceBackingProxy(SkSurface::ContentChangeMode mode,
952 sk_sp<GrRenderTargetProxy> newRTP,
953 GrColorType grColorType,
954 sk_sp<SkColorSpace> colorSpace,
955 GrSurfaceOrigin origin,
956 const SkSurfaceProps& props) {
957 auto sdc = SurfaceDrawContext::Make(fContext.get(), grColorType, std::move(newRTP),
958 std::move(colorSpace), origin, props);
959 if (!sdc) {
960 return false;
961 }
962
963 SkASSERT(sdc->dimensions() == fSurfaceDrawContext->dimensions());
964 SkASSERT(sdc->numSamples() == fSurfaceDrawContext->numSamples());
965 SkASSERT(sdc->asSurfaceProxy()->priv().isExact());
966 if (mode == SkSurface::kRetain_ContentChangeMode) {
967 if (fContext->abandoned()) {
968 return false;
969 }
970
971 SkASSERT(fSurfaceDrawContext->asTextureProxy());
972 SkAssertResult(sdc->blitTexture(fSurfaceDrawContext->readSurfaceView(),
973 SkIRect::MakeWH(this->width(), this->height()),
974 SkIPoint::Make(0, 0)));
975 }
976
977 fSurfaceDrawContext = std::move(sdc);
978 return true;
979 }
980
asyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)981 void Device::asyncRescaleAndReadPixels(const SkImageInfo& info,
982 const SkIRect& srcRect,
983 RescaleGamma rescaleGamma,
984 RescaleMode rescaleMode,
985 ReadPixelsCallback callback,
986 ReadPixelsContext context) {
987 auto* sdc = fSurfaceDrawContext.get();
988 // Context TODO: Elevate direct context requirement to public API.
989 auto dContext = sdc->recordingContext()->asDirectContext();
990 if (!dContext) {
991 return;
992 }
993 sdc->asyncRescaleAndReadPixels(dContext, info, srcRect, rescaleGamma, rescaleMode, callback,
994 context);
995 }
996
asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,SkISize dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)997 void Device::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
998 sk_sp<SkColorSpace> dstColorSpace,
999 const SkIRect& srcRect,
1000 SkISize dstSize,
1001 RescaleGamma rescaleGamma,
1002 RescaleMode rescaleMode,
1003 ReadPixelsCallback callback,
1004 ReadPixelsContext context) {
1005 auto* sdc = fSurfaceDrawContext.get();
1006 // Context TODO: Elevate direct context requirement to public API.
1007 auto dContext = sdc->recordingContext()->asDirectContext();
1008 if (!dContext) {
1009 return;
1010 }
1011 sdc->asyncRescaleAndReadPixelsYUV420(dContext,
1012 yuvColorSpace,
1013 std::move(dstColorSpace),
1014 srcRect,
1015 dstSize,
1016 rescaleGamma,
1017 rescaleMode,
1018 callback,
1019 context);
1020 }
1021
1022 ///////////////////////////////////////////////////////////////////////////////
1023
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)1024 SkBaseDevice* Device::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
1025 ASSERT_SINGLE_OWNER
1026
1027 SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry);
1028
1029 // layers are never drawn in repeat modes, so we can request an approx
1030 // match and ignore any padding.
1031 SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox
1032 : SkBackingFit::kExact;
1033
1034 SkASSERT(cinfo.fInfo.colorType() != kRGBA_1010102_SkColorType);
1035
1036 auto sdc = SurfaceDrawContext::MakeWithFallback(
1037 fContext.get(), SkColorTypeToGrColorType(cinfo.fInfo.colorType()),
1038 fSurfaceDrawContext->colorInfo().refColorSpace(), fit, cinfo.fInfo.dimensions(), props,
1039 fSurfaceDrawContext->numSamples(), GrMipmapped::kNo,
1040 fSurfaceDrawContext->asSurfaceProxy()->isProtected(), kBottomLeft_GrSurfaceOrigin,
1041 SkBudgeted::kYes);
1042 if (!sdc) {
1043 return nullptr;
1044 }
1045
1046 // Skia's convention is to only clear a device if it is non-opaque.
1047 InitContents init = cinfo.fInfo.isOpaque() ? InitContents::kUninit : InitContents::kClear;
1048
1049 return Device::Make(std::move(sdc), cinfo.fInfo.alphaType(), init).release();
1050 }
1051
makeSurface(const SkImageInfo & info,const SkSurfaceProps & props)1052 sk_sp<SkSurface> Device::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1053 ASSERT_SINGLE_OWNER
1054 // TODO: Change the signature of newSurface to take a budgeted parameter.
1055 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
1056 return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info,
1057 fSurfaceDrawContext->numSamples(),
1058 fSurfaceDrawContext->origin(), &props);
1059 }
1060
getImageFilterCache()1061 SkImageFilterCache* Device::getImageFilterCache() {
1062 ASSERT_SINGLE_OWNER
1063 // We always return a transient cache, so it is freed after each
1064 // filter traversal.
1065 return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
1066 }
1067
1068 ////////////////////////////////////////////////////////////////////////////////////
1069
android_utils_clipWithStencil()1070 bool Device::android_utils_clipWithStencil() {
1071 SkRegion clipRegion;
1072 this->onAsRgnClip(&clipRegion);
1073 if (clipRegion.isEmpty()) {
1074 return false;
1075 }
1076 auto sdc = fSurfaceDrawContext.get();
1077 SkASSERT(sdc);
1078 GrPaint grPaint;
1079 grPaint.setXPFactory(GrDisableColorXPFactory::Get());
1080 static constexpr GrUserStencilSettings kDrawToStencil(
1081 GrUserStencilSettings::StaticInit<
1082 0x1,
1083 GrUserStencilTest::kAlways,
1084 0x1,
1085 GrUserStencilOp::kReplace,
1086 GrUserStencilOp::kReplace,
1087 0x1>()
1088 );
1089 // Regions don't actually need AA, but in DMSAA mode everything is antialiased.
1090 GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias());
1091 sdc->drawRegion(nullptr, std::move(grPaint), aa, SkMatrix::I(), clipRegion,
1092 GrStyle::SimpleFill(), &kDrawToStencil);
1093 return true;
1094 }
1095
drawBlurImage(const SkImage * image,const SkBlurArg & blurArg)1096 bool Device::drawBlurImage(const SkImage* image, const SkBlurArg& blurArg)
1097 {
1098 if (image == nullptr) {
1099 return false;
1100 }
1101 if (auto[view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo); view) {
1102 return fSurfaceDrawContext->drawBlurImage(std::move(view), blurArg);
1103 }
1104 }
1105
1106 } // namespace skgpu::v1
1107