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