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 
17 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 
19 #include <GLES2/gl2.h>
20 #include <GLES2/gl2ext.h>
21 
22 #include <utils/String8.h>
23 #include <utils/Trace.h>
24 
25 #include "Description.h"
26 #include "Program.h"
27 #include "ProgramCache.h"
28 
29 namespace android {
30 // -----------------------------------------------------------------------------------------------
31 
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);
47 
48 public:
Formatter()49     Formatter() : mIndent(0) {}
50 
getString() const51     String8 getString() const { return mString; }
52 
operator <<(Formatter & out,const char * in)53     friend Formatter& operator<<(Formatter& out, const char* in) {
54         for (int i = 0; i < out.mIndent; i++) {
55             out.mString.append("    ");
56         }
57         out.mString.append(in);
58         out.mString.append("\n");
59         return out;
60     }
operator <<(Formatter & out,const String8 & in)61     friend inline Formatter& operator<<(Formatter& out, const String8& in) {
62         return operator<<(out, in.string());
63     }
operator <<(Formatter & to,FormaterManipFunc func)64     friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
65         return (*func)(to);
66     }
67 };
indent(Formatter & f)68 Formatter& indent(Formatter& f) {
69     f.mIndent++;
70     return f;
71 }
dedent(Formatter & f)72 Formatter& dedent(Formatter& f) {
73     f.mIndent--;
74     return f;
75 }
76 
77 // -----------------------------------------------------------------------------------------------
78 
ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)79 ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)
80 
81 ProgramCache::ProgramCache() {}
82 
~ProgramCache()83 ProgramCache::~ProgramCache() {}
84 
primeCache(bool hasWideColor)85 void ProgramCache::primeCache(bool hasWideColor) {
86     uint32_t shaderCount = 0;
87     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK;
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();
96         if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) {
97             continue;
98         }
99         Program* program = mCache.valueFor(shaderKey);
100         if (program == nullptr) {
101             program = generateProgram(shaderKey);
102             mCache.add(shaderKey, program);
103             shaderCount++;
104         }
105     }
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 
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 
computeKey(const Description & description)132 ProgramCache::Key ProgramCache::computeKey(const Description& description) {
133     Key needs;
134     needs.set(Key::TEXTURE_MASK,
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)
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,
152                  description.hasOutputTransformMatrix() || description.hasColorMatrix() ||
153                  (!description.hasInputTransformMatrix() && description.hasSaturationMatrix()) ?
154                      Key::OUTPUT_TRANSFORM_MATRIX_ON : Key::OUTPUT_TRANSFORM_MATRIX_OFF);
155 
156     needs.set(Key::Y410_BT2020_MASK,
157               description.mY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
158 
159     if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
160         switch (description.mInputTransferFunction) {
161             case Description::TransferFunction::LINEAR:
162             default:
163                 needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_LINEAR);
164                 break;
165             case Description::TransferFunction::SRGB:
166                 needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_SRGB);
167                 break;
168             case Description::TransferFunction::ST2084:
169                 needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_ST2084);
170                 break;
171             case Description::TransferFunction::HLG:
172                 needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_HLG);
173                 break;
174         }
175 
176         switch (description.mOutputTransferFunction) {
177             case Description::TransferFunction::LINEAR:
178             default:
179                 needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_LINEAR);
180                 break;
181             case Description::TransferFunction::SRGB:
182                 needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_SRGB);
183                 break;
184             case Description::TransferFunction::ST2084:
185                 needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_ST2084);
186                 break;
187             case Description::TransferFunction::HLG:
188                 needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_HLG);
189                 break;
190         }
191     }
192 
193     return needs;
194 }
195 
196 // Generate EOTF that converts signal values to relative display light,
197 // both normalized to [0, 1].
generateEOTF(Formatter & fs,const Key & needs)198 void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) {
199     switch (needs.getInputTF()) {
200         case Key::INPUT_TF_SRGB:
201             fs << R"__SHADER__(
202                 float EOTF_sRGB(float srgb) {
203                     return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
204                 }
205 
206                 vec3 EOTF_sRGB(const vec3 srgb) {
207                     return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
208                 }
209 
210                 vec3 EOTF(const vec3 srgb) {
211                     return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
212                 }
213             )__SHADER__";
214             break;
215         case Key::INPUT_TF_ST2084:
216             fs << R"__SHADER__(
217                 vec3 EOTF(const highp vec3 color) {
218                     const highp float m1 = (2610.0 / 4096.0) / 4.0;
219                     const highp float m2 = (2523.0 / 4096.0) * 128.0;
220                     const highp float c1 = (3424.0 / 4096.0);
221                     const highp float c2 = (2413.0 / 4096.0) * 32.0;
222                     const highp float c3 = (2392.0 / 4096.0) * 32.0;
223 
224                     highp vec3 tmp = pow(color, 1.0 / vec3(m2));
225                     tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp);
226                     return pow(tmp, 1.0 / vec3(m1));
227                 }
228             )__SHADER__";
229             break;
230         case Key::INPUT_TF_HLG:
231             fs << R"__SHADER__(
232                 highp float EOTF_channel(const highp float channel) {
233                     const highp float a = 0.17883277;
234                     const highp float b = 0.28466892;
235                     const highp float c = 0.55991073;
236                     return channel <= 0.5 ? channel * channel / 3.0 :
237                             (exp((channel - c) / a) + b) / 12.0;
238                 }
239 
240                 vec3 EOTF(const highp vec3 color) {
241                     return vec3(EOTF_channel(color.r), EOTF_channel(color.g),
242                             EOTF_channel(color.b));
243                 }
244             )__SHADER__";
245             break;
246         default:
247             fs << R"__SHADER__(
248                 vec3 EOTF(const vec3 linear) {
249                     return linear;
250                 }
251             )__SHADER__";
252             break;
253     }
254 }
255 
generateToneMappingProcess(Formatter & fs,const Key & needs)256 void ProgramCache::generateToneMappingProcess(Formatter& fs, const Key& needs) {
257     // Convert relative light to absolute light.
258     switch (needs.getInputTF()) {
259         case Key::INPUT_TF_ST2084:
260             fs << R"__SHADER__(
261                 highp vec3 ScaleLuminance(highp vec3 color) {
262                     return color * 10000.0;
263                 }
264             )__SHADER__";
265             break;
266         case Key::INPUT_TF_HLG:
267             fs << R"__SHADER__(
268                 highp vec3 ScaleLuminance(highp vec3 color) {
269                     // The formula is:
270                     // alpha * pow(Y, gamma - 1.0) * color + beta;
271                     // where alpha is 1000.0, gamma is 1.2, beta is 0.0.
272                     return color * 1000.0 * pow(color.y, 0.2);
273                 }
274             )__SHADER__";
275             break;
276         default:
277             fs << R"__SHADER__(
278                 highp vec3 ScaleLuminance(highp vec3 color) {
279                     return color * displayMaxLuminance;
280                 }
281             )__SHADER__";
282             break;
283     }
284 
285     // Tone map absolute light to display luminance range.
286     switch (needs.getInputTF()) {
287         case Key::INPUT_TF_ST2084:
288         case Key::INPUT_TF_HLG:
289             switch (needs.getOutputTF()) {
290                 case Key::OUTPUT_TF_HLG:
291                     // Right now when mixed PQ and HLG contents are presented,
292                     // HLG content will always be converted to PQ. However, for
293                     // completeness, we simply clamp the value to [0.0, 1000.0].
294                     fs << R"__SHADER__(
295                         highp vec3 ToneMap(highp vec3 color) {
296                             return clamp(color, 0.0, 1000.0);
297                         }
298                     )__SHADER__";
299                     break;
300                 case Key::OUTPUT_TF_ST2084:
301                     fs << R"__SHADER__(
302                         highp vec3 ToneMap(highp vec3 color) {
303                             return color;
304                         }
305                     )__SHADER__";
306                     break;
307                 default:
308                     fs << R"__SHADER__(
309                         highp vec3 ToneMap(highp vec3 color) {
310                             const float maxMasteringLumi = 1000.0;
311                             const float maxContentLumi = 1000.0;
312                             const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
313                             float maxOutLumi = displayMaxLuminance;
314 
315                             float nits = color.y;
316 
317                             // clamp to max input luminance
318                             nits = clamp(nits, 0.0, maxInLumi);
319 
320                             // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
321                             if (maxInLumi <= maxOutLumi) {
322                                 nits *= maxOutLumi / maxInLumi;
323                             } else {
324                                 // three control points
325                                 const float x0 = 10.0;
326                                 const float y0 = 17.0;
327                                 float x1 = maxOutLumi * 0.75;
328                                 float y1 = x1;
329                                 float x2 = x1 + (maxInLumi - x1) / 2.0;
330                                 float y2 = y1 + (maxOutLumi - y1) * 0.75;
331 
332                                 // horizontal distances between the last three control points
333                                 float h12 = x2 - x1;
334                                 float h23 = maxInLumi - x2;
335                                 // tangents at the last three control points
336                                 float m1 = (y2 - y1) / h12;
337                                 float m3 = (maxOutLumi - y2) / h23;
338                                 float m2 = (m1 + m3) / 2.0;
339 
340                                 if (nits < x0) {
341                                     // scale [0.0, x0] to [0.0, y0] linearly
342                                     float slope = y0 / x0;
343                                     nits *= slope;
344                                 } else if (nits < x1) {
345                                     // scale [x0, x1] to [y0, y1] linearly
346                                     float slope = (y1 - y0) / (x1 - x0);
347                                     nits = y0 + (nits - x0) * slope;
348                                 } else if (nits < x2) {
349                                     // scale [x1, x2] to [y1, y2] using Hermite interp
350                                     float t = (nits - x1) / h12;
351                                     nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
352                                             (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
353                                 } else {
354                                     // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
355                                     float t = (nits - x2) / h23;
356                                     nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
357                                             (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
358                                 }
359                             }
360 
361                             return color * (nits / max(1e-6, color.y));
362                         }
363                     )__SHADER__";
364                     break;
365             }
366             break;
367         default:
368             // inverse tone map; the output luminance can be up to maxOutLumi.
369             fs << R"__SHADER__(
370                 highp vec3 ToneMap(highp vec3 color) {
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;
392                         nits *= slope;
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 
407                     return color * (nits / max(1e-6, color.y));
408                 }
409             )__SHADER__";
410             break;
411     }
412 
413     // convert absolute light to relative light.
414     switch (needs.getOutputTF()) {
415         case Key::OUTPUT_TF_ST2084:
416             fs << R"__SHADER__(
417                 highp vec3 NormalizeLuminance(highp vec3 color) {
418                     return color / 10000.0;
419                 }
420             )__SHADER__";
421             break;
422         case Key::OUTPUT_TF_HLG:
423             fs << R"__SHADER__(
424                 highp vec3 NormalizeLuminance(highp vec3 color) {
425                     return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2);
426                 }
427             )__SHADER__";
428             break;
429         default:
430             fs << R"__SHADER__(
431                 highp vec3 NormalizeLuminance(highp vec3 color) {
432                     return color / displayMaxLuminance;
433                 }
434             )__SHADER__";
435             break;
436     }
437 }
438 
439 // Generate OOTF that modifies the relative scence light to relative display light.
generateOOTF(Formatter & fs,const ProgramCache::Key & needs)440 void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) {
441     if (!needs.needsToneMapping()) {
442         fs << R"__SHADER__(
443             highp vec3 OOTF(const highp vec3 color) {
444                 return color;
445             }
446         )__SHADER__";
447     } else {
448         generateToneMappingProcess(fs, needs);
449         fs << R"__SHADER__(
450             highp vec3 OOTF(const highp vec3 color) {
451                 return NormalizeLuminance(ToneMap(ScaleLuminance(color)));
452             }
453         )__SHADER__";
454     }
455 }
456 
457 // Generate OETF that converts relative display light to signal values,
458 // both normalized to [0, 1]
generateOETF(Formatter & fs,const Key & needs)459 void ProgramCache::generateOETF(Formatter& fs, const Key& needs) {
460     switch (needs.getOutputTF()) {
461         case Key::OUTPUT_TF_SRGB:
462             fs << R"__SHADER__(
463                 float OETF_sRGB(const float linear) {
464                     return linear <= 0.0031308 ?
465                             linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
466                 }
467 
468                 vec3 OETF_sRGB(const vec3 linear) {
469                     return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
470                 }
471 
472                 vec3 OETF(const vec3 linear) {
473                     return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
474                 }
475             )__SHADER__";
476             break;
477         case Key::OUTPUT_TF_ST2084:
478             fs << R"__SHADER__(
479                 vec3 OETF(const vec3 linear) {
480                     const highp float m1 = (2610.0 / 4096.0) / 4.0;
481                     const highp float m2 = (2523.0 / 4096.0) * 128.0;
482                     const highp float c1 = (3424.0 / 4096.0);
483                     const highp float c2 = (2413.0 / 4096.0) * 32.0;
484                     const highp float c3 = (2392.0 / 4096.0) * 32.0;
485 
486                     highp vec3 tmp = pow(linear, vec3(m1));
487                     tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
488                     return pow(tmp, vec3(m2));
489                 }
490             )__SHADER__";
491             break;
492         case Key::OUTPUT_TF_HLG:
493             fs << R"__SHADER__(
494                 highp float OETF_channel(const highp float channel) {
495                     const highp float a = 0.17883277;
496                     const highp float b = 0.28466892;
497                     const highp float c = 0.55991073;
498                     return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) :
499                             a * log(12.0 * channel - b) + c;
500                 }
501 
502                 vec3 OETF(const highp vec3 color) {
503                     return vec3(OETF_channel(color.r), OETF_channel(color.g),
504                             OETF_channel(color.b));
505                 }
506             )__SHADER__";
507             break;
508         default:
509             fs << R"__SHADER__(
510                 vec3 OETF(const vec3 linear) {
511                     return linear;
512                 }
513             )__SHADER__";
514             break;
515     }
516 }
517 
generateVertexShader(const Key & needs)518 String8 ProgramCache::generateVertexShader(const Key& needs) {
519     Formatter vs;
520     if (needs.isTexturing()) {
521         vs << "attribute vec4 texCoords;"
522            << "varying vec2 outTexCoords;";
523     }
524     vs << "attribute vec4 position;"
525        << "uniform mat4 projection;"
526        << "uniform mat4 texture;"
527        << "void main(void) {" << indent << "gl_Position = projection * position;";
528     if (needs.isTexturing()) {
529         vs << "outTexCoords = (texture * texCoords).st;";
530     }
531     vs << dedent << "}";
532     return vs.getString();
533 }
534 
generateFragmentShader(const Key & needs)535 String8 ProgramCache::generateFragmentShader(const Key& needs) {
536     Formatter fs;
537     if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
538         fs << "#extension GL_OES_EGL_image_external : require";
539     }
540 
541     // default precision is required-ish in fragment shaders
542     fs << "precision mediump float;";
543 
544     if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
545         fs << "uniform samplerExternalOES sampler;"
546            << "varying vec2 outTexCoords;";
547     } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
548         fs << "uniform sampler2D sampler;"
549            << "varying vec2 outTexCoords;";
550     }
551 
552     if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) {
553         fs << "uniform vec4 color;";
554     }
555 
556     if (needs.isY410BT2020()) {
557         fs << R"__SHADER__(
558             vec3 convertY410BT2020(const vec3 color) {
559                 const vec3 offset = vec3(0.0625, 0.5, 0.5);
560                 const mat3 transform = mat3(
561                     vec3(1.1678,  1.1678, 1.1678),
562                     vec3(   0.0, -0.1878, 2.1481),
563                     vec3(1.6836, -0.6523,   0.0));
564                 // Y is in G, U is in R, and V is in B
565                 return clamp(transform * (color.grb - offset), 0.0, 1.0);
566             }
567             )__SHADER__";
568     }
569 
570     if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
571         // Currently, display maximum luminance is needed when doing tone mapping.
572         if (needs.needsToneMapping()) {
573             fs << "uniform float displayMaxLuminance;";
574         }
575 
576         if (needs.hasInputTransformMatrix()) {
577             fs << "uniform mat4 inputTransformMatrix;";
578             fs << R"__SHADER__(
579                 highp vec3 InputTransform(const highp vec3 color) {
580                     return vec3(inputTransformMatrix * vec4(color, 1.0));
581                 }
582             )__SHADER__";
583         } else {
584             fs << R"__SHADER__(
585                 highp vec3 InputTransform(const highp vec3 color) {
586                     return color;
587                 }
588             )__SHADER__";
589         }
590 
591         // the transformation from a wider colorspace to a narrower one can
592         // result in >1.0 or <0.0 pixel values
593         if (needs.hasOutputTransformMatrix()) {
594             fs << "uniform mat4 outputTransformMatrix;";
595             fs << R"__SHADER__(
596                 highp vec3 OutputTransform(const highp vec3 color) {
597                     return clamp(vec3(outputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0);
598                 }
599             )__SHADER__";
600         } else {
601             fs << R"__SHADER__(
602                 highp vec3 OutputTransform(const highp vec3 color) {
603                     return clamp(color, 0.0, 1.0);
604                 }
605             )__SHADER__";
606         }
607 
608         generateEOTF(fs, needs);
609         generateOOTF(fs, needs);
610         generateOETF(fs, needs);
611     }
612 
613     fs << "void main(void) {" << indent;
614     if (needs.isTexturing()) {
615         fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
616         if (needs.isY410BT2020()) {
617             fs << "gl_FragColor.rgb = convertY410BT2020(gl_FragColor.rgb);";
618         }
619     } else {
620         fs << "gl_FragColor.rgb = color.rgb;";
621         fs << "gl_FragColor.a = 1.0;";
622     }
623     if (needs.isOpaque()) {
624         fs << "gl_FragColor.a = 1.0;";
625     }
626     if (needs.hasAlpha()) {
627         // modulate the current alpha value with alpha set
628         if (needs.isPremultiplied()) {
629             // ... and the color too if we're premultiplied
630             fs << "gl_FragColor *= color.a;";
631         } else {
632             fs << "gl_FragColor.a *= color.a;";
633         }
634     }
635 
636     if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
637         if (!needs.isOpaque() && needs.isPremultiplied()) {
638             // un-premultiply if needed before linearization
639             // avoid divide by 0 by adding 0.5/256 to the alpha channel
640             fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
641         }
642         fs << "gl_FragColor.rgb = OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
643         if (!needs.isOpaque() && needs.isPremultiplied()) {
644             // and re-premultiply if needed after gamma correction
645             fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
646         }
647     }
648 
649     fs << dedent << "}";
650     return fs.getString();
651 }
652 
generateProgram(const Key & needs)653 Program* ProgramCache::generateProgram(const Key& needs) {
654     ATRACE_CALL();
655 
656     // vertex shader
657     String8 vs = generateVertexShader(needs);
658 
659     // fragment shader
660     String8 fs = generateFragmentShader(needs);
661 
662     Program* program = new Program(needs, vs.string(), fs.string());
663     return program;
664 }
665 
useProgram(const Description & description)666 void ProgramCache::useProgram(const Description& description) {
667     // generate the key for the shader based on the description
668     Key needs(computeKey(description));
669 
670     // look-up the program in the cache
671     Program* program = mCache.valueFor(needs);
672     if (program == nullptr) {
673         // we didn't find our program, so generate one...
674         nsecs_t time = -systemTime();
675         program = generateProgram(needs);
676         mCache.add(needs, program);
677         time += systemTime();
678 
679         ALOGV(">>> generated new program: needs=%08X, time=%u ms (%zu programs)", needs.mKey,
680               uint32_t(ns2ms(time)), mCache.size());
681     }
682 
683     // here we have a suitable program for this description
684     if (program->isValid()) {
685         program->use();
686         program->setUniforms(description);
687     }
688 }
689 
690 } /* namespace android */
691