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 asOpsTask()55 OpsTask* asOpsTask() override { return this; } 56 isEmpty()57 bool isEmpty() const { return fOpChains.empty(); } usesMSAASurface()58 bool usesMSAASurface() const { return fUsesMSAASurface; } renderPassXferBarriers()59 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 addSampledTexture(GrSurfaceProxy * proxy)74 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 SkASSERT(proxy->asTextureProxy()); 81 fSampledProxies.push_back(proxy); 82 } 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 numClips()112 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; name()121 const char* name() const final { return "Ops"; } numOpChains()122 int numOpChains() const { return fOpChains.size(); } getChain(int index)123 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. setInitialStencilContent(StencilContent initialContent)143 void setInitialStencilContent(StencilContent initialContent) { 144 fInitialStencilContent = initialContent; 145 } 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: isColorNoOp()153 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 return fOpChains.empty() && GrLoadOp::kLoad == fColorLoadOp; 157 } 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. setMustPreserveStencil()163 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. setCannotMergeBackward()168 void setCannotMergeBackward() { fCannotMergeBackward = true; } 169 170 class OpChain { 171 public: 172 OpChain(GrOp::Owner, GrProcessorSet::Analysis, GrAppliedClip*, const GrDstProxyView*); ~OpChain()173 ~OpChain() { 174 // The ops are stored in a GrMemoryPool and must be explicitly deleted via the pool. 175 SkASSERT(fList.empty()); 176 } 177 178 OpChain(const OpChain&) = delete; 179 OpChain& operator=(const OpChain&) = delete; 180 OpChain(OpChain&&) = default; 181 OpChain& operator=(OpChain&&) = default; 182 183 void visitProxies(const GrVisitProxyFunc&) const; 184 head()185 GrOp* head() const { return fList.head(); } 186 appliedClip()187 GrAppliedClip* appliedClip() const { return fAppliedClip; } dstProxyView()188 const GrDstProxyView& dstProxyView() const { return fDstProxyView; } bounds()189 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 shouldExecute()206 bool shouldExecute() const { 207 return SkToBool(this->head()); 208 } 209 210 using sk_is_trivially_relocatable = std::true_type; 211 212 private: 213 class List { 214 public: 215 List() = default; 216 List(GrOp::Owner); 217 List(List&&); 218 List& operator=(List&& that); 219 empty()220 bool empty() const { return !SkToBool(fHead); } head()221 GrOp* head() const { return fHead.get(); } tail()222 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 314