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