blob: b0d336bc0079cddcabed12c826f81a6146b40739 [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"
bsalomon@google.com34cccde2013-01-04 18:34:30 +000014#include "GrTexture.h"
bsalomon@google.com047696c2012-09-11 13:29:29 +000015#include "GrTextureAccess.h"
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +000016#include "GrTypesPriv.h"
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000017
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000018class GrBackendEffectFactory;
tomhudson@google.com168e6342012-04-18 17:49:20 +000019class GrContext;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000020class GrEffect;
twiz@google.coma5e65ec2012-08-02 15:15:16 +000021class SkString;
22
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000023/**
24 * A Wrapper class for GrEffect. Its ref-count will track owners that may use effects to enqueue
25 * new draw operations separately from ownership within a deferred drawing queue. When the
26 * GrEffectRef ref count reaches zero the scratch GrResources owned by the effect can be recycled
27 * in service of later draws. However, the deferred draw queue may still own direct references to
28 * the underlying GrEffect.
bsalomon@google.comd42aca32013-04-23 15:37:27 +000029 *
30 * GrEffectRefs created by new are placed in a per-thread managed pool. The pool is destroyed when
31 * the thread ends. Therefore, all dynamically allocated GrEffectRefs must be unreffed before thread
32 * termination.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000033 */
34class GrEffectRef : public SkRefCnt {
35public:
36 SK_DECLARE_INST_COUNT(GrEffectRef);
bsalomon@google.comd42aca32013-04-23 15:37:27 +000037 virtual ~GrEffectRef();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000038
39 GrEffect* get() { return fEffect; }
40 const GrEffect* get() const { return fEffect; }
41
bsalomon@google.com6340a412013-01-22 19:55:59 +000042 const GrEffect* operator-> () { return fEffect; }
43 const GrEffect* operator-> () const { return fEffect; }
44
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000045 void* operator new(size_t size);
46 void operator delete(void* target);
47
bsalomon@google.comd42aca32013-04-23 15:37:27 +000048 void* operator new(size_t size, void* placement) {
49 return ::operator new(size, placement);
50 }
51 void operator delete(void* target, void* placement) {
52 ::operator delete(target, placement);
53 }
54
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000055private:
bsalomon@google.com64287c52013-01-16 15:25:55 +000056 friend class GrEffect; // to construct these
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000057
58 explicit GrEffectRef(GrEffect* effect);
59
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000060 GrEffect* fEffect;
61
62 typedef SkRefCnt INHERITED;
63};
64
bsalomon@google.com50db75c2013-01-11 13:54:30 +000065/** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
66 Ganesh shading pipeline.
bsalomon@google.com289efe02012-05-21 20:57:59 +000067 Subclasses must have a function that produces a human-readable name:
68 static const char* Name();
bsalomon@google.com50db75c2013-01-11 13:54:30 +000069 GrEffect objects *must* be immutable: after being constructed, their fields may not change.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000070
71 GrEffect subclass objects should be created by factory functions that return GrEffectRef.
72 There is no public way to wrap a GrEffect in a GrEffectRef. Thus, a factory should be a static
73 member function of a GrEffect subclass.
bsalomon@google.com6340a412013-01-22 19:55:59 +000074
bsalomon@google.comd42aca32013-04-23 15:37:27 +000075 Because almost no code should ever handle a GrEffect directly outside of a GrEffectRef, we
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000076 privately inherit from SkRefCnt to help prevent accidental direct ref'ing/unref'ing of effects.
bsalomon@google.comd42aca32013-04-23 15:37:27 +000077
78 Dynamically allocated GrEffects and their corresponding GrEffectRefs are managed by a per-thread
79 memory pool. The ref count of an effect must reach 0 before the thread terminates and the pool
80 is destroyed. To create a static effect use the macro GR_CREATE_STATIC_EFFECT declared below.
bsalomon@google.com289efe02012-05-21 20:57:59 +000081 */
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000082class GrEffect : private SkRefCnt {
tomhudson@google.com168e6342012-04-18 17:49:20 +000083public:
bsalomon@google.coma469c282012-10-24 18:28:34 +000084 SK_DECLARE_INST_COUNT(GrEffect)
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000085
bsalomon@google.comc7818882013-03-20 19:19:53 +000086 /**
87 * The types of vertex coordinates available to an effect in the vertex shader. Effects can
88 * require their own vertex attribute but these coordinates are made available by the framework
89 * in all programs. kCustom_CoordsType is provided to signify that an alternative set of coords
90 * is used (usually an explicit vertex attribute) but its meaning is determined by the effect
91 * subclass.
92 */
93 enum CoordsType {
94 kLocal_CoordsType,
95 kPosition_CoordsType,
96
97 kCustom_CoordsType,
98 };
99
bsalomon@google.coma469c282012-10-24 18:28:34 +0000100 virtual ~GrEffect();
tomhudson@google.com168e6342012-04-18 17:49:20 +0000101
bsalomon@google.com371e1052013-01-11 21:08:55 +0000102 /**
bsalomon@google.com371e1052013-01-11 21:08:55 +0000103 * This function is used to perform optimizations. When called the color and validFlags params
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000104 * indicate whether the input components to this effect in the FS will have known values.
105 * validFlags is a bitfield of GrColorComponentFlags. The function updates both params to
106 * indicate known values of its output. A component of the color param only has meaning if the
107 * corresponding bit in validFlags is set.
bsalomon@google.com371e1052013-01-11 21:08:55 +0000108 */
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
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000154 /** Will this effect read the destination pixel value? */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000155 bool willReadDstColor() const { return fWillReadDstColor; }
156
157 /** Will this effect read the fragment position? */
158 bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000159
160 int numVertexAttribs() const { return fVertexAttribTypes.count(); }
161
162 GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; }
163
164 static const int kMaxVertexAttribs = 2;
165
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000166 /** Useful for effects that want to insert a texture matrix that is implied by the texture
167 dimensions */
168 static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000169 SkASSERT(NULL != texture);
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000170 SkMatrix mat;
171 mat.setIDiv(texture->width(), texture->height());
172 return mat;
173 }
174
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000175 void* operator new(size_t size);
176 void operator delete(void* target);
177
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000178 void* operator new(size_t size, void* placement) {
179 return ::operator new(size, placement);
180 }
181 void operator delete(void* target, void* placement) {
182 ::operator delete(target, placement);
183 }
184
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000185 /** These functions are used when recording effects into a deferred drawing queue. The inc call
186 keeps the effect alive outside of GrEffectRef while allowing any resources owned by the
187 effect to be returned to the cache for reuse. The dec call must balance the inc call. */
188 void incDeferredRefCounts() const {
189 this->ref();
190 int count = fTextureAccesses.count();
191 for (int t = 0; t < count; ++t) {
192 fTextureAccesses[t]->getTexture()->incDeferredRefCount();
193 }
194 }
195 void decDeferredRefCounts() const {
196 int count = fTextureAccesses.count();
197 for (int t = 0; t < count; ++t) {
198 fTextureAccesses[t]->getTexture()->decDeferredRefCount();
199 }
200 this->unref();
201 }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000202
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000203protected:
204 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000205 * Subclasses call this from their constructor to register GrTextureAccesses. The effect
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000206 * subclass manages the lifetime of the accesses (this function only stores a pointer). The
207 * GrTextureAccess is typically a member field of the GrEffet subclass. This must only be
208 * called from the constructor because GrEffects are immutable.
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000209 */
210 void addTextureAccess(const GrTextureAccess* textureAccess);
211
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000212 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000213 * Subclasses call this from their constructor to register vertex attributes (at most
214 * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000215 * immutable.
216 */
217 void addVertexAttrib(GrSLType type);
218
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000219 GrEffect() : fWillReadDstColor(false), fWillReadFragmentPosition(false), fEffectRef(NULL) {}
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000220
bsalomon@google.com6340a412013-01-22 19:55:59 +0000221 /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
222 an example factory function. */
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000223 static GrEffectRef* CreateEffectRef(GrEffect* effect) {
224 if (NULL == effect->fEffectRef) {
225 effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000226 } else {
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000227 effect->fEffectRef->ref();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000228 }
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000229 return effect->fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000230 }
231
bsalomon@google.comca432082013-01-23 19:53:46 +0000232 static const GrEffectRef* CreateEffectRef(const GrEffect* effect) {
233 return CreateEffectRef(const_cast<GrEffect*>(effect));
234 }
235
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000236 /** Used by GR_CREATE_STATIC_EFFECT below */
237 static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000238 SkASSERT(NULL == effect->fEffectRef);
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000239 effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect));
240 return effect->fEffectRef;
241 }
242
243
bsalomon@google.com6340a412013-01-22 19:55:59 +0000244 /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a
245 GrEffectRef. E.g.:
246
247 class EffectSubclass : public GrEffect {
248 public:
249 GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) {
250 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...)));
251 return CreateEffectRef(effect);
252 }
253 */
254 class AutoEffectUnref {
255 public:
256 AutoEffectUnref(GrEffect* effect) : fEffect(effect) { }
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000257 ~AutoEffectUnref() { fEffect->unref(); }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000258 operator GrEffect*() { return fEffect; }
259 private:
260 GrEffect* fEffect;
261 };
262
263 /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass
264 */
265 template <typename T>
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000266 static const T& CastEffect(const GrEffect& effectRef) {
267 return *static_cast<const T*>(&effectRef);
bsalomon@google.com6340a412013-01-22 19:55:59 +0000268 }
269
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000270 /**
271 * If the effect subclass will read the destination pixel value then it must call this function
272 * from its constructor. Otherwise, when its generated backend-specific effect class attempts
273 * to generate code that reads the destination pixel it will fail.
274 */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000275 void setWillReadDstColor() { fWillReadDstColor = true; }
276
277 /**
278 * If the effect will generate a backend-specific effect that will read the fragment position
279 * in the FS then it must call this method from its constructor. Otherwise, the request to
280 * access the fragment position will be denied.
281 */
282 void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000283
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000284private:
bsalomon@google.comca432082013-01-23 19:53:46 +0000285 bool isEqual(const GrEffect& other) const {
286 if (&this->getFactory() != &other.getFactory()) {
287 return false;
288 }
289 bool result = this->onIsEqual(other);
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000290#ifdef SK_DEBUG
bsalomon@google.comca432082013-01-23 19:53:46 +0000291 if (result) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000292 SkASSERT(this->numTextures() == other.numTextures());
bsalomon@google.comca432082013-01-23 19:53:46 +0000293 for (int i = 0; i < this->numTextures(); ++i) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000294 SkASSERT(*fTextureAccesses[i] == *other.fTextureAccesses[i]);
bsalomon@google.comca432082013-01-23 19:53:46 +0000295 }
296 }
297#endif
298 return result;
299 }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000300
301 /** Subclass implements this to support isEqual(). It will only be called if it is known that
bsalomon@google.com6340a412013-01-22 19:55:59 +0000302 the two effects are of the same subclass (i.e. they return the same object from
303 getFactory()).*/
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000304 virtual bool onIsEqual(const GrEffect& other) const = 0;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000305
bsalomon@google.com6340a412013-01-22 19:55:59 +0000306 void EffectRefDestroyed() { fEffectRef = NULL; }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000307
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000308 friend class GrEffectRef; // to call EffectRefDestroyed()
bsalomon@google.comca432082013-01-23 19:53:46 +0000309 friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000310 // from deferred state, to call isEqual on naked GrEffects, and
311 // to inc/dec deferred ref counts.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000312
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000313 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
314 SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000315 bool fWillReadDstColor;
316 bool fWillReadFragmentPosition;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000317 GrEffectRef* fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000318
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000319 typedef SkRefCnt INHERITED;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000320};
321
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000322inline GrEffectRef::GrEffectRef(GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000323 SkASSERT(NULL != effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000324 effect->ref();
325 fEffect = effect;
326}
327
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000328/**
329 * This creates an effect outside of the effect memory pool. The effect's destructor will be called
330 * at global destruction time. NAME will be the name of the created GrEffectRef.
331 */
332#define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS) \
333enum { \
334 k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8), \
335 k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef) \
336}; \
337static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage; \
338static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset; \
339static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
340static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect); \
341static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect)); \
342static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
343
344
tomhudson@google.com168e6342012-04-18 17:49:20 +0000345#endif