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) { 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 92 const char* name() const override { return "YUV to RGB"; } 93 94 SkYUVColorSpace getColorSpace() const { return fColorSpace; } 95 96 class GLSLProcessor : public GrGLSLFragmentProcessor { 97 public: 98 // this class always generates the same code. 99 static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) {} 100 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: 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: 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 163 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { 164 return new GLSLProcessor; 165 } 166 167 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { 168 GLSLProcessor::GenKey(*this, caps, b); 169 } 170 171 bool onIsEqual(const GrFragmentProcessor& sBase) const override { 172 const YUVtoRGBEffect& s = sBase.cast<YUVtoRGBEffect>(); 173 return fColorSpace == s.getColorSpace(); 174 } 175 176 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 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 217 const char* name() const override { return "RGBToYUV"; } 218 219 SkYUVColorSpace getColorSpace() const { return fColorSpace; } 220 221 OutputChannels outputChannels() const { return fOutputChannels; } 222 223 class GLSLProcessor : public GrGLSLFragmentProcessor { 224 public: 225 GLSLProcessor() : fLastColorSpace(-1), fLastOutputChannels(-1) {} 226 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: 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: 319 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { 320 return new GLSLProcessor; 321 } 322 323 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 332 bool onIsEqual(const GrFragmentProcessor& sBase) const override { 333 const RGBToYUVEffect& s = sBase.cast<RGBToYUVEffect>(); 334 return fColorSpace == s.getColorSpace() && fOutputChannels == s.outputChannels(); 335 } 336 337 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* 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* 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* 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* 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* 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* 385 GrYUVEffect::CreateRGBToV(const GrFragmentProcessor* rgbFP, SkYUVColorSpace colorSpace) { 386 SkASSERT(rgbFP); 387 return new RGBToYUVEffect(rgbFP, colorSpace, RGBToYUVEffect::kV_OutputChannels); 388 } 389