• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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 
8 #include "SkArenaAlloc.h"
9 #include "SkBitmapProcShader.h"
10 #include "SkBitmapProcState.h"
11 #include "SkColor.h"
12 #include "SkEmptyShader.h"
13 #include "SkLightingShader.h"
14 #include "SkMathPriv.h"
15 #include "SkNormalSource.h"
16 #include "SkPoint3.h"
17 #include "SkReadBuffer.h"
18 #include "SkWriteBuffer.h"
19 
20 ////////////////////////////////////////////////////////////////////////////
21 
22 /*
23    SkLightingShader TODOs:
24         support different light types
25         support multiple lights
26         fix non-opaque diffuse textures
27 
28     To Test:
29         A8 diffuse textures
30         down & upsampled draws
31 */
32 
33 
34 
35 /** \class SkLightingShaderImpl
36     This subclass of shader applies lighting.
37 */
38 class SkLightingShaderImpl : public SkShader {
39 public:
40     /** Create a new lighting shader that uses the provided normal map and
41         lights to light the diffuse bitmap.
42         @param diffuseShader     the shader that provides the diffuse colors
43         @param normalSource      the source of normals for lighting computation
44         @param lights            the lights applied to the geometry
45     */
SkLightingShaderImpl(sk_sp<SkShader> diffuseShader,sk_sp<SkNormalSource> normalSource,sk_sp<SkLights> lights)46     SkLightingShaderImpl(sk_sp<SkShader> diffuseShader,
47                          sk_sp<SkNormalSource> normalSource,
48                          sk_sp<SkLights> lights)
49         : fDiffuseShader(std::move(diffuseShader))
50         , fNormalSource(std::move(normalSource))
51         , fLights(std::move(lights)) {}
52 
53     bool isOpaque() const override;
54 
55 #if SK_SUPPORT_GPU
56     sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
57 #endif
58 
59     class LightingShaderContext : public SkShader::Context {
60     public:
61         // The context takes ownership of the context and provider. It will call their destructors
62         // and then indirectly free their memory by calling free() on heapAllocated
63         LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&,
64                               SkShader::Context* diffuseContext, SkNormalSource::Provider*,
65                               void* heapAllocated);
66 
67         void shadeSpan(int x, int y, SkPMColor[], int count) override;
68 
getFlags() const69         uint32_t getFlags() const override { return fFlags; }
70 
71     private:
72         SkShader::Context*        fDiffuseContext;
73         SkNormalSource::Provider* fNormalProvider;
74         SkColor                   fPaintColor;
75         uint32_t                  fFlags;
76 
77         typedef SkShader::Context INHERITED;
78     };
79 
80     SK_TO_STRING_OVERRIDE()
81     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingShaderImpl)
82 
83 protected:
84     void flatten(SkWriteBuffer&) const override;
85     Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
86 
87 private:
88     sk_sp<SkShader> fDiffuseShader;
89     sk_sp<SkNormalSource> fNormalSource;
90     sk_sp<SkLights> fLights;
91 
92     friend class SkLightingShader;
93 
94     typedef SkShader INHERITED;
95 };
96 
97 ////////////////////////////////////////////////////////////////////////////
98 
99 #if SK_SUPPORT_GPU
100 
101 #include "GrCoordTransform.h"
102 #include "GrFragmentProcessor.h"
103 #include "glsl/GrGLSLFragmentProcessor.h"
104 #include "glsl/GrGLSLFragmentShaderBuilder.h"
105 #include "glsl/GrGLSLProgramDataManager.h"
106 #include "glsl/GrGLSLUniformHandler.h"
107 #include "SkGr.h"
108 
109 // This FP expects a premul'd color input for its diffuse color. Premul'ing of the paint's color is
110 // handled by the asFragmentProcessor() factory, but shaders providing diffuse color must output it
111 // premul'd.
112 class LightingFP : public GrFragmentProcessor {
113 public:
LightingFP(sk_sp<GrFragmentProcessor> normalFP,sk_sp<SkLights> lights)114     LightingFP(sk_sp<GrFragmentProcessor> normalFP, sk_sp<SkLights> lights)
115             : INHERITED(kPreservesOpaqueInput_OptimizationFlag) {
116         // fuse all ambient lights into a single one
117         fAmbientColor = lights->ambientLightColor();
118         for (int i = 0; i < lights->numLights(); ++i) {
119             if (SkLights::Light::kDirectional_LightType == lights->light(i).type()) {
120                 fDirectionalLights.push_back(lights->light(i));
121                 // TODO get the handle to the shadow map if there is one
122             } else {
123                 SkDEBUGFAIL("Unimplemented Light Type passed to LightingFP");
124             }
125         }
126 
127         this->registerChildProcessor(std::move(normalFP));
128         this->initClassID<LightingFP>();
129     }
130 
131     class GLSLLightingFP : public GrGLSLFragmentProcessor {
132     public:
GLSLLightingFP()133         GLSLLightingFP() {
134             fAmbientColor.fX = 0.0f;
135         }
136 
emitCode(EmitArgs & args)137         void emitCode(EmitArgs& args) override {
138 
139             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
140             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
141             const LightingFP& lightingFP = args.fFp.cast<LightingFP>();
142 
143             const char *lightDirsUniName = nullptr;
144             const char *lightColorsUniName = nullptr;
145             if (lightingFP.fDirectionalLights.count() != 0) {
146                 fLightDirsUni = uniformHandler->addUniformArray(
147                         kFragment_GrShaderFlag,
148                         kVec3f_GrSLType,
149                         kDefault_GrSLPrecision,
150                         "LightDir",
151                         lightingFP.fDirectionalLights.count(),
152                         &lightDirsUniName);
153                 fLightColorsUni = uniformHandler->addUniformArray(
154                         kFragment_GrShaderFlag,
155                         kVec3f_GrSLType,
156                         kDefault_GrSLPrecision,
157                         "LightColor",
158                         lightingFP.fDirectionalLights.count(),
159                         &lightColorsUniName);
160             }
161 
162             const char* ambientColorUniName = nullptr;
163             fAmbientColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
164                                                           kVec3f_GrSLType, kDefault_GrSLPrecision,
165                                                           "AmbientColor", &ambientColorUniName);
166 
167             fragBuilder->codeAppendf("vec4 diffuseColor = %s;", args.fInputColor);
168 
169             SkString dstNormalName("dstNormal");
170             this->emitChild(0, nullptr, &dstNormalName, args);
171 
172             fragBuilder->codeAppendf("vec3 normal = %s.xyz;", dstNormalName.c_str());
173 
174             fragBuilder->codeAppend( "vec3 result = vec3(0.0);");
175 
176             // diffuse light
177             if (lightingFP.fDirectionalLights.count() != 0) {
178                 fragBuilder->codeAppendf("for (int i = 0; i < %d; i++) {",
179                                          lightingFP.fDirectionalLights.count());
180                 // TODO: modulate the contribution from each light based on the shadow map
181                 fragBuilder->codeAppendf("    float NdotL = clamp(dot(normal, %s[i]), 0.0, 1.0);",
182                                          lightDirsUniName);
183                 fragBuilder->codeAppendf("    result += %s[i]*diffuseColor.rgb*NdotL;",
184                                          lightColorsUniName);
185                 fragBuilder->codeAppend("}");
186             }
187 
188             // ambient light
189             fragBuilder->codeAppendf("result += %s * diffuseColor.rgb;", ambientColorUniName);
190 
191             // Clamping to alpha (equivalent to an unpremul'd clamp to 1.0)
192             fragBuilder->codeAppendf("%s = vec4(clamp(result.rgb, 0.0, diffuseColor.a), "
193                                                "diffuseColor.a);", args.fOutputColor);
194         }
195 
GenKey(const GrProcessor & proc,const GrShaderCaps &,GrProcessorKeyBuilder * b)196         static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
197             const LightingFP& lightingFP = proc.cast<LightingFP>();
198             b->add32(lightingFP.fDirectionalLights.count());
199         }
200 
201     protected:
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)202         void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
203             const LightingFP& lightingFP = proc.cast<LightingFP>();
204 
205             const SkTArray<SkLights::Light>& directionalLights = lightingFP.directionalLights();
206             if (directionalLights != fDirectionalLights) {
207                 SkTArray<SkColor3f> lightDirs(directionalLights.count());
208                 SkTArray<SkVector3> lightColors(directionalLights.count());
209                 for (const SkLights::Light& light : directionalLights) {
210                     lightDirs.push_back(light.dir());
211                     lightColors.push_back(light.color());
212                 }
213 
214                 pdman.set3fv(fLightDirsUni, directionalLights.count(), &(lightDirs[0].fX));
215                 pdman.set3fv(fLightColorsUni, directionalLights.count(), &(lightColors[0].fX));
216 
217                 fDirectionalLights = directionalLights;
218             }
219 
220             const SkColor3f& ambientColor = lightingFP.ambientColor();
221             if (ambientColor != fAmbientColor) {
222                 pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX);
223                 fAmbientColor = ambientColor;
224             }
225         }
226 
227     private:
228         SkTArray<SkLights::Light> fDirectionalLights;
229         GrGLSLProgramDataManager::UniformHandle fLightDirsUni;
230         GrGLSLProgramDataManager::UniformHandle fLightColorsUni;
231 
232         SkColor3f fAmbientColor;
233         GrGLSLProgramDataManager::UniformHandle fAmbientColorUni;
234     };
235 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const236     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
237         GLSLLightingFP::GenKey(*this, caps, b);
238     }
239 
name() const240     const char* name() const override { return "LightingFP"; }
241 
directionalLights() const242     const SkTArray<SkLights::Light>& directionalLights() const { return fDirectionalLights; }
ambientColor() const243     const SkColor3f& ambientColor() const { return fAmbientColor; }
244 
245 private:
onCreateGLSLInstance() const246     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; }
247 
onIsEqual(const GrFragmentProcessor & proc) const248     bool onIsEqual(const GrFragmentProcessor& proc) const override {
249         const LightingFP& lightingFP = proc.cast<LightingFP>();
250         return fDirectionalLights == lightingFP.fDirectionalLights &&
251                fAmbientColor == lightingFP.fAmbientColor;
252     }
253 
254     SkTArray<SkLights::Light> fDirectionalLights;
255     SkColor3f                 fAmbientColor;
256 
257     typedef GrFragmentProcessor INHERITED;
258 };
259 
260 ////////////////////////////////////////////////////////////////////////////
261 
asFragmentProcessor(const AsFPArgs & args) const262 sk_sp<GrFragmentProcessor> SkLightingShaderImpl::asFragmentProcessor(const AsFPArgs& args) const {
263     sk_sp<GrFragmentProcessor> normalFP(fNormalSource->asFragmentProcessor(args));
264     if (!normalFP) {
265         return nullptr;
266     }
267 
268     if (fDiffuseShader) {
269         sk_sp<GrFragmentProcessor> fpPipeline[] = {
270             fDiffuseShader->asFragmentProcessor(args),
271             sk_make_sp<LightingFP>(std::move(normalFP), fLights)
272         };
273         if(!fpPipeline[0]) {
274             return nullptr;
275         }
276 
277         sk_sp<GrFragmentProcessor> innerLightFP = GrFragmentProcessor::RunInSeries(fpPipeline, 2);
278         // FP is wrapped because paint's alpha needs to be applied to output
279         return GrFragmentProcessor::MulOutputByInputAlpha(std::move(innerLightFP));
280     } else {
281         // FP is wrapped because paint comes in unpremul'd to fragment shader, but LightingFP
282         // expects premul'd color.
283         return GrFragmentProcessor::PremulInput(sk_make_sp<LightingFP>(std::move(normalFP),
284                                                                        fLights));
285     }
286 }
287 
288 #endif
289 
290 ////////////////////////////////////////////////////////////////////////////
291 
isOpaque() const292 bool SkLightingShaderImpl::isOpaque() const {
293     return (fDiffuseShader ? fDiffuseShader->isOpaque() : false);
294 }
295 
LightingShaderContext(const SkLightingShaderImpl & shader,const ContextRec & rec,SkShader::Context * diffuseContext,SkNormalSource::Provider * normalProvider,void * heapAllocated)296 SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(
297         const SkLightingShaderImpl& shader, const ContextRec& rec,
298         SkShader::Context* diffuseContext, SkNormalSource::Provider* normalProvider,
299         void* heapAllocated)
300     : INHERITED(shader, rec)
301     , fDiffuseContext(diffuseContext)
302     , fNormalProvider(normalProvider) {
303     bool isOpaque = shader.isOpaque();
304 
305     // update fFlags
306     uint32_t flags = 0;
307     if (isOpaque && (255 == this->getPaintAlpha())) {
308         flags |= kOpaqueAlpha_Flag;
309     }
310 
311     fPaintColor = rec.fPaint->getColor();
312     fFlags = flags;
313 }
314 
convert(SkColor3f color,U8CPU a)315 static inline SkPMColor convert(SkColor3f color, U8CPU a) {
316     if (color.fX <= 0.0f) {
317         color.fX = 0.0f;
318     } else if (color.fX >= 255.0f) {
319         color.fX = 255.0f;
320     }
321 
322     if (color.fY <= 0.0f) {
323         color.fY = 0.0f;
324     } else if (color.fY >= 255.0f) {
325         color.fY = 255.0f;
326     }
327 
328     if (color.fZ <= 0.0f) {
329         color.fZ = 0.0f;
330     } else if (color.fZ >= 255.0f) {
331         color.fZ = 255.0f;
332     }
333 
334     return SkPreMultiplyARGB(a, (int) color.fX,  (int) color.fY, (int) color.fZ);
335 }
336 
337 // larger is better (fewer times we have to loop), but we shouldn't
338 // take up too much stack-space (each one here costs 16 bytes)
339 #define BUFFER_MAX 16
shadeSpan(int x,int y,SkPMColor result[],int count)340 void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y,
341                                                             SkPMColor result[], int count) {
342     const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShaderImpl&>(fShader);
343 
344     SkPMColor diffuse[BUFFER_MAX];
345     SkPoint3 normals[BUFFER_MAX];
346 
347     SkColor diffColor = fPaintColor;
348 
349     do {
350         int n = SkTMin(count, BUFFER_MAX);
351 
352         fNormalProvider->fillScanLine(x, y, normals, n);
353 
354         if (fDiffuseContext) {
355             fDiffuseContext->shadeSpan(x, y, diffuse, n);
356         }
357 
358         for (int i = 0; i < n; ++i) {
359             if (fDiffuseContext) {
360                 diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]);
361             }
362 
363             SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f);
364 
365             // Adding ambient light
366             accum.fX += lightShader.fLights->ambientLightColor().fX * SkColorGetR(diffColor);
367             accum.fY += lightShader.fLights->ambientLightColor().fY * SkColorGetG(diffColor);
368             accum.fZ += lightShader.fLights->ambientLightColor().fZ * SkColorGetB(diffColor);
369 
370             // This is all done in linear unpremul color space (each component 0..255.0f though)
371             for (int l = 0; l < lightShader.fLights->numLights(); ++l) {
372                 const SkLights::Light& light = lightShader.fLights->light(l);
373 
374                 SkScalar illuminanceScalingFactor = 1.0f;
375 
376                 if (SkLights::Light::kDirectional_LightType == light.type()) {
377                     illuminanceScalingFactor = normals[i].dot(light.dir());
378                     if (illuminanceScalingFactor < 0.0f) {
379                         illuminanceScalingFactor = 0.0f;
380                     }
381                 }
382 
383                 accum.fX += light.color().fX * SkColorGetR(diffColor) * illuminanceScalingFactor;
384                 accum.fY += light.color().fY * SkColorGetG(diffColor) * illuminanceScalingFactor;
385                 accum.fZ += light.color().fZ * SkColorGetB(diffColor) * illuminanceScalingFactor;
386             }
387 
388             // convert() premultiplies the accumulate color with alpha
389             result[i] = convert(accum, SkColorGetA(diffColor));
390         }
391 
392         result += n;
393         x += n;
394         count -= n;
395     } while (count > 0);
396 }
397 
398 ////////////////////////////////////////////////////////////////////////////
399 
400 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const401 void SkLightingShaderImpl::toString(SkString* str) const {
402     str->appendf("LightingShader: ()");
403 }
404 #endif
405 
CreateProc(SkReadBuffer & buf)406 sk_sp<SkFlattenable> SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) {
407 
408     // Discarding SkShader flattenable params
409     bool hasLocalMatrix = buf.readBool();
410     SkAssertResult(!hasLocalMatrix);
411 
412     sk_sp<SkLights> lights = SkLights::MakeFromBuffer(buf);
413 
414     sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>());
415 
416     bool hasDiffuse = buf.readBool();
417     sk_sp<SkShader> diffuseShader = nullptr;
418     if (hasDiffuse) {
419         diffuseShader = buf.readFlattenable<SkShader>();
420     }
421 
422     return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
423                                             std::move(lights));
424 }
425 
flatten(SkWriteBuffer & buf) const426 void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
427     this->INHERITED::flatten(buf);
428 
429     fLights->flatten(buf);
430 
431     buf.writeFlattenable(fNormalSource.get());
432     buf.writeBool(fDiffuseShader);
433     if (fDiffuseShader) {
434         buf.writeFlattenable(fDiffuseShader.get());
435     }
436 }
437 
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const438 SkShader::Context* SkLightingShaderImpl::onMakeContext(
439     const ContextRec& rec, SkArenaAlloc* alloc) const
440 {
441     SkShader::Context *diffuseContext = nullptr;
442     if (fDiffuseShader) {
443         diffuseContext = fDiffuseShader->makeContext(rec, alloc);
444         if (!diffuseContext) {
445             return nullptr;
446         }
447     }
448 
449     SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, alloc);
450     if (!normalProvider) {
451         return nullptr;
452     }
453 
454     return alloc->make<LightingShaderContext>(*this, rec, diffuseContext, normalProvider, nullptr);
455 }
456 
457 ///////////////////////////////////////////////////////////////////////////////
458 
Make(sk_sp<SkShader> diffuseShader,sk_sp<SkNormalSource> normalSource,sk_sp<SkLights> lights)459 sk_sp<SkShader> SkLightingShader::Make(sk_sp<SkShader> diffuseShader,
460                                        sk_sp<SkNormalSource> normalSource,
461                                        sk_sp<SkLights> lights) {
462     SkASSERT(lights);
463     if (!normalSource) {
464         normalSource = SkNormalSource::MakeFlat();
465     }
466 
467     return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
468                                             std::move(lights));
469 }
470 
471 ///////////////////////////////////////////////////////////////////////////////
472 
473 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader)
474     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingShaderImpl)
475 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
476 
477 ///////////////////////////////////////////////////////////////////////////////
478