Fix buffer overflow on Mac

For OpenGL on Mac, Swiftshader renders directly to the IOSurface given
to us by the OS. This surface is not necessarily vertically padded so
its height is a multiple of 2. Since we render 4 pixels at a time in a
quad, the bottom 2 pixels may not be written to legal memory if the
height of the target surface is an odd number.

This change prevents Swiftshader from rendering quads on Mac if doing so
would overflow the buffer.

Bug: chromium:944796
Bug: angleproject:2764

Change-Id: I08bec895980b42f99b8a4434969edcaf7d331284
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/32030
Presubmit-Ready: Sean Risser <srisser@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Sean Risser <srisser@google.com>
diff --git a/src/Renderer/QuadRasterizer.cpp b/src/Renderer/QuadRasterizer.cpp
index 6b319b4..947a88b 100644
--- a/src/Renderer/QuadRasterizer.cpp
+++ b/src/Renderer/QuadRasterizer.cpp
@@ -53,8 +53,8 @@
 
 		Do
 		{
-			Int yMin = *Pointer<Int>(primitive + OFFSET(Primitive,yMin));
-			Int yMax = *Pointer<Int>(primitive + OFFSET(Primitive,yMax));
+			yMin = *Pointer<Int>(primitive + OFFSET(Primitive,yMin));
+			yMax = *Pointer<Int>(primitive + OFFSET(Primitive,yMax));
 
 			Int cluster2 = cluster + cluster;
 			yMin += clusterCount * 2 - 2 - cluster2;
@@ -63,7 +63,7 @@
 
 			If(yMin < yMax)
 			{
-				rasterize(yMin, yMax);
+				rasterize();
 			}
 
 			primitive += sizeof(Primitive) * state.multiSample;
@@ -90,7 +90,7 @@
 		Return();
 	}
 
-	void QuadRasterizer::rasterize(Int &yMin, Int &yMax)
+	void QuadRasterizer::rasterize()
 	{
 		Pointer<Byte> cBuffer[RENDERTARGETS];
 		Pointer<Byte> zBuffer;
@@ -114,7 +114,7 @@
 			sBuffer = *Pointer<Pointer<Byte>>(data + OFFSET(DrawData,stencilBuffer)) + yMin * *Pointer<Int>(data + OFFSET(DrawData,stencilPitchB));
 		}
 
-		Int y = yMin;
+		y = yMin;
 
 		Do
 		{
@@ -287,7 +287,7 @@
 						cMask[q] = SignMask(PackSigned(mask, mask)) & 0x0000000F;
 					}
 
-					quad(cBuffer, zBuffer, sBuffer, cMask, x, y);
+					quad(cBuffer, zBuffer, sBuffer, cMask, x);
 				}
 			}
 
diff --git a/src/Renderer/QuadRasterizer.hpp b/src/Renderer/QuadRasterizer.hpp
index 1d7681d..77bbce1 100644
--- a/src/Renderer/QuadRasterizer.hpp
+++ b/src/Renderer/QuadRasterizer.hpp
@@ -40,11 +40,15 @@
 
 		UInt occlusion;
 
+		Int y;
+		Int yMin;
+		Int yMax;
+
 #if PERF_PROFILE
 		Long cycles[PERF_TIMERS];
 #endif
 
-		virtual void quad(Pointer<Byte> cBuffer[4], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x, Int &y) = 0;
+		virtual void quad(Pointer<Byte> cBuffer[4], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x) = 0;
 
 		bool interpolateZ() const;
 		bool interpolateW() const;
@@ -54,7 +58,7 @@
 		const PixelShader *const shader;
 
 	private:
-		void rasterize(Int &yMin, Int &yMax);
+		void rasterize();
 	};
 }
 
diff --git a/src/Shader/PixelRoutine.cpp b/src/Shader/PixelRoutine.cpp
index 146e42d..12040fd 100644
--- a/src/Shader/PixelRoutine.cpp
+++ b/src/Shader/PixelRoutine.cpp
@@ -48,7 +48,7 @@
 	{
 	}
 
-	void PixelRoutine::quad(Pointer<Byte> cBuffer[RENDERTARGETS], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x, Int &y)
+	void PixelRoutine::quad(Pointer<Byte> cBuffer[RENDERTARGETS], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x)
 	{
 		#if PERF_PROFILE
 			Long pipeTime = Ticks();
@@ -1684,10 +1684,17 @@
 					c23 |= masked;
 				}
 
-				c23 &= *Pointer<Short4>(constants + OFFSET(Constants,maskD23Q) + xMask * 8);
-				value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD23Q) + xMask * 8);
-				c23 |= value;
-				*Pointer<Short4>(buffer) = c23;
+#ifdef __APPLE__
+				// On Mac we render directly to an IOSurface that isn't vertically padded. So we
+				// only render the bottom half of quads when it won't overflow the buffer.
+				If ((y + 1) < yMax)
+#endif
+				{
+					c23 &= *Pointer<Short4>(constants + OFFSET(Constants,maskD23Q) + xMask * 8);
+					value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD23Q) + xMask * 8);
+					c23 |= value;
+					*Pointer<Short4>(buffer) = c23;
+				}
 			}
 			break;
 		case FORMAT_A8B8G8R8:
diff --git a/src/Shader/PixelRoutine.hpp b/src/Shader/PixelRoutine.hpp
index 1cd076e..ad78fc7 100644
--- a/src/Shader/PixelRoutine.hpp
+++ b/src/Shader/PixelRoutine.hpp
@@ -47,7 +47,7 @@
 		virtual Bool alphaTest(Int cMask[4]) = 0;
 		virtual void rasterOperation(Float4 &fog, Pointer<Byte> cBuffer[4], Int &x, Int sMask[4], Int zMask[4], Int cMask[4]) = 0;
 
-		virtual void quad(Pointer<Byte> cBuffer[4], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x, Int &y);
+		virtual void quad(Pointer<Byte> cBuffer[4], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x);
 
 		void alphaTest(Int &aMask, Short4 &alpha);
 		void alphaToCoverage(Int cMask[4], Float4 &alpha);