1 /* 2 * Copyright 2012 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 GrEffect_DEFINED 9 #define GrEffect_DEFINED 10 11 #include "GrColor.h" 12 #include "GrEffectUnitTest.h" 13 #include "GrTexture.h" 14 #include "GrTextureAccess.h" 15 #include "GrTypesPriv.h" 16 17 class GrBackendEffectFactory; 18 class GrContext; 19 class GrCoordTransform; 20 class GrEffect; 21 class GrVertexEffect; 22 class SkString; 23 24 /** 25 * A Wrapper class for GrEffect. Its ref-count will track owners that may use effects to enqueue 26 * new draw operations separately from ownership within a deferred drawing queue. When the 27 * GrEffectRef ref count reaches zero the scratch GrResources owned by the effect can be recycled 28 * in service of later draws. However, the deferred draw queue may still own direct references to 29 * the underlying GrEffect. 30 * 31 * GrEffectRefs created by new are placed in a per-thread managed pool. The pool is destroyed when 32 * the thread ends. Therefore, all dynamically allocated GrEffectRefs must be unreffed before thread 33 * termination. 34 */ 35 class GrEffectRef : public SkRefCnt { 36 public: 37 SK_DECLARE_INST_COUNT(GrEffectRef); 38 virtual ~GrEffectRef(); 39 40 GrEffect* get() { return fEffect; } 41 const GrEffect* get() const { return fEffect; } 42 43 const GrEffect* operator-> () { return fEffect; } 44 const GrEffect* operator-> () const { return fEffect; } 45 46 void* operator new(size_t size); 47 void operator delete(void* target); 48 49 void* operator new(size_t size, void* placement) { 50 return ::operator new(size, placement); 51 } 52 void operator delete(void* target, void* placement) { 53 ::operator delete(target, placement); 54 } 55 56 private: 57 friend class GrEffect; // to construct these 58 59 explicit GrEffectRef(GrEffect* effect); 60 61 GrEffect* fEffect; 62 63 typedef SkRefCnt INHERITED; 64 }; 65 66 /** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the 67 Ganesh shading pipeline. 68 Subclasses must have a function that produces a human-readable name: 69 static const char* Name(); 70 GrEffect objects *must* be immutable: after being constructed, their fields may not change. 71 72 GrEffect subclass objects should be created by factory functions that return GrEffectRef. 73 There is no public way to wrap a GrEffect in a GrEffectRef. Thus, a factory should be a static 74 member function of a GrEffect subclass. 75 76 Because almost no code should ever handle a GrEffect directly outside of a GrEffectRef, we 77 privately inherit from SkRefCnt to help prevent accidental direct ref'ing/unref'ing of effects. 78 79 Dynamically allocated GrEffects and their corresponding GrEffectRefs are managed by a per-thread 80 memory pool. The ref count of an effect must reach 0 before the thread terminates and the pool 81 is destroyed. To create a static effect use the macro GR_CREATE_STATIC_EFFECT declared below. 82 */ 83 class GrEffect : private SkRefCnt { 84 public: 85 SK_DECLARE_INST_COUNT(GrEffect) 86 87 virtual ~GrEffect(); 88 89 /** 90 * This function is used to perform optimizations. When called the color and validFlags params 91 * indicate whether the input components to this effect in the FS will have known values. 92 * validFlags is a bitfield of GrColorComponentFlags. The function updates both params to 93 * indicate known values of its output. A component of the color param only has meaning if the 94 * corresponding bit in validFlags is set. 95 */ 96 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0; 97 98 /** Will this effect read the source color value? */ 99 bool willUseInputColor() const { return fWillUseInputColor; } 100 101 /** This object, besides creating back-end-specific helper objects, is used for run-time-type- 102 identification. The factory should be an instance of templated class, 103 GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have 104 a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created 105 by the factory. 106 107 Example: 108 class MyCustomEffect : public GrEffect { 109 ... 110 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 111 return GrTBackendEffectFactory<MyCustomEffect>::getInstance(); 112 } 113 ... 114 }; 115 */ 116 virtual const GrBackendEffectFactory& getFactory() const = 0; 117 118 /** Returns true if this and other effect conservatively draw identically. It can only return 119 true when the two effects are of the same subclass (i.e. they return the same object from 120 from getFactory()). 121 122 A return value of true from isEqual() should not be used to test whether the effects would 123 generate the same shader code. To test for identical code generation use the EffectKey 124 computed by the GrBackendEffectFactory: 125 effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB). 126 */ 127 bool isEqual(const GrEffectRef& other) const { 128 return this->isEqual(*other.get()); 129 } 130 131 /** Human-meaningful string to identify this effect; may be embedded 132 in generated shader code. */ 133 const char* name() const; 134 135 int numTransforms() const { return fCoordTransforms.count(); } 136 137 /** Returns the coordinate transformation at index. index must be valid according to 138 numTransforms(). */ 139 const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; } 140 141 int numTextures() const { return fTextureAccesses.count(); } 142 143 /** Returns the access pattern for the texture at index. index must be valid according to 144 numTextures(). */ 145 const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; } 146 147 /** Shortcut for textureAccess(index).texture(); */ 148 GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); } 149 150 /** Will this effect read the destination pixel value? */ 151 bool willReadDstColor() const { return fWillReadDstColor; } 152 153 /** Will this effect read the fragment position? */ 154 bool willReadFragmentPosition() const { return fWillReadFragmentPosition; } 155 156 /** Will this effect emit custom vertex shader code? 157 (To set this value the effect must inherit from GrVertexEffect.) */ 158 bool hasVertexCode() const { return fHasVertexCode; } 159 160 int numVertexAttribs() const { 161 SkASSERT(0 == fVertexAttribTypes.count() || fHasVertexCode); 162 return fVertexAttribTypes.count(); 163 } 164 165 GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; } 166 167 static const int kMaxVertexAttribs = 2; 168 169 /** Useful for effects that want to insert a texture matrix that is implied by the texture 170 dimensions */ 171 static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) { 172 SkASSERT(NULL != texture); 173 SkMatrix mat; 174 mat.setIDiv(texture->width(), texture->height()); 175 return mat; 176 } 177 178 void* operator new(size_t size); 179 void operator delete(void* target); 180 181 void* operator new(size_t size, void* placement) { 182 return ::operator new(size, placement); 183 } 184 void operator delete(void* target, void* placement) { 185 ::operator delete(target, placement); 186 } 187 188 /** These functions are used when recording effects into a deferred drawing queue. The inc call 189 keeps the effect alive outside of GrEffectRef while allowing any resources owned by the 190 effect to be returned to the cache for reuse. The dec call must balance the inc call. */ 191 void incDeferredRefCounts() const { 192 this->ref(); 193 int count = fTextureAccesses.count(); 194 for (int t = 0; t < count; ++t) { 195 fTextureAccesses[t]->getTexture()->incDeferredRefCount(); 196 } 197 } 198 void decDeferredRefCounts() const { 199 int count = fTextureAccesses.count(); 200 for (int t = 0; t < count; ++t) { 201 fTextureAccesses[t]->getTexture()->decDeferredRefCount(); 202 } 203 this->unref(); 204 } 205 206 protected: 207 /** 208 * Subclasses call this from their constructor to register coordinate transformations. The 209 * effect subclass manages the lifetime of the transformations (this function only stores a 210 * pointer). The GrCoordTransform is typically a member field of the GrEffect subclass. When the 211 * matrix has perspective, the transformed coordinates will have 3 components. Otherwise they'll 212 * have 2. This must only be called from the constructor because GrEffects are immutable. 213 */ 214 void addCoordTransform(const GrCoordTransform* coordTransform); 215 216 /** 217 * Subclasses call this from their constructor to register GrTextureAccesses. The effect 218 * subclass manages the lifetime of the accesses (this function only stores a pointer). The 219 * GrTextureAccess is typically a member field of the GrEffect subclass. This must only be 220 * called from the constructor because GrEffects are immutable. 221 */ 222 void addTextureAccess(const GrTextureAccess* textureAccess); 223 224 GrEffect() 225 : fWillReadDstColor(false) 226 , fWillReadFragmentPosition(false) 227 , fWillUseInputColor(true) 228 , fHasVertexCode(false) 229 , fEffectRef(NULL) {} 230 231 /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for 232 an example factory function. */ 233 static GrEffectRef* CreateEffectRef(GrEffect* effect) { 234 if (NULL == effect->fEffectRef) { 235 effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect)); 236 } else { 237 effect->fEffectRef->ref(); 238 } 239 return effect->fEffectRef; 240 } 241 242 static const GrEffectRef* CreateEffectRef(const GrEffect* effect) { 243 return CreateEffectRef(const_cast<GrEffect*>(effect)); 244 } 245 246 /** Used by GR_CREATE_STATIC_EFFECT below */ 247 static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) { 248 SkASSERT(NULL == effect->fEffectRef); 249 effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect)); 250 return effect->fEffectRef; 251 } 252 253 254 /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a 255 GrEffectRef. E.g.: 256 257 class EffectSubclass : public GrEffect { 258 public: 259 GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) { 260 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...))); 261 return CreateEffectRef(effect); 262 } 263 */ 264 class AutoEffectUnref { 265 public: 266 AutoEffectUnref(GrEffect* effect) : fEffect(effect) { } 267 ~AutoEffectUnref() { fEffect->unref(); } 268 operator GrEffect*() { return fEffect; } 269 private: 270 GrEffect* fEffect; 271 }; 272 273 /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass 274 */ 275 template <typename T> 276 static const T& CastEffect(const GrEffect& effectRef) { 277 return *static_cast<const T*>(&effectRef); 278 } 279 280 /** 281 * If the effect subclass will read the destination pixel value then it must call this function 282 * from its constructor. Otherwise, when its generated backend-specific effect class attempts 283 * to generate code that reads the destination pixel it will fail. 284 */ 285 void setWillReadDstColor() { fWillReadDstColor = true; } 286 287 /** 288 * If the effect will generate a backend-specific effect that will read the fragment position 289 * in the FS then it must call this method from its constructor. Otherwise, the request to 290 * access the fragment position will be denied. 291 */ 292 void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; } 293 294 /** 295 * If the effect will generate a result that does not depend on the input color value then it must 296 * call this function from its constructor. Otherwise, when its generated backend-specific code 297 * might fail during variable binding due to unused variables. 298 */ 299 void setWillNotUseInputColor() { fWillUseInputColor = false; } 300 301 private: 302 bool isEqual(const GrEffect& other) const { 303 if (&this->getFactory() != &other.getFactory()) { 304 return false; 305 } 306 bool result = this->onIsEqual(other); 307 #ifdef SK_DEBUG 308 if (result) { 309 this->assertEquality(other); 310 } 311 #endif 312 return result; 313 } 314 315 SkDEBUGCODE(void assertEquality(const GrEffect& other) const;) 316 317 /** Subclass implements this to support isEqual(). It will only be called if it is known that 318 the two effects are of the same subclass (i.e. they return the same object from 319 getFactory()).*/ 320 virtual bool onIsEqual(const GrEffect& other) const = 0; 321 322 void EffectRefDestroyed() { fEffectRef = NULL; } 323 324 friend class GrEffectRef; // to call EffectRefDestroyed() 325 friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage 326 // from deferred state, to call isEqual on naked GrEffects, and 327 // to inc/dec deferred ref counts. 328 friend class GrVertexEffect; // to set fHasVertexCode and build fVertexAttribTypes. 329 330 SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms; 331 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses; 332 SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes; 333 bool fWillReadDstColor; 334 bool fWillReadFragmentPosition; 335 bool fWillUseInputColor; 336 bool fHasVertexCode; 337 GrEffectRef* fEffectRef; 338 339 typedef SkRefCnt INHERITED; 340 }; 341 342 inline GrEffectRef::GrEffectRef(GrEffect* effect) { 343 SkASSERT(NULL != effect); 344 effect->ref(); 345 fEffect = effect; 346 } 347 348 /** 349 * This creates an effect outside of the effect memory pool. The effect's destructor will be called 350 * at global destruction time. NAME will be the name of the created GrEffectRef. 351 */ 352 #define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS) \ 353 enum { \ 354 k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8), \ 355 k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef) \ 356 }; \ 357 static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage; \ 358 static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset; \ 359 static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\ 360 static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect); \ 361 static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect)); \ 362 static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME) 363 364 365 #endif 366