Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/gpu/ganesh/ops/OpsTask.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019 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
#ifndef OpsTask_DEFINED
8
#define OpsTask_DEFINED
9
10
#include "include/core/SkRect.h"
11
#include "include/core/SkRefCnt.h"
12
#include "include/core/SkSpan.h"
13
#include "include/core/SkTypes.h"
14
#include "include/private/base/SkDebug.h"
15
#include "include/private/base/SkTArray.h"
16
#include "include/private/base/SkTo.h"
17
#include "include/private/base/SkTypeTraits.h"
18
#include "include/private/gpu/ganesh/GrTypesPriv.h"
19
#include "src/gpu/Swizzle.h"
20
#include "src/gpu/ganesh/GrDstProxyView.h"
21
#include "src/gpu/ganesh/GrProcessorSet.h"
22
#include "src/gpu/ganesh/GrRenderTask.h"
23
#include "src/gpu/ganesh/GrSurfaceProxy.h"
24
#include "src/gpu/ganesh/GrXferProcessor.h"
25
#include "src/gpu/ganesh/ops/GrOp.h"
26
27
#include <array>
28
#include <cstdint>
29
30
class GrAppliedClip;
31
class GrArenas;
32
class GrAuditTrail;
33
class GrCaps;
34
class GrDrawingManager;
35
class GrOpFlushState;
36
class GrRecordingContext;
37
class GrResourceAllocator;
38
class GrSurfaceProxyView;
39
class GrTextureResolveManager;
40
class OpsTaskTestingAccess;
41
class SkArenaAlloc;
42
class SkString;
43
enum GrSurfaceOrigin : int;
44
45
namespace skgpu::ganesh {
46
47
class SurfaceDrawContext;
48
49
class OpsTask : public GrRenderTask {
50
public:
51
    // Manage the arenas life time by maintaining are reference to it.
52
    OpsTask(GrDrawingManager*, GrSurfaceProxyView, GrAuditTrail*, sk_sp<GrArenas>);
53
    ~OpsTask() override;
54
55
267k
    OpsTask* asOpsTask() override { return this; }
56
57
112
    bool isEmpty() const { return fOpChains.empty(); }
58
37.1k
    bool usesMSAASurface() const { return fUsesMSAASurface; }
59
0
    GrXferBarrierFlags renderPassXferBarriers() const { return fRenderPassXferBarriers; }
60
61
    /**
62
     * Empties the draw buffer of any queued up draws.
63
     */
64
    void endFlush(GrDrawingManager*) override;
65
66
    void onPrePrepare(GrRecordingContext*) override;
67
    /**
68
     * Together these two functions flush all queued up draws to GrCommandBuffer. The return value
69
     * of onExecute() indicates whether any commands were actually issued to the GPU.
70
     */
71
    void onPrepare(GrOpFlushState* flushState) override;
72
    bool onExecute(GrOpFlushState* flushState) override;
73
74
407k
    void addSampledTexture(GrSurfaceProxy* proxy) {
75
        // This function takes a GrSurfaceProxy because all subsequent uses of the proxy do not
76
        // require the specifics of GrTextureProxy, so this avoids a number of unnecessary virtual
77
        // asTextureProxy() calls. However, sampling the proxy implicitly requires that the proxy
78
        // be a texture. Eventually, when proxies are a unified type with flags, this can just
79
        // assert that capability.
80
407k
        SkASSERT(proxy->asTextureProxy());
81
407k
        fSampledProxies.push_back(proxy);
82
407k
    }
83
84
    void addOp(GrDrawingManager*, GrOp::Owner, GrTextureResolveManager, const GrCaps&);
85
86
    void addDrawOp(GrDrawingManager*, GrOp::Owner, bool usesMSAA, const GrProcessorSet::Analysis&,
87
                   GrAppliedClip&&, const GrDstProxyView&, GrTextureResolveManager, const GrCaps&);
88
89
    void discard();
90
91
    enum class CanDiscardPreviousOps : bool {
92
        kYes = true,
93
        kNo = false
94
    };
95
96
    // Perform book-keeping for a fullscreen clear, regardless of how the clear is implemented later
97
    // (i.e. setColorLoadOp(), adding a ClearOp, or adding a FillRectOp that covers the device).
98
    // Returns true if the clear can be converted into a load op (barring device caps).
99
    bool resetForFullscreenClear(CanDiscardPreviousOps);
100
101
    // Must only be called if native color buffer clearing is enabled.
102
    void setColorLoadOp(GrLoadOp op, std::array<float, 4> color = {0, 0, 0, 0});
103
104
    // Returns whether the given opsTask can be appended at the end of this one.
105
    bool canMerge(const OpsTask*) const;
106
107
    // Merge as many opsTasks as possible from the head of 'tasks'. They should all be
108
    // renderPass compatible. Return the number of tasks merged into 'this'.
109
    int mergeFrom(SkSpan<const sk_sp<GrRenderTask>> tasks);
110
111
#ifdef SK_DEBUG
112
0
    int numClips() const override { return fNumClips; }
113
    void visitProxies_debugOnly(const GrVisitProxyFunc&) const override;
114
#endif
115
116
#if defined(GPU_TEST_UTILS)
117
    void dump(const SkString& label,
118
              SkString indent,
119
              bool printDependencies,
120
              bool close) const override;
121
0
    const char* name() const final { return "Ops"; }
122
0
    int numOpChains() const { return fOpChains.size(); }
123
0
    const GrOp* getChain(int index) const { return fOpChains[index].head(); }
124
#endif
125
126
protected:
127
    enum class StencilContent {
128
        kDontCare,
129
        kUserBitsCleared,  // User bits: cleared
130
                           // Clip bit: don't care (Ganesh always pre-clears the clip bit.)
131
        kPreserved
132
    };
133
134
    // Lets the caller specify what the content of the stencil buffer should be at the beginning
135
    // of the render pass.
136
    //
137
    // When requesting kClear: Tilers will load the stencil buffer with a "clear" op; non-tilers
138
    // will clear the stencil on first load, and then preserve it on subsequent loads. (Preserving
139
    // works because SurfaceDrawContexts are required to leave the user bits in a cleared state
140
    // once finished.)
141
    //
142
    // NOTE: initialContent must not be kClear if caps.performStencilClearsAsDraws() is true.
143
9.53k
    void setInitialStencilContent(StencilContent initialContent) {
144
9.53k
        fInitialStencilContent = initialContent;
145
9.53k
    }
146
147
    void recordOp(GrOp::Owner, bool usesMSAA, GrProcessorSet::Analysis, GrAppliedClip*,
148
                  const GrDstProxyView*, const GrCaps&);
149
150
    ExpectedOutcome onMakeClosed(GrRecordingContext*, SkIRect* targetUpdateBounds) override;
151
152
private:
153
748k
    bool isColorNoOp() const {
154
        // TODO: GrLoadOp::kDiscard (i.e., storing a discard) should also be grounds for skipping
155
        // execution. We currently don't because of Vulkan. See http://skbug.com/9373.
156
748k
        return fOpChains.empty() && GrLoadOp::kLoad == fColorLoadOp;
157
748k
    }
158
159
    void deleteOps();
160
161
    // If a surfaceDrawContext splits its opsTask, it uses this method to guarantee stencil values
162
    // get preserved across its split tasks.
163
8.89k
    void setMustPreserveStencil() { fMustPreserveStencil = true; }
164
165
    // Prevents this opsTask from merging backward. This is used by DMSAA when a non-multisampled
166
    // opsTask cannot be promoted to MSAA, or when we split a multisampled opsTask in order to
167
    // resolve its texture.
168
0
    void setCannotMergeBackward() { fCannotMergeBackward = true; }
169
170
    class OpChain {
171
    public:
172
        OpChain(GrOp::Owner, GrProcessorSet::Analysis, GrAppliedClip*, const GrDstProxyView*);
173
254k
        ~OpChain() {
174
            // The ops are stored in a GrMemoryPool and must be explicitly deleted via the pool.
175
254k
            SkASSERT(fList.empty());
176
254k
        }
177
178
        OpChain(const OpChain&) = delete;
179
        OpChain& operator=(const OpChain&) = delete;
180
12.7k
        OpChain(OpChain&&) = default;
181
        OpChain& operator=(OpChain&&) = default;
182
183
        void visitProxies(const GrVisitProxyFunc&) const;
184
185
1.44M
        GrOp* head() const { return fList.head(); }
186
187
482k
        GrAppliedClip* appliedClip() const { return fAppliedClip; }
188
482k
        const GrDstProxyView& dstProxyView() const { return fDstProxyView; }
189
509k
        const SkRect& bounds() const { return fBounds; }
190
191
        // Deletes all the ops in the chain.
192
        void deleteOps();
193
194
        // Attempts to move the ops from the passed chain to this chain at the head. Also attempts
195
        // to merge ops between the chains. Upon success the passed chain is empty.
196
        // Fails when the chains aren't of the same op type, have different clips or dst proxies.
197
        bool prependChain(OpChain*, const GrCaps&, SkArenaAlloc* opsTaskArena, GrAuditTrail*);
198
199
        // Attempts to add 'op' to this chain either by merging or adding to the tail. Returns
200
        // 'op' to the caller upon failure, otherwise null. Fails when the op and chain aren't of
201
        // the same op type, have different clips or dst proxies.
202
        GrOp::Owner appendOp(GrOp::Owner op, GrProcessorSet::Analysis, const GrDstProxyView*,
203
                             const GrAppliedClip*, const GrCaps&, SkArenaAlloc* opsTaskArena,
204
                             GrAuditTrail*);
205
206
482k
        bool shouldExecute() const {
207
482k
            return SkToBool(this->head());
208
482k
        }
209
210
        using sk_is_trivially_relocatable = std::true_type;
211
212
    private:
213
        class List {
214
        public:
215
0
            List() = default;
216
            List(GrOp::Owner);
217
            List(List&&);
218
            List& operator=(List&& that);
219
220
839k
            bool empty() const { return !SkToBool(fHead); }
221
2.71M
            GrOp* head() const { return fHead.get(); }
222
210k
            GrOp* tail() const { return fTail; }
223
224
            GrOp::Owner popHead();
225
            GrOp::Owner removeOp(GrOp* op);
226
            void pushHead(GrOp::Owner op);
227
            void pushTail(GrOp::Owner);
228
229
            void validate() const;
230
231
            using sk_is_trivially_relocatable = std::true_type;
232
233
        private:
234
            GrOp::Owner fHead{nullptr};
235
            GrOp* fTail{nullptr};
236
237
            static_assert(::sk_is_trivially_relocatable<decltype(fHead)>::value);
238
            static_assert(::sk_is_trivially_relocatable<decltype(fTail)>::value);
239
        };
240
241
        void validate() const;
242
243
        bool tryConcat(List*, GrProcessorSet::Analysis, const GrDstProxyView&, const GrAppliedClip*,
244
                       const SkRect& bounds, const GrCaps&, SkArenaAlloc* opsTaskArena,
245
                       GrAuditTrail*);
246
        static List DoConcat(List, List, const GrCaps&, SkArenaAlloc* opsTaskArena, GrAuditTrail*);
247
248
        List fList;
249
        GrProcessorSet::Analysis fProcessorAnalysis;
250
        GrDstProxyView fDstProxyView;
251
        GrAppliedClip* fAppliedClip;
252
        SkRect fBounds;
253
254
        static_assert(::sk_is_trivially_relocatable<decltype(fProcessorAnalysis)>::value);
255
        static_assert(::sk_is_trivially_relocatable<decltype(fDstProxyView)>::value);
256
        static_assert(::sk_is_trivially_relocatable<decltype(fAppliedClip)>::value);
257
        static_assert(::sk_is_trivially_relocatable<decltype(fBounds)>::value);
258
    };
259
260
    void onMakeSkippable() override;
261
262
    bool onIsUsed(GrSurfaceProxy*) const override;
263
264
    void gatherProxyIntervals(GrResourceAllocator*) const override;
265
266
    void forwardCombine(const GrCaps&);
267
268
    // Remove all ops, proxies, etc. Used in the merging algorithm when tasks can be skipped.
269
    void reset();
270
271
    friend class ::OpsTaskTestingAccess;
272
273
    // The SDC and OpsTask have to work together to handle buffer clears. In most cases, buffer
274
    // clearing can be done natively, in which case the op list's load ops are sufficient. In other
275
    // cases, draw ops must be used, which makes the SDC the best place for those decisions. This,
276
    // however, requires that the SDC be able to coordinate with the op list to achieve similar ends
277
    friend class skgpu::ganesh::SurfaceDrawContext;
278
279
    GrAuditTrail* fAuditTrail;
280
281
    bool fUsesMSAASurface;
282
    skgpu::Swizzle fTargetSwizzle;
283
    GrSurfaceOrigin fTargetOrigin;
284
285
    GrLoadOp fColorLoadOp = GrLoadOp::kLoad;
286
    std::array<float, 4> fLoadClearColor = {0, 0, 0, 0};
287
    StencilContent fInitialStencilContent = StencilContent::kDontCare;
288
    bool fMustPreserveStencil = false;
289
    bool fCannotMergeBackward = false;
290
291
    uint32_t fLastClipStackGenID = SK_InvalidUniqueID;
292
    SkIRect fLastDevClipBounds;
293
    int fLastClipNumAnalyticElements;
294
295
    GrXferBarrierFlags fRenderPassXferBarriers = GrXferBarrierFlags::kNone;
296
297
    // For ops/opsTask we have mean: 5 stdDev: 28
298
    skia_private::STArray<25, OpChain> fOpChains;
299
300
    sk_sp<GrArenas> fArenas;
301
    SkDEBUGCODE(int fNumClips;)
302
303
    // TODO: We could look into this being a set if we find we're adding a lot of duplicates that is
304
    // causing slow downs.
305
    skia_private::TArray<GrSurfaceProxy*, true> fSampledProxies;
306
307
    SkRect fTotalBounds = SkRect::MakeEmpty();
308
    SkIRect fClippedContentBounds = SkIRect::MakeEmpty();
309
};
310
311
}  // namespace skgpu::ganesh
312
313
#endif // OpsTask_DEFINED