GrEffect.h revision 7839ce1af63bf12fe7b3caa866970bbbb3afb13d
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 "GrNoncopyable.h" 14#include "GrRefCnt.h" 15#include "GrTexture.h" 16#include "GrTextureAccess.h" 17#include "GrTypesPriv.h" 18 19class GrBackendEffectFactory; 20class GrContext; 21class GrEffect; 22class 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 */ 35class GrEffectRef : public SkRefCnt { 36public: 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 56private: 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 GrRefCnt 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 */ 83class GrEffect : private GrRefCnt { 84public: 85 SK_DECLARE_INST_COUNT(GrEffect) 86 87 /** 88 * The types of vertex coordinates available to an effect in the vertex shader. Effects can 89 * require their own vertex attribute but these coordinates are made available by the framework 90 * in all programs. kCustom_CoordsType is provided to signify that an alternative set of coords 91 * is used (usually an explicit vertex attribute) but its meaning is determined by the effect 92 * subclass. 93 */ 94 enum CoordsType { 95 kLocal_CoordsType, 96 kPosition_CoordsType, 97 98 kCustom_CoordsType, 99 }; 100 101 virtual ~GrEffect(); 102 103 /** 104 * This function is used to perform optimizations. When called the color and validFlags params 105 * indicate whether the input components to this effect in the FS will have known values. 106 * validFlags is a bitfield of GrColorComponentFlags. The function updates both params to 107 * indicate known values of its output. A component of the color param only has meaning if the 108 * corresponding bit in validFlags is set. 109 */ 110 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0; 111 112 /** This object, besides creating back-end-specific helper objects, is used for run-time-type- 113 identification. The factory should be an instance of templated class, 114 GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have 115 a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created 116 by the factory. 117 118 Example: 119 class MyCustomEffect : public GrEffect { 120 ... 121 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 122 return GrTBackendEffectFactory<MyCustomEffect>::getInstance(); 123 } 124 ... 125 }; 126 */ 127 virtual const GrBackendEffectFactory& getFactory() const = 0; 128 129 /** Returns true if this and other effect conservatively draw identically. It can only return 130 true when the two effects are of the same subclass (i.e. they return the same object from 131 from getFactory()). 132 133 A return value of true from isEqual() should not be used to test whether the effects would 134 generate the same shader code. To test for identical code generation use the EffectKey 135 computed by the GrBackendEffectFactory: 136 effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB). 137 */ 138 bool isEqual(const GrEffectRef& other) const { 139 return this->isEqual(*other.get()); 140 } 141 142 /** Human-meaningful string to identify this effect; may be embedded 143 in generated shader code. */ 144 const char* name() const; 145 146 int numTextures() const { return fTextureAccesses.count(); } 147 148 /** Returns the access pattern for the texture at index. index must be valid according to 149 numTextures(). */ 150 const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; } 151 152 /** Shortcut for textureAccess(index).texture(); */ 153 GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); } 154 155 /** Will this effect read the destination pixel value? */ 156 bool willReadDstColor() const { return fWillReadDstColor; } 157 158 /** Will this effect read the fragment position? */ 159 bool willReadFragmentPosition() const { return fWillReadFragmentPosition; } 160 161 int numVertexAttribs() const { return fVertexAttribTypes.count(); } 162 163 GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; } 164 165 static const int kMaxVertexAttribs = 2; 166 167 /** Useful for effects that want to insert a texture matrix that is implied by the texture 168 dimensions */ 169 static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) { 170 GrAssert(NULL != texture); 171 SkMatrix mat; 172 mat.setIDiv(texture->width(), texture->height()); 173 return mat; 174 } 175 176 void* operator new(size_t size); 177 void operator delete(void* target); 178 179 void* operator new(size_t size, void* placement) { 180 return ::operator new(size, placement); 181 } 182 void operator delete(void* target, void* placement) { 183 ::operator delete(target, placement); 184 } 185 186 /** These functions are used when recording effects into a deferred drawing queue. The inc call 187 keeps the effect alive outside of GrEffectRef while allowing any resources owned by the 188 effect to be returned to the cache for reuse. The dec call must balance the inc call. */ 189 void incDeferredRefCounts() const { 190 this->ref(); 191 int count = fTextureAccesses.count(); 192 for (int t = 0; t < count; ++t) { 193 fTextureAccesses[t]->getTexture()->incDeferredRefCount(); 194 } 195 } 196 void decDeferredRefCounts() const { 197 int count = fTextureAccesses.count(); 198 for (int t = 0; t < count; ++t) { 199 fTextureAccesses[t]->getTexture()->decDeferredRefCount(); 200 } 201 this->unref(); 202 } 203 204protected: 205 /** 206 * Subclasses call this from their constructor to register GrTextureAccesses. The effect 207 * subclass manages the lifetime of the accesses (this function only stores a pointer). This 208 * must only be called from the constructor because GrEffects are immutable. 209 */ 210 void addTextureAccess(const GrTextureAccess* textureAccess); 211 212 /** 213 * Subclasses call this from their constructor to register vertex attributes (at most 214 * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are 215 * immutable. 216 */ 217 void addVertexAttrib(GrSLType type); 218 219 GrEffect() : fWillReadDstColor(false), fWillReadFragmentPosition(false), fEffectRef(NULL) {} 220 221 /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for 222 an example factory function. */ 223 static GrEffectRef* CreateEffectRef(GrEffect* effect) { 224 if (NULL == effect->fEffectRef) { 225 effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect)); 226 } else { 227 effect->fEffectRef->ref(); 228 } 229 return effect->fEffectRef; 230 } 231 232 static const GrEffectRef* CreateEffectRef(const GrEffect* effect) { 233 return CreateEffectRef(const_cast<GrEffect*>(effect)); 234 } 235 236 /** Used by GR_CREATE_STATIC_EFFECT below */ 237 static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) { 238 GrAssert(NULL == effect->fEffectRef); 239 effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect)); 240 return effect->fEffectRef; 241 } 242 243 244 /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a 245 GrEffectRef. E.g.: 246 247 class EffectSubclass : public GrEffect { 248 public: 249 GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) { 250 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...))); 251 return CreateEffectRef(effect); 252 } 253 */ 254 class AutoEffectUnref { 255 public: 256 AutoEffectUnref(GrEffect* effect) : fEffect(effect) { } 257 ~AutoEffectUnref() { fEffect->unref(); } 258 operator GrEffect*() { return fEffect; } 259 private: 260 GrEffect* fEffect; 261 }; 262 263 /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass 264 */ 265 template <typename T> 266 static const T& CastEffect(const GrEffect& effectRef) { 267 return *static_cast<const T*>(&effectRef); 268 } 269 270 /** 271 * If the effect subclass will read the destination pixel value then it must call this function 272 * from its constructor. Otherwise, when its generated backend-specific effect class attempts 273 * to generate code that reads the destination pixel it will fail. 274 */ 275 void setWillReadDstColor() { fWillReadDstColor = true; } 276 277 /** 278 * If the effect will generate a backend-specific effect that will read the fragment position 279 * in the FS then it must call this method from its constructor. Otherwise, the request to 280 * access the fragment position will be denied. 281 */ 282 void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; } 283 284private: 285 bool isEqual(const GrEffect& other) const { 286 if (&this->getFactory() != &other.getFactory()) { 287 return false; 288 } 289 bool result = this->onIsEqual(other); 290#if GR_DEBUG 291 if (result) { 292 GrAssert(this->numTextures() == other.numTextures()); 293 for (int i = 0; i < this->numTextures(); ++i) { 294 GrAssert(*fTextureAccesses[i] == *other.fTextureAccesses[i]); 295 } 296 } 297#endif 298 return result; 299 } 300 301 /** Subclass implements this to support isEqual(). It will only be called if it is known that 302 the two effects are of the same subclass (i.e. they return the same object from 303 getFactory()).*/ 304 virtual bool onIsEqual(const GrEffect& other) const = 0; 305 306 void EffectRefDestroyed() { fEffectRef = NULL; } 307 308 friend class GrEffectRef; // to call EffectRefDestroyed() 309 friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage 310 // from deferred state, to call isEqual on naked GrEffects, and 311 // to inc/dec deferred ref counts. 312 313 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses; 314 SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes; 315 bool fWillReadDstColor; 316 bool fWillReadFragmentPosition; 317 GrEffectRef* fEffectRef; 318 319 typedef GrRefCnt INHERITED; 320}; 321 322inline GrEffectRef::GrEffectRef(GrEffect* effect) { 323 GrAssert(NULL != effect); 324 effect->ref(); 325 fEffect = effect; 326} 327 328/** 329 * This creates an effect outside of the effect memory pool. The effect's destructor will be called 330 * at global destruction time. NAME will be the name of the created GrEffectRef. 331 */ 332#define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS) \ 333enum { \ 334 k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8), \ 335 k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef) \ 336}; \ 337static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage; \ 338static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset; \ 339static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\ 340static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect); \ 341static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect)); \ 342static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME) 343 344 345#endif 346