OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkBitmapProcShader.h" | 8 #include "SkBitmapProcShader.h" |
9 #include "SkBitmapProcState.h" | 9 #include "SkBitmapProcState.h" |
10 #include "SkColor.h" | 10 #include "SkColor.h" |
11 #include "SkEmptyShader.h" | 11 #include "SkEmptyShader.h" |
12 #include "SkErrorInternals.h" | 12 #include "SkErrorInternals.h" |
13 #include "SkLightingShader.h" | 13 #include "SkLightingShader.h" |
14 #include "SkMathPriv.h" | 14 #include "SkMathPriv.h" |
15 #include "SkNormalSource.h" | 15 #include "SkNormalSource.h" |
16 #include "SkPoint3.h" | 16 #include "SkPoint3.h" |
17 #include "SkReadBuffer.h" | 17 #include "SkReadBuffer.h" |
18 #include "SkWriteBuffer.h" | 18 #include "SkWriteBuffer.h" |
19 | 19 |
20 //////////////////////////////////////////////////////////////////////////// | 20 //////////////////////////////////////////////////////////////////////////// |
21 | 21 |
22 /* | 22 /* |
23 SkLightingShader TODOs: | 23 SkLightingShader TODOs: |
24 support other than clamp mode | |
25 allow 'diffuse' & 'normal' to be of different dimensions? | |
26 support different light types | 24 support different light types |
27 support multiple lights | 25 support multiple lights |
28 enforce normal map is 4 channel | 26 fix non-opaque diffuse textures |
29 use SkImages instead if SkBitmaps | |
30 | 27 |
31 To Test: | 28 To Test: |
32 non-opaque diffuse textures | |
33 A8 diffuse textures | 29 A8 diffuse textures |
34 down & upsampled draws | 30 down & upsampled draws |
35 */ | 31 */ |
36 | 32 |
37 | 33 |
38 | 34 |
39 /** \class SkLightingShaderImpl | 35 /** \class SkLightingShaderImpl |
40 This subclass of shader applies lighting. | 36 This subclass of shader applies lighting. |
41 */ | 37 */ |
42 class SkLightingShaderImpl : public SkShader { | 38 class SkLightingShaderImpl : public SkShader { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 | 70 |
75 ~LightingShaderContext() override; | 71 ~LightingShaderContext() override; |
76 | 72 |
77 void shadeSpan(int x, int y, SkPMColor[], int count) override; | 73 void shadeSpan(int x, int y, SkPMColor[], int count) override; |
78 | 74 |
79 uint32_t getFlags() const override { return fFlags; } | 75 uint32_t getFlags() const override { return fFlags; } |
80 | 76 |
81 private: | 77 private: |
82 SkShader::Context* fDiffuseContext; | 78 SkShader::Context* fDiffuseContext; |
83 SkNormalSource::Provider* fNormalProvider; | 79 SkNormalSource::Provider* fNormalProvider; |
80 SkColor fPaintColor; | |
84 uint32_t fFlags; | 81 uint32_t fFlags; |
85 | 82 |
86 void* fHeapAllocated; | 83 void* fHeapAllocated; |
87 | 84 |
88 typedef SkShader::Context INHERITED; | 85 typedef SkShader::Context INHERITED; |
89 }; | 86 }; |
90 | 87 |
91 SK_TO_STRING_OVERRIDE() | 88 SK_TO_STRING_OVERRIDE() |
92 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingShaderImpl) | 89 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingShaderImpl) |
93 | 90 |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 const SkMatrix* localMatrix , | 260 const SkMatrix* localMatrix , |
264 SkFilterQuality filterQuali ty, | 261 SkFilterQuality filterQuali ty, |
265 SkSourceGammaTreatment gamm aTreatment) const { | 262 SkSourceGammaTreatment gamm aTreatment) const { |
266 sk_sp<GrFragmentProcessor> normalFP( | 263 sk_sp<GrFragmentProcessor> normalFP( |
267 fNormalSource->asFragmentProcessor(context, viewM, localMatrix, filt erQuality, | 264 fNormalSource->asFragmentProcessor(context, viewM, localMatrix, filt erQuality, |
268 gammaTreatment)); | 265 gammaTreatment)); |
269 if (!normalFP) { | 266 if (!normalFP) { |
270 return nullptr; | 267 return nullptr; |
271 } | 268 } |
272 | 269 |
273 sk_sp<GrFragmentProcessor> fpPipeline[] = { | 270 if (fDiffuseShader) { |
274 fDiffuseShader->asFragmentProcessor(context, viewM, localMatrix, fil terQuality, | 271 sk_sp<GrFragmentProcessor> fpPipeline[] = { |
robertphillips
2016/07/11 14:02:04
this seems over tabbed
dvonbeck
2016/07/11 19:37:29
Done.
| |
275 gammaTreatment), | 272 fDiffuseShader->asFragmentProcessor(context, viewM, localMatrix, filterQuality, |
276 sk_make_sp<LightingFP>(std::move(normalFP), fLights) | 273 gammaTreatment), |
277 }; | 274 sk_make_sp<LightingFP>(std::move(normalFP), fLights) |
278 if(!fpPipeline[0]) { | 275 }; |
279 return nullptr; | 276 if(!fpPipeline[0]) { |
277 return nullptr; | |
278 } | |
279 | |
280 sk_sp<GrFragmentProcessor> innerLightFP = GrFragmentProcessor::RunInSeri es(fpPipeline, 2); | |
281 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(innerLightFP )); | |
282 } else { | |
283 return sk_make_sp<LightingFP>(std::move(normalFP), fLights); | |
egdaniel
2016/07/11 18:00:59
I think we still need to do the premul of alpha af
dvonbeck
2016/07/11 19:37:29
The alpha of the input color gets passed down to t
| |
280 } | 284 } |
281 | |
282 sk_sp<GrFragmentProcessor> inner(GrFragmentProcessor::RunInSeries(fpPipeline , 2)); | |
283 | |
284 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)); | |
285 } | 285 } |
286 | 286 |
287 #endif | 287 #endif |
288 | 288 |
289 //////////////////////////////////////////////////////////////////////////// | 289 //////////////////////////////////////////////////////////////////////////// |
290 | 290 |
291 bool SkLightingShaderImpl::isOpaque() const { | 291 bool SkLightingShaderImpl::isOpaque() const { |
robertphillips
2016/07/11 14:02:04
Hmmm, what happens if the paint's color is transpa
dvonbeck
2016/07/11 19:37:29
I don't know :S, we don't know the paint at shader
robertphillips
2016/07/11 20:51:42
We can't pull the alpha out of 'fPaintColor' ?
dvonbeck
2016/07/12 21:01:44
No, fPaintColor is a field of LightingShaderContex
| |
292 return fDiffuseShader->isOpaque(); | 292 return (fDiffuseShader ? fDiffuseShader->isOpaque() : true); |
293 } | 293 } |
294 | 294 |
295 SkLightingShaderImpl::LightingShaderContext::LightingShaderContext( | 295 SkLightingShaderImpl::LightingShaderContext::LightingShaderContext( |
296 const SkLightingShaderImpl& shader, const ContextRec& rec, | 296 const SkLightingShaderImpl& shader, const ContextRec& rec, |
297 SkShader::Context* diffuseContext, SkNormalSource::Provider* normalProvi der, | 297 SkShader::Context* diffuseContext, SkNormalSource::Provider* normalProvi der, |
298 void* heapAllocated) | 298 void* heapAllocated) |
299 : INHERITED(shader, rec) | 299 : INHERITED(shader, rec) |
300 , fDiffuseContext(diffuseContext) | 300 , fDiffuseContext(diffuseContext) |
301 , fNormalProvider(normalProvider) | 301 , fNormalProvider(normalProvider) |
302 , fHeapAllocated(heapAllocated) { | 302 , fHeapAllocated(heapAllocated) { |
303 bool isOpaque = shader.isOpaque(); | 303 bool isOpaque = shader.isOpaque(); |
304 | 304 |
305 // update fFlags | 305 // update fFlags |
306 uint32_t flags = 0; | 306 uint32_t flags = 0; |
307 if (isOpaque && (255 == this->getPaintAlpha())) { | 307 if (isOpaque && (255 == this->getPaintAlpha())) { |
308 flags |= kOpaqueAlpha_Flag; | 308 flags |= kOpaqueAlpha_Flag; |
309 } | 309 } |
310 | 310 |
311 fPaintColor = rec.fPaint->getColor(); | |
311 fFlags = flags; | 312 fFlags = flags; |
312 } | 313 } |
313 | 314 |
314 SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() { | 315 SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() { |
315 // The dependencies have been created outside of the context on memory that was allocated by | 316 // The dependencies have been created outside of the context on memory that was allocated by |
316 // the onCreateContext() method. Call the destructors and free the memory. | 317 // the onCreateContext() method. Call the destructors and free the memory. |
317 fDiffuseContext->~Context(); | 318 if (fDiffuseContext) { |
319 fDiffuseContext->~Context(); | |
320 } | |
318 fNormalProvider->~Provider(); | 321 fNormalProvider->~Provider(); |
319 | 322 |
320 sk_free(fHeapAllocated); | 323 sk_free(fHeapAllocated); |
321 } | 324 } |
322 | 325 |
323 static inline SkPMColor convert(SkColor3f color, U8CPU a) { | 326 static inline SkPMColor convert(SkColor3f color, U8CPU a) { |
324 if (color.fX <= 0.0f) { | 327 if (color.fX <= 0.0f) { |
325 color.fX = 0.0f; | 328 color.fX = 0.0f; |
326 } else if (color.fX >= 255.0f) { | 329 } else if (color.fX >= 255.0f) { |
327 color.fX = 255.0f; | 330 color.fX = 255.0f; |
(...skipping 17 matching lines...) Expand all Loading... | |
345 // larger is better (fewer times we have to loop), but we shouldn't | 348 // 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) | 349 // take up too much stack-space (each one here costs 16 bytes) |
347 #define BUFFER_MAX 16 | 350 #define BUFFER_MAX 16 |
348 void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y, | 351 void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y, |
349 SkPMColor result[], int count) { | 352 SkPMColor result[], int count) { |
350 const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShader Impl&>(fShader); | 353 const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShader Impl&>(fShader); |
351 | 354 |
352 SkPMColor diffuse[BUFFER_MAX]; | 355 SkPMColor diffuse[BUFFER_MAX]; |
353 SkPoint3 normals[BUFFER_MAX]; | 356 SkPoint3 normals[BUFFER_MAX]; |
354 | 357 |
358 SkColor diffColor = fPaintColor; | |
359 | |
355 do { | 360 do { |
356 int n = SkTMin(count, BUFFER_MAX); | 361 int n = SkTMin(count, BUFFER_MAX); |
357 | 362 |
358 fDiffuseContext->shadeSpan(x, y, diffuse, n); | |
359 fNormalProvider->fillScanLine(x, y, normals, n); | 363 fNormalProvider->fillScanLine(x, y, normals, n); |
360 | 364 |
365 if (fDiffuseContext) { | |
366 fDiffuseContext->shadeSpan(x, y, diffuse, n); | |
367 } | |
368 | |
361 for (int i = 0; i < n; ++i) { | 369 for (int i = 0; i < n; ++i) { |
362 | 370 if (fDiffuseContext) { |
363 SkColor diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]); | 371 diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]); |
372 } | |
364 | 373 |
365 SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f); | 374 SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f); |
366 // This is all done in linear unpremul color space (each component 0 ..255.0f though) | 375 // This is all done in linear unpremul color space (each component 0 ..255.0f though) |
367 for (int l = 0; l < lightShader.fLights->numLights(); ++l) { | 376 for (int l = 0; l < lightShader.fLights->numLights(); ++l) { |
368 const SkLights::Light& light = lightShader.fLights->light(l); | 377 const SkLights::Light& light = lightShader.fLights->light(l); |
369 | 378 |
370 if (SkLights::Light::kAmbient_LightType == light.type()) { | 379 if (SkLights::Light::kAmbient_LightType == light.type()) { |
371 accum += light.color().makeScale(255.0f); | 380 accum += light.color().makeScale(255.0f); |
372 } else { | 381 } else { |
373 SkScalar NdotL = normals[i].dot(light.dir()); | 382 SkScalar NdotL = normals[i].dot(light.dir()); |
374 if (NdotL < 0.0f) { | 383 if (NdotL < 0.0f) { |
375 NdotL = 0.0f; | 384 NdotL = 0.0f; |
376 } | 385 } |
377 | 386 |
378 accum.fX += light.color().fX * SkColorGetR(diffColor) * Ndot L; | 387 accum.fX += light.color().fX * SkColorGetR(diffColor) * Ndot L; |
379 accum.fY += light.color().fY * SkColorGetG(diffColor) * Ndot L; | 388 accum.fY += light.color().fY * SkColorGetG(diffColor) * Ndot L; |
380 accum.fZ += light.color().fZ * SkColorGetB(diffColor) * Ndot L; | 389 accum.fZ += light.color().fZ * SkColorGetB(diffColor) * Ndot L; |
381 } | 390 } |
382 } | 391 } |
383 | 392 |
384 result[i] = convert(accum, SkColorGetA(diffColor)); | 393 result[i] = convert(accum, SkColorGetA(diffColor)); |
egdaniel
2016/07/11 18:00:59
Add comment that convert also switches the result
dvonbeck
2016/07/11 19:37:29
Done.
| |
385 } | 394 } |
386 | 395 |
387 result += n; | 396 result += n; |
388 x += n; | 397 x += n; |
389 count -= n; | 398 count -= n; |
390 } while (count > 0); | 399 } while (count > 0); |
391 } | 400 } |
392 | 401 |
393 //////////////////////////////////////////////////////////////////////////// | 402 //////////////////////////////////////////////////////////////////////////// |
394 | 403 |
(...skipping 28 matching lines...) Expand all Loading... | |
423 if (!buf.readScalarArray(&dir.fX, 3)) { | 432 if (!buf.readScalarArray(&dir.fX, 3)) { |
424 return nullptr; | 433 return nullptr; |
425 } | 434 } |
426 builder.add(SkLights::Light(color, dir)); | 435 builder.add(SkLights::Light(color, dir)); |
427 } | 436 } |
428 } | 437 } |
429 | 438 |
430 sk_sp<SkLights> lights(builder.finish()); | 439 sk_sp<SkLights> lights(builder.finish()); |
431 | 440 |
432 sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>()); | 441 sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>()); |
433 sk_sp<SkShader> diffuseShader(buf.readFlattenable<SkShader>()); | 442 |
443 bool hasDiffuse = buf.readBool(); | |
444 sk_sp<SkShader> diffuseShader = nullptr; | |
445 if (hasDiffuse) { | |
446 diffuseShader = buf.readFlattenable<SkShader>(); | |
447 } | |
434 | 448 |
435 return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move( normalSource), | 449 return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move( normalSource), |
436 std::move(lights)); | 450 std::move(lights)); |
437 } | 451 } |
438 | 452 |
439 void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const { | 453 void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const { |
440 this->INHERITED::flatten(buf); | 454 this->INHERITED::flatten(buf); |
441 | 455 |
442 buf.writeInt(fLights->numLights()); | 456 buf.writeInt(fLights->numLights()); |
443 for (int l = 0; l < fLights->numLights(); ++l) { | 457 for (int l = 0; l < fLights->numLights(); ++l) { |
444 const SkLights::Light& light = fLights->light(l); | 458 const SkLights::Light& light = fLights->light(l); |
445 | 459 |
446 bool isAmbient = SkLights::Light::kAmbient_LightType == light.type(); | 460 bool isAmbient = SkLights::Light::kAmbient_LightType == light.type(); |
447 | 461 |
448 buf.writeBool(isAmbient); | 462 buf.writeBool(isAmbient); |
449 buf.writeScalarArray(&light.color().fX, 3); | 463 buf.writeScalarArray(&light.color().fX, 3); |
450 if (!isAmbient) { | 464 if (!isAmbient) { |
451 buf.writeScalarArray(&light.dir().fX, 3); | 465 buf.writeScalarArray(&light.dir().fX, 3); |
452 } | 466 } |
453 } | 467 } |
454 | 468 |
455 buf.writeFlattenable(fNormalSource.get()); | 469 buf.writeFlattenable(fNormalSource.get()); |
robertphillips
2016/07/11 14:02:04
Normally this would require a bump in the .skp ver
dvonbeck
2016/07/11 19:37:29
Acknowledged. It's changed quite a few times by no
| |
456 buf.writeFlattenable(fDiffuseShader.get()); | 470 buf.writeBool(fDiffuseShader); |
471 if (fDiffuseShader) { | |
472 buf.writeFlattenable(fDiffuseShader.get()); | |
473 } | |
457 } | 474 } |
458 | 475 |
459 size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const { | 476 size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const { |
460 return sizeof(LightingShaderContext); | 477 return sizeof(LightingShaderContext); |
461 } | 478 } |
462 | 479 |
463 SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, | 480 SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, |
464 void* storage) const { | 481 void* storage) const { |
465 size_t heapRequired = fDiffuseShader->contextSize(rec) + | 482 size_t heapRequired = (fDiffuseShader ? fDiffuseShader->contextSize(rec) : 0 ) + |
466 fNormalSource->providerSize(rec); | 483 fNormalSource->providerSize(rec); |
467 void* heapAllocated = sk_malloc_throw(heapRequired); | 484 void* heapAllocated = sk_malloc_throw(heapRequired); |
468 | 485 |
469 void* diffuseContextStorage = heapAllocated; | 486 void* diffuseContextStorage = heapAllocated; |
470 SkShader::Context* diffuseContext = fDiffuseShader->createContext(rec, diffu seContextStorage); | 487 void* normalProviderStorage = (char*) diffuseContextStorage + |
471 if (!diffuseContext) { | 488 (fDiffuseShader ? fDiffuseShader->contextSize( rec) : 0); |
472 sk_free(heapAllocated); | 489 |
473 return nullptr; | 490 SkShader::Context *diffuseContext = nullptr; |
491 if (fDiffuseShader) { | |
492 diffuseContext = fDiffuseShader->createContext(rec, diffuseContextStorag e); | |
493 if (!diffuseContext) { | |
494 sk_free(heapAllocated); | |
495 return nullptr; | |
496 } | |
474 } | 497 } |
475 | 498 |
476 void* normalProviderStorage = (char*)heapAllocated + fDiffuseShader->context Size(rec); | |
477 SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, | 499 SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, |
478 normalP roviderStorage); | 500 normalP roviderStorage); |
479 if (!normalProvider) { | 501 if (!normalProvider) { |
480 diffuseContext->~Context(); | 502 diffuseContext->~Context(); |
481 sk_free(heapAllocated); | 503 sk_free(heapAllocated); |
482 return nullptr; | 504 return nullptr; |
483 } | 505 } |
484 | 506 |
485 return new (storage) LightingShaderContext(*this, rec, diffuseContext, norma lProvider, | 507 return new (storage) LightingShaderContext(*this, rec, diffuseContext, norma lProvider, |
486 heapAllocated); | 508 heapAllocated); |
487 } | 509 } |
488 | 510 |
489 /////////////////////////////////////////////////////////////////////////////// | 511 /////////////////////////////////////////////////////////////////////////////// |
490 | 512 |
491 sk_sp<SkShader> SkLightingShader::Make(sk_sp<SkShader> diffuseShader, | 513 sk_sp<SkShader> SkLightingShader::Make(sk_sp<SkShader> diffuseShader, |
492 sk_sp<SkNormalSource> normalSource, | 514 sk_sp<SkNormalSource> normalSource, |
493 sk_sp<SkLights> lights) { | 515 sk_sp<SkLights> lights) { |
494 if (!diffuseShader || !normalSource) { | 516 if (!normalSource) { |
495 // TODO: Use paint's color in absence of a diffuseShader | 517 normalSource = SkNormalSource::MakeFlat(); |
496 // TODO: Use a default implementation of normalSource instead | |
497 return nullptr; | |
498 } | 518 } |
499 | 519 |
500 return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move( normalSource), | 520 return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move( normalSource), |
501 std::move(lights)); | 521 std::move(lights)); |
502 } | 522 } |
503 | 523 |
504 /////////////////////////////////////////////////////////////////////////////// | 524 /////////////////////////////////////////////////////////////////////////////// |
505 | 525 |
506 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader) | 526 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader) |
507 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingShaderImpl) | 527 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingShaderImpl) |
508 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 528 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
509 | 529 |
510 /////////////////////////////////////////////////////////////////////////////// | 530 /////////////////////////////////////////////////////////////////////////////// |
OLD | NEW |