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 #include <utils/String8.h>
     18 
     19 #include "Caches.h"
     20 #include "ProgramCache.h"
     21 #include "Properties.h"
     22 
     23 namespace android {
     24 namespace uirenderer {
     25 
     26 ///////////////////////////////////////////////////////////////////////////////
     27 // Defines
     28 ///////////////////////////////////////////////////////////////////////////////
     29 
     30 #define MODULATE_OP_NO_MODULATE 0
     31 #define MODULATE_OP_MODULATE 1
     32 #define MODULATE_OP_MODULATE_A8 2
     33 
     34 #define STR(x) STR1(x)
     35 #define STR1(x) #x
     36 
     37 ///////////////////////////////////////////////////////////////////////////////
     38 // Vertex shaders snippets
     39 ///////////////////////////////////////////////////////////////////////////////
     40 
     41 const char* gVS_Header_Start =
     42         "#version 100\n"
     43         "attribute vec4 position;\n";
     44 const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n";
     45 const char* gVS_Header_Attributes_Colors = "attribute vec4 colors;\n";
     46 const char* gVS_Header_Attributes_VertexAlphaParameters = "attribute float vtxAlpha;\n";
     47 const char* gVS_Header_Uniforms_TextureTransform = "uniform mat4 mainTextureTransform;\n";
     48 const char* gVS_Header_Uniforms =
     49         "uniform mat4 projection;\n"
     50         "uniform mat4 transform;\n";
     51 const char* gVS_Header_Uniforms_HasGradient = "uniform mat4 screenSpace;\n";
     52 const char* gVS_Header_Uniforms_HasBitmap =
     53         "uniform mat4 textureTransform;\n"
     54         "uniform mediump vec2 textureDimension;\n";
     55 const char* gVS_Header_Uniforms_HasRoundRectClip =
     56         "uniform mat4 roundRectInvTransform;\n"
     57         "uniform mediump vec4 roundRectInnerRectLTWH;\n"
     58         "uniform mediump float roundRectRadius;\n";
     59 const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n";
     60 const char* gVS_Header_Varyings_HasColors = "varying vec4 outColors;\n";
     61 const char* gVS_Header_Varyings_HasVertexAlpha = "varying float alpha;\n";
     62 const char* gVS_Header_Varyings_HasBitmap = "varying highp vec2 outBitmapTexCoords;\n";
     63 const char* gVS_Header_Varyings_HasGradient[6] = {
     64         // Linear
     65         "varying highp vec2 linear;\n", "varying float linear;\n",
     66 
     67         // Circular
     68         "varying highp vec2 circular;\n", "varying highp vec2 circular;\n",
     69 
     70         // Sweep
     71         "varying highp vec2 sweep;\n", "varying highp vec2 sweep;\n",
     72 };
     73 const char* gVS_Header_Varyings_HasRoundRectClip = "varying mediump vec2 roundRectPos;\n";
     74 const char* gVS_Main = "\nvoid main(void) {\n";
     75 const char* gVS_Main_OutTexCoords = "    outTexCoords = texCoords;\n";
     76 const char* gVS_Main_OutColors = "    outColors = colors;\n";
     77 const char* gVS_Main_OutTransformedTexCoords =
     78         "    outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
     79 const char* gVS_Main_OutGradient[6] = {
     80         // Linear
     81         "    linear = vec2((screenSpace * position).x, 0.5);\n",
     82         "    linear = (screenSpace * position).x;\n",
     83 
     84         // Circular
     85         "    circular = (screenSpace * position).xy;\n",
     86         "    circular = (screenSpace * position).xy;\n",
     87 
     88         // Sweep
     89         "    sweep = (screenSpace * position).xy;\n", "    sweep = (screenSpace * position).xy;\n"};
     90 const char* gVS_Main_OutBitmapTexCoords =
     91         "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
     92 const char* gVS_Main_Position =
     93         "    vec4 transformedPosition = projection * transform * position;\n"
     94         "    gl_Position = transformedPosition;\n";
     95 
     96 const char* gVS_Main_VertexAlpha = "    alpha = vtxAlpha;\n";
     97 
     98 const char* gVS_Main_HasRoundRectClip =
     99         "    roundRectPos = ((roundRectInvTransform * transformedPosition).xy / roundRectRadius) - "
    100         "roundRectInnerRectLTWH.xy;\n";
    101 const char* gVS_Footer = "}\n\n";
    102 
    103 ///////////////////////////////////////////////////////////////////////////////
    104 // Fragment shaders snippets
    105 ///////////////////////////////////////////////////////////////////////////////
    106 
    107 const char* gFS_Header_Start = "#version 100\n";
    108 const char* gFS_Header_Extension_FramebufferFetch =
    109         "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
    110 const char* gFS_Header_Extension_ExternalTexture =
    111         "#extension GL_OES_EGL_image_external : require\n\n";
    112 const char* gFS_Header = "precision mediump float;\n\n";
    113 const char* gFS_Uniforms_Color = "uniform vec4 color;\n";
    114 const char* gFS_Uniforms_TextureSampler = "uniform sampler2D baseSampler;\n";
    115 const char* gFS_Uniforms_ExternalTextureSampler = "uniform samplerExternalOES baseSampler;\n";
    116 const char* gFS_Uniforms_GradientSampler[2] = {
    117         "uniform vec2 screenSize;\n"
    118         "uniform sampler2D gradientSampler;\n",
    119 
    120         "uniform vec2 screenSize;\n"
    121         "uniform vec4 startColor;\n"
    122         "uniform vec4 endColor;\n"};
    123 const char* gFS_Uniforms_BitmapSampler = "uniform sampler2D bitmapSampler;\n";
    124 const char* gFS_Uniforms_BitmapExternalSampler = "uniform samplerExternalOES bitmapSampler;\n";
    125 const char* gFS_Uniforms_ColorOp[3] = {
    126         // None
    127         "",
    128         // Matrix
    129         "uniform mat4 colorMatrix;\n"
    130         "uniform vec4 colorMatrixVector;\n",
    131         // PorterDuff
    132         "uniform vec4 colorBlend;\n"};
    133 
    134 const char* gFS_Uniforms_HasRoundRectClip =
    135         "uniform mediump vec4 roundRectInnerRectLTWH;\n"
    136         "uniform mediump float roundRectRadius;\n";
    137 
    138 const char* gFS_Uniforms_ColorSpaceConversion =
    139         // TODO: Should we use a 3D LUT to combine the matrix and transfer functions?
    140         // 32x32x32 fp16 LUTs (for scRGB output) are large and heavy to generate...
    141         "uniform mat3 colorSpaceMatrix;\n";
    142 
    143 const char* gFS_Uniforms_TransferFunction[4] = {
    144         // In this order: g, a, b, c, d, e, f
    145         // See ColorSpace::TransferParameters
    146         // We'll use hardware sRGB conversion as much as possible
    147         "", "uniform float transferFunction[7];\n", "uniform float transferFunction[5];\n",
    148         "uniform float transferFunctionGamma;\n"};
    149 
    150 const char* gFS_OETF[2] = {
    151         R"__SHADER__(
    152         vec4 OETF(const vec4 linear) {
    153             return linear;
    154         }
    155         )__SHADER__",
    156         // We expect linear data to be scRGB so we mirror the gamma function
    157         R"__SHADER__(
    158         vec4 OETF(const vec4 linear) {
    159             return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a);
    160         }
    161         )__SHADER__"};
    162 
    163 const char* gFS_ColorConvert[3] = {
    164         // Just OETF
    165         R"__SHADER__(
    166         vec4 colorConvert(const vec4 color) {
    167             return OETF(color);
    168         }
    169         )__SHADER__",
    170         // Full color conversion for opaque bitmaps
    171         R"__SHADER__(
    172         vec4 colorConvert(const vec4 color) {
    173             return OETF(vec4(colorSpaceMatrix * EOTF_Parametric(color.rgb), color.a));
    174         }
    175         )__SHADER__",
    176         // Full color conversion for translucent bitmaps
    177         // Note: 0.5/256=0.0019
    178         R"__SHADER__(
    179         vec4 colorConvert(in vec4 color) {
    180             color.rgb /= color.a + 0.0019;
    181             color = OETF(vec4(colorSpaceMatrix * EOTF_Parametric(color.rgb), color.a));
    182             color.rgb *= color.a + 0.0019;
    183             return color;
    184         }
    185         )__SHADER__",
    186 };
    187 
    188 const char* gFS_sRGB_TransferFunctions = R"__SHADER__(
    189         float OETF_sRGB(const float linear) {
    190             // IEC 61966-2-1:1999
    191             return linear <= 0.0031308 ? linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
    192         }
    193 
    194         vec3 OETF_sRGB(const vec3 linear) {
    195             return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
    196         }
    197 
    198         float EOTF_sRGB(float srgb) {
    199             // IEC 61966-2-1:1999
    200             return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
    201         }
    202 )__SHADER__";
    203 
    204 const char* gFS_TransferFunction[4] = {
    205         // Conversion done by the texture unit (sRGB)
    206         R"__SHADER__(
    207         vec3 EOTF_Parametric(const vec3 x) {
    208             return x;
    209         }
    210         )__SHADER__",
    211         // Full transfer function
    212         // TODO: We should probably use a 1D LUT (256x1 with texelFetch() since input is 8 bit)
    213         // TODO: That would cause 3 dependent texture fetches. Is it worth it?
    214         R"__SHADER__(
    215         float EOTF_Parametric(float x) {
    216             return x <= transferFunction[4]
    217                   ? transferFunction[3] * x + transferFunction[6]
    218                   : pow(transferFunction[1] * x + transferFunction[2], transferFunction[0])
    219                           + transferFunction[5];
    220         }
    221 
    222         vec3 EOTF_Parametric(const vec3 x) {
    223             return vec3(EOTF_Parametric(x.r), EOTF_Parametric(x.g), EOTF_Parametric(x.b));
    224         }
    225         )__SHADER__",
    226         // Limited transfer function, e = f = 0.0
    227         R"__SHADER__(
    228         float EOTF_Parametric(float x) {
    229             return x <= transferFunction[4]
    230                   ? transferFunction[3] * x
    231                   : pow(transferFunction[1] * x + transferFunction[2], transferFunction[0]);
    232         }
    233 
    234         vec3 EOTF_Parametric(const vec3 x) {
    235             return vec3(EOTF_Parametric(x.r), EOTF_Parametric(x.g), EOTF_Parametric(x.b));
    236         }
    237         )__SHADER__",
    238         // Gamma transfer function, e = f = 0.0
    239         R"__SHADER__(
    240         vec3 EOTF_Parametric(const vec3 x) {
    241             return vec3(pow(x.r, transferFunctionGamma),
    242                         pow(x.g, transferFunctionGamma),
    243                         pow(x.b, transferFunctionGamma));
    244         }
    245         )__SHADER__"};
    246 
    247 // Dithering must be done in the quantization space
    248 // When we are writing to an sRGB framebuffer, we must do the following:
    249 //     EOTF(OETF(color) + dither)
    250 // The dithering pattern is generated with a triangle noise generator in the range [-1.0,1.0]
    251 // TODO: Handle linear fp16 render targets
    252 const char* gFS_GradientFunctions = R"__SHADER__(
    253         float triangleNoise(const highp vec2 n) {
    254             highp vec2 p = fract(n * vec2(5.3987, 5.4421));
    255             p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
    256             highp float xy = p.x * p.y;
    257             return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
    258         }
    259 )__SHADER__";
    260 
    261 const char* gFS_GradientPreamble[2] = {
    262         // Linear framebuffer
    263         R"__SHADER__(
    264         vec4 dither(const vec4 color) {
    265             return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
    266         }
    267         )__SHADER__",
    268         // sRGB framebuffer
    269         R"__SHADER__(
    270         vec4 dither(const vec4 color) {
    271             vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
    272             return vec4(dithered * dithered, color.a);
    273         }
    274         )__SHADER__",
    275 };
    276 
    277 // Uses luminance coefficients from Rec.709 to choose the appropriate gamma
    278 // The gamma() function assumes that bright text will be displayed on a dark
    279 // background and that dark text will be displayed on bright background
    280 // The gamma coefficient is chosen to thicken or thin the text accordingly
    281 // The dot product used to compute the luminance could be approximated with
    282 // a simple max(color.r, color.g, color.b)
    283 const char* gFS_Gamma_Preamble = R"__SHADER__(
    284         #define GAMMA (%.2f)
    285         #define GAMMA_INV (%.2f)
    286 
    287         float gamma(float a, const vec3 color) {
    288             float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
    289             return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA);
    290         }
    291 )__SHADER__";
    292 
    293 const char* gFS_Main =
    294         "\nvoid main(void) {\n"
    295         "    vec4 fragColor;\n";
    296 
    297 const char* gFS_Main_AddDither = "    fragColor = dither(fragColor);\n";
    298 
    299 // General case
    300 const char* gFS_Main_FetchColor = "    fragColor = color;\n";
    301 const char* gFS_Main_ModulateColor = "    fragColor *= color.a;\n";
    302 const char* gFS_Main_ApplyVertexAlphaLinearInterp = "    fragColor *= alpha;\n";
    303 const char* gFS_Main_ApplyVertexAlphaShadowInterp =
    304         // map alpha through shadow alpha sampler
    305         "    fragColor *= texture2D(baseSampler, vec2(alpha, 0.5)).a;\n";
    306 const char* gFS_Main_FetchTexture[2] = {
    307         // Don't modulate
    308         "    fragColor = colorConvert(texture2D(baseSampler, outTexCoords));\n",
    309         // Modulate
    310         "    fragColor = color * colorConvert(texture2D(baseSampler, outTexCoords));\n"};
    311 const char* gFS_Main_FetchA8Texture[4] = {
    312         // Don't modulate
    313         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
    314         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
    315         // Modulate
    316         "    fragColor = color * texture2D(baseSampler, outTexCoords).a;\n",
    317         "    fragColor = color * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n",
    318 };
    319 const char* gFS_Main_FetchGradient[6] = {
    320         // Linear
    321         "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
    322 
    323         "    vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
    324 
    325         // Circular
    326         "    vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
    327 
    328         "    vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
    329 
    330         // Sweep
    331         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
    332         "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
    333 
    334         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
    335         "    vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, "
    336         "1.0));\n"};
    337 const char* gFS_Main_FetchBitmap =
    338         "    vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n";
    339 const char* gFS_Main_FetchBitmapNpot =
    340         "    vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, "
    341         "wrap(outBitmapTexCoords)));\n";
    342 const char* gFS_Main_BlendShadersBG = "    fragColor = blendShaders(gradientColor, bitmapColor)";
    343 const char* gFS_Main_BlendShadersGB = "    fragColor = blendShaders(bitmapColor, gradientColor)";
    344 const char* gFS_Main_BlendShaders_Modulate[6] = {
    345         // Don't modulate
    346         ";\n", ";\n",
    347         // Modulate
    348         " * color.a;\n", " * color.a;\n",
    349         // Modulate with alpha 8 texture
    350         " * texture2D(baseSampler, outTexCoords).a;\n",
    351         " * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n",
    352 };
    353 const char* gFS_Main_GradientShader_Modulate[6] = {
    354         // Don't modulate
    355         "    fragColor = gradientColor;\n", "    fragColor = gradientColor;\n",
    356         // Modulate
    357         "    fragColor = gradientColor * color.a;\n", "    fragColor = gradientColor * color.a;\n",
    358         // Modulate with alpha 8 texture
    359         "    fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n",
    360         "    fragColor = gradientColor * gamma(texture2D(baseSampler, outTexCoords).a, "
    361         "gradientColor.rgb);\n",
    362 };
    363 const char* gFS_Main_BitmapShader_Modulate[6] = {
    364         // Don't modulate
    365         "    fragColor = bitmapColor;\n", "    fragColor = bitmapColor;\n",
    366         // Modulate
    367         "    fragColor = bitmapColor * color.a;\n", "    fragColor = bitmapColor * color.a;\n",
    368         // Modulate with alpha 8 texture
    369         "    fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n",
    370         "    fragColor = bitmapColor * gamma(texture2D(baseSampler, outTexCoords).a, "
    371         "bitmapColor.rgb);\n",
    372 };
    373 const char* gFS_Main_FragColor = "    gl_FragColor = fragColor;\n";
    374 const char* gFS_Main_FragColor_HasColors = "    gl_FragColor *= outColors;\n";
    375 const char* gFS_Main_FragColor_Blend =
    376         "    gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
    377 const char* gFS_Main_FragColor_Blend_Swap =
    378         "    gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
    379 const char* gFS_Main_ApplyColorOp[3] = {
    380         // None
    381         "",
    382         // Matrix
    383         "    fragColor.rgb /= (fragColor.a + 0.0019);\n"  // un-premultiply
    384         "    fragColor *= colorMatrix;\n"
    385         "    fragColor += colorMatrixVector;\n"
    386         "    fragColor.rgb *= (fragColor.a + 0.0019);\n",  // re-premultiply
    387         // PorterDuff
    388         "    fragColor = blendColors(colorBlend, fragColor);\n"};
    389 
    390 // Note: LTWH (left top width height) -> xyzw
    391 // roundRectPos is now divided by roundRectRadius in vertex shader
    392 // after we also subtract roundRectInnerRectLTWH.xy from roundRectPos
    393 const char* gFS_Main_FragColor_HasRoundRectClip =
    394         "    mediump vec2 fragToLT = -roundRectPos;\n"
    395         "    mediump vec2 fragFromRB = roundRectPos - roundRectInnerRectLTWH.zw;\n"
    396 
    397         // since distance is divided by radius, it's in [0;1] so precision is not an issue
    398         // this also lets us clamp(0.0, 1.0) instead of max() which is cheaper on GPUs
    399         "    mediump vec2 dist = clamp(max(fragToLT, fragFromRB), 0.0, 1.0);\n"
    400         "    mediump float linearDist = clamp(roundRectRadius - (length(dist) * roundRectRadius), "
    401         "0.0, 1.0);\n"
    402         "    gl_FragColor *= linearDist;\n";
    403 
    404 const char* gFS_Main_DebugHighlight = "    gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
    405 const char* gFS_Footer = "}\n\n";
    406 
    407 ///////////////////////////////////////////////////////////////////////////////
    408 // PorterDuff snippets
    409 ///////////////////////////////////////////////////////////////////////////////
    410 
    411 const char* gBlendOps[18] = {
    412         // Clear
    413         "return vec4(0.0, 0.0, 0.0, 0.0);\n",
    414         // Src
    415         "return src;\n",
    416         // Dst
    417         "return dst;\n",
    418         // SrcOver
    419         "return src + dst * (1.0 - src.a);\n",
    420         // DstOver
    421         "return dst + src * (1.0 - dst.a);\n",
    422         // SrcIn
    423         "return src * dst.a;\n",
    424         // DstIn
    425         "return dst * src.a;\n",
    426         // SrcOut
    427         "return src * (1.0 - dst.a);\n",
    428         // DstOut
    429         "return dst * (1.0 - src.a);\n",
    430         // SrcAtop
    431         "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
    432         // DstAtop
    433         "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
    434         // Xor
    435         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
    436         "src.a + dst.a - 2.0 * src.a * dst.a);\n",
    437         // Plus
    438         "return min(src + dst, 1.0);\n",
    439         // Modulate
    440         "return src * dst;\n",
    441         // Screen
    442         "return src + dst - src * dst;\n",
    443         // Overlay
    444         "return clamp(vec4(mix("
    445         "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
    446         "src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + "
    447         "dst.rgb * (1.0 - src.a), "
    448         "step(dst.a, 2.0 * dst.rgb)), "
    449         "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
    450         // Darken
    451         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
    452         "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
    453         // Lighten
    454         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
    455         "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
    456 };
    457 
    458 ///////////////////////////////////////////////////////////////////////////////
    459 // Constructors/destructors
    460 ///////////////////////////////////////////////////////////////////////////////
    461 
    462 ProgramCache::ProgramCache(const Extensions& extensions)
    463         : mHasES3(extensions.getMajorGlVersion() >= 3)
    464         , mHasLinearBlending(extensions.hasLinearBlending()) {}
    465 
    466 ProgramCache::~ProgramCache() {
    467     clear();
    468 }
    469 
    470 ///////////////////////////////////////////////////////////////////////////////
    471 // Cache management
    472 ///////////////////////////////////////////////////////////////////////////////
    473 
    474 void ProgramCache::clear() {
    475     PROGRAM_LOGD("Clearing program cache");
    476     mCache.clear();
    477 }
    478 
    479 Program* ProgramCache::get(const ProgramDescription& description) {
    480     programid key = description.key();
    481     if (key == (PROGRAM_KEY_TEXTURE | PROGRAM_KEY_A8_TEXTURE)) {
    482         // program for A8, unmodulated, texture w/o shader (black text/path textures) is equivalent
    483         // to standard texture program (bitmaps, patches). Consider them equivalent.
    484         key = PROGRAM_KEY_TEXTURE;
    485     }
    486 
    487     auto iter = mCache.find(key);
    488     Program* program = nullptr;
    489     if (iter == mCache.end()) {
    490         description.log("Could not find program");
    491         program = generateProgram(description, key);
    492         mCache[key] = std::unique_ptr<Program>(program);
    493     } else {
    494         program = iter->second.get();
    495     }
    496     return program;
    497 }
    498 
    499 ///////////////////////////////////////////////////////////////////////////////
    500 // Program generation
    501 ///////////////////////////////////////////////////////////////////////////////
    502 
    503 Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
    504     String8 vertexShader = generateVertexShader(description);
    505     String8 fragmentShader = generateFragmentShader(description);
    506 
    507     return new Program(description, vertexShader.string(), fragmentShader.string());
    508 }
    509 
    510 static inline size_t gradientIndex(const ProgramDescription& description) {
    511     return description.gradientType * 2 + description.isSimpleGradient;
    512 }
    513 
    514 String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
    515     // Add attributes
    516     String8 shader(gVS_Header_Start);
    517     if (description.hasTexture || description.hasExternalTexture) {
    518         shader.append(gVS_Header_Attributes_TexCoords);
    519     }
    520     if (description.hasVertexAlpha) {
    521         shader.append(gVS_Header_Attributes_VertexAlphaParameters);
    522     }
    523     if (description.hasColors) {
    524         shader.append(gVS_Header_Attributes_Colors);
    525     }
    526     // Uniforms
    527     shader.append(gVS_Header_Uniforms);
    528     if (description.hasTextureTransform) {
    529         shader.append(gVS_Header_Uniforms_TextureTransform);
    530     }
    531     if (description.hasGradient) {
    532         shader.append(gVS_Header_Uniforms_HasGradient);
    533     }
    534     if (description.hasBitmap) {
    535         shader.append(gVS_Header_Uniforms_HasBitmap);
    536     }
    537     if (description.hasRoundRectClip) {
    538         shader.append(gVS_Header_Uniforms_HasRoundRectClip);
    539     }
    540     // Varyings
    541     if (description.hasTexture || description.hasExternalTexture) {
    542         shader.append(gVS_Header_Varyings_HasTexture);
    543     }
    544     if (description.hasVertexAlpha) {
    545         shader.append(gVS_Header_Varyings_HasVertexAlpha);
    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     if (description.hasRoundRectClip) {
    557         shader.append(gVS_Header_Varyings_HasRoundRectClip);
    558     }
    559 
    560     // Begin the shader
    561     shader.append(gVS_Main);
    562     {
    563         if (description.hasTextureTransform) {
    564             shader.append(gVS_Main_OutTransformedTexCoords);
    565         } else if (description.hasTexture || description.hasExternalTexture) {
    566             shader.append(gVS_Main_OutTexCoords);
    567         }
    568         if (description.hasVertexAlpha) {
    569             shader.append(gVS_Main_VertexAlpha);
    570         }
    571         if (description.hasColors) {
    572             shader.append(gVS_Main_OutColors);
    573         }
    574         if (description.hasBitmap) {
    575             shader.append(gVS_Main_OutBitmapTexCoords);
    576         }
    577         // Output transformed position
    578         shader.append(gVS_Main_Position);
    579         if (description.hasGradient) {
    580             shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
    581         }
    582         if (description.hasRoundRectClip) {
    583             shader.append(gVS_Main_HasRoundRectClip);
    584         }
    585     }
    586     // End the shader
    587     shader.append(gVS_Footer);
    588 
    589     PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
    590 
    591     return shader;
    592 }
    593 
    594 static bool shaderOp(const ProgramDescription& description, String8& shader, const int modulateOp,
    595                      const char** snippets) {
    596     int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
    597     op = op * 2 + description.hasGammaCorrection;
    598     shader.append(snippets[op]);
    599     return description.hasAlpha8Texture;
    600 }
    601 
    602 String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
    603     String8 shader(gFS_Header_Start);
    604 
    605     const bool blendFramebuffer = description.framebufferMode >= SkBlendMode::kPlus;
    606     if (blendFramebuffer) {
    607         shader.append(gFS_Header_Extension_FramebufferFetch);
    608     }
    609     if (description.hasExternalTexture ||
    610         (description.hasBitmap && description.isShaderBitmapExternal)) {
    611         shader.append(gFS_Header_Extension_ExternalTexture);
    612     }
    613 
    614     shader.append(gFS_Header);
    615 
    616     // Varyings
    617     if (description.hasTexture || description.hasExternalTexture) {
    618         shader.append(gVS_Header_Varyings_HasTexture);
    619     }
    620     if (description.hasVertexAlpha) {
    621         shader.append(gVS_Header_Varyings_HasVertexAlpha);
    622     }
    623     if (description.hasColors) {
    624         shader.append(gVS_Header_Varyings_HasColors);
    625     }
    626     if (description.hasGradient) {
    627         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
    628     }
    629     if (description.hasBitmap) {
    630         shader.append(gVS_Header_Varyings_HasBitmap);
    631     }
    632     if (description.hasRoundRectClip) {
    633         shader.append(gVS_Header_Varyings_HasRoundRectClip);
    634     }
    635 
    636     // Uniforms
    637     int modulateOp = MODULATE_OP_NO_MODULATE;
    638     const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
    639                              !description.hasGradient && !description.hasBitmap;
    640 
    641     if (description.modulate || singleColor) {
    642         shader.append(gFS_Uniforms_Color);
    643         if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
    644     }
    645     if (description.hasTexture || description.useShadowAlphaInterp) {
    646         shader.append(gFS_Uniforms_TextureSampler);
    647     } else if (description.hasExternalTexture) {
    648         shader.append(gFS_Uniforms_ExternalTextureSampler);
    649     }
    650     if (description.hasGradient) {
    651         shader.append(gFS_Uniforms_GradientSampler[description.isSimpleGradient]);
    652     }
    653     if (description.hasRoundRectClip) {
    654         shader.append(gFS_Uniforms_HasRoundRectClip);
    655     }
    656 
    657     if (description.hasGammaCorrection) {
    658         shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma,
    659                             1.0f / Properties::textGamma);
    660     }
    661 
    662     if (description.hasBitmap) {
    663         if (description.isShaderBitmapExternal) {
    664             shader.append(gFS_Uniforms_BitmapExternalSampler);
    665         } else {
    666             shader.append(gFS_Uniforms_BitmapSampler);
    667         }
    668     }
    669     shader.append(gFS_Uniforms_ColorOp[static_cast<int>(description.colorOp)]);
    670 
    671     if (description.hasColorSpaceConversion) {
    672         shader.append(gFS_Uniforms_ColorSpaceConversion);
    673     }
    674     shader.append(gFS_Uniforms_TransferFunction[static_cast<int>(description.transferFunction)]);
    675 
    676     // Generate required functions
    677     if (description.hasGradient && description.hasBitmap) {
    678         generateBlend(shader, "blendShaders", description.shadersMode);
    679     }
    680     if (description.colorOp == ProgramDescription::ColorFilterMode::Blend) {
    681         generateBlend(shader, "blendColors", description.colorMode);
    682     }
    683     if (blendFramebuffer) {
    684         generateBlend(shader, "blendFramebuffer", description.framebufferMode);
    685     }
    686     if (description.useShaderBasedWrap) {
    687         generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
    688     }
    689     if (description.hasGradient || description.hasLinearTexture ||
    690         description.hasColorSpaceConversion) {
    691         shader.append(gFS_sRGB_TransferFunctions);
    692     }
    693     if (description.hasBitmap || ((description.hasTexture || description.hasExternalTexture) &&
    694                                   !description.hasAlpha8Texture)) {
    695         shader.append(gFS_TransferFunction[static_cast<int>(description.transferFunction)]);
    696         shader.append(
    697                 gFS_OETF[(description.hasLinearTexture || description.hasColorSpaceConversion) &&
    698                          !mHasLinearBlending]);
    699         shader.append(gFS_ColorConvert[description.hasColorSpaceConversion
    700                                                ? 1 + description.hasTranslucentConversion
    701                                                : 0]);
    702     }
    703     if (description.hasGradient) {
    704         shader.append(gFS_GradientFunctions);
    705         shader.append(gFS_GradientPreamble[mHasLinearBlending]);
    706     }
    707 
    708     // Begin the shader
    709     shader.append(gFS_Main);
    710     {
    711         // Stores the result in fragColor directly
    712         if (description.hasTexture || description.hasExternalTexture) {
    713             if (description.hasAlpha8Texture) {
    714                 if (!description.hasGradient && !description.hasBitmap) {
    715                     shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 +
    716                                                           description.hasGammaCorrection]);
    717                 }
    718             } else {
    719                 shader.append(gFS_Main_FetchTexture[modulateOp]);
    720             }
    721         } else {
    722             if (!description.hasGradient && !description.hasBitmap) {
    723                 shader.append(gFS_Main_FetchColor);
    724             }
    725         }
    726         if (description.hasGradient) {
    727             shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
    728         }
    729         if (description.hasBitmap) {
    730             if (!description.useShaderBasedWrap) {
    731                 shader.append(gFS_Main_FetchBitmap);
    732             } else {
    733                 shader.append(gFS_Main_FetchBitmapNpot);
    734             }
    735         }
    736         bool applyModulate = false;
    737         // Case when we have two shaders set
    738         if (description.hasGradient && description.hasBitmap) {
    739             if (description.isBitmapFirst) {
    740                 shader.append(gFS_Main_BlendShadersBG);
    741             } else {
    742                 shader.append(gFS_Main_BlendShadersGB);
    743             }
    744             applyModulate =
    745                     shaderOp(description, shader, modulateOp, gFS_Main_BlendShaders_Modulate);
    746         } else {
    747             if (description.hasGradient) {
    748                 applyModulate =
    749                         shaderOp(description, shader, modulateOp, gFS_Main_GradientShader_Modulate);
    750             } else if (description.hasBitmap) {
    751                 applyModulate =
    752                         shaderOp(description, shader, modulateOp, gFS_Main_BitmapShader_Modulate);
    753             }
    754         }
    755 
    756         if (description.modulate && applyModulate) {
    757             shader.append(gFS_Main_ModulateColor);
    758         }
    759 
    760         // Apply the color op if needed
    761         shader.append(gFS_Main_ApplyColorOp[static_cast<int>(description.colorOp)]);
    762 
    763         if (description.hasVertexAlpha) {
    764             if (description.useShadowAlphaInterp) {
    765                 shader.append(gFS_Main_ApplyVertexAlphaShadowInterp);
    766             } else {
    767                 shader.append(gFS_Main_ApplyVertexAlphaLinearInterp);
    768             }
    769         }
    770 
    771         if (description.hasGradient) {
    772             shader.append(gFS_Main_AddDither);
    773         }
    774 
    775         // Output the fragment
    776         if (!blendFramebuffer) {
    777             shader.append(gFS_Main_FragColor);
    778         } else {
    779             shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend
    780                                                   : gFS_Main_FragColor_Blend_Swap);
    781         }
    782         if (description.hasColors) {
    783             shader.append(gFS_Main_FragColor_HasColors);
    784         }
    785         if (description.hasRoundRectClip) {
    786             shader.append(gFS_Main_FragColor_HasRoundRectClip);
    787         }
    788         if (description.hasDebugHighlight) {
    789             shader.append(gFS_Main_DebugHighlight);
    790         }
    791     }
    792     // End the shader
    793     shader.append(gFS_Footer);
    794 
    795 #if DEBUG_PROGRAMS
    796     PROGRAM_LOGD("*** Generated fragment shader:\n\n");
    797     printLongString(shader);
    798 #endif
    799 
    800     return shader;
    801 }
    802 
    803 void ProgramCache::generateBlend(String8& shader, const char* name, SkBlendMode mode) {
    804     shader.append("\nvec4 ");
    805     shader.append(name);
    806     shader.append("(vec4 src, vec4 dst) {\n");
    807     shader.append("    ");
    808     shader.append(gBlendOps[(int)mode]);
    809     shader.append("}\n");
    810 }
    811 
    812 void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
    813     shader.append("\nhighp vec2 wrap(highp vec2 texCoords) {\n");
    814     if (wrapS == GL_MIRRORED_REPEAT) {
    815         shader.append("    highp float xMod2 = mod(texCoords.x, 2.0);\n");
    816         shader.append("    if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
    817     }
    818     if (wrapT == GL_MIRRORED_REPEAT) {
    819         shader.append("    highp float yMod2 = mod(texCoords.y, 2.0);\n");
    820         shader.append("    if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
    821     }
    822     shader.append("    return vec2(");
    823     switch (wrapS) {
    824         case GL_CLAMP_TO_EDGE:
    825             shader.append("texCoords.x");
    826             break;
    827         case GL_REPEAT:
    828             shader.append("mod(texCoords.x, 1.0)");
    829             break;
    830         case GL_MIRRORED_REPEAT:
    831             shader.append("xMod2");
    832             break;
    833     }
    834     shader.append(", ");
    835     switch (wrapT) {
    836         case GL_CLAMP_TO_EDGE:
    837             shader.append("texCoords.y");
    838             break;
    839         case GL_REPEAT:
    840             shader.append("mod(texCoords.y, 1.0)");
    841             break;
    842         case GL_MIRRORED_REPEAT:
    843             shader.append("yMod2");
    844             break;
    845     }
    846     shader.append(");\n");
    847     shader.append("}\n");
    848 }
    849 
    850 void ProgramCache::printLongString(const String8& shader) const {
    851     ssize_t index = 0;
    852     ssize_t lastIndex = 0;
    853     const char* str = shader.string();
    854     while ((index = shader.find("\n", index)) > -1) {
    855         String8 line(str, index - lastIndex);
    856         if (line.length() == 0) line.append("\n");
    857         ALOGD("%s", line.string());
    858         index++;
    859         str += (index - lastIndex);
    860         lastIndex = index;
    861     }
    862 }
    863 
    864 };  // namespace uirenderer
    865 };  // namespace android
    866