Line data Source code
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 0 : class YUVtoRGBEffect : public GrFragmentProcessor {
64 : public:
65 0 : 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 0 : w[0] = SkIntToScalar(sizes[0].fWidth);
72 0 : h[0] = SkIntToScalar(sizes[0].fHeight);
73 0 : w[1] = SkIntToScalar(sizes[1].fWidth);
74 0 : h[1] = SkIntToScalar(sizes[1].fHeight);
75 0 : w[2] = SkIntToScalar(sizes[2].fWidth);
76 0 : h[2] = SkIntToScalar(sizes[2].fHeight);
77 : const SkMatrix yuvMatrix[3] = {
78 0 : SkMatrix::I(),
79 0 : SkMatrix::MakeScale(w[1] / w[0], h[1] / h[0]),
80 0 : SkMatrix::MakeScale(w[2] / w[0], h[2] / h[0])
81 0 : };
82 : GrSamplerParams::FilterMode uvFilterMode =
83 0 : ((sizes[1].fWidth != sizes[0].fWidth) ||
84 0 : (sizes[1].fHeight != sizes[0].fHeight) ||
85 0 : (sizes[2].fWidth != sizes[0].fWidth) ||
86 0 : (sizes[2].fHeight != sizes[0].fHeight)) ?
87 : GrSamplerParams::kBilerp_FilterMode :
88 0 : GrSamplerParams::kNone_FilterMode;
89 : return sk_sp<GrFragmentProcessor>(new YUVtoRGBEffect(
90 0 : resourceProvider, std::move(yProxy), std::move(uProxy), std::move(vProxy),
91 0 : yuvMatrix, uvFilterMode, colorSpace, nv12));
92 : }
93 :
94 0 : const char* name() const override { return "YUV to RGB"; }
95 :
96 0 : SkYUVColorSpace getColorSpace() const { return fColorSpace; }
97 :
98 0 : bool isNV12() const {
99 0 : return fNV12;
100 : }
101 :
102 0 : class GLSLProcessor : public GrGLSLFragmentProcessor {
103 : public:
104 0 : void emitCode(EmitArgs& args) override {
105 0 : GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
106 0 : const YUVtoRGBEffect& effect = args.fFp.cast<YUVtoRGBEffect>();
107 :
108 0 : const char* colorSpaceMatrix = nullptr;
109 0 : fMatrixUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
110 : kMat44f_GrSLType, kDefault_GrSLPrecision,
111 0 : "ColorSpaceMatrix", &colorSpaceMatrix);
112 0 : fragBuilder->codeAppendf("%s = vec4(", args.fOutputColor);
113 0 : fragBuilder->appendTextureLookup(args.fTexSamplers[0],
114 0 : args.fTransformedCoords[0].c_str(),
115 0 : args.fTransformedCoords[0].getType());
116 0 : fragBuilder->codeAppend(".r,");
117 0 : fragBuilder->appendTextureLookup(args.fTexSamplers[1],
118 0 : args.fTransformedCoords[1].c_str(),
119 0 : args.fTransformedCoords[1].getType());
120 0 : if (effect.fNV12) {
121 0 : fragBuilder->codeAppendf(".rg,");
122 : } else {
123 0 : fragBuilder->codeAppend(".r,");
124 0 : fragBuilder->appendTextureLookup(args.fTexSamplers[2],
125 0 : args.fTransformedCoords[2].c_str(),
126 0 : args.fTransformedCoords[2].getType());
127 0 : fragBuilder->codeAppendf(".g,");
128 : }
129 0 : fragBuilder->codeAppendf("1.0) * %s;", colorSpaceMatrix);
130 0 : }
131 :
132 : protected:
133 0 : void onSetData(const GrGLSLProgramDataManager& pdman,
134 : const GrFragmentProcessor& processor) override {
135 0 : const YUVtoRGBEffect& yuvEffect = processor.cast<YUVtoRGBEffect>();
136 0 : switch (yuvEffect.getColorSpace()) {
137 : case kJPEG_SkYUVColorSpace:
138 0 : pdman.setMatrix4f(fMatrixUni, kJPEGConversionMatrix);
139 0 : break;
140 : case kRec601_SkYUVColorSpace:
141 0 : pdman.setMatrix4f(fMatrixUni, kRec601ConversionMatrix);
142 0 : break;
143 : case kRec709_SkYUVColorSpace:
144 0 : pdman.setMatrix4f(fMatrixUni, kRec709ConversionMatrix);
145 0 : break;
146 : }
147 0 : }
148 :
149 : private:
150 : GrGLSLProgramDataManager::UniformHandle fMatrixUni;
151 :
152 : typedef GrGLSLFragmentProcessor INHERITED;
153 : };
154 :
155 : private:
156 0 : 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 0 : : INHERITED(kPreservesOpaqueInput_OptimizationFlag)
161 : , fYTransform(resourceProvider, yuvMatrix[0], yProxy.get())
162 0 : , fYSampler(resourceProvider, std::move(yProxy))
163 0 : , fUTransform(resourceProvider, yuvMatrix[1], uProxy.get())
164 0 : , fUSampler(resourceProvider, std::move(uProxy), uvFilterMode)
165 : , fVSampler(resourceProvider, vProxy, uvFilterMode)
166 : , fColorSpace(colorSpace)
167 0 : , fNV12(nv12) {
168 0 : this->initClassID<YUVtoRGBEffect>();
169 0 : this->addCoordTransform(&fYTransform);
170 0 : this->addTextureSampler(&fYSampler);
171 0 : this->addCoordTransform(&fUTransform);
172 0 : this->addTextureSampler(&fUSampler);
173 0 : if (!fNV12) {
174 0 : fVTransform = GrCoordTransform(resourceProvider, yuvMatrix[2], vProxy.get());
175 0 : this->addCoordTransform(&fVTransform);
176 0 : this->addTextureSampler(&fVSampler);
177 : }
178 0 : }
179 :
180 0 : GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
181 0 : return new GLSLProcessor;
182 : }
183 :
184 0 : void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
185 0 : b->add32(fNV12);
186 0 : }
187 :
188 0 : bool onIsEqual(const GrFragmentProcessor& sBase) const override {
189 0 : const YUVtoRGBEffect& s = sBase.cast<YUVtoRGBEffect>();
190 0 : return (fColorSpace == s.getColorSpace()) && (fNV12 == s.isNV12());
191 : }
192 :
193 : GrCoordTransform fYTransform;
194 : TextureSampler fYSampler;
195 : GrCoordTransform fUTransform;
196 : TextureSampler fUSampler;
197 : GrCoordTransform fVTransform;
198 : TextureSampler fVSampler;
199 : SkYUVColorSpace fColorSpace;
200 : bool fNV12;
201 :
202 : typedef GrFragmentProcessor INHERITED;
203 : };
204 :
205 :
206 0 : class RGBToYUVEffect : public GrFragmentProcessor {
207 : public:
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 :
221 0 : RGBToYUVEffect(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace,
222 : OutputChannels output)
223 : // This could advertise kConstantOutputForConstantInput, but doesn't seem useful.
224 0 : : INHERITED(kPreservesOpaqueInput_OptimizationFlag)
225 : , fColorSpace(colorSpace)
226 0 : , fOutputChannels(output) {
227 0 : this->initClassID<RGBToYUVEffect>();
228 0 : this->registerChildProcessor(std::move(rgbFP));
229 0 : }
230 :
231 0 : const char* name() const override { return "RGBToYUV"; }
232 :
233 0 : SkYUVColorSpace getColorSpace() const { return fColorSpace; }
234 :
235 0 : OutputChannels outputChannels() const { return fOutputChannels; }
236 :
237 0 : class GLSLProcessor : public GrGLSLFragmentProcessor {
238 : public:
239 0 : GLSLProcessor() : fLastColorSpace(-1), fLastOutputChannels(-1) {}
240 :
241 0 : void emitCode(EmitArgs& args) override {
242 0 : GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
243 0 : OutputChannels oc = args.fFp.cast<RGBToYUVEffect>().outputChannels();
244 :
245 0 : SkString outputColor("rgbColor");
246 0 : this->emitChild(0, args.fInputColor, &outputColor, args);
247 :
248 : const char* uniName;
249 0 : switch (oc) {
250 : case kYUV_OutputChannels:
251 0 : fRGBToYUVUni = args.fUniformHandler->addUniformArray(
252 : kFragment_GrShaderFlag,
253 : kVec4f_GrSLType, kDefault_GrSLPrecision,
254 0 : "RGBToYUV", 3, &uniName);
255 0 : 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 0 : uniName, uniName);
261 0 : break;
262 : case kUV_OutputChannels:
263 0 : fRGBToYUVUni = args.fUniformHandler->addUniformArray(
264 : kFragment_GrShaderFlag,
265 : kVec4f_GrSLType, kDefault_GrSLPrecision,
266 0 : "RGBToUV", 2, &uniName);
267 0 : 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 0 : args.fOutputColor, uniName, uniName, uniName, uniName);
272 0 : break;
273 : case kY_OutputChannels:
274 : case kU_OutputChannels:
275 : case kV_OutputChannels:
276 0 : fRGBToYUVUni = args.fUniformHandler->addUniform(
277 : kFragment_GrShaderFlag,
278 : kVec4f_GrSLType, kDefault_GrSLPrecision,
279 0 : "RGBToYUorV", &uniName);
280 0 : fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s.rgb) + %s.a);\n",
281 0 : args.fOutputColor, uniName, uniName);
282 0 : break;
283 : }
284 0 : }
285 :
286 : private:
287 0 : void onSetData(const GrGLSLProgramDataManager& pdman,
288 : const GrFragmentProcessor& processor) override {
289 0 : const RGBToYUVEffect& effect = processor.cast<RGBToYUVEffect>();
290 0 : OutputChannels oc = effect.outputChannels();
291 0 : if (effect.getColorSpace() != fLastColorSpace || oc != fLastOutputChannels) {
292 :
293 0 : const float* matrix = nullptr;
294 0 : switch (effect.getColorSpace()) {
295 : case kJPEG_SkYUVColorSpace:
296 0 : matrix = kJPEGInverseConversionMatrix;
297 0 : break;
298 : case kRec601_SkYUVColorSpace:
299 0 : matrix = kRec601InverseConversionMatrix;
300 0 : break;
301 : case kRec709_SkYUVColorSpace:
302 0 : matrix = kRec709InverseConversionMatrix;
303 0 : break;
304 : }
305 0 : switch (oc) {
306 : case kYUV_OutputChannels:
307 0 : pdman.set4fv(fRGBToYUVUni, 3, matrix);
308 0 : break;
309 : case kUV_OutputChannels:
310 0 : pdman.set4fv(fRGBToYUVUni, 2, matrix + 4);
311 0 : break;
312 : case kY_OutputChannels:
313 0 : pdman.set4fv(fRGBToYUVUni, 1, matrix);
314 0 : break;
315 : case kU_OutputChannels:
316 0 : pdman.set4fv(fRGBToYUVUni, 1, matrix + 4);
317 0 : break;
318 : case kV_OutputChannels:
319 0 : pdman.set4fv(fRGBToYUVUni, 1, matrix + 8);
320 0 : break;
321 : }
322 0 : fLastColorSpace = effect.getColorSpace();
323 : }
324 0 : }
325 : GrGLSLProgramDataManager::UniformHandle fRGBToYUVUni;
326 : int fLastColorSpace;
327 : int fLastOutputChannels;
328 :
329 : typedef GrGLSLFragmentProcessor INHERITED;
330 : };
331 :
332 : private:
333 0 : GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
334 0 : return new GLSLProcessor;
335 : }
336 :
337 0 : void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
338 : // kY, kU, and kV all generate the same code, just upload different coefficients.
339 0 : if (kU_OutputChannels == fOutputChannels || kV_OutputChannels == fOutputChannels) {
340 0 : b->add32(kY_OutputChannels);
341 : } else {
342 0 : b->add32(fOutputChannels);
343 : }
344 0 : }
345 :
346 0 : bool onIsEqual(const GrFragmentProcessor& sBase) const override {
347 0 : const RGBToYUVEffect& s = sBase.cast<RGBToYUVEffect>();
348 0 : return fColorSpace == s.getColorSpace() && fOutputChannels == s.outputChannels();
349 : }
350 :
351 : GrCoordTransform fTransform;
352 : TextureSampler fTextureSampler;
353 : SkYUVColorSpace fColorSpace;
354 : OutputChannels fOutputChannels;
355 :
356 : typedef GrFragmentProcessor INHERITED;
357 : };
358 :
359 : }
360 :
361 : //////////////////////////////////////////////////////////////////////////////
362 :
363 0 : sk_sp<GrFragmentProcessor> GrYUVEffect::MakeYUVToRGB(GrResourceProvider* resourceProvider,
364 : sk_sp<GrTextureProxy> yProxy,
365 : sk_sp<GrTextureProxy> uProxy,
366 : sk_sp<GrTextureProxy> vProxy,
367 : const SkISize sizes[3],
368 : SkYUVColorSpace colorSpace, bool nv12) {
369 0 : SkASSERT(yProxy && uProxy && vProxy && sizes);
370 : return YUVtoRGBEffect::Make(resourceProvider,
371 0 : std::move(yProxy), std::move(uProxy), std::move(vProxy),
372 0 : sizes, colorSpace, nv12);
373 : }
374 :
375 : sk_sp<GrFragmentProcessor>
376 0 : GrYUVEffect::MakeRGBToYUV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
377 0 : SkASSERT(rgbFP);
378 : return sk_sp<GrFragmentProcessor>(
379 0 : new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kYUV_OutputChannels));
380 : }
381 :
382 : sk_sp<GrFragmentProcessor>
383 0 : GrYUVEffect::MakeRGBToY(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
384 0 : SkASSERT(rgbFP);
385 : return sk_sp<GrFragmentProcessor>(
386 0 : new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kY_OutputChannels));
387 : }
388 :
389 : sk_sp<GrFragmentProcessor>
390 0 : GrYUVEffect::MakeRGBToUV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
391 0 : SkASSERT(rgbFP);
392 : return sk_sp<GrFragmentProcessor>(
393 0 : new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kUV_OutputChannels));
394 : }
395 :
396 : sk_sp<GrFragmentProcessor>
397 0 : GrYUVEffect::MakeRGBToU(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
398 0 : SkASSERT(rgbFP);
399 : return sk_sp<GrFragmentProcessor>(
400 0 : new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kU_OutputChannels));
401 : }
402 :
403 : sk_sp<GrFragmentProcessor>
404 0 : GrYUVEffect::MakeRGBToV(sk_sp<GrFragmentProcessor> rgbFP, SkYUVColorSpace colorSpace) {
405 0 : SkASSERT(rgbFP);
406 : return sk_sp<GrFragmentProcessor>(
407 0 : new RGBToYUVEffect(std::move(rgbFP), colorSpace, RGBToYUVEffect::kV_OutputChannels));
408 : }
|