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