|
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 |