1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 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/core/SkDistanceFieldGen.h" 9cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 10cb93a386Sopenharmony_ci#include "src/gpu/GrShaderCaps.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h" 12cb93a386Sopenharmony_ci#include "src/gpu/effects/GrAtlasedShaderHelpers.h" 13cb93a386Sopenharmony_ci#include "src/gpu/effects/GrDistanceFieldGeoProc.h" 14cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 15cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramDataManager.h" 16cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLUniformHandler.h" 17cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h" 18cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci// Assuming a radius of a little less than the diagonal of the fragment 21cb93a386Sopenharmony_ci#define SK_DistanceFieldAAFactor "0.65" 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ciclass GrDistanceFieldA8TextGeoProc::Impl : public ProgramImpl { 24cb93a386Sopenharmony_cipublic: 25cb93a386Sopenharmony_ci void setData(const GrGLSLProgramDataManager& pdman, 26cb93a386Sopenharmony_ci const GrShaderCaps& shaderCaps, 27cb93a386Sopenharmony_ci const GrGeometryProcessor& geomProc) override { 28cb93a386Sopenharmony_ci const GrDistanceFieldA8TextGeoProc& dfa8gp = geomProc.cast<GrDistanceFieldA8TextGeoProc>(); 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#ifdef SK_GAMMA_APPLY_TO_A8 31cb93a386Sopenharmony_ci float distanceAdjust = dfa8gp.fDistanceAdjust; 32cb93a386Sopenharmony_ci if (distanceAdjust != fDistanceAdjust) { 33cb93a386Sopenharmony_ci fDistanceAdjust = distanceAdjust; 34cb93a386Sopenharmony_ci pdman.set1f(fDistanceAdjustUni, distanceAdjust); 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci#endif 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci const SkISize& atlasDimensions = dfa8gp.fAtlasDimensions; 39cb93a386Sopenharmony_ci SkASSERT(SkIsPow2(atlasDimensions.fWidth) && SkIsPow2(atlasDimensions.fHeight)); 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci if (fAtlasDimensions != atlasDimensions) { 42cb93a386Sopenharmony_ci pdman.set2f(fAtlasDimensionsInvUniform, 43cb93a386Sopenharmony_ci 1.0f / atlasDimensions.fWidth, 44cb93a386Sopenharmony_ci 1.0f / atlasDimensions.fHeight); 45cb93a386Sopenharmony_ci fAtlasDimensions = atlasDimensions; 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci SetTransform(pdman, shaderCaps, fLocalMatrixUniform, dfa8gp.fLocalMatrix, &fLocalMatrix); 48cb93a386Sopenharmony_ci } 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ciprivate: 51cb93a386Sopenharmony_ci void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ 52cb93a386Sopenharmony_ci const GrDistanceFieldA8TextGeoProc& dfTexEffect = 53cb93a386Sopenharmony_ci args.fGeomProc.cast<GrDistanceFieldA8TextGeoProc>(); 54cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; 57cb93a386Sopenharmony_ci GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; 58cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci // emit attributes 61cb93a386Sopenharmony_ci varyingHandler->emitAttributes(dfTexEffect); 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci const char* atlasDimensionsInvName; 64cb93a386Sopenharmony_ci fAtlasDimensionsInvUniform = uniformHandler->addUniform(nullptr, 65cb93a386Sopenharmony_ci kVertex_GrShaderFlag, 66cb93a386Sopenharmony_ci kFloat2_GrSLType, 67cb93a386Sopenharmony_ci "AtlasDimensionsInv", 68cb93a386Sopenharmony_ci &atlasDimensionsInvName); 69cb93a386Sopenharmony_ci#ifdef SK_GAMMA_APPLY_TO_A8 70cb93a386Sopenharmony_ci // adjust based on gamma 71cb93a386Sopenharmony_ci const char* distanceAdjustUniName = nullptr; 72cb93a386Sopenharmony_ci // width, height, 1/(3*width) 73cb93a386Sopenharmony_ci fDistanceAdjustUni = uniformHandler->addUniform(nullptr, kFragment_GrShaderFlag, 74cb93a386Sopenharmony_ci kHalf_GrSLType, "DistanceAdjust", 75cb93a386Sopenharmony_ci &distanceAdjustUniName); 76cb93a386Sopenharmony_ci#endif 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci // Setup pass through color 79cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s;\n", args.fOutputColor); 80cb93a386Sopenharmony_ci varyingHandler->addPassThroughAttribute(dfTexEffect.fInColor.asShaderVar(), 81cb93a386Sopenharmony_ci args.fOutputColor); 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci // Setup position 84cb93a386Sopenharmony_ci gpArgs->fPositionVar = dfTexEffect.fInPosition.asShaderVar(); 85cb93a386Sopenharmony_ci WriteLocalCoord(vertBuilder, 86cb93a386Sopenharmony_ci uniformHandler, 87cb93a386Sopenharmony_ci *args.fShaderCaps, 88cb93a386Sopenharmony_ci gpArgs, 89cb93a386Sopenharmony_ci gpArgs->fPositionVar, 90cb93a386Sopenharmony_ci dfTexEffect.fLocalMatrix, 91cb93a386Sopenharmony_ci &fLocalMatrixUniform); 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci // add varyings 94cb93a386Sopenharmony_ci GrGLSLVarying uv, texIdx, st; 95cb93a386Sopenharmony_ci append_index_uv_varyings(args, 96cb93a386Sopenharmony_ci dfTexEffect.numTextureSamplers(), 97cb93a386Sopenharmony_ci dfTexEffect.fInTextureCoords.name(), 98cb93a386Sopenharmony_ci atlasDimensionsInvName, 99cb93a386Sopenharmony_ci &uv, 100cb93a386Sopenharmony_ci &texIdx, 101cb93a386Sopenharmony_ci &st); 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci bool isUniformScale = (dfTexEffect.fFlags & kUniformScale_DistanceFieldEffectMask) == 104cb93a386Sopenharmony_ci kUniformScale_DistanceFieldEffectMask; 105cb93a386Sopenharmony_ci bool isSimilarity = SkToBool(dfTexEffect.fFlags & kSimilarity_DistanceFieldEffectFlag ); 106cb93a386Sopenharmony_ci bool isGammaCorrect = SkToBool(dfTexEffect.fFlags & kGammaCorrect_DistanceFieldEffectFlag); 107cb93a386Sopenharmony_ci bool isAliased = SkToBool(dfTexEffect.fFlags & kAliased_DistanceFieldEffectFlag ); 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci // Use highp to work around aliasing issues 110cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 uv = %s;\n", uv.fsIn()); 111cb93a386Sopenharmony_ci fragBuilder->codeAppend("half4 texColor;"); 112cb93a386Sopenharmony_ci append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(), 113cb93a386Sopenharmony_ci texIdx, "uv", "texColor"); 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci fragBuilder->codeAppend("half distance = " 116cb93a386Sopenharmony_ci SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");"); 117cb93a386Sopenharmony_ci#ifdef SK_GAMMA_APPLY_TO_A8 118cb93a386Sopenharmony_ci // adjust width based on gamma 119cb93a386Sopenharmony_ci fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); 120cb93a386Sopenharmony_ci#endif 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci fragBuilder->codeAppend("half afwidth;"); 123cb93a386Sopenharmony_ci if (isUniformScale) { 124cb93a386Sopenharmony_ci // For uniform scale, we adjust for the effect of the transformation on the distance 125cb93a386Sopenharmony_ci // by using the length of the gradient of the t coordinate in the y direction. 126cb93a386Sopenharmony_ci // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space. 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ci // this gives us a smooth step across approximately one fragment 129cb93a386Sopenharmony_ci if (args.fShaderCaps->avoidDfDxForGradientsWhenPossible()) { 130cb93a386Sopenharmony_ci fragBuilder->codeAppendf( 131cb93a386Sopenharmony_ci "afwidth = abs(" SK_DistanceFieldAAFactor "*half(dFdy(%s.y)));", st.fsIn()); 132cb93a386Sopenharmony_ci } else { 133cb93a386Sopenharmony_ci fragBuilder->codeAppendf( 134cb93a386Sopenharmony_ci "afwidth = abs(" SK_DistanceFieldAAFactor "*half(dFdx(%s.x)));", st.fsIn()); 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci } else if (isSimilarity) { 137cb93a386Sopenharmony_ci // For similarity transform, we adjust the effect of the transformation on the distance 138cb93a386Sopenharmony_ci // by using the length of the gradient of the texture coordinates. We use st coordinates 139cb93a386Sopenharmony_ci // to ensure we're mapping 1:1 from texel space to pixel space. 140cb93a386Sopenharmony_ci // We use the y gradient because there is a bug in the Mali 400 in the x direction. 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci // this gives us a smooth step across approximately one fragment 143cb93a386Sopenharmony_ci if (args.fShaderCaps->avoidDfDxForGradientsWhenPossible()) { 144cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half st_grad_len = length(half2(dFdy(%s)));", st.fsIn()); 145cb93a386Sopenharmony_ci } else { 146cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half st_grad_len = length(half2(dFdx(%s)));", st.fsIn()); 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);"); 149cb93a386Sopenharmony_ci } else { 150cb93a386Sopenharmony_ci // For general transforms, to determine the amount of correction we multiply a unit 151cb93a386Sopenharmony_ci // vector pointing along the SDF gradient direction by the Jacobian of the st coords 152cb93a386Sopenharmony_ci // (which is the inverse transform for this fragment) and take the length of the result. 153cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 dist_grad = half2(float2(dFdx(distance), " 154cb93a386Sopenharmony_ci "dFdy(distance)));"); 155cb93a386Sopenharmony_ci // the length of the gradient may be 0, so we need to check for this 156cb93a386Sopenharmony_ci // this also compensates for the Adreno, which likes to drop tiles on division by 0 157cb93a386Sopenharmony_ci fragBuilder->codeAppend("half dg_len2 = dot(dist_grad, dist_grad);"); 158cb93a386Sopenharmony_ci fragBuilder->codeAppend("if (dg_len2 < 0.0001) {"); 159cb93a386Sopenharmony_ci fragBuilder->codeAppend("dist_grad = half2(0.7071, 0.7071);"); 160cb93a386Sopenharmony_ci fragBuilder->codeAppend("} else {"); 161cb93a386Sopenharmony_ci fragBuilder->codeAppend("dist_grad = dist_grad*half(inversesqrt(dg_len2));"); 162cb93a386Sopenharmony_ci fragBuilder->codeAppend("}"); 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 Jdx = half2(dFdx(%s));", st.fsIn()); 165cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 Jdy = half2(dFdy(%s));", st.fsIn()); 166cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 grad = half2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); 167cb93a386Sopenharmony_ci fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci // this gives us a smooth step across approximately one fragment 170cb93a386Sopenharmony_ci fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci if (isAliased) { 174cb93a386Sopenharmony_ci fragBuilder->codeAppend("half val = distance > 0 ? 1.0 : 0.0;"); 175cb93a386Sopenharmony_ci } else if (isGammaCorrect) { 176cb93a386Sopenharmony_ci // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are 177cb93a386Sopenharmony_ci // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want 178cb93a386Sopenharmony_ci // distance mapped linearly to coverage, so use a linear step: 179cb93a386Sopenharmony_ci fragBuilder->codeAppend( 180cb93a386Sopenharmony_ci "half val = saturate((distance + afwidth) / (2.0 * afwidth));"); 181cb93a386Sopenharmony_ci } else { 182cb93a386Sopenharmony_ci fragBuilder->codeAppend("half val = smoothstep(-afwidth, afwidth, distance);"); 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s = half4(val);", args.fOutputCoverage); 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ciprivate: 189cb93a386Sopenharmony_ci#ifdef SK_GAMMA_APPLY_TO_A8 190cb93a386Sopenharmony_ci float fDistanceAdjust = -1.f; 191cb93a386Sopenharmony_ci#endif 192cb93a386Sopenharmony_ci SkISize fAtlasDimensions = {-1, -1}; 193cb93a386Sopenharmony_ci SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci UniformHandle fDistanceAdjustUni; 196cb93a386Sopenharmony_ci UniformHandle fAtlasDimensionsInvUniform; 197cb93a386Sopenharmony_ci UniformHandle fLocalMatrixUniform; 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci using INHERITED = ProgramImpl; 200cb93a386Sopenharmony_ci}; 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ciGrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(const GrShaderCaps& caps, 205cb93a386Sopenharmony_ci const GrSurfaceProxyView* views, 206cb93a386Sopenharmony_ci int numViews, 207cb93a386Sopenharmony_ci GrSamplerState params, 208cb93a386Sopenharmony_ci#ifdef SK_GAMMA_APPLY_TO_A8 209cb93a386Sopenharmony_ci float distanceAdjust, 210cb93a386Sopenharmony_ci#endif 211cb93a386Sopenharmony_ci uint32_t flags, 212cb93a386Sopenharmony_ci const SkMatrix& localMatrix) 213cb93a386Sopenharmony_ci : INHERITED(kGrDistanceFieldA8TextGeoProc_ClassID) 214cb93a386Sopenharmony_ci , fLocalMatrix(localMatrix) 215cb93a386Sopenharmony_ci , fFlags(flags & kNonLCD_DistanceFieldEffectMask) 216cb93a386Sopenharmony_ci#ifdef SK_GAMMA_APPLY_TO_A8 217cb93a386Sopenharmony_ci , fDistanceAdjust(distanceAdjust) 218cb93a386Sopenharmony_ci#endif 219cb93a386Sopenharmony_ci{ 220cb93a386Sopenharmony_ci SkASSERT(numViews <= kMaxTextures); 221cb93a386Sopenharmony_ci SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask)); 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci if (flags & kPerspective_DistanceFieldEffectFlag) { 224cb93a386Sopenharmony_ci fInPosition = {"inPosition", kFloat3_GrVertexAttribType, kFloat3_GrSLType}; 225cb93a386Sopenharmony_ci } else { 226cb93a386Sopenharmony_ci fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType }; 229cb93a386Sopenharmony_ci fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType, 230cb93a386Sopenharmony_ci caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType}; 231cb93a386Sopenharmony_ci this->setVertexAttributes(&fInPosition, 3); 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_ci if (numViews) { 234cb93a386Sopenharmony_ci fAtlasDimensions = views[0].proxy()->dimensions(); 235cb93a386Sopenharmony_ci } 236cb93a386Sopenharmony_ci for (int i = 0; i < numViews; ++i) { 237cb93a386Sopenharmony_ci const GrSurfaceProxy* proxy = views[i].proxy(); 238cb93a386Sopenharmony_ci SkASSERT(proxy); 239cb93a386Sopenharmony_ci SkASSERT(proxy->dimensions() == fAtlasDimensions); 240cb93a386Sopenharmony_ci fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle()); 241cb93a386Sopenharmony_ci } 242cb93a386Sopenharmony_ci this->setTextureSamplerCnt(numViews); 243cb93a386Sopenharmony_ci} 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_civoid GrDistanceFieldA8TextGeoProc::addNewViews(const GrSurfaceProxyView* views, 246cb93a386Sopenharmony_ci int numViews, 247cb93a386Sopenharmony_ci GrSamplerState params) { 248cb93a386Sopenharmony_ci SkASSERT(numViews <= kMaxTextures); 249cb93a386Sopenharmony_ci // Just to make sure we don't try to add too many proxies 250cb93a386Sopenharmony_ci numViews = std::min(numViews, kMaxTextures); 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci if (!fTextureSamplers[0].isInitialized()) { 253cb93a386Sopenharmony_ci fAtlasDimensions = views[0].proxy()->dimensions(); 254cb93a386Sopenharmony_ci } 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci for (int i = 0; i < numViews; ++i) { 257cb93a386Sopenharmony_ci const GrSurfaceProxy* proxy = views[i].proxy(); 258cb93a386Sopenharmony_ci SkASSERT(proxy); 259cb93a386Sopenharmony_ci SkASSERT(proxy->dimensions() == fAtlasDimensions); 260cb93a386Sopenharmony_ci if (!fTextureSamplers[i].isInitialized()) { 261cb93a386Sopenharmony_ci fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle()); 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci this->setTextureSamplerCnt(numViews); 265cb93a386Sopenharmony_ci} 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_ciSkString GrDistanceFieldA8TextGeoProc::getShaderDfxInfo() const 268cb93a386Sopenharmony_ci{ 269cb93a386Sopenharmony_ci SkString format; 270cb93a386Sopenharmony_ci format.printf("ShaderDfx_GrDistanceFieldA8TextGeoProc_%d_%d_%d_%d_%d", fFlags, numTextureSamplers(), 271cb93a386Sopenharmony_ci fLocalMatrix.isIdentity(), fLocalMatrix.isScaleTranslate(), fLocalMatrix.hasPerspective()); 272cb93a386Sopenharmony_ci return format; 273cb93a386Sopenharmony_ci} 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_civoid GrDistanceFieldA8TextGeoProc::addToKey(const GrShaderCaps& caps, 276cb93a386Sopenharmony_ci GrProcessorKeyBuilder* b) const { 277cb93a386Sopenharmony_ci uint32_t key = 0; 278cb93a386Sopenharmony_ci key |= fFlags; 279cb93a386Sopenharmony_ci key |= ProgramImpl::ComputeMatrixKey(caps, fLocalMatrix) << 16; 280cb93a386Sopenharmony_ci b->add32(key); 281cb93a386Sopenharmony_ci b->add32(this->numTextureSamplers()); 282cb93a386Sopenharmony_ci} 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl> GrDistanceFieldA8TextGeoProc::makeProgramImpl( 285cb93a386Sopenharmony_ci const GrShaderCaps&) const { 286cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 287cb93a386Sopenharmony_ci} 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_ciGR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc); 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_ci#if GR_TEST_UTILS 294cb93a386Sopenharmony_ciGrGeometryProcessor* GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) { 295cb93a386Sopenharmony_ci auto [view, ct, at] = d->randomAlphaOnlyView(); 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ci GrSamplerState::WrapMode wrapModes[2]; 298cb93a386Sopenharmony_ci GrTest::TestWrapModes(d->fRandom, wrapModes); 299cb93a386Sopenharmony_ci GrSamplerState samplerState(wrapModes, d->fRandom->nextBool() 300cb93a386Sopenharmony_ci ? GrSamplerState::Filter::kLinear 301cb93a386Sopenharmony_ci : GrSamplerState::Filter::kNearest); 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci uint32_t flags = 0; 304cb93a386Sopenharmony_ci flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0; 305cb93a386Sopenharmony_ci if (flags & kSimilarity_DistanceFieldEffectFlag) { 306cb93a386Sopenharmony_ci flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0; 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom); 309cb93a386Sopenharmony_ci#ifdef SK_GAMMA_APPLY_TO_A8 310cb93a386Sopenharmony_ci float lum = d->fRandom->nextF(); 311cb93a386Sopenharmony_ci#endif 312cb93a386Sopenharmony_ci return GrDistanceFieldA8TextGeoProc::Make(d->allocator(), *d->caps()->shaderCaps(), 313cb93a386Sopenharmony_ci &view, 1, 314cb93a386Sopenharmony_ci samplerState, 315cb93a386Sopenharmony_ci#ifdef SK_GAMMA_APPLY_TO_A8 316cb93a386Sopenharmony_ci lum, 317cb93a386Sopenharmony_ci#endif 318cb93a386Sopenharmony_ci flags, localMatrix); 319cb93a386Sopenharmony_ci} 320cb93a386Sopenharmony_ci#endif 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_ciclass GrDistanceFieldPathGeoProc::Impl : public ProgramImpl { 325cb93a386Sopenharmony_cipublic: 326cb93a386Sopenharmony_ci void setData(const GrGLSLProgramDataManager& pdman, 327cb93a386Sopenharmony_ci const GrShaderCaps& shaderCaps, 328cb93a386Sopenharmony_ci const GrGeometryProcessor& geomProc) override { 329cb93a386Sopenharmony_ci const GrDistanceFieldPathGeoProc& dfpgp = geomProc.cast<GrDistanceFieldPathGeoProc>(); 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_ci // We always set the matrix uniform; it's either used to transform from local to device 332cb93a386Sopenharmony_ci // for the output position, or from device to local for the local coord variable. 333cb93a386Sopenharmony_ci SetTransform(pdman, shaderCaps, fMatrixUniform, dfpgp.fMatrix, &fMatrix); 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci const SkISize& atlasDimensions = dfpgp.fAtlasDimensions; 336cb93a386Sopenharmony_ci SkASSERT(SkIsPow2(atlasDimensions.fWidth) && SkIsPow2(atlasDimensions.fHeight)); 337cb93a386Sopenharmony_ci if (fAtlasDimensions != atlasDimensions) { 338cb93a386Sopenharmony_ci pdman.set2f(fAtlasDimensionsInvUniform, 339cb93a386Sopenharmony_ci 1.0f / atlasDimensions.fWidth, 340cb93a386Sopenharmony_ci 1.0f / atlasDimensions.fHeight); 341cb93a386Sopenharmony_ci fAtlasDimensions = atlasDimensions; 342cb93a386Sopenharmony_ci } 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ciprivate: 346cb93a386Sopenharmony_ci void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ 347cb93a386Sopenharmony_ci const GrDistanceFieldPathGeoProc& dfPathEffect = 348cb93a386Sopenharmony_ci args.fGeomProc.cast<GrDistanceFieldPathGeoProc>(); 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 351cb93a386Sopenharmony_ci 352cb93a386Sopenharmony_ci GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; 353cb93a386Sopenharmony_ci GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; 354cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci // emit attributes 357cb93a386Sopenharmony_ci varyingHandler->emitAttributes(dfPathEffect); 358cb93a386Sopenharmony_ci 359cb93a386Sopenharmony_ci const char* atlasDimensionsInvName; 360cb93a386Sopenharmony_ci fAtlasDimensionsInvUniform = uniformHandler->addUniform(nullptr, 361cb93a386Sopenharmony_ci kVertex_GrShaderFlag, 362cb93a386Sopenharmony_ci kFloat2_GrSLType, 363cb93a386Sopenharmony_ci "AtlasDimensionsInv", 364cb93a386Sopenharmony_ci &atlasDimensionsInvName); 365cb93a386Sopenharmony_ci 366cb93a386Sopenharmony_ci GrGLSLVarying uv, texIdx, st; 367cb93a386Sopenharmony_ci append_index_uv_varyings(args, 368cb93a386Sopenharmony_ci dfPathEffect.numTextureSamplers(), 369cb93a386Sopenharmony_ci dfPathEffect.fInTextureCoords.name(), 370cb93a386Sopenharmony_ci atlasDimensionsInvName, 371cb93a386Sopenharmony_ci &uv, 372cb93a386Sopenharmony_ci &texIdx, 373cb93a386Sopenharmony_ci &st); 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ci // setup pass through color 376cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s;", args.fOutputColor); 377cb93a386Sopenharmony_ci varyingHandler->addPassThroughAttribute(dfPathEffect.fInColor.asShaderVar(), 378cb93a386Sopenharmony_ci args.fOutputColor); 379cb93a386Sopenharmony_ci 380cb93a386Sopenharmony_ci if (dfPathEffect.fMatrix.hasPerspective()) { 381cb93a386Sopenharmony_ci // Setup position (output position is transformed, local coords are pass through) 382cb93a386Sopenharmony_ci WriteOutputPosition(vertBuilder, 383cb93a386Sopenharmony_ci uniformHandler, 384cb93a386Sopenharmony_ci *args.fShaderCaps, 385cb93a386Sopenharmony_ci gpArgs, 386cb93a386Sopenharmony_ci dfPathEffect.fInPosition.name(), 387cb93a386Sopenharmony_ci dfPathEffect.fMatrix, 388cb93a386Sopenharmony_ci &fMatrixUniform); 389cb93a386Sopenharmony_ci gpArgs->fLocalCoordVar = dfPathEffect.fInPosition.asShaderVar(); 390cb93a386Sopenharmony_ci } else { 391cb93a386Sopenharmony_ci // Setup position (output position is pass through, local coords are transformed) 392cb93a386Sopenharmony_ci WriteOutputPosition(vertBuilder, gpArgs, dfPathEffect.fInPosition.name()); 393cb93a386Sopenharmony_ci WriteLocalCoord(vertBuilder, 394cb93a386Sopenharmony_ci uniformHandler, 395cb93a386Sopenharmony_ci *args.fShaderCaps, 396cb93a386Sopenharmony_ci gpArgs, 397cb93a386Sopenharmony_ci dfPathEffect.fInPosition.asShaderVar(), 398cb93a386Sopenharmony_ci dfPathEffect.fMatrix, 399cb93a386Sopenharmony_ci &fMatrixUniform); 400cb93a386Sopenharmony_ci } 401cb93a386Sopenharmony_ci 402cb93a386Sopenharmony_ci // Use highp to work around aliasing issues 403cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 uv = %s;", uv.fsIn()); 404cb93a386Sopenharmony_ci fragBuilder->codeAppend("half4 texColor;"); 405cb93a386Sopenharmony_ci append_multitexture_lookup(args, dfPathEffect.numTextureSamplers(), texIdx, "uv", 406cb93a386Sopenharmony_ci "texColor"); 407cb93a386Sopenharmony_ci 408cb93a386Sopenharmony_ci fragBuilder->codeAppend("half distance = " 409cb93a386Sopenharmony_ci SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");"); 410cb93a386Sopenharmony_ci 411cb93a386Sopenharmony_ci fragBuilder->codeAppend("half afwidth;"); 412cb93a386Sopenharmony_ci bool isUniformScale = (dfPathEffect.fFlags & kUniformScale_DistanceFieldEffectMask) == 413cb93a386Sopenharmony_ci kUniformScale_DistanceFieldEffectMask; 414cb93a386Sopenharmony_ci bool isSimilarity = SkToBool(dfPathEffect.fFlags & kSimilarity_DistanceFieldEffectFlag ); 415cb93a386Sopenharmony_ci bool isGammaCorrect = SkToBool(dfPathEffect.fFlags & kGammaCorrect_DistanceFieldEffectFlag); 416cb93a386Sopenharmony_ci if (isUniformScale) { 417cb93a386Sopenharmony_ci // For uniform scale, we adjust for the effect of the transformation on the distance 418cb93a386Sopenharmony_ci // by using the length of the gradient of the t coordinate in the y direction. 419cb93a386Sopenharmony_ci // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space. 420cb93a386Sopenharmony_ci 421cb93a386Sopenharmony_ci // this gives us a smooth step across approximately one fragment 422cb93a386Sopenharmony_ci if (args.fShaderCaps->avoidDfDxForGradientsWhenPossible()) { 423cb93a386Sopenharmony_ci fragBuilder->codeAppendf( 424cb93a386Sopenharmony_ci "afwidth = abs(" SK_DistanceFieldAAFactor "*half(dFdy(%s.y)));", st.fsIn()); 425cb93a386Sopenharmony_ci } else { 426cb93a386Sopenharmony_ci fragBuilder->codeAppendf( 427cb93a386Sopenharmony_ci "afwidth = abs(" SK_DistanceFieldAAFactor "*half(dFdx(%s.x)));", st.fsIn()); 428cb93a386Sopenharmony_ci } 429cb93a386Sopenharmony_ci } else if (isSimilarity) { 430cb93a386Sopenharmony_ci // For similarity transform, we adjust the effect of the transformation on the distance 431cb93a386Sopenharmony_ci // by using the length of the gradient of the texture coordinates. We use st coordinates 432cb93a386Sopenharmony_ci // to ensure we're mapping 1:1 from texel space to pixel space. 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_ci // this gives us a smooth step across approximately one fragment 435cb93a386Sopenharmony_ci if (args.fShaderCaps->avoidDfDxForGradientsWhenPossible()) { 436cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half st_grad_len = half(length(dFdy(%s)));", st.fsIn()); 437cb93a386Sopenharmony_ci } else { 438cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half st_grad_len = half(length(dFdx(%s)));", st.fsIn()); 439cb93a386Sopenharmony_ci } 440cb93a386Sopenharmony_ci fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);"); 441cb93a386Sopenharmony_ci } else { 442cb93a386Sopenharmony_ci // For general transforms, to determine the amount of correction we multiply a unit 443cb93a386Sopenharmony_ci // vector pointing along the SDF gradient direction by the Jacobian of the st coords 444cb93a386Sopenharmony_ci // (which is the inverse transform for this fragment) and take the length of the result. 445cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 dist_grad = half2(dFdx(distance), " 446cb93a386Sopenharmony_ci "dFdy(distance));"); 447cb93a386Sopenharmony_ci // the length of the gradient may be 0, so we need to check for this 448cb93a386Sopenharmony_ci // this also compensates for the Adreno, which likes to drop tiles on division by 0 449cb93a386Sopenharmony_ci fragBuilder->codeAppend("half dg_len2 = dot(dist_grad, dist_grad);"); 450cb93a386Sopenharmony_ci fragBuilder->codeAppend("if (dg_len2 < 0.0001) {"); 451cb93a386Sopenharmony_ci fragBuilder->codeAppend("dist_grad = half2(0.7071, 0.7071);"); 452cb93a386Sopenharmony_ci fragBuilder->codeAppend("} else {"); 453cb93a386Sopenharmony_ci fragBuilder->codeAppend("dist_grad = dist_grad*half(inversesqrt(dg_len2));"); 454cb93a386Sopenharmony_ci fragBuilder->codeAppend("}"); 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 Jdx = half2(dFdx(%s));", st.fsIn()); 457cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 Jdy = half2(dFdy(%s));", st.fsIn()); 458cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 grad = half2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); 459cb93a386Sopenharmony_ci fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); 460cb93a386Sopenharmony_ci 461cb93a386Sopenharmony_ci // this gives us a smooth step across approximately one fragment 462cb93a386Sopenharmony_ci fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); 463cb93a386Sopenharmony_ci } 464cb93a386Sopenharmony_ci // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are 465cb93a386Sopenharmony_ci // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want distance 466cb93a386Sopenharmony_ci // mapped linearly to coverage, so use a linear step: 467cb93a386Sopenharmony_ci if (isGammaCorrect) { 468cb93a386Sopenharmony_ci fragBuilder->codeAppend( 469cb93a386Sopenharmony_ci "half val = saturate((distance + afwidth) / (2.0 * afwidth));"); 470cb93a386Sopenharmony_ci } else { 471cb93a386Sopenharmony_ci fragBuilder->codeAppend("half val = smoothstep(-afwidth, afwidth, distance);"); 472cb93a386Sopenharmony_ci } 473cb93a386Sopenharmony_ci 474cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s = half4(val);", args.fOutputCoverage); 475cb93a386Sopenharmony_ci } 476cb93a386Sopenharmony_ci 477cb93a386Sopenharmony_ci SkMatrix fMatrix; // view matrix if perspective, local matrix otherwise 478cb93a386Sopenharmony_ci UniformHandle fMatrixUniform; 479cb93a386Sopenharmony_ci 480cb93a386Sopenharmony_ci SkISize fAtlasDimensions; 481cb93a386Sopenharmony_ci UniformHandle fAtlasDimensionsInvUniform; 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci using INHERITED = ProgramImpl; 484cb93a386Sopenharmony_ci}; 485cb93a386Sopenharmony_ci 486cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 487cb93a386Sopenharmony_ci 488cb93a386Sopenharmony_ciGrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(const GrShaderCaps& caps, 489cb93a386Sopenharmony_ci const SkMatrix& matrix, 490cb93a386Sopenharmony_ci bool wideColor, 491cb93a386Sopenharmony_ci const GrSurfaceProxyView* views, 492cb93a386Sopenharmony_ci int numViews, 493cb93a386Sopenharmony_ci GrSamplerState params, 494cb93a386Sopenharmony_ci uint32_t flags) 495cb93a386Sopenharmony_ci : INHERITED(kGrDistanceFieldPathGeoProc_ClassID) 496cb93a386Sopenharmony_ci , fMatrix(matrix) 497cb93a386Sopenharmony_ci , fFlags(flags & kNonLCD_DistanceFieldEffectMask) { 498cb93a386Sopenharmony_ci SkASSERT(numViews <= kMaxTextures); 499cb93a386Sopenharmony_ci SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask)); 500cb93a386Sopenharmony_ci 501cb93a386Sopenharmony_ci fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 502cb93a386Sopenharmony_ci fInColor = MakeColorAttribute("inColor", wideColor); 503cb93a386Sopenharmony_ci fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType, 504cb93a386Sopenharmony_ci caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType}; 505cb93a386Sopenharmony_ci this->setVertexAttributes(&fInPosition, 3); 506cb93a386Sopenharmony_ci 507cb93a386Sopenharmony_ci if (numViews) { 508cb93a386Sopenharmony_ci fAtlasDimensions = views[0].proxy()->dimensions(); 509cb93a386Sopenharmony_ci } 510cb93a386Sopenharmony_ci 511cb93a386Sopenharmony_ci for (int i = 0; i < numViews; ++i) { 512cb93a386Sopenharmony_ci const GrSurfaceProxy* proxy = views[i].proxy(); 513cb93a386Sopenharmony_ci SkASSERT(proxy); 514cb93a386Sopenharmony_ci SkASSERT(proxy->dimensions() == fAtlasDimensions); 515cb93a386Sopenharmony_ci fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle()); 516cb93a386Sopenharmony_ci } 517cb93a386Sopenharmony_ci this->setTextureSamplerCnt(numViews); 518cb93a386Sopenharmony_ci} 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_civoid GrDistanceFieldPathGeoProc::addNewViews(const GrSurfaceProxyView* views, 521cb93a386Sopenharmony_ci int numViews, 522cb93a386Sopenharmony_ci GrSamplerState params) { 523cb93a386Sopenharmony_ci SkASSERT(numViews <= kMaxTextures); 524cb93a386Sopenharmony_ci // Just to make sure we don't try to add too many proxies 525cb93a386Sopenharmony_ci numViews = std::min(numViews, kMaxTextures); 526cb93a386Sopenharmony_ci 527cb93a386Sopenharmony_ci if (!fTextureSamplers[0].isInitialized()) { 528cb93a386Sopenharmony_ci fAtlasDimensions = views[0].proxy()->dimensions(); 529cb93a386Sopenharmony_ci } 530cb93a386Sopenharmony_ci 531cb93a386Sopenharmony_ci for (int i = 0; i < numViews; ++i) { 532cb93a386Sopenharmony_ci const GrSurfaceProxy* proxy = views[i].proxy(); 533cb93a386Sopenharmony_ci SkASSERT(proxy); 534cb93a386Sopenharmony_ci SkASSERT(proxy->dimensions() == fAtlasDimensions); 535cb93a386Sopenharmony_ci if (!fTextureSamplers[i].isInitialized()) { 536cb93a386Sopenharmony_ci fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle()); 537cb93a386Sopenharmony_ci } 538cb93a386Sopenharmony_ci } 539cb93a386Sopenharmony_ci this->setTextureSamplerCnt(numViews); 540cb93a386Sopenharmony_ci} 541cb93a386Sopenharmony_ci 542cb93a386Sopenharmony_ciSkString GrDistanceFieldPathGeoProc::getShaderDfxInfo() const 543cb93a386Sopenharmony_ci{ 544cb93a386Sopenharmony_ci SkString format; 545cb93a386Sopenharmony_ci format.printf("ShaderDfx_GrDistanceFieldPathGeoProc_%d_%d_%d_%d_%d", fFlags, numTextureSamplers(), 546cb93a386Sopenharmony_ci fMatrix.isIdentity(), fMatrix.isScaleTranslate(), fMatrix.hasPerspective()); 547cb93a386Sopenharmony_ci return format; 548cb93a386Sopenharmony_ci} 549cb93a386Sopenharmony_ci 550cb93a386Sopenharmony_civoid GrDistanceFieldPathGeoProc::addToKey(const GrShaderCaps& caps, 551cb93a386Sopenharmony_ci GrProcessorKeyBuilder* b) const { 552cb93a386Sopenharmony_ci uint32_t key = fFlags; 553cb93a386Sopenharmony_ci key |= ProgramImpl::ComputeMatrixKey(caps, fMatrix) << 16; 554cb93a386Sopenharmony_ci key |= fMatrix.hasPerspective() << (16 + ProgramImpl::kMatrixKeyBits); 555cb93a386Sopenharmony_ci b->add32(key); 556cb93a386Sopenharmony_ci b->add32(this->numTextureSamplers()); 557cb93a386Sopenharmony_ci} 558cb93a386Sopenharmony_ci 559cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl> GrDistanceFieldPathGeoProc::makeProgramImpl( 560cb93a386Sopenharmony_ci const GrShaderCaps&) const { 561cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 562cb93a386Sopenharmony_ci} 563cb93a386Sopenharmony_ci 564cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 565cb93a386Sopenharmony_ci 566cb93a386Sopenharmony_ciGR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc); 567cb93a386Sopenharmony_ci 568cb93a386Sopenharmony_ci#if GR_TEST_UTILS 569cb93a386Sopenharmony_ciGrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) { 570cb93a386Sopenharmony_ci auto [view, ct, at] = d->randomAlphaOnlyView(); 571cb93a386Sopenharmony_ci 572cb93a386Sopenharmony_ci GrSamplerState::WrapMode wrapModes[2]; 573cb93a386Sopenharmony_ci GrTest::TestWrapModes(d->fRandom, wrapModes); 574cb93a386Sopenharmony_ci GrSamplerState samplerState(wrapModes, d->fRandom->nextBool() 575cb93a386Sopenharmony_ci ? GrSamplerState::Filter::kLinear 576cb93a386Sopenharmony_ci : GrSamplerState::Filter::kNearest); 577cb93a386Sopenharmony_ci 578cb93a386Sopenharmony_ci uint32_t flags = 0; 579cb93a386Sopenharmony_ci flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0; 580cb93a386Sopenharmony_ci if (flags & kSimilarity_DistanceFieldEffectFlag) { 581cb93a386Sopenharmony_ci flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0; 582cb93a386Sopenharmony_ci } 583cb93a386Sopenharmony_ci SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom); 584cb93a386Sopenharmony_ci bool wideColor = d->fRandom->nextBool(); 585cb93a386Sopenharmony_ci return GrDistanceFieldPathGeoProc::Make(d->allocator(), *d->caps()->shaderCaps(), 586cb93a386Sopenharmony_ci localMatrix, 587cb93a386Sopenharmony_ci wideColor, 588cb93a386Sopenharmony_ci &view, 1, 589cb93a386Sopenharmony_ci samplerState, 590cb93a386Sopenharmony_ci flags); 591cb93a386Sopenharmony_ci} 592cb93a386Sopenharmony_ci#endif 593cb93a386Sopenharmony_ci 594cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 595cb93a386Sopenharmony_ci 596cb93a386Sopenharmony_ciclass GrDistanceFieldLCDTextGeoProc::Impl : public ProgramImpl { 597cb93a386Sopenharmony_cipublic: 598cb93a386Sopenharmony_ci void setData(const GrGLSLProgramDataManager& pdman, 599cb93a386Sopenharmony_ci const GrShaderCaps& shaderCaps, 600cb93a386Sopenharmony_ci const GrGeometryProcessor& geomProc) override { 601cb93a386Sopenharmony_ci SkASSERT(fDistanceAdjustUni.isValid()); 602cb93a386Sopenharmony_ci 603cb93a386Sopenharmony_ci const GrDistanceFieldLCDTextGeoProc& dflcd = geomProc.cast<GrDistanceFieldLCDTextGeoProc>(); 604cb93a386Sopenharmony_ci GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dflcd.fDistanceAdjust; 605cb93a386Sopenharmony_ci if (wa != fDistanceAdjust) { 606cb93a386Sopenharmony_ci pdman.set3f(fDistanceAdjustUni, wa.fR, wa.fG, wa.fB); 607cb93a386Sopenharmony_ci fDistanceAdjust = wa; 608cb93a386Sopenharmony_ci } 609cb93a386Sopenharmony_ci 610cb93a386Sopenharmony_ci const SkISize& atlasDimensions = dflcd.fAtlasDimensions; 611cb93a386Sopenharmony_ci SkASSERT(SkIsPow2(atlasDimensions.fWidth) && SkIsPow2(atlasDimensions.fHeight)); 612cb93a386Sopenharmony_ci if (fAtlasDimensions != atlasDimensions) { 613cb93a386Sopenharmony_ci pdman.set2f(fAtlasDimensionsInvUniform, 614cb93a386Sopenharmony_ci 1.0f / atlasDimensions.fWidth, 615cb93a386Sopenharmony_ci 1.0f / atlasDimensions.fHeight); 616cb93a386Sopenharmony_ci fAtlasDimensions = atlasDimensions; 617cb93a386Sopenharmony_ci } 618cb93a386Sopenharmony_ci SetTransform(pdman, shaderCaps, fLocalMatrixUniform, dflcd.fLocalMatrix, &fLocalMatrix); 619cb93a386Sopenharmony_ci } 620cb93a386Sopenharmony_ci 621cb93a386Sopenharmony_ciprivate: 622cb93a386Sopenharmony_ci void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { 623cb93a386Sopenharmony_ci const GrDistanceFieldLCDTextGeoProc& dfTexEffect = 624cb93a386Sopenharmony_ci args.fGeomProc.cast<GrDistanceFieldLCDTextGeoProc>(); 625cb93a386Sopenharmony_ci 626cb93a386Sopenharmony_ci GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; 627cb93a386Sopenharmony_ci GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; 628cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 629cb93a386Sopenharmony_ci 630cb93a386Sopenharmony_ci // emit attributes 631cb93a386Sopenharmony_ci varyingHandler->emitAttributes(dfTexEffect); 632cb93a386Sopenharmony_ci 633cb93a386Sopenharmony_ci const char* atlasDimensionsInvName; 634cb93a386Sopenharmony_ci fAtlasDimensionsInvUniform = uniformHandler->addUniform(nullptr, 635cb93a386Sopenharmony_ci kVertex_GrShaderFlag, 636cb93a386Sopenharmony_ci kFloat2_GrSLType, 637cb93a386Sopenharmony_ci "AtlasDimensionsInv", 638cb93a386Sopenharmony_ci &atlasDimensionsInvName); 639cb93a386Sopenharmony_ci 640cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci // setup pass through color 643cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s;\n", args.fOutputColor); 644cb93a386Sopenharmony_ci varyingHandler->addPassThroughAttribute(dfTexEffect.fInColor.asShaderVar(), 645cb93a386Sopenharmony_ci args.fOutputColor); 646cb93a386Sopenharmony_ci 647cb93a386Sopenharmony_ci // Setup position 648cb93a386Sopenharmony_ci gpArgs->fPositionVar = dfTexEffect.fInPosition.asShaderVar(); 649cb93a386Sopenharmony_ci WriteLocalCoord(vertBuilder, 650cb93a386Sopenharmony_ci uniformHandler, 651cb93a386Sopenharmony_ci *args.fShaderCaps, 652cb93a386Sopenharmony_ci gpArgs, 653cb93a386Sopenharmony_ci dfTexEffect.fInPosition.asShaderVar(), 654cb93a386Sopenharmony_ci dfTexEffect.fLocalMatrix, 655cb93a386Sopenharmony_ci &fLocalMatrixUniform); 656cb93a386Sopenharmony_ci 657cb93a386Sopenharmony_ci // set up varyings 658cb93a386Sopenharmony_ci GrGLSLVarying uv, texIdx, st; 659cb93a386Sopenharmony_ci append_index_uv_varyings(args, 660cb93a386Sopenharmony_ci dfTexEffect.numTextureSamplers(), 661cb93a386Sopenharmony_ci dfTexEffect.fInTextureCoords.name(), 662cb93a386Sopenharmony_ci atlasDimensionsInvName, 663cb93a386Sopenharmony_ci &uv, 664cb93a386Sopenharmony_ci &texIdx, 665cb93a386Sopenharmony_ci &st); 666cb93a386Sopenharmony_ci 667cb93a386Sopenharmony_ci GrGLSLVarying delta(kFloat_GrSLType); 668cb93a386Sopenharmony_ci varyingHandler->addVarying("Delta", &delta); 669cb93a386Sopenharmony_ci if (dfTexEffect.fFlags & kBGR_DistanceFieldEffectFlag) { 670cb93a386Sopenharmony_ci vertBuilder->codeAppendf("%s = -%s.x/3.0;", delta.vsOut(), atlasDimensionsInvName); 671cb93a386Sopenharmony_ci } else { 672cb93a386Sopenharmony_ci vertBuilder->codeAppendf("%s = %s.x/3.0;", delta.vsOut(), atlasDimensionsInvName); 673cb93a386Sopenharmony_ci } 674cb93a386Sopenharmony_ci 675cb93a386Sopenharmony_ci // add frag shader code 676cb93a386Sopenharmony_ci bool isUniformScale = (dfTexEffect.fFlags & kUniformScale_DistanceFieldEffectMask) == 677cb93a386Sopenharmony_ci kUniformScale_DistanceFieldEffectMask; 678cb93a386Sopenharmony_ci bool isSimilarity = SkToBool(dfTexEffect.fFlags & kSimilarity_DistanceFieldEffectFlag ); 679cb93a386Sopenharmony_ci bool isGammaCorrect = SkToBool(dfTexEffect.fFlags & kGammaCorrect_DistanceFieldEffectFlag); 680cb93a386Sopenharmony_ci 681cb93a386Sopenharmony_ci // create LCD offset adjusted by inverse of transform 682cb93a386Sopenharmony_ci // Use highp to work around aliasing issues 683cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 uv = %s;\n", uv.fsIn()); 684cb93a386Sopenharmony_ci 685cb93a386Sopenharmony_ci if (isUniformScale) { 686cb93a386Sopenharmony_ci if (args.fShaderCaps->avoidDfDxForGradientsWhenPossible()) { 687cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half st_grad_len = half(abs(dFdy(%s.y)));", st.fsIn()); 688cb93a386Sopenharmony_ci } else { 689cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half st_grad_len = half(abs(dFdx(%s.x)));", st.fsIn()); 690cb93a386Sopenharmony_ci } 691cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 offset = half2(half(st_grad_len*%s), 0.0);", 692cb93a386Sopenharmony_ci delta.fsIn()); 693cb93a386Sopenharmony_ci } else if (isSimilarity) { 694cb93a386Sopenharmony_ci // For a similarity matrix with rotation, the gradient will not be aligned 695cb93a386Sopenharmony_ci // with the texel coordinate axes, so we need to calculate it. 696cb93a386Sopenharmony_ci if (args.fShaderCaps->avoidDfDxForGradientsWhenPossible()) { 697cb93a386Sopenharmony_ci // We use dFdy instead and rotate -90 degrees to get the gradient in the x 698cb93a386Sopenharmony_ci // direction. 699cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 st_grad = half2(dFdy(%s));", st.fsIn()); 700cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 offset = half2(%s*float2(st_grad.y, -st_grad.x));", 701cb93a386Sopenharmony_ci delta.fsIn()); 702cb93a386Sopenharmony_ci } else { 703cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 st_grad = half2(dFdx(%s));", st.fsIn()); 704cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 offset = half(%s)*st_grad;", delta.fsIn()); 705cb93a386Sopenharmony_ci } 706cb93a386Sopenharmony_ci fragBuilder->codeAppend("half st_grad_len = length(st_grad);"); 707cb93a386Sopenharmony_ci } else { 708cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 st = half2(%s);\n", st.fsIn()); 709cb93a386Sopenharmony_ci 710cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 Jdx = half2(dFdx(st));"); 711cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 Jdy = half2(dFdy(st));"); 712cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 offset = half2(half(%s))*Jdx;", delta.fsIn()); 713cb93a386Sopenharmony_ci } 714cb93a386Sopenharmony_ci 715cb93a386Sopenharmony_ci // sample the texture by index 716cb93a386Sopenharmony_ci fragBuilder->codeAppend("half4 texColor;"); 717cb93a386Sopenharmony_ci append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(), 718cb93a386Sopenharmony_ci texIdx, "uv", "texColor"); 719cb93a386Sopenharmony_ci 720cb93a386Sopenharmony_ci // green is distance to uv center 721cb93a386Sopenharmony_ci fragBuilder->codeAppend("half3 distance;"); 722cb93a386Sopenharmony_ci fragBuilder->codeAppend("distance.y = texColor.r;"); 723cb93a386Sopenharmony_ci // red is distance to left offset 724cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 uv_adjusted = half2(uv) - offset;"); 725cb93a386Sopenharmony_ci append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(), 726cb93a386Sopenharmony_ci texIdx, "uv_adjusted", "texColor"); 727cb93a386Sopenharmony_ci fragBuilder->codeAppend("distance.x = texColor.r;"); 728cb93a386Sopenharmony_ci // blue is distance to right offset 729cb93a386Sopenharmony_ci fragBuilder->codeAppend("uv_adjusted = half2(uv) + offset;"); 730cb93a386Sopenharmony_ci append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(), 731cb93a386Sopenharmony_ci texIdx, "uv_adjusted", "texColor"); 732cb93a386Sopenharmony_ci fragBuilder->codeAppend("distance.z = texColor.r;"); 733cb93a386Sopenharmony_ci 734cb93a386Sopenharmony_ci fragBuilder->codeAppend("distance = " 735cb93a386Sopenharmony_ci "half3(" SK_DistanceFieldMultiplier ")*(distance - half3(" SK_DistanceFieldThreshold"));"); 736cb93a386Sopenharmony_ci 737cb93a386Sopenharmony_ci // adjust width based on gamma 738cb93a386Sopenharmony_ci const char* distanceAdjustUniName = nullptr; 739cb93a386Sopenharmony_ci fDistanceAdjustUni = uniformHandler->addUniform(nullptr, kFragment_GrShaderFlag, 740cb93a386Sopenharmony_ci kHalf3_GrSLType, "DistanceAdjust", 741cb93a386Sopenharmony_ci &distanceAdjustUniName); 742cb93a386Sopenharmony_ci fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); 743cb93a386Sopenharmony_ci 744cb93a386Sopenharmony_ci // To be strictly correct, we should compute the anti-aliasing factor separately 745cb93a386Sopenharmony_ci // for each color component. However, this is only important when using perspective 746cb93a386Sopenharmony_ci // transformations, and even then using a single factor seems like a reasonable 747cb93a386Sopenharmony_ci // trade-off between quality and speed. 748cb93a386Sopenharmony_ci fragBuilder->codeAppend("half afwidth;"); 749cb93a386Sopenharmony_ci if (isSimilarity) { 750cb93a386Sopenharmony_ci // For similarity transform (uniform scale-only is a subset of this), we adjust for the 751cb93a386Sopenharmony_ci // effect of the transformation on the distance by using the length of the gradient of 752cb93a386Sopenharmony_ci // the texture coordinates. We use st coordinates to ensure we're mapping 1:1 from texel 753cb93a386Sopenharmony_ci // space to pixel space. 754cb93a386Sopenharmony_ci 755cb93a386Sopenharmony_ci // this gives us a smooth step across approximately one fragment 756cb93a386Sopenharmony_ci fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*st_grad_len;"); 757cb93a386Sopenharmony_ci } else { 758cb93a386Sopenharmony_ci // For general transforms, to determine the amount of correction we multiply a unit 759cb93a386Sopenharmony_ci // vector pointing along the SDF gradient direction by the Jacobian of the st coords 760cb93a386Sopenharmony_ci // (which is the inverse transform for this fragment) and take the length of the result. 761cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 dist_grad = half2(half(dFdx(distance.r)), " 762cb93a386Sopenharmony_ci "half(dFdy(distance.r)));"); 763cb93a386Sopenharmony_ci // the length of the gradient may be 0, so we need to check for this 764cb93a386Sopenharmony_ci // this also compensates for the Adreno, which likes to drop tiles on division by 0 765cb93a386Sopenharmony_ci fragBuilder->codeAppend("half dg_len2 = dot(dist_grad, dist_grad);"); 766cb93a386Sopenharmony_ci fragBuilder->codeAppend("if (dg_len2 < 0.0001) {"); 767cb93a386Sopenharmony_ci fragBuilder->codeAppend("dist_grad = half2(0.7071, 0.7071);"); 768cb93a386Sopenharmony_ci fragBuilder->codeAppend("} else {"); 769cb93a386Sopenharmony_ci fragBuilder->codeAppend("dist_grad = dist_grad*half(inversesqrt(dg_len2));"); 770cb93a386Sopenharmony_ci fragBuilder->codeAppend("}"); 771cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 grad = half2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); 772cb93a386Sopenharmony_ci fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); 773cb93a386Sopenharmony_ci 774cb93a386Sopenharmony_ci // this gives us a smooth step across approximately one fragment 775cb93a386Sopenharmony_ci fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); 776cb93a386Sopenharmony_ci } 777cb93a386Sopenharmony_ci 778cb93a386Sopenharmony_ci // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are 779cb93a386Sopenharmony_ci // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want distance 780cb93a386Sopenharmony_ci // mapped linearly to coverage, so use a linear step: 781cb93a386Sopenharmony_ci if (isGammaCorrect) { 782cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s = " 783cb93a386Sopenharmony_ci "half4(saturate((distance + half3(afwidth)) / half3(2.0 * afwidth)), 1.0);", 784cb93a386Sopenharmony_ci args.fOutputCoverage); 785cb93a386Sopenharmony_ci } else { 786cb93a386Sopenharmony_ci fragBuilder->codeAppendf( 787cb93a386Sopenharmony_ci "half4 %s = half4(smoothstep(half3(-afwidth), half3(afwidth), distance), 1.0);", 788cb93a386Sopenharmony_ci args.fOutputCoverage); 789cb93a386Sopenharmony_ci } 790cb93a386Sopenharmony_ci } 791cb93a386Sopenharmony_ci 792cb93a386Sopenharmony_ciprivate: 793cb93a386Sopenharmony_ci DistanceAdjust fDistanceAdjust = DistanceAdjust::Make(1.0f, 1.0f, 1.0f); 794cb93a386Sopenharmony_ci SkISize fAtlasDimensions = {-1, -1}; 795cb93a386Sopenharmony_ci SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); 796cb93a386Sopenharmony_ci 797cb93a386Sopenharmony_ci UniformHandle fDistanceAdjustUni; 798cb93a386Sopenharmony_ci UniformHandle fAtlasDimensionsInvUniform; 799cb93a386Sopenharmony_ci UniformHandle fLocalMatrixUniform; 800cb93a386Sopenharmony_ci}; 801cb93a386Sopenharmony_ci 802cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 803cb93a386Sopenharmony_ci 804cb93a386Sopenharmony_ciGrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(const GrShaderCaps& caps, 805cb93a386Sopenharmony_ci const GrSurfaceProxyView* views, 806cb93a386Sopenharmony_ci int numViews, 807cb93a386Sopenharmony_ci GrSamplerState params, 808cb93a386Sopenharmony_ci DistanceAdjust distanceAdjust, 809cb93a386Sopenharmony_ci uint32_t flags, 810cb93a386Sopenharmony_ci const SkMatrix& localMatrix) 811cb93a386Sopenharmony_ci : INHERITED(kGrDistanceFieldLCDTextGeoProc_ClassID) 812cb93a386Sopenharmony_ci , fLocalMatrix(localMatrix) 813cb93a386Sopenharmony_ci , fDistanceAdjust(distanceAdjust) 814cb93a386Sopenharmony_ci , fFlags(flags & kLCD_DistanceFieldEffectMask) { 815cb93a386Sopenharmony_ci SkASSERT(numViews <= kMaxTextures); 816cb93a386Sopenharmony_ci SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag)); 817cb93a386Sopenharmony_ci 818cb93a386Sopenharmony_ci if (fFlags & kPerspective_DistanceFieldEffectFlag) { 819cb93a386Sopenharmony_ci fInPosition = {"inPosition", kFloat3_GrVertexAttribType, kFloat3_GrSLType}; 820cb93a386Sopenharmony_ci } else { 821cb93a386Sopenharmony_ci fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 822cb93a386Sopenharmony_ci } 823cb93a386Sopenharmony_ci fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType}; 824cb93a386Sopenharmony_ci fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType, 825cb93a386Sopenharmony_ci caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType}; 826cb93a386Sopenharmony_ci this->setVertexAttributes(&fInPosition, 3); 827cb93a386Sopenharmony_ci 828cb93a386Sopenharmony_ci if (numViews) { 829cb93a386Sopenharmony_ci fAtlasDimensions = views[0].proxy()->dimensions(); 830cb93a386Sopenharmony_ci } 831cb93a386Sopenharmony_ci 832cb93a386Sopenharmony_ci for (int i = 0; i < numViews; ++i) { 833cb93a386Sopenharmony_ci const GrSurfaceProxy* proxy = views[i].proxy(); 834cb93a386Sopenharmony_ci SkASSERT(proxy); 835cb93a386Sopenharmony_ci SkASSERT(proxy->dimensions() == fAtlasDimensions); 836cb93a386Sopenharmony_ci fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle()); 837cb93a386Sopenharmony_ci } 838cb93a386Sopenharmony_ci this->setTextureSamplerCnt(numViews); 839cb93a386Sopenharmony_ci} 840cb93a386Sopenharmony_ci 841cb93a386Sopenharmony_civoid GrDistanceFieldLCDTextGeoProc::addNewViews(const GrSurfaceProxyView* views, 842cb93a386Sopenharmony_ci int numViews, 843cb93a386Sopenharmony_ci GrSamplerState params) { 844cb93a386Sopenharmony_ci SkASSERT(numViews <= kMaxTextures); 845cb93a386Sopenharmony_ci // Just to make sure we don't try to add too many proxies 846cb93a386Sopenharmony_ci numViews = std::min(numViews, kMaxTextures); 847cb93a386Sopenharmony_ci 848cb93a386Sopenharmony_ci if (!fTextureSamplers[0].isInitialized()) { 849cb93a386Sopenharmony_ci fAtlasDimensions = views[0].proxy()->dimensions(); 850cb93a386Sopenharmony_ci } 851cb93a386Sopenharmony_ci 852cb93a386Sopenharmony_ci for (int i = 0; i < numViews; ++i) { 853cb93a386Sopenharmony_ci const GrSurfaceProxy* proxy = views[i].proxy(); 854cb93a386Sopenharmony_ci SkASSERT(proxy); 855cb93a386Sopenharmony_ci SkASSERT(proxy->dimensions() == fAtlasDimensions); 856cb93a386Sopenharmony_ci if (!fTextureSamplers[i].isInitialized()) { 857cb93a386Sopenharmony_ci fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle()); 858cb93a386Sopenharmony_ci } 859cb93a386Sopenharmony_ci } 860cb93a386Sopenharmony_ci this->setTextureSamplerCnt(numViews); 861cb93a386Sopenharmony_ci} 862cb93a386Sopenharmony_ci 863cb93a386Sopenharmony_ciSkString GrDistanceFieldLCDTextGeoProc::getShaderDfxInfo() const 864cb93a386Sopenharmony_ci{ 865cb93a386Sopenharmony_ci SkString format; 866cb93a386Sopenharmony_ci format.printf("ShaderDfx_GrDistanceFieldLCDTextGeoProc_%d_%d_%d_%d_%d", fFlags, numTextureSamplers(), 867cb93a386Sopenharmony_ci fLocalMatrix.isIdentity(), fLocalMatrix.isScaleTranslate(), fLocalMatrix.hasPerspective()); 868cb93a386Sopenharmony_ci return format; 869cb93a386Sopenharmony_ci} 870cb93a386Sopenharmony_ci 871cb93a386Sopenharmony_civoid GrDistanceFieldLCDTextGeoProc::addToKey(const GrShaderCaps& caps, 872cb93a386Sopenharmony_ci GrProcessorKeyBuilder* b) const { 873cb93a386Sopenharmony_ci uint32_t key = 0; 874cb93a386Sopenharmony_ci key |= ProgramImpl::ComputeMatrixKey(caps, fLocalMatrix); 875cb93a386Sopenharmony_ci key |= fFlags << 16; 876cb93a386Sopenharmony_ci b->add32(key); 877cb93a386Sopenharmony_ci b->add32(this->numTextureSamplers()); 878cb93a386Sopenharmony_ci} 879cb93a386Sopenharmony_ci 880cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl> GrDistanceFieldLCDTextGeoProc::makeProgramImpl( 881cb93a386Sopenharmony_ci const GrShaderCaps&) const { 882cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 883cb93a386Sopenharmony_ci} 884cb93a386Sopenharmony_ci 885cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 886cb93a386Sopenharmony_ci 887cb93a386Sopenharmony_ciGR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc); 888cb93a386Sopenharmony_ci 889cb93a386Sopenharmony_ci#if GR_TEST_UTILS 890cb93a386Sopenharmony_ciGrGeometryProcessor* GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) { 891cb93a386Sopenharmony_ci auto [view, ct, at] = d->randomView(); 892cb93a386Sopenharmony_ci 893cb93a386Sopenharmony_ci GrSamplerState::WrapMode wrapModes[2]; 894cb93a386Sopenharmony_ci GrTest::TestWrapModes(d->fRandom, wrapModes); 895cb93a386Sopenharmony_ci GrSamplerState samplerState(wrapModes, d->fRandom->nextBool() 896cb93a386Sopenharmony_ci ? GrSamplerState::Filter::kLinear 897cb93a386Sopenharmony_ci : GrSamplerState::Filter::kNearest); 898cb93a386Sopenharmony_ci DistanceAdjust wa = { 0.0f, 0.1f, -0.1f }; 899cb93a386Sopenharmony_ci uint32_t flags = kUseLCD_DistanceFieldEffectFlag; 900cb93a386Sopenharmony_ci flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0; 901cb93a386Sopenharmony_ci if (flags & kSimilarity_DistanceFieldEffectFlag) { 902cb93a386Sopenharmony_ci flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0; 903cb93a386Sopenharmony_ci } 904cb93a386Sopenharmony_ci flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0; 905cb93a386Sopenharmony_ci SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom); 906cb93a386Sopenharmony_ci 907cb93a386Sopenharmony_ci return GrDistanceFieldLCDTextGeoProc::Make(d->allocator(), *d->caps()->shaderCaps(), &view, 908cb93a386Sopenharmony_ci 1, samplerState, wa, flags, localMatrix); 909cb93a386Sopenharmony_ci} 910cb93a386Sopenharmony_ci#endif 911