blob: 5fed5329fb3ade31c6083444488d7e4ac345f5f3 [file] [log] [blame]
tomhudson@google.com168e6342012-04-18 17:49:20 +00001/*
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
bsalomon@google.com8ea78d82012-10-24 20:11:30 +00008#ifndef GrEffect_DEFINED
9#define GrEffect_DEFINED
tomhudson@google.com168e6342012-04-18 17:49:20 +000010
bsalomon@google.com371e1052013-01-11 21:08:55 +000011#include "GrColor.h"
bsalomon@google.com6f261be2012-10-24 19:07:10 +000012#include "GrEffectUnitTest.h"
bsalomon@google.com34cccde2013-01-04 18:34:30 +000013#include "GrTexture.h"
bsalomon@google.com047696c2012-09-11 13:29:29 +000014#include "GrTextureAccess.h"
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +000015#include "GrTypesPriv.h"
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000016
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000017class GrBackendEffectFactory;
tomhudson@google.com168e6342012-04-18 17:49:20 +000018class GrContext;
bsalomon@google.com77af6802013-10-02 13:04:56 +000019class GrCoordTransform;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000020class GrEffect;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000021class GrVertexEffect;
twiz@google.coma5e65ec2012-08-02 15:15:16 +000022class SkString;
23
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000024/**
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.
bsalomon@google.comd42aca32013-04-23 15:37:27 +000030 *
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.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000034 */
35class GrEffectRef : public SkRefCnt {
36public:
37 SK_DECLARE_INST_COUNT(GrEffectRef);
bsalomon@google.comd42aca32013-04-23 15:37:27 +000038 virtual ~GrEffectRef();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000039
40 GrEffect* get() { return fEffect; }
41 const GrEffect* get() const { return fEffect; }
42
bsalomon@google.com6340a412013-01-22 19:55:59 +000043 const GrEffect* operator-> () { return fEffect; }
44 const GrEffect* operator-> () const { return fEffect; }
45
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000046 void* operator new(size_t size);
47 void operator delete(void* target);
48
bsalomon@google.comd42aca32013-04-23 15:37:27 +000049 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
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000056private:
bsalomon@google.com64287c52013-01-16 15:25:55 +000057 friend class GrEffect; // to construct these
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000058
59 explicit GrEffectRef(GrEffect* effect);
60
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000061 GrEffect* fEffect;
62
63 typedef SkRefCnt INHERITED;
64};
65
bsalomon@google.com50db75c2013-01-11 13:54:30 +000066/** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
67 Ganesh shading pipeline.
bsalomon@google.com289efe02012-05-21 20:57:59 +000068 Subclasses must have a function that produces a human-readable name:
69 static const char* Name();
bsalomon@google.com50db75c2013-01-11 13:54:30 +000070 GrEffect objects *must* be immutable: after being constructed, their fields may not change.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000071
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.
bsalomon@google.com6340a412013-01-22 19:55:59 +000075
bsalomon@google.comd42aca32013-04-23 15:37:27 +000076 Because almost no code should ever handle a GrEffect directly outside of a GrEffectRef, we
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000077 privately inherit from SkRefCnt to help prevent accidental direct ref'ing/unref'ing of effects.
bsalomon@google.comd42aca32013-04-23 15:37:27 +000078
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.
bsalomon@google.com289efe02012-05-21 20:57:59 +000082 */
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000083class GrEffect : private SkRefCnt {
tomhudson@google.com168e6342012-04-18 17:49:20 +000084public:
bsalomon@google.coma469c282012-10-24 18:28:34 +000085 SK_DECLARE_INST_COUNT(GrEffect)
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000086
bsalomon@google.coma469c282012-10-24 18:28:34 +000087 virtual ~GrEffect();
tomhudson@google.com168e6342012-04-18 17:49:20 +000088
bsalomon@google.com371e1052013-01-11 21:08:55 +000089 /**
bsalomon@google.com371e1052013-01-11 21:08:55 +000090 * This function is used to perform optimizations. When called the color and validFlags params
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000091 * 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.
bsalomon@google.com371e1052013-01-11 21:08:55 +000095 */
96 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0;
tomhudson@google.com168e6342012-04-18 17:49:20 +000097
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000098 /** Will this effect read the source color value? */
99 bool willUseInputColor() const { return fWillUseInputColor; }
100
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000101 /** 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,
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000103 GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000104 a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created
105 by the factory.
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000106
107 Example:
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000108 class MyCustomEffect : public GrEffect {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000109 ...
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000110 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
111 return GrTBackendEffectFactory<MyCustomEffect>::getInstance();
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000112 }
113 ...
114 };
115 */
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000116 virtual const GrBackendEffectFactory& getFactory() const = 0;
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000117
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000118 /** 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()).
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000121
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000122 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).
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000126 */
bsalomon@google.com6340a412013-01-22 19:55:59 +0000127 bool isEqual(const GrEffectRef& other) const {
bsalomon@google.comca432082013-01-23 19:53:46 +0000128 return this->isEqual(*other.get());
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000129 }
tomhudson@google.com168e6342012-04-18 17:49:20 +0000130
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000131 /** Human-meaningful string to identify this effect; may be embedded
132 in generated shader code. */
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000133 const char* name() const;
bsalomon@google.com289efe02012-05-21 20:57:59 +0000134
bsalomon@google.com77af6802013-10-02 13:04:56 +0000135 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
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000141 int numTextures() const { return fTextureAccesses.count(); }
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000142
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000143 /** Returns the access pattern for the texture at index. index must be valid according to
144 numTextures(). */
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000145 const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; }
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000146
147 /** Shortcut for textureAccess(index).texture(); */
148 GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000149
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000150 /** Will this effect read the destination pixel value? */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000151 bool willReadDstColor() const { return fWillReadDstColor; }
152
153 /** Will this effect read the fragment position? */
154 bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000155
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000156 /** 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 }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000164
165 GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; }
166
167 static const int kMaxVertexAttribs = 2;
168
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000169 /** 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) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000172 SkASSERT(NULL != texture);
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000173 SkMatrix mat;
174 mat.setIDiv(texture->width(), texture->height());
175 return mat;
176 }
177
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000178 void* operator new(size_t size);
179 void operator delete(void* target);
180
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000181 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
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000188 /** 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 }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000205
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000206protected:
207 /**
bsalomon@google.com77af6802013-10-02 13:04:56 +0000208 * 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 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000217 * Subclasses call this from their constructor to register GrTextureAccesses. The effect
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000218 * subclass manages the lifetime of the accesses (this function only stores a pointer). The
bsalomon@google.com77af6802013-10-02 13:04:56 +0000219 * GrTextureAccess is typically a member field of the GrEffect subclass. This must only be
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000220 * called from the constructor because GrEffects are immutable.
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000221 */
222 void addTextureAccess(const GrTextureAccess* textureAccess);
223
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000224 GrEffect()
225 : fWillReadDstColor(false)
226 , fWillReadFragmentPosition(false)
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000227 , fWillUseInputColor(true)
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000228 , fHasVertexCode(false)
229 , fEffectRef(NULL) {}
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000230
bsalomon@google.com6340a412013-01-22 19:55:59 +0000231 /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
232 an example factory function. */
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000233 static GrEffectRef* CreateEffectRef(GrEffect* effect) {
234 if (NULL == effect->fEffectRef) {
235 effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000236 } else {
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000237 effect->fEffectRef->ref();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000238 }
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000239 return effect->fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000240 }
241
bsalomon@google.comca432082013-01-23 19:53:46 +0000242 static const GrEffectRef* CreateEffectRef(const GrEffect* effect) {
243 return CreateEffectRef(const_cast<GrEffect*>(effect));
244 }
245
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000246 /** Used by GR_CREATE_STATIC_EFFECT below */
247 static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000248 SkASSERT(NULL == effect->fEffectRef);
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000249 effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect));
250 return effect->fEffectRef;
251 }
252
253
bsalomon@google.com6340a412013-01-22 19:55:59 +0000254 /** 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) { }
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000267 ~AutoEffectUnref() { fEffect->unref(); }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000268 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>
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000276 static const T& CastEffect(const GrEffect& effectRef) {
277 return *static_cast<const T*>(&effectRef);
bsalomon@google.com6340a412013-01-22 19:55:59 +0000278 }
279
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000280 /**
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 */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000285 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; }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000293
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000294 /**
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
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000301private:
bsalomon@google.comca432082013-01-23 19:53:46 +0000302 bool isEqual(const GrEffect& other) const {
303 if (&this->getFactory() != &other.getFactory()) {
304 return false;
305 }
306 bool result = this->onIsEqual(other);
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000307#ifdef SK_DEBUG
bsalomon@google.comca432082013-01-23 19:53:46 +0000308 if (result) {
bsalomon@google.com77af6802013-10-02 13:04:56 +0000309 this->assertEquality(other);
bsalomon@google.comca432082013-01-23 19:53:46 +0000310 }
311#endif
312 return result;
313 }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000314
bsalomon@google.com77af6802013-10-02 13:04:56 +0000315 SkDEBUGCODE(void assertEquality(const GrEffect& other) const;)
316
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000317 /** Subclass implements this to support isEqual(). It will only be called if it is known that
bsalomon@google.com6340a412013-01-22 19:55:59 +0000318 the two effects are of the same subclass (i.e. they return the same object from
319 getFactory()).*/
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000320 virtual bool onIsEqual(const GrEffect& other) const = 0;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000321
bsalomon@google.com6340a412013-01-22 19:55:59 +0000322 void EffectRefDestroyed() { fEffectRef = NULL; }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000323
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000324 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.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000329
bsalomon@google.com77af6802013-10-02 13:04:56 +0000330 SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000331 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
332 SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000333 bool fWillReadDstColor;
334 bool fWillReadFragmentPosition;
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000335 bool fWillUseInputColor;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000336 bool fHasVertexCode;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000337 GrEffectRef* fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000338
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000339 typedef SkRefCnt INHERITED;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000340};
341
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000342inline GrEffectRef::GrEffectRef(GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000343 SkASSERT(NULL != effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000344 effect->ref();
345 fEffect = effect;
346}
347
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000348/**
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) \
353enum { \
354 k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8), \
355 k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef) \
356}; \
357static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage; \
358static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset; \
359static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
360static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect); \
361static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect)); \
362static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
363
364
tomhudson@google.com168e6342012-04-18 17:49:20 +0000365#endif