|
1 #include "GrBicubicEffect.h" |
|
2 |
|
3 #define DS(x) SkDoubleToScalar(x) |
|
4 |
|
5 const SkScalar GrBicubicEffect::gMitchellCoefficients[16] = { |
|
6 DS( 1.0 / 18.0), DS(-9.0 / 18.0), DS( 15.0 / 18.0), DS( -7.0 / 18.0), |
|
7 DS(16.0 / 18.0), DS( 0.0 / 18.0), DS(-36.0 / 18.0), DS( 21.0 / 18.0), |
|
8 DS( 1.0 / 18.0), DS( 9.0 / 18.0), DS( 27.0 / 18.0), DS(-21.0 / 18.0), |
|
9 DS( 0.0 / 18.0), DS( 0.0 / 18.0), DS( -6.0 / 18.0), DS( 7.0 / 18.0), |
|
10 }; |
|
11 |
|
12 |
|
13 class GrGLBicubicEffect : public GrGLEffect { |
|
14 public: |
|
15 GrGLBicubicEffect(const GrBackendEffectFactory& factory, |
|
16 const GrDrawEffect&); |
|
17 |
|
18 virtual void emitCode(GrGLShaderBuilder*, |
|
19 const GrDrawEffect&, |
|
20 EffectKey, |
|
21 const char* outputColor, |
|
22 const char* inputColor, |
|
23 const TransformedCoordsArray&, |
|
24 const TextureSamplerArray&) SK_OVERRIDE; |
|
25 |
|
26 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; |
|
27 |
|
28 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { |
|
29 const GrTextureDomain& domain = drawEffect.castEffect<GrBicubicEffect>().domain(); |
|
30 return GrTextureDomain::GLDomain::DomainKey(domain); |
|
31 } |
|
32 |
|
33 private: |
|
34 typedef GrGLUniformManager::UniformHandle UniformHandle; |
|
35 |
|
36 UniformHandle fCoefficientsUni; |
|
37 UniformHandle fImageIncrementUni; |
|
38 GrTextureDomain::GLDomain fDomain; |
|
39 |
|
40 typedef GrGLEffect INHERITED; |
|
41 }; |
|
42 |
|
43 GrGLBicubicEffect::GrGLBicubicEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
|
44 : INHERITED(factory) { |
|
45 } |
|
46 |
|
47 void GrGLBicubicEffect::emitCode(GrGLShaderBuilder* builder, |
|
48 const GrDrawEffect& drawEffect, |
|
49 EffectKey key, |
|
50 const char* outputColor, |
|
51 const char* inputColor, |
|
52 const TransformedCoordsArray& coords, |
|
53 const TextureSamplerArray& samplers) { |
|
54 const GrTextureDomain& domain = drawEffect.castEffect<GrBicubicEffect>().domain(); |
|
55 |
|
56 SkString coords2D = builder->ensureFSCoords2D(coords, 0); |
|
57 fCoefficientsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
|
58 kMat44f_GrSLType, "Coefficients"); |
|
59 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
|
60 kVec2f_GrSLType, "ImageIncrement"); |
|
61 |
|
62 const char* imgInc = builder->getUniformCStr(fImageIncrementUni); |
|
63 const char* coeff = builder->getUniformCStr(fCoefficientsUni); |
|
64 |
|
65 SkString cubicBlendName; |
|
66 |
|
67 static const GrGLShaderVar gCubicBlendArgs[] = { |
|
68 GrGLShaderVar("coefficients", kMat44f_GrSLType), |
|
69 GrGLShaderVar("t", kFloat_GrSLType), |
|
70 GrGLShaderVar("c0", kVec4f_GrSLType), |
|
71 GrGLShaderVar("c1", kVec4f_GrSLType), |
|
72 GrGLShaderVar("c2", kVec4f_GrSLType), |
|
73 GrGLShaderVar("c3", kVec4f_GrSLType), |
|
74 }; |
|
75 builder->fsEmitFunction(kVec4f_GrSLType, |
|
76 "cubicBlend", |
|
77 SK_ARRAY_COUNT(gCubicBlendArgs), |
|
78 gCubicBlendArgs, |
|
79 "\tvec4 ts = vec4(1.0, t, t * t, t * t * t);\n" |
|
80 "\tvec4 c = coefficients * ts;\n" |
|
81 "\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n", |
|
82 &cubicBlendName); |
|
83 builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5);\n", coords2D.c_str(), imgInc); |
|
84 // We unnormalize the coord in order to determine our fractional offset (f) within the texel |
|
85 // We then snap coord to a texel center and renormalize. The snap prevents cases where the |
|
86 // starting coords are near a texel boundary and accumulations of imgInc would cause us to skip/ |
|
87 // double hit a texel. |
|
88 builder->fsCodeAppendf("\tcoord /= %s;\n", imgInc); |
|
89 builder->fsCodeAppend("\tvec2 f = fract(coord);\n"); |
|
90 builder->fsCodeAppendf("\tcoord = (coord - f + vec2(0.5)) * %s;\n", imgInc); |
|
91 builder->fsCodeAppend("\tvec4 rowColors[4];\n"); |
|
92 for (int y = 0; y < 4; ++y) { |
|
93 for (int x = 0; x < 4; ++x) { |
|
94 SkString coord; |
|
95 coord.printf("coord + %s * vec2(%d, %d)", imgInc, x - 1, y - 1); |
|
96 SkString sampleVar; |
|
97 sampleVar.printf("rowColors[%d]", x); |
|
98 fDomain.sampleTexture(builder, domain, sampleVar.c_str(), coord, samplers[0]); |
|
99 } |
|
100 builder->fsCodeAppendf("\tvec4 s%d = %s(%s, f.x, rowColors[0], rowColors[1], rowColors[2], rowColors[3]);\n", y, cubicBlendName.c_str(), coeff); |
|
101 } |
|
102 SkString bicubicColor; |
|
103 bicubicColor.printf("%s(%s, f.y, s0, s1, s2, s3)", cubicBlendName.c_str(), coeff); |
|
104 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, (GrGLSLExpr4(bicubicColor.c_str()) * GrGLSLExpr4(inputColor)).c_str()); |
|
105 } |
|
106 |
|
107 void GrGLBicubicEffect::setData(const GrGLUniformManager& uman, |
|
108 const GrDrawEffect& drawEffect) { |
|
109 const GrBicubicEffect& effect = drawEffect.castEffect<GrBicubicEffect>(); |
|
110 const GrTexture& texture = *effect.texture(0); |
|
111 float imageIncrement[2]; |
|
112 imageIncrement[0] = 1.0f / texture.width(); |
|
113 imageIncrement[1] = 1.0f / texture.height(); |
|
114 uman.set2fv(fImageIncrementUni, 1, imageIncrement); |
|
115 uman.setMatrix4f(fCoefficientsUni, effect.coefficients()); |
|
116 fDomain.setData(uman, effect.domain(), texture.origin()); |
|
117 } |
|
118 |
|
119 static inline void convert_row_major_scalar_coeffs_to_column_major_floats(float dst[16], |
|
120 const SkScalar src[16]) { |
|
121 for (int y = 0; y < 4; y++) { |
|
122 for (int x = 0; x < 4; x++) { |
|
123 dst[x * 4 + y] = SkScalarToFloat(src[y * 4 + x]); |
|
124 } |
|
125 } |
|
126 } |
|
127 |
|
128 GrBicubicEffect::GrBicubicEffect(GrTexture* texture, |
|
129 const SkScalar coefficients[16], |
|
130 const SkMatrix &matrix, |
|
131 const SkShader::TileMode tileModes[2]) |
|
132 : INHERITED(texture, matrix, GrTextureParams(tileModes, GrTextureParams::kNone_FilterMode)) |
|
133 , fDomain(GrTextureDomain::IgnoredDomain()) { |
|
134 convert_row_major_scalar_coeffs_to_column_major_floats(fCoefficients, coefficients); |
|
135 } |
|
136 |
|
137 GrBicubicEffect::GrBicubicEffect(GrTexture* texture, |
|
138 const SkScalar coefficients[16], |
|
139 const SkMatrix &matrix, |
|
140 const SkRect& domain) |
|
141 : INHERITED(texture, matrix, GrTextureParams(SkShader::kClamp_TileMode, |
|
142 GrTextureParams::kNone_FilterMode)) |
|
143 , fDomain(domain, GrTextureDomain::kClamp_Mode) { |
|
144 convert_row_major_scalar_coeffs_to_column_major_floats(fCoefficients, coefficients); |
|
145 } |
|
146 |
|
147 GrBicubicEffect::~GrBicubicEffect() { |
|
148 } |
|
149 |
|
150 const GrBackendEffectFactory& GrBicubicEffect::getFactory() const { |
|
151 return GrTBackendEffectFactory<GrBicubicEffect>::getInstance(); |
|
152 } |
|
153 |
|
154 bool GrBicubicEffect::onIsEqual(const GrEffect& sBase) const { |
|
155 const GrBicubicEffect& s = CastEffect<GrBicubicEffect>(sBase); |
|
156 return this->textureAccess(0) == s.textureAccess(0) && |
|
157 !memcmp(fCoefficients, s.coefficients(), 16); |
|
158 } |
|
159 |
|
160 void GrBicubicEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { |
|
161 // FIXME: Perhaps we can do better. |
|
162 *validFlags = 0; |
|
163 return; |
|
164 } |
|
165 |
|
166 GR_DEFINE_EFFECT_TEST(GrBicubicEffect); |
|
167 |
|
168 GrEffectRef* GrBicubicEffect::TestCreate(SkRandom* random, |
|
169 GrContext* context, |
|
170 const GrDrawTargetCaps&, |
|
171 GrTexture* textures[]) { |
|
172 int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : |
|
173 GrEffectUnitTest::kAlphaTextureIdx; |
|
174 SkScalar coefficients[16]; |
|
175 for (int i = 0; i < 16; i++) { |
|
176 coefficients[i] = random->nextSScalar1(); |
|
177 } |
|
178 return GrBicubicEffect::Create(textures[texIdx], coefficients); |
|
179 } |