blob: 883438603d7a72909d5956aa146e321632fdf2bb [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.comc7818882013-03-20 19:19:53 +000073 /**
74 * The types of vertex coordinates available to an effect in the vertex shader. Effects can
75 * require their own vertex attribute but these coordinates are made available by the framework
76 * in all programs. kCustom_CoordsType is provided to signify that an alternative set of coords
77 * is used (usually an explicit vertex attribute) but its meaning is determined by the effect
78 * subclass.
79 */
80 enum CoordsType {
81 kLocal_CoordsType,
82 kPosition_CoordsType,
83
84 kCustom_CoordsType,
85 };
86
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 /**
90 * Flags for getConstantColorComponents. They are defined so that the bit order reflects the
91 * GrColor shift order.
92 */
93 enum ValidComponentFlags {
94 kR_ValidComponentFlag = 1 << (GrColor_SHIFT_R / 8),
95 kG_ValidComponentFlag = 1 << (GrColor_SHIFT_G / 8),
96 kB_ValidComponentFlag = 1 << (GrColor_SHIFT_B / 8),
97 kA_ValidComponentFlag = 1 << (GrColor_SHIFT_A / 8),
98
99 kAll_ValidComponentFlags = (kR_ValidComponentFlag | kG_ValidComponentFlag |
100 kB_ValidComponentFlag | kA_ValidComponentFlag)
101 };
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. The
106 * function updates both params to indicate known values of its output. A component of the color
107 * param only has meaning if the corresponding bit in validFlags is set.
108 */
109 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000110
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000111 /** This object, besides creating back-end-specific helper objects, is used for run-time-type-
112 identification. The factory should be an instance of templated class,
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000113 GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000114 a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created
115 by the factory.
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000116
117 Example:
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000118 class MyCustomEffect : public GrEffect {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000119 ...
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000120 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
121 return GrTBackendEffectFactory<MyCustomEffect>::getInstance();
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000122 }
123 ...
124 };
125 */
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000126 virtual const GrBackendEffectFactory& getFactory() const = 0;
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000127
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000128 /** Returns true if this and other effect conservatively draw identically. It can only return
129 true when the two effects are of the same subclass (i.e. they return the same object from
130 from getFactory()).
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000131
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000132 A return value of true from isEqual() should not be used to test whether the effects would
133 generate the same shader code. To test for identical code generation use the EffectKey
134 computed by the GrBackendEffectFactory:
135 effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB).
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000136 */
bsalomon@google.com6340a412013-01-22 19:55:59 +0000137 bool isEqual(const GrEffectRef& other) const {
bsalomon@google.comca432082013-01-23 19:53:46 +0000138 return this->isEqual(*other.get());
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000139 }
tomhudson@google.com168e6342012-04-18 17:49:20 +0000140
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000141 /** Human-meaningful string to identify this effect; may be embedded
142 in generated shader code. */
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000143 const char* name() const;
bsalomon@google.com289efe02012-05-21 20:57:59 +0000144
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000145 int numTextures() const { return fTextureAccesses.count(); }
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000146
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000147 /** Returns the access pattern for the texture at index. index must be valid according to
148 numTextures(). */
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000149 const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; }
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000150
151 /** Shortcut for textureAccess(index).texture(); */
152 GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000153
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
161
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000162 /** Useful for effects that want to insert a texture matrix that is implied by the texture
163 dimensions */
164 static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) {
165 GrAssert(NULL != texture);
166 SkMatrix mat;
167 mat.setIDiv(texture->width(), texture->height());
168 return mat;
169 }
170
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000171 void* operator new(size_t size);
172 void operator delete(void* target);
173
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000174 /** These functions are used when recording effects into a deferred drawing queue. The inc call
175 keeps the effect alive outside of GrEffectRef while allowing any resources owned by the
176 effect to be returned to the cache for reuse. The dec call must balance the inc call. */
177 void incDeferredRefCounts() const {
178 this->ref();
179 int count = fTextureAccesses.count();
180 for (int t = 0; t < count; ++t) {
181 fTextureAccesses[t]->getTexture()->incDeferredRefCount();
182 }
183 }
184 void decDeferredRefCounts() const {
185 int count = fTextureAccesses.count();
186 for (int t = 0; t < count; ++t) {
187 fTextureAccesses[t]->getTexture()->decDeferredRefCount();
188 }
189 this->unref();
190 }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000191
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000192protected:
193 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000194 * Subclasses call this from their constructor to register GrTextureAccesses. The effect
195 * subclass manages the lifetime of the accesses (this function only stores a pointer). This
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000196 * must only be called from the constructor because GrEffects are immutable.
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000197 */
198 void addTextureAccess(const GrTextureAccess* textureAccess);
199
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000200 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000201 * Subclasses call this from their constructor to register vertex attributes (at most
202 * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000203 * immutable.
204 */
205 void addVertexAttrib(GrSLType type);
206
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000207 GrEffect() : fEffectRef(NULL) {};
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000208
bsalomon@google.com6340a412013-01-22 19:55:59 +0000209 /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
210 an example factory function. */
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000211 static GrEffectRef* CreateEffectRef(GrEffect* effect) {
212 if (NULL == effect->fEffectRef) {
213 effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000214 } else {
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000215 effect->fEffectRef->ref();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000216 }
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000217 return effect->fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000218 }
219
bsalomon@google.comca432082013-01-23 19:53:46 +0000220 static const GrEffectRef* CreateEffectRef(const GrEffect* effect) {
221 return CreateEffectRef(const_cast<GrEffect*>(effect));
222 }
223
bsalomon@google.com6340a412013-01-22 19:55:59 +0000224 /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a
225 GrEffectRef. E.g.:
226
227 class EffectSubclass : public GrEffect {
228 public:
229 GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) {
230 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...)));
231 return CreateEffectRef(effect);
232 }
233 */
234 class AutoEffectUnref {
235 public:
236 AutoEffectUnref(GrEffect* effect) : fEffect(effect) { }
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000237 ~AutoEffectUnref() { fEffect->unref(); }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000238 operator GrEffect*() { return fEffect; }
239 private:
240 GrEffect* fEffect;
241 };
242
243 /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass
244 */
245 template <typename T>
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000246 static const T& CastEffect(const GrEffect& effectRef) {
247 return *static_cast<const T*>(&effectRef);
bsalomon@google.com6340a412013-01-22 19:55:59 +0000248 }
249
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000250private:
bsalomon@google.comca432082013-01-23 19:53:46 +0000251 bool isEqual(const GrEffect& other) const {
252 if (&this->getFactory() != &other.getFactory()) {
253 return false;
254 }
255 bool result = this->onIsEqual(other);
256#if GR_DEBUG
257 if (result) {
258 GrAssert(this->numTextures() == other.numTextures());
259 for (int i = 0; i < this->numTextures(); ++i) {
260 GrAssert(*fTextureAccesses[i] == *other.fTextureAccesses[i]);
261 }
262 }
263#endif
264 return result;
265 }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000266
267 /** Subclass implements this to support isEqual(). It will only be called if it is known that
bsalomon@google.com6340a412013-01-22 19:55:59 +0000268 the two effects are of the same subclass (i.e. they return the same object from
269 getFactory()).*/
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000270 virtual bool onIsEqual(const GrEffect& other) const = 0;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000271
bsalomon@google.com6340a412013-01-22 19:55:59 +0000272 void EffectRefDestroyed() { fEffectRef = NULL; }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000273
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000274 friend class GrEffectRef; // to call EffectRefDestroyed()
bsalomon@google.comca432082013-01-23 19:53:46 +0000275 friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000276 // from deferred state, to call isEqual on naked GrEffects, and
277 // to inc/dec deferred ref counts.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000278
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000279 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
280 SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
281 GrEffectRef* fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000282
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000283 typedef GrRefCnt INHERITED;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000284};
285
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000286inline GrEffectRef::GrEffectRef(GrEffect* effect) {
287 GrAssert(NULL != effect);
288 effect->ref();
289 fEffect = effect;
290}
291
tomhudson@google.com168e6342012-04-18 17:49:20 +0000292#endif