• 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 "GrInvariantOutput.h"
13 #include "GrProcessor.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:
Create(GrTexture * yTexture,GrTexture * uTexture,GrTexture * vTexture,const SkISize sizes[3],SkYUVColorSpace colorSpace)65     static GrFragmentProcessor* Create(GrTexture* yTexture, GrTexture* uTexture,
66                                        GrTexture* vTexture, const SkISize sizes[3],
67                                        SkYUVColorSpace colorSpace) {
68         SkScalar w[3], h[3];
69         w[0] = SkIntToScalar(sizes[0].fWidth)  / SkIntToScalar(yTexture->width());
70         h[0] = SkIntToScalar(sizes[0].fHeight) / SkIntToScalar(yTexture->height());
71         w[1] = SkIntToScalar(sizes[1].fWidth)  / SkIntToScalar(uTexture->width());
72         h[1] = SkIntToScalar(sizes[1].fHeight) / SkIntToScalar(uTexture->height());
73         w[2] = SkIntToScalar(sizes[2].fWidth)  / SkIntToScalar(vTexture->width());
74         h[2] = SkIntToScalar(sizes[2].fHeight) / SkIntToScalar(vTexture->height());
75         SkMatrix yuvMatrix[3];
76         yuvMatrix[0] = GrCoordTransform::MakeDivByTextureWHMatrix(yTexture);
77         yuvMatrix[1] = yuvMatrix[0];
78         yuvMatrix[1].preScale(w[1] / w[0], h[1] / h[0]);
79         yuvMatrix[2] = yuvMatrix[0];
80         yuvMatrix[2].preScale(w[2] / w[0], h[2] / h[0]);
81         GrTextureParams::FilterMode uvFilterMode =
82             ((sizes[1].fWidth  != sizes[0].fWidth) ||
83              (sizes[1].fHeight != sizes[0].fHeight) ||
84              (sizes[2].fWidth  != sizes[0].fWidth) ||
85              (sizes[2].fHeight != sizes[0].fHeight)) ?
86             GrTextureParams::kBilerp_FilterMode :
87             GrTextureParams::kNone_FilterMode;
88         return new YUVtoRGBEffect(yTexture, uTexture, vTexture, yuvMatrix, uvFilterMode,
89                                   colorSpace);
90     }
91 
name() const92     const char* name() const override { return "YUV to RGB"; }
93 
getColorSpace() const94     SkYUVColorSpace getColorSpace() const { return fColorSpace; }
95 
96     class GLSLProcessor : public GrGLSLFragmentProcessor {
97     public:
98         // this class always generates the same code.
GenKey(const GrProcessor &,const GrGLSLCaps &,GrProcessorKeyBuilder *)99         static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) {}
100 
emitCode(EmitArgs & args)101         void emitCode(EmitArgs& args) override {
102             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
103 
104             const char* colorSpaceMatrix = nullptr;
105             fMatrixUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
106                                                           kMat44f_GrSLType, kDefault_GrSLPrecision,
107                                                           "ColorSpaceMatrix", &colorSpaceMatrix);
108             fragBuilder->codeAppendf("%s = vec4(", args.fOutputColor);
109             fragBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0].c_str(),
110                                              args.fCoords[0].getType());
111             fragBuilder->codeAppend(".r,");
112             fragBuilder->appendTextureLookup(args.fSamplers[1], args.fCoords[1].c_str(),
113                                              args.fCoords[1].getType());
114             fragBuilder->codeAppend(".r,");
115             fragBuilder->appendTextureLookup(args.fSamplers[2], args.fCoords[2].c_str(),
116                                              args.fCoords[2].getType());
117             fragBuilder->codeAppendf(".r, 1.0) * %s;", colorSpaceMatrix);
118         }
119 
120     protected:
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & processor)121         void onSetData(const GrGLSLProgramDataManager& pdman,
122                        const GrProcessor& processor) override {
123             const YUVtoRGBEffect& yuvEffect = processor.cast<YUVtoRGBEffect>();
124             switch (yuvEffect.getColorSpace()) {
125                 case kJPEG_SkYUVColorSpace:
126                     pdman.setMatrix4f(fMatrixUni, kJPEGConversionMatrix);
127                     break;
128                 case kRec601_SkYUVColorSpace:
129                     pdman.setMatrix4f(fMatrixUni, kRec601ConversionMatrix);
130                     break;
131                 case kRec709_SkYUVColorSpace:
132                     pdman.setMatrix4f(fMatrixUni, kRec709ConversionMatrix);
133                     break;
134             }
135         }
136 
137     private:
138         GrGLSLProgramDataManager::UniformHandle fMatrixUni;
139 
140         typedef GrGLSLFragmentProcessor INHERITED;
141     };
142 
143 private:
YUVtoRGBEffect(GrTexture * yTexture,GrTexture * uTexture,GrTexture * vTexture,const SkMatrix yuvMatrix[3],GrTextureParams::FilterMode uvFilterMode,SkYUVColorSpace colorSpace)144     YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture,
145                    const SkMatrix yuvMatrix[3], GrTextureParams::FilterMode uvFilterMode,
146                    SkYUVColorSpace colorSpace)
147     : fYTransform(kLocal_GrCoordSet, yuvMatrix[0], yTexture, GrTextureParams::kNone_FilterMode)
148     , fYAccess(yTexture)
149     , fUTransform(kLocal_GrCoordSet, yuvMatrix[1], uTexture, uvFilterMode)
150     , fUAccess(uTexture, uvFilterMode)
151     , fVTransform(kLocal_GrCoordSet, yuvMatrix[2], vTexture, uvFilterMode)
152     , fVAccess(vTexture, uvFilterMode)
153     , fColorSpace(colorSpace) {
154         this->initClassID<YUVtoRGBEffect>();
155         this->addCoordTransform(&fYTransform);
156         this->addTextureAccess(&fYAccess);
157         this->addCoordTransform(&fUTransform);
158         this->addTextureAccess(&fUAccess);
159         this->addCoordTransform(&fVTransform);
160         this->addTextureAccess(&fVAccess);
161     }
162 
onCreateGLSLInstance() const163     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
164         return new GLSLProcessor;
165     }
166 
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const167     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
168         GLSLProcessor::GenKey(*this, caps, b);
169     }
170 
onIsEqual(const GrFragmentProcessor & sBase) const171     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
172         const YUVtoRGBEffect& s = sBase.cast<YUVtoRGBEffect>();
173         return fColorSpace == s.getColorSpace();
174     }
175 
onComputeInvariantOutput(GrInvariantOutput * inout) const176     void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
177         // YUV is opaque
178         inout->setToOther(kA_GrColorComponentFlag, 0xFF << GrColor_SHIFT_A,
179                           GrInvariantOutput::kWillNot_ReadInput);
180     }
181 
182     GrCoordTransform fYTransform;
183     GrTextureAccess fYAccess;
184     GrCoordTransform fUTransform;
185     GrTextureAccess fUAccess;
186     GrCoordTransform fVTransform;
187     GrTextureAccess fVAccess;
188     SkYUVColorSpace fColorSpace;
189 
190     typedef GrFragmentProcessor INHERITED;
191 };
192 
193 
194 class RGBToYUVEffect : public GrFragmentProcessor {
195 public:
196     enum OutputChannels {
197         // output color r = y, g = u, b = v, a = a
198         kYUV_OutputChannels,
199         // output color rgba = y
200         kY_OutputChannels,
201         // output color r = u, g = v, b = 0, a = a
202         kUV_OutputChannels,
203         // output color rgba = u
204         kU_OutputChannels,
205         // output color rgba = v
206         kV_OutputChannels
207     };
208 
RGBToYUVEffect(const GrFragmentProcessor * rgbFP,SkYUVColorSpace colorSpace,OutputChannels output)209     RGBToYUVEffect(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colorSpace,
210                    OutputChannels output)
211         : fColorSpace(colorSpace)
212         , fOutputChannels(output) {
213         this->initClassID<RGBToYUVEffect>();
214         this->registerChildProcessor(rgbFP);
215     }
216 
name() const217     const char* name() const override { return "RGBToYUV"; }
218 
getColorSpace() const219     SkYUVColorSpace getColorSpace() const { return fColorSpace; }
220 
outputChannels() const221     OutputChannels outputChannels() const { return fOutputChannels; }
222 
223     class GLSLProcessor : public GrGLSLFragmentProcessor {
224     public:
GLSLProcessor()225         GLSLProcessor() : fLastColorSpace(-1), fLastOutputChannels(-1) {}
226 
emitCode(EmitArgs & args)227         void emitCode(EmitArgs& args) override {
228             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
229             OutputChannels oc = args.fFp.cast<RGBToYUVEffect>().outputChannels();
230 
231             SkString outputColor("rgbColor");
232             this->emitChild(0, args.fInputColor, &outputColor, args);
233 
234             const char* uniName;
235             switch (oc) {
236                 case kYUV_OutputChannels:
237                     fRGBToYUVUni = args.fUniformHandler->addUniformArray(
238                         kFragment_GrShaderFlag,
239                         kVec4f_GrSLType, kDefault_GrSLPrecision,
240                         "RGBToYUV", 3, &uniName);
241                     fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s[0].rgb) + %s[0].a,"
242                                                        "dot(rgbColor.rgb, %s[1].rgb) + %s[1].a,"
243                                                        "dot(rgbColor.rgb, %s[2].rgb) + %s[2].a,"
244                                                        "rgbColor.a);",
245                                              args.fOutputColor, uniName, uniName, uniName, uniName,
246                                              uniName, uniName);
247                     break;
248                 case kUV_OutputChannels:
249                     fRGBToYUVUni = args.fUniformHandler->addUniformArray(
250                         kFragment_GrShaderFlag,
251                         kVec4f_GrSLType, kDefault_GrSLPrecision,
252                         "RGBToUV", 2, &uniName);
253                     fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s[0].rgb) + %s[0].a,"
254                                                        "dot(rgbColor.rgb, %s[1].rgb) + %s[1].a,"
255                                                        "0.0,"
256                                                        "rgbColor.a);",
257                                              args.fOutputColor, uniName, uniName, uniName, uniName);
258                     break;
259                 case kY_OutputChannels:
260                 case kU_OutputChannels:
261                 case kV_OutputChannels:
262                     fRGBToYUVUni = args.fUniformHandler->addUniform(
263                         kFragment_GrShaderFlag,
264                         kVec4f_GrSLType, kDefault_GrSLPrecision,
265                         "RGBToYUorV", &uniName);
266                     fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s.rgb) + %s.a);\n",
267                                              args.fOutputColor, uniName, uniName);
268                     break;
269             }
270         }
271 
272     private:
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & processor)273         void onSetData(const GrGLSLProgramDataManager& pdman,
274                        const GrProcessor& processor) override {
275             const RGBToYUVEffect& effect = processor.cast<RGBToYUVEffect>();
276             OutputChannels oc = effect.outputChannels();
277             if (effect.getColorSpace() != fLastColorSpace || oc != fLastOutputChannels) {
278 
279                 const float* matrix = nullptr;
280                 switch (effect.getColorSpace()) {
281                     case kJPEG_SkYUVColorSpace:
282                         matrix = kJPEGInverseConversionMatrix;
283                         break;
284                     case kRec601_SkYUVColorSpace:
285                         matrix = kRec601InverseConversionMatrix;
286                         break;
287                     case kRec709_SkYUVColorSpace:
288                         matrix = kRec709InverseConversionMatrix;
289                         break;
290                 }
291                 switch (oc) {
292                     case kYUV_OutputChannels:
293                         pdman.set4fv(fRGBToYUVUni, 3, matrix);
294                         break;
295                     case kUV_OutputChannels:
296                         pdman.set4fv(fRGBToYUVUni, 2, matrix + 4);
297                         break;
298                     case kY_OutputChannels:
299                         pdman.set4fv(fRGBToYUVUni, 1, matrix);
300                         break;
301                     case kU_OutputChannels:
302                         pdman.set4fv(fRGBToYUVUni, 1, matrix + 4);
303                         break;
304                     case kV_OutputChannels:
305                         pdman.set4fv(fRGBToYUVUni, 1, matrix + 8);
306                         break;
307                 }
308                 fLastColorSpace = effect.getColorSpace();
309             }
310         }
311         GrGLSLProgramDataManager::UniformHandle fRGBToYUVUni;
312         int                                     fLastColorSpace;
313         int                                     fLastOutputChannels;
314 
315         typedef GrGLSLFragmentProcessor INHERITED;
316     };
317 
318 private:
onCreateGLSLInstance() const319     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
320         return new GLSLProcessor;
321     }
322 
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const323     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
324         // kY, kU, and kV all generate the same code, just upload different coefficients.
325         if (kU_OutputChannels == fOutputChannels || kV_OutputChannels == fOutputChannels) {
326             b->add32(kY_OutputChannels);
327         } else {
328             b->add32(fOutputChannels);
329         }
330     }
331 
onIsEqual(const GrFragmentProcessor & sBase) const332     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
333         const RGBToYUVEffect& s = sBase.cast<RGBToYUVEffect>();
334         return fColorSpace == s.getColorSpace() && fOutputChannels == s.outputChannels();
335     }
336 
onComputeInvariantOutput(GrInvariantOutput * inout) const337     void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
338         inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput);
339     }
340 
341     GrCoordTransform    fTransform;
342     GrTextureAccess     fAccess;
343     SkYUVColorSpace     fColorSpace;
344     OutputChannels      fOutputChannels;
345 
346     typedef GrFragmentProcessor INHERITED;
347 };
348 
349 }
350 
351 //////////////////////////////////////////////////////////////////////////////
352 
353 const GrFragmentProcessor*
CreateYUVToRGB(GrTexture * yTexture,GrTexture * uTexture,GrTexture * vTexture,const SkISize sizes[3],SkYUVColorSpace colorSpace)354 GrYUVEffect::CreateYUVToRGB(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture,
355                             const SkISize sizes[3], SkYUVColorSpace colorSpace) {
356     SkASSERT(yTexture && uTexture && vTexture && sizes);
357     return YUVtoRGBEffect::Create(yTexture, uTexture, vTexture, sizes, colorSpace);
358 }
359 
360 const GrFragmentProcessor*
CreateRGBToYUV(const GrFragmentProcessor * rgbFP,SkYUVColorSpace colorSpace)361 GrYUVEffect::CreateRGBToYUV(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colorSpace) {
362     SkASSERT(rgbFP);
363     return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kYUV_OutputChannels);
364 }
365 
366 const GrFragmentProcessor*
CreateRGBToY(const GrFragmentProcessor * rgbFP,SkYUVColorSpace colorSpace)367 GrYUVEffect::CreateRGBToY(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colorSpace) {
368     SkASSERT(rgbFP);
369     return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kY_OutputChannels);
370 }
371 
372 const GrFragmentProcessor*
CreateRGBToUV(const GrFragmentProcessor * rgbFP,SkYUVColorSpace colorSpace)373 GrYUVEffect::CreateRGBToUV(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colorSpace) {
374     SkASSERT(rgbFP);
375     return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kUV_OutputChannels);
376 }
377 
378 const GrFragmentProcessor*
CreateRGBToU(const GrFragmentProcessor * rgbFP,SkYUVColorSpace colorSpace)379 GrYUVEffect::CreateRGBToU(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colorSpace) {
380     SkASSERT(rgbFP);
381     return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kU_OutputChannels);
382 }
383 
384 const GrFragmentProcessor*
CreateRGBToV(const GrFragmentProcessor * rgbFP,SkYUVColorSpace colorSpace)385 GrYUVEffect::CreateRGBToV(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colorSpace) {
386     SkASSERT(rgbFP);
387     return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kV_OutputChannels);
388 }
389