Home | History | Annotate | Download | only in effects
      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     virtual void emitCode(GrGLShaderBuilder*,
     18                           const GrDrawEffect&,
     19                           EffectKey,
     20                           const char* outputColor,
     21                           const char* inputColor,
     22                           const TransformedCoordsArray&,
     23                           const TextureSamplerArray&) SK_OVERRIDE;
     24 
     25     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
     26 
     27 private:
     28     typedef GrGLUniformManager::UniformHandle        UniformHandle;
     29 
     30     UniformHandle       fCoefficientsUni;
     31     UniformHandle       fImageIncrementUni;
     32 
     33     typedef GrGLEffect INHERITED;
     34 };
     35 
     36 GrGLBicubicEffect::GrGLBicubicEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
     37     : INHERITED(factory) {
     38 }
     39 
     40 void GrGLBicubicEffect::emitCode(GrGLShaderBuilder* builder,
     41                                  const GrDrawEffect&,
     42                                  EffectKey key,
     43                                  const char* outputColor,
     44                                  const char* inputColor,
     45                                  const TransformedCoordsArray& coords,
     46                                  const TextureSamplerArray& samplers) {
     47     sk_ignore_unused_variable(inputColor);
     48 
     49     SkString coords2D = builder->ensureFSCoords2D(coords, 0);
     50     fCoefficientsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
     51                                            kMat44f_GrSLType, "Coefficients");
     52     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
     53                                              kVec2f_GrSLType, "ImageIncrement");
     54 
     55     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
     56     const char* coeff = builder->getUniformCStr(fCoefficientsUni);
     57 
     58     SkString cubicBlendName;
     59 
     60     static const GrGLShaderVar gCubicBlendArgs[] = {
     61         GrGLShaderVar("coefficients",  kMat44f_GrSLType),
     62         GrGLShaderVar("t",             kFloat_GrSLType),
     63         GrGLShaderVar("c0",            kVec4f_GrSLType),
     64         GrGLShaderVar("c1",            kVec4f_GrSLType),
     65         GrGLShaderVar("c2",            kVec4f_GrSLType),
     66         GrGLShaderVar("c3",            kVec4f_GrSLType),
     67     };
     68     builder->fsEmitFunction(kVec4f_GrSLType,
     69                             "cubicBlend",
     70                             SK_ARRAY_COUNT(gCubicBlendArgs),
     71                             gCubicBlendArgs,
     72                             "\tvec4 ts = vec4(1.0, t, t * t, t * t * t);\n"
     73                             "\tvec4 c = coefficients * ts;\n"
     74                             "\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n",
     75                             &cubicBlendName);
     76     builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5);\n", coords2D.c_str(), imgInc);
     77     // We unnormalize the coord in order to determine our fractional offset (f) within the texel
     78     // We then snap coord to a texel center and renormalize. The snap prevents cases where the
     79     // starting coords are near a texel boundary and accumulations of imgInc would cause us to skip/
     80     // double hit a texel.
     81     builder->fsCodeAppendf("\tcoord /= %s;\n", imgInc);
     82     builder->fsCodeAppend("\tvec2 f = fract(coord);\n");
     83     builder->fsCodeAppendf("\tcoord = (coord - f + vec2(0.5)) * %s;\n", imgInc);
     84     for (int y = 0; y < 4; ++y) {
     85         for (int x = 0; x < 4; ++x) {
     86             SkString coord;
     87             coord.printf("coord + %s * vec2(%d, %d)", imgInc, x - 1, y - 1);
     88             builder->fsCodeAppendf("\tvec4 s%d%d = ", x, y);
     89             builder->fsAppendTextureLookup(samplers[0], coord.c_str());
     90             builder->fsCodeAppend(";\n");
     91         }
     92         builder->fsCodeAppendf("\tvec4 s%d = %s(%s, f.x, s0%d, s1%d, s2%d, s3%d);\n", y, cubicBlendName.c_str(), coeff, y, y, y, y);
     93     }
     94     builder->fsCodeAppendf("\t%s = %s(%s, f.y, s0, s1, s2, s3);\n", outputColor, cubicBlendName.c_str(), coeff);
     95 }
     96 
     97 void GrGLBicubicEffect::setData(const GrGLUniformManager& uman,
     98                                 const GrDrawEffect& drawEffect) {
     99     const GrBicubicEffect& effect = drawEffect.castEffect<GrBicubicEffect>();
    100     GrTexture& texture = *effect.texture(0);
    101     float imageIncrement[2];
    102     imageIncrement[0] = 1.0f / texture.width();
    103     imageIncrement[1] = 1.0f / texture.height();
    104     uman.set2fv(fImageIncrementUni, 1, imageIncrement);
    105     uman.setMatrix4f(fCoefficientsUni, effect.coefficients());
    106 }
    107 
    108 GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
    109                                  const SkScalar coefficients[16],
    110                                  const SkMatrix &matrix,
    111                                  const SkShader::TileMode tileModes[2])
    112   : INHERITED(texture, matrix, GrTextureParams(tileModes, GrTextureParams::kNone_FilterMode)) {
    113     for (int y = 0; y < 4; y++) {
    114         for (int x = 0; x < 4; x++) {
    115             // Convert from row-major scalars to column-major floats.
    116             fCoefficients[x * 4 + y] = SkScalarToFloat(coefficients[y * 4 + x]);
    117         }
    118     }
    119     this->setWillNotUseInputColor();
    120 }
    121 
    122 GrBicubicEffect::~GrBicubicEffect() {
    123 }
    124 
    125 const GrBackendEffectFactory& GrBicubicEffect::getFactory() const {
    126     return GrTBackendEffectFactory<GrBicubicEffect>::getInstance();
    127 }
    128 
    129 bool GrBicubicEffect::onIsEqual(const GrEffect& sBase) const {
    130     const GrBicubicEffect& s = CastEffect<GrBicubicEffect>(sBase);
    131     return this->textureAccess(0) == s.textureAccess(0) &&
    132            !memcmp(fCoefficients, s.coefficients(), 16);
    133 }
    134 
    135 void GrBicubicEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
    136     // FIXME:  Perhaps we can do better.
    137     *validFlags = 0;
    138     return;
    139 }
    140 
    141 GR_DEFINE_EFFECT_TEST(GrBicubicEffect);
    142 
    143 GrEffectRef* GrBicubicEffect::TestCreate(SkRandom* random,
    144                                          GrContext* context,
    145                                          const GrDrawTargetCaps&,
    146                                          GrTexture* textures[]) {
    147     int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
    148                                       GrEffectUnitTest::kAlphaTextureIdx;
    149     SkScalar coefficients[16];
    150     for (int i = 0; i < 16; i++) {
    151         coefficients[i] = random->nextSScalar1();
    152     }
    153     return GrBicubicEffect::Create(textures[texIdx], coefficients);
    154 }
    155