Prevent floating-point error accumulation during blitting.

The numeric imprecision can accumulate quickly and cause visible
sampling errors.

Bug chromium:848238

Change-Id: Ie41c10a0462e5b5e5c3ed5f7329ece00dab3f7f9
Reviewed-on: https://swiftshader-review.googlesource.com/19148
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Common/Version.h b/src/Common/Version.h
index ea9a476..9a28e1b 100644
--- a/src/Common/Version.h
+++ b/src/Common/Version.h
@@ -15,7 +15,7 @@
 #define MAJOR_VERSION 4
 #define MINOR_VERSION 0
 #define BUILD_VERSION 0
-#define BUILD_REVISION 5
+#define BUILD_REVISION 6
 
 #define STRINGIFY(x) #x
 #define MACRO_STRINGIFY(x) STRINGIFY(x)
diff --git a/src/Renderer/Blitter.cpp b/src/Renderer/Blitter.cpp
index c77491c..17c7199 100644
--- a/src/Renderer/Blitter.cpp
+++ b/src/Renderer/Blitter.cpp
@@ -163,28 +163,26 @@
 			swap(sRect.y0, sRect.y1);
 		}
 
-		source->lockInternal((int)sRect.x0, (int)sRect.y0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
-		dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
+		source->lockInternal(0, 0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
+		dest->lockInternal(0, 0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
 
 		float w = sRect.width() / dRect.width();
 		float h = sRect.height() / dRect.height();
 
-		const float xStart = sRect.x0 + 0.5f * w;
-		float y = sRect.y0 + 0.5f * h;
+		float xStart = sRect.x0 + (0.5f - dRect.x0) * w;
+		float yStart = sRect.y0 + (0.5f - dRect.y0) * h;
 
 		for(int j = dRect.y0; j < dRect.y1; j++)
 		{
-			float x = xStart;
+			float y = yStart + j * h;
 
 			for(int i = dRect.x0; i < dRect.x1; i++)
 			{
+				float x = xStart + i * w;
+
 				// FIXME: Support RGBA mask
 				dest->copyInternal(source, i, j, x, y, options.filter);
-
-				x += w;
 			}
-
-			y += h;
 		}
 
 		source->unlockInternal();
@@ -200,21 +198,21 @@
 		float h = static_cast<float>(source->getHeight()) / static_cast<float>(dest->getHeight());
 		float d = static_cast<float>(source->getDepth())  / static_cast<float>(dest->getDepth());
 
-		float z = 0.5f * d;
 		for(int k = 0; k < dest->getDepth(); k++)
 		{
-			float y = 0.5f * h;
+			float z = (k + 0.5f) * d;
+
 			for(int j = 0; j < dest->getHeight(); j++)
 			{
-				float x = 0.5f * w;
+				float y = (j + 0.5f) * h;
+
 				for(int i = 0; i < dest->getWidth(); i++)
 				{
+					float x = (i + 0.5f) * w;
+
 					dest->copyInternal(source, i, j, k, x, y, z, true);
-					x += w;
 				}
-				y += h;
 			}
-			z += d;
 		}
 
 		source->unlockInternal();
@@ -1237,15 +1235,14 @@
 				}
 			}
 
-			Float y = y0;
-
 			For(Int j = y0d, j < y1d, j++)
 			{
-				Float x = x0;
+				Float y = state.clearOperation ? y0 : y0 + Float(j) * h;
 				Pointer<Byte> destLine = dest + (dstQuadLayout ? j & Int(~1) : RValue<Int>(j)) * dPitchB;
 
 				For(Int i = x0d, i < x1d, i++)
 				{
+					Float x = state.clearOperation ? x0 : x0 + Float(i) * w;
 					Pointer<Byte> d = destLine + (dstQuadLayout ? (((j & Int(1)) << 1) + (i * 2) - (i & Int(1))) : RValue<Int>(i)) * dstBytes;
 
 					if(hasConstantColorI)
@@ -1379,11 +1376,7 @@
 							d += *Pointer<Int>(blit + OFFSET(BlitData,dSliceB));
 						}
 					}
-
-					if(!state.clearOperation) { x += w; }
 				}
-
-				if(!state.clearOperation) { y += h; }
 			}
 		}
 
@@ -1456,8 +1449,8 @@
 
 		data.w = sRect.width() / dRect.width();
 		data.h = sRect.height() / dRect.height();
-		data.x0 = sRect.x0 + 0.5f * data.w;
-		data.y0 = sRect.y0 + 0.5f * data.h;
+		data.x0 = sRect.x0 + (0.5f - dRect.x0) * data.w;
+		data.y0 = sRect.y0 + (0.5f - dRect.y0) * data.h;
 
 		data.x0d = dRect.x0;
 		data.x1d = dRect.x1;