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