Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Side by Side Diff: src/core/SkNormalSource.cpp

Issue 2063793002: API change to allow for NormalSource selection at the user level. (Closed) Base URL: https://skia.googlesource.com/skia@dvonbeck-normal-factor-out
Patch Set: Fixed CPU behavior when normal.Z=-1 Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 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 "SkError.h" 8 #include "SkError.h"
9 #include "SkErrorInternals.h" 9 #include "SkErrorInternals.h"
10 #include "SkLightingShader.h" 10 #include "SkLightingShader.h"
11 #include "SkMatrix.h"
11 #include "SkNormalSource.h" 12 #include "SkNormalSource.h"
12 #include "SkReadBuffer.h" 13 #include "SkReadBuffer.h"
13 #include "SkWriteBuffer.h" 14 #include "SkWriteBuffer.h"
14 15
15 // Genretating vtable 16 // Genretating vtable
16 SkNormalSource::~SkNormalSource() {} 17 SkNormalSource::~SkNormalSource() {}
17 18
18 /////////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////////
19 20
20 class NormalMapSourceImpl : public SkNormalSource { 21 class NormalMapSourceImpl : public SkNormalSource {
21 public: 22 public:
22 NormalMapSourceImpl(sk_sp<SkShader> mapShader, const SkVector &normRotation) 23 NormalMapSourceImpl(sk_sp<SkShader> mapShader, const SkMatrix& invCTM)
23 : fMapShader(std::move(mapShader)) 24 : fMapShader(std::move(mapShader))
24 , fNormRotation(normRotation) {} 25 , fInvCTM(invCTM) {}
25 26
26 #if SK_SUPPORT_GPU 27 #if SK_SUPPORT_GPU
27 sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, 28 sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*,
28 const SkMatrix& viewM, 29 const SkMatrix& viewM,
29 const SkMatrix* localMatrix, 30 const SkMatrix* localMatrix,
30 SkFilterQuality, 31 SkFilterQuality,
31 SkSourceGammaTreatment) const override; 32 SkSourceGammaTreatment) const override;
32 #endif 33 #endif
33 34
34 SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec, 35 SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec,
(...skipping 16 matching lines...) Expand all
51 52
52 void fillScanLine(int x, int y, SkPoint3 output[], int count) const over ride; 53 void fillScanLine(int x, int y, SkPoint3 output[], int count) const over ride;
53 private: 54 private:
54 const NormalMapSourceImpl& fSource; 55 const NormalMapSourceImpl& fSource;
55 SkShader::Context* fMapContext; 56 SkShader::Context* fMapContext;
56 57
57 typedef SkNormalSource::Provider INHERITED; 58 typedef SkNormalSource::Provider INHERITED;
58 }; 59 };
59 60
60 sk_sp<SkShader> fMapShader; 61 sk_sp<SkShader> fMapShader;
61 SkVector fNormRotation; 62 SkMatrix fInvCTM; // Inverse of the canvas total matrix, used for rot ating normals.
62 63
63 friend class SkNormalSource; 64 friend class SkNormalSource;
64 65
65 typedef SkNormalSource INHERITED; 66 typedef SkNormalSource INHERITED;
66 }; 67 };
67 68
68 //////////////////////////////////////////////////////////////////////////// 69 ////////////////////////////////////////////////////////////////////////////
69 70
70 #if SK_SUPPORT_GPU 71 #if SK_SUPPORT_GPU
71 72
72 #include "GrCoordTransform.h" 73 #include "GrCoordTransform.h"
73 #include "GrInvariantOutput.h" 74 #include "GrInvariantOutput.h"
74 #include "GrTextureParams.h" 75 #include "GrTextureParams.h"
75 #include "glsl/GrGLSLFragmentProcessor.h" 76 #include "glsl/GrGLSLFragmentProcessor.h"
76 #include "glsl/GrGLSLFragmentShaderBuilder.h" 77 #include "glsl/GrGLSLFragmentShaderBuilder.h"
77 #include "SkGr.h" 78 #include "SkGr.h"
78 79
79 class NormalMapFP : public GrFragmentProcessor { 80 class NormalMapFP : public GrFragmentProcessor {
80 public: 81 public:
81 NormalMapFP(sk_sp<GrFragmentProcessor> mapFP, const SkVector& normRotation) 82 NormalMapFP(sk_sp<GrFragmentProcessor> mapFP, const SkMatrix& invCTM)
82 : fNormRotation(normRotation) { 83 : fInvCTM(invCTM) {
83 this->registerChildProcessor(mapFP); 84 this->registerChildProcessor(mapFP);
84 85
85 this->initClassID<NormalMapFP>(); 86 this->initClassID<NormalMapFP>();
86 } 87 }
87 88
88 class GLSLNormalMapFP : public GrGLSLFragmentProcessor { 89 class GLSLNormalMapFP : public GrGLSLFragmentProcessor {
89 public: 90 public:
90 GLSLNormalMapFP() { 91 GLSLNormalMapFP() {
91 fNormRotation.set(0.0f, 0.0f); 92 fInvCTM.reset();
92 } 93 }
93 94
94 void emitCode(EmitArgs& args) override { 95 void emitCode(EmitArgs& args) override {
95
96 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; 96 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
97 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 97 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
98 98
99 // add uniform 99 // add uniform
100 const char* xformUniName = nullptr; 100 const char* xformUniName = nullptr;
robertphillips 2016/07/06 16:36:33 It looks like we only use the upper left 2x2 - why
dvonbeck 2016/07/06 18:07:48 Done.
101 fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 101 fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kMat3 3f_GrSLType,
102 kVec2f_GrSLType, kDefault_GrS LPrecision, 102 kDefault_GrSLPrecision, "Xfor m", &xformUniName);
103 "Xform", &xformUniName);
104 103
105 SkString dstNormalColorName("dstNormalColor"); 104 SkString dstNormalColorName("dstNormalColor");
106 this->emitChild(0, nullptr, &dstNormalColorName, args); 105 this->emitChild(0, nullptr, &dstNormalColorName, args);
107 fragBuilder->codeAppendf("vec3 normal = %s.rgb - vec3(0.5);", 106 fragBuilder->codeAppendf("vec3 normal = normalize(%s.rgb - vec3(0.5) );",
108 dstNormalColorName.c_str()); 107 dstNormalColorName.c_str());
109 108
110 // TODO: inverse map the light direction vectors in the vertex shade r rather than 109 // TODO: inverse map the light direction vectors in the vertex shade r rather than
111 // transforming all the normals here! 110 // transforming all the normals here!
112 fragBuilder->codeAppendf(
113 "mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);",
114 xformUniName, xformUniName, xformUniName, xformUniName);
115 111
robertphillips 2016/07/06 16:36:34 A branch in the shader is expensive !
dvonbeck 2016/07/06 18:07:48 The code seemed to run just fine ignoring the divi
robertphillips 2016/07/06 19:11:14 I would say leave the guard for now. I just wanted
dvonbeck 2016/07/06 19:34:36 Alright! I think it should be fine here considerin
116 fragBuilder->codeAppend("normal = normalize(m*normal);"); 112 // If there's no x & y components, return (0, 0, +/- 1) instead to a void division by 0
117 fragBuilder->codeAppendf("%s = vec4(normal, 0);", args.fOutputColor) ; 113 fragBuilder->codeAppend( "if (abs(normal.z) > 0.9999) {");
robertphillips 2016/07/06 16:36:33 Might as well just set it to (0, 0, 1, 0).
dvonbeck 2016/07/06 18:07:48 Needs to handle (0, 0, -1, 0) as well. I could set
robertphillips 2016/07/06 19:11:14 Okay - leave it as is.
114 fragBuilder->codeAppendf(" %s = normalize(vec4(0.0, 0.0, normal.z , 0.0));",
115 args.fOutputColor);
116 // Else, Normalizing the transformed X and Y, while keeping constant both Z and the
117 // vector's angle in the XY plane. This maintains the "slope" for th e surface while
118 // appropriately rotating the normal for any anisotropic scaling tha t occurs.
119 // Here, we call scaling factor the number that must divide the tran sformed X and Y so
120 // that the normal's length remains equal to 1.
121 fragBuilder->codeAppend( "} else {");
122 fragBuilder->codeAppendf(" vec2 transformed = mat2(%s) * normal.x y;",
123 xformUniName);
124 fragBuilder->codeAppend( " float scalingFactorSquared = "
robertphillips 2016/07/06 16:36:34 Using pows for squares seems a bit overkill.
dvonbeck 2016/07/06 18:07:48 Should I be using *?
robertphillips 2016/07/06 19:11:14 Right, I would just have multiplies. The compiler
dvonbeck 2016/07/06 19:34:36 Done.
125 "(pow(transformed.x, 2) + pow(t ransformed.y, 2))"
126 "/(1.0 - pow(normal.z, 2));");
127 fragBuilder->codeAppendf(" %s = vec4(transformed*inversesqrt(scal ingFactorSquared),"
128 "normal.z, 0.0);",
129 args.fOutputColor);
130 fragBuilder->codeAppend( "}");
118 } 131 }
119 132
120 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, 133 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
121 GrProcessorKeyBuilder* b) { 134 GrProcessorKeyBuilder* b) {
122 b->add32(0x0); 135 b->add32(0x0);
123 } 136 }
124 137
125 protected: 138 protected:
126 void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { 139 void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
127 const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>(); 140 const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
128 141
129 const SkVector& normRotation = normalMapFP.normRotation(); 142 const SkMatrix& invCTM = normalMapFP.invCTM();
130 if (normRotation != fNormRotation) { 143 fInvCTM = invCTM;
131 pdman.set2fv(fXformUni, 1, &normRotation.fX); 144 pdman.setSkMatrix(fXformUni, fInvCTM);
132 fNormRotation = normRotation;
133 }
134 } 145 }
135 146
136 private: 147 private:
137 SkVector fNormRotation; 148 SkMatrix fInvCTM;
138 GrGLSLProgramDataManager::UniformHandle fXformUni; 149 GrGLSLProgramDataManager::UniformHandle fXformUni;
139 }; 150 };
140 151
141 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { 152 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
142 GLSLNormalMapFP::GenKey(*this, caps, b); 153 GLSLNormalMapFP::GenKey(*this, caps, b);
143 } 154 }
144 155
145 const char* name() const override { return "NormalMapFP"; } 156 const char* name() const override { return "NormalMapFP"; }
146 157
147 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { 158 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
148 inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput); 159 inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput);
149 } 160 }
150 161
151 const SkVector& normRotation() const { return fNormRotation; } 162 const SkMatrix& invCTM() const { return fInvCTM; }
152 163
153 private: 164 private:
154 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; } 165 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; }
155 166
156 bool onIsEqual(const GrFragmentProcessor& proc) const override { 167 bool onIsEqual(const GrFragmentProcessor& proc) const override {
157 const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>(); 168 const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
158 return fNormRotation == normalMapFP.fNormRotation; 169 return fInvCTM == normalMapFP.fInvCTM;
159 } 170 }
160 171
161 SkVector fNormRotation; 172 SkMatrix fInvCTM;
162 }; 173 };
163 174
164 sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor( 175 sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor(
165 GrContext *context, 176 GrContext *context,
166 const SkMatrix &viewM, 177 const SkMatrix &viewM,
167 const SkMatrix *localMatrix , 178 const SkMatrix *localMatrix ,
168 SkFilterQuality filterQuali ty, 179 SkFilterQuality filterQuali ty,
169 SkSourceGammaTreatment gamm aTreatment) const { 180 SkSourceGammaTreatment gamm aTreatment) const {
170 181
171 sk_sp<GrFragmentProcessor> mapFP = fMapShader->asFragmentProcessor(context, viewM, 182 sk_sp<GrFragmentProcessor> mapFP = fMapShader->asFragmentProcessor(context, viewM,
172 localMatrix, filterQuality, gammaTreatment); 183 localMatrix, filterQuality, gammaTreatment);
173 184
174 return sk_make_sp<NormalMapFP>(std::move(mapFP), fNormRotation); 185 return sk_make_sp<NormalMapFP>(std::move(mapFP), fInvCTM);
175 } 186 }
176 187
177 #endif // SK_SUPPORT_GPU 188 #endif // SK_SUPPORT_GPU
178 189
179 //////////////////////////////////////////////////////////////////////////// 190 ////////////////////////////////////////////////////////////////////////////
180 191
181 NormalMapSourceImpl::Provider::Provider(const NormalMapSourceImpl& source, 192 NormalMapSourceImpl::Provider::Provider(const NormalMapSourceImpl& source,
182 SkShader::Context* mapContext) 193 SkShader::Context* mapContext)
183 : fSource(source) 194 : fSource(source)
184 , fMapContext(mapContext) { 195 , fMapContext(mapContext) {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 242
232 fMapContext->shadeSpan(x, y, tmpNormalColors, n); 243 fMapContext->shadeSpan(x, y, tmpNormalColors, n);
233 244
234 for (int i = 0; i < n; i++) { 245 for (int i = 0; i < n; i++) {
235 SkPoint3 tempNorm; 246 SkPoint3 tempNorm;
236 247
237 tempNorm.set(SkIntToScalar(SkGetPackedR32(tmpNormalColors[i])) - 127 .0f, 248 tempNorm.set(SkIntToScalar(SkGetPackedR32(tmpNormalColors[i])) - 127 .0f,
238 SkIntToScalar(SkGetPackedG32(tmpNormalColors[i])) - 127 .0f, 249 SkIntToScalar(SkGetPackedG32(tmpNormalColors[i])) - 127 .0f,
239 SkIntToScalar(SkGetPackedB32(tmpNormalColors[i])) - 127 .0f); 250 SkIntToScalar(SkGetPackedB32(tmpNormalColors[i])) - 127 .0f);
240 tempNorm.normalize(); 251 tempNorm.normalize();
241 252
robertphillips 2016/07/06 16:36:33 There 3 overlength lines here.
dvonbeck 2016/07/06 18:07:48 Done.
242 output[i].fX = fSource.fNormRotation.fX * tempNorm.fX + 253 if (!SkScalarNearlyEqual(SkScalarAbs(tempNorm.fZ), 1.0f)) {
243 fSource.fNormRotation.fY * tempNorm.fY; 254 SkVector transformed = fSource.fInvCTM.mapVector(tempNorm.fX, te mpNorm.fY);
244 output[i].fY = -fSource.fNormRotation.fY * tempNorm.fX + 255
245 fSource.fNormRotation.fX * tempNorm.fY; 256 // Normalizing the transformed X and Y, while keeping constant b oth Z and the vector's
246 output[i].fZ = tempNorm.fZ; 257 // angle in the XY plane. This maintains the "slope" for the sur face while appropriately
258 // rotating the normal for any anisotropic scaling that occurs.
259 // Here, we call scaling factor the number that must divide the transformed X and Y so
260 // that the normal's length remains equal to 1.
261 SkScalar scalingFactorSquared =
262 (SkScalarSquare(transformed.fX) + SkScalarSquare(transfo rmed.fY))
263 / (1.0f - SkScalarSquare(tempNorm.fZ));
264 SkScalar invScalingFactor = SkScalarInvert(SkScalarSqrt(scalingF actorSquared));
265
266 output[i].fX = transformed.fX * invScalingFactor;
267 output[i].fY = transformed.fY * invScalingFactor;
268 output[i].fZ = tempNorm.fZ;
269 } else {
robertphillips 2016/07/06 16:36:34 Might as well just set this to (0, 0, 1) and skip
dvonbeck 2016/07/06 18:07:48 Needs to handle (0, 0, -1) as well. I could set it
robertphillips 2016/07/06 19:11:14 Nope, just leave it as is.
270 output[i] = {0.0f, 0.0f, tempNorm.fZ};
271 output[i].normalize();
272 }
273
274 SkASSERT(SkScalarNearlyEqual(output[i].length(), 1.0f))
247 } 275 }
248 276
249 output += n; 277 output += n;
250 x += n; 278 x += n;
251 count -= n; 279 count -= n;
252 } while (count > 0); 280 } while (count > 0);
253 } 281 }
254 282
255 //////////////////////////////////////////////////////////////////////////////// 283 ////////////////////////////////////////////////////////////////////////////////
256 284
257 sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) { 285 sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) {
258 286
259 sk_sp<SkShader> mapShader = buf.readFlattenable<SkShader>(); 287 sk_sp<SkShader> mapShader = buf.readFlattenable<SkShader>();
260 288
261 SkVector normRotation = {1,0}; 289 SkMatrix invCTM;
262 if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) { 290 buf.readMatrix(&invCTM);
263 normRotation = buf.readPoint();
264 }
265 291
266 return sk_make_sp<NormalMapSourceImpl>(std::move(mapShader), normRotation); 292 return sk_make_sp<NormalMapSourceImpl>(std::move(mapShader), invCTM);
267 } 293 }
268 294
269 void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const { 295 void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const {
270 this->INHERITED::flatten(buf); 296 this->INHERITED::flatten(buf);
271 297
272 buf.writeFlattenable(fMapShader.get()); 298 buf.writeFlattenable(fMapShader.get());
273 buf.writePoint(fNormRotation); 299 buf.writeMatrix(fInvCTM);
274 } 300 }
275 301
276 //////////////////////////////////////////////////////////////////////////// 302 ////////////////////////////////////////////////////////////////////////////
277 303
278 sk_sp<SkNormalSource> SkNormalSource::MakeFromNormalMap(sk_sp<SkShader> map, 304 sk_sp<SkNormalSource> SkNormalSource::MakeFromNormalMap(sk_sp<SkShader> map, con st SkMatrix& ctm) {
279 const SkVector &normRota tion) { 305 SkMatrix invCTM;
280 SkASSERT(SkScalarNearlyEqual(normRotation.lengthSqd(), SK_Scalar1)); 306
281 if (!map) { 307 if (!ctm.invert(&invCTM) || !map) {
282 return nullptr; 308 return nullptr;
283 } 309 }
284 310
285 return sk_make_sp<NormalMapSourceImpl>(std::move(map), normRotation); 311 return sk_make_sp<NormalMapSourceImpl>(std::move(map), invCTM);
286 } 312 }
287 313
288 //////////////////////////////////////////////////////////////////////////// 314 ////////////////////////////////////////////////////////////////////////////
289 315
290 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkNormalSource) 316 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkNormalSource)
291 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl) 317 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl)
292 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 318 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
293 319
294 //////////////////////////////////////////////////////////////////////////// 320 ////////////////////////////////////////////////////////////////////////////
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698