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