OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkGradientShaderPriv.h" | 8 #include "SkGradientShaderPriv.h" |
9 #include "SkLinearGradient.h" | 9 #include "SkLinearGradient.h" |
10 #include "SkRadialGradient.h" | 10 #include "SkRadialGradient.h" |
(...skipping 813 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
824 #include "SkGr.h" | 824 #include "SkGr.h" |
825 | 825 |
826 GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory) | 826 GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory) |
827 : INHERITED(factory) | 827 : INHERITED(factory) |
828 , fCachedYCoord(SK_ScalarMax) | 828 , fCachedYCoord(SK_ScalarMax) |
829 , fEffectMatrix(kCoordsType) { | 829 , fEffectMatrix(kCoordsType) { |
830 } | 830 } |
831 | 831 |
832 GrGLGradientEffect::~GrGLGradientEffect() { } | 832 GrGLGradientEffect::~GrGLGradientEffect() { } |
833 | 833 |
834 void GrGLGradientEffect::emitYCoordUniform(GrGLShaderBuilder* builder) { | 834 void GrGLGradientEffect::emitUniforms(GrGLShaderBuilder* builder, EffectKey key)
{ |
835 fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, | 835 |
836 kFloat_GrSLType, "GradientYCoordFS"); | 836 if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)) { // 2 Color
case |
| 837 fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibi
lity, |
| 838 kVec4f_GrSLType, "GradientStartColo
r"); |
| 839 fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibili
ty, |
| 840 kVec4f_GrSLType, "GradientEndColor"); |
| 841 |
| 842 } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){ //
3 Color Case |
| 843 fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibi
lity, |
| 844 kVec4f_GrSLType, "GradientStartColo
r"); |
| 845 fColorMidUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibili
ty, |
| 846 kVec4f_GrSLType, "GradientMidColor"); |
| 847 fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibili
ty, |
| 848 kVec4f_GrSLType, "GradientEndColor"
); |
| 849 |
| 850 } else { // if not a fast case |
| 851 fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
| 852 kFloat_GrSLType, "GradientYCoordFS"); |
| 853 } |
| 854 } |
| 855 |
| 856 static inline void set_color_uni(const GrGLUniformManager& uman, |
| 857 const GrGLUniformManager::UniformHandle uni, |
| 858 const SkColor* color) { |
| 859 uman.set4f(uni, |
| 860 SkColorGetR(*color) / 255.f, |
| 861 SkColorGetG(*color) / 255.f, |
| 862 SkColorGetB(*color) / 255.f, |
| 863 SkColorGetA(*color) / 255.f); |
| 864 } |
| 865 |
| 866 static inline void set_mul_color_uni(const GrGLUniformManager& uman, |
| 867 const GrGLUniformManager::UniformHandle uni
, |
| 868 const SkColor* color){ |
| 869 float a = SkColorGetA(*color) / 255.f; |
| 870 float aDiv255 = a / 255.f; |
| 871 uman.set4f(uni, |
| 872 SkColorGetR(*color) * aDiv255, |
| 873 SkColorGetG(*color) * aDiv255, |
| 874 SkColorGetB(*color) * aDiv255, |
| 875 a); |
837 } | 876 } |
838 | 877 |
839 void GrGLGradientEffect::setData(const GrGLUniformManager& uman, | 878 void GrGLGradientEffect::setData(const GrGLUniformManager& uman, |
840 const GrDrawEffect& drawEffect) { | 879 const GrDrawEffect& drawEffect) { |
| 880 |
841 const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>(); | 881 const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>(); |
842 const GrTexture* texture = e.texture(0); | |
843 fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, texture); | |
844 | 882 |
845 SkScalar yCoord = e.getYCoord(); | 883 |
846 if (yCoord != fCachedYCoord) { | 884 if (GrGradientEffect::kTwo_ColorType == e.getColorType()){ |
847 uman.set1f(fFSYUni, yCoord); | 885 |
848 fCachedYCoord = yCoord; | 886 fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, NULL); |
| 887 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
| 888 set_mul_color_uni(uman, fColorStartUni, e.getColors(0)); |
| 889 set_mul_color_uni(uman, fColorEndUni, e.getColors(1)); |
| 890 } else { |
| 891 set_color_uni(uman, fColorStartUni, e.getColors(0)); |
| 892 set_color_uni(uman, fColorEndUni, e.getColors(1)); |
| 893 } |
| 894 |
| 895 } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){ |
| 896 |
| 897 fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, NULL); |
| 898 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
| 899 set_mul_color_uni(uman, fColorStartUni, e.getColors(0)); |
| 900 set_mul_color_uni(uman, fColorMidUni, e.getColors(1)); |
| 901 set_mul_color_uni(uman, fColorEndUni, e.getColors(2)); |
| 902 } else { |
| 903 set_color_uni(uman, fColorStartUni, e.getColors(0)); |
| 904 set_color_uni(uman, fColorMidUni, e.getColors(1)); |
| 905 set_color_uni(uman, fColorEndUni, e.getColors(2)); |
| 906 } |
| 907 } else { |
| 908 const GrTexture* texture = e.texture(0); |
| 909 fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, texture); |
| 910 |
| 911 SkScalar yCoord = e.getYCoord(); |
| 912 if (yCoord != fCachedYCoord) { |
| 913 uman.set1f(fFSYUni, yCoord); |
| 914 fCachedYCoord = yCoord; |
| 915 } |
849 } | 916 } |
850 } | 917 } |
851 | 918 |
852 GrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrDrawEffect& drawE
ffect) { | 919 |
| 920 GrGLEffect::EffectKey GrGLGradientEffect::GenBaseGradientKey(const GrDrawEffect&
drawEffect) { |
853 const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>(); | 921 const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>(); |
854 const GrTexture* texture = e.texture(0); | 922 const GrTexture* texture = NULL; |
855 return GrGLEffectMatrix::GenKey(e.getMatrix(), drawEffect, kCoordsType, text
ure); | 923 |
| 924 if (GrGradientEffect::kTexture_ColorType == e.getColorType()){ |
| 925 texture = e.texture(0); |
| 926 } |
| 927 |
| 928 EffectKey key = GrGLEffectMatrix::GenKey(e.getMatrix(), drawEffect, kCoordsT
ype, texture); |
| 929 |
| 930 if (GrGradientEffect::kTwo_ColorType == e.getColorType()) { |
| 931 key |= kTwoColorKey; |
| 932 } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){ |
| 933 key |= kThreeColorKey; |
| 934 } |
| 935 |
| 936 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
| 937 key |= kPremulBeforeInterpKey; |
| 938 } |
| 939 |
| 940 return key; |
856 } | 941 } |
857 | 942 |
858 void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder, | 943 void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder, |
859 EffectKey key, | 944 EffectKey key, |
860 SkString* fsCoordName, | 945 SkString* fsCoordName, |
861 SkString* vsVaryingName, | 946 SkString* vsVaryingName, |
862 GrSLType* vsVaryingType) { | 947 GrSLType* vsVaryingType) { |
863 fEffectMatrix.emitCodeMakeFSCoords2D(builder, | 948 fEffectMatrix.emitCodeMakeFSCoords2D(builder, |
864 key & kMatrixKeyMask, | 949 key & kMatrixKeyMask, |
865 fsCoordName, | 950 fsCoordName, |
866 vsVaryingName, | 951 vsVaryingName, |
867 vsVaryingType); | 952 vsVaryingType); |
868 } | 953 } |
869 | 954 |
870 void GrGLGradientEffect::emitColorLookup(GrGLShaderBuilder* builder, | 955 void GrGLGradientEffect::emitColor(GrGLShaderBuilder* builder, |
871 const char* gradientTValue, | 956 const char* gradientTValue, |
872 const char* outputColor, | 957 EffectKey key, |
873 const char* inputColor, | 958 const char* outputColor, |
874 const GrGLShaderBuilder::TextureSampler
& sampler) { | 959 const char* inputColor, |
| 960 const GrGLShaderBuilder::TextureSamplerArray&
samplers) { |
| 961 if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)){ |
| 962 builder->fsCodeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.
0));\n", |
| 963 builder->getUniformVariable(fColorStartUni).c_str
(), |
| 964 builder->getUniformVariable(fColorEndUni).c_str()
, |
| 965 gradientTValue); |
| 966 // Note that we could skip this step if both colors are known to be opaq
ue. Two |
| 967 // considerations: |
| 968 // The gradient SkShader reporting opaque is more restrictive than neces
sary in the two pt |
| 969 // case. Make sure the key reflects this optimization (and note that it
can use the same |
| 970 // shader as thekBeforeIterp case). This same optimization applies to th
e 3 color case below. |
| 971 if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(key))
{ |
| 972 builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n"); |
| 973 } |
875 | 974 |
876 builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n", | 975 SkString output; |
877 gradientTValue, | 976 builder->fsCodeAppendf("\t%s = ", outputColor); |
878 builder->getUniformVariable(fFSYUni).c_str()); | 977 GrGLSLModulatef<4>(&output, inputColor, "colorTemp"); |
879 builder->fsCodeAppendf("\t%s = ", outputColor); | 978 builder->fsCodeAppend(output.c_str()); |
880 builder->fsAppendTextureLookupAndModulate(inputColor, sampler, "coord"); | 979 builder->fsCodeAppend(";\n"); |
881 builder->fsCodeAppend(";\n"); | 980 } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){ |
| 981 builder->fsCodeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n", |
| 982 gradientTValue); |
| 983 builder->fsCodeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) *
%s +(1.0 - min(abs(oneMinus2t), 1.0)) * %s + clamp(-oneMinus2t, 0.0, 1.0) * %s;
\n", |
| 984 builder->getUniformVariable(fColorStartUni).c_str
(), |
| 985 builder->getUniformVariable(fColorMidUni).c_str()
, |
| 986 builder->getUniformVariable(fColorEndUni).c_str()
); |
| 987 if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(key))
{ |
| 988 builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n"); |
| 989 } |
| 990 |
| 991 SkString output; |
| 992 builder->fsCodeAppendf("\t%s = ", outputColor); |
| 993 GrGLSLModulatef<4>(&output, inputColor, "colorTemp"); |
| 994 builder->fsCodeAppend(output.c_str()); |
| 995 builder->fsCodeAppend(";\n"); |
| 996 } else { |
| 997 builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n", |
| 998 gradientTValue, |
| 999 builder->getUniformVariable(fFSYUni).c_str()); |
| 1000 builder->fsCodeAppendf("\t%s = ", outputColor); |
| 1001 builder->fsAppendTextureLookupAndModulate(inputColor, |
| 1002 samplers[0], |
| 1003 "coord"); |
| 1004 builder->fsCodeAppend(";\n"); |
| 1005 } |
882 } | 1006 } |
883 | 1007 |
884 ///////////////////////////////////////////////////////////////////// | 1008 ///////////////////////////////////////////////////////////////////// |
885 | 1009 |
886 GrGradientEffect::GrGradientEffect(GrContext* ctx, | 1010 GrGradientEffect::GrGradientEffect(GrContext* ctx, |
887 const SkGradientShaderBase& shader, | 1011 const SkGradientShaderBase& shader, |
888 const SkMatrix& matrix, | 1012 const SkMatrix& matrix, |
889 SkShader::TileMode tileMode) { | 1013 SkShader::TileMode tileMode) { |
890 // TODO: check for simple cases where we don't need a texture: | 1014 |
891 //GradientInfo info; | |
892 //shader.asAGradient(&info); | |
893 //if (info.fColorCount == 2) { ... | |
894 | 1015 |
895 fMatrix = matrix; | 1016 fMatrix = matrix; |
896 | |
897 SkBitmap bitmap; | |
898 shader.getGradientTableBitmap(&bitmap); | |
899 | |
900 fIsOpaque = shader.isOpaque(); | 1017 fIsOpaque = shader.isOpaque(); |
901 | 1018 |
902 GrTextureStripAtlas::Desc desc; | 1019 SkShader::GradientInfo info; |
903 desc.fWidth = bitmap.width(); | 1020 SkScalar pos[3] = {0}; |
904 desc.fHeight = 32; | |
905 desc.fRowHeight = bitmap.height(); | |
906 desc.fContext = ctx; | |
907 desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config()); | |
908 fAtlas = GrTextureStripAtlas::GetAtlas(desc); | |
909 SkASSERT(NULL != fAtlas); | |
910 | 1021 |
911 // We always filter the gradient table. Each table is one row of a texture,
so always y-clamp. | 1022 info.fColorCount = 3; |
912 GrTextureParams params; | 1023 info.fColors = &fColors[0]; |
913 params.setFilterMode(GrTextureParams::kBilerp_FilterMode); | 1024 info.fColorOffsets = &pos[0]; |
914 params.setTileModeX(tileMode); | 1025 shader.asAGradient(&info); |
915 | 1026 |
916 fRow = fAtlas->lockRow(bitmap); | 1027 // The two and three color specializations do not currently support tiling. |
917 if (-1 != fRow) { | 1028 bool foundSpecialCase = false; |
918 fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * | 1029 if (SkShader::kClamp_TileMode == info.fTileMode) { |
919 fAtlas->getVerticalScaleFactor(); | 1030 if (2 == info.fColorCount) { |
920 fTextureAccess.reset(fAtlas->getTexture(), params); | 1031 fRow = -1; // flag for no atlas |
| 1032 fColorType = kTwo_ColorType; |
| 1033 foundSpecialCase = true; |
| 1034 } else if (3 == info.fColorCount && |
| 1035 (SkScalarAbs(pos[1] - SK_ScalarHalf) < SK_Scalar1 / 1000)) {
// 3 color symmetric |
| 1036 fRow = -1; // flag for no atlas |
| 1037 fColorType = kThree_ColorType; |
| 1038 foundSpecialCase = true; |
| 1039 } |
| 1040 } |
| 1041 if (foundSpecialCase) { |
| 1042 if (SkGradientShader::kInterpolateColorsInPremul_Flag & info.fGradientFl
ags) { |
| 1043 fPremulType = kBeforeInterp_PremulType; |
| 1044 } else { |
| 1045 fPremulType = kAfterInterp_PremulType; |
| 1046 } |
921 } else { | 1047 } else { |
922 GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, ¶m
s); | 1048 // doesn't matter how this is set, just be consistent because it is part
of the effect key. |
923 fTextureAccess.reset(texture, params); | 1049 fPremulType = kBeforeInterp_PremulType; |
924 fYCoord = SK_ScalarHalf; | 1050 SkBitmap bitmap; |
| 1051 shader.getGradientTableBitmap(&bitmap); |
| 1052 fColorType = kTexture_ColorType; |
| 1053 |
| 1054 GrTextureStripAtlas::Desc desc; |
| 1055 desc.fWidth = bitmap.width(); |
| 1056 desc.fHeight = 32; |
| 1057 desc.fRowHeight = bitmap.height(); |
| 1058 desc.fContext = ctx; |
| 1059 desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config()); |
| 1060 fAtlas = GrTextureStripAtlas::GetAtlas(desc); |
| 1061 SkASSERT(NULL != fAtlas); |
925 | 1062 |
926 // Unlock immediately, this is not great, but we don't have a way of | 1063 // We always filter the gradient table. Each table is one row of a textu
re, always y-clamp. |
927 // knowing when else to unlock it currently, so it may get purged from | 1064 GrTextureParams params; |
928 // the cache, but it'll still be ref'd until it's no longer being used. | 1065 params.setFilterMode(GrTextureParams::kBilerp_FilterMode); |
929 GrUnlockAndUnrefCachedBitmapTexture(texture); | 1066 params.setTileModeX(tileMode); |
| 1067 |
| 1068 fRow = fAtlas->lockRow(bitmap); |
| 1069 if (-1 != fRow) { |
| 1070 fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * |
| 1071 fAtlas->getVerticalScaleFactor(); |
| 1072 fTextureAccess.reset(fAtlas->getTexture(), params); |
| 1073 } else { |
| 1074 GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, &p
arams); |
| 1075 fTextureAccess.reset(texture, params); |
| 1076 fYCoord = SK_ScalarHalf; |
| 1077 |
| 1078 // Unlock immediately, this is not great, but we don't have a way of |
| 1079 // knowing when else to unlock it currently, so it may get purged fr
om |
| 1080 // the cache, but it'll still be ref'd until it's no longer being us
ed. |
| 1081 GrUnlockAndUnrefCachedBitmapTexture(texture); |
| 1082 } |
| 1083 this->addTextureAccess(&fTextureAccess); |
930 } | 1084 } |
931 this->addTextureAccess(&fTextureAccess); | |
932 } | 1085 } |
933 | 1086 |
934 GrGradientEffect::~GrGradientEffect() { | 1087 GrGradientEffect::~GrGradientEffect() { |
935 if (this->useAtlas()) { | 1088 if (this->useAtlas()) { |
936 fAtlas->unlockRow(fRow); | 1089 fAtlas->unlockRow(fRow); |
937 } | 1090 } |
938 } | 1091 } |
939 | 1092 |
940 bool GrGradientEffect::onIsEqual(const GrEffect& effect) const { | 1093 bool GrGradientEffect::onIsEqual(const GrEffect& effect) const { |
941 const GrGradientEffect& s = CastEffect<GrGradientEffect>(effect); | 1094 const GrGradientEffect& s = CastEffect<GrGradientEffect>(effect); |
942 return fTextureAccess.getTexture() == s.fTextureAccess.getTexture() && | 1095 |
943 fTextureAccess.getParams().getTileModeX() == | 1096 if (this->fColorType == s.getColorType()){ |
| 1097 |
| 1098 if (kTwo_ColorType == fColorType) { |
| 1099 if (*this->getColors(0) != *s.getColors(0) || |
| 1100 *this->getColors(1) != *s.getColors(1)) { |
| 1101 return false; |
| 1102 } |
| 1103 } else if (kThree_ColorType == fColorType) { |
| 1104 if (*this->getColors(0) != *s.getColors(0) || |
| 1105 *this->getColors(1) != *s.getColors(1) || |
| 1106 *this->getColors(2) != *s.getColors(2)) { |
| 1107 return false; |
| 1108 } |
| 1109 } |
| 1110 |
| 1111 return fTextureAccess.getTexture() == s.fTextureAccess.getTexture() && |
| 1112 fTextureAccess.getParams().getTileModeX() == |
944 s.fTextureAccess.getParams().getTileModeX() && | 1113 s.fTextureAccess.getParams().getTileModeX() && |
945 this->useAtlas() == s.useAtlas() && | 1114 this->useAtlas() == s.useAtlas() && |
946 fYCoord == s.getYCoord() && | 1115 fYCoord == s.getYCoord() && |
947 fMatrix.cheapEqualTo(s.getMatrix()); | 1116 fMatrix.cheapEqualTo(s.getMatrix()); |
| 1117 } |
| 1118 |
| 1119 return false; |
948 } | 1120 } |
949 | 1121 |
950 void GrGradientEffect::getConstantColorComponents(GrColor* color, uint32_t* vali
dFlags) const { | 1122 void GrGradientEffect::getConstantColorComponents(GrColor* color, uint32_t* vali
dFlags) const { |
951 if (fIsOpaque && (kA_GrColorComponentFlag & *validFlags) && 0xff == GrColorU
npackA(*color)) { | 1123 if (fIsOpaque && (kA_GrColorComponentFlag & *validFlags) && 0xff == GrColorU
npackA(*color)) { |
952 *validFlags = kA_GrColorComponentFlag; | 1124 *validFlags = kA_GrColorComponentFlag; |
953 } else { | 1125 } else { |
954 *validFlags = 0; | 1126 *validFlags = 0; |
955 } | 1127 } |
956 } | 1128 } |
957 | 1129 |
(...skipping 15 matching lines...) Expand all Loading... |
973 (*stops)[i] = stop; | 1145 (*stops)[i] = stop; |
974 stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - st
op) : 1.f; | 1146 stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - st
op) : 1.f; |
975 } | 1147 } |
976 } | 1148 } |
977 *tm = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileM
odeCount)); | 1149 *tm = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileM
odeCount)); |
978 | 1150 |
979 return outColors; | 1151 return outColors; |
980 } | 1152 } |
981 | 1153 |
982 #endif | 1154 #endif |
OLD | NEW |