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 
Key()122         inline Key() : mKey(0) {}
Key(const Key & rhs)123         inline Key(const Key& rhs) : mKey(rhs.mKey) {}
124 
set(key_t mask,key_t value)125         inline Key& set(key_t mask, key_t value) {
126             mKey = (mKey & ~mask) | value;
127             return *this;
128         }
129 
isTexturing()130         inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
hasTextureCoords()131         inline bool hasTextureCoords() const { return isTexturing() && !drawShadows(); }
getTextureTarget()132         inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
isPremultiplied()133         inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
isOpaque()134         inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
hasAlpha()135         inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
hasRoundedCorners()136         inline bool hasRoundedCorners() const {
137             return (mKey & ROUNDED_CORNERS_MASK) == ROUNDED_CORNERS_ON;
138         }
drawShadows()139         inline bool drawShadows() const { return (mKey & SHADOW_MASK) == SHADOW_ON; }
hasInputTransformMatrix()140         inline bool hasInputTransformMatrix() const {
141             return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON;
142         }
hasOutputTransformMatrix()143         inline bool hasOutputTransformMatrix() const {
144             return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON;
145         }
hasTransformMatrix()146         inline bool hasTransformMatrix() const {
147             return hasInputTransformMatrix() || hasOutputTransformMatrix();
148         }
getInputTF()149         inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
getOutputTF()150         inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); }
151 
152         // When HDR and non-HDR contents are mixed, or different types of HDR contents are
153         // mixed, we will do a tone mapping process to tone map the input content to output
154         // content. Currently, the following conversions handled, they are:
155         // * SDR -> HLG
156         // * SDR -> PQ
157         // * HLG -> PQ
needsToneMapping()158         inline bool needsToneMapping() const {
159             int inputTF = getInputTF();
160             int outputTF = getOutputTF();
161 
162             // Return false when converting from SDR to SDR.
163             if (inputTF == Key::INPUT_TF_SRGB && outputTF == Key::OUTPUT_TF_LINEAR) {
164                 return false;
165             }
166             if (inputTF == Key::INPUT_TF_LINEAR && outputTF == Key::OUTPUT_TF_SRGB) {
167                 return false;
168             }
169 
170             inputTF >>= Key::INPUT_TF_SHIFT;
171             outputTF >>= Key::OUTPUT_TF_SHIFT;
172             return inputTF != outputTF;
173         }
isY410BT2020()174         inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
175 
176         // for use by std::unordered_map
177 
178         bool operator==(const Key& other) const { return mKey == other.mKey; }
179 
180         struct Hash {
operatorHash181             size_t operator()(const Key& key) const { return static_cast<size_t>(key.mKey); }
182         };
183     };
184 
185     ProgramCache() = default;
186     ~ProgramCache() = default;
187 
188     // Generate shaders to populate the cache
189     void primeCache(const EGLContext context, bool useColorManagement, bool toneMapperShaderOnly);
190 
getSize(const EGLContext context)191     size_t getSize(const EGLContext context) { return mCaches[context].size(); }
192 
193     // useProgram lookup a suitable program in the cache or generates one
194     // if none can be found.
195     void useProgram(const EGLContext context, const Description& description);
196 
197 private:
198     // compute a cache Key from a Description
199     static Key computeKey(const Description& description);
200     // Generate EOTF based from Key.
201     static void generateEOTF(Formatter& fs, const Key& needs);
202     // Generate necessary tone mapping methods for OOTF.
203     static void generateToneMappingProcess(Formatter& fs, const Key& needs);
204     // Generate OOTF based from Key.
205     static void generateOOTF(Formatter& fs, const Key& needs);
206     // Generate OETF based from Key.
207     static void generateOETF(Formatter& fs, const Key& needs);
208     // generates a program from the Key
209     static std::unique_ptr<Program> generateProgram(const Key& needs);
210     // generates the vertex shader from the Key
211     static String8 generateVertexShader(const Key& needs);
212     // generates the fragment shader from the Key
213     static String8 generateFragmentShader(const Key& needs);
214 
215     // Key/Value map used for caching Programs. Currently the cache
216     // is never shrunk (and the GL program objects are never deleted).
217     std::unordered_map<EGLContext, std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash>>
218             mCaches;
219 };
220 
221 } // namespace gl
222 } // namespace renderengine
223 
224 ANDROID_BASIC_TYPES_TRAITS(renderengine::gl::ProgramCache::Key)
225 
226 } // namespace android
227 
228 #endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */
229