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/SkStrokeRec.h" 14 #include "include/core/SkTypes.h" 15 #include "include/private/GrRecordingContext.h" 16 #include "include/private/SkColorData.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/GrPathRendering.h" 25 #include "src/gpu/GrPrimitiveProcessor.h" 26 #include "src/gpu/GrRenderTask.h" 27 #include "src/gpu/ops/GrDrawOp.h" 28 #include "src/gpu/ops/GrOp.h" 29 30 class GrAuditTrail; 31 class GrCaps; 32 class GrClearOp; 33 class GrGpuBuffer; 34 class GrRenderTargetProxy; 35 36 class GrOpsTask : public GrRenderTask { 37 private: 38 using DstProxyView = GrXferProcessor::DstProxyView; 39 40 public: 41 // The Arenas must outlive the GrOpsTask, either by preserving the context that owns 42 // the pool, or by moving the pool to the DDL that takes over the GrOpsTask. 43 GrOpsTask(GrRecordingContext::Arenas, GrSurfaceProxyView, GrAuditTrail*); 44 ~GrOpsTask() override; 45 asOpsTask()46 GrOpsTask* asOpsTask() override { return this; } 47 isEmpty()48 bool isEmpty() const { return fOpChains.empty(); } 49 50 /** 51 * Empties the draw buffer of any queued up draws. 52 */ 53 void endFlush() override; 54 55 void onPrePrepare(GrRecordingContext*) override; 56 /** 57 * Together these two functions flush all queued up draws to GrCommandBuffer. The return value 58 * of executeOps() indicates whether any commands were actually issued to the GPU. 59 */ 60 void onPrepare(GrOpFlushState* flushState) override; 61 bool onExecute(GrOpFlushState* flushState) override; 62 addSampledTexture(GrSurfaceProxy * proxy)63 void addSampledTexture(GrSurfaceProxy* proxy) { 64 // This function takes a GrSurfaceProxy because all subsequent uses of the proxy do not 65 // require the specifics of GrTextureProxy, so this avoids a number of unnecessary virtual 66 // asTextureProxy() calls. However, sampling the proxy implicitly requires that the proxy 67 // be a texture. Eventually, when proxies are a unified type with flags, this can just 68 // assert that capability. 69 SkASSERT(proxy->asTextureProxy()); 70 fSampledProxies.push_back(proxy); 71 } 72 addOp(std::unique_ptr<GrOp> op,GrTextureResolveManager textureResolveManager,const GrCaps & caps)73 void addOp(std::unique_ptr<GrOp> op, GrTextureResolveManager textureResolveManager, 74 const GrCaps& caps) { 75 auto addDependency = [ textureResolveManager, &caps, this ] ( 76 GrSurfaceProxy* p, GrMipMapped mipmapped) { 77 this->addDependency(p, mipmapped, textureResolveManager, caps); 78 }; 79 80 op->visitProxies(addDependency); 81 82 this->recordOp(std::move(op), GrProcessorSet::EmptySetAnalysis(), nullptr, nullptr, caps); 83 } 84 addWaitOp(std::unique_ptr<GrOp> op,GrTextureResolveManager textureResolveManager,const GrCaps & caps)85 void addWaitOp(std::unique_ptr<GrOp> op, GrTextureResolveManager textureResolveManager, 86 const GrCaps& caps) { 87 fHasWaitOp = true; 88 this->addOp(std::move(op), textureResolveManager, caps); 89 } 90 addDrawOp(std::unique_ptr<GrDrawOp> op,const GrProcessorSet::Analysis & processorAnalysis,GrAppliedClip && clip,const DstProxyView & dstProxyView,GrTextureResolveManager textureResolveManager,const GrCaps & caps)91 void addDrawOp(std::unique_ptr<GrDrawOp> op, const GrProcessorSet::Analysis& processorAnalysis, 92 GrAppliedClip&& clip, const DstProxyView& dstProxyView, 93 GrTextureResolveManager textureResolveManager, const GrCaps& caps) { 94 auto addDependency = [ textureResolveManager, &caps, this ] ( 95 GrSurfaceProxy* p, GrMipMapped mipmapped) { 96 this->addSampledTexture(p); 97 this->addDependency(p, mipmapped, textureResolveManager, caps); 98 }; 99 100 op->visitProxies(addDependency); 101 clip.visitProxies(addDependency); 102 if (dstProxyView.proxy()) { 103 this->addSampledTexture(dstProxyView.proxy()); 104 addDependency(dstProxyView.proxy(), GrMipMapped::kNo); 105 } 106 107 this->recordOp(std::move(op), processorAnalysis, clip.doesClip() ? &clip : nullptr, 108 &dstProxyView, caps); 109 } 110 111 void discard(); 112 113 SkDEBUGCODE(void dump(bool printDependencies) const override;) SkDEBUGCODE(int numClips ()const override{ return fNumClips; })114 SkDEBUGCODE(int numClips() const override { return fNumClips; }) 115 SkDEBUGCODE(void visitProxies_debugOnly(const GrOp::VisitProxyFunc&) const override;) 116 117 #if GR_TEST_UTILS 118 int numOpChains() const { return fOpChains.count(); } getChain(int index)119 const GrOp* getChain(int index) const { return fOpChains[index].head(); } 120 #endif 121 122 private: isNoOp()123 bool isNoOp() const { 124 // TODO: GrLoadOp::kDiscard (i.e., storing a discard) should also be grounds for skipping 125 // execution. We currently don't because of Vulkan. See http://skbug.com/9373. 126 // 127 // TODO: We should also consider stencil load/store here. We get away with it for now 128 // because we never discard stencil buffers. 129 return fOpChains.empty() && GrLoadOp::kLoad == fColorLoadOp; 130 } 131 132 void deleteOps(); 133 134 enum class StencilContent { 135 kDontCare, 136 kUserBitsCleared, // User bits: cleared 137 // Clip bit: don't care (Ganesh always pre-clears the clip bit.) 138 kPreserved 139 }; 140 141 // Lets the caller specify what the content of the stencil buffer should be at the beginning 142 // of the render pass. 143 // 144 // When requesting kClear: Tilers will load the stencil buffer with a "clear" op; non-tilers 145 // will clear the stencil on first load, and then preserve it on subsequent loads. (Preserving 146 // works because renderTargetContexts are required to leave the user bits in a cleared state 147 // once finished.) 148 // 149 // NOTE: initialContent must not be kClear if caps.performStencilClearsAsDraws() is true. setInitialStencilContent(StencilContent initialContent)150 void setInitialStencilContent(StencilContent initialContent) { 151 fInitialStencilContent = initialContent; 152 } 153 154 // If a renderTargetContext splits its opsTask, it uses this method to guarantee stencil values 155 // get preserved across its split tasks. setMustPreserveStencil()156 void setMustPreserveStencil() { fMustPreserveStencil = true; } 157 158 // Must only be called if native color buffer clearing is enabled. 159 void setColorLoadOp(GrLoadOp op, const SkPMColor4f& color); 160 // Sets the clear color to transparent black setColorLoadOp(GrLoadOp op)161 void setColorLoadOp(GrLoadOp op) { 162 static const SkPMColor4f kDefaultClearColor = {0.f, 0.f, 0.f, 0.f}; 163 this->setColorLoadOp(op, kDefaultClearColor); 164 } 165 166 enum class CanDiscardPreviousOps : bool { 167 kYes = true, 168 kNo = false 169 }; 170 171 // Perform book-keeping for a fullscreen clear, regardless of how the clear is implemented later 172 // (i.e. setColorLoadOp(), adding a ClearOp, or adding a GrFillRectOp that covers the device). 173 // Returns true if the clear can be converted into a load op (barring device caps). 174 bool resetForFullscreenClear(CanDiscardPreviousOps); 175 176 class OpChain { 177 public: 178 OpChain(const OpChain&) = delete; 179 OpChain& operator=(const OpChain&) = delete; 180 OpChain(std::unique_ptr<GrOp>, GrProcessorSet::Analysis, GrAppliedClip*, 181 const DstProxyView*); 182 ~OpChain()183 ~OpChain() { 184 // The ops are stored in a GrMemoryPool and must be explicitly deleted via the pool. 185 SkASSERT(fList.empty()); 186 } 187 188 void visitProxies(const GrOp::VisitProxyFunc&) const; 189 head()190 GrOp* head() const { return fList.head(); } 191 appliedClip()192 GrAppliedClip* appliedClip() const { return fAppliedClip; } dstProxyView()193 const DstProxyView& dstProxyView() const { return fDstProxyView; } bounds()194 const SkRect& bounds() const { return fBounds; } 195 196 // Deletes all the ops in the chain via the pool. 197 void deleteOps(GrOpMemoryPool* pool); 198 199 // Attempts to move the ops from the passed chain to this chain at the head. Also attempts 200 // to merge ops between the chains. Upon success the passed chain is empty. 201 // Fails when the chains aren't of the same op type, have different clips or dst proxies. 202 bool prependChain(OpChain*, const GrCaps&, GrRecordingContext::Arenas*, GrAuditTrail*); 203 204 // Attempts to add 'op' to this chain either by merging or adding to the tail. Returns 205 // 'op' to the caller upon failure, otherwise null. Fails when the op and chain aren't of 206 // the same op type, have different clips or dst proxies. 207 std::unique_ptr<GrOp> appendOp(std::unique_ptr<GrOp> op, GrProcessorSet::Analysis, 208 const DstProxyView*, const GrAppliedClip*, const GrCaps&, 209 GrRecordingContext::Arenas*, GrAuditTrail*); 210 setSkipExecuteFlag()211 void setSkipExecuteFlag() { fSkipExecute = true; } shouldExecute()212 bool shouldExecute() const { 213 return SkToBool(this->head()) && !fSkipExecute; 214 } 215 216 private: 217 class List { 218 public: 219 List() = default; 220 List(std::unique_ptr<GrOp>); 221 List(List&&); 222 List& operator=(List&& that); 223 empty()224 bool empty() const { return !SkToBool(fHead); } head()225 GrOp* head() const { return fHead.get(); } tail()226 GrOp* tail() const { return fTail; } 227 228 std::unique_ptr<GrOp> popHead(); 229 std::unique_ptr<GrOp> removeOp(GrOp* op); 230 void pushHead(std::unique_ptr<GrOp> op); 231 void pushTail(std::unique_ptr<GrOp>); 232 233 void validate() const; 234 235 private: 236 std::unique_ptr<GrOp> fHead; 237 GrOp* fTail = nullptr; 238 }; 239 240 void validate() const; 241 242 bool tryConcat(List*, GrProcessorSet::Analysis, const DstProxyView&, const GrAppliedClip*, 243 const SkRect& bounds, const GrCaps&, GrRecordingContext::Arenas*, 244 GrAuditTrail*); 245 static List DoConcat(List, List, const GrCaps&, GrRecordingContext::Arenas*, GrAuditTrail*); 246 247 List fList; 248 GrProcessorSet::Analysis fProcessorAnalysis; 249 DstProxyView fDstProxyView; 250 GrAppliedClip* fAppliedClip; 251 SkRect fBounds; 252 253 // We set this flag to true if any of the ops' proxies fail to instantiate so that we know 254 // not to try and draw the op. 255 bool fSkipExecute = false; 256 }; 257 258 259 bool onIsUsed(GrSurfaceProxy*) const override; 260 261 void handleInternalAllocationFailure() override; 262 263 void gatherProxyIntervals(GrResourceAllocator*) const override; 264 265 void recordOp(std::unique_ptr<GrOp>, GrProcessorSet::Analysis, GrAppliedClip*, 266 const DstProxyView*, const GrCaps& caps); 267 268 void forwardCombine(const GrCaps&); 269 270 ExpectedOutcome onMakeClosed(const GrCaps& caps, SkIRect* targetUpdateBounds) override; 271 272 friend class GrRenderTargetContextPriv; // for stencil clip state. TODO: this is invasive 273 274 // The RTC and OpsTask have to work together to handle buffer clears. In most cases, buffer 275 // clearing can be done natively, in which case the op list's load ops are sufficient. In other 276 // cases, draw ops must be used, which makes the RTC the best place for those decisions. This, 277 // however, requires that the RTC be able to coordinate with the op list to achieve similar ends 278 friend class GrRenderTargetContext; 279 280 // This is a backpointer to the Arenas that holds the memory for this GrOpsTask's ops. In the 281 // DDL case, the Arenas must have been detached from the original recording context and moved 282 // into the owning DDL. 283 GrRecordingContext::Arenas fArenas; 284 GrAuditTrail* fAuditTrail; 285 286 GrLoadOp fColorLoadOp = GrLoadOp::kLoad; 287 SkPMColor4f fLoadClearColor = SK_PMColor4fTRANSPARENT; 288 StencilContent fInitialStencilContent = StencilContent::kDontCare; 289 bool fMustPreserveStencil = false; 290 291 uint32_t fLastClipStackGenID; 292 SkIRect fLastDevClipBounds; 293 int fLastClipNumAnalyticFPs; 294 295 // We must track if we have a wait op so that we don't delete the op when we have a full clear. 296 bool fHasWaitOp = false;; 297 298 // For ops/opsTask we have mean: 5 stdDev: 28 299 SkSTArray<25, OpChain, true> fOpChains; 300 301 // MDB TODO: 4096 for the first allocation of the clip space will be huge overkill. 302 // Gather statistics to determine the correct size. 303 SkArenaAlloc fClipAllocator{4096}; 304 SkDEBUGCODE(int fNumClips;) 305 306 // TODO: We could look into this being a set if we find we're adding a lot of duplicates that is 307 // causing slow downs. 308 SkTArray<GrSurfaceProxy*, true> fSampledProxies; 309 310 SkRect fTotalBounds = SkRect::MakeEmpty(); 311 SkIRect fClippedContentBounds = SkIRect::MakeEmpty(); 312 }; 313 314 #endif 315