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