OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkArithmeticMode_gpu.h" | 8 #include "SkArithmeticMode_gpu.h" |
9 | 9 |
10 #if SK_SUPPORT_GPU | 10 #if SK_SUPPORT_GPU |
11 #include "GrContext.h" | 11 #include "GrContext.h" |
12 #include "GrFragmentProcessor.h" | 12 #include "GrFragmentProcessor.h" |
13 #include "GrInvariantOutput.h" | 13 #include "GrInvariantOutput.h" |
14 #include "GrProcessor.h" | 14 #include "GrProcessor.h" |
15 #include "GrTexture.h" | 15 #include "GrTexture.h" |
16 #include "gl/GrGLCaps.h" | 16 #include "gl/GrGLCaps.h" |
17 #include "gl/GrGLProcessor.h" | 17 #include "gl/GrGLProcessor.h" |
18 #include "gl/GrGLProgramDataManager.h" | 18 #include "gl/GrGLProgramDataManager.h" |
19 #include "gl/builders/GrGLProgramBuilder.h" | 19 #include "gl/builders/GrGLProgramBuilder.h" |
20 | 20 |
21 static const bool gUseUnpremul = false; | 21 static const bool gUseUnpremul = false; |
22 | 22 |
| 23 static void add_arithmetic_code(GrGLFPFragmentBuilder* fsBuilder, |
| 24 const char* inputColor, |
| 25 const char* dstColor, |
| 26 const char* outputColor, |
| 27 const char* kUni, |
| 28 bool enforcePMColor) { |
| 29 // We don't try to optimize for this case at all |
| 30 if (NULL == inputColor) { |
| 31 fsBuilder->codeAppend("const vec4 src = vec4(1);"); |
| 32 } else { |
| 33 fsBuilder->codeAppendf("vec4 src = %s;", inputColor); |
| 34 if (gUseUnpremul) { |
| 35 fsBuilder->codeAppend("src.rgb = clamp(src.rgb / src.a, 0.0, 1.0);")
; |
| 36 } |
| 37 } |
| 38 |
| 39 fsBuilder->codeAppendf("vec4 dst = %s;", dstColor); |
| 40 if (gUseUnpremul) { |
| 41 fsBuilder->codeAppend("dst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);"); |
| 42 } |
| 43 |
| 44 fsBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s
.w;", |
| 45 outputColor, kUni, kUni, kUni, kUni); |
| 46 fsBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputCol
or); |
| 47 if (gUseUnpremul) { |
| 48 fsBuilder->codeAppendf("%s.rgb *= %s.a;", outputColor, outputColor); |
| 49 } else if (enforcePMColor) { |
| 50 fsBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);", |
| 51 outputColor, outputColor, outputColor); |
| 52 } |
| 53 } |
| 54 |
23 class GLArithmeticFP : public GrGLFragmentProcessor { | 55 class GLArithmeticFP : public GrGLFragmentProcessor { |
24 public: | 56 public: |
25 GLArithmeticFP(const GrProcessor&); | 57 GLArithmeticFP(const GrProcessor&) |
26 virtual ~GLArithmeticFP(); | 58 : fEnforcePMColor(true) { |
| 59 } |
27 | 60 |
28 virtual void emitCode(GrGLFPBuilder*, | 61 ~GLArithmeticFP() SK_OVERRIDE {} |
29 const GrFragmentProcessor&, | |
30 const char* outputColor, | |
31 const char* inputColor, | |
32 const TransformedCoordsArray&, | |
33 const TextureSamplerArray&) SK_OVERRIDE; | |
34 | 62 |
35 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_O
VERRIDE; | 63 void emitCode(GrGLFPBuilder* builder, |
| 64 const GrFragmentProcessor& fp, |
| 65 const char* outputColor, |
| 66 const char* inputColor, |
| 67 const TransformedCoordsArray& coords, |
| 68 const TextureSamplerArray& samplers) SK_OVERRIDE { |
| 69 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); |
| 70 fsBuilder->codeAppend("vec4 bgColor = "); |
| 71 fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0]
.getType()); |
| 72 fsBuilder->codeAppendf(";"); |
| 73 const char* dstColor = "bgColor"; |
36 | 74 |
37 static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyB
uilder* b); | 75 fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
| 76 kVec4f_GrSLType, kDefault_GrSLPrecision, |
| 77 "k"); |
| 78 const char* kUni = builder->getUniformCStr(fKUni); |
| 79 |
| 80 add_arithmetic_code(fsBuilder, inputColor, dstColor, outputColor, kUni,
fEnforcePMColor); |
| 81 } |
| 82 |
| 83 void setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) S
K_OVERRIDE { |
| 84 const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>(); |
| 85 pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); |
| 86 fEnforcePMColor = arith.enforcePMColor(); |
| 87 } |
| 88 |
| 89 static void GenKey(const GrProcessor& proc, const GrGLCaps& caps, GrProcesso
rKeyBuilder* b) { |
| 90 const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>(); |
| 91 uint32_t key = arith.enforcePMColor() ? 1 : 0; |
| 92 b->add32(key); |
| 93 } |
38 | 94 |
39 private: | 95 private: |
40 GrGLProgramDataManager::UniformHandle fKUni; | 96 GrGLProgramDataManager::UniformHandle fKUni; |
41 bool fEnforcePMColor; | 97 bool fEnforcePMColor; |
42 | 98 |
43 typedef GrGLFragmentProcessor INHERITED; | 99 typedef GrGLFragmentProcessor INHERITED; |
44 }; | 100 }; |
45 | 101 |
46 /////////////////////////////////////////////////////////////////////////////// | 102 /////////////////////////////////////////////////////////////////////////////// |
47 | 103 |
48 GrArithmeticFP::GrArithmeticFP(float k1, float k2, float k3, float k4, | 104 GrArithmeticFP::GrArithmeticFP(float k1, float k2, float k3, float k4, |
49 bool enforcePMColor, GrTexture* background) | 105 bool enforcePMColor, GrTexture* background) |
50 : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { | 106 : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { |
51 this->initClassID<GrArithmeticFP>(); | 107 this->initClassID<GrArithmeticFP>(); |
52 if (background) { | 108 |
53 fBackgroundTransform.reset(kLocal_GrCoordSet, background, | 109 SkASSERT(background); |
54 GrTextureParams::kNone_FilterMode); | 110 |
55 this->addCoordTransform(&fBackgroundTransform); | 111 fBackgroundTransform.reset(kLocal_GrCoordSet, background, |
56 fBackgroundAccess.reset(background); | 112 GrTextureParams::kNone_FilterMode); |
57 this->addTextureAccess(&fBackgroundAccess); | 113 this->addCoordTransform(&fBackgroundTransform); |
58 } else { | 114 fBackgroundAccess.reset(background); |
59 this->setWillReadDstColor(); | 115 this->addTextureAccess(&fBackgroundAccess); |
60 } | |
61 } | 116 } |
62 | 117 |
63 void GrArithmeticFP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuild
er* b) const { | 118 void GrArithmeticFP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuild
er* b) const { |
64 GLArithmeticFP::GenKey(*this, caps, b); | 119 GLArithmeticFP::GenKey(*this, caps, b); |
65 } | 120 } |
66 | 121 |
67 GrGLFragmentProcessor* GrArithmeticFP::createGLInstance() const { | 122 GrGLFragmentProcessor* GrArithmeticFP::createGLInstance() const { |
68 return SkNEW_ARGS(GLArithmeticFP, (*this)); | 123 return SkNEW_ARGS(GLArithmeticFP, (*this)); |
69 } | 124 } |
70 | 125 |
71 bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const { | 126 bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const { |
72 const GrArithmeticFP& fp = fpBase.cast<GrArithmeticFP>(); | 127 const GrArithmeticFP& fp = fpBase.cast<GrArithmeticFP>(); |
73 return fK1 == fp.fK1 && | 128 return fK1 == fp.fK1 && |
74 fK2 == fp.fK2 && | 129 fK2 == fp.fK2 && |
75 fK3 == fp.fK3 && | 130 fK3 == fp.fK3 && |
76 fK4 == fp.fK4 && | 131 fK4 == fp.fK4 && |
77 fEnforcePMColor == fp.fEnforcePMColor; | 132 fEnforcePMColor == fp.fEnforcePMColor; |
78 } | 133 } |
79 | 134 |
80 void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const { | 135 void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const { |
81 // TODO: optimize this | 136 // TODO: optimize this |
82 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); | 137 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); |
83 } | 138 } |
84 | 139 |
85 /////////////////////////////////////////////////////////////////////////////// | 140 /////////////////////////////////////////////////////////////////////////////// |
86 | 141 |
87 GLArithmeticFP::GLArithmeticFP(const GrProcessor&) | |
88 : fEnforcePMColor(true) { | |
89 } | |
90 | |
91 GLArithmeticFP::~GLArithmeticFP() { | |
92 } | |
93 | |
94 void GLArithmeticFP::emitCode(GrGLFPBuilder* builder, | |
95 const GrFragmentProcessor& fp, | |
96 const char* outputColor, | |
97 const char* inputColor, | |
98 const TransformedCoordsArray& coords, | |
99 const TextureSamplerArray& samplers) { | |
100 | |
101 GrTexture* backgroundTex = fp.cast<GrArithmeticFP>().backgroundTexture(); | |
102 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | |
103 const char* dstColor; | |
104 if (backgroundTex) { | |
105 fsBuilder->codeAppend("\t\tvec4 bgColor = "); | |
106 fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0]
.getType()); | |
107 fsBuilder->codeAppendf(";\n"); | |
108 dstColor = "bgColor"; | |
109 } else { | |
110 dstColor = fsBuilder->dstColor(); | |
111 } | |
112 | |
113 SkASSERT(dstColor); | |
114 fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
115 kVec4f_GrSLType, kDefault_GrSLPrecision, | |
116 "k"); | |
117 const char* kUni = builder->getUniformCStr(fKUni); | |
118 | |
119 // We don't try to optimize for this case at all | |
120 if (NULL == inputColor) { | |
121 fsBuilder->codeAppendf("\t\tconst vec4 src = vec4(1);\n"); | |
122 } else { | |
123 fsBuilder->codeAppendf("\t\tvec4 src = %s;\n", inputColor); | |
124 if (gUseUnpremul) { | |
125 fsBuilder->codeAppendf("\t\tsrc.rgb = clamp(src.rgb / src.a, 0.0, 1.
0);\n"); | |
126 } | |
127 } | |
128 | |
129 fsBuilder->codeAppendf("\t\tvec4 dst = %s;\n", dstColor); | |
130 if (gUseUnpremul) { | |
131 fsBuilder->codeAppendf("\t\tdst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);\
n"); | |
132 } | |
133 | |
134 fsBuilder->codeAppendf("\t\t%s = %s.x * src * dst + %s.y * src + %s.z * dst
+ %s.w;\n", outputColor, kUni, kUni, kUni, kUni); | |
135 fsBuilder->codeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outpu
tColor); | |
136 if (gUseUnpremul) { | |
137 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor
); | |
138 } else if (fEnforcePMColor) { | |
139 fsBuilder->codeAppendf("\t\t%s.rgb = min(%s.rgb, %s.a);\n", outputColor,
outputColor, outputColor); | |
140 } | |
141 } | |
142 | |
143 void GLArithmeticFP::setData(const GrGLProgramDataManager& pdman, const GrProces
sor& processor) { | |
144 const GrArithmeticFP& arith = processor.cast<GrArithmeticFP>(); | |
145 pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); | |
146 fEnforcePMColor = arith.enforcePMColor(); | |
147 } | |
148 | |
149 void GLArithmeticFP::GenKey(const GrProcessor& processor, const GrGLCaps&, | |
150 GrProcessorKeyBuilder* b) { | |
151 const GrArithmeticFP& arith = processor.cast<GrArithmeticFP>(); | |
152 uint32_t key = arith.enforcePMColor() ? 1 : 0; | |
153 if (arith.backgroundTexture()) { | |
154 key |= 2; | |
155 } | |
156 b->add32(key); | |
157 } | |
158 | |
159 GrFragmentProcessor* GrArithmeticFP::TestCreate(SkRandom* rand, | 142 GrFragmentProcessor* GrArithmeticFP::TestCreate(SkRandom* rand, |
160 GrContext*, | 143 GrContext*, |
161 const GrDrawTargetCaps&, | 144 const GrDrawTargetCaps&, |
162 GrTexture*[]) { | 145 GrTexture* textures[]) { |
163 float k1 = rand->nextF(); | 146 float k1 = rand->nextF(); |
164 float k2 = rand->nextF(); | 147 float k2 = rand->nextF(); |
165 float k3 = rand->nextF(); | 148 float k3 = rand->nextF(); |
166 float k4 = rand->nextF(); | 149 float k4 = rand->nextF(); |
167 bool enforcePMColor = rand->nextBool(); | 150 bool enforcePMColor = rand->nextBool(); |
168 | 151 |
169 return SkNEW_ARGS(GrArithmeticFP, (k1, k2, k3, k4, enforcePMColor, NULL)); | 152 return SkNEW_ARGS(GrArithmeticFP, (k1, k2, k3, k4, enforcePMColor, textures[
0])); |
170 } | 153 } |
171 | 154 |
172 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP); | 155 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP); |
173 | 156 |
| 157 /////////////////////////////////////////////////////////////////////////////// |
| 158 // Xfer Processor |
| 159 /////////////////////////////////////////////////////////////////////////////// |
| 160 |
| 161 class GLArithmeticXP : public GrGLXferProcessor { |
| 162 public: |
| 163 GLArithmeticXP(const GrProcessor&) |
| 164 : fEnforcePMColor(true) { |
| 165 } |
| 166 |
| 167 ~GLArithmeticXP() SK_OVERRIDE {} |
| 168 |
| 169 void emitCode(const EmitArgs& args) SK_OVERRIDE { |
| 170 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); |
| 171 |
| 172 const char* dstColor = fsBuilder->dstColor(); |
| 173 |
| 174 fKUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
| 175 kVec4f_GrSLType, kDefault_GrSLPrecision, |
| 176 "k"); |
| 177 const char* kUni = args.fPB->getUniformCStr(fKUni); |
| 178 |
| 179 add_arithmetic_code(fsBuilder, args.fInputColor, dstColor, args.fOutputP
rimary, kUni, |
| 180 fEnforcePMColor); |
| 181 |
| 182 fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;", |
| 183 args.fOutputPrimary, args.fOutputPrimary, args.fI
nputCoverage, |
| 184 args.fInputCoverage, dstColor); |
| 185 } |
| 186 |
| 187 void setData(const GrGLProgramDataManager& pdman, |
| 188 const GrXferProcessor& processor) SK_OVERRIDE { |
| 189 const GrArithmeticXP& arith = processor.cast<GrArithmeticXP>(); |
| 190 pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); |
| 191 fEnforcePMColor = arith.enforcePMColor(); |
| 192 }; |
| 193 |
| 194 static void GenKey(const GrProcessor& processor, const GrGLCaps& caps, |
| 195 GrProcessorKeyBuilder* b) { |
| 196 const GrArithmeticXP& arith = processor.cast<GrArithmeticXP>(); |
| 197 uint32_t key = arith.enforcePMColor() ? 1 : 0; |
| 198 b->add32(key); |
| 199 } |
| 200 |
| 201 private: |
| 202 GrGLProgramDataManager::UniformHandle fKUni; |
| 203 bool fEnforcePMColor; |
| 204 |
| 205 typedef GrGLXferProcessor INHERITED; |
| 206 }; |
| 207 |
| 208 /////////////////////////////////////////////////////////////////////////////// |
| 209 |
| 210 GrArithmeticXP::GrArithmeticXP(float k1, float k2, float k3, float k4, bool enfo
rcePMColor) |
| 211 : fK1(k1) |
| 212 , fK2(k2) |
| 213 , fK3(k3) |
| 214 , fK4(k4) |
| 215 , fEnforcePMColor(enforcePMColor) { |
| 216 this->initClassID<GrPorterDuffXferProcessor>(); |
| 217 this->setWillReadDstColor(); |
| 218 } |
| 219 |
| 220 void GrArithmeticXP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuild
er* b) const { |
| 221 GLArithmeticXP::GenKey(*this, caps, b); |
| 222 } |
| 223 |
| 224 GrGLXferProcessor* GrArithmeticXP::createGLInstance() const { |
| 225 return SkNEW_ARGS(GLArithmeticXP, (*this)); |
| 226 } |
| 227 |
| 228 GrXferProcessor::OptFlags GrArithmeticXP::getOptimizations(const GrProcOptInfo&
colorPOI, |
| 229 const GrProcOptInfo&
coveragePOI, |
| 230 bool doesStencilWrite
, |
| 231 GrColor* overrideColo
r, |
| 232 const GrDrawTargetCap
s& caps) { |
| 233 return GrXferProcessor::kNone_Opt; |
| 234 } |
| 235 |
| 236 /////////////////////////////////////////////////////////////////////////////// |
| 237 |
| 238 GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float
k4, |
| 239 bool enforcePMColor) |
| 240 : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { |
| 241 this->initClassID<GrArithmeticXPFactory>(); |
| 242 } |
| 243 |
| 244 void GrArithmeticXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, |
| 245 const GrProcOptInfo& coveragePOI, |
| 246 GrXPFactory::InvariantOutput* out
put) const { |
| 247 output->fWillBlendWithDst = true; |
| 248 |
| 249 // TODO: We could try to optimize this more. For example if we have solid co
verage and fK1 and |
| 250 // fK3 are zero, then we won't be blending the color with dst at all so we c
an know what the |
| 251 // output color is (up to the valid color components passed in). |
| 252 output->fBlendedColorFlags = 0; |
| 253 } |
| 254 |
| 255 GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory); |
| 256 |
| 257 GrXPFactory* GrArithmeticXPFactory::TestCreate(SkRandom* random, |
| 258 GrContext*, |
| 259 const GrDrawTargetCaps&, |
| 260 GrTexture*[]) { |
| 261 float k1 = random->nextF(); |
| 262 float k2 = random->nextF(); |
| 263 float k3 = random->nextF(); |
| 264 float k4 = random->nextF(); |
| 265 bool enforcePMColor = random->nextBool(); |
| 266 |
| 267 return GrArithmeticXPFactory::Create(k1, k2, k3, k4, enforcePMColor); |
| 268 } |
| 269 |
174 #endif | 270 #endif |
OLD | NEW |