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