1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gl/builders/GrGLProgramBuilder.h"
9#include "GrYUVtoRGBEffect.h"
10
11#include "GrCoordTransform.h"
12#include "GrProcessor.h"
13#include "gl/GrGLProcessor.h"
14#include "GrTBackendProcessorFactory.h"
15
16namespace {
17
18class YUVtoRGBEffect : public GrFragmentProcessor {
19public:
20    static GrFragmentProcessor* Create(GrTexture* yTexture, GrTexture* uTexture,
21                                       GrTexture* vTexture, SkYUVColorSpace colorSpace) {
22        return SkNEW_ARGS(YUVtoRGBEffect, (yTexture, uTexture, vTexture, colorSpace));
23    }
24
25    static const char* Name() { return "YUV to RGB"; }
26
27    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE {
28        return GrTBackendFragmentProcessorFactory<YUVtoRGBEffect>::getInstance();
29    }
30
31    virtual void getConstantColorComponents(GrColor* color,
32                                            uint32_t* validFlags) const SK_OVERRIDE {
33        // YUV is opaque
34        *color = 0xFF;
35        *validFlags = kA_GrColorComponentFlag;
36    }
37
38    SkYUVColorSpace getColorSpace() const {
39        return fColorSpace;
40    }
41
42    class GLProcessor : public GrGLFragmentProcessor {
43    public:
44        static const GrGLfloat kJPEGConversionMatrix[16];
45        static const GrGLfloat kRec601ConversionMatrix[16];
46
47        // this class always generates the same code.
48        static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
49
50        GLProcessor(const GrBackendProcessorFactory& factory,
51                    const GrProcessor&)
52        : INHERITED(factory) {
53        }
54
55        virtual void emitCode(GrGLProgramBuilder* builder,
56                              const GrFragmentProcessor&,
57                              const GrProcessorKey&,
58                              const char* outputColor,
59                              const char* inputColor,
60                              const TransformedCoordsArray& coords,
61                              const TextureSamplerArray& samplers) SK_OVERRIDE {
62            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
63
64            const char* yuvMatrix   = NULL;
65            fMatrixUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
66                                             kMat44f_GrSLType, "YUVMatrix",
67                                             &yuvMatrix);
68            fsBuilder->codeAppendf("\t%s = vec4(\n\t\t", outputColor);
69            fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType());
70            fsBuilder->codeAppend(".r,\n\t\t");
71            fsBuilder->appendTextureLookup(samplers[1], coords[0].c_str(), coords[0].getType());
72            fsBuilder->codeAppend(".r,\n\t\t");
73            fsBuilder->appendTextureLookup(samplers[2], coords[0].c_str(), coords[0].getType());
74            fsBuilder->codeAppendf(".r,\n\t\t1.0) * %s;\n", yuvMatrix);
75        }
76
77        virtual void setData(const GrGLProgramDataManager& pdman,
78                             const GrProcessor& processor) SK_OVERRIDE {
79            const YUVtoRGBEffect& yuvEffect = processor.cast<YUVtoRGBEffect>();
80            switch (yuvEffect.getColorSpace()) {
81                case kJPEG_SkYUVColorSpace:
82                    pdman.setMatrix4f(fMatrixUni, kJPEGConversionMatrix);
83                    break;
84                case kRec601_SkYUVColorSpace:
85                    pdman.setMatrix4f(fMatrixUni, kRec601ConversionMatrix);
86                    break;
87            }
88        }
89
90    private:
91        GrGLProgramDataManager::UniformHandle fMatrixUni;
92
93        typedef GrGLFragmentProcessor INHERITED;
94    };
95
96private:
97    YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture,
98                   SkYUVColorSpace colorSpace)
99     : fCoordTransform(kLocal_GrCoordSet, GrCoordTransform::MakeDivByTextureWHMatrix(yTexture),
100                       yTexture)
101    , fYAccess(yTexture)
102    , fUAccess(uTexture)
103    , fVAccess(vTexture)
104    , fColorSpace(colorSpace) {
105        this->addCoordTransform(&fCoordTransform);
106        this->addTextureAccess(&fYAccess);
107        this->addTextureAccess(&fUAccess);
108        this->addTextureAccess(&fVAccess);
109        this->setWillNotUseInputColor();
110    }
111
112    virtual bool onIsEqual(const GrProcessor& sBase) const {
113        const YUVtoRGBEffect& s = sBase.cast<YUVtoRGBEffect>();
114        return fYAccess.getTexture() == s.fYAccess.getTexture() &&
115               fUAccess.getTexture() == s.fUAccess.getTexture() &&
116               fVAccess.getTexture() == s.fVAccess.getTexture() &&
117               fColorSpace == s.getColorSpace();
118    }
119
120    GrCoordTransform fCoordTransform;
121    GrTextureAccess fYAccess;
122    GrTextureAccess fUAccess;
123    GrTextureAccess fVAccess;
124    SkYUVColorSpace fColorSpace;
125
126    typedef GrFragmentProcessor INHERITED;
127};
128
129const GrGLfloat YUVtoRGBEffect::GLProcessor::kJPEGConversionMatrix[16] = {
130    1.0f,  0.0f,      1.402f,  -0.701f,
131    1.0f, -0.34414f, -0.71414f, 0.529f,
132    1.0f,  1.772f,    0.0f,    -0.886f,
133    0.0f,  0.0f,      0.0f,     1.0};
134const GrGLfloat YUVtoRGBEffect::GLProcessor::kRec601ConversionMatrix[16] = {
135    1.164f,  0.0f,    1.596f, -0.87075f,
136    1.164f, -0.391f, -0.813f,  0.52925f,
137    1.164f,  2.018f,  0.0f,   -1.08175f,
138    0.0f,    0.0f,    0.0f,    1.0};
139}
140
141//////////////////////////////////////////////////////////////////////////////
142
143GrFragmentProcessor*
144GrYUVtoRGBEffect::Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture,
145                         SkYUVColorSpace colorSpace) {
146    return YUVtoRGBEffect::Create(yTexture, uTexture, vTexture, colorSpace);
147}
148