String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) { String8 shader; const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; if (blendFramebuffer) { shader.append(gFS_Header_Extension_FramebufferFetch); } if (description.hasExternalTexture) { shader.append(gFS_Header_Extension_ExternalTexture); } shader.append(gFS_Header); // Varyings if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.hasVertexAlpha) { shader.append(gVS_Header_Varyings_HasVertexAlpha); } if (description.hasColors) { shader.append(gVS_Header_Varyings_HasColors); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]); } if (description.hasBitmap) { shader.append(gVS_Header_Varyings_HasBitmap); } if (description.hasRoundRectClip) { shader.append(gVS_Header_Varyings_HasRoundRectClip); } // Uniforms int modulateOp = MODULATE_OP_NO_MODULATE; const bool singleColor = !description.hasTexture && !description.hasExternalTexture && !description.hasGradient && !description.hasBitmap; if (description.modulate || singleColor) { shader.append(gFS_Uniforms_Color); if (!singleColor) modulateOp = MODULATE_OP_MODULATE; } if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); } else if (description.hasExternalTexture) { shader.append(gFS_Uniforms_ExternalTextureSampler); } if (description.hasGradient) { shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient], gFS_Uniforms_Dither); } if (description.hasGammaCorrection) { shader.append(gFS_Uniforms_Gamma); } if (description.hasRoundRectClip) { shader.append(gFS_Uniforms_HasRoundRectClip); } // Optimization for common cases if (!description.hasVertexAlpha && !blendFramebuffer && !description.hasColors && description.colorOp == ProgramDescription::kColorNone && !description.hasDebugHighlight && !description.emulateStencil && !description.hasRoundRectClip) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; const bool singleTexture = (description.hasTexture || description.hasExternalTexture) && !description.hasAlpha8Texture && noShader; const bool singleA8Texture = description.hasTexture && description.hasAlpha8Texture && noShader; const bool singleGradient = !description.hasTexture && !description.hasExternalTexture && description.hasGradient && !description.hasBitmap && description.gradientType == ProgramDescription::kGradientLinear; if (singleColor) { shader.append(gFS_Fast_SingleColor); fast = true; } else if (singleTexture) { if (!description.modulate) { shader.append(gFS_Fast_SingleTexture); } else { shader.append(gFS_Fast_SingleModulateTexture); } fast = true; } else if (singleA8Texture) { if (!description.modulate) { if (description.hasGammaCorrection) { shader.append(gFS_Fast_SingleA8Texture_ApplyGamma); } else { shader.append(gFS_Fast_SingleA8Texture); } } else { if (description.hasGammaCorrection) { shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma); } else { shader.append(gFS_Fast_SingleModulateA8Texture); } } fast = true; } else if (singleGradient) { if (!description.modulate) { shader.appendFormat(gFS_Fast_SingleGradient[description.isSimpleGradient], gFS_Main_Dither[mHasES3]); } else { shader.appendFormat(gFS_Fast_SingleModulateGradient[description.isSimpleGradient], gFS_Main_Dither[mHasES3]); } fast = true; } if (fast) { #if DEBUG_PROGRAMS PROGRAM_LOGD("*** Fast case:\n"); PROGRAM_LOGD("*** Generated fragment shader:\n\n"); printLongString(shader); #endif return shader; } } if (description.hasBitmap) { shader.append(gFS_Uniforms_BitmapSampler); } shader.append(gFS_Uniforms_ColorOp[description.colorOp]); // Generate required functions if (description.hasGradient && description.hasBitmap) { generateBlend(shader, "blendShaders", description.shadersMode); } if (description.colorOp == ProgramDescription::kColorBlend) { generateBlend(shader, "blendColors", description.colorMode); } if (blendFramebuffer) { generateBlend(shader, "blendFramebuffer", description.framebufferMode); } if (description.isBitmapNpot) { generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); } // Begin the shader shader.append(gFS_Main); { if (description.emulateStencil) { shader.append(gFS_Main_EmulateStencil); } // Stores the result in fragColor directly if (description.hasTexture || description.hasExternalTexture) { if (description.hasAlpha8Texture) { if (!description.hasGradient && !description.hasBitmap) { shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 + description.hasGammaCorrection]); } } else { shader.append(gFS_Main_FetchTexture[modulateOp]); } } else { if (!description.hasGradient && !description.hasBitmap) { shader.append(gFS_Main_FetchColor); } } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[gradientIndex(description)]); shader.appendFormat(gFS_Main_AddDitherToGradient, gFS_Main_Dither[mHasES3]); } if (description.hasBitmap) { if (!description.isBitmapNpot) { shader.append(gFS_Main_FetchBitmap); } else { shader.append(gFS_Main_FetchBitmapNpot); } } bool applyModulate = false; // Case when we have two shaders set if (description.hasGradient && description.hasBitmap) { if (description.isBitmapFirst) { shader.append(gFS_Main_BlendShadersBG); } else { shader.append(gFS_Main_BlendShadersGB); } applyModulate = shaderOp(description, shader, modulateOp, gFS_Main_BlendShaders_Modulate); } else { if (description.hasGradient) { applyModulate = shaderOp(description, shader, modulateOp, gFS_Main_GradientShader_Modulate); } else if (description.hasBitmap) { applyModulate = shaderOp(description, shader, modulateOp, gFS_Main_BitmapShader_Modulate); } } if (description.modulate && applyModulate) { shader.append(gFS_Main_ModulateColor); } // Apply the color op if needed shader.append(gFS_Main_ApplyColorOp[description.colorOp]); if (description.hasVertexAlpha) { if (description.useShadowAlphaInterp) { shader.append(gFS_Main_ApplyVertexAlphaShadowInterp); } else { shader.append(gFS_Main_ApplyVertexAlphaLinearInterp); } } // Output the fragment if (!blendFramebuffer) { shader.append(gFS_Main_FragColor); } else { shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap); } if (description.hasColors) { shader.append(gFS_Main_FragColor_HasColors); } if (description.hasRoundRectClip) { shader.append(gFS_Main_FragColor_HasRoundRectClip); } if (description.hasDebugHighlight) { shader.append(gFS_Main_DebugHighlight); } } if (description.emulateStencil) { shader.append(gFS_Footer_EmulateStencil); } // End the shader shader.append(gFS_Footer); #if DEBUG_PROGRAMS PROGRAM_LOGD("*** Generated fragment shader:\n\n"); printLongString(shader); #endif return shader; }
String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) { String8 shader; const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; if (blendFramebuffer) { shader.append(gFS_Header_Extension_FramebufferFetch); } if (description.hasExternalTexture) { shader.append(gFS_Header_Extension_ExternalTexture); } shader.append(gFS_Header); // Varyings if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.isAA) { shader.append(gVS_Header_Varyings_IsAA); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { int index = Caches::getInstance().extensions.needsHighpTexCoords() ? 1 : 0; shader.append(description.isPoint ? gVS_Header_Varyings_PointHasBitmap[index] : gVS_Header_Varyings_HasBitmap[index]); } // Uniforms int modulateOp = MODULATE_OP_NO_MODULATE; const bool singleColor = !description.hasTexture && !description.hasExternalTexture && !description.hasGradient && !description.hasBitmap; if (description.modulate || singleColor) { shader.append(gFS_Uniforms_Color); if (!singleColor) modulateOp = MODULATE_OP_MODULATE; } if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); } else if (description.hasExternalTexture) { shader.append(gFS_Uniforms_ExternalTextureSampler); } if (description.isAA) { shader.append(gFS_Uniforms_AA); } if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } if (description.hasBitmap && description.isPoint) { shader.append(gFS_Header_Uniforms_PointHasBitmap); } // Optimization for common cases if (!description.isAA && !blendFramebuffer && description.colorOp == ProgramDescription::kColorNone && !description.isPoint) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; const bool singleTexture = (description.hasTexture || description.hasExternalTexture) && !description.hasAlpha8Texture && noShader; const bool singleA8Texture = description.hasTexture && description.hasAlpha8Texture && noShader; const bool singleGradient = !description.hasTexture && !description.hasExternalTexture && description.hasGradient && !description.hasBitmap && description.gradientType == ProgramDescription::kGradientLinear; if (singleColor) { shader.append(gFS_Fast_SingleColor); fast = true; } else if (singleTexture) { if (!description.modulate) { shader.append(gFS_Fast_SingleTexture); } else { shader.append(gFS_Fast_SingleModulateTexture); } fast = true; } else if (singleA8Texture) { if (!description.modulate) { shader.append(gFS_Fast_SingleA8Texture); } else { shader.append(gFS_Fast_SingleModulateA8Texture); } fast = true; } else if (singleGradient) { if (!description.modulate) { shader.append(gFS_Fast_SingleGradient); } else { shader.append(gFS_Fast_SingleModulateGradient); } fast = true; } if (fast) { #if DEBUG_PROGRAMS PROGRAM_LOGD("*** Fast case:\n"); PROGRAM_LOGD("*** Generated fragment shader:\n\n"); printLongString(shader); #endif return shader; } } if (description.hasBitmap) { shader.append(gFS_Uniforms_BitmapSampler); } shader.append(gFS_Uniforms_ColorOp[description.colorOp]); // Generate required functions if (description.hasGradient && description.hasBitmap) { generateBlend(shader, "blendShaders", description.shadersMode); } if (description.colorOp == ProgramDescription::kColorBlend) { generateBlend(shader, "blendColors", description.colorMode); } if (blendFramebuffer) { generateBlend(shader, "blendFramebuffer", description.framebufferMode); } if (description.isBitmapNpot) { generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); } // Begin the shader shader.append(gFS_Main); { // Stores the result in fragColor directly if (description.hasTexture || description.hasExternalTexture) { if (description.hasAlpha8Texture) { if (!description.hasGradient && !description.hasBitmap) { shader.append(gFS_Main_FetchA8Texture[modulateOp]); } } else { shader.append(gFS_Main_FetchTexture[modulateOp]); } } else { if ((!description.hasGradient && !description.hasBitmap) || description.modulate) { shader.append(gFS_Main_FetchColor); } } if (description.isAA) { shader.append(gFS_Main_AccountForAA); } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[description.gradientType]); } if (description.hasBitmap) { if (description.isPoint) { shader.append(gFS_Main_PointBitmapTexCoords); } if (!description.isBitmapNpot) { shader.append(gFS_Main_FetchBitmap); } else { shader.append(gFS_Main_FetchBitmapNpot); } } bool applyModulate = false; // Case when we have two shaders set if (description.hasGradient && description.hasBitmap) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; if (description.isBitmapFirst) { shader.append(gFS_Main_BlendShadersBG); } else { shader.append(gFS_Main_BlendShadersGB); } shader.append(gFS_Main_BlendShaders_Modulate[op]); applyModulate = true; } else { if (description.hasGradient) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; shader.append(gFS_Main_GradientShader_Modulate[op]); applyModulate = true; } else if (description.hasBitmap) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; shader.append(gFS_Main_BitmapShader_Modulate[op]); applyModulate = true; } } if (description.modulate && applyModulate) { shader.append(gFS_Main_ModulateColor); } // Apply the color op if needed shader.append(gFS_Main_ApplyColorOp[description.colorOp]); // Output the fragment if (!blendFramebuffer) { shader.append(gFS_Main_FragColor); } else { shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap); } } // End the shader shader.append(gFS_Footer); #if DEBUG_PROGRAMS PROGRAM_LOGD("*** Generated fragment shader:\n\n"); printLongString(shader); #endif return shader; }