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