YUV to RGB converter

This is a first piece of the GPU YUV decoder, which is the actual effect that performs the conversion. For now, it simply applies the conversion matrix, since it is all I need. I may add modes if different matrices need to be applied or if I add color profile support here.

I'll try to keep these cls short and easy to review, but there should be a few of them coming once this one is in.

BUG=skia:
R=senorblanco@chromium.org, senorblanco@google.com, reed@google.com, bsalomon@google.com

Author: sugoi@chromium.org

Review URL: https://codereview.chromium.org/378503006
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
new file mode 100644
index 0000000..1e3810f
--- /dev/null
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrYUVtoRGBEffect.h"
+
+#include "GrCoordTransform.h"
+#include "GrEffect.h"
+#include "gl/GrGLEffect.h"
+#include "GrTBackendEffectFactory.h"
+
+namespace {
+
+class YUVtoRGBEffect : public GrEffect {
+public:
+    static GrEffectRef* Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture) {
+        AutoEffectUnref effect(SkNEW_ARGS(YUVtoRGBEffect, (yTexture, uTexture, vTexture)));
+        return CreateEffectRef(effect);
+    }
+
+    static const char* Name() { return "YUV to RGB"; }
+
+    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
+        return GrTBackendEffectFactory<YUVtoRGBEffect>::getInstance();
+    }
+
+    virtual void getConstantColorComponents(GrColor* color,
+                                            uint32_t* validFlags) const SK_OVERRIDE {
+        // YUV is opaque
+        *color = 0xFF;
+        *validFlags = kA_GrColorComponentFlag;
+    }
+
+    class GLEffect : public GrGLEffect {
+    public:
+        // this class always generates the same code.
+        static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { return 0; }
+
+        GLEffect(const GrBackendEffectFactory& factory,
+                 const GrDrawEffect&)
+        : INHERITED(factory) {
+        }
+
+        virtual void emitCode(GrGLShaderBuilder* builder,
+                              const GrDrawEffect&,
+                              EffectKey,
+                              const char* outputColor,
+                              const char* inputColor,
+                              const TransformedCoordsArray& coords,
+                              const TextureSamplerArray& samplers) SK_OVERRIDE {
+            const char* yuvMatrix   = "yuvMatrix";
+            builder->fsCodeAppendf("\tconst mat4 %s = mat4(1.0,  0.0,    1.402, -0.701,\n\t\t\t"
+                                                          "1.0, -0.344, -0.714,  0.529,\n\t\t\t"
+                                                          "1.0,  1.772,  0.0,   -0.886,\n\t\t\t"
+                                                          "0.0,  0.0,    0.0,    1.0);\n",
+                                   yuvMatrix);
+            builder->fsCodeAppendf("\t%s = vec4(\n\t\t", outputColor);
+            builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
+            builder->fsCodeAppend(".r,\n\t\t");
+            builder->fsAppendTextureLookup(samplers[1], coords[0].c_str(), coords[0].type());
+            builder->fsCodeAppend(".r,\n\t\t");
+            builder->fsAppendTextureLookup(samplers[2], coords[0].c_str(), coords[0].type());
+            builder->fsCodeAppendf(".r,\n\t\t1.0) * %s;\n", yuvMatrix);
+        }
+
+        typedef GrGLEffect INHERITED;
+    };
+
+private:
+    YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture)
+    : fCoordTransform(kLocal_GrCoordSet, MakeDivByTextureWHMatrix(yTexture), yTexture)
+    , fYAccess(yTexture)
+    , fUAccess(uTexture)
+    , fVAccess(vTexture) {
+        this->addCoordTransform(&fCoordTransform);
+        this->addTextureAccess(&fYAccess);
+        this->addTextureAccess(&fUAccess);
+        this->addTextureAccess(&fVAccess);
+        this->setWillNotUseInputColor();
+    }
+
+    virtual bool onIsEqual(const GrEffect& sBase) const {
+        const YUVtoRGBEffect& s = CastEffect<YUVtoRGBEffect>(sBase);
+        return fYAccess.getTexture() == s.fYAccess.getTexture() &&
+               fUAccess.getTexture() == s.fUAccess.getTexture() &&
+               fVAccess.getTexture() == s.fVAccess.getTexture();
+    }
+
+    GrCoordTransform fCoordTransform;
+    GrTextureAccess fYAccess;
+    GrTextureAccess fUAccess;
+    GrTextureAccess fVAccess;
+
+    typedef GrEffect INHERITED;
+};
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GrEffectRef* GrYUVtoRGBEffect::Create(GrTexture* yTexture,
+                                      GrTexture* uTexture,
+                                      GrTexture* vTexture) {
+    return YUVtoRGBEffect::Create(yTexture, uTexture, vTexture);
+}