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*/
38class SkLightingShaderImpl : public SkShader {
39public:
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    */
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
69        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
83protected:
84    void flatten(SkWriteBuffer&) const override;
85    Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
86
87private:
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.
112class LightingFP : public GrFragmentProcessor {
113public:
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:
133        GLSLLightingFP() {
134            fAmbientColor.fX = 0.0f;
135        }
136
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
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:
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
236    void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
237        GLSLLightingFP::GenKey(*this, caps, b);
238    }
239
240    const char* name() const override { return "LightingFP"; }
241
242    const SkTArray<SkLights::Light>& directionalLights() const { return fDirectionalLights; }
243    const SkColor3f& ambientColor() const { return fAmbientColor; }
244
245private:
246    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; }
247
248    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
262sk_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
292bool SkLightingShaderImpl::isOpaque() const {
293    return (fDiffuseShader ? fDiffuseShader->isOpaque() : false);
294}
295
296SkLightingShaderImpl::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
315static 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
340void 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
401void SkLightingShaderImpl::toString(SkString* str) const {
402    str->appendf("LightingShader: ()");
403}
404#endif
405
406sk_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
426void 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
438SkShader::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
459sk_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
473SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader)
474    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingShaderImpl)
475SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
476
477///////////////////////////////////////////////////////////////////////////////
478