13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*-------------------------------------------------------------------------
23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Quality Program OpenGL (ES) Module
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 rasterization test utils.
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glsRasterizationTestUtil.hpp"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuVector.hpp"
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuSurface.hpp"
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuTestLog.hpp"
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuTextureUtil.hpp"
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuVectorUtil.hpp"
303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuFloat.hpp"
313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMath.h"
323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "rrRasterizer.hpp"
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <limits>
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace deqp
383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
393c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace gls
403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
413c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace RasterizationTestUtil
423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
433c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace
443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
463c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool lineLineIntersect (const tcu::Vector<deInt64, 2>& line0Beg, const tcu::Vector<deInt64, 2>& line0End, const tcu::Vector<deInt64, 2>& line1Beg, const tcu::Vector<deInt64, 2>& line1End)
473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	typedef tcu::Vector<deInt64, 2> I64Vec2;
493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Lines do not intersect if the other line's endpoints are on the same side
513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// otherwise, the do intersect
523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Test line 0
543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 line			= line0End - line0Beg;
563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 v0			= line1Beg - line0Beg;
573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 v1			= line1End - line0Beg;
583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64 crossProduct0	= (line.x() * v0.y() - line.y() * v0.x());
593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64 crossProduct1	= (line.x() * v1.y() - line.y() * v1.x());
603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// check signs
623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if ((crossProduct0 < 0 && crossProduct1 < 0) ||
633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(crossProduct0 > 0 && crossProduct1 > 0))
643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return false;
653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Test line 1
683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 line			= line1End - line1Beg;
703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 v0			= line0Beg - line1Beg;
713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 v1			= line0End - line1Beg;
723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64 crossProduct0	= (line.x() * v0.y() - line.y() * v0.x());
733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deInt64 crossProduct1	= (line.x() * v1.y() - line.y() * v1.x());
743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// check signs
763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if ((crossProduct0 < 0 && crossProduct1 < 0) ||
773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(crossProduct0 > 0 && crossProduct1 > 0))
783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return false;
793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return true;
823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
843c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool isTriangleClockwise (const tcu::Vec4& p0, const tcu::Vec4& p1, const tcu::Vec4& p2)
853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2	u				(p1.x() / p1.w() - p0.x() / p0.w(), p1.y() / p1.w() - p0.y() / p0.w());
873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2	v				(p2.x() / p2.w() - p0.x() / p0.w(), p2.y() / p2.w() - p0.y() / p0.w());
883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float		crossProduct	= (u.x() * v.y() - u.y() * v.x());
893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return crossProduct > 0.0f;
913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
933c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool compareColors (const tcu::RGBA& colorA, const tcu::RGBA& colorB, int redBits, int greenBits, int blueBits)
943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int thresholdRed		= 1 << (8 - redBits);
963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int thresholdGreen	= 1 << (8 - greenBits);
973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int thresholdBlue		= 1 << (8 - blueBits);
983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return	deAbs32(colorA.getRed()   - colorB.getRed())   <= thresholdRed   &&
1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			deAbs32(colorA.getGreen() - colorB.getGreen()) <= thresholdGreen &&
1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			deAbs32(colorA.getBlue()  - colorB.getBlue())  <= thresholdBlue;
1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool pixelNearLineSegment (const tcu::IVec2& pixel, const tcu::Vec2& p0, const tcu::Vec2& p1)
1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 pixelCenterPosition = tcu::Vec2(pixel.x() + 0.5f, pixel.y() + 0.5f);
1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// "Near" = Distance from the line to the pixel is less than 2 * pixel_max_radius. (pixel_max_radius = sqrt(2) / 2)
1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float maxPixelDistance		= 1.414f;
1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float maxPixelDistanceSquared	= 2.0f;
1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Near the line
1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2	line			= p1                  - p0;
1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2	v				= pixelCenterPosition - p0;
1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float		crossProduct	= (line.x() * v.y() - line.y() * v.x());
1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// distance to line: (line x v) / |line|
1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		//     |(line x v) / |line|| > maxPixelDistance
1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// ==> (line x v)^2 / |line|^2 > maxPixelDistance^2
1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// ==> (line x v)^2 > maxPixelDistance^2 * |line|^2
1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (crossProduct * crossProduct > maxPixelDistanceSquared * tcu::lengthSquared(line))
1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return false;
1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Between the endpoints
1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// distance from line endpoint 1 to pixel is less than line length + maxPixelDistance
1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float maxDistance = tcu::length(p1 - p0) + maxPixelDistance;
1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (tcu::length(pixelCenterPosition - p0) > maxDistance)
1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return false;
1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (tcu::length(pixelCenterPosition - p1) > maxDistance)
1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return false;
1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return true;
1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool pixelOnlyOnASharedEdge (const tcu::IVec2& pixel, const TriangleSceneSpec::SceneTriangle& triangle, const tcu::IVec2& viewportSize)
1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (triangle.sharedEdge[0] || triangle.sharedEdge[1] || triangle.sharedEdge[2])
1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 triangleNormalizedDeviceSpace[3] =
1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2(triangle.positions[0].x() / triangle.positions[0].w(), triangle.positions[0].y() / triangle.positions[0].w()),
1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2(triangle.positions[1].x() / triangle.positions[1].w(), triangle.positions[1].y() / triangle.positions[1].w()),
1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2(triangle.positions[2].x() / triangle.positions[2].w(), triangle.positions[2].y() / triangle.positions[2].w()),
1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 triangleScreenSpace[3] =
1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(triangleNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(triangleNormalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
1553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(triangleNormalizedDeviceSpace[2] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool pixelOnEdge0 = pixelNearLineSegment(pixel, triangleScreenSpace[0], triangleScreenSpace[1]);
1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool pixelOnEdge1 = pixelNearLineSegment(pixel, triangleScreenSpace[1], triangleScreenSpace[2]);
1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool pixelOnEdge2 = pixelNearLineSegment(pixel, triangleScreenSpace[2], triangleScreenSpace[0]);
1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// If the pixel is on a multiple edges return false
1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (pixelOnEdge0 && !pixelOnEdge1 && !pixelOnEdge2)
1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return triangle.sharedEdge[0];
1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!pixelOnEdge0 && pixelOnEdge1 && !pixelOnEdge2)
1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return triangle.sharedEdge[1];
1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!pixelOnEdge0 && !pixelOnEdge1 && pixelOnEdge2)
1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return triangle.sharedEdge[2];
1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return false;
1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat triangleArea (const tcu::Vec2& s0, const tcu::Vec2& s1, const tcu::Vec2& s2)
1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2	u				(s1.x() - s0.x(), s1.y() - s0.y());
1783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2	v				(s2.x() - s0.x(), s2.y() - s0.y());
1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float		crossProduct	= (u.x() * v.y() - u.y() * v.x());
1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return crossProduct / 2.0f;
1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytcu::IVec4 getTriangleAABB (const TriangleSceneSpec::SceneTriangle& triangle, const tcu::IVec2& viewportSize)
1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 normalizedDeviceSpace[3] =
1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vec2(triangle.positions[0].x() / triangle.positions[0].w(), triangle.positions[0].y() / triangle.positions[0].w()),
1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vec2(triangle.positions[1].x() / triangle.positions[1].w(), triangle.positions[1].y() / triangle.positions[1].w()),
1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vec2(triangle.positions[2].x() / triangle.positions[2].w(), triangle.positions[2].y() / triangle.positions[2].w()),
1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 screenSpace[3] =
1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		(normalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		(normalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		(normalizedDeviceSpace[2] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::IVec4 aabb;
2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	aabb.x() = (int)deFloatFloor(de::min(de::min(screenSpace[0].x(), screenSpace[1].x()), screenSpace[2].x()));
2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	aabb.y() = (int)deFloatFloor(de::min(de::min(screenSpace[0].y(), screenSpace[1].y()), screenSpace[2].y()));
2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	aabb.z() = (int)deFloatCeil (de::max(de::max(screenSpace[0].x(), screenSpace[1].x()), screenSpace[2].x()));
2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	aabb.w() = (int)deFloatCeil (de::max(de::max(screenSpace[0].y(), screenSpace[1].y()), screenSpace[2].y()));
2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return aabb;
2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2093c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat getExponentEpsilonFromULP (int valueExponent, deUint32 ulp)
2103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(ulp < (1u<<10));
2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// assume mediump precision, using ulp as ulps in a 10 bit mantissa
2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return tcu::Float32::construct(+1, valueExponent, (1u<<23) + (ulp << (23 - 10))).asFloat() - tcu::Float32::construct(+1, valueExponent, (1u<<23)).asFloat();
2153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat getValueEpsilonFromULP (float value, deUint32 ulp)
2183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(value != std::numeric_limits<float>::infinity() && value != -std::numeric_limits<float>::infinity());
2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int exponent = tcu::Float32(value).exponent();
2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return getExponentEpsilonFromULP(exponent, ulp);
2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat getMaxValueWithinError (float value, deUint32 ulp)
2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (value == std::numeric_limits<float>::infinity() || value == -std::numeric_limits<float>::infinity())
2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return value;
2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return value + getValueEpsilonFromULP(value, ulp);
2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat getMinValueWithinError (float value, deUint32 ulp)
2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (value == std::numeric_limits<float>::infinity() || value == -std::numeric_limits<float>::infinity())
2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return value;
2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return value - getValueEpsilonFromULP(value, ulp);
2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat getMinFlushToZero (float value)
2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// flush to zero if that decreases the value
2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// assume mediump precision
2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (value > 0.0f && value < tcu::Float32::construct(+1, -14, 1u<<23).asFloat())
2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return 0.0f;
2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return value;
2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat getMaxFlushToZero (float value)
2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// flush to zero if that increases the value
2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// assume mediump precision
2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (value < 0.0f && value > tcu::Float32::construct(-1, -14, 1u<<23).asFloat())
2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return 0.0f;
2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return value;
2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytcu::IVec3 convertRGB8ToNativeFormat (const tcu::RGBA& color, const RasterizationArguments& args)
2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::IVec3 pixelNativeColor;
2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int channelNdx = 0; channelNdx < 3; ++channelNdx)
2643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int channelBitCount	= (channelNdx == 0) ? (args.redBits) : (channelNdx == 1) ? (args.greenBits) : (args.blueBits);
2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int channelPixelValue	= (channelNdx == 0) ? (color.getRed()) : (channelNdx == 1) ? (color.getGreen()) : (color.getBlue());
2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (channelBitCount <= 8)
2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			pixelNativeColor[channelNdx] = channelPixelValue >> (8 - channelBitCount);
2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (channelBitCount == 8)
2713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			pixelNativeColor[channelNdx] = channelPixelValue;
2723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// just in case someone comes up with 8+ bits framebuffers pixel formats. But as
2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// we can only read in rgba8, we have to guess the trailing bits. Guessing 0.
2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			pixelNativeColor[channelNdx] = channelPixelValue << (channelBitCount - 8);
2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return pixelNativeColor;
2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*--------------------------------------------------------------------*//*!
2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Returns the maximum value of x / y, where x c [minDividend, maxDividend]
2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * and y c [minDivisor, maxDivisor]
2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat maximalRangeDivision (float minDividend, float maxDividend, float minDivisor, float maxDivisor)
2883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(minDividend <= maxDividend);
2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(minDivisor <= maxDivisor);
2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// special cases
2933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (minDividend == 0.0f && maxDividend == 0.0f)
2943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return 0.0f;
2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (minDivisor <= 0.0f && maxDivisor >= 0.0f)
2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return std::numeric_limits<float>::infinity();
2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return de::max(de::max(minDividend / minDivisor, minDividend / maxDivisor), de::max(maxDividend / minDivisor, maxDividend / maxDivisor));
2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*--------------------------------------------------------------------*//*!
3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Returns the minimum value of x / y, where x c [minDividend, maxDividend]
3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * and y c [minDivisor, maxDivisor]
3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat minimalRangeDivision (float minDividend, float maxDividend, float minDivisor, float maxDivisor)
3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(minDividend <= maxDividend);
3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(minDivisor <= maxDivisor);
3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// special cases
3113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (minDividend == 0.0f && maxDividend == 0.0f)
3123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return 0.0f;
3133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (minDivisor <= 0.0f && maxDivisor >= 0.0f)
3143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return -std::numeric_limits<float>::infinity();
3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return de::min(de::min(minDividend / minDivisor, minDividend / maxDivisor), de::min(maxDividend / minDivisor, maxDividend / maxDivisor));
3173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3192306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrystatic bool isLineXMajor (const tcu::Vec2& lineScreenSpaceP0, const tcu::Vec2& lineScreenSpaceP1)
3202306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
3212306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	return de::abs(lineScreenSpaceP1.x() - lineScreenSpaceP0.x()) >= de::abs(lineScreenSpaceP1.y() - lineScreenSpaceP0.y());
3222306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
3232306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
3242306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrystatic bool isPackedSSLineXMajor (const tcu::Vec4& packedLine)
3252306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
3262306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::Vec2 lineScreenSpaceP0 = packedLine.swizzle(0, 1);
3272306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::Vec2 lineScreenSpaceP1 = packedLine.swizzle(2, 3);
3282306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
3292306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	return isLineXMajor(lineScreenSpaceP0, lineScreenSpaceP1);
3302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
3312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
3323c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct InterpolationRange
3333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vec3 max;
3353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vec3 min;
3363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3383c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct LineInterpolationRange
3393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vec2 max;
3413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vec2 min;
3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3443c827367444ee418f129b2c238299f49d3264554Jarkko PoyryInterpolationRange calcTriangleInterpolationWeights (const tcu::Vec4& p0, const tcu::Vec4& p1, const tcu::Vec4& p2, const tcu::Vec2& ndpixel)
3453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int roundError		= 1;
3473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int barycentricError	= 3;
3483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int divError			= 8;
3493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 nd0 = p0.swizzle(0, 1) / p0.w();
3513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 nd1 = p1.swizzle(0, 1) / p1.w();
3523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 nd2 = p2.swizzle(0, 1) / p2.w();
3533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float ka = triangleArea(ndpixel, nd1, nd2);
3553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float kb = triangleArea(ndpixel, nd2, nd0);
3563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float kc = triangleArea(ndpixel, nd0, nd1);
3573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float kaMax = getMaxFlushToZero(getMaxValueWithinError(ka, barycentricError));
3593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float kbMax = getMaxFlushToZero(getMaxValueWithinError(kb, barycentricError));
3603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float kcMax = getMaxFlushToZero(getMaxValueWithinError(kc, barycentricError));
3613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float kaMin = getMinFlushToZero(getMinValueWithinError(ka, barycentricError));
3623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float kbMin = getMinFlushToZero(getMinValueWithinError(kb, barycentricError));
3633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float kcMin = getMinFlushToZero(getMinValueWithinError(kc, barycentricError));
3643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(kaMin <= kaMax);
3653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(kbMin <= kbMax);
3663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(kcMin <= kcMax);
3673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// calculate weights: vec3(ka / p0.w, kb / p1.w, kc / p2.w) / (ka / p0.w + kb / p1.w + kc / p2.w)
3693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float maxPreDivisionValues[3] =
3703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		getMaxFlushToZero(getMaxValueWithinError(getMaxFlushToZero(kaMax / p0.w()), divError)),
3723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		getMaxFlushToZero(getMaxValueWithinError(getMaxFlushToZero(kbMax / p1.w()), divError)),
3733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		getMaxFlushToZero(getMaxValueWithinError(getMaxFlushToZero(kcMax / p2.w()), divError)),
3743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
3753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float minPreDivisionValues[3] =
3763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		getMinFlushToZero(getMinValueWithinError(getMinFlushToZero(kaMin / p0.w()), divError)),
3783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		getMinFlushToZero(getMinValueWithinError(getMinFlushToZero(kbMin / p1.w()), divError)),
3793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		getMinFlushToZero(getMinValueWithinError(getMinFlushToZero(kcMin / p2.w()), divError)),
3803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
3813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(minPreDivisionValues[0] <= maxPreDivisionValues[0]);
3823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(minPreDivisionValues[1] <= maxPreDivisionValues[1]);
3833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(minPreDivisionValues[2] <= maxPreDivisionValues[2]);
3843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float maxDivisor = getMaxFlushToZero(getMaxValueWithinError(maxPreDivisionValues[0] + maxPreDivisionValues[1] + maxPreDivisionValues[2], 2*roundError));
3863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float minDivisor = getMinFlushToZero(getMinValueWithinError(minPreDivisionValues[0] + minPreDivisionValues[1] + minPreDivisionValues[2], 2*roundError));
3873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(minDivisor <= maxDivisor);
3883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	InterpolationRange returnValue;
3903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.max.x() = getMaxFlushToZero(getMaxValueWithinError(getMaxFlushToZero(maximalRangeDivision(minPreDivisionValues[0], maxPreDivisionValues[0], minDivisor, maxDivisor)), divError));
3923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.max.y() = getMaxFlushToZero(getMaxValueWithinError(getMaxFlushToZero(maximalRangeDivision(minPreDivisionValues[1], maxPreDivisionValues[1], minDivisor, maxDivisor)), divError));
3933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.max.z() = getMaxFlushToZero(getMaxValueWithinError(getMaxFlushToZero(maximalRangeDivision(minPreDivisionValues[2], maxPreDivisionValues[2], minDivisor, maxDivisor)), divError));
3943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.min.x() = getMinFlushToZero(getMinValueWithinError(getMinFlushToZero(minimalRangeDivision(minPreDivisionValues[0], maxPreDivisionValues[0], minDivisor, maxDivisor)), divError));
3953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.min.y() = getMinFlushToZero(getMinValueWithinError(getMinFlushToZero(minimalRangeDivision(minPreDivisionValues[1], maxPreDivisionValues[1], minDivisor, maxDivisor)), divError));
3963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.min.z() = getMinFlushToZero(getMinValueWithinError(getMinFlushToZero(minimalRangeDivision(minPreDivisionValues[2], maxPreDivisionValues[2], minDivisor, maxDivisor)), divError));
3973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(returnValue.min.x() <= returnValue.max.x());
3993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(returnValue.min.y() <= returnValue.max.y());
4003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(returnValue.min.z() <= returnValue.max.z());
4013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return returnValue;
4033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4052306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko PöyryLineInterpolationRange calcLineInterpolationWeights (const tcu::Vec2& pa, float wa, const tcu::Vec2& pb, float wb, const tcu::Vec2& pr)
4063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4072306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int roundError	= 1;
4082306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int divError		= 3;
4093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4102306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// calc weights:
4112306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	//			(1-t) / wa					t / wb
4122306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	//		-------------------	,	-------------------
4132306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	//		(1-t) / wa + t / wb		(1-t) / wa + t / wb
4143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4152306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// Allow 1 ULP
4162306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		dividend	= tcu::dot(pr - pa, pb - pa);
4172306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		dividendMax	= getMaxValueWithinError(dividend, 1);
4182306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		dividendMin	= getMinValueWithinError(dividend, 1);
4192306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(dividendMin <= dividendMax);
4203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4212306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// Assuming lengthSquared will not be implemented as sqrt(x)^2, allow 1 ULP
4222306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		divisor		= tcu::lengthSquared(pb - pa);
4232306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		divisorMax	= getMaxValueWithinError(divisor, 1);
4242306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		divisorMin	= getMinValueWithinError(divisor, 1);
4252306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(divisorMin <= divisorMax);
4263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4272306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// Allow 3 ULP precision for division
4282306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		tMax		= getMaxValueWithinError(maximalRangeDivision(dividendMin, dividendMax, divisorMin, divisorMax), divError);
4292306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		tMin		= getMinValueWithinError(minimalRangeDivision(dividendMin, dividendMax, divisorMin, divisorMax), divError);
4303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(tMin <= tMax);
4313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4322306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveTMax			= getMaxValueWithinError(maximalRangeDivision(tMin, tMax, wb, wb), divError);
4332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveTMin			= getMinValueWithinError(minimalRangeDivision(tMin, tMax, wb, wb), divError);
4343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(perspectiveTMin <= perspectiveTMax);
4353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveInvTMax		= getMaxValueWithinError(maximalRangeDivision((1.0f - tMax), (1.0f - tMin), wa, wa), divError);
4372306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveInvTMin		= getMinValueWithinError(minimalRangeDivision((1.0f - tMax), (1.0f - tMin), wa, wa), divError);
4383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(perspectiveInvTMin <= perspectiveInvTMax);
4393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveDivisorMax	= getMaxValueWithinError(perspectiveTMax + perspectiveInvTMax, roundError);
4412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveDivisorMin	= getMinValueWithinError(perspectiveTMin + perspectiveInvTMin, roundError);
4423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(perspectiveDivisorMin <= perspectiveDivisorMax);
4433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	LineInterpolationRange returnValue;
4453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.max.x() = getMaxValueWithinError(maximalRangeDivision(perspectiveInvTMin,	perspectiveInvTMax,	perspectiveDivisorMin, perspectiveDivisorMax), divError);
4463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.max.y() = getMaxValueWithinError(maximalRangeDivision(perspectiveTMin,		perspectiveTMax,	perspectiveDivisorMin, perspectiveDivisorMax), divError);
4473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.min.x() = getMinValueWithinError(minimalRangeDivision(perspectiveInvTMin,	perspectiveInvTMax,	perspectiveDivisorMin, perspectiveDivisorMax), divError);
4483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.min.y() = getMinValueWithinError(minimalRangeDivision(perspectiveTMin,		perspectiveTMax,	perspectiveDivisorMin, perspectiveDivisorMax), divError);
4493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(returnValue.min.x() <= returnValue.max.x());
4513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(returnValue.min.y() <= returnValue.max.y());
4523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return returnValue;
4543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4562306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko PöyryLineInterpolationRange calcLineInterpolationWeightsAxisProjected (const tcu::Vec2& pa, float wa, const tcu::Vec2& pb, float wb, const tcu::Vec2& pr)
4573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4582306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int	roundError		= 1;
4592306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int	divError		= 3;
4602306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const bool	isXMajor		= isLineXMajor(pa, pb);
4612306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int	majorAxisNdx	= (isXMajor) ? (0) : (1);
4623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4632306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// calc weights:
4642306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	//			(1-t) / wa					t / wb
4652306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	//		-------------------	,	-------------------
4662306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	//		(1-t) / wa + t / wb		(1-t) / wa + t / wb
4673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4682306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// Use axis projected (inaccurate) method, i.e. for X-major lines:
4692306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	//     (xd - xa) * (xb - xa)      xd - xa
4702306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// t = ---------------------  ==  -------
4712306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	//       ( xb - xa ) ^ 2          xb - xa
4723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Allow 1 ULP
4742306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		dividend	= (pr[majorAxisNdx] - pa[majorAxisNdx]);
4753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float		dividendMax	= getMaxValueWithinError(dividend, 1);
4762306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		dividendMin	= getMinValueWithinError(dividend, 1);
4773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(dividendMin <= dividendMax);
4783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4792306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// Allow 1 ULP
4802306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		divisor		= (pb[majorAxisNdx] - pa[majorAxisNdx]);
4813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float		divisorMax	= getMaxValueWithinError(divisor, 1);
4822306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		divisorMin	= getMinValueWithinError(divisor, 1);
4833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(divisorMin <= divisorMax);
4843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Allow 3 ULP precision for division
4863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float		tMax		= getMaxValueWithinError(maximalRangeDivision(dividendMin, dividendMax, divisorMin, divisorMax), divError);
4873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float		tMin		= getMinValueWithinError(minimalRangeDivision(dividendMin, dividendMax, divisorMin, divisorMax), divError);
4883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(tMin <= tMax);
4893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4902306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveTMax			= getMaxValueWithinError(maximalRangeDivision(tMin, tMax, wb, wb), divError);
4912306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveTMin			= getMinValueWithinError(minimalRangeDivision(tMin, tMax, wb, wb), divError);
4923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(perspectiveTMin <= perspectiveTMax);
4933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4942306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveInvTMax		= getMaxValueWithinError(maximalRangeDivision((1.0f - tMax), (1.0f - tMin), wa, wa), divError);
4952306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveInvTMin		= getMinValueWithinError(minimalRangeDivision((1.0f - tMax), (1.0f - tMin), wa, wa), divError);
4963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(perspectiveInvTMin <= perspectiveInvTMax);
4973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4982306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveDivisorMax	= getMaxValueWithinError(perspectiveTMax + perspectiveInvTMax, roundError);
4992306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float		perspectiveDivisorMin	= getMinValueWithinError(perspectiveTMin + perspectiveInvTMin, roundError);
5003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(perspectiveDivisorMin <= perspectiveDivisorMax);
5013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	LineInterpolationRange returnValue;
5033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.max.x() = getMaxValueWithinError(maximalRangeDivision(perspectiveInvTMin,	perspectiveInvTMax,	perspectiveDivisorMin, perspectiveDivisorMax), divError);
5043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.max.y() = getMaxValueWithinError(maximalRangeDivision(perspectiveTMin,		perspectiveTMax,	perspectiveDivisorMin, perspectiveDivisorMax), divError);
5053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.min.x() = getMinValueWithinError(minimalRangeDivision(perspectiveInvTMin,	perspectiveInvTMax,	perspectiveDivisorMin, perspectiveDivisorMax), divError);
5063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	returnValue.min.y() = getMinValueWithinError(minimalRangeDivision(perspectiveTMin,		perspectiveTMax,	perspectiveDivisorMin, perspectiveDivisorMax), divError);
5073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(returnValue.min.x() <= returnValue.max.x());
5093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(returnValue.min.y() <= returnValue.max.y());
5103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return returnValue;
5123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5142306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrytemplate <typename WeightEquation>
5152306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko PöyryLineInterpolationRange calcSingleSampleLineInterpolationRangeWithWeightEquation (const tcu::Vec2&	pa,
5162306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																				 float				wa,
5172306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																				 const tcu::Vec2&	pb,
5182306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																				 float				wb,
5192306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																				 const tcu::IVec2&	pixel,
5202306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																				 int				subpixelBits,
5212306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																				 WeightEquation		weightEquation)
5223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// allow interpolation weights anywhere in the central subpixels
5243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float testSquareSize = (2.0f / (1UL << subpixelBits));
5253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float testSquarePos  = (0.5f - testSquareSize / 2);
5262306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
5273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 corners[4] =
5283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5292306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::Vec2(pixel.x() + testSquarePos + 0.0f,				pixel.y() + testSquarePos + 0.0f),
5302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::Vec2(pixel.x() + testSquarePos + 0.0f,				pixel.y() + testSquarePos + testSquareSize),
5312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::Vec2(pixel.x() + testSquarePos + testSquareSize,	pixel.y() + testSquarePos + testSquareSize),
5322306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::Vec2(pixel.x() + testSquarePos + testSquareSize,	pixel.y() + testSquarePos + 0.0f),
5333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
5343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// calculate interpolation as a line
5363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const LineInterpolationRange weights[4] =
5373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5382306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		weightEquation(pa, wa, pb, wb, corners[0]),
5392306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		weightEquation(pa, wa, pb, wb, corners[1]),
5402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		weightEquation(pa, wa, pb, wb, corners[2]),
5412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		weightEquation(pa, wa, pb, wb, corners[3]),
5423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
5433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 minWeights = tcu::min(tcu::min(weights[0].min, weights[1].min), tcu::min(weights[2].min, weights[3].min));
5453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2 maxWeights = tcu::max(tcu::max(weights[0].max, weights[1].max), tcu::max(weights[2].max, weights[3].max));
5463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	LineInterpolationRange result;
5483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	result.min = minWeights;
5493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	result.max = maxWeights;
5503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return result;
5513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5532306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko PöyryLineInterpolationRange calcSingleSampleLineInterpolationRange (const tcu::Vec2& pa, float wa, const tcu::Vec2& pb, float wb, const tcu::IVec2& pixel, int subpixelBits)
5542306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
5552306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	return calcSingleSampleLineInterpolationRangeWithWeightEquation(pa, wa, pb, wb, pixel, subpixelBits, calcLineInterpolationWeights);
5562306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
5572306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
5582306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko PöyryLineInterpolationRange calcSingleSampleLineInterpolationRangeAxisProjected (const tcu::Vec2& pa, float wa, const tcu::Vec2& pb, float wb, const tcu::IVec2& pixel, int subpixelBits)
5592306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
5602306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	return calcSingleSampleLineInterpolationRangeWithWeightEquation(pa, wa, pb, wb, pixel, subpixelBits, calcLineInterpolationWeightsAxisProjected);
5612306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
5622306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
5633c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct TriangleInterpolator
5643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const TriangleSceneSpec& scene;
5663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TriangleInterpolator (const TriangleSceneSpec& scene_)
5683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: scene(scene_)
5693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	InterpolationRange interpolate (int primitiveNdx, const tcu::IVec2 pixel, const tcu::IVec2 viewportSize, bool multisample, int subpixelBits) const
5733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// allow anywhere in the pixel area in multisample
5753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// allow only in the center subpixels (4 subpixels) in singlesample
5763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float testSquareSize = (multisample) ? (1.0f) : (2.0f / (1UL << subpixelBits));
5773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float testSquarePos  = (multisample) ? (0.0f) : (0.5f - testSquareSize / 2);
5783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 corners[4] =
5793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2((pixel.x() + testSquarePos + 0.0f)           / viewportSize.x() * 2.0f - 1.0f, (pixel.y() + testSquarePos + 0.0f          ) / viewportSize.y() * 2.0f - 1.0f),
5813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2((pixel.x() + testSquarePos + 0.0f)           / viewportSize.x() * 2.0f - 1.0f, (pixel.y() + testSquarePos + testSquareSize) / viewportSize.y() * 2.0f - 1.0f),
5823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2((pixel.x() + testSquarePos + testSquareSize) / viewportSize.x() * 2.0f - 1.0f, (pixel.y() + testSquarePos + testSquareSize) / viewportSize.y() * 2.0f - 1.0f),
5833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2((pixel.x() + testSquarePos + testSquareSize) / viewportSize.x() * 2.0f - 1.0f, (pixel.y() + testSquarePos + 0.0f          ) / viewportSize.y() * 2.0f - 1.0f),
5843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
5853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const InterpolationRange weights[4] =
5863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			calcTriangleInterpolationWeights(scene.triangles[primitiveNdx].positions[0], scene.triangles[primitiveNdx].positions[1], scene.triangles[primitiveNdx].positions[2], corners[0]),
5883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			calcTriangleInterpolationWeights(scene.triangles[primitiveNdx].positions[0], scene.triangles[primitiveNdx].positions[1], scene.triangles[primitiveNdx].positions[2], corners[1]),
5893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			calcTriangleInterpolationWeights(scene.triangles[primitiveNdx].positions[0], scene.triangles[primitiveNdx].positions[1], scene.triangles[primitiveNdx].positions[2], corners[2]),
5903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			calcTriangleInterpolationWeights(scene.triangles[primitiveNdx].positions[0], scene.triangles[primitiveNdx].positions[1], scene.triangles[primitiveNdx].positions[2], corners[3]),
5913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
5923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		InterpolationRange result;
5943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		result.min = tcu::min(tcu::min(weights[0].min, weights[1].min), tcu::min(weights[2].min, weights[3].min));
5953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		result.max = tcu::max(tcu::max(weights[0].max, weights[1].max), tcu::max(weights[2].max, weights[3].max));
5963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return result;
5973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
5993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*--------------------------------------------------------------------*//*!
6013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Used only by verifyMultisampleLineGroupInterpolation to calculate
6023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * correct line interpolations for the triangulated lines.
6033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
6043c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct MultisampleLineInterpolator
6053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const LineSceneSpec& scene;
6073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	MultisampleLineInterpolator (const LineSceneSpec& scene_)
6093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: scene(scene_)
6103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	InterpolationRange interpolate (int primitiveNdx, const tcu::IVec2 pixel, const tcu::IVec2 viewportSize, bool multisample, int subpixelBits) const
6143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(multisample);
6163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_UNREF(multisample);
6173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_UNREF(subpixelBits);
6183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// in triangulation, one line emits two triangles
6203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		lineNdx		= primitiveNdx / 2;
6213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// allow interpolation weights anywhere in the pixel
6233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 corners[4] =
6243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6252306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			tcu::Vec2(pixel.x() + 0.0f, pixel.y() + 0.0f),
6262306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			tcu::Vec2(pixel.x() + 0.0f, pixel.y() + 1.0f),
6272306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			tcu::Vec2(pixel.x() + 1.0f, pixel.y() + 1.0f),
6282306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			tcu::Vec2(pixel.x() + 1.0f, pixel.y() + 0.0f),
6293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
6303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const float		wa = scene.lines[lineNdx].positions[0].w();
6322306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const float		wb = scene.lines[lineNdx].positions[1].w();
6332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::Vec2	pa = tcu::Vec2((scene.lines[lineNdx].positions[0].x() / wa + 1.0f) * 0.5f * viewportSize.x(),
6342306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry									   (scene.lines[lineNdx].positions[0].y() / wa + 1.0f) * 0.5f * viewportSize.y());
6352306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::Vec2	pb = tcu::Vec2((scene.lines[lineNdx].positions[1].x() / wb + 1.0f) * 0.5f * viewportSize.x(),
6362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry									   (scene.lines[lineNdx].positions[1].y() / wb + 1.0f) * 0.5f * viewportSize.y());
6372306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
6383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// calculate interpolation as a line
6393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const LineInterpolationRange weights[4] =
6403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			calcLineInterpolationWeights(pa, wa, pb, wb, corners[0]),
6422306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			calcLineInterpolationWeights(pa, wa, pb, wb, corners[1]),
6432306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			calcLineInterpolationWeights(pa, wa, pb, wb, corners[2]),
6442306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			calcLineInterpolationWeights(pa, wa, pb, wb, corners[3]),
6453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
6463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 minWeights = tcu::min(tcu::min(weights[0].min, weights[1].min), tcu::min(weights[2].min, weights[3].min));
6483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 maxWeights = tcu::max(tcu::max(weights[0].max, weights[1].max), tcu::max(weights[2].max, weights[3].max));
6493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// convert to three-component form. For all triangles, the vertex 0 is always emitted by the line starting point, and vertex 2 by the ending point
6513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		InterpolationRange result;
6523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		result.min = tcu::Vec3(minWeights.x(), 0.0f, minWeights.y());
6533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		result.max = tcu::Vec3(maxWeights.x(), 0.0f, maxWeights.y());
6543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return result;
6553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
6573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6583c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate <typename Interpolator>
6593c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool verifyTriangleGroupInterpolationWithInterpolator (const tcu::Surface& surface, const TriangleSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log, const Interpolator& interpolator)
6603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::RGBA		invalidPixelColor	= tcu::RGBA(255, 0, 0, 255);
6623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool			multisampled		= (args.numSamples != 0);
6633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::IVec2	viewportSize		= tcu::IVec2(surface.getWidth(), surface.getHeight());
6643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			errorFloodThreshold	= 4;
6653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int					errorCount			= 0;
6663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int					invalidPixels		= 0;
6673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int					subPixelBits		= args.subpixelBits;
6683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Surface		errorMask			(surface.getWidth(), surface.getHeight());
6693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
6713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// log format
6733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << tcu::TestLog::Message << "Verifying rasterization result. Native format is RGB" << args.redBits << args.greenBits << args.blueBits << tcu::TestLog::EndMessage;
6753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (args.redBits > 8 || args.greenBits > 8 || args.blueBits > 8)
6763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Warning! More than 8 bits in a color channel, this may produce false negatives." << tcu::TestLog::EndMessage;
6773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// subpixel bits in in a valid range?
6793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (subPixelBits < 0)
6813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Invalid subpixel count (" << subPixelBits << "), assuming 0" << tcu::TestLog::EndMessage;
6833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		subPixelBits = 0;
6843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (subPixelBits > 16)
6863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// At high subpixel bit counts we might overflow. Checking at lower bit count is ok, but is less strict
6883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Subpixel count is greater than 16 (" << subPixelBits << "). Checking results using less strict 16 bit requirements. This may produce false positives." << tcu::TestLog::EndMessage;
6893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		subPixelBits = 16;
6903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// check pixels
6933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int y = 0; y < surface.getHeight(); ++y)
6953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int x = 0; x < surface.getWidth();  ++x)
6963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::RGBA		color				= surface.getPixel(x, y);
6983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool				stackBottomFound	= false;
6993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int					stackSize			= 0;
7003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vec4			colorStackMin;
7013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vec4			colorStackMax;
7023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Iterate triangle coverage front to back, find the stack of pontentially contributing fragments
7043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int triNdx = (int)scene.triangles.size() - 1; triNdx >= 0; --triNdx)
7053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const CoverageType coverage = calculateTriangleCoverage(scene.triangles[triNdx].positions[0],
7073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	scene.triangles[triNdx].positions[1],
7083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	scene.triangles[triNdx].positions[2],
7093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	tcu::IVec2(x, y),
7103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	viewportSize,
7113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	subPixelBits,
7123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	multisampled);
7133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (coverage == COVERAGE_FULL || coverage == COVERAGE_PARTIAL)
7153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// potentially contributes to the result fragment's value
7173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const InterpolationRange weights = interpolator.interpolate(triNdx, tcu::IVec2(x, y), viewportSize, multisampled, subPixelBits);
7183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const tcu::Vec4 fragmentColorMax =	de::clamp(weights.max.x(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[0] +
7203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													de::clamp(weights.max.y(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[1] +
7213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													de::clamp(weights.max.z(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[2];
7223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const tcu::Vec4 fragmentColorMin =	de::clamp(weights.min.x(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[0] +
7233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													de::clamp(weights.min.y(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[1] +
7243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													de::clamp(weights.min.z(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[2];
7253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (stackSize++ == 0)
7273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
7283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// first triangle, set the values properly
7293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					colorStackMin = fragmentColorMin;
7303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					colorStackMax = fragmentColorMax;
7313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
7323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
7333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
7343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// contributing triangle
7353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					colorStackMin = tcu::min(colorStackMin, fragmentColorMin);
7363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					colorStackMax = tcu::max(colorStackMax, fragmentColorMax);
7373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
7383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (coverage == COVERAGE_FULL)
7403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
7413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// loop terminates, this is the bottommost fragment
7423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					stackBottomFound = true;
7433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					break;
7443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
7453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Partial coverage == background may be visible
7493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (stackSize != 0 && !stackBottomFound)
7503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			stackSize++;
7523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			colorStackMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
7533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Is the result image color in the valid range.
7563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (stackSize == 0)
7573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// No coverage, allow only background (black, value=0)
7593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::IVec3	pixelNativeColor	= convertRGB8ToNativeFormat(color, args);
7603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			threshold			= 1;
7613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (pixelNativeColor.x() > threshold ||
7633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				pixelNativeColor.y() > threshold ||
7643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				pixelNativeColor.z() > threshold)
7653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				++errorCount;
7673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// don't fill the logs with too much data
7693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (errorCount < errorFloodThreshold)
7703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
7713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					log << tcu::TestLog::Message
7723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "Found an invalid pixel at (" << x << "," << y << ")\n"
7733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tPixel color:\t\t" << color << "\n"
7743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tExpected background color.\n"
7753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< tcu::TestLog::EndMessage;
7763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
7773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				++invalidPixels;
7793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				errorMask.setPixel(x, y, invalidPixelColor);
7803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
7833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(stackSize);
7853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Each additional step in the stack may cause conversion error of 1 bit due to undefined rounding direction
7873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			thresholdRed	= stackSize - 1;
7883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			thresholdGreen	= stackSize - 1;
7893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			thresholdBlue	= stackSize - 1;
7903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec3		valueRangeMin	= tcu::Vec3(colorStackMin.xyz());
7923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec3		valueRangeMax	= tcu::Vec3(colorStackMax.xyz());
7933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::IVec3	formatLimit		((1 << args.redBits) - 1, (1 << args.greenBits) - 1, (1 << args.blueBits) - 1);
7953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec3		colorMinF		(de::clamp(valueRangeMin.x() * formatLimit.x(), 0.0f, (float)formatLimit.x()),
7963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												 de::clamp(valueRangeMin.y() * formatLimit.y(), 0.0f, (float)formatLimit.y()),
7973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												 de::clamp(valueRangeMin.z() * formatLimit.z(), 0.0f, (float)formatLimit.z()));
7983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::Vec3		colorMaxF		(de::clamp(valueRangeMax.x() * formatLimit.x(), 0.0f, (float)formatLimit.x()),
7993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												 de::clamp(valueRangeMax.y() * formatLimit.y(), 0.0f, (float)formatLimit.y()),
8003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												 de::clamp(valueRangeMax.z() * formatLimit.z(), 0.0f, (float)formatLimit.z()));
8013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::IVec3	colorMin		((int)deFloatFloor(colorMinF.x()),
8023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												 (int)deFloatFloor(colorMinF.y()),
8033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												 (int)deFloatFloor(colorMinF.z()));
8043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::IVec3	colorMax		((int)deFloatCeil (colorMaxF.x()),
8053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												 (int)deFloatCeil (colorMaxF.y()),
8063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												 (int)deFloatCeil (colorMaxF.z()));
8073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Convert pixel color from rgba8 to the real pixel format. Usually rgba8 or 565
8093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::IVec3 pixelNativeColor = convertRGB8ToNativeFormat(color, args);
8103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Validity check
8123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (pixelNativeColor.x() < colorMin.x() - thresholdRed   ||
8133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				pixelNativeColor.y() < colorMin.y() - thresholdGreen ||
8143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				pixelNativeColor.z() < colorMin.z() - thresholdBlue  ||
8153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				pixelNativeColor.x() > colorMax.x() + thresholdRed   ||
8163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				pixelNativeColor.y() > colorMax.y() + thresholdGreen ||
8173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				pixelNativeColor.z() > colorMax.z() + thresholdBlue)
8183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
8193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				++errorCount;
8203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// don't fill the logs with too much data
8223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (errorCount <= errorFloodThreshold)
8233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
8243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					log << tcu::TestLog::Message
8253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "Found an invalid pixel at (" << x << "," << y << ")\n"
8263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tPixel color:\t\t" << color << "\n"
8273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tNative color:\t\t" << pixelNativeColor << "\n"
8283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tAllowed error:\t\t" << tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue) << "\n"
8293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tReference native color min: " << tcu::clamp(colorMin - tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue), tcu::IVec3(0,0,0), formatLimit) << "\n"
8303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tReference native color max: " << tcu::clamp(colorMax + tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue), tcu::IVec3(0,0,0), formatLimit) << "\n"
8313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tReference native float min: " << tcu::clamp(colorMinF - tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue).cast<float>(), tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>()) << "\n"
8323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tReference native float max: " << tcu::clamp(colorMaxF + tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue).cast<float>(), tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>()) << "\n"
8333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tFmin:\t" << tcu::clamp(valueRangeMin, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f)) << "\n"
8343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< "\tFmax:\t" << tcu::clamp(valueRangeMax, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f)) << "\n"
8353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						<< tcu::TestLog::EndMessage;
8363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
8373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				++invalidPixels;
8393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				errorMask.setPixel(x, y, invalidPixelColor);
8403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
8413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
8423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// don't just hide failures
8453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (errorCount > errorFloodThreshold)
8463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Omitted " << (errorCount-errorFloodThreshold) << " pixel error description(s)." << tcu::TestLog::EndMessage;
8473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// report result
8493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (invalidPixels)
8503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << invalidPixels << " invalid pixel(s) found." << tcu::TestLog::EndMessage;
8523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
8533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("Result", "Result",			surface)
8543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
8553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::EndImageSet;
8563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return false;
8583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
8603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
8623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
8633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("Result", "Result", surface)
8643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::EndImageSet;
8653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
8673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8703c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool verifyMultisampleLineGroupRasterization (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
8713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Multisampled line == 2 triangles
8733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2		viewportSize	= tcu::Vec2((float)surface.getWidth(), (float)surface.getHeight());
8753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float			halfLineWidth	= scene.lineWidth * 0.5f;
8763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TriangleSceneSpec	triangleScene;
8773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	triangleScene.triangles.resize(2 * scene.lines.size());
8793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
8803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Transform to screen space, add pixel offsets, convert back to normalized device space, and test as triangles
8823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineNormalizedDeviceSpace[2] =
8833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2(scene.lines[lineNdx].positions[0].x() / scene.lines[lineNdx].positions[0].w(), scene.lines[lineNdx].positions[0].y() / scene.lines[lineNdx].positions[0].w()),
8853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2(scene.lines[lineNdx].positions[1].x() / scene.lines[lineNdx].positions[1].w(), scene.lines[lineNdx].positions[1].y() / scene.lines[lineNdx].positions[1].w()),
8863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
8873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineScreenSpace[2] =
8883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(lineNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize,
8903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(lineNormalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize,
8913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
8923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineDir			= tcu::normalize(lineScreenSpace[1] - lineScreenSpace[0]);
8943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineNormalDir	= tcu::Vec2(lineDir.y(), -lineDir.x());
8953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineQuadScreenSpace[4] =
8973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineScreenSpace[0] + lineNormalDir * halfLineWidth,
8993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineScreenSpace[0] - lineNormalDir * halfLineWidth,
9003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineScreenSpace[1] - lineNormalDir * halfLineWidth,
9013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineScreenSpace[1] + lineNormalDir * halfLineWidth,
9023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
9033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineQuadNormalizedDeviceSpace[4] =
9043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineQuadScreenSpace[0] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
9063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineQuadScreenSpace[1] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
9073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineQuadScreenSpace[2] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
9083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineQuadScreenSpace[3] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
9093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
9103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].positions[0] = tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);	triangleScene.triangles[lineNdx*2 + 0].sharedEdge[0] = false;
9123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].positions[1] = tcu::Vec4(lineQuadNormalizedDeviceSpace[1].x(), lineQuadNormalizedDeviceSpace[1].y(), 0.0f, 1.0f);	triangleScene.triangles[lineNdx*2 + 0].sharedEdge[1] = false;
9133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].positions[2] = tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);	triangleScene.triangles[lineNdx*2 + 0].sharedEdge[2] = true;
9143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].positions[0] = tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);	triangleScene.triangles[lineNdx*2 + 1].sharedEdge[0] = true;
9163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].positions[1] = tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);	triangleScene.triangles[lineNdx*2 + 1].sharedEdge[1] = false;
9173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].positions[2] = tcu::Vec4(lineQuadNormalizedDeviceSpace[3].x(), lineQuadNormalizedDeviceSpace[3].y(), 0.0f, 1.0f);	triangleScene.triangles[lineNdx*2 + 1].sharedEdge[2] = false;
9183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return verifyTriangleGroupRasterization(surface, triangleScene, args, log);
9213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9233c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool verifyMultisampleLineGroupInterpolation (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
9243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Multisampled line == 2 triangles
9263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2		viewportSize	= tcu::Vec2((float)surface.getWidth(), (float)surface.getHeight());
9283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float			halfLineWidth	= scene.lineWidth * 0.5f;
9293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TriangleSceneSpec	triangleScene;
9303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	triangleScene.triangles.resize(2 * scene.lines.size());
9323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
9333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Transform to screen space, add pixel offsets, convert back to normalized device space, and test as triangles
9353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineNormalizedDeviceSpace[2] =
9363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2(scene.lines[lineNdx].positions[0].x() / scene.lines[lineNdx].positions[0].w(), scene.lines[lineNdx].positions[0].y() / scene.lines[lineNdx].positions[0].w()),
9383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tcu::Vec2(scene.lines[lineNdx].positions[1].x() / scene.lines[lineNdx].positions[1].w(), scene.lines[lineNdx].positions[1].y() / scene.lines[lineNdx].positions[1].w()),
9393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
9403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineScreenSpace[2] =
9413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(lineNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize,
9433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(lineNormalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize,
9443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
9453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineDir			= tcu::normalize(lineScreenSpace[1] - lineScreenSpace[0]);
9473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineNormalDir	= tcu::Vec2(lineDir.y(), -lineDir.x());
9483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineQuadScreenSpace[4] =
9503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineScreenSpace[0] + lineNormalDir * halfLineWidth,
9523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineScreenSpace[0] - lineNormalDir * halfLineWidth,
9533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineScreenSpace[1] - lineNormalDir * halfLineWidth,
9543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineScreenSpace[1] + lineNormalDir * halfLineWidth,
9553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
9563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2 lineQuadNormalizedDeviceSpace[4] =
9573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineQuadScreenSpace[0] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
9593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineQuadScreenSpace[1] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
9603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineQuadScreenSpace[2] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
9613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineQuadScreenSpace[3] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
9623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
9633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].positions[0] = tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);
9653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].positions[1] = tcu::Vec4(lineQuadNormalizedDeviceSpace[1].x(), lineQuadNormalizedDeviceSpace[1].y(), 0.0f, 1.0f);
9663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].positions[2] = tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);
9673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].sharedEdge[0] = false;
9693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].sharedEdge[1] = false;
9703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].sharedEdge[2] = true;
9713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].colors[0] = scene.lines[lineNdx].colors[0];
9733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].colors[1] = scene.lines[lineNdx].colors[0];
9743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 0].colors[2] = scene.lines[lineNdx].colors[1];
9753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].positions[0] = tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);
9773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].positions[1] = tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);
9783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].positions[2] = tcu::Vec4(lineQuadNormalizedDeviceSpace[3].x(), lineQuadNormalizedDeviceSpace[3].y(), 0.0f, 1.0f);
9793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].sharedEdge[0] = true;
9813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].sharedEdge[1] = false;
9823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].sharedEdge[2] = false;
9833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].colors[0] = scene.lines[lineNdx].colors[0];
9853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].colors[1] = scene.lines[lineNdx].colors[1];
9863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[lineNdx*2 + 1].colors[2] = scene.lines[lineNdx].colors[1];
9873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return verifyTriangleGroupInterpolationWithInterpolator(surface, triangleScene, args, log, MultisampleLineInterpolator(scene));
9903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9923c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool verifyMultisamplePointGroupRasterization (const tcu::Surface& surface, const PointSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
9933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Multisampled point == 2 triangles
9953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2		viewportSize	= tcu::Vec2((float)surface.getWidth(), (float)surface.getHeight());
9973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TriangleSceneSpec	triangleScene;
9983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	triangleScene.triangles.resize(2 * scene.points.size());
10003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int pointNdx = 0; pointNdx < (int)scene.points.size(); ++pointNdx)
10013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Transform to screen space, add pixel offsets, convert back to normalized device space, and test as triangles
10033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2	pointNormalizedDeviceSpace			= tcu::Vec2(scene.points[pointNdx].position.x() / scene.points[pointNdx].position.w(), scene.points[pointNdx].position.y() / scene.points[pointNdx].position.w());
10043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2	pointScreenSpace					= (pointNormalizedDeviceSpace + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize;
10053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float		offset								= scene.points[pointNdx].pointSize * 0.5f;
10063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::Vec2	lineQuadNormalizedDeviceSpace[4]	=
10073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(pointScreenSpace + tcu::Vec2(-offset, -offset))/ viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
10093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(pointScreenSpace + tcu::Vec2(-offset,  offset))/ viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
10103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(pointScreenSpace + tcu::Vec2( offset,  offset))/ viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
10113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(pointScreenSpace + tcu::Vec2( offset, -offset))/ viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
10123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
10133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[pointNdx*2 + 0].positions[0] = tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);	triangleScene.triangles[pointNdx*2 + 0].sharedEdge[0] = false;
10153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[pointNdx*2 + 0].positions[1] = tcu::Vec4(lineQuadNormalizedDeviceSpace[1].x(), lineQuadNormalizedDeviceSpace[1].y(), 0.0f, 1.0f);	triangleScene.triangles[pointNdx*2 + 0].sharedEdge[1] = false;
10163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[pointNdx*2 + 0].positions[2] = tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);	triangleScene.triangles[pointNdx*2 + 0].sharedEdge[2] = true;
10173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[pointNdx*2 + 1].positions[0] = tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);	triangleScene.triangles[pointNdx*2 + 1].sharedEdge[0] = true;
10193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[pointNdx*2 + 1].positions[1] = tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);	triangleScene.triangles[pointNdx*2 + 1].sharedEdge[1] = false;
10203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		triangleScene.triangles[pointNdx*2 + 1].positions[2] = tcu::Vec4(lineQuadNormalizedDeviceSpace[3].x(), lineQuadNormalizedDeviceSpace[3].y(), 0.0f, 1.0f);	triangleScene.triangles[pointNdx*2 + 1].sharedEdge[2] = false;
10213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return verifyTriangleGroupRasterization(surface, triangleScene, args, log);
10243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10262306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyryvoid genScreenSpaceLines (std::vector<tcu::Vec4>& screenspaceLines, const std::vector<LineSceneSpec::SceneLine>& lines, const tcu::IVec2& viewportSize)
10272306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
10282306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(screenspaceLines.size() == lines.size());
10292306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
10302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	for (int lineNdx = 0; lineNdx < (int)lines.size(); ++lineNdx)
10312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
10322306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::Vec2 lineNormalizedDeviceSpace[2] =
10332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
10342306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			tcu::Vec2(lines[lineNdx].positions[0].x() / lines[lineNdx].positions[0].w(), lines[lineNdx].positions[0].y() / lines[lineNdx].positions[0].w()),
10352306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			tcu::Vec2(lines[lineNdx].positions[1].x() / lines[lineNdx].positions[1].w(), lines[lineNdx].positions[1].y() / lines[lineNdx].positions[1].w()),
10362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		};
10372306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::Vec4 lineScreenSpace[2] =
10382306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
10392306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			tcu::Vec4((lineNormalizedDeviceSpace[0].x() + 1.0f) * 0.5f * (float)viewportSize.x(), (lineNormalizedDeviceSpace[0].y() + 1.0f) * 0.5f * (float)viewportSize.y(), 0.0f, 1.0f),
10402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			tcu::Vec4((lineNormalizedDeviceSpace[1].x() + 1.0f) * 0.5f * (float)viewportSize.x(), (lineNormalizedDeviceSpace[1].y() + 1.0f) * 0.5f * (float)viewportSize.y(), 0.0f, 1.0f),
10412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		};
10422306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
10432306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		screenspaceLines[lineNdx] = tcu::Vec4(lineScreenSpace[0].x(), lineScreenSpace[0].y(), lineScreenSpace[1].x(), lineScreenSpace[1].y());
10442306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
10452306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
10462306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
10473c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool verifySinglesampleLineGroupRasterization (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
10483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(deFloatFrac(scene.lineWidth) != 0.5f); // rounding direction is not defined, disallow undefined cases
10503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(scene.lines.size() < 255); // indices are stored as unsigned 8-bit ints
10513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10522306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	bool					allOK				= true;
10532306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	bool					overdrawInReference	= false;
10542306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int						referenceFragments	= 0;
10552306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int						resultFragments		= 0;
10562306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int						lineWidth			= deFloorFloatToInt32(scene.lineWidth + 0.5f);
10572306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	bool					imageShown			= false;
10582306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	std::vector<bool>		lineIsXMajor		(scene.lines.size());
10592306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	std::vector<tcu::Vec4>	screenspaceLines(scene.lines.size());
10603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Reference renderer produces correct fragments using the diamond-rule. Make 2D int array, each cell contains the highest index (first index = 1) of the overlapping lines or 0 if no line intersects the pixel
10623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::TextureLevel referenceLineMap(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT8), surface.getWidth(), surface.getHeight());
10633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::clear(referenceLineMap.getAccess(), tcu::IVec4(0, 0, 0, 0));
10643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10652306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	genScreenSpaceLines(screenspaceLines, scene.lines, tcu::IVec2(surface.getWidth(), surface.getHeight()));
10662306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
10673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
10683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		rr::SingleSampleLineRasterizer rasterizer(tcu::IVec4(0, 0, surface.getWidth(), surface.getHeight()));
10702306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		rasterizer.init(tcu::Vec4(screenspaceLines[lineNdx][0],
10712306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry								  screenspaceLines[lineNdx][1],
10722306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry								  0.0f,
10732306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry								  1.0f),
10742306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						tcu::Vec4(screenspaceLines[lineNdx][2],
10752306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry								  screenspaceLines[lineNdx][3],
10762306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry								  0.0f,
10772306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry								  1.0f),
10782306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						scene.lineWidth);
10793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// calculate majority of later use
10812306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		lineIsXMajor[lineNdx] = isPackedSSLineXMajor(screenspaceLines[lineNdx]);
10823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (;;)
10843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			maxPackets			= 32;
10863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int					numRasterized		= 0;
10873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			rr::FragmentPacket	packets[maxPackets];
10883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			rasterizer.rasterize(packets, DE_NULL, maxPackets, numRasterized);
10903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int packetNdx = 0; packetNdx < numRasterized; ++packetNdx)
10923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
10933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
10943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
10953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if ((deUint32)packets[packetNdx].coverage & (1 << fragNdx))
10963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
10973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const tcu::IVec2 fragPos = packets[packetNdx].position + tcu::IVec2(fragNdx%2, fragNdx/2);
10983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						// Check for overdraw
11003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						if (!overdrawInReference)
11013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							overdrawInReference = referenceLineMap.getAccess().getPixelInt(fragPos.x(), fragPos.y()).x() != 0;
11023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						// Output pixel
11043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						referenceLineMap.getAccess().setPixel(tcu::IVec4(lineNdx + 1, 0, 0, 0), fragPos.x(), fragPos.y());
11053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
11063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
11073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
11083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (numRasterized != maxPackets)
11103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				break;
11113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
11123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Requirement 1: The coordinates of a fragment produced by the algorithm may not deviate by more than one unit
11153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Surface	errorMask			(surface.getWidth(), surface.getHeight());
11173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool			missingFragments	= false;
11183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::clear(errorMask.getAccess(), tcu::IVec4(0, 255, 0, 255));
11203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Searching for deviating fragments." << tcu::TestLog::EndMessage;
11223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 0; y < referenceLineMap.getHeight(); ++y)
11243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 0; x < referenceLineMap.getWidth(); ++x)
11253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
11263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const bool reference	= referenceLineMap.getAccess().getPixelInt(x, y).x() != 0;
11273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const bool result		= compareColors(surface.getPixel(x, y), tcu::RGBA::white, args.redBits, args.greenBits, args.blueBits);
11283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (reference)
11303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				++referenceFragments;
11313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (result)
11323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				++resultFragments;
11333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (reference == result)
11353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				continue;
11363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Reference fragment here, matching result fragment must be nearby
11383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (reference && !result)
11393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
11403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				bool foundFragment = false;
11413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (x == 0 || y == 0 || x == referenceLineMap.getWidth() - 1 || y == referenceLineMap.getHeight() -1)
11433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
11443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// image boundary, missing fragment could be over the image edge
11453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					foundFragment = true;
11463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
11473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// find nearby fragment
11493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int dy = -1; dy < 2 && !foundFragment; ++dy)
11503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int dx = -1; dx < 2 && !foundFragment; ++dx)
11513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
11523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (compareColors(surface.getPixel(x+dx, y+dy), tcu::RGBA::white, args.redBits, args.greenBits, args.blueBits))
11533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						foundFragment = true;
11543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
11553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!foundFragment)
11573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
11583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					missingFragments = true;
11593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					errorMask.setPixel(x, y, tcu::RGBA::red);
11603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
11613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
11623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
11633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (missingFragments)
11653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
11663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << tcu::TestLog::Message << "Invalid deviation(s) found." << tcu::TestLog::EndMessage;
11673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
11683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< tcu::TestLog::Image("Result", "Result",			surface)
11693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
11703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< tcu::TestLog::EndImageSet;
11713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			imageShown = true;
11733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			allOK = false;
11743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
11753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
11763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
11773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << tcu::TestLog::Message << "No invalid deviations found." << tcu::TestLog::EndMessage;
11783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
11793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Requirement 2: The total number of fragments produced by the algorithm may differ from
11823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//                that produced by the diamond-exit rule by no more than one.
11833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Check is not valid if the primitives intersect or otherwise share same fragments
11853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!overdrawInReference)
11863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
11873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int allowedDeviation = (int)scene.lines.size() * lineWidth; // one pixel per primitive in the major direction
11883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << tcu::TestLog::Message << "Verifying fragment counts:\n"
11903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< "\tDiamond-exit rule: " << referenceFragments << " fragments.\n"
11913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< "\tResult image: " << resultFragments << " fragments.\n"
11923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< "\tAllowing deviation of " << allowedDeviation << " fragments.\n"
11933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< tcu::TestLog::EndMessage;
11943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (deAbs32(referenceFragments - resultFragments) > allowedDeviation)
11963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
11973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				tcu::Surface reference(surface.getWidth(), surface.getHeight());
11983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// show a helpful reference image
12003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				tcu::clear(reference.getAccess(), tcu::IVec4(0, 0, 0, 255));
12013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int y = 0; y < surface.getHeight(); ++y)
12023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int x = 0; x < surface.getWidth(); ++x)
12033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (referenceLineMap.getAccess().getPixelInt(x, y).x())
12043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						reference.setPixel(x, y, tcu::RGBA::white);
12053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				log << tcu::TestLog::Message << "Invalid fragment count in result image." << tcu::TestLog::EndMessage;
12073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
12083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< tcu::TestLog::Image("Reference", "Reference",	reference)
12093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< tcu::TestLog::Image("Result", "Result",			surface)
12103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< tcu::TestLog::EndImageSet;
12113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				allOK = false;
12133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				imageShown = true;
12143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
12153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else
12163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
12173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				log << tcu::TestLog::Message << "Fragment count is valid." << tcu::TestLog::EndMessage;
12183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
12193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
12213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << tcu::TestLog::Message << "Overdraw in scene. Fragment count cannot be verified. Skipping fragment count checks." << tcu::TestLog::EndMessage;
12233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
12253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Requirement 3: Line width must be constant
12273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
12283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool invalidWidthFound = false;
12293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Verifying line widths of the x-major lines." << tcu::TestLog::EndMessage;
12313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = 1; y < referenceLineMap.getHeight() - 1; ++y)
12323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			bool	fullyVisibleLine		= false;
12343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			bool	previousPixelUndefined	= false;
12353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		currentLine				= 0;
12363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		currentWidth			= 1;
12373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int x = 1; x < referenceLineMap.getWidth() - 1; ++x)
12393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
12403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const bool	result	= compareColors(surface.getPixel(x, y), tcu::RGBA::white, args.redBits, args.greenBits, args.blueBits);
12413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				int			lineID	= 0;
12423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Which line does this fragment belong to?
12443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (result)
12463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
12473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					bool multipleNearbyLines = false;
12483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int dy = -1; dy < 2; ++dy)
12503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int dx = -1; dx < 2; ++dx)
12513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
12523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const int nearbyID = referenceLineMap.getAccess().getPixelInt(x+dx, y+dy).x();
12533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						if (nearbyID)
12543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						{
12553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							if (lineID && lineID != nearbyID)
12563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								multipleNearbyLines = true;
12573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							lineID = nearbyID;
12583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						}
12593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
12603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (multipleNearbyLines)
12623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
12633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						// Another line is too close, don't try to calculate width here
12643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						previousPixelUndefined = true;
12653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						continue;
12663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
12673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
12683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Only line with id of lineID is nearby
12703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (previousPixelUndefined)
12723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
12733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// The line might have been overdrawn or not
12743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentLine = lineID;
12753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentWidth = 1;
12763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					fullyVisibleLine = false;
12773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					previousPixelUndefined = false;
12783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
12793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (lineID == currentLine)
12803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
12813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Current line continues
12823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					++currentWidth;
12833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
12843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (lineID > currentLine)
12853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
12863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Another line was drawn over or the line ends
12873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentLine = lineID;
12883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentWidth = 1;
12893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					fullyVisibleLine = true;
12903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
12913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
12923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
12933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// The line ends
12943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (fullyVisibleLine && !lineIsXMajor[currentLine-1])
12953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
12963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						// check width
12973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						if (currentWidth != lineWidth)
12983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						{
12993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							log << tcu::TestLog::Message << "\tInvalid line width at (" << x - currentWidth << ", " << y << ") - (" << x - 1 << ", " << y << "). Detected width of " << currentWidth << ", expected " << lineWidth << tcu::TestLog::EndMessage;
13003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							invalidWidthFound = true;
13013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						}
13023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
13033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentLine = lineID;
13053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentWidth = 1;
13063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					fullyVisibleLine = false;
13073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
13083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
13093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
13103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Verifying line widths of the y-major lines." << tcu::TestLog::EndMessage;
13123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = 1; x < referenceLineMap.getWidth() - 1; ++x)
13133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
13143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			bool	fullyVisibleLine		= false;
13153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			bool	previousPixelUndefined	= false;
13163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		currentLine				= 0;
13173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		currentWidth			= 1;
13183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int y = 1; y < referenceLineMap.getHeight() - 1; ++y)
13203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
13213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const bool	result	= compareColors(surface.getPixel(x, y), tcu::RGBA::white, args.redBits, args.greenBits, args.blueBits);
13223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				int			lineID	= 0;
13233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Which line does this fragment belong to?
13253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (result)
13273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
13283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					bool multipleNearbyLines = false;
13293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int dy = -1; dy < 2; ++dy)
13313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int dx = -1; dx < 2; ++dx)
13323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
13333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const int nearbyID = referenceLineMap.getAccess().getPixelInt(x+dx, y+dy).x();
13343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						if (nearbyID)
13353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						{
13363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							if (lineID && lineID != nearbyID)
13373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								multipleNearbyLines = true;
13383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							lineID = nearbyID;
13393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						}
13403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
13413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (multipleNearbyLines)
13433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
13443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						// Another line is too close, don't try to calculate width here
13453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						previousPixelUndefined = true;
13463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						continue;
13473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
13483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
13493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Only line with id of lineID is nearby
13513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (previousPixelUndefined)
13533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
13543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// The line might have been overdrawn or not
13553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentLine = lineID;
13563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentWidth = 1;
13573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					fullyVisibleLine = false;
13583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					previousPixelUndefined = false;
13593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
13603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (lineID == currentLine)
13613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
13623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Current line continues
13633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					++currentWidth;
13643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
13653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (lineID > currentLine)
13663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
13673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Another line was drawn over or the line ends
13683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentLine = lineID;
13693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentWidth = 1;
13703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					fullyVisibleLine = true;
13713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
13723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
13733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
13743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// The line ends
13753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (fullyVisibleLine && lineIsXMajor[currentLine-1])
13763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
13773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						// check width
13783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						if (currentWidth != lineWidth)
13793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						{
13803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							log << tcu::TestLog::Message << "\tInvalid line width at (" << x << ", " << y - currentWidth << ") - (" << x  << ", " << y - 1 << "). Detected width of " << currentWidth << ", expected " << lineWidth << tcu::TestLog::EndMessage;
13813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							invalidWidthFound = true;
13823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						}
13833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
13843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentLine = lineID;
13863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					currentWidth = 1;
13873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					fullyVisibleLine = false;
13883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
13893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
13903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
13913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (invalidWidthFound)
13933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
13943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << tcu::TestLog::Message << "Invalid line width found, image is not valid." << tcu::TestLog::EndMessage;
13953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			allOK = false;
13963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
13973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
13983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
13993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << tcu::TestLog::Message << "Line widths are valid." << tcu::TestLog::EndMessage;
14003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
14013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
14023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//\todo [2013-10-24 jarkko].
14043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//Requirement 4. If two line segments share a common endpoint, and both segments are either
14053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//x-major (both left-to-right or both right-to-left) or y-major (both bottom-totop
14063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//or both top-to-bottom), then rasterizing both segments may not produce
14073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//duplicate fragments, nor may any fragments be omitted so as to interrupt
14083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//continuity of the connected segments.
14093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!imageShown)
14113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
14123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
14133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("Result", "Result", surface)
14143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::EndImageSet;
14153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
14163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return allOK;
14183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
14193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14202306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrystruct SingleSampleNarrowLineCandidate
14213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
14223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int			lineNdx;
14233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::IVec3	colorMin;
14243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::IVec3	colorMax;
14253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vec3	colorMinF;
14263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vec3	colorMaxF;
14273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vec3	valueRangeMin;
14283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vec3	valueRangeMax;
14293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
14303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyryvoid setMaskMapCoverageBitForLine (int bitNdx, const tcu::Vec2& screenSpaceP0, const tcu::Vec2& screenSpaceP1, float lineWidth, tcu::PixelBufferAccess maskMap)
14323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
14332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	enum
14342306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
14352306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		MAX_PACKETS = 32,
14362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	};
14373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14382306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	rr::SingleSampleLineRasterizer	rasterizer				(tcu::IVec4(0, 0, maskMap.getWidth(), maskMap.getHeight()));
14392306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int								numRasterized			= MAX_PACKETS;
14402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	rr::FragmentPacket				packets[MAX_PACKETS];
14413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14422306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	rasterizer.init(tcu::Vec4(screenSpaceP0.x(), screenSpaceP0.y(), 0.0f, 1.0f),
14432306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					tcu::Vec4(screenSpaceP1.x(), screenSpaceP1.y(), 0.0f, 1.0f),
14442306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					lineWidth);
14453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14462306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	while (numRasterized == MAX_PACKETS)
14472306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
14482306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		rasterizer.rasterize(packets, DE_NULL, MAX_PACKETS, numRasterized);
14493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14502306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		for (int packetNdx = 0; packetNdx < numRasterized; ++packetNdx)
14512306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
14522306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
14532306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			{
14542306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				if ((deUint32)packets[packetNdx].coverage & (1 << fragNdx))
14552306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				{
14562306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const tcu::IVec2	fragPos			= packets[packetNdx].position + tcu::IVec2(fragNdx%2, fragNdx/2);
14573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14582306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					DE_ASSERT(deInBounds32(fragPos.x(), 0, maskMap.getWidth()));
14592306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					DE_ASSERT(deInBounds32(fragPos.y(), 0, maskMap.getHeight()));
14603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14612306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const int			previousMask	= maskMap.getPixelInt(fragPos.x(), fragPos.y()).x();
14622306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const int			newMask			= (previousMask) | (1UL << bitNdx);
14632306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
14642306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					maskMap.setPixel(tcu::IVec4(newMask, 0, 0, 0), fragPos.x(), fragPos.y());
14652306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				}
14662306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			}
14672306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
14682306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
14692306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
14702306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
14712306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyryvoid setMaskMapCoverageBitForLines (const std::vector<tcu::Vec4>& screenspaceLines, float lineWidth, tcu::PixelBufferAccess maskMap)
14722306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
14732306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	for (int lineNdx = 0; lineNdx < (int)screenspaceLines.size(); ++lineNdx)
14743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
14752306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::Vec2 pa = screenspaceLines[lineNdx].swizzle(0, 1);
14762306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::Vec2 pb = screenspaceLines[lineNdx].swizzle(2, 3);
14773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14782306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		setMaskMapCoverageBitForLine(lineNdx, pa, pb, lineWidth, maskMap);
14792306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
14802306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
14813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14822306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry// verify line interpolation assuming line pixels are interpolated independently depending only on screen space location
14832306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrybool verifyLineGroupPixelIndependentInterpolation (const tcu::Surface&				surface,
14842306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry												   const LineSceneSpec&				scene,
14852306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry												   const RasterizationArguments&	args,
14862306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry												   tcu::TestLog&					log,
14872306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry												   LineInterpolationMethod			interpolationMethod)
14882306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
14892306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(scene.lines.size() < 8); // coverage indices are stored as bitmask in a unsigned 8-bit ints
14902306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(interpolationMethod == LINEINTERPOLATION_STRICTLY_CORRECT || interpolationMethod == LINEINTERPOLATION_PROJECTED);
14913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14922306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::RGBA			invalidPixelColor	= tcu::RGBA(255, 0, 0, 255);
14932306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::IVec2		viewportSize		= tcu::IVec2(surface.getWidth(), surface.getHeight());
14942306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int				errorFloodThreshold	= 4;
14952306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int						errorCount			= 0;
14962306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	tcu::Surface			errorMask			(surface.getWidth(), surface.getHeight());
14972306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int						invalidPixels		= 0;
14982306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	std::vector<tcu::Vec4>	screenspaceLines	(scene.lines.size()); //!< packed (x0, y0, x1, y1)
14993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15002306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// Reference renderer produces correct fragments using the diamond-exit-rule. Make 2D int array, store line coverage as a 8-bit bitfield
15012306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// The map is used to find lines with potential coverage to a given pixel
15022306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	tcu::TextureLevel		referenceLineMap	(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT8), surface.getWidth(), surface.getHeight());
15033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15042306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	tcu::clear(referenceLineMap.getAccess(), tcu::IVec4(0, 0, 0, 0));
15052306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
15063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15072306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// log format
15083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15092306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	log << tcu::TestLog::Message << "Verifying rasterization result. Native format is RGB" << args.redBits << args.greenBits << args.blueBits << tcu::TestLog::EndMessage;
15102306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	if (args.redBits > 8 || args.greenBits > 8 || args.blueBits > 8)
15112306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		log << tcu::TestLog::Message << "Warning! More than 8 bits in a color channel, this may produce false negatives." << tcu::TestLog::EndMessage;
15122306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
15132306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// prepare lookup map
15142306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
15152306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	genScreenSpaceLines(screenspaceLines, scene.lines, viewportSize);
15162306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	setMaskMapCoverageBitForLines(screenspaceLines, scene.lineWidth, referenceLineMap.getAccess());
15173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Find all possible lines with coverage, check pixel color matches one of them
15193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int y = 1; y < surface.getHeight() - 1; ++y)
15213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int x = 1; x < surface.getWidth()  - 1; ++x)
15223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
15233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::RGBA		color					= surface.getPixel(x, y);
15243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::IVec3	pixelNativeColor		= convertRGB8ToNativeFormat(color, args);	// Convert pixel color from rgba8 to the real pixel format. Usually rgba8 or 565
15253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int					lineCoverageSet			= 0;										// !< lines that may cover this fragment
15263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int					lineSurroundingCoverage = 0xFFFF;									// !< lines that will cover this fragment
15273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool				matchFound				= false;
15283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::IVec3	formatLimit				((1 << args.redBits) - 1, (1 << args.greenBits) - 1, (1 << args.blueBits) - 1);
15293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		std::vector<SingleSampleNarrowLineCandidate> candidates;
15313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Find lines with possible coverage
15333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int dy = -1; dy < 2; ++dy)
15353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int dx = -1; dx < 2; ++dx)
15363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
15373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int coverage = referenceLineMap.getAccess().getPixelInt(x+dx, y+dy).x();
15383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineCoverageSet			|= coverage;
15403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			lineSurroundingCoverage	&= coverage;
15413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
15423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// background color is possible?
15443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (lineSurroundingCoverage == 0 && compareColors(color, tcu::RGBA::black, args.redBits, args.greenBits, args.blueBits))
15453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			continue;
15463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Check those lines
15483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
15503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
15513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (((lineCoverageSet >> lineNdx) & 0x01) != 0)
15523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
15532306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const float						wa				= scene.lines[lineNdx].positions[0].w();
15542306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const float						wb				= scene.lines[lineNdx].positions[1].w();
15552306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec2					pa				= screenspaceLines[lineNdx].swizzle(0, 1);
15562306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec2					pb				= screenspaceLines[lineNdx].swizzle(2, 3);
15572306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
15582306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const LineInterpolationRange	range			= (interpolationMethod == LINEINTERPOLATION_STRICTLY_CORRECT)
15592306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	? (calcSingleSampleLineInterpolationRange(pa, wa, pb, wb, tcu::IVec2(x, y), args.subpixelBits))
15602306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	: (calcSingleSampleLineInterpolationRangeAxisProjected(pa, wa, pb, wb, tcu::IVec2(x, y), args.subpixelBits));
15612306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
15622306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec4					valueMin		= de::clamp(range.min.x(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[0] + de::clamp(range.min.y(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[1];
15632306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec4					valueMax		= de::clamp(range.max.x(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[0] + de::clamp(range.max.y(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[1];
15642306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
15652306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec3					colorMinF		(de::clamp(valueMin.x() * formatLimit.x(), 0.0f, (float)formatLimit.x()),
15662306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																 de::clamp(valueMin.y() * formatLimit.y(), 0.0f, (float)formatLimit.y()),
15672306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																 de::clamp(valueMin.z() * formatLimit.z(), 0.0f, (float)formatLimit.z()));
15682306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec3					colorMaxF		(de::clamp(valueMax.x() * formatLimit.x(), 0.0f, (float)formatLimit.x()),
15692306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																 de::clamp(valueMax.y() * formatLimit.y(), 0.0f, (float)formatLimit.y()),
15702306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																 de::clamp(valueMax.z() * formatLimit.z(), 0.0f, (float)formatLimit.z()));
15712306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::IVec3				colorMin		((int)deFloatFloor(colorMinF.x()),
15722306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																 (int)deFloatFloor(colorMinF.y()),
15732306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																 (int)deFloatFloor(colorMinF.z()));
15742306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::IVec3				colorMax		((int)deFloatCeil (colorMaxF.x()),
15752306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																 (int)deFloatCeil (colorMaxF.y()),
15762306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																 (int)deFloatCeil (colorMaxF.z()));
15773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Verify validity
15793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (pixelNativeColor.x() < colorMin.x() ||
15803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					pixelNativeColor.y() < colorMin.y() ||
15813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					pixelNativeColor.z() < colorMin.z() ||
15823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					pixelNativeColor.x() > colorMax.x() ||
15833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					pixelNativeColor.y() > colorMax.y() ||
15843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					pixelNativeColor.z() > colorMax.z())
15853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
15863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (errorCount < errorFloodThreshold)
15873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
15883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						// Store candidate information for logging
15892306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						SingleSampleNarrowLineCandidate candidate;
15903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						candidate.lineNdx		= lineNdx;
15923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						candidate.colorMin		= colorMin;
15933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						candidate.colorMax		= colorMax;
15943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						candidate.colorMinF		= colorMinF;
15953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						candidate.colorMaxF		= colorMaxF;
15963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						candidate.valueRangeMin	= valueMin.swizzle(0, 1, 2);
15973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						candidate.valueRangeMax	= valueMax.swizzle(0, 1, 2);
15983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						candidates.push_back(candidate);
16003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
16013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
16023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
16033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
16043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					matchFound = true;
16053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					break;
16063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
16073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
16083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
16093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (matchFound)
16113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			continue;
16123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// invalid fragment
16143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		++invalidPixels;
16153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		errorMask.setPixel(x, y, invalidPixelColor);
16163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		++errorCount;
16183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// don't fill the logs with too much data
16203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (errorCount < errorFloodThreshold)
16213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
16223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			log << tcu::TestLog::Message
16233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< "Found an invalid pixel at (" << x << "," << y << "), " << (int)candidates.size() << " candidate reference value(s) found:\n"
16243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< "\tPixel color:\t\t" << color << "\n"
16253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< "\tNative color:\t\t" << pixelNativeColor << "\n"
16263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				<< tcu::TestLog::EndMessage;
16273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int candidateNdx = 0; candidateNdx < (int)candidates.size(); ++candidateNdx)
16293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
16302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const SingleSampleNarrowLineCandidate& candidate = candidates[candidateNdx];
16313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				log << tcu::TestLog::Message << "\tCandidate (line " << candidate.lineNdx << "):\n"
16333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< "\t\tReference native color min: " << tcu::clamp(candidate.colorMin, tcu::IVec3(0,0,0), formatLimit) << "\n"
16343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< "\t\tReference native color max: " << tcu::clamp(candidate.colorMax, tcu::IVec3(0,0,0), formatLimit) << "\n"
16353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< "\t\tReference native float min: " << tcu::clamp(candidate.colorMinF, tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>()) << "\n"
16363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< "\t\tReference native float max: " << tcu::clamp(candidate.colorMaxF, tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>()) << "\n"
16373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< "\t\tFmin:\t" << tcu::clamp(candidate.valueRangeMin, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f)) << "\n"
16383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< "\t\tFmax:\t" << tcu::clamp(candidate.valueRangeMax, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f)) << "\n"
16393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					<< tcu::TestLog::EndMessage;
16403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
16413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
16423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
16433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// don't just hide failures
16453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (errorCount > errorFloodThreshold)
16463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Omitted " << (errorCount-errorFloodThreshold) << " pixel error description(s)." << tcu::TestLog::EndMessage;
16473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// report result
16493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (invalidPixels)
16503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
16513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << invalidPixels << " invalid pixel(s) found." << tcu::TestLog::EndMessage;
16523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
16533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("Result", "Result",			surface)
16543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
16553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::EndImageSet;
16563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return false;
16583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
16593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
16603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
16613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
16623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
16633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("Result", "Result", surface)
16643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::EndImageSet;
16653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
16673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
16683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
16693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16702306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrybool verifySinglesampleNarrowLineGroupInterpolation (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
16712306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
16722306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(scene.lineWidth == 1.0f);
16732306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	return verifyLineGroupPixelIndependentInterpolation(surface, scene, args, log, LINEINTERPOLATION_STRICTLY_CORRECT);
16742306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
16752306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
16762306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrybool verifyLineGroupInterpolationWithProjectedWeights (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
16772306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
16782306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	return verifyLineGroupPixelIndependentInterpolation(surface, scene, args, log, LINEINTERPOLATION_PROJECTED);
16792306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
16802306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
16812306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrystruct SingleSampleWideLineCandidate
16822306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
16832306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	struct InterpolationPointCandidate
16842306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
16852306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::IVec2	interpolationPoint;
16862306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::IVec3	colorMin;
16872306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::IVec3	colorMax;
16882306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::Vec3	colorMinF;
16892306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::Vec3	colorMaxF;
16902306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::Vec3	valueRangeMin;
16912306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		tcu::Vec3	valueRangeMax;
16922306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	};
16932306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
16942306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int							lineNdx;
16952306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int							numCandidates;
16962306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	InterpolationPointCandidate	interpolationCandidates[3];
16972306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry};
16982306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
16992306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry// return point on line at a given position on a given axis
17002306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrytcu::Vec2 getLineCoordAtAxisCoord (const tcu::Vec2& pa, const tcu::Vec2& pb, bool isXAxis, float axisCoord)
17012306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
17022306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int	fixedCoordNdx		= (isXAxis) ? (0) : (1);
17032306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int	varyingCoordNdx		= (isXAxis) ? (1) : (0);
17042306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17052306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float	fixedDifference		= pb[fixedCoordNdx] - pa[fixedCoordNdx];
17062306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float	varyingDifference	= pb[varyingCoordNdx] - pa[varyingCoordNdx];
17072306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17082306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(fixedDifference != 0.0f);
17092306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17102306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float	resultFixedCoord	= axisCoord;
17112306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const float	resultVaryingCoord	= pa[varyingCoordNdx] + (axisCoord - pa[fixedCoordNdx]) * (varyingDifference / fixedDifference);
17122306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17132306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	return (isXAxis) ? (tcu::Vec2(resultFixedCoord, resultVaryingCoord))
17142306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					 : (tcu::Vec2(resultVaryingCoord, resultFixedCoord));
17152306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
17162306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17172306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrybool isBlack (const tcu::RGBA& c)
17182306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
17192306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0;
17202306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
17212306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17222306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyrybool verifySinglesampleWideLineGroupInterpolation (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
17232306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry{
17242306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(deFloatFrac(scene.lineWidth) != 0.5f); // rounding direction is not defined, disallow undefined cases
17252306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	DE_ASSERT(scene.lines.size() < 8); // coverage indices are stored as bitmask in a unsigned 8-bit ints
17262306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17272306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	enum
17282306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
17292306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		FLAG_ROOT_NOT_SET = (1u << 16)
17302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	};
17312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17322306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::RGBA						invalidPixelColor	= tcu::RGBA(255, 0, 0, 255);
17332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const tcu::IVec2					viewportSize		= tcu::IVec2(surface.getWidth(), surface.getHeight());
17342306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	const int							errorFloodThreshold	= 4;
17352306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int									errorCount			= 0;
17362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	tcu::Surface						errorMask			(surface.getWidth(), surface.getHeight());
17372306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	int									invalidPixels		= 0;
17382306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	std::vector<tcu::Vec4>				effectiveLines		(scene.lines.size()); //!< packed (x0, y0, x1, y1)
17392306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	std::vector<bool>					lineIsXMajor		(scene.lines.size());
17402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// for each line, for every distinct major direction fragment, store root pixel location (along
17422306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// minor direction);
17432306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	std::vector<std::vector<deUint32> >	rootPixelLocation	(scene.lines.size()); //!< packed [16b - flags] [16b - coordinate]
17442306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17452306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// log format
17462306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17472306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	log << tcu::TestLog::Message << "Verifying rasterization result. Native format is RGB" << args.redBits << args.greenBits << args.blueBits << tcu::TestLog::EndMessage;
17482306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	if (args.redBits > 8 || args.greenBits > 8 || args.blueBits > 8)
17492306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		log << tcu::TestLog::Message << "Warning! More than 8 bits in a color channel, this may produce false negatives." << tcu::TestLog::EndMessage;
17502306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17512306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// Reference renderer produces correct fragments using the diamond-exit-rule. Make 2D int array, store line coverage as a 8-bit bitfield
17522306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// The map is used to find lines with potential coverage to a given pixel
17532306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	tcu::TextureLevel referenceLineMap(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT8), surface.getWidth(), surface.getHeight());
17542306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	tcu::clear(referenceLineMap.getAccess(), tcu::IVec4(0, 0, 0, 0));
17552306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17562306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
17572306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17582306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// calculate mask and effective line coordinates
17592306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
17602306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		std::vector<tcu::Vec4> screenspaceLines(scene.lines.size());
17612306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17622306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		genScreenSpaceLines(screenspaceLines, scene.lines, viewportSize);
17632306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		setMaskMapCoverageBitForLines(screenspaceLines, scene.lineWidth, referenceLineMap.getAccess());
17642306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17652306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
17662306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
17672306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const tcu::Vec2	lineScreenSpaceP0	= screenspaceLines[lineNdx].swizzle(0, 1);
17682306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const tcu::Vec2	lineScreenSpaceP1	= screenspaceLines[lineNdx].swizzle(2, 3);
17692306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const bool		isXMajor			= isPackedSSLineXMajor(screenspaceLines[lineNdx]);
17702306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17712306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			lineIsXMajor[lineNdx] = isXMajor;
17722306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17732306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			// wide line interpolations are calculated for a line moved in minor direction
17742306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			{
17752306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const float		offsetLength	= (scene.lineWidth - 1.0f) / 2.0f;
17762306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec2	offsetDirection	= (isXMajor) ? (tcu::Vec2(0.0f, -1.0f)) : (tcu::Vec2(-1.0f, 0.0f));
17772306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec2	offset			= offsetDirection * offsetLength;
17782306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17792306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				effectiveLines[lineNdx] = tcu::Vec4(lineScreenSpaceP0.x() + offset.x(),
17802306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry													lineScreenSpaceP0.y() + offset.y(),
17812306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry													lineScreenSpaceP1.x() + offset.x(),
17822306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry													lineScreenSpaceP1.y() + offset.y());
17832306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			}
17842306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
17852306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
17862306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
17872306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
17882306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
17892306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// Calculate root pixel lookup table for this line. Since the implementation's fragment
17902306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// major coordinate range might not be a subset of the correct line range (they are allowed
17912306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// to vary by one pixel), we must extend the domain to cover whole viewport along major
17922306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// dimension.
17932306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		//
17942306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// Expanding line strip to (effectively) infinite line might result in exit-diamnod set
17952306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// that is not a superset of the exit-diamond set of the line strip. In practice, this
17962306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// won't be an issue, since the allow-one-pixel-variation rule should tolerate this even
17972306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// if the original and extended line would resolve differently a diamond the line just
17982306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// touches (precision lost in expansion changes enter/exit status).
17992306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18002306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
18012306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const bool						isXMajor			= lineIsXMajor[lineNdx];
18022306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const int						majorSize			= (isXMajor) ? (surface.getWidth()) : (surface.getHeight());
18032306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			rr::LineExitDiamondGenerator	diamondGenerator;
18042306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			rr::LineExitDiamond				diamonds[32];
18052306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			int								numRasterized		= DE_LENGTH_OF_ARRAY(diamonds);
18062306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18072306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			// Expand to effectively infinite line (endpoints are just one pixel over viewport boundaries)
18082306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const tcu::Vec2					expandedP0		= getLineCoordAtAxisCoord(effectiveLines[lineNdx].swizzle(0, 1), effectiveLines[lineNdx].swizzle(2, 3), isXMajor, -1.0f);
18092306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const tcu::Vec2					expandedP1		= getLineCoordAtAxisCoord(effectiveLines[lineNdx].swizzle(0, 1), effectiveLines[lineNdx].swizzle(2, 3), isXMajor, (float)majorSize + 1.0f);
18102306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18112306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			diamondGenerator.init(tcu::Vec4(expandedP0.x(), expandedP0.y(), 0.0f, 1.0f),
18122306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry								  tcu::Vec4(expandedP1.x(), expandedP1.y(), 0.0f, 1.0f));
18132306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18142306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			rootPixelLocation[lineNdx].resize(majorSize, FLAG_ROOT_NOT_SET);
18152306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18162306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			while (numRasterized == DE_LENGTH_OF_ARRAY(diamonds))
18172306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			{
18182306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				diamondGenerator.rasterize(diamonds, DE_LENGTH_OF_ARRAY(diamonds), numRasterized);
18192306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18202306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				for (int packetNdx = 0; packetNdx < numRasterized; ++packetNdx)
18212306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				{
18222306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const tcu::IVec2	fragPos			= diamonds[packetNdx].position;
18232306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const int			majorPos		= (isXMajor) ? (fragPos.x()) : (fragPos.y());
18242306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const int			rootPos			= (isXMajor) ? (fragPos.y()) : (fragPos.x());
18252306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const deUint32		packed			= (deUint32)((deUint16)((deInt16)rootPos));
18262306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18272306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					// infinite line will generate some diamonds outside the viewport
18282306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					if (deInBounds32(majorPos, 0, majorSize))
18292306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					{
18302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						DE_ASSERT((rootPixelLocation[lineNdx][majorPos] & FLAG_ROOT_NOT_SET) != 0u);
18312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						rootPixelLocation[lineNdx][majorPos] = packed;
18322306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					}
18332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				}
18342306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			}
18352306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			// Filled whole lookup table
18372306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			for (int majorPos = 0; majorPos < majorSize; ++majorPos)
18382306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				DE_ASSERT((rootPixelLocation[lineNdx][majorPos] & FLAG_ROOT_NOT_SET) == 0u);
18392306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
18402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
18412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18422306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// Find all possible lines with coverage, check pixel color matches one of them
18432306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18442306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	for (int y = 1; y < surface.getHeight() - 1; ++y)
18452306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	for (int x = 1; x < surface.getWidth()  - 1; ++x)
18462306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
18472306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::RGBA		color					= surface.getPixel(x, y);
18482306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::IVec3	pixelNativeColor		= convertRGB8ToNativeFormat(color, args);	// Convert pixel color from rgba8 to the real pixel format. Usually rgba8 or 565
18492306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		int					lineCoverageSet			= 0;										// !< lines that may cover this fragment
18502306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		int					lineSurroundingCoverage = 0xFFFF;									// !< lines that will cover this fragment
18512306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		bool				matchFound				= false;
18522306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const tcu::IVec3	formatLimit				((1 << args.redBits) - 1, (1 << args.greenBits) - 1, (1 << args.blueBits) - 1);
18532306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18542306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		std::vector<SingleSampleWideLineCandidate> candidates;
18552306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18562306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// Find lines with possible coverage
18572306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18582306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		for (int dy = -1; dy < 2; ++dy)
18592306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		for (int dx = -1; dx < 2; ++dx)
18602306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
18612306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			const int coverage = referenceLineMap.getAccess().getPixelInt(x+dx, y+dy).x();
18622306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18632306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			lineCoverageSet			|= coverage;
18642306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			lineSurroundingCoverage	&= coverage;
18652306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
18662306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18672306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// background color is possible?
18682306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		if (lineSurroundingCoverage == 0 && compareColors(color, tcu::RGBA::black, args.redBits, args.greenBits, args.blueBits))
18692306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			continue;
18702306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18712306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// Check those lines
18722306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18732306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
18742306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
18752306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			if (((lineCoverageSet >> lineNdx) & 0x01) != 0)
18762306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			{
18772306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const float						wa				= scene.lines[lineNdx].positions[0].w();
18782306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const float						wb				= scene.lines[lineNdx].positions[1].w();
18792306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec2					pa				= effectiveLines[lineNdx].swizzle(0, 1);
18802306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::Vec2					pb				= effectiveLines[lineNdx].swizzle(2, 3);
18812306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18822306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				// \note Wide line fragments are generated by replicating the root fragment for each
18832306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				//       fragment column (row for y-major). Calculate interpolation at the root
18842306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				//       fragment.
18852306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const bool						isXMajor		= lineIsXMajor[lineNdx];
18862306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const int						majorPosition	= (isXMajor) ? (x) : (y);
18872306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const deUint32					minorInfoPacked	= rootPixelLocation[lineNdx][majorPosition];
18882306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const int						minorPosition	= (int)((deInt16)((deUint16)(minorInfoPacked & 0xFFFFu)));
18892306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::IVec2				idealRootPos	= (isXMajor) ? (tcu::IVec2(majorPosition, minorPosition)) : (tcu::IVec2(minorPosition, majorPosition));
18902306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const tcu::IVec2				minorDirection	= (isXMajor) ? (tcu::IVec2(0, 1)) : (tcu::IVec2(1, 0));
18912306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18922306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				SingleSampleWideLineCandidate	candidate;
18932306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18942306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				candidate.lineNdx		= lineNdx;
18952306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				candidate.numCandidates	= 0;
18962306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(candidate.interpolationCandidates) == 3);
18972306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
18982306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				// Interpolation happens at the root fragment, which is then replicated in minor
18992306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				// direction. Search for implementation's root position near accurate root.
19002306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				for (int minorOffset = -1; minorOffset < 2; ++minorOffset)
19012306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				{
19022306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const tcu::IVec2				rootPosition	= idealRootPos + minorOffset * minorDirection;
19032306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19042306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					// A fragment can be root fragment only if it exists
19052306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					// \note root fragment can "exist" outside viewport
19062306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					// \note no pixel format theshold since in this case allowing only black is more conservative
19072306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					if (deInBounds32(rootPosition.x(), 0, surface.getWidth()) &&
19082306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						deInBounds32(rootPosition.y(), 0, surface.getHeight()) &&
19092306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						isBlack(surface.getPixel(rootPosition.x(), rootPosition.y())))
19102306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					{
19112306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						continue;
19122306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					}
19132306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19142306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const LineInterpolationRange	range			= calcSingleSampleLineInterpolationRange(pa, wa, pb, wb, rootPosition, args.subpixelBits);
19152306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19162306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const tcu::Vec4					valueMin		= de::clamp(range.min.x(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[0] + de::clamp(range.min.y(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[1];
19172306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const tcu::Vec4					valueMax		= de::clamp(range.max.x(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[0] + de::clamp(range.max.y(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[1];
19182306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19192306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const tcu::Vec3					colorMinF		(de::clamp(valueMin.x() * formatLimit.x(), 0.0f, (float)formatLimit.x()),
19202306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	de::clamp(valueMin.y() * formatLimit.y(), 0.0f, (float)formatLimit.y()),
19212306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	de::clamp(valueMin.z() * formatLimit.z(), 0.0f, (float)formatLimit.z()));
19222306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const tcu::Vec3					colorMaxF		(de::clamp(valueMax.x() * formatLimit.x(), 0.0f, (float)formatLimit.x()),
19232306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	de::clamp(valueMax.y() * formatLimit.y(), 0.0f, (float)formatLimit.y()),
19242306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	de::clamp(valueMax.z() * formatLimit.z(), 0.0f, (float)formatLimit.z()));
19252306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const tcu::IVec3				colorMin		((int)deFloatFloor(colorMinF.x()),
19262306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	(int)deFloatFloor(colorMinF.y()),
19272306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	(int)deFloatFloor(colorMinF.z()));
19282306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const tcu::IVec3				colorMax		((int)deFloatCeil (colorMaxF.x()),
19292306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	(int)deFloatCeil (colorMaxF.y()),
19302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry																	(int)deFloatCeil (colorMaxF.z()));
19312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19322306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					// Verify validity
19332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					if (pixelNativeColor.x() < colorMin.x() ||
19342306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						pixelNativeColor.y() < colorMin.y() ||
19352306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						pixelNativeColor.z() < colorMin.z() ||
19362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						pixelNativeColor.x() > colorMax.x() ||
19372306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						pixelNativeColor.y() > colorMax.y() ||
19382306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						pixelNativeColor.z() > colorMax.z())
19392306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					{
19402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						if (errorCount < errorFloodThreshold)
19412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						{
19422306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							// Store candidate information for logging
19432306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							SingleSampleWideLineCandidate::InterpolationPointCandidate& interpolationCandidate = candidate.interpolationCandidates[candidate.numCandidates++];
19442306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							DE_ASSERT(candidate.numCandidates <= DE_LENGTH_OF_ARRAY(candidate.interpolationCandidates));
19452306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19462306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							interpolationCandidate.interpolationPoint	= rootPosition;
19472306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							interpolationCandidate.colorMin				= colorMin;
19482306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							interpolationCandidate.colorMax				= colorMax;
19492306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							interpolationCandidate.colorMinF			= colorMinF;
19502306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							interpolationCandidate.colorMaxF			= colorMaxF;
19512306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							interpolationCandidate.valueRangeMin		= valueMin.swizzle(0, 1, 2);
19522306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry							interpolationCandidate.valueRangeMax		= valueMax.swizzle(0, 1, 2);
19532306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						}
19542306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					}
19552306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					else
19562306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					{
19572306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						matchFound = true;
19582306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						break;
19592306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					}
19602306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				}
19612306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19622306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				if (!matchFound)
19632306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				{
19642306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					// store info for logging
19652306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					if (errorCount < errorFloodThreshold && candidate.numCandidates > 0)
19662306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						candidates.push_back(candidate);
19672306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				}
19682306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				else
19692306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				{
19702306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					// no need to check other lines
19712306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					break;
19722306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				}
19732306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			}
19742306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
19752306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19762306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		if (matchFound)
19772306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			continue;
19782306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19792306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// invalid fragment
19802306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		++invalidPixels;
19812306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		errorMask.setPixel(x, y, invalidPixelColor);
19822306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19832306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		++errorCount;
19842306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19852306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// don't fill the logs with too much data
19862306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		if (errorCount < errorFloodThreshold)
19872306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
19882306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			tcu::MessageBuilder msg(&log);
19892306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19902306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			msg	<< "Found an invalid pixel at (" << x << "," << y << "), " << (int)candidates.size() << " candidate reference value(s) found:\n"
19912306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				<< "\tPixel color:\t\t" << color << "\n"
19922306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				<< "\tNative color:\t\t" << pixelNativeColor << "\n";
19932306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19942306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			for (int lineCandidateNdx = 0; lineCandidateNdx < (int)candidates.size(); ++lineCandidateNdx)
19952306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			{
19962306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				const SingleSampleWideLineCandidate& candidate = candidates[lineCandidateNdx];
19972306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
19982306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				msg << "\tCandidate line (line " << candidate.lineNdx << "):\n";
19992306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
20002306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				for (int interpolationCandidateNdx = 0; interpolationCandidateNdx < candidate.numCandidates; ++interpolationCandidateNdx)
20012306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				{
20022306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					const SingleSampleWideLineCandidate::InterpolationPointCandidate& interpolationCandidate = candidate.interpolationCandidates[interpolationCandidateNdx];
20032306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
20042306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry					msg	<< "\t\tCandidate interpolation point (index " << interpolationCandidateNdx << "):\n"
20052306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						<< "\t\t\tRoot fragment position (non-replicated fragment): " << interpolationCandidate.interpolationPoint << ":\n"
20062306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						<< "\t\t\tReference native color min: " << tcu::clamp(interpolationCandidate.colorMin, tcu::IVec3(0,0,0), formatLimit) << "\n"
20072306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						<< "\t\t\tReference native color max: " << tcu::clamp(interpolationCandidate.colorMax, tcu::IVec3(0,0,0), formatLimit) << "\n"
20082306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						<< "\t\t\tReference native float min: " << tcu::clamp(interpolationCandidate.colorMinF, tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>()) << "\n"
20092306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						<< "\t\t\tReference native float max: " << tcu::clamp(interpolationCandidate.colorMaxF, tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>()) << "\n"
20102306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						<< "\t\t\tFmin:\t" << tcu::clamp(interpolationCandidate.valueRangeMin, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f)) << "\n"
20112306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry						<< "\t\t\tFmax:\t" << tcu::clamp(interpolationCandidate.valueRangeMax, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f)) << "\n";
20122306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				}
20132306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			}
20142306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
20152306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			msg << tcu::TestLog::EndMessage;
20162306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
20172306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
20182306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
20192306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// don't just hide failures
20202306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	if (errorCount > errorFloodThreshold)
20212306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		log << tcu::TestLog::Message << "Omitted " << (errorCount-errorFloodThreshold) << " pixel error description(s)." << tcu::TestLog::EndMessage;
20222306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
20232306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	// report result
20242306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	if (invalidPixels)
20252306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
20262306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		log << tcu::TestLog::Message << invalidPixels << " invalid pixel(s) found." << tcu::TestLog::EndMessage;
20272306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
20282306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			<< tcu::TestLog::Image("Result", "Result",			surface)
20292306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
20302306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			<< tcu::TestLog::EndImageSet;
20312306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
20322306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		return false;
20332306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
20342306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	else
20352306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
20362306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
20372306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
20382306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			<< tcu::TestLog::Image("Result", "Result", surface)
20392306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			<< tcu::TestLog::EndImageSet;
20402306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
20412306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		return true;
20422306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
20432306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry}
20442306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
20453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // anonymous
20463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20473c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCoverageType calculateTriangleCoverage (const tcu::Vec4& p0, const tcu::Vec4& p1, const tcu::Vec4& p2, const tcu::IVec2& pixel, const tcu::IVec2& viewportSize, int subpixelBits, bool multisample)
20483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
20493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	typedef tcu::Vector<deInt64, 2> I64Vec2;
20503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64		numSubPixels						= ((deUint64)1) << subpixelBits;
20523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64		pixelHitBoxSize						= (multisample) ? (numSubPixels) : (2+2);	//!< allow 4 central (2x2) for non-multisample pixels. Rounding may move edges 1 subpixel to any direction.
20533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool			order								= isTriangleClockwise(p0, p1, p2);			//!< clockwise / counter-clockwise
20543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec4&	orderedP0							= p0;										//!< vertices of a clockwise triangle
20553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec4&	orderedP1							= (order) ? (p1) : (p2);
20563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec4&	orderedP2							= (order) ? (p2) : (p1);
20573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2		triangleNormalizedDeviceSpace[3]	=
20583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
20593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vec2(orderedP0.x() / orderedP0.w(), orderedP0.y() / orderedP0.w()),
20603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vec2(orderedP1.x() / orderedP1.w(), orderedP1.y() / orderedP1.w()),
20613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::Vec2(orderedP2.x() / orderedP2.w(), orderedP2.y() / orderedP2.w()),
20623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
20633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vec2		triangleScreenSpace[3]				=
20643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
20653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		(triangleNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
20663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		(triangleNormalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
20673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		(triangleNormalizedDeviceSpace[2] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
20683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
20693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Broad bounding box - pixel check
20713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
20723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float minX = de::min(de::min(triangleScreenSpace[0].x(), triangleScreenSpace[1].x()), triangleScreenSpace[2].x());
20733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float minY = de::min(de::min(triangleScreenSpace[0].y(), triangleScreenSpace[1].y()), triangleScreenSpace[2].y());
20743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float maxX = de::max(de::max(triangleScreenSpace[0].x(), triangleScreenSpace[1].x()), triangleScreenSpace[2].x());
20753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float maxY = de::max(de::max(triangleScreenSpace[0].y(), triangleScreenSpace[1].y()), triangleScreenSpace[2].y());
20763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if ((float)pixel.x() > maxX + 1 ||
20783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(float)pixel.y() > maxY + 1 ||
20793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(float)pixel.x() < minX - 1 ||
20803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(float)pixel.y() < minY - 1)
20813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return COVERAGE_NONE;
20823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
20833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Broad triangle - pixel area intersection
20853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
20863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 pixelCenterPosition = I64Vec2(pixel.x(), pixel.y()) * I64Vec2(numSubPixels, numSubPixels) + I64Vec2(numSubPixels / 2, numSubPixels / 2);
20873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 triangleSubPixelSpaceRound[3] =
20883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
20893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(deRoundFloatToInt32(triangleScreenSpace[0].x()*numSubPixels), deRoundFloatToInt32(triangleScreenSpace[0].y()*numSubPixels)),
20903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(deRoundFloatToInt32(triangleScreenSpace[1].x()*numSubPixels), deRoundFloatToInt32(triangleScreenSpace[1].y()*numSubPixels)),
20913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(deRoundFloatToInt32(triangleScreenSpace[2].x()*numSubPixels), deRoundFloatToInt32(triangleScreenSpace[2].y()*numSubPixels)),
20923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
20933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Check (using cross product) if pixel center is
20953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// a) too far from any edge
20963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// b) fully inside all edges
20973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		bool insideAllEdges = true;
20983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int vtxNdx = 0; vtxNdx < 3; ++vtxNdx)
20993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
21003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		otherVtxNdx				= (vtxNdx + 1) % 3;
21013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deInt64	maxPixelDistanceSquared	= pixelHitBoxSize*pixelHitBoxSize; // Max distance from the pixel center from within the pixel is (sqrt(2) * boxWidth/2). Use 2x value for rounding tolerance
21023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const I64Vec2	edge					= triangleSubPixelSpaceRound[otherVtxNdx]	- triangleSubPixelSpaceRound[vtxNdx];
21033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const I64Vec2	v						= pixelCenterPosition						- triangleSubPixelSpaceRound[vtxNdx];
21043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deInt64	crossProduct			= (edge.x() * v.y() - edge.y() * v.x());
21053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// distance from edge: (edge x v) / |edge|
21073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			//     (edge x v) / |edge| > maxPixelDistance
21083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// ==> (edge x v)^2 / edge^2 > maxPixelDistance^2    | edge x v > 0
21093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// ==> (edge x v)^2 > maxPixelDistance^2 * edge^2
21103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (crossProduct < 0 && crossProduct*crossProduct > maxPixelDistanceSquared * tcu::lengthSquared(edge))
21113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return COVERAGE_NONE;
21123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (crossProduct < 0 || crossProduct*crossProduct < maxPixelDistanceSquared * tcu::lengthSquared(edge))
21133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				insideAllEdges = false;
21143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
21153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (insideAllEdges)
21173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return COVERAGE_FULL;
21183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
21193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Accurate intersection for edge pixels
21213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
21223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		//  In multisampling, the sample points can be anywhere in the pixel, and in single sampling only in the center.
21233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 pixelCorners[4] =
21243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
21253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2((pixel.x()+0) * numSubPixels, (pixel.y()+0) * numSubPixels),
21263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2((pixel.x()+1) * numSubPixels, (pixel.y()+0) * numSubPixels),
21273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2((pixel.x()+1) * numSubPixels, (pixel.y()+1) * numSubPixels),
21283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2((pixel.x()+0) * numSubPixels, (pixel.y()+1) * numSubPixels),
21293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
21303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 pixelCenterCorners[4] =
21313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
21323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(pixel.x() * numSubPixels + numSubPixels/2 + 0, pixel.y() * numSubPixels + numSubPixels/2 + 0),
21333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(pixel.x() * numSubPixels + numSubPixels/2 + 1, pixel.y() * numSubPixels + numSubPixels/2 + 0),
21343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(pixel.x() * numSubPixels + numSubPixels/2 + 1, pixel.y() * numSubPixels + numSubPixels/2 + 1),
21353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(pixel.x() * numSubPixels + numSubPixels/2 + 0, pixel.y() * numSubPixels + numSubPixels/2 + 1),
21363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
21373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// both rounding directions
21393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 triangleSubPixelSpaceFloor[3] =
21403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
21413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(deFloorFloatToInt32(triangleScreenSpace[0].x()*numSubPixels), deFloorFloatToInt32(triangleScreenSpace[0].y()*numSubPixels)),
21423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(deFloorFloatToInt32(triangleScreenSpace[1].x()*numSubPixels), deFloorFloatToInt32(triangleScreenSpace[1].y()*numSubPixels)),
21433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(deFloorFloatToInt32(triangleScreenSpace[2].x()*numSubPixels), deFloorFloatToInt32(triangleScreenSpace[2].y()*numSubPixels)),
21443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
21453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2 triangleSubPixelSpaceCeil[3] =
21463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
21473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(deCeilFloatToInt32(triangleScreenSpace[0].x()*numSubPixels), deCeilFloatToInt32(triangleScreenSpace[0].y()*numSubPixels)),
21483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(deCeilFloatToInt32(triangleScreenSpace[1].x()*numSubPixels), deCeilFloatToInt32(triangleScreenSpace[1].y()*numSubPixels)),
21493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			I64Vec2(deCeilFloatToInt32(triangleScreenSpace[2].x()*numSubPixels), deCeilFloatToInt32(triangleScreenSpace[2].y()*numSubPixels)),
21503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
21513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const I64Vec2* const corners = (multisample) ? (pixelCorners) : (pixelCenterCorners);
21523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Test if any edge (with any rounding) intersects the pixel (boundary). If it does => Partial. If not => fully inside or outside
21543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int edgeNdx = 0; edgeNdx < 3; ++edgeNdx)
21563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int startRounding = 0; startRounding < 4; ++startRounding)
21573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int endRounding = 0; endRounding < 4; ++endRounding)
21583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
21593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		nextEdgeNdx	= (edgeNdx+1) % 3;
21603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const I64Vec2	startPos	((startRounding&0x01)	? (triangleSubPixelSpaceFloor[edgeNdx].x())		: (triangleSubPixelSpaceCeil[edgeNdx].x()),		(startRounding&0x02)	? (triangleSubPixelSpaceFloor[edgeNdx].y())		: (triangleSubPixelSpaceCeil[edgeNdx].y()));
21613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const I64Vec2	endPos		((endRounding&0x01)		? (triangleSubPixelSpaceFloor[nextEdgeNdx].x())	: (triangleSubPixelSpaceCeil[nextEdgeNdx].x()),	(endRounding&0x02)		? (triangleSubPixelSpaceFloor[nextEdgeNdx].y())	: (triangleSubPixelSpaceCeil[nextEdgeNdx].y()));
21623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int pixelEdgeNdx = 0; pixelEdgeNdx < 4; ++pixelEdgeNdx)
21643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
21653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int pixelEdgeEnd = (pixelEdgeNdx + 1) % 4;
21663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (lineLineIntersect(startPos, endPos, corners[pixelEdgeNdx], corners[pixelEdgeEnd]))
21683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return COVERAGE_PARTIAL;
21693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
21703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
21713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// fully inside or outside
21733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int edgeNdx = 0; edgeNdx < 3; ++edgeNdx)
21743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
21753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		nextEdgeNdx		= (edgeNdx+1) % 3;
21763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const I64Vec2&	startPos		= triangleSubPixelSpaceFloor[edgeNdx];
21773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const I64Vec2&	endPos			= triangleSubPixelSpaceFloor[nextEdgeNdx];
21783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const I64Vec2	edge			= endPos - startPos;
21793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const I64Vec2	v				= corners[0] - endPos;
21803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deInt64	crossProduct	= (edge.x() * v.y() - edge.y() * v.x());
21813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// a corner of the pixel is outside => "fully inside" option is impossible
21833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (crossProduct < 0)
21843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return COVERAGE_NONE;
21853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
21863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return COVERAGE_FULL;
21883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
21893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
21903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21913c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool verifyTriangleGroupRasterization (const tcu::Surface& surface, const TriangleSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log, VerificationMode mode)
21923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(mode < VERIFICATIONMODE_LAST);
21943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::RGBA		backGroundColor				= tcu::RGBA(0, 0, 0, 255);
21963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::RGBA		triangleColor				= tcu::RGBA(255, 255, 255, 255);
21973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::RGBA		missingPixelColor			= tcu::RGBA(255, 0, 255, 255);
21983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::RGBA		unexpectedPixelColor		= tcu::RGBA(255, 0, 0, 255);
21993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::RGBA		partialPixelColor			= tcu::RGBA(255, 255, 0, 255);
22003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::RGBA		primitivePixelColor			= tcu::RGBA(30, 30, 30, 255);
22013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			weakVerificationThreshold	= 10;
22023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool			multisampled				= (args.numSamples != 0);
22033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::IVec2	viewportSize				= tcu::IVec2(surface.getWidth(), surface.getHeight());
22043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int					missingPixels				= 0;
22053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int					unexpectedPixels			= 0;
22063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int					subPixelBits				= args.subpixelBits;
22073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::TextureLevel	coverageMap					(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT8), surface.getWidth(), surface.getHeight());
22083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Surface		errorMask					(surface.getWidth(), surface.getHeight());
22093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// subpixel bits in in a valid range?
22113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (subPixelBits < 0)
22133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
22143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Invalid subpixel count (" << subPixelBits << "), assuming 0" << tcu::TestLog::EndMessage;
22153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		subPixelBits = 0;
22163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
22173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (subPixelBits > 16)
22183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
22193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// At high subpixel bit counts we might overflow. Checking at lower bit count is ok, but is less strict
22203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Subpixel count is greater than 16 (" << subPixelBits << "). Checking results using less strict 16 bit requirements. This may produce false positives." << tcu::TestLog::EndMessage;
22213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		subPixelBits = 16;
22223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
22233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// generate coverage map
22253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::clear(coverageMap.getAccess(), tcu::IVec4(COVERAGE_NONE, 0, 0, 0));
22273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int triNdx = 0; triNdx < (int)scene.triangles.size(); ++triNdx)
22293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
22303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::IVec4 aabb = getTriangleAABB(scene.triangles[triNdx], viewportSize);
22313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int y = de::max(0, aabb.y()); y <= de::min(aabb.w(), coverageMap.getHeight() - 1); ++y)
22333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int x = de::max(0, aabb.x()); x <= de::min(aabb.z(), coverageMap.getWidth() - 1); ++x)
22343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
22353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (coverageMap.getAccess().getPixelUint(x, y).x() == COVERAGE_FULL)
22363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				continue;
22373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const CoverageType coverage = calculateTriangleCoverage(scene.triangles[triNdx].positions[0],
22393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	scene.triangles[triNdx].positions[1],
22403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	scene.triangles[triNdx].positions[2],
22413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	tcu::IVec2(x, y),
22423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	viewportSize,
22433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	subPixelBits,
22443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry																	multisampled);
22453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (coverage == COVERAGE_FULL)
22473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
22483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				coverageMap.getAccess().setPixel(tcu::IVec4(COVERAGE_FULL, 0, 0, 0), x, y);
22493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
22503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else if (coverage == COVERAGE_PARTIAL)
22513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
22523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				CoverageType resultCoverage = COVERAGE_PARTIAL;
22533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Sharing an edge with another triangle?
22553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// There should always be such a triangle, but the pixel in the other triangle might be
22563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// on multiple edges, some of which are not shared. In these cases the coverage cannot be determined.
22573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Assume full coverage if the pixel is only on a shared edge in shared triangle too.
22583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (pixelOnlyOnASharedEdge(tcu::IVec2(x, y), scene.triangles[triNdx], viewportSize))
22593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
22603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					bool friendFound = false;
22613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int friendTriNdx = 0; friendTriNdx < (int)scene.triangles.size(); ++friendTriNdx)
22623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
22633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						if (friendTriNdx != triNdx && pixelOnlyOnASharedEdge(tcu::IVec2(x, y), scene.triangles[friendTriNdx], viewportSize))
22643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						{
22653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							friendFound = true;
22663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							break;
22673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						}
22683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
22693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (friendFound)
22713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						resultCoverage = COVERAGE_FULL;
22723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
22733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				coverageMap.getAccess().setPixel(tcu::IVec4(resultCoverage, 0, 0, 0), x, y);
22753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
22763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
22773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
22783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// check pixels
22803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
22823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int y = 0; y < surface.getHeight(); ++y)
22843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int x = 0; x < surface.getWidth(); ++x)
22853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
22863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const tcu::RGBA		color				= surface.getPixel(x, y);
22873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool			imageNoCoverage		= compareColors(color, backGroundColor, args.redBits, args.greenBits, args.blueBits);
22883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool			imageFullCoverage	= compareColors(color, triangleColor, args.redBits, args.greenBits, args.blueBits);
22893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CoverageType		referenceCoverage	= (CoverageType)coverageMap.getAccess().getPixelUint(x, y).x();
22903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		switch (referenceCoverage)
22923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
22933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			case COVERAGE_NONE:
22943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!imageNoCoverage)
22953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
22963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// coverage where there should not be
22973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					++unexpectedPixels;
22983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					errorMask.setPixel(x, y, unexpectedPixelColor);
22993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
23003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				break;
23013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			case COVERAGE_PARTIAL:
23033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// anything goes
23043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				errorMask.setPixel(x, y, partialPixelColor);
23053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				break;
23063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			case COVERAGE_FULL:
23083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!imageFullCoverage)
23093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
23103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// no coverage where there should be
23113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					++missingPixels;
23123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					errorMask.setPixel(x, y, missingPixelColor);
23133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
23143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
23153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
23163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					errorMask.setPixel(x, y, primitivePixelColor);
23173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
23183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				break;
23193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			default:
23213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				DE_ASSERT(false);
23223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
23233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
23243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Output results
23263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	log << tcu::TestLog::Message << "Verifying rasterization result." << tcu::TestLog::EndMessage;
23273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (((mode == VERIFICATIONMODE_STRICT) && (missingPixels + unexpectedPixels > 0)) ||
23293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		((mode == VERIFICATIONMODE_WEAK)   && (missingPixels + unexpectedPixels > weakVerificationThreshold)))
23303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
23313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "Invalid pixels found:\n\t"
23323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< missingPixels << " missing pixels. (Marked with purple)\n\t"
23333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< unexpectedPixels << " incorrectly filled pixels. (Marked with red)\n\t"
23343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "Unknown (subpixel on edge) pixels are marked with yellow."
23353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::EndMessage;
23363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
23373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("Result",	"Result",		surface)
23383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
23393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::EndImageSet;
23403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return false;
23423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
23433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
23443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
23453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
23463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
23473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::Image("Result", "Result", surface)
23483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< tcu::TestLog::EndImageSet;
23493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
23513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
23523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
23533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23543c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool verifyLineGroupRasterization (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
23553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
23563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool multisampled = args.numSamples != 0;
23573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (multisampled)
23593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return verifyMultisampleLineGroupRasterization(surface, scene, args, log);
23603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
23613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return verifySinglesampleLineGroupRasterization(surface, scene, args, log);
23623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
23633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23643c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool verifyPointGroupRasterization (const tcu::Surface& surface, const PointSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
23653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
23663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Splitting to triangles is a valid solution in multisampled cases and even in non-multisample cases too.
23673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return verifyMultisamplePointGroupRasterization(surface, scene, args, log);
23683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
23693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23703c827367444ee418f129b2c238299f49d3264554Jarkko Poyrybool verifyTriangleGroupInterpolation (const tcu::Surface& surface, const TriangleSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
23713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
23723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return verifyTriangleGroupInterpolationWithInterpolator(surface, scene, args, log, TriangleInterpolator(scene));
23733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
23743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23752306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko PöyryLineInterpolationMethod verifyLineGroupInterpolation (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log)
23763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
23773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool multisampled = args.numSamples != 0;
23783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
23793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (multisampled)
23802306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
23812306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		if (verifyMultisampleLineGroupInterpolation(surface, scene, args, log))
23822306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			return LINEINTERPOLATION_STRICTLY_CORRECT;
23832306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		return LINEINTERPOLATION_INCORRECT;
23842306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
23853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
23862306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	{
23872306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		const bool isNarrow = (scene.lineWidth == 1.0f);
23882306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
23892306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// accurate interpolation
23902306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		if (isNarrow)
23912306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
23922306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			if (verifySinglesampleNarrowLineGroupInterpolation(surface, scene, args, log))
23932306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				return LINEINTERPOLATION_STRICTLY_CORRECT;
23942306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
23952306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		else
23962306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		{
23972306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			if (verifySinglesampleWideLineGroupInterpolation(surface, scene, args, log))
23982306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry				return LINEINTERPOLATION_STRICTLY_CORRECT;
23992306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		}
24002306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
24012306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		// check with projected (inaccurate) interpolation
24022306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		log << tcu::TestLog::Message << "Accurate verification failed, checking with projected weights (inaccurate equation)." << tcu::TestLog::EndMessage;
24032306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		if (verifyLineGroupInterpolationWithProjectedWeights(surface, scene, args, log))
24042306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry			return LINEINTERPOLATION_PROJECTED;
24052306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry
24062306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry		return LINEINTERPOLATION_INCORRECT;
24072306a3bf8214ab2c51d8023ca1ccd979fb8d31bbJarkko Pöyry	}
24083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
24093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
24103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // StateQueryUtil
24113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // gls
24123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // deqp
2413