| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright 2013 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
| Chia-I Wu | 93e14df | 2018-06-04 10:10:17 -0700 | [diff] [blame] | 17 | #define ATRACE_TAG ATRACE_TAG_GRAPHICS | 
 | 18 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 19 | #include <GLES2/gl2.h> | 
 | 20 | #include <GLES2/gl2ext.h> | 
 | 21 |  | 
 | 22 | #include <utils/String8.h> | 
| Chia-I Wu | 93e14df | 2018-06-04 10:10:17 -0700 | [diff] [blame] | 23 | #include <utils/Trace.h> | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 24 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 25 | #include "Description.h" | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 26 | #include "Program.h" | 
 | 27 | #include "ProgramCache.h" | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 28 |  | 
 | 29 | namespace android { | 
 | 30 | // ----------------------------------------------------------------------------------------------- | 
 | 31 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 32 | /* | 
 | 33 |  * A simple formatter class to automatically add the endl and | 
 | 34 |  * manage the indentation. | 
 | 35 |  */ | 
 | 36 |  | 
 | 37 | class Formatter; | 
 | 38 | static Formatter& indent(Formatter& f); | 
 | 39 | static Formatter& dedent(Formatter& f); | 
 | 40 |  | 
 | 41 | class Formatter { | 
 | 42 |     String8 mString; | 
 | 43 |     int mIndent; | 
 | 44 |     typedef Formatter& (*FormaterManipFunc)(Formatter&); | 
 | 45 |     friend Formatter& indent(Formatter& f); | 
 | 46 |     friend Formatter& dedent(Formatter& f); | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 47 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 48 | public: | 
| Andy McFadden | 892f22d | 2013-08-15 10:05:01 -0700 | [diff] [blame] | 49 |     Formatter() : mIndent(0) {} | 
 | 50 |  | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 51 |     String8 getString() const { return mString; } | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 52 |  | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 53 |     friend Formatter& operator<<(Formatter& out, const char* in) { | 
 | 54 |         for (int i = 0; i < out.mIndent; i++) { | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 55 |             out.mString.append("    "); | 
 | 56 |         } | 
 | 57 |         out.mString.append(in); | 
 | 58 |         out.mString.append("\n"); | 
 | 59 |         return out; | 
 | 60 |     } | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 61 |     friend inline Formatter& operator<<(Formatter& out, const String8& in) { | 
 | 62 |         return operator<<(out, in.string()); | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 63 |     } | 
 | 64 |     friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) { | 
 | 65 |         return (*func)(to); | 
 | 66 |     } | 
 | 67 | }; | 
 | 68 | Formatter& indent(Formatter& f) { | 
 | 69 |     f.mIndent++; | 
 | 70 |     return f; | 
 | 71 | } | 
 | 72 | Formatter& dedent(Formatter& f) { | 
 | 73 |     f.mIndent--; | 
 | 74 |     return f; | 
 | 75 | } | 
 | 76 |  | 
 | 77 | // ----------------------------------------------------------------------------------------------- | 
 | 78 |  | 
 | 79 | ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache) | 
 | 80 |  | 
| Chia-I Wu | 93e14df | 2018-06-04 10:10:17 -0700 | [diff] [blame] | 81 | ProgramCache::ProgramCache() {} | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 82 |  | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 83 | ProgramCache::~ProgramCache() {} | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 84 |  | 
| Chia-I Wu | 93e14df | 2018-06-04 10:10:17 -0700 | [diff] [blame] | 85 | void ProgramCache::primeCache(bool hasWideColor) { | 
| Riley Andrews | a51fafc | 2014-09-29 13:29:40 -0700 | [diff] [blame] | 86 |     uint32_t shaderCount = 0; | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 87 |     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK; | 
| Riley Andrews | a51fafc | 2014-09-29 13:29:40 -0700 | [diff] [blame] | 88 |     // Prime the cache for all combinations of the above masks, | 
 | 89 |     // leaving off the experimental color matrix mask options. | 
 | 90 |  | 
 | 91 |     nsecs_t timeBefore = systemTime(); | 
 | 92 |     for (uint32_t keyVal = 0; keyVal <= keyMask; keyVal++) { | 
 | 93 |         Key shaderKey; | 
 | 94 |         shaderKey.set(keyMask, keyVal); | 
 | 95 |         uint32_t tex = shaderKey.getTextureTarget(); | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 96 |         if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) { | 
| Riley Andrews | a51fafc | 2014-09-29 13:29:40 -0700 | [diff] [blame] | 97 |             continue; | 
 | 98 |         } | 
 | 99 |         Program* program = mCache.valueFor(shaderKey); | 
| Peiyong Lin | 566a3b4 | 2018-01-09 18:22:43 -0800 | [diff] [blame] | 100 |         if (program == nullptr) { | 
| Riley Andrews | a51fafc | 2014-09-29 13:29:40 -0700 | [diff] [blame] | 101 |             program = generateProgram(shaderKey); | 
 | 102 |             mCache.add(shaderKey, program); | 
 | 103 |             shaderCount++; | 
 | 104 |         } | 
 | 105 |     } | 
| Chia-I Wu | 93e14df | 2018-06-04 10:10:17 -0700 | [diff] [blame] | 106 |  | 
 | 107 |     // Prime for sRGB->P3 conversion | 
 | 108 |     if (hasWideColor) { | 
 | 109 |         Key shaderKey; | 
 | 110 |         shaderKey.set(Key::BLEND_MASK | Key::TEXTURE_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK | | 
 | 111 |                               Key::INPUT_TF_MASK | Key::OUTPUT_TF_MASK, | 
 | 112 |                       Key::BLEND_PREMULT | Key::TEXTURE_EXT | Key::OUTPUT_TRANSFORM_MATRIX_ON | | 
 | 113 |                               Key::INPUT_TF_SRGB | Key::OUTPUT_TF_SRGB); | 
 | 114 |         for (int i = 0; i < 4; i++) { | 
 | 115 |             shaderKey.set(Key::OPACITY_MASK, | 
 | 116 |                           (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT); | 
 | 117 |             shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE); | 
 | 118 |             Program* program = mCache.valueFor(shaderKey); | 
 | 119 |             if (program == nullptr) { | 
 | 120 |                 program = generateProgram(shaderKey); | 
 | 121 |                 mCache.add(shaderKey, program); | 
 | 122 |                 shaderCount++; | 
 | 123 |             } | 
 | 124 |         } | 
 | 125 |     } | 
 | 126 |  | 
| Riley Andrews | a51fafc | 2014-09-29 13:29:40 -0700 | [diff] [blame] | 127 |     nsecs_t timeAfter = systemTime(); | 
 | 128 |     float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6; | 
 | 129 |     ALOGD("shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs); | 
 | 130 | } | 
 | 131 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 132 | ProgramCache::Key ProgramCache::computeKey(const Description& description) { | 
 | 133 |     Key needs; | 
 | 134 |     needs.set(Key::TEXTURE_MASK, | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 135 |               !description.mTextureEnabled | 
 | 136 |                       ? Key::TEXTURE_OFF | 
 | 137 |                       : description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES | 
 | 138 |                               ? Key::TEXTURE_EXT | 
 | 139 |                               : description.mTexture.getTextureTarget() == GL_TEXTURE_2D | 
 | 140 |                                       ? Key::TEXTURE_2D | 
 | 141 |                                       : Key::TEXTURE_OFF) | 
 | 142 |             .set(Key::ALPHA_MASK, | 
 | 143 |                  (description.mColor.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE) | 
 | 144 |             .set(Key::BLEND_MASK, | 
 | 145 |                  description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) | 
 | 146 |             .set(Key::OPACITY_MASK, | 
 | 147 |                  description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT) | 
| Peiyong Lin | a296b0c | 2018-04-30 16:55:29 -0700 | [diff] [blame] | 148 |             .set(Key::Key::INPUT_TRANSFORM_MATRIX_MASK, | 
 | 149 |                  description.hasInputTransformMatrix() ? | 
 | 150 |                      Key::INPUT_TRANSFORM_MATRIX_ON : Key::INPUT_TRANSFORM_MATRIX_OFF) | 
 | 151 |             .set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK, | 
| Chia-I Wu | 6d84411 | 2018-06-27 07:17:41 +0800 | [diff] [blame] | 152 |                  description.hasOutputTransformMatrix() || description.hasColorMatrix() ? | 
| Peiyong Lin | a296b0c | 2018-04-30 16:55:29 -0700 | [diff] [blame] | 153 |                      Key::OUTPUT_TRANSFORM_MATRIX_ON : Key::OUTPUT_TRANSFORM_MATRIX_OFF); | 
| Chia-I Wu | 7e65bc0 | 2018-01-11 14:31:38 -0800 | [diff] [blame] | 154 |  | 
| Chia-I Wu | 131d376 | 2018-01-11 14:35:27 -0800 | [diff] [blame] | 155 |     needs.set(Key::Y410_BT2020_MASK, | 
 | 156 |               description.mY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF); | 
 | 157 |  | 
| Peiyong Lin | a296b0c | 2018-04-30 16:55:29 -0700 | [diff] [blame] | 158 |     if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) { | 
| Chia-I Wu | 7e65bc0 | 2018-01-11 14:31:38 -0800 | [diff] [blame] | 159 |         switch (description.mInputTransferFunction) { | 
 | 160 |             case Description::TransferFunction::LINEAR: | 
 | 161 |             default: | 
 | 162 |                 needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_LINEAR); | 
 | 163 |                 break; | 
 | 164 |             case Description::TransferFunction::SRGB: | 
 | 165 |                 needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_SRGB); | 
 | 166 |                 break; | 
| Chia-I Wu | 131d376 | 2018-01-11 14:35:27 -0800 | [diff] [blame] | 167 |             case Description::TransferFunction::ST2084: | 
 | 168 |                 needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_ST2084); | 
 | 169 |                 break; | 
| Peiyong Lin | a3fb7d6 | 2018-04-11 17:41:47 -0700 | [diff] [blame] | 170 |             case Description::TransferFunction::HLG: | 
 | 171 |                 needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_HLG); | 
 | 172 |                 break; | 
| Chia-I Wu | 7e65bc0 | 2018-01-11 14:31:38 -0800 | [diff] [blame] | 173 |         } | 
 | 174 |  | 
 | 175 |         switch (description.mOutputTransferFunction) { | 
 | 176 |             case Description::TransferFunction::LINEAR: | 
 | 177 |             default: | 
 | 178 |                 needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_LINEAR); | 
 | 179 |                 break; | 
 | 180 |             case Description::TransferFunction::SRGB: | 
 | 181 |                 needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_SRGB); | 
 | 182 |                 break; | 
| Chia-I Wu | 131d376 | 2018-01-11 14:35:27 -0800 | [diff] [blame] | 183 |             case Description::TransferFunction::ST2084: | 
 | 184 |                 needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_ST2084); | 
 | 185 |                 break; | 
| Peiyong Lin | a3fb7d6 | 2018-04-11 17:41:47 -0700 | [diff] [blame] | 186 |             case Description::TransferFunction::HLG: | 
 | 187 |                 needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_HLG); | 
 | 188 |                 break; | 
| Chia-I Wu | 7e65bc0 | 2018-01-11 14:31:38 -0800 | [diff] [blame] | 189 |         } | 
 | 190 |     } | 
 | 191 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 192 |     return needs; | 
 | 193 | } | 
 | 194 |  | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 195 | // Generate EOTF that converts signal values to relative display light, | 
 | 196 | // both normalized to [0, 1]. | 
 | 197 | void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) { | 
 | 198 |     switch (needs.getInputTF()) { | 
 | 199 |         case Key::INPUT_TF_SRGB: | 
 | 200 |             fs << R"__SHADER__( | 
 | 201 |                 float EOTF_sRGB(float srgb) { | 
 | 202 |                     return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); | 
 | 203 |                 } | 
 | 204 |  | 
 | 205 |                 vec3 EOTF_sRGB(const vec3 srgb) { | 
 | 206 |                     return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b)); | 
 | 207 |                 } | 
 | 208 |  | 
 | 209 |                 vec3 EOTF(const vec3 srgb) { | 
 | 210 |                     return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb)); | 
 | 211 |                 } | 
 | 212 |             )__SHADER__"; | 
 | 213 |             break; | 
 | 214 |         case Key::INPUT_TF_ST2084: | 
 | 215 |             fs << R"__SHADER__( | 
 | 216 |                 vec3 EOTF(const highp vec3 color) { | 
 | 217 |                     const highp float m1 = (2610.0 / 4096.0) / 4.0; | 
 | 218 |                     const highp float m2 = (2523.0 / 4096.0) * 128.0; | 
 | 219 |                     const highp float c1 = (3424.0 / 4096.0); | 
 | 220 |                     const highp float c2 = (2413.0 / 4096.0) * 32.0; | 
 | 221 |                     const highp float c3 = (2392.0 / 4096.0) * 32.0; | 
 | 222 |  | 
| Siddharth Kapoor | ac1f7c9 | 2018-12-05 20:29:06 +0800 | [diff] [blame] | 223 |                     highp vec3 tmp = pow(clamp(color, 0.0, 1.0), 1.0 / vec3(m2)); | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 224 |                     tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp); | 
 | 225 |                     return pow(tmp, 1.0 / vec3(m1)); | 
 | 226 |                 } | 
 | 227 |             )__SHADER__"; | 
 | 228 |             break; | 
 | 229 |         case Key::INPUT_TF_HLG: | 
 | 230 |             fs << R"__SHADER__( | 
 | 231 |                 highp float EOTF_channel(const highp float channel) { | 
 | 232 |                     const highp float a = 0.17883277; | 
 | 233 |                     const highp float b = 0.28466892; | 
 | 234 |                     const highp float c = 0.55991073; | 
 | 235 |                     return channel <= 0.5 ? channel * channel / 3.0 : | 
 | 236 |                             (exp((channel - c) / a) + b) / 12.0; | 
 | 237 |                 } | 
 | 238 |  | 
 | 239 |                 vec3 EOTF(const highp vec3 color) { | 
 | 240 |                     return vec3(EOTF_channel(color.r), EOTF_channel(color.g), | 
 | 241 |                             EOTF_channel(color.b)); | 
 | 242 |                 } | 
 | 243 |             )__SHADER__"; | 
 | 244 |             break; | 
 | 245 |         default: | 
 | 246 |             fs << R"__SHADER__( | 
 | 247 |                 vec3 EOTF(const vec3 linear) { | 
 | 248 |                     return linear; | 
 | 249 |                 } | 
 | 250 |             )__SHADER__"; | 
 | 251 |             break; | 
 | 252 |     } | 
 | 253 | } | 
 | 254 |  | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 255 | void ProgramCache::generateToneMappingProcess(Formatter& fs, const Key& needs) { | 
 | 256 |     // Convert relative light to absolute light. | 
 | 257 |     switch (needs.getInputTF()) { | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 258 |         case Key::INPUT_TF_ST2084: | 
 | 259 |             fs << R"__SHADER__( | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 260 |                 highp vec3 ScaleLuminance(highp vec3 color) { | 
 | 261 |                     return color * 10000.0; | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 262 |                 } | 
 | 263 |             )__SHADER__"; | 
 | 264 |             break; | 
 | 265 |         case Key::INPUT_TF_HLG: | 
 | 266 |             fs << R"__SHADER__( | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 267 |                 highp vec3 ScaleLuminance(highp vec3 color) { | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 268 |                     // The formula is: | 
 | 269 |                     // alpha * pow(Y, gamma - 1.0) * color + beta; | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 270 |                     // where alpha is 1000.0, gamma is 1.2, beta is 0.0. | 
 | 271 |                     return color * 1000.0 * pow(color.y, 0.2); | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 272 |                 } | 
 | 273 |             )__SHADER__"; | 
 | 274 |             break; | 
 | 275 |         default: | 
 | 276 |             fs << R"__SHADER__( | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 277 |                 highp vec3 ScaleLuminance(highp vec3 color) { | 
 | 278 |                     return color * displayMaxLuminance; | 
 | 279 |                 } | 
 | 280 |             )__SHADER__"; | 
 | 281 |             break; | 
 | 282 |     } | 
 | 283 |  | 
 | 284 |     // Tone map absolute light to display luminance range. | 
 | 285 |     switch (needs.getInputTF()) { | 
 | 286 |         case Key::INPUT_TF_ST2084: | 
 | 287 |         case Key::INPUT_TF_HLG: | 
 | 288 |             switch (needs.getOutputTF()) { | 
 | 289 |                 case Key::OUTPUT_TF_HLG: | 
 | 290 |                     // Right now when mixed PQ and HLG contents are presented, | 
 | 291 |                     // HLG content will always be converted to PQ. However, for | 
 | 292 |                     // completeness, we simply clamp the value to [0.0, 1000.0]. | 
 | 293 |                     fs << R"__SHADER__( | 
 | 294 |                         highp vec3 ToneMap(highp vec3 color) { | 
 | 295 |                             return clamp(color, 0.0, 1000.0); | 
 | 296 |                         } | 
 | 297 |                     )__SHADER__"; | 
 | 298 |                     break; | 
 | 299 |                 case Key::OUTPUT_TF_ST2084: | 
 | 300 |                     fs << R"__SHADER__( | 
 | 301 |                         highp vec3 ToneMap(highp vec3 color) { | 
 | 302 |                             return color; | 
 | 303 |                         } | 
 | 304 |                     )__SHADER__"; | 
 | 305 |                     break; | 
 | 306 |                 default: | 
 | 307 |                     fs << R"__SHADER__( | 
 | 308 |                         highp vec3 ToneMap(highp vec3 color) { | 
 | 309 |                             const float maxMasteringLumi = 1000.0; | 
 | 310 |                             const float maxContentLumi = 1000.0; | 
 | 311 |                             const float maxInLumi = min(maxMasteringLumi, maxContentLumi); | 
 | 312 |                             float maxOutLumi = displayMaxLuminance; | 
 | 313 |  | 
 | 314 |                             float nits = color.y; | 
 | 315 |  | 
 | 316 |                             // clamp to max input luminance | 
 | 317 |                             nits = clamp(nits, 0.0, maxInLumi); | 
 | 318 |  | 
 | 319 |                             // scale [0.0, maxInLumi] to [0.0, maxOutLumi] | 
 | 320 |                             if (maxInLumi <= maxOutLumi) { | 
| Chia-I Wu | 8e86a2d | 2018-10-03 11:32:27 -0700 | [diff] [blame] | 321 |                                 return color * (maxOutLumi / maxInLumi); | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 322 |                             } else { | 
 | 323 |                                 // three control points | 
 | 324 |                                 const float x0 = 10.0; | 
 | 325 |                                 const float y0 = 17.0; | 
 | 326 |                                 float x1 = maxOutLumi * 0.75; | 
 | 327 |                                 float y1 = x1; | 
 | 328 |                                 float x2 = x1 + (maxInLumi - x1) / 2.0; | 
 | 329 |                                 float y2 = y1 + (maxOutLumi - y1) * 0.75; | 
 | 330 |  | 
 | 331 |                                 // horizontal distances between the last three control points | 
| Peiyong Lin | f2410b6 | 2018-05-14 16:31:17 -0700 | [diff] [blame] | 332 |                                 float h12 = x2 - x1; | 
 | 333 |                                 float h23 = maxInLumi - x2; | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 334 |                                 // tangents at the last three control points | 
| Peiyong Lin | f2410b6 | 2018-05-14 16:31:17 -0700 | [diff] [blame] | 335 |                                 float m1 = (y2 - y1) / h12; | 
 | 336 |                                 float m3 = (maxOutLumi - y2) / h23; | 
 | 337 |                                 float m2 = (m1 + m3) / 2.0; | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 338 |  | 
 | 339 |                                 if (nits < x0) { | 
 | 340 |                                     // scale [0.0, x0] to [0.0, y0] linearly | 
| Peiyong Lin | f2410b6 | 2018-05-14 16:31:17 -0700 | [diff] [blame] | 341 |                                     float slope = y0 / x0; | 
| Chia-I Wu | 8e86a2d | 2018-10-03 11:32:27 -0700 | [diff] [blame] | 342 |                                     return color * slope; | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 343 |                                 } else if (nits < x1) { | 
 | 344 |                                     // scale [x0, x1] to [y0, y1] linearly | 
| Peiyong Lin | f2410b6 | 2018-05-14 16:31:17 -0700 | [diff] [blame] | 345 |                                     float slope = (y1 - y0) / (x1 - x0); | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 346 |                                     nits = y0 + (nits - x0) * slope; | 
 | 347 |                                 } else if (nits < x2) { | 
 | 348 |                                     // scale [x1, x2] to [y1, y2] using Hermite interp | 
 | 349 |                                     float t = (nits - x1) / h12; | 
 | 350 |                                     nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) + | 
 | 351 |                                             (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; | 
 | 352 |                                 } else { | 
 | 353 |                                     // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp | 
 | 354 |                                     float t = (nits - x2) / h23; | 
 | 355 |                                     nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) + | 
 | 356 |                                             (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t; | 
 | 357 |                                 } | 
 | 358 |                             } | 
 | 359 |  | 
| Chia-I Wu | 8e86a2d | 2018-10-03 11:32:27 -0700 | [diff] [blame] | 360 |                             // color.y is greater than x0 and is thus non-zero | 
 | 361 |                             return color * (nits / color.y); | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 362 |                         } | 
 | 363 |                     )__SHADER__"; | 
 | 364 |                     break; | 
 | 365 |             } | 
 | 366 |             break; | 
 | 367 |         default: | 
| Peiyong Lin | 9a1b655 | 2018-05-23 16:52:29 -0700 | [diff] [blame] | 368 |             // inverse tone map; the output luminance can be up to maxOutLumi. | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 369 |             fs << R"__SHADER__( | 
 | 370 |                 highp vec3 ToneMap(highp vec3 color) { | 
| Peiyong Lin | 9a1b655 | 2018-05-23 16:52:29 -0700 | [diff] [blame] | 371 |                     const float maxOutLumi = 3000.0; | 
 | 372 |  | 
 | 373 |                     const float x0 = 5.0; | 
 | 374 |                     const float y0 = 2.5; | 
 | 375 |                     float x1 = displayMaxLuminance * 0.7; | 
 | 376 |                     float y1 = maxOutLumi * 0.15; | 
 | 377 |                     float x2 = displayMaxLuminance * 0.9; | 
 | 378 |                     float y2 = maxOutLumi * 0.45; | 
 | 379 |                     float x3 = displayMaxLuminance; | 
 | 380 |                     float y3 = maxOutLumi; | 
 | 381 |  | 
 | 382 |                     float c1 = y1 / 3.0; | 
 | 383 |                     float c2 = y2 / 2.0; | 
 | 384 |                     float c3 = y3 / 1.5; | 
 | 385 |  | 
 | 386 |                     float nits = color.y; | 
 | 387 |  | 
 | 388 |                     float scale; | 
 | 389 |                     if (nits <= x0) { | 
 | 390 |                         // scale [0.0, x0] to [0.0, y0] linearly | 
 | 391 |                         const float slope = y0 / x0; | 
| Chia-I Wu | 8e86a2d | 2018-10-03 11:32:27 -0700 | [diff] [blame] | 392 |                         return color * slope; | 
| Peiyong Lin | 9a1b655 | 2018-05-23 16:52:29 -0700 | [diff] [blame] | 393 |                     } else if (nits <= x1) { | 
 | 394 |                         // scale [x0, x1] to [y0, y1] using a curve | 
 | 395 |                         float t = (nits - x0) / (x1 - x0); | 
 | 396 |                         nits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + t * t * y1; | 
 | 397 |                     } else if (nits <= x2) { | 
 | 398 |                         // scale [x1, x2] to [y1, y2] using a curve | 
 | 399 |                         float t = (nits - x1) / (x2 - x1); | 
 | 400 |                         nits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + t * t * y2; | 
 | 401 |                     } else { | 
 | 402 |                         // scale [x2, x3] to [y2, y3] using a curve | 
 | 403 |                         float t = (nits - x2) / (x3 - x2); | 
 | 404 |                         nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3; | 
 | 405 |                     } | 
 | 406 |  | 
| Chia-I Wu | 8e86a2d | 2018-10-03 11:32:27 -0700 | [diff] [blame] | 407 |                     // color.y is greater than x0 and is thus non-zero | 
 | 408 |                     return color * (nits / color.y); | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 409 |                 } | 
 | 410 |             )__SHADER__"; | 
 | 411 |             break; | 
 | 412 |     } | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 413 |  | 
 | 414 |     // convert absolute light to relative light. | 
 | 415 |     switch (needs.getOutputTF()) { | 
 | 416 |         case Key::OUTPUT_TF_ST2084: | 
 | 417 |             fs << R"__SHADER__( | 
 | 418 |                 highp vec3 NormalizeLuminance(highp vec3 color) { | 
 | 419 |                     return color / 10000.0; | 
 | 420 |                 } | 
 | 421 |             )__SHADER__"; | 
 | 422 |             break; | 
 | 423 |         case Key::OUTPUT_TF_HLG: | 
 | 424 |             fs << R"__SHADER__( | 
 | 425 |                 highp vec3 NormalizeLuminance(highp vec3 color) { | 
 | 426 |                     return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2); | 
 | 427 |                 } | 
 | 428 |             )__SHADER__"; | 
 | 429 |             break; | 
 | 430 |         default: | 
 | 431 |             fs << R"__SHADER__( | 
 | 432 |                 highp vec3 NormalizeLuminance(highp vec3 color) { | 
 | 433 |                     return color / displayMaxLuminance; | 
 | 434 |                 } | 
 | 435 |             )__SHADER__"; | 
 | 436 |             break; | 
 | 437 |     } | 
 | 438 | } | 
 | 439 |  | 
 | 440 | // Generate OOTF that modifies the relative scence light to relative display light. | 
 | 441 | void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { | 
 | 442 |     if (!needs.needsToneMapping()) { | 
 | 443 |         fs << R"__SHADER__( | 
 | 444 |             highp vec3 OOTF(const highp vec3 color) { | 
 | 445 |                 return color; | 
 | 446 |             } | 
 | 447 |         )__SHADER__"; | 
 | 448 |     } else { | 
 | 449 |         generateToneMappingProcess(fs, needs); | 
 | 450 |         fs << R"__SHADER__( | 
 | 451 |             highp vec3 OOTF(const highp vec3 color) { | 
 | 452 |                 return NormalizeLuminance(ToneMap(ScaleLuminance(color))); | 
 | 453 |             } | 
 | 454 |         )__SHADER__"; | 
 | 455 |     } | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 456 | } | 
 | 457 |  | 
 | 458 | // Generate OETF that converts relative display light to signal values, | 
 | 459 | // both normalized to [0, 1] | 
 | 460 | void ProgramCache::generateOETF(Formatter& fs, const Key& needs) { | 
 | 461 |     switch (needs.getOutputTF()) { | 
 | 462 |         case Key::OUTPUT_TF_SRGB: | 
 | 463 |             fs << R"__SHADER__( | 
 | 464 |                 float OETF_sRGB(const float linear) { | 
 | 465 |                     return linear <= 0.0031308 ? | 
 | 466 |                             linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; | 
 | 467 |                 } | 
 | 468 |  | 
 | 469 |                 vec3 OETF_sRGB(const vec3 linear) { | 
 | 470 |                     return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b)); | 
 | 471 |                 } | 
 | 472 |  | 
 | 473 |                 vec3 OETF(const vec3 linear) { | 
 | 474 |                     return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)); | 
 | 475 |                 } | 
 | 476 |             )__SHADER__"; | 
 | 477 |             break; | 
 | 478 |         case Key::OUTPUT_TF_ST2084: | 
 | 479 |             fs << R"__SHADER__( | 
 | 480 |                 vec3 OETF(const vec3 linear) { | 
| Peiyong Lin | 834be49 | 2018-05-18 15:12:55 -0700 | [diff] [blame] | 481 |                     const highp float m1 = (2610.0 / 4096.0) / 4.0; | 
 | 482 |                     const highp float m2 = (2523.0 / 4096.0) * 128.0; | 
 | 483 |                     const highp float c1 = (3424.0 / 4096.0); | 
 | 484 |                     const highp float c2 = (2413.0 / 4096.0) * 32.0; | 
 | 485 |                     const highp float c3 = (2392.0 / 4096.0) * 32.0; | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 486 |  | 
| Peiyong Lin | 834be49 | 2018-05-18 15:12:55 -0700 | [diff] [blame] | 487 |                     highp vec3 tmp = pow(linear, vec3(m1)); | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 488 |                     tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); | 
 | 489 |                     return pow(tmp, vec3(m2)); | 
 | 490 |                 } | 
 | 491 |             )__SHADER__"; | 
 | 492 |             break; | 
 | 493 |         case Key::OUTPUT_TF_HLG: | 
 | 494 |             fs << R"__SHADER__( | 
 | 495 |                 highp float OETF_channel(const highp float channel) { | 
 | 496 |                     const highp float a = 0.17883277; | 
 | 497 |                     const highp float b = 0.28466892; | 
 | 498 |                     const highp float c = 0.55991073; | 
 | 499 |                     return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) : | 
 | 500 |                             a * log(12.0 * channel - b) + c; | 
 | 501 |                 } | 
 | 502 |  | 
 | 503 |                 vec3 OETF(const highp vec3 color) { | 
 | 504 |                     return vec3(OETF_channel(color.r), OETF_channel(color.g), | 
 | 505 |                             OETF_channel(color.b)); | 
 | 506 |                 } | 
 | 507 |             )__SHADER__"; | 
 | 508 |             break; | 
 | 509 |         default: | 
 | 510 |             fs << R"__SHADER__( | 
 | 511 |                 vec3 OETF(const vec3 linear) { | 
 | 512 |                     return linear; | 
 | 513 |                 } | 
 | 514 |             )__SHADER__"; | 
 | 515 |             break; | 
 | 516 |     } | 
 | 517 | } | 
 | 518 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 519 | String8 ProgramCache::generateVertexShader(const Key& needs) { | 
 | 520 |     Formatter vs; | 
 | 521 |     if (needs.isTexturing()) { | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 522 |         vs << "attribute vec4 texCoords;" | 
 | 523 |            << "varying vec2 outTexCoords;"; | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 524 |     } | 
 | 525 |     vs << "attribute vec4 position;" | 
 | 526 |        << "uniform mat4 projection;" | 
 | 527 |        << "uniform mat4 texture;" | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 528 |        << "void main(void) {" << indent << "gl_Position = projection * position;"; | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 529 |     if (needs.isTexturing()) { | 
 | 530 |         vs << "outTexCoords = (texture * texCoords).st;"; | 
 | 531 |     } | 
 | 532 |     vs << dedent << "}"; | 
 | 533 |     return vs.getString(); | 
 | 534 | } | 
 | 535 |  | 
 | 536 | String8 ProgramCache::generateFragmentShader(const Key& needs) { | 
 | 537 |     Formatter fs; | 
 | 538 |     if (needs.getTextureTarget() == Key::TEXTURE_EXT) { | 
 | 539 |         fs << "#extension GL_OES_EGL_image_external : require"; | 
 | 540 |     } | 
| Mathias Agopian | 458197d | 2013-08-15 14:56:51 -0700 | [diff] [blame] | 541 |  | 
 | 542 |     // default precision is required-ish in fragment shaders | 
 | 543 |     fs << "precision mediump float;"; | 
 | 544 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 545 |     if (needs.getTextureTarget() == Key::TEXTURE_EXT) { | 
 | 546 |         fs << "uniform samplerExternalOES sampler;" | 
 | 547 |            << "varying vec2 outTexCoords;"; | 
 | 548 |     } else if (needs.getTextureTarget() == Key::TEXTURE_2D) { | 
 | 549 |         fs << "uniform sampler2D sampler;" | 
 | 550 |            << "varying vec2 outTexCoords;"; | 
| chaviw | 13fdc49 | 2017-06-27 12:40:18 -0700 | [diff] [blame] | 551 |     } | 
 | 552 |  | 
 | 553 |     if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) { | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 554 |         fs << "uniform vec4 color;"; | 
 | 555 |     } | 
| chaviw | 13fdc49 | 2017-06-27 12:40:18 -0700 | [diff] [blame] | 556 |  | 
| Chia-I Wu | 131d376 | 2018-01-11 14:35:27 -0800 | [diff] [blame] | 557 |     if (needs.isY410BT2020()) { | 
 | 558 |         fs << R"__SHADER__( | 
 | 559 |             vec3 convertY410BT2020(const vec3 color) { | 
 | 560 |                 const vec3 offset = vec3(0.0625, 0.5, 0.5); | 
 | 561 |                 const mat3 transform = mat3( | 
 | 562 |                     vec3(1.1678,  1.1678, 1.1678), | 
 | 563 |                     vec3(   0.0, -0.1878, 2.1481), | 
 | 564 |                     vec3(1.6836, -0.6523,   0.0)); | 
 | 565 |                 // Y is in G, U is in R, and V is in B | 
 | 566 |                 return clamp(transform * (color.grb - offset), 0.0, 1.0); | 
 | 567 |             } | 
 | 568 |             )__SHADER__"; | 
 | 569 |     } | 
 | 570 |  | 
| Peiyong Lin | a296b0c | 2018-04-30 16:55:29 -0700 | [diff] [blame] | 571 |     if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) { | 
| Peiyong Lin | 53f320e | 2018-04-23 17:31:06 -0700 | [diff] [blame] | 572 |         // Currently, display maximum luminance is needed when doing tone mapping. | 
 | 573 |         if (needs.needsToneMapping()) { | 
| Chia-I Wu | 8bbacdf | 2018-05-04 15:19:37 -0700 | [diff] [blame] | 574 |             fs << "uniform float displayMaxLuminance;"; | 
| Peiyong Lin | fb06930 | 2018-04-25 14:34:31 -0700 | [diff] [blame] | 575 |         } | 
| Romain Guy | 88d37dd | 2017-05-26 17:57:05 -0700 | [diff] [blame] | 576 |  | 
| Peiyong Lin | a296b0c | 2018-04-30 16:55:29 -0700 | [diff] [blame] | 577 |         if (needs.hasInputTransformMatrix()) { | 
| Peiyong Lin | 76dd77a | 2018-05-09 15:35:33 -0700 | [diff] [blame] | 578 |             fs << "uniform mat4 inputTransformMatrix;"; | 
| Peiyong Lin | a296b0c | 2018-04-30 16:55:29 -0700 | [diff] [blame] | 579 |             fs << R"__SHADER__( | 
 | 580 |                 highp vec3 InputTransform(const highp vec3 color) { | 
| Chia-I Wu | 0647d4e | 2018-10-03 11:10:12 -0700 | [diff] [blame] | 581 |                     return clamp(vec3(inputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0); | 
| Peiyong Lin | a296b0c | 2018-04-30 16:55:29 -0700 | [diff] [blame] | 582 |                 } | 
 | 583 |             )__SHADER__"; | 
 | 584 |         } else { | 
 | 585 |             fs << R"__SHADER__( | 
 | 586 |                 highp vec3 InputTransform(const highp vec3 color) { | 
 | 587 |                     return color; | 
 | 588 |                 } | 
 | 589 |             )__SHADER__"; | 
 | 590 |         } | 
 | 591 |  | 
 | 592 |         // the transformation from a wider colorspace to a narrower one can | 
 | 593 |         // result in >1.0 or <0.0 pixel values | 
 | 594 |         if (needs.hasOutputTransformMatrix()) { | 
 | 595 |             fs << "uniform mat4 outputTransformMatrix;"; | 
 | 596 |             fs << R"__SHADER__( | 
 | 597 |                 highp vec3 OutputTransform(const highp vec3 color) { | 
 | 598 |                     return clamp(vec3(outputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0); | 
 | 599 |                 } | 
 | 600 |             )__SHADER__"; | 
 | 601 |         } else { | 
 | 602 |             fs << R"__SHADER__( | 
 | 603 |                 highp vec3 OutputTransform(const highp vec3 color) { | 
 | 604 |                     return clamp(color, 0.0, 1.0); | 
 | 605 |                 } | 
 | 606 |             )__SHADER__"; | 
 | 607 |         } | 
 | 608 |  | 
| Peiyong Lin | 2542cb0 | 2018-04-30 17:29:53 -0700 | [diff] [blame] | 609 |         generateEOTF(fs, needs); | 
 | 610 |         generateOOTF(fs, needs); | 
 | 611 |         generateOETF(fs, needs); | 
| Romain Guy | 88d37dd | 2017-05-26 17:57:05 -0700 | [diff] [blame] | 612 |     } | 
| Chia-I Wu | 7e65bc0 | 2018-01-11 14:31:38 -0800 | [diff] [blame] | 613 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 614 |     fs << "void main(void) {" << indent; | 
 | 615 |     if (needs.isTexturing()) { | 
 | 616 |         fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; | 
| Chia-I Wu | 131d376 | 2018-01-11 14:35:27 -0800 | [diff] [blame] | 617 |         if (needs.isY410BT2020()) { | 
 | 618 |             fs << "gl_FragColor.rgb = convertY410BT2020(gl_FragColor.rgb);"; | 
 | 619 |         } | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 620 |     } else { | 
| chaviw | 13fdc49 | 2017-06-27 12:40:18 -0700 | [diff] [blame] | 621 |         fs << "gl_FragColor.rgb = color.rgb;"; | 
 | 622 |         fs << "gl_FragColor.a = 1.0;"; | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 623 |     } | 
| Mathias Agopian | 2eaefe1 | 2013-08-14 16:33:27 -0700 | [diff] [blame] | 624 |     if (needs.isOpaque()) { | 
 | 625 |         fs << "gl_FragColor.a = 1.0;"; | 
 | 626 |     } | 
| chaviw | 13fdc49 | 2017-06-27 12:40:18 -0700 | [diff] [blame] | 627 |     if (needs.hasAlpha()) { | 
 | 628 |         // modulate the current alpha value with alpha set | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 629 |         if (needs.isPremultiplied()) { | 
 | 630 |             // ... and the color too if we're premultiplied | 
| chaviw | 13fdc49 | 2017-06-27 12:40:18 -0700 | [diff] [blame] | 631 |             fs << "gl_FragColor *= color.a;"; | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 632 |         } else { | 
| chaviw | 13fdc49 | 2017-06-27 12:40:18 -0700 | [diff] [blame] | 633 |             fs << "gl_FragColor.a *= color.a;"; | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 634 |         } | 
 | 635 |     } | 
| Mathias Agopian | ff2ed70 | 2013-09-01 21:36:12 -0700 | [diff] [blame] | 636 |  | 
| Peiyong Lin | a296b0c | 2018-04-30 16:55:29 -0700 | [diff] [blame] | 637 |     if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) { | 
| Mathias Agopian | ff2ed70 | 2013-09-01 21:36:12 -0700 | [diff] [blame] | 638 |         if (!needs.isOpaque() && needs.isPremultiplied()) { | 
 | 639 |             // un-premultiply if needed before linearization | 
| Romain Guy | 88d37dd | 2017-05-26 17:57:05 -0700 | [diff] [blame] | 640 |             // avoid divide by 0 by adding 0.5/256 to the alpha channel | 
 | 641 |             fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);"; | 
| Mathias Agopian | ff2ed70 | 2013-09-01 21:36:12 -0700 | [diff] [blame] | 642 |         } | 
| Peiyong Lin | a296b0c | 2018-04-30 16:55:29 -0700 | [diff] [blame] | 643 |         fs << "gl_FragColor.rgb = OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));"; | 
| Mathias Agopian | ff2ed70 | 2013-09-01 21:36:12 -0700 | [diff] [blame] | 644 |         if (!needs.isOpaque() && needs.isPremultiplied()) { | 
 | 645 |             // and re-premultiply if needed after gamma correction | 
| Romain Guy | 88d37dd | 2017-05-26 17:57:05 -0700 | [diff] [blame] | 646 |             fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);"; | 
| Mathias Agopian | ff2ed70 | 2013-09-01 21:36:12 -0700 | [diff] [blame] | 647 |         } | 
 | 648 |     } | 
 | 649 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 650 |     fs << dedent << "}"; | 
 | 651 |     return fs.getString(); | 
 | 652 | } | 
 | 653 |  | 
 | 654 | Program* ProgramCache::generateProgram(const Key& needs) { | 
| Chia-I Wu | 93e14df | 2018-06-04 10:10:17 -0700 | [diff] [blame] | 655 |     ATRACE_CALL(); | 
 | 656 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 657 |     // vertex shader | 
 | 658 |     String8 vs = generateVertexShader(needs); | 
 | 659 |  | 
 | 660 |     // fragment shader | 
 | 661 |     String8 fs = generateFragmentShader(needs); | 
 | 662 |  | 
 | 663 |     Program* program = new Program(needs, vs.string(), fs.string()); | 
 | 664 |     return program; | 
 | 665 | } | 
 | 666 |  | 
 | 667 | void ProgramCache::useProgram(const Description& description) { | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 668 |     // generate the key for the shader based on the description | 
 | 669 |     Key needs(computeKey(description)); | 
 | 670 |  | 
| Chia-I Wu | b027f80 | 2017-11-29 14:00:52 -0800 | [diff] [blame] | 671 |     // look-up the program in the cache | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 672 |     Program* program = mCache.valueFor(needs); | 
| Peiyong Lin | 566a3b4 | 2018-01-09 18:22:43 -0800 | [diff] [blame] | 673 |     if (program == nullptr) { | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 674 |         // we didn't find our program, so generate one... | 
 | 675 |         nsecs_t time = -systemTime(); | 
 | 676 |         program = generateProgram(needs); | 
 | 677 |         mCache.add(needs, program); | 
 | 678 |         time += systemTime(); | 
 | 679 |  | 
| Chia-I Wu | 93e14df | 2018-06-04 10:10:17 -0700 | [diff] [blame] | 680 |         ALOGV(">>> generated new program: needs=%08X, time=%u ms (%zu programs)", needs.mKey, | 
 | 681 |               uint32_t(ns2ms(time)), mCache.size()); | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 682 |     } | 
 | 683 |  | 
 | 684 |     // here we have a suitable program for this description | 
 | 685 |     if (program->isValid()) { | 
 | 686 |         program->use(); | 
 | 687 |         program->setUniforms(description); | 
 | 688 |     } | 
 | 689 | } | 
 | 690 |  | 
| Mathias Agopian | 3f84483 | 2013-08-07 21:24:32 -0700 | [diff] [blame] | 691 | } /* namespace android */ |