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 #ifndef SF_RENDER_ENGINE_PROGRAMCACHE_H
18 #define SF_RENDER_ENGINE_PROGRAMCACHE_H
19 
20 #include <memory>
21 #include <unordered_map>
22 
23 #include <EGL/egl.h>
24 #include <GLES2/gl2.h>
25 #include <renderengine/private/Description.h>
26 #include <utils/Singleton.h>
27 #include <utils/TypeHelpers.h>
28 
29 namespace android {
30 
31 class String8;
32 
33 namespace renderengine {
34 
35 struct Description;
36 
37 namespace gl {
38 
39 class Formatter;
40 class Program;
41 
42 /*
43  * This class generates GLSL programs suitable to handle a given
44  * Description. It's responsible for figuring out what to
45  * generate from a Description.
46  * It also maintains a cache of these Programs.
47  */
48 class ProgramCache : public Singleton<ProgramCache> {
49 public:
50     /*
51      * Key is used to retrieve a Program in the cache.
52      * A Key is generated from a Description.
53      */
54     class Key {
55         friend class ProgramCache;
56         typedef uint32_t key_t;
57         key_t mKey;
58 
59     public:
60         enum {
61             BLEND_SHIFT = 0,
62             BLEND_MASK = 1 << BLEND_SHIFT,
63             BLEND_PREMULT = 1 << BLEND_SHIFT,
64             BLEND_NORMAL = 0 << BLEND_SHIFT,
65 
66             OPACITY_SHIFT = 1,
67             OPACITY_MASK = 1 << OPACITY_SHIFT,
68             OPACITY_OPAQUE = 1 << OPACITY_SHIFT,
69             OPACITY_TRANSLUCENT = 0 << OPACITY_SHIFT,
70 
71             ALPHA_SHIFT = 2,
72             ALPHA_MASK = 1 << ALPHA_SHIFT,
73             ALPHA_LT_ONE = 1 << ALPHA_SHIFT,
74             ALPHA_EQ_ONE = 0 << ALPHA_SHIFT,
75 
76             TEXTURE_SHIFT = 3,
77             TEXTURE_MASK = 3 << TEXTURE_SHIFT,
78             TEXTURE_OFF = 0 << TEXTURE_SHIFT,
79             TEXTURE_EXT = 1 << TEXTURE_SHIFT,
80             TEXTURE_2D = 2 << TEXTURE_SHIFT,
81 
82             ROUNDED_CORNERS_SHIFT = 5,
83             ROUNDED_CORNERS_MASK = 1 << ROUNDED_CORNERS_SHIFT,
84             ROUNDED_CORNERS_OFF = 0 << ROUNDED_CORNERS_SHIFT,
85             ROUNDED_CORNERS_ON = 1 << ROUNDED_CORNERS_SHIFT,
86 
87             INPUT_TRANSFORM_MATRIX_SHIFT = 6,
88             INPUT_TRANSFORM_MATRIX_MASK = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
89             INPUT_TRANSFORM_MATRIX_OFF = 0 << INPUT_TRANSFORM_MATRIX_SHIFT,
90             INPUT_TRANSFORM_MATRIX_ON = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
91 
92             OUTPUT_TRANSFORM_MATRIX_SHIFT = 7,
93             OUTPUT_TRANSFORM_MATRIX_MASK = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
94             OUTPUT_TRANSFORM_MATRIX_OFF = 0 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
95             OUTPUT_TRANSFORM_MATRIX_ON = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
96 
97             INPUT_TF_SHIFT = 8,
98             INPUT_TF_MASK = 3 << INPUT_TF_SHIFT,
99             INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT,
100             INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT,
101             INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT,
102             INPUT_TF_HLG = 3 << INPUT_TF_SHIFT,
103 
104             OUTPUT_TF_SHIFT = 10,
105             OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT,
106             OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT,
107             OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT,
108             OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT,
109             OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT,
110 
111             Y410_BT2020_SHIFT = 12,
112             Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT,
113             Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT,
114             Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT,
115 
116             SHADOW_SHIFT = 13,
117             SHADOW_MASK = 1 << SHADOW_SHIFT,
118             SHADOW_OFF = 0 << SHADOW_SHIFT,
119             SHADOW_ON = 1 << SHADOW_SHIFT,
120 
121             DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT = 14,
122             DISPLAY_COLOR_TRANSFORM_MATRIX_MASK = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT,
123             DISPLAY_COLOR_TRANSFORM_MATRIX_OFF = 0 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT,
124             DISPLAY_COLOR_TRANSFORM_MATRIX_ON = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT,
125         };
126 
Key()127         inline Key() : mKey(0) {}
Key(const Key & rhs)128         inline Key(const Key& rhs) : mKey(rhs.mKey) {}
129 
set(key_t mask,key_t value)130         inline Key& set(key_t mask, key_t value) {
131             mKey = (mKey & ~mask) | value;
132             return *this;
133         }
134 
isTexturing()135         inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
hasTextureCoords()136         inline bool hasTextureCoords() const { return isTexturing() && !drawShadows(); }
getTextureTarget()137         inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
isPremultiplied()138         inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
isOpaque()139         inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
hasAlpha()140         inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
hasRoundedCorners()141         inline bool hasRoundedCorners() const {
142             return (mKey & ROUNDED_CORNERS_MASK) == ROUNDED_CORNERS_ON;
143         }
drawShadows()144         inline bool drawShadows() const { return (mKey & SHADOW_MASK) == SHADOW_ON; }
hasInputTransformMatrix()145         inline bool hasInputTransformMatrix() const {
146             return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON;
147         }
hasOutputTransformMatrix()148         inline bool hasOutputTransformMatrix() const {
149             return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON;
150         }
hasDisplayColorMatrix()151         inline bool hasDisplayColorMatrix() const {
152             return (mKey & DISPLAY_COLOR_TRANSFORM_MATRIX_MASK) ==
153                     DISPLAY_COLOR_TRANSFORM_MATRIX_ON;
154         }
hasTransformMatrix()155         inline bool hasTransformMatrix() const {
156             return hasInputTransformMatrix() || hasOutputTransformMatrix();
157         }
getInputTF()158         inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
getOutputTF()159         inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); }
160 
161         // When HDR and non-HDR contents are mixed, or different types of HDR contents are
162         // mixed, we will do a tone mapping process to tone map the input content to output
163         // content. Currently, the following conversions handled, they are:
164         // * SDR -> HLG
165         // * SDR -> PQ
166         // * HLG -> PQ
needsToneMapping()167         inline bool needsToneMapping() const {
168             int inputTF = getInputTF();
169             int outputTF = getOutputTF();
170 
171             // Return false when converting from SDR to SDR.
172             if (inputTF == Key::INPUT_TF_SRGB && outputTF == Key::OUTPUT_TF_LINEAR) {
173                 return false;
174             }
175             if (inputTF == Key::INPUT_TF_LINEAR && outputTF == Key::OUTPUT_TF_SRGB) {
176                 return false;
177             }
178 
179             inputTF >>= Key::INPUT_TF_SHIFT;
180             outputTF >>= Key::OUTPUT_TF_SHIFT;
181             return inputTF != outputTF;
182         }
isY410BT2020()183         inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
184 
185         // for use by std::unordered_map
186 
187         bool operator==(const Key& other) const { return mKey == other.mKey; }
188 
189         struct Hash {
operatorHash190             size_t operator()(const Key& key) const { return static_cast<size_t>(key.mKey); }
191         };
192     };
193 
194     ProgramCache() = default;
195     ~ProgramCache() = default;
196 
197     // Generate shaders to populate the cache
198     void primeCache(const EGLContext context, bool useColorManagement, bool toneMapperShaderOnly);
199 
getSize(const EGLContext context)200     size_t getSize(const EGLContext context) { return mCaches[context].size(); }
201 
202     // useProgram lookup a suitable program in the cache or generates one
203     // if none can be found.
204     void useProgram(const EGLContext context, const Description& description);
205 
purgeCaches()206     void purgeCaches() { mCaches.clear(); }
207 
208 private:
209     // compute a cache Key from a Description
210     static Key computeKey(const Description& description);
211     // Generate EOTF based from Key.
212     static void generateEOTF(Formatter& fs, const Key& needs);
213     // Generate necessary tone mapping methods for OOTF.
214     static void generateToneMappingProcess(Formatter& fs, const Key& needs);
215     // Generate OOTF based from Key.
216     static void generateOOTF(Formatter& fs, const Key& needs);
217     // Generate OETF based from Key.
218     static void generateOETF(Formatter& fs, const Key& needs);
219     // generates a program from the Key
220     static std::unique_ptr<Program> generateProgram(const Key& needs);
221     // generates the vertex shader from the Key
222     static String8 generateVertexShader(const Key& needs);
223     // generates the fragment shader from the Key
224     static String8 generateFragmentShader(const Key& needs);
225 
226     // Key/Value map used for caching Programs. Currently the cache
227     // is never shrunk (and the GL program objects are never deleted).
228     std::unordered_map<EGLContext, std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash>>
229             mCaches;
230 };
231 
232 } // namespace gl
233 } // namespace renderengine
234 
235 ANDROID_BASIC_TYPES_TRAITS(renderengine::gl::ProgramCache::Key)
236 
237 } // namespace android
238 
239 #endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */
240