1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program Reference Renderer
3e5c31af7Sopenharmony_ci * -----------------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief Reference rasterizer
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "rrRasterizer.hpp"
25e5c31af7Sopenharmony_ci#include "deMath.h"
26e5c31af7Sopenharmony_ci#include "tcuVectorUtil.hpp"
27e5c31af7Sopenharmony_ci
28e5c31af7Sopenharmony_cinamespace rr
29e5c31af7Sopenharmony_ci{
30e5c31af7Sopenharmony_ci
31e5c31af7Sopenharmony_ciinline deInt64 toSubpixelCoord (float v, int bits)
32e5c31af7Sopenharmony_ci{
33e5c31af7Sopenharmony_ci	return (deInt64)(v * (float)(1 << bits) + (v < 0.f ? -0.5f : 0.5f));
34e5c31af7Sopenharmony_ci}
35e5c31af7Sopenharmony_ci
36e5c31af7Sopenharmony_ciinline deInt64 toSubpixelCoord (deInt32 v, int bits)
37e5c31af7Sopenharmony_ci{
38e5c31af7Sopenharmony_ci	return v << bits;
39e5c31af7Sopenharmony_ci}
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_ciinline deInt32 ceilSubpixelToPixelCoord (deInt64 coord, int bits, bool fillEdge)
42e5c31af7Sopenharmony_ci{
43e5c31af7Sopenharmony_ci	if (coord >= 0)
44e5c31af7Sopenharmony_ci		return (deInt32)((coord + ((1ll << bits) - (fillEdge ? 0 : 1))) >> bits);
45e5c31af7Sopenharmony_ci	else
46e5c31af7Sopenharmony_ci		return (deInt32)((coord + (fillEdge ? 1 : 0)) >> bits);
47e5c31af7Sopenharmony_ci}
48e5c31af7Sopenharmony_ci
49e5c31af7Sopenharmony_ciinline deInt32 floorSubpixelToPixelCoord (deInt64 coord, int bits, bool fillEdge)
50e5c31af7Sopenharmony_ci{
51e5c31af7Sopenharmony_ci	if (coord >= 0)
52e5c31af7Sopenharmony_ci		return (deInt32)((coord - (fillEdge ? 1 : 0)) >> bits);
53e5c31af7Sopenharmony_ci	else
54e5c31af7Sopenharmony_ci		return (deInt32)((coord - ((1ll << bits) - (fillEdge ? 0 : 1))) >> bits);
55e5c31af7Sopenharmony_ci}
56e5c31af7Sopenharmony_ci
57e5c31af7Sopenharmony_cistatic inline void initEdgeCCW (EdgeFunction& edge, const HorizontalFill horizontalFill, const VerticalFill verticalFill, const deInt64 x0, const deInt64 y0, const deInt64 x1, const deInt64 y1)
58e5c31af7Sopenharmony_ci{
59e5c31af7Sopenharmony_ci	// \note See EdgeFunction documentation for details.
60e5c31af7Sopenharmony_ci
61e5c31af7Sopenharmony_ci	const deInt64	xd			= x1-x0;
62e5c31af7Sopenharmony_ci	const deInt64	yd			= y1-y0;
63e5c31af7Sopenharmony_ci	bool			inclusive	= false;	//!< Inclusive in CCW orientation.
64e5c31af7Sopenharmony_ci
65e5c31af7Sopenharmony_ci	if (yd == 0)
66e5c31af7Sopenharmony_ci		inclusive = verticalFill == FILL_BOTTOM ? xd >= 0 : xd <= 0;
67e5c31af7Sopenharmony_ci	else
68e5c31af7Sopenharmony_ci		inclusive = horizontalFill == FILL_LEFT ? yd <= 0 : yd >= 0;
69e5c31af7Sopenharmony_ci
70e5c31af7Sopenharmony_ci	edge.a			= (y0 - y1);
71e5c31af7Sopenharmony_ci	edge.b			= (x1 - x0);
72e5c31af7Sopenharmony_ci	edge.c			= x0*y1 - y0*x1;
73e5c31af7Sopenharmony_ci	edge.inclusive	= inclusive; //!< \todo [pyry] Swap for CW triangles
74e5c31af7Sopenharmony_ci}
75e5c31af7Sopenharmony_ci
76e5c31af7Sopenharmony_cistatic inline void reverseEdge (EdgeFunction& edge)
77e5c31af7Sopenharmony_ci{
78e5c31af7Sopenharmony_ci	edge.a			= -edge.a;
79e5c31af7Sopenharmony_ci	edge.b			= -edge.b;
80e5c31af7Sopenharmony_ci	edge.c			= -edge.c;
81e5c31af7Sopenharmony_ci	edge.inclusive	= !edge.inclusive;
82e5c31af7Sopenharmony_ci}
83e5c31af7Sopenharmony_ci
84e5c31af7Sopenharmony_cistatic inline deInt64 evaluateEdge (const EdgeFunction& edge, const deInt64 x, const deInt64 y)
85e5c31af7Sopenharmony_ci{
86e5c31af7Sopenharmony_ci	return edge.a*x + edge.b*y + edge.c;
87e5c31af7Sopenharmony_ci}
88e5c31af7Sopenharmony_ci
89e5c31af7Sopenharmony_cistatic inline bool isInsideCCW (const EdgeFunction& edge, const deInt64 edgeVal)
90e5c31af7Sopenharmony_ci{
91e5c31af7Sopenharmony_ci	return edge.inclusive ? (edgeVal >= 0) : (edgeVal > 0);
92e5c31af7Sopenharmony_ci}
93e5c31af7Sopenharmony_ci
94e5c31af7Sopenharmony_cinamespace LineRasterUtil
95e5c31af7Sopenharmony_ci{
96e5c31af7Sopenharmony_ci
97e5c31af7Sopenharmony_cistruct SubpixelLineSegment
98e5c31af7Sopenharmony_ci{
99e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2>	m_v0;
100e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2>	m_v1;
101e5c31af7Sopenharmony_ci
102e5c31af7Sopenharmony_ci	SubpixelLineSegment (const tcu::Vector<deInt64,2>& v0, const tcu::Vector<deInt64,2>& v1)
103e5c31af7Sopenharmony_ci		: m_v0(v0)
104e5c31af7Sopenharmony_ci		, m_v1(v1)
105e5c31af7Sopenharmony_ci	{
106e5c31af7Sopenharmony_ci	}
107e5c31af7Sopenharmony_ci
108e5c31af7Sopenharmony_ci	tcu::Vector<deInt64,2> direction (void) const
109e5c31af7Sopenharmony_ci	{
110e5c31af7Sopenharmony_ci		return m_v1 - m_v0;
111e5c31af7Sopenharmony_ci	}
112e5c31af7Sopenharmony_ci};
113e5c31af7Sopenharmony_ci
114e5c31af7Sopenharmony_cienum LINE_SIDE
115e5c31af7Sopenharmony_ci{
116e5c31af7Sopenharmony_ci	LINE_SIDE_INTERSECT = 0,
117e5c31af7Sopenharmony_ci	LINE_SIDE_LEFT,
118e5c31af7Sopenharmony_ci	LINE_SIDE_RIGHT
119e5c31af7Sopenharmony_ci};
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_cistatic tcu::Vector<deInt64,2> toSubpixelVector (const tcu::Vec2& v, int bits)
122e5c31af7Sopenharmony_ci{
123e5c31af7Sopenharmony_ci	return tcu::Vector<deInt64,2>(toSubpixelCoord(v.x(), bits), toSubpixelCoord(v.y(), bits));
124e5c31af7Sopenharmony_ci}
125e5c31af7Sopenharmony_ci
126e5c31af7Sopenharmony_cistatic tcu::Vector<deInt64,2> toSubpixelVector (const tcu::IVec2& v, int bits)
127e5c31af7Sopenharmony_ci{
128e5c31af7Sopenharmony_ci	return tcu::Vector<deInt64,2>(toSubpixelCoord(v.x(), bits), toSubpixelCoord(v.y(), bits));
129e5c31af7Sopenharmony_ci}
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ci#if defined(DE_DEBUG)
132e5c31af7Sopenharmony_cistatic bool isTheCenterOfTheFragment (const tcu::Vector<deInt64,2>& a, int bits)
133e5c31af7Sopenharmony_ci{
134e5c31af7Sopenharmony_ci	const deUint64 pixelSize = 1ll << bits;
135e5c31af7Sopenharmony_ci	const deUint64 halfPixel = 1ll << (bits - 1);
136e5c31af7Sopenharmony_ci	return	((a.x() & (pixelSize-1)) == halfPixel &&
137e5c31af7Sopenharmony_ci				(a.y() & (pixelSize-1)) == halfPixel);
138e5c31af7Sopenharmony_ci}
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_cistatic bool inViewport (const tcu::IVec2& p, const tcu::IVec4& viewport)
141e5c31af7Sopenharmony_ci{
142e5c31af7Sopenharmony_ci	return	p.x() >= viewport.x() &&
143e5c31af7Sopenharmony_ci			p.y() >= viewport.y() &&
144e5c31af7Sopenharmony_ci			p.x() <  viewport.x() + viewport.z() &&
145e5c31af7Sopenharmony_ci			p.y() <  viewport.y() + viewport.w();
146e5c31af7Sopenharmony_ci}
147e5c31af7Sopenharmony_ci#endif // DE_DEBUG
148e5c31af7Sopenharmony_ci
149e5c31af7Sopenharmony_ci// returns true if vertex is on the left side of the line
150e5c31af7Sopenharmony_cistatic bool vertexOnLeftSideOfLine (const tcu::Vector<deInt64,2>& p, const SubpixelLineSegment& l)
151e5c31af7Sopenharmony_ci{
152e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> u = l.direction();
153e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> v = ( p - l.m_v0);
154e5c31af7Sopenharmony_ci	const deInt64 crossProduct = (u.x() * v.y() - u.y() * v.x());
155e5c31af7Sopenharmony_ci	return crossProduct < 0;
156e5c31af7Sopenharmony_ci}
157e5c31af7Sopenharmony_ci
158e5c31af7Sopenharmony_ci// returns true if vertex is on the right side of the line
159e5c31af7Sopenharmony_cistatic bool vertexOnRightSideOfLine (const tcu::Vector<deInt64,2>& p, const SubpixelLineSegment& l)
160e5c31af7Sopenharmony_ci{
161e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> u = l.direction();
162e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> v = ( p - l.m_v0);
163e5c31af7Sopenharmony_ci	const deInt64 crossProduct = (u.x() * v.y() - u.y() * v.x());
164e5c31af7Sopenharmony_ci	return crossProduct > 0;
165e5c31af7Sopenharmony_ci}
166e5c31af7Sopenharmony_ci
167e5c31af7Sopenharmony_ci// returns true if vertex is on the line
168e5c31af7Sopenharmony_cistatic bool vertexOnLine (const tcu::Vector<deInt64,2>& p, const SubpixelLineSegment& l)
169e5c31af7Sopenharmony_ci{
170e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> u = l.direction();
171e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> v = ( p - l.m_v0);
172e5c31af7Sopenharmony_ci	const deInt64 crossProduct = (u.x() * v.y() - u.y() * v.x());
173e5c31af7Sopenharmony_ci	return crossProduct == 0; // cross product == 0
174e5c31af7Sopenharmony_ci}
175e5c31af7Sopenharmony_ci
176e5c31af7Sopenharmony_ci// returns true if vertex is on the line segment
177e5c31af7Sopenharmony_cistatic bool vertexOnLineSegment (const tcu::Vector<deInt64,2>& p, const SubpixelLineSegment& l)
178e5c31af7Sopenharmony_ci{
179e5c31af7Sopenharmony_ci	if (!vertexOnLine(p, l))
180e5c31af7Sopenharmony_ci		return false;
181e5c31af7Sopenharmony_ci
182e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> v	= l.direction();
183e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> u1	= ( p - l.m_v0);
184e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> u2	= ( p - l.m_v1);
185e5c31af7Sopenharmony_ci
186e5c31af7Sopenharmony_ci	if (v.x() == 0 && v.y() == 0)
187e5c31af7Sopenharmony_ci		return false;
188e5c31af7Sopenharmony_ci
189e5c31af7Sopenharmony_ci	return	tcu::dot( v, u1) >= 0 &&
190e5c31af7Sopenharmony_ci			tcu::dot(-v, u2) >= 0; // dot (A->B, A->V) >= 0 and dot (B->A, B->V) >= 0
191e5c31af7Sopenharmony_ci}
192e5c31af7Sopenharmony_ci
193e5c31af7Sopenharmony_cistatic LINE_SIDE getVertexSide (const tcu::Vector<deInt64,2>& v, const SubpixelLineSegment& l)
194e5c31af7Sopenharmony_ci{
195e5c31af7Sopenharmony_ci	if (vertexOnLeftSideOfLine(v, l))
196e5c31af7Sopenharmony_ci		return LINE_SIDE_LEFT;
197e5c31af7Sopenharmony_ci	else if (vertexOnRightSideOfLine(v, l))
198e5c31af7Sopenharmony_ci		return LINE_SIDE_RIGHT;
199e5c31af7Sopenharmony_ci	else if (vertexOnLine(v, l))
200e5c31af7Sopenharmony_ci		return LINE_SIDE_INTERSECT;
201e5c31af7Sopenharmony_ci	else
202e5c31af7Sopenharmony_ci	{
203e5c31af7Sopenharmony_ci		DE_ASSERT(false);
204e5c31af7Sopenharmony_ci		return LINE_SIDE_INTERSECT;
205e5c31af7Sopenharmony_ci	}
206e5c31af7Sopenharmony_ci}
207e5c31af7Sopenharmony_ci
208e5c31af7Sopenharmony_ci// returns true if angle between line and given cornerExitNormal is in range (-45, 45)
209e5c31af7Sopenharmony_cibool lineInCornerAngleRange (const SubpixelLineSegment& line, const tcu::Vector<deInt64,2>& cornerExitNormal)
210e5c31af7Sopenharmony_ci{
211e5c31af7Sopenharmony_ci	// v0 -> v1 has angle difference to cornerExitNormal in range (-45, 45)
212e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> v = line.direction();
213e5c31af7Sopenharmony_ci	const deInt64 dotProduct = dot(v, cornerExitNormal);
214e5c31af7Sopenharmony_ci
215e5c31af7Sopenharmony_ci	// dotProduct > |v1-v0|*|cornerExitNormal|/sqrt(2)
216e5c31af7Sopenharmony_ci	if (dotProduct < 0)
217e5c31af7Sopenharmony_ci		return false;
218e5c31af7Sopenharmony_ci	return 2 * dotProduct * dotProduct > tcu::lengthSquared(v)*tcu::lengthSquared(cornerExitNormal);
219e5c31af7Sopenharmony_ci}
220e5c31af7Sopenharmony_ci
221e5c31af7Sopenharmony_ci// returns true if angle between line and given cornerExitNormal is in range (-135, 135)
222e5c31af7Sopenharmony_cibool lineInCornerOutsideAngleRange (const SubpixelLineSegment& line, const tcu::Vector<deInt64,2>& cornerExitNormal)
223e5c31af7Sopenharmony_ci{
224e5c31af7Sopenharmony_ci	// v0 -> v1 has angle difference to cornerExitNormal in range (-135, 135)
225e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2> v = line.direction();
226e5c31af7Sopenharmony_ci	const deInt64 dotProduct = dot(v, cornerExitNormal);
227e5c31af7Sopenharmony_ci
228e5c31af7Sopenharmony_ci	// dotProduct > -|v1-v0|*|cornerExitNormal|/sqrt(2)
229e5c31af7Sopenharmony_ci	if (dotProduct >= 0)
230e5c31af7Sopenharmony_ci		return true;
231e5c31af7Sopenharmony_ci	return 2 * (-dotProduct) * (-dotProduct) < tcu::lengthSquared(v)*tcu::lengthSquared(cornerExitNormal);
232e5c31af7Sopenharmony_ci}
233e5c31af7Sopenharmony_ci
234e5c31af7Sopenharmony_cibool doesLineSegmentExitDiamond (const SubpixelLineSegment& line, const tcu::Vector<deInt64,2>& diamondCenter, int bits)
235e5c31af7Sopenharmony_ci{
236e5c31af7Sopenharmony_ci	DE_ASSERT(isTheCenterOfTheFragment(diamondCenter, bits));
237e5c31af7Sopenharmony_ci
238e5c31af7Sopenharmony_ci	// Diamond Center is at diamondCenter in subpixel coords
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci	const deInt64 halfPixel = 1ll << (bits - 1);
241e5c31af7Sopenharmony_ci
242e5c31af7Sopenharmony_ci	// Reject distant diamonds early
243e5c31af7Sopenharmony_ci	{
244e5c31af7Sopenharmony_ci		const tcu::Vector<deInt64,2>	u				= line.direction();
245e5c31af7Sopenharmony_ci		const tcu::Vector<deInt64,2>	v				= (diamondCenter - line.m_v0);
246e5c31af7Sopenharmony_ci		const deInt64					crossProduct	= (u.x() * v.y() - u.y() * v.x());
247e5c31af7Sopenharmony_ci
248e5c31af7Sopenharmony_ci		// crossProduct = |p| |l| sin(theta)
249e5c31af7Sopenharmony_ci		// distanceFromLine = |p| sin(theta)
250e5c31af7Sopenharmony_ci		// => distanceFromLine = crossProduct / |l|
251e5c31af7Sopenharmony_ci		//
252e5c31af7Sopenharmony_ci		// |distanceFromLine| > C
253e5c31af7Sopenharmony_ci		// => distanceFromLine^2 > C^2
254e5c31af7Sopenharmony_ci		// => crossProduct^2 / |l|^2 > C^2
255e5c31af7Sopenharmony_ci		// => crossProduct^2 > |l|^2 * C^2
256e5c31af7Sopenharmony_ci
257e5c31af7Sopenharmony_ci		const deInt64	floorSqrtMaxInt64			= 3037000499LL; //!< floor(sqrt(MAX_INT64))
258e5c31af7Sopenharmony_ci
259e5c31af7Sopenharmony_ci		const deInt64	broadRejectDistance			= 2 * halfPixel;
260e5c31af7Sopenharmony_ci		const deInt64	broadRejectDistanceSquared	= broadRejectDistance * broadRejectDistance;
261e5c31af7Sopenharmony_ci		const bool		crossProductOverflows		= (crossProduct > floorSqrtMaxInt64 || crossProduct < -floorSqrtMaxInt64);
262e5c31af7Sopenharmony_ci		const deInt64	crossProductSquared			= (crossProductOverflows) ? (0) : (crossProduct * crossProduct); // avoid overflow
263e5c31af7Sopenharmony_ci		const deInt64	lineLengthSquared			= tcu::lengthSquared(u);
264e5c31af7Sopenharmony_ci		const bool		limitValueCouldOverflow		= ((64 - deClz64(lineLengthSquared)) + (64 - deClz64(broadRejectDistanceSquared))) > 63;
265e5c31af7Sopenharmony_ci		const deInt64	limitValue					= (limitValueCouldOverflow) ? (0) : (lineLengthSquared * broadRejectDistanceSquared); // avoid overflow
266e5c31af7Sopenharmony_ci
267e5c31af7Sopenharmony_ci		// only cross overflows
268e5c31af7Sopenharmony_ci		if (crossProductOverflows && !limitValueCouldOverflow)
269e5c31af7Sopenharmony_ci			return false;
270e5c31af7Sopenharmony_ci
271e5c31af7Sopenharmony_ci		// both representable
272e5c31af7Sopenharmony_ci		if (!crossProductOverflows && !limitValueCouldOverflow)
273e5c31af7Sopenharmony_ci		{
274e5c31af7Sopenharmony_ci			if (crossProductSquared > limitValue)
275e5c31af7Sopenharmony_ci				return false;
276e5c31af7Sopenharmony_ci		}
277e5c31af7Sopenharmony_ci	}
278e5c31af7Sopenharmony_ci
279e5c31af7Sopenharmony_ci	const struct DiamondBound
280e5c31af7Sopenharmony_ci	{
281e5c31af7Sopenharmony_ci		tcu::Vector<deInt64,2>	p0;
282e5c31af7Sopenharmony_ci		tcu::Vector<deInt64,2>	p1;
283e5c31af7Sopenharmony_ci		bool					edgeInclusive; // would a point on the bound be inside of the region
284e5c31af7Sopenharmony_ci	} bounds[] =
285e5c31af7Sopenharmony_ci	{
286e5c31af7Sopenharmony_ci		{ diamondCenter + tcu::Vector<deInt64,2>(0,				-halfPixel),	diamondCenter + tcu::Vector<deInt64,2>(-halfPixel,	0),				 false	},
287e5c31af7Sopenharmony_ci		{ diamondCenter + tcu::Vector<deInt64,2>(-halfPixel,	0),				diamondCenter + tcu::Vector<deInt64,2>(0,			halfPixel),		 false	},
288e5c31af7Sopenharmony_ci		{ diamondCenter + tcu::Vector<deInt64,2>(0,				halfPixel),		diamondCenter + tcu::Vector<deInt64,2>(halfPixel,	0),				 true	},
289e5c31af7Sopenharmony_ci		{ diamondCenter + tcu::Vector<deInt64,2>(halfPixel,		0),				diamondCenter + tcu::Vector<deInt64,2>(0,			-halfPixel),	 true	},
290e5c31af7Sopenharmony_ci	};
291e5c31af7Sopenharmony_ci
292e5c31af7Sopenharmony_ci	const struct DiamondCorners
293e5c31af7Sopenharmony_ci	{
294e5c31af7Sopenharmony_ci		enum CORNER_EDGE_CASE_BEHAVIOR
295e5c31af7Sopenharmony_ci		{
296e5c31af7Sopenharmony_ci			CORNER_EDGE_CASE_NONE,							// if the line intersects just a corner, no entering or exiting
297e5c31af7Sopenharmony_ci			CORNER_EDGE_CASE_HIT,							// if the line intersects just a corner, entering and exit
298e5c31af7Sopenharmony_ci			CORNER_EDGE_CASE_HIT_FIRST_QUARTER,				// if the line intersects just a corner and the line has either endpoint in (+X,-Y) direction (preturbing moves the line inside)
299e5c31af7Sopenharmony_ci			CORNER_EDGE_CASE_HIT_SECOND_QUARTER				// if the line intersects just a corner and the line has either endpoint in (+X,+Y) direction (preturbing moves the line inside)
300e5c31af7Sopenharmony_ci		};
301e5c31af7Sopenharmony_ci		enum CORNER_START_CASE_BEHAVIOR
302e5c31af7Sopenharmony_ci		{
303e5c31af7Sopenharmony_ci			CORNER_START_CASE_NONE,							// the line starting point is outside, no exiting
304e5c31af7Sopenharmony_ci			CORNER_START_CASE_OUTSIDE,						// exit, if line does not intersect the region (preturbing moves the start point inside)
305e5c31af7Sopenharmony_ci			CORNER_START_CASE_POSITIVE_Y_45,				// exit, if line the angle of line vector and X-axis is in range (0, 45] in positive Y side.
306e5c31af7Sopenharmony_ci			CORNER_START_CASE_NEGATIVE_Y_45					// exit, if line the angle of line vector and X-axis is in range [0, 45] in negative Y side.
307e5c31af7Sopenharmony_ci		};
308e5c31af7Sopenharmony_ci		enum CORNER_END_CASE_BEHAVIOR
309e5c31af7Sopenharmony_ci		{
310e5c31af7Sopenharmony_ci			CORNER_END_CASE_NONE,							// end is inside, no exiting (preturbing moves the line end inside)
311e5c31af7Sopenharmony_ci			CORNER_END_CASE_DIRECTION,						// exit, if line intersected the region (preturbing moves the line end outside)
312e5c31af7Sopenharmony_ci			CORNER_END_CASE_DIRECTION_AND_FIRST_QUARTER,	// exit, if line intersected the region, or line originates from (+X,-Y) direction (preturbing moves the line end outside)
313e5c31af7Sopenharmony_ci			CORNER_END_CASE_DIRECTION_AND_SECOND_QUARTER	// exit, if line intersected the region, or line originates from (+X,+Y) direction (preturbing moves the line end outside)
314e5c31af7Sopenharmony_ci		};
315e5c31af7Sopenharmony_ci
316e5c31af7Sopenharmony_ci		tcu::Vector<deInt64,2>		dp;
317e5c31af7Sopenharmony_ci		bool						pointInclusive;			// would a point in this corner intersect with the region
318e5c31af7Sopenharmony_ci		CORNER_EDGE_CASE_BEHAVIOR	lineBehavior;			// would a line segment going through this corner intersect with the region
319e5c31af7Sopenharmony_ci		CORNER_START_CASE_BEHAVIOR	startBehavior;			// how the corner behaves if the start point at the corner
320e5c31af7Sopenharmony_ci		CORNER_END_CASE_BEHAVIOR	endBehavior;			// how the corner behaves if the end point at the corner
321e5c31af7Sopenharmony_ci	} corners[] =
322e5c31af7Sopenharmony_ci	{
323e5c31af7Sopenharmony_ci		{ tcu::Vector<deInt64,2>(0,				-halfPixel),	false,	DiamondCorners::CORNER_EDGE_CASE_HIT_SECOND_QUARTER,	DiamondCorners::CORNER_START_CASE_POSITIVE_Y_45,	DiamondCorners::CORNER_END_CASE_DIRECTION_AND_SECOND_QUARTER},
324e5c31af7Sopenharmony_ci		{ tcu::Vector<deInt64,2>(-halfPixel,	0),				false,	DiamondCorners::CORNER_EDGE_CASE_NONE,					DiamondCorners::CORNER_START_CASE_NONE,				DiamondCorners::CORNER_END_CASE_DIRECTION					},
325e5c31af7Sopenharmony_ci		{ tcu::Vector<deInt64,2>(0,				halfPixel),		false,	DiamondCorners::CORNER_EDGE_CASE_HIT_FIRST_QUARTER,		DiamondCorners::CORNER_START_CASE_NEGATIVE_Y_45,	DiamondCorners::CORNER_END_CASE_DIRECTION_AND_FIRST_QUARTER	},
326e5c31af7Sopenharmony_ci		{ tcu::Vector<deInt64,2>(halfPixel,		0),				true,	DiamondCorners::CORNER_EDGE_CASE_HIT,					DiamondCorners::CORNER_START_CASE_OUTSIDE,			DiamondCorners::CORNER_END_CASE_NONE						},
327e5c31af7Sopenharmony_ci	};
328e5c31af7Sopenharmony_ci
329e5c31af7Sopenharmony_ci	// Corner cases at the corners
330e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(corners); ++ndx)
331e5c31af7Sopenharmony_ci	{
332e5c31af7Sopenharmony_ci		const tcu::Vector<deInt64,2> p	= diamondCenter + corners[ndx].dp;
333e5c31af7Sopenharmony_ci		const bool intersectsAtCorner	= LineRasterUtil::vertexOnLineSegment(p, line);
334e5c31af7Sopenharmony_ci
335e5c31af7Sopenharmony_ci		if (!intersectsAtCorner)
336e5c31af7Sopenharmony_ci			continue;
337e5c31af7Sopenharmony_ci
338e5c31af7Sopenharmony_ci		// line segment body intersects with the corner
339e5c31af7Sopenharmony_ci		if (p != line.m_v0 && p != line.m_v1)
340e5c31af7Sopenharmony_ci		{
341e5c31af7Sopenharmony_ci			if (corners[ndx].lineBehavior == DiamondCorners::CORNER_EDGE_CASE_HIT)
342e5c31af7Sopenharmony_ci				return true;
343e5c31af7Sopenharmony_ci
344e5c31af7Sopenharmony_ci			// endpoint in (+X, -Y) (X or Y may be 0) direction <==> x*y <= 0
345e5c31af7Sopenharmony_ci			if (corners[ndx].lineBehavior == DiamondCorners::CORNER_EDGE_CASE_HIT_FIRST_QUARTER &&
346e5c31af7Sopenharmony_ci				(line.direction().x() * line.direction().y()) <= 0)
347e5c31af7Sopenharmony_ci				return true;
348e5c31af7Sopenharmony_ci
349e5c31af7Sopenharmony_ci			// endpoint in (+X, +Y) (Y > 0) direction <==> x*y > 0
350e5c31af7Sopenharmony_ci			if (corners[ndx].lineBehavior == DiamondCorners::CORNER_EDGE_CASE_HIT_SECOND_QUARTER &&
351e5c31af7Sopenharmony_ci				(line.direction().x() * line.direction().y()) > 0)
352e5c31af7Sopenharmony_ci				return true;
353e5c31af7Sopenharmony_ci		}
354e5c31af7Sopenharmony_ci
355e5c31af7Sopenharmony_ci		// line exits the area at the corner
356e5c31af7Sopenharmony_ci		if (lineInCornerAngleRange(line, corners[ndx].dp))
357e5c31af7Sopenharmony_ci		{
358e5c31af7Sopenharmony_ci			const bool startIsInside = corners[ndx].pointInclusive || p != line.m_v0;
359e5c31af7Sopenharmony_ci			const bool endIsOutside = !corners[ndx].pointInclusive || p != line.m_v1;
360e5c31af7Sopenharmony_ci
361e5c31af7Sopenharmony_ci			// starting point is inside the region and end endpoint is outside
362e5c31af7Sopenharmony_ci			if (startIsInside && endIsOutside)
363e5c31af7Sopenharmony_ci				return true;
364e5c31af7Sopenharmony_ci		}
365e5c31af7Sopenharmony_ci
366e5c31af7Sopenharmony_ci		// line end is at the corner
367e5c31af7Sopenharmony_ci		if (p == line.m_v1)
368e5c31af7Sopenharmony_ci		{
369e5c31af7Sopenharmony_ci			if (corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION ||
370e5c31af7Sopenharmony_ci				corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION_AND_FIRST_QUARTER ||
371e5c31af7Sopenharmony_ci				corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION_AND_SECOND_QUARTER)
372e5c31af7Sopenharmony_ci			{
373e5c31af7Sopenharmony_ci				// did the line intersect the region
374e5c31af7Sopenharmony_ci				if (lineInCornerAngleRange(line, corners[ndx].dp))
375e5c31af7Sopenharmony_ci					return true;
376e5c31af7Sopenharmony_ci			}
377e5c31af7Sopenharmony_ci
378e5c31af7Sopenharmony_ci			// due to the perturbed endpoint, lines at this the angle will cause and enter-exit pair
379e5c31af7Sopenharmony_ci			if (corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION_AND_FIRST_QUARTER &&
380e5c31af7Sopenharmony_ci				line.direction().x() < 0 &&
381e5c31af7Sopenharmony_ci				line.direction().y() > 0)
382e5c31af7Sopenharmony_ci				return true;
383e5c31af7Sopenharmony_ci			if (corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION_AND_SECOND_QUARTER &&
384e5c31af7Sopenharmony_ci				line.direction().x() > 0 &&
385e5c31af7Sopenharmony_ci				line.direction().y() > 0)
386e5c31af7Sopenharmony_ci				return true;
387e5c31af7Sopenharmony_ci		}
388e5c31af7Sopenharmony_ci
389e5c31af7Sopenharmony_ci		// line start is at the corner
390e5c31af7Sopenharmony_ci		if (p == line.m_v0)
391e5c31af7Sopenharmony_ci		{
392e5c31af7Sopenharmony_ci			if (corners[ndx].startBehavior == DiamondCorners::CORNER_START_CASE_OUTSIDE)
393e5c31af7Sopenharmony_ci			{
394e5c31af7Sopenharmony_ci				// if the line is not going inside, it will exit
395e5c31af7Sopenharmony_ci				if (lineInCornerOutsideAngleRange(line, corners[ndx].dp))
396e5c31af7Sopenharmony_ci					return true;
397e5c31af7Sopenharmony_ci			}
398e5c31af7Sopenharmony_ci
399e5c31af7Sopenharmony_ci			// exit, if line the angle between line vector and X-axis is in range (0, 45] in positive Y side.
400e5c31af7Sopenharmony_ci			if (corners[ndx].startBehavior == DiamondCorners::CORNER_START_CASE_POSITIVE_Y_45 &&
401e5c31af7Sopenharmony_ci				line.direction().x() > 0 &&
402e5c31af7Sopenharmony_ci				line.direction().y() > 0 &&
403e5c31af7Sopenharmony_ci				line.direction().y() <= line.direction().x())
404e5c31af7Sopenharmony_ci				return true;
405e5c31af7Sopenharmony_ci
406e5c31af7Sopenharmony_ci			// exit, if line the angle between line vector and X-axis is in range [0, 45] in negative Y side.
407e5c31af7Sopenharmony_ci			if (corners[ndx].startBehavior == DiamondCorners::CORNER_START_CASE_NEGATIVE_Y_45 &&
408e5c31af7Sopenharmony_ci				 line.direction().x() > 0 &&
409e5c31af7Sopenharmony_ci				 line.direction().y() <= 0 &&
410e5c31af7Sopenharmony_ci				-line.direction().y() <= line.direction().x())
411e5c31af7Sopenharmony_ci				return true;
412e5c31af7Sopenharmony_ci		}
413e5c31af7Sopenharmony_ci	}
414e5c31af7Sopenharmony_ci
415e5c31af7Sopenharmony_ci	// Does the line intersect boundary at the left == exits the diamond
416e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(bounds); ++ndx)
417e5c31af7Sopenharmony_ci	{
418e5c31af7Sopenharmony_ci		const bool startVertexInside =	LineRasterUtil::vertexOnLeftSideOfLine						(line.m_v0, LineRasterUtil::SubpixelLineSegment(bounds[ndx].p0, bounds[ndx].p1)) ||
419e5c31af7Sopenharmony_ci										(bounds[ndx].edgeInclusive && LineRasterUtil::vertexOnLine	(line.m_v0, LineRasterUtil::SubpixelLineSegment(bounds[ndx].p0, bounds[ndx].p1)));
420e5c31af7Sopenharmony_ci		const bool endVertexInside =	LineRasterUtil::vertexOnLeftSideOfLine						(line.m_v1, LineRasterUtil::SubpixelLineSegment(bounds[ndx].p0, bounds[ndx].p1)) ||
421e5c31af7Sopenharmony_ci										(bounds[ndx].edgeInclusive && LineRasterUtil::vertexOnLine	(line.m_v1, LineRasterUtil::SubpixelLineSegment(bounds[ndx].p0, bounds[ndx].p1)));
422e5c31af7Sopenharmony_ci
423e5c31af7Sopenharmony_ci		// start must be on inside this half space (left or at the inclusive boundary)
424e5c31af7Sopenharmony_ci		if (!startVertexInside)
425e5c31af7Sopenharmony_ci			continue;
426e5c31af7Sopenharmony_ci
427e5c31af7Sopenharmony_ci		// end must be outside of this half-space (right or at non-inclusive boundary)
428e5c31af7Sopenharmony_ci		if (endVertexInside)
429e5c31af7Sopenharmony_ci			continue;
430e5c31af7Sopenharmony_ci
431e5c31af7Sopenharmony_ci		// Does the line via v0 and v1 intersect the line segment p0-p1
432e5c31af7Sopenharmony_ci		// <==> p0 and p1 are the different sides (LEFT, RIGHT) of the v0-v1 line.
433e5c31af7Sopenharmony_ci		// Corners are not allowed, they are checked already
434e5c31af7Sopenharmony_ci		LineRasterUtil::LINE_SIDE sideP0 = LineRasterUtil::getVertexSide(bounds[ndx].p0, line);
435e5c31af7Sopenharmony_ci		LineRasterUtil::LINE_SIDE sideP1 = LineRasterUtil::getVertexSide(bounds[ndx].p1, line);
436e5c31af7Sopenharmony_ci
437e5c31af7Sopenharmony_ci		if (sideP0 != LineRasterUtil::LINE_SIDE_INTERSECT &&
438e5c31af7Sopenharmony_ci			sideP1 != LineRasterUtil::LINE_SIDE_INTERSECT &&
439e5c31af7Sopenharmony_ci			sideP0 != sideP1)
440e5c31af7Sopenharmony_ci			return true;
441e5c31af7Sopenharmony_ci	}
442e5c31af7Sopenharmony_ci
443e5c31af7Sopenharmony_ci	return false;
444e5c31af7Sopenharmony_ci}
445e5c31af7Sopenharmony_ci
446e5c31af7Sopenharmony_ci} // LineRasterUtil
447e5c31af7Sopenharmony_ci
448e5c31af7Sopenharmony_ciTriangleRasterizer::TriangleRasterizer (const tcu::IVec4& viewport, const int numSamples, const RasterizationState& state, const int subpixelBits)
449e5c31af7Sopenharmony_ci	: m_viewport				(viewport)
450e5c31af7Sopenharmony_ci	, m_numSamples				(numSamples)
451e5c31af7Sopenharmony_ci	, m_winding					(state.winding)
452e5c31af7Sopenharmony_ci	, m_horizontalFill			(state.horizontalFill)
453e5c31af7Sopenharmony_ci	, m_verticalFill			(state.verticalFill)
454e5c31af7Sopenharmony_ci	, m_subpixelBits			(subpixelBits)
455e5c31af7Sopenharmony_ci	, m_face					(FACETYPE_LAST)
456e5c31af7Sopenharmony_ci	, m_viewportOrientation		(state.viewportOrientation)
457e5c31af7Sopenharmony_ci{
458e5c31af7Sopenharmony_ci}
459e5c31af7Sopenharmony_ci
460e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
461e5c31af7Sopenharmony_ci * \brief Initialize triangle rasterization
462e5c31af7Sopenharmony_ci * \param v0 Screen-space coordinates (x, y, z) and 1/w for vertex 0.
463e5c31af7Sopenharmony_ci * \param v1 Screen-space coordinates (x, y, z) and 1/w for vertex 1.
464e5c31af7Sopenharmony_ci * \param v2 Screen-space coordinates (x, y, z) and 1/w for vertex 2.
465e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
466e5c31af7Sopenharmony_civoid TriangleRasterizer::init (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2)
467e5c31af7Sopenharmony_ci{
468e5c31af7Sopenharmony_ci	m_v0 = v0;
469e5c31af7Sopenharmony_ci	m_v1 = v1;
470e5c31af7Sopenharmony_ci	m_v2 = v2;
471e5c31af7Sopenharmony_ci
472e5c31af7Sopenharmony_ci	// Positions in fixed-point coordinates.
473e5c31af7Sopenharmony_ci	const deInt64	x0		= toSubpixelCoord(v0.x(), m_subpixelBits);
474e5c31af7Sopenharmony_ci	const deInt64	y0		= toSubpixelCoord(v0.y(), m_subpixelBits);
475e5c31af7Sopenharmony_ci	const deInt64	x1		= toSubpixelCoord(v1.x(), m_subpixelBits);
476e5c31af7Sopenharmony_ci	const deInt64	y1		= toSubpixelCoord(v1.y(), m_subpixelBits);
477e5c31af7Sopenharmony_ci	const deInt64	x2		= toSubpixelCoord(v2.x(), m_subpixelBits);
478e5c31af7Sopenharmony_ci	const deInt64	y2		= toSubpixelCoord(v2.y(), m_subpixelBits);
479e5c31af7Sopenharmony_ci
480e5c31af7Sopenharmony_ci	// Initialize edge functions.
481e5c31af7Sopenharmony_ci	if (m_winding == WINDING_CCW)
482e5c31af7Sopenharmony_ci	{
483e5c31af7Sopenharmony_ci		initEdgeCCW(m_edge01, m_horizontalFill, m_verticalFill, x0, y0, x1, y1);
484e5c31af7Sopenharmony_ci		initEdgeCCW(m_edge12, m_horizontalFill, m_verticalFill, x1, y1, x2, y2);
485e5c31af7Sopenharmony_ci		initEdgeCCW(m_edge20, m_horizontalFill, m_verticalFill, x2, y2, x0, y0);
486e5c31af7Sopenharmony_ci	}
487e5c31af7Sopenharmony_ci	else
488e5c31af7Sopenharmony_ci	{
489e5c31af7Sopenharmony_ci		// Reverse edges
490e5c31af7Sopenharmony_ci		initEdgeCCW(m_edge01, m_horizontalFill, m_verticalFill, x1, y1, x0, y0);
491e5c31af7Sopenharmony_ci		initEdgeCCW(m_edge12, m_horizontalFill, m_verticalFill, x2, y2, x1, y1);
492e5c31af7Sopenharmony_ci		initEdgeCCW(m_edge20, m_horizontalFill, m_verticalFill, x0, y0, x2, y2);
493e5c31af7Sopenharmony_ci	}
494e5c31af7Sopenharmony_ci
495e5c31af7Sopenharmony_ci	// Determine face.
496e5c31af7Sopenharmony_ci	const deInt64	s				= evaluateEdge(m_edge01, x2, y2);
497e5c31af7Sopenharmony_ci	const bool		positiveArea	= (m_winding == WINDING_CCW) ? (s > 0) : (s < 0);
498e5c31af7Sopenharmony_ci
499e5c31af7Sopenharmony_ci	if (m_viewportOrientation == VIEWPORTORIENTATION_UPPER_LEFT)
500e5c31af7Sopenharmony_ci		m_face = positiveArea ? FACETYPE_BACK : FACETYPE_FRONT;
501e5c31af7Sopenharmony_ci	else
502e5c31af7Sopenharmony_ci		m_face = positiveArea ? FACETYPE_FRONT : FACETYPE_BACK;
503e5c31af7Sopenharmony_ci
504e5c31af7Sopenharmony_ci	if (!positiveArea)
505e5c31af7Sopenharmony_ci	{
506e5c31af7Sopenharmony_ci		// Reverse edges so that we can use CCW area tests & interpolation
507e5c31af7Sopenharmony_ci		reverseEdge(m_edge01);
508e5c31af7Sopenharmony_ci		reverseEdge(m_edge12);
509e5c31af7Sopenharmony_ci		reverseEdge(m_edge20);
510e5c31af7Sopenharmony_ci	}
511e5c31af7Sopenharmony_ci
512e5c31af7Sopenharmony_ci	// Bounding box
513e5c31af7Sopenharmony_ci	const deInt64	xMin	= de::min(de::min(x0, x1), x2);
514e5c31af7Sopenharmony_ci	const deInt64	xMax	= de::max(de::max(x0, x1), x2);
515e5c31af7Sopenharmony_ci	const deInt64	yMin	= de::min(de::min(y0, y1), y2);
516e5c31af7Sopenharmony_ci	const deInt64	yMax	= de::max(de::max(y0, y1), y2);
517e5c31af7Sopenharmony_ci
518e5c31af7Sopenharmony_ci	m_bboxMin.x() = floorSubpixelToPixelCoord	(xMin, m_subpixelBits, m_horizontalFill	== FILL_LEFT);
519e5c31af7Sopenharmony_ci	m_bboxMin.y() = floorSubpixelToPixelCoord	(yMin, m_subpixelBits, m_verticalFill	== FILL_BOTTOM);
520e5c31af7Sopenharmony_ci	m_bboxMax.x() = ceilSubpixelToPixelCoord	(xMax, m_subpixelBits, m_horizontalFill	== FILL_RIGHT);
521e5c31af7Sopenharmony_ci	m_bboxMax.y() = ceilSubpixelToPixelCoord	(yMax, m_subpixelBits, m_verticalFill	== FILL_TOP);
522e5c31af7Sopenharmony_ci
523e5c31af7Sopenharmony_ci	// Clamp to viewport
524e5c31af7Sopenharmony_ci	const int		wX0		= m_viewport.x();
525e5c31af7Sopenharmony_ci	const int		wY0		= m_viewport.y();
526e5c31af7Sopenharmony_ci	const int		wX1		= wX0 + m_viewport.z() - 1;
527e5c31af7Sopenharmony_ci	const int		wY1		= wY0 + m_viewport.w() -1;
528e5c31af7Sopenharmony_ci
529e5c31af7Sopenharmony_ci	m_bboxMin.x() = de::clamp(m_bboxMin.x(), wX0, wX1);
530e5c31af7Sopenharmony_ci	m_bboxMin.y() = de::clamp(m_bboxMin.y(), wY0, wY1);
531e5c31af7Sopenharmony_ci	m_bboxMax.x() = de::clamp(m_bboxMax.x(), wX0, wX1);
532e5c31af7Sopenharmony_ci	m_bboxMax.y() = de::clamp(m_bboxMax.y(), wY0, wY1);
533e5c31af7Sopenharmony_ci
534e5c31af7Sopenharmony_ci	m_curPos = m_bboxMin;
535e5c31af7Sopenharmony_ci}
536e5c31af7Sopenharmony_ci
537e5c31af7Sopenharmony_civoid TriangleRasterizer::rasterizeSingleSample (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
538e5c31af7Sopenharmony_ci{
539e5c31af7Sopenharmony_ci	DE_ASSERT(maxFragmentPackets > 0);
540e5c31af7Sopenharmony_ci
541e5c31af7Sopenharmony_ci	const deUint64	halfPixel	= 1ll << (m_subpixelBits - 1);
542e5c31af7Sopenharmony_ci	int				packetNdx	= 0;
543e5c31af7Sopenharmony_ci
544e5c31af7Sopenharmony_ci	// For depth interpolation; given barycentrics A, B, C = (1 - A - B)
545e5c31af7Sopenharmony_ci	// we can reformulate the usual z = z0*A + z1*B + z2*C into more
546e5c31af7Sopenharmony_ci	// stable equation z = A*(z0 - z2) + B*(z1 - z2) + z2.
547e5c31af7Sopenharmony_ci	const float		za			= m_v0.z()-m_v2.z();
548e5c31af7Sopenharmony_ci	const float		zb			= m_v1.z()-m_v2.z();
549e5c31af7Sopenharmony_ci	const float		zc			= m_v2.z();
550e5c31af7Sopenharmony_ci
551e5c31af7Sopenharmony_ci	while (m_curPos.y() <= m_bboxMax.y() && packetNdx < maxFragmentPackets)
552e5c31af7Sopenharmony_ci	{
553e5c31af7Sopenharmony_ci		const int		x0		= m_curPos.x();
554e5c31af7Sopenharmony_ci		const int		y0		= m_curPos.y();
555e5c31af7Sopenharmony_ci
556e5c31af7Sopenharmony_ci		// Subpixel coords
557e5c31af7Sopenharmony_ci		const deInt64	sx0		= toSubpixelCoord(x0,   m_subpixelBits)	+ halfPixel;
558e5c31af7Sopenharmony_ci		const deInt64	sx1		= toSubpixelCoord(x0+1, m_subpixelBits)	+ halfPixel;
559e5c31af7Sopenharmony_ci		const deInt64	sy0		= toSubpixelCoord(y0,   m_subpixelBits)	+ halfPixel;
560e5c31af7Sopenharmony_ci		const deInt64	sy1		= toSubpixelCoord(y0+1, m_subpixelBits)	+ halfPixel;
561e5c31af7Sopenharmony_ci
562e5c31af7Sopenharmony_ci		const deInt64	sx[4]	= { sx0, sx1, sx0, sx1 };
563e5c31af7Sopenharmony_ci		const deInt64	sy[4]	= { sy0, sy0, sy1, sy1 };
564e5c31af7Sopenharmony_ci
565e5c31af7Sopenharmony_ci		// Viewport test
566e5c31af7Sopenharmony_ci		const bool		outX1	= x0+1 == m_viewport.x()+m_viewport.z();
567e5c31af7Sopenharmony_ci		const bool		outY1	= y0+1 == m_viewport.y()+m_viewport.w();
568e5c31af7Sopenharmony_ci
569e5c31af7Sopenharmony_ci		DE_ASSERT(x0 < m_viewport.x()+m_viewport.z());
570e5c31af7Sopenharmony_ci		DE_ASSERT(y0 < m_viewport.y()+m_viewport.w());
571e5c31af7Sopenharmony_ci
572e5c31af7Sopenharmony_ci		// Edge values
573e5c31af7Sopenharmony_ci		tcu::Vector<deInt64, 4>	e01;
574e5c31af7Sopenharmony_ci		tcu::Vector<deInt64, 4>	e12;
575e5c31af7Sopenharmony_ci		tcu::Vector<deInt64, 4>	e20;
576e5c31af7Sopenharmony_ci
577e5c31af7Sopenharmony_ci		// Coverage
578e5c31af7Sopenharmony_ci		deUint64		coverage	= 0;
579e5c31af7Sopenharmony_ci
580e5c31af7Sopenharmony_ci		// Evaluate edge values
581e5c31af7Sopenharmony_ci		for (int i = 0; i < 4; i++)
582e5c31af7Sopenharmony_ci		{
583e5c31af7Sopenharmony_ci			e01[i] = evaluateEdge(m_edge01, sx[i], sy[i]);
584e5c31af7Sopenharmony_ci			e12[i] = evaluateEdge(m_edge12, sx[i], sy[i]);
585e5c31af7Sopenharmony_ci			e20[i] = evaluateEdge(m_edge20, sx[i], sy[i]);
586e5c31af7Sopenharmony_ci		}
587e5c31af7Sopenharmony_ci
588e5c31af7Sopenharmony_ci		// Compute coverage mask
589e5c31af7Sopenharmony_ci		coverage = setCoverageValue(coverage, 1, 0, 0, 0,						isInsideCCW(m_edge01, e01[0]) && isInsideCCW(m_edge12, e12[0]) && isInsideCCW(m_edge20, e20[0]));
590e5c31af7Sopenharmony_ci		coverage = setCoverageValue(coverage, 1, 1, 0, 0, !outX1 &&				isInsideCCW(m_edge01, e01[1]) && isInsideCCW(m_edge12, e12[1]) && isInsideCCW(m_edge20, e20[1]));
591e5c31af7Sopenharmony_ci		coverage = setCoverageValue(coverage, 1, 0, 1, 0, !outY1 &&				isInsideCCW(m_edge01, e01[2]) && isInsideCCW(m_edge12, e12[2]) && isInsideCCW(m_edge20, e20[2]));
592e5c31af7Sopenharmony_ci		coverage = setCoverageValue(coverage, 1, 1, 1, 0, !outX1 && !outY1 &&	isInsideCCW(m_edge01, e01[3]) && isInsideCCW(m_edge12, e12[3]) && isInsideCCW(m_edge20, e20[3]));
593e5c31af7Sopenharmony_ci
594e5c31af7Sopenharmony_ci		// Advance to next location
595e5c31af7Sopenharmony_ci		m_curPos.x() += 2;
596e5c31af7Sopenharmony_ci		if (m_curPos.x() > m_bboxMax.x())
597e5c31af7Sopenharmony_ci		{
598e5c31af7Sopenharmony_ci			m_curPos.y() += 2;
599e5c31af7Sopenharmony_ci			m_curPos.x()  = m_bboxMin.x();
600e5c31af7Sopenharmony_ci		}
601e5c31af7Sopenharmony_ci
602e5c31af7Sopenharmony_ci		if (coverage == 0)
603e5c31af7Sopenharmony_ci			continue; // Discard.
604e5c31af7Sopenharmony_ci
605e5c31af7Sopenharmony_ci		// Floating-point edge values for barycentrics etc.
606e5c31af7Sopenharmony_ci		const tcu::Vec4		e01f	= e01.asFloat();
607e5c31af7Sopenharmony_ci		const tcu::Vec4		e12f	= e12.asFloat();
608e5c31af7Sopenharmony_ci		const tcu::Vec4		e20f	= e20.asFloat();
609e5c31af7Sopenharmony_ci
610e5c31af7Sopenharmony_ci		// Compute depth values.
611e5c31af7Sopenharmony_ci		if (depthValues)
612e5c31af7Sopenharmony_ci		{
613e5c31af7Sopenharmony_ci			const tcu::Vec4		edgeSum	= e01f + e12f + e20f;
614e5c31af7Sopenharmony_ci			const tcu::Vec4		z0		= e12f / edgeSum;
615e5c31af7Sopenharmony_ci			const tcu::Vec4		z1		= e20f / edgeSum;
616e5c31af7Sopenharmony_ci
617e5c31af7Sopenharmony_ci			depthValues[packetNdx*4+0] = z0[0]*za + z1[0]*zb + zc;
618e5c31af7Sopenharmony_ci			depthValues[packetNdx*4+1] = z0[1]*za + z1[1]*zb + zc;
619e5c31af7Sopenharmony_ci			depthValues[packetNdx*4+2] = z0[2]*za + z1[2]*zb + zc;
620e5c31af7Sopenharmony_ci			depthValues[packetNdx*4+3] = z0[3]*za + z1[3]*zb + zc;
621e5c31af7Sopenharmony_ci		}
622e5c31af7Sopenharmony_ci
623e5c31af7Sopenharmony_ci		// Compute barycentrics and write out fragment packet
624e5c31af7Sopenharmony_ci		{
625e5c31af7Sopenharmony_ci			FragmentPacket& packet = fragmentPackets[packetNdx];
626e5c31af7Sopenharmony_ci
627e5c31af7Sopenharmony_ci			const tcu::Vec4		b0		= e12f * m_v0.w();
628e5c31af7Sopenharmony_ci			const tcu::Vec4		b1		= e20f * m_v1.w();
629e5c31af7Sopenharmony_ci			const tcu::Vec4		b2		= e01f * m_v2.w();
630e5c31af7Sopenharmony_ci			const tcu::Vec4		bSum	= b0 + b1 + b2;
631e5c31af7Sopenharmony_ci
632e5c31af7Sopenharmony_ci			packet.position			= tcu::IVec2(x0, y0);
633e5c31af7Sopenharmony_ci			packet.coverage			= coverage;
634e5c31af7Sopenharmony_ci			packet.barycentric[0]	= b0 / bSum;
635e5c31af7Sopenharmony_ci			packet.barycentric[1]	= b1 / bSum;
636e5c31af7Sopenharmony_ci			packet.barycentric[2]	= 1.0f - packet.barycentric[0] - packet.barycentric[1];
637e5c31af7Sopenharmony_ci
638e5c31af7Sopenharmony_ci			packetNdx += 1;
639e5c31af7Sopenharmony_ci		}
640e5c31af7Sopenharmony_ci	}
641e5c31af7Sopenharmony_ci
642e5c31af7Sopenharmony_ci	DE_ASSERT(packetNdx <= maxFragmentPackets);
643e5c31af7Sopenharmony_ci	numPacketsRasterized = packetNdx;
644e5c31af7Sopenharmony_ci}
645e5c31af7Sopenharmony_ci
646e5c31af7Sopenharmony_ci// Sample positions - ordered as (x, y) list.
647e5c31af7Sopenharmony_cistatic const float s_samplePts2[] =
648e5c31af7Sopenharmony_ci{
649e5c31af7Sopenharmony_ci	0.3f, 0.3f,
650e5c31af7Sopenharmony_ci	0.7f, 0.7f
651e5c31af7Sopenharmony_ci};
652e5c31af7Sopenharmony_ci
653e5c31af7Sopenharmony_cistatic const float s_samplePts4[] =
654e5c31af7Sopenharmony_ci{
655e5c31af7Sopenharmony_ci	0.25f, 0.25f,
656e5c31af7Sopenharmony_ci	0.75f, 0.25f,
657e5c31af7Sopenharmony_ci	0.25f, 0.75f,
658e5c31af7Sopenharmony_ci	0.75f, 0.75f
659e5c31af7Sopenharmony_ci};
660e5c31af7Sopenharmony_ci
661e5c31af7Sopenharmony_cistatic const float s_samplePts8[] =
662e5c31af7Sopenharmony_ci{
663e5c31af7Sopenharmony_ci	7.f  / 16.f,  9.f / 16.f,
664e5c31af7Sopenharmony_ci	9.f  / 16.f, 13.f / 16.f,
665e5c31af7Sopenharmony_ci	11.f / 16.f,  3.f / 16.f,
666e5c31af7Sopenharmony_ci	13.f / 16.f, 11.f / 16.f,
667e5c31af7Sopenharmony_ci	1.f  / 16.f,  7.f / 16.f,
668e5c31af7Sopenharmony_ci	5.f  / 16.f,  1.f / 16.f,
669e5c31af7Sopenharmony_ci	15.f / 16.f,  5.f / 16.f,
670e5c31af7Sopenharmony_ci	3.f  / 16.f, 15.f / 16.f
671e5c31af7Sopenharmony_ci};
672e5c31af7Sopenharmony_ci
673e5c31af7Sopenharmony_cistatic const float s_samplePts16[] =
674e5c31af7Sopenharmony_ci{
675e5c31af7Sopenharmony_ci	1.f / 8.f, 1.f / 8.f,
676e5c31af7Sopenharmony_ci	3.f / 8.f, 1.f / 8.f,
677e5c31af7Sopenharmony_ci	5.f / 8.f, 1.f / 8.f,
678e5c31af7Sopenharmony_ci	7.f / 8.f, 1.f / 8.f,
679e5c31af7Sopenharmony_ci	1.f / 8.f, 3.f / 8.f,
680e5c31af7Sopenharmony_ci	3.f / 8.f, 3.f / 8.f,
681e5c31af7Sopenharmony_ci	5.f / 8.f, 3.f / 8.f,
682e5c31af7Sopenharmony_ci	7.f / 8.f, 3.f / 8.f,
683e5c31af7Sopenharmony_ci	1.f / 8.f, 5.f / 8.f,
684e5c31af7Sopenharmony_ci	3.f / 8.f, 5.f / 8.f,
685e5c31af7Sopenharmony_ci	5.f / 8.f, 5.f / 8.f,
686e5c31af7Sopenharmony_ci	7.f / 8.f, 5.f / 8.f,
687e5c31af7Sopenharmony_ci	1.f / 8.f, 7.f / 8.f,
688e5c31af7Sopenharmony_ci	3.f / 8.f, 7.f / 8.f,
689e5c31af7Sopenharmony_ci	5.f / 8.f, 7.f / 8.f,
690e5c31af7Sopenharmony_ci	7.f / 8.f, 7.f / 8.f
691e5c31af7Sopenharmony_ci};
692e5c31af7Sopenharmony_ci
693e5c31af7Sopenharmony_citemplate<int NumSamples>
694e5c31af7Sopenharmony_civoid TriangleRasterizer::rasterizeMultiSample (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
695e5c31af7Sopenharmony_ci{
696e5c31af7Sopenharmony_ci	DE_ASSERT(maxFragmentPackets > 0);
697e5c31af7Sopenharmony_ci
698e5c31af7Sopenharmony_ci	// Big enough to hold maximum multisample count
699e5c31af7Sopenharmony_ci	deInt64			samplePos[DE_LENGTH_OF_ARRAY(s_samplePts16)];
700e5c31af7Sopenharmony_ci	const float *	samplePts	= DE_NULL;
701e5c31af7Sopenharmony_ci	const deUint64	halfPixel	= 1ll << (m_subpixelBits - 1);
702e5c31af7Sopenharmony_ci	int				packetNdx	= 0;
703e5c31af7Sopenharmony_ci
704e5c31af7Sopenharmony_ci	// For depth interpolation, see rasterizeSingleSample
705e5c31af7Sopenharmony_ci	const float		za			= m_v0.z()-m_v2.z();
706e5c31af7Sopenharmony_ci	const float		zb			= m_v1.z()-m_v2.z();
707e5c31af7Sopenharmony_ci	const float		zc			= m_v2.z();
708e5c31af7Sopenharmony_ci
709e5c31af7Sopenharmony_ci	switch (NumSamples)
710e5c31af7Sopenharmony_ci	{
711e5c31af7Sopenharmony_ci		case 2:		samplePts = s_samplePts2;	break;
712e5c31af7Sopenharmony_ci		case 4:		samplePts = s_samplePts4;	break;
713e5c31af7Sopenharmony_ci		case 8:		samplePts = s_samplePts8;	break;
714e5c31af7Sopenharmony_ci		case 16:	samplePts = s_samplePts16;	break;
715e5c31af7Sopenharmony_ci		default:
716e5c31af7Sopenharmony_ci			DE_ASSERT(false);
717e5c31af7Sopenharmony_ci	}
718e5c31af7Sopenharmony_ci
719e5c31af7Sopenharmony_ci	for (int c = 0; c < NumSamples * 2; ++c)
720e5c31af7Sopenharmony_ci		samplePos[c] = toSubpixelCoord(samplePts[c], m_subpixelBits);
721e5c31af7Sopenharmony_ci
722e5c31af7Sopenharmony_ci	while (m_curPos.y() <= m_bboxMax.y() && packetNdx < maxFragmentPackets)
723e5c31af7Sopenharmony_ci	{
724e5c31af7Sopenharmony_ci		const int		x0		= m_curPos.x();
725e5c31af7Sopenharmony_ci		const int		y0		= m_curPos.y();
726e5c31af7Sopenharmony_ci
727e5c31af7Sopenharmony_ci		// Base subpixel coords
728e5c31af7Sopenharmony_ci		const deInt64	sx0		= toSubpixelCoord(x0,   m_subpixelBits);
729e5c31af7Sopenharmony_ci		const deInt64	sx1		= toSubpixelCoord(x0+1, m_subpixelBits);
730e5c31af7Sopenharmony_ci		const deInt64	sy0		= toSubpixelCoord(y0,   m_subpixelBits);
731e5c31af7Sopenharmony_ci		const deInt64	sy1		= toSubpixelCoord(y0+1, m_subpixelBits);
732e5c31af7Sopenharmony_ci
733e5c31af7Sopenharmony_ci		const deInt64	sx[4]	= { sx0, sx1, sx0, sx1 };
734e5c31af7Sopenharmony_ci		const deInt64	sy[4]	= { sy0, sy0, sy1, sy1 };
735e5c31af7Sopenharmony_ci
736e5c31af7Sopenharmony_ci		// Viewport test
737e5c31af7Sopenharmony_ci		const bool		outX1	= x0+1 == m_viewport.x()+m_viewport.z();
738e5c31af7Sopenharmony_ci		const bool		outY1	= y0+1 == m_viewport.y()+m_viewport.w();
739e5c31af7Sopenharmony_ci
740e5c31af7Sopenharmony_ci		DE_ASSERT(x0 < m_viewport.x()+m_viewport.z());
741e5c31af7Sopenharmony_ci		DE_ASSERT(y0 < m_viewport.y()+m_viewport.w());
742e5c31af7Sopenharmony_ci
743e5c31af7Sopenharmony_ci		// Edge values
744e5c31af7Sopenharmony_ci		tcu::Vector<deInt64, 4>	e01[NumSamples];
745e5c31af7Sopenharmony_ci		tcu::Vector<deInt64, 4>	e12[NumSamples];
746e5c31af7Sopenharmony_ci		tcu::Vector<deInt64, 4>	e20[NumSamples];
747e5c31af7Sopenharmony_ci
748e5c31af7Sopenharmony_ci		// Coverage
749e5c31af7Sopenharmony_ci		deUint64		coverage	= 0;
750e5c31af7Sopenharmony_ci
751e5c31af7Sopenharmony_ci		// Evaluate edge values at sample positions
752e5c31af7Sopenharmony_ci		for (int sampleNdx = 0; sampleNdx < NumSamples; sampleNdx++)
753e5c31af7Sopenharmony_ci		{
754e5c31af7Sopenharmony_ci			const deInt64 ox = samplePos[sampleNdx*2 + 0];
755e5c31af7Sopenharmony_ci			const deInt64 oy = samplePos[sampleNdx*2 + 1];
756e5c31af7Sopenharmony_ci
757e5c31af7Sopenharmony_ci			for (int fragNdx = 0; fragNdx < 4; fragNdx++)
758e5c31af7Sopenharmony_ci			{
759e5c31af7Sopenharmony_ci				e01[sampleNdx][fragNdx] = evaluateEdge(m_edge01, sx[fragNdx] + ox, sy[fragNdx] + oy);
760e5c31af7Sopenharmony_ci				e12[sampleNdx][fragNdx] = evaluateEdge(m_edge12, sx[fragNdx] + ox, sy[fragNdx] + oy);
761e5c31af7Sopenharmony_ci				e20[sampleNdx][fragNdx] = evaluateEdge(m_edge20, sx[fragNdx] + ox, sy[fragNdx] + oy);
762e5c31af7Sopenharmony_ci			}
763e5c31af7Sopenharmony_ci		}
764e5c31af7Sopenharmony_ci
765e5c31af7Sopenharmony_ci		// Compute coverage mask
766e5c31af7Sopenharmony_ci		for (int sampleNdx = 0; sampleNdx < NumSamples; sampleNdx++)
767e5c31af7Sopenharmony_ci		{
768e5c31af7Sopenharmony_ci			coverage = setCoverageValue(coverage, NumSamples, 0, 0, sampleNdx,						isInsideCCW(m_edge01, e01[sampleNdx][0]) && isInsideCCW(m_edge12, e12[sampleNdx][0]) && isInsideCCW(m_edge20, e20[sampleNdx][0]));
769e5c31af7Sopenharmony_ci			coverage = setCoverageValue(coverage, NumSamples, 1, 0, sampleNdx, !outX1 &&			isInsideCCW(m_edge01, e01[sampleNdx][1]) && isInsideCCW(m_edge12, e12[sampleNdx][1]) && isInsideCCW(m_edge20, e20[sampleNdx][1]));
770e5c31af7Sopenharmony_ci			coverage = setCoverageValue(coverage, NumSamples, 0, 1, sampleNdx, !outY1 &&			isInsideCCW(m_edge01, e01[sampleNdx][2]) && isInsideCCW(m_edge12, e12[sampleNdx][2]) && isInsideCCW(m_edge20, e20[sampleNdx][2]));
771e5c31af7Sopenharmony_ci			coverage = setCoverageValue(coverage, NumSamples, 1, 1, sampleNdx, !outX1 && !outY1 &&	isInsideCCW(m_edge01, e01[sampleNdx][3]) && isInsideCCW(m_edge12, e12[sampleNdx][3]) && isInsideCCW(m_edge20, e20[sampleNdx][3]));
772e5c31af7Sopenharmony_ci		}
773e5c31af7Sopenharmony_ci
774e5c31af7Sopenharmony_ci		// Advance to next location
775e5c31af7Sopenharmony_ci		m_curPos.x() += 2;
776e5c31af7Sopenharmony_ci		if (m_curPos.x() > m_bboxMax.x())
777e5c31af7Sopenharmony_ci		{
778e5c31af7Sopenharmony_ci			m_curPos.y() += 2;
779e5c31af7Sopenharmony_ci			m_curPos.x()  = m_bboxMin.x();
780e5c31af7Sopenharmony_ci		}
781e5c31af7Sopenharmony_ci
782e5c31af7Sopenharmony_ci		if (coverage == 0)
783e5c31af7Sopenharmony_ci			continue; // Discard.
784e5c31af7Sopenharmony_ci
785e5c31af7Sopenharmony_ci		// Compute depth values.
786e5c31af7Sopenharmony_ci		if (depthValues)
787e5c31af7Sopenharmony_ci		{
788e5c31af7Sopenharmony_ci			for (int sampleNdx = 0; sampleNdx < NumSamples; sampleNdx++)
789e5c31af7Sopenharmony_ci			{
790e5c31af7Sopenharmony_ci				// Floating-point edge values at sample coordinates.
791e5c31af7Sopenharmony_ci				const tcu::Vec4&	e01f	= e01[sampleNdx].asFloat();
792e5c31af7Sopenharmony_ci				const tcu::Vec4&	e12f	= e12[sampleNdx].asFloat();
793e5c31af7Sopenharmony_ci				const tcu::Vec4&	e20f	= e20[sampleNdx].asFloat();
794e5c31af7Sopenharmony_ci
795e5c31af7Sopenharmony_ci				const tcu::Vec4		edgeSum	= e01f + e12f + e20f;
796e5c31af7Sopenharmony_ci				const tcu::Vec4		z0		= e12f / edgeSum;
797e5c31af7Sopenharmony_ci				const tcu::Vec4		z1		= e20f / edgeSum;
798e5c31af7Sopenharmony_ci
799e5c31af7Sopenharmony_ci				depthValues[(packetNdx*4+0)*NumSamples + sampleNdx] = z0[0]*za + z1[0]*zb + zc;
800e5c31af7Sopenharmony_ci				depthValues[(packetNdx*4+1)*NumSamples + sampleNdx] = z0[1]*za + z1[1]*zb + zc;
801e5c31af7Sopenharmony_ci				depthValues[(packetNdx*4+2)*NumSamples + sampleNdx] = z0[2]*za + z1[2]*zb + zc;
802e5c31af7Sopenharmony_ci				depthValues[(packetNdx*4+3)*NumSamples + sampleNdx] = z0[3]*za + z1[3]*zb + zc;
803e5c31af7Sopenharmony_ci			}
804e5c31af7Sopenharmony_ci		}
805e5c31af7Sopenharmony_ci
806e5c31af7Sopenharmony_ci		// Compute barycentrics and write out fragment packet
807e5c31af7Sopenharmony_ci		{
808e5c31af7Sopenharmony_ci			FragmentPacket& packet = fragmentPackets[packetNdx];
809e5c31af7Sopenharmony_ci
810e5c31af7Sopenharmony_ci			// Floating-point edge values at pixel center.
811e5c31af7Sopenharmony_ci			tcu::Vec4			e01f;
812e5c31af7Sopenharmony_ci			tcu::Vec4			e12f;
813e5c31af7Sopenharmony_ci			tcu::Vec4			e20f;
814e5c31af7Sopenharmony_ci
815e5c31af7Sopenharmony_ci			for (int i = 0; i < 4; i++)
816e5c31af7Sopenharmony_ci			{
817e5c31af7Sopenharmony_ci				e01f[i] = float(evaluateEdge(m_edge01, sx[i] + halfPixel, sy[i] + halfPixel));
818e5c31af7Sopenharmony_ci				e12f[i] = float(evaluateEdge(m_edge12, sx[i] + halfPixel, sy[i] + halfPixel));
819e5c31af7Sopenharmony_ci				e20f[i] = float(evaluateEdge(m_edge20, sx[i] + halfPixel, sy[i] + halfPixel));
820e5c31af7Sopenharmony_ci			}
821e5c31af7Sopenharmony_ci
822e5c31af7Sopenharmony_ci			// Barycentrics & scale.
823e5c31af7Sopenharmony_ci			const tcu::Vec4		b0		= e12f * m_v0.w();
824e5c31af7Sopenharmony_ci			const tcu::Vec4		b1		= e20f * m_v1.w();
825e5c31af7Sopenharmony_ci			const tcu::Vec4		b2		= e01f * m_v2.w();
826e5c31af7Sopenharmony_ci			const tcu::Vec4		bSum	= b0 + b1 + b2;
827e5c31af7Sopenharmony_ci
828e5c31af7Sopenharmony_ci			packet.position			= tcu::IVec2(x0, y0);
829e5c31af7Sopenharmony_ci			packet.coverage			= coverage;
830e5c31af7Sopenharmony_ci			packet.barycentric[0]	= b0 / bSum;
831e5c31af7Sopenharmony_ci			packet.barycentric[1]	= b1 / bSum;
832e5c31af7Sopenharmony_ci			packet.barycentric[2]	= 1.0f - packet.barycentric[0] - packet.barycentric[1];
833e5c31af7Sopenharmony_ci
834e5c31af7Sopenharmony_ci			packetNdx += 1;
835e5c31af7Sopenharmony_ci		}
836e5c31af7Sopenharmony_ci	}
837e5c31af7Sopenharmony_ci
838e5c31af7Sopenharmony_ci	DE_ASSERT(packetNdx <= maxFragmentPackets);
839e5c31af7Sopenharmony_ci	numPacketsRasterized = packetNdx;
840e5c31af7Sopenharmony_ci}
841e5c31af7Sopenharmony_ci
842e5c31af7Sopenharmony_civoid TriangleRasterizer::rasterize (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
843e5c31af7Sopenharmony_ci{
844e5c31af7Sopenharmony_ci	DE_ASSERT(maxFragmentPackets > 0);
845e5c31af7Sopenharmony_ci
846e5c31af7Sopenharmony_ci	switch (m_numSamples)
847e5c31af7Sopenharmony_ci	{
848e5c31af7Sopenharmony_ci		case 1:		rasterizeSingleSample		(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
849e5c31af7Sopenharmony_ci		case 2:		rasterizeMultiSample<2>		(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
850e5c31af7Sopenharmony_ci		case 4:		rasterizeMultiSample<4>		(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
851e5c31af7Sopenharmony_ci		case 8:		rasterizeMultiSample<8>		(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
852e5c31af7Sopenharmony_ci		case 16:	rasterizeMultiSample<16>	(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
853e5c31af7Sopenharmony_ci		default:
854e5c31af7Sopenharmony_ci			DE_ASSERT(DE_FALSE);
855e5c31af7Sopenharmony_ci	}
856e5c31af7Sopenharmony_ci}
857e5c31af7Sopenharmony_ci
858e5c31af7Sopenharmony_ciSingleSampleLineRasterizer::SingleSampleLineRasterizer (const tcu::IVec4& viewport, const int subpixelBits)
859e5c31af7Sopenharmony_ci	: m_viewport		(viewport)
860e5c31af7Sopenharmony_ci	, m_subpixelBits	(subpixelBits)
861e5c31af7Sopenharmony_ci	, m_curRowFragment	(0)
862e5c31af7Sopenharmony_ci	, m_lineWidth		(0.0f)
863e5c31af7Sopenharmony_ci	, m_stippleCounter  (0)
864e5c31af7Sopenharmony_ci{
865e5c31af7Sopenharmony_ci}
866e5c31af7Sopenharmony_ci
867e5c31af7Sopenharmony_ciSingleSampleLineRasterizer::~SingleSampleLineRasterizer (void)
868e5c31af7Sopenharmony_ci{
869e5c31af7Sopenharmony_ci}
870e5c31af7Sopenharmony_ci
871e5c31af7Sopenharmony_civoid SingleSampleLineRasterizer::init (const tcu::Vec4& v0, const tcu::Vec4& v1, float lineWidth, deUint32 stippleFactor, deUint16 stipplePattern)
872e5c31af7Sopenharmony_ci{
873e5c31af7Sopenharmony_ci	const bool						isXMajor		= de::abs((v1 - v0).x()) >= de::abs((v1 - v0).y());
874e5c31af7Sopenharmony_ci
875e5c31af7Sopenharmony_ci	// Bounding box \note: with wide lines, the line is actually moved as in the spec
876e5c31af7Sopenharmony_ci	const deInt32					lineWidthPixels	= (lineWidth > 1.0f) ? (deInt32)floor(lineWidth + 0.5f) : 1;
877e5c31af7Sopenharmony_ci
878e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2>	widthOffset		= (isXMajor ? tcu::Vector<deInt64,2>(0, -1) : tcu::Vector<deInt64,2>(-1, 0)) * (toSubpixelCoord(lineWidthPixels - 1, m_subpixelBits) / 2);
879e5c31af7Sopenharmony_ci
880e5c31af7Sopenharmony_ci	const deInt64					x0				= toSubpixelCoord(v0.x(), m_subpixelBits) + widthOffset.x();
881e5c31af7Sopenharmony_ci	const deInt64					y0				= toSubpixelCoord(v0.y(), m_subpixelBits) + widthOffset.y();
882e5c31af7Sopenharmony_ci	const deInt64					x1				= toSubpixelCoord(v1.x(), m_subpixelBits) + widthOffset.x();
883e5c31af7Sopenharmony_ci	const deInt64					y1				= toSubpixelCoord(v1.y(), m_subpixelBits) + widthOffset.y();
884e5c31af7Sopenharmony_ci
885e5c31af7Sopenharmony_ci	// line endpoints might be perturbed, add some margin
886e5c31af7Sopenharmony_ci	const deInt64					xMin			= de::min(x0, x1) - toSubpixelCoord(1, m_subpixelBits);
887e5c31af7Sopenharmony_ci	const deInt64					xMax			= de::max(x0, x1) + toSubpixelCoord(1, m_subpixelBits);
888e5c31af7Sopenharmony_ci	const deInt64					yMin			= de::min(y0, y1) - toSubpixelCoord(1, m_subpixelBits);
889e5c31af7Sopenharmony_ci	const deInt64					yMax			= de::max(y0, y1) + toSubpixelCoord(1, m_subpixelBits);
890e5c31af7Sopenharmony_ci
891e5c31af7Sopenharmony_ci	// Remove invisible area
892e5c31af7Sopenharmony_ci
893e5c31af7Sopenharmony_ci	if (isXMajor)
894e5c31af7Sopenharmony_ci	{
895e5c31af7Sopenharmony_ci		// clamp to viewport in major direction
896e5c31af7Sopenharmony_ci		m_bboxMin.x() = de::clamp(floorSubpixelToPixelCoord(xMin, m_subpixelBits, true), m_viewport.x(), m_viewport.x() + m_viewport.z() - 1);
897e5c31af7Sopenharmony_ci		m_bboxMax.x() = de::clamp(ceilSubpixelToPixelCoord (xMax, m_subpixelBits, true), m_viewport.x(), m_viewport.x() + m_viewport.z() - 1);
898e5c31af7Sopenharmony_ci
899e5c31af7Sopenharmony_ci		// clamp to padded viewport in minor direction (wide lines might bleed over viewport in minor direction)
900e5c31af7Sopenharmony_ci		m_bboxMin.y() = de::clamp(floorSubpixelToPixelCoord(yMin, m_subpixelBits, true), m_viewport.y() - lineWidthPixels, m_viewport.y() + m_viewport.w() - 1);
901e5c31af7Sopenharmony_ci		m_bboxMax.y() = de::clamp(ceilSubpixelToPixelCoord (yMax, m_subpixelBits, true), m_viewport.y() - lineWidthPixels, m_viewport.y() + m_viewport.w() - 1);
902e5c31af7Sopenharmony_ci	}
903e5c31af7Sopenharmony_ci	else
904e5c31af7Sopenharmony_ci	{
905e5c31af7Sopenharmony_ci		// clamp to viewport in major direction
906e5c31af7Sopenharmony_ci		m_bboxMin.y() = de::clamp(floorSubpixelToPixelCoord(yMin, m_subpixelBits, true), m_viewport.y(), m_viewport.y() + m_viewport.w() - 1);
907e5c31af7Sopenharmony_ci		m_bboxMax.y() = de::clamp(ceilSubpixelToPixelCoord (yMax, m_subpixelBits, true), m_viewport.y(), m_viewport.y() + m_viewport.w() - 1);
908e5c31af7Sopenharmony_ci
909e5c31af7Sopenharmony_ci		// clamp to padded viewport in minor direction (wide lines might bleed over viewport in minor direction)
910e5c31af7Sopenharmony_ci		m_bboxMin.x() = de::clamp(floorSubpixelToPixelCoord(xMin, m_subpixelBits, true), m_viewport.x() - lineWidthPixels, m_viewport.x() + m_viewport.z() - 1);
911e5c31af7Sopenharmony_ci		m_bboxMax.x() = de::clamp(ceilSubpixelToPixelCoord (xMax, m_subpixelBits, true), m_viewport.x() - lineWidthPixels, m_viewport.x() + m_viewport.z() - 1);
912e5c31af7Sopenharmony_ci	}
913e5c31af7Sopenharmony_ci
914e5c31af7Sopenharmony_ci	m_lineWidth = lineWidth;
915e5c31af7Sopenharmony_ci
916e5c31af7Sopenharmony_ci	m_v0 = v0;
917e5c31af7Sopenharmony_ci	m_v1 = v1;
918e5c31af7Sopenharmony_ci
919e5c31af7Sopenharmony_ci	// Choose direction of traversal and whether to start at bbox min or max. Direction matters
920e5c31af7Sopenharmony_ci    // for the stipple counter.
921e5c31af7Sopenharmony_ci	int											xDelta				= (m_v1 - m_v0).x() > 0 ? 1 : -1;
922e5c31af7Sopenharmony_ci	int											yDelta				= (m_v1 - m_v0).y() > 0 ? 1 : -1;
923e5c31af7Sopenharmony_ci
924e5c31af7Sopenharmony_ci	m_curPos.x() = xDelta > 0 ? m_bboxMin.x() : m_bboxMax.x();
925e5c31af7Sopenharmony_ci	m_curPos.y() = yDelta > 0 ? m_bboxMin.y() : m_bboxMax.y();
926e5c31af7Sopenharmony_ci
927e5c31af7Sopenharmony_ci	m_curRowFragment = 0;
928e5c31af7Sopenharmony_ci	m_stippleFactor = stippleFactor;
929e5c31af7Sopenharmony_ci	m_stipplePattern = stipplePattern;
930e5c31af7Sopenharmony_ci}
931e5c31af7Sopenharmony_ci
932e5c31af7Sopenharmony_civoid SingleSampleLineRasterizer::rasterize (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
933e5c31af7Sopenharmony_ci{
934e5c31af7Sopenharmony_ci	DE_ASSERT(maxFragmentPackets > 0);
935e5c31af7Sopenharmony_ci
936e5c31af7Sopenharmony_ci	const deInt64								halfPixel			= 1ll << (m_subpixelBits - 1);
937e5c31af7Sopenharmony_ci	const deInt32								lineWidth			= (m_lineWidth > 1.0f) ? deFloorFloatToInt32(m_lineWidth + 0.5f) : 1;
938e5c31af7Sopenharmony_ci	const bool									isXMajor			= de::abs((m_v1 - m_v0).x()) >= de::abs((m_v1 - m_v0).y());
939e5c31af7Sopenharmony_ci	const tcu::IVec2							minorDirection		= (isXMajor) ? (tcu::IVec2(0, 1)) : (tcu::IVec2(1, 0));
940e5c31af7Sopenharmony_ci	const int									minViewportLimit	= (isXMajor) ? (m_viewport.y()) : (m_viewport.x());
941e5c31af7Sopenharmony_ci	const int									maxViewportLimit	= (isXMajor) ? (m_viewport.y() + m_viewport.w()) : (m_viewport.x() + m_viewport.z());
942e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2>				widthOffset			= -minorDirection.cast<deInt64>() * (toSubpixelCoord(lineWidth - 1, m_subpixelBits) / 2);
943e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2>				pa					= LineRasterUtil::toSubpixelVector(m_v0.xy(), m_subpixelBits) + widthOffset;
944e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2>				pb					= LineRasterUtil::toSubpixelVector(m_v1.xy(), m_subpixelBits) + widthOffset;
945e5c31af7Sopenharmony_ci	const LineRasterUtil::SubpixelLineSegment	line				= LineRasterUtil::SubpixelLineSegment(pa, pb);
946e5c31af7Sopenharmony_ci
947e5c31af7Sopenharmony_ci	int											packetNdx			= 0;
948e5c31af7Sopenharmony_ci	int											xDelta				= (m_v1 - m_v0).x() > 0 ? 1 : -1;
949e5c31af7Sopenharmony_ci	int											yDelta				= (m_v1 - m_v0).y() > 0 ? 1 : -1;
950e5c31af7Sopenharmony_ci
951e5c31af7Sopenharmony_ci	while (m_curPos.y() <= m_bboxMax.y() && m_curPos.y() >= m_bboxMin.y() && packetNdx < maxFragmentPackets)
952e5c31af7Sopenharmony_ci	{
953e5c31af7Sopenharmony_ci		const tcu::Vector<deInt64,2> diamondPosition = LineRasterUtil::toSubpixelVector(m_curPos, m_subpixelBits) + tcu::Vector<deInt64,2>(halfPixel,halfPixel);
954e5c31af7Sopenharmony_ci
955e5c31af7Sopenharmony_ci		// Should current fragment be drawn? == does the segment exit this diamond?
956e5c31af7Sopenharmony_ci		if (LineRasterUtil::doesLineSegmentExitDiamond(line, diamondPosition, m_subpixelBits))
957e5c31af7Sopenharmony_ci		{
958e5c31af7Sopenharmony_ci			const tcu::Vector<deInt64,2>	pr					= diamondPosition;
959e5c31af7Sopenharmony_ci			const float						t					= tcu::dot((pr - pa).asFloat(), (pb - pa).asFloat()) / tcu::lengthSquared(pb.asFloat() - pa.asFloat());
960e5c31af7Sopenharmony_ci
961e5c31af7Sopenharmony_ci			// Rasterize on only fragments that are would end up in the viewport (i.e. visible)
962e5c31af7Sopenharmony_ci			const int						fragmentLocation	= (isXMajor) ? (m_curPos.y()) : (m_curPos.x());
963e5c31af7Sopenharmony_ci			const int						rowFragBegin		= de::max(0, minViewportLimit - fragmentLocation);
964e5c31af7Sopenharmony_ci			const int						rowFragEnd			= de::min(maxViewportLimit - fragmentLocation, lineWidth);
965e5c31af7Sopenharmony_ci
966e5c31af7Sopenharmony_ci			int stippleBit = (m_stippleCounter / m_stippleFactor) % 16;
967e5c31af7Sopenharmony_ci			bool stipplePass = (m_stipplePattern & (1 << stippleBit)) != 0;
968e5c31af7Sopenharmony_ci			m_stippleCounter++;
969e5c31af7Sopenharmony_ci
970e5c31af7Sopenharmony_ci			if (stipplePass)
971e5c31af7Sopenharmony_ci			{
972e5c31af7Sopenharmony_ci				// Wide lines require multiple fragments.
973e5c31af7Sopenharmony_ci				for (; rowFragBegin + m_curRowFragment < rowFragEnd; m_curRowFragment++)
974e5c31af7Sopenharmony_ci				{
975e5c31af7Sopenharmony_ci					const int			replicationId	= rowFragBegin + m_curRowFragment;
976e5c31af7Sopenharmony_ci					const tcu::IVec2	fragmentPos		= m_curPos + minorDirection * replicationId;
977e5c31af7Sopenharmony_ci
978e5c31af7Sopenharmony_ci					// We only rasterize visible area
979e5c31af7Sopenharmony_ci					DE_ASSERT(LineRasterUtil::inViewport(fragmentPos, m_viewport));
980e5c31af7Sopenharmony_ci
981e5c31af7Sopenharmony_ci					// Compute depth values.
982e5c31af7Sopenharmony_ci					if (depthValues)
983e5c31af7Sopenharmony_ci					{
984e5c31af7Sopenharmony_ci						const float za = m_v0.z();
985e5c31af7Sopenharmony_ci						const float zb = m_v1.z();
986e5c31af7Sopenharmony_ci
987e5c31af7Sopenharmony_ci						depthValues[packetNdx*4+0] = (1 - t) * za + t * zb;
988e5c31af7Sopenharmony_ci						depthValues[packetNdx*4+1] = 0;
989e5c31af7Sopenharmony_ci						depthValues[packetNdx*4+2] = 0;
990e5c31af7Sopenharmony_ci						depthValues[packetNdx*4+3] = 0;
991e5c31af7Sopenharmony_ci					}
992e5c31af7Sopenharmony_ci
993e5c31af7Sopenharmony_ci					{
994e5c31af7Sopenharmony_ci						// output this fragment
995e5c31af7Sopenharmony_ci						// \note In order to make consistent output with multisampled line rasterization, output "barycentric" coordinates
996e5c31af7Sopenharmony_ci						FragmentPacket& packet = fragmentPackets[packetNdx];
997e5c31af7Sopenharmony_ci
998e5c31af7Sopenharmony_ci						const tcu::Vec4		b0		= tcu::Vec4(1 - t);
999e5c31af7Sopenharmony_ci						const tcu::Vec4		b1		= tcu::Vec4(t);
1000e5c31af7Sopenharmony_ci						const tcu::Vec4		ooSum	= 1.0f / (b0 + b1);
1001e5c31af7Sopenharmony_ci
1002e5c31af7Sopenharmony_ci						packet.position			= fragmentPos;
1003e5c31af7Sopenharmony_ci						packet.coverage			= getCoverageBit(1, 0, 0, 0);
1004e5c31af7Sopenharmony_ci						packet.barycentric[0]	= b0 * ooSum;
1005e5c31af7Sopenharmony_ci						packet.barycentric[1]	= b1 * ooSum;
1006e5c31af7Sopenharmony_ci						packet.barycentric[2]	= tcu::Vec4(0.0f);
1007e5c31af7Sopenharmony_ci
1008e5c31af7Sopenharmony_ci						packetNdx += 1;
1009e5c31af7Sopenharmony_ci					}
1010e5c31af7Sopenharmony_ci
1011e5c31af7Sopenharmony_ci					if (packetNdx == maxFragmentPackets)
1012e5c31af7Sopenharmony_ci					{
1013e5c31af7Sopenharmony_ci						m_curRowFragment++; // don't redraw this fragment again next time
1014e5c31af7Sopenharmony_ci						m_stippleCounter--; // reuse same stipple counter next time
1015e5c31af7Sopenharmony_ci						numPacketsRasterized = packetNdx;
1016e5c31af7Sopenharmony_ci						return;
1017e5c31af7Sopenharmony_ci					}
1018e5c31af7Sopenharmony_ci				}
1019e5c31af7Sopenharmony_ci
1020e5c31af7Sopenharmony_ci				m_curRowFragment = 0;
1021e5c31af7Sopenharmony_ci			}
1022e5c31af7Sopenharmony_ci		}
1023e5c31af7Sopenharmony_ci
1024e5c31af7Sopenharmony_ci		m_curPos.x() += xDelta;
1025e5c31af7Sopenharmony_ci		if (m_curPos.x() > m_bboxMax.x() || m_curPos.x() < m_bboxMin.x())
1026e5c31af7Sopenharmony_ci		{
1027e5c31af7Sopenharmony_ci			m_curPos.y() += yDelta;
1028e5c31af7Sopenharmony_ci			m_curPos.x() = xDelta > 0 ? m_bboxMin.x() : m_bboxMax.x();
1029e5c31af7Sopenharmony_ci		}
1030e5c31af7Sopenharmony_ci	}
1031e5c31af7Sopenharmony_ci
1032e5c31af7Sopenharmony_ci	DE_ASSERT(packetNdx <= maxFragmentPackets);
1033e5c31af7Sopenharmony_ci	numPacketsRasterized = packetNdx;
1034e5c31af7Sopenharmony_ci}
1035e5c31af7Sopenharmony_ci
1036e5c31af7Sopenharmony_ciMultiSampleLineRasterizer::MultiSampleLineRasterizer (const int numSamples, const tcu::IVec4& viewport, const int subpixelBits)
1037e5c31af7Sopenharmony_ci	: m_numSamples			(numSamples)
1038e5c31af7Sopenharmony_ci	, m_triangleRasterizer0 (viewport, m_numSamples, RasterizationState(), subpixelBits)
1039e5c31af7Sopenharmony_ci	, m_triangleRasterizer1 (viewport, m_numSamples, RasterizationState(), subpixelBits)
1040e5c31af7Sopenharmony_ci{
1041e5c31af7Sopenharmony_ci}
1042e5c31af7Sopenharmony_ci
1043e5c31af7Sopenharmony_ciMultiSampleLineRasterizer::~MultiSampleLineRasterizer ()
1044e5c31af7Sopenharmony_ci{
1045e5c31af7Sopenharmony_ci}
1046e5c31af7Sopenharmony_ci
1047e5c31af7Sopenharmony_civoid MultiSampleLineRasterizer::init (const tcu::Vec4& v0, const tcu::Vec4& v1, float lineWidth)
1048e5c31af7Sopenharmony_ci{
1049e5c31af7Sopenharmony_ci	// allow creation of single sampled rasterizer objects but do not allow using them
1050e5c31af7Sopenharmony_ci	DE_ASSERT(m_numSamples > 1);
1051e5c31af7Sopenharmony_ci
1052e5c31af7Sopenharmony_ci	const tcu::Vec2 lineVec		= tcu::Vec2(tcu::Vec4(v1).xy()) - tcu::Vec2(tcu::Vec4(v0).xy());
1053e5c31af7Sopenharmony_ci	const tcu::Vec2 normal2		= tcu::normalize(tcu::Vec2(-lineVec[1], lineVec[0]));
1054e5c31af7Sopenharmony_ci	const tcu::Vec4 normal4		= tcu::Vec4(normal2.x(), normal2.y(), 0, 0);
1055e5c31af7Sopenharmony_ci	const float offset			= lineWidth / 2.0f;
1056e5c31af7Sopenharmony_ci
1057e5c31af7Sopenharmony_ci	const tcu::Vec4 p0 = v0 + normal4 * offset;
1058e5c31af7Sopenharmony_ci	const tcu::Vec4 p1 = v0 - normal4 * offset;
1059e5c31af7Sopenharmony_ci	const tcu::Vec4 p2 = v1 - normal4 * offset;
1060e5c31af7Sopenharmony_ci	const tcu::Vec4 p3 = v1 + normal4 * offset;
1061e5c31af7Sopenharmony_ci
1062e5c31af7Sopenharmony_ci	// Edge 0 -> 1 is always along the line and edge 1 -> 2 is in 90 degree angle to the line
1063e5c31af7Sopenharmony_ci	m_triangleRasterizer0.init(p0, p3, p2);
1064e5c31af7Sopenharmony_ci	m_triangleRasterizer1.init(p2, p1, p0);
1065e5c31af7Sopenharmony_ci}
1066e5c31af7Sopenharmony_ci
1067e5c31af7Sopenharmony_civoid MultiSampleLineRasterizer::rasterize (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
1068e5c31af7Sopenharmony_ci{
1069e5c31af7Sopenharmony_ci	DE_ASSERT(maxFragmentPackets > 0);
1070e5c31af7Sopenharmony_ci
1071e5c31af7Sopenharmony_ci	m_triangleRasterizer0.rasterize(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);
1072e5c31af7Sopenharmony_ci
1073e5c31af7Sopenharmony_ci	// Remove 3rd barycentric value and rebalance. Lines do not have non-zero barycentric at index 2
1074e5c31af7Sopenharmony_ci	for (int packNdx = 0; packNdx < numPacketsRasterized; ++packNdx)
1075e5c31af7Sopenharmony_ci	for (int fragNdx = 0; fragNdx < 4; fragNdx++)
1076e5c31af7Sopenharmony_ci	{
1077e5c31af7Sopenharmony_ci		float removedValue = fragmentPackets[packNdx].barycentric[2][fragNdx];
1078e5c31af7Sopenharmony_ci		fragmentPackets[packNdx].barycentric[2][fragNdx] = 0.0f;
1079e5c31af7Sopenharmony_ci		fragmentPackets[packNdx].barycentric[1][fragNdx] += removedValue;
1080e5c31af7Sopenharmony_ci	}
1081e5c31af7Sopenharmony_ci
1082e5c31af7Sopenharmony_ci	// rasterizer 0 filled the whole buffer?
1083e5c31af7Sopenharmony_ci	if (numPacketsRasterized == maxFragmentPackets)
1084e5c31af7Sopenharmony_ci		return;
1085e5c31af7Sopenharmony_ci
1086e5c31af7Sopenharmony_ci	{
1087e5c31af7Sopenharmony_ci		FragmentPacket* const nextFragmentPackets	= fragmentPackets + numPacketsRasterized;
1088e5c31af7Sopenharmony_ci		float* nextDepthValues						= (depthValues) ? (depthValues+4*numPacketsRasterized*m_numSamples) : (DE_NULL);
1089e5c31af7Sopenharmony_ci		int numPacketsRasterized2					= 0;
1090e5c31af7Sopenharmony_ci
1091e5c31af7Sopenharmony_ci		m_triangleRasterizer1.rasterize(nextFragmentPackets, nextDepthValues, maxFragmentPackets - numPacketsRasterized, numPacketsRasterized2);
1092e5c31af7Sopenharmony_ci
1093e5c31af7Sopenharmony_ci		numPacketsRasterized += numPacketsRasterized2;
1094e5c31af7Sopenharmony_ci
1095e5c31af7Sopenharmony_ci		// Fix swapped barycentrics in the second triangle
1096e5c31af7Sopenharmony_ci		for (int packNdx = 0; packNdx < numPacketsRasterized2; ++packNdx)
1097e5c31af7Sopenharmony_ci		for (int fragNdx = 0; fragNdx < 4; fragNdx++)
1098e5c31af7Sopenharmony_ci		{
1099e5c31af7Sopenharmony_ci			float removedValue = nextFragmentPackets[packNdx].barycentric[2][fragNdx];
1100e5c31af7Sopenharmony_ci			nextFragmentPackets[packNdx].barycentric[2][fragNdx] = 0.0f;
1101e5c31af7Sopenharmony_ci			nextFragmentPackets[packNdx].barycentric[1][fragNdx] += removedValue;
1102e5c31af7Sopenharmony_ci
1103e5c31af7Sopenharmony_ci			// edge has reversed direction
1104e5c31af7Sopenharmony_ci			std::swap(nextFragmentPackets[packNdx].barycentric[0][fragNdx], nextFragmentPackets[packNdx].barycentric[1][fragNdx]);
1105e5c31af7Sopenharmony_ci		}
1106e5c31af7Sopenharmony_ci	}
1107e5c31af7Sopenharmony_ci}
1108e5c31af7Sopenharmony_ci
1109e5c31af7Sopenharmony_ciLineExitDiamondGenerator::LineExitDiamondGenerator (const int subpixelBits)
1110e5c31af7Sopenharmony_ci	: m_subpixelBits(subpixelBits)
1111e5c31af7Sopenharmony_ci{
1112e5c31af7Sopenharmony_ci}
1113e5c31af7Sopenharmony_ci
1114e5c31af7Sopenharmony_ciLineExitDiamondGenerator::~LineExitDiamondGenerator (void)
1115e5c31af7Sopenharmony_ci{
1116e5c31af7Sopenharmony_ci}
1117e5c31af7Sopenharmony_ci
1118e5c31af7Sopenharmony_civoid LineExitDiamondGenerator::init (const tcu::Vec4& v0, const tcu::Vec4& v1)
1119e5c31af7Sopenharmony_ci{
1120e5c31af7Sopenharmony_ci	const deInt64					x0				= toSubpixelCoord(v0.x(), m_subpixelBits);
1121e5c31af7Sopenharmony_ci	const deInt64					y0				= toSubpixelCoord(v0.y(), m_subpixelBits);
1122e5c31af7Sopenharmony_ci	const deInt64					x1				= toSubpixelCoord(v1.x(), m_subpixelBits);
1123e5c31af7Sopenharmony_ci	const deInt64					y1				= toSubpixelCoord(v1.y(), m_subpixelBits);
1124e5c31af7Sopenharmony_ci
1125e5c31af7Sopenharmony_ci	// line endpoints might be perturbed, add some margin
1126e5c31af7Sopenharmony_ci	const deInt64					xMin			= de::min(x0, x1) - toSubpixelCoord(1, m_subpixelBits);
1127e5c31af7Sopenharmony_ci	const deInt64					xMax			= de::max(x0, x1) + toSubpixelCoord(1, m_subpixelBits);
1128e5c31af7Sopenharmony_ci	const deInt64					yMin			= de::min(y0, y1) - toSubpixelCoord(1, m_subpixelBits);
1129e5c31af7Sopenharmony_ci	const deInt64					yMax			= de::max(y0, y1) + toSubpixelCoord(1, m_subpixelBits);
1130e5c31af7Sopenharmony_ci
1131e5c31af7Sopenharmony_ci	m_bboxMin.x() = floorSubpixelToPixelCoord(xMin, m_subpixelBits, true);
1132e5c31af7Sopenharmony_ci	m_bboxMin.y() = floorSubpixelToPixelCoord(yMin, m_subpixelBits, true);
1133e5c31af7Sopenharmony_ci	m_bboxMax.x() = ceilSubpixelToPixelCoord (xMax, m_subpixelBits, true);
1134e5c31af7Sopenharmony_ci	m_bboxMax.y() = ceilSubpixelToPixelCoord (yMax, m_subpixelBits, true);
1135e5c31af7Sopenharmony_ci
1136e5c31af7Sopenharmony_ci	m_v0 = v0;
1137e5c31af7Sopenharmony_ci	m_v1 = v1;
1138e5c31af7Sopenharmony_ci
1139e5c31af7Sopenharmony_ci	m_curPos = m_bboxMin;
1140e5c31af7Sopenharmony_ci}
1141e5c31af7Sopenharmony_ci
1142e5c31af7Sopenharmony_civoid LineExitDiamondGenerator::rasterize (LineExitDiamond* const lineDiamonds, const int maxDiamonds, int& numWritten)
1143e5c31af7Sopenharmony_ci{
1144e5c31af7Sopenharmony_ci	DE_ASSERT(maxDiamonds > 0);
1145e5c31af7Sopenharmony_ci
1146e5c31af7Sopenharmony_ci	const deInt64								halfPixel			= 1ll << (m_subpixelBits - 1);
1147e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2>				pa					= LineRasterUtil::toSubpixelVector(m_v0.xy(), m_subpixelBits);
1148e5c31af7Sopenharmony_ci	const tcu::Vector<deInt64,2>				pb					= LineRasterUtil::toSubpixelVector(m_v1.xy(), m_subpixelBits);
1149e5c31af7Sopenharmony_ci	const LineRasterUtil::SubpixelLineSegment	line				= LineRasterUtil::SubpixelLineSegment(pa, pb);
1150e5c31af7Sopenharmony_ci
1151e5c31af7Sopenharmony_ci	int											diamondNdx			= 0;
1152e5c31af7Sopenharmony_ci
1153e5c31af7Sopenharmony_ci	while (m_curPos.y() <= m_bboxMax.y() && diamondNdx < maxDiamonds)
1154e5c31af7Sopenharmony_ci	{
1155e5c31af7Sopenharmony_ci		const tcu::Vector<deInt64,2> diamondPosition = LineRasterUtil::toSubpixelVector(m_curPos, m_subpixelBits) + tcu::Vector<deInt64,2>(halfPixel,halfPixel);
1156e5c31af7Sopenharmony_ci
1157e5c31af7Sopenharmony_ci		if (LineRasterUtil::doesLineSegmentExitDiamond(line, diamondPosition, m_subpixelBits))
1158e5c31af7Sopenharmony_ci		{
1159e5c31af7Sopenharmony_ci			LineExitDiamond& packet = lineDiamonds[diamondNdx];
1160e5c31af7Sopenharmony_ci			packet.position = m_curPos;
1161e5c31af7Sopenharmony_ci			++diamondNdx;
1162e5c31af7Sopenharmony_ci		}
1163e5c31af7Sopenharmony_ci
1164e5c31af7Sopenharmony_ci		++m_curPos.x();
1165e5c31af7Sopenharmony_ci		if (m_curPos.x() > m_bboxMax.x())
1166e5c31af7Sopenharmony_ci		{
1167e5c31af7Sopenharmony_ci			++m_curPos.y();
1168e5c31af7Sopenharmony_ci			m_curPos.x() = m_bboxMin.x();
1169e5c31af7Sopenharmony_ci		}
1170e5c31af7Sopenharmony_ci	}
1171e5c31af7Sopenharmony_ci
1172e5c31af7Sopenharmony_ci	DE_ASSERT(diamondNdx <= maxDiamonds);
1173e5c31af7Sopenharmony_ci	numWritten = diamondNdx;
1174e5c31af7Sopenharmony_ci}
1175e5c31af7Sopenharmony_ci
1176e5c31af7Sopenharmony_ci} // rr
1177