Reland "Snap coordinates for shader nearest-neighbor decal filtering"

This is a reland of 4e68ec693fdbb1a074b744f78e4999b60b517389

Original change's description:
> Snap coordinates for shader nearest-neighbor decal filtering
> 
> Bug: skia:10403
> Change-Id: I875b1a4bb7cacbe6721a69aa8ed02118b989729d
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297596
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Michael Ludwig <michaelludwig@google.com>

Bug: skia:10403
Change-Id: Idcf0b9a2d85410901a6d6fc2bedf628122cf9ae4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297799
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/effects/GrTextureEffect.cpp b/src/gpu/effects/GrTextureEffect.cpp
index 0f1b0fb..5113cbf 100644
--- a/src/gpu/effects/GrTextureEffect.cpp
+++ b/src/gpu/effects/GrTextureEffect.cpp
@@ -671,17 +671,20 @@
                 }
 
                 // Do hard-edge shader transition to border color for kClampToBorderNearest at the
-                // subset boundaries.
+                // subset boundaries. Snap the input coordinates to nearest neighbor (with an
+                // epsilon) before comparing to the subset rect to avoid GPU interpolation errors
                 if (m[0] == ShaderMode::kClampToBorderNearest) {
                     fb->codeAppendf(
-                            "if (inCoord.x < %s.x || inCoord.x > %s.z) {"
+                            "float snappedX = floor(inCoord.x + 0.001) + 0.5;"
+                            "if (snappedX < %s.x || snappedX > %s.z) {"
                             "    textureColor = %s;"
                             "}",
                             subsetName, subsetName, borderName);
                 }
                 if (m[1] == ShaderMode::kClampToBorderNearest) {
                     fb->codeAppendf(
-                            "if (inCoord.y < %s.y || inCoord.y > %s.w) {"
+                            "float snappedY = floor(inCoord.y + 0.001) + 0.5;"
+                            "if (snappedY < %s.y || snappedY > %s.w) {"
                             "    textureColor = %s;"
                             "}",
                             subsetName, subsetName, borderName);