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 #define LOG_TAG "OpenGLRenderer"
     18 
     19 #include <utils/String8.h>
     20 
     21 #include "Caches.h"
     22 #include "Dither.h"
     23 #include "ProgramCache.h"
     24 
     25 namespace android {
     26 namespace uirenderer {
     27 
     28 ///////////////////////////////////////////////////////////////////////////////
     29 // Defines
     30 ///////////////////////////////////////////////////////////////////////////////
     31 
     32 #define MODULATE_OP_NO_MODULATE 0
     33 #define MODULATE_OP_MODULATE 1
     34 #define MODULATE_OP_MODULATE_A8 2
     35 
     36 #define STR(x) STR1(x)
     37 #define STR1(x) #x
     38 
     39 ///////////////////////////////////////////////////////////////////////////////
     40 // Vertex shaders snippets
     41 ///////////////////////////////////////////////////////////////////////////////
     42 
     43 const char* gVS_Header_Attributes =
     44         "attribute vec4 position;\n";
     45 const char* gVS_Header_Attributes_TexCoords =
     46         "attribute vec2 texCoords;\n";
     47 const char* gVS_Header_Attributes_Colors =
     48         "attribute vec4 colors;\n";
     49 const char* gVS_Header_Attributes_AAVertexShapeParameters =
     50         "attribute float vtxAlpha;\n";
     51 const char* gVS_Header_Uniforms_TextureTransform =
     52         "uniform mat4 mainTextureTransform;\n";
     53 const char* gVS_Header_Uniforms =
     54         "uniform mat4 projection;\n" \
     55         "uniform mat4 transform;\n";
     56 const char* gVS_Header_Uniforms_HasGradient =
     57         "uniform mat4 screenSpace;\n";
     58 const char* gVS_Header_Uniforms_HasBitmap =
     59         "uniform mat4 textureTransform;\n"
     60         "uniform mediump vec2 textureDimension;\n";
     61 const char* gVS_Header_Varyings_HasTexture =
     62         "varying vec2 outTexCoords;\n";
     63 const char* gVS_Header_Varyings_HasColors =
     64         "varying vec4 outColors;\n";
     65 const char* gVS_Header_Varyings_IsAAVertexShape =
     66         "varying float alpha;\n";
     67 const char* gVS_Header_Varyings_HasBitmap =
     68         "varying highp vec2 outBitmapTexCoords;\n";
     69 const char* gVS_Header_Varyings_HasGradient[6] = {
     70         // Linear
     71         "varying highp vec2 linear;\n"
     72         "varying vec2 ditherTexCoords;\n",
     73         "varying float linear;\n"
     74         "varying vec2 ditherTexCoords;\n",
     75 
     76         // Circular
     77         "varying highp vec2 circular;\n"
     78         "varying vec2 ditherTexCoords;\n",
     79         "varying highp vec2 circular;\n"
     80         "varying vec2 ditherTexCoords;\n",
     81 
     82         // Sweep
     83         "varying highp vec2 sweep;\n"
     84         "varying vec2 ditherTexCoords;\n",
     85         "varying highp vec2 sweep;\n"
     86         "varying vec2 ditherTexCoords;\n",
     87 };
     88 const char* gVS_Main =
     89         "\nvoid main(void) {\n";
     90 const char* gVS_Main_OutTexCoords =
     91         "    outTexCoords = texCoords;\n";
     92 const char* gVS_Main_OutColors =
     93         "    outColors = colors;\n";
     94 const char* gVS_Main_OutTransformedTexCoords =
     95         "    outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
     96 const char* gVS_Main_OutGradient[6] = {
     97         // Linear
     98         "    linear = vec2((screenSpace * position).x, 0.5);\n"
     99         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
    100         "    linear = (screenSpace * position).x;\n"
    101         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
    102 
    103         // Circular
    104         "    circular = (screenSpace * position).xy;\n"
    105         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
    106         "    circular = (screenSpace * position).xy;\n"
    107         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
    108 
    109         // Sweep
    110         "    sweep = (screenSpace * position).xy;\n"
    111         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
    112         "    sweep = (screenSpace * position).xy;\n"
    113         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
    114 };
    115 const char* gVS_Main_OutBitmapTexCoords =
    116         "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
    117 const char* gVS_Main_Position =
    118         "    gl_Position = projection * transform * position;\n";
    119 const char* gVS_Main_AAVertexShape =
    120         "    alpha = vtxAlpha;\n";
    121 const char* gVS_Footer =
    122         "}\n\n";
    123 
    124 ///////////////////////////////////////////////////////////////////////////////
    125 // Fragment shaders snippets
    126 ///////////////////////////////////////////////////////////////////////////////
    127 
    128 const char* gFS_Header_Extension_FramebufferFetch =
    129         "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
    130 const char* gFS_Header_Extension_ExternalTexture =
    131         "#extension GL_OES_EGL_image_external : require\n\n";
    132 const char* gFS_Header =
    133         "precision mediump float;\n\n";
    134 const char* gFS_Uniforms_Color =
    135         "uniform vec4 color;\n";
    136 const char* gFS_Uniforms_TextureSampler =
    137         "uniform sampler2D baseSampler;\n";
    138 const char* gFS_Uniforms_ExternalTextureSampler =
    139         "uniform samplerExternalOES baseSampler;\n";
    140 const char* gFS_Uniforms_Dither =
    141         "uniform sampler2D ditherSampler;";
    142 const char* gFS_Uniforms_GradientSampler[2] = {
    143         "%s\n"
    144         "uniform sampler2D gradientSampler;\n",
    145         "%s\n"
    146         "uniform vec4 startColor;\n"
    147         "uniform vec4 endColor;\n"
    148 };
    149 const char* gFS_Uniforms_BitmapSampler =
    150         "uniform sampler2D bitmapSampler;\n";
    151 const char* gFS_Uniforms_ColorOp[4] = {
    152         // None
    153         "",
    154         // Matrix
    155         "uniform mat4 colorMatrix;\n"
    156         "uniform vec4 colorMatrixVector;\n",
    157         // Lighting
    158         "uniform vec4 lightingMul;\n"
    159         "uniform vec4 lightingAdd;\n",
    160         // PorterDuff
    161         "uniform vec4 colorBlend;\n"
    162 };
    163 const char* gFS_Uniforms_Gamma =
    164         "uniform float gamma;\n";
    165 
    166 const char* gFS_Main =
    167         "\nvoid main(void) {\n"
    168         "    lowp vec4 fragColor;\n";
    169 
    170 const char* gFS_Main_Dither[2] = {
    171         // ES 2.0
    172         "texture2D(ditherSampler, ditherTexCoords).a * " STR(DITHER_KERNEL_SIZE_INV_SQUARE),
    173         // ES 3.0
    174         "texture2D(ditherSampler, ditherTexCoords).a"
    175 };
    176 const char* gFS_Main_AddDitherToGradient =
    177         "    gradientColor += %s;\n";
    178 
    179 // Fast cases
    180 const char* gFS_Fast_SingleColor =
    181         "\nvoid main(void) {\n"
    182         "    gl_FragColor = color;\n"
    183         "}\n\n";
    184 const char* gFS_Fast_SingleTexture =
    185         "\nvoid main(void) {\n"
    186         "    gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
    187         "}\n\n";
    188 const char* gFS_Fast_SingleModulateTexture =
    189         "\nvoid main(void) {\n"
    190         "    gl_FragColor = color.a * texture2D(baseSampler, outTexCoords);\n"
    191         "}\n\n";
    192 const char* gFS_Fast_SingleA8Texture =
    193         "\nvoid main(void) {\n"
    194         "    gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
    195         "}\n\n";
    196 const char* gFS_Fast_SingleA8Texture_ApplyGamma =
    197         "\nvoid main(void) {\n"
    198         "    gl_FragColor = vec4(0.0, 0.0, 0.0, pow(texture2D(baseSampler, outTexCoords).a, gamma));\n"
    199         "}\n\n";
    200 const char* gFS_Fast_SingleModulateA8Texture =
    201         "\nvoid main(void) {\n"
    202         "    gl_FragColor = color * texture2D(baseSampler, outTexCoords).a;\n"
    203         "}\n\n";
    204 const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma =
    205         "\nvoid main(void) {\n"
    206         "    gl_FragColor = color * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
    207         "}\n\n";
    208 const char* gFS_Fast_SingleGradient[2] = {
    209         "\nvoid main(void) {\n"
    210         "    gl_FragColor = %s + texture2D(gradientSampler, linear);\n"
    211         "}\n\n",
    212         "\nvoid main(void) {\n"
    213         "    gl_FragColor = %s + mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
    214         "}\n\n",
    215 };
    216 const char* gFS_Fast_SingleModulateGradient[2] = {
    217         "\nvoid main(void) {\n"
    218         "    gl_FragColor = %s + color.a * texture2D(gradientSampler, linear);\n"
    219         "}\n\n",
    220         "\nvoid main(void) {\n"
    221         "    gl_FragColor = %s + color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
    222         "}\n\n"
    223 };
    224 
    225 // General case
    226 const char* gFS_Main_FetchColor =
    227         "    fragColor = color;\n";
    228 const char* gFS_Main_ModulateColor =
    229         "    fragColor *= color.a;\n";
    230 const char* gFS_Main_AccountForAAVertexShape =
    231         "    fragColor *= alpha;\n";
    232 
    233 const char* gFS_Main_FetchTexture[2] = {
    234         // Don't modulate
    235         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
    236         // Modulate
    237         "    fragColor = color * texture2D(baseSampler, outTexCoords);\n"
    238 };
    239 const char* gFS_Main_FetchA8Texture[4] = {
    240         // Don't modulate
    241         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
    242         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
    243         // Modulate
    244         "    fragColor = color * texture2D(baseSampler, outTexCoords).a;\n",
    245         "    fragColor = color * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
    246 };
    247 const char* gFS_Main_FetchGradient[6] = {
    248         // Linear
    249         "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
    250 
    251         "    vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
    252 
    253         // Circular
    254         "    vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
    255 
    256         "    vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
    257 
    258         // Sweep
    259         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
    260         "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
    261 
    262         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
    263         "    vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
    264 };
    265 const char* gFS_Main_FetchBitmap =
    266         "    vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
    267 const char* gFS_Main_FetchBitmapNpot =
    268         "    vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
    269 const char* gFS_Main_BlendShadersBG =
    270         "    fragColor = blendShaders(gradientColor, bitmapColor)";
    271 const char* gFS_Main_BlendShadersGB =
    272         "    fragColor = blendShaders(bitmapColor, gradientColor)";
    273 const char* gFS_Main_BlendShaders_Modulate[6] = {
    274         // Don't modulate
    275         ";\n",
    276         ";\n",
    277         // Modulate
    278         " * color.a;\n",
    279         " * color.a;\n",
    280         // Modulate with alpha 8 texture
    281         " * texture2D(baseSampler, outTexCoords).a;\n",
    282         " * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
    283 };
    284 const char* gFS_Main_GradientShader_Modulate[6] = {
    285         // Don't modulate
    286         "    fragColor = gradientColor;\n",
    287         "    fragColor = gradientColor;\n",
    288         // Modulate
    289         "    fragColor = gradientColor * color.a;\n",
    290         "    fragColor = gradientColor * color.a;\n",
    291         // Modulate with alpha 8 texture
    292         "    fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n",
    293         "    fragColor = gradientColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
    294     };
    295 const char* gFS_Main_BitmapShader_Modulate[6] = {
    296         // Don't modulate
    297         "    fragColor = bitmapColor;\n",
    298         "    fragColor = bitmapColor;\n",
    299         // Modulate
    300         "    fragColor = bitmapColor * color.a;\n",
    301         "    fragColor = bitmapColor * color.a;\n",
    302         // Modulate with alpha 8 texture
    303         "    fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n",
    304         "    fragColor = bitmapColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
    305     };
    306 const char* gFS_Main_FragColor =
    307         "    gl_FragColor = fragColor;\n";
    308 const char* gFS_Main_FragColor_HasColors =
    309         "    gl_FragColor *= outColors;\n";
    310 const char* gFS_Main_FragColor_Blend =
    311         "    gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
    312 const char* gFS_Main_FragColor_Blend_Swap =
    313         "    gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
    314 const char* gFS_Main_ApplyColorOp[4] = {
    315         // None
    316         "",
    317         // Matrix
    318         "    fragColor *= colorMatrix;\n"
    319         "    fragColor += colorMatrixVector;\n"
    320         "    fragColor.rgb *= fragColor.a;\n",
    321         // Lighting
    322         "    float lightingAlpha = fragColor.a;\n"
    323         "    fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n"
    324         "    fragColor.a = lightingAlpha;\n",
    325         // PorterDuff
    326         "    fragColor = blendColors(colorBlend, fragColor);\n"
    327 };
    328 const char* gFS_Main_DebugHighlight =
    329         "    gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
    330 const char* gFS_Main_EmulateStencil =
    331         "    gl_FragColor.rgba = vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 1.0);\n"
    332         "    return;\n"
    333         "    /*\n";
    334 const char* gFS_Footer_EmulateStencil =
    335         "    */\n";
    336 const char* gFS_Footer =
    337         "}\n\n";
    338 
    339 ///////////////////////////////////////////////////////////////////////////////
    340 // PorterDuff snippets
    341 ///////////////////////////////////////////////////////////////////////////////
    342 
    343 const char* gBlendOps[18] = {
    344         // Clear
    345         "return vec4(0.0, 0.0, 0.0, 0.0);\n",
    346         // Src
    347         "return src;\n",
    348         // Dst
    349         "return dst;\n",
    350         // SrcOver
    351         "return src + dst * (1.0 - src.a);\n",
    352         // DstOver
    353         "return dst + src * (1.0 - dst.a);\n",
    354         // SrcIn
    355         "return src * dst.a;\n",
    356         // DstIn
    357         "return dst * src.a;\n",
    358         // SrcOut
    359         "return src * (1.0 - dst.a);\n",
    360         // DstOut
    361         "return dst * (1.0 - src.a);\n",
    362         // SrcAtop
    363         "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
    364         // DstAtop
    365         "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
    366         // Xor
    367         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
    368                 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
    369         // Add
    370         "return min(src + dst, 1.0);\n",
    371         // Multiply
    372         "return src * dst;\n",
    373         // Screen
    374         "return src + dst - src * dst;\n",
    375         // Overlay
    376         "return clamp(vec4(mix("
    377                 "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
    378                 "src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
    379                 "step(dst.a, 2.0 * dst.rgb)), "
    380                 "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
    381         // Darken
    382         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
    383                 "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
    384         // Lighten
    385         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
    386                 "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
    387 };
    388 
    389 ///////////////////////////////////////////////////////////////////////////////
    390 // Constructors/destructors
    391 ///////////////////////////////////////////////////////////////////////////////
    392 
    393 ProgramCache::ProgramCache(): mHasES3(Extensions::getInstance().getMajorGlVersion() >= 3) {
    394 }
    395 
    396 ProgramCache::~ProgramCache() {
    397     clear();
    398 }
    399 
    400 ///////////////////////////////////////////////////////////////////////////////
    401 // Cache management
    402 ///////////////////////////////////////////////////////////////////////////////
    403 
    404 void ProgramCache::clear() {
    405     PROGRAM_LOGD("Clearing program cache");
    406 
    407     size_t count = mCache.size();
    408     for (size_t i = 0; i < count; i++) {
    409         delete mCache.valueAt(i);
    410     }
    411     mCache.clear();
    412 }
    413 
    414 Program* ProgramCache::get(const ProgramDescription& description) {
    415     programid key = description.key();
    416     if (key == (PROGRAM_KEY_TEXTURE | PROGRAM_KEY_A8_TEXTURE)) {
    417         // program for A8, unmodulated, texture w/o shader (black text/path textures) is equivalent
    418         // to standard texture program (bitmaps, patches). Consider them equivalent.
    419         key = PROGRAM_KEY_TEXTURE;
    420     }
    421 
    422     ssize_t index = mCache.indexOfKey(key);
    423     Program* program = NULL;
    424     if (index < 0) {
    425         description.log("Could not find program");
    426         program = generateProgram(description, key);
    427         mCache.add(key, program);
    428     } else {
    429         program = mCache.valueAt(index);
    430     }
    431     return program;
    432 }
    433 
    434 ///////////////////////////////////////////////////////////////////////////////
    435 // Program generation
    436 ///////////////////////////////////////////////////////////////////////////////
    437 
    438 Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
    439     String8 vertexShader = generateVertexShader(description);
    440     String8 fragmentShader = generateFragmentShader(description);
    441 
    442     return new Program(description, vertexShader.string(), fragmentShader.string());
    443 }
    444 
    445 static inline size_t gradientIndex(const ProgramDescription& description) {
    446     return description.gradientType * 2 + description.isSimpleGradient;
    447 }
    448 
    449 String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
    450     // Add attributes
    451     String8 shader(gVS_Header_Attributes);
    452     if (description.hasTexture || description.hasExternalTexture) {
    453         shader.append(gVS_Header_Attributes_TexCoords);
    454     }
    455     if (description.isAA) {
    456         shader.append(gVS_Header_Attributes_AAVertexShapeParameters);
    457     }
    458     if (description.hasColors) {
    459         shader.append(gVS_Header_Attributes_Colors);
    460     }
    461     // Uniforms
    462     shader.append(gVS_Header_Uniforms);
    463     if (description.hasTextureTransform) {
    464         shader.append(gVS_Header_Uniforms_TextureTransform);
    465     }
    466     if (description.hasGradient) {
    467         shader.append(gVS_Header_Uniforms_HasGradient);
    468     }
    469     if (description.hasBitmap) {
    470         shader.append(gVS_Header_Uniforms_HasBitmap);
    471     }
    472     // Varyings
    473     if (description.hasTexture || description.hasExternalTexture) {
    474         shader.append(gVS_Header_Varyings_HasTexture);
    475     }
    476     if (description.isAA) {
    477         shader.append(gVS_Header_Varyings_IsAAVertexShape);
    478     }
    479     if (description.hasColors) {
    480         shader.append(gVS_Header_Varyings_HasColors);
    481     }
    482     if (description.hasGradient) {
    483         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
    484     }
    485     if (description.hasBitmap) {
    486         shader.append(gVS_Header_Varyings_HasBitmap);
    487     }
    488 
    489     // Begin the shader
    490     shader.append(gVS_Main); {
    491         if (description.hasTextureTransform) {
    492             shader.append(gVS_Main_OutTransformedTexCoords);
    493         } else if (description.hasTexture || description.hasExternalTexture) {
    494             shader.append(gVS_Main_OutTexCoords);
    495         }
    496         if (description.isAA) {
    497             shader.append(gVS_Main_AAVertexShape);
    498         }
    499         if (description.hasColors) {
    500             shader.append(gVS_Main_OutColors);
    501         }
    502         if (description.hasBitmap) {
    503             shader.append(gVS_Main_OutBitmapTexCoords);
    504         }
    505         // Output transformed position
    506         shader.append(gVS_Main_Position);
    507         if (description.hasGradient) {
    508             shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
    509         }
    510     }
    511     // End the shader
    512     shader.append(gVS_Footer);
    513 
    514     PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
    515 
    516     return shader;
    517 }
    518 
    519 static bool shaderOp(const ProgramDescription& description, String8& shader,
    520         const int modulateOp, const char** snippets) {
    521     int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
    522     op = op * 2 + description.hasGammaCorrection;
    523     shader.append(snippets[op]);
    524     return description.hasAlpha8Texture;
    525 }
    526 
    527 String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
    528     String8 shader;
    529 
    530     const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
    531     if (blendFramebuffer) {
    532         shader.append(gFS_Header_Extension_FramebufferFetch);
    533     }
    534     if (description.hasExternalTexture) {
    535         shader.append(gFS_Header_Extension_ExternalTexture);
    536     }
    537 
    538     shader.append(gFS_Header);
    539 
    540     // Varyings
    541     if (description.hasTexture || description.hasExternalTexture) {
    542         shader.append(gVS_Header_Varyings_HasTexture);
    543     }
    544     if (description.isAA) {
    545         shader.append(gVS_Header_Varyings_IsAAVertexShape);
    546     }
    547     if (description.hasColors) {
    548         shader.append(gVS_Header_Varyings_HasColors);
    549     }
    550     if (description.hasGradient) {
    551         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
    552     }
    553     if (description.hasBitmap) {
    554         shader.append(gVS_Header_Varyings_HasBitmap);
    555     }
    556 
    557     // Uniforms
    558     int modulateOp = MODULATE_OP_NO_MODULATE;
    559     const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
    560             !description.hasGradient && !description.hasBitmap;
    561 
    562     if (description.modulate || singleColor) {
    563         shader.append(gFS_Uniforms_Color);
    564         if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
    565     }
    566     if (description.hasTexture) {
    567         shader.append(gFS_Uniforms_TextureSampler);
    568     } else if (description.hasExternalTexture) {
    569         shader.append(gFS_Uniforms_ExternalTextureSampler);
    570     }
    571     if (description.hasGradient) {
    572         shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient],
    573                 gFS_Uniforms_Dither);
    574     }
    575     if (description.hasGammaCorrection) {
    576         shader.append(gFS_Uniforms_Gamma);
    577     }
    578 
    579     // Optimization for common cases
    580     if (!description.isAA && !blendFramebuffer && !description.hasColors &&
    581             description.colorOp == ProgramDescription::kColorNone &&
    582             !description.hasDebugHighlight && !description.emulateStencil) {
    583         bool fast = false;
    584 
    585         const bool noShader = !description.hasGradient && !description.hasBitmap;
    586         const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
    587                 !description.hasAlpha8Texture && noShader;
    588         const bool singleA8Texture = description.hasTexture &&
    589                 description.hasAlpha8Texture && noShader;
    590         const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
    591                 description.hasGradient && !description.hasBitmap &&
    592                 description.gradientType == ProgramDescription::kGradientLinear;
    593 
    594         if (singleColor) {
    595             shader.append(gFS_Fast_SingleColor);
    596             fast = true;
    597         } else if (singleTexture) {
    598             if (!description.modulate) {
    599                 shader.append(gFS_Fast_SingleTexture);
    600             } else {
    601                 shader.append(gFS_Fast_SingleModulateTexture);
    602             }
    603             fast = true;
    604         } else if (singleA8Texture) {
    605             if (!description.modulate) {
    606                 if (description.hasGammaCorrection) {
    607                     shader.append(gFS_Fast_SingleA8Texture_ApplyGamma);
    608                 } else {
    609                     shader.append(gFS_Fast_SingleA8Texture);
    610                 }
    611             } else {
    612                 if (description.hasGammaCorrection) {
    613                     shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma);
    614                 } else {
    615                     shader.append(gFS_Fast_SingleModulateA8Texture);
    616                 }
    617             }
    618             fast = true;
    619         } else if (singleGradient) {
    620             if (!description.modulate) {
    621                 shader.appendFormat(gFS_Fast_SingleGradient[description.isSimpleGradient],
    622                         gFS_Main_Dither[mHasES3]);
    623             } else {
    624                 shader.appendFormat(gFS_Fast_SingleModulateGradient[description.isSimpleGradient],
    625                         gFS_Main_Dither[mHasES3]);
    626             }
    627             fast = true;
    628         }
    629 
    630         if (fast) {
    631 #if DEBUG_PROGRAMS
    632                 PROGRAM_LOGD("*** Fast case:\n");
    633                 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
    634                 printLongString(shader);
    635 #endif
    636 
    637             return shader;
    638         }
    639     }
    640 
    641     if (description.hasBitmap) {
    642         shader.append(gFS_Uniforms_BitmapSampler);
    643     }
    644     shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
    645 
    646     // Generate required functions
    647     if (description.hasGradient && description.hasBitmap) {
    648         generateBlend(shader, "blendShaders", description.shadersMode);
    649     }
    650     if (description.colorOp == ProgramDescription::kColorBlend) {
    651         generateBlend(shader, "blendColors", description.colorMode);
    652     }
    653     if (blendFramebuffer) {
    654         generateBlend(shader, "blendFramebuffer", description.framebufferMode);
    655     }
    656     if (description.isBitmapNpot) {
    657         generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
    658     }
    659 
    660     // Begin the shader
    661     shader.append(gFS_Main); {
    662         if (description.emulateStencil) {
    663             shader.append(gFS_Main_EmulateStencil);
    664         }
    665         // Stores the result in fragColor directly
    666         if (description.hasTexture || description.hasExternalTexture) {
    667             if (description.hasAlpha8Texture) {
    668                 if (!description.hasGradient && !description.hasBitmap) {
    669                     shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 +
    670                                                           description.hasGammaCorrection]);
    671                 }
    672             } else {
    673                 shader.append(gFS_Main_FetchTexture[modulateOp]);
    674             }
    675         } else {
    676             if (!description.hasGradient && !description.hasBitmap) {
    677                 shader.append(gFS_Main_FetchColor);
    678             }
    679         }
    680         if (description.hasGradient) {
    681             shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
    682             shader.appendFormat(gFS_Main_AddDitherToGradient, gFS_Main_Dither[mHasES3]);
    683         }
    684         if (description.hasBitmap) {
    685             if (!description.isBitmapNpot) {
    686                 shader.append(gFS_Main_FetchBitmap);
    687             } else {
    688                 shader.append(gFS_Main_FetchBitmapNpot);
    689             }
    690         }
    691         bool applyModulate = false;
    692         // Case when we have two shaders set
    693         if (description.hasGradient && description.hasBitmap) {
    694             if (description.isBitmapFirst) {
    695                 shader.append(gFS_Main_BlendShadersBG);
    696             } else {
    697                 shader.append(gFS_Main_BlendShadersGB);
    698             }
    699             applyModulate = shaderOp(description, shader, modulateOp,
    700                     gFS_Main_BlendShaders_Modulate);
    701         } else {
    702             if (description.hasGradient) {
    703                 applyModulate = shaderOp(description, shader, modulateOp,
    704                         gFS_Main_GradientShader_Modulate);
    705             } else if (description.hasBitmap) {
    706                 applyModulate = shaderOp(description, shader, modulateOp,
    707                         gFS_Main_BitmapShader_Modulate);
    708             }
    709         }
    710 
    711         if (description.modulate && applyModulate) {
    712             shader.append(gFS_Main_ModulateColor);
    713         }
    714 
    715         // Apply the color op if needed
    716         shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
    717 
    718         if (description.isAA) {
    719             shader.append(gFS_Main_AccountForAAVertexShape);
    720         }
    721 
    722         // Output the fragment
    723         if (!blendFramebuffer) {
    724             shader.append(gFS_Main_FragColor);
    725         } else {
    726             shader.append(!description.swapSrcDst ?
    727                     gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
    728         }
    729         if (description.hasColors) {
    730             shader.append(gFS_Main_FragColor_HasColors);
    731         }
    732         if (description.hasDebugHighlight) {
    733             shader.append(gFS_Main_DebugHighlight);
    734         }
    735     }
    736     if (description.emulateStencil) {
    737         shader.append(gFS_Footer_EmulateStencil);
    738     }
    739     // End the shader
    740     shader.append(gFS_Footer);
    741 
    742 #if DEBUG_PROGRAMS
    743         PROGRAM_LOGD("*** Generated fragment shader:\n\n");
    744         printLongString(shader);
    745 #endif
    746 
    747     return shader;
    748 }
    749 
    750 void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
    751     shader.append("\nvec4 ");
    752     shader.append(name);
    753     shader.append("(vec4 src, vec4 dst) {\n");
    754     shader.append("    ");
    755     shader.append(gBlendOps[mode]);
    756     shader.append("}\n");
    757 }
    758 
    759 void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
    760     shader.append("\nhighp vec2 wrap(highp vec2 texCoords) {\n");
    761     if (wrapS == GL_MIRRORED_REPEAT) {
    762         shader.append("    highp float xMod2 = mod(texCoords.x, 2.0);\n");
    763         shader.append("    if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
    764     }
    765     if (wrapT == GL_MIRRORED_REPEAT) {
    766         shader.append("    highp float yMod2 = mod(texCoords.y, 2.0);\n");
    767         shader.append("    if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
    768     }
    769     shader.append("    return vec2(");
    770     switch (wrapS) {
    771         case GL_CLAMP_TO_EDGE:
    772             shader.append("texCoords.x");
    773             break;
    774         case GL_REPEAT:
    775             shader.append("mod(texCoords.x, 1.0)");
    776             break;
    777         case GL_MIRRORED_REPEAT:
    778             shader.append("xMod2");
    779             break;
    780     }
    781     shader.append(", ");
    782     switch (wrapT) {
    783         case GL_CLAMP_TO_EDGE:
    784             shader.append("texCoords.y");
    785             break;
    786         case GL_REPEAT:
    787             shader.append("mod(texCoords.y, 1.0)");
    788             break;
    789         case GL_MIRRORED_REPEAT:
    790             shader.append("yMod2");
    791             break;
    792     }
    793     shader.append(");\n");
    794     shader.append("}\n");
    795 }
    796 
    797 void ProgramCache::printLongString(const String8& shader) const {
    798     ssize_t index = 0;
    799     ssize_t lastIndex = 0;
    800     const char* str = shader.string();
    801     while ((index = shader.find("\n", index)) > -1) {
    802         String8 line(str, index - lastIndex);
    803         if (line.length() == 0) line.append("\n");
    804         PROGRAM_LOGD("%s", line.string());
    805         index++;
    806         str += (index - lastIndex);
    807         lastIndex = index;
    808     }
    809 }
    810 
    811 }; // namespace uirenderer
    812 }; // namespace android
    813