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