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