OLD | NEW |
---|---|
(Empty) | |
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: | |
65 static GrFragmentProcessor* Create(GrTexture* yTexture, GrTexture* uTexture, | |
66 GrTexture* vTexture, const SkISize sizes[ 3], | |
67 SkYUVColorSpace colorSpace) { | |
robertphillips
2016/01/29 20:33:13
Don't all the 'sizes' need to be the same in this
bsalomon
2016/02/01 20:27:45
Most of these comments are about YUVtoRGBEffect. I
| |
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, uvFil terMode, | |
89 colorSpace); | |
90 } | |
91 | |
92 const char* name() const override { return "YUV to RGB"; } | |
93 | |
94 SkYUVColorSpace getColorSpace() const { | |
robertphillips
2016/01/29 20:33:13
1 line ?
bsalomon
2016/02/01 20:27:45
Done.
| |
95 return fColorSpace; | |
96 } | |
97 | |
98 class GLSLProcessor : public GrGLSLFragmentProcessor { | |
99 public: | |
100 // this class always generates the same code. | |
101 static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKey Builder*) {} | |
102 | |
103 GLSLProcessor(const GrProcessor&) {} | |
104 | |
robertphillips
2016/01/29 20:33:13
rm virtual ?
bsalomon
2016/02/01 20:27:45
Done.
| |
105 virtual void emitCode(EmitArgs& args) override { | |
106 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; | |
107 | |
robertphillips
2016/01/29 20:33:13
yuvMatrix -> colorSpaceMat ?
bsalomon
2016/02/01 20:27:45
Done.
| |
108 const char* yuvMatrix = nullptr; | |
109 fMatrixUni = args.fUniformHandler->addUniform( | |
110 GrGLSLUniformHandler::k Fragment_Visibility, | |
111 kMat44f_GrSLType, kDefa ult_GrSLPrecision, | |
112 "YUVMatrix", &yuvMatrix ); | |
robertphillips
2016/01/29 20:33:13
rm formatting control characters ?
bsalomon
2016/02/01 20:27:45
Done.
| |
113 fragBuilder->codeAppendf("\t%s = vec4(\n\t\t", args.fOutputColor); | |
114 fragBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0]. c_str(), | |
115 args.fCoords[0].getType()); | |
116 fragBuilder->codeAppend(".r,\n\t\t"); | |
117 fragBuilder->appendTextureLookup(args.fSamplers[1], args.fCoords[1]. c_str(), | |
118 args.fCoords[1].getType()); | |
119 fragBuilder->codeAppend(".r,\n\t\t"); | |
120 fragBuilder->appendTextureLookup(args.fSamplers[2], args.fCoords[2]. c_str(), | |
121 args.fCoords[2].getType()); | |
122 fragBuilder->codeAppendf(".r,\n\t\t1.0) * %s;\n", yuvMatrix); | |
123 } | |
124 | |
125 protected: | |
robertphillips
2016/01/29 20:33:13
rm virtual ?
bsalomon
2016/02/01 20:27:45
Done.
| |
126 virtual void onSetData(const GrGLSLProgramDataManager& pdman, | |
127 const GrProcessor& processor) override { | |
128 const YUVtoRGBEffect& yuvEffect = processor.cast<YUVtoRGBEffect>(); | |
129 switch (yuvEffect.getColorSpace()) { | |
130 case kJPEG_SkYUVColorSpace: | |
131 pdman.setMatrix4f(fMatrixUni, kJPEGConversionMatrix); | |
132 break; | |
133 case kRec601_SkYUVColorSpace: | |
134 pdman.setMatrix4f(fMatrixUni, kRec601ConversionMatrix); | |
135 break; | |
136 case kRec709_SkYUVColorSpace: | |
137 pdman.setMatrix4f(fMatrixUni, kRec709ConversionMatrix); | |
138 break; | |
139 } | |
140 } | |
141 | |
142 private: | |
143 GrGLSLProgramDataManager::UniformHandle fMatrixUni; | |
144 | |
145 typedef GrGLSLFragmentProcessor INHERITED; | |
146 }; | |
147 | |
148 private: | |
149 YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture , | |
150 const SkMatrix yuvMatrix[3], GrTextureParams::FilterMode uvFi lterMode, | |
151 SkYUVColorSpace colorSpace) | |
152 : fYTransform(kLocal_GrCoordSet, yuvMatrix[0], yTexture, GrTextureParams::kN one_FilterMode) | |
153 , fYAccess(yTexture) | |
154 , fUTransform(kLocal_GrCoordSet, yuvMatrix[1], uTexture, uvFilterMode) | |
155 , fUAccess(uTexture, uvFilterMode) | |
156 , fVTransform(kLocal_GrCoordSet, yuvMatrix[2], vTexture, uvFilterMode) | |
157 , fVAccess(vTexture, uvFilterMode) | |
158 , fColorSpace(colorSpace) { | |
159 this->initClassID<YUVtoRGBEffect>(); | |
160 this->addCoordTransform(&fYTransform); | |
161 this->addTextureAccess(&fYAccess); | |
162 this->addCoordTransform(&fUTransform); | |
163 this->addTextureAccess(&fUAccess); | |
164 this->addCoordTransform(&fVTransform); | |
165 this->addTextureAccess(&fVAccess); | |
166 } | |
167 | |
168 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { | |
169 return new GLSLProcessor(*this); | |
170 } | |
171 | |
robertphillips
2016/01/29 20:33:13
rm virtual ?
bsalomon
2016/02/01 20:27:45
Done.
| |
172 virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, | |
173 GrProcessorKeyBuilder* b) const override { | |
174 GLSLProcessor::GenKey(*this, caps, b); | |
175 } | |
176 | |
177 bool onIsEqual(const GrFragmentProcessor& sBase) const override { | |
178 const YUVtoRGBEffect& s = sBase.cast<YUVtoRGBEffect>(); | |
179 return fColorSpace == s.getColorSpace(); | |
180 } | |
181 | |
182 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { | |
183 // YUV is opaque | |
184 inout->setToOther(kA_GrColorComponentFlag, 0xFF << GrColor_SHIFT_A, | |
185 GrInvariantOutput::kWillNot_ReadInput); | |
186 } | |
187 | |
188 GrCoordTransform fYTransform; | |
189 GrTextureAccess fYAccess; | |
190 GrCoordTransform fUTransform; | |
191 GrTextureAccess fUAccess; | |
192 GrCoordTransform fVTransform; | |
193 GrTextureAccess fVAccess; | |
194 SkYUVColorSpace fColorSpace; | |
195 | |
196 typedef GrFragmentProcessor INHERITED; | |
197 }; | |
198 | |
199 | |
200 class RGBToYUVEffect : public GrFragmentProcessor { | |
201 public: | |
202 enum OutputChannels { | |
203 // output color r = y, g = u, b = v, a = a | |
204 kYUV_OutputChannels, | |
205 // output color rgba = y | |
206 kY_OutputChannels, | |
207 // output color r = u, g = v, b = 0, a = a | |
208 kUV_OutputChannels, | |
209 // output color rgba = u | |
210 kU_OutputChannels, | |
211 // output color rgba = v | |
212 kV_OutputChannels | |
213 }; | |
214 | |
215 RGBToYUVEffect(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colorSpace, | |
216 OutputChannels output) | |
217 : fColorSpace(colorSpace) | |
218 , fOutputChannels(output) { | |
219 this->initClassID<RGBToYUVEffect>(); | |
220 this->registerChildProcessor(rgbFP); | |
221 } | |
222 | |
223 const char* name() const override { return "RGBToYUV"; } | |
224 | |
225 SkYUVColorSpace getColorSpace() const { return fColorSpace; } | |
226 | |
227 OutputChannels outputChannels() const { return fOutputChannels; } | |
228 | |
229 class GLSLProcessor : public GrGLSLFragmentProcessor { | |
230 public: | |
231 GLSLProcessor(const GrProcessor&) : fLastColorSpace(-1), fLastOutputChan nels(-1) {} | |
232 | |
robertphillips
2016/01/29 20:33:13
rm virtual ?
bsalomon
2016/02/01 20:27:45
Done.
| |
233 virtual void emitCode(EmitArgs& args) override { | |
234 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; | |
235 OutputChannels oc = args.fFp.cast<RGBToYUVEffect>().outputChannels() ; | |
236 | |
237 SkString outputColor("rgbColor"); | |
238 this->emitChild(0, args.fInputColor, &outputColor, args); | |
239 | |
240 const char* uniName; | |
241 switch (oc) { | |
242 case kYUV_OutputChannels: | |
243 fRGBToYUVUni = args.fUniformHandler->addUniformArray( | |
244 GrGLSLUniformHandler::kFragment_Visibility, | |
245 kVec4f_GrSLType, kDefault_GrSLPrecision, | |
246 "RGBToYUV", 3, &uniName); | |
247 fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s[0]. rgb) + %s[0].a," | |
248 "dot(rgbColor.rgb, %s[1]. rgb) + %s[1].a," | |
249 "dot(rgbColor.rgb, %s[2]. rgb) + %s[2].a," | |
250 "rgbColor.a);", | |
251 args.fOutputColor, uniName, uniName , uniName, uniName, | |
252 uniName, uniName); | |
253 break; | |
254 case kUV_OutputChannels: | |
255 fRGBToYUVUni = args.fUniformHandler->addUniformArray( | |
256 GrGLSLUniformHandler::kFragment_Visibility, | |
257 kVec4f_GrSLType, kDefault_GrSLPrecision, | |
258 "RGBToUV", 2, &uniName); | |
259 fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s[0]. rgb) + %s[0].a," | |
260 "dot(rgbColor.rgb, %s[1]. rgb) + %s[1].a," | |
261 "0.0," | |
262 "rgbColor.a);", | |
263 args.fOutputColor, uniName, uniName , uniName, uniName); | |
264 break; | |
265 case kY_OutputChannels: | |
266 case kU_OutputChannels: | |
267 case kV_OutputChannels: | |
268 fRGBToYUVUni = args.fUniformHandler->addUniform( | |
269 GrGLSLUniformHandler::kFragment_Visibility, | |
270 kVec4f_GrSLType, kDefault_GrSLPrecision, | |
271 "RGBToYUorV", &uniName); | |
272 fragBuilder->codeAppendf("%s = vec4(dot(rgbColor.rgb, %s.rgb ) + %s.a);\n", | |
273 args.fOutputColor, uniName, uniName ); | |
274 break; | |
275 } | |
276 } | |
277 | |
278 private: | |
279 void onSetData(const GrGLSLProgramDataManager& pdman, | |
280 const GrProcessor& processor) override { | |
281 const RGBToYUVEffect& effect = processor.cast<RGBToYUVEffect>(); | |
282 OutputChannels oc = effect.outputChannels(); | |
283 if (effect.getColorSpace() != fLastColorSpace || oc != fLastOutputCh annels) { | |
284 | |
285 const float* matrix = nullptr; | |
286 switch (effect.getColorSpace()) { | |
287 case kJPEG_SkYUVColorSpace: | |
288 matrix = kJPEGInverseConversionMatrix; | |
289 break; | |
290 case kRec601_SkYUVColorSpace: | |
291 matrix = kRec601InverseConversionMatrix; | |
292 break; | |
293 case kRec709_SkYUVColorSpace: | |
294 matrix = kRec709InverseConversionMatrix; | |
295 break; | |
296 } | |
297 switch (oc) { | |
298 case kYUV_OutputChannels: | |
299 pdman.set4fv(fRGBToYUVUni, 3, matrix); | |
300 break; | |
301 case kUV_OutputChannels: | |
302 pdman.set4fv(fRGBToYUVUni, 2, matrix + 4); | |
303 break; | |
304 case kY_OutputChannels: | |
305 pdman.set4fv(fRGBToYUVUni, 1, matrix); | |
306 break; | |
307 case kU_OutputChannels: | |
308 pdman.set4fv(fRGBToYUVUni, 1, matrix + 4); | |
309 break; | |
310 case kV_OutputChannels: | |
311 pdman.set4fv(fRGBToYUVUni, 1, matrix + 8); | |
312 break; | |
313 } | |
314 fLastColorSpace = effect.getColorSpace(); | |
315 } | |
316 } | |
317 GrGLSLProgramDataManager::UniformHandle fRGBToYUVUni; | |
318 int fLastColorSpace; | |
319 int fLastOutputChannels; | |
320 | |
321 typedef GrGLSLFragmentProcessor INHERITED; | |
322 }; | |
323 | |
324 private: | |
325 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { | |
326 return new GLSLProcessor(*this); | |
327 } | |
328 | |
329 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { | |
330 // kY, kU, and kV all generate the same code, just upload different coef ficients. | |
331 if (kU_OutputChannels == fOutputChannels || kV_OutputChannels == fOutput Channels) { | |
332 b->add32(kY_OutputChannels); | |
333 } else { | |
334 b->add32(fOutputChannels); | |
335 } | |
336 } | |
337 | |
338 bool onIsEqual(const GrFragmentProcessor& sBase) const override { | |
339 const RGBToYUVEffect& s = sBase.cast<RGBToYUVEffect>(); | |
340 return fColorSpace == s.getColorSpace() && fOutputChannels == s.outputCh annels(); | |
341 } | |
342 | |
343 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { | |
344 inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput); | |
345 } | |
346 | |
347 GrCoordTransform fTransform; | |
348 GrTextureAccess fAccess; | |
349 SkYUVColorSpace fColorSpace; | |
350 OutputChannels fOutputChannels; | |
351 | |
352 typedef GrFragmentProcessor INHERITED; | |
353 }; | |
354 | |
355 } | |
356 | |
357 ////////////////////////////////////////////////////////////////////////////// | |
358 | |
359 const GrFragmentProcessor* | |
360 GrYUVEffect::CreateYUVToRGB(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture, | |
361 const SkISize sizes[3], SkYUVColorSpace colorSpace) { | |
362 SkASSERT(yTexture && uTexture && vTexture && sizes); | |
363 return YUVtoRGBEffect::Create(yTexture, uTexture, vTexture, sizes, colorSpac e); | |
364 } | |
365 | |
366 const GrFragmentProcessor* | |
367 GrYUVEffect::CreateRGBToYUV(const GrFragmentProcessor* rgbFP, SkYUVColorSpace co lorSpace) { | |
368 SkASSERT(rgbFP); | |
369 return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kYUV_OutputChan nels); | |
370 } | |
371 | |
372 const GrFragmentProcessor* | |
373 GrYUVEffect::CreateRGBToY(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colo rSpace) { | |
374 SkASSERT(rgbFP); | |
375 return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kY_OutputChanne ls); | |
376 } | |
377 | |
378 const GrFragmentProcessor* | |
379 GrYUVEffect::CreateRGBToUV(const GrFragmentProcessor* rgbFP, SkYUVColorSpace col orSpace) { | |
380 SkASSERT(rgbFP); | |
381 return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kUV_OutputChann els); | |
382 } | |
383 | |
384 const GrFragmentProcessor* | |
385 GrYUVEffect::CreateRGBToU(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colo rSpace) { | |
386 SkASSERT(rgbFP); | |
387 return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kU_OutputChanne ls); | |
388 } | |
389 | |
390 const GrFragmentProcessor* | |
391 GrYUVEffect::CreateRGBToV(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colo rSpace) { | |
392 SkASSERT(rgbFP); | |
393 return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kV_OutputChanne ls); | |
394 } | |
OLD | NEW |