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