ProgramCache.cpp revision 707b2f78ccaa09965d7e030fda3a883ce9b75ea8
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 "ProgramCache.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/////////////////////////////////////////////////////////////////////////////// 35// Vertex shaders snippets 36/////////////////////////////////////////////////////////////////////////////// 37 38const char* gVS_Header_Attributes = 39 "attribute vec4 position;\n"; 40const char* gVS_Header_Attributes_TexCoords = 41 "attribute vec2 texCoords;\n"; 42const char* gVS_Header_Uniforms = 43 "uniform mat4 transform;\n"; 44const char* gVS_Header_Uniforms_HasGradient[3] = { 45 // Linear 46 "uniform mat4 screenSpace;\n", 47 // Circular 48 "uniform mat4 screenSpace;\n", 49 // Sweep 50 "uniform mat4 screenSpace;\n" 51}; 52const char* gVS_Header_Uniforms_HasBitmap = 53 "uniform mat4 textureTransform;\n" 54 "uniform vec2 textureDimension;\n"; 55const char* gVS_Header_Varyings_HasTexture = 56 "varying vec2 outTexCoords;\n"; 57const char* gVS_Header_Varyings_HasBitmap = 58 "varying vec2 outBitmapTexCoords;\n"; 59const char* gVS_Header_Varyings_HasGradient[3] = { 60 // Linear 61 "varying vec2 linear;\n", 62 // Circular 63 "varying vec2 circular;\n", 64 // Sweep 65 "varying vec2 sweep;\n" 66}; 67const char* gVS_Main = 68 "\nvoid main(void) {\n"; 69const char* gVS_Main_OutTexCoords = 70 " outTexCoords = texCoords;\n"; 71const char* gVS_Main_OutGradient[3] = { 72 // Linear 73 " linear = vec2((screenSpace * position).x, 0.5);\n", 74 // Circular 75 " circular = (screenSpace * position).xy;\n", 76 // Sweep 77 " sweep = (screenSpace * position).xy;\n" 78}; 79const char* gVS_Main_OutBitmapTexCoords = 80 " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; 81const char* gVS_Main_Position = 82 " gl_Position = transform * position;\n"; 83const char* gVS_Footer = 84 "}\n\n"; 85 86/////////////////////////////////////////////////////////////////////////////// 87// Fragment shaders snippets 88/////////////////////////////////////////////////////////////////////////////// 89 90const char* gFS_Header_Extension_FramebufferFetch = 91 "#extension GL_NV_shader_framebuffer_fetch : enable\n\n"; 92const char* gFS_Header = 93 "precision mediump float;\n\n"; 94const char* gFS_Uniforms_Color = 95 "uniform vec4 color;\n"; 96const char* gFS_Uniforms_TextureSampler = 97 "uniform sampler2D sampler;\n"; 98const char* gFS_Uniforms_GradientSampler[3] = { 99 // Linear 100 "uniform sampler2D gradientSampler;\n", 101 // Circular 102 "uniform sampler2D gradientSampler;\n", 103 // Sweep 104 "uniform sampler2D gradientSampler;\n" 105}; 106const char* gFS_Uniforms_BitmapSampler = 107 "uniform sampler2D bitmapSampler;\n"; 108const char* gFS_Uniforms_ColorOp[4] = { 109 // None 110 "", 111 // Matrix 112 "uniform mat4 colorMatrix;\n" 113 "uniform vec4 colorMatrixVector;\n", 114 // Lighting 115 "uniform vec4 lightingMul;\n" 116 "uniform vec4 lightingAdd;\n", 117 // PorterDuff 118 "uniform vec4 colorBlend;\n" 119}; 120const char* gFS_Main = 121 "\nvoid main(void) {\n" 122 " lowp vec4 fragColor;\n"; 123 124// Fast cases 125const char* gFS_Fast_SingleColor = 126 "\nvoid main(void) {\n" 127 " gl_FragColor = color;\n" 128 "}\n\n"; 129const char* gFS_Fast_SingleTexture = 130 "\nvoid main(void) {\n" 131 " gl_FragColor = texture2D(sampler, outTexCoords);\n" 132 "}\n\n"; 133const char* gFS_Fast_SingleModulateTexture = 134 "\nvoid main(void) {\n" 135 " gl_FragColor = color.a * texture2D(sampler, outTexCoords);\n" 136 "}\n\n"; 137const char* gFS_Fast_SingleA8Texture = 138 "\nvoid main(void) {\n" 139 " gl_FragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n" 140 "}\n\n"; 141const char* gFS_Fast_SingleModulateA8Texture = 142 "\nvoid main(void) {\n" 143 " gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n" 144 "}\n\n"; 145const char* gFS_Fast_SingleGradient = 146 "\nvoid main(void) {\n" 147 " gl_FragColor = texture2D(gradientSampler, linear);\n" 148 "}\n\n"; 149const char* gFS_Fast_SingleModulateGradient = 150 "\nvoid main(void) {\n" 151 " gl_FragColor = color.a * texture2D(gradientSampler, linear);\n" 152 "}\n\n"; 153 154// General case 155const char* gFS_Main_FetchColor = 156 " fragColor = color;\n"; 157const char* gFS_Main_FetchTexture[2] = { 158 // Don't modulate 159 " fragColor = texture2D(sampler, outTexCoords);\n", 160 // Modulate 161 " fragColor = color * texture2D(sampler, outTexCoords);\n" 162}; 163const char* gFS_Main_FetchA8Texture[2] = { 164 // Don't modulate 165 " fragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n", 166 // Modulate 167 " fragColor = color * texture2D(sampler, outTexCoords).a;\n" 168}; 169const char* gFS_Main_FetchGradient[3] = { 170 // Linear 171 " vec4 gradientColor = texture2D(gradientSampler, linear);\n", 172 // Circular 173 " float index = length(circular);\n" 174 " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n", 175 // Sweep 176 " float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" 177 " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n" 178}; 179const char* gFS_Main_FetchBitmap = 180 " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n"; 181const char* gFS_Main_FetchBitmapNpot = 182 " vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n"; 183const char* gFS_Main_BlendShadersBG = 184 " fragColor = blendShaders(gradientColor, bitmapColor)"; 185const char* gFS_Main_BlendShadersGB = 186 " fragColor = blendShaders(bitmapColor, gradientColor)"; 187const char* gFS_Main_BlendShaders_Modulate[3] = { 188 // Don't modulate 189 ";\n", 190 // Modulate 191 " * fragColor.a;\n", 192 // Modulate with alpha 8 texture 193 " * texture2D(sampler, outTexCoords).a;\n" 194}; 195const char* gFS_Main_GradientShader_Modulate[3] = { 196 // Don't modulate 197 " fragColor = gradientColor;\n", 198 // Modulate 199 " fragColor = gradientColor * fragColor.a;\n", 200 // Modulate with alpha 8 texture 201 " fragColor = gradientColor * texture2D(sampler, outTexCoords).a;\n" 202 }; 203const char* gFS_Main_BitmapShader_Modulate[3] = { 204 // Don't modulate 205 " fragColor = bitmapColor;\n", 206 // Modulate 207 " fragColor = bitmapColor * fragColor.a;\n", 208 // Modulate with alpha 8 texture 209 " fragColor = bitmapColor * texture2D(sampler, outTexCoords).a;\n" 210 }; 211const char* gFS_Main_FragColor = 212 " gl_FragColor = fragColor;\n"; 213const char* gFS_Main_FragColor_Blend = 214 " gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n"; 215const char* gFS_Main_FragColor_Blend_Swap = 216 " gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n"; 217const char* gFS_Main_ApplyColorOp[4] = { 218 // None 219 "", 220 // Matrix 221 // TODO: Fix premultiplied alpha computations for color matrix 222 " fragColor *= colorMatrix;\n" 223 " fragColor += colorMatrixVector;\n" 224 " fragColor.rgb *= fragColor.a;\n", 225 // Lighting 226 " float lightingAlpha = fragColor.a;\n" 227 " fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n" 228 " fragColor.a = lightingAlpha;\n", 229 // PorterDuff 230 " fragColor = blendColors(colorBlend, fragColor);\n" 231}; 232const char* gFS_Footer = 233 "}\n\n"; 234 235/////////////////////////////////////////////////////////////////////////////// 236// PorterDuff snippets 237/////////////////////////////////////////////////////////////////////////////// 238 239const char* gBlendOps[18] = { 240 // Clear 241 "return vec4(0.0, 0.0, 0.0, 0.0);\n", 242 // Src 243 "return src;\n", 244 // Dst 245 "return dst;\n", 246 // SrcOver 247 "return src + dst * (1.0 - src.a);\n", 248 // DstOver 249 "return dst + src * (1.0 - dst.a);\n", 250 // SrcIn 251 "return src * dst.a;\n", 252 // DstIn 253 "return dst * src.a;\n", 254 // SrcOut 255 "return src * (1.0 - dst.a);\n", 256 // DstOut 257 "return dst * (1.0 - src.a);\n", 258 // SrcAtop 259 "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n", 260 // DstAtop 261 "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n", 262 // Xor 263 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, " 264 "src.a + dst.a - 2.0 * src.a * dst.a);\n", 265 // Add 266 "return min(src + dst, 1.0);\n", 267 // Multiply 268 "return src * dst;\n", 269 // Screen 270 "return src + dst - src * dst;\n", 271 // Overlay 272 "return clamp(vec4(mix(" 273 "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), " 274 "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), " 275 "step(dst.a, 2.0 * dst.rgb)), " 276 "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n", 277 // Darken 278 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + " 279 "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n", 280 // Lighten 281 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + " 282 "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n", 283}; 284 285/////////////////////////////////////////////////////////////////////////////// 286// Constructors/destructors 287/////////////////////////////////////////////////////////////////////////////// 288 289ProgramCache::ProgramCache() { 290} 291 292ProgramCache::~ProgramCache() { 293 clear(); 294} 295 296/////////////////////////////////////////////////////////////////////////////// 297// Cache management 298/////////////////////////////////////////////////////////////////////////////// 299 300void ProgramCache::clear() { 301 size_t count = mCache.size(); 302 for (size_t i = 0; i < count; i++) { 303 delete mCache.valueAt(i); 304 } 305 mCache.clear(); 306} 307 308Program* ProgramCache::get(const ProgramDescription& description) { 309 programid key = description.key(); 310 ssize_t index = mCache.indexOfKey(key); 311 Program* program = NULL; 312 if (index < 0) { 313 description.log("Could not find program"); 314 program = generateProgram(description, key); 315 mCache.add(key, program); 316 } else { 317 program = mCache.valueAt(index); 318 } 319 return program; 320} 321 322/////////////////////////////////////////////////////////////////////////////// 323// Program generation 324/////////////////////////////////////////////////////////////////////////////// 325 326Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) { 327 String8 vertexShader = generateVertexShader(description); 328 String8 fragmentShader = generateFragmentShader(description); 329 330 Program* program = new Program(vertexShader.string(), fragmentShader.string()); 331 return program; 332} 333 334String8 ProgramCache::generateVertexShader(const ProgramDescription& description) { 335 // Add attributes 336 String8 shader(gVS_Header_Attributes); 337 if (description.hasTexture) { 338 shader.append(gVS_Header_Attributes_TexCoords); 339 } 340 // Uniforms 341 shader.append(gVS_Header_Uniforms); 342 if (description.hasGradient) { 343 shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]); 344 } 345 if (description.hasBitmap) { 346 shader.append(gVS_Header_Uniforms_HasBitmap); 347 } 348 // Varyings 349 if (description.hasTexture) { 350 shader.append(gVS_Header_Varyings_HasTexture); 351 } 352 if (description.hasGradient) { 353 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); 354 } 355 if (description.hasBitmap) { 356 shader.append(gVS_Header_Varyings_HasBitmap); 357 } 358 359 // Begin the shader 360 shader.append(gVS_Main); { 361 if (description.hasTexture) { 362 shader.append(gVS_Main_OutTexCoords); 363 } 364 if (description.hasGradient) { 365 shader.append(gVS_Main_OutGradient[description.gradientType]); 366 } 367 if (description.hasBitmap) { 368 shader.append(gVS_Main_OutBitmapTexCoords); 369 } 370 // Output transformed position 371 shader.append(gVS_Main_Position); 372 } 373 // End the shader 374 shader.append(gVS_Footer); 375 376 PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string()); 377 378 return shader; 379} 380 381String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) { 382 // Set the default precision 383 String8 shader; 384 385 const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; 386 if (blendFramebuffer) { 387 shader.append(gFS_Header_Extension_FramebufferFetch); 388 } 389 390 shader.append(gFS_Header); 391 392 // Varyings 393 if (description.hasTexture) { 394 shader.append(gVS_Header_Varyings_HasTexture); 395 } 396 if (description.hasGradient) { 397 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); 398 } 399 if (description.hasBitmap) { 400 shader.append(gVS_Header_Varyings_HasBitmap); 401 } 402 403 // Uniforms 404 int modulateOp = MODULATE_OP_NO_MODULATE; 405 const bool singleColor = !description.hasTexture && 406 !description.hasGradient && !description.hasBitmap; 407 408 if (description.modulate || singleColor) { 409 shader.append(gFS_Uniforms_Color); 410 if (!singleColor) modulateOp = MODULATE_OP_MODULATE; 411 } 412 if (description.hasTexture) { 413 shader.append(gFS_Uniforms_TextureSampler); 414 } 415 if (description.hasGradient) { 416 shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); 417 } 418 419 // Optimization for common cases 420 if (!blendFramebuffer) { 421 bool fast = false; 422 423 const bool noShader = !description.hasGradient && !description.hasBitmap; 424 const bool singleTexture = description.hasTexture && 425 !description.hasAlpha8Texture && noShader; 426 const bool singleA8Texture = description.hasTexture && 427 description.hasAlpha8Texture && noShader; 428 const bool singleGradient = !description.hasTexture && 429 description.hasGradient && !description.hasBitmap && 430 description.gradientType == ProgramDescription::kGradientLinear; 431 432 if (singleColor) { 433 shader.append(gFS_Fast_SingleColor); 434 fast = true; 435 } else if (singleTexture) { 436 if (!description.modulate) { 437 shader.append(gFS_Fast_SingleTexture); 438 } else { 439 shader.append(gFS_Fast_SingleModulateTexture); 440 } 441 fast = true; 442 } else if (singleA8Texture) { 443 if (!description.modulate) { 444 shader.append(gFS_Fast_SingleA8Texture); 445 } else { 446 shader.append(gFS_Fast_SingleModulateA8Texture); 447 } 448 fast = true; 449 } else if (singleGradient) { 450 if (!description.modulate) { 451 shader.append(gFS_Fast_SingleGradient); 452 } else { 453 shader.append(gFS_Fast_SingleModulateGradient); 454 } 455 fast = true; 456 } 457 458 if (fast) { 459 if (DEBUG_PROGRAM_CACHE) { 460 PROGRAM_LOGD("*** Fast case:\n"); 461 PROGRAM_LOGD("*** Generated fragment shader:\n\n"); 462 printLongString(shader); 463 } 464 465 return shader; 466 } 467 } 468 469 if (description.hasBitmap) { 470 shader.append(gFS_Uniforms_BitmapSampler); 471 } 472 shader.append(gFS_Uniforms_ColorOp[description.colorOp]); 473 474 // Generate required functions 475 if (description.hasGradient && description.hasBitmap) { 476 generateBlend(shader, "blendShaders", description.shadersMode); 477 } 478 if (description.colorOp == ProgramDescription::kColorBlend) { 479 generateBlend(shader, "blendColors", description.colorMode); 480 } 481 if (blendFramebuffer) { 482 generateBlend(shader, "blendFramebuffer", description.framebufferMode); 483 } 484 if (description.isBitmapNpot) { 485 generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); 486 } 487 488 // Begin the shader 489 shader.append(gFS_Main); { 490 // Stores the result in fragColor directly 491 if (description.hasTexture) { 492 if (description.hasAlpha8Texture) { 493 if (!description.hasGradient && !description.hasBitmap) { 494 shader.append(gFS_Main_FetchA8Texture[modulateOp]); 495 } 496 } else { 497 shader.append(gFS_Main_FetchTexture[modulateOp]); 498 } 499 } else { 500 if ((!description.hasGradient && !description.hasBitmap) || description.modulate) { 501 shader.append(gFS_Main_FetchColor); 502 } 503 } 504 if (description.hasGradient) { 505 shader.append(gFS_Main_FetchGradient[description.gradientType]); 506 } 507 if (description.hasBitmap) { 508 if (!description.isBitmapNpot) { 509 shader.append(gFS_Main_FetchBitmap); 510 } else { 511 shader.append(gFS_Main_FetchBitmapNpot); 512 } 513 } 514 // Case when we have two shaders set 515 if (description.hasGradient && description.hasBitmap) { 516 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; 517 if (description.isBitmapFirst) { 518 shader.append(gFS_Main_BlendShadersBG); 519 } else { 520 shader.append(gFS_Main_BlendShadersGB); 521 } 522 shader.append(gFS_Main_BlendShaders_Modulate[op]); 523 } else { 524 if (description.hasGradient) { 525 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; 526 shader.append(gFS_Main_GradientShader_Modulate[op]); 527 } else if (description.hasBitmap) { 528 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; 529 shader.append(gFS_Main_BitmapShader_Modulate[op]); 530 } 531 } 532 // Apply the color op if needed 533 shader.append(gFS_Main_ApplyColorOp[description.colorOp]); 534 // Output the fragment 535 if (!blendFramebuffer) { 536 shader.append(gFS_Main_FragColor); 537 } else { 538 shader.append(!description.swapSrcDst ? 539 gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap); 540 } 541 } 542 // End the shader 543 shader.append(gFS_Footer); 544 545 if (DEBUG_PROGRAM_CACHE) { 546 PROGRAM_LOGD("*** Generated fragment shader:\n\n"); 547 printLongString(shader); 548 } 549 550 return shader; 551} 552 553void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) { 554 shader.append("\nvec4 "); 555 shader.append(name); 556 shader.append("(vec4 src, vec4 dst) {\n"); 557 shader.append(" "); 558 shader.append(gBlendOps[mode]); 559 shader.append("}\n"); 560} 561 562void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) { 563 shader.append("\nvec2 wrap(vec2 texCoords) {\n"); 564 if (wrapS == GL_MIRRORED_REPEAT) { 565 shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n"); 566 shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n"); 567 } 568 if (wrapT == GL_MIRRORED_REPEAT) { 569 shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n"); 570 shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n"); 571 } 572 shader.append(" return vec2("); 573 switch (wrapS) { 574 case GL_CLAMP_TO_EDGE: 575 shader.append("texCoords.x"); 576 break; 577 case GL_REPEAT: 578 shader.append("mod(texCoords.x, 1.0)"); 579 break; 580 case GL_MIRRORED_REPEAT: 581 shader.append("xMod2"); 582 break; 583 } 584 shader.append(", "); 585 switch (wrapT) { 586 case GL_CLAMP_TO_EDGE: 587 shader.append("texCoords.y"); 588 break; 589 case GL_REPEAT: 590 shader.append("mod(texCoords.y, 1.0)"); 591 break; 592 case GL_MIRRORED_REPEAT: 593 shader.append("yMod2"); 594 break; 595 } 596 shader.append(");\n"); 597 shader.append("}\n"); 598} 599 600void ProgramCache::printLongString(const String8& shader) const { 601 ssize_t index = 0; 602 ssize_t lastIndex = 0; 603 const char* str = shader.string(); 604 while ((index = shader.find("\n", index)) > -1) { 605 String8 line(str, index - lastIndex); 606 if (line.length() == 0) line.append("\n"); 607 PROGRAM_LOGD("%s", line.string()); 608 index++; 609 str += (index - lastIndex); 610 lastIndex = index; 611 } 612} 613 614}; // namespace uirenderer 615}; // namespace android 616