• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrYUVEffect.h"
9 
10 #include "GrCoordTransform.h"
11 #include "GrFragmentProcessor.h"
12 #include "GrProcessor.h"
13 #include "GrTextureProxy.h"
14 #include "glsl/GrGLSLFragmentProcessor.h"
15 #include "glsl/GrGLSLFragmentShaderBuilder.h"
16 #include "glsl/GrGLSLProgramDataManager.h"
17 #include "glsl/GrGLSLUniformHandler.h"
18 
19 namespace {
20 
21 static const float kJPEGConversionMatrix[16] = {
22     1.0f,  0.0f,      1.402f,  -0.701f,
23     1.0f, -0.34414f, -0.71414f, 0.529f,
24     1.0f,  1.772f,    0.0f,    -0.886f,
25     0.0f,  0.0f,      0.0f,     1.0
26 };
27 
28 static const float kRec601ConversionMatrix[16] = {
29     1.164f,  0.0f,    1.596f, -0.87075f,
30     1.164f, -0.391f, -0.813f,  0.52925f,
31     1.164f,  2.018f,  0.0f,   -1.08175f,
32     0.0f,    0.0f,    0.0f,    1.0}
33 ;
34 
35 static const float kRec709ConversionMatrix[16] = {
36     1.164f,  0.0f,    1.793f, -0.96925f,
37     1.164f, -0.213f, -0.533f,  0.30025f,
38     1.164f,  2.112f,  0.0f,   -1.12875f,
39     0.0f,    0.0f,    0.0f,    1.0f}
40 ;
41 
42 static const float kJPEGInverseConversionMatrix[16] = {
43      0.299001f,  0.586998f,  0.114001f,  0.0000821798f,
44     -0.168736f, -0.331263f,  0.499999f,  0.499954f,
45      0.499999f, -0.418686f, -0.0813131f, 0.499941f,
46      0.f,        0.f,        0.f,        1.f
47 };
48 
49 static const float kRec601InverseConversionMatrix[16] = {
50      0.256951f,  0.504421f,  0.0977346f, 0.0625f,
51     -0.148212f, -0.290954f,  0.439166f,  0.5f,
52      0.439166f, -0.367886f, -0.0712802f, 0.5f,
53      0.f,        0.f,        0.f,        1.f
54 };
55 
56 static const float kRec709InverseConversionMatrix[16] = {
57      0.182663f,  0.614473f, 0.061971f, 0.0625f,
58     -0.100672f, -0.338658f, 0.43933f,  0.5f,
59      0.439142f, -0.39891f, -0.040231f, 0.5f,
60      0.f,        0.f,       0.f,       1.
61 };
62 
63 class YUVtoRGBEffect : public GrFragmentProcessor {
64 public:
Make(GrResourceProvider * resourceProvider,sk_sp<GrTextureProxy> yProxy,sk_sp<GrTextureProxy> uProxy,sk_sp<GrTextureProxy> vProxy,const SkISize sizes[3],SkYUVColorSpace colorSpace,bool nv12)65     static sk_sp<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
66                                            sk_sp<GrTextureProxy> yProxy,
67                                            sk_sp<GrTextureProxy> uProxy,
68                                            sk_sp<GrTextureProxy> vProxy, const SkISize sizes[3],
69                                            SkYUVColorSpace colorSpace, bool nv12) {
70         SkScalar w[3], h[3];
71         w[0] = SkIntToScalar(sizes[0].fWidth);
72         h[0] = SkIntToScalar(sizes[0].fHeight);
73         w[1] = SkIntToScalar(sizes[1].fWidth);
74         h[1] = SkIntToScalar(sizes[1].fHeight);
75         w[2] = SkIntToScalar(sizes[2].fWidth);
76         h[2] = SkIntToScalar(sizes[2].fHeight);
77         const SkMatrix yuvMatrix[3] = {
78             SkMatrix::I(),
79             SkMatrix::MakeScale(w[1] / w[0], h[1] / h[0]),
80             SkMatrix::MakeScale(w[2] / w[0], h[2] / h[0])
81         };
82         GrSamplerParams::FilterMode uvFilterMode =
83             ((sizes[1].fWidth  != sizes[0].fWidth) ||
84              (sizes[1].fHeight != sizes[0].fHeight) ||
85              (sizes[2].fWidth  != sizes[0].fWidth) ||
86              (sizes[2].fHeight != sizes[0].fHeight)) ?
87             GrSamplerParams::kBilerp_FilterMode :
88             GrSamplerParams::kNone_FilterMode;
89         return sk_sp<GrFragmentProcessor>(new YUVtoRGBEffect(
90             resourceProvider, std::move(yProxy), std::move(uProxy), std::move(vProxy),
91             yuvMatrix, uvFilterMode, colorSpace, nv12));
92     }
93 
name() const94     const char* name() const override { return "YUV to RGB"; }
95 
getColorSpace() const96     SkYUVColorSpace getColorSpace() const { return fColorSpace; }
97 
isNV12() const98     bool isNV12() const {
99         return fNV12;
100     }
101 
102     class GLSLProcessor : public GrGLSLFragmentProcessor {
103     public:
emitCode(EmitArgs & args)104         void emitCode(EmitArgs& args) override {
105             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
106             const YUVtoRGBEffect& effect = args.fFp.cast<YUVtoRGBEffect>();
107 
108             const char* colorSpaceMatrix = nullptr;
109             fMatrixUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
110                                                           kMat44f_GrSLType, kDefault_GrSLPrecision,
111                                                           "ColorSpaceMatrix", &colorSpaceMatrix);
112             fragBuilder->codeAppendf("%s = vec4(", args.fOutputColor);
113             fragBuilder->appendTextureLookup(args.fTexSamplers[0],
114                                              args.fTransformedCoords[0].c_str(),
115                                              args.fTransformedCoords[0].getType());
116             fragBuilder->codeAppend(".r,");
117             fragBuilder->appendTextureLookup(args.fTexSamplers[1],
118                                              args.fTransformedCoords[1].c_str(),
119                                              args.fTransformedCoords[1].getType());
120             if (effect.fNV12) {
121                 fragBuilder->codeAppendf(".rg,");
122             } else {
123                 fragBuilder->codeAppend(".r,");
124                 fragBuilder->appendTextureLookup(args.fTexSamplers[2],
125                                                  args.fTransformedCoords[2].c_str(),
126                                                  args.fTransformedCoords[2].getType());
127                 fragBuilder->codeAppendf(".g,");
128             }
129             fragBuilder->codeAppendf("1.0) * %s;", colorSpaceMatrix);
130         }
131 
132     protected:
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & processor)133         void onSetData(const GrGLSLProgramDataManager& pdman,
134                        const GrProcessor& processor) override {
135             const YUVtoRGBEffect& yuvEffect = processor.cast<YUVtoRGBEffect>();
136             switch (yuvEffect.getColorSpace()) {
137                 case kJPEG_SkYUVColorSpace:
138                     pdman.setMatrix4f(fMatrixUni, kJPEGConversionMatrix);
139                     break;
140                 case kRec601_SkYUVColorSpace:
141                     pdman.setMatrix4f(fMatrixUni, kRec601ConversionMatrix);
142                     break;
143                 case kRec709_SkYUVColorSpace:
144                     pdman.setMatrix4f(fMatrixUni, kRec709ConversionMatrix);
145                     break;
146             }
147         }
148 
149     private:
150         GrGLSLProgramDataManager::UniformHandle fMatrixUni;
151 
152         typedef GrGLSLFragmentProcessor INHERITED;
153     };
154 
155 private:
YUVtoRGBEffect(GrResourceProvider * resourceProvider,sk_sp<GrTextureProxy> yProxy,sk_sp<GrTextureProxy> uProxy,sk_sp<GrTextureProxy> vProxy,const SkMatrix yuvMatrix[3],GrSamplerParams::FilterMode uvFilterMode,SkYUVColorSpace colorSpace,bool nv12)156     YUVtoRGBEffect(GrResourceProvider* resourceProvider,
157                    sk_sp<GrTextureProxy> yProxy, sk_sp<GrTextureProxy> uProxy,
158                    sk_sp<GrTextureProxy> vProxy, const SkMatrix yuvMatrix[3],
159                    GrSamplerParams::FilterMode uvFilterMode, SkYUVColorSpace colorSpace, bool nv12)
160             : INHERITED(kPreservesOpaqueInput_OptimizationFlag)
161             , fYTransform(resourceProvider, yuvMatrix[0], yProxy.get(),
162                           GrSamplerParams::kNone_FilterMode)
163             , fYSampler(resourceProvider, std::move(yProxy))
164             , fUTransform(resourceProvider, yuvMatrix[1], uProxy.get(), uvFilterMode)
165             , fUSampler(resourceProvider, std::move(uProxy), uvFilterMode)
166             , fVSampler(resourceProvider, vProxy, uvFilterMode)
167             , fColorSpace(colorSpace)
168             , fNV12(nv12) {
169         this->initClassID<YUVtoRGBEffect>();
170         this->addCoordTransform(&fYTransform);
171         this->addTextureSampler(&fYSampler);
172         this->addCoordTransform(&fUTransform);
173         this->addTextureSampler(&fUSampler);
174         if (!fNV12) {
175             fVTransform = GrCoordTransform(resourceProvider, yuvMatrix[2], vProxy.get(),
176                                            uvFilterMode);
177             this->addCoordTransform(&fVTransform);
178             this->addTextureSampler(&fVSampler);
179         }
180     }
181 
onCreateGLSLInstance() const182     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
183         return new GLSLProcessor;
184     }
185 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const186     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
187         b->add32(fNV12);
188     }
189 
onIsEqual(const GrFragmentProcessor & sBase) const190     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
191         const YUVtoRGBEffect& s = sBase.cast<YUVtoRGBEffect>();
192         return (fColorSpace == s.getColorSpace()) && (fNV12 == s.isNV12());
193     }
194 
195     GrCoordTransform fYTransform;
196     TextureSampler   fYSampler;
197     GrCoordTransform fUTransform;
198     TextureSampler   fUSampler;
199     GrCoordTransform fVTransform;
200     TextureSampler   fVSampler;
201     SkYUVColorSpace fColorSpace;
202     bool fNV12;
203 
204     typedef GrFragmentProcessor INHERITED;
205 };
206 
207 
208 class RGBToYUVEffect : public GrFragmentProcessor {
209 public:
210     enum OutputChannels {
211         // output color r = y, g = u, b = v, a = a
212         kYUV_OutputChannels,
213         // output color rgba = y
214         kY_OutputChannels,
215         // output color r = u, g = v, b = 0, a = a
216         kUV_OutputChannels,
217         // output color rgba = u
218         kU_OutputChannels,
219         // output color rgba = v
220         kV_OutputChannels
221     };
222 
RGBToYUVEffect(sk_sp<GrFragmentProcessor> rgbFP,SkYUVColorSpace colorSpace,OutputChannels output)223     RGBToYUVEffect(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace,
224                    OutputChannels output)
225             // This could advertise kConstantOutputForConstantInput, but doesn't seem useful.
226             : INHERITED(kPreservesOpaqueInput_OptimizationFlag)
227             , fColorSpace(colorSpace)
228             , fOutputChannels(output) {
229         this->initClassID<RGBToYUVEffect>();
230         this->registerChildProcessor(std::move(rgbFP));
231     }
232 
name() const233     const char* name() const override { return "RGBToYUV"; }
234 
getColorSpace() const235     SkYUVColorSpace getColorSpace() const { return fColorSpace; }
236 
outputChannels() const237     OutputChannels outputChannels() const { return fOutputChannels; }
238 
239     class GLSLProcessor : public GrGLSLFragmentProcessor {
240     public:
GLSLProcessor()241         GLSLProcessor() : fLastColorSpace(-1), fLastOutputChannels(-1) {}
242 
emitCode(EmitArgs & args)243         void emitCode(EmitArgs& args) override {
244             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
245             OutputChannels oc = args.fFp.cast<RGBToYUVEffect>().outputChannels();
246 
247             SkString outputColor("rgbColor");
248             this->emitChild(0, args.fInputColor, &outputColor, args);
249 
250             const char* uniName;
251             switch (oc) {
252                 case kYUV_OutputChannels:
253                     fRGBToYUVUni = args.fUniformHandler->addUniformArray(
254                         kFragment_GrShaderFlag,
255                         kVec4f_GrSLType, kDefault_GrSLPrecision,
256                         "RGBToYUV", 3, &uniName);
257                     fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s[0].rgb) + %s[0].a,"
258                                                        "dot(rgbColor.rgb, %s[1].rgb) + %s[1].a,"
259                                                        "dot(rgbColor.rgb, %s[2].rgb) + %s[2].a,"
260                                                        "rgbColor.a);",
261                                              args.fOutputColor, uniName, uniName, uniName, uniName,
262                                              uniName, uniName);
263                     break;
264                 case kUV_OutputChannels:
265                     fRGBToYUVUni = args.fUniformHandler->addUniformArray(
266                         kFragment_GrShaderFlag,
267                         kVec4f_GrSLType, kDefault_GrSLPrecision,
268                         "RGBToUV", 2, &uniName);
269                     fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s[0].rgb) + %s[0].a,"
270                                                        "dot(rgbColor.rgb, %s[1].rgb) + %s[1].a,"
271                                                        "0.0,"
272                                                        "rgbColor.a);",
273                                              args.fOutputColor, uniName, uniName, uniName, uniName);
274                     break;
275                 case kY_OutputChannels:
276                 case kU_OutputChannels:
277                 case kV_OutputChannels:
278                     fRGBToYUVUni = args.fUniformHandler->addUniform(
279                         kFragment_GrShaderFlag,
280                         kVec4f_GrSLType, kDefault_GrSLPrecision,
281                         "RGBToYUorV", &uniName);
282                     fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s.rgb) + %s.a);\n",
283                                              args.fOutputColor, uniName, uniName);
284                     break;
285             }
286         }
287 
288     private:
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & processor)289         void onSetData(const GrGLSLProgramDataManager& pdman,
290                        const GrProcessor& processor) override {
291             const RGBToYUVEffect& effect = processor.cast<RGBToYUVEffect>();
292             OutputChannels oc = effect.outputChannels();
293             if (effect.getColorSpace() != fLastColorSpace || oc != fLastOutputChannels) {
294 
295                 const float* matrix = nullptr;
296                 switch (effect.getColorSpace()) {
297                     case kJPEG_SkYUVColorSpace:
298                         matrix = kJPEGInverseConversionMatrix;
299                         break;
300                     case kRec601_SkYUVColorSpace:
301                         matrix = kRec601InverseConversionMatrix;
302                         break;
303                     case kRec709_SkYUVColorSpace:
304                         matrix = kRec709InverseConversionMatrix;
305                         break;
306                 }
307                 switch (oc) {
308                     case kYUV_OutputChannels:
309                         pdman.set4fv(fRGBToYUVUni, 3, matrix);
310                         break;
311                     case kUV_OutputChannels:
312                         pdman.set4fv(fRGBToYUVUni, 2, matrix + 4);
313                         break;
314                     case kY_OutputChannels:
315                         pdman.set4fv(fRGBToYUVUni, 1, matrix);
316                         break;
317                     case kU_OutputChannels:
318                         pdman.set4fv(fRGBToYUVUni, 1, matrix + 4);
319                         break;
320                     case kV_OutputChannels:
321                         pdman.set4fv(fRGBToYUVUni, 1, matrix + 8);
322                         break;
323                 }
324                 fLastColorSpace = effect.getColorSpace();
325             }
326         }
327         GrGLSLProgramDataManager::UniformHandle fRGBToYUVUni;
328         int                                     fLastColorSpace;
329         int                                     fLastOutputChannels;
330 
331         typedef GrGLSLFragmentProcessor INHERITED;
332     };
333 
334 private:
onCreateGLSLInstance() const335     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
336         return new GLSLProcessor;
337     }
338 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const339     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
340         // kY, kU, and kV all generate the same code, just upload different coefficients.
341         if (kU_OutputChannels == fOutputChannels || kV_OutputChannels == fOutputChannels) {
342             b->add32(kY_OutputChannels);
343         } else {
344             b->add32(fOutputChannels);
345         }
346     }
347 
onIsEqual(const GrFragmentProcessor & sBase) const348     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
349         const RGBToYUVEffect& s = sBase.cast<RGBToYUVEffect>();
350         return fColorSpace == s.getColorSpace() && fOutputChannels == s.outputChannels();
351     }
352 
353     GrCoordTransform    fTransform;
354     TextureSampler      fTextureSampler;
355     SkYUVColorSpace     fColorSpace;
356     OutputChannels      fOutputChannels;
357 
358     typedef GrFragmentProcessor INHERITED;
359 };
360 
361 }
362 
363 //////////////////////////////////////////////////////////////////////////////
364 
MakeYUVToRGB(GrResourceProvider * resourceProvider,sk_sp<GrTextureProxy> yProxy,sk_sp<GrTextureProxy> uProxy,sk_sp<GrTextureProxy> vProxy,const SkISize sizes[3],SkYUVColorSpace colorSpace,bool nv12)365 sk_sp<GrFragmentProcessor> GrYUVEffect::MakeYUVToRGB(GrResourceProvider* resourceProvider,
366                                                      sk_sp<GrTextureProxy> yProxy,
367                                                      sk_sp<GrTextureProxy> uProxy,
368                                                      sk_sp<GrTextureProxy> vProxy,
369                                                      const SkISize sizes[3],
370                                                      SkYUVColorSpace colorSpace, bool nv12) {
371     SkASSERT(yProxy && uProxy && vProxy && sizes);
372     return YUVtoRGBEffect::Make(resourceProvider,
373                                 std::move(yProxy), std::move(uProxy), std::move(vProxy),
374                                 sizes, colorSpace, nv12);
375 }
376 
377 sk_sp<GrFragmentProcessor>
MakeRGBToYUV(sk_sp<GrFragmentProcessor> rgbFP,SkYUVColorSpace colorSpace)378 GrYUVEffect::MakeRGBToYUV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
379     SkASSERT(rgbFP);
380     return sk_sp<GrFragmentProcessor>(
381         new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kYUV_OutputChannels));
382 }
383 
384 sk_sp<GrFragmentProcessor>
MakeRGBToY(sk_sp<GrFragmentProcessor> rgbFP,SkYUVColorSpace colorSpace)385 GrYUVEffect::MakeRGBToY(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
386     SkASSERT(rgbFP);
387     return sk_sp<GrFragmentProcessor>(
388         new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kY_OutputChannels));
389 }
390 
391 sk_sp<GrFragmentProcessor>
MakeRGBToUV(sk_sp<GrFragmentProcessor> rgbFP,SkYUVColorSpace colorSpace)392 GrYUVEffect::MakeRGBToUV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
393     SkASSERT(rgbFP);
394     return sk_sp<GrFragmentProcessor>(
395         new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kUV_OutputChannels));
396 }
397 
398 sk_sp<GrFragmentProcessor>
MakeRGBToU(sk_sp<GrFragmentProcessor> rgbFP,SkYUVColorSpace colorSpace)399 GrYUVEffect::MakeRGBToU(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
400     SkASSERT(rgbFP);
401     return sk_sp<GrFragmentProcessor>(
402         new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kU_OutputChannels));
403 }
404 
405 sk_sp<GrFragmentProcessor>
MakeRGBToV(sk_sp<GrFragmentProcessor> rgbFP,SkYUVColorSpace colorSpace)406 GrYUVEffect::MakeRGBToV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
407     SkASSERT(rgbFP);
408     return sk_sp<GrFragmentProcessor>(
409         new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kV_OutputChannels));
410 }
411