blob: 96ce28840456dc6aa469670f08ac4d16f0bdd83d [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
joshualittb0a8a372014-09-23 09:50:21 -07008#ifndef GrProcessor_DEFINED
9#define GrProcessor_DEFINED
tomhudson@google.com168e6342012-04-18 17:49:20 +000010
joshualittb0a8a372014-09-23 09:50:21 -070011#include "GrBackendProcessorFactory.h"
bsalomon@google.com371e1052013-01-11 21:08:55 +000012#include "GrColor.h"
joshualittb0a8a372014-09-23 09:50:21 -070013#include "GrProcessorUnitTest.h"
bsalomon95740982014-09-04 13:12:37 -070014#include "GrProgramElement.h"
bsalomon@google.com047696c2012-09-11 13:29:29 +000015#include "GrTextureAccess.h"
egdaniel9e4d6d12014-10-15 13:49:02 -070016#include "SkMath.h"
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000017
tomhudson@google.com168e6342012-04-18 17:49:20 +000018class GrContext;
bsalomon@google.com77af6802013-10-02 13:04:56 +000019class GrCoordTransform;
bsalomon95740982014-09-04 13:12:37 -070020
bsalomon98b33eb2014-10-15 11:05:26 -070021/** Provides custom shader code to the Ganesh shading pipeline. GrProcessor objects *must* be
22 immutable: after being constructed, their fields may not change.
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000023
joshualittb0a8a372014-09-23 09:50:21 -070024 Dynamically allocated GrProcessors are managed by a per-thread memory pool. The ref count of an
bsalomon98b33eb2014-10-15 11:05:26 -070025 processor must reach 0 before the thread terminates and the pool is destroyed. To create a
26 static processor use the helper macro GR_CREATE_STATIC_PROCESSOR declared below.
27 */
joshualittb0a8a372014-09-23 09:50:21 -070028class GrProcessor : public GrProgramElement {
tomhudson@google.com168e6342012-04-18 17:49:20 +000029public:
joshualittb0a8a372014-09-23 09:50:21 -070030 SK_DECLARE_INST_COUNT(GrProcessor)
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000031
joshualittb0a8a372014-09-23 09:50:21 -070032 virtual ~GrProcessor();
tomhudson@google.com168e6342012-04-18 17:49:20 +000033
egdaniel1a8ecdf2014-10-03 06:24:12 -070034 struct InvariantOutput{
egdanielab84fae2014-10-14 06:48:46 -070035 InvariantOutput() : fColor(0), fValidFlags(0), fIsSingleComponent(false),
egdaniel9e4d6d12014-10-15 13:49:02 -070036 fNonMulStageFound(false), fWillUseInputColor(true) {}
37
38 enum ReadInput {
39 kWill_ReadInput,
40 kWillNot_ReadInput,
41 };
joshualitt65171342014-10-09 07:25:36 -070042
egdanielccb2e382014-10-13 12:53:46 -070043 void mulByUnknownOpaqueColor() {
44 if (this->isOpaque()) {
45 fValidFlags = kA_GrColorComponentFlag;
46 fIsSingleComponent = false;
47 } else {
48 // Since the current state is not opaque we no longer care if the color being
49 // multiplied is opaque.
50 this->mulByUnknownColor();
51 }
52 }
53
54 void mulByUnknownColor() {
55 if (this->hasZeroAlpha()) {
egdanielab84fae2014-10-14 06:48:46 -070056 this->internalSetToTransparentBlack();
egdanielccb2e382014-10-13 12:53:46 -070057 } else {
egdanielab84fae2014-10-14 06:48:46 -070058 this->internalSetToUnknown();
egdanielccb2e382014-10-13 12:53:46 -070059 }
60 }
61
62 void mulByUnknownAlpha() {
63 if (this->hasZeroAlpha()) {
egdanielab84fae2014-10-14 06:48:46 -070064 this->internalSetToTransparentBlack();
egdanielccb2e382014-10-13 12:53:46 -070065 } else {
66 // We don't need to change fIsSingleComponent in this case
67 fValidFlags = 0;
68 }
69 }
70
egdaniel9e4d6d12014-10-15 13:49:02 -070071 void mulByKnownAlpha(uint8_t alpha) {
72 if (this->hasZeroAlpha() || 0 == alpha) {
73 this->internalSetToTransparentBlack();
74 } else {
75 if (alpha != 255) {
76 // Multiply color by alpha
77 fColor = GrColorPackRGBA(SkMulDiv255Round(GrColorUnpackR(fColor), alpha),
78 SkMulDiv255Round(GrColorUnpackG(fColor), alpha),
79 SkMulDiv255Round(GrColorUnpackB(fColor), alpha),
80 SkMulDiv255Round(GrColorUnpackA(fColor), alpha));
81 }
82 }
83 }
84
85 void invalidateComponents(uint8_t invalidateFlags, ReadInput readsInput) {
egdanielccb2e382014-10-13 12:53:46 -070086 fValidFlags &= ~invalidateFlags;
87 fIsSingleComponent = false;
egdaniel9e4d6d12014-10-15 13:49:02 -070088 if (kWillNot_ReadInput == readsInput) {
89 fWillUseInputColor = false;
90 }
egdanielccb2e382014-10-13 12:53:46 -070091 }
92
egdaniel9e4d6d12014-10-15 13:49:02 -070093 void setToOther(uint8_t validFlags, GrColor color, ReadInput readsInput) {
egdanielccb2e382014-10-13 12:53:46 -070094 fValidFlags = validFlags;
95 fColor = color;
96 fIsSingleComponent = false;
egdanielab84fae2014-10-14 06:48:46 -070097 fNonMulStageFound = true;
egdaniel9e4d6d12014-10-15 13:49:02 -070098 if (kWillNot_ReadInput == readsInput) {
99 fWillUseInputColor = false;
100 }
egdanielccb2e382014-10-13 12:53:46 -0700101 }
102
egdaniel9e4d6d12014-10-15 13:49:02 -0700103 void setToUnknown(ReadInput readsInput) {
egdanielab84fae2014-10-14 06:48:46 -0700104 this->internalSetToUnknown();
105 fNonMulStageFound= true;
egdaniel9e4d6d12014-10-15 13:49:02 -0700106 if (kWillNot_ReadInput == readsInput) {
107 fWillUseInputColor = false;
108 }
egdanielccb2e382014-10-13 12:53:46 -0700109 }
110
egdaniel1a8ecdf2014-10-03 06:24:12 -0700111 bool isOpaque() const {
112 return ((fValidFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(fColor));
113 }
114
115 bool isSolidWhite() const {
116 return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor);
117 }
118
egdanielccb2e382014-10-13 12:53:46 -0700119 GrColor color() const { return fColor; }
120 uint8_t validFlags() const { return fValidFlags; }
121
egdaniel1a8ecdf2014-10-03 06:24:12 -0700122 /**
123 * If isSingleComponent is true, then the flag values for r, g, b, and a must all be the
124 * same. If the flags are all set then all color components must be equal.
125 */
126 SkDEBUGCODE(void validate() const;)
127
128 private:
egdanielab84fae2014-10-14 06:48:46 -0700129 void internalSetToTransparentBlack() {
130 fValidFlags = kRGBA_GrColorComponentFlags;
131 fColor = 0;
132 fIsSingleComponent = true;
133 }
134
135 void internalSetToUnknown() {
136 fValidFlags = 0;
137 fIsSingleComponent = false;
138 }
139
egdanielccb2e382014-10-13 12:53:46 -0700140 bool hasZeroAlpha() const {
141 return ((fValidFlags & kA_GrColorComponentFlag) && 0 == GrColorUnpackA(fColor));
142 }
egdaniel1a8ecdf2014-10-03 06:24:12 -0700143
egdanielccb2e382014-10-13 12:53:46 -0700144 SkDEBUGCODE(bool colorComponentsAllEqual() const;)
egdaniel1a8ecdf2014-10-03 06:24:12 -0700145 /**
146 * If alpha is valid, check that any valid R,G,B values are <= A
147 */
148 SkDEBUGCODE(bool validPreMulColor() const;)
egdanielccb2e382014-10-13 12:53:46 -0700149
150 // Friended class that have "controller" code which loop over stages calling
151 // computeInvarianteOutput(). These controllers may need to manually adjust the internal
152 // members of InvariantOutput
153 friend class GrDrawState;
154 friend class GrOptDrawState;
155 friend class GrPaint;
egdaniel9e4d6d12014-10-15 13:49:02 -0700156 friend class GrProcessor;
egdanielccb2e382014-10-13 12:53:46 -0700157
158 GrColor fColor;
159 uint32_t fValidFlags;
160 bool fIsSingleComponent;
egdanielab84fae2014-10-14 06:48:46 -0700161 bool fNonMulStageFound;
egdaniel9e4d6d12014-10-15 13:49:02 -0700162 bool fWillUseInputColor;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700163 };
164
bsalomon@google.com371e1052013-01-11 21:08:55 +0000165 /**
egdaniel1a8ecdf2014-10-03 06:24:12 -0700166 * This function is used to perform optimizations. When called the invarientOuput param
bsalomon98b33eb2014-10-15 11:05:26 -0700167 * indicate whether the input components to this processor in the FS will have known values.
egdaniel1a8ecdf2014-10-03 06:24:12 -0700168 * In inout the validFlags member is a bitfield of GrColorComponentFlags. The isSingleComponent
169 * member indicates whether the input will be 1 or 4 bytes. The function updates the members of
170 * inout to indicate known values of its output. A component of the color member only has
171 * meaning if the corresponding bit in validFlags is set.
bsalomon@google.com371e1052013-01-11 21:08:55 +0000172 */
egdaniel1a8ecdf2014-10-03 06:24:12 -0700173 void computeInvariantOutput(InvariantOutput* inout) const {
egdaniel9e4d6d12014-10-15 13:49:02 -0700174 inout->fWillUseInputColor = true;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700175 this->onComputeInvariantOutput(inout);
176#ifdef SK_DEBUG
177 inout->validate();
178#endif
179 }
tomhudson@google.com168e6342012-04-18 17:49:20 +0000180
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000181 /** This object, besides creating back-end-specific helper objects, is used for run-time-type-
182 identification. The factory should be an instance of templated class,
bsalomonb762cb52014-10-15 11:25:21 -0700183 GrTBackendProcessorFactory. It is templated on the subclass of GrProcessor. The subclass
184 must have a nested type (or typedef) named GLProcessor which will be the subclass of
joshualittb0a8a372014-09-23 09:50:21 -0700185 GrGLProcessor created by the factory.
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000186
187 Example:
bsalomon98b33eb2014-10-15 11:05:26 -0700188 class MyCustomProcessor : public GrProcessor {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000189 ...
bsalomonb762cb52014-10-15 11:25:21 -0700190 virtual const GrBackendProcessorFactory& getFactory() const SK_OVERRIDE {
191 return GrTBackendProcessorFactory<MyCustomProcessor>::getInstance();
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000192 }
193 ...
194 };
195 */
joshualittb0a8a372014-09-23 09:50:21 -0700196 virtual const GrBackendProcessorFactory& getFactory() const = 0;
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000197
bsalomon98b33eb2014-10-15 11:05:26 -0700198 /** Human-meaningful string to identify this prcoessor; may be embedded
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000199 in generated shader code. */
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000200 const char* name() const;
bsalomon@google.com289efe02012-05-21 20:57:59 +0000201
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000202 int numTextures() const { return fTextureAccesses.count(); }
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000203
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000204 /** Returns the access pattern for the texture at index. index must be valid according to
205 numTextures(). */
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000206 const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; }
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000207
208 /** Shortcut for textureAccess(index).texture(); */
209 GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000210
bsalomon98b33eb2014-10-15 11:05:26 -0700211 /** Will this processor read the fragment position? */
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000212 bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000213
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000214 void* operator new(size_t size);
215 void operator delete(void* target);
216
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000217 void* operator new(size_t size, void* placement) {
218 return ::operator new(size, placement);
219 }
220 void operator delete(void* target, void* placement) {
221 ::operator delete(target, placement);
222 }
223
joshualitt49586be2014-09-16 08:21:41 -0700224 /**
joshualittb0a8a372014-09-23 09:50:21 -0700225 * Helper for down-casting to a GrProcessor subclass
joshualitt49586be2014-09-16 08:21:41 -0700226 */
227 template <typename T> const T& cast() const { return *static_cast<const T*>(this); }
228
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000229protected:
bsalomon420d7e92014-10-16 09:18:09 -0700230 GrProcessor() : fWillReadFragmentPosition(false) {}
231
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000232 /**
bsalomon98b33eb2014-10-15 11:05:26 -0700233 * Subclasses call this from their constructor to register GrTextureAccesses. The processor
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000234 * subclass manages the lifetime of the accesses (this function only stores a pointer). The
joshualittb0a8a372014-09-23 09:50:21 -0700235 * GrTextureAccess is typically a member field of the GrProcessor subclass. This must only be
236 * called from the constructor because GrProcessors are immutable.
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000237 */
238 void addTextureAccess(const GrTextureAccess* textureAccess);
239
bsalomon420d7e92014-10-16 09:18:09 -0700240 bool hasSameTextureAccesses(const GrProcessor&) const;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000241
242 /**
bsalomon98b33eb2014-10-15 11:05:26 -0700243 * If the prcoessor will generate a backend-specific processor that will read the fragment
244 * position in the FS then it must call this method from its constructor. Otherwise, the
245 * request to access the fragment position will be denied.
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000246 */
247 void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000248
bsalomon0e08fc12014-10-15 08:19:04 -0700249private:
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000250
egdaniel1a8ecdf2014-10-03 06:24:12 -0700251 /**
252 * Subclass implements this to support getConstantColorComponents(...).
253 */
254 virtual void onComputeInvariantOutput(InvariantOutput* inout) const = 0;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000255
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000256 SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000257 bool fWillReadFragmentPosition;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000258
bsalomon95740982014-09-04 13:12:37 -0700259 typedef GrProgramElement INHERITED;
tomhudson@google.com168e6342012-04-18 17:49:20 +0000260};
261
bsalomon98b33eb2014-10-15 11:05:26 -0700262
263/**
264 * This creates a processor outside of the memory pool. The processor's destructor will be called
265 * at global destruction time. NAME will be the name of the created instance.
266 */
267#define GR_CREATE_STATIC_PROCESSOR(NAME, PROC_CLASS, ARGS) \
268static SkAlignedSStorage<sizeof(PROC_CLASS)> g_##NAME##_Storage; \
269static PROC_CLASS* NAME SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), PROC_CLASS, ARGS); \
270static SkAutoTDestroy<GrProcessor> NAME##_ad(NAME);
271
tomhudson@google.com168e6342012-04-18 17:49:20 +0000272#endif