blob: 2792476a6de7b4a31b6625d7d242951ff49712e5 [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.com371e1052013-01-11 21:08:55 +000013#include "GrNoncopyable.h"
14#include "GrRefCnt.h"
bsalomon@google.com34cccde2013-01-04 18:34:30 +000015#include "GrTexture.h"
bsalomon@google.com047696c2012-09-11 13:29:29 +000016#include "GrTextureAccess.h"
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +000017#include "GrTypesPriv.h"
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000018
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000019class GrBackendEffectFactory;
tomhudson@google.com168e6342012-04-18 17:49:20 +000020class GrContext;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000021class GrEffect;
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.
30 */
31class GrEffectRef : public SkRefCnt {
32public:
33 SK_DECLARE_INST_COUNT(GrEffectRef);
34
35 GrEffect* get() { return fEffect; }
36 const GrEffect* get() const { return fEffect; }
37
bsalomon@google.com6340a412013-01-22 19:55:59 +000038 const GrEffect* operator-> () { return fEffect; }
39 const GrEffect* operator-> () const { return fEffect; }
40
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000041 void* operator new(size_t size);
42 void operator delete(void* target);
43
44private:
bsalomon@google.com64287c52013-01-16 15:25:55 +000045 friend class GrEffect; // to construct these
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000046
47 explicit GrEffectRef(GrEffect* effect);
48
49 virtual ~GrEffectRef();
50
51 GrEffect* fEffect;
52
53 typedef SkRefCnt INHERITED;
54};
55
bsalomon@google.com50db75c2013-01-11 13:54:30 +000056/** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
57 Ganesh shading pipeline.
bsalomon@google.com289efe02012-05-21 20:57:59 +000058 Subclasses must have a function that produces a human-readable name:
59 static const char* Name();
bsalomon@google.com50db75c2013-01-11 13:54:30 +000060 GrEffect objects *must* be immutable: after being constructed, their fields may not change.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000061
62 GrEffect subclass objects should be created by factory functions that return GrEffectRef.
63 There is no public way to wrap a GrEffect in a GrEffectRef. Thus, a factory should be a static
64 member function of a GrEffect subclass.
bsalomon@google.com6340a412013-01-22 19:55:59 +000065
66 Because almost no code should ever handle a GrEffect outside of a GrEffectRef, we privately
67 inherit from GrRefCnt to help prevent accidental direct ref'ing/unref'ing of effects.
bsalomon@google.com289efe02012-05-21 20:57:59 +000068 */
bsalomon@google.com6340a412013-01-22 19:55:59 +000069class GrEffect : private GrRefCnt {
tomhudson@google.com168e6342012-04-18 17:49:20 +000070public:
bsalomon@google.coma469c282012-10-24 18:28:34 +000071 SK_DECLARE_INST_COUNT(GrEffect)
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000072
bsalomon@google.coma469c282012-10-24 18:28:34 +000073 virtual ~GrEffect();
tomhudson@google.com168e6342012-04-18 17:49:20 +000074
bsalomon@google.com371e1052013-01-11 21:08:55 +000075 /**
76 * Flags for getConstantColorComponents. They are defined so that the bit order reflects the
77 * GrColor shift order.
78 */
79 enum ValidComponentFlags {
80 kR_ValidComponentFlag = 1 << (GrColor_SHIFT_R / 8),
81 kG_ValidComponentFlag = 1 << (GrColor_SHIFT_G / 8),
82 kB_ValidComponentFlag = 1 << (GrColor_SHIFT_B / 8),
83 kA_ValidComponentFlag = 1 << (GrColor_SHIFT_A / 8),
84
85 kAll_ValidComponentFlags = (kR_ValidComponentFlag | kG_ValidComponentFlag |
86 kB_ValidComponentFlag | kA_ValidComponentFlag)
87 };
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. The
92 * function updates both params to indicate known values of its output. A component of the color
93 * param only has meaning if the corresponding bit in validFlags is set.
94 */
95 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0;
tomhudson@google.com168e6342012-04-18 17:49:20 +000096
bsalomon@google.com422e81a2012-10-25 14:11:03 +000097 /** This object, besides creating back-end-specific helper objects, is used for run-time-type-
98 identification. The factory should be an instance of templated class,
bsalomon@google.com396e61f2012-10-25 19:00:29 +000099 GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000100 a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created
101 by the factory.
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000102
103 Example:
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000104 class MyCustomEffect : public GrEffect {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000105 ...
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000106 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
107 return GrTBackendEffectFactory<MyCustomEffect>::getInstance();
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000108 }
109 ...
110 };
111 */
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000112 virtual const GrBackendEffectFactory& getFactory() const = 0;
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000113
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000114 /** Returns true if this and other effect conservatively draw identically. It can only return
115 true when the two effects are of the same subclass (i.e. they return the same object from
116 from getFactory()).
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000117
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000118 A return value of true from isEqual() should not be used to test whether the effects would
119 generate the same shader code. To test for identical code generation use the EffectKey
120 computed by the GrBackendEffectFactory:
121 effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB).
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000122 */
bsalomon@google.com6340a412013-01-22 19:55:59 +0000123 bool isEqual(const GrEffectRef& other) const {
bsalomon@google.comca432082013-01-23 19:53:46 +0000124 return this->isEqual(*other.get());
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000125 }
tomhudson@google.com168e6342012-04-18 17:49:20 +0000126
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000127 /** Human-meaningful string to identify this effect; may be embedded
128 in generated shader code. */
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000129 const char* name() const;
bsalomon@google.com289efe02012-05-21 20:57:59 +0000130
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000131 int numTextures() const { return fTextureAccesses.count(); }
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000132
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000133 /** Returns the access pattern for the texture at index. index must be valid according to
134 numTextures(). */
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000135 const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; }
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000136
137 /** Shortcut for textureAccess(index).texture(); */
138 GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000139
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000140
141 int numVertexAttribs() const { return fVertexAttribTypes.count(); }
142
143 GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; }
144
145 static const int kMaxVertexAttribs = 2;
146
147
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000148 /** Useful for effects that want to insert a texture matrix that is implied by the texture
149 dimensions */
150 static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) {
151 GrAssert(NULL != texture);
152 SkMatrix mat;
153 mat.setIDiv(texture->width(), texture->height());
154 return mat;
155 }
156
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000157 void* operator new(size_t size);
158 void operator delete(void* target);
159
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000160 /** These functions are used when recording effects into a deferred drawing queue. The inc call
161 keeps the effect alive outside of GrEffectRef while allowing any resources owned by the
162 effect to be returned to the cache for reuse. The dec call must balance the inc call. */
163 void incDeferredRefCounts() const {
164 this->ref();
165 int count = fTextureAccesses.count();
166 for (int t = 0; t < count; ++t) {
167 fTextureAccesses[t]->getTexture()->incDeferredRefCount();
168 }
169 }
170 void decDeferredRefCounts() const {
171 int count = fTextureAccesses.count();
172 for (int t = 0; t < count; ++t) {
173 fTextureAccesses[t]->getTexture()->decDeferredRefCount();
174 }
175 this->unref();
176 }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000177
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000178protected:
179 /**
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000180 * Subclasses call this from their constructor to register GrTextureAccesses. The effect
181 * subclass manages the lifetime of the accesses (this function only stores a pointer). This
182 * must only be called from the constructor because GrEffects are immutable.
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000183 */
184 void addTextureAccess(const GrTextureAccess* textureAccess);
185
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000186 /**
187 * Subclasses call this from their constructor to register vertex attributes (at most
188 * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
189 * immutable.
190 */
191 void addVertexAttrib(GrSLType type);
192
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000193 GrEffect() : fEffectRef(NULL) {};
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000194
bsalomon@google.com6340a412013-01-22 19:55:59 +0000195 /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
196 an example factory function. */
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000197 static GrEffectRef* CreateEffectRef(GrEffect* effect) {
198 if (NULL == effect->fEffectRef) {
199 effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000200 } else {
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000201 effect->fEffectRef->ref();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000202 }
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000203 return effect->fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000204 }
205
bsalomon@google.comca432082013-01-23 19:53:46 +0000206 static const GrEffectRef* CreateEffectRef(const GrEffect* effect) {
207 return CreateEffectRef(const_cast<GrEffect*>(effect));
208 }
209
bsalomon@google.com6340a412013-01-22 19:55:59 +0000210 /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a
211 GrEffectRef. E.g.:
212
213 class EffectSubclass : public GrEffect {
214 public:
215 GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) {
216 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...)));
217 return CreateEffectRef(effect);
218 }
219 */
220 class AutoEffectUnref {
221 public:
222 AutoEffectUnref(GrEffect* effect) : fEffect(effect) { }
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000223 ~AutoEffectUnref() { fEffect->unref(); }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000224 operator GrEffect*() { return fEffect; }
225 private:
226 GrEffect* fEffect;
227 };
228
229 /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass
230 */
231 template <typename T>
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000232 static const T& CastEffect(const GrEffect& effectRef) {
233 return *static_cast<const T*>(&effectRef);
bsalomon@google.com6340a412013-01-22 19:55:59 +0000234 }
235
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000236private:
bsalomon@google.comca432082013-01-23 19:53:46 +0000237 bool isEqual(const GrEffect& other) const {
238 if (&this->getFactory() != &other.getFactory()) {
239 return false;
240 }
241 bool result = this->onIsEqual(other);
242#if GR_DEBUG
243 if (result) {
244 GrAssert(this->numTextures() == other.numTextures());
245 for (int i = 0; i < this->numTextures(); ++i) {
246 GrAssert(*fTextureAccesses[i] == *other.fTextureAccesses[i]);
247 }
248 }
249#endif
250 return result;
251 }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000252
253 /** Subclass implements this to support isEqual(). It will only be called if it is known that
bsalomon@google.com6340a412013-01-22 19:55:59 +0000254 the two effects are of the same subclass (i.e. they return the same object from
255 getFactory()).*/
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000256 virtual bool onIsEqual(const GrEffect& other) const = 0;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000257
bsalomon@google.com6340a412013-01-22 19:55:59 +0000258 void EffectRefDestroyed() { fEffectRef = NULL; }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000259
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000260 friend class GrEffectRef; // to call EffectRefDestroyed()
bsalomon@google.comca432082013-01-23 19:53:46 +0000261 friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000262 // from deferred state, to call isEqual on naked GrEffects, and
263 // to inc/dec deferred ref counts.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000264
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000265 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
266 SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
267 GrEffectRef* fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000268
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000269 typedef GrRefCnt INHERITED;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000270};
271
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000272inline GrEffectRef::GrEffectRef(GrEffect* effect) {
273 GrAssert(NULL != effect);
274 effect->ref();
275 fEffect = effect;
276}
277
tomhudson@google.com168e6342012-04-18 17:49:20 +0000278#endif