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