1 /* 2 * Copyright 2015 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 GrOp_DEFINED 9 #define GrOp_DEFINED 10 11 #include "../private/SkAtomics.h" 12 #include "GrGpuResource.h" 13 #include "GrNonAtomicRef.h" 14 #include "GrXferProcessor.h" 15 #include "SkMatrix.h" 16 #include "SkRect.h" 17 #include "SkString.h" 18 19 #include <new> 20 21 class GrCaps; 22 class GrGpuCommandBuffer; 23 class GrOpFlushState; 24 25 /** 26 * GrOp is the base class for all Ganesh deferred GPU operations. To facilitate reordering and to 27 * minimize draw calls, Ganesh does not generate geometry inline with draw calls. Instead, it 28 * captures the arguments to the draw and then generates the geometry when flushing. This gives GrOp 29 * subclasses complete freedom to decide how/when to combine in order to produce fewer draw calls 30 * and minimize state changes. 31 * 32 * Ops of the same subclass may be merged using combineIfPossible. When two ops merge, one 33 * takes on the union of the data and the other is left empty. The merged op becomes responsible 34 * for drawing the data from both the original ops. 35 * 36 * If there are any possible optimizations which might require knowing more about the full state of 37 * the draw, e.g. whether or not the GrOp is allowed to tweak alpha for coverage, then this 38 * information will be communicated to the GrOp prior to geometry generation. 39 * 40 * The bounds of the op must contain all the vertices in device space *irrespective* of the clip. 41 * The bounds are used in determining which clip elements must be applied and thus the bounds cannot 42 * in turn depend upon the clip. 43 */ 44 #define GR_OP_SPEW 0 45 #if GR_OP_SPEW 46 #define GrOP_SPEW(code) code 47 #define GrOP_INFO(...) SkDebugf(__VA_ARGS__) 48 #else 49 #define GrOP_SPEW(code) 50 #define GrOP_INFO(...) 51 #endif 52 53 // A helper macro to generate a class static id 54 #define DEFINE_OP_CLASS_ID \ 55 static uint32_t ClassID() { \ 56 static uint32_t kClassID = GenOpClassID(); \ 57 return kClassID; \ 58 } 59 60 class GrOp : private SkNoncopyable { 61 public: 62 GrOp(uint32_t classID); 63 virtual ~GrOp(); 64 65 virtual const char* name() const = 0; 66 combineIfPossible(GrOp * that,const GrCaps & caps)67 bool combineIfPossible(GrOp* that, const GrCaps& caps) { 68 if (this->classID() != that->classID()) { 69 return false; 70 } 71 72 return this->onCombineIfPossible(that, caps); 73 } 74 bounds()75 const SkRect& bounds() const { 76 SkASSERT(kUninitialized_BoundsFlag != fBoundsFlags); 77 return fBounds; 78 } 79 setClippedBounds(const SkRect & clippedBounds)80 void setClippedBounds(const SkRect& clippedBounds) { 81 fBounds = clippedBounds; 82 // The clipped bounds already incorporate any effect of the bounds flags. 83 fBoundsFlags = 0; 84 } 85 hasAABloat()86 bool hasAABloat() const { 87 SkASSERT(fBoundsFlags != kUninitialized_BoundsFlag); 88 return SkToBool(fBoundsFlags & kAABloat_BoundsFlag); 89 } 90 hasZeroArea()91 bool hasZeroArea() const { 92 SkASSERT(fBoundsFlags != kUninitialized_BoundsFlag); 93 return SkToBool(fBoundsFlags & kZeroArea_BoundsFlag); 94 } 95 96 void* operator new(size_t size); 97 void operator delete(void* target); 98 new(size_t size,void * placement)99 void* operator new(size_t size, void* placement) { 100 return ::operator new(size, placement); 101 } delete(void * target,void * placement)102 void operator delete(void* target, void* placement) { 103 ::operator delete(target, placement); 104 } 105 106 /** 107 * Helper for safely down-casting to a GrOp subclass 108 */ cast()109 template <typename T> const T& cast() const { 110 SkASSERT(T::ClassID() == this->classID()); 111 return *static_cast<const T*>(this); 112 } 113 cast()114 template <typename T> T* cast() { 115 SkASSERT(T::ClassID() == this->classID()); 116 return static_cast<T*>(this); 117 } 118 classID()119 uint32_t classID() const { SkASSERT(kIllegalOpID != fClassID); return fClassID; } 120 121 // We lazily initialize the uniqueID because currently the only user is GrAuditTrail uniqueID()122 uint32_t uniqueID() const { 123 if (kIllegalOpID == fUniqueID) { 124 fUniqueID = GenOpID(); 125 } 126 return fUniqueID; 127 } 128 129 /** 130 * This is called to notify the op that it has been recorded into a GrOpList. Ops can use this 131 * to begin preparations for the flush of the op list. Note that the op still may either be 132 * combined into another op or have another op combined into it via combineIfPossible() after 133 * this call is made. 134 */ wasRecorded()135 virtual void wasRecorded() {} 136 137 /** 138 * Called prior to executing. The op should perform any resource creation or data transfers 139 * necessary before execute() is called. 140 */ prepare(GrOpFlushState * state)141 void prepare(GrOpFlushState* state) { this->onPrepare(state); } 142 143 /** Issues the op's commands to GrGpu. */ execute(GrOpFlushState * state)144 void execute(GrOpFlushState* state) { this->onExecute(state); } 145 146 /** Used for spewing information about ops when debugging. */ dumpInfo()147 virtual SkString dumpInfo() const { 148 SkString string; 149 string.appendf("OpBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", 150 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); 151 return string; 152 } 153 154 protected: 155 /** 156 * Indicates that the op will produce geometry that extends beyond its bounds for the 157 * purpose of ensuring that the fragment shader runs on partially covered pixels for 158 * non-MSAA antialiasing. 159 */ 160 enum class HasAABloat { 161 kYes, 162 kNo 163 }; 164 /** 165 * Indicates that the geometry represented by the op has zero area (e.g. it is hairline or 166 * points). 167 */ 168 enum class IsZeroArea { 169 kYes, 170 kNo 171 }; setBounds(const SkRect & newBounds,HasAABloat aabloat,IsZeroArea zeroArea)172 void setBounds(const SkRect& newBounds, HasAABloat aabloat, IsZeroArea zeroArea) { 173 fBounds = newBounds; 174 this->setBoundsFlags(aabloat, zeroArea); 175 } setTransformedBounds(const SkRect & srcBounds,const SkMatrix & m,HasAABloat aabloat,IsZeroArea zeroArea)176 void setTransformedBounds(const SkRect& srcBounds, const SkMatrix& m, 177 HasAABloat aabloat, IsZeroArea zeroArea) { 178 m.mapRect(&fBounds, srcBounds); 179 this->setBoundsFlags(aabloat, zeroArea); 180 } 181 joinBounds(const GrOp & that)182 void joinBounds(const GrOp& that) { 183 if (that.hasAABloat()) { 184 fBoundsFlags |= kAABloat_BoundsFlag; 185 } 186 if (that.hasZeroArea()) { 187 fBoundsFlags |= kZeroArea_BoundsFlag; 188 } 189 return fBounds.joinPossiblyEmptyRect(that.fBounds); 190 } 191 replaceBounds(const GrOp & that)192 void replaceBounds(const GrOp& that) { 193 fBounds = that.fBounds; 194 fBoundsFlags = that.fBoundsFlags; 195 } 196 GenOpClassID()197 static uint32_t GenOpClassID() { return GenID(&gCurrOpClassID); } 198 199 private: 200 virtual bool onCombineIfPossible(GrOp*, const GrCaps& caps) = 0; 201 202 virtual void onPrepare(GrOpFlushState*) = 0; 203 virtual void onExecute(GrOpFlushState*) = 0; 204 GenID(int32_t * idCounter)205 static uint32_t GenID(int32_t* idCounter) { 206 // The atomic inc returns the old value not the incremented value. So we add 207 // 1 to the returned value. 208 uint32_t id = static_cast<uint32_t>(sk_atomic_inc(idCounter)) + 1; 209 if (!id) { 210 SkFAIL("This should never wrap as it should only be called once for each GrOp " 211 "subclass."); 212 } 213 return id; 214 } 215 setBoundsFlags(HasAABloat aabloat,IsZeroArea zeroArea)216 void setBoundsFlags(HasAABloat aabloat, IsZeroArea zeroArea) { 217 fBoundsFlags = 0; 218 fBoundsFlags |= (HasAABloat::kYes == aabloat) ? kAABloat_BoundsFlag : 0; 219 fBoundsFlags |= (IsZeroArea ::kYes == zeroArea) ? kZeroArea_BoundsFlag : 0; 220 } 221 222 enum { 223 kIllegalOpID = 0, 224 }; 225 226 enum BoundsFlags { 227 kAABloat_BoundsFlag = 0x1, 228 kZeroArea_BoundsFlag = 0x2, 229 SkDEBUGCODE(kUninitialized_BoundsFlag = 0x4) 230 }; 231 232 const uint16_t fClassID; 233 uint16_t fBoundsFlags; 234 GenOpID()235 static uint32_t GenOpID() { return GenID(&gCurrOpUniqueID); } 236 mutable uint32_t fUniqueID; 237 SkRect fBounds; 238 239 static int32_t gCurrOpUniqueID; 240 static int32_t gCurrOpClassID; 241 }; 242 243 #endif 244