blob: e7590b6793495e6d9052c2284e4497269af85b6b [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.com0ac6af42013-01-16 15:16:18 +000019class GrEffect;
twiz@google.coma5e65ec2012-08-02 15:15:16 +000020class SkString;
21
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000022/**
23 * A Wrapper class for GrEffect. Its ref-count will track owners that may use effects to enqueue
24 * new draw operations separately from ownership within a deferred drawing queue. When the
25 * GrEffectRef ref count reaches zero the scratch GrResources owned by the effect can be recycled
26 * in service of later draws. However, the deferred draw queue may still own direct references to
27 * the underlying GrEffect.
bsalomon@google.comd42aca32013-04-23 15:37:27 +000028 *
29 * GrEffectRefs created by new are placed in a per-thread managed pool. The pool is destroyed when
30 * the thread ends. Therefore, all dynamically allocated GrEffectRefs must be unreffed before thread
31 * termination.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000032 */
33class GrEffectRef : public SkRefCnt {
34public:
35 SK_DECLARE_INST_COUNT(GrEffectRef);
bsalomon@google.comd42aca32013-04-23 15:37:27 +000036 virtual ~GrEffectRef();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000037
38 GrEffect* get() { return fEffect; }
39 const GrEffect* get() const { return fEffect; }
40
bsalomon@google.com6340a412013-01-22 19:55:59 +000041 const GrEffect* operator-> () { return fEffect; }
42 const GrEffect* operator-> () const { return fEffect; }
43
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000044 void* operator new(size_t size);
45 void operator delete(void* target);
46
bsalomon@google.comd42aca32013-04-23 15:37:27 +000047 void* operator new(size_t size, void* placement) {
48 return ::operator new(size, placement);
49 }
50 void operator delete(void* target, void* placement) {
51 ::operator delete(target, placement);
52 }
53
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000054private:
bsalomon@google.com64287c52013-01-16 15:25:55 +000055 friend class GrEffect; // to construct these
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000056
57 explicit GrEffectRef(GrEffect* effect);
58
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000059 GrEffect* fEffect;
60
61 typedef SkRefCnt INHERITED;
62};
63
bsalomon@google.com50db75c2013-01-11 13:54:30 +000064/** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
65 Ganesh shading pipeline.
bsalomon@google.com289efe02012-05-21 20:57:59 +000066 Subclasses must have a function that produces a human-readable name:
67 static const char* Name();
bsalomon@google.com50db75c2013-01-11 13:54:30 +000068 GrEffect objects *must* be immutable: after being constructed, their fields may not change.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000069
70 GrEffect subclass objects should be created by factory functions that return GrEffectRef.
71 There is no public way to wrap a GrEffect in a GrEffectRef. Thus, a factory should be a static
72 member function of a GrEffect subclass.
bsalomon@google.com6340a412013-01-22 19:55:59 +000073
bsalomon@google.comd42aca32013-04-23 15:37:27 +000074 Because almost no code should ever handle a GrEffect directly outside of a GrEffectRef, we
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000075 privately inherit from SkRefCnt to help prevent accidental direct ref'ing/unref'ing of effects.
bsalomon@google.comd42aca32013-04-23 15:37:27 +000076
77 Dynamically allocated GrEffects and their corresponding GrEffectRefs are managed by a per-thread
78 memory pool. The ref count of an effect must reach 0 before the thread terminates and the pool
79 is destroyed. To create a static effect use the macro GR_CREATE_STATIC_EFFECT declared below.
bsalomon@google.com289efe02012-05-21 20:57:59 +000080 */
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000081class GrEffect : private SkRefCnt {
tomhudson@google.com168e6342012-04-18 17:49:20 +000082public:
bsalomon@google.coma469c282012-10-24 18:28:34 +000083 SK_DECLARE_INST_COUNT(GrEffect)
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000084
bsalomon@google.comc7818882013-03-20 19:19:53 +000085 /**
86 * The types of vertex coordinates available to an effect in the vertex shader. Effects can
87 * require their own vertex attribute but these coordinates are made available by the framework
commit-bot@chromium.org76eaf742013-09-30 18:41:38 +000088 * in all programs.
bsalomon@google.comc7818882013-03-20 19:19:53 +000089 */
90 enum CoordsType {
91 kLocal_CoordsType,
92 kPosition_CoordsType,
bsalomon@google.comc7818882013-03-20 19:19:53 +000093 };
94
bsalomon@google.coma469c282012-10-24 18:28:34 +000095 virtual ~GrEffect();
tomhudson@google.com168e6342012-04-18 17:49:20 +000096
bsalomon@google.com371e1052013-01-11 21:08:55 +000097 /**
bsalomon@google.com371e1052013-01-11 21:08:55 +000098 * This function is used to perform optimizations. When called the color and validFlags params
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000099 * indicate whether the input components to this effect in the FS will have known values.
100 * validFlags is a bitfield of GrColorComponentFlags. The function updates both params to
101 * indicate known values of its output. A component of the color param only has meaning if the
102 * corresponding bit in validFlags is set.
bsalomon@google.com371e1052013-01-11 21:08:55 +0000103 */
104 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000105
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000106 /** This object, besides creating back-end-specific helper objects, is used for run-time-type-
107 identification. The factory should be an instance of templated class,
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000108 GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000109 a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created
110 by the factory.
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000111
112 Example:
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000113 class MyCustomEffect : public GrEffect {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000114 ...
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000115 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
116 return GrTBackendEffectFactory<MyCustomEffect>::getInstance();
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000117 }
118 ...
119 };
120 */
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000121 virtual const GrBackendEffectFactory& getFactory() const = 0;
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000122
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000123 /** Returns true if this and other effect conservatively draw identically. It can only return
124 true when the two effects are of the same subclass (i.e. they return the same object from
125 from getFactory()).
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000126
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000127 A return value of true from isEqual() should not be used to test whether the effects would
128 generate the same shader code. To test for identical code generation use the EffectKey
129 computed by the GrBackendEffectFactory:
130 effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB).
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000131 */
bsalomon@google.com6340a412013-01-22 19:55:59 +0000132 bool isEqual(const GrEffectRef& other) const {
bsalomon@google.comca432082013-01-23 19:53:46 +0000133 return this->isEqual(*other.get());
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000134 }
tomhudson@google.com168e6342012-04-18 17:49:20 +0000135
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000136 /** Human-meaningful string to identify this effect; may be embedded
137 in generated shader code. */
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000138 const char* name() const;
bsalomon@google.com289efe02012-05-21 20:57:59 +0000139
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000140 int numTextures() const { return fTextureAccesses.count(); }
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000141
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000142 /** Returns the access pattern for the texture at index. index must be valid according to
143 numTextures(). */
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000144 const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; }
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000145
146 /** Shortcut for textureAccess(index).texture(); */
147 GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000148
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000149 /** Will this effect read the destination pixel value? */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000150 bool willReadDstColor() const { return fWillReadDstColor; }
151
152 /** Will this effect read the fragment position? */
153 bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000154
155 int numVertexAttribs() const { return fVertexAttribTypes.count(); }
156
157 GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; }
158
159 static const int kMaxVertexAttribs = 2;
160
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000161 /** Useful for effects that want to insert a texture matrix that is implied by the texture
162 dimensions */
163 static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000164 SkASSERT(NULL != texture);
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000165 SkMatrix mat;
166 mat.setIDiv(texture->width(), texture->height());
167 return mat;
168 }
169
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000170 void* operator new(size_t size);
171 void operator delete(void* target);
172
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000173 void* operator new(size_t size, void* placement) {
174 return ::operator new(size, placement);
175 }
176 void operator delete(void* target, void* placement) {
177 ::operator delete(target, placement);
178 }
179
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000180 /** These functions are used when recording effects into a deferred drawing queue. The inc call
181 keeps the effect alive outside of GrEffectRef while allowing any resources owned by the
182 effect to be returned to the cache for reuse. The dec call must balance the inc call. */
183 void incDeferredRefCounts() const {
184 this->ref();
185 int count = fTextureAccesses.count();
186 for (int t = 0; t < count; ++t) {
187 fTextureAccesses[t]->getTexture()->incDeferredRefCount();
188 }
189 }
190 void decDeferredRefCounts() const {
191 int count = fTextureAccesses.count();
192 for (int t = 0; t < count; ++t) {
193 fTextureAccesses[t]->getTexture()->decDeferredRefCount();
194 }
195 this->unref();
196 }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000197
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000198protected:
199 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000200 * Subclasses call this from their constructor to register GrTextureAccesses. The effect
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000201 * subclass manages the lifetime of the accesses (this function only stores a pointer). The
202 * GrTextureAccess is typically a member field of the GrEffet subclass. This must only be
203 * called from the constructor because GrEffects are immutable.
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000204 */
205 void addTextureAccess(const GrTextureAccess* textureAccess);
206
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000207 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000208 * Subclasses call this from their constructor to register vertex attributes (at most
209 * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000210 * immutable.
211 */
212 void addVertexAttrib(GrSLType type);
213
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000214 GrEffect() : fWillReadDstColor(false), fWillReadFragmentPosition(false), fEffectRef(NULL) {}
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000215
bsalomon@google.com6340a412013-01-22 19:55:59 +0000216 /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
217 an example factory function. */
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000218 static GrEffectRef* CreateEffectRef(GrEffect* effect) {
219 if (NULL == effect->fEffectRef) {
220 effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000221 } else {
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000222 effect->fEffectRef->ref();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000223 }
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000224 return effect->fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000225 }
226
bsalomon@google.comca432082013-01-23 19:53:46 +0000227 static const GrEffectRef* CreateEffectRef(const GrEffect* effect) {
228 return CreateEffectRef(const_cast<GrEffect*>(effect));
229 }
230
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000231 /** Used by GR_CREATE_STATIC_EFFECT below */
232 static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000233 SkASSERT(NULL == effect->fEffectRef);
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000234 effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect));
235 return effect->fEffectRef;
236 }
237
238
bsalomon@google.com6340a412013-01-22 19:55:59 +0000239 /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a
240 GrEffectRef. E.g.:
241
242 class EffectSubclass : public GrEffect {
243 public:
244 GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) {
245 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...)));
246 return CreateEffectRef(effect);
247 }
248 */
249 class AutoEffectUnref {
250 public:
251 AutoEffectUnref(GrEffect* effect) : fEffect(effect) { }
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000252 ~AutoEffectUnref() { fEffect->unref(); }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000253 operator GrEffect*() { return fEffect; }
254 private:
255 GrEffect* fEffect;
256 };
257
258 /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass
259 */
260 template <typename T>
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000261 static const T& CastEffect(const GrEffect& effectRef) {
262 return *static_cast<const T*>(&effectRef);
bsalomon@google.com6340a412013-01-22 19:55:59 +0000263 }
264
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000265 /**
266 * If the effect subclass will read the destination pixel value then it must call this function
267 * from its constructor. Otherwise, when its generated backend-specific effect class attempts
268 * to generate code that reads the destination pixel it will fail.
269 */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000270 void setWillReadDstColor() { fWillReadDstColor = true; }
271
272 /**
273 * If the effect will generate a backend-specific effect that will read the fragment position
274 * in the FS then it must call this method from its constructor. Otherwise, the request to
275 * access the fragment position will be denied.
276 */
277 void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000278
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000279private:
bsalomon@google.comca432082013-01-23 19:53:46 +0000280 bool isEqual(const GrEffect& other) const {
281 if (&this->getFactory() != &other.getFactory()) {
282 return false;
283 }
284 bool result = this->onIsEqual(other);
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000285#ifdef SK_DEBUG
bsalomon@google.comca432082013-01-23 19:53:46 +0000286 if (result) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000287 SkASSERT(this->numTextures() == other.numTextures());
bsalomon@google.comca432082013-01-23 19:53:46 +0000288 for (int i = 0; i < this->numTextures(); ++i) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000289 SkASSERT(*fTextureAccesses[i] == *other.fTextureAccesses[i]);
bsalomon@google.comca432082013-01-23 19:53:46 +0000290 }
291 }
292#endif
293 return result;
294 }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000295
296 /** Subclass implements this to support isEqual(). It will only be called if it is known that
bsalomon@google.com6340a412013-01-22 19:55:59 +0000297 the two effects are of the same subclass (i.e. they return the same object from
298 getFactory()).*/
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000299 virtual bool onIsEqual(const GrEffect& other) const = 0;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000300
bsalomon@google.com6340a412013-01-22 19:55:59 +0000301 void EffectRefDestroyed() { fEffectRef = NULL; }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000302
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000303 friend class GrEffectRef; // to call EffectRefDestroyed()
bsalomon@google.comca432082013-01-23 19:53:46 +0000304 friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000305 // from deferred state, to call isEqual on naked GrEffects, and
306 // to inc/dec deferred ref counts.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000307
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000308 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
309 SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000310 bool fWillReadDstColor;
311 bool fWillReadFragmentPosition;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000312 GrEffectRef* fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000313
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000314 typedef SkRefCnt INHERITED;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000315};
316
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000317inline GrEffectRef::GrEffectRef(GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000318 SkASSERT(NULL != effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000319 effect->ref();
320 fEffect = effect;
321}
322
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000323/**
324 * This creates an effect outside of the effect memory pool. The effect's destructor will be called
325 * at global destruction time. NAME will be the name of the created GrEffectRef.
326 */
327#define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS) \
328enum { \
329 k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8), \
330 k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef) \
331}; \
332static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage; \
333static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset; \
334static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
335static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect); \
336static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect)); \
337static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
338
339
tomhudson@google.com168e6342012-04-18 17:49:20 +0000340#endif