1 /*
2  * Copyright 2018 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 "GrYUVtoRGBEffect.h"
9 
10 static const float kJPEGConversionMatrix[16] = {
11     1.0f,  0.0f,       1.402f,    -0.703749f,
12     1.0f, -0.344136f, -0.714136f,  0.531211f,
13     1.0f,  1.772f,     0.0f,      -0.889475f,
14     0.0f,  0.0f,       0.0f,       1.0
15 };
16 
17 static const float kRec601ConversionMatrix[16] = {
18     1.164f,  0.0f,    1.596f, -0.87075f,
19     1.164f, -0.391f, -0.813f,  0.52925f,
20     1.164f,  2.018f,  0.0f,   -1.08175f,
21     0.0f,    0.0f,    0.0f,    1.0
22 };
23 
24 static const float kRec709ConversionMatrix[16] = {
25     1.164f,  0.0f,    1.793f, -0.96925f,
26     1.164f, -0.213f, -0.533f,  0.30025f,
27     1.164f,  2.112f,  0.0f,   -1.12875f,
28     0.0f,    0.0f,    0.0f,    1.0f
29 };
30 
31 static const float kIdentityConversionMatrix[16] = {
32     1.0f, 0.0f, 0.0f, 0.0f,
33     0.0f, 1.0f, 0.0f, 0.0f,
34     0.0f, 0.0f, 1.0f, 0.0f,
35     0.0f, 0.0f, 0.0f, 1.0f
36 };
37 
Make(const sk_sp<GrTextureProxy> proxies[],const SkYUVAIndex yuvaIndices[4],SkYUVColorSpace yuvColorSpace,GrSamplerState::Filter filterMode)38 std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const sk_sp<GrTextureProxy> proxies[],
39                                                             const SkYUVAIndex yuvaIndices[4],
40                                                             SkYUVColorSpace yuvColorSpace,
41                                                             GrSamplerState::Filter filterMode) {
42     int numPlanes;
43     SkAssertResult(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes));
44 
45     const SkISize YSize = proxies[yuvaIndices[SkYUVAIndex::kY_Index].fIndex]->isize();
46 
47     GrSamplerState::Filter minimizeFilterMode = GrSamplerState::Filter::kMipMap == filterMode ?
48                                                 GrSamplerState::Filter::kMipMap :
49                                                 GrSamplerState::Filter::kBilerp;
50 
51     GrSamplerState::Filter filterModes[4];
52     SkSize scales[4];
53     for (int i = 0; i < numPlanes; ++i) {
54         SkISize size = proxies[i]->isize();
55         scales[i] = SkSize::Make(SkIntToScalar(size.width()) / SkIntToScalar(YSize.width()),
56                                  SkIntToScalar(size.height()) / SkIntToScalar(YSize.height()));
57         filterModes[i] = (size == YSize) ? filterMode : minimizeFilterMode;
58     }
59 
60     SkMatrix44 mat;
61     switch (yuvColorSpace) {
62         case kJPEG_SkYUVColorSpace:
63             mat.setColMajorf(kJPEGConversionMatrix);
64             break;
65         case kRec601_SkYUVColorSpace:
66             mat.setColMajorf(kRec601ConversionMatrix);
67             break;
68         case kRec709_SkYUVColorSpace:
69             mat.setColMajorf(kRec709ConversionMatrix);
70             break;
71         case kIdentity_SkYUVColorSpace:
72             mat.setColMajorf(kIdentityConversionMatrix);
73             break;
74     }
75     return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(
76             proxies, scales, filterModes, numPlanes, yuvaIndices, mat));
77 }
78 
79 #ifdef SK_DEBUG
dumpInfo() const80 SkString GrYUVtoRGBEffect::dumpInfo() const {
81     SkString str;
82     for (int i = 0; i < this->numTextureSamplers(); ++i) {
83         str.appendf("%d: %d %d ", i,
84                     this->textureSampler(i).proxy()->uniqueID().asUInt(),
85                     this->textureSampler(i).proxy()->underlyingUniqueID().asUInt());
86     }
87     str.appendf("\n");
88 
89     return str;
90 }
91 #endif
92 
93 #include "glsl/GrGLSLFragmentProcessor.h"
94 #include "glsl/GrGLSLFragmentShaderBuilder.h"
95 #include "glsl/GrGLSLProgramBuilder.h"
96 #include "GrTexture.h"
97 #include "SkSLCPP.h"
98 #include "SkSLUtil.h"
99 class GrGLSLYUVtoRGBEffect : public GrGLSLFragmentProcessor {
100 public:
GrGLSLYUVtoRGBEffect()101     GrGLSLYUVtoRGBEffect() {}
emitCode(EmitArgs & args)102     void emitCode(EmitArgs& args) override {
103         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
104         const GrYUVtoRGBEffect& _outer = args.fFp.cast<GrYUVtoRGBEffect>();
105         (void)_outer;
106 
107         auto colorSpaceMatrix = _outer.colorSpaceMatrix();
108         (void)colorSpaceMatrix;
109         fColorSpaceMatrixVar =
110                 args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4x4_GrSLType,
111                                                  "colorSpaceMatrix");
112 
113         int numSamplers = args.fTexSamplers.count();
114 
115         SkString coords[4];
116         for (int i = 0; i < numSamplers; ++i) {
117             coords[i] = fragBuilder->ensureCoords2D(args.fTransformedCoords[i]);
118         }
119 
120         for (int i = 0; i < numSamplers; ++i) {
121             fragBuilder->codeAppendf(
122                 "half4 tmp%d = texture(%s, %s).%s;",
123                     i,
124                     fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[i]).c_str(),
125                     coords[i].c_str(),
126                     fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[i]).c_str());
127         }
128 
129         static const char kChannelToChar[4] = { 'x', 'y', 'z', 'w' };
130 
131         fragBuilder->codeAppendf(
132             "half4 yuvOne = half4(half(tmp%d.%c), half(tmp%d.%c), half(tmp%d.%c), 1.0) * %s;",
133                 _outer.yuvaIndex(0).fIndex, kChannelToChar[(int)_outer.yuvaIndex(0).fChannel],
134                 _outer.yuvaIndex(1).fIndex, kChannelToChar[(int)_outer.yuvaIndex(1).fChannel],
135                 _outer.yuvaIndex(2).fIndex, kChannelToChar[(int)_outer.yuvaIndex(2).fChannel],
136                 args.fUniformHandler->getUniformCStr(fColorSpaceMatrixVar));
137 
138 
139         if (_outer.yuvaIndex(3).fIndex >= 0) {
140             fragBuilder->codeAppendf(
141                 "half a = tmp%d.%c;", _outer.yuvaIndex(3).fIndex,
142                                        kChannelToChar[(int)_outer.yuvaIndex(3).fChannel]);
143             // premultiply alpha
144             fragBuilder->codeAppend("yuvOne *= a;");
145         } else {
146             fragBuilder->codeAppendf("half a = 1.0;");
147         }
148 
149         fragBuilder->codeAppendf("%s = half4(yuvOne.xyz, a);", args.fOutputColor);
150     }
151 
152 private:
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & _proc)153     void onSetData(const GrGLSLProgramDataManager& pdman,
154                    const GrFragmentProcessor& _proc) override {
155         const GrYUVtoRGBEffect& _outer = _proc.cast<GrYUVtoRGBEffect>();
156         { pdman.setSkMatrix44(fColorSpaceMatrixVar, (_outer.colorSpaceMatrix())); }
157     }
158     UniformHandle fColorSpaceMatrixVar;
159 };
onCreateGLSLInstance() const160 GrGLSLFragmentProcessor* GrYUVtoRGBEffect::onCreateGLSLInstance() const {
161     return new GrGLSLYUVtoRGBEffect();
162 }
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const163 void GrYUVtoRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
164                                              GrProcessorKeyBuilder* b) const {
165     b->add32(this->numTextureSamplers());
166 
167     uint32_t packed = 0;
168     for (int i = 0; i < 4; ++i) {
169         if (this->yuvaIndex(i).fIndex < 0) {
170             continue;
171         }
172 
173         uint8_t index = this->yuvaIndex(i).fIndex;
174         uint8_t chann = (uint8_t) this->yuvaIndex(i).fChannel;
175 
176         SkASSERT(index < 4 && chann < 4);
177 
178         packed |= (index | (chann << 2)) << (i * 4);
179     }
180     b->add32(packed);
181 }
onIsEqual(const GrFragmentProcessor & other) const182 bool GrYUVtoRGBEffect::onIsEqual(const GrFragmentProcessor& other) const {
183     const GrYUVtoRGBEffect& that = other.cast<GrYUVtoRGBEffect>();
184 
185     for (int i = 0; i < 4; ++i) {
186         if (fYUVAIndices[i] != that.fYUVAIndices[i]) {
187             return false;
188         }
189     }
190 
191     for (int i = 0; i < this->numTextureSamplers(); ++i) {
192         // 'fSamplers' is checked by the base class
193         if (fSamplerTransforms[i] != that.fSamplerTransforms[i]) {
194             return false;
195         }
196     }
197 
198     if (fColorSpaceMatrix != that.fColorSpaceMatrix) {
199         return false;
200     }
201 
202     return true;
203 }
GrYUVtoRGBEffect(const GrYUVtoRGBEffect & src)204 GrYUVtoRGBEffect::GrYUVtoRGBEffect(const GrYUVtoRGBEffect& src)
205         : INHERITED(kGrYUVtoRGBEffect_ClassID, src.optimizationFlags())
206         , fColorSpaceMatrix(src.fColorSpaceMatrix) {
207     int numPlanes = src.numTextureSamplers();
208     for (int i = 0; i < numPlanes; ++i) {
209         fSamplers[i].reset(sk_ref_sp(src.fSamplers[i].proxy()), src.fSamplers[i].samplerState());
210         fSamplerTransforms[i] = src.fSamplerTransforms[i];
211         fSamplerCoordTransforms[i] = src.fSamplerCoordTransforms[i];
212     }
213 
214     this->setTextureSamplerCnt(numPlanes);
215     for (int i = 0; i < numPlanes; ++i) {
216         this->addCoordTransform(&fSamplerCoordTransforms[i]);
217     }
218 
219     memcpy(fYUVAIndices, src.fYUVAIndices, sizeof(fYUVAIndices));
220 }
clone() const221 std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::clone() const {
222     return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(*this));
223 }
onTextureSampler(int index) const224 const GrFragmentProcessor::TextureSampler& GrYUVtoRGBEffect::onTextureSampler(int index) const {
225     SkASSERT(index < this->numTextureSamplers());
226     return fSamplers[index];
227 }
228