Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2010 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 ANDROID_HWUI_PROGRAM_CACHE_H
     18 #define ANDROID_HWUI_PROGRAM_CACHE_H
     19 
     20 #include <utils/KeyedVector.h>
     21 #include <utils/Log.h>
     22 #include <utils/String8.h>
     23 
     24 #include <GLES2/gl2.h>
     25 
     26 #include <SkXfermode.h>
     27 
     28 #include "Debug.h"
     29 #include "Program.h"
     30 
     31 namespace android {
     32 namespace uirenderer {
     33 
     34 ///////////////////////////////////////////////////////////////////////////////
     35 // Defines
     36 ///////////////////////////////////////////////////////////////////////////////
     37 
     38 // Debug
     39 #if DEBUG_PROGRAMS
     40     #define PROGRAM_LOGD(...) LOGD(__VA_ARGS__)
     41 #else
     42     #define PROGRAM_LOGD(...)
     43 #endif
     44 
     45 // TODO: This should be set in properties
     46 #define PANEL_BIT_DEPTH 20
     47 #define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
     48 #define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
     49 
     50 #define PROGRAM_KEY_TEXTURE 0x1
     51 #define PROGRAM_KEY_A8_TEXTURE 0x2
     52 #define PROGRAM_KEY_BITMAP 0x4
     53 #define PROGRAM_KEY_GRADIENT 0x8
     54 #define PROGRAM_KEY_BITMAP_FIRST 0x10
     55 #define PROGRAM_KEY_COLOR_MATRIX 0x20
     56 #define PROGRAM_KEY_COLOR_LIGHTING 0x40
     57 #define PROGRAM_KEY_COLOR_BLEND 0x80
     58 #define PROGRAM_KEY_BITMAP_NPOT 0x100
     59 #define PROGRAM_KEY_SWAP_SRC_DST 0x2000
     60 
     61 #define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
     62 #define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
     63 
     64 // Encode the xfermodes on 6 bits
     65 #define PROGRAM_MAX_XFERMODE 0x1f
     66 #define PROGRAM_XFERMODE_SHADER_SHIFT 26
     67 #define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
     68 #define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
     69 
     70 #define PROGRAM_BITMAP_WRAPS_SHIFT 9
     71 #define PROGRAM_BITMAP_WRAPT_SHIFT 11
     72 
     73 #define PROGRAM_GRADIENT_TYPE_SHIFT 33
     74 #define PROGRAM_MODULATE_SHIFT 35
     75 
     76 #define PROGRAM_IS_POINT_SHIFT 36
     77 
     78 #define PROGRAM_HAS_AA_SHIFT 37
     79 
     80 #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
     81 #define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
     82 
     83 ///////////////////////////////////////////////////////////////////////////////
     84 // Types
     85 ///////////////////////////////////////////////////////////////////////////////
     86 
     87 typedef uint64_t programid;
     88 
     89 ///////////////////////////////////////////////////////////////////////////////
     90 // Cache
     91 ///////////////////////////////////////////////////////////////////////////////
     92 
     93 /**
     94  * Describe the features required for a given program. The features
     95  * determine the generation of both the vertex and fragment shaders.
     96  * A ProgramDescription must be used in conjunction with a ProgramCache.
     97  */
     98 struct ProgramDescription {
     99     enum ColorModifier {
    100         kColorNone,
    101         kColorMatrix,
    102         kColorLighting,
    103         kColorBlend
    104     };
    105 
    106     enum Gradient {
    107         kGradientLinear,
    108         kGradientCircular,
    109         kGradientSweep
    110     };
    111 
    112     ProgramDescription() {
    113         reset();
    114     }
    115 
    116     // Texturing
    117     bool hasTexture;
    118     bool hasAlpha8Texture;
    119     bool hasExternalTexture;
    120     bool hasTextureTransform;
    121 
    122     // Modulate, this should only be set when setColor() return true
    123     bool modulate;
    124 
    125     // Shaders
    126     bool hasBitmap;
    127     bool isBitmapNpot;
    128 
    129     bool isAA;
    130 
    131     bool hasGradient;
    132     Gradient gradientType;
    133 
    134     SkXfermode::Mode shadersMode;
    135 
    136     bool isBitmapFirst;
    137     GLenum bitmapWrapS;
    138     GLenum bitmapWrapT;
    139 
    140     // Color operations
    141     ColorModifier colorOp;
    142     SkXfermode::Mode colorMode;
    143 
    144     // Framebuffer blending (requires Extensions.hasFramebufferFetch())
    145     // Ignored for all values < SkXfermode::kPlus_Mode
    146     SkXfermode::Mode framebufferMode;
    147     bool swapSrcDst;
    148 
    149     bool isPoint;
    150     float pointSize;
    151 
    152     /**
    153      * Resets this description. All fields are reset back to the default
    154      * values they hold after building a new instance.
    155      */
    156     void reset() {
    157         hasTexture = false;
    158         hasAlpha8Texture = false;
    159         hasExternalTexture = false;
    160         hasTextureTransform = false;
    161 
    162         isAA = false;
    163 
    164         modulate = false;
    165 
    166         hasBitmap = false;
    167         isBitmapNpot = false;
    168 
    169         hasGradient = false;
    170         gradientType = kGradientLinear;
    171 
    172         shadersMode = SkXfermode::kClear_Mode;
    173 
    174         isBitmapFirst = false;
    175         bitmapWrapS = GL_CLAMP_TO_EDGE;
    176         bitmapWrapT = GL_CLAMP_TO_EDGE;
    177 
    178         colorOp = kColorNone;
    179         colorMode = SkXfermode::kClear_Mode;
    180 
    181         framebufferMode = SkXfermode::kClear_Mode;
    182         swapSrcDst = false;
    183 
    184         isPoint = false;
    185         pointSize = 0.0f;
    186     }
    187 
    188     /**
    189      * Indicates, for a given color, whether color modulation is required in
    190      * the fragment shader. When this method returns true, the program should
    191      * be provided with a modulation color.
    192      */
    193     bool setColor(const float r, const float g, const float b, const float a) {
    194         modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
    195                 g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
    196         return modulate;
    197     }
    198 
    199     /**
    200      * Indicates, for a given color, whether color modulation is required in
    201      * the fragment shader. When this method returns true, the program should
    202      * be provided with a modulation color.
    203      */
    204     bool setAlpha8Color(const float r, const float g, const float b, const float a) {
    205         modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
    206                 g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
    207         return modulate;
    208     }
    209 
    210     /**
    211      * Computes the unique key identifying this program.
    212      */
    213     programid key() const {
    214         programid key = 0;
    215         if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
    216         if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
    217         if (hasBitmap) {
    218             key |= PROGRAM_KEY_BITMAP;
    219             if (isBitmapNpot) {
    220                 key |= PROGRAM_KEY_BITMAP_NPOT;
    221                 key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
    222                 key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
    223             }
    224         }
    225         if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
    226         key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
    227         if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
    228         if (hasBitmap && hasGradient) {
    229             key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
    230         }
    231         switch (colorOp) {
    232             case kColorMatrix:
    233                 key |= PROGRAM_KEY_COLOR_MATRIX;
    234                 break;
    235             case kColorLighting:
    236                 key |= PROGRAM_KEY_COLOR_LIGHTING;
    237                 break;
    238             case kColorBlend:
    239                 key |= PROGRAM_KEY_COLOR_BLEND;
    240                 key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
    241                 break;
    242             case kColorNone:
    243                 break;
    244         }
    245         key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
    246         if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
    247         if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
    248         if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
    249         if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
    250         if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
    251         if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
    252         return key;
    253     }
    254 
    255     /**
    256      * Logs the specified message followed by the key identifying this program.
    257      */
    258     void log(const char* message) const {
    259 #if DEBUG_PROGRAMS
    260         programid k = key();
    261         PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
    262                 uint32_t(k & 0xffffffff));
    263 #endif
    264     }
    265 
    266 private:
    267     inline uint32_t getEnumForWrap(GLenum wrap) const {
    268         switch (wrap) {
    269             case GL_CLAMP_TO_EDGE:
    270                 return 0;
    271             case GL_REPEAT:
    272                 return 1;
    273             case GL_MIRRORED_REPEAT:
    274                 return 2;
    275         }
    276         return 0;
    277     }
    278 
    279 }; // struct ProgramDescription
    280 
    281 /**
    282  * Generates and caches program. Programs are generated based on
    283  * ProgramDescriptions.
    284  */
    285 class ProgramCache {
    286 public:
    287     ProgramCache();
    288     ~ProgramCache();
    289 
    290     Program* get(const ProgramDescription& description);
    291 
    292     void clear();
    293 
    294 private:
    295     Program* generateProgram(const ProgramDescription& description, programid key);
    296     String8 generateVertexShader(const ProgramDescription& description);
    297     String8 generateFragmentShader(const ProgramDescription& description);
    298     void generateBlend(String8& shader, const char* name, SkXfermode::Mode mode);
    299     void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT);
    300 
    301     void printLongString(const String8& shader) const;
    302 
    303     KeyedVector<programid, Program*> mCache;
    304 }; // class ProgramCache
    305 
    306 }; // namespace uirenderer
    307 }; // namespace android
    308 
    309 #endif // ANDROID_HWUI_PROGRAM_CACHE_H
    310