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 <GLES2/gl2.h>
21
22#include <utils/KeyedVector.h>
23#include <utils/Singleton.h>
24#include <utils/TypeHelpers.h>
25
26#include "Description.h"
27
28namespace android {
29
30class Description;
31class Formatter;
32class Program;
33class String8;
34
35/*
36 * This class generates GLSL programs suitable to handle a given
37 * Description. It's responsible for figuring out what to
38 * generate from a Description.
39 * It also maintains a cache of these Programs.
40 */
41class ProgramCache : public Singleton<ProgramCache> {
42public:
43    /*
44     * Key is used to retrieve a Program in the cache.
45     * A Key is generated from a Description.
46     */
47    class Key {
48        friend class ProgramCache;
49        typedef uint32_t key_t;
50        key_t mKey;
51
52    public:
53        enum {
54            BLEND_SHIFT = 0,
55            BLEND_MASK = 1 << BLEND_SHIFT,
56            BLEND_PREMULT = 1 << BLEND_SHIFT,
57            BLEND_NORMAL = 0 << BLEND_SHIFT,
58
59            OPACITY_SHIFT = 1,
60            OPACITY_MASK = 1 << OPACITY_SHIFT,
61            OPACITY_OPAQUE = 1 << OPACITY_SHIFT,
62            OPACITY_TRANSLUCENT = 0 << OPACITY_SHIFT,
63
64            ALPHA_SHIFT = 2,
65            ALPHA_MASK = 1 << ALPHA_SHIFT,
66            ALPHA_LT_ONE = 1 << ALPHA_SHIFT,
67            ALPHA_EQ_ONE = 0 << ALPHA_SHIFT,
68
69            TEXTURE_SHIFT = 3,
70            TEXTURE_MASK = 3 << TEXTURE_SHIFT,
71            TEXTURE_OFF = 0 << TEXTURE_SHIFT,
72            TEXTURE_EXT = 1 << TEXTURE_SHIFT,
73            TEXTURE_2D = 2 << TEXTURE_SHIFT,
74
75            INPUT_TRANSFORM_MATRIX_SHIFT = 5,
76            INPUT_TRANSFORM_MATRIX_MASK = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
77            INPUT_TRANSFORM_MATRIX_OFF = 0 << INPUT_TRANSFORM_MATRIX_SHIFT,
78            INPUT_TRANSFORM_MATRIX_ON = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
79
80            OUTPUT_TRANSFORM_MATRIX_SHIFT = 6,
81            OUTPUT_TRANSFORM_MATRIX_MASK = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
82            OUTPUT_TRANSFORM_MATRIX_OFF = 0 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
83            OUTPUT_TRANSFORM_MATRIX_ON = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
84
85            INPUT_TF_SHIFT = 7,
86            INPUT_TF_MASK = 3 << INPUT_TF_SHIFT,
87            INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT,
88            INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT,
89            INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT,
90            INPUT_TF_HLG = 3 << INPUT_TF_SHIFT,
91
92            OUTPUT_TF_SHIFT = 9,
93            OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT,
94            OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT,
95            OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT,
96            OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT,
97            OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT,
98
99            Y410_BT2020_SHIFT = 11,
100            Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT,
101            Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT,
102            Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT,
103        };
104
105        inline Key() : mKey(0) {}
106        inline Key(const Key& rhs) : mKey(rhs.mKey) {}
107
108        inline Key& set(key_t mask, key_t value) {
109            mKey = (mKey & ~mask) | value;
110            return *this;
111        }
112
113        inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
114        inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
115        inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
116        inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
117        inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
118        inline bool hasInputTransformMatrix() const {
119            return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON;
120        }
121        inline bool hasOutputTransformMatrix() const {
122            return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON;
123        }
124        inline bool hasTransformMatrix() const {
125            return hasInputTransformMatrix() || hasOutputTransformMatrix();
126        }
127        inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
128        inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); }
129
130        // When HDR and non-HDR contents are mixed, or different types of HDR contents are
131        // mixed, we will do a tone mapping process to tone map the input content to output
132        // content. Currently, the following conversions handled, they are:
133        // * SDR -> HLG
134        // * SDR -> PQ
135        // * HLG -> PQ
136        inline bool needsToneMapping() const {
137            int inputTF = getInputTF();
138            int outputTF = getOutputTF();
139
140            // Return false when converting from SDR to SDR.
141            if (inputTF == Key::INPUT_TF_SRGB && outputTF == Key::OUTPUT_TF_LINEAR) {
142                return false;
143            }
144            if (inputTF == Key::INPUT_TF_LINEAR && outputTF == Key::OUTPUT_TF_SRGB) {
145                return false;
146            }
147
148            inputTF >>= Key::INPUT_TF_SHIFT;
149            outputTF >>= Key::OUTPUT_TF_SHIFT;
150            return inputTF != outputTF;
151        }
152        inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
153
154        // this is the definition of a friend function -- not a method of class Needs
155        friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
156            return (lhs.mKey < rhs.mKey) ? 1 : 0;
157        }
158    };
159
160    ProgramCache();
161    ~ProgramCache();
162
163    // Generate shaders to populate the cache
164    void primeCache(bool hasWideColor);
165
166    // useProgram lookup a suitable program in the cache or generates one
167    // if none can be found.
168    void useProgram(const Description& description);
169
170private:
171    // compute a cache Key from a Description
172    static Key computeKey(const Description& description);
173    // Generate EOTF based from Key.
174    static void generateEOTF(Formatter& fs, const Key& needs);
175    // Generate necessary tone mapping methods for OOTF.
176    static void generateToneMappingProcess(Formatter& fs, const Key& needs);
177    // Generate OOTF based from Key.
178    static void generateOOTF(Formatter& fs, const Key& needs);
179    // Generate OETF based from Key.
180    static void generateOETF(Formatter& fs, const Key& needs);
181    // generates a program from the Key
182    static Program* generateProgram(const Key& needs);
183    // generates the vertex shader from the Key
184    static String8 generateVertexShader(const Key& needs);
185    // generates the fragment shader from the Key
186    static String8 generateFragmentShader(const Key& needs);
187
188    // Key/Value map used for caching Programs. Currently the cache
189    // is never shrunk.
190    DefaultKeyedVector<Key, Program*> mCache;
191};
192
193ANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key)
194
195} /* namespace android */
196
197#endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */
198