| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 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 "SkColorPriv.h" | 8 #include "SkColorPriv.h" |
| 9 #include "SkColorSpace_Base.h" | 9 #include "SkColorSpace_Base.h" |
| 10 #include "SkColorSpaceXform.h" | 10 #include "SkColorSpaceXform.h" |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 v = v * 255.0f; | 257 v = v * 255.0f; |
| 258 if (v >= 254.5f) { | 258 if (v >= 254.5f) { |
| 259 return 255; | 259 return 255; |
| 260 } else if (v >= 0.5f) { | 260 } else if (v >= 0.5f) { |
| 261 return (uint8_t) (v + 0.5f); | 261 return (uint8_t) (v + 0.5f); |
| 262 } else { | 262 } else { |
| 263 return 0; | 263 return 0; |
| 264 } | 264 } |
| 265 } | 265 } |
| 266 | 266 |
| 267 static void build_table_linear_to_gamma(uint8_t* outTable, int outTableSize, flo
at exponent) { | 267 static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) { |
| 268 float toGammaExp = 1.0f / exponent; | 268 float toGammaExp = 1.0f / exponent; |
| 269 | 269 |
| 270 for (int i = 0; i < outTableSize; i++) { | 270 for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) { |
| 271 float x = ((float) i) * (1.0f / ((float) (outTableSize - 1))); | 271 float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTable
Size - 1))); |
| 272 outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp)); | 272 outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp)); |
| 273 } | 273 } |
| 274 } | 274 } |
| 275 | 275 |
| 276 // Inverse table lookup. Ex: what index corresponds to the input value? This w
ill | 276 // Inverse table lookup. Ex: what index corresponds to the input value? This w
ill |
| 277 // have strange results when the table is non-increasing. But any sane gamma | 277 // have strange results when the table is non-increasing. But any sane gamma |
| 278 // function will be increasing. | 278 // function will be increasing. |
| 279 static float inverse_interp_lut(float input, float* table, int tableSize) { | 279 static float inverse_interp_lut(float input, const float* table, int tableSize)
{ |
| 280 if (input <= table[0]) { | 280 if (input <= table[0]) { |
| 281 return table[0]; | 281 return table[0]; |
| 282 } else if (input >= table[tableSize - 1]) { | 282 } else if (input >= table[tableSize - 1]) { |
| 283 return 1.0f; | 283 return 1.0f; |
| 284 } | 284 } |
| 285 | 285 |
| 286 for (int i = 1; i < tableSize; i++) { | 286 for (int i = 1; i < tableSize; i++) { |
| 287 if (table[i] >= input) { | 287 if (table[i] >= input) { |
| 288 // We are guaranteed that input is greater than table[i - 1]. | 288 // We are guaranteed that input is greater than table[i - 1]. |
| 289 float diff = input - table[i - 1]; | 289 float diff = input - table[i - 1]; |
| 290 float distance = table[i] - table[i - 1]; | 290 float distance = table[i] - table[i - 1]; |
| 291 float index = (i - 1) + diff / distance; | 291 float index = (i - 1) + diff / distance; |
| 292 return index / (tableSize - 1); | 292 return index / (tableSize - 1); |
| 293 } | 293 } |
| 294 } | 294 } |
| 295 | 295 |
| 296 // Should be unreachable, since we'll return before the loop if input is | 296 // Should be unreachable, since we'll return before the loop if input is |
| 297 // larger than the last entry. | 297 // larger than the last entry. |
| 298 SkASSERT(false); | 298 SkASSERT(false); |
| 299 return 0.0f; | 299 return 0.0f; |
| 300 } | 300 } |
| 301 | 301 |
| 302 static void build_table_linear_to_gamma(uint8_t* outTable, int outTableSize, flo
at* inTable, | 302 static void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable, |
| 303 int inTableSize) { | 303 int inTableSize) { |
| 304 for (int i = 0; i < outTableSize; i++) { | 304 for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) { |
| 305 float x = ((float) i) * (1.0f / ((float) (outTableSize - 1))); | 305 float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTable
Size - 1))); |
| 306 float y = inverse_interp_lut(x, inTable, inTableSize); | 306 float y = inverse_interp_lut(x, inTable, inTableSize); |
| 307 outTable[i] = clamp_normalized_float_to_byte(y); | 307 outTable[i] = clamp_normalized_float_to_byte(y); |
| 308 } | 308 } |
| 309 } | 309 } |
| 310 | 310 |
| 311 static float inverse_parametric(float x, float g, float a, float b, float c, flo
at d, float e, | 311 static float inverse_parametric(float x, float g, float a, float b, float c, flo
at d, float e, |
| 312 float f) { | 312 float f) { |
| 313 // We need to take the inverse of the following piecewise function. | 313 // We need to take the inverse of the following piecewise function. |
| 314 // Y = (aX + b)^g + c for X >= d | 314 // Y = (aX + b)^g + c for X >= d |
| 315 // Y = eX + f otherwise | 315 // Y = eX + f otherwise |
| (...skipping 16 matching lines...) Expand all Loading... |
| 332 // X = ((Y - C)^(1 / G) - B) / A | 332 // X = ((Y - C)^(1 / G) - B) / A |
| 333 if (0.0f == a || 0.0f == g) { | 333 if (0.0f == a || 0.0f == g) { |
| 334 // The gamma curve for this segment is constant, so the inverse is undef
ined. | 334 // The gamma curve for this segment is constant, so the inverse is undef
ined. |
| 335 // Since this is the upper segment, guess one. | 335 // Since this is the upper segment, guess one. |
| 336 return 1.0f; | 336 return 1.0f; |
| 337 } | 337 } |
| 338 | 338 |
| 339 return (powf(x - c, 1.0f / g) - b) / a; | 339 return (powf(x - c, 1.0f / g) - b) / a; |
| 340 } | 340 } |
| 341 | 341 |
| 342 static void build_table_linear_to_gamma(uint8_t* outTable, int outTableSize, flo
at g, float a, | 342 static void build_table_linear_to_gamma(uint8_t* outTable, float g, float a, |
| 343 float b, float c, float d, float e, floa
t f) { | 343 float b, float c, float d, float e, floa
t f) { |
| 344 for (int i = 0; i < outTableSize; i++) { | 344 for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) { |
| 345 float x = ((float) i) * (1.0f / ((float) (outTableSize - 1))); | 345 float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTable
Size - 1))); |
| 346 float y = inverse_parametric(x, g, a, b, c, d, e, f); | 346 float y = inverse_parametric(x, g, a, b, c, d, e, f); |
| 347 outTable[i] = clamp_normalized_float_to_byte(y); | 347 outTable[i] = clamp_normalized_float_to_byte(y); |
| 348 } | 348 } |
| 349 } | 349 } |
| 350 | 350 |
| 351 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 351 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 352 | 352 |
| 353 template <typename T> |
| 354 struct GammaFns { |
| 355 const T* fSRGBTable; |
| 356 const T* f2Dot2Table; |
| 357 |
| 358 void (*fBuildFromValue)(T*, float); |
| 359 void (*fBuildFromTable)(T*, const float*, int); |
| 360 void (*fBuildFromParam)(T*, float, float, float, float, float, float, float)
; |
| 361 }; |
| 362 |
| 363 static const GammaFns<float> kToLinear { |
| 364 sk_linear_from_srgb, |
| 365 sk_linear_from_2dot2, |
| 366 &build_table_linear_from_gamma, |
| 367 &build_table_linear_from_gamma, |
| 368 &build_table_linear_from_gamma, |
| 369 }; |
| 370 |
| 371 static const GammaFns<uint8_t> kFromLinear { |
| 372 linear_to_srgb, |
| 373 linear_to_2dot2, |
| 374 &build_table_linear_to_gamma, |
| 375 &build_table_linear_to_gamma, |
| 376 &build_table_linear_to_gamma, |
| 377 }; |
| 378 |
| 379 // Build tables to transform src gamma to linear. |
| 380 template <typename T> |
| 381 static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage,
int gammaTableSize, |
| 382 const sk_sp<SkColorSpace>& space, const GammaFns<
T>& fns) { |
| 383 switch (space->gammaNamed()) { |
| 384 case SkColorSpace::kSRGB_GammaNamed: |
| 385 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRG
BTable; |
| 386 break; |
| 387 case SkColorSpace::k2Dot2Curve_GammaNamed: |
| 388 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Do
t2Table; |
| 389 break; |
| 390 case SkColorSpace::kLinear_GammaNamed: |
| 391 (*fns.fBuildFromValue)(gammaTableStorage, 1.0f); |
| 392 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = gammaTab
leStorage; |
| 393 break; |
| 394 default: { |
| 395 const SkGammas* gammas = as_CSB(space)->gammas(); |
| 396 SkASSERT(gammas); |
| 397 |
| 398 for (int i = 0; i < 3; i++) { |
| 399 if (i > 0) { |
| 400 // Check if this curve matches the first curve. In this cas
e, we can |
| 401 // share the same table pointer. This should almost always
be true. |
| 402 // I've never seen a profile where all three gamma curves di
dn't match. |
| 403 // But it is possible that they won't. |
| 404 if (gammas->data(0) == gammas->data(i)) { |
| 405 outGammaTables[i] = outGammaTables[0]; |
| 406 continue; |
| 407 } |
| 408 } |
| 409 |
| 410 if (gammas->isNamed(i)) { |
| 411 switch (gammas->data(i).fNamed) { |
| 412 case SkColorSpace::kSRGB_GammaNamed: |
| 413 outGammaTables[i] = fns.fSRGBTable; |
| 414 break; |
| 415 case SkColorSpace::k2Dot2Curve_GammaNamed: |
| 416 outGammaTables[i] = fns.f2Dot2Table; |
| 417 break; |
| 418 case SkColorSpace::kLinear_GammaNamed: |
| 419 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaT
ableSize], 1.0f); |
| 420 outGammaTables[i] = &gammaTableStorage[i * gammaTabl
eSize]; |
| 421 break; |
| 422 default: |
| 423 SkASSERT(false); |
| 424 break; |
| 425 } |
| 426 } else if (gammas->isValue(i)) { |
| 427 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize
], |
| 428 gammas->data(i).fValue); |
| 429 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; |
| 430 } else if (gammas->isTable(i)) { |
| 431 (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize
], gammas->table(i), |
| 432 gammas->data(i).fTable.fSize); |
| 433 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; |
| 434 } else { |
| 435 SkASSERT(gammas->isParametric(i)); |
| 436 const SkGammas::Params& params = gammas->params(i); |
| 437 (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize
], params.fG, |
| 438 params.fA, params.fB, params.fC, para
ms.fD, params.fE, |
| 439 params.fF); |
| 440 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; |
| 441 } |
| 442 } |
| 443 } |
| 444 } |
| 445 } |
| 446 |
| 447 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 448 |
| 353 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, | 449 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, |
| 354 const sk_sp<SkColorSpa
ce>& dstSpace) { | 450 const sk_sp<SkColorSpa
ce>& dstSpace) { |
| 355 if (!srcSpace || !dstSpace) { | 451 if (!srcSpace || !dstSpace) { |
| 356 // Invalid input | 452 // Invalid input |
| 357 return nullptr; | 453 return nullptr; |
| 358 } | 454 } |
| 359 | 455 |
| 360 if (as_CSB(dstSpace)->colorLUT()) { | 456 if (as_CSB(dstSpace)->colorLUT()) { |
| 361 // It would be really weird for a dst profile to have a color LUT. I do
n't think | 457 // It would be really weird for a dst profile to have a color LUT. I do
n't think |
| 362 // we need to support this. | 458 // we need to support this. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1); | 509 srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1); |
| 414 srcToDstArray[10] = srcToDstMatrix.getFloat(2, 2); | 510 srcToDstArray[10] = srcToDstMatrix.getFloat(2, 2); |
| 415 srcToDstArray[11] = 0.0f; | 511 srcToDstArray[11] = 0.0f; |
| 416 } | 512 } |
| 417 | 513 |
| 418 template <SkColorSpace::GammaNamed Dst> | 514 template <SkColorSpace::GammaNamed Dst> |
| 419 SkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatri
x44& srcToDst, | 515 SkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatri
x44& srcToDst, |
| 420 const sk_sp<SkColorSpace>& dstSpace) | 516 const sk_sp<SkColorSpace>& dstSpace) |
| 421 { | 517 { |
| 422 build_src_to_dst(fSrcToDst, srcToDst); | 518 build_src_to_dst(fSrcToDst, srcToDst); |
| 423 | 519 build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kT
oLinear); |
| 424 // Build tables to transform src gamma to linear. | 520 build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::k
DstGammaTableSize, |
| 425 switch (srcSpace->gammaNamed()) { | 521 dstSpace, kFromLinear); |
| 426 case SkColorSpace::kSRGB_GammaNamed: | |
| 427 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = sk_li
near_from_srgb; | |
| 428 break; | |
| 429 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
| 430 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = sk_li
near_from_2dot2; | |
| 431 break; | |
| 432 case SkColorSpace::kLinear_GammaNamed: | |
| 433 build_table_linear_from_gamma(fSrcGammaTableStorage, 1.0f); | |
| 434 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = fSrcG
ammaTableStorage; | |
| 435 break; | |
| 436 default: { | |
| 437 const SkGammas* gammas = as_CSB(srcSpace)->gammas(); | |
| 438 SkASSERT(gammas); | |
| 439 | |
| 440 for (int i = 0; i < 3; i++) { | |
| 441 const SkGammaCurve& curve = (*gammas)[i]; | |
| 442 | |
| 443 if (i > 0) { | |
| 444 // Check if this curve matches the first curve. In this cas
e, we can | |
| 445 // share the same table pointer. Logically, this should alm
ost always | |
| 446 // be true. I've never seen a profile where all three gamma
curves | |
| 447 // didn't match. But it is possible that they won't. | |
| 448 // TODO (msarett): | |
| 449 // This comparison won't catch the case where each gamma cur
ve has a | |
| 450 // pointer to its own look-up table, but the tables actually
match. | |
| 451 // Should we perform a deep compare of gamma tables here? O
r should | |
| 452 // we catch this when parsing the profile? Or should we not
worry | |
| 453 // about a bit of redundant work? | |
| 454 if (curve.quickEquals((*gammas)[0])) { | |
| 455 fSrcGammaTables[i] = fSrcGammaTables[0]; | |
| 456 continue; | |
| 457 } | |
| 458 } | |
| 459 | |
| 460 if (curve.isNamed()) { | |
| 461 switch (curve.fNamed) { | |
| 462 case SkColorSpace::kSRGB_GammaNamed: | |
| 463 fSrcGammaTables[i] = sk_linear_from_srgb; | |
| 464 break; | |
| 465 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
| 466 fSrcGammaTables[i] = sk_linear_from_2dot2; | |
| 467 break; | |
| 468 case SkColorSpace::kLinear_GammaNamed: | |
| 469 build_table_linear_from_gamma(&fSrcGammaTableStorage
[i * 256], 1.0f); | |
| 470 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]
; | |
| 471 break; | |
| 472 default: | |
| 473 SkASSERT(false); | |
| 474 break; | |
| 475 } | |
| 476 } else if (curve.isValue()) { | |
| 477 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], curve.fValue); | |
| 478 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
| 479 } else if (curve.isTable()) { | |
| 480 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], | |
| 481 curve.fTable.get(), curve.fTab
leSize); | |
| 482 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
| 483 } else { | |
| 484 SkASSERT(curve.isParametric()); | |
| 485 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], curve.fG, | |
| 486 curve.fA, curve.fB, curve.fC,
curve.fD, curve.fE, | |
| 487 curve.fF); | |
| 488 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
| 489 } | |
| 490 } | |
| 491 } | |
| 492 } | |
| 493 | |
| 494 // Build tables to transform linear to dst gamma. | |
| 495 // FIXME (msarett): | |
| 496 // Should we spend all of this time bulding the dst gamma tables when the cl
ient only | |
| 497 // wants to convert to F16? | |
| 498 switch (dstSpace->gammaNamed()) { | |
| 499 case SkColorSpace::kSRGB_GammaNamed: | |
| 500 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
| 501 break; | |
| 502 case SkColorSpace::kLinear_GammaNamed: | |
| 503 build_table_linear_to_gamma(fDstGammaTableStorage, kDstGammaTableSiz
e, 1.0f); | |
| 504 fDstGammaTables[0] = fDstGammaTables[1] = fDstGammaTables[2] = fDstG
ammaTableStorage; | |
| 505 break; | |
| 506 default: { | |
| 507 const SkGammas* gammas = as_CSB(dstSpace)->gammas(); | |
| 508 SkASSERT(gammas); | |
| 509 | |
| 510 for (int i = 0; i < 3; i++) { | |
| 511 const SkGammaCurve& curve = (*gammas)[i]; | |
| 512 | |
| 513 if (i > 0) { | |
| 514 // Check if this curve matches the first curve. In this cas
e, we can | |
| 515 // share the same table pointer. Logically, this should alm
ost always | |
| 516 // be true. I've never seen a profile where all three gamma
curves | |
| 517 // didn't match. But it is possible that they won't. | |
| 518 // TODO (msarett): | |
| 519 // This comparison won't catch the case where each gamma cur
ve has a | |
| 520 // pointer to its own look-up table (but the tables actually
match). | |
| 521 // Should we perform a deep compare of gamma tables here? O
r should | |
| 522 // we catch this when parsing the profile? Or should we not
worry | |
| 523 // about a bit of redundant work? | |
| 524 if (curve.quickEquals((*gammas)[0])) { | |
| 525 fDstGammaTables[i] = fDstGammaTables[0]; | |
| 526 continue; | |
| 527 } | |
| 528 } | |
| 529 | |
| 530 if (curve.isNamed()) { | |
| 531 switch (curve.fNamed) { | |
| 532 case SkColorSpace::kSRGB_GammaNamed: | |
| 533 fDstGammaTables[i] = linear_to_srgb; | |
| 534 break; | |
| 535 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
| 536 fDstGammaTables[i] = linear_to_2dot2; | |
| 537 break; | |
| 538 case SkColorSpace::kLinear_GammaNamed: | |
| 539 build_table_linear_to_gamma( | |
| 540 &fDstGammaTableStorage[i * kDstGammaTableSiz
e], | |
| 541 kDstGammaTableSize, 1.0f); | |
| 542 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDst
GammaTableSize]; | |
| 543 break; | |
| 544 default: | |
| 545 SkASSERT(false); | |
| 546 break; | |
| 547 } | |
| 548 } else if (curve.isValue()) { | |
| 549 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
| 550 kDstGammaTableSize, curve.fValue
); | |
| 551 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
| 552 } else if (curve.isTable()) { | |
| 553 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
| 554 kDstGammaTableSize, curve.fTable
.get(), | |
| 555 curve.fTableSize); | |
| 556 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
| 557 } else { | |
| 558 SkASSERT(curve.isParametric()); | |
| 559 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
| 560 kDstGammaTableSize, curve.fG, cu
rve.fA, curve.fB, | |
| 561 curve.fC, curve.fD, curve.fE, cu
rve.fF); | |
| 562 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
| 563 } | |
| 564 } | |
| 565 } | |
| 566 } | |
| 567 } | 522 } |
| 568 | 523 |
| 569 template <> | 524 template <> |
| 570 void SkFastXform<SkColorSpace::kSRGB_GammaNamed> | 525 void SkFastXform<SkColorSpace::kSRGB_GammaNamed> |
| 571 ::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const | 526 ::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const |
| 572 { | 527 { |
| 573 SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst); | 528 SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst); |
| 574 } | 529 } |
| 575 | 530 |
| 576 template <> | 531 template <> |
| (...skipping 17 matching lines...) Expand all Loading... |
| 594 SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst
); | 549 SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst
); |
| 595 } | 550 } |
| 596 | 551 |
| 597 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 552 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 598 | 553 |
| 599 SkDefaultXform::SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatr
ix44& srcToDst, | 554 SkDefaultXform::SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatr
ix44& srcToDst, |
| 600 const sk_sp<SkColorSpace>& dstSpace) | 555 const sk_sp<SkColorSpace>& dstSpace) |
| 601 : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) | 556 : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) |
| 602 , fSrcToDst(srcToDst) | 557 , fSrcToDst(srcToDst) |
| 603 { | 558 { |
| 604 // Build tables to transform src gamma to linear. | 559 build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kT
oLinear); |
| 605 switch (srcSpace->gammaNamed()) { | 560 build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::k
DstGammaTableSize, |
| 606 case SkColorSpace::kSRGB_GammaNamed: | 561 dstSpace, kFromLinear); |
| 607 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = sk_li
near_from_srgb; | |
| 608 break; | |
| 609 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
| 610 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = sk_li
near_from_2dot2; | |
| 611 break; | |
| 612 case SkColorSpace::kLinear_GammaNamed: | |
| 613 build_table_linear_from_gamma(fSrcGammaTableStorage, 1.0f); | |
| 614 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = fSrcG
ammaTableStorage; | |
| 615 break; | |
| 616 default: { | |
| 617 const SkGammas* gammas = as_CSB(srcSpace)->gammas(); | |
| 618 SkASSERT(gammas); | |
| 619 | |
| 620 for (int i = 0; i < 3; i++) { | |
| 621 const SkGammaCurve& curve = (*gammas)[i]; | |
| 622 | |
| 623 if (i > 0) { | |
| 624 // Check if this curve matches the first curve. In this cas
e, we can | |
| 625 // share the same table pointer. Logically, this should alm
ost always | |
| 626 // be true. I've never seen a profile where all three gamma
curves | |
| 627 // didn't match. But it is possible that they won't. | |
| 628 // TODO (msarett): | |
| 629 // This comparison won't catch the case where each gamma cur
ve has a | |
| 630 // pointer to its own look-up table, but the tables actually
match. | |
| 631 // Should we perform a deep compare of gamma tables here? O
r should | |
| 632 // we catch this when parsing the profile? Or should we not
worry | |
| 633 // about a bit of redundant work? | |
| 634 if (curve.quickEquals((*gammas)[0])) { | |
| 635 fSrcGammaTables[i] = fSrcGammaTables[0]; | |
| 636 continue; | |
| 637 } | |
| 638 } | |
| 639 | |
| 640 if (curve.isNamed()) { | |
| 641 switch (curve.fNamed) { | |
| 642 case SkColorSpace::kSRGB_GammaNamed: | |
| 643 fSrcGammaTables[i] = sk_linear_from_srgb; | |
| 644 break; | |
| 645 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
| 646 fSrcGammaTables[i] = sk_linear_from_2dot2; | |
| 647 break; | |
| 648 case SkColorSpace::kLinear_GammaNamed: | |
| 649 build_table_linear_from_gamma(&fSrcGammaTableStorage
[i * 256], 1.0f); | |
| 650 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]
; | |
| 651 break; | |
| 652 default: | |
| 653 SkASSERT(false); | |
| 654 break; | |
| 655 } | |
| 656 } else if (curve.isValue()) { | |
| 657 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], curve.fValue); | |
| 658 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
| 659 } else if (curve.isTable()) { | |
| 660 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], | |
| 661 curve.fTable.get(), curve.fTab
leSize); | |
| 662 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
| 663 } else { | |
| 664 SkASSERT(curve.isParametric()); | |
| 665 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], curve.fG, | |
| 666 curve.fA, curve.fB, curve.fC,
curve.fD, curve.fE, | |
| 667 curve.fF); | |
| 668 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
| 669 } | |
| 670 } | |
| 671 } | |
| 672 } | |
| 673 | |
| 674 // Build tables to transform linear to dst gamma. | |
| 675 switch (dstSpace->gammaNamed()) { | |
| 676 case SkColorSpace::kSRGB_GammaNamed: | |
| 677 fDstGammaTables[0] = fDstGammaTables[1] = fDstGammaTables[2] = linea
r_to_srgb; | |
| 678 break; | |
| 679 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
| 680 fDstGammaTables[0] = fDstGammaTables[1] = fDstGammaTables[2] = linea
r_to_2dot2; | |
| 681 break; | |
| 682 case SkColorSpace::kLinear_GammaNamed: | |
| 683 build_table_linear_to_gamma(fDstGammaTableStorage, kDstGammaTableSiz
e, 1.0f); | |
| 684 fDstGammaTables[0] = fDstGammaTables[1] = fDstGammaTables[2] = fDstG
ammaTableStorage; | |
| 685 break; | |
| 686 default: { | |
| 687 const SkGammas* gammas = as_CSB(dstSpace)->gammas(); | |
| 688 SkASSERT(gammas); | |
| 689 | |
| 690 for (int i = 0; i < 3; i++) { | |
| 691 const SkGammaCurve& curve = (*gammas)[i]; | |
| 692 | |
| 693 if (i > 0) { | |
| 694 // Check if this curve matches the first curve. In this cas
e, we can | |
| 695 // share the same table pointer. Logically, this should alm
ost always | |
| 696 // be true. I've never seen a profile where all three gamma
curves | |
| 697 // didn't match. But it is possible that they won't. | |
| 698 // TODO (msarett): | |
| 699 // This comparison won't catch the case where each gamma cur
ve has a | |
| 700 // pointer to its own look-up table (but the tables actually
match). | |
| 701 // Should we perform a deep compare of gamma tables here? O
r should | |
| 702 // we catch this when parsing the profile? Or should we not
worry | |
| 703 // about a bit of redundant work? | |
| 704 if (curve.quickEquals((*gammas)[0])) { | |
| 705 fDstGammaTables[i] = fDstGammaTables[0]; | |
| 706 continue; | |
| 707 } | |
| 708 } | |
| 709 | |
| 710 if (curve.isNamed()) { | |
| 711 switch (curve.fNamed) { | |
| 712 case SkColorSpace::kSRGB_GammaNamed: | |
| 713 fDstGammaTables[i] = linear_to_srgb; | |
| 714 break; | |
| 715 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
| 716 fDstGammaTables[i] = linear_to_2dot2; | |
| 717 break; | |
| 718 case SkColorSpace::kLinear_GammaNamed: | |
| 719 build_table_linear_to_gamma( | |
| 720 &fDstGammaTableStorage[i * kDstGammaTableSiz
e], | |
| 721 kDstGammaTableSize, 1.0f); | |
| 722 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDst
GammaTableSize]; | |
| 723 break; | |
| 724 default: | |
| 725 SkASSERT(false); | |
| 726 break; | |
| 727 } | |
| 728 } else if (curve.isValue()) { | |
| 729 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
| 730 kDstGammaTableSize, curve.fValue
); | |
| 731 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
| 732 } else if (curve.isTable()) { | |
| 733 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
| 734 kDstGammaTableSize, curve.fTable
.get(), | |
| 735 curve.fTableSize); | |
| 736 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
| 737 } else { | |
| 738 SkASSERT(curve.isParametric()); | |
| 739 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
| 740 kDstGammaTableSize, curve.fG, cu
rve.fA, curve.fB, | |
| 741 curve.fC, curve.fD, curve.fE, cu
rve.fF); | |
| 742 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
| 743 } | |
| 744 } | |
| 745 } | |
| 746 } | |
| 747 } | 562 } |
| 748 | 563 |
| 749 static float byte_to_float(uint8_t byte) { | 564 static float byte_to_float(uint8_t byte) { |
| 750 return ((float) byte) * (1.0f / 255.0f); | 565 return ((float) byte) * (1.0f / 255.0f); |
| 751 } | 566 } |
| 752 | 567 |
| 753 // Clamp to the 0-1 range. | 568 // Clamp to the 0-1 range. |
| 754 static float clamp_normalized_float(float v) { | 569 static float clamp_normalized_float(float v) { |
| 755 if (v > 1.0f) { | 570 if (v > 1.0f) { |
| 756 return 1.0f; | 571 return 1.0f; |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 dst++; | 722 dst++; |
| 908 src++; | 723 src++; |
| 909 } | 724 } |
| 910 } | 725 } |
| 911 | 726 |
| 912 void SkDefaultXform::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
{ | 727 void SkDefaultXform::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
{ |
| 913 // FIXME (msarett): | 728 // FIXME (msarett): |
| 914 // Planning to delete SkDefaultXform. Not going to bother to implement this
. | 729 // Planning to delete SkDefaultXform. Not going to bother to implement this
. |
| 915 memset(dst, 0, len * sizeof(RGBAF16)); | 730 memset(dst, 0, len * sizeof(RGBAF16)); |
| 916 } | 731 } |
| OLD | NEW |