1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/effects/GrYUVtoRGBEffect.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkYUVAInfo.h" 11cb93a386Sopenharmony_ci#include "src/core/SkYUVMath.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrYUVATextureProxies.h" 14cb93a386Sopenharmony_ci#include "src/gpu/effects/GrMatrixEffect.h" 15cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h" 16cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 17cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramBuilder.h" 18cb93a386Sopenharmony_ci#include "src/sksl/SkSLUtil.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_cistatic void border_colors(const GrYUVATextureProxies& yuvaProxies, float planeBorders[4][4]) { 21cb93a386Sopenharmony_ci float m[20]; 22cb93a386Sopenharmony_ci SkColorMatrix_RGB2YUV(yuvaProxies.yuvaInfo().yuvColorSpace(), m); 23cb93a386Sopenharmony_ci for (int i = 0; i < SkYUVAInfo::kYUVAChannelCount; ++i) { 24cb93a386Sopenharmony_ci auto [plane, channel] = yuvaProxies.yuvaLocations()[i]; 25cb93a386Sopenharmony_ci if (plane == -1) { 26cb93a386Sopenharmony_ci return; 27cb93a386Sopenharmony_ci } 28cb93a386Sopenharmony_ci auto c = static_cast<int>(channel); 29cb93a386Sopenharmony_ci planeBorders[plane][c] = m[i*5 + 4]; 30cb93a386Sopenharmony_ci } 31cb93a386Sopenharmony_ci} 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const GrYUVATextureProxies& yuvaProxies, 34cb93a386Sopenharmony_ci GrSamplerState samplerState, 35cb93a386Sopenharmony_ci const GrCaps& caps, 36cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 37cb93a386Sopenharmony_ci const SkRect* subset, 38cb93a386Sopenharmony_ci const SkRect* domain) { 39cb93a386Sopenharmony_ci SkASSERT(!subset || SkRect::Make(yuvaProxies.yuvaInfo().dimensions()).contains(*subset)); 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci int numPlanes = yuvaProxies.yuvaInfo().numPlanes(); 42cb93a386Sopenharmony_ci if (!yuvaProxies.isValid()) { 43cb93a386Sopenharmony_ci return nullptr; 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci bool usesBorder = samplerState.wrapModeX() == GrSamplerState::WrapMode::kClampToBorder || 47cb93a386Sopenharmony_ci samplerState.wrapModeY() == GrSamplerState::WrapMode::kClampToBorder; 48cb93a386Sopenharmony_ci float planeBorders[4][4] = {}; 49cb93a386Sopenharmony_ci if (usesBorder) { 50cb93a386Sopenharmony_ci border_colors(yuvaProxies, planeBorders); 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci bool snap[2] = {false, false}; 54cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> planeFPs[SkYUVAInfo::kMaxPlanes]; 55cb93a386Sopenharmony_ci for (int i = 0; i < numPlanes; ++i) { 56cb93a386Sopenharmony_ci bool useSubset = SkToBool(subset); 57cb93a386Sopenharmony_ci GrSurfaceProxyView view = yuvaProxies.makeView(i); 58cb93a386Sopenharmony_ci SkMatrix planeMatrix = yuvaProxies.yuvaInfo().originMatrix(); 59cb93a386Sopenharmony_ci // The returned matrix is a view matrix but we need a local matrix. 60cb93a386Sopenharmony_ci SkAssertResult(planeMatrix.invert(&planeMatrix)); 61cb93a386Sopenharmony_ci SkRect planeSubset; 62cb93a386Sopenharmony_ci SkRect planeDomain; 63cb93a386Sopenharmony_ci bool makeLinearWithSnap = false; 64cb93a386Sopenharmony_ci auto [ssx, ssy] = yuvaProxies.yuvaInfo().planeSubsamplingFactors(i); 65cb93a386Sopenharmony_ci SkASSERT(ssx > 0 && ssx <= 4); 66cb93a386Sopenharmony_ci SkASSERT(ssy > 0 && ssy <= 2); 67cb93a386Sopenharmony_ci float scaleX = 1.f; 68cb93a386Sopenharmony_ci float scaleY = 1.f; 69cb93a386Sopenharmony_ci if (ssx > 1 || ssy > 1) { 70cb93a386Sopenharmony_ci scaleX = 1.f/ssx; 71cb93a386Sopenharmony_ci scaleY = 1.f/ssy; 72cb93a386Sopenharmony_ci // We would want to add a translation to this matrix to handle other sitings. 73cb93a386Sopenharmony_ci SkASSERT(yuvaProxies.yuvaInfo().sitingX() == SkYUVAInfo::Siting::kCentered); 74cb93a386Sopenharmony_ci SkASSERT(yuvaProxies.yuvaInfo().sitingY() == SkYUVAInfo::Siting::kCentered); 75cb93a386Sopenharmony_ci planeMatrix.postConcat(SkMatrix::Scale(scaleX, scaleY)); 76cb93a386Sopenharmony_ci if (subset) { 77cb93a386Sopenharmony_ci planeSubset = {subset->fLeft *scaleX, 78cb93a386Sopenharmony_ci subset->fTop *scaleY, 79cb93a386Sopenharmony_ci subset->fRight *scaleX, 80cb93a386Sopenharmony_ci subset->fBottom*scaleY}; 81cb93a386Sopenharmony_ci } else { 82cb93a386Sopenharmony_ci planeSubset = SkRect::Make(view.dimensions()); 83cb93a386Sopenharmony_ci } 84cb93a386Sopenharmony_ci if (domain) { 85cb93a386Sopenharmony_ci planeDomain = {domain->fLeft *scaleX, 86cb93a386Sopenharmony_ci domain->fTop *scaleY, 87cb93a386Sopenharmony_ci domain->fRight *scaleX, 88cb93a386Sopenharmony_ci domain->fBottom*scaleY}; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci // If the image is not a multiple of the subsampling then the subsampled plane needs to 91cb93a386Sopenharmony_ci // be tiled at less than its full width/height. This only matters when the mode is not 92cb93a386Sopenharmony_ci // clamp. 93cb93a386Sopenharmony_ci if (samplerState.wrapModeX() != GrSamplerState::WrapMode::kClamp) { 94cb93a386Sopenharmony_ci int dx = (ssx*view.width() - yuvaProxies.yuvaInfo().width()); 95cb93a386Sopenharmony_ci float maxRight = view.width() - dx*scaleX; 96cb93a386Sopenharmony_ci if (planeSubset.fRight > maxRight) { 97cb93a386Sopenharmony_ci planeSubset.fRight = maxRight; 98cb93a386Sopenharmony_ci useSubset = true; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci if (samplerState.wrapModeY() != GrSamplerState::WrapMode::kClamp) { 102cb93a386Sopenharmony_ci int dy = (ssy*view.height() - yuvaProxies.yuvaInfo().height()); 103cb93a386Sopenharmony_ci float maxBottom = view.height() - dy*scaleY; 104cb93a386Sopenharmony_ci if (planeSubset.fBottom > maxBottom) { 105cb93a386Sopenharmony_ci planeSubset.fBottom = maxBottom; 106cb93a386Sopenharmony_ci useSubset = true; 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci // This promotion of nearest to linear filtering for UV planes exists to mimic 110cb93a386Sopenharmony_ci // libjpeg[-turbo]'s do_fancy_upsampling option. We will filter the subsampled plane, 111cb93a386Sopenharmony_ci // however we want to filter at a fixed point for each logical image pixel to simulate 112cb93a386Sopenharmony_ci // nearest neighbor. 113cb93a386Sopenharmony_ci if (samplerState.filter() == GrSamplerState::Filter::kNearest) { 114cb93a386Sopenharmony_ci bool snapX = (ssx != 1), 115cb93a386Sopenharmony_ci snapY = (ssy != 1); 116cb93a386Sopenharmony_ci makeLinearWithSnap = snapX || snapY; 117cb93a386Sopenharmony_ci snap[0] |= snapX; 118cb93a386Sopenharmony_ci snap[1] |= snapY; 119cb93a386Sopenharmony_ci if (domain) { 120cb93a386Sopenharmony_ci // The outer YUVToRGB effect will ensure sampling happens at pixel centers 121cb93a386Sopenharmony_ci // within this plane. 122cb93a386Sopenharmony_ci planeDomain = {std::floor(planeDomain.fLeft) + 0.5f, 123cb93a386Sopenharmony_ci std::floor(planeDomain.fTop) + 0.5f, 124cb93a386Sopenharmony_ci std::floor(planeDomain.fRight) + 0.5f, 125cb93a386Sopenharmony_ci std::floor(planeDomain.fBottom) + 0.5f}; 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci } else { 129cb93a386Sopenharmony_ci if (subset) { 130cb93a386Sopenharmony_ci planeSubset = *subset; 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci if (domain) { 133cb93a386Sopenharmony_ci planeDomain = *domain; 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci if (useSubset) { 137cb93a386Sopenharmony_ci if (makeLinearWithSnap) { 138cb93a386Sopenharmony_ci // The plane is subsampled and we have an overall subset on the image. We're 139cb93a386Sopenharmony_ci // emulating do_fancy_upsampling using linear filtering but snapping look ups to the 140cb93a386Sopenharmony_ci // y-plane pixel centers. Consider a logical image pixel at the edge of the subset. 141cb93a386Sopenharmony_ci // When computing the logical pixel color value we should use a 50/50 blend of two 142cb93a386Sopenharmony_ci // values from the subsampled plane. Depending on where the subset edge falls in 143cb93a386Sopenharmony_ci // actual subsampled plane, one of those values may come from outside the subset. 144cb93a386Sopenharmony_ci // Hence, we use this custom inset factory which applies the wrap mode to 145cb93a386Sopenharmony_ci // planeSubset but allows linear filtering to read pixels from the plane that are 146cb93a386Sopenharmony_ci // just outside planeSubset. 147cb93a386Sopenharmony_ci SkRect* domainRect = domain ? &planeDomain : nullptr; 148cb93a386Sopenharmony_ci planeFPs[i] = GrTextureEffect::MakeCustomLinearFilterInset(std::move(view), 149cb93a386Sopenharmony_ci kUnknown_SkAlphaType, 150cb93a386Sopenharmony_ci planeMatrix, 151cb93a386Sopenharmony_ci samplerState.wrapModeX(), 152cb93a386Sopenharmony_ci samplerState.wrapModeY(), 153cb93a386Sopenharmony_ci planeSubset, 154cb93a386Sopenharmony_ci domainRect, 155cb93a386Sopenharmony_ci {scaleX/2.f, scaleY/2.f}, 156cb93a386Sopenharmony_ci caps, 157cb93a386Sopenharmony_ci planeBorders[i]); 158cb93a386Sopenharmony_ci } else if (domain) { 159cb93a386Sopenharmony_ci planeFPs[i] = GrTextureEffect::MakeSubset(std::move(view), 160cb93a386Sopenharmony_ci kUnknown_SkAlphaType, 161cb93a386Sopenharmony_ci planeMatrix, 162cb93a386Sopenharmony_ci samplerState, 163cb93a386Sopenharmony_ci planeSubset, 164cb93a386Sopenharmony_ci planeDomain, 165cb93a386Sopenharmony_ci caps, 166cb93a386Sopenharmony_ci planeBorders[i]); 167cb93a386Sopenharmony_ci } else { 168cb93a386Sopenharmony_ci planeFPs[i] = GrTextureEffect::MakeSubset(std::move(view), 169cb93a386Sopenharmony_ci kUnknown_SkAlphaType, 170cb93a386Sopenharmony_ci planeMatrix, 171cb93a386Sopenharmony_ci samplerState, 172cb93a386Sopenharmony_ci planeSubset, 173cb93a386Sopenharmony_ci caps, 174cb93a386Sopenharmony_ci planeBorders[i]); 175cb93a386Sopenharmony_ci } 176cb93a386Sopenharmony_ci } else { 177cb93a386Sopenharmony_ci GrSamplerState planeSampler = samplerState; 178cb93a386Sopenharmony_ci if (makeLinearWithSnap) { 179cb93a386Sopenharmony_ci planeSampler.setFilterMode(GrSamplerState::Filter::kLinear); 180cb93a386Sopenharmony_ci } 181cb93a386Sopenharmony_ci planeFPs[i] = GrTextureEffect::Make(std::move(view), 182cb93a386Sopenharmony_ci kUnknown_SkAlphaType, 183cb93a386Sopenharmony_ci planeMatrix, 184cb93a386Sopenharmony_ci planeSampler, 185cb93a386Sopenharmony_ci caps, 186cb93a386Sopenharmony_ci planeBorders[i]); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci } 189cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp( 190cb93a386Sopenharmony_ci new GrYUVtoRGBEffect(planeFPs, 191cb93a386Sopenharmony_ci numPlanes, 192cb93a386Sopenharmony_ci yuvaProxies.yuvaLocations(), 193cb93a386Sopenharmony_ci snap, 194cb93a386Sopenharmony_ci yuvaProxies.yuvaInfo().yuvColorSpace())); 195cb93a386Sopenharmony_ci return GrMatrixEffect::Make(localMatrix, std::move(fp)); 196cb93a386Sopenharmony_ci} 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_cistatic SkAlphaType alpha_type(const SkYUVAInfo::YUVALocations locations) { 199cb93a386Sopenharmony_ci return locations[SkYUVAInfo::YUVAChannels::kA].fPlane >= 0 ? kPremul_SkAlphaType 200cb93a386Sopenharmony_ci : kOpaque_SkAlphaType; 201cb93a386Sopenharmony_ci} 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ciGrYUVtoRGBEffect::GrYUVtoRGBEffect(std::unique_ptr<GrFragmentProcessor> planeFPs[4], 204cb93a386Sopenharmony_ci int numPlanes, 205cb93a386Sopenharmony_ci const SkYUVAInfo::YUVALocations& locations, 206cb93a386Sopenharmony_ci const bool snap[2], 207cb93a386Sopenharmony_ci SkYUVColorSpace yuvColorSpace) 208cb93a386Sopenharmony_ci : GrFragmentProcessor(kGrYUVtoRGBEffect_ClassID, 209cb93a386Sopenharmony_ci ModulateForClampedSamplerOptFlags(alpha_type(locations))) 210cb93a386Sopenharmony_ci , fLocations(locations) 211cb93a386Sopenharmony_ci , fYUVColorSpace(yuvColorSpace) { 212cb93a386Sopenharmony_ci std::copy_n(snap, 2, fSnap); 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci if (fSnap[0] || fSnap[1]) { 215cb93a386Sopenharmony_ci // Need this so that we can access coords in SKSL to perform snapping. 216cb93a386Sopenharmony_ci this->setUsesSampleCoordsDirectly(); 217cb93a386Sopenharmony_ci for (int i = 0; i < numPlanes; ++i) { 218cb93a386Sopenharmony_ci this->registerChild(std::move(planeFPs[i]), SkSL::SampleUsage::Explicit()); 219cb93a386Sopenharmony_ci } 220cb93a386Sopenharmony_ci } else { 221cb93a386Sopenharmony_ci for (int i = 0; i < numPlanes; ++i) { 222cb93a386Sopenharmony_ci this->registerChild(std::move(planeFPs[i])); 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci } 225cb93a386Sopenharmony_ci} 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci#if GR_TEST_UTILS 228cb93a386Sopenharmony_ciSkString GrYUVtoRGBEffect::onDumpInfo() const { 229cb93a386Sopenharmony_ci SkString str("("); 230cb93a386Sopenharmony_ci for (int i = 0; i < SkYUVAInfo::kYUVAChannelCount; ++i) { 231cb93a386Sopenharmony_ci str.appendf("Locations[%d]=%d %d, ", 232cb93a386Sopenharmony_ci i, fLocations[i].fPlane, static_cast<int>(fLocations[i].fChannel)); 233cb93a386Sopenharmony_ci } 234cb93a386Sopenharmony_ci str.appendf("YUVColorSpace=%d, snap=(%d, %d))", 235cb93a386Sopenharmony_ci static_cast<int>(fYUVColorSpace), fSnap[0], fSnap[1]); 236cb93a386Sopenharmony_ci return str; 237cb93a386Sopenharmony_ci} 238cb93a386Sopenharmony_ci#endif 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor::ProgramImpl> GrYUVtoRGBEffect::onMakeProgramImpl() const { 241cb93a386Sopenharmony_ci class Impl : public ProgramImpl { 242cb93a386Sopenharmony_ci public: 243cb93a386Sopenharmony_ci void emitCode(EmitArgs& args) override { 244cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 245cb93a386Sopenharmony_ci const GrYUVtoRGBEffect& yuvEffect = args.fFp.cast<GrYUVtoRGBEffect>(); 246cb93a386Sopenharmony_ci 247cb93a386Sopenharmony_ci int numPlanes = yuvEffect.numChildProcessors(); 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci const char* sampleCoords = ""; 250cb93a386Sopenharmony_ci if (yuvEffect.fSnap[0] || yuvEffect.fSnap[1]) { 251cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 snappedCoords = %s;", args.fSampleCoord); 252cb93a386Sopenharmony_ci if (yuvEffect.fSnap[0]) { 253cb93a386Sopenharmony_ci fragBuilder->codeAppend("snappedCoords.x = floor(snappedCoords.x) + 0.5;"); 254cb93a386Sopenharmony_ci } 255cb93a386Sopenharmony_ci if (yuvEffect.fSnap[1]) { 256cb93a386Sopenharmony_ci fragBuilder->codeAppend("snappedCoords.y = floor(snappedCoords.y) + 0.5;"); 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci sampleCoords = "snappedCoords"; 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 color;"); 262cb93a386Sopenharmony_ci const bool hasAlpha = yuvEffect.fLocations[SkYUVAInfo::YUVAChannels::kA].fPlane >= 0; 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci for (int planeIdx = 0; planeIdx < numPlanes; ++planeIdx) { 265cb93a386Sopenharmony_ci std::string colorChannel; 266cb93a386Sopenharmony_ci std::string planeChannel; 267cb93a386Sopenharmony_ci for (int locIdx = 0; locIdx < (hasAlpha ? 4 : 3); ++locIdx) { 268cb93a386Sopenharmony_ci auto [yuvPlane, yuvChannel] = yuvEffect.fLocations[locIdx]; 269cb93a386Sopenharmony_ci if (yuvPlane == planeIdx) { 270cb93a386Sopenharmony_ci colorChannel.push_back("rgba"[locIdx]); 271cb93a386Sopenharmony_ci planeChannel.push_back("rgba"[static_cast<int>(yuvChannel)]); 272cb93a386Sopenharmony_ci } 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci SkASSERT(colorChannel.size() == planeChannel.size()); 276cb93a386Sopenharmony_ci if (!colorChannel.empty()) { 277cb93a386Sopenharmony_ci fragBuilder->codeAppendf( 278cb93a386Sopenharmony_ci "color.%s = (%s).%s;", 279cb93a386Sopenharmony_ci colorChannel.c_str(), 280cb93a386Sopenharmony_ci this->invokeChild(planeIdx, args, sampleCoords).c_str(), 281cb93a386Sopenharmony_ci planeChannel.c_str()); 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_ci if (!hasAlpha) { 286cb93a386Sopenharmony_ci fragBuilder->codeAppendf("color.a = 1;"); 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci if (kIdentity_SkYUVColorSpace != yuvEffect.fYUVColorSpace) { 290cb93a386Sopenharmony_ci fColorSpaceMatrixVar = args.fUniformHandler->addUniform(&yuvEffect, 291cb93a386Sopenharmony_ci kFragment_GrShaderFlag, kHalf3x3_GrSLType, "colorSpaceMatrix"); 292cb93a386Sopenharmony_ci fColorSpaceTranslateVar = args.fUniformHandler->addUniform(&yuvEffect, 293cb93a386Sopenharmony_ci kFragment_GrShaderFlag, kHalf3_GrSLType, "colorSpaceTranslate"); 294cb93a386Sopenharmony_ci fragBuilder->codeAppendf( 295cb93a386Sopenharmony_ci "color.rgb = saturate(color.rgb * %s + %s);", 296cb93a386Sopenharmony_ci args.fUniformHandler->getUniformCStr(fColorSpaceMatrixVar), 297cb93a386Sopenharmony_ci args.fUniformHandler->getUniformCStr(fColorSpaceTranslateVar)); 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci if (hasAlpha) { 300cb93a386Sopenharmony_ci // premultiply alpha 301cb93a386Sopenharmony_ci fragBuilder->codeAppendf("color.rgb *= color.a;"); 302cb93a386Sopenharmony_ci } 303cb93a386Sopenharmony_ci fragBuilder->codeAppendf("return color;"); 304cb93a386Sopenharmony_ci } 305cb93a386Sopenharmony_ci 306cb93a386Sopenharmony_ci private: 307cb93a386Sopenharmony_ci void onSetData(const GrGLSLProgramDataManager& pdman, 308cb93a386Sopenharmony_ci const GrFragmentProcessor& proc) override { 309cb93a386Sopenharmony_ci const GrYUVtoRGBEffect& yuvEffect = proc.cast<GrYUVtoRGBEffect>(); 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ci if (yuvEffect.fYUVColorSpace != kIdentity_SkYUVColorSpace) { 312cb93a386Sopenharmony_ci SkASSERT(fColorSpaceMatrixVar.isValid()); 313cb93a386Sopenharmony_ci float yuvM[20]; 314cb93a386Sopenharmony_ci SkColorMatrix_YUV2RGB(yuvEffect.fYUVColorSpace, yuvM); 315cb93a386Sopenharmony_ci // We drop the fourth column entirely since the transformation 316cb93a386Sopenharmony_ci // should not depend on alpha. The fifth column is sent as a separate 317cb93a386Sopenharmony_ci // vector. The fourth row is also dropped entirely because alpha should 318cb93a386Sopenharmony_ci // never be modified. 319cb93a386Sopenharmony_ci SkASSERT(yuvM[3] == 0 && yuvM[8] == 0 && yuvM[13] == 0 && yuvM[18] == 1); 320cb93a386Sopenharmony_ci SkASSERT(yuvM[15] == 0 && yuvM[16] == 0 && yuvM[17] == 0 && yuvM[19] == 0); 321cb93a386Sopenharmony_ci float mtx[9] = { 322cb93a386Sopenharmony_ci yuvM[ 0], yuvM[ 1], yuvM[ 2], 323cb93a386Sopenharmony_ci yuvM[ 5], yuvM[ 6], yuvM[ 7], 324cb93a386Sopenharmony_ci yuvM[10], yuvM[11], yuvM[12], 325cb93a386Sopenharmony_ci }; 326cb93a386Sopenharmony_ci float v[3] = {yuvM[4], yuvM[9], yuvM[14]}; 327cb93a386Sopenharmony_ci pdman.setMatrix3f(fColorSpaceMatrixVar, mtx); 328cb93a386Sopenharmony_ci pdman.set3fv(fColorSpaceTranslateVar, 1, v); 329cb93a386Sopenharmony_ci } 330cb93a386Sopenharmony_ci } 331cb93a386Sopenharmony_ci 332cb93a386Sopenharmony_ci UniformHandle fColorSpaceMatrixVar; 333cb93a386Sopenharmony_ci UniformHandle fColorSpaceTranslateVar; 334cb93a386Sopenharmony_ci }; 335cb93a386Sopenharmony_ci 336cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 337cb93a386Sopenharmony_ci} 338cb93a386Sopenharmony_ci 339cb93a386Sopenharmony_ciSkString GrYUVtoRGBEffect::getShaderDfxInfo() const 340cb93a386Sopenharmony_ci{ 341cb93a386Sopenharmony_ci SkString format; 342cb93a386Sopenharmony_ci format.printf("ShaderDfx_GrYUVtoRGBEffect"); 343cb93a386Sopenharmony_ci for (auto [plane, channel] : fLocations) { 344cb93a386Sopenharmony_ci format.appendf("_%d_%d", plane, channel); 345cb93a386Sopenharmony_ci } 346cb93a386Sopenharmony_ci format.appendf("_%d_%d_%d", fYUVColorSpace, fSnap[0], fSnap[1]); 347cb93a386Sopenharmony_ci return format; 348cb93a386Sopenharmony_ci} 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_civoid GrYUVtoRGBEffect::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { 351cb93a386Sopenharmony_ci uint32_t packed = 0; 352cb93a386Sopenharmony_ci int i = 0; 353cb93a386Sopenharmony_ci for (auto [plane, channel] : fLocations) { 354cb93a386Sopenharmony_ci if (plane < 0) { 355cb93a386Sopenharmony_ci continue; 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci uint8_t chann = static_cast<int>(channel); 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci SkASSERT(plane < 4 && chann < 4); 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_ci packed |= (plane | (chann << 2)) << (i++ * 4); 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci if (fYUVColorSpace == kIdentity_SkYUVColorSpace) { 365cb93a386Sopenharmony_ci packed |= 1 << 16; 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci if (fSnap[0]) { 368cb93a386Sopenharmony_ci packed |= 1 << 17; 369cb93a386Sopenharmony_ci } 370cb93a386Sopenharmony_ci if (fSnap[1]) { 371cb93a386Sopenharmony_ci packed |= 1 << 18; 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci b->add32(packed); 374cb93a386Sopenharmony_ci} 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_cibool GrYUVtoRGBEffect::onIsEqual(const GrFragmentProcessor& other) const { 377cb93a386Sopenharmony_ci const GrYUVtoRGBEffect& that = other.cast<GrYUVtoRGBEffect>(); 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci return fLocations == that.fLocations && 380cb93a386Sopenharmony_ci std::equal(fSnap, fSnap + 2, that.fSnap) && 381cb93a386Sopenharmony_ci fYUVColorSpace == that.fYUVColorSpace; 382cb93a386Sopenharmony_ci} 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_ciGrYUVtoRGBEffect::GrYUVtoRGBEffect(const GrYUVtoRGBEffect& src) 385cb93a386Sopenharmony_ci : GrFragmentProcessor(src) 386cb93a386Sopenharmony_ci , fLocations((src.fLocations)) 387cb93a386Sopenharmony_ci , fYUVColorSpace(src.fYUVColorSpace) { 388cb93a386Sopenharmony_ci std::copy_n(src.fSnap, 2, fSnap); 389cb93a386Sopenharmony_ci} 390cb93a386Sopenharmony_ci 391cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::clone() const { 392cb93a386Sopenharmony_ci return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(*this)); 393cb93a386Sopenharmony_ci} 394