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 */
38 class SkLightingShaderImpl : public SkShader {
39 public:
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 */
SkLightingShaderImpl(sk_sp<SkShader> diffuseShader,sk_sp<SkNormalSource> normalSource,sk_sp<SkLights> lights)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
getFlags() const69 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
83 protected:
84 void flatten(SkWriteBuffer&) const override;
85 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
86
87 private:
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.
112 class LightingFP : public GrFragmentProcessor {
113 public:
LightingFP(sk_sp<GrFragmentProcessor> normalFP,sk_sp<SkLights> lights)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:
GLSLLightingFP()133 GLSLLightingFP() {
134 fAmbientColor.fX = 0.0f;
135 }
136
emitCode(EmitArgs & args)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
GenKey(const GrProcessor & proc,const GrShaderCaps &,GrProcessorKeyBuilder * b)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:
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)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
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const236 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
237 GLSLLightingFP::GenKey(*this, caps, b);
238 }
239
name() const240 const char* name() const override { return "LightingFP"; }
241
directionalLights() const242 const SkTArray<SkLights::Light>& directionalLights() const { return fDirectionalLights; }
ambientColor() const243 const SkColor3f& ambientColor() const { return fAmbientColor; }
244
245 private:
onCreateGLSLInstance() const246 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; }
247
onIsEqual(const GrFragmentProcessor & proc) const248 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
asFragmentProcessor(const AsFPArgs & args) const262 sk_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
isOpaque() const292 bool SkLightingShaderImpl::isOpaque() const {
293 return (fDiffuseShader ? fDiffuseShader->isOpaque() : false);
294 }
295
LightingShaderContext(const SkLightingShaderImpl & shader,const ContextRec & rec,SkShader::Context * diffuseContext,SkNormalSource::Provider * normalProvider,void * heapAllocated)296 SkLightingShaderImpl::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
convert(SkColor3f color,U8CPU a)315 static 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
shadeSpan(int x,int y,SkPMColor result[],int count)340 void 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
toString(SkString * str) const401 void SkLightingShaderImpl::toString(SkString* str) const {
402 str->appendf("LightingShader: ()");
403 }
404 #endif
405
CreateProc(SkReadBuffer & buf)406 sk_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
flatten(SkWriteBuffer & buf) const426 void 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
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const438 SkShader::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
Make(sk_sp<SkShader> diffuseShader,sk_sp<SkNormalSource> normalSource,sk_sp<SkLights> lights)459 sk_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
473 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader)
474 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingShaderImpl)
475 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
476
477 ///////////////////////////////////////////////////////////////////////////////
478