blob: a84810c094101158023a1e947ada5071e274066b [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.
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
77 privately inherit from GrRefCnt to help prevent accidental direct ref'ing/unref'ing of effects.
78
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 */
bsalomon@google.com6340a412013-01-22 19:55:59 +000083class GrEffect : private GrRefCnt {
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.comc7818882013-03-20 19:19:53 +000087 /**
88 * The types of vertex coordinates available to an effect in the vertex shader. Effects can
89 * require their own vertex attribute but these coordinates are made available by the framework
90 * in all programs. kCustom_CoordsType is provided to signify that an alternative set of coords
91 * is used (usually an explicit vertex attribute) but its meaning is determined by the effect
92 * subclass.
93 */
94 enum CoordsType {
95 kLocal_CoordsType,
96 kPosition_CoordsType,
97
98 kCustom_CoordsType,
99 };
100
bsalomon@google.coma469c282012-10-24 18:28:34 +0000101 virtual ~GrEffect();
tomhudson@google.com168e6342012-04-18 17:49:20 +0000102
bsalomon@google.com371e1052013-01-11 21:08:55 +0000103 /**
bsalomon@google.com371e1052013-01-11 21:08:55 +0000104 * This function is used to perform optimizations. When called the color and validFlags params
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000105 * indicate whether the input components to this effect in the FS will have known values.
106 * validFlags is a bitfield of GrColorComponentFlags. The function updates both params to
107 * indicate known values of its output. A component of the color param only has meaning if the
108 * corresponding bit in validFlags is set.
bsalomon@google.com371e1052013-01-11 21:08:55 +0000109 */
110 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000111
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000112 /** This object, besides creating back-end-specific helper objects, is used for run-time-type-
113 identification. The factory should be an instance of templated class,
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000114 GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000115 a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created
116 by the factory.
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000117
118 Example:
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000119 class MyCustomEffect : public GrEffect {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000120 ...
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000121 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
122 return GrTBackendEffectFactory<MyCustomEffect>::getInstance();
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000123 }
124 ...
125 };
126 */
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000127 virtual const GrBackendEffectFactory& getFactory() const = 0;
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000128
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000129 /** Returns true if this and other effect conservatively draw identically. It can only return
130 true when the two effects are of the same subclass (i.e. they return the same object from
131 from getFactory()).
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000132
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000133 A return value of true from isEqual() should not be used to test whether the effects would
134 generate the same shader code. To test for identical code generation use the EffectKey
135 computed by the GrBackendEffectFactory:
136 effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB).
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000137 */
bsalomon@google.com6340a412013-01-22 19:55:59 +0000138 bool isEqual(const GrEffectRef& other) const {
bsalomon@google.comca432082013-01-23 19:53:46 +0000139 return this->isEqual(*other.get());
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000140 }
tomhudson@google.com168e6342012-04-18 17:49:20 +0000141
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000142 /** Human-meaningful string to identify this effect; may be embedded
143 in generated shader code. */
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000144 const char* name() const;
bsalomon@google.com289efe02012-05-21 20:57:59 +0000145
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000146 int numTextures() const { return fTextureAccesses.count(); }
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000147
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000148 /** Returns the access pattern for the texture at index. index must be valid according to
149 numTextures(). */
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000150 const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; }
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000151
152 /** Shortcut for textureAccess(index).texture(); */
153 GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000154
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000155 /** Will this effect read the destination pixel value? */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000156 bool willReadDstColor() const { return fWillReadDstColor; }
157
158 /** Will this effect read the fragment position? */
159 bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000160
161 int numVertexAttribs() const { return fVertexAttribTypes.count(); }
162
163 GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; }
164
165 static const int kMaxVertexAttribs = 2;
166
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000167 /** Useful for effects that want to insert a texture matrix that is implied by the texture
168 dimensions */
169 static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000170 SkASSERT(NULL != texture);
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000171 SkMatrix mat;
172 mat.setIDiv(texture->width(), texture->height());
173 return mat;
174 }
175
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000176 void* operator new(size_t size);
177 void operator delete(void* target);
178
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000179 void* operator new(size_t size, void* placement) {
180 return ::operator new(size, placement);
181 }
182 void operator delete(void* target, void* placement) {
183 ::operator delete(target, placement);
184 }
185
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000186 /** These functions are used when recording effects into a deferred drawing queue. The inc call
187 keeps the effect alive outside of GrEffectRef while allowing any resources owned by the
188 effect to be returned to the cache for reuse. The dec call must balance the inc call. */
189 void incDeferredRefCounts() const {
190 this->ref();
191 int count = fTextureAccesses.count();
192 for (int t = 0; t < count; ++t) {
193 fTextureAccesses[t]->getTexture()->incDeferredRefCount();
194 }
195 }
196 void decDeferredRefCounts() const {
197 int count = fTextureAccesses.count();
198 for (int t = 0; t < count; ++t) {
199 fTextureAccesses[t]->getTexture()->decDeferredRefCount();
200 }
201 this->unref();
202 }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000203
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000204protected:
205 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000206 * Subclasses call this from their constructor to register GrTextureAccesses. The effect
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000207 * subclass manages the lifetime of the accesses (this function only stores a pointer). The
208 * GrTextureAccess is typically a member field of the GrEffet subclass. This must only be
209 * called from the constructor because GrEffects are immutable.
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000210 */
211 void addTextureAccess(const GrTextureAccess* textureAccess);
212
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000213 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000214 * Subclasses call this from their constructor to register vertex attributes (at most
215 * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000216 * immutable.
217 */
218 void addVertexAttrib(GrSLType type);
219
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000220 GrEffect() : fWillReadDstColor(false), fWillReadFragmentPosition(false), fEffectRef(NULL) {}
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000221
bsalomon@google.com6340a412013-01-22 19:55:59 +0000222 /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
223 an example factory function. */
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000224 static GrEffectRef* CreateEffectRef(GrEffect* effect) {
225 if (NULL == effect->fEffectRef) {
226 effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000227 } else {
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000228 effect->fEffectRef->ref();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000229 }
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000230 return effect->fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000231 }
232
bsalomon@google.comca432082013-01-23 19:53:46 +0000233 static const GrEffectRef* CreateEffectRef(const GrEffect* effect) {
234 return CreateEffectRef(const_cast<GrEffect*>(effect));
235 }
236
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000237 /** Used by GR_CREATE_STATIC_EFFECT below */
238 static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000239 SkASSERT(NULL == effect->fEffectRef);
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000240 effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect));
241 return effect->fEffectRef;
242 }
243
244
bsalomon@google.com6340a412013-01-22 19:55:59 +0000245 /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a
246 GrEffectRef. E.g.:
247
248 class EffectSubclass : public GrEffect {
249 public:
250 GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) {
251 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...)));
252 return CreateEffectRef(effect);
253 }
254 */
255 class AutoEffectUnref {
256 public:
257 AutoEffectUnref(GrEffect* effect) : fEffect(effect) { }
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000258 ~AutoEffectUnref() { fEffect->unref(); }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000259 operator GrEffect*() { return fEffect; }
260 private:
261 GrEffect* fEffect;
262 };
263
264 /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass
265 */
266 template <typename T>
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000267 static const T& CastEffect(const GrEffect& effectRef) {
268 return *static_cast<const T*>(&effectRef);
bsalomon@google.com6340a412013-01-22 19:55:59 +0000269 }
270
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000271 /**
272 * If the effect subclass will read the destination pixel value then it must call this function
273 * from its constructor. Otherwise, when its generated backend-specific effect class attempts
274 * to generate code that reads the destination pixel it will fail.
275 */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000276 void setWillReadDstColor() { fWillReadDstColor = true; }
277
278 /**
279 * If the effect will generate a backend-specific effect that will read the fragment position
280 * in the FS then it must call this method from its constructor. Otherwise, the request to
281 * access the fragment position will be denied.
282 */
283 void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000284
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000285private:
bsalomon@google.comca432082013-01-23 19:53:46 +0000286 bool isEqual(const GrEffect& other) const {
287 if (&this->getFactory() != &other.getFactory()) {
288 return false;
289 }
290 bool result = this->onIsEqual(other);
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000291#ifdef SK_DEBUG
bsalomon@google.comca432082013-01-23 19:53:46 +0000292 if (result) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000293 SkASSERT(this->numTextures() == other.numTextures());
bsalomon@google.comca432082013-01-23 19:53:46 +0000294 for (int i = 0; i < this->numTextures(); ++i) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000295 SkASSERT(*fTextureAccesses[i] == *other.fTextureAccesses[i]);
bsalomon@google.comca432082013-01-23 19:53:46 +0000296 }
297 }
298#endif
299 return result;
300 }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000301
302 /** Subclass implements this to support isEqual(). It will only be called if it is known that
bsalomon@google.com6340a412013-01-22 19:55:59 +0000303 the two effects are of the same subclass (i.e. they return the same object from
304 getFactory()).*/
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000305 virtual bool onIsEqual(const GrEffect& other) const = 0;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000306
bsalomon@google.com6340a412013-01-22 19:55:59 +0000307 void EffectRefDestroyed() { fEffectRef = NULL; }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000308
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000309 friend class GrEffectRef; // to call EffectRefDestroyed()
bsalomon@google.comca432082013-01-23 19:53:46 +0000310 friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000311 // from deferred state, to call isEqual on naked GrEffects, and
312 // to inc/dec deferred ref counts.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000313
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000314 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
315 SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000316 bool fWillReadDstColor;
317 bool fWillReadFragmentPosition;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000318 GrEffectRef* fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000319
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000320 typedef GrRefCnt INHERITED;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000321};
322
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000323inline GrEffectRef::GrEffectRef(GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000324 SkASSERT(NULL != effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000325 effect->ref();
326 fEffect = effect;
327}
328
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000329/**
330 * This creates an effect outside of the effect memory pool. The effect's destructor will be called
331 * at global destruction time. NAME will be the name of the created GrEffectRef.
332 */
333#define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS) \
334enum { \
335 k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8), \
336 k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef) \
337}; \
338static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage; \
339static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset; \
340static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
341static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect); \
342static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect)); \
343static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
344
345
tomhudson@google.com168e6342012-04-18 17:49:20 +0000346#endif