13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*-------------------------------------------------------------------------
23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Quality Program Reference Renderer
33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * -----------------------------------------------
43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Copyright 2014 The Android Open Source Project
63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Licensed under the Apache License, Version 2.0 (the "License");
83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * you may not use this file except in compliance with the License.
93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * You may obtain a copy of the License at
103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *      http://www.apache.org/licenses/LICENSE-2.0
123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Unless required by applicable law or agreed to in writing, software
143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distributed under the License is distributed on an "AS IS" BASIS,
153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * See the License for the specific language governing permissions and
173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * limitations under the License.
183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*!
203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \file
213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Reference rasterizer
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "rrRasterizer.hpp"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMath.h"
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuVectorUtil.hpp"
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace rr
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
313c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deInt64 toSubpixelCoord (float v)
323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return (deInt64)(v * (1<<RASTERIZER_SUBPIXEL_BITS) + (v < 0.f ? -0.5f : 0.5f));
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deInt64 toSubpixelCoord (deInt32 v)
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return v << RASTERIZER_SUBPIXEL_BITS;
393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
413c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deInt32 ceilSubpixelToPixelCoord (deInt64 coord, bool fillEdge)
423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (coord >= 0)
443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return (deInt32)((coord + ((1ll<<RASTERIZER_SUBPIXEL_BITS) - (fillEdge ? 0 : 1))) >> RASTERIZER_SUBPIXEL_BITS);
453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return (deInt32)((coord + (fillEdge ? 1 : 0)) >> RASTERIZER_SUBPIXEL_BITS);
473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
493c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deInt32 floorSubpixelToPixelCoord (deInt64 coord, bool fillEdge)
503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (coord >= 0)
523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return (deInt32)((coord - (fillEdge ? 1 : 0)) >> RASTERIZER_SUBPIXEL_BITS);
533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return (deInt32)((coord - ((1ll<<RASTERIZER_SUBPIXEL_BITS) - (fillEdge ? 0 : 1))) >> RASTERIZER_SUBPIXEL_BITS);
553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
573c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline void initEdgeCCW (EdgeFunction& edge, const HorizontalFill horizontalFill, const VerticalFill verticalFill, const deInt64 x0, const deInt64 y0, const deInt64 x1, const deInt64 y1)
583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// \note See EdgeFunction documentation for details.
603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	xd			= x1-x0;
623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	yd			= y1-y0;
633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool			inclusive	= false;	//!< Inclusive in CCW orientation.
643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (yd == 0)
663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		inclusive = verticalFill == FILL_BOTTOM ? xd >= 0 : xd <= 0;
673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		inclusive = horizontalFill == FILL_LEFT ? yd <= 0 : yd >= 0;
693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	edge.a			= (y0 - y1);
713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	edge.b			= (x1 - x0);
723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	edge.c			= x0*y1 - y0*x1;
733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	edge.inclusive	= inclusive; //!< \todo [pyry] Swap for CW triangles
743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
763c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline void reverseEdge (EdgeFunction& edge)
773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	edge.a			= -edge.a;
793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	edge.b			= -edge.b;
803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	edge.c			= -edge.c;
813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	edge.inclusive	= !edge.inclusive;
823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
843c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline deInt64 evaluateEdge (const EdgeFunction& edge, const deInt64 x, const deInt64 y)
853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return edge.a*x + edge.b*y + edge.c;
873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
893c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline bool isInsideCCW (const EdgeFunction& edge, const deInt64 edgeVal)
903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return edge.inclusive ? (edgeVal >= 0) : (edgeVal > 0);
923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
943c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace LineRasterUtil
953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
973c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct SubpixelLineSegment
983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2>	m_v0;
1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2>	m_v1;
1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SubpixelLineSegment (const tcu::Vector<deInt64,2>& v0, const tcu::Vector<deInt64,2>& v1)
1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: m_v0(v0)
1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		, m_v1(v1)
1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vector<deInt64,2> direction (void) const
1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return m_v1 - m_v0;
1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyryenum LINE_SIDE
1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	LINE_SIDE_INTERSECT = 0,
1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	LINE_SIDE_LEFT,
1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	LINE_SIDE_RIGHT
1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic tcu::Vector<deInt64,2> toSubpixelVector (const tcu::Vec2& v)
1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return tcu::Vector<deInt64,2>(toSubpixelCoord(v.x()), toSubpixelCoord(v.y()));
1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic tcu::Vector<deInt64,2> toSubpixelVector (const tcu::IVec2& v)
1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return tcu::Vector<deInt64,2>(toSubpixelCoord(v.x()), toSubpixelCoord(v.y()));
1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#if defined(DE_DEBUG)
1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool isTheCenterOfTheFragment (const tcu::Vector<deInt64,2>& a)
1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64 pixelSize = 1ll << (RASTERIZER_SUBPIXEL_BITS);
1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64 halfPixel = 1ll << (RASTERIZER_SUBPIXEL_BITS-1);
1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return	((a.x() & (pixelSize-1)) == halfPixel &&
1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				(a.y() & (pixelSize-1)) == halfPixel);
1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool inViewport (const tcu::IVec2& p, const tcu::IVec4& viewport)
1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return	p.x() >= viewport.x() &&
1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			p.y() >= viewport.y() &&
1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			p.x() <  viewport.x() + viewport.z() &&
1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			p.y() <  viewport.y() + viewport.w();
1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1473e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry#endif // DE_DEBUG
1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// returns true if vertex is on the left side of the line
1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool vertexOnLeftSideOfLine (const tcu::Vector<deInt64,2>& p, const SubpixelLineSegment& l)
1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> u = l.direction();
1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> v = ( p - l.m_v0);
1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64 crossProduct = (u.x() * v.y() - u.y() * v.x());
1553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return crossProduct < 0;
1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// returns true if vertex is on the right side of the line
1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool vertexOnRightSideOfLine (const tcu::Vector<deInt64,2>& p, const SubpixelLineSegment& l)
1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> u = l.direction();
1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> v = ( p - l.m_v0);
1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64 crossProduct = (u.x() * v.y() - u.y() * v.x());
1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return crossProduct > 0;
1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// returns true if vertex is on the line
1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool vertexOnLine (const tcu::Vector<deInt64,2>& p, const SubpixelLineSegment& l)
1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> u = l.direction();
1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> v = ( p - l.m_v0);
1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64 crossProduct = (u.x() * v.y() - u.y() * v.x());
1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return crossProduct == 0; // cross product == 0
1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// returns true if vertex is on the line segment
1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool vertexOnLineSegment (const tcu::Vector<deInt64,2>& p, const SubpixelLineSegment& l)
1783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!vertexOnLine(p, l))
1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return false;
1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> v	= l.direction();
1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> u1	= ( p - l.m_v0);
1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> u2	= ( p - l.m_v1);
1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (v.x() == 0 && v.y() == 0)
1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return false;
1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return	tcu::dot( v, u1) >= 0 &&
1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::dot(-v, u2) >= 0; // dot (A->B, A->V) >= 0 and dot (B->A, B->V) >= 0
1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic LINE_SIDE getVertexSide (const tcu::Vector<deInt64,2>& v, const SubpixelLineSegment& l)
1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (vertexOnLeftSideOfLine(v, l))
1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return LINE_SIDE_LEFT;
1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (vertexOnRightSideOfLine(v, l))
1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return LINE_SIDE_RIGHT;
1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (vertexOnLine(v, l))
2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return LINE_SIDE_INTERSECT;
2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(false);
2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return LINE_SIDE_INTERSECT;
2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// returns true if angle between line and given cornerExitNormal is in range (-45, 45)
2093c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool lineInCornerAngleRange (const SubpixelLineSegment& line, const tcu::Vector<deInt64,2>& cornerExitNormal)
2103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// v0 -> v1 has angle difference to cornerExitNormal in range (-45, 45)
2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> v = line.direction();
2133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64 dotProduct = dot(v, cornerExitNormal);
2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// dotProduct > |v1-v0|*|cornerExitNormal|/sqrt(2)
2163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (dotProduct < 0)
2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return false;
2183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return 2 * dotProduct * dotProduct > tcu::lengthSquared(v)*tcu::lengthSquared(cornerExitNormal);
2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// returns true if angle between line and given cornerExitNormal is in range (-135, 135)
2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool lineInCornerOutsideAngleRange (const SubpixelLineSegment& line, const tcu::Vector<deInt64,2>& cornerExitNormal)
2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// v0 -> v1 has angle difference to cornerExitNormal in range (-135, 135)
2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<deInt64,2> v = line.direction();
2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64 dotProduct = dot(v, cornerExitNormal);
2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// dotProduct > -|v1-v0|*|cornerExitNormal|/sqrt(2)
2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (dotProduct >= 0)
2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return 2 * (-dotProduct) * (-dotProduct) < tcu::lengthSquared(v)*tcu::lengthSquared(cornerExitNormal);
2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool doesLineSegmentExitDiamond (const SubpixelLineSegment& line, const tcu::Vector<deInt64,2>& diamondCenter)
2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(isTheCenterOfTheFragment(diamondCenter));
2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Diamond Center is at diamondCenter in subpixel coords
2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64 halfPixel = 1ll << (RASTERIZER_SUBPIXEL_BITS-1);
2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24206beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry	// Reject distant diamonds early
24306beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry	{
24406beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const tcu::Vector<deInt64,2>	u				= line.direction();
24506beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const tcu::Vector<deInt64,2>	v				= (diamondCenter - line.m_v0);
24606beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const deInt64					crossProduct	= (u.x() * v.y() - u.y() * v.x());
24706beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry
24806beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		// crossProduct = |p| |l| sin(theta)
24906beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		// distanceFromLine = |p| sin(theta)
25006beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		// => distanceFromLine = crossProduct / |l|
25106beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		//
25206beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		// |distanceFromLine| > C
25306beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		// => distanceFromLine^2 > C^2
25406beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		// => crossProduct^2 / |l|^2 > C^2
25506beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		// => crossProduct^2 > |l|^2 * C^2
25606beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry
25706beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const deInt64	floorSqrtMaxInt64			= 3037000499LL; //!< floor(sqrt(MAX_INT64))
25806beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry
25906beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const deInt64	broadRejectDistance			= 2 * halfPixel;
26006beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const deInt64	broadRejectDistanceSquared	= broadRejectDistance * broadRejectDistance;
26106beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const bool		crossProductOverflows		= (crossProduct > floorSqrtMaxInt64 || crossProduct < -floorSqrtMaxInt64);
26206beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const deInt64	crossProductSquared			= (crossProductOverflows) ? (0) : (crossProduct * crossProduct); // avoid overflow
26306beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const deInt64	lineLengthSquared			= tcu::lengthSquared(u);
26406beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const bool		limitValueCouldOverflow		= ((64 - deClz64(lineLengthSquared)) + (64 - deClz64(broadRejectDistanceSquared))) > 63;
26506beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		const deInt64	limitValue					= (limitValueCouldOverflow) ? (0) : (lineLengthSquared * broadRejectDistanceSquared); // avoid overflow
26606beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry
26706beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		// only cross overflows
26806beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		if (crossProductOverflows && !limitValueCouldOverflow)
26906beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry			return false;
27006beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry
27106beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		// both representable
27206beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		if (!crossProductOverflows && !limitValueCouldOverflow)
27306beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		{
27406beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry			if (crossProductSquared > limitValue)
27506beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry				return false;
27606beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry		}
27706beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry	}
27806beb4d23816942e7ccc49c81530bb8702a6f336Jarkko Pöyry
2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const struct DiamondBound
2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vector<deInt64,2>	p0;
2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vector<deInt64,2>	p1;
2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool					edgeInclusive; // would a point on the bound be inside of the region
2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	} bounds[] =
2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{ diamondCenter + tcu::Vector<deInt64,2>(0,				-halfPixel),	diamondCenter + tcu::Vector<deInt64,2>(-halfPixel,	0),				 false	},
2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{ diamondCenter + tcu::Vector<deInt64,2>(-halfPixel,	0),				diamondCenter + tcu::Vector<deInt64,2>(0,			halfPixel),		 false	},
2883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{ diamondCenter + tcu::Vector<deInt64,2>(0,				halfPixel),		diamondCenter + tcu::Vector<deInt64,2>(halfPixel,	0),				 true	},
2893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{ diamondCenter + tcu::Vector<deInt64,2>(halfPixel,		0),				diamondCenter + tcu::Vector<deInt64,2>(0,			-halfPixel),	 true	},
2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const struct DiamondCorners
2933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		enum CORNER_EDGE_CASE_BEHAVIOR
2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			CORNER_EDGE_CASE_NONE,							// if the line intersects just a corner, no entering or exiting
2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			CORNER_EDGE_CASE_HIT,							// if the line intersects just a corner, entering and exit
2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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)
2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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)
3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		enum CORNER_START_CASE_BEHAVIOR
3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			CORNER_START_CASE_NONE,							// the line starting point is outside, no exiting
3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			CORNER_START_CASE_OUTSIDE,						// exit, if line does not intersect the region (preturbing moves the start point inside)
3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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.
3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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.
3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		enum CORNER_END_CASE_BEHAVIOR
3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			CORNER_END_CASE_NONE,							// end is inside, no exiting (preturbing moves the line end inside)
3113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			CORNER_END_CASE_DIRECTION,						// exit, if line intersected the region (preturbing moves the line end outside)
3123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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)
3133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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)
3143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vector<deInt64,2>		dp;
3173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool						pointInclusive;			// would a point in this corner intersect with the region
3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CORNER_EDGE_CASE_BEHAVIOR	lineBehavior;			// would a line segment going through this corner intersect with the region
3193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CORNER_START_CASE_BEHAVIOR	startBehavior;			// how the corner behaves if the start point at the corner
3203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CORNER_END_CASE_BEHAVIOR	endBehavior;			// how the corner behaves if the end point at the corner
3213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	} corners[] =
3223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{ 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},
3243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{ tcu::Vector<deInt64,2>(-halfPixel,	0),				false,	DiamondCorners::CORNER_EDGE_CASE_NONE,					DiamondCorners::CORNER_START_CASE_NONE,				DiamondCorners::CORNER_END_CASE_DIRECTION					},
3253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{ 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	},
3263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{ tcu::Vector<deInt64,2>(halfPixel,		0),				true,	DiamondCorners::CORNER_EDGE_CASE_HIT,					DiamondCorners::CORNER_START_CASE_OUTSIDE,			DiamondCorners::CORNER_END_CASE_NONE						},
3273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
3283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Corner cases at the corners
3303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(corners); ++ndx)
3313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vector<deInt64,2> p	= diamondCenter + corners[ndx].dp;
3333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool intersectsAtCorner	= LineRasterUtil::vertexOnLineSegment(p, line);
3343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!intersectsAtCorner)
3363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			continue;
3373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// line segment body intersects with the corner
3393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (p != line.m_v0 && p != line.m_v1)
3403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (corners[ndx].lineBehavior == DiamondCorners::CORNER_EDGE_CASE_HIT)
3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return true;
3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// endpoint in (+X, -Y) (X or Y may be 0) direction <==> x*y <= 0
3453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (corners[ndx].lineBehavior == DiamondCorners::CORNER_EDGE_CASE_HIT_FIRST_QUARTER &&
3463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				(line.direction().x() * line.direction().y()) <= 0)
3473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return true;
3483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// endpoint in (+X, +Y) (Y > 0) direction <==> x*y > 0
3503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (corners[ndx].lineBehavior == DiamondCorners::CORNER_EDGE_CASE_HIT_SECOND_QUARTER &&
3513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				(line.direction().x() * line.direction().y()) > 0)
3523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return true;
3533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// line exits the area at the corner
3563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (lineInCornerAngleRange(line, corners[ndx].dp))
3573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const bool startIsInside = corners[ndx].pointInclusive || p != line.m_v0;
3593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const bool endIsOutside = !corners[ndx].pointInclusive || p != line.m_v1;
3603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// starting point is inside the region and end endpoint is outside
3623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (startIsInside && endIsOutside)
3633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return true;
3643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// line end is at the corner
3673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (p == line.m_v1)
3683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION ||
3703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION_AND_FIRST_QUARTER ||
3713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION_AND_SECOND_QUARTER)
3723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
3733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// did the line intersect the region
3743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (lineInCornerAngleRange(line, corners[ndx].dp))
3753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return true;
3763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// due to the perturbed endpoint, lines at this the angle will cause and enter-exit pair
3793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION_AND_FIRST_QUARTER &&
3803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				line.direction().x() < 0 &&
3813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				line.direction().y() > 0)
3823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return true;
3833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (corners[ndx].endBehavior == DiamondCorners::CORNER_END_CASE_DIRECTION_AND_SECOND_QUARTER &&
3843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				line.direction().x() > 0 &&
3853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				line.direction().y() > 0)
3863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return true;
3873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// line start is at the corner
3903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (p == line.m_v0)
3913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (corners[ndx].startBehavior == DiamondCorners::CORNER_START_CASE_OUTSIDE)
3933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
3943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// if the line is not going inside, it will exit
3953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (lineInCornerOutsideAngleRange(line, corners[ndx].dp))
3963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return true;
3973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// exit, if line the angle between line vector and X-axis is in range (0, 45] in positive Y side.
4003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (corners[ndx].startBehavior == DiamondCorners::CORNER_START_CASE_POSITIVE_Y_45 &&
4013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				line.direction().x() > 0 &&
4023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				line.direction().y() > 0 &&
4033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				line.direction().y() <= line.direction().x())
4043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return true;
4053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// exit, if line the angle between line vector and X-axis is in range [0, 45] in negative Y side.
4073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (corners[ndx].startBehavior == DiamondCorners::CORNER_START_CASE_NEGATIVE_Y_45 &&
4083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				 line.direction().x() > 0 &&
4093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				 line.direction().y() <= 0 &&
4103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				-line.direction().y() <= line.direction().x())
4113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return true;
4123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
4133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Does the line intersect boundary at the left == exits the diamond
4163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(bounds); ++ndx)
4173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool startVertexInside =	LineRasterUtil::vertexOnLeftSideOfLine						(line.m_v0, LineRasterUtil::SubpixelLineSegment(bounds[ndx].p0, bounds[ndx].p1)) ||
4193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										(bounds[ndx].edgeInclusive && LineRasterUtil::vertexOnLine	(line.m_v0, LineRasterUtil::SubpixelLineSegment(bounds[ndx].p0, bounds[ndx].p1)));
4203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool endVertexInside =	LineRasterUtil::vertexOnLeftSideOfLine						(line.m_v1, LineRasterUtil::SubpixelLineSegment(bounds[ndx].p0, bounds[ndx].p1)) ||
4213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										(bounds[ndx].edgeInclusive && LineRasterUtil::vertexOnLine	(line.m_v1, LineRasterUtil::SubpixelLineSegment(bounds[ndx].p0, bounds[ndx].p1)));
4223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// start must be on inside this half space (left or at the inclusive boundary)
4243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!startVertexInside)
4253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			continue;
4263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// end must be outside of this half-space (right or at non-inclusive boundary)
4283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (endVertexInside)
4293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			continue;
4303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Does the line via v0 and v1 intersect the line segment p0-p1
4323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// <==> p0 and p1 are the different sides (LEFT, RIGHT) of the v0-v1 line.
4333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Corners are not allowed, they are checked already
4343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		LineRasterUtil::LINE_SIDE sideP0 = LineRasterUtil::getVertexSide(bounds[ndx].p0, line);
4353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		LineRasterUtil::LINE_SIDE sideP1 = LineRasterUtil::getVertexSide(bounds[ndx].p1, line);
4363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (sideP0 != LineRasterUtil::LINE_SIDE_INTERSECT &&
4383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			sideP1 != LineRasterUtil::LINE_SIDE_INTERSECT &&
4393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			sideP0 != sideP1)
4403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return true;
4413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return false;
4443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // LineRasterUtil
4473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4483c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTriangleRasterizer::TriangleRasterizer (const tcu::IVec4& viewport, const int numSamples, const RasterizationState& state)
4491409d3b197da7b68b13c2f5e15023f50b7078294David Sodman	: m_viewport				(viewport)
4501409d3b197da7b68b13c2f5e15023f50b7078294David Sodman	, m_numSamples				(numSamples)
4511409d3b197da7b68b13c2f5e15023f50b7078294David Sodman	, m_winding					(state.winding)
4521409d3b197da7b68b13c2f5e15023f50b7078294David Sodman	, m_horizontalFill			(state.horizontalFill)
4531409d3b197da7b68b13c2f5e15023f50b7078294David Sodman	, m_verticalFill			(state.verticalFill)
4541409d3b197da7b68b13c2f5e15023f50b7078294David Sodman	, m_face					(FACETYPE_LAST)
4551409d3b197da7b68b13c2f5e15023f50b7078294David Sodman	, m_viewportOrientation		(state.viewportOrientation)
4563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*--------------------------------------------------------------------*//*!
4603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Initialize triangle rasterization
4613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \param v0 Screen-space coordinates (x, y, z) and 1/w for vertex 0.
4623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \param v1 Screen-space coordinates (x, y, z) and 1/w for vertex 1.
4633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \param v2 Screen-space coordinates (x, y, z) and 1/w for vertex 2.
4643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
4653c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TriangleRasterizer::init (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2)
4663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_v0 = v0;
4683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_v1 = v1;
4693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_v2 = v2;
4703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Positions in fixed-point coordinates.
4723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	x0		= toSubpixelCoord(v0.x());
4733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	y0		= toSubpixelCoord(v0.y());
4743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	x1		= toSubpixelCoord(v1.x());
4753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	y1		= toSubpixelCoord(v1.y());
4763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	x2		= toSubpixelCoord(v2.x());
4773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	y2		= toSubpixelCoord(v2.y());
4783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Initialize edge functions.
4803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_winding == WINDING_CCW)
4813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		initEdgeCCW(m_edge01, m_horizontalFill, m_verticalFill, x0, y0, x1, y1);
4833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		initEdgeCCW(m_edge12, m_horizontalFill, m_verticalFill, x1, y1, x2, y2);
4843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		initEdgeCCW(m_edge20, m_horizontalFill, m_verticalFill, x2, y2, x0, y0);
4853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
4873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Reverse edges
4893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		initEdgeCCW(m_edge01, m_horizontalFill, m_verticalFill, x1, y1, x0, y0);
4903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		initEdgeCCW(m_edge12, m_horizontalFill, m_verticalFill, x2, y2, x1, y1);
4913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		initEdgeCCW(m_edge20, m_horizontalFill, m_verticalFill, x0, y0, x2, y2);
4923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Determine face.
4953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	s				= evaluateEdge(m_edge01, x2, y2);
4963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool		positiveArea	= (m_winding == WINDING_CCW) ? (s > 0) : (s < 0);
4971409d3b197da7b68b13c2f5e15023f50b7078294David Sodman
4981409d3b197da7b68b13c2f5e15023f50b7078294David Sodman	if (m_viewportOrientation == VIEWPORTORIENTATION_UPPER_LEFT)
4991409d3b197da7b68b13c2f5e15023f50b7078294David Sodman		m_face = positiveArea ? FACETYPE_BACK : FACETYPE_FRONT;
5001409d3b197da7b68b13c2f5e15023f50b7078294David Sodman	else
5011409d3b197da7b68b13c2f5e15023f50b7078294David Sodman		m_face = positiveArea ? FACETYPE_FRONT : FACETYPE_BACK;
5023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!positiveArea)
5043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Reverse edges so that we can use CCW area tests & interpolation
5063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		reverseEdge(m_edge01);
5073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		reverseEdge(m_edge12);
5083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		reverseEdge(m_edge20);
5093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Bounding box
5123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	xMin	= de::min(de::min(x0, x1), x2);
5133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	xMax	= de::max(de::max(x0, x1), x2);
5143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	yMin	= de::min(de::min(y0, y1), y2);
5153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64	yMax	= de::max(de::max(y0, y1), y2);
5163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_bboxMin.x() = floorSubpixelToPixelCoord	(xMin, m_horizontalFill	== FILL_LEFT);
5183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_bboxMin.y() = floorSubpixelToPixelCoord	(yMin, m_verticalFill	== FILL_BOTTOM);
5193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_bboxMax.x() = ceilSubpixelToPixelCoord	(xMax, m_horizontalFill	== FILL_RIGHT);
5203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_bboxMax.y() = ceilSubpixelToPixelCoord	(yMax, m_verticalFill	== FILL_TOP);
5213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Clamp to viewport
5233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		wX0		= m_viewport.x();
5243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		wY0		= m_viewport.y();
5253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		wX1		= wX0 + m_viewport.z() - 1;
5263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		wY1		= wY0 + m_viewport.w() -1;
5273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_bboxMin.x() = de::clamp(m_bboxMin.x(), wX0, wX1);
5293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_bboxMin.y() = de::clamp(m_bboxMin.y(), wY0, wY1);
5303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_bboxMax.x() = de::clamp(m_bboxMax.x(), wX0, wX1);
5313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_bboxMax.y() = de::clamp(m_bboxMax.y(), wY0, wY1);
5323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_curPos = m_bboxMin;
5343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5363c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TriangleRasterizer::rasterizeSingleSample (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
5373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(maxFragmentPackets > 0);
5393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64	halfPixel	= 1ll << (RASTERIZER_SUBPIXEL_BITS-1);
5413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int				packetNdx	= 0;
5423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
543f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	// For depth interpolation; given barycentrics A, B, C = (1 - A - B)
544f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	// we can reformulate the usual z = z0*A + z1*B + z2*C into more
545f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	// stable equation z = A*(z0 - z2) + B*(z1 - z2) + z2.
546f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	const float		za			= m_v0.z()-m_v2.z();
547f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	const float		zb			= m_v1.z()-m_v2.z();
548f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	const float		zc			= m_v2.z();
549f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos
5503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	while (m_curPos.y() <= m_bboxMax.y() && packetNdx < maxFragmentPackets)
5513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		x0		= m_curPos.x();
5533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		y0		= m_curPos.y();
5543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Subpixel coords
5563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sx0		= toSubpixelCoord(x0)	+ halfPixel;
5573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sx1		= toSubpixelCoord(x0+1)	+ halfPixel;
5583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sy0		= toSubpixelCoord(y0)	+ halfPixel;
5593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sy1		= toSubpixelCoord(y0+1)	+ halfPixel;
5603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sx[4]	= { sx0, sx1, sx0, sx1 };
5623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sy[4]	= { sy0, sy0, sy1, sy1 };
5633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Viewport test
5653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool		outX1	= x0+1 == m_viewport.x()+m_viewport.z();
5663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool		outY1	= y0+1 == m_viewport.y()+m_viewport.w();
5673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(x0 < m_viewport.x()+m_viewport.z());
5693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(y0 < m_viewport.y()+m_viewport.w());
5703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Edge values
5723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vector<deInt64, 4>	e01;
5733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vector<deInt64, 4>	e12;
5743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vector<deInt64, 4>	e20;
5753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Coverage
5773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deUint64		coverage	= 0;
5783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Evaluate edge values
5803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int i = 0; i < 4; i++)
5813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			e01[i] = evaluateEdge(m_edge01, sx[i], sy[i]);
5833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			e12[i] = evaluateEdge(m_edge12, sx[i], sy[i]);
5843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			e20[i] = evaluateEdge(m_edge20, sx[i], sy[i]);
5853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
5863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Compute coverage mask
5883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		coverage = setCoverageValue(coverage, 1, 0, 0, 0,						isInsideCCW(m_edge01, e01[0]) && isInsideCCW(m_edge12, e12[0]) && isInsideCCW(m_edge20, e20[0]));
5893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		coverage = setCoverageValue(coverage, 1, 1, 0, 0, !outX1 &&				isInsideCCW(m_edge01, e01[1]) && isInsideCCW(m_edge12, e12[1]) && isInsideCCW(m_edge20, e20[1]));
5903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		coverage = setCoverageValue(coverage, 1, 0, 1, 0, !outY1 &&				isInsideCCW(m_edge01, e01[2]) && isInsideCCW(m_edge12, e12[2]) && isInsideCCW(m_edge20, e20[2]));
5913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		coverage = setCoverageValue(coverage, 1, 1, 1, 0, !outX1 && !outY1 &&	isInsideCCW(m_edge01, e01[3]) && isInsideCCW(m_edge12, e12[3]) && isInsideCCW(m_edge20, e20[3]));
5923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Advance to next location
5943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_curPos.x() += 2;
5953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_curPos.x() > m_bboxMax.x())
5963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_curPos.y() += 2;
5983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_curPos.x()  = m_bboxMin.x();
5993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (coverage == 0)
6023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			continue; // Discard.
6033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Floating-point edge values for barycentrics etc.
6053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec4		e01f	= e01.asFloat();
6063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec4		e12f	= e12.asFloat();
6073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec4		e20f	= e20.asFloat();
6083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Compute depth values.
6103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (depthValues)
6113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
612f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			const tcu::Vec4		edgeSum	= e01f + e12f + e20f;
613f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			const tcu::Vec4		z0		= e12f / edgeSum;
614f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			const tcu::Vec4		z1		= e20f / edgeSum;
615f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos
616f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			depthValues[packetNdx*4+0] = z0[0]*za + z1[0]*zb + zc;
617f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			depthValues[packetNdx*4+1] = z0[1]*za + z1[1]*zb + zc;
618f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			depthValues[packetNdx*4+2] = z0[2]*za + z1[2]*zb + zc;
619f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			depthValues[packetNdx*4+3] = z0[3]*za + z1[3]*zb + zc;
6203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Compute barycentrics and write out fragment packet
6233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			FragmentPacket& packet = fragmentPackets[packetNdx];
6253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec4		b0		= e12f * m_v0.w();
6273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec4		b1		= e20f * m_v1.w();
6283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec4		b2		= e01f * m_v2.w();
629f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			const tcu::Vec4		bSum	= b0 + b1 + b2;
6303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			packet.position			= tcu::IVec2(x0, y0);
6323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			packet.coverage			= coverage;
633f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			packet.barycentric[0]	= b0 / bSum;
634f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			packet.barycentric[1]	= b1 / bSum;
6353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			packet.barycentric[2]	= 1.0f - packet.barycentric[0] - packet.barycentric[1];
6363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			packetNdx += 1;
6383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(packetNdx <= maxFragmentPackets);
6423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	numPacketsRasterized = packetNdx;
6433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Sample positions - ordered as (x, y) list.
6463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// \note Macros are used to eliminate function calls even in debug builds.
6483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#define SAMPLE_POS_TO_SUBPIXEL_COORD(POS)	\
6493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	(deInt64)((POS) * (1<<RASTERIZER_SUBPIXEL_BITS) + 0.5f)
6503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#define SAMPLE_POS(X, Y)	\
6523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS_TO_SUBPIXEL_COORD(X), SAMPLE_POS_TO_SUBPIXEL_COORD(Y)
6533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6543c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const deInt64 s_samplePos2[] =
6553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(0.3f, 0.3f),
6573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(0.7f, 0.7f)
6583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
6593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6603c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const deInt64 s_samplePos4[] =
6613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(0.25f, 0.25f),
6633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(0.75f, 0.25f),
6643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(0.25f, 0.75f),
6653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(0.75f, 0.75f)
6663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
6673c827367444ee418f129b2c238299f49d3264554Jarkko PoyryDE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_samplePos4) == 4*2);
6683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6693c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const deInt64 s_samplePos8[] =
6703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS( 7.f/16.f,  9.f/16.f),
6723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS( 9.f/16.f, 13.f/16.f),
6733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(11.f/16.f,  3.f/16.f),
6743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(13.f/16.f, 11.f/16.f),
6753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS( 1.f/16.f,  7.f/16.f),
6763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS( 5.f/16.f,  1.f/16.f),
6773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(15.f/16.f,  5.f/16.f),
6783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS( 3.f/16.f, 15.f/16.f)
6793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
6803c827367444ee418f129b2c238299f49d3264554Jarkko PoyryDE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_samplePos8) == 8*2);
6813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6823c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const deInt64 s_samplePos16[] =
6833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(1.f/8.f, 1.f/8.f),
6853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(3.f/8.f, 1.f/8.f),
6863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(5.f/8.f, 1.f/8.f),
6873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(7.f/8.f, 1.f/8.f),
6883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(1.f/8.f, 3.f/8.f),
6893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(3.f/8.f, 3.f/8.f),
6903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(5.f/8.f, 3.f/8.f),
6913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(7.f/8.f, 3.f/8.f),
6923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(1.f/8.f, 5.f/8.f),
6933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(3.f/8.f, 5.f/8.f),
6943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(5.f/8.f, 5.f/8.f),
6953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(7.f/8.f, 5.f/8.f),
6963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(1.f/8.f, 7.f/8.f),
6973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(3.f/8.f, 7.f/8.f),
6983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(5.f/8.f, 7.f/8.f),
6993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SAMPLE_POS(7.f/8.f, 7.f/8.f)
7003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
7013c827367444ee418f129b2c238299f49d3264554Jarkko PoyryDE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_samplePos16) == 16*2);
7023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#undef SAMPLE_POS
7043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#undef SAMPLE_POS_TO_SUBPIXEL_COORD
7053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7063c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<int NumSamples>
7073c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TriangleRasterizer::rasterizeMultiSample (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
7083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
7093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(maxFragmentPackets > 0);
7103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deInt64*	samplePos	= DE_NULL;
7123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64	halfPixel	= 1ll << (RASTERIZER_SUBPIXEL_BITS-1);
7133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int				packetNdx	= 0;
7143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
715f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	// For depth interpolation, see rasterizeSingleSample
716f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	const float		za			= m_v0.z()-m_v2.z();
717f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	const float		zb			= m_v1.z()-m_v2.z();
718f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos	const float		zc			= m_v2.z();
719f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos
7203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (NumSamples)
7213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 2:		samplePos = s_samplePos2;	break;
7233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 4:		samplePos = s_samplePos4;	break;
7243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 8:		samplePos = s_samplePos8;	break;
7253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 16:	samplePos = s_samplePos16;	break;
7263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
7273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
7283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	while (m_curPos.y() <= m_bboxMax.y() && packetNdx < maxFragmentPackets)
7313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		x0		= m_curPos.x();
7333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		y0		= m_curPos.y();
7343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Base subpixel coords
7363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sx0		= toSubpixelCoord(x0);
7373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sx1		= toSubpixelCoord(x0+1);
7383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sy0		= toSubpixelCoord(y0);
7393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sy1		= toSubpixelCoord(y0+1);
7403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sx[4]	= { sx0, sx1, sx0, sx1 };
7423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64	sy[4]	= { sy0, sy0, sy1, sy1 };
7433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Viewport test
7453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool		outX1	= x0+1 == m_viewport.x()+m_viewport.z();
7463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool		outY1	= y0+1 == m_viewport.y()+m_viewport.w();
7473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(x0 < m_viewport.x()+m_viewport.z());
7493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(y0 < m_viewport.y()+m_viewport.w());
7503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Edge values
7523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vector<deInt64, 4>	e01[NumSamples];
7533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vector<deInt64, 4>	e12[NumSamples];
7543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vector<deInt64, 4>	e20[NumSamples];
7553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Coverage
7573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deUint64		coverage	= 0;
7583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Evaluate edge values at sample positions
7603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int sampleNdx = 0; sampleNdx < NumSamples; sampleNdx++)
7613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deInt64 ox = samplePos[sampleNdx*2 + 0];
7633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deInt64 oy = samplePos[sampleNdx*2 + 1];
7643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int fragNdx = 0; fragNdx < 4; fragNdx++)
7663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				e01[sampleNdx][fragNdx] = evaluateEdge(m_edge01, sx[fragNdx] + ox, sy[fragNdx] + oy);
7683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				e12[sampleNdx][fragNdx] = evaluateEdge(m_edge12, sx[fragNdx] + ox, sy[fragNdx] + oy);
7693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				e20[sampleNdx][fragNdx] = evaluateEdge(m_edge20, sx[fragNdx] + ox, sy[fragNdx] + oy);
7703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Compute coverage mask
7743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int sampleNdx = 0; sampleNdx < NumSamples; sampleNdx++)
7753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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]));
7773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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]));
7783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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]));
7793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			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]));
7803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Advance to next location
7833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_curPos.x() += 2;
7843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_curPos.x() > m_bboxMax.x())
7853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_curPos.y() += 2;
7873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_curPos.x()  = m_bboxMin.x();
7883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (coverage == 0)
7913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			continue; // Discard.
7923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Compute depth values.
7943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (depthValues)
7953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int sampleNdx = 0; sampleNdx < NumSamples; sampleNdx++)
7973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Floating-point edge values at sample coordinates.
7993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const tcu::Vec4&	e01f	= e01[sampleNdx].asFloat();
8003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const tcu::Vec4&	e12f	= e12[sampleNdx].asFloat();
8013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const tcu::Vec4&	e20f	= e20[sampleNdx].asFloat();
8023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
803f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos				const tcu::Vec4		edgeSum	= e01f + e12f + e20f;
804f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos				const tcu::Vec4		z0		= e12f / edgeSum;
805f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos				const tcu::Vec4		z1		= e20f / edgeSum;
8063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
807f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos				depthValues[(packetNdx*4+0)*NumSamples + sampleNdx] = z0[0]*za + z1[0]*zb + zc;
808f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos				depthValues[(packetNdx*4+1)*NumSamples + sampleNdx] = z0[1]*za + z1[1]*zb + zc;
809f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos				depthValues[(packetNdx*4+2)*NumSamples + sampleNdx] = z0[2]*za + z1[2]*zb + zc;
810f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos				depthValues[(packetNdx*4+3)*NumSamples + sampleNdx] = z0[3]*za + z1[3]*zb + zc;
8113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
8123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
8133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Compute barycentrics and write out fragment packet
8153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			FragmentPacket& packet = fragmentPackets[packetNdx];
8173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Floating-point edge values at pixel center.
8193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec4			e01f;
8203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec4			e12f;
8213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec4			e20f;
8223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int i = 0; i < 4; i++)
8243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
8253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				e01f[i] = float(evaluateEdge(m_edge01, sx[i] + halfPixel, sy[i] + halfPixel));
8263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				e12f[i] = float(evaluateEdge(m_edge12, sx[i] + halfPixel, sy[i] + halfPixel));
8273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				e20f[i] = float(evaluateEdge(m_edge20, sx[i] + halfPixel, sy[i] + halfPixel));
8283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
8293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Barycentrics & scale.
8313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec4		b0		= e12f * m_v0.w();
8323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec4		b1		= e20f * m_v1.w();
8333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec4		b2		= e01f * m_v2.w();
834f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			const tcu::Vec4		bSum	= b0 + b1 + b2;
8353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			packet.position			= tcu::IVec2(x0, y0);
8373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			packet.coverage			= coverage;
838f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			packet.barycentric[0]	= b0 / bSum;
839f4238ec8ad0e9b0995142dc3b0b9a18de167ae3fPyry Haulos			packet.barycentric[1]	= b1 / bSum;
8403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			packet.barycentric[2]	= 1.0f - packet.barycentric[0] - packet.barycentric[1];
8413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			packetNdx += 1;
8433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
8443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(packetNdx <= maxFragmentPackets);
8473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	numPacketsRasterized = packetNdx;
8483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8503c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TriangleRasterizer::rasterize (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
8513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(maxFragmentPackets > 0);
8533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (m_numSamples)
8553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 1:		rasterizeSingleSample		(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
8573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 2:		rasterizeMultiSample<2>		(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
8583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 4:		rasterizeMultiSample<4>		(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
8593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 8:		rasterizeMultiSample<8>		(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
8603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 16:	rasterizeMultiSample<16>	(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);	break;
8613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
8623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(DE_FALSE);
8633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8663c827367444ee418f129b2c238299f49d3264554Jarkko PoyrySingleSampleLineRasterizer::SingleSampleLineRasterizer (const tcu::IVec4& viewport)
8673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: m_viewport		(viewport)
8683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_curRowFragment	(0)
8693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_lineWidth		(0.0f)
8703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8732306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko PöyrySingleSampleLineRasterizer::~SingleSampleLineRasterizer (void)
8743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8773c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid SingleSampleLineRasterizer::init (const tcu::Vec4& v0, const tcu::Vec4& v1, float lineWidth)
8783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8793e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const bool						isXMajor		= de::abs((v1 - v0).x()) >= de::abs((v1 - v0).y());
8803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8813e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	// Bounding box \note: with wide lines, the line is actually moved as in the spec
8823e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const deInt32					lineWidthPixels	= (lineWidth > 1.0f) ? (deInt32)floor(lineWidth + 0.5f) : 1;
8833e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry
8843e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const tcu::Vector<deInt64,2>	widthOffset		= (isXMajor ? tcu::Vector<deInt64,2>(0, -1) : tcu::Vector<deInt64,2>(-1, 0)) * (toSubpixelCoord(lineWidthPixels - 1) / 2);
8853e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry
8863e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const deInt64					x0				= toSubpixelCoord(v0.x()) + widthOffset.x();
8873e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const deInt64					y0				= toSubpixelCoord(v0.y()) + widthOffset.y();
8883e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const deInt64					x1				= toSubpixelCoord(v1.x()) + widthOffset.x();
8893e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const deInt64					y1				= toSubpixelCoord(v1.y()) + widthOffset.y();
8903e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry
8913e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	// line endpoints might be perturbed, add some margin
8923e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const deInt64					xMin			= de::min(x0, x1) - toSubpixelCoord(1);
8933e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const deInt64					xMax			= de::max(x0, x1) + toSubpixelCoord(1);
8943e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const deInt64					yMin			= de::min(y0, y1) - toSubpixelCoord(1);
8953e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	const deInt64					yMax			= de::max(y0, y1) + toSubpixelCoord(1);
8963e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry
8973e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	// Remove invisible area
8983e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry
8993e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	if (isXMajor)
9003e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	{
9013e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		// clamp to viewport in major direction
9023e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		m_bboxMin.x() = de::clamp(floorSubpixelToPixelCoord(xMin, true), m_viewport.x(), m_viewport.x() + m_viewport.z() - 1);
9033e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		m_bboxMax.x() = de::clamp(ceilSubpixelToPixelCoord (xMax, true), m_viewport.x(), m_viewport.x() + m_viewport.z() - 1);
9043e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry
9053e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		// clamp to padded viewport in minor direction (wide lines might bleed over viewport in minor direction)
9063e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		m_bboxMin.y() = de::clamp(floorSubpixelToPixelCoord(yMin, true), m_viewport.y() - lineWidthPixels, m_viewport.y() + m_viewport.w() - 1);
9073e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		m_bboxMax.y() = de::clamp(ceilSubpixelToPixelCoord (yMax, true), m_viewport.y() - lineWidthPixels, m_viewport.y() + m_viewport.w() - 1);
9083e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	}
9093e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	else
9103e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	{
9113e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		// clamp to viewport in major direction
9123e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		m_bboxMin.y() = de::clamp(floorSubpixelToPixelCoord(yMin, true), m_viewport.y(), m_viewport.y() + m_viewport.w() - 1);
9133e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		m_bboxMax.y() = de::clamp(ceilSubpixelToPixelCoord (yMax, true), m_viewport.y(), m_viewport.y() + m_viewport.w() - 1);
9143e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry
9153e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		// clamp to padded viewport in minor direction (wide lines might bleed over viewport in minor direction)
9163e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		m_bboxMin.x() = de::clamp(floorSubpixelToPixelCoord(xMin, true), m_viewport.x() - lineWidthPixels, m_viewport.x() + m_viewport.z() - 1);
9173e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry		m_bboxMax.x() = de::clamp(ceilSubpixelToPixelCoord (xMax, true), m_viewport.x() - lineWidthPixels, m_viewport.x() + m_viewport.z() - 1);
9183e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry	}
9193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_lineWidth = lineWidth;
9213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_v0 = v0;
9233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_v1 = v1;
9243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_curPos = m_bboxMin;
9263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_curRowFragment = 0;
9273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9293c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid SingleSampleLineRasterizer::rasterize (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
9303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(maxFragmentPackets > 0);
9323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64								halfPixel			= 1ll << (RASTERIZER_SUBPIXEL_BITS-1);
9342306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt32								lineWidth			= (m_lineWidth > 1.0f) ? deFloorFloatToInt32(m_lineWidth + 0.5f) : 1;
9352306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const bool									isXMajor			= de::abs((m_v1 - m_v0).x()) >= de::abs((m_v1 - m_v0).y());
9362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::IVec2							minorDirection		= (isXMajor) ? (tcu::IVec2(0, 1)) : (tcu::IVec2(1, 0));
9372306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int									minViewportLimit	= (isXMajor) ? (m_viewport.y()) : (m_viewport.x());
9382306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int									maxViewportLimit	= (isXMajor) ? (m_viewport.y() + m_viewport.w()) : (m_viewport.x() + m_viewport.z());
9392306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::Vector<deInt64,2>				widthOffset			= -minorDirection.cast<deInt64>() * (toSubpixelCoord(lineWidth - 1) / 2);
9402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::Vector<deInt64,2>				pa					= LineRasterUtil::toSubpixelVector(m_v0.xy()) + widthOffset;
9412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::Vector<deInt64,2>				pb					= LineRasterUtil::toSubpixelVector(m_v1.xy()) + widthOffset;
9422306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const LineRasterUtil::SubpixelLineSegment	line				= LineRasterUtil::SubpixelLineSegment(pa, pb);
9433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9442306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int											packetNdx			= 0;
9453e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry
9463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	while (m_curPos.y() <= m_bboxMax.y() && packetNdx < maxFragmentPackets)
9473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vector<deInt64,2> diamondPosition = LineRasterUtil::toSubpixelVector(m_curPos) + tcu::Vector<deInt64,2>(halfPixel,halfPixel);
9493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Should current fragment be drawn? == does the segment exit this diamond?
9513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (LineRasterUtil::doesLineSegmentExitDiamond(line, diamondPosition))
9523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9532306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const tcu::Vector<deInt64,2>	pr					= diamondPosition;
9542306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const float						t					= tcu::dot((pr - pa).asFloat(), (pb - pa).asFloat()) / tcu::lengthSquared(pb.asFloat() - pa.asFloat());
9553e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry
9563e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry			// Rasterize on only fragments that are would end up in the viewport (i.e. visible)
9572306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const int						fragmentLocation	= (isXMajor) ? (m_curPos.y()) : (m_curPos.x());
9583e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry			const int						rowFragBegin		= de::max(0, minViewportLimit - fragmentLocation);
9593e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry			const int						rowFragEnd			= de::min(maxViewportLimit - fragmentLocation, lineWidth);
9603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Wide lines require multiple fragments.
9623e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry			for (; rowFragBegin + m_curRowFragment < rowFragEnd; m_curRowFragment++)
9633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
9642306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const int			replicationId	= rowFragBegin + m_curRowFragment;
9652306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::IVec2	fragmentPos		= m_curPos + minorDirection * replicationId;
9663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9673e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry				// We only rasterize visible area
9683e351a9e69e78f8893d2cea7b1ed4089dfaebecbJarkko Pöyry				DE_ASSERT(LineRasterUtil::inViewport(fragmentPos, m_viewport));
9693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Compute depth values.
9713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (depthValues)
9723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
9733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float za = m_v0.z();
9743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float zb = m_v1.z();
9753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					depthValues[packetNdx*4+0] = (1 - t) * za + t * zb;
9773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					depthValues[packetNdx*4+1] = 0;
9783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					depthValues[packetNdx*4+2] = 0;
9793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					depthValues[packetNdx*4+3] = 0;
9803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
9813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
9833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// output this fragment
9843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// \note In order to make consistent output with multisampled line rasterization, output "barycentric" coordinates
9853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					FragmentPacket& packet = fragmentPackets[packetNdx];
9863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const tcu::Vec4		b0		= tcu::Vec4(1 - t);
9883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const tcu::Vec4		b1		= tcu::Vec4(t);
9893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const tcu::Vec4		ooSum	= 1.0f / (b0 + b1);
9903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					packet.position			= fragmentPos;
9923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					packet.coverage			= getCoverageBit(1, 0, 0, 0);
9933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					packet.barycentric[0]	= b0 * ooSum;
9943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					packet.barycentric[1]	= b1 * ooSum;
9953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					packet.barycentric[2]	= tcu::Vec4(0.0f);
9963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					packetNdx += 1;
9983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
9993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (packetNdx == maxFragmentPackets)
10013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
10023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_curRowFragment++; // don't redraw this fragment again next time
10033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					numPacketsRasterized = packetNdx;
10043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return;
10053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
10063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
10073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_curRowFragment = 0;
10093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		++m_curPos.x();
10123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_curPos.x() > m_bboxMax.x())
10133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			++m_curPos.y();
10153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_curPos.x() = m_bboxMin.x();
10163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(packetNdx <= maxFragmentPackets);
10203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	numPacketsRasterized = packetNdx;
10213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10233c827367444ee418f129b2c238299f49d3264554Jarkko PoyryMultiSampleLineRasterizer::MultiSampleLineRasterizer (const int numSamples, const tcu::IVec4& viewport)
10243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: m_numSamples			(numSamples)
10253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_triangleRasterizer0 (viewport, m_numSamples, RasterizationState())
10263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_triangleRasterizer1 (viewport, m_numSamples, RasterizationState())
10273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10303c827367444ee418f129b2c238299f49d3264554Jarkko PoyryMultiSampleLineRasterizer::~MultiSampleLineRasterizer ()
10313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10343c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid MultiSampleLineRasterizer::init (const tcu::Vec4& v0, const tcu::Vec4& v1, float lineWidth)
10353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// allow creation of single sampled rasterizer objects but do not allow using them
10373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(m_numSamples > 1);
10383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 lineVec		= tcu::Vec2(tcu::Vec4(v1).xy()) - tcu::Vec2(tcu::Vec4(v0).xy());
10403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 normal2		= tcu::normalize(tcu::Vec2(-lineVec[1], lineVec[0]));
10413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec4 normal4		= tcu::Vec4(normal2.x(), normal2.y(), 0, 0);
10423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float offset			= lineWidth / 2.0f;
10433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec4 p0 = v0 + normal4 * offset;
10453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec4 p1 = v0 - normal4 * offset;
10463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec4 p2 = v1 - normal4 * offset;
10473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec4 p3 = v1 + normal4 * offset;
10483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Edge 0 -> 1 is always along the line and edge 1 -> 2 is in 90 degree angle to the line
10503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_triangleRasterizer0.init(p0, p3, p2);
10513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_triangleRasterizer1.init(p2, p1, p0);
10523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10543c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid MultiSampleLineRasterizer::rasterize (FragmentPacket* const fragmentPackets, float* const depthValues, const int maxFragmentPackets, int& numPacketsRasterized)
10553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(maxFragmentPackets > 0);
10573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_triangleRasterizer0.rasterize(fragmentPackets, depthValues, maxFragmentPackets, numPacketsRasterized);
10593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Remove 3rd barycentric value and rebalance. Lines do not have non-zero barycentric at index 2
10613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int packNdx = 0; packNdx < numPacketsRasterized; ++packNdx)
10623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int fragNdx = 0; fragNdx < 4; fragNdx++)
10633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		float removedValue = fragmentPackets[packNdx].barycentric[2][fragNdx];
10653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fragmentPackets[packNdx].barycentric[2][fragNdx] = 0.0f;
10663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fragmentPackets[packNdx].barycentric[1][fragNdx] += removedValue;
10673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// rasterizer 0 filled the whole buffer?
10703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (numPacketsRasterized == maxFragmentPackets)
10713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return;
10723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		FragmentPacket* const nextFragmentPackets	= fragmentPackets + numPacketsRasterized;
10753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		float* nextDepthValues						= (depthValues) ? (depthValues+4*numPacketsRasterized*m_numSamples) : (DE_NULL);
10763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int numPacketsRasterized2					= 0;
10773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_triangleRasterizer1.rasterize(nextFragmentPackets, nextDepthValues, maxFragmentPackets - numPacketsRasterized, numPacketsRasterized2);
10793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		numPacketsRasterized += numPacketsRasterized2;
10813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Fix swapped barycentrics in the second triangle
10833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int packNdx = 0; packNdx < numPacketsRasterized2; ++packNdx)
10843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int fragNdx = 0; fragNdx < 4; fragNdx++)
10853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			float removedValue = nextFragmentPackets[packNdx].barycentric[2][fragNdx];
10873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			nextFragmentPackets[packNdx].barycentric[2][fragNdx] = 0.0f;
10883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			nextFragmentPackets[packNdx].barycentric[1][fragNdx] += removedValue;
10893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// edge has reversed direction
10913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			std::swap(nextFragmentPackets[packNdx].barycentric[0][fragNdx], nextFragmentPackets[packNdx].barycentric[1][fragNdx]);
10923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10962306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko PöyryLineExitDiamondGenerator::LineExitDiamondGenerator (void)
10972306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
10982306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
10992306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11002306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko PöyryLineExitDiamondGenerator::~LineExitDiamondGenerator (void)
11012306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
11022306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
11032306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11042306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyryvoid LineExitDiamondGenerator::init (const tcu::Vec4& v0, const tcu::Vec4& v1)
11052306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
11062306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64					x0				= toSubpixelCoord(v0.x());
11072306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64					y0				= toSubpixelCoord(v0.y());
11082306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64					x1				= toSubpixelCoord(v1.x());
11092306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64					y1				= toSubpixelCoord(v1.y());
11102306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11112306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// line endpoints might be perturbed, add some margin
11122306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64					xMin			= de::min(x0, x1) - toSubpixelCoord(1);
11132306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64					xMax			= de::max(x0, x1) + toSubpixelCoord(1);
11142306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64					yMin			= de::min(y0, y1) - toSubpixelCoord(1);
11152306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64					yMax			= de::max(y0, y1) + toSubpixelCoord(1);
11162306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11172306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	m_bboxMin.x() = floorSubpixelToPixelCoord(xMin, true);
11182306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	m_bboxMin.y() = floorSubpixelToPixelCoord(yMin, true);
11192306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	m_bboxMax.x() = ceilSubpixelToPixelCoord (xMax, true);
11202306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	m_bboxMax.y() = ceilSubpixelToPixelCoord (yMax, true);
11212306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11222306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	m_v0 = v0;
11232306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	m_v1 = v1;
11242306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11252306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	m_curPos = m_bboxMin;
11262306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
11272306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11282306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyryvoid LineExitDiamondGenerator::rasterize (LineExitDiamond* const lineDiamonds, const int maxDiamonds, int& numWritten)
11292306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
11302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(maxDiamonds > 0);
11312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11322306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const deInt64								halfPixel			= 1ll << (RASTERIZER_SUBPIXEL_BITS-1);
11332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::Vector<deInt64,2>				pa					= LineRasterUtil::toSubpixelVector(m_v0.xy());
11342306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::Vector<deInt64,2>				pb					= LineRasterUtil::toSubpixelVector(m_v1.xy());
11352306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const LineRasterUtil::SubpixelLineSegment	line				= LineRasterUtil::SubpixelLineSegment(pa, pb);
11362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11372306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int											diamondNdx			= 0;
11382306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11392306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	while (m_curPos.y() <= m_bboxMax.y() && diamondNdx < maxDiamonds)
11402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
11412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::Vector<deInt64,2> diamondPosition = LineRasterUtil::toSubpixelVector(m_curPos) + tcu::Vector<deInt64,2>(halfPixel,halfPixel);
11422306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11432306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		if (LineRasterUtil::doesLineSegmentExitDiamond(line, diamondPosition))
11442306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
11452306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			LineExitDiamond& packet = lineDiamonds[diamondNdx];
11462306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			packet.position = m_curPos;
11472306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			++diamondNdx;
11482306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
11492306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11502306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		++m_curPos.x();
11512306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		if (m_curPos.x() > m_bboxMax.x())
11522306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
11532306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			++m_curPos.y();
11542306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			m_curPos.x() = m_bboxMin.x();
11552306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
11562306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
11572306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11582306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(diamondNdx <= maxDiamonds);
11592306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	numWritten = diamondNdx;
11602306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
11612306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
11623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // rr
1163