Home | History | Annotate | Download | only in gl
      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 
    117         inline Key() : mKey(0) {}
    118         inline Key(const Key& rhs) : mKey(rhs.mKey) {}
    119 
    120         inline Key& set(key_t mask, key_t value) {
    121             mKey = (mKey & ~mask) | value;
    122             return *this;
    123         }
    124 
    125         inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
    126         inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
    127         inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
    128         inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
    129         inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
    130         inline bool hasRoundedCorners() const {
    131             return (mKey & ROUNDED_CORNERS_MASK) == ROUNDED_CORNERS_ON;
    132         }
    133         inline bool hasInputTransformMatrix() const {
    134             return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON;
    135         }
    136         inline bool hasOutputTransformMatrix() const {
    137             return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON;
    138         }
    139         inline bool hasTransformMatrix() const {
    140             return hasInputTransformMatrix() || hasOutputTransformMatrix();
    141         }
    142         inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
    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
    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         }
    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 {
    174             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 
    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