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