| OLD | NEW |
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/color_transform.h" | 5 #include "ui/gfx/color_transform.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <list> | 9 #include <list> |
| 10 #include <memory> | 10 #include <memory> |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 #endif | 26 #endif |
| 27 | 27 |
| 28 using std::abs; | 28 using std::abs; |
| 29 using std::copysign; | 29 using std::copysign; |
| 30 using std::exp; | 30 using std::exp; |
| 31 using std::log; | 31 using std::log; |
| 32 using std::max; | 32 using std::max; |
| 33 using std::min; | 33 using std::min; |
| 34 using std::pow; | 34 using std::pow; |
| 35 using std::sqrt; | 35 using std::sqrt; |
| 36 using std::endl; |
| 36 | 37 |
| 37 namespace gfx { | 38 namespace gfx { |
| 38 | 39 |
| 39 namespace { | 40 namespace { |
| 40 | 41 |
| 41 void InitStringStream(std::stringstream* ss) { | 42 void InitStringStream(std::stringstream* ss) { |
| 42 ss->imbue(std::locale::classic()); | 43 ss->imbue(std::locale::classic()); |
| 43 ss->precision(8); | 44 ss->precision(8); |
| 44 *ss << std::scientific; | 45 *ss << std::scientific; |
| 45 } | 46 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 return 1.0f + log(v) / log(10.0f) / 2.0f; | 82 return 1.0f + log(v) / log(10.0f) / 2.0f; |
| 82 | 83 |
| 83 case ColorSpace::TransferID::LOG_SQRT: | 84 case ColorSpace::TransferID::LOG_SQRT: |
| 84 if (v < sqrt(10.0f) / 1000.0f) | 85 if (v < sqrt(10.0f) / 1000.0f) |
| 85 return 0.0f; | 86 return 0.0f; |
| 86 return 1.0f + log(v) / log(10.0f) / 2.5f; | 87 return 1.0f + log(v) / log(10.0f) / 2.5f; |
| 87 | 88 |
| 88 case ColorSpace::TransferID::IEC61966_2_4: { | 89 case ColorSpace::TransferID::IEC61966_2_4: { |
| 89 float a = 1.099296826809442f; | 90 float a = 1.099296826809442f; |
| 90 float b = 0.018053968510807f; | 91 float b = 0.018053968510807f; |
| 91 if (v < -b) { | 92 if (v < -b) |
| 92 return -a * pow(-v, 0.45f) + (a - 1.0f); | 93 return -a * pow(-v, 0.45f) + (a - 1.0f); |
| 93 } else if (v <= b) { | 94 else if (v <= b) |
| 94 return 4.5f * v; | 95 return 4.5f * v; |
| 95 } else { | 96 return a * pow(v, 0.45f) - (a - 1.0f); |
| 96 return a * pow(v, 0.45f) - (a - 1.0f); | |
| 97 } | |
| 98 } | 97 } |
| 99 | 98 |
| 100 case ColorSpace::TransferID::BT1361_ECG: { | 99 case ColorSpace::TransferID::BT1361_ECG: { |
| 101 float a = 1.099f; | 100 float a = 1.099f; |
| 102 float b = 0.018f; | 101 float b = 0.018f; |
| 103 float l = 0.0045f; | 102 float l = 0.0045f; |
| 104 if (v < -l) { | 103 if (v < -l) |
| 105 return -(a * pow(-4.0f * v, 0.45f) + (a - 1.0f)) / 4.0f; | 104 return -(a * pow(-4.0f * v, 0.45f) + (a - 1.0f)) / 4.0f; |
| 106 } else if (v <= b) { | 105 else if (v <= b) |
| 107 return 4.5f * v; | 106 return 4.5f * v; |
| 108 } else { | 107 else |
| 109 return a * pow(v, 0.45f) - (a - 1.0f); | 108 return a * pow(v, 0.45f) - (a - 1.0f); |
| 110 } | |
| 111 } | 109 } |
| 112 | 110 |
| 113 case ColorSpace::TransferID::SMPTEST2084: { | 111 case ColorSpace::TransferID::SMPTEST2084: { |
| 114 // Go from scRGB levels to 0-1. | 112 // Go from scRGB levels to 0-1. |
| 115 v *= 80.0f / 10000.0f; | 113 v *= 80.0f / 10000.0f; |
| 116 v = max(0.0f, v); | 114 v = max(0.0f, v); |
| 117 float m1 = (2610.0f / 4096.0f) / 4.0f; | 115 float m1 = (2610.0f / 4096.0f) / 4.0f; |
| 118 float m2 = (2523.0f / 4096.0f) * 128.0f; | 116 float m2 = (2523.0f / 4096.0f) * 128.0f; |
| 119 float c1 = 3424.0f / 4096.0f; | 117 float c1 = 3424.0f / 4096.0f; |
| 120 float c2 = (2413.0f / 4096.0f) * 32.0f; | 118 float c2 = (2413.0f / 4096.0f) * 32.0f; |
| 121 float c3 = (2392.0f / 4096.0f) * 32.0f; | 119 float c3 = (2392.0f / 4096.0f) * 32.0f; |
| 122 return pow((c1 + c2 * pow(v, m1)) / (1.0f + c3 * pow(v, m1)), m2); | 120 return pow((c1 + c2 * pow(v, m1)) / (1.0f + c3 * pow(v, m1)), m2); |
| 123 } | 121 } |
| 124 | 122 |
| 125 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf | 123 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf |
| 126 case ColorSpace::TransferID::ARIB_STD_B67: { | 124 case ColorSpace::TransferID::ARIB_STD_B67: { |
| 127 const float a = 0.17883277f; | 125 const float a = 0.17883277f; |
| 128 const float b = 0.28466892f; | 126 const float b = 0.28466892f; |
| 129 const float c = 0.55991073f; | 127 const float c = 0.55991073f; |
| 130 v = max(0.0f, v); | 128 v = max(0.0f, v); |
| 131 if (v <= 1) | 129 if (v <= 1) |
| 132 return 0.5f * sqrt(v); | 130 return 0.5f * sqrt(v); |
| 133 else | 131 return a * log(v - b) + c; |
| 134 return a * log(v - b) + c; | |
| 135 } | 132 } |
| 136 | 133 |
| 137 default: | 134 default: |
| 138 // Handled by SkColorSpaceTransferFn. | 135 // Handled by SkColorSpaceTransferFn. |
| 139 break; | 136 break; |
| 140 } | 137 } |
| 141 NOTREACHED(); | 138 NOTREACHED(); |
| 142 return 0; | 139 return 0; |
| 143 } | 140 } |
| 144 | 141 |
| 145 float ToLinear(ColorSpace::TransferID id, float v) { | 142 float ToLinear(ColorSpace::TransferID id, float v) { |
| 146 switch (id) { | 143 switch (id) { |
| 147 case ColorSpace::TransferID::LOG: | 144 case ColorSpace::TransferID::LOG: |
| 148 if (v < 0.0f) | 145 if (v < 0.0f) |
| 149 return 0.0f; | 146 return 0.0f; |
| 150 return pow(10.0f, (v - 1.0f) * 2.0f); | 147 return pow(10.0f, (v - 1.0f) * 2.0f); |
| 151 | 148 |
| 152 case ColorSpace::TransferID::LOG_SQRT: | 149 case ColorSpace::TransferID::LOG_SQRT: |
| 153 if (v < 0.0f) | 150 if (v < 0.0f) |
| 154 return 0.0f; | 151 return 0.0f; |
| 155 return pow(10.0f, (v - 1.0f) * 2.5f); | 152 return pow(10.0f, (v - 1.0f) * 2.5f); |
| 156 | 153 |
| 157 case ColorSpace::TransferID::IEC61966_2_4: { | 154 case ColorSpace::TransferID::IEC61966_2_4: { |
| 158 float a = 1.099296826809442f; | 155 float a = 1.099296826809442f; |
| 159 float b = 0.018053968510807f; | 156 // Equal to FromLinear(ColorSpace::TransferID::IEC61966_2_4, -a). |
| 160 if (v < FromLinear(ColorSpace::TransferID::IEC61966_2_4, -a)) { | 157 float from_linear_neg_a = -1.047844f; |
| 158 // Equal to FromLinear(ColorSpace::TransferID::IEC61966_2_4, b). |
| 159 float from_linear_b = 0.081243f; |
| 160 if (v < from_linear_neg_a) |
| 161 return -pow((a - 1.0f - v) / a, 1.0f / 0.45f); | 161 return -pow((a - 1.0f - v) / a, 1.0f / 0.45f); |
| 162 } else if (v <= FromLinear(ColorSpace::TransferID::IEC61966_2_4, b)) { | 162 else if (v <= from_linear_b) |
| 163 return v / 4.5f; | 163 return v / 4.5f; |
| 164 } else { | 164 return pow((v + a - 1.0f) / a, 1.0f / 0.45f); |
| 165 return pow((v + a - 1.0f) / a, 1.0f / 0.45f); | |
| 166 } | |
| 167 } | 165 } |
| 168 | 166 |
| 169 case ColorSpace::TransferID::BT1361_ECG: { | 167 case ColorSpace::TransferID::BT1361_ECG: { |
| 170 float a = 1.099f; | 168 float a = 1.099f; |
| 171 float b = 0.018f; | 169 // Equal to FromLinear(ColorSpace::TransferID::BT1361_ECG, -l). |
| 172 float l = 0.0045f; | 170 float from_linear_neg_l = -0.020250f; |
| 173 if (v < FromLinear(ColorSpace::TransferID::BT1361_ECG, -l)) { | 171 // Equal to FromLinear(ColorSpace::TransferID::BT1361_ECG, b). |
| 172 float from_linear_b = 0.081000f; |
| 173 if (v < from_linear_neg_l) |
| 174 return -pow((1.0f - a - v * 4.0f) / a, 1.0f / 0.45f) / 4.0f; | 174 return -pow((1.0f - a - v * 4.0f) / a, 1.0f / 0.45f) / 4.0f; |
| 175 } else if (v <= FromLinear(ColorSpace::TransferID::BT1361_ECG, b)) { | 175 else if (v <= from_linear_b) |
| 176 return v / 4.5f; | 176 return v / 4.5f; |
| 177 } else { | 177 return pow((v + a - 1.0f) / a, 1.0f / 0.45f); |
| 178 return pow((v + a - 1.0f) / a, 1.0f / 0.45f); | |
| 179 } | |
| 180 } | 178 } |
| 181 | 179 |
| 182 case ColorSpace::TransferID::SMPTEST2084: { | 180 case ColorSpace::TransferID::SMPTEST2084: { |
| 183 v = max(0.0f, v); | 181 v = max(0.0f, v); |
| 184 float m1 = (2610.0f / 4096.0f) / 4.0f; | 182 float m1 = (2610.0f / 4096.0f) / 4.0f; |
| 185 float m2 = (2523.0f / 4096.0f) * 128.0f; | 183 float m2 = (2523.0f / 4096.0f) * 128.0f; |
| 186 float c1 = 3424.0f / 4096.0f; | 184 float c1 = 3424.0f / 4096.0f; |
| 187 float c2 = (2413.0f / 4096.0f) * 32.0f; | 185 float c2 = (2413.0f / 4096.0f) * 32.0f; |
| 188 float c3 = (2392.0f / 4096.0f) * 32.0f; | 186 float c3 = (2392.0f / 4096.0f) * 32.0f; |
| 189 v = pow(max(pow(v, 1.0f / m2) - c1, 0.0f) / (c2 - c3 * pow(v, 1.0f / m2)), | 187 v = pow(max(pow(v, 1.0f / m2) - c1, 0.0f) / (c2 - c3 * pow(v, 1.0f / m2)), |
| 190 1.0f / m1); | 188 1.0f / m1); |
| 191 // This matches the scRGB definition that 1.0 means 80 nits. | 189 // This matches the scRGB definition that 1.0 means 80 nits. |
| 192 // TODO(hubbe): It would be *nice* if 1.0 meant more than that, but | 190 // TODO(hubbe): It would be *nice* if 1.0 meant more than that, but |
| 193 // that might be difficult to do right now. | 191 // that might be difficult to do right now. |
| 194 v *= 10000.0f / 80.0f; | 192 v *= 10000.0f / 80.0f; |
| 195 return v; | 193 return v; |
| 196 } | 194 } |
| 197 | 195 |
| 198 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: | 196 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: |
| 199 v = max(0.0f, v); | 197 v = max(0.0f, v); |
| 200 return min(2.3f * pow(v, 2.8f), v / 5.0f + 0.8f); | 198 return min(2.3f * pow(v, 2.8f), v / 5.0f + 0.8f); |
| 201 | 199 |
| 202 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf | 200 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf |
| 203 case ColorSpace::TransferID::ARIB_STD_B67: { | 201 case ColorSpace::TransferID::ARIB_STD_B67: { |
| 204 v = max(0.0f, v); | 202 v = max(0.0f, v); |
| 205 const float a = 0.17883277f; | 203 const float a = 0.17883277f; |
| 206 const float b = 0.28466892f; | 204 const float b = 0.28466892f; |
| 207 const float c = 0.55991073f; | 205 const float c = 0.55991073f; |
| 208 float v_ = 0.0f; | 206 if (v <= 0.5f) |
| 209 if (v <= 0.5f) { | 207 return (v * 2.0f) * (v * 2.0f); |
| 210 v_ = (v * 2.0f) * (v * 2.0f); | 208 return exp((v - c) / a) + b; |
| 211 } else { | |
| 212 v_ = exp((v - c) / a) + b; | |
| 213 } | |
| 214 return v_; | |
| 215 } | 209 } |
| 216 | 210 |
| 217 default: | 211 default: |
| 218 // Handled by SkColorSpaceTransferFn. | 212 // Handled by SkColorSpaceTransferFn. |
| 219 break; | 213 break; |
| 220 } | 214 } |
| 221 NOTREACHED(); | 215 NOTREACHED(); |
| 222 return 0; | 216 return 0; |
| 223 } | 217 } |
| 224 | 218 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 | 258 |
| 265 // Join methods, returns true if the |next| transform was successfully | 259 // Join methods, returns true if the |next| transform was successfully |
| 266 // assimilated into |this|. | 260 // assimilated into |this|. |
| 267 // If Join() returns true, |next| is no longer needed and can be deleted. | 261 // If Join() returns true, |next| is no longer needed and can be deleted. |
| 268 virtual bool Join(ColorTransformStep* next) { return false; } | 262 virtual bool Join(ColorTransformStep* next) { return false; } |
| 269 | 263 |
| 270 // Return true if this is a null transform. | 264 // Return true if this is a null transform. |
| 271 virtual bool IsNull() { return false; } | 265 virtual bool IsNull() { return false; } |
| 272 virtual void Transform(ColorTransform::TriStim* color, size_t num) const = 0; | 266 virtual void Transform(ColorTransform::TriStim* color, size_t num) const = 0; |
| 273 virtual bool CanAppendShaderSource() { return false; } | 267 virtual bool CanAppendShaderSource() { return false; } |
| 274 virtual void AppendShaderSource(std::stringstream* result) { NOTREACHED(); } | 268 // In the shader, |hdr| will appear before |src|, so any helper functions that |
| 269 // are created should be put in |hdr|. Any helper functions should have |
| 270 // |step_index| included in the function name, to ensure that there are no |
| 271 // naming conflicts. |
| 272 virtual void AppendShaderSource(std::stringstream* hdr, |
| 273 std::stringstream* src, |
| 274 size_t step_index) const { |
| 275 NOTREACHED(); |
| 276 } |
| 275 | 277 |
| 276 private: | 278 private: |
| 277 DISALLOW_COPY_AND_ASSIGN(ColorTransformStep); | 279 DISALLOW_COPY_AND_ASSIGN(ColorTransformStep); |
| 278 }; | 280 }; |
| 279 | 281 |
| 280 class ColorTransformInternal : public ColorTransform { | 282 class ColorTransformInternal : public ColorTransform { |
| 281 public: | 283 public: |
| 282 ColorTransformInternal(const ColorSpace& from, | 284 ColorTransformInternal(const ColorSpace& from, |
| 283 const ColorSpace& to, | 285 const ColorSpace& to, |
| 284 Intent intent); | 286 Intent intent); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 311 gfx::ColorSpace src_; | 313 gfx::ColorSpace src_; |
| 312 gfx::ColorSpace dst_; | 314 gfx::ColorSpace dst_; |
| 313 }; | 315 }; |
| 314 | 316 |
| 315 class ColorTransformNull : public ColorTransformStep { | 317 class ColorTransformNull : public ColorTransformStep { |
| 316 public: | 318 public: |
| 317 ColorTransformNull* GetNull() override { return this; } | 319 ColorTransformNull* GetNull() override { return this; } |
| 318 bool IsNull() override { return true; } | 320 bool IsNull() override { return true; } |
| 319 void Transform(ColorTransform::TriStim* color, size_t num) const override {} | 321 void Transform(ColorTransform::TriStim* color, size_t num) const override {} |
| 320 bool CanAppendShaderSource() override { return true; } | 322 bool CanAppendShaderSource() override { return true; } |
| 321 void AppendShaderSource(std::stringstream* result) override {} | 323 void AppendShaderSource(std::stringstream* hdr, |
| 324 std::stringstream* src, |
| 325 size_t step_index) const override {} |
| 322 }; | 326 }; |
| 323 | 327 |
| 324 class ColorTransformMatrix : public ColorTransformStep { | 328 class ColorTransformMatrix : public ColorTransformStep { |
| 325 public: | 329 public: |
| 326 explicit ColorTransformMatrix(const class Transform& matrix) | 330 explicit ColorTransformMatrix(const class Transform& matrix) |
| 327 : matrix_(matrix) {} | 331 : matrix_(matrix) {} |
| 328 ColorTransformMatrix* GetMatrix() override { return this; } | 332 ColorTransformMatrix* GetMatrix() override { return this; } |
| 329 bool Join(ColorTransformStep* next_untyped) override { | 333 bool Join(ColorTransformStep* next_untyped) override { |
| 330 ColorTransformMatrix* next = next_untyped->GetMatrix(); | 334 ColorTransformMatrix* next = next_untyped->GetMatrix(); |
| 331 if (!next) | 335 if (!next) |
| 332 return false; | 336 return false; |
| 333 class Transform tmp = next->matrix_; | 337 class Transform tmp = next->matrix_; |
| 334 tmp *= matrix_; | 338 tmp *= matrix_; |
| 335 matrix_ = tmp; | 339 matrix_ = tmp; |
| 336 return true; | 340 return true; |
| 337 } | 341 } |
| 338 | 342 |
| 339 bool IsNull() override { | 343 bool IsNull() override { |
| 340 return SkMatrixIsApproximatelyIdentity(matrix_.matrix()); | 344 return SkMatrixIsApproximatelyIdentity(matrix_.matrix()); |
| 341 } | 345 } |
| 342 | 346 |
| 343 void Transform(ColorTransform::TriStim* colors, size_t num) const override { | 347 void Transform(ColorTransform::TriStim* colors, size_t num) const override { |
| 344 for (size_t i = 0; i < num; i++) | 348 for (size_t i = 0; i < num; i++) |
| 345 matrix_.TransformPoint(colors + i); | 349 matrix_.TransformPoint(colors + i); |
| 346 } | 350 } |
| 347 | 351 |
| 348 bool CanAppendShaderSource() override { return true; } | 352 bool CanAppendShaderSource() override { return true; } |
| 349 | 353 |
| 350 void AppendShaderSource(std::stringstream* result) override { | 354 void AppendShaderSource(std::stringstream* hdr, |
| 355 std::stringstream* src, |
| 356 size_t step_index) const override { |
| 351 const SkMatrix44& m = matrix_.matrix(); | 357 const SkMatrix44& m = matrix_.matrix(); |
| 352 *result << " color = mat3("; | 358 *src << " color = mat3("; |
| 353 *result << m.get(0, 0) << ", " << m.get(1, 0) << ", " << m.get(2, 0) << ","; | 359 *src << m.get(0, 0) << ", " << m.get(1, 0) << ", " << m.get(2, 0) << ","; |
| 354 *result << std::endl; | 360 *src << endl; |
| 355 *result << " "; | 361 *src << " "; |
| 356 *result << m.get(0, 1) << ", " << m.get(1, 1) << ", " << m.get(2, 1) << ","; | 362 *src << m.get(0, 1) << ", " << m.get(1, 1) << ", " << m.get(2, 1) << ","; |
| 357 *result << std::endl; | 363 *src << endl; |
| 358 *result << " "; | 364 *src << " "; |
| 359 *result << m.get(0, 2) << ", " << m.get(1, 2) << ", " << m.get(2, 2) << ")"; | 365 *src << m.get(0, 2) << ", " << m.get(1, 2) << ", " << m.get(2, 2) << ")"; |
| 360 *result << " * color;" << std::endl; | 366 *src << " * color;" << endl; |
| 361 | 367 |
| 362 // Only print the translational component if it isn't the identity. | 368 // Only print the translational component if it isn't the identity. |
| 363 if (m.get(0, 3) != 0.f || m.get(1, 3) != 0.f || m.get(2, 3) != 0.f) { | 369 if (m.get(0, 3) != 0.f || m.get(1, 3) != 0.f || m.get(2, 3) != 0.f) { |
| 364 *result << " color += vec3("; | 370 *src << " color += vec3("; |
| 365 *result << m.get(0, 3) << ", " << m.get(1, 3) << ", " << m.get(2, 3); | 371 *src << m.get(0, 3) << ", " << m.get(1, 3) << ", " << m.get(2, 3); |
| 366 *result << ");" << std::endl; | 372 *src << ");" << endl; |
| 367 } | 373 } |
| 368 } | 374 } |
| 369 | 375 |
| 370 private: | 376 private: |
| 371 class Transform matrix_; | 377 class Transform matrix_; |
| 372 }; | 378 }; |
| 373 | 379 |
| 374 class ColorTransformSkTransferFn : public ColorTransformStep { | 380 class ColorTransformPerChannelTransferFn : public ColorTransformStep { |
| 381 public: |
| 382 explicit ColorTransformPerChannelTransferFn(bool extended) |
| 383 : extended_(extended) {} |
| 384 |
| 385 void Transform(ColorTransform::TriStim* colors, size_t num) const override { |
| 386 for (size_t i = 0; i < num; i++) { |
| 387 ColorTransform::TriStim& c = colors[i]; |
| 388 if (extended_) { |
| 389 c.set_x(copysign(Evaluate(abs(c.x())), c.x())); |
| 390 c.set_y(copysign(Evaluate(abs(c.y())), c.y())); |
| 391 c.set_z(copysign(Evaluate(abs(c.z())), c.z())); |
| 392 } else { |
| 393 c.set_x(Evaluate(c.x())); |
| 394 c.set_y(Evaluate(c.y())); |
| 395 c.set_z(Evaluate(c.z())); |
| 396 } |
| 397 } |
| 398 } |
| 399 |
| 400 void AppendShaderSource(std::stringstream* hdr, |
| 401 std::stringstream* src, |
| 402 size_t step_index) const override { |
| 403 *hdr << "float TransferFn" << step_index << "(float v) {" << endl; |
| 404 AppendTransferShaderSource(hdr); |
| 405 *hdr << "}" << endl; |
| 406 if (extended_) { |
| 407 *src << " color.r = sign(color.r) * TransferFn" << step_index |
| 408 << "(abs(color.r));" << endl; |
| 409 *src << " color.g = sign(color.g) * TransferFn" << step_index |
| 410 << "(abs(color.g));" << endl; |
| 411 *src << " color.b = sign(color.b) * TransferFn" << step_index |
| 412 << "(abs(color.b));" << endl; |
| 413 } else { |
| 414 *src << " color.r = TransferFn" << step_index << "(color.r);" << endl; |
| 415 *src << " color.g = TransferFn" << step_index << "(color.g);" << endl; |
| 416 *src << " color.b = TransferFn" << step_index << "(color.b);" << endl; |
| 417 } |
| 418 } |
| 419 |
| 420 virtual float Evaluate(float x) const = 0; |
| 421 // Populate the body of a shader function that takes a float v and returns |
| 422 // Evaluate(v). |
| 423 virtual void AppendTransferShaderSource(std::stringstream* src) const = 0; |
| 424 |
| 425 protected: |
| 426 // True if the transfer function is extended to be defined for all real |
| 427 // values by point symmetry. |
| 428 bool extended_ = false; |
| 429 }; |
| 430 |
| 431 class ColorTransformSkTransferFn : public ColorTransformPerChannelTransferFn { |
| 375 public: | 432 public: |
| 376 explicit ColorTransformSkTransferFn(const SkColorSpaceTransferFn& fn, | 433 explicit ColorTransformSkTransferFn(const SkColorSpaceTransferFn& fn, |
| 377 bool extended) | 434 bool extended) |
| 378 : fn_(fn), extended_(extended) {} | 435 : ColorTransformPerChannelTransferFn(extended), fn_(fn) {} |
| 436 // ColorTransformStep implementation. |
| 379 ColorTransformSkTransferFn* GetSkTransferFn() override { return this; } | 437 ColorTransformSkTransferFn* GetSkTransferFn() override { return this; } |
| 380 | |
| 381 bool Join(ColorTransformStep* next_untyped) override { | 438 bool Join(ColorTransformStep* next_untyped) override { |
| 382 ColorTransformSkTransferFn* next = next_untyped->GetSkTransferFn(); | 439 ColorTransformSkTransferFn* next = next_untyped->GetSkTransferFn(); |
| 383 if (!next) | 440 if (!next) |
| 384 return false; | 441 return false; |
| 385 if (!extended_ && !next->extended_ && | 442 if (!extended_ && !next->extended_ && |
| 386 SkTransferFnsApproximatelyCancel(fn_, next->fn_)) { | 443 SkTransferFnsApproximatelyCancel(fn_, next->fn_)) { |
| 387 // Set to be the identity. | 444 // Set to be the identity. |
| 388 fn_.fA = 1; | 445 fn_.fA = 1; |
| 389 fn_.fB = 0; | 446 fn_.fB = 0; |
| 390 fn_.fC = 1; | 447 fn_.fC = 1; |
| 391 fn_.fD = 0; | 448 fn_.fD = 0; |
| 392 fn_.fE = 0; | 449 fn_.fE = 0; |
| 393 fn_.fF = 0; | 450 fn_.fF = 0; |
| 394 fn_.fG = 1; | 451 fn_.fG = 1; |
| 395 return true; | 452 return true; |
| 396 } | 453 } |
| 397 return false; | 454 return false; |
| 398 } | 455 } |
| 399 | 456 bool CanAppendShaderSource() override { return true; } |
| 400 bool IsNull() override { return SkTransferFnIsApproximatelyIdentity(fn_); } | 457 bool IsNull() override { return SkTransferFnIsApproximatelyIdentity(fn_); } |
| 401 | 458 |
| 402 void Transform(ColorTransform::TriStim* colors, size_t num) const override { | 459 // ColorTransformPerChannelTransferFn implementation: |
| 403 for (size_t i = 0; i < num; i++) { | 460 float Evaluate(float v) const override { return SkTransferFnEval(fn_, v); } |
| 404 ColorTransform::TriStim& c = colors[i]; | 461 void AppendTransferShaderSource(std::stringstream* result) const override { |
| 405 if (extended_) { | |
| 406 c.set_x(copysign(SkTransferFnEval(fn_, abs(c.x())), c.x())); | |
| 407 c.set_y(copysign(SkTransferFnEval(fn_, abs(c.y())), c.y())); | |
| 408 c.set_z(copysign(SkTransferFnEval(fn_, abs(c.z())), c.z())); | |
| 409 } else { | |
| 410 c.set_x(SkTransferFnEval(fn_, c.x())); | |
| 411 c.set_y(SkTransferFnEval(fn_, c.y())); | |
| 412 c.set_z(SkTransferFnEval(fn_, c.z())); | |
| 413 } | |
| 414 } | |
| 415 } | |
| 416 | |
| 417 bool CanAppendShaderSource() override { return true; } | |
| 418 | |
| 419 void AppendShaderSourceChannel(std::stringstream* result, | |
| 420 const std::string& value) { | |
| 421 std::string abs_value = "abs(" + value + ")"; | |
| 422 const float kEpsilon = 1.f / 1024.f; | 462 const float kEpsilon = 1.f / 1024.f; |
| 423 | 463 |
| 424 // Construct the linear segment | 464 // Construct the linear segment |
| 425 // linear = C * x + F | 465 // linear = C * x + F |
| 426 // Elide operations that will be close to the identity. | 466 // Elide operations that will be close to the identity. |
| 427 std::string linear = value; | 467 std::string linear = "v"; |
| 428 if (std::abs(fn_.fC - 1.f) > kEpsilon) | 468 if (std::abs(fn_.fC - 1.f) > kEpsilon) |
| 429 linear = Str(fn_.fC) + " * " + linear; | 469 linear = Str(fn_.fC) + " * " + linear; |
| 430 if (std::abs(fn_.fF) > kEpsilon) | 470 if (std::abs(fn_.fF) > kEpsilon) |
| 431 linear = linear + " + " + Str(fn_.fF); | 471 linear = linear + " + " + Str(fn_.fF); |
| 432 | 472 |
| 433 // Construct the nonlinear segment. | 473 // Construct the nonlinear segment. |
| 434 // nonlinear = pow(A * x + B, G) + E | 474 // nonlinear = pow(A * x + B, G) + E |
| 435 // Elide operations (especially the pow) that will be close to the | 475 // Elide operations (especially the pow) that will be close to the |
| 436 // identity. | 476 // identity. |
| 437 std::string nonlinear = extended_ ? abs_value : value; | 477 std::string nonlinear = "v"; |
| 438 if (std::abs(fn_.fA - 1.f) > kEpsilon) | 478 if (std::abs(fn_.fA - 1.f) > kEpsilon) |
| 439 nonlinear = Str(fn_.fA) + " * " + nonlinear; | 479 nonlinear = Str(fn_.fA) + " * " + nonlinear; |
| 440 if (std::abs(fn_.fB) > kEpsilon) | 480 if (std::abs(fn_.fB) > kEpsilon) |
| 441 nonlinear = nonlinear + " + " + Str(fn_.fB); | 481 nonlinear = nonlinear + " + " + Str(fn_.fB); |
| 442 if (std::abs(fn_.fG - 1.f) > kEpsilon) | 482 if (std::abs(fn_.fG - 1.f) > kEpsilon) |
| 443 nonlinear = "pow(" + nonlinear + ", " + Str(fn_.fG) + ")"; | 483 nonlinear = "pow(" + nonlinear + ", " + Str(fn_.fG) + ")"; |
| 444 if (std::abs(fn_.fE) > kEpsilon) | 484 if (std::abs(fn_.fE) > kEpsilon) |
| 445 nonlinear = nonlinear + " + " + Str(fn_.fE); | 485 nonlinear = nonlinear + " + " + Str(fn_.fE); |
| 446 if (extended_) { | 486 |
| 447 if (nonlinear == abs_value) | 487 // Add both parts, skipping the if clause if possible. |
| 448 nonlinear = value; | 488 if (fn_.fD > kEpsilon) { |
| 449 else | 489 *result << " if (v < " << Str(fn_.fD) << ")" << endl; |
| 450 nonlinear = "sign(" + value + ") * (" + nonlinear + ")"; | 490 *result << " return " << linear << ";" << endl; |
| 491 *result << " return " << nonlinear << ";" << endl; |
| 492 } else { |
| 493 *result << " return " << nonlinear << ";" << endl; |
| 451 } | 494 } |
| 452 | |
| 453 // Add both parts, skpping the if clause if possible. | |
| 454 if (fn_.fD > kEpsilon) { | |
| 455 if (extended_) { | |
| 456 *result << " if (" << abs_value << " < " << Str(fn_.fD) << ")" | |
| 457 << std::endl; | |
| 458 } else { | |
| 459 *result << " if (" << value << " < " << Str(fn_.fD) << ")" | |
| 460 << std::endl; | |
| 461 } | |
| 462 *result << " " << value << " = " << linear << ";" << std::endl; | |
| 463 *result << " else" << std::endl; | |
| 464 *result << " " << value << " = " << nonlinear << ";" << std::endl; | |
| 465 } else { | |
| 466 *result << " " << value << " = " << nonlinear << ";" << std::endl; | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 void AppendShaderSource(std::stringstream* result) override { | |
| 471 // Append the transfer function for each channel. | |
| 472 AppendShaderSourceChannel(result, "color.r"); | |
| 473 AppendShaderSourceChannel(result, "color.g"); | |
| 474 AppendShaderSourceChannel(result, "color.b"); | |
| 475 } | 495 } |
| 476 | 496 |
| 477 private: | 497 private: |
| 478 SkColorSpaceTransferFn fn_; | 498 SkColorSpaceTransferFn fn_; |
| 479 // True if the transfer function is extended to be defined for all real | |
| 480 // values. | |
| 481 const bool extended_ = false; | |
| 482 }; | 499 }; |
| 483 | 500 |
| 484 class ColorTransformFromLinear : public ColorTransformStep { | 501 class ColorTransformFromLinear : public ColorTransformPerChannelTransferFn { |
| 485 public: | 502 public: |
| 503 // ColorTransformStep implementation. |
| 486 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer) | 504 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer) |
| 487 : transfer_(transfer) {} | 505 : ColorTransformPerChannelTransferFn(false), transfer_(transfer) {} |
| 488 ColorTransformFromLinear* GetFromLinear() override { return this; } | 506 ColorTransformFromLinear* GetFromLinear() override { return this; } |
| 507 bool CanAppendShaderSource() override { return true; } |
| 489 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } | 508 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } |
| 490 void Transform(ColorTransform::TriStim* colors, size_t num) const override { | 509 |
| 491 for (size_t i = 0; i < num; i++) { | 510 // ColorTransformPerChannelTransferFn implementation: |
| 492 colors[i].set_x(FromLinear(transfer_, colors[i].x())); | 511 float Evaluate(float v) const override { return FromLinear(transfer_, v); } |
| 493 colors[i].set_y(FromLinear(transfer_, colors[i].y())); | 512 void AppendTransferShaderSource(std::stringstream* src) const override { |
| 494 colors[i].set_z(FromLinear(transfer_, colors[i].z())); | 513 // This is a string-ized copy-paste from FromLinear. |
| 514 switch (transfer_) { |
| 515 case ColorSpace::TransferID::LOG: |
| 516 *src << " if (v < 0.01)\n" |
| 517 " return 0.0;\n" |
| 518 " return 1.0 + log(v) / log(10.0) / 2.0;\n"; |
| 519 return; |
| 520 case ColorSpace::TransferID::LOG_SQRT: |
| 521 *src << " if (v < sqrt(10.0) / 1000.0)\n" |
| 522 " return 0.0;\n" |
| 523 " return 1.0 + log(v) / log(10.0) / 2.5;\n"; |
| 524 return; |
| 525 case ColorSpace::TransferID::IEC61966_2_4: |
| 526 *src << " float a = 1.099296826809442;\n" |
| 527 " float b = 0.018053968510807;\n" |
| 528 " if (v < -b)\n" |
| 529 " return -a * pow(-v, 0.45) + (a - 1.0);\n" |
| 530 " else if (v <= b)\n" |
| 531 " return 4.5 * v;\n" |
| 532 " return a * pow(v, 0.45) - (a - 1.0);\n"; |
| 533 return; |
| 534 case ColorSpace::TransferID::BT1361_ECG: |
| 535 *src << " float a = 1.099;\n" |
| 536 " float b = 0.018;\n" |
| 537 " float l = 0.0045;\n" |
| 538 " if (v < -l)\n" |
| 539 " return -(a * pow(-4.0 * v, 0.45) + (a - 1.0)) / 4.0;\n" |
| 540 " else if (v <= b)\n" |
| 541 " return 4.5 * v;\n" |
| 542 " return a * pow(v, 0.45) - (a - 1.0);\n"; |
| 543 return; |
| 544 case ColorSpace::TransferID::SMPTEST2084: |
| 545 *src << " v *= 80.0 / 10000.0;\n" |
| 546 " v = max(0.0, v);\n" |
| 547 " float m1 = (2610.0 / 4096.0) / 4.0;\n" |
| 548 " float m2 = (2523.0 / 4096.0) * 128.0;\n" |
| 549 " float c1 = 3424.0 / 4096.0;\n" |
| 550 " float c2 = (2413.0 / 4096.0) * 32.0;\n" |
| 551 " float c3 = (2392.0 / 4096.0) * 32.0;\n" |
| 552 " return pow((c1 + c2 * pow(v, m1)) / \n" |
| 553 " (1.0 + c3 * pow(v, m1)), m2);\n"; |
| 554 return; |
| 555 case ColorSpace::TransferID::ARIB_STD_B67: |
| 556 *src << " const float a = 0.17883277;\n" |
| 557 " const float b = 0.28466892;\n" |
| 558 " const float c = 0.55991073;\n" |
| 559 " v = max(0.0, v);\n" |
| 560 " if (v <= 1.0)\n" |
| 561 " return 0.5 * sqrt(v);\n" |
| 562 " return a * log(v - b) + c;\n"; |
| 563 return; |
| 564 default: |
| 565 break; |
| 495 } | 566 } |
| 567 NOTREACHED(); |
| 496 } | 568 } |
| 497 | 569 |
| 498 private: | 570 private: |
| 499 friend class ColorTransformToLinear; | 571 friend class ColorTransformToLinear; |
| 500 ColorSpace::TransferID transfer_; | 572 ColorSpace::TransferID transfer_; |
| 501 }; | 573 }; |
| 502 | 574 |
| 503 class ColorTransformToLinear : public ColorTransformStep { | 575 class ColorTransformToLinear : public ColorTransformPerChannelTransferFn { |
| 504 public: | 576 public: |
| 505 explicit ColorTransformToLinear(ColorSpace::TransferID transfer) | 577 explicit ColorTransformToLinear(ColorSpace::TransferID transfer) |
| 506 : transfer_(transfer) {} | 578 : ColorTransformPerChannelTransferFn(false), transfer_(transfer) {} |
| 507 | 579 // ColorTransformStep implementation: |
| 508 bool Join(ColorTransformStep* next_untyped) override { | 580 bool Join(ColorTransformStep* next_untyped) override { |
| 509 ColorTransformFromLinear* next = next_untyped->GetFromLinear(); | 581 ColorTransformFromLinear* next = next_untyped->GetFromLinear(); |
| 510 if (!next) | 582 if (!next) |
| 511 return false; | 583 return false; |
| 512 if (transfer_ == next->transfer_) { | 584 if (transfer_ == next->transfer_) { |
| 513 transfer_ = ColorSpace::TransferID::LINEAR; | 585 transfer_ = ColorSpace::TransferID::LINEAR; |
| 514 return true; | 586 return true; |
| 515 } | 587 } |
| 516 return false; | 588 return false; |
| 517 } | 589 } |
| 518 | 590 bool CanAppendShaderSource() override { return true; } |
| 519 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } | 591 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } |
| 520 | 592 |
| 593 // ColorTransformPerChannelTransferFn implementation: |
| 594 float Evaluate(float v) const override { return ToLinear(transfer_, v); } |
| 595 void AppendTransferShaderSource(std::stringstream* src) const override { |
| 596 // This is a string-ized copy-paste from ToLinear. |
| 597 switch (transfer_) { |
| 598 case ColorSpace::TransferID::LOG: |
| 599 *src << " if (v < 0.0)\n" |
| 600 " return 0.0;\n" |
| 601 " return pow(10.0, (v - 1.0) * 2.0);\n"; |
| 602 return; |
| 603 case ColorSpace::TransferID::LOG_SQRT: |
| 604 *src << " if (v < 0.0)\n" |
| 605 " return 0.0;\n" |
| 606 " return pow(10.0, (v - 1.0) * 2.5);\n"; |
| 607 return; |
| 608 case ColorSpace::TransferID::IEC61966_2_4: |
| 609 *src << " float a = 1.099296826809442;\n" |
| 610 " float from_linear_neg_a = -1.047844;\n" |
| 611 " float from_linear_b = 0.081243;\n" |
| 612 " if (v < from_linear_neg_a)\n" |
| 613 " return -pow((a - 1.0 - v) / a, 1.0 / 0.45);\n" |
| 614 " else if (v <= from_linear_b)\n" |
| 615 " return v / 4.5;\n" |
| 616 " return pow((v + a - 1.0) / a, 1.0 / 0.45);\n"; |
| 617 return; |
| 618 case ColorSpace::TransferID::BT1361_ECG: |
| 619 *src << " float a = 1.099;\n" |
| 620 " float from_linear_neg_l = -0.020250;\n" |
| 621 " float from_linear_b = 0.081000;\n" |
| 622 " if (v < from_linear_neg_l)\n" |
| 623 " return -pow((1.0 - a - v * 4.0) / a, 1.0 / 0.45) / 4.0;\n" |
| 624 " else if (v <= from_linear_b)\n" |
| 625 " return v / 4.5;\n" |
| 626 " return pow((v + a - 1.0) / a, 1.0 / 0.45);\n"; |
| 627 return; |
| 628 case ColorSpace::TransferID::SMPTEST2084: |
| 629 *src << " v = max(0.0, v);\n" |
| 630 " float m1 = (2610.0 / 4096.0) / 4.0;\n" |
| 631 " float m2 = (2523.0 / 4096.0) * 128.0;\n" |
| 632 " float c1 = 3424.0 / 4096.0;\n" |
| 633 " float c2 = (2413.0 / 4096.0) * 32.0;\n" |
| 634 " float c3 = (2392.0 / 4096.0) * 32.0;\n" |
| 635 " v = pow(max(pow(v, 1.0 / m2) - c1, 0.0) /\n" |
| 636 " (c2 - c3 * pow(v, 1.0 / m2)), 1.0 / m1);\n" |
| 637 " v *= 10000.0 / 80.0;\n" |
| 638 " return v;\n"; |
| 639 return; |
| 640 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: |
| 641 *src << " v = max(0.0, v);\n" |
| 642 " return min(2.3 * pow(v, 2.8), v / 5.0 + 0.8);\n"; |
| 643 return; |
| 644 case ColorSpace::TransferID::ARIB_STD_B67: |
| 645 *src << " v = max(0.0, v);\n" |
| 646 " float a = 0.17883277;\n" |
| 647 " float b = 0.28466892;\n" |
| 648 " float c = 0.55991073;\n" |
| 649 " if (v <= 0.5)\n" |
| 650 " return (v * 2.0) * (v * 2.0);\n" |
| 651 " return exp((v - c) / a) + b;\n"; |
| 652 return; |
| 653 default: |
| 654 break; |
| 655 } |
| 656 NOTREACHED(); |
| 657 } |
| 658 |
| 659 private: |
| 660 ColorSpace::TransferID transfer_; |
| 661 }; |
| 662 |
| 663 class ColorTransformSMPTEST2048NonHdrToLinear : public ColorTransformStep { |
| 664 public: |
| 521 // Assumes BT2020 primaries. | 665 // Assumes BT2020 primaries. |
| 522 static float Luma(const ColorTransform::TriStim& c) { | 666 static float Luma(const ColorTransform::TriStim& c) { |
| 523 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f; | 667 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f; |
| 524 } | 668 } |
| 525 | |
| 526 static ColorTransform::TriStim ClipToWhite(ColorTransform::TriStim& c) { | 669 static ColorTransform::TriStim ClipToWhite(ColorTransform::TriStim& c) { |
| 527 float maximum = max(max(c.x(), c.y()), c.z()); | 670 float maximum = max(max(c.x(), c.y()), c.z()); |
| 528 if (maximum > 1.0f) { | 671 if (maximum > 1.0f) { |
| 529 float l = Luma(c); | 672 float l = Luma(c); |
| 530 c.Scale(1.0f / maximum); | 673 c.Scale(1.0f / maximum); |
| 531 ColorTransform::TriStim white(1.0f, 1.0f, 1.0f); | 674 ColorTransform::TriStim white(1.0f, 1.0f, 1.0f); |
| 532 white.Scale((1.0f - 1.0f / maximum) * l / Luma(white)); | 675 white.Scale((1.0f - 1.0f / maximum) * l / Luma(white)); |
| 533 ColorTransform::TriStim black(0.0f, 0.0f, 0.0f); | 676 ColorTransform::TriStim black(0.0f, 0.0f, 0.0f); |
| 534 c += white - black; | 677 c += white - black; |
| 535 } | 678 } |
| 536 return c; | 679 return c; |
| 537 } | 680 } |
| 538 | |
| 539 void Transform(ColorTransform::TriStim* colors, size_t num) const override { | 681 void Transform(ColorTransform::TriStim* colors, size_t num) const override { |
| 540 if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) { | 682 for (size_t i = 0; i < num; i++) { |
| 541 for (size_t i = 0; i < num; i++) { | 683 ColorTransform::TriStim ret( |
| 542 ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()), | 684 ToLinear(ColorSpace::TransferID::SMPTEST2084_NON_HDR, colors[i].x()), |
| 543 ToLinear(transfer_, colors[i].y()), | 685 ToLinear(ColorSpace::TransferID::SMPTEST2084_NON_HDR, colors[i].y()), |
| 544 ToLinear(transfer_, colors[i].z())); | 686 ToLinear(ColorSpace::TransferID::SMPTEST2084_NON_HDR, colors[i].z())); |
| 545 if (Luma(ret) > 0.0) { | 687 if (Luma(ret) > 0.0) { |
| 546 ColorTransform::TriStim smpte2084( | 688 ColorTransform::TriStim smpte2084( |
| 547 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()), | 689 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()), |
| 548 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()), | 690 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()), |
| 549 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z())); | 691 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z())); |
| 550 smpte2084.Scale(Luma(ret) / Luma(smpte2084)); | 692 smpte2084.Scale(Luma(ret) / Luma(smpte2084)); |
| 551 ret = ClipToWhite(smpte2084); | 693 ret = ClipToWhite(smpte2084); |
| 552 } | |
| 553 colors[i] = ret; | |
| 554 } | 694 } |
| 555 } else { | 695 colors[i] = ret; |
| 556 for (size_t i = 0; i < num; i++) { | |
| 557 colors[i].set_x(ToLinear(transfer_, colors[i].x())); | |
| 558 colors[i].set_y(ToLinear(transfer_, colors[i].y())); | |
| 559 colors[i].set_z(ToLinear(transfer_, colors[i].z())); | |
| 560 } | |
| 561 } | 696 } |
| 562 } | 697 } |
| 563 | |
| 564 private: | |
| 565 ColorSpace::TransferID transfer_; | |
| 566 }; | 698 }; |
| 567 | 699 |
| 568 // BT2020 Constant Luminance is different than most other | 700 // BT2020 Constant Luminance is different than most other |
| 569 // ways to encode RGB values as YUV. The basic idea is that | 701 // ways to encode RGB values as YUV. The basic idea is that |
| 570 // transfer functions are applied on the Y value instead of | 702 // transfer functions are applied on the Y value instead of |
| 571 // on the RGB values. However, running the transfer function | 703 // on the RGB values. However, running the transfer function |
| 572 // on the U and V values doesn't make any sense since they | 704 // on the U and V values doesn't make any sense since they |
| 573 // are centered at 0.5. To work around this, the transfer function | 705 // are centered at 0.5. To work around this, the transfer function |
| 574 // is applied to the Y, R and B values, and then the U and V | 706 // is applied to the Y, R and B values, and then the U and V |
| 575 // values are calculated from that. | 707 // values are calculated from that. |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 645 } | 777 } |
| 646 if (V <= 0) { | 778 if (V <= 0) { |
| 647 R_Y = V * (-2.0 * -0.8591); | 779 R_Y = V * (-2.0 * -0.8591); |
| 648 } else { | 780 } else { |
| 649 R_Y = V * (2.0 * 0.4969); | 781 R_Y = V * (2.0 * 0.4969); |
| 650 } | 782 } |
| 651 // Return an RYB value, later steps will fix it. | 783 // Return an RYB value, later steps will fix it. |
| 652 YUV[i] = ColorTransform::TriStim(R_Y + Y, YUV[i].x(), B_Y + Y); | 784 YUV[i] = ColorTransform::TriStim(R_Y + Y, YUV[i].x(), B_Y + Y); |
| 653 } | 785 } |
| 654 } | 786 } |
| 787 bool CanAppendShaderSource() override { return true; } |
| 788 void AppendShaderSource(std::stringstream* hdr, |
| 789 std::stringstream* src, |
| 790 size_t step_index) const override { |
| 791 *hdr << "vec3 BT2020_YUV_to_RYB_Step" << step_index << "(vec3 color) {" |
| 792 << endl; |
| 793 *hdr << " float Y = color.x;" << endl; |
| 794 *hdr << " float U = color.y;" << endl; |
| 795 *hdr << " float V = color.z;" << endl; |
| 796 *hdr << " float B_Y = 0.0;" << endl; |
| 797 *hdr << " float R_Y = 0.0;" << endl; |
| 798 *hdr << " if (U <= 0.0) {" << endl; |
| 799 *hdr << " B_Y = Y * (-2.0 * -0.9702);" << endl; |
| 800 *hdr << " } else {" << endl; |
| 801 *hdr << " B_Y = U * (2.0 * 0.7910);" << endl; |
| 802 *hdr << " }" << endl; |
| 803 *hdr << " if (V <= 0.0) {" << endl; |
| 804 *hdr << " R_Y = V * (-2.0 * -0.8591);" << endl; |
| 805 *hdr << " } else {" << endl; |
| 806 *hdr << " R_Y = V * (2.0 * 0.4969);" << endl; |
| 807 *hdr << " }" << endl; |
| 808 *hdr << " return vec3(R_Y + Y, Y, B_Y + Y);" << endl; |
| 809 *hdr << "}" << endl; |
| 810 |
| 811 *src << " color.rgb = BT2020_YUV_to_RYB_Step" << step_index |
| 812 << "(color.rgb);" << endl; |
| 813 } |
| 655 | 814 |
| 656 private: | 815 private: |
| 657 bool null_ = false; | 816 bool null_ = false; |
| 658 }; | 817 }; |
| 659 | 818 |
| 660 void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform( | 819 void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform( |
| 661 ColorSpace from, | 820 ColorSpace from, |
| 662 const ColorSpace& to, | 821 const ColorSpace& to, |
| 663 ColorTransform::Intent intent) { | 822 ColorTransform::Intent intent) { |
| 664 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) { | 823 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 706 // If the target color space is not defined, just apply the adjust and | 865 // If the target color space is not defined, just apply the adjust and |
| 707 // tranfer matrices. This path is used by YUV to RGB color conversion | 866 // tranfer matrices. This path is used by YUV to RGB color conversion |
| 708 // when full color conversion is not enabled. | 867 // when full color conversion is not enabled. |
| 709 if (!to.IsValid()) | 868 if (!to.IsValid()) |
| 710 return; | 869 return; |
| 711 | 870 |
| 712 SkColorSpaceTransferFn to_linear_fn; | 871 SkColorSpaceTransferFn to_linear_fn; |
| 713 if (from.GetTransferFunction(&to_linear_fn)) { | 872 if (from.GetTransferFunction(&to_linear_fn)) { |
| 714 steps_.push_back(base::MakeUnique<ColorTransformSkTransferFn>( | 873 steps_.push_back(base::MakeUnique<ColorTransformSkTransferFn>( |
| 715 to_linear_fn, from.HasExtendedSkTransferFn())); | 874 to_linear_fn, from.HasExtendedSkTransferFn())); |
| 875 } else if (from.transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) { |
| 876 steps_.push_back( |
| 877 base::MakeUnique<ColorTransformSMPTEST2048NonHdrToLinear>()); |
| 716 } else { | 878 } else { |
| 717 steps_.push_back(base::MakeUnique<ColorTransformToLinear>(from.transfer_)); | 879 steps_.push_back(base::MakeUnique<ColorTransformToLinear>(from.transfer_)); |
| 718 } | 880 } |
| 719 | 881 |
| 720 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { | 882 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { |
| 721 // BT2020 CL is a special case. | 883 // BT2020 CL is a special case. |
| 722 steps_.push_back(base::MakeUnique<ColorTransformFromBT2020CL>()); | 884 steps_.push_back(base::MakeUnique<ColorTransformFromBT2020CL>()); |
| 723 } | 885 } |
| 724 steps_.push_back( | 886 steps_.push_back( |
| 725 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); | 887 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 if (dst_profile) { | 1024 if (dst_profile) { |
| 863 steps_.push_back(base::MakeUnique<QCMSColorTransform>( | 1025 steps_.push_back(base::MakeUnique<QCMSColorTransform>( |
| 864 GetXYZD50Profile(), std::move(dst_profile))); | 1026 GetXYZD50Profile(), std::move(dst_profile))); |
| 865 } | 1027 } |
| 866 | 1028 |
| 867 if (intent != Intent::TEST_NO_OPT) | 1029 if (intent != Intent::TEST_NO_OPT) |
| 868 Simplify(); | 1030 Simplify(); |
| 869 } | 1031 } |
| 870 | 1032 |
| 871 std::string ColorTransformInternal::GetShaderSource() const { | 1033 std::string ColorTransformInternal::GetShaderSource() const { |
| 872 std::stringstream result; | 1034 std::stringstream hdr; |
| 873 InitStringStream(&result); | 1035 std::stringstream src; |
| 874 result << "vec3 DoColorConversion(vec3 color) {" << std::endl; | 1036 InitStringStream(&hdr); |
| 1037 InitStringStream(&src); |
| 1038 src << "vec3 DoColorConversion(vec3 color) {" << endl; |
| 1039 size_t step_index = 0; |
| 875 for (const auto& step : steps_) | 1040 for (const auto& step : steps_) |
| 876 step->AppendShaderSource(&result); | 1041 step->AppendShaderSource(&hdr, &src, step_index++); |
| 877 result << " return color;" << std::endl; | 1042 src << " return color;" << endl; |
| 878 result << "}" << std::endl; | 1043 src << "}" << endl; |
| 879 return result.str(); | 1044 return hdr.str() + src.str(); |
| 880 } | 1045 } |
| 881 | 1046 |
| 882 bool ColorTransformInternal::CanGetShaderSource() const { | 1047 bool ColorTransformInternal::CanGetShaderSource() const { |
| 883 for (const auto& step : steps_) { | 1048 for (const auto& step : steps_) { |
| 884 if (!step->CanAppendShaderSource()) | 1049 if (!step->CanAppendShaderSource()) |
| 885 return false; | 1050 return false; |
| 886 } | 1051 } |
| 887 return true; | 1052 return true; |
| 888 } | 1053 } |
| 889 | 1054 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 const ColorSpace& to, | 1091 const ColorSpace& to, |
| 927 Intent intent) { | 1092 Intent intent) { |
| 928 return std::unique_ptr<ColorTransform>( | 1093 return std::unique_ptr<ColorTransform>( |
| 929 new ColorTransformInternal(from, to, intent)); | 1094 new ColorTransformInternal(from, to, intent)); |
| 930 } | 1095 } |
| 931 | 1096 |
| 932 ColorTransform::ColorTransform() {} | 1097 ColorTransform::ColorTransform() {} |
| 933 ColorTransform::~ColorTransform() {} | 1098 ColorTransform::~ColorTransform() {} |
| 934 | 1099 |
| 935 } // namespace gfx | 1100 } // namespace gfx |
| OLD | NEW |