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