1 /* 2 * Copyright 2018 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 "GrYUVtoRGBEffect.h" 9 10 static const float kJPEGConversionMatrix[16] = { 11 1.0f, 0.0f, 1.402f, -0.703749f, 12 1.0f, -0.344136f, -0.714136f, 0.531211f, 13 1.0f, 1.772f, 0.0f, -0.889475f, 14 0.0f, 0.0f, 0.0f, 1.0 15 }; 16 17 static const float kRec601ConversionMatrix[16] = { 18 1.164f, 0.0f, 1.596f, -0.87075f, 19 1.164f, -0.391f, -0.813f, 0.52925f, 20 1.164f, 2.018f, 0.0f, -1.08175f, 21 0.0f, 0.0f, 0.0f, 1.0 22 }; 23 24 static const float kRec709ConversionMatrix[16] = { 25 1.164f, 0.0f, 1.793f, -0.96925f, 26 1.164f, -0.213f, -0.533f, 0.30025f, 27 1.164f, 2.112f, 0.0f, -1.12875f, 28 0.0f, 0.0f, 0.0f, 1.0f 29 }; 30 31 std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const sk_sp<GrTextureProxy> proxies[], 32 const SkYUVAIndex yuvaIndices[4], 33 SkYUVColorSpace yuvColorSpace, 34 GrSamplerState::Filter filterMode) { 35 int numPlanes; 36 SkAssertResult(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes)); 37 38 const SkISize YSize = proxies[yuvaIndices[SkYUVAIndex::kY_Index].fIndex]->isize(); 39 40 GrSamplerState::Filter minimizeFilterMode = GrSamplerState::Filter::kMipMap == filterMode ? 41 GrSamplerState::Filter::kMipMap : 42 GrSamplerState::Filter::kBilerp; 43 44 GrSamplerState::Filter filterModes[4]; 45 SkSize scales[4]; 46 for (int i = 0; i < numPlanes; ++i) { 47 SkISize size = proxies[i]->isize(); 48 scales[i] = SkSize::Make(SkIntToScalar(size.width()) / SkIntToScalar(YSize.width()), 49 SkIntToScalar(size.height()) / SkIntToScalar(YSize.height())); 50 filterModes[i] = (size == YSize) ? filterMode : minimizeFilterMode; 51 } 52 53 SkMatrix44 mat; 54 switch (yuvColorSpace) { 55 case kJPEG_SkYUVColorSpace: 56 mat.setColMajorf(kJPEGConversionMatrix); 57 break; 58 case kRec601_SkYUVColorSpace: 59 mat.setColMajorf(kRec601ConversionMatrix); 60 break; 61 case kRec709_SkYUVColorSpace: 62 mat.setColMajorf(kRec709ConversionMatrix); 63 break; 64 } 65 return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect( 66 proxies, scales, filterModes, numPlanes, yuvaIndices, mat)); 67 } 68 69 #ifdef SK_DEBUG 70 SkString GrYUVtoRGBEffect::dumpInfo() const { 71 SkString str; 72 for (int i = 0; i < this->numTextureSamplers(); ++i) { 73 str.appendf("%d: %d %d ", i, 74 this->textureSampler(i).proxy()->uniqueID().asUInt(), 75 this->textureSampler(i).proxy()->underlyingUniqueID().asUInt()); 76 } 77 str.appendf("\n"); 78 79 return str; 80 } 81 #endif 82 83 #include "glsl/GrGLSLFragmentProcessor.h" 84 #include "glsl/GrGLSLFragmentShaderBuilder.h" 85 #include "glsl/GrGLSLProgramBuilder.h" 86 #include "GrTexture.h" 87 #include "SkSLCPP.h" 88 #include "SkSLUtil.h" 89 class GrGLSLYUVtoRGBEffect : public GrGLSLFragmentProcessor { 90 public: 91 GrGLSLYUVtoRGBEffect() {} 92 void emitCode(EmitArgs& args) override { 93 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 94 const GrYUVtoRGBEffect& _outer = args.fFp.cast<GrYUVtoRGBEffect>(); 95 (void)_outer; 96 97 auto colorSpaceMatrix = _outer.colorSpaceMatrix(); 98 (void)colorSpaceMatrix; 99 fColorSpaceMatrixVar = 100 args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4x4_GrSLType, 101 kDefault_GrSLPrecision, "colorSpaceMatrix"); 102 103 int numSamplers = args.fTexSamplers.count(); 104 105 SkString coords[4]; 106 for (int i = 0; i < numSamplers; ++i) { 107 coords[i] = fragBuilder->ensureCoords2D(args.fTransformedCoords[i]); 108 } 109 110 for (int i = 0; i < numSamplers; ++i) { 111 fragBuilder->codeAppendf( 112 "half4 tmp%d = texture(%s, %s).%s;", 113 i, 114 fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[i]).c_str(), 115 coords[i].c_str(), 116 fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[i]).c_str()); 117 } 118 119 static const char kChannelToChar[4] = { 'x', 'y', 'z', 'w' }; 120 121 fragBuilder->codeAppendf( 122 "half4 yuvOne = half4(tmp%d.%c, tmp%d.%c, tmp%d.%c, 1.0) * %s;", 123 _outer.yuvaIndex(0).fIndex, kChannelToChar[(int)_outer.yuvaIndex(0).fChannel], 124 _outer.yuvaIndex(1).fIndex, kChannelToChar[(int)_outer.yuvaIndex(1).fChannel], 125 _outer.yuvaIndex(2).fIndex, kChannelToChar[(int)_outer.yuvaIndex(2).fChannel], 126 args.fUniformHandler->getUniformCStr(fColorSpaceMatrixVar)); 127 128 129 if (_outer.yuvaIndex(3).fIndex >= 0) { 130 fragBuilder->codeAppendf( 131 "float a = tmp%d.%c;", _outer.yuvaIndex(3).fIndex, 132 kChannelToChar[(int)_outer.yuvaIndex(3).fChannel]); 133 // premultiply alpha 134 fragBuilder->codeAppend("yuvOne *= a;"); 135 } else { 136 fragBuilder->codeAppendf("float a = 1.0;"); 137 } 138 139 fragBuilder->codeAppendf("%s = half4(yuvOne.xyz, a);", args.fOutputColor); 140 } 141 142 private: 143 void onSetData(const GrGLSLProgramDataManager& pdman, 144 const GrFragmentProcessor& _proc) override { 145 const GrYUVtoRGBEffect& _outer = _proc.cast<GrYUVtoRGBEffect>(); 146 { pdman.setSkMatrix44(fColorSpaceMatrixVar, (_outer.colorSpaceMatrix())); } 147 } 148 UniformHandle fColorSpaceMatrixVar; 149 }; 150 GrGLSLFragmentProcessor* GrYUVtoRGBEffect::onCreateGLSLInstance() const { 151 return new GrGLSLYUVtoRGBEffect(); 152 } 153 void GrYUVtoRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, 154 GrProcessorKeyBuilder* b) const { 155 b->add32(this->numTextureSamplers()); 156 157 uint32_t packed = 0; 158 for (int i = 0; i < 4; ++i) { 159 if (this->yuvaIndex(i).fIndex < 0) { 160 continue; 161 } 162 163 uint8_t index = this->yuvaIndex(i).fIndex; 164 uint8_t chann = (uint8_t) this->yuvaIndex(i).fChannel; 165 166 SkASSERT(index < 4 && chann < 4); 167 168 packed |= (index | (chann << 2)) << (i * 4); 169 } 170 b->add32(packed); 171 } 172 bool GrYUVtoRGBEffect::onIsEqual(const GrFragmentProcessor& other) const { 173 const GrYUVtoRGBEffect& that = other.cast<GrYUVtoRGBEffect>(); 174 175 for (int i = 0; i < 4; ++i) { 176 if (fYUVAIndices[i] != that.fYUVAIndices[i]) { 177 return false; 178 } 179 } 180 181 for (int i = 0; i < this->numTextureSamplers(); ++i) { 182 // 'fSamplers' is checked by the base class 183 if (fSamplerTransforms[i] != that.fSamplerTransforms[i]) { 184 return false; 185 } 186 } 187 188 if (fColorSpaceMatrix != that.fColorSpaceMatrix) { 189 return false; 190 } 191 192 return true; 193 } 194 GrYUVtoRGBEffect::GrYUVtoRGBEffect(const GrYUVtoRGBEffect& src) 195 : INHERITED(kGrYUVtoRGBEffect_ClassID, src.optimizationFlags()) 196 , fColorSpaceMatrix(src.fColorSpaceMatrix) { 197 int numPlanes = src.numTextureSamplers(); 198 for (int i = 0; i < numPlanes; ++i) { 199 fSamplers[i].reset(sk_ref_sp(src.fSamplers[i].proxy()), src.fSamplers[i].samplerState()); 200 fSamplerTransforms[i] = src.fSamplerTransforms[i]; 201 fSamplerCoordTransforms[i] = src.fSamplerCoordTransforms[i]; 202 } 203 204 this->setTextureSamplerCnt(numPlanes); 205 for (int i = 0; i < numPlanes; ++i) { 206 this->addCoordTransform(&fSamplerCoordTransforms[i]); 207 } 208 209 memcpy(fYUVAIndices, src.fYUVAIndices, sizeof(fYUVAIndices)); 210 } 211 std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::clone() const { 212 return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(*this)); 213 } 214 const GrFragmentProcessor::TextureSampler& GrYUVtoRGBEffect::onTextureSampler(int index) const { 215 SkASSERT(index < this->numTextureSamplers()); 216 return fSamplers[index]; 217 } 218