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