blob: 6b15c0dc72582baff00f051ec3b2c16056faf104 [file] [log] [blame]
bsalomonf267c1e2016-02-01 13:16:14 -08001/*
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
19namespace {
20
21static 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
28static 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
35static 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
42static 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
49static 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
56static 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
63class YUVtoRGBEffect : public GrFragmentProcessor {
64public:
bungeman06ca8ec2016-06-09 08:01:03 -070065 static sk_sp<GrFragmentProcessor> Make(GrTexture* yTexture, GrTexture* uTexture,
66 GrTexture* vTexture, const SkISize sizes[3],
jbaumanb445a572016-06-09 13:24:48 -070067 SkYUVColorSpace colorSpace, bool nv12) {
bsalomonf267c1e2016-02-01 13:16:14 -080068 SkScalar w[3], h[3];
Robert Phillips67c18d62017-01-20 12:44:06 -050069 w[0] = SkIntToScalar(sizes[0].fWidth);
70 h[0] = SkIntToScalar(sizes[0].fHeight);
71 w[1] = SkIntToScalar(sizes[1].fWidth);
72 h[1] = SkIntToScalar(sizes[1].fHeight);
73 w[2] = SkIntToScalar(sizes[2].fWidth);
74 h[2] = SkIntToScalar(sizes[2].fHeight);
75 const SkMatrix yuvMatrix[3] = {
76 SkMatrix::I(),
77 SkMatrix::MakeScale(w[1] / w[0], h[1] / h[0]),
78 SkMatrix::MakeScale(w[2] / w[0], h[2] / h[0])
79 };
Brian Salomon514baff2016-11-17 15:17:07 -050080 GrSamplerParams::FilterMode uvFilterMode =
bsalomonf267c1e2016-02-01 13:16:14 -080081 ((sizes[1].fWidth != sizes[0].fWidth) ||
82 (sizes[1].fHeight != sizes[0].fHeight) ||
83 (sizes[2].fWidth != sizes[0].fWidth) ||
84 (sizes[2].fHeight != sizes[0].fHeight)) ?
Brian Salomon514baff2016-11-17 15:17:07 -050085 GrSamplerParams::kBilerp_FilterMode :
86 GrSamplerParams::kNone_FilterMode;
jbaumanb445a572016-06-09 13:24:48 -070087 return sk_sp<GrFragmentProcessor>(new YUVtoRGBEffect(
88 yTexture, uTexture, vTexture, yuvMatrix, uvFilterMode, colorSpace, nv12));
bsalomonf267c1e2016-02-01 13:16:14 -080089 }
90
91 const char* name() const override { return "YUV to RGB"; }
92
93 SkYUVColorSpace getColorSpace() const { return fColorSpace; }
94
jbaumanb445a572016-06-09 13:24:48 -070095 bool isNV12() const {
96 return fNV12;
97 }
98
bsalomonf267c1e2016-02-01 13:16:14 -080099 class GLSLProcessor : public GrGLSLFragmentProcessor {
100 public:
bsalomonf267c1e2016-02-01 13:16:14 -0800101 void emitCode(EmitArgs& args) override {
cdalton85285412016-02-18 12:37:07 -0800102 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
jbaumanb445a572016-06-09 13:24:48 -0700103 const YUVtoRGBEffect& effect = args.fFp.cast<YUVtoRGBEffect>();
bsalomonf267c1e2016-02-01 13:16:14 -0800104
105 const char* colorSpaceMatrix = nullptr;
cdalton5e58cee2016-02-11 12:49:47 -0800106 fMatrixUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
107 kMat44f_GrSLType, kDefault_GrSLPrecision,
108 "ColorSpaceMatrix", &colorSpaceMatrix);
bsalomonf267c1e2016-02-01 13:16:14 -0800109 fragBuilder->codeAppendf("%s = vec4(", args.fOutputColor);
bsalomon1a1aa932016-09-12 09:30:36 -0700110 fragBuilder->appendTextureLookup(args.fTexSamplers[0],
111 args.fTransformedCoords[0].c_str(),
112 args.fTransformedCoords[0].getType());
bsalomonf267c1e2016-02-01 13:16:14 -0800113 fragBuilder->codeAppend(".r,");
bsalomon1a1aa932016-09-12 09:30:36 -0700114 fragBuilder->appendTextureLookup(args.fTexSamplers[1],
115 args.fTransformedCoords[1].c_str(),
116 args.fTransformedCoords[1].getType());
jbaumanb445a572016-06-09 13:24:48 -0700117 if (effect.fNV12) {
118 fragBuilder->codeAppendf(".rg,");
119 } else {
120 fragBuilder->codeAppend(".r,");
bsalomon1a1aa932016-09-12 09:30:36 -0700121 fragBuilder->appendTextureLookup(args.fTexSamplers[2],
122 args.fTransformedCoords[2].c_str(),
123 args.fTransformedCoords[2].getType());
jbaumanb445a572016-06-09 13:24:48 -0700124 fragBuilder->codeAppendf(".g,");
125 }
126 fragBuilder->codeAppendf("1.0) * %s;", colorSpaceMatrix);
bsalomonf267c1e2016-02-01 13:16:14 -0800127 }
128
129 protected:
130 void onSetData(const GrGLSLProgramDataManager& pdman,
131 const GrProcessor& processor) override {
132 const YUVtoRGBEffect& yuvEffect = processor.cast<YUVtoRGBEffect>();
133 switch (yuvEffect.getColorSpace()) {
134 case kJPEG_SkYUVColorSpace:
135 pdman.setMatrix4f(fMatrixUni, kJPEGConversionMatrix);
136 break;
137 case kRec601_SkYUVColorSpace:
138 pdman.setMatrix4f(fMatrixUni, kRec601ConversionMatrix);
139 break;
140 case kRec709_SkYUVColorSpace:
141 pdman.setMatrix4f(fMatrixUni, kRec709ConversionMatrix);
142 break;
143 }
144 }
145
146 private:
147 GrGLSLProgramDataManager::UniformHandle fMatrixUni;
148
149 typedef GrGLSLFragmentProcessor INHERITED;
150 };
151
152private:
153 YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture,
Brian Salomon514baff2016-11-17 15:17:07 -0500154 const SkMatrix yuvMatrix[3], GrSamplerParams::FilterMode uvFilterMode,
jbaumanb445a572016-06-09 13:24:48 -0700155 SkYUVColorSpace colorSpace, bool nv12)
Brian Salomon514baff2016-11-17 15:17:07 -0500156 : fYTransform(yuvMatrix[0], yTexture, GrSamplerParams::kNone_FilterMode)
Brian Salomon0bbecb22016-11-17 11:38:22 -0500157 , fYSampler(yTexture)
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400158 , fUTransform(yuvMatrix[1], uTexture, uvFilterMode)
Brian Salomon0bbecb22016-11-17 11:38:22 -0500159 , fUSampler(uTexture, uvFilterMode)
160 , fVSampler(vTexture, uvFilterMode)
jbaumanb445a572016-06-09 13:24:48 -0700161 , fColorSpace(colorSpace)
162 , fNV12(nv12) {
bsalomonf267c1e2016-02-01 13:16:14 -0800163 this->initClassID<YUVtoRGBEffect>();
164 this->addCoordTransform(&fYTransform);
Brian Salomon0bbecb22016-11-17 11:38:22 -0500165 this->addTextureSampler(&fYSampler);
bsalomonf267c1e2016-02-01 13:16:14 -0800166 this->addCoordTransform(&fUTransform);
Brian Salomon0bbecb22016-11-17 11:38:22 -0500167 this->addTextureSampler(&fUSampler);
jbaumanb445a572016-06-09 13:24:48 -0700168 if (!fNV12) {
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400169 fVTransform = GrCoordTransform(yuvMatrix[2], vTexture, uvFilterMode);
jbaumanb445a572016-06-09 13:24:48 -0700170 this->addCoordTransform(&fVTransform);
Brian Salomon0bbecb22016-11-17 11:38:22 -0500171 this->addTextureSampler(&fVSampler);
jbaumanb445a572016-06-09 13:24:48 -0700172 }
bsalomonf267c1e2016-02-01 13:16:14 -0800173 }
174
175 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillips9cdb9922016-02-03 12:25:40 -0800176 return new GLSLProcessor;
bsalomonf267c1e2016-02-01 13:16:14 -0800177 }
178
Brian Salomon94efbf52016-11-29 13:43:05 -0500179 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
jbaumanb445a572016-06-09 13:24:48 -0700180 b->add32(fNV12);
bsalomonf267c1e2016-02-01 13:16:14 -0800181 }
182
183 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
184 const YUVtoRGBEffect& s = sBase.cast<YUVtoRGBEffect>();
jbaumanb445a572016-06-09 13:24:48 -0700185 return (fColorSpace == s.getColorSpace()) && (fNV12 == s.isNV12());
bsalomonf267c1e2016-02-01 13:16:14 -0800186 }
187
188 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
189 // YUV is opaque
Brian Salomon5f13fba2017-01-23 14:35:25 -0500190 inout->setToOther(kA_GrColorComponentFlag, 0xFF << GrColor_SHIFT_A);
bsalomonf267c1e2016-02-01 13:16:14 -0800191 }
192
193 GrCoordTransform fYTransform;
Brian Salomon0bbecb22016-11-17 11:38:22 -0500194 TextureSampler fYSampler;
bsalomonf267c1e2016-02-01 13:16:14 -0800195 GrCoordTransform fUTransform;
Brian Salomon0bbecb22016-11-17 11:38:22 -0500196 TextureSampler fUSampler;
bsalomonf267c1e2016-02-01 13:16:14 -0800197 GrCoordTransform fVTransform;
Brian Salomon0bbecb22016-11-17 11:38:22 -0500198 TextureSampler fVSampler;
bsalomonf267c1e2016-02-01 13:16:14 -0800199 SkYUVColorSpace fColorSpace;
jbaumanb445a572016-06-09 13:24:48 -0700200 bool fNV12;
bsalomonf267c1e2016-02-01 13:16:14 -0800201
202 typedef GrFragmentProcessor INHERITED;
203};
204
205
206class RGBToYUVEffect : public GrFragmentProcessor {
207public:
208 enum OutputChannels {
209 // output color r = y, g = u, b = v, a = a
210 kYUV_OutputChannels,
211 // output color rgba = y
212 kY_OutputChannels,
213 // output color r = u, g = v, b = 0, a = a
214 kUV_OutputChannels,
215 // output color rgba = u
216 kU_OutputChannels,
217 // output color rgba = v
218 kV_OutputChannels
219 };
220
bungeman06ca8ec2016-06-09 08:01:03 -0700221 RGBToYUVEffect(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace,
bsalomonf267c1e2016-02-01 13:16:14 -0800222 OutputChannels output)
223 : fColorSpace(colorSpace)
224 , fOutputChannels(output) {
225 this->initClassID<RGBToYUVEffect>();
bungeman06ca8ec2016-06-09 08:01:03 -0700226 this->registerChildProcessor(std::move(rgbFP));
bsalomonf267c1e2016-02-01 13:16:14 -0800227 }
228
229 const char* name() const override { return "RGBToYUV"; }
230
231 SkYUVColorSpace getColorSpace() const { return fColorSpace; }
232
233 OutputChannels outputChannels() const { return fOutputChannels; }
234
235 class GLSLProcessor : public GrGLSLFragmentProcessor {
236 public:
robertphillips9cdb9922016-02-03 12:25:40 -0800237 GLSLProcessor() : fLastColorSpace(-1), fLastOutputChannels(-1) {}
bsalomonf267c1e2016-02-01 13:16:14 -0800238
239 void emitCode(EmitArgs& args) override {
cdalton85285412016-02-18 12:37:07 -0800240 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomonf267c1e2016-02-01 13:16:14 -0800241 OutputChannels oc = args.fFp.cast<RGBToYUVEffect>().outputChannels();
242
243 SkString outputColor("rgbColor");
244 this->emitChild(0, args.fInputColor, &outputColor, args);
245
246 const char* uniName;
247 switch (oc) {
248 case kYUV_OutputChannels:
249 fRGBToYUVUni = args.fUniformHandler->addUniformArray(
cdalton5e58cee2016-02-11 12:49:47 -0800250 kFragment_GrShaderFlag,
bsalomonf267c1e2016-02-01 13:16:14 -0800251 kVec4f_GrSLType, kDefault_GrSLPrecision,
252 "RGBToYUV", 3, &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 "dot(rgbColor.rgb, %s[2].rgb) + %s[2].a,"
256 "rgbColor.a);",
257 args.fOutputColor, uniName, uniName, uniName, uniName,
258 uniName, uniName);
259 break;
260 case kUV_OutputChannels:
261 fRGBToYUVUni = args.fUniformHandler->addUniformArray(
cdalton5e58cee2016-02-11 12:49:47 -0800262 kFragment_GrShaderFlag,
bsalomonf267c1e2016-02-01 13:16:14 -0800263 kVec4f_GrSLType, kDefault_GrSLPrecision,
264 "RGBToUV", 2, &uniName);
265 fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s[0].rgb) + %s[0].a,"
266 "dot(rgbColor.rgb, %s[1].rgb) + %s[1].a,"
267 "0.0,"
268 "rgbColor.a);",
269 args.fOutputColor, uniName, uniName, uniName, uniName);
270 break;
271 case kY_OutputChannels:
272 case kU_OutputChannels:
273 case kV_OutputChannels:
274 fRGBToYUVUni = args.fUniformHandler->addUniform(
cdalton5e58cee2016-02-11 12:49:47 -0800275 kFragment_GrShaderFlag,
bsalomonf267c1e2016-02-01 13:16:14 -0800276 kVec4f_GrSLType, kDefault_GrSLPrecision,
277 "RGBToYUorV", &uniName);
278 fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s.rgb) + %s.a);\n",
279 args.fOutputColor, uniName, uniName);
280 break;
281 }
282 }
283
284 private:
285 void onSetData(const GrGLSLProgramDataManager& pdman,
286 const GrProcessor& processor) override {
287 const RGBToYUVEffect& effect = processor.cast<RGBToYUVEffect>();
288 OutputChannels oc = effect.outputChannels();
289 if (effect.getColorSpace() != fLastColorSpace || oc != fLastOutputChannels) {
290
291 const float* matrix = nullptr;
292 switch (effect.getColorSpace()) {
293 case kJPEG_SkYUVColorSpace:
294 matrix = kJPEGInverseConversionMatrix;
295 break;
296 case kRec601_SkYUVColorSpace:
297 matrix = kRec601InverseConversionMatrix;
298 break;
299 case kRec709_SkYUVColorSpace:
300 matrix = kRec709InverseConversionMatrix;
301 break;
302 }
303 switch (oc) {
304 case kYUV_OutputChannels:
305 pdman.set4fv(fRGBToYUVUni, 3, matrix);
306 break;
307 case kUV_OutputChannels:
308 pdman.set4fv(fRGBToYUVUni, 2, matrix + 4);
309 break;
310 case kY_OutputChannels:
311 pdman.set4fv(fRGBToYUVUni, 1, matrix);
312 break;
313 case kU_OutputChannels:
314 pdman.set4fv(fRGBToYUVUni, 1, matrix + 4);
315 break;
316 case kV_OutputChannels:
317 pdman.set4fv(fRGBToYUVUni, 1, matrix + 8);
318 break;
319 }
320 fLastColorSpace = effect.getColorSpace();
321 }
322 }
323 GrGLSLProgramDataManager::UniformHandle fRGBToYUVUni;
324 int fLastColorSpace;
325 int fLastOutputChannels;
326
327 typedef GrGLSLFragmentProcessor INHERITED;
328 };
329
330private:
331 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillips9cdb9922016-02-03 12:25:40 -0800332 return new GLSLProcessor;
bsalomonf267c1e2016-02-01 13:16:14 -0800333 }
334
Brian Salomon94efbf52016-11-29 13:43:05 -0500335 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
bsalomonf267c1e2016-02-01 13:16:14 -0800336 // kY, kU, and kV all generate the same code, just upload different coefficients.
337 if (kU_OutputChannels == fOutputChannels || kV_OutputChannels == fOutputChannels) {
338 b->add32(kY_OutputChannels);
339 } else {
340 b->add32(fOutputChannels);
341 }
342 }
343
344 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
345 const RGBToYUVEffect& s = sBase.cast<RGBToYUVEffect>();
346 return fColorSpace == s.getColorSpace() && fOutputChannels == s.outputChannels();
347 }
348
349 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
Brian Salomon5f13fba2017-01-23 14:35:25 -0500350 inout->setToUnknown();
bsalomonf267c1e2016-02-01 13:16:14 -0800351 }
352
353 GrCoordTransform fTransform;
Brian Salomon0bbecb22016-11-17 11:38:22 -0500354 TextureSampler fTextureSampler;
bsalomonf267c1e2016-02-01 13:16:14 -0800355 SkYUVColorSpace fColorSpace;
356 OutputChannels fOutputChannels;
357
358 typedef GrFragmentProcessor INHERITED;
359};
360
361}
362
363//////////////////////////////////////////////////////////////////////////////
364
jbaumanb445a572016-06-09 13:24:48 -0700365sk_sp<GrFragmentProcessor> GrYUVEffect::MakeYUVToRGB(GrTexture* yTexture, GrTexture* uTexture,
366 GrTexture* vTexture, const SkISize sizes[3],
367 SkYUVColorSpace colorSpace, bool nv12) {
bsalomonf267c1e2016-02-01 13:16:14 -0800368 SkASSERT(yTexture && uTexture && vTexture && sizes);
jbaumanb445a572016-06-09 13:24:48 -0700369 return YUVtoRGBEffect::Make(yTexture, uTexture, vTexture, sizes, colorSpace, nv12);
bsalomonf267c1e2016-02-01 13:16:14 -0800370}
371
bungeman06ca8ec2016-06-09 08:01:03 -0700372sk_sp<GrFragmentProcessor>
373GrYUVEffect::MakeRGBToYUV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800374 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700375 return sk_sp<GrFragmentProcessor>(
376 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kYUV_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800377}
378
bungeman06ca8ec2016-06-09 08:01:03 -0700379sk_sp<GrFragmentProcessor>
380GrYUVEffect::MakeRGBToY(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800381 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700382 return sk_sp<GrFragmentProcessor>(
383 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kY_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800384}
385
bungeman06ca8ec2016-06-09 08:01:03 -0700386sk_sp<GrFragmentProcessor>
387GrYUVEffect::MakeRGBToUV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800388 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700389 return sk_sp<GrFragmentProcessor>(
390 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kUV_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800391}
392
bungeman06ca8ec2016-06-09 08:01:03 -0700393sk_sp<GrFragmentProcessor>
394GrYUVEffect::MakeRGBToU(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800395 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700396 return sk_sp<GrFragmentProcessor>(
397 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kU_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800398}
399
bungeman06ca8ec2016-06-09 08:01:03 -0700400sk_sp<GrFragmentProcessor>
401GrYUVEffect::MakeRGBToV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800402 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700403 return sk_sp<GrFragmentProcessor>(
404 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kV_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800405}