public abstract IEnumerable<FragmentQuad> Rasterize(InputAssemblerPrimitiveOutput primitive);
		public override IEnumerable<FragmentQuad> Rasterize(InputAssemblerPrimitiveOutput primitive)
		{
		    _primitive = primitive;
            _p0 = _primitive.Vertices[0].Position;
            _p1 = _primitive.Vertices[1].Position;
            _p2 = _primitive.Vertices[2].Position;

			// Precompute alpha, beta and gamma denominator values. These are the same for all fragments.
			_alphaDenominator = ComputeFunction(_p0.X, _p0.Y, ref _p1, ref _p2);
			_betaDenominator = ComputeFunction(_p1.X, _p1.Y, ref _p2, ref _p0);
			_gammaDenominator = ComputeFunction(_p2.X, _p2.Y, ref _p0, ref _p1);

            // TODO: Handle degenerate triangles. The following code might be right, but need to check.
		    //const float degenerateThreshold = 0.001f;
            //if (_alphaDenominator < degenerateThreshold || _betaDenominator < degenerateThreshold || _gammaDenominator < degenerateThreshold)
            //    yield break;

            // Compute screen-space triangle bounding box.
			var screenBounds = Box2D.CreateBoundingBox(ref _p0, ref _p1, ref _p2);

            // Clip triangle bounding box to screen bounds.
		    screenBounds = ScreenBounds.IntersectWith(ref screenBounds);

			// Calculate start and end positions. Because of the need to calculate derivatives
			// in the pixel shader, we require that fragment quads always have even numbered
			// coordinates (both x and y) for the top-left fragment.
            var startX = RoundDownToEven(screenBounds.MinX);
            var startY = RoundDownToEven(screenBounds.MinY);

            // Scan pixels in target area, checking if they are inside the triangle.
            // If they are, calculate the coverage.
		    var maxX = screenBounds.MaxX;
		    var maxY = screenBounds.MaxY;
			for (int y = startY; y < maxY; y += 2)
				for (int x = startX; x < maxX; x += 2)
				{
				    if (FragmentFilter != null)
				    {
                        if (!FragmentFilter(x, y)
                            && !FragmentFilter(x + 1, y)
                            && !FragmentFilter(x, y + 1)
                            && !FragmentFilter(x + 1, y + 1))
                            continue;
				    }

				    // First check whether any fragments in this quad are covered. If not, we don't
					// need to do any (expensive) interpolation of attributes.
					var fragmentQuad = new FragmentQuad
					{
						Fragment0 = CreateFragment(x, y, FragmentQuadLocation.TopLeft, ref screenBounds),
                        Fragment1 = CreateFragment(x + 1, y, FragmentQuadLocation.TopRight, ref screenBounds),
                        Fragment2 = CreateFragment(x, y + 1, FragmentQuadLocation.BottomLeft, ref screenBounds),
                        Fragment3 = CreateFragment(x + 1, y + 1, FragmentQuadLocation.BottomRight, ref screenBounds),
					};

					if (RasterizerState.IsMultisampleEnabled)
					{
						// For multisampling, we test coverage and interpolate attributes in two separate steps.
						// Check all samples to determine whether they are inside the triangle.
						bool covered0 = CalculateSampleCoverage(ref fragmentQuad.Fragment0);
						bool covered1 = CalculateSampleCoverage(ref fragmentQuad.Fragment1);
						bool covered2 = CalculateSampleCoverage(ref fragmentQuad.Fragment2);
						bool covered3 = CalculateSampleCoverage(ref fragmentQuad.Fragment3);

						if (!covered0 && !covered1 && !covered2 && !covered3)
							continue;

						// Otherwise, we do have at least one fragment with covered samples, so continue
						// with interpolation. We need to interpolate values for all fragments in this quad,
						// even though they may not all be covered, because we need all four fragments in order
						// to calculate derivatives correctly.
						InterpolateFragmentData(ref fragmentQuad.Fragment0);
						InterpolateFragmentData(ref fragmentQuad.Fragment1);
						InterpolateFragmentData(ref fragmentQuad.Fragment2);
						InterpolateFragmentData(ref fragmentQuad.Fragment3);
					}
					else
					{
						BarycentricCoordinates fragment0Coordinates, fragment1Coordinates, fragment2Coordinates, fragment3Coordinates;

						// For non-multisampling, we can re-use the same calculations for coverage and interpolation.
						bool covered0 = CalculateCoverageAndInterpolateFragmentData(ref fragmentQuad.Fragment0, out fragment0Coordinates);
						bool covered1 = CalculateCoverageAndInterpolateFragmentData(ref fragmentQuad.Fragment1, out fragment1Coordinates);
						bool covered2 = CalculateCoverageAndInterpolateFragmentData(ref fragmentQuad.Fragment2, out fragment2Coordinates);
						bool covered3 = CalculateCoverageAndInterpolateFragmentData(ref fragmentQuad.Fragment3, out fragment3Coordinates);

						if (!covered0 && !covered1 && !covered2 && !covered3)
							continue;

						// Create pixel shader input.
						fragmentQuad.Fragment0.Data = CreatePixelShaderInput(ref fragment0Coordinates);
						fragmentQuad.Fragment1.Data = CreatePixelShaderInput(ref fragment1Coordinates);
						fragmentQuad.Fragment2.Data = CreatePixelShaderInput(ref fragment2Coordinates);
						fragmentQuad.Fragment3.Data = CreatePixelShaderInput(ref fragment3Coordinates);
					}

					yield return fragmentQuad;
				}
		}