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