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