blob: 78752702f549bbd8296379e093e0e14ca428c06e [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.com77af6802013-10-02 13:04:56 +000019class GrCoordTransform;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000020class GrEffect;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000021class GrVertexEffect;
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
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000077 privately inherit from SkRefCnt to help prevent accidental direct ref'ing/unref'ing of effects.
bsalomon@google.comd42aca32013-04-23 15:37:27 +000078
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 */
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000083class GrEffect : private SkRefCnt {
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.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 /**
bsalomon@google.com371e1052013-01-11 21:08:55 +000090 * This function is used to perform optimizations. When called the color and validFlags params
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000091 * indicate whether the input components to this effect in the FS will have known values.
92 * validFlags is a bitfield of GrColorComponentFlags. The function updates both params to
93 * indicate known values of its output. A component of the color param only has meaning if the
94 * corresponding bit in validFlags is set.
bsalomon@google.com371e1052013-01-11 21:08:55 +000095 */
96 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0;
tomhudson@google.com168e6342012-04-18 17:49:20 +000097
bsalomon@google.com422e81a2012-10-25 14:11:03 +000098 /** This object, besides creating back-end-specific helper objects, is used for run-time-type-
99 identification. The factory should be an instance of templated class,
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000100 GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000101 a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created
102 by the factory.
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000103
104 Example:
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000105 class MyCustomEffect : public GrEffect {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000106 ...
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000107 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
108 return GrTBackendEffectFactory<MyCustomEffect>::getInstance();
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000109 }
110 ...
111 };
112 */
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000113 virtual const GrBackendEffectFactory& getFactory() const = 0;
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000114
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000115 /** Returns true if this and other effect conservatively draw identically. It can only return
116 true when the two effects are of the same subclass (i.e. they return the same object from
117 from getFactory()).
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000118
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000119 A return value of true from isEqual() should not be used to test whether the effects would
120 generate the same shader code. To test for identical code generation use the EffectKey
121 computed by the GrBackendEffectFactory:
122 effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB).
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000123 */
bsalomon@google.com6340a412013-01-22 19:55:59 +0000124 bool isEqual(const GrEffectRef& other) const {
bsalomon@google.comca432082013-01-23 19:53:46 +0000125 return this->isEqual(*other.get());
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000126 }
tomhudson@google.com168e6342012-04-18 17:49:20 +0000127
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000128 /** Human-meaningful string to identify this effect; may be embedded
129 in generated shader code. */
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000130 const char* name() const;
bsalomon@google.com289efe02012-05-21 20:57:59 +0000131
bsalomon@google.com77af6802013-10-02 13:04:56 +0000132 int numTransforms() const { return fCoordTransforms.count(); }
133
134 /** Returns the coordinate transformation at index. index must be valid according to
135 numTransforms(). */
136 const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; }
137
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000138 int numTextures() const { return fTextureAccesses.count(); }
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000139
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000140 /** Returns the access pattern for the texture at index. index must be valid according to
141 numTextures(). */
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000142 const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; }
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000143
144 /** Shortcut for textureAccess(index).texture(); */
145 GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000146
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000147 /** Will this effect read the destination pixel value? */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000148 bool willReadDstColor() const { return fWillReadDstColor; }
149
150 /** Will this effect read the fragment position? */
151 bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000152
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000153 /** Will this effect emit custom vertex shader code?
154 (To set this value the effect must inherit from GrVertexEffect.) */
155 bool hasVertexCode() const { return fHasVertexCode; }
156
157 int numVertexAttribs() const {
158 SkASSERT(0 == fVertexAttribTypes.count() || fHasVertexCode);
159 return fVertexAttribTypes.count();
160 }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000161
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 /**
bsalomon@google.com77af6802013-10-02 13:04:56 +0000205 * Subclasses call this from their constructor to register coordinate transformations. The
206 * effect subclass manages the lifetime of the transformations (this function only stores a
207 * pointer). The GrCoordTransform is typically a member field of the GrEffect subclass. When the
208 * matrix has perspective, the transformed coordinates will have 3 components. Otherwise they'll
209 * have 2. This must only be called from the constructor because GrEffects are immutable.
210 */
211 void addCoordTransform(const GrCoordTransform* coordTransform);
212
213 /**
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000214 * Subclasses call this from their constructor to register GrTextureAccesses. The effect
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000215 * subclass manages the lifetime of the accesses (this function only stores a pointer). The
bsalomon@google.com77af6802013-10-02 13:04:56 +0000216 * GrTextureAccess is typically a member field of the GrEffect subclass. This must only be
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000217 * called from the constructor because GrEffects are immutable.
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000218 */
219 void addTextureAccess(const GrTextureAccess* textureAccess);
220
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000221 GrEffect()
222 : fWillReadDstColor(false)
223 , fWillReadFragmentPosition(false)
224 , fHasVertexCode(false)
225 , fEffectRef(NULL) {}
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000226
bsalomon@google.com6340a412013-01-22 19:55:59 +0000227 /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
228 an example factory function. */
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000229 static GrEffectRef* CreateEffectRef(GrEffect* effect) {
230 if (NULL == effect->fEffectRef) {
231 effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000232 } else {
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000233 effect->fEffectRef->ref();
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000234 }
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000235 return effect->fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000236 }
237
bsalomon@google.comca432082013-01-23 19:53:46 +0000238 static const GrEffectRef* CreateEffectRef(const GrEffect* effect) {
239 return CreateEffectRef(const_cast<GrEffect*>(effect));
240 }
241
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000242 /** Used by GR_CREATE_STATIC_EFFECT below */
243 static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000244 SkASSERT(NULL == effect->fEffectRef);
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000245 effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect));
246 return effect->fEffectRef;
247 }
248
249
bsalomon@google.com6340a412013-01-22 19:55:59 +0000250 /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a
251 GrEffectRef. E.g.:
252
253 class EffectSubclass : public GrEffect {
254 public:
255 GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) {
256 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...)));
257 return CreateEffectRef(effect);
258 }
259 */
260 class AutoEffectUnref {
261 public:
262 AutoEffectUnref(GrEffect* effect) : fEffect(effect) { }
bsalomon@google.com838f6e12013-01-23 21:37:01 +0000263 ~AutoEffectUnref() { fEffect->unref(); }
bsalomon@google.com6340a412013-01-22 19:55:59 +0000264 operator GrEffect*() { return fEffect; }
265 private:
266 GrEffect* fEffect;
267 };
268
269 /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass
270 */
271 template <typename T>
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000272 static const T& CastEffect(const GrEffect& effectRef) {
273 return *static_cast<const T*>(&effectRef);
bsalomon@google.com6340a412013-01-22 19:55:59 +0000274 }
275
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000276 /**
277 * If the effect subclass will read the destination pixel value then it must call this function
278 * from its constructor. Otherwise, when its generated backend-specific effect class attempts
279 * to generate code that reads the destination pixel it will fail.
280 */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000281 void setWillReadDstColor() { fWillReadDstColor = true; }
282
283 /**
284 * If the effect will generate a backend-specific effect that will read the fragment position
285 * in the FS then it must call this method from its constructor. Otherwise, the request to
286 * access the fragment position will be denied.
287 */
288 void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000289
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000290private:
bsalomon@google.comca432082013-01-23 19:53:46 +0000291 bool isEqual(const GrEffect& other) const {
292 if (&this->getFactory() != &other.getFactory()) {
293 return false;
294 }
295 bool result = this->onIsEqual(other);
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000296#ifdef SK_DEBUG
bsalomon@google.comca432082013-01-23 19:53:46 +0000297 if (result) {
bsalomon@google.com77af6802013-10-02 13:04:56 +0000298 this->assertEquality(other);
bsalomon@google.comca432082013-01-23 19:53:46 +0000299 }
300#endif
301 return result;
302 }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000303
bsalomon@google.com77af6802013-10-02 13:04:56 +0000304 SkDEBUGCODE(void assertEquality(const GrEffect& other) const;)
305
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000306 /** Subclass implements this to support isEqual(). It will only be called if it is known that
bsalomon@google.com6340a412013-01-22 19:55:59 +0000307 the two effects are of the same subclass (i.e. they return the same object from
308 getFactory()).*/
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000309 virtual bool onIsEqual(const GrEffect& other) const = 0;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000310
bsalomon@google.com6340a412013-01-22 19:55:59 +0000311 void EffectRefDestroyed() { fEffectRef = NULL; }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000312
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000313 friend class GrEffectRef; // to call EffectRefDestroyed()
314 friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
315 // from deferred state, to call isEqual on naked GrEffects, and
316 // to inc/dec deferred ref counts.
317 friend class GrVertexEffect; // to set fHasVertexCode and build fVertexAttribTypes.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000318
bsalomon@google.com77af6802013-10-02 13:04:56 +0000319 SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000320 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
321 SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000322 bool fWillReadDstColor;
323 bool fWillReadFragmentPosition;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000324 bool fHasVertexCode;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000325 GrEffectRef* fEffectRef;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000326
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000327 typedef SkRefCnt INHERITED;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000328};
329
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000330inline GrEffectRef::GrEffectRef(GrEffect* effect) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000331 SkASSERT(NULL != effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000332 effect->ref();
333 fEffect = effect;
334}
335
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000336/**
337 * This creates an effect outside of the effect memory pool. The effect's destructor will be called
338 * at global destruction time. NAME will be the name of the created GrEffectRef.
339 */
340#define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS) \
341enum { \
342 k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8), \
343 k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef) \
344}; \
345static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage; \
346static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset; \
347static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
348static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect); \
349static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect)); \
350static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
351
352
tomhudson@google.com168e6342012-04-18 17:49:20 +0000353#endif