Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(231)

Side by Side Diff: src/core/SkLightingShader.cpp

Issue 2132113002: SkLS accepts nullptr for pointer args, handles alpha accurately, has new GM (Closed) Base URL: https://skia.googlesource.com/skia@dvonbeck-diffuse-api-change
Patch Set: comment I forgot about diffuseshader nullptr Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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 ///////////////////////////////////////////////////////////////////////////////
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698