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 */ 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 72 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: 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 125 const char* name() const override { return "LightingFP"; } 126 127 std::unique_ptr<GrFragmentProcessor> clone() const override { 128 return std::unique_ptr<GrFragmentProcessor>(new LightingFP(*this)); 129 } 130 131 const SkTArray<SkLights::Light>& directionalLights() const { return fDirectionalLights; } 132 const SkColor3f& ambientColor() const { return fAmbientColor; } 133 134 private: 135 class GLSLLightingFP : public GrGLSLFragmentProcessor { 136 public: 137 GLSLLightingFP() { 138 fAmbientColor.fX = 0.0f; 139 } 140 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 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: 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 241 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { 242 GLSLLightingFP::GenKey(*this, caps, b); 243 } 244 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 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 268 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; } 269 270 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 284 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 313 bool SkLightingShaderImpl::isOpaque() const { 314 return (fDiffuseShader ? fDiffuseShader->isOpaque() : false); 315 } 316 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 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 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 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 443 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 456 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 476 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 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 499 void SkLightingShader::RegisterFlattenables() { SK_REGISTER_FLATTENABLE(SkLightingShaderImpl); } 500