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