blob: cbe25e82f8deb4c1bfe44ffb35561dfee4d696c3 [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];
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;
jbaumanb445a572016-06-09 13:24:48 -070088 return sk_sp<GrFragmentProcessor>(new YUVtoRGBEffect(
89 yTexture, uTexture, vTexture, yuvMatrix, uvFilterMode, colorSpace, nv12));
bsalomonf267c1e2016-02-01 13:16:14 -080090 }
91
92 const char* name() const override { return "YUV to RGB"; }
93
94 SkYUVColorSpace getColorSpace() const { return fColorSpace; }
95
jbaumanb445a572016-06-09 13:24:48 -070096 bool isNV12() const {
97 return fNV12;
98 }
99
bsalomonf267c1e2016-02-01 13:16:14 -0800100 class GLSLProcessor : public GrGLSLFragmentProcessor {
101 public:
bsalomonf267c1e2016-02-01 13:16:14 -0800102 void emitCode(EmitArgs& args) override {
cdalton85285412016-02-18 12:37:07 -0800103 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
jbaumanb445a572016-06-09 13:24:48 -0700104 const YUVtoRGBEffect& effect = args.fFp.cast<YUVtoRGBEffect>();
bsalomonf267c1e2016-02-01 13:16:14 -0800105
106 const char* colorSpaceMatrix = nullptr;
cdalton5e58cee2016-02-11 12:49:47 -0800107 fMatrixUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
108 kMat44f_GrSLType, kDefault_GrSLPrecision,
109 "ColorSpaceMatrix", &colorSpaceMatrix);
bsalomonf267c1e2016-02-01 13:16:14 -0800110 fragBuilder->codeAppendf("%s = vec4(", args.fOutputColor);
bsalomon1a1aa932016-09-12 09:30:36 -0700111 fragBuilder->appendTextureLookup(args.fTexSamplers[0],
112 args.fTransformedCoords[0].c_str(),
113 args.fTransformedCoords[0].getType());
bsalomonf267c1e2016-02-01 13:16:14 -0800114 fragBuilder->codeAppend(".r,");
bsalomon1a1aa932016-09-12 09:30:36 -0700115 fragBuilder->appendTextureLookup(args.fTexSamplers[1],
116 args.fTransformedCoords[1].c_str(),
117 args.fTransformedCoords[1].getType());
jbaumanb445a572016-06-09 13:24:48 -0700118 if (effect.fNV12) {
119 fragBuilder->codeAppendf(".rg,");
120 } else {
121 fragBuilder->codeAppend(".r,");
bsalomon1a1aa932016-09-12 09:30:36 -0700122 fragBuilder->appendTextureLookup(args.fTexSamplers[2],
123 args.fTransformedCoords[2].c_str(),
124 args.fTransformedCoords[2].getType());
jbaumanb445a572016-06-09 13:24:48 -0700125 fragBuilder->codeAppendf(".g,");
126 }
127 fragBuilder->codeAppendf("1.0) * %s;", colorSpaceMatrix);
bsalomonf267c1e2016-02-01 13:16:14 -0800128 }
129
130 protected:
131 void onSetData(const GrGLSLProgramDataManager& pdman,
132 const GrProcessor& processor) override {
133 const YUVtoRGBEffect& yuvEffect = processor.cast<YUVtoRGBEffect>();
134 switch (yuvEffect.getColorSpace()) {
135 case kJPEG_SkYUVColorSpace:
136 pdman.setMatrix4f(fMatrixUni, kJPEGConversionMatrix);
137 break;
138 case kRec601_SkYUVColorSpace:
139 pdman.setMatrix4f(fMatrixUni, kRec601ConversionMatrix);
140 break;
141 case kRec709_SkYUVColorSpace:
142 pdman.setMatrix4f(fMatrixUni, kRec709ConversionMatrix);
143 break;
144 }
145 }
146
147 private:
148 GrGLSLProgramDataManager::UniformHandle fMatrixUni;
149
150 typedef GrGLSLFragmentProcessor INHERITED;
151 };
152
153private:
154 YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture,
155 const SkMatrix yuvMatrix[3], GrTextureParams::FilterMode uvFilterMode,
jbaumanb445a572016-06-09 13:24:48 -0700156 SkYUVColorSpace colorSpace, bool nv12)
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400157 : fYTransform(yuvMatrix[0], yTexture, GrTextureParams::kNone_FilterMode)
jbaumanb445a572016-06-09 13:24:48 -0700158 , fYAccess(yTexture)
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400159 , fUTransform(yuvMatrix[1], uTexture, uvFilterMode)
jbaumanb445a572016-06-09 13:24:48 -0700160 , fUAccess(uTexture, uvFilterMode)
161 , fVAccess(vTexture, uvFilterMode)
162 , fColorSpace(colorSpace)
163 , fNV12(nv12) {
bsalomonf267c1e2016-02-01 13:16:14 -0800164 this->initClassID<YUVtoRGBEffect>();
165 this->addCoordTransform(&fYTransform);
166 this->addTextureAccess(&fYAccess);
167 this->addCoordTransform(&fUTransform);
168 this->addTextureAccess(&fUAccess);
jbaumanb445a572016-06-09 13:24:48 -0700169 if (!fNV12) {
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400170 fVTransform = GrCoordTransform(yuvMatrix[2], vTexture, uvFilterMode);
jbaumanb445a572016-06-09 13:24:48 -0700171 this->addCoordTransform(&fVTransform);
172 this->addTextureAccess(&fVAccess);
173 }
bsalomonf267c1e2016-02-01 13:16:14 -0800174 }
175
176 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillips9cdb9922016-02-03 12:25:40 -0800177 return new GLSLProcessor;
bsalomonf267c1e2016-02-01 13:16:14 -0800178 }
179
180 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
jbaumanb445a572016-06-09 13:24:48 -0700181 b->add32(fNV12);
bsalomonf267c1e2016-02-01 13:16:14 -0800182 }
183
184 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
185 const YUVtoRGBEffect& s = sBase.cast<YUVtoRGBEffect>();
jbaumanb445a572016-06-09 13:24:48 -0700186 return (fColorSpace == s.getColorSpace()) && (fNV12 == s.isNV12());
bsalomonf267c1e2016-02-01 13:16:14 -0800187 }
188
189 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
190 // YUV is opaque
191 inout->setToOther(kA_GrColorComponentFlag, 0xFF << GrColor_SHIFT_A,
192 GrInvariantOutput::kWillNot_ReadInput);
193 }
194
195 GrCoordTransform fYTransform;
196 GrTextureAccess fYAccess;
197 GrCoordTransform fUTransform;
198 GrTextureAccess fUAccess;
199 GrCoordTransform fVTransform;
200 GrTextureAccess fVAccess;
201 SkYUVColorSpace fColorSpace;
jbaumanb445a572016-06-09 13:24:48 -0700202 bool fNV12;
bsalomonf267c1e2016-02-01 13:16:14 -0800203
204 typedef GrFragmentProcessor INHERITED;
205};
206
207
208class RGBToYUVEffect : public GrFragmentProcessor {
209public:
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
bungeman06ca8ec2016-06-09 08:01:03 -0700223 RGBToYUVEffect(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace,
bsalomonf267c1e2016-02-01 13:16:14 -0800224 OutputChannels output)
225 : fColorSpace(colorSpace)
226 , fOutputChannels(output) {
227 this->initClassID<RGBToYUVEffect>();
bungeman06ca8ec2016-06-09 08:01:03 -0700228 this->registerChildProcessor(std::move(rgbFP));
bsalomonf267c1e2016-02-01 13:16:14 -0800229 }
230
231 const char* name() const override { return "RGBToYUV"; }
232
233 SkYUVColorSpace getColorSpace() const { return fColorSpace; }
234
235 OutputChannels outputChannels() const { return fOutputChannels; }
236
237 class GLSLProcessor : public GrGLSLFragmentProcessor {
238 public:
robertphillips9cdb9922016-02-03 12:25:40 -0800239 GLSLProcessor() : fLastColorSpace(-1), fLastOutputChannels(-1) {}
bsalomonf267c1e2016-02-01 13:16:14 -0800240
241 void emitCode(EmitArgs& args) override {
cdalton85285412016-02-18 12:37:07 -0800242 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomonf267c1e2016-02-01 13:16:14 -0800243 OutputChannels oc = args.fFp.cast<RGBToYUVEffect>().outputChannels();
244
245 SkString outputColor("rgbColor");
246 this->emitChild(0, args.fInputColor, &outputColor, args);
247
248 const char* uniName;
249 switch (oc) {
250 case kYUV_OutputChannels:
251 fRGBToYUVUni = args.fUniformHandler->addUniformArray(
cdalton5e58cee2016-02-11 12:49:47 -0800252 kFragment_GrShaderFlag,
bsalomonf267c1e2016-02-01 13:16:14 -0800253 kVec4f_GrSLType, kDefault_GrSLPrecision,
254 "RGBToYUV", 3, &uniName);
255 fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s[0].rgb) + %s[0].a,"
256 "dot(rgbColor.rgb, %s[1].rgb) + %s[1].a,"
257 "dot(rgbColor.rgb, %s[2].rgb) + %s[2].a,"
258 "rgbColor.a);",
259 args.fOutputColor, uniName, uniName, uniName, uniName,
260 uniName, uniName);
261 break;
262 case kUV_OutputChannels:
263 fRGBToYUVUni = args.fUniformHandler->addUniformArray(
cdalton5e58cee2016-02-11 12:49:47 -0800264 kFragment_GrShaderFlag,
bsalomonf267c1e2016-02-01 13:16:14 -0800265 kVec4f_GrSLType, kDefault_GrSLPrecision,
266 "RGBToUV", 2, &uniName);
267 fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s[0].rgb) + %s[0].a,"
268 "dot(rgbColor.rgb, %s[1].rgb) + %s[1].a,"
269 "0.0,"
270 "rgbColor.a);",
271 args.fOutputColor, uniName, uniName, uniName, uniName);
272 break;
273 case kY_OutputChannels:
274 case kU_OutputChannels:
275 case kV_OutputChannels:
276 fRGBToYUVUni = args.fUniformHandler->addUniform(
cdalton5e58cee2016-02-11 12:49:47 -0800277 kFragment_GrShaderFlag,
bsalomonf267c1e2016-02-01 13:16:14 -0800278 kVec4f_GrSLType, kDefault_GrSLPrecision,
279 "RGBToYUorV", &uniName);
280 fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s.rgb) + %s.a);\n",
281 args.fOutputColor, uniName, uniName);
282 break;
283 }
284 }
285
286 private:
287 void onSetData(const GrGLSLProgramDataManager& pdman,
288 const GrProcessor& processor) override {
289 const RGBToYUVEffect& effect = processor.cast<RGBToYUVEffect>();
290 OutputChannels oc = effect.outputChannels();
291 if (effect.getColorSpace() != fLastColorSpace || oc != fLastOutputChannels) {
292
293 const float* matrix = nullptr;
294 switch (effect.getColorSpace()) {
295 case kJPEG_SkYUVColorSpace:
296 matrix = kJPEGInverseConversionMatrix;
297 break;
298 case kRec601_SkYUVColorSpace:
299 matrix = kRec601InverseConversionMatrix;
300 break;
301 case kRec709_SkYUVColorSpace:
302 matrix = kRec709InverseConversionMatrix;
303 break;
304 }
305 switch (oc) {
306 case kYUV_OutputChannels:
307 pdman.set4fv(fRGBToYUVUni, 3, matrix);
308 break;
309 case kUV_OutputChannels:
310 pdman.set4fv(fRGBToYUVUni, 2, matrix + 4);
311 break;
312 case kY_OutputChannels:
313 pdman.set4fv(fRGBToYUVUni, 1, matrix);
314 break;
315 case kU_OutputChannels:
316 pdman.set4fv(fRGBToYUVUni, 1, matrix + 4);
317 break;
318 case kV_OutputChannels:
319 pdman.set4fv(fRGBToYUVUni, 1, matrix + 8);
320 break;
321 }
322 fLastColorSpace = effect.getColorSpace();
323 }
324 }
325 GrGLSLProgramDataManager::UniformHandle fRGBToYUVUni;
326 int fLastColorSpace;
327 int fLastOutputChannels;
328
329 typedef GrGLSLFragmentProcessor INHERITED;
330 };
331
332private:
333 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillips9cdb9922016-02-03 12:25:40 -0800334 return new GLSLProcessor;
bsalomonf267c1e2016-02-01 13:16:14 -0800335 }
336
337 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
338 // kY, kU, and kV all generate the same code, just upload different coefficients.
339 if (kU_OutputChannels == fOutputChannels || kV_OutputChannels == fOutputChannels) {
340 b->add32(kY_OutputChannels);
341 } else {
342 b->add32(fOutputChannels);
343 }
344 }
345
346 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
347 const RGBToYUVEffect& s = sBase.cast<RGBToYUVEffect>();
348 return fColorSpace == s.getColorSpace() && fOutputChannels == s.outputChannels();
349 }
350
351 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
352 inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput);
353 }
354
355 GrCoordTransform fTransform;
356 GrTextureAccess fAccess;
357 SkYUVColorSpace fColorSpace;
358 OutputChannels fOutputChannels;
359
360 typedef GrFragmentProcessor INHERITED;
361};
362
363}
364
365//////////////////////////////////////////////////////////////////////////////
366
jbaumanb445a572016-06-09 13:24:48 -0700367sk_sp<GrFragmentProcessor> GrYUVEffect::MakeYUVToRGB(GrTexture* yTexture, GrTexture* uTexture,
368 GrTexture* vTexture, const SkISize sizes[3],
369 SkYUVColorSpace colorSpace, bool nv12) {
bsalomonf267c1e2016-02-01 13:16:14 -0800370 SkASSERT(yTexture && uTexture && vTexture && sizes);
jbaumanb445a572016-06-09 13:24:48 -0700371 return YUVtoRGBEffect::Make(yTexture, uTexture, vTexture, sizes, colorSpace, nv12);
bsalomonf267c1e2016-02-01 13:16:14 -0800372}
373
bungeman06ca8ec2016-06-09 08:01:03 -0700374sk_sp<GrFragmentProcessor>
375GrYUVEffect::MakeRGBToYUV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800376 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700377 return sk_sp<GrFragmentProcessor>(
378 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kYUV_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800379}
380
bungeman06ca8ec2016-06-09 08:01:03 -0700381sk_sp<GrFragmentProcessor>
382GrYUVEffect::MakeRGBToY(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800383 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700384 return sk_sp<GrFragmentProcessor>(
385 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kY_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800386}
387
bungeman06ca8ec2016-06-09 08:01:03 -0700388sk_sp<GrFragmentProcessor>
389GrYUVEffect::MakeRGBToUV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800390 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700391 return sk_sp<GrFragmentProcessor>(
392 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kUV_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800393}
394
bungeman06ca8ec2016-06-09 08:01:03 -0700395sk_sp<GrFragmentProcessor>
396GrYUVEffect::MakeRGBToU(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800397 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700398 return sk_sp<GrFragmentProcessor>(
399 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kU_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800400}
401
bungeman06ca8ec2016-06-09 08:01:03 -0700402sk_sp<GrFragmentProcessor>
403GrYUVEffect::MakeRGBToV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
bsalomonf267c1e2016-02-01 13:16:14 -0800404 SkASSERT(rgbFP);
bungeman06ca8ec2016-06-09 08:01:03 -0700405 return sk_sp<GrFragmentProcessor>(
406 new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kV_OutputChannels));
bsalomonf267c1e2016-02-01 13:16:14 -0800407}