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