62 const float border[4],
63 bool alwaysUseShaderTileMode,
67 float fA = 0.f, fB = 0.f;
69 Span makeInset(
float o)
const {
70 Span r = {fA + o, fB - o};
72 r.fA = r.fB = (r.fA + r.fB) / 2;
77 bool contains(Span r)
const {
return fA <= r.fA && fB >= r.fB; }
80 ShaderMode fShaderMode = ShaderMode::kNone;
81 Span fShaderSubset = {};
82 Span fShaderClamp = {};
83 Wrap fHWWrap = Wrap::kClamp;
87 auto filter = sampler.
filter();
90 auto canDoWrapInHW = [&](
int size,
Wrap wrap) {
91 if (alwaysUseShaderTileMode) {
95 if (wrap == Wrap::kClampToBorder &&
103 !(wrap == Wrap::kClamp || wrap == Wrap::kClampToBorder)) {
116 bool aniso = sampler.
isAniso();
120 (!domain || !subset.
contains(*domain));
121 bool needsShaderWrap = !canDoWrapInHW(dim.
width(), sampler.
wrapModeX()) ||
123 if (needsShaderWrap || anisoSubset) {
125 ? MipmapMode::kLinear
135 auto resolve = [&](
int size,
Wrap wrap, Span subset, Span domain,
float linearFilterInset) {
137 bool canDoModeInHW = canDoWrapInHW(size, wrap);
138 if (canDoModeInHW && size > 0 && subset.fA <= 0 && subset.fB >= size) {
139 r.fShaderMode = ShaderMode::kNone;
141 r.fShaderSubset = r.fShaderClamp = {0, 0};
145 r.fShaderSubset = subset;
146 bool domainIsSafe =
false;
147 if (filter == Filter::kNearest) {
148 Span isubset{std::floor(subset.fA), std::ceil(subset.fB)};
149 if (domain.fA > isubset.fA && domain.fB < isubset.fB) {
158 if (r.fShaderClamp.contains(domain)) {
162 if (!alwaysUseShaderTileMode && domainIsSafe) {
166 r.fShaderMode = ShaderMode::kNone;
167 r.fHWWrap = Wrap::kClamp;
168 r.fShaderSubset = r.fShaderClamp = {0, 0};
171 r.fShaderMode = GetShaderMode(wrap, filter, mm);
172 r.fHWWrap = Wrap::kClamp;
179 auto domainX = domain ? Span{domain->
fLeft, domain->
fRight}
181 x = resolve(dim.
width(), sampler.
wrapModeX(), subsetX, domainX, linearFilterInset.
fX);
184 auto domainY = domain ? Span{domain->
fTop, domain->
fBottom}
186 y = resolve(dim.
height(), sampler.
wrapModeY(), subsetY, domainY, linearFilterInset.
fY);
200 x.fShaderSubset.fB,
y.fShaderSubset.fB};
202 x.fShaderClamp.fB,
y.fShaderClamp.fB};
203 std::copy_n(border, 4,
fBorder);
373 using ShaderMode = GrTextureEffect::ShaderMode;
376 auto* fb =
args.fFragBuilder;
378 if (te.fShaderModes[0] == ShaderMode::kNone &&
379 te.fShaderModes[1] == ShaderMode::kNone) {
380 fb->codeAppendf(
"return ");
381 fb->appendTextureLookup(fSamplerHandle,
args.fSampleCoord);
382 fb->codeAppendf(
";");
403 fb->codeAppendf(
"float2 inCoord = %s;",
args.fSampleCoord);
405 const auto& m = te.fShaderModes;
407 const char* borderName =
nullptr;
408 if (te.hasClampToBorderShaderMode()) {
409 fBorderUni =
args.fUniformHandler->addUniform(
412 auto modeUsesSubset = [](ShaderMode m) {
414 case ShaderMode::kNone:
return false;
415 case ShaderMode::kClamp:
return false;
416 case ShaderMode::kRepeat_Nearest_None:
return true;
417 case ShaderMode::kRepeat_Linear_None:
return true;
418 case ShaderMode::kRepeat_Nearest_Mipmap:
return true;
419 case ShaderMode::kRepeat_Linear_Mipmap:
return true;
420 case ShaderMode::kMirrorRepeat:
return true;
421 case ShaderMode::kClampToBorder_Nearest:
return true;
422 case ShaderMode::kClampToBorder_Filter:
return true;
427 auto modeUsesClamp = [](ShaderMode m) {
429 case ShaderMode::kNone:
return false;
430 case ShaderMode::kClamp:
return true;
431 case ShaderMode::kRepeat_Nearest_None:
return true;
432 case ShaderMode::kRepeat_Linear_None:
return true;
433 case ShaderMode::kRepeat_Nearest_Mipmap:
return true;
434 case ShaderMode::kRepeat_Linear_Mipmap:
return true;
435 case ShaderMode::kMirrorRepeat:
return true;
436 case ShaderMode::kClampToBorder_Nearest:
return false;
437 case ShaderMode::kClampToBorder_Filter:
return true;
442 bool useSubset[2] = {modeUsesSubset(m[0]), modeUsesSubset(m[1])};
443 bool useClamp [2] = {modeUsesClamp (m[0]), modeUsesClamp (m[1])};
445 const char* subsetName =
nullptr;
446 if (useSubset[0] || useSubset[1]) {
447 fSubsetUni =
args.fUniformHandler->addUniform(
451 const char* clampName =
nullptr;
452 if (useClamp[0] || useClamp[1]) {
453 fClampUni =
args.fUniformHandler->addUniform(
457 bool unormCoordsRequiredForShaderMode = ShaderModeRequiresUnormCoord(m[0]) ||
458 ShaderModeRequiresUnormCoord(m[1]);
461 SkASSERT(!(unormCoordsRequiredForShaderMode && te.matrixEffectShouldNormalize()));
462 bool sampleCoordsMustBeNormalized =
465 const char* idims =
nullptr;
466 if (unormCoordsRequiredForShaderMode && sampleCoordsMustBeNormalized) {
474 auto read = [&](
const char* coord) {
478 normCoord.
printf(
"(%s) * %s", coord, idims);
482 fb->appendTextureLookup(&
result, fSamplerHandle, normCoord.
c_str());
487 auto subsetCoord = [&](ShaderMode mode,
488 const char* coordSwizzle,
489 const char* subsetStartSwizzle,
490 const char* subsetStopSwizzle,
491 const char* extraCoord,
492 const char* coordWeight) {
496 case ShaderMode::kNone:
497 case ShaderMode::kClampToBorder_Nearest:
498 case ShaderMode::kClampToBorder_Filter:
499 case ShaderMode::kClamp:
500 fb->codeAppendf(
"subsetCoord.%s = inCoord.%s;", coordSwizzle, coordSwizzle);
502 case ShaderMode::kRepeat_Nearest_None:
503 case ShaderMode::kRepeat_Linear_None:
505 "subsetCoord.%s = mod(inCoord.%s - %s.%s, %s.%s - %s.%s) + %s.%s;",
506 coordSwizzle, coordSwizzle, subsetName, subsetStartSwizzle, subsetName,
507 subsetStopSwizzle, subsetName, subsetStartSwizzle, subsetName,
510 case ShaderMode::kRepeat_Nearest_Mipmap:
511 case ShaderMode::kRepeat_Linear_Mipmap:
524 fb->codeAppendf(
"float w = %s.%s - %s.%s;", subsetName, subsetStopSwizzle,
525 subsetName, subsetStartSwizzle);
526 fb->codeAppendf(
"float w2 = 2 * w;");
527 fb->codeAppendf(
"float d = inCoord.%s - %s.%s;", coordSwizzle, subsetName,
529 fb->codeAppend(
"float m = mod(d, w2);");
530 fb->codeAppend(
"float o = mix(m, w2 - m, step(w, m));");
531 fb->codeAppendf(
"subsetCoord.%s = o + %s.%s;", coordSwizzle, subsetName,
533 fb->codeAppendf(
"%s = w - o + %s.%s;", extraCoord, subsetName,
537 fb->codeAppend(
"float hw = w/2;");
538 fb->codeAppend(
"float n = mod(d - hw, w2);");
539 fb->codeAppendf(
"%s = saturate(half(mix(n, w2 - n, step(w, n)) - hw + 0.5));",
543 case ShaderMode::kMirrorRepeat:
545 fb->codeAppendf(
"float w = %s.%s - %s.%s;", subsetName, subsetStopSwizzle,
546 subsetName, subsetStartSwizzle);
547 fb->codeAppendf(
"float w2 = 2 * w;");
548 fb->codeAppendf(
"float m = mod(inCoord.%s - %s.%s, w2);", coordSwizzle,
549 subsetName, subsetStartSwizzle);
550 fb->codeAppendf(
"subsetCoord.%s = mix(m, w2 - m, step(w, m)) + %s.%s;",
551 coordSwizzle, subsetName, subsetStartSwizzle);
557 auto clampCoord = [&](
bool clamp,
558 const char* coordSwizzle,
559 const char* clampStartSwizzle,
560 const char* clampStopSwizzle) {
562 fb->codeAppendf(
"clampedCoord%s = clamp(subsetCoord%s, %s%s, %s%s);",
563 coordSwizzle, coordSwizzle,
564 clampName, clampStartSwizzle,
565 clampName, clampStopSwizzle);
567 fb->codeAppendf(
"clampedCoord%s = subsetCoord%s;", coordSwizzle, coordSwizzle);
572 const char* extraRepeatCoordX =
nullptr;
573 const char* repeatCoordWeightX =
nullptr;
574 const char* extraRepeatCoordY =
nullptr;
575 const char* repeatCoordWeightY =
nullptr;
577 bool mipmapRepeatX = m[0] == ShaderMode::kRepeat_Nearest_Mipmap ||
578 m[0] == ShaderMode::kRepeat_Linear_Mipmap;
579 bool mipmapRepeatY = m[1] == ShaderMode::kRepeat_Nearest_Mipmap ||
580 m[1] == ShaderMode::kRepeat_Linear_Mipmap;
582 if (mipmapRepeatX || mipmapRepeatY) {
583 fb->codeAppend(
"float2 extraRepeatCoord;");
586 fb->codeAppend(
"half repeatCoordWeightX;");
587 extraRepeatCoordX =
"extraRepeatCoord.x";
588 repeatCoordWeightX =
"repeatCoordWeightX";
591 fb->codeAppend(
"half repeatCoordWeightY;");
592 extraRepeatCoordY =
"extraRepeatCoord.y";
593 repeatCoordWeightY =
"repeatCoordWeightY";
597 fb->codeAppend(
"float2 subsetCoord;");
598 subsetCoord(te.fShaderModes[0],
"x",
"x",
"z", extraRepeatCoordX, repeatCoordWeightX);
599 subsetCoord(te.fShaderModes[1],
"y",
"y",
"w", extraRepeatCoordY, repeatCoordWeightY);
600 fb->codeAppend(
"float2 clampedCoord;");
601 if (useClamp[0] == useClamp[1]) {
602 clampCoord(useClamp[0],
"",
".xy",
".zw");
604 clampCoord(useClamp[0],
".x",
".x",
".z");
605 clampCoord(useClamp[1],
".y",
".y",
".w");
608 if (mipmapRepeatX && mipmapRepeatY) {
609 fb->codeAppendf(
"extraRepeatCoord = clamp(extraRepeatCoord, %s.xy, %s.zw);",
610 clampName, clampName);
611 }
else if (mipmapRepeatX) {
612 fb->codeAppendf(
"extraRepeatCoord.x = clamp(extraRepeatCoord.x, %s.x, %s.z);",
613 clampName, clampName);
614 }
else if (mipmapRepeatY) {
615 fb->codeAppendf(
"extraRepeatCoord.y = clamp(extraRepeatCoord.y, %s.y, %s.w);",
616 clampName, clampName);
622 if (mipmapRepeatX && mipmapRepeatY) {
624 "half4 textureColor ="
625 " mix(mix(%s, %s, repeatCoordWeightX),"
626 " mix(%s, %s, repeatCoordWeightX),"
627 " repeatCoordWeightY);",
628 read(
"clampedCoord").c_str(),
629 read(
"float2(extraRepeatCoord.x, clampedCoord.y)").c_str(),
630 read(
"float2(clampedCoord.x, extraRepeatCoord.y)").c_str(),
631 read(
"float2(extraRepeatCoord.x, extraRepeatCoord.y)").c_str());
633 }
else if (mipmapRepeatX) {
634 fb->codeAppendf(
"half4 textureColor = mix(%s, %s, repeatCoordWeightX);",
635 read(
"clampedCoord").c_str(),
636 read(
"float2(extraRepeatCoord.x, clampedCoord.y)").c_str());
637 }
else if (mipmapRepeatY) {
638 fb->codeAppendf(
"half4 textureColor = mix(%s, %s, repeatCoordWeightY);",
639 read(
"clampedCoord").c_str(),
640 read(
"float2(clampedCoord.x, extraRepeatCoord.y)").c_str());
642 fb->codeAppendf(
"half4 textureColor = %s;",
read(
"clampedCoord").c_str());
651 bool repeatLinearFilterX = m[0] == ShaderMode::kRepeat_Linear_None ||
652 m[0] == ShaderMode::kRepeat_Linear_Mipmap;
653 bool repeatLinearFilterY = m[1] == ShaderMode::kRepeat_Linear_None ||
654 m[1] == ShaderMode::kRepeat_Linear_Mipmap;
655 if (repeatLinearFilterX || m[0] == ShaderMode::kClampToBorder_Filter) {
656 fb->codeAppend(
"half errX = half(subsetCoord.x - clampedCoord.x);");
657 if (repeatLinearFilterX) {
658 fb->codeAppendf(
"float repeatCoordX = errX > 0 ? %s.x : %s.z;",
659 clampName, clampName);
660 repeatLinearReadX =
read(
"float2(repeatCoordX, clampedCoord.y)");
663 if (repeatLinearFilterY || m[1] == ShaderMode::kClampToBorder_Filter) {
664 fb->codeAppend(
"half errY = half(subsetCoord.y - clampedCoord.y);");
665 if (repeatLinearFilterY) {
666 fb->codeAppendf(
"float repeatCoordY = errY > 0 ? %s.y : %s.w;",
667 clampName, clampName);
668 repeatLinearReadY =
read(
"float2(clampedCoord.x, repeatCoordY)");
676 const char* ifStr =
"if";
677 if (repeatLinearFilterX && repeatLinearFilterY) {
678 auto repeatLinearReadXY =
read(
"float2(repeatCoordX, repeatCoordY)");
680 "if (errX != 0 && errY != 0) {"
682 " textureColor = mix(mix(textureColor, %s, errX),"
683 " mix(%s, %s, errX),"
686 repeatLinearReadX.
c_str(), repeatLinearReadY.
c_str(),
687 repeatLinearReadXY.c_str());
690 if (repeatLinearFilterX) {
693 " textureColor = mix(textureColor, %s, abs(errX));"
695 ifStr, repeatLinearReadX.
c_str());
697 if (repeatLinearFilterY) {
700 " textureColor = mix(textureColor, %s, abs(errY));"
702 ifStr, repeatLinearReadY.
c_str());
707 if (m[0] == ShaderMode::kClampToBorder_Filter) {
708 fb->codeAppendf(
"textureColor = mix(textureColor, %s, min(abs(errX), 1));", borderName);
710 if (m[1] == ShaderMode::kClampToBorder_Filter) {
711 fb->codeAppendf(
"textureColor = mix(textureColor, %s, min(abs(errY), 1));", borderName);
717 if (m[0] == ShaderMode::kClampToBorder_Nearest) {
719 "float snappedX = floor(inCoord.x + 0.001) + 0.5;"
720 "if (snappedX < %s.x || snappedX > %s.z) {"
721 " textureColor = %s;"
723 subsetName, subsetName, borderName);
725 if (m[1] == ShaderMode::kClampToBorder_Nearest) {
727 "float snappedY = floor(inCoord.y + 0.001) + 0.5;"
728 "if (snappedY < %s.y || snappedY > %s.w) {"
729 " textureColor = %s;"
731 subsetName, subsetName, borderName);
733 fb->codeAppendf(
"return textureColor;");
static std::unique_ptr< GrFragmentProcessor > MakeCustomLinearFilterInset(GrSurfaceProxyView, SkAlphaType, const SkMatrix &, GrSamplerState::WrapMode wx, GrSamplerState::WrapMode wy, const SkRect &subset, const SkRect *domain, SkVector inset, const GrCaps &caps, const float border[4]=kDefaultBorder)
static std::unique_ptr< GrFragmentProcessor > MakeSubset(GrSurfaceProxyView, SkAlphaType, const SkMatrix &, GrSamplerState, const SkRect &subset, const GrCaps &caps, const float border[4]=kDefaultBorder, bool alwaysUseShaderTileMode=false)
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView, SkAlphaType, const SkMatrix &=SkMatrix::I(), GrSamplerState::Filter=GrSamplerState::Filter::kNearest, GrSamplerState::MipmapMode mipmapMode=GrSamplerState::MipmapMode::kNone)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d