Approximate common gamma tables as single values

This should improve performance of gamma conversion in
software (we can use vector math instead of table look
ups).

Additionally this allows us to quickly and easily
identify sRGB-like gammas.

On gpu, identifying sRGB gamma improves performance/memory,
because the hardware may support gamma conversion.

This will help us identify situations where gamma
conversion is not necessary.
Ex: sRGB input -> sRGB display

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1950183006

Review-Url: https://codereview.chromium.org/1950183006
This commit is contained in:
msarett 2016-05-09 14:27:48 -07:00 committed by Commit bot
parent 05c987cee3
commit 2c3eca38c9
2 changed files with 31 additions and 6 deletions

View File

@ -324,13 +324,38 @@ bool SkColorSpace::LoadGammas(SkGammaCurve* gammas, uint32_t numGammas, const ui
// The table entry is the gamma (with a bias of 256).
uint16_t value = read_big_endian_short((const uint8_t*) table);
gammas[i].fValue = value / 256.0f;
SkColorSpacePrintf("gamma %d %g\n", value, *gamma);
SkColorSpacePrintf("gamma %d %g\n", value, gammas[i].fValue);
break;
}
// Fill in the interpolation table.
// FIXME (msarett):
// We should recognize commonly occurring tables and just set gamma to 2.2f.
// Check for frequently occurring curves and use a fast approximation.
// We do this by sampling a few values and see if they match our expectation.
// A more robust solution would be to compare each value in this curve against
// a 2.2f curve see if we remain below an error threshold. At this time,
// we haven't seen any images in the wild that make this kind of
// calculation necessary. We encounter identical gamma curves over and
// over again, but relatively few variations.
if (1024 == count) {
if (0 == read_big_endian_short((const uint8_t*) &table[0]) &&
3341 == read_big_endian_short((const uint8_t*) &table[256]) &&
14057 == read_big_endian_short((const uint8_t*) &table[512]) &&
34318 == read_big_endian_short((const uint8_t*) &table[768]) &&
65535 == read_big_endian_short((const uint8_t*) &table[1023])) {
gammas[i].fValue = 2.2f;
break;
}
} else if (26 == count) {
if (0 == read_big_endian_short((const uint8_t*) &table[0]) &&
3062 == read_big_endian_short((const uint8_t*) &table[6]) &&
12824 == read_big_endian_short((const uint8_t*) &table[12]) &&
31237 == read_big_endian_short((const uint8_t*) &table[18]) &&
65535 == read_big_endian_short((const uint8_t*) &table[25])) {
gammas[i].fValue = 2.2f;
break;
}
}
// Otherwise, fill in the interpolation table.
gammas[i].fTableSize = count;
gammas[i].fTable = std::unique_ptr<float[]>(new float[count]);
for (uint32_t j = 0; j < count; j++) {
@ -373,7 +398,7 @@ bool SkColorSpace::LoadGammas(SkGammaCurve* gammas, uint32_t numGammas, const ui
}
// Adjust src and len if there is another gamma curve to load.
if (0 != numGammas) {
if (i != numGammas - 1) {
// Each curve is padded to 4-byte alignment.
tagBytes = SkAlign4(tagBytes);
if (len < tagBytes) {

View File

@ -74,7 +74,7 @@ DEF_TEST(ColorSpaceParsePngICCProfile, r) {
const float red[] = { 0.436066f, 0.222488f, 0.013916f };
const float green[] = { 0.385147f, 0.716873f, 0.0970764f };
const float blue[] = { 0.143066f, 0.0606079f, 0.714096f };
const float gamma[] = { 0, 0, 0 }; // table-based gamma returns 0 from this its float-getter
const float gamma[] = { 2.2f, 2.2f, 2.2f };
test_space(r, colorSpace, red, green, blue, gamma);
#endif
}