Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/gpu/v1/SurfaceDrawContext.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2015 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/SurfaceDrawContext_v1.h"
9
10
#include "include/core/SkDrawable.h"
11
#include "include/core/SkVertices.h"
12
#include "include/gpu/GrBackendSemaphore.h"
13
#include "include/gpu/GrDirectContext.h"
14
#include "include/gpu/GrRecordingContext.h"
15
#include "include/private/GrImageContext.h"
16
#include "include/private/SkShadowFlags.h"
17
#include "include/private/SkVx.h"
18
#include "include/utils/SkShadowUtils.h"
19
#include "src/core/SkAutoPixmapStorage.h"
20
#include "src/core/SkConvertPixels.h"
21
#include "src/core/SkDrawProcs.h"
22
#include "src/core/SkDrawShadowInfo.h"
23
#include "src/core/SkGlyphRunPainter.h"
24
#include "src/core/SkLatticeIter.h"
25
#include "src/core/SkMatrixPriv.h"
26
#include "src/core/SkMatrixProvider.h"
27
#include "src/core/SkRRectPriv.h"
28
#include "src/gpu/GrAppliedClip.h"
29
#include "src/gpu/GrAttachment.h"
30
#include "src/gpu/GrCaps.h"
31
#include "src/gpu/GrClip.h"
32
#include "src/gpu/GrColor.h"
33
#include "src/gpu/GrDataUtils.h"
34
#include "src/gpu/GrDirectContextPriv.h"
35
#include "src/gpu/GrDrawingManager.h"
36
#include "src/gpu/GrGpuResourcePriv.h"
37
#include "src/gpu/GrImageContextPriv.h"
38
#include "src/gpu/GrImageInfo.h"
39
#include "src/gpu/GrMemoryPool.h"
40
#include "src/gpu/GrProxyProvider.h"
41
#include "src/gpu/GrRenderTarget.h"
42
#include "src/gpu/GrResourceProvider.h"
43
#include "src/gpu/GrStencilSettings.h"
44
#include "src/gpu/GrStyle.h"
45
#include "src/gpu/GrTracing.h"
46
#include "src/gpu/SkGr.h"
47
#include "src/gpu/effects/GrBicubicEffect.h"
48
#include "src/gpu/effects/GrBlendFragmentProcessor.h"
49
#include "src/gpu/effects/GrDisableColorXP.h"
50
#include "src/gpu/effects/GrRRectEffect.h"
51
#include "src/gpu/effects/GrTextureEffect.h"
52
#include "src/gpu/geometry/GrQuad.h"
53
#include "src/gpu/geometry/GrQuadUtils.h"
54
#include "src/gpu/geometry/GrStyledShape.h"
55
#include "src/gpu/ops/GrClearOp.h"
56
#include "src/gpu/ops/GrDrawAtlasOp.h"
57
#include "src/gpu/ops/GrDrawOp.h"
58
#include "src/gpu/ops/GrDrawVerticesOp.h"
59
#include "src/gpu/ops/GrDrawableOp.h"
60
#include "src/gpu/ops/GrFillRRectOp.h"
61
#include "src/gpu/ops/GrFillRectOp.h"
62
#include "src/gpu/ops/GrLatticeOp.h"
63
#include "src/gpu/ops/GrOp.h"
64
#include "src/gpu/ops/GrOvalOpFactory.h"
65
#include "src/gpu/ops/GrRegionOp.h"
66
#include "src/gpu/ops/GrShadowRRectOp.h"
67
#include "src/gpu/ops/GrStrokeRectOp.h"
68
#include "src/gpu/ops/GrTextureOp.h"
69
#include "src/gpu/text/GrSDFTControl.h"
70
#include "src/gpu/text/GrTextBlobCache.h"
71
#include "src/gpu/v1/PathRenderer.h"
72
73
#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
74
214k
#define ASSERT_SINGLE_OWNER        GR_ASSERT_SINGLE_OWNER(this->singleOwner())
75
341k
#define RETURN_IF_ABANDONED        if (fContext->abandoned()) { return; }
76
0
#define RETURN_FALSE_IF_ABANDONED  if (fContext->abandoned()) { return false; }
77
78
//////////////////////////////////////////////////////////////////////////////
79
80
namespace {
81
82
119k
void op_bounds(SkRect* bounds, const GrOp* op) {
83
119k
    *bounds = op->bounds();
84
119k
    if (op->hasZeroArea()) {
85
5.94k
        if (op->hasAABloat()) {
86
3.84k
            bounds->outset(0.5f, 0.5f);
87
2.10k
        } else {
88
            // We don't know which way the particular GPU will snap lines or points at integer
89
            // coords. So we ensure that the bounds is large enough for either snap.
90
2.10k
            SkRect before = *bounds;
91
2.10k
            bounds->roundOut(bounds);
92
2.10k
            if (bounds->fLeft == before.fLeft) {
93
466
                bounds->fLeft -= 1;
94
466
            }
95
2.10k
            if (bounds->fTop == before.fTop) {
96
431
                bounds->fTop -= 1;
97
431
            }
98
2.10k
            if (bounds->fRight == before.fRight) {
99
401
                bounds->fRight += 1;
100
401
            }
101
2.10k
            if (bounds->fBottom == before.fBottom) {
102
858
                bounds->fBottom += 1;
103
858
            }
104
2.10k
        }
105
5.94k
    }
106
119k
}
107
108
} // anonymous namespace
109
110
namespace skgpu::v1 {
111
112
using DoSimplify = GrStyledShape::DoSimplify;
113
114
class AutoCheckFlush {
115
public:
116
147k
    AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
117
147k
        SkASSERT(fDrawingManager);
118
147k
    }
119
147k
    ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
120
121
private:
122
    GrDrawingManager* fDrawingManager;
123
};
124
125
std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::Make(GrRecordingContext* rContext,
126
                                                             GrColorType colorType,
127
                                                             sk_sp<GrSurfaceProxy> proxy,
128
                                                             sk_sp<SkColorSpace> colorSpace,
129
                                                             GrSurfaceOrigin origin,
130
                                                             const SkSurfaceProps& surfaceProps,
131
63.5k
                                                             bool flushTimeOpsTask) {
132
63.5k
    if (!rContext || !proxy) {
133
0
        return nullptr;
134
0
    }
135
136
63.5k
    const GrBackendFormat& format = proxy->backendFormat();
137
63.5k
    GrSwizzle readSwizzle, writeSwizzle;
138
63.5k
    if (colorType != GrColorType::kUnknown) {
139
63.5k
        readSwizzle = rContext->priv().caps()->getReadSwizzle(format, colorType);
140
63.5k
        writeSwizzle = rContext->priv().caps()->getWriteSwizzle(format, colorType);
141
63.5k
    }
142
143
63.5k
    GrSurfaceProxyView readView (           proxy, origin,  readSwizzle);
144
63.5k
    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
145
146
63.5k
    return std::make_unique<SurfaceDrawContext>(rContext,
147
63.5k
                                                std::move(readView),
148
63.5k
                                                std::move(writeView),
149
63.5k
                                                colorType,
150
63.5k
                                                std::move(colorSpace),
151
63.5k
                                                surfaceProps,
152
63.5k
                                                flushTimeOpsTask);
153
63.5k
}
154
155
std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::Make(
156
        GrRecordingContext* rContext,
157
        sk_sp<SkColorSpace> colorSpace,
158
        SkBackingFit fit,
159
        SkISize dimensions,
160
        const GrBackendFormat& format,
161
        int sampleCnt,
162
        GrMipmapped mipMapped,
163
        GrProtected isProtected,
164
        GrSwizzle readSwizzle,
165
        GrSwizzle writeSwizzle,
166
        GrSurfaceOrigin origin,
167
        SkBudgeted budgeted,
168
0
        const SkSurfaceProps& surfaceProps) {
169
    // It is probably not necessary to check if the context is abandoned here since uses of the
170
    // SurfaceDrawContext which need the context will mostly likely fail later on without an
171
    // issue. However having this hear adds some reassurance in case there is a path doesn't handle
172
    // an abandoned context correctly. It also lets us early out of some extra work.
173
0
    if (rContext->abandoned()) {
174
0
        return nullptr;
175
0
    }
176
177
0
    sk_sp<GrTextureProxy> proxy = rContext->priv().proxyProvider()->createProxy(
178
0
            format,
179
0
            dimensions,
180
0
            GrRenderable::kYes,
181
0
            sampleCnt,
182
0
            mipMapped,
183
0
            fit,
184
0
            budgeted,
185
0
            isProtected);
186
0
    if (!proxy) {
187
0
        return nullptr;
188
0
    }
189
190
0
    GrSurfaceProxyView readView (           proxy, origin,  readSwizzle);
191
0
    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
192
193
0
    auto sdc = std::make_unique<SurfaceDrawContext>(rContext,
194
0
                                                    std::move(readView),
195
0
                                                    std::move(writeView),
196
0
                                                    GrColorType::kUnknown,
197
0
                                                    std::move(colorSpace),
198
0
                                                    surfaceProps);
199
0
    sdc->discard();
200
0
    return sdc;
201
0
}
202
203
std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::Make(
204
        GrRecordingContext* rContext,
205
        GrColorType colorType,
206
        sk_sp<SkColorSpace> colorSpace,
207
        SkBackingFit fit,
208
        SkISize dimensions,
209
        const SkSurfaceProps& surfaceProps,
210
        int sampleCnt,
211
        GrMipmapped mipMapped,
212
        GrProtected isProtected,
213
        GrSurfaceOrigin origin,
214
63.8k
        SkBudgeted budgeted) {
215
63.8k
    auto format = rContext->priv().caps()->getDefaultBackendFormat(colorType, GrRenderable::kYes);
216
63.8k
    if (!format.isValid()) {
217
0
        return nullptr;
218
0
    }
219
63.8k
    sk_sp<GrTextureProxy> proxy = rContext->priv().proxyProvider()->createProxy(format,
220
63.8k
                                                                                dimensions,
221
63.8k
                                                                                GrRenderable::kYes,
222
63.8k
                                                                                sampleCnt,
223
63.8k
                                                                                mipMapped,
224
63.8k
                                                                                fit,
225
63.8k
                                                                                budgeted,
226
63.8k
                                                                                isProtected);
227
63.8k
    if (!proxy) {
228
321
        return nullptr;
229
321
    }
230
231
63.5k
    return SurfaceDrawContext::Make(rContext,
232
63.5k
                                    colorType,
233
63.5k
                                    std::move(proxy),
234
63.5k
                                    std::move(colorSpace),
235
63.5k
                                    origin,
236
63.5k
                                    surfaceProps);
237
63.5k
}
238
239
std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::MakeWithFallback(
240
        GrRecordingContext* rContext,
241
        GrColorType colorType,
242
        sk_sp<SkColorSpace> colorSpace,
243
        SkBackingFit fit,
244
        SkISize dimensions,
245
        const SkSurfaceProps& surfaceProps,
246
        int sampleCnt,
247
        GrMipmapped mipMapped,
248
        GrProtected isProtected,
249
        GrSurfaceOrigin origin,
250
29.3k
        SkBudgeted budgeted) {
251
29.3k
    const GrCaps* caps = rContext->priv().caps();
252
29.3k
    auto [ct, _] = caps->getFallbackColorTypeAndFormat(colorType, sampleCnt);
253
29.3k
    if (ct == GrColorType::kUnknown) {
254
0
        return nullptr;
255
0
    }
256
29.3k
    return SurfaceDrawContext::Make(rContext, ct, colorSpace, fit, dimensions, surfaceProps,
257
29.3k
                                    sampleCnt, mipMapped, isProtected, origin, budgeted);
258
29.3k
}
259
260
std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::MakeFromBackendTexture(
261
        GrRecordingContext* rContext,
262
        GrColorType colorType,
263
        sk_sp<SkColorSpace> colorSpace,
264
        const GrBackendTexture& tex,
265
        int sampleCnt,
266
        GrSurfaceOrigin origin,
267
        const SkSurfaceProps& surfaceProps,
268
0
        sk_sp<GrRefCntedCallback> releaseHelper) {
269
0
    SkASSERT(sampleCnt > 0);
270
0
    sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
271
0
            tex, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
272
0
            std::move(releaseHelper)));
273
0
    if (!proxy) {
274
0
        return nullptr;
275
0
    }
276
277
0
    return SurfaceDrawContext::Make(rContext, colorType, std::move(proxy), std::move(colorSpace),
278
0
                                    origin, surfaceProps);
279
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::MakeFromBackendTexture(GrRecordingContext*, GrColorType, sk_sp<SkColorSpace>, GrBackendTexture const&, int, GrSurfaceOrigin, SkSurfaceProps const&, sk_sp<GrRefCntedCallback>)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::MakeFromBackendTexture(GrRecordingContext*, GrColorType, sk_sp<SkColorSpace>, GrBackendTexture const&, int, GrSurfaceOrigin, SkSurfaceProps const&, sk_sp<GrRefCntedCallback>)
280
281
// In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
282
// GrOpsTask to be picked up and added to by SurfaceDrawContexts lower in the call
283
// stack. When this occurs with a closed GrOpsTask, a new one will be allocated
284
// when the surfaceDrawContext attempts to use it (via getOpsTask).
285
SurfaceDrawContext::SurfaceDrawContext(GrRecordingContext* rContext,
286
                                       GrSurfaceProxyView readView,
287
                                       GrSurfaceProxyView writeView,
288
                                       GrColorType colorType,
289
                                       sk_sp<SkColorSpace> colorSpace,
290
                                       const SkSurfaceProps& surfaceProps,
291
                                       bool flushTimeOpsTask)
292
        : SurfaceFillContext(rContext,
293
                             std::move(readView),
294
                             std::move(writeView),
295
                             {colorType, kPremul_SkAlphaType, std::move(colorSpace)},
296
                             flushTimeOpsTask)
297
        , fSurfaceProps(surfaceProps)
298
        , fCanUseDynamicMSAA(
299
                (fSurfaceProps.flags() & SkSurfaceProps::kDynamicMSAA_Flag) &&
300
                rContext->priv().caps()->supportsDynamicMSAA(this->asRenderTargetProxy()))
301
134k
        , fGlyphPainter(*this) {
302
67.3k
    SkDEBUGCODE(this->validate();)
303
134k
}
skgpu::v1::SurfaceDrawContext::SurfaceDrawContext(GrRecordingContext*, GrSurfaceProxyView, GrSurfaceProxyView, GrColorType, sk_sp<SkColorSpace>, SkSurfaceProps const&, bool)
Line
Count
Source
301
67.3k
        , fGlyphPainter(*this) {
302
67.3k
    SkDEBUGCODE(this->validate();)
303
67.3k
}
skgpu::v1::SurfaceDrawContext::SurfaceDrawContext(GrRecordingContext*, GrSurfaceProxyView, GrSurfaceProxyView, GrColorType, sk_sp<SkColorSpace>, SkSurfaceProps const&, bool)
Line
Count
Source
301
67.3k
        , fGlyphPainter(*this) {
302
67.3k
    SkDEBUGCODE(this->validate();)
303
67.3k
}
304
305
134k
SurfaceDrawContext::~SurfaceDrawContext() {
306
67.3k
    ASSERT_SINGLE_OWNER
307
134k
}
skgpu::v1::SurfaceDrawContext::~SurfaceDrawContext()
Line
Count
Source
305
67.3k
SurfaceDrawContext::~SurfaceDrawContext() {
306
67.3k
    ASSERT_SINGLE_OWNER
307
67.3k
}
skgpu::v1::SurfaceDrawContext::~SurfaceDrawContext()
Line
Count
Source
305
67.3k
SurfaceDrawContext::~SurfaceDrawContext() {
306
67.3k
    ASSERT_SINGLE_OWNER
307
67.3k
}
308
309
89.6k
void SurfaceDrawContext::willReplaceOpsTask(GrOpsTask* prevTask, GrOpsTask* nextTask) {
310
89.6k
    if (prevTask && fNeedsStencil) {
311
        // Store the stencil values in memory upon completion of fOpsTask.
312
5.28k
        prevTask->setMustPreserveStencil();
313
        // Reload the stencil buffer content at the beginning of newOpsTask.
314
        // FIXME: Could the topo sort insert a task between these two that modifies the stencil
315
        // values?
316
5.28k
        nextTask->setInitialStencilContent(GrOpsTask::StencilContent::kPreserved);
317
5.28k
    }
318
89.6k
#if GR_GPU_STATS && GR_TEST_UTILS
319
89.6k
    if (fCanUseDynamicMSAA) {
320
0
        fContext->priv().dmsaaStats().fNumRenderPasses++;
321
0
    }
322
89.6k
#endif
323
89.6k
}
324
325
163k
inline GrAAType SurfaceDrawContext::chooseAAType(GrAA aa) {
326
163k
    if (this->numSamples() > 1 || fCanUseDynamicMSAA) {
327
        // Always trigger DMSAA when it's available. The coverage ops that know how to handle both
328
        // single and multisample targets without popping will do so without calling chooseAAType.
329
0
        return GrAAType::kMSAA;
330
0
    }
331
163k
    return (aa == GrAA::kYes) ? GrAAType::kCoverage : GrAAType::kNone;
332
163k
}
333
334
void SurfaceDrawContext::drawGlyphRunListNoCache(const GrClip* clip,
335
                                                 const SkMatrixProvider& viewMatrix,
336
                                                 const SkGlyphRunList& glyphRunList,
337
13
                                                 const SkPaint& paint) {
338
13
    GrSDFTControl control =
339
13
            fContext->priv().getSDFTControl(fSurfaceProps.isUseDeviceIndependentFonts());
340
13
    const SkPoint drawOrigin = glyphRunList.origin();
341
13
    SkMatrix drawMatrix = viewMatrix.localToDevice();
342
13
    drawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
343
13
    GrSubRunAllocator* const alloc = this->subRunAlloc();
344
345
13
    for (auto& glyphRun : glyphRunList) {
346
13
        GrSubRunNoCachePainter painter{this, alloc, clip, viewMatrix, glyphRunList, paint};
347
348
        // Make and add the text ops.
349
13
        fGlyphPainter.processGlyphRun(glyphRun,
350
13
                                      drawMatrix,
351
13
                                      paint,
352
13
                                      control,
353
13
                                      &painter);
354
13
    }
355
13
}
356
357
void SurfaceDrawContext::drawGlyphRunListWithCache(const GrClip* clip,
358
                                                   const SkMatrixProvider& viewMatrix,
359
                                                   const SkGlyphRunList& glyphRunList,
360
772
                                                   const SkPaint& paint) {
361
772
    SkMatrix drawMatrix(viewMatrix.localToDevice());
362
772
    drawMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());
363
364
772
    GrSDFTControl control =
365
772
            this->recordingContext()->priv().getSDFTControl(
366
772
                    this->surfaceProps().isUseDeviceIndependentFonts());
367
368
772
    auto [canCache, key] = GrTextBlob::Key::Make(glyphRunList,
369
772
                                                 paint,
370
772
                                                 fSurfaceProps,
371
772
                                                 this->colorInfo(),
372
772
                                                 drawMatrix,
373
772
                                                 control);
374
375
772
    sk_sp<GrTextBlob> blob;
376
772
    GrTextBlobCache* textBlobCache = fContext->priv().getTextBlobCache();
377
772
    if (canCache) {
378
531
        blob = textBlobCache->find(key);
379
531
    }
380
381
772
    if (blob == nullptr || !blob->canReuse(paint, drawMatrix)) {
382
772
        if (blob != nullptr) {
383
            // We have to remake the blob because changes may invalidate our masks.
384
            // TODO we could probably get away with reuse most of the time if the pointer is unique,
385
            //      but we'd have to clear the SubRun information
386
0
            textBlobCache->remove(blob.get());
387
0
        }
388
389
772
        blob = GrTextBlob::Make(glyphRunList, paint, drawMatrix, control, &fGlyphPainter);
390
391
772
        if (canCache) {
392
531
            blob->addKey(key);
393
            // The blob may already have been created on a different thread. Use the first one
394
            // that was there.
395
531
            blob = textBlobCache->addOrReturnExisting(glyphRunList, blob);
396
531
        }
397
772
    }
398
399
3.52k
    for (const GrSubRun& subRun : blob->subRunList()) {
400
3.52k
        subRun.draw(clip, viewMatrix, glyphRunList, paint, this);
401
3.52k
    }
402
772
}
403
404
// choose to use the GrTextBlob cache or not.
405
bool gGrDrawTextNoCache = false;
406
void SurfaceDrawContext::drawGlyphRunList(const GrClip* clip,
407
                                          const SkMatrixProvider& viewMatrix,
408
                                          const SkGlyphRunList& glyphRunList,
409
1.57k
                                          const SkPaint& paint) {
410
785
    ASSERT_SINGLE_OWNER
411
1.57k
    RETURN_IF_ABANDONED
412
785
    SkDEBUGCODE(this->validate();)
413
1.57k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawGlyphRunList", fContext);
414
415
    // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
416
    // secondary command buffers because it would require stopping and starting a render pass which
417
    // we don't have access to.
418
1.57k
    if (this->wrapsVkSecondaryCB()) {
419
0
        return;
420
0
    }
421
422
1.57k
    if (gGrDrawTextNoCache || glyphRunList.blob() == nullptr) {
423
        // If the glyphRunList does not have an associated text blob, then it was created by one of
424
        // the direct draw APIs (drawGlyphs, etc.). There is no need to create a GrTextBlob just
425
        // build the sub run directly and place it in the op.
426
26
        this->drawGlyphRunListNoCache(clip, viewMatrix, glyphRunList, paint);
427
1.54k
    } else {
428
1.54k
        this->drawGlyphRunListWithCache(clip, viewMatrix, glyphRunList, paint);
429
1.54k
    }
430
1.57k
}
skgpu::v1::SurfaceDrawContext::drawGlyphRunList(GrClip const*, SkMatrixProvider const&, SkGlyphRunList const&, SkPaint const&)
Line
Count
Source
409
785
                                          const SkPaint& paint) {
410
785
    ASSERT_SINGLE_OWNER
411
785
    RETURN_IF_ABANDONED
412
785
    SkDEBUGCODE(this->validate();)
413
785
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawGlyphRunList", fContext);
414
415
    // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
416
    // secondary command buffers because it would require stopping and starting a render pass which
417
    // we don't have access to.
418
785
    if (this->wrapsVkSecondaryCB()) {
419
0
        return;
420
0
    }
421
422
785
    if (gGrDrawTextNoCache || glyphRunList.blob() == nullptr) {
423
        // If the glyphRunList does not have an associated text blob, then it was created by one of
424
        // the direct draw APIs (drawGlyphs, etc.). There is no need to create a GrTextBlob just
425
        // build the sub run directly and place it in the op.
426
13
        this->drawGlyphRunListNoCache(clip, viewMatrix, glyphRunList, paint);
427
772
    } else {
428
772
        this->drawGlyphRunListWithCache(clip, viewMatrix, glyphRunList, paint);
429
772
    }
430
785
}
skgpu::v1::SurfaceDrawContext::drawGlyphRunList(GrClip const*, SkMatrixProvider const&, SkGlyphRunList const&, SkPaint const&)
Line
Count
Source
409
785
                                          const SkPaint& paint) {
410
785
    ASSERT_SINGLE_OWNER
411
785
    RETURN_IF_ABANDONED
412
785
    SkDEBUGCODE(this->validate();)
413
785
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawGlyphRunList", fContext);
414
415
    // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
416
    // secondary command buffers because it would require stopping and starting a render pass which
417
    // we don't have access to.
418
785
    if (this->wrapsVkSecondaryCB()) {
419
0
        return;
420
0
    }
421
422
785
    if (gGrDrawTextNoCache || glyphRunList.blob() == nullptr) {
423
        // If the glyphRunList does not have an associated text blob, then it was created by one of
424
        // the direct draw APIs (drawGlyphs, etc.). There is no need to create a GrTextBlob just
425
        // build the sub run directly and place it in the op.
426
13
        this->drawGlyphRunListNoCache(clip, viewMatrix, glyphRunList, paint);
427
772
    } else {
428
772
        this->drawGlyphRunListWithCache(clip, viewMatrix, glyphRunList, paint);
429
772
    }
430
785
}
431
432
void SurfaceDrawContext::drawPaint(const GrClip* clip,
433
                                   GrPaint&& paint,
434
7.64k
                                   const SkMatrix& viewMatrix) {
435
    // Start with the render target, since that is the maximum content we could possibly fill.
436
    // drawFilledQuad() will automatically restrict it to clip bounds for us if possible.
437
7.64k
    if (!paint.numTotalFragmentProcessors()) {
438
        // The paint is trivial so we won't need to use local coordinates, so skip calculating the
439
        // inverse view matrix.
440
7.62k
        SkRect r = this->asSurfaceProxy()->getBoundsRect();
441
7.62k
        this->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), r, r);
442
19
    } else {
443
        // Use the inverse view matrix to arrive at appropriate local coordinates for the paint.
444
19
        SkMatrix localMatrix;
445
19
        if (!viewMatrix.invert(&localMatrix)) {
446
0
            return;
447
0
        }
448
19
        SkIRect bounds = SkIRect::MakeSize(this->asSurfaceProxy()->dimensions());
449
19
        this->fillPixelsWithLocalMatrix(clip, std::move(paint), bounds, localMatrix);
450
19
    }
451
7.64k
}
452
453
enum class SurfaceDrawContext::QuadOptimization {
454
    // The rect to draw doesn't intersect clip or render target, so no draw op should be added
455
    kDiscarded,
456
    // The rect to draw was converted to some other op and appended to the oplist, so no additional
457
    // op is necessary. Currently this can convert it to a clear op or a rrect op. Only valid if
458
    // a constColor is provided.
459
    kSubmitted,
460
    // The clip was folded into the device quad, with updated edge flags and local coords, and
461
    // caller is responsible for adding an appropriate op.
462
    kClipApplied,
463
    // No change to clip, but quad updated to better fit clip/render target, and caller is
464
    // responsible for adding an appropriate op.
465
    kCropped
466
};
467
468
SurfaceDrawContext::QuadOptimization SurfaceDrawContext::attemptQuadOptimization(
469
        const GrClip* clip, const GrUserStencilSettings* stencilSettings, GrAA* aa, DrawQuad* quad,
470
96.4k
        GrPaint* paint) {
471
    // Optimization requirements:
472
    // 1. kDiscard applies when clip bounds and quad bounds do not intersect
473
    // 2a. kSubmitted applies when constColor and final geom is pixel aligned rect;
474
    //       pixel aligned rect requires rect clip and (rect quad or quad covers clip) OR
475
    // 2b. kSubmitted applies when constColor and rrect clip and quad covers clip
476
    // 4. kClipApplied applies when rect clip and (rect quad or quad covers clip)
477
    // 5. kCropped in all other scenarios (although a crop may be a no-op)
478
96.4k
    const SkPMColor4f* constColor = nullptr;
479
96.4k
    SkPMColor4f paintColor;
480
96.4k
    if (!stencilSettings && paint && !paint->hasCoverageFragmentProcessor() &&
481
16.5k
        paint->isConstantBlendedColor(&paintColor)) {
482
        // Only consider clears/rrects when it's easy to guarantee 100% fill with single color
483
9.98k
        constColor = &paintColor;
484
9.98k
    }
485
486
    // Save the old AA flags since CropToRect will modify 'quad' and if kCropped is returned, it's
487
    // better to just keep the old flags instead of introducing mixed edge flags.
488
96.4k
    GrQuadAAFlags oldFlags = quad->fEdgeFlags;
489
490
    // Use the logical size of the render target, which allows for "fullscreen" clears even if
491
    // the render target has an approximate backing fit
492
96.4k
    SkRect rtRect = this->asSurfaceProxy()->getBoundsRect();
493
494
    // For historical reasons, we assume AA for exact bounds checking in IsOutsideClip.
495
    // TODO(michaelludwig) - Hopefully that can be revisited when the clipping optimizations are
496
    // refactored to work better with round rects and dmsaa.
497
96.4k
    SkRect drawBounds = quad->fDevice.bounds();
498
96.4k
    if (!quad->fDevice.isFinite() || drawBounds.isEmpty() ||
499
95.6k
        GrClip::IsOutsideClip(SkIRect::MakeSize(this->dimensions()), drawBounds, GrAA::kYes)) {
500
1.53k
        return QuadOptimization::kDiscarded;
501
94.8k
    } else if (GrQuadUtils::WillUseHairline(quad->fDevice, GrAAType::kCoverage, quad->fEdgeFlags)) {
502
        // Don't try to apply the clip early if we know rendering will use hairline methods, as this
503
        // has an effect on the op bounds not otherwise taken into account in this function.
504
197
        return QuadOptimization::kCropped;
505
197
    }
506
507
94.6k
    auto conservativeCrop = [&]() {
508
84.4k
        static constexpr int kLargeDrawLimit = 15000;
509
        // Crop the quad to the render target. This doesn't change the visual results of drawing but
510
        // is meant to help numerical stability for excessively large draws.
511
84.4k
        if (drawBounds.width() > kLargeDrawLimit || drawBounds.height() > kLargeDrawLimit) {
512
879
            GrQuadUtils::CropToRect(rtRect, *aa, quad, /* compute local */ !constColor);
513
879
        }
514
84.4k
    };
SurfaceDrawContext.cpp:skgpu::v1::SurfaceDrawContext::attemptQuadOptimization(GrClip const*, GrUserStencilSettings const*, GrAA*, DrawQuad*, GrPaint*)::$_0::operator()() const
Line
Count
Source
507
84.4k
    auto conservativeCrop = [&]() {
508
84.4k
        static constexpr int kLargeDrawLimit = 15000;
509
        // Crop the quad to the render target. This doesn't change the visual results of drawing but
510
        // is meant to help numerical stability for excessively large draws.
511
84.4k
        if (drawBounds.width() > kLargeDrawLimit || drawBounds.height() > kLargeDrawLimit) {
512
879
            GrQuadUtils::CropToRect(rtRect, *aa, quad, /* compute local */ !constColor);
513
879
        }
514
84.4k
    };
Unexecuted instantiation: SurfaceDrawContext.cpp:skgpu::v1::SurfaceDrawContext::attemptQuadOptimization(GrClip const*, GrUserStencilSettings const*, GrAA*, DrawQuad*, GrPaint*)::$_1::operator()() const
515
516
94.6k
    bool simpleColor = !stencilSettings && constColor;
517
48.5k
    GrClip::PreClipResult result = clip ? clip->preApply(drawBounds, *aa)
518
46.1k
                                        : GrClip::PreClipResult(GrClip::Effect::kUnclipped);
519
94.6k
    switch(result.fEffect) {
520
495
        case GrClip::Effect::kClippedOut:
521
495
            return QuadOptimization::kDiscarded;
522
87.2k
        case GrClip::Effect::kUnclipped:
523
87.2k
            if (!simpleColor) {
524
77.9k
                conservativeCrop();
525
77.9k
                return QuadOptimization::kClipApplied;
526
9.37k
            } else {
527
                // Update result to store the render target bounds in order and then fall
528
                // through to attempt the draw->native clear optimization
529
9.37k
                result = GrClip::PreClipResult(SkRRect::MakeRect(rtRect), *aa);
530
9.37k
            }
531
9.37k
            break;
532
6.90k
        case GrClip::Effect::kClipped:
533
6.90k
            if (!result.fIsRRect || (stencilSettings && result.fAA != *aa) ||
534
6.53k
                (!result.fRRect.isRect() && !simpleColor)) {
535
                // The clip and draw state are too complicated to try and reduce
536
6.53k
                conservativeCrop();
537
6.53k
                return QuadOptimization::kCropped;
538
6.53k
            } // Else fall through to attempt to combine the draw and clip geometry together
539
371
            break;
540
0
        default:
541
0
            SkUNREACHABLE;
542
9.74k
    }
543
544
    // If we reached here, we know we're an axis-aligned clip that is either a rect or a round rect,
545
    // so we can potentially combine it with the draw geometry so that no clipping is needed.
546
9.74k
    SkASSERT(result.fEffect == GrClip::Effect::kClipped && result.fIsRRect);
547
9.74k
    SkRect clippedBounds = result.fRRect.getBounds();
548
9.74k
    clippedBounds.intersect(rtRect);
549
9.74k
    if (!drawBounds.intersect(clippedBounds)) {
550
        // Our fractional bounds aren't actually inside the clip. GrClip::preApply() can sometimes
551
        // think in terms of rounded-out bounds. Discard the draw.
552
0
        return QuadOptimization::kDiscarded;
553
0
    }
554
    // Guard against the clipped draw turning into a hairline draw after intersection
555
9.74k
    if (drawBounds.width() < 1.f || drawBounds.height() < 1.f) {
556
110
        return QuadOptimization::kCropped;
557
110
    }
558
559
9.63k
    if (result.fRRect.isRect()) {
560
        // No rounded corners, so we might be able to become a native clear or we might be able to
561
        // modify geometry and edge flags to represent intersected shape of clip and draw.
562
9.60k
        if (GrQuadUtils::CropToRect(clippedBounds, result.fAA, quad,
563
9.34k
                                    /*compute local*/ !constColor)) {
564
9.34k
            if (simpleColor && quad->fDevice.quadType() == GrQuad::Type::kAxisAligned) {
565
                // Clear optimization is possible
566
9.13k
                drawBounds = quad->fDevice.bounds();
567
9.13k
                if (drawBounds.contains(rtRect)) {
568
                    // Fullscreen clear
569
9.03k
                    this->clear(*constColor);
570
9.03k
                    return QuadOptimization::kSubmitted;
571
95
                } else if (GrClip::IsPixelAligned(drawBounds) &&
572
91
                           drawBounds.width() > 256 && drawBounds.height() > 256) {
573
                    // Scissor + clear (round shouldn't do anything since we are pixel aligned)
574
14
                    SkIRect scissorRect;
575
14
                    drawBounds.round(&scissorRect);
576
14
                    this->clear(scissorRect, *constColor);
577
14
                    return QuadOptimization::kSubmitted;
578
14
                }
579
290
            }
580
581
            // else the draw and clip were combined so just update the AA to reflect combination
582
290
            if (*aa == GrAA::kNo && result.fAA == GrAA::kYes &&
583
62
                quad->fEdgeFlags != GrQuadAAFlags::kNone) {
584
                // The clip was anti-aliased and now the draw needs to be upgraded to AA to
585
                // properly reflect the smooth edge of the clip.
586
62
                *aa = GrAA::kYes;
587
62
            }
588
            // We intentionally do not downgrade AA here because we don't know if we need to
589
            // preserve MSAA (see GrQuadAAFlags docs). But later in the pipeline, the ops can
590
            // use GrResolveAATypeForQuad() to turn off coverage AA when all flags are off.
591
            // deviceQuad is exactly the intersection of original quad and clip, so it can be
592
            // drawn with no clip (submitted by caller)
593
290
            return QuadOptimization::kClipApplied;
594
290
        }
595
26
    } else {
596
        // Rounded corners and constant filled color (limit ourselves to solid colors because
597
        // there is no way to use custom local coordinates with drawRRect).
598
26
        SkASSERT(simpleColor);
599
26
        if (GrQuadUtils::CropToRect(clippedBounds, result.fAA, quad,
600
26
                                    /* compute local */ false) &&
601
20
            quad->fDevice.quadType() == GrQuad::Type::kAxisAligned &&
602
20
            quad->fDevice.bounds().contains(clippedBounds)) {
603
            // Since the cropped quad became a rectangle which covered the bounds of the rrect,
604
            // we can draw the rrect directly and ignore the edge flags
605
20
            this->drawRRect(nullptr, std::move(*paint), result.fAA, SkMatrix::I(), result.fRRect,
606
20
                            GrStyle::SimpleFill());
607
20
            return QuadOptimization::kSubmitted;
608
20
        }
609
274
    }
610
611
    // The quads have been updated to better fit the clip bounds, but can't get rid of
612
    // the clip entirely
613
274
    quad->fEdgeFlags = oldFlags;
614
274
    return QuadOptimization::kCropped;
615
274
}
616
617
void SurfaceDrawContext::drawFilledQuad(const GrClip* clip,
618
                                        GrPaint&& paint,
619
                                        GrAA aa,
620
                                        DrawQuad* quad,
621
107k
                                        const GrUserStencilSettings* ss) {
622
53.6k
    ASSERT_SINGLE_OWNER
623
107k
    RETURN_IF_ABANDONED
624
53.6k
    SkDEBUGCODE(this->validate();)
625
107k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawFilledQuad", fContext);
626
627
53.6k
    AutoCheckFlush acf(this->drawingManager());
628
629
53.6k
    QuadOptimization opt = this->attemptQuadOptimization(clip, ss, &aa, quad, &paint);
630
107k
    if (opt >= QuadOptimization::kClipApplied) {
631
        // These optimizations require caller to add an op themselves
632
70.9k
        const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip;
633
85.1k
        GrAAType aaType;
634
85.1k
        if (ss) {
635
21.6k
            aaType = (aa == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
636
63.5k
        } else if (fCanUseDynamicMSAA && aa == GrAA::kNo) {
637
            // The SkGpuDevice ensures GrAA is always kYes when using dmsaa. If the caller calls
638
            // into here with GrAA::kNo, trust that they know what they're doing and that the
639
            // rendering will be equal with or without msaa.
640
0
            aaType = GrAAType::kNone;
641
63.5k
        } else {
642
63.5k
            aaType = this->chooseAAType(aa);
643
63.5k
        }
644
85.1k
        this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType,
645
85.1k
                                                      quad, ss));
646
85.1k
    }
647
    // All other optimization levels were completely handled inside attempt(), so no extra op needed
648
53.6k
}
skgpu::v1::SurfaceDrawContext::drawFilledQuad(GrClip const*, GrPaint&&, GrAA, DrawQuad*, GrUserStencilSettings const*)
Line
Count
Source
621
53.6k
                                        const GrUserStencilSettings* ss) {
622
53.6k
    ASSERT_SINGLE_OWNER
623
53.6k
    RETURN_IF_ABANDONED
624
53.6k
    SkDEBUGCODE(this->validate();)
625
53.6k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawFilledQuad", fContext);
626
627
53.6k
    AutoCheckFlush acf(this->drawingManager());
628
629
53.6k
    QuadOptimization opt = this->attemptQuadOptimization(clip, ss, &aa, quad, &paint);
630
53.6k
    if (opt >= QuadOptimization::kClipApplied) {
631
        // These optimizations require caller to add an op themselves
632
35.4k
        const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip;
633
42.5k
        GrAAType aaType;
634
42.5k
        if (ss) {
635
10.8k
            aaType = (aa == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
636
31.7k
        } else if (fCanUseDynamicMSAA && aa == GrAA::kNo) {
637
            // The SkGpuDevice ensures GrAA is always kYes when using dmsaa. If the caller calls
638
            // into here with GrAA::kNo, trust that they know what they're doing and that the
639
            // rendering will be equal with or without msaa.
640
0
            aaType = GrAAType::kNone;
641
31.7k
        } else {
642
31.7k
            aaType = this->chooseAAType(aa);
643
31.7k
        }
644
42.5k
        this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType,
645
42.5k
                                                      quad, ss));
646
42.5k
    }
647
    // All other optimization levels were completely handled inside attempt(), so no extra op needed
648
53.6k
}
skgpu::v1::SurfaceDrawContext::drawFilledQuad(GrClip const*, GrPaint&&, GrAA, DrawQuad*, GrUserStencilSettings const*)
Line
Count
Source
621
53.6k
                                        const GrUserStencilSettings* ss) {
622
53.6k
    ASSERT_SINGLE_OWNER
623
53.6k
    RETURN_IF_ABANDONED
624
53.6k
    SkDEBUGCODE(this->validate();)
625
53.6k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawFilledQuad", fContext);
626
627
53.6k
    AutoCheckFlush acf(this->drawingManager());
628
629
53.6k
    QuadOptimization opt = this->attemptQuadOptimization(clip, ss, &aa, quad, &paint);
630
53.6k
    if (opt >= QuadOptimization::kClipApplied) {
631
        // These optimizations require caller to add an op themselves
632
35.4k
        const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip;
633
42.5k
        GrAAType aaType;
634
42.5k
        if (ss) {
635
10.8k
            aaType = (aa == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
636
31.7k
        } else if (fCanUseDynamicMSAA && aa == GrAA::kNo) {
637
            // The SkGpuDevice ensures GrAA is always kYes when using dmsaa. If the caller calls
638
            // into here with GrAA::kNo, trust that they know what they're doing and that the
639
            // rendering will be equal with or without msaa.
640
0
            aaType = GrAAType::kNone;
641
31.7k
        } else {
642
31.7k
            aaType = this->chooseAAType(aa);
643
31.7k
        }
644
42.5k
        this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType,
645
42.5k
                                                      quad, ss));
646
42.5k
    }
647
    // All other optimization levels were completely handled inside attempt(), so no extra op needed
648
53.6k
}
649
650
void SurfaceDrawContext::drawTexture(const GrClip* clip,
651
                                     GrSurfaceProxyView view,
652
                                     SkAlphaType srcAlphaType,
653
                                     GrSamplerState::Filter filter,
654
                                     GrSamplerState::MipmapMode mm,
655
                                     SkBlendMode blendMode,
656
                                     const SkPMColor4f& color,
657
                                     const SkRect& srcRect,
658
                                     const SkRect& dstRect,
659
                                     GrAA aa,
660
                                     GrQuadAAFlags edgeAA,
661
                                     SkCanvas::SrcRectConstraint constraint,
662
                                     const SkMatrix& viewMatrix,
663
42.7k
                                     sk_sp<GrColorSpaceXform> colorSpaceXform) {
664
    // If we are using dmsaa then go through GrFillRRectOp (via fillRectToRect).
665
42.7k
    if ((this->alwaysAntialias() || this->caps()->reducedShaderMode()) && aa == GrAA::kYes) {
666
0
        GrPaint paint;
667
0
        paint.setColor4f(color);
668
0
        std::unique_ptr<GrFragmentProcessor> fp;
669
0
        if (constraint == SkCanvas::kStrict_SrcRectConstraint) {
670
0
            fp = GrTextureEffect::MakeSubset(view, srcAlphaType, SkMatrix::I(),
671
0
                                             GrSamplerState(filter, mm), srcRect,
672
0
                                             *this->caps());
673
0
        } else {
674
0
            fp = GrTextureEffect::Make(view, srcAlphaType, SkMatrix::I(), filter, mm);
675
0
        }
676
0
        if (colorSpaceXform) {
677
0
            fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(colorSpaceXform));
678
0
        }
679
0
        fp = GrBlendFragmentProcessor::Make(std::move(fp), nullptr, SkBlendMode::kModulate);
680
0
        paint.setColorFragmentProcessor(std::move(fp));
681
0
        if (blendMode != SkBlendMode::kSrcOver) {
682
0
            paint.setXPFactory(SkBlendMode_AsXPFactory(blendMode));
683
0
        }
684
0
        this->fillRectToRect(clip, std::move(paint), GrAA::kYes, viewMatrix, dstRect, srcRect);
685
0
        return;
686
0
    }
687
688
42.7k
    const SkRect* subset = constraint == SkCanvas::kStrict_SrcRectConstraint ?
689
31.2k
            &srcRect : nullptr;
690
42.7k
    DrawQuad quad{GrQuad::MakeFromRect(dstRect, viewMatrix), GrQuad(srcRect), edgeAA};
691
692
42.7k
    this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(colorSpaceXform), filter,
693
42.7k
                           mm, color, blendMode, aa, &quad, subset);
694
42.7k
}
695
696
void SurfaceDrawContext::drawTexturedQuad(const GrClip* clip,
697
                                          GrSurfaceProxyView proxyView,
698
                                          SkAlphaType srcAlphaType,
699
                                          sk_sp<GrColorSpaceXform> textureXform,
700
                                          GrSamplerState::Filter filter,
701
                                          GrSamplerState::MipmapMode mm,
702
                                          const SkPMColor4f& color,
703
                                          SkBlendMode blendMode,
704
                                          GrAA aa,
705
                                          DrawQuad* quad,
706
42.7k
                                          const SkRect* subset) {
707
42.7k
    ASSERT_SINGLE_OWNER
708
42.7k
    RETURN_IF_ABANDONED
709
42.7k
    SkDEBUGCODE(this->validate();)
710
42.7k
    SkASSERT(proxyView.asTextureProxy());
711
42.7k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawTexturedQuad", fContext);
712
713
42.7k
    AutoCheckFlush acf(this->drawingManager());
714
715
    // Functionally this is very similar to drawFilledQuad except that there's no constColor to
716
    // enable the kSubmitted optimizations, no stencil settings support, and its a GrTextureOp.
717
42.7k
    QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr/*stencil*/, &aa, quad,
718
42.7k
                                                         nullptr/*paint*/);
719
720
42.7k
    SkASSERT(opt != QuadOptimization::kSubmitted);
721
42.7k
    if (opt != QuadOptimization::kDiscarded) {
722
        // And the texture op if not discarded
723
42.7k
        const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip;
724
42.7k
        GrAAType aaType = this->chooseAAType(aa);
725
42.7k
        auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
726
0
        auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
727
42.7k
                                                          : GrTextureOp::Saturate::kNo;
728
        // Use the provided subset, although hypothetically we could detect that the cropped local
729
        // quad is sufficiently inside the subset and the constraint could be dropped.
730
42.7k
        this->addDrawOp(finalClip,
731
42.7k
                        GrTextureOp::Make(fContext, std::move(proxyView), srcAlphaType,
732
42.7k
                                          std::move(textureXform), filter, mm, color, saturate,
733
42.7k
                                          blendMode, aaType, quad, subset));
734
42.7k
    }
735
42.7k
}
736
737
void SurfaceDrawContext::drawRect(const GrClip* clip,
738
                                  GrPaint&& paint,
739
                                  GrAA aa,
740
                                  const SkMatrix& viewMatrix,
741
                                  const SkRect& rect,
742
3.32k
                                  const GrStyle* style) {
743
3.32k
    if (!style) {
744
55
        style = &GrStyle::SimpleFill();
745
55
    }
746
3.32k
    ASSERT_SINGLE_OWNER
747
3.32k
    RETURN_IF_ABANDONED
748
3.32k
    SkDEBUGCODE(this->validate();)
749
3.32k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawRect", fContext);
750
751
    // Path effects should've been devolved to a path in SkGpuDevice
752
3.32k
    SkASSERT(!style->pathEffect());
753
754
3.32k
    AutoCheckFlush acf(this->drawingManager());
755
756
3.32k
    const SkStrokeRec& stroke = style->strokeRec();
757
3.32k
    if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
758
        // Fills the rect, using rect as its own local coordinates
759
2.72k
        this->fillRectToRect(clip, std::move(paint), aa, viewMatrix, rect, rect);
760
2.72k
        return;
761
602
    } else if ((stroke.getStyle() == SkStrokeRec::kStroke_Style ||
762
475
                stroke.getStyle() == SkStrokeRec::kHairline_Style) &&
763
346
               rect.width()                                        &&
764
346
               rect.height()                                       &&
765
346
               !this->caps()->reducedShaderMode()) {
766
        // Only use the StrokeRectOp for non-empty rectangles. Empty rectangles will be processed by
767
        // GrStyledShape to handle stroke caps and dashing properly.
768
        //
769
        // http://skbug.com/12206 -- there is a double-blend issue with the bevel version of
770
        // AAStrokeRectOp, and if we increase the AA bloat for MSAA it becomes more pronounced.
771
        // Don't use the bevel version with DMSAA.
772
346
        GrAAType aaType = (fCanUseDynamicMSAA &&
773
0
                           stroke.getJoin() == SkPaint::kMiter_Join &&
774
0
                           stroke.getMiter() >= SK_ScalarSqrt2) ? GrAAType::kCoverage
775
346
                                                                : this->chooseAAType(aa);
776
346
        GrOp::Owner op = GrStrokeRectOp::Make(
777
346
                fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
778
        // op may be null if the stroke is not supported or if using coverage aa and the view matrix
779
        // does not preserve rectangles.
780
346
        if (op) {
781
176
            this->addDrawOp(clip, std::move(op));
782
176
            return;
783
176
        }
784
426
    }
785
426
    assert_alive(paint);
786
426
    this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
787
426
                                     GrStyledShape(rect, *style, DoSimplify::kNo));
788
426
}
789
790
void SurfaceDrawContext::fillRectToRect(const GrClip* clip,
791
                                        GrPaint&& paint,
792
                                        GrAA aa,
793
                                        const SkMatrix& viewMatrix,
794
                                        const SkRect& rectToDraw,
795
16.5k
                                        const SkRect& localRect) {
796
16.5k
    DrawQuad quad{GrQuad::MakeFromRect(rectToDraw, viewMatrix), GrQuad(localRect),
797
14.0k
                  aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone};
798
799
    // If we are using dmsaa then attempt to draw the rect with GrFillRRectOp.
800
16.5k
    if ((fContext->priv().caps()->reducedShaderMode() || this->alwaysAntialias()) &&
801
0
        this->caps()->drawInstancedSupport()                                      &&
802
0
        aa == GrAA::kYes) {  // If aa is kNo when using dmsaa, the rect is axis aligned. Don't use
803
                             // GrFillRRectOp because it might require dual source blending.
804
                             // http://skbug.com/11756
805
0
        QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr/*stencil*/, &aa, &quad,
806
0
                                                             &paint);
807
0
        if (opt < QuadOptimization::kClipApplied) {
808
            // The optimization was completely handled inside attempt().
809
0
            return;
810
0
        }
811
812
0
        SkRect croppedRect, croppedLocal{};
813
0
        const GrClip* optimizedClip = clip;
814
0
        if (clip && viewMatrix.isScaleTranslate() && quad.fDevice.asRect(&croppedRect) &&
815
0
            (!paint.usesLocalCoords() || quad.fLocal.asRect(&croppedLocal))) {
816
            // The cropped quad is still a rect, and our view matrix preserves rects. Map it back
817
            // to pre-matrix space.
818
0
            SkMatrix inverse;
819
0
            if (!viewMatrix.invert(&inverse)) {
820
0
                return;
821
0
            }
822
0
            SkASSERT(inverse.rectStaysRect());
823
0
            inverse.mapRect(&croppedRect);
824
0
            if (opt == QuadOptimization::kClipApplied) {
825
0
                optimizedClip = nullptr;
826
0
            }
827
0
        } else {
828
            // Even if attemptQuadOptimization gave us an optimized quad, GrFillRRectOp needs a rect
829
            // in pre-matrix space, so use the original rect. Also preserve the original clip.
830
0
            croppedRect = rectToDraw;
831
0
            croppedLocal = localRect;
832
0
        }
833
834
0
        if (auto op = GrFillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint),
835
0
                                          viewMatrix, SkRRect::MakeRect(croppedRect), croppedLocal,
836
0
                                          GrAA::kYes)) {
837
0
            this->addDrawOp(optimizedClip, std::move(op));
838
0
            return;
839
0
        }
840
16.5k
    }
841
842
16.5k
    assert_alive(paint);
843
16.5k
    this->drawFilledQuad(clip, std::move(paint), aa, &quad);
844
16.5k
}
845
846
void SurfaceDrawContext::drawQuadSet(const GrClip* clip,
847
                                     GrPaint&& paint,
848
                                     GrAA aa,
849
                                     const SkMatrix& viewMatrix,
850
                                     const GrQuadSetEntry quads[],
851
0
                                     int cnt) {
852
0
    GrAAType aaType = this->chooseAAType(aa);
853
854
0
    GrFillRectOp::AddFillRectOps(this, clip, fContext, std::move(paint), aaType, viewMatrix,
855
0
                                 quads, cnt);
856
0
}
857
858
12.8k
int SurfaceDrawContext::maxWindowRectangles() const {
859
12.8k
    return this->asRenderTargetProxy()->maxWindowRectangles(*this->caps());
860
12.8k
}
861
862
25.1k
GrOpsTask::CanDiscardPreviousOps SurfaceDrawContext::canDiscardPreviousOpsOnFullClear() const {
863
25.1k
#if GR_TEST_UTILS
864
25.1k
    if (fPreserveOpsOnFullClear_TestingOnly) {
865
0
        return GrOpsTask::CanDiscardPreviousOps::kNo;
866
0
    }
867
25.1k
#endif
868
    // Regardless of how the clear is implemented (native clear or a fullscreen quad), all prior ops
869
    // would normally be overwritten. The one exception is if the render target context is marked as
870
    // needing a stencil buffer then there may be a prior op that writes to the stencil buffer.
871
    // Although the clear will ignore the stencil buffer, following draw ops may not so we can't get
872
    // rid of all the preceding ops. Beware! If we ever add any ops that have a side effect beyond
873
    // modifying the stencil buffer we will need a more elaborate tracking system (skbug.com/7002).
874
25.1k
    return GrOpsTask::CanDiscardPreviousOps(!fNeedsStencil);
875
25.1k
}
876
877
10.4k
void SurfaceDrawContext::setNeedsStencil() {
878
    // Don't clear stencil until after we've set fNeedsStencil. This ensures we don't loop forever
879
    // in the event that there are driver bugs and we need to clear as a draw.
880
10.4k
    bool hasInitializedStencil = fNeedsStencil;
881
10.4k
    fNeedsStencil = true;
882
10.4k
    if (!hasInitializedStencil) {
883
136
        this->asRenderTargetProxy()->setNeedsStencil();
884
136
        if (this->caps()->performStencilClearsAsDraws()) {
885
            // There is a driver bug with clearing stencil. We must use an op to manually clear the
886
            // stencil buffer before the op that required 'setNeedsStencil'.
887
0
            this->internalStencilClear(nullptr, /* inside mask */ false);
888
136
        } else {
889
136
            this->getOpsTask()->setInitialStencilContent(
890
136
                    GrOpsTask::StencilContent::kUserBitsCleared);
891
136
        }
892
136
    }
893
10.4k
}
894
895
1.82k
void SurfaceDrawContext::internalStencilClear(const SkIRect* scissor, bool insideStencilMask) {
896
1.82k
    this->setNeedsStencil();
897
898
1.82k
    GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions());
899
1.82k
    if (scissor && !scissorState.set(*scissor)) {
900
        // The requested clear region is off screen, so nothing to do.
901
0
        return;
902
0
    }
903
904
1.82k
    bool clearWithDraw = this->caps()->performStencilClearsAsDraws() ||
905
1.82k
                         (scissorState.enabled() && this->caps()->performPartialClearsAsDraws());
906
1.82k
    if (clearWithDraw) {
907
0
        const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
908
909
        // Configure the paint to have no impact on the color buffer
910
0
        GrPaint paint;
911
0
        paint.setXPFactory(GrDisableColorXPFactory::Get());
912
0
        this->addDrawOp(nullptr,
913
0
                        GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
914
0
                                                    SkRect::Make(scissorState.rect()), ss));
915
1.82k
    } else {
916
1.82k
        this->addOp(GrClearOp::MakeStencilClip(fContext, scissorState, insideStencilMask));
917
1.82k
    }
918
1.82k
}
919
920
bool SurfaceDrawContext::stencilPath(const GrHardClip* clip,
921
                                     GrAA doStencilMSAA,
922
                                     const SkMatrix& viewMatrix,
923
0
                                     const SkPath& path) {
924
0
    SkIRect clipBounds = clip ? clip->getConservativeBounds()
925
0
                              : SkIRect::MakeSize(this->dimensions());
926
0
    GrStyledShape shape(path, GrStyledShape::DoSimplify::kNo);
927
928
0
    PathRenderer::CanDrawPathArgs canDrawArgs;
929
0
    canDrawArgs.fCaps = fContext->priv().caps();
930
0
    canDrawArgs.fProxy = this->asRenderTargetProxy();
931
0
    canDrawArgs.fClipConservativeBounds = &clipBounds;
932
0
    canDrawArgs.fViewMatrix = &viewMatrix;
933
0
    canDrawArgs.fShape = &shape;
934
0
    canDrawArgs.fPaint = nullptr;
935
0
    canDrawArgs.fSurfaceProps = &fSurfaceProps;
936
0
    canDrawArgs.fAAType = (doStencilMSAA == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
937
0
    canDrawArgs.fHasUserStencilSettings = false;
938
0
    auto pr = this->drawingManager()->getPathRenderer(canDrawArgs,
939
0
                                                      false,
940
0
                                                      PathRendererChain::DrawType::kStencil);
941
0
    if (!pr) {
942
0
        SkDebugf("WARNING: No path renderer to stencil path.\n");
943
0
        return false;
944
0
    }
945
946
0
    PathRenderer::StencilPathArgs args;
947
0
    args.fContext = fContext;
948
0
    args.fSurfaceDrawContext = this;
949
0
    args.fClip = clip;
950
0
    args.fClipConservativeBounds = &clipBounds;
951
0
    args.fViewMatrix = &viewMatrix;
952
0
    args.fShape = &shape;
953
0
    args.fDoStencilMSAA = doStencilMSAA;
954
0
    pr->stencilPath(args);
955
0
    return true;
956
0
}
957
958
void SurfaceDrawContext::drawTextureSet(const GrClip* clip,
959
                                        GrTextureSetEntry set[],
960
                                        int cnt,
961
                                        int proxyRunCnt,
962
                                        GrSamplerState::Filter filter,
963
                                        GrSamplerState::MipmapMode mm,
964
                                        SkBlendMode mode,
965
                                        GrAA aa,
966
                                        SkCanvas::SrcRectConstraint constraint,
967
                                        const SkMatrix& viewMatrix,
968
0
                                        sk_sp<GrColorSpaceXform> texXform) {
969
0
    ASSERT_SINGLE_OWNER
970
0
    RETURN_IF_ABANDONED
971
0
    SkDEBUGCODE(this->validate();)
972
0
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawTextureSet", fContext);
973
974
    // Create the minimum number of GrTextureOps needed to draw this set. Individual
975
    // GrTextureOps can rebind the texture between draws thus avoiding GrPaint (re)creation.
976
0
    AutoCheckFlush acf(this->drawingManager());
977
0
    GrAAType aaType = this->chooseAAType(aa);
978
0
    auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
979
0
    auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
980
0
                                                      : GrTextureOp::Saturate::kNo;
981
0
    GrTextureOp::AddTextureSetOps(this, clip, fContext, set, cnt, proxyRunCnt, filter, mm, saturate,
982
0
                                  mode, aaType, constraint, viewMatrix, std::move(texXform));
983
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawTextureSet(GrClip const*, GrTextureSetEntry*, int, int, SkFilterMode, SkMipmapMode, SkBlendMode, GrAA, SkCanvas::SrcRectConstraint, SkMatrix const&, sk_sp<GrColorSpaceXform>)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawTextureSet(GrClip const*, GrTextureSetEntry*, int, int, SkFilterMode, SkMipmapMode, SkBlendMode, GrAA, SkCanvas::SrcRectConstraint, SkMatrix const&, sk_sp<GrColorSpaceXform>)
984
985
void SurfaceDrawContext::drawVertices(const GrClip* clip,
986
                                      GrPaint&& paint,
987
                                      const SkMatrixProvider& matrixProvider,
988
                                      sk_sp<SkVertices> vertices,
989
                                      GrPrimitiveType* overridePrimType,
990
1.85k
                                      const SkRuntimeEffect* effect) {
991
1.85k
    ASSERT_SINGLE_OWNER
992
1.85k
    RETURN_IF_ABANDONED
993
1.85k
    SkDEBUGCODE(this->validate();)
994
1.85k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawVertices", fContext);
995
996
1.85k
    AutoCheckFlush acf(this->drawingManager());
997
998
1.85k
    SkASSERT(vertices);
999
1.85k
    GrAAType aaType = fCanUseDynamicMSAA ? GrAAType::kMSAA : this->chooseAAType(GrAA::kNo);
1000
1.85k
    GrOp::Owner op =
1001
1.85k
            GrDrawVerticesOp::Make(fContext, std::move(paint), std::move(vertices), matrixProvider,
1002
1.85k
                                   aaType, this->colorInfo().refColorSpaceXformFromSRGB(),
1003
1.85k
                                   overridePrimType, effect);
1004
1.85k
    this->addDrawOp(clip, std::move(op));
1005
1.85k
}
1006
1007
///////////////////////////////////////////////////////////////////////////////
1008
1009
void SurfaceDrawContext::drawAtlas(const GrClip* clip,
1010
                                   GrPaint&& paint,
1011
                                   const SkMatrix& viewMatrix,
1012
                                   int spriteCount,
1013
                                   const SkRSXform xform[],
1014
                                   const SkRect texRect[],
1015
0
                                   const SkColor colors[]) {
1016
0
    ASSERT_SINGLE_OWNER
1017
0
    RETURN_IF_ABANDONED
1018
0
    SkDEBUGCODE(this->validate();)
1019
0
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawAtlas", fContext);
1020
1021
0
    AutoCheckFlush acf(this->drawingManager());
1022
1023
0
    GrAAType aaType = this->chooseAAType(GrAA::kNo);
1024
0
    GrOp::Owner op = GrDrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1025
0
                                         aaType, spriteCount, xform, texRect, colors);
1026
0
    this->addDrawOp(clip, std::move(op));
1027
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawAtlas(GrClip const*, GrPaint&&, SkMatrix const&, int, SkRSXform const*, SkRect const*, unsigned int const*)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawAtlas(GrClip const*, GrPaint&&, SkMatrix const&, int, SkRSXform const*, SkRect const*, unsigned int const*)
1028
1029
///////////////////////////////////////////////////////////////////////////////
1030
1031
void SurfaceDrawContext::drawRRect(const GrClip* origClip,
1032
                                   GrPaint&& paint,
1033
                                   GrAA aa,
1034
                                   const SkMatrix& viewMatrix,
1035
                                   const SkRRect& rrect,
1036
118
                                   const GrStyle& style) {
1037
118
    ASSERT_SINGLE_OWNER
1038
118
    RETURN_IF_ABANDONED
1039
118
    SkDEBUGCODE(this->validate();)
1040
118
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawRRect", fContext);
1041
1042
118
    SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1043
1044
118
    const SkStrokeRec& stroke = style.strokeRec();
1045
118
    if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
1046
13
       return;
1047
13
    }
1048
1049
105
    const GrClip* clip = origClip;
1050
    // It is not uncommon to clip to a round rect and then draw that same round rect. Since our
1051
    // lower level clip code works from op bounds, which are SkRects, it doesn't detect that the
1052
    // clip can be ignored. The following test attempts to mitigate the stencil clip cost but only
1053
    // works for axis-aligned round rects. This also only works for filled rrects since the stroke
1054
    // width outsets beyond the rrect itself.
1055
    // TODO: skbug.com/10462 - There was mixed performance wins and regressions when this
1056
    // optimization was turned on outside of Android Framework. I (michaelludwig) believe this is
1057
    // do to the overhead in determining if an SkClipStack is just a rrect. Once that is improved,
1058
    // re-enable this and see if we avoid the regressions.
1059
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1060
    SkRRect devRRect;
1061
    if (clip && stroke.getStyle() == SkStrokeRec::kFill_Style &&
1062
        rrect.transform(viewMatrix, &devRRect)) {
1063
        GrClip::PreClipResult result = clip->preApply(devRRect.getBounds(), aa);
1064
        switch(result.fEffect) {
1065
            case GrClip::Effect::kClippedOut:
1066
                return;
1067
            case GrClip::Effect::kUnclipped:
1068
                clip = nullptr;
1069
                break;
1070
            case GrClip::Effect::kClipped:
1071
                // Currently there's no general-purpose rrect-to-rrect contains function, and if we
1072
                // got here, we know the devRRect's bounds aren't fully contained by the clip.
1073
                // Testing for equality between the two is a reasonable stop-gap for now.
1074
                if (result.fIsRRect && result.fRRect == devRRect) {
1075
                    // NOTE: On the android framework, we allow this optimization even when the clip
1076
                    // is non-AA and the draw is AA.
1077
                    if (result.fAA == aa || (result.fAA == GrAA::kNo && aa == GrAA::kYes)) {
1078
                        clip = nullptr;
1079
                    }
1080
                }
1081
                break;
1082
            default:
1083
                SkUNREACHABLE;
1084
        }
1085
    }
1086
#endif
1087
1088
105
    AutoCheckFlush acf(this->drawingManager());
1089
1090
105
    GrAAType aaType = this->chooseAAType(aa);
1091
1092
105
    GrOp::Owner op;
1093
105
    if (aaType == GrAAType::kCoverage                          &&
1094
81
        !fCanUseDynamicMSAA                                    &&
1095
81
        !this->caps()->reducedShaderMode()                     &&
1096
81
        rrect.isSimple()                                       &&
1097
66
        rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY &&
1098
61
        viewMatrix.rectStaysRect() && viewMatrix.isSimilarity()) {
1099
        // In specific cases we use a dedicated circular round rect op to try and get better perf.
1100
5
        assert_alive(paint);
1101
5
        op = GrOvalOpFactory::MakeCircularRRectOp(fContext, std::move(paint), viewMatrix, rrect,
1102
5
                                                  stroke, this->caps()->shaderCaps());
1103
5
    }
1104
105
    if (!op && style.isSimpleFill()) {
1105
100
        assert_alive(paint);
1106
100
        op = GrFillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint), viewMatrix, rrect,
1107
100
                                 rrect.rect(), GrAA(aaType != GrAAType::kNone));
1108
100
    }
1109
105
    if (!op && (aaType == GrAAType::kCoverage || fCanUseDynamicMSAA)) {
1110
76
        assert_alive(paint);
1111
76
        op = GrOvalOpFactory::MakeRRectOp(
1112
76
                fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1113
76
    }
1114
105
    if (op) {
1115
7
        this->addDrawOp(clip, std::move(op));
1116
7
        return;
1117
7
    }
1118
1119
98
    assert_alive(paint);
1120
98
    this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1121
98
                                     GrStyledShape(rrect, style, DoSimplify::kNo));
1122
98
}
1123
1124
///////////////////////////////////////////////////////////////////////////////
1125
1126
bool SurfaceDrawContext::drawFastShadow(const GrClip* clip,
1127
                                        const SkMatrix& viewMatrix,
1128
                                        const SkPath& path,
1129
0
                                        const SkDrawShadowRec& rec) {
1130
0
    ASSERT_SINGLE_OWNER
1131
0
    if (fContext->abandoned()) {
1132
0
        return true;
1133
0
    }
1134
0
    SkDEBUGCODE(this->validate();)
1135
0
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawFastShadow", fContext);
1136
1137
    // check z plane
1138
0
    bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1139
0
                               !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1140
0
    bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1141
0
    if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1142
0
        return false;
1143
0
    }
1144
1145
0
    SkRRect rrect;
1146
0
    SkRect rect;
1147
    // we can only handle rects, circles, and simple rrects with circular corners
1148
0
    bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsNearlySimpleCircular(rrect) &&
1149
0
                   rrect.getSimpleRadii().fX > SK_ScalarNearlyZero;
1150
0
    if (!isRRect &&
1151
0
        path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1152
0
        rect.width() > SK_ScalarNearlyZero) {
1153
0
        rrect.setOval(rect);
1154
0
        isRRect = true;
1155
0
    }
1156
0
    if (!isRRect && path.isRect(&rect)) {
1157
0
        rrect.setRect(rect);
1158
0
        isRRect = true;
1159
0
    }
1160
1161
0
    if (!isRRect) {
1162
0
        return false;
1163
0
    }
1164
1165
0
    if (rrect.isEmpty()) {
1166
0
        return true;
1167
0
    }
1168
1169
0
    AutoCheckFlush acf(this->drawingManager());
1170
1171
0
    SkPoint3 devLightPos = rec.fLightPos;
1172
0
    bool directional = SkToBool(rec.fFlags & kDirectionalLight_ShadowFlag);
1173
0
    if (!directional) {
1174
        // transform light
1175
0
        viewMatrix.mapPoints((SkPoint*)&devLightPos.fX, 1);
1176
0
    }
1177
1178
    // 1/scale
1179
0
    SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1180
0
        SkScalarInvert(SkScalarAbs(viewMatrix[SkMatrix::kMScaleX])) :
1181
0
        sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1182
0
                       viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1183
1184
0
    SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1185
0
    bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1186
1187
0
    if (SkColorGetA(rec.fAmbientColor) > 0) {
1188
0
        SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1189
0
        const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1190
0
        const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
1191
1192
        // Outset the shadow rrect to the border of the penumbra
1193
0
        SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1194
0
        SkRRect ambientRRect;
1195
0
        SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1196
        // If the rrect was an oval then its outset will also be one.
1197
        // We set it explicitly to avoid errors.
1198
0
        if (rrect.isOval()) {
1199
0
            ambientRRect = SkRRect::MakeOval(outsetRect);
1200
0
        } else {
1201
0
            SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
1202
0
            ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1203
0
        }
1204
1205
0
        GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
1206
0
        if (transparent) {
1207
            // set a large inset to force a fill
1208
0
            devSpaceInsetWidth = ambientRRect.width();
1209
0
        }
1210
1211
0
        GrOp::Owner op = GrShadowRRectOp::Make(fContext,
1212
0
                                               ambientColor,
1213
0
                                               viewMatrix,
1214
0
                                               ambientRRect,
1215
0
                                               devSpaceAmbientBlur,
1216
0
                                               devSpaceInsetWidth);
1217
0
        if (op) {
1218
0
            this->addDrawOp(clip, std::move(op));
1219
0
        }
1220
0
    }
1221
1222
0
    if (SkColorGetA(rec.fSpotColor) > 0) {
1223
0
        SkScalar devSpaceSpotBlur;
1224
0
        SkScalar spotScale;
1225
0
        SkVector spotOffset;
1226
0
        if (directional) {
1227
0
            SkDrawShadowMetrics::GetDirectionalParams(occluderHeight, devLightPos.fX,
1228
0
                                                      devLightPos.fY, devLightPos.fZ,
1229
0
                                                      rec.fLightRadius, &devSpaceSpotBlur,
1230
0
                                                      &spotScale, &spotOffset);
1231
0
        } else {
1232
0
            SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1233
0
                                               devLightPos.fZ, rec.fLightRadius,
1234
0
                                               &devSpaceSpotBlur, &spotScale, &spotOffset);
1235
0
        }
1236
        // handle scale of radius due to CTM
1237
0
        const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1238
1239
        // Adjust translate for the effect of the scale.
1240
0
        spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1241
0
        spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1242
        // This offset is in dev space, need to transform it into source space.
1243
0
        SkMatrix ctmInverse;
1244
0
        if (viewMatrix.invert(&ctmInverse)) {
1245
0
            ctmInverse.mapPoints(&spotOffset, 1);
1246
0
        } else {
1247
            // Since the matrix is a similarity, this should never happen, but just in case...
1248
0
            SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1249
0
            SkASSERT(false);
1250
0
        }
1251
1252
        // Compute the transformed shadow rrect
1253
0
        SkRRect spotShadowRRect;
1254
0
        SkMatrix shadowTransform;
1255
0
        shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1256
0
        rrect.transform(shadowTransform, &spotShadowRRect);
1257
0
        SkScalar spotRadius = spotShadowRRect.getSimpleRadii().fX;
1258
1259
        // Compute the insetWidth
1260
0
        SkScalar blurOutset = srcSpaceSpotBlur;
1261
0
        SkScalar insetWidth = blurOutset;
1262
0
        if (transparent) {
1263
            // If transparent, just do a fill
1264
0
            insetWidth += spotShadowRRect.width();
1265
0
        } else {
1266
            // For shadows, instead of using a stroke we specify an inset from the penumbra
1267
            // border. We want to extend this inset area so that it meets up with the caster
1268
            // geometry. The inset geometry will by default already be inset by the blur width.
1269
            //
1270
            // We compare the min and max corners inset by the radius between the original
1271
            // rrect and the shadow rrect. The distance between the two plus the difference
1272
            // between the scaled radius and the original radius gives the distance from the
1273
            // transformed shadow shape to the original shape in that corner. The max
1274
            // of these gives the maximum distance we need to cover.
1275
            //
1276
            // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1277
            // that to get the full insetWidth.
1278
0
            SkScalar maxOffset;
1279
0
            if (rrect.isRect()) {
1280
                // Manhattan distance works better for rects
1281
0
                maxOffset = std::max(std::max(SkTAbs(spotShadowRRect.rect().fLeft -
1282
0
                                                 rrect.rect().fLeft),
1283
0
                                          SkTAbs(spotShadowRRect.rect().fTop -
1284
0
                                                 rrect.rect().fTop)),
1285
0
                                   std::max(SkTAbs(spotShadowRRect.rect().fRight -
1286
0
                                                 rrect.rect().fRight),
1287
0
                                          SkTAbs(spotShadowRRect.rect().fBottom -
1288
0
                                                 rrect.rect().fBottom)));
1289
0
            } else {
1290
0
                SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
1291
0
                SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1292
0
                                                        rrect.rect().fLeft + dr,
1293
0
                                                        spotShadowRRect.rect().fTop -
1294
0
                                                        rrect.rect().fTop + dr);
1295
0
                SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1296
0
                                                         rrect.rect().fRight - dr,
1297
0
                                                         spotShadowRRect.rect().fBottom -
1298
0
                                                         rrect.rect().fBottom - dr);
1299
0
                maxOffset = SkScalarSqrt(std::max(SkPointPriv::LengthSqd(upperLeftOffset),
1300
0
                                                  SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
1301
0
            }
1302
0
            insetWidth += std::max(blurOutset, maxOffset);
1303
0
        }
1304
1305
        // Outset the shadow rrect to the border of the penumbra
1306
0
        SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1307
0
        if (spotShadowRRect.isOval()) {
1308
0
            spotShadowRRect = SkRRect::MakeOval(outsetRect);
1309
0
        } else {
1310
0
            SkScalar outsetRad = spotRadius + blurOutset;
1311
0
            spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1312
0
        }
1313
1314
0
        GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
1315
1316
0
        GrOp::Owner op = GrShadowRRectOp::Make(fContext,
1317
0
                                               spotColor,
1318
0
                                               viewMatrix,
1319
0
                                               spotShadowRRect,
1320
0
                                               2.0f * devSpaceSpotBlur,
1321
0
                                               insetWidth);
1322
0
        if (op) {
1323
0
            this->addDrawOp(clip, std::move(op));
1324
0
        }
1325
0
    }
1326
1327
0
    return true;
1328
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawFastShadow(GrClip const*, SkMatrix const&, SkPath const&, SkDrawShadowRec const&)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawFastShadow(GrClip const*, SkMatrix const&, SkPath const&, SkDrawShadowRec const&)
1329
1330
///////////////////////////////////////////////////////////////////////////////
1331
1332
void SurfaceDrawContext::drawRegion(const GrClip* clip,
1333
                                    GrPaint&& paint,
1334
                                    GrAA aa,
1335
                                    const SkMatrix& viewMatrix,
1336
                                    const SkRegion& region,
1337
                                    const GrStyle& style,
1338
0
                                    const GrUserStencilSettings* ss) {
1339
0
    ASSERT_SINGLE_OWNER
1340
0
    RETURN_IF_ABANDONED
1341
0
    SkDEBUGCODE(this->validate();)
1342
0
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawRegion", fContext);
1343
1344
0
    if (GrAA::kYes == aa) {
1345
        // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1346
        // to see whether aa is really required.
1347
0
        if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1348
0
            SkScalarIsInt(viewMatrix.getTranslateX()) &&
1349
0
            SkScalarIsInt(viewMatrix.getTranslateY())) {
1350
0
            aa = GrAA::kNo;
1351
0
        }
1352
0
    }
1353
0
    bool complexStyle = !style.isSimpleFill();
1354
0
    if (complexStyle || GrAA::kYes == aa) {
1355
0
        SkPath path;
1356
0
        region.getBoundaryPath(&path);
1357
0
        path.setIsVolatile(true);
1358
1359
0
        return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1360
0
    }
1361
1362
0
    GrAAType aaType = (this->numSamples() > 1)
1363
0
                    ? GrAAType::kMSAA
1364
0
                    : GrAAType::kNone;
1365
0
    GrOp::Owner op = GrRegionOp::Make(fContext, std::move(paint), viewMatrix, region, aaType, ss);
1366
0
    this->addDrawOp(clip, std::move(op));
1367
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawRegion(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, SkRegion const&, GrStyle const&, GrUserStencilSettings const*)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawRegion(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, SkRegion const&, GrStyle const&, GrUserStencilSettings const*)
1368
1369
void SurfaceDrawContext::drawOval(const GrClip* clip,
1370
                                  GrPaint&& paint,
1371
                                  GrAA aa,
1372
                                  const SkMatrix& viewMatrix,
1373
                                  const SkRect& oval,
1374
46
                                  const GrStyle& style) {
1375
23
    ASSERT_SINGLE_OWNER
1376
46
    RETURN_IF_ABANDONED
1377
23
    SkDEBUGCODE(this->validate();)
1378
46
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawOval", fContext);
1379
1380
23
    const SkStrokeRec& stroke = style.strokeRec();
1381
1382
46
    if (oval.isEmpty() && !style.pathEffect()) {
1383
0
        if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1384
0
            return;
1385
0
        }
1386
1387
0
        this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
1388
0
        return;
1389
0
    }
1390
1391
46
    AutoCheckFlush acf(this->drawingManager());
1392
1393
46
    GrAAType aaType = this->chooseAAType(aa);
1394
1395
46
    GrOp::Owner op;
1396
46
    if (aaType == GrAAType::kCoverage      &&
1397
42
        !fCanUseDynamicMSAA                &&
1398
42
        !this->caps()->reducedShaderMode() &&
1399
42
        oval.width() > SK_ScalarNearlyZero &&
1400
42
        oval.width() == oval.height()      &&
1401
38
        viewMatrix.isSimilarity()) {
1402
        // In specific cases we use a dedicated circle op to try and get better perf.
1403
28
        assert_alive(paint);
1404
28
        op = GrOvalOpFactory::MakeCircleOp(fContext, std::move(paint), viewMatrix, oval, style,
1405
28
                                           this->caps()->shaderCaps());
1406
28
    }
1407
46
    if (!op && style.isSimpleFill()) {
1408
        // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1409
        // the arc equation. This same special geometry and fragment branch also turn out to be a
1410
        // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1411
        // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1412
        // ovals the exact same way we do round rects.
1413
18
        assert_alive(paint);
1414
18
        op = GrFillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint), viewMatrix,
1415
18
                                 SkRRect::MakeOval(oval), oval, GrAA(aaType != GrAAType::kNone));
1416
18
    }
1417
46
    if (!op && (aaType == GrAAType::kCoverage || fCanUseDynamicMSAA)) {
1418
14
        assert_alive(paint);
1419
14
        op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1420
14
                                         this->caps()->shaderCaps());
1421
14
    }
1422
46
    if (op) {
1423
42
        this->addDrawOp(clip, std::move(op));
1424
42
        return;
1425
42
    }
1426
1427
4
    assert_alive(paint);
1428
4
    this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1429
4
                                     GrStyledShape(SkRRect::MakeOval(oval), SkPathDirection::kCW, 2,
1430
4
                                                   false, style, DoSimplify::kNo));
1431
4
}
skgpu::v1::SurfaceDrawContext::drawOval(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, SkRect const&, GrStyle const&)
Line
Count
Source
1374
23
                                  const GrStyle& style) {
1375
23
    ASSERT_SINGLE_OWNER
1376
23
    RETURN_IF_ABANDONED
1377
23
    SkDEBUGCODE(this->validate();)
1378
23
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawOval", fContext);
1379
1380
23
    const SkStrokeRec& stroke = style.strokeRec();
1381
1382
23
    if (oval.isEmpty() && !style.pathEffect()) {
1383
0
        if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1384
0
            return;
1385
0
        }
1386
1387
0
        this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
1388
0
        return;
1389
0
    }
1390
1391
23
    AutoCheckFlush acf(this->drawingManager());
1392
1393
23
    GrAAType aaType = this->chooseAAType(aa);
1394
1395
23
    GrOp::Owner op;
1396
23
    if (aaType == GrAAType::kCoverage      &&
1397
21
        !fCanUseDynamicMSAA                &&
1398
21
        !this->caps()->reducedShaderMode() &&
1399
21
        oval.width() > SK_ScalarNearlyZero &&
1400
21
        oval.width() == oval.height()      &&
1401
19
        viewMatrix.isSimilarity()) {
1402
        // In specific cases we use a dedicated circle op to try and get better perf.
1403
14
        assert_alive(paint);
1404
14
        op = GrOvalOpFactory::MakeCircleOp(fContext, std::move(paint), viewMatrix, oval, style,
1405
14
                                           this->caps()->shaderCaps());
1406
14
    }
1407
23
    if (!op && style.isSimpleFill()) {
1408
        // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1409
        // the arc equation. This same special geometry and fragment branch also turn out to be a
1410
        // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1411
        // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1412
        // ovals the exact same way we do round rects.
1413
9
        assert_alive(paint);
1414
9
        op = GrFillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint), viewMatrix,
1415
9
                                 SkRRect::MakeOval(oval), oval, GrAA(aaType != GrAAType::kNone));
1416
9
    }
1417
23
    if (!op && (aaType == GrAAType::kCoverage || fCanUseDynamicMSAA)) {
1418
7
        assert_alive(paint);
1419
7
        op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1420
7
                                         this->caps()->shaderCaps());
1421
7
    }
1422
23
    if (op) {
1423
21
        this->addDrawOp(clip, std::move(op));
1424
21
        return;
1425
21
    }
1426
1427
2
    assert_alive(paint);
1428
2
    this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1429
2
                                     GrStyledShape(SkRRect::MakeOval(oval), SkPathDirection::kCW, 2,
1430
2
                                                   false, style, DoSimplify::kNo));
1431
2
}
skgpu::v1::SurfaceDrawContext::drawOval(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, SkRect const&, GrStyle const&)
Line
Count
Source
1374
23
                                  const GrStyle& style) {
1375
23
    ASSERT_SINGLE_OWNER
1376
23
    RETURN_IF_ABANDONED
1377
23
    SkDEBUGCODE(this->validate();)
1378
23
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawOval", fContext);
1379
1380
23
    const SkStrokeRec& stroke = style.strokeRec();
1381
1382
23
    if (oval.isEmpty() && !style.pathEffect()) {
1383
0
        if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1384
0
            return;
1385
0
        }
1386
1387
0
        this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
1388
0
        return;
1389
0
    }
1390
1391
23
    AutoCheckFlush acf(this->drawingManager());
1392
1393
23
    GrAAType aaType = this->chooseAAType(aa);
1394
1395
23
    GrOp::Owner op;
1396
23
    if (aaType == GrAAType::kCoverage      &&
1397
21
        !fCanUseDynamicMSAA                &&
1398
21
        !this->caps()->reducedShaderMode() &&
1399
21
        oval.width() > SK_ScalarNearlyZero &&
1400
21
        oval.width() == oval.height()      &&
1401
19
        viewMatrix.isSimilarity()) {
1402
        // In specific cases we use a dedicated circle op to try and get better perf.
1403
14
        assert_alive(paint);
1404
14
        op = GrOvalOpFactory::MakeCircleOp(fContext, std::move(paint), viewMatrix, oval, style,
1405
14
                                           this->caps()->shaderCaps());
1406
14
    }
1407
23
    if (!op && style.isSimpleFill()) {
1408
        // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1409
        // the arc equation. This same special geometry and fragment branch also turn out to be a
1410
        // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1411
        // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1412
        // ovals the exact same way we do round rects.
1413
9
        assert_alive(paint);
1414
9
        op = GrFillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint), viewMatrix,
1415
9
                                 SkRRect::MakeOval(oval), oval, GrAA(aaType != GrAAType::kNone));
1416
9
    }
1417
23
    if (!op && (aaType == GrAAType::kCoverage || fCanUseDynamicMSAA)) {
1418
7
        assert_alive(paint);
1419
7
        op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1420
7
                                         this->caps()->shaderCaps());
1421
7
    }
1422
23
    if (op) {
1423
21
        this->addDrawOp(clip, std::move(op));
1424
21
        return;
1425
21
    }
1426
1427
2
    assert_alive(paint);
1428
2
    this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1429
2
                                     GrStyledShape(SkRRect::MakeOval(oval), SkPathDirection::kCW, 2,
1430
2
                                                   false, style, DoSimplify::kNo));
1431
2
}
1432
1433
void SurfaceDrawContext::drawArc(const GrClip* clip,
1434
                                 GrPaint&& paint,
1435
                                 GrAA aa,
1436
                                 const SkMatrix& viewMatrix,
1437
                                 const SkRect& oval,
1438
                                 SkScalar startAngle,
1439
                                 SkScalar sweepAngle,
1440
                                 bool useCenter,
1441
0
                                 const GrStyle& style) {
1442
0
    ASSERT_SINGLE_OWNER
1443
0
    RETURN_IF_ABANDONED
1444
0
    SkDEBUGCODE(this->validate();)
1445
0
            GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawArc", fContext);
1446
1447
0
    AutoCheckFlush acf(this->drawingManager());
1448
1449
0
    GrAAType aaType = this->chooseAAType(aa);
1450
0
    if (aaType == GrAAType::kCoverage) {
1451
0
        const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1452
0
        GrOp::Owner op = GrOvalOpFactory::MakeArcOp(fContext,
1453
0
                                                    std::move(paint),
1454
0
                                                    viewMatrix,
1455
0
                                                    oval,
1456
0
                                                    startAngle,
1457
0
                                                    sweepAngle,
1458
0
                                                    useCenter,
1459
0
                                                    style,
1460
0
                                                    shaderCaps);
1461
0
        if (op) {
1462
0
            this->addDrawOp(clip, std::move(op));
1463
0
            return;
1464
0
        }
1465
0
        assert_alive(paint);
1466
0
    }
1467
0
    this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1468
0
                                     GrStyledShape::MakeArc(oval, startAngle, sweepAngle, useCenter,
1469
0
                                                            style, DoSimplify::kNo));
1470
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawArc(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, SkRect const&, float, float, bool, GrStyle const&)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawArc(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, SkRect const&, float, float, bool, GrStyle const&)
1471
1472
void SurfaceDrawContext::drawImageLattice(const GrClip* clip,
1473
                                          GrPaint&& paint,
1474
                                          const SkMatrix& viewMatrix,
1475
                                          GrSurfaceProxyView view,
1476
                                          SkAlphaType alphaType,
1477
                                          sk_sp<GrColorSpaceXform> csxf,
1478
                                          GrSamplerState::Filter filter,
1479
                                          std::unique_ptr<SkLatticeIter> iter,
1480
0
                                          const SkRect& dst) {
1481
0
    ASSERT_SINGLE_OWNER
1482
0
    RETURN_IF_ABANDONED
1483
0
    SkDEBUGCODE(this->validate();)
1484
0
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawImageLattice", fContext);
1485
1486
0
    AutoCheckFlush acf(this->drawingManager());
1487
1488
0
    GrOp::Owner op =
1489
0
            GrLatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(view),
1490
0
                                   alphaType, std::move(csxf), filter, std::move(iter), dst);
1491
0
    this->addDrawOp(clip, std::move(op));
1492
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawImageLattice(GrClip const*, GrPaint&&, SkMatrix const&, GrSurfaceProxyView, SkAlphaType, sk_sp<GrColorSpaceXform>, SkFilterMode, std::__1::unique_ptr<SkLatticeIter, std::__1::default_delete<SkLatticeIter> >, SkRect const&)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawImageLattice(GrClip const*, GrPaint&&, SkMatrix const&, GrSurfaceProxyView, SkAlphaType, sk_sp<GrColorSpaceXform>, SkFilterMode, std::__1::unique_ptr<SkLatticeIter, std::__1::default_delete<SkLatticeIter> >, SkRect const&)
1493
1494
void SurfaceDrawContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1495
0
                                      const SkRect& bounds) {
1496
0
    GrOp::Owner op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
1497
0
    SkASSERT(op);
1498
0
    this->addOp(std::move(op));
1499
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawDrawable(std::__1::unique_ptr<SkDrawable::GpuDrawHandler, std::__1::default_delete<SkDrawable::GpuDrawHandler> >, SkRect const&)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawDrawable(std::__1::unique_ptr<SkDrawable::GpuDrawHandler, std::__1::default_delete<SkDrawable::GpuDrawHandler> >, SkRect const&)
1500
1501
void SurfaceDrawContext::setLastClip(uint32_t clipStackGenID,
1502
                                     const SkIRect& devClipBounds,
1503
1.82k
                                     int numClipAnalyticElements) {
1504
1.82k
    GrOpsTask* opsTask = this->getOpsTask();
1505
1.82k
    opsTask->fLastClipStackGenID = clipStackGenID;
1506
1.82k
    opsTask->fLastDevClipBounds = devClipBounds;
1507
1.82k
    opsTask->fLastClipNumAnalyticElements = numClipAnalyticElements;
1508
1.82k
}
1509
1510
bool SurfaceDrawContext::mustRenderClip(uint32_t clipStackGenID,
1511
                                        const SkIRect& devClipBounds,
1512
2.21k
                                        int numClipAnalyticElements) {
1513
2.21k
    GrOpsTask* opsTask = this->getOpsTask();
1514
2.21k
    return opsTask->fLastClipStackGenID != clipStackGenID ||
1515
525
           !opsTask->fLastDevClipBounds.contains(devClipBounds) ||
1516
385
           opsTask->fLastClipNumAnalyticElements != numClipAnalyticElements;
1517
2.21k
}
1518
1519
bool SurfaceDrawContext::waitOnSemaphores(int numSemaphores,
1520
                                          const GrBackendSemaphore waitSemaphores[],
1521
0
                                          bool deleteSemaphoresAfterWait) {
1522
0
    ASSERT_SINGLE_OWNER
1523
0
    RETURN_FALSE_IF_ABANDONED
1524
0
    SkDEBUGCODE(this->validate();)
1525
0
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "waitOnSemaphores", fContext);
1526
1527
0
    AutoCheckFlush acf(this->drawingManager());
1528
1529
0
    if (numSemaphores && !this->caps()->semaphoreSupport()) {
1530
0
        return false;
1531
0
    }
1532
1533
0
    auto direct = fContext->asDirectContext();
1534
0
    if (!direct) {
1535
0
        return false;
1536
0
    }
1537
1538
0
    auto resourceProvider = direct->priv().resourceProvider();
1539
1540
0
    GrWrapOwnership ownership =
1541
0
            deleteSemaphoresAfterWait ? kAdopt_GrWrapOwnership : kBorrow_GrWrapOwnership;
1542
1543
0
    std::unique_ptr<std::unique_ptr<GrSemaphore>[]> grSemaphores(
1544
0
            new std::unique_ptr<GrSemaphore>[numSemaphores]);
1545
0
    for (int i = 0; i < numSemaphores; ++i) {
1546
0
        grSemaphores[i] = resourceProvider->wrapBackendSemaphore(waitSemaphores[i],
1547
0
                                                                 GrSemaphoreWrapType::kWillWait,
1548
0
                                                                 ownership);
1549
0
    }
1550
0
    this->drawingManager()->newWaitRenderTask(this->asSurfaceProxyRef(), std::move(grSemaphores),
1551
0
                                              numSemaphores);
1552
0
    return true;
1553
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::waitOnSemaphores(int, GrBackendSemaphore const*, bool)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::waitOnSemaphores(int, GrBackendSemaphore const*, bool)
1554
1555
void SurfaceDrawContext::drawPath(const GrClip* clip,
1556
                                  GrPaint&& paint,
1557
                                  GrAA aa,
1558
                                  const SkMatrix& viewMatrix,
1559
                                  const SkPath& path,
1560
1.62k
                                  const GrStyle& style) {
1561
811
    ASSERT_SINGLE_OWNER
1562
1.62k
    RETURN_IF_ABANDONED
1563
811
    SkDEBUGCODE(this->validate();)
1564
1.62k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawPath", fContext);
1565
1566
811
    GrStyledShape shape(path, style, DoSimplify::kNo);
1567
811
    this->drawShape(clip, std::move(paint), aa, viewMatrix, std::move(shape));
1568
811
}
skgpu::v1::SurfaceDrawContext::drawPath(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, SkPath const&, GrStyle const&)
Line
Count
Source
1560
811
                                  const GrStyle& style) {
1561
811
    ASSERT_SINGLE_OWNER
1562
811
    RETURN_IF_ABANDONED
1563
811
    SkDEBUGCODE(this->validate();)
1564
811
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawPath", fContext);
1565
1566
811
    GrStyledShape shape(path, style, DoSimplify::kNo);
1567
811
    this->drawShape(clip, std::move(paint), aa, viewMatrix, std::move(shape));
1568
811
}
skgpu::v1::SurfaceDrawContext::drawPath(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, SkPath const&, GrStyle const&)
Line
Count
Source
1560
811
                                  const GrStyle& style) {
1561
811
    ASSERT_SINGLE_OWNER
1562
811
    RETURN_IF_ABANDONED
1563
811
    SkDEBUGCODE(this->validate();)
1564
811
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawPath", fContext);
1565
1566
811
    GrStyledShape shape(path, style, DoSimplify::kNo);
1567
811
    this->drawShape(clip, std::move(paint), aa, viewMatrix, std::move(shape));
1568
811
}
1569
1570
void SurfaceDrawContext::drawShape(const GrClip* clip,
1571
                                   GrPaint&& paint,
1572
                                   GrAA aa,
1573
                                   const SkMatrix& viewMatrix,
1574
90.9k
                                   GrStyledShape&& shape) {
1575
45.4k
    ASSERT_SINGLE_OWNER
1576
90.9k
    RETURN_IF_ABANDONED
1577
45.4k
    SkDEBUGCODE(this->validate();)
1578
90.9k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawShape", fContext);
1579
1580
90.9k
    if (shape.isEmpty()) {
1581
62
        if (shape.inverseFilled()) {
1582
0
            this->drawPaint(clip, std::move(paint), viewMatrix);
1583
0
        }
1584
62
        return;
1585
62
    }
1586
1587
90.9k
    AutoCheckFlush acf(this->drawingManager());
1588
1589
    // If we get here in drawShape(), we definitely need to use path rendering
1590
90.9k
    this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, std::move(shape),
1591
90.9k
                                     /* attemptDrawSimple */ true);
1592
90.9k
}
skgpu::v1::SurfaceDrawContext::drawShape(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, GrStyledShape&&)
Line
Count
Source
1574
45.4k
                                   GrStyledShape&& shape) {
1575
45.4k
    ASSERT_SINGLE_OWNER
1576
45.4k
    RETURN_IF_ABANDONED
1577
45.4k
    SkDEBUGCODE(this->validate();)
1578
45.4k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawShape", fContext);
1579
1580
45.4k
    if (shape.isEmpty()) {
1581
31
        if (shape.inverseFilled()) {
1582
0
            this->drawPaint(clip, std::move(paint), viewMatrix);
1583
0
        }
1584
31
        return;
1585
31
    }
1586
1587
45.4k
    AutoCheckFlush acf(this->drawingManager());
1588
1589
    // If we get here in drawShape(), we definitely need to use path rendering
1590
45.4k
    this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, std::move(shape),
1591
45.4k
                                     /* attemptDrawSimple */ true);
1592
45.4k
}
skgpu::v1::SurfaceDrawContext::drawShape(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, GrStyledShape&&)
Line
Count
Source
1574
45.4k
                                   GrStyledShape&& shape) {
1575
45.4k
    ASSERT_SINGLE_OWNER
1576
45.4k
    RETURN_IF_ABANDONED
1577
45.4k
    SkDEBUGCODE(this->validate();)
1578
45.4k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawShape", fContext);
1579
1580
45.4k
    if (shape.isEmpty()) {
1581
31
        if (shape.inverseFilled()) {
1582
0
            this->drawPaint(clip, std::move(paint), viewMatrix);
1583
0
        }
1584
31
        return;
1585
31
    }
1586
1587
45.4k
    AutoCheckFlush acf(this->drawingManager());
1588
1589
    // If we get here in drawShape(), we definitely need to use path rendering
1590
45.4k
    this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, std::move(shape),
1591
45.4k
                                     /* attemptDrawSimple */ true);
1592
45.4k
}
1593
1594
45.8k
static SkIRect get_clip_bounds(const SurfaceDrawContext* sdc, const GrClip* clip) {
1595
45.8k
    return clip ? clip->getConservativeBounds() : SkIRect::MakeWH(sdc->width(), sdc->height());
1596
45.8k
}
1597
1598
bool SurfaceDrawContext::drawAndStencilPath(const GrHardClip* clip,
1599
                                            const GrUserStencilSettings* ss,
1600
                                            SkRegion::Op op,
1601
                                            bool invert,
1602
                                            GrAA aa,
1603
                                            const SkMatrix& viewMatrix,
1604
0
                                            const SkPath& path) {
1605
0
    ASSERT_SINGLE_OWNER
1606
0
    RETURN_FALSE_IF_ABANDONED
1607
0
    SkDEBUGCODE(this->validate();)
1608
0
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawAndStencilPath", fContext);
1609
1610
0
    if (path.isEmpty() && path.isInverseFillType()) {
1611
0
        GrPaint paint;
1612
0
        paint.setCoverageSetOpXPFactory(op, invert);
1613
0
        this->stencilRect(clip, ss, std::move(paint), GrAA::kNo, SkMatrix::I(),
1614
0
                          SkRect::Make(this->dimensions()));
1615
0
        return true;
1616
0
    }
1617
1618
0
    AutoCheckFlush acf(this->drawingManager());
1619
1620
    // An Assumption here is that path renderer would use some form of tweaking
1621
    // the src color (either the input alpha or in the frag shader) to implement
1622
    // aa. If we have some future driver-mojo path AA that can do the right
1623
    // thing WRT to the blend then we'll need some query on the PR.
1624
0
    GrAAType aaType = this->chooseAAType(aa);
1625
0
    bool hasUserStencilSettings = !ss->isUnused();
1626
1627
0
    SkIRect clipConservativeBounds = get_clip_bounds(this, clip);
1628
1629
0
    GrPaint paint;
1630
0
    paint.setCoverageSetOpXPFactory(op, invert);
1631
1632
0
    GrStyledShape shape(path, GrStyle::SimpleFill());
1633
0
    PathRenderer::CanDrawPathArgs canDrawArgs;
1634
0
    canDrawArgs.fCaps = this->caps();
1635
0
    canDrawArgs.fProxy = this->asRenderTargetProxy();
1636
0
    canDrawArgs.fViewMatrix = &viewMatrix;
1637
0
    canDrawArgs.fShape = &shape;
1638
0
    canDrawArgs.fPaint = &paint;
1639
0
    canDrawArgs.fSurfaceProps = &fSurfaceProps;
1640
0
    canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1641
0
    canDrawArgs.fAAType = aaType;
1642
0
    canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
1643
1644
0
    using DrawType = PathRendererChain::DrawType;
1645
1646
    // Don't allow the SW renderer
1647
0
    auto pr = this->drawingManager()->getPathRenderer(canDrawArgs,
1648
0
                                                      false,
1649
0
                                                      DrawType::kStencilAndColor);
1650
0
    if (!pr) {
1651
0
        return false;
1652
0
    }
1653
1654
0
    PathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1655
0
                                    std::move(paint),
1656
0
                                    ss,
1657
0
                                    this,
1658
0
                                    clip,
1659
0
                                    &clipConservativeBounds,
1660
0
                                    &viewMatrix,
1661
0
                                    &shape,
1662
0
                                    aaType,
1663
0
                                    this->colorInfo().isLinearlyBlended()};
1664
0
    pr->drawPath(args);
1665
0
    return true;
1666
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawAndStencilPath(GrHardClip const*, GrUserStencilSettings const*, SkRegion::Op, bool, GrAA, SkMatrix const&, SkPath const&)
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::drawAndStencilPath(GrHardClip const*, GrUserStencilSettings const*, SkRegion::Op, bool, GrAA, SkMatrix const&, SkPath const&)
1667
1668
0
SkBudgeted SurfaceDrawContext::isBudgeted() const {
1669
0
    ASSERT_SINGLE_OWNER
1670
1671
0
    if (fContext->abandoned()) {
1672
0
        return SkBudgeted::kNo;
1673
0
    }
1674
1675
0
    SkDEBUGCODE(this->validate();)
1676
1677
0
    return this->asSurfaceProxy()->isBudgeted();
1678
0
}
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::isBudgeted() const
Unexecuted instantiation: skgpu::v1::SurfaceDrawContext::isBudgeted() const
1679
1680
void SurfaceDrawContext::drawStrokedLine(const GrClip* clip,
1681
                                         GrPaint&& paint,
1682
                                         GrAA aa,
1683
                                         const SkMatrix& viewMatrix,
1684
                                         const SkPoint points[2],
1685
105
                                         const SkStrokeRec& stroke) {
1686
105
    ASSERT_SINGLE_OWNER
1687
1688
105
    SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style);
1689
105
    SkASSERT(stroke.getWidth() > 0);
1690
    // Adding support for round capping would require a
1691
    // SurfaceDrawContext::fillRRectWithLocalMatrix entry point
1692
105
    SkASSERT(SkPaint::kRound_Cap != stroke.getCap());
1693
1694
105
    const SkScalar halfWidth = 0.5f * stroke.getWidth();
1695
105
    if (halfWidth <= 0.f) {
1696
        // Prevents underflow when stroke width is epsilon > 0 (so technically not a hairline).
1697
        // The CTM would need to have a scale near 1/epsilon in order for this to have meaningful
1698
        // coverage (although that would likely overflow elsewhere and cause the draw to drop due
1699
        // to non-finite bounds). At any other scale, this line is so thin, it's coverage is
1700
        // negligible, so discarding the draw is visually equivalent.
1701
0
        return;
1702
0
    }
1703
1704
105
    SkVector parallel = points[1] - points[0];
1705
1706
105
    if (!SkPoint::Normalize(&parallel)) {
1707
23
        parallel.fX = 1.0f;
1708
23
        parallel.fY = 0.0f;
1709
23
    }
1710
105
    parallel *= halfWidth;
1711
1712
105
    SkVector ortho = { parallel.fY, -parallel.fX };
1713
105
    if (SkPaint::kButt_Cap == stroke.getCap()) {
1714
        // No extra extension for butt caps
1715
0
        parallel = {0.f, 0.f};
1716
0
    }
1717
    // Order is TL, TR, BR, BL where arbitrarily "down" is p0 to p1 and "right" is positive
1718
105
    SkPoint corners[4] = { points[0] - ortho - parallel,
1719
105
                           points[0] + ortho - parallel,
1720
105
                           points[1] + ortho + parallel,
1721
105
                           points[1] - ortho + parallel };
1722
1723
104
    GrQuadAAFlags edgeAA = (aa == GrAA::kYes) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
1724
105
    this->fillQuadWithEdgeAA(clip, std::move(paint), aa, edgeAA, viewMatrix, corners, nullptr);
1725
105
}
1726
1727
bool SurfaceDrawContext::drawSimpleShape(const GrClip* clip,
1728
                                         GrPaint* paint,
1729
                                         GrAA aa,
1730
                                         const SkMatrix& viewMatrix,
1731
45.2k
                                         const GrStyledShape& shape) {
1732
45.2k
    if (!shape.style().hasPathEffect()) {
1733
41.0k
        GrAAType aaType = this->chooseAAType(aa);
1734
41.0k
        SkPoint linePts[2];
1735
41.0k
        SkRRect rrect;
1736
        // We can ignore the starting point and direction since there is no path effect.
1737
41.0k
        bool inverted;
1738
41.0k
        if (shape.asLine(linePts, &inverted) && !inverted &&
1739
295
            shape.style().strokeRec().getStyle() == SkStrokeRec::kStroke_Style &&
1740
211
            shape.style().strokeRec().getCap() != SkPaint::kRound_Cap) {
1741
            // The stroked line is an oriented rectangle, which looks the same or better (if
1742
            // perspective) compared to path rendering. The exception is subpixel/hairline lines
1743
            // that are non-AA or MSAA, in which case the default path renderer achieves higher
1744
            // quality.
1745
            // FIXME(michaelludwig): If the fill rect op could take an external coverage, or checks
1746
            // for and outsets thin non-aa rects to 1px, the path renderer could be skipped.
1747
143
            SkScalar coverage;
1748
143
            if (aaType == GrAAType::kCoverage ||
1749
39
                !SkDrawTreatAAStrokeAsHairline(shape.style().strokeRec().getWidth(), viewMatrix,
1750
105
                                               &coverage)) {
1751
105
                this->drawStrokedLine(clip, std::move(*paint), aa, viewMatrix, linePts,
1752
105
                                      shape.style().strokeRec());
1753
105
                return true;
1754
105
            }
1755
40.9k
        } else if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
1756
1.61k
            if (rrect.isRect()) {
1757
1.49k
                this->drawRect(clip, std::move(*paint), aa, viewMatrix, rrect.rect(),
1758
1.49k
                               &shape.style());
1759
1.49k
                return true;
1760
116
            } else if (rrect.isOval()) {
1761
23
                this->drawOval(clip, std::move(*paint), aa, viewMatrix, rrect.rect(),
1762
23
                               shape.style());
1763
23
                return true;
1764
23
            }
1765
93
            this->drawRRect(clip, std::move(*paint), aa, viewMatrix, rrect, shape.style());
1766
93
            return true;
1767
39.3k
        } else if (GrAAType::kCoverage == aaType &&
1768
29.4k
                   shape.style().isSimpleFill()  &&
1769
23.5k
                   viewMatrix.rectStaysRect()    &&
1770
7.18k
                   !this->caps()->reducedShaderMode()) {
1771
            // TODO: the rectStaysRect restriction could be lifted if we were willing to apply the
1772
            // matrix to all the points individually rather than just to the rect
1773
7.18k
            SkRect rects[2];
1774
7.18k
            if (shape.asNestedRects(rects)) {
1775
                // Concave AA paths are expensive - try to avoid them for special cases
1776
4.39k
                GrOp::Owner op = GrStrokeRectOp::MakeNested(
1777
4.39k
                                fContext, std::move(*paint), viewMatrix, rects);
1778
4.39k
                if (op) {
1779
877
                    this->addDrawOp(clip, std::move(op));
1780
877
                }
1781
                // Returning here indicates that there is nothing to draw in this case.
1782
4.39k
                return true;
1783
4.39k
            }
1784
39.1k
        }
1785
41.0k
    }
1786
39.1k
    return false;
1787
39.1k
}
1788
1789
void SurfaceDrawContext::drawShapeUsingPathRenderer(const GrClip* clip,
1790
                                                    GrPaint&& paint,
1791
                                                    GrAA aa,
1792
                                                    const SkMatrix& viewMatrix,
1793
                                                    GrStyledShape&& shape,
1794
91.9k
                                                    bool attemptDrawSimple) {
1795
45.9k
    ASSERT_SINGLE_OWNER
1796
91.9k
    RETURN_IF_ABANDONED
1797
91.9k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "internalDrawPath", fContext);
1798
1799
91.9k
    if (!viewMatrix.isFinite() || !shape.bounds().isFinite()) {
1800
338
        return;
1801
338
    }
1802
1803
91.6k
    SkIRect clipConservativeBounds = get_clip_bounds(this, clip);
1804
1805
    // Always allow paths to trigger DMSAA.
1806
91.6k
    GrAAType aaType = fCanUseDynamicMSAA ? GrAAType::kMSAA : this->chooseAAType(aa);
1807
1808
91.6k
    PathRenderer::CanDrawPathArgs canDrawArgs;
1809
91.6k
    canDrawArgs.fCaps = this->caps();
1810
91.6k
    canDrawArgs.fProxy = this->asRenderTargetProxy();
1811
91.6k
    canDrawArgs.fViewMatrix = &viewMatrix;
1812
91.6k
    canDrawArgs.fShape = &shape;
1813
91.6k
    canDrawArgs.fPaint = &paint;
1814
91.6k
    canDrawArgs.fSurfaceProps = &fSurfaceProps;
1815
91.6k
    canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1816
91.6k
    canDrawArgs.fHasUserStencilSettings = false;
1817
91.6k
    canDrawArgs.fAAType = aaType;
1818
1819
91.6k
    constexpr static bool kDisallowSWPathRenderer = false;
1820
91.6k
    constexpr static bool kAllowSWPathRenderer = true;
1821
91.6k
    using DrawType = PathRendererChain::DrawType;
1822
1823
91.6k
    PathRenderer* pr = nullptr;
1824
1825
91.6k
    if (!shape.style().strokeRec().isFillStyle() && !shape.isEmpty()) {
1826
        // Give the tessellation path renderer a chance to claim this stroke before we simplify it.
1827
26.4k
        PathRenderer* tess = this->drawingManager()->getTessellationPathRenderer();
1828
26.4k
        if (tess && tess->canDrawPath(canDrawArgs) == PathRenderer::CanDrawPath::kYes) {
1829
0
            pr = tess;
1830
0
        }
1831
26.4k
    }
1832
1833
91.6k
    if (!pr) {
1834
        // The shape isn't a stroke that can be drawn directly. Simplify if possible.
1835
91.6k
        shape.simplify();
1836
1837
91.6k
        if (shape.isEmpty() && !shape.inverseFilled()) {
1838
104
            return;
1839
104
        }
1840
1841
91.5k
        if (attemptDrawSimple || shape.simplified()) {
1842
            // Usually we enter drawShapeUsingPathRenderer() because the shape+style was too complex
1843
            // for dedicated draw ops. However, if GrStyledShape was able to reduce something we
1844
            // ought to try again instead of going right to path rendering.
1845
90.4k
            if (this->drawSimpleShape(clip, &paint, aa, viewMatrix, shape)) {
1846
12.2k
                return;
1847
12.2k
            }
1848
79.3k
        }
1849
1850
        // Try a 1st time without applying any of the style to the geometry (and barring sw)
1851
79.3k
        pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1852
79.3k
                                                     DrawType::kColor);
1853
79.3k
    }
1854
1855
79.3k
    SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
1856
79.3k
    if (styleScale == 0.0f) {
1857
0
        return;
1858
0
    }
1859
1860
79.3k
    if (!pr && shape.style().pathEffect()) {
1861
        // It didn't work above, so try again with the path effect applied.
1862
8.36k
        shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1863
8.36k
        if (shape.isEmpty()) {
1864
2.25k
            return;
1865
2.25k
        }
1866
6.10k
        pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1867
6.10k
                                                     DrawType::kColor);
1868
6.10k
    }
1869
77.0k
    if (!pr) {
1870
23.9k
        if (shape.style().applies()) {
1871
11.1k
            shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
1872
11.1k
            if (shape.isEmpty()) {
1873
4
                return;
1874
4
            }
1875
            // This time, allow SW renderer
1876
11.1k
            pr = this->drawingManager()->getPathRenderer(canDrawArgs, kAllowSWPathRenderer,
1877
11.1k
                                                         DrawType::kColor);
1878
12.7k
        } else {
1879
12.7k
            pr = this->drawingManager()->getSoftwarePathRenderer();
1880
#if GR_PATH_RENDERER_SPEW
1881
            SkDebugf("falling back to: %s\n", pr->name());
1882
#endif
1883
12.7k
        }
1884
23.9k
    }
1885
1886
77.0k
    if (!pr) {
1887
#ifdef SK_DEBUG
1888
        SkDebugf("Unable to find path renderer compatible with path.\n");
1889
#endif
1890
0
        return;
1891
0
    }
1892
1893
77.0k
    PathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1894
77.0k
                                    std::move(paint),
1895
77.0k
                                    &GrUserStencilSettings::kUnused,
1896
77.0k
                                    this,
1897
77.0k
                                    clip,
1898
77.0k
                                    &clipConservativeBounds,
1899
77.0k
                                    &viewMatrix,
1900
77.0k
                                    canDrawArgs.fShape,
1901
77.0k
                                    aaType,
1902
77.0k
                                    this->colorInfo().isLinearlyBlended()};
1903
77.0k
    pr->drawPath(args);
1904
77.0k
}
skgpu::v1::SurfaceDrawContext::drawShapeUsingPathRenderer(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, GrStyledShape&&, bool)
Line
Count
Source
1794
45.9k
                                                    bool attemptDrawSimple) {
1795
45.9k
    ASSERT_SINGLE_OWNER
1796
45.9k
    RETURN_IF_ABANDONED
1797
45.9k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "internalDrawPath", fContext);
1798
1799
45.9k
    if (!viewMatrix.isFinite() || !shape.bounds().isFinite()) {
1800
169
        return;
1801
169
    }
1802
1803
45.8k
    SkIRect clipConservativeBounds = get_clip_bounds(this, clip);
1804
1805
    // Always allow paths to trigger DMSAA.
1806
45.8k
    GrAAType aaType = fCanUseDynamicMSAA ? GrAAType::kMSAA : this->chooseAAType(aa);
1807
1808
45.8k
    PathRenderer::CanDrawPathArgs canDrawArgs;
1809
45.8k
    canDrawArgs.fCaps = this->caps();
1810
45.8k
    canDrawArgs.fProxy = this->asRenderTargetProxy();
1811
45.8k
    canDrawArgs.fViewMatrix = &viewMatrix;
1812
45.8k
    canDrawArgs.fShape = &shape;
1813
45.8k
    canDrawArgs.fPaint = &paint;
1814
45.8k
    canDrawArgs.fSurfaceProps = &fSurfaceProps;
1815
45.8k
    canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1816
45.8k
    canDrawArgs.fHasUserStencilSettings = false;
1817
45.8k
    canDrawArgs.fAAType = aaType;
1818
1819
45.8k
    constexpr static bool kDisallowSWPathRenderer = false;
1820
45.8k
    constexpr static bool kAllowSWPathRenderer = true;
1821
45.8k
    using DrawType = PathRendererChain::DrawType;
1822
1823
45.8k
    PathRenderer* pr = nullptr;
1824
1825
45.8k
    if (!shape.style().strokeRec().isFillStyle() && !shape.isEmpty()) {
1826
        // Give the tessellation path renderer a chance to claim this stroke before we simplify it.
1827
13.2k
        PathRenderer* tess = this->drawingManager()->getTessellationPathRenderer();
1828
13.2k
        if (tess && tess->canDrawPath(canDrawArgs) == PathRenderer::CanDrawPath::kYes) {
1829
0
            pr = tess;
1830
0
        }
1831
13.2k
    }
1832
1833
45.8k
    if (!pr) {
1834
        // The shape isn't a stroke that can be drawn directly. Simplify if possible.
1835
45.8k
        shape.simplify();
1836
1837
45.8k
        if (shape.isEmpty() && !shape.inverseFilled()) {
1838
52
            return;
1839
52
        }
1840
1841
45.7k
        if (attemptDrawSimple || shape.simplified()) {
1842
            // Usually we enter drawShapeUsingPathRenderer() because the shape+style was too complex
1843
            // for dedicated draw ops. However, if GrStyledShape was able to reduce something we
1844
            // ought to try again instead of going right to path rendering.
1845
45.2k
            if (this->drawSimpleShape(clip, &paint, aa, viewMatrix, shape)) {
1846
6.11k
                return;
1847
6.11k
            }
1848
39.6k
        }
1849
1850
        // Try a 1st time without applying any of the style to the geometry (and barring sw)
1851
39.6k
        pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1852
39.6k
                                                     DrawType::kColor);
1853
39.6k
    }
1854
1855
39.6k
    SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
1856
39.6k
    if (styleScale == 0.0f) {
1857
0
        return;
1858
0
    }
1859
1860
39.6k
    if (!pr && shape.style().pathEffect()) {
1861
        // It didn't work above, so try again with the path effect applied.
1862
4.18k
        shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1863
4.18k
        if (shape.isEmpty()) {
1864
1.12k
            return;
1865
1.12k
        }
1866
3.05k
        pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1867
3.05k
                                                     DrawType::kColor);
1868
3.05k
    }
1869
38.5k
    if (!pr) {
1870
11.9k
        if (shape.style().applies()) {
1871
5.59k
            shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
1872
5.59k
            if (shape.isEmpty()) {
1873
2
                return;
1874
2
            }
1875
            // This time, allow SW renderer
1876
5.59k
            pr = this->drawingManager()->getPathRenderer(canDrawArgs, kAllowSWPathRenderer,
1877
5.59k
                                                         DrawType::kColor);
1878
6.39k
        } else {
1879
6.39k
            pr = this->drawingManager()->getSoftwarePathRenderer();
1880
#if GR_PATH_RENDERER_SPEW
1881
            SkDebugf("falling back to: %s\n", pr->name());
1882
#endif
1883
6.39k
        }
1884
11.9k
    }
1885
1886
38.5k
    if (!pr) {
1887
#ifdef SK_DEBUG
1888
        SkDebugf("Unable to find path renderer compatible with path.\n");
1889
#endif
1890
0
        return;
1891
0
    }
1892
1893
38.5k
    PathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1894
38.5k
                                    std::move(paint),
1895
38.5k
                                    &GrUserStencilSettings::kUnused,
1896
38.5k
                                    this,
1897
38.5k
                                    clip,
1898
38.5k
                                    &clipConservativeBounds,
1899
38.5k
                                    &viewMatrix,
1900
38.5k
                                    canDrawArgs.fShape,
1901
38.5k
                                    aaType,
1902
38.5k
                                    this->colorInfo().isLinearlyBlended()};
1903
38.5k
    pr->drawPath(args);
1904
38.5k
}
skgpu::v1::SurfaceDrawContext::drawShapeUsingPathRenderer(GrClip const*, GrPaint&&, GrAA, SkMatrix const&, GrStyledShape&&, bool)
Line
Count
Source
1794
45.9k
                                                    bool attemptDrawSimple) {
1795
45.9k
    ASSERT_SINGLE_OWNER
1796
45.9k
    RETURN_IF_ABANDONED
1797
45.9k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "internalDrawPath", fContext);
1798
1799
45.9k
    if (!viewMatrix.isFinite() || !shape.bounds().isFinite()) {
1800
169
        return;
1801
169
    }
1802
1803
45.8k
    SkIRect clipConservativeBounds = get_clip_bounds(this, clip);
1804
1805
    // Always allow paths to trigger DMSAA.
1806
45.8k
    GrAAType aaType = fCanUseDynamicMSAA ? GrAAType::kMSAA : this->chooseAAType(aa);
1807
1808
45.8k
    PathRenderer::CanDrawPathArgs canDrawArgs;
1809
45.8k
    canDrawArgs.fCaps = this->caps();
1810
45.8k
    canDrawArgs.fProxy = this->asRenderTargetProxy();
1811
45.8k
    canDrawArgs.fViewMatrix = &viewMatrix;
1812
45.8k
    canDrawArgs.fShape = &shape;
1813
45.8k
    canDrawArgs.fPaint = &paint;
1814
45.8k
    canDrawArgs.fSurfaceProps = &fSurfaceProps;
1815
45.8k
    canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1816
45.8k
    canDrawArgs.fHasUserStencilSettings = false;
1817
45.8k
    canDrawArgs.fAAType = aaType;
1818
1819
45.8k
    constexpr static bool kDisallowSWPathRenderer = false;
1820
45.8k
    constexpr static bool kAllowSWPathRenderer = true;
1821
45.8k
    using DrawType = PathRendererChain::DrawType;
1822
1823
45.8k
    PathRenderer* pr = nullptr;
1824
1825
45.8k
    if (!shape.style().strokeRec().isFillStyle() && !shape.isEmpty()) {
1826
        // Give the tessellation path renderer a chance to claim this stroke before we simplify it.
1827
13.2k
        PathRenderer* tess = this->drawingManager()->getTessellationPathRenderer();
1828
13.2k
        if (tess && tess->canDrawPath(canDrawArgs) == PathRenderer::CanDrawPath::kYes) {
1829
0
            pr = tess;
1830
0
        }
1831
13.2k
    }
1832
1833
45.8k
    if (!pr) {
1834
        // The shape isn't a stroke that can be drawn directly. Simplify if possible.
1835
45.8k
        shape.simplify();
1836
1837
45.8k
        if (shape.isEmpty() && !shape.inverseFilled()) {
1838
52
            return;
1839
52
        }
1840
1841
45.7k
        if (attemptDrawSimple || shape.simplified()) {
1842
            // Usually we enter drawShapeUsingPathRenderer() because the shape+style was too complex
1843
            // for dedicated draw ops. However, if GrStyledShape was able to reduce something we
1844
            // ought to try again instead of going right to path rendering.
1845
45.2k
            if (this->drawSimpleShape(clip, &paint, aa, viewMatrix, shape)) {
1846
6.11k
                return;
1847
6.11k
            }
1848
39.6k
        }
1849
1850
        // Try a 1st time without applying any of the style to the geometry (and barring sw)
1851
39.6k
        pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1852
39.6k
                                                     DrawType::kColor);
1853
39.6k
    }
1854
1855
39.6k
    SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
1856
39.6k
    if (styleScale == 0.0f) {
1857
0
        return;
1858
0
    }
1859
1860
39.6k
    if (!pr && shape.style().pathEffect()) {
1861
        // It didn't work above, so try again with the path effect applied.
1862
4.18k
        shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1863
4.18k
        if (shape.isEmpty()) {
1864
1.12k
            return;
1865
1.12k
        }
1866
3.05k
        pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1867
3.05k
                                                     DrawType::kColor);
1868
3.05k
    }
1869
38.5k
    if (!pr) {
1870
11.9k
        if (shape.style().applies()) {
1871
5.59k
            shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
1872
5.59k
            if (shape.isEmpty()) {
1873
2
                return;
1874
2
            }
1875
            // This time, allow SW renderer
1876
5.59k
            pr = this->drawingManager()->getPathRenderer(canDrawArgs, kAllowSWPathRenderer,
1877
5.59k
                                                         DrawType::kColor);
1878
6.39k
        } else {
1879
6.39k
            pr = this->drawingManager()->getSoftwarePathRenderer();
1880
#if GR_PATH_RENDERER_SPEW
1881
            SkDebugf("falling back to: %s\n", pr->name());
1882
#endif
1883
6.39k
        }
1884
11.9k
    }
1885
1886
38.5k
    if (!pr) {
1887
0
#ifdef SK_DEBUG
1888
0
        SkDebugf("Unable to find path renderer compatible with path.\n");
1889
0
#endif
1890
0
        return;
1891
0
    }
1892
1893
38.5k
    PathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1894
38.5k
                                    std::move(paint),
1895
38.5k
                                    &GrUserStencilSettings::kUnused,
1896
38.5k
                                    this,
1897
38.5k
                                    clip,
1898
38.5k
                                    &clipConservativeBounds,
1899
38.5k
                                    &viewMatrix,
1900
38.5k
                                    canDrawArgs.fShape,
1901
38.5k
                                    aaType,
1902
38.5k
                                    this->colorInfo().isLinearlyBlended()};
1903
38.5k
    pr->drawPath(args);
1904
38.5k
}
1905
1906
void SurfaceDrawContext::addDrawOp(const GrClip* clip,
1907
                                   GrOp::Owner op,
1908
119k
                                   const std::function<WillAddOpFn>& willAddFn) {
1909
119k
    ASSERT_SINGLE_OWNER
1910
119k
    if (fContext->abandoned()) {
1911
0
        return;
1912
0
    }
1913
119k
    GrDrawOp* drawOp = (GrDrawOp*)op.get();
1914
119k
    SkDEBUGCODE(this->validate();)
1915
119k
    SkDEBUGCODE(drawOp->fAddDrawOpCalled = true;)
1916
119k
    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "addDrawOp", fContext);
1917
1918
    // Setup clip
1919
119k
    SkRect bounds;
1920
119k
    op_bounds(&bounds, op.get());
1921
119k
    GrAppliedClip appliedClip(this->dimensions(), this->asSurfaceProxy()->backingStoreDimensions());
1922
119k
    const bool opUsesMSAA = drawOp->usesMSAA();
1923
119k
    bool skipDraw = false;
1924
119k
    if (clip) {
1925
        // Have a complex clip, so defer to its early clip culling
1926
41.3k
        GrAAType aaType;
1927
41.3k
        if (opUsesMSAA) {
1928
0
            aaType = GrAAType::kMSAA;
1929
41.3k
        } else {
1930
21.5k
            aaType = op->hasAABloat() ? GrAAType::kCoverage : GrAAType::kNone;
1931
41.3k
        }
1932
41.3k
        skipDraw = clip->apply(fContext, this, drawOp, aaType,
1933
41.3k
                               &appliedClip, &bounds) == GrClip::Effect::kClippedOut;
1934
78.5k
    } else {
1935
        // No clipping, so just clip the bounds against the logical render target dimensions
1936
78.5k
        skipDraw = !bounds.intersect(this->asSurfaceProxy()->getBoundsRect());
1937
78.5k
    }
1938
1939
119k
    if (skipDraw) {
1940
9.15k
        return;
1941
9.15k
    }
1942
1943
110k
    GrClampType clampType = GrColorTypeClampType(this->colorInfo().colorType());
1944
110k
    GrProcessorSet::Analysis analysis = drawOp->finalize(*this->caps(), &appliedClip, clampType);
1945
1946
110k
    const bool opUsesStencil = drawOp->usesStencil();
1947
1948
    // Always trigger DMSAA when there is stencil. This ensures stencil contents get properly
1949
    // preserved between render passes, if needed.
1950
110k
    const bool drawNeedsMSAA = opUsesMSAA || (fCanUseDynamicMSAA && opUsesStencil);
1951
1952
    // Must be called before setDstProxyView so that it sees the final bounds of the op.
1953
110k
    op->setClippedBounds(bounds);
1954
1955
    // Determine if the Op will trigger the use of a separate DMSAA attachment that requires manual
1956
    // resolves.
1957
    // TODO: Currently usesAttachmentIfDMSAA checks if this is a textureProxy or not. This check is
1958
    // really only for GL which uses a normal texture sampling when using barriers. For Vulkan it
1959
    // is possible to use the msaa buffer as an input attachment even if this is not a texture.
1960
    // However, support for that is not fully implemented yet in Vulkan. Once it is, this check
1961
    // should change to a virtual caps check that returns whether we need to break up an OpsTask
1962
    // if it has barriers and we are about to promote to MSAA.
1963
110k
    bool usesAttachmentIfDMSAA =
1964
110k
            fCanUseDynamicMSAA &&
1965
0
            (!this->caps()->msaaResolvesAutomatically() || !this->asTextureProxy());
1966
110k
    bool opRequiresDMSAAAttachment = usesAttachmentIfDMSAA && drawNeedsMSAA;
1967
110k
    bool opTriggersDMSAAAttachment =
1968
110k
            opRequiresDMSAAAttachment && !this->getOpsTask()->usesMSAASurface();
1969
110k
    if (opTriggersDMSAAAttachment) {
1970
        // This will be the op that actually triggers use of a DMSAA attachment. Texture barriers
1971
        // can't be moved to a DMSAA attachment, so if there already are any on the current opsTask
1972
        // then we need to split.
1973
0
        if (this->getOpsTask()->renderPassXferBarriers() & GrXferBarrierFlags::kTexture) {
1974
0
            SkASSERT(!this->getOpsTask()->isColorNoOp());
1975
0
            this->replaceOpsTask()->setCannotMergeBackward();
1976
0
        }
1977
0
    }
1978
1979
110k
    GrDstProxyView dstProxyView;
1980
110k
    if (analysis.requiresDstTexture()) {
1981
11.3k
        if (!this->setupDstProxyView(drawOp->bounds(), drawNeedsMSAA, &dstProxyView)) {
1982
0
            return;
1983
0
        }
1984
#ifdef SK_DEBUG
1985
        if (fCanUseDynamicMSAA && drawNeedsMSAA && !this->caps()->msaaResolvesAutomatically()) {
1986
            // Since we aren't literally writing to the render target texture while using a DMSAA
1987
            // attachment, we need to resolve that texture before sampling it. Ensure the current
1988
            // opsTask got closed off in order to initiate an implicit resolve.
1989
            SkASSERT(this->getOpsTask()->isEmpty());
1990
        }
1991
#endif
1992
11.3k
    }
1993
1994
110k
    auto opsTask = this->getOpsTask();
1995
110k
    if (willAddFn) {
1996
0
        willAddFn(op.get(), opsTask->uniqueID());
1997
0
    }
1998
1999
    // Note if the op needs stencil. Stencil clipping already called setNeedsStencil for itself, if
2000
    // needed.
2001
110k
    if (opUsesStencil) {
2002
8.59k
        this->setNeedsStencil();
2003
8.59k
    }
2004
2005
110k
#if GR_GPU_STATS && GR_TEST_UTILS
2006
110k
    if (fCanUseDynamicMSAA && drawNeedsMSAA) {
2007
0
        if (!opsTask->usesMSAASurface()) {
2008
0
            fContext->priv().dmsaaStats().fNumMultisampleRenderPasses++;
2009
0
        }
2010
0
        fContext->priv().dmsaaStats().fTriggerCounts[op->name()]++;
2011
0
    }
2012
110k
#endif
2013
2014
110k
    opsTask->addDrawOp(this->drawingManager(), std::move(op), drawNeedsMSAA, analysis,
2015
110k
                       std::move(appliedClip), dstProxyView,
2016
110k
                       GrTextureResolveManager(this->drawingManager()), *this->caps());
2017
2018
#ifdef SK_DEBUG
2019
    if (fCanUseDynamicMSAA && drawNeedsMSAA) {
2020
        SkASSERT(opsTask->usesMSAASurface());
2021
    }
2022
#endif
2023
110k
}
2024
2025
bool SurfaceDrawContext::setupDstProxyView(const SkRect& opBounds,
2026
                                           bool opRequiresMSAA,
2027
11.3k
                                           GrDstProxyView* dstProxyView) {
2028
    // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2029
    // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2030
    // start and stop the render pass in order to make the copy.
2031
11.3k
    if (this->asRenderTargetProxy()->wrapsVkSecondaryCB()) {
2032
0
        return false;
2033
0
    }
2034
2035
    // First get the dstSampleFlags as if we will put the draw into the current GrOpsTask
2036
11.3k
    auto dstSampleFlags = this->caps()->getDstSampleFlagsForProxy(
2037
11.3k
            this->asRenderTargetProxy(), this->getOpsTask()->usesMSAASurface() || opRequiresMSAA);
2038
2039
    // If we don't have barriers for this draw then we will definitely be breaking up the GrOpsTask.
2040
    // However, if using dynamic MSAA, the new GrOpsTask will not have MSAA already enabled on it
2041
    // and that may allow us to use texture barriers. So we check if we can use barriers on the new
2042
    // ops task and then break it up if so.
2043
11.3k
    if (!(dstSampleFlags & GrDstSampleFlags::kRequiresTextureBarrier) &&
2044
11.3k
        fCanUseDynamicMSAA && this->getOpsTask()->usesMSAASurface() && !opRequiresMSAA) {
2045
0
        auto newFlags =
2046
0
                this->caps()->getDstSampleFlagsForProxy(this->asRenderTargetProxy(),
2047
0
                                                        false/*=opRequiresMSAA*/);
2048
0
        if (newFlags & GrDstSampleFlags::kRequiresTextureBarrier) {
2049
            // We can't have an empty ops task if we are in DMSAA and the ops task already returns
2050
            // true for usesMSAASurface.
2051
0
            SkASSERT(!this->getOpsTask()->isColorNoOp());
2052
0
            this->replaceOpsTask()->setCannotMergeBackward();
2053
0
            dstSampleFlags = newFlags;
2054
0
        }
2055
0
    }
2056
2057
11.3k
    if (dstSampleFlags & GrDstSampleFlags::kRequiresTextureBarrier) {
2058
        // If we require a barrier to sample the dst it means we are sampling the RT itself
2059
        // either as a texture or input attachment. In this case we don't need to break up the
2060
        // GrOpsTask.
2061
0
        dstProxyView->setProxyView(this->readSurfaceView());
2062
0
        dstProxyView->setOffset(0, 0);
2063
0
        dstProxyView->setDstSampleFlags(dstSampleFlags);
2064
0
        return true;
2065
0
    }
2066
11.3k
    SkASSERT(dstSampleFlags == GrDstSampleFlags::kNone);
2067
2068
    // We are using a different surface from the main color attachment to sample the dst from. If we
2069
    // are in DMSAA we can just use the single sampled RT texture itself. Otherwise, we must do a
2070
    // copy.
2071
    // We do have to check if we ended up here becasue we don't have texture barriers but do have
2072
    // msaaResolvesAutomatically (i.e. render-to-msaa-texture). In that case there will be no op or
2073
    // barrier between draws to flush the render target before being used as a texture in the next
2074
    // draw. So in that case we just fall through to doing a copy.
2075
11.3k
    if (fCanUseDynamicMSAA && opRequiresMSAA && this->asTextureProxy() &&
2076
0
        !this->caps()->msaaResolvesAutomatically()) {
2077
0
        this->replaceOpsTaskIfModifiesColor()->setCannotMergeBackward();
2078
0
        dstProxyView->setProxyView(this->readSurfaceView());
2079
0
        dstProxyView->setOffset(0, 0);
2080
0
        dstProxyView->setDstSampleFlags(dstSampleFlags);
2081
0
        return true;
2082
0
    }
2083
2084
    // Now we fallback to doing a copy.
2085
2086
11.3k
    GrColorType colorType = this->colorInfo().colorType();
2087
    // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2088
    // have per-sample dst values by making the copy multisampled.
2089
11.3k
    GrCaps::DstCopyRestrictions restrictions = this->caps()->getDstCopyRestrictions(
2090
11.3k
            this->asRenderTargetProxy(), colorType);
2091
2092
11.3k
    SkIRect copyRect = SkIRect::MakeSize(this->asSurfaceProxy()->backingStoreDimensions());
2093
11.3k
    if (!restrictions.fMustCopyWholeSrc) {
2094
        // If we don't need the whole source, restrict to the op's bounds. We add an extra pixel
2095
        // of padding to account for AA bloat and the unpredictable rounding of coords near pixel
2096
        // centers during rasterization.
2097
11.3k
        SkIRect conservativeDrawBounds = opBounds.roundOut();
2098
11.3k
        conservativeDrawBounds.outset(1, 1);
2099
11.3k
        SkAssertResult(copyRect.intersect(conservativeDrawBounds));
2100
11.3k
    }
2101
2102
11.3k
    SkIPoint dstOffset;
2103
11.3k
    SkBackingFit fit;
2104
11.3k
    if (restrictions.fRectsMustMatch == GrSurfaceProxy::RectsMustMatch::kYes) {
2105
0
        dstOffset = {0, 0};
2106
0
        fit = SkBackingFit::kExact;
2107
11.3k
    } else {
2108
11.3k
        dstOffset = {copyRect.fLeft, copyRect.fTop};
2109
11.3k
        fit = SkBackingFit::kApprox;
2110
11.3k
    }
2111
11.3k
    auto copy = GrSurfaceProxy::Copy(fContext,
2112
11.3k
                                     this->asSurfaceProxyRef(),
2113
11.3k
                                     this->origin(),
2114
11.3k
                                     GrMipmapped::kNo,
2115
11.3k
                                     copyRect,
2116
11.3k
                                     fit,
2117
11.3k
                                     SkBudgeted::kYes,
2118
11.3k
                                     restrictions.fRectsMustMatch);
2119
11.3k
    SkASSERT(copy);
2120
2121
11.3k
    dstProxyView->setProxyView({std::move(copy), this->origin(), this->readSwizzle()});
2122
11.3k
    dstProxyView->setOffset(dstOffset);
2123
11.3k
    dstProxyView->setDstSampleFlags(dstSampleFlags);
2124
11.3k
    return true;
2125
11.3k
}
2126
2127
0
GrOpsTask* SurfaceDrawContext::replaceOpsTaskIfModifiesColor() {
2128
0
    if (!this->getOpsTask()->isColorNoOp()) {
2129
0
        this->replaceOpsTask();
2130
0
    }
2131
0
    return this->getOpsTask();
2132
0
}
2133
2134
} // namespace skgpu::v1