xref: /aosp_15_r20/external/deqp/framework/common/tcuRasterizationVerifier.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1*35238bceSAndroid Build Coastguard Worker /*-------------------------------------------------------------------------
2*35238bceSAndroid Build Coastguard Worker  * drawElements Quality Program Tester Core
3*35238bceSAndroid Build Coastguard Worker  * ----------------------------------------
4*35238bceSAndroid Build Coastguard Worker  *
5*35238bceSAndroid Build Coastguard Worker  * Copyright 2014 The Android Open Source Project
6*35238bceSAndroid Build Coastguard Worker  *
7*35238bceSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
8*35238bceSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
9*35238bceSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
10*35238bceSAndroid Build Coastguard Worker  *
11*35238bceSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
12*35238bceSAndroid Build Coastguard Worker  *
13*35238bceSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
14*35238bceSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
15*35238bceSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*35238bceSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
17*35238bceSAndroid Build Coastguard Worker  * limitations under the License.
18*35238bceSAndroid Build Coastguard Worker  *
19*35238bceSAndroid Build Coastguard Worker  *//*!
20*35238bceSAndroid Build Coastguard Worker  * \file
21*35238bceSAndroid Build Coastguard Worker  * \brief Rasterization verifier utils.
22*35238bceSAndroid Build Coastguard Worker  *//*--------------------------------------------------------------------*/
23*35238bceSAndroid Build Coastguard Worker 
24*35238bceSAndroid Build Coastguard Worker #include "tcuRasterizationVerifier.hpp"
25*35238bceSAndroid Build Coastguard Worker #include "tcuVector.hpp"
26*35238bceSAndroid Build Coastguard Worker #include "tcuSurface.hpp"
27*35238bceSAndroid Build Coastguard Worker #include "tcuTestLog.hpp"
28*35238bceSAndroid Build Coastguard Worker #include "tcuTextureUtil.hpp"
29*35238bceSAndroid Build Coastguard Worker #include "tcuVectorUtil.hpp"
30*35238bceSAndroid Build Coastguard Worker #include "tcuFloat.hpp"
31*35238bceSAndroid Build Coastguard Worker 
32*35238bceSAndroid Build Coastguard Worker #include "deMath.h"
33*35238bceSAndroid Build Coastguard Worker #include "deStringUtil.hpp"
34*35238bceSAndroid Build Coastguard Worker 
35*35238bceSAndroid Build Coastguard Worker #include "rrRasterizer.hpp"
36*35238bceSAndroid Build Coastguard Worker 
37*35238bceSAndroid Build Coastguard Worker #include <limits>
38*35238bceSAndroid Build Coastguard Worker 
39*35238bceSAndroid Build Coastguard Worker namespace tcu
40*35238bceSAndroid Build Coastguard Worker {
41*35238bceSAndroid Build Coastguard Worker namespace
42*35238bceSAndroid Build Coastguard Worker {
43*35238bceSAndroid Build Coastguard Worker 
44*35238bceSAndroid Build Coastguard Worker bool verifyLineGroupInterpolationWithProjectedWeights(const tcu::Surface &surface, const LineSceneSpec &scene,
45*35238bceSAndroid Build Coastguard Worker                                                       const RasterizationArguments &args, tcu::TestLog &log);
46*35238bceSAndroid Build Coastguard Worker 
lineLineIntersect(const tcu::Vector<int64_t,2> & line0Beg,const tcu::Vector<int64_t,2> & line0End,const tcu::Vector<int64_t,2> & line1Beg,const tcu::Vector<int64_t,2> & line1End)47*35238bceSAndroid Build Coastguard Worker bool lineLineIntersect(const tcu::Vector<int64_t, 2> &line0Beg, const tcu::Vector<int64_t, 2> &line0End,
48*35238bceSAndroid Build Coastguard Worker                        const tcu::Vector<int64_t, 2> &line1Beg, const tcu::Vector<int64_t, 2> &line1End)
49*35238bceSAndroid Build Coastguard Worker {
50*35238bceSAndroid Build Coastguard Worker     typedef tcu::Vector<int64_t, 2> I64Vec2;
51*35238bceSAndroid Build Coastguard Worker 
52*35238bceSAndroid Build Coastguard Worker     // Lines do not intersect if the other line's endpoints are on the same side
53*35238bceSAndroid Build Coastguard Worker     // otherwise, the do intersect
54*35238bceSAndroid Build Coastguard Worker 
55*35238bceSAndroid Build Coastguard Worker     // Test line 0
56*35238bceSAndroid Build Coastguard Worker     {
57*35238bceSAndroid Build Coastguard Worker         const I64Vec2 line          = line0End - line0Beg;
58*35238bceSAndroid Build Coastguard Worker         const I64Vec2 v0            = line1Beg - line0Beg;
59*35238bceSAndroid Build Coastguard Worker         const I64Vec2 v1            = line1End - line0Beg;
60*35238bceSAndroid Build Coastguard Worker         const int64_t crossProduct0 = (line.x() * v0.y() - line.y() * v0.x());
61*35238bceSAndroid Build Coastguard Worker         const int64_t crossProduct1 = (line.x() * v1.y() - line.y() * v1.x());
62*35238bceSAndroid Build Coastguard Worker 
63*35238bceSAndroid Build Coastguard Worker         // check signs
64*35238bceSAndroid Build Coastguard Worker         if ((crossProduct0 < 0 && crossProduct1 < 0) || (crossProduct0 > 0 && crossProduct1 > 0))
65*35238bceSAndroid Build Coastguard Worker             return false;
66*35238bceSAndroid Build Coastguard Worker     }
67*35238bceSAndroid Build Coastguard Worker 
68*35238bceSAndroid Build Coastguard Worker     // Test line 1
69*35238bceSAndroid Build Coastguard Worker     {
70*35238bceSAndroid Build Coastguard Worker         const I64Vec2 line          = line1End - line1Beg;
71*35238bceSAndroid Build Coastguard Worker         const I64Vec2 v0            = line0Beg - line1Beg;
72*35238bceSAndroid Build Coastguard Worker         const I64Vec2 v1            = line0End - line1Beg;
73*35238bceSAndroid Build Coastguard Worker         const int64_t crossProduct0 = (line.x() * v0.y() - line.y() * v0.x());
74*35238bceSAndroid Build Coastguard Worker         const int64_t crossProduct1 = (line.x() * v1.y() - line.y() * v1.x());
75*35238bceSAndroid Build Coastguard Worker 
76*35238bceSAndroid Build Coastguard Worker         // check signs
77*35238bceSAndroid Build Coastguard Worker         if ((crossProduct0 < 0 && crossProduct1 < 0) || (crossProduct0 > 0 && crossProduct1 > 0))
78*35238bceSAndroid Build Coastguard Worker             return false;
79*35238bceSAndroid Build Coastguard Worker     }
80*35238bceSAndroid Build Coastguard Worker 
81*35238bceSAndroid Build Coastguard Worker     return true;
82*35238bceSAndroid Build Coastguard Worker }
83*35238bceSAndroid Build Coastguard Worker 
isTriangleClockwise(const tcu::Vec4 & p0,const tcu::Vec4 & p1,const tcu::Vec4 & p2)84*35238bceSAndroid Build Coastguard Worker bool isTriangleClockwise(const tcu::Vec4 &p0, const tcu::Vec4 &p1, const tcu::Vec4 &p2)
85*35238bceSAndroid Build Coastguard Worker {
86*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 u(p1.x() / p1.w() - p0.x() / p0.w(), p1.y() / p1.w() - p0.y() / p0.w());
87*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 v(p2.x() / p2.w() - p0.x() / p0.w(), p2.y() / p2.w() - p0.y() / p0.w());
88*35238bceSAndroid Build Coastguard Worker     const float crossProduct = (u.x() * v.y() - u.y() * v.x());
89*35238bceSAndroid Build Coastguard Worker 
90*35238bceSAndroid Build Coastguard Worker     return crossProduct > 0.0f;
91*35238bceSAndroid Build Coastguard Worker }
92*35238bceSAndroid Build Coastguard Worker 
compareColors(const tcu::RGBA & colorA,const tcu::RGBA & colorB,int redBits,int greenBits,int blueBits)93*35238bceSAndroid Build Coastguard Worker bool compareColors(const tcu::RGBA &colorA, const tcu::RGBA &colorB, int redBits, int greenBits, int blueBits)
94*35238bceSAndroid Build Coastguard Worker {
95*35238bceSAndroid Build Coastguard Worker     const int thresholdRed   = 1 << (8 - redBits);
96*35238bceSAndroid Build Coastguard Worker     const int thresholdGreen = 1 << (8 - greenBits);
97*35238bceSAndroid Build Coastguard Worker     const int thresholdBlue  = 1 << (8 - blueBits);
98*35238bceSAndroid Build Coastguard Worker 
99*35238bceSAndroid Build Coastguard Worker     return deAbs32(colorA.getRed() - colorB.getRed()) <= thresholdRed &&
100*35238bceSAndroid Build Coastguard Worker            deAbs32(colorA.getGreen() - colorB.getGreen()) <= thresholdGreen &&
101*35238bceSAndroid Build Coastguard Worker            deAbs32(colorA.getBlue() - colorB.getBlue()) <= thresholdBlue;
102*35238bceSAndroid Build Coastguard Worker }
103*35238bceSAndroid Build Coastguard Worker 
pixelNearLineSegment(const tcu::IVec2 & pixel,const tcu::Vec2 & p0,const tcu::Vec2 & p1)104*35238bceSAndroid Build Coastguard Worker bool pixelNearLineSegment(const tcu::IVec2 &pixel, const tcu::Vec2 &p0, const tcu::Vec2 &p1)
105*35238bceSAndroid Build Coastguard Worker {
106*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 pixelCenterPosition = tcu::Vec2((float)pixel.x() + 0.5f, (float)pixel.y() + 0.5f);
107*35238bceSAndroid Build Coastguard Worker 
108*35238bceSAndroid Build Coastguard Worker     // "Near" = Distance from the line to the pixel is less than 2 * pixel_max_radius. (pixel_max_radius = sqrt(2) / 2)
109*35238bceSAndroid Build Coastguard Worker     const float maxPixelDistance        = 1.414f;
110*35238bceSAndroid Build Coastguard Worker     const float maxPixelDistanceSquared = 2.0f;
111*35238bceSAndroid Build Coastguard Worker 
112*35238bceSAndroid Build Coastguard Worker     // Near the line
113*35238bceSAndroid Build Coastguard Worker     {
114*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 line     = p1 - p0;
115*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 v        = pixelCenterPosition - p0;
116*35238bceSAndroid Build Coastguard Worker         const float crossProduct = (line.x() * v.y() - line.y() * v.x());
117*35238bceSAndroid Build Coastguard Worker 
118*35238bceSAndroid Build Coastguard Worker         // distance to line: (line x v) / |line|
119*35238bceSAndroid Build Coastguard Worker         //     |(line x v) / |line|| > maxPixelDistance
120*35238bceSAndroid Build Coastguard Worker         // ==> (line x v)^2 / |line|^2 > maxPixelDistance^2
121*35238bceSAndroid Build Coastguard Worker         // ==> (line x v)^2 > maxPixelDistance^2 * |line|^2
122*35238bceSAndroid Build Coastguard Worker 
123*35238bceSAndroid Build Coastguard Worker         if (crossProduct * crossProduct > maxPixelDistanceSquared * tcu::lengthSquared(line))
124*35238bceSAndroid Build Coastguard Worker             return false;
125*35238bceSAndroid Build Coastguard Worker     }
126*35238bceSAndroid Build Coastguard Worker 
127*35238bceSAndroid Build Coastguard Worker     // Between the endpoints
128*35238bceSAndroid Build Coastguard Worker     {
129*35238bceSAndroid Build Coastguard Worker         // distance from line endpoint 1 to pixel is less than line length + maxPixelDistance
130*35238bceSAndroid Build Coastguard Worker         const float maxDistance = tcu::length(p1 - p0) + maxPixelDistance;
131*35238bceSAndroid Build Coastguard Worker 
132*35238bceSAndroid Build Coastguard Worker         if (tcu::length(pixelCenterPosition - p0) > maxDistance)
133*35238bceSAndroid Build Coastguard Worker             return false;
134*35238bceSAndroid Build Coastguard Worker         if (tcu::length(pixelCenterPosition - p1) > maxDistance)
135*35238bceSAndroid Build Coastguard Worker             return false;
136*35238bceSAndroid Build Coastguard Worker     }
137*35238bceSAndroid Build Coastguard Worker 
138*35238bceSAndroid Build Coastguard Worker     return true;
139*35238bceSAndroid Build Coastguard Worker }
140*35238bceSAndroid Build Coastguard Worker 
pixelOnlyOnASharedEdge(const tcu::IVec2 & pixel,const TriangleSceneSpec::SceneTriangle & triangle,const tcu::IVec2 & viewportSize)141*35238bceSAndroid Build Coastguard Worker bool pixelOnlyOnASharedEdge(const tcu::IVec2 &pixel, const TriangleSceneSpec::SceneTriangle &triangle,
142*35238bceSAndroid Build Coastguard Worker                             const tcu::IVec2 &viewportSize)
143*35238bceSAndroid Build Coastguard Worker {
144*35238bceSAndroid Build Coastguard Worker     if (triangle.sharedEdge[0] || triangle.sharedEdge[1] || triangle.sharedEdge[2])
145*35238bceSAndroid Build Coastguard Worker     {
146*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 triangleNormalizedDeviceSpace[3] = {
147*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(triangle.positions[0].x() / triangle.positions[0].w(),
148*35238bceSAndroid Build Coastguard Worker                       triangle.positions[0].y() / triangle.positions[0].w()),
149*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(triangle.positions[1].x() / triangle.positions[1].w(),
150*35238bceSAndroid Build Coastguard Worker                       triangle.positions[1].y() / triangle.positions[1].w()),
151*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(triangle.positions[2].x() / triangle.positions[2].w(),
152*35238bceSAndroid Build Coastguard Worker                       triangle.positions[2].y() / triangle.positions[2].w()),
153*35238bceSAndroid Build Coastguard Worker         };
154*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 triangleScreenSpace[3] = {
155*35238bceSAndroid Build Coastguard Worker             (triangleNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
156*35238bceSAndroid Build Coastguard Worker                 tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
157*35238bceSAndroid Build Coastguard Worker             (triangleNormalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
158*35238bceSAndroid Build Coastguard Worker                 tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
159*35238bceSAndroid Build Coastguard Worker             (triangleNormalizedDeviceSpace[2] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
160*35238bceSAndroid Build Coastguard Worker                 tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
161*35238bceSAndroid Build Coastguard Worker         };
162*35238bceSAndroid Build Coastguard Worker 
163*35238bceSAndroid Build Coastguard Worker         const bool pixelOnEdge0 = pixelNearLineSegment(pixel, triangleScreenSpace[0], triangleScreenSpace[1]);
164*35238bceSAndroid Build Coastguard Worker         const bool pixelOnEdge1 = pixelNearLineSegment(pixel, triangleScreenSpace[1], triangleScreenSpace[2]);
165*35238bceSAndroid Build Coastguard Worker         const bool pixelOnEdge2 = pixelNearLineSegment(pixel, triangleScreenSpace[2], triangleScreenSpace[0]);
166*35238bceSAndroid Build Coastguard Worker 
167*35238bceSAndroid Build Coastguard Worker         // If the pixel is on a multiple edges return false
168*35238bceSAndroid Build Coastguard Worker 
169*35238bceSAndroid Build Coastguard Worker         if (pixelOnEdge0 && !pixelOnEdge1 && !pixelOnEdge2)
170*35238bceSAndroid Build Coastguard Worker             return triangle.sharedEdge[0];
171*35238bceSAndroid Build Coastguard Worker         if (!pixelOnEdge0 && pixelOnEdge1 && !pixelOnEdge2)
172*35238bceSAndroid Build Coastguard Worker             return triangle.sharedEdge[1];
173*35238bceSAndroid Build Coastguard Worker         if (!pixelOnEdge0 && !pixelOnEdge1 && pixelOnEdge2)
174*35238bceSAndroid Build Coastguard Worker             return triangle.sharedEdge[2];
175*35238bceSAndroid Build Coastguard Worker     }
176*35238bceSAndroid Build Coastguard Worker 
177*35238bceSAndroid Build Coastguard Worker     return false;
178*35238bceSAndroid Build Coastguard Worker }
179*35238bceSAndroid Build Coastguard Worker 
triangleArea(const tcu::Vec2 & s0,const tcu::Vec2 & s1,const tcu::Vec2 & s2)180*35238bceSAndroid Build Coastguard Worker float triangleArea(const tcu::Vec2 &s0, const tcu::Vec2 &s1, const tcu::Vec2 &s2)
181*35238bceSAndroid Build Coastguard Worker {
182*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 u(s1.x() - s0.x(), s1.y() - s0.y());
183*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 v(s2.x() - s0.x(), s2.y() - s0.y());
184*35238bceSAndroid Build Coastguard Worker     const float crossProduct = (u.x() * v.y() - u.y() * v.x());
185*35238bceSAndroid Build Coastguard Worker 
186*35238bceSAndroid Build Coastguard Worker     return crossProduct / 2.0f;
187*35238bceSAndroid Build Coastguard Worker }
188*35238bceSAndroid Build Coastguard Worker 
getTriangleAABB(const TriangleSceneSpec::SceneTriangle & triangle,const tcu::IVec2 & viewportSize)189*35238bceSAndroid Build Coastguard Worker tcu::IVec4 getTriangleAABB(const TriangleSceneSpec::SceneTriangle &triangle, const tcu::IVec2 &viewportSize)
190*35238bceSAndroid Build Coastguard Worker {
191*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 normalizedDeviceSpace[3] = {
192*35238bceSAndroid Build Coastguard Worker         tcu::Vec2(triangle.positions[0].x() / triangle.positions[0].w(),
193*35238bceSAndroid Build Coastguard Worker                   triangle.positions[0].y() / triangle.positions[0].w()),
194*35238bceSAndroid Build Coastguard Worker         tcu::Vec2(triangle.positions[1].x() / triangle.positions[1].w(),
195*35238bceSAndroid Build Coastguard Worker                   triangle.positions[1].y() / triangle.positions[1].w()),
196*35238bceSAndroid Build Coastguard Worker         tcu::Vec2(triangle.positions[2].x() / triangle.positions[2].w(),
197*35238bceSAndroid Build Coastguard Worker                   triangle.positions[2].y() / triangle.positions[2].w()),
198*35238bceSAndroid Build Coastguard Worker     };
199*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 screenSpace[3] = {
200*35238bceSAndroid Build Coastguard Worker         (normalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
201*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
202*35238bceSAndroid Build Coastguard Worker         (normalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
203*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
204*35238bceSAndroid Build Coastguard Worker         (normalizedDeviceSpace[2] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
205*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
206*35238bceSAndroid Build Coastguard Worker     };
207*35238bceSAndroid Build Coastguard Worker 
208*35238bceSAndroid Build Coastguard Worker     tcu::IVec4 aabb;
209*35238bceSAndroid Build Coastguard Worker 
210*35238bceSAndroid Build Coastguard Worker     aabb.x() = (int)deFloatFloor(de::min(de::min(screenSpace[0].x(), screenSpace[1].x()), screenSpace[2].x()));
211*35238bceSAndroid Build Coastguard Worker     aabb.y() = (int)deFloatFloor(de::min(de::min(screenSpace[0].y(), screenSpace[1].y()), screenSpace[2].y()));
212*35238bceSAndroid Build Coastguard Worker     aabb.z() = (int)deFloatCeil(de::max(de::max(screenSpace[0].x(), screenSpace[1].x()), screenSpace[2].x()));
213*35238bceSAndroid Build Coastguard Worker     aabb.w() = (int)deFloatCeil(de::max(de::max(screenSpace[0].y(), screenSpace[1].y()), screenSpace[2].y()));
214*35238bceSAndroid Build Coastguard Worker 
215*35238bceSAndroid Build Coastguard Worker     return aabb;
216*35238bceSAndroid Build Coastguard Worker }
217*35238bceSAndroid Build Coastguard Worker 
getExponentEpsilonFromULP(int valueExponent,uint32_t ulp)218*35238bceSAndroid Build Coastguard Worker float getExponentEpsilonFromULP(int valueExponent, uint32_t ulp)
219*35238bceSAndroid Build Coastguard Worker {
220*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(ulp < (1u << 10));
221*35238bceSAndroid Build Coastguard Worker 
222*35238bceSAndroid Build Coastguard Worker     // assume mediump precision, using ulp as ulps in a 10 bit mantissa
223*35238bceSAndroid Build Coastguard Worker     return tcu::Float32::construct(+1, valueExponent, (1u << 23) + (ulp << (23 - 10))).asFloat() -
224*35238bceSAndroid Build Coastguard Worker            tcu::Float32::construct(+1, valueExponent, (1u << 23)).asFloat();
225*35238bceSAndroid Build Coastguard Worker }
226*35238bceSAndroid Build Coastguard Worker 
getValueEpsilonFromULP(float value,uint32_t ulp)227*35238bceSAndroid Build Coastguard Worker float getValueEpsilonFromULP(float value, uint32_t ulp)
228*35238bceSAndroid Build Coastguard Worker {
229*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(value != std::numeric_limits<float>::infinity() && value != -std::numeric_limits<float>::infinity());
230*35238bceSAndroid Build Coastguard Worker 
231*35238bceSAndroid Build Coastguard Worker     const int exponent = tcu::Float32(value).exponent();
232*35238bceSAndroid Build Coastguard Worker     return getExponentEpsilonFromULP(exponent, ulp);
233*35238bceSAndroid Build Coastguard Worker }
234*35238bceSAndroid Build Coastguard Worker 
getMaxValueWithinError(float value,uint32_t ulp)235*35238bceSAndroid Build Coastguard Worker float getMaxValueWithinError(float value, uint32_t ulp)
236*35238bceSAndroid Build Coastguard Worker {
237*35238bceSAndroid Build Coastguard Worker     if (value == std::numeric_limits<float>::infinity() || value == -std::numeric_limits<float>::infinity())
238*35238bceSAndroid Build Coastguard Worker         return value;
239*35238bceSAndroid Build Coastguard Worker 
240*35238bceSAndroid Build Coastguard Worker     return value + getValueEpsilonFromULP(value, ulp);
241*35238bceSAndroid Build Coastguard Worker }
242*35238bceSAndroid Build Coastguard Worker 
getMinValueWithinError(float value,uint32_t ulp)243*35238bceSAndroid Build Coastguard Worker float getMinValueWithinError(float value, uint32_t ulp)
244*35238bceSAndroid Build Coastguard Worker {
245*35238bceSAndroid Build Coastguard Worker     if (value == std::numeric_limits<float>::infinity() || value == -std::numeric_limits<float>::infinity())
246*35238bceSAndroid Build Coastguard Worker         return value;
247*35238bceSAndroid Build Coastguard Worker 
248*35238bceSAndroid Build Coastguard Worker     return value - getValueEpsilonFromULP(value, ulp);
249*35238bceSAndroid Build Coastguard Worker }
250*35238bceSAndroid Build Coastguard Worker 
getMinFlushToZero(float value)251*35238bceSAndroid Build Coastguard Worker float getMinFlushToZero(float value)
252*35238bceSAndroid Build Coastguard Worker {
253*35238bceSAndroid Build Coastguard Worker     // flush to zero if that decreases the value
254*35238bceSAndroid Build Coastguard Worker     // assume mediump precision
255*35238bceSAndroid Build Coastguard Worker     if (value > 0.0f && value < tcu::Float32::construct(+1, -14, 1u << 23).asFloat())
256*35238bceSAndroid Build Coastguard Worker         return 0.0f;
257*35238bceSAndroid Build Coastguard Worker     return value;
258*35238bceSAndroid Build Coastguard Worker }
259*35238bceSAndroid Build Coastguard Worker 
getMaxFlushToZero(float value)260*35238bceSAndroid Build Coastguard Worker float getMaxFlushToZero(float value)
261*35238bceSAndroid Build Coastguard Worker {
262*35238bceSAndroid Build Coastguard Worker     // flush to zero if that increases the value
263*35238bceSAndroid Build Coastguard Worker     // assume mediump precision
264*35238bceSAndroid Build Coastguard Worker     if (value < 0.0f && value > tcu::Float32::construct(-1, -14, 1u << 23).asFloat())
265*35238bceSAndroid Build Coastguard Worker         return 0.0f;
266*35238bceSAndroid Build Coastguard Worker     return value;
267*35238bceSAndroid Build Coastguard Worker }
268*35238bceSAndroid Build Coastguard Worker 
convertRGB8ToNativeFormat(const tcu::RGBA & color,const RasterizationArguments & args)269*35238bceSAndroid Build Coastguard Worker tcu::IVec3 convertRGB8ToNativeFormat(const tcu::RGBA &color, const RasterizationArguments &args)
270*35238bceSAndroid Build Coastguard Worker {
271*35238bceSAndroid Build Coastguard Worker     tcu::IVec3 pixelNativeColor;
272*35238bceSAndroid Build Coastguard Worker 
273*35238bceSAndroid Build Coastguard Worker     for (int channelNdx = 0; channelNdx < 3; ++channelNdx)
274*35238bceSAndroid Build Coastguard Worker     {
275*35238bceSAndroid Build Coastguard Worker         const int channelBitCount   = (channelNdx == 0) ? (args.redBits) :
276*35238bceSAndroid Build Coastguard Worker                                       (channelNdx == 1) ? (args.greenBits) :
277*35238bceSAndroid Build Coastguard Worker                                                           (args.blueBits);
278*35238bceSAndroid Build Coastguard Worker         const int channelPixelValue = (channelNdx == 0) ? (color.getRed()) :
279*35238bceSAndroid Build Coastguard Worker                                       (channelNdx == 1) ? (color.getGreen()) :
280*35238bceSAndroid Build Coastguard Worker                                                           (color.getBlue());
281*35238bceSAndroid Build Coastguard Worker 
282*35238bceSAndroid Build Coastguard Worker         if (channelBitCount <= 8)
283*35238bceSAndroid Build Coastguard Worker             pixelNativeColor[channelNdx] = channelPixelValue >> (8 - channelBitCount);
284*35238bceSAndroid Build Coastguard Worker         else if (channelBitCount == 8)
285*35238bceSAndroid Build Coastguard Worker             pixelNativeColor[channelNdx] = channelPixelValue;
286*35238bceSAndroid Build Coastguard Worker         else
287*35238bceSAndroid Build Coastguard Worker         {
288*35238bceSAndroid Build Coastguard Worker             // just in case someone comes up with 8+ bits framebuffers pixel formats. But as
289*35238bceSAndroid Build Coastguard Worker             // we can only read in rgba8, we have to guess the trailing bits. Guessing 0.
290*35238bceSAndroid Build Coastguard Worker             pixelNativeColor[channelNdx] = channelPixelValue << (channelBitCount - 8);
291*35238bceSAndroid Build Coastguard Worker         }
292*35238bceSAndroid Build Coastguard Worker     }
293*35238bceSAndroid Build Coastguard Worker 
294*35238bceSAndroid Build Coastguard Worker     return pixelNativeColor;
295*35238bceSAndroid Build Coastguard Worker }
296*35238bceSAndroid Build Coastguard Worker 
297*35238bceSAndroid Build Coastguard Worker /*--------------------------------------------------------------------*//*!
298*35238bceSAndroid Build Coastguard Worker  * Returns the maximum value of x / y, where x c [minDividend, maxDividend]
299*35238bceSAndroid Build Coastguard Worker  * and y c [minDivisor, maxDivisor]
300*35238bceSAndroid Build Coastguard Worker  *//*--------------------------------------------------------------------*/
maximalRangeDivision(float minDividend,float maxDividend,float minDivisor,float maxDivisor)301*35238bceSAndroid Build Coastguard Worker float maximalRangeDivision(float minDividend, float maxDividend, float minDivisor, float maxDivisor)
302*35238bceSAndroid Build Coastguard Worker {
303*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minDividend <= maxDividend);
304*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minDivisor <= maxDivisor);
305*35238bceSAndroid Build Coastguard Worker 
306*35238bceSAndroid Build Coastguard Worker     // special cases
307*35238bceSAndroid Build Coastguard Worker     if (minDividend == 0.0f && maxDividend == 0.0f)
308*35238bceSAndroid Build Coastguard Worker         return 0.0f;
309*35238bceSAndroid Build Coastguard Worker     if (minDivisor <= 0.0f && maxDivisor >= 0.0f)
310*35238bceSAndroid Build Coastguard Worker         return std::numeric_limits<float>::infinity();
311*35238bceSAndroid Build Coastguard Worker 
312*35238bceSAndroid Build Coastguard Worker     return de::max(de::max(minDividend / minDivisor, minDividend / maxDivisor),
313*35238bceSAndroid Build Coastguard Worker                    de::max(maxDividend / minDivisor, maxDividend / maxDivisor));
314*35238bceSAndroid Build Coastguard Worker }
315*35238bceSAndroid Build Coastguard Worker 
316*35238bceSAndroid Build Coastguard Worker /*--------------------------------------------------------------------*//*!
317*35238bceSAndroid Build Coastguard Worker  * Returns the minimum value of x / y, where x c [minDividend, maxDividend]
318*35238bceSAndroid Build Coastguard Worker  * and y c [minDivisor, maxDivisor]
319*35238bceSAndroid Build Coastguard Worker  *//*--------------------------------------------------------------------*/
minimalRangeDivision(float minDividend,float maxDividend,float minDivisor,float maxDivisor)320*35238bceSAndroid Build Coastguard Worker float minimalRangeDivision(float minDividend, float maxDividend, float minDivisor, float maxDivisor)
321*35238bceSAndroid Build Coastguard Worker {
322*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minDividend <= maxDividend);
323*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minDivisor <= maxDivisor);
324*35238bceSAndroid Build Coastguard Worker 
325*35238bceSAndroid Build Coastguard Worker     // special cases
326*35238bceSAndroid Build Coastguard Worker     if (minDividend == 0.0f && maxDividend == 0.0f)
327*35238bceSAndroid Build Coastguard Worker         return 0.0f;
328*35238bceSAndroid Build Coastguard Worker     if (minDivisor <= 0.0f && maxDivisor >= 0.0f)
329*35238bceSAndroid Build Coastguard Worker         return -std::numeric_limits<float>::infinity();
330*35238bceSAndroid Build Coastguard Worker 
331*35238bceSAndroid Build Coastguard Worker     return de::min(de::min(minDividend / minDivisor, minDividend / maxDivisor),
332*35238bceSAndroid Build Coastguard Worker                    de::min(maxDividend / minDivisor, maxDividend / maxDivisor));
333*35238bceSAndroid Build Coastguard Worker }
334*35238bceSAndroid Build Coastguard Worker 
isLineXMajor(const tcu::Vec2 & lineScreenSpaceP0,const tcu::Vec2 & lineScreenSpaceP1)335*35238bceSAndroid Build Coastguard Worker static bool isLineXMajor(const tcu::Vec2 &lineScreenSpaceP0, const tcu::Vec2 &lineScreenSpaceP1)
336*35238bceSAndroid Build Coastguard Worker {
337*35238bceSAndroid Build Coastguard Worker     return de::abs(lineScreenSpaceP1.x() - lineScreenSpaceP0.x()) >=
338*35238bceSAndroid Build Coastguard Worker            de::abs(lineScreenSpaceP1.y() - lineScreenSpaceP0.y());
339*35238bceSAndroid Build Coastguard Worker }
340*35238bceSAndroid Build Coastguard Worker 
isPackedSSLineXMajor(const tcu::Vec4 & packedLine)341*35238bceSAndroid Build Coastguard Worker static bool isPackedSSLineXMajor(const tcu::Vec4 &packedLine)
342*35238bceSAndroid Build Coastguard Worker {
343*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 lineScreenSpaceP0 = packedLine.swizzle(0, 1);
344*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 lineScreenSpaceP1 = packedLine.swizzle(2, 3);
345*35238bceSAndroid Build Coastguard Worker 
346*35238bceSAndroid Build Coastguard Worker     return isLineXMajor(lineScreenSpaceP0, lineScreenSpaceP1);
347*35238bceSAndroid Build Coastguard Worker }
348*35238bceSAndroid Build Coastguard Worker 
349*35238bceSAndroid Build Coastguard Worker struct InterpolationRange
350*35238bceSAndroid Build Coastguard Worker {
351*35238bceSAndroid Build Coastguard Worker     tcu::Vec3 max;
352*35238bceSAndroid Build Coastguard Worker     tcu::Vec3 min;
353*35238bceSAndroid Build Coastguard Worker };
354*35238bceSAndroid Build Coastguard Worker 
355*35238bceSAndroid Build Coastguard Worker struct LineInterpolationRange
356*35238bceSAndroid Build Coastguard Worker {
357*35238bceSAndroid Build Coastguard Worker     tcu::Vec2 max;
358*35238bceSAndroid Build Coastguard Worker     tcu::Vec2 min;
359*35238bceSAndroid Build Coastguard Worker };
360*35238bceSAndroid Build Coastguard Worker 
calcTriangleInterpolationWeights(const tcu::Vec4 & p0,const tcu::Vec4 & p1,const tcu::Vec4 & p2,const tcu::Vec2 & ndpixel)361*35238bceSAndroid Build Coastguard Worker InterpolationRange calcTriangleInterpolationWeights(const tcu::Vec4 &p0, const tcu::Vec4 &p1, const tcu::Vec4 &p2,
362*35238bceSAndroid Build Coastguard Worker                                                     const tcu::Vec2 &ndpixel)
363*35238bceSAndroid Build Coastguard Worker {
364*35238bceSAndroid Build Coastguard Worker     const int roundError       = 1;
365*35238bceSAndroid Build Coastguard Worker     const int barycentricError = 3;
366*35238bceSAndroid Build Coastguard Worker     const int divError         = 8;
367*35238bceSAndroid Build Coastguard Worker 
368*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 nd0 = p0.swizzle(0, 1) / p0.w();
369*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 nd1 = p1.swizzle(0, 1) / p1.w();
370*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 nd2 = p2.swizzle(0, 1) / p2.w();
371*35238bceSAndroid Build Coastguard Worker 
372*35238bceSAndroid Build Coastguard Worker     const float ka = triangleArea(ndpixel, nd1, nd2);
373*35238bceSAndroid Build Coastguard Worker     const float kb = triangleArea(ndpixel, nd2, nd0);
374*35238bceSAndroid Build Coastguard Worker     const float kc = triangleArea(ndpixel, nd0, nd1);
375*35238bceSAndroid Build Coastguard Worker 
376*35238bceSAndroid Build Coastguard Worker     const float kaMax = getMaxFlushToZero(getMaxValueWithinError(ka, barycentricError));
377*35238bceSAndroid Build Coastguard Worker     const float kbMax = getMaxFlushToZero(getMaxValueWithinError(kb, barycentricError));
378*35238bceSAndroid Build Coastguard Worker     const float kcMax = getMaxFlushToZero(getMaxValueWithinError(kc, barycentricError));
379*35238bceSAndroid Build Coastguard Worker     const float kaMin = getMinFlushToZero(getMinValueWithinError(ka, barycentricError));
380*35238bceSAndroid Build Coastguard Worker     const float kbMin = getMinFlushToZero(getMinValueWithinError(kb, barycentricError));
381*35238bceSAndroid Build Coastguard Worker     const float kcMin = getMinFlushToZero(getMinValueWithinError(kc, barycentricError));
382*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(kaMin <= kaMax);
383*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(kbMin <= kbMax);
384*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(kcMin <= kcMax);
385*35238bceSAndroid Build Coastguard Worker 
386*35238bceSAndroid Build Coastguard Worker     // calculate weights: vec3(ka / p0.w, kb / p1.w, kc / p2.w) / (ka / p0.w + kb / p1.w + kc / p2.w)
387*35238bceSAndroid Build Coastguard Worker     const float maxPreDivisionValues[3] = {
388*35238bceSAndroid Build Coastguard Worker         getMaxFlushToZero(getMaxValueWithinError(getMaxFlushToZero(kaMax / p0.w()), divError)),
389*35238bceSAndroid Build Coastguard Worker         getMaxFlushToZero(getMaxValueWithinError(getMaxFlushToZero(kbMax / p1.w()), divError)),
390*35238bceSAndroid Build Coastguard Worker         getMaxFlushToZero(getMaxValueWithinError(getMaxFlushToZero(kcMax / p2.w()), divError)),
391*35238bceSAndroid Build Coastguard Worker     };
392*35238bceSAndroid Build Coastguard Worker     const float minPreDivisionValues[3] = {
393*35238bceSAndroid Build Coastguard Worker         getMinFlushToZero(getMinValueWithinError(getMinFlushToZero(kaMin / p0.w()), divError)),
394*35238bceSAndroid Build Coastguard Worker         getMinFlushToZero(getMinValueWithinError(getMinFlushToZero(kbMin / p1.w()), divError)),
395*35238bceSAndroid Build Coastguard Worker         getMinFlushToZero(getMinValueWithinError(getMinFlushToZero(kcMin / p2.w()), divError)),
396*35238bceSAndroid Build Coastguard Worker     };
397*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minPreDivisionValues[0] <= maxPreDivisionValues[0]);
398*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minPreDivisionValues[1] <= maxPreDivisionValues[1]);
399*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minPreDivisionValues[2] <= maxPreDivisionValues[2]);
400*35238bceSAndroid Build Coastguard Worker 
401*35238bceSAndroid Build Coastguard Worker     const float maxDivisor = getMaxFlushToZero(getMaxValueWithinError(
402*35238bceSAndroid Build Coastguard Worker         maxPreDivisionValues[0] + maxPreDivisionValues[1] + maxPreDivisionValues[2], 2 * roundError));
403*35238bceSAndroid Build Coastguard Worker     const float minDivisor = getMinFlushToZero(getMinValueWithinError(
404*35238bceSAndroid Build Coastguard Worker         minPreDivisionValues[0] + minPreDivisionValues[1] + minPreDivisionValues[2], 2 * roundError));
405*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minDivisor <= maxDivisor);
406*35238bceSAndroid Build Coastguard Worker 
407*35238bceSAndroid Build Coastguard Worker     InterpolationRange returnValue;
408*35238bceSAndroid Build Coastguard Worker 
409*35238bceSAndroid Build Coastguard Worker     returnValue.max.x() = getMaxFlushToZero(
410*35238bceSAndroid Build Coastguard Worker         getMaxValueWithinError(getMaxFlushToZero(maximalRangeDivision(minPreDivisionValues[0], maxPreDivisionValues[0],
411*35238bceSAndroid Build Coastguard Worker                                                                       minDivisor, maxDivisor)),
412*35238bceSAndroid Build Coastguard Worker                                divError));
413*35238bceSAndroid Build Coastguard Worker     returnValue.max.y() = getMaxFlushToZero(
414*35238bceSAndroid Build Coastguard Worker         getMaxValueWithinError(getMaxFlushToZero(maximalRangeDivision(minPreDivisionValues[1], maxPreDivisionValues[1],
415*35238bceSAndroid Build Coastguard Worker                                                                       minDivisor, maxDivisor)),
416*35238bceSAndroid Build Coastguard Worker                                divError));
417*35238bceSAndroid Build Coastguard Worker     returnValue.max.z() = getMaxFlushToZero(
418*35238bceSAndroid Build Coastguard Worker         getMaxValueWithinError(getMaxFlushToZero(maximalRangeDivision(minPreDivisionValues[2], maxPreDivisionValues[2],
419*35238bceSAndroid Build Coastguard Worker                                                                       minDivisor, maxDivisor)),
420*35238bceSAndroid Build Coastguard Worker                                divError));
421*35238bceSAndroid Build Coastguard Worker     returnValue.min.x() = getMinFlushToZero(
422*35238bceSAndroid Build Coastguard Worker         getMinValueWithinError(getMinFlushToZero(minimalRangeDivision(minPreDivisionValues[0], maxPreDivisionValues[0],
423*35238bceSAndroid Build Coastguard Worker                                                                       minDivisor, maxDivisor)),
424*35238bceSAndroid Build Coastguard Worker                                divError));
425*35238bceSAndroid Build Coastguard Worker     returnValue.min.y() = getMinFlushToZero(
426*35238bceSAndroid Build Coastguard Worker         getMinValueWithinError(getMinFlushToZero(minimalRangeDivision(minPreDivisionValues[1], maxPreDivisionValues[1],
427*35238bceSAndroid Build Coastguard Worker                                                                       minDivisor, maxDivisor)),
428*35238bceSAndroid Build Coastguard Worker                                divError));
429*35238bceSAndroid Build Coastguard Worker     returnValue.min.z() = getMinFlushToZero(
430*35238bceSAndroid Build Coastguard Worker         getMinValueWithinError(getMinFlushToZero(minimalRangeDivision(minPreDivisionValues[2], maxPreDivisionValues[2],
431*35238bceSAndroid Build Coastguard Worker                                                                       minDivisor, maxDivisor)),
432*35238bceSAndroid Build Coastguard Worker                                divError));
433*35238bceSAndroid Build Coastguard Worker 
434*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(returnValue.min.x() <= returnValue.max.x());
435*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(returnValue.min.y() <= returnValue.max.y());
436*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(returnValue.min.z() <= returnValue.max.z());
437*35238bceSAndroid Build Coastguard Worker 
438*35238bceSAndroid Build Coastguard Worker     return returnValue;
439*35238bceSAndroid Build Coastguard Worker }
440*35238bceSAndroid Build Coastguard Worker 
calcLineInterpolationWeights(const tcu::Vec2 & pa,float wa,const tcu::Vec2 & pb,float wb,const tcu::Vec2 & pr)441*35238bceSAndroid Build Coastguard Worker LineInterpolationRange calcLineInterpolationWeights(const tcu::Vec2 &pa, float wa, const tcu::Vec2 &pb, float wb,
442*35238bceSAndroid Build Coastguard Worker                                                     const tcu::Vec2 &pr)
443*35238bceSAndroid Build Coastguard Worker {
444*35238bceSAndroid Build Coastguard Worker     const int roundError = 1;
445*35238bceSAndroid Build Coastguard Worker     const int divError   = 3;
446*35238bceSAndroid Build Coastguard Worker 
447*35238bceSAndroid Build Coastguard Worker     // calc weights:
448*35238bceSAndroid Build Coastguard Worker     //            (1-t) / wa                    t / wb
449*35238bceSAndroid Build Coastguard Worker     //        -------------------    , -------------------
450*35238bceSAndroid Build Coastguard Worker     //        (1-t) / wa + t / wb        (1-t) / wa + t / wb
451*35238bceSAndroid Build Coastguard Worker 
452*35238bceSAndroid Build Coastguard Worker     // Allow 1 ULP
453*35238bceSAndroid Build Coastguard Worker     const float dividend    = tcu::dot(pr - pa, pb - pa);
454*35238bceSAndroid Build Coastguard Worker     const float dividendMax = getMaxValueWithinError(dividend, 1);
455*35238bceSAndroid Build Coastguard Worker     const float dividendMin = getMinValueWithinError(dividend, 1);
456*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(dividendMin <= dividendMax);
457*35238bceSAndroid Build Coastguard Worker 
458*35238bceSAndroid Build Coastguard Worker     // Assuming lengthSquared will not be implemented as sqrt(x)^2, allow 1 ULP
459*35238bceSAndroid Build Coastguard Worker     const float divisor    = tcu::lengthSquared(pb - pa);
460*35238bceSAndroid Build Coastguard Worker     const float divisorMax = getMaxValueWithinError(divisor, 1);
461*35238bceSAndroid Build Coastguard Worker     const float divisorMin = getMinValueWithinError(divisor, 1);
462*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(divisorMin <= divisorMax);
463*35238bceSAndroid Build Coastguard Worker 
464*35238bceSAndroid Build Coastguard Worker     // Allow 3 ULP precision for division
465*35238bceSAndroid Build Coastguard Worker     const float tMax =
466*35238bceSAndroid Build Coastguard Worker         getMaxValueWithinError(maximalRangeDivision(dividendMin, dividendMax, divisorMin, divisorMax), divError);
467*35238bceSAndroid Build Coastguard Worker     const float tMin =
468*35238bceSAndroid Build Coastguard Worker         getMinValueWithinError(minimalRangeDivision(dividendMin, dividendMax, divisorMin, divisorMax), divError);
469*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(tMin <= tMax);
470*35238bceSAndroid Build Coastguard Worker 
471*35238bceSAndroid Build Coastguard Worker     const float perspectiveTMax = getMaxValueWithinError(maximalRangeDivision(tMin, tMax, wb, wb), divError);
472*35238bceSAndroid Build Coastguard Worker     const float perspectiveTMin = getMinValueWithinError(minimalRangeDivision(tMin, tMax, wb, wb), divError);
473*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(perspectiveTMin <= perspectiveTMax);
474*35238bceSAndroid Build Coastguard Worker 
475*35238bceSAndroid Build Coastguard Worker     const float perspectiveInvTMax =
476*35238bceSAndroid Build Coastguard Worker         getMaxValueWithinError(maximalRangeDivision((1.0f - tMax), (1.0f - tMin), wa, wa), divError);
477*35238bceSAndroid Build Coastguard Worker     const float perspectiveInvTMin =
478*35238bceSAndroid Build Coastguard Worker         getMinValueWithinError(minimalRangeDivision((1.0f - tMax), (1.0f - tMin), wa, wa), divError);
479*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(perspectiveInvTMin <= perspectiveInvTMax);
480*35238bceSAndroid Build Coastguard Worker 
481*35238bceSAndroid Build Coastguard Worker     const float perspectiveDivisorMax = getMaxValueWithinError(perspectiveTMax + perspectiveInvTMax, roundError);
482*35238bceSAndroid Build Coastguard Worker     const float perspectiveDivisorMin = getMinValueWithinError(perspectiveTMin + perspectiveInvTMin, roundError);
483*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(perspectiveDivisorMin <= perspectiveDivisorMax);
484*35238bceSAndroid Build Coastguard Worker 
485*35238bceSAndroid Build Coastguard Worker     LineInterpolationRange returnValue;
486*35238bceSAndroid Build Coastguard Worker     returnValue.max.x() = getMaxValueWithinError(
487*35238bceSAndroid Build Coastguard Worker         maximalRangeDivision(perspectiveInvTMin, perspectiveInvTMax, perspectiveDivisorMin, perspectiveDivisorMax),
488*35238bceSAndroid Build Coastguard Worker         divError);
489*35238bceSAndroid Build Coastguard Worker     returnValue.max.y() = getMaxValueWithinError(
490*35238bceSAndroid Build Coastguard Worker         maximalRangeDivision(perspectiveTMin, perspectiveTMax, perspectiveDivisorMin, perspectiveDivisorMax), divError);
491*35238bceSAndroid Build Coastguard Worker     returnValue.min.x() = getMinValueWithinError(
492*35238bceSAndroid Build Coastguard Worker         minimalRangeDivision(perspectiveInvTMin, perspectiveInvTMax, perspectiveDivisorMin, perspectiveDivisorMax),
493*35238bceSAndroid Build Coastguard Worker         divError);
494*35238bceSAndroid Build Coastguard Worker     returnValue.min.y() = getMinValueWithinError(
495*35238bceSAndroid Build Coastguard Worker         minimalRangeDivision(perspectiveTMin, perspectiveTMax, perspectiveDivisorMin, perspectiveDivisorMax), divError);
496*35238bceSAndroid Build Coastguard Worker 
497*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(returnValue.min.x() <= returnValue.max.x());
498*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(returnValue.min.y() <= returnValue.max.y());
499*35238bceSAndroid Build Coastguard Worker 
500*35238bceSAndroid Build Coastguard Worker     return returnValue;
501*35238bceSAndroid Build Coastguard Worker }
502*35238bceSAndroid Build Coastguard Worker 
calcLineInterpolationWeightsAxisProjected(const tcu::Vec2 & pa,float wa,const tcu::Vec2 & pb,float wb,const tcu::Vec2 & pr)503*35238bceSAndroid Build Coastguard Worker LineInterpolationRange calcLineInterpolationWeightsAxisProjected(const tcu::Vec2 &pa, float wa, const tcu::Vec2 &pb,
504*35238bceSAndroid Build Coastguard Worker                                                                  float wb, const tcu::Vec2 &pr)
505*35238bceSAndroid Build Coastguard Worker {
506*35238bceSAndroid Build Coastguard Worker     const int roundError   = 1;
507*35238bceSAndroid Build Coastguard Worker     const int divError     = 3;
508*35238bceSAndroid Build Coastguard Worker     const bool isXMajor    = isLineXMajor(pa, pb);
509*35238bceSAndroid Build Coastguard Worker     const int majorAxisNdx = (isXMajor) ? (0) : (1);
510*35238bceSAndroid Build Coastguard Worker 
511*35238bceSAndroid Build Coastguard Worker     // calc weights:
512*35238bceSAndroid Build Coastguard Worker     //            (1-t) / wa                    t / wb
513*35238bceSAndroid Build Coastguard Worker     //        -------------------    , -------------------
514*35238bceSAndroid Build Coastguard Worker     //        (1-t) / wa + t / wb        (1-t) / wa + t / wb
515*35238bceSAndroid Build Coastguard Worker 
516*35238bceSAndroid Build Coastguard Worker     // Use axis projected (inaccurate) method, i.e. for X-major lines:
517*35238bceSAndroid Build Coastguard Worker     //     (xd - xa) * (xb - xa)      xd - xa
518*35238bceSAndroid Build Coastguard Worker     // t = ---------------------  ==  -------
519*35238bceSAndroid Build Coastguard Worker     //       ( xb - xa ) ^ 2          xb - xa
520*35238bceSAndroid Build Coastguard Worker 
521*35238bceSAndroid Build Coastguard Worker     // Allow 1 ULP
522*35238bceSAndroid Build Coastguard Worker     const float dividend    = (pr[majorAxisNdx] - pa[majorAxisNdx]);
523*35238bceSAndroid Build Coastguard Worker     const float dividendMax = getMaxValueWithinError(dividend, 1);
524*35238bceSAndroid Build Coastguard Worker     const float dividendMin = getMinValueWithinError(dividend, 1);
525*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(dividendMin <= dividendMax);
526*35238bceSAndroid Build Coastguard Worker 
527*35238bceSAndroid Build Coastguard Worker     // Allow 1 ULP
528*35238bceSAndroid Build Coastguard Worker     const float divisor    = (pb[majorAxisNdx] - pa[majorAxisNdx]);
529*35238bceSAndroid Build Coastguard Worker     const float divisorMax = getMaxValueWithinError(divisor, 1);
530*35238bceSAndroid Build Coastguard Worker     const float divisorMin = getMinValueWithinError(divisor, 1);
531*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(divisorMin <= divisorMax);
532*35238bceSAndroid Build Coastguard Worker 
533*35238bceSAndroid Build Coastguard Worker     // Allow 3 ULP precision for division
534*35238bceSAndroid Build Coastguard Worker     const float tMax =
535*35238bceSAndroid Build Coastguard Worker         getMaxValueWithinError(maximalRangeDivision(dividendMin, dividendMax, divisorMin, divisorMax), divError);
536*35238bceSAndroid Build Coastguard Worker     const float tMin =
537*35238bceSAndroid Build Coastguard Worker         getMinValueWithinError(minimalRangeDivision(dividendMin, dividendMax, divisorMin, divisorMax), divError);
538*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(tMin <= tMax);
539*35238bceSAndroid Build Coastguard Worker 
540*35238bceSAndroid Build Coastguard Worker     const float perspectiveTMax = getMaxValueWithinError(maximalRangeDivision(tMin, tMax, wb, wb), divError);
541*35238bceSAndroid Build Coastguard Worker     const float perspectiveTMin = getMinValueWithinError(minimalRangeDivision(tMin, tMax, wb, wb), divError);
542*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(perspectiveTMin <= perspectiveTMax);
543*35238bceSAndroid Build Coastguard Worker 
544*35238bceSAndroid Build Coastguard Worker     const float perspectiveInvTMax =
545*35238bceSAndroid Build Coastguard Worker         getMaxValueWithinError(maximalRangeDivision((1.0f - tMax), (1.0f - tMin), wa, wa), divError);
546*35238bceSAndroid Build Coastguard Worker     const float perspectiveInvTMin =
547*35238bceSAndroid Build Coastguard Worker         getMinValueWithinError(minimalRangeDivision((1.0f - tMax), (1.0f - tMin), wa, wa), divError);
548*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(perspectiveInvTMin <= perspectiveInvTMax);
549*35238bceSAndroid Build Coastguard Worker 
550*35238bceSAndroid Build Coastguard Worker     const float perspectiveDivisorMax = getMaxValueWithinError(perspectiveTMax + perspectiveInvTMax, roundError);
551*35238bceSAndroid Build Coastguard Worker     const float perspectiveDivisorMin = getMinValueWithinError(perspectiveTMin + perspectiveInvTMin, roundError);
552*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(perspectiveDivisorMin <= perspectiveDivisorMax);
553*35238bceSAndroid Build Coastguard Worker 
554*35238bceSAndroid Build Coastguard Worker     LineInterpolationRange returnValue;
555*35238bceSAndroid Build Coastguard Worker     returnValue.max.x() = getMaxValueWithinError(
556*35238bceSAndroid Build Coastguard Worker         maximalRangeDivision(perspectiveInvTMin, perspectiveInvTMax, perspectiveDivisorMin, perspectiveDivisorMax),
557*35238bceSAndroid Build Coastguard Worker         divError);
558*35238bceSAndroid Build Coastguard Worker     returnValue.max.y() = getMaxValueWithinError(
559*35238bceSAndroid Build Coastguard Worker         maximalRangeDivision(perspectiveTMin, perspectiveTMax, perspectiveDivisorMin, perspectiveDivisorMax), divError);
560*35238bceSAndroid Build Coastguard Worker     returnValue.min.x() = getMinValueWithinError(
561*35238bceSAndroid Build Coastguard Worker         minimalRangeDivision(perspectiveInvTMin, perspectiveInvTMax, perspectiveDivisorMin, perspectiveDivisorMax),
562*35238bceSAndroid Build Coastguard Worker         divError);
563*35238bceSAndroid Build Coastguard Worker     returnValue.min.y() = getMinValueWithinError(
564*35238bceSAndroid Build Coastguard Worker         minimalRangeDivision(perspectiveTMin, perspectiveTMax, perspectiveDivisorMin, perspectiveDivisorMax), divError);
565*35238bceSAndroid Build Coastguard Worker 
566*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(returnValue.min.x() <= returnValue.max.x());
567*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(returnValue.min.y() <= returnValue.max.y());
568*35238bceSAndroid Build Coastguard Worker 
569*35238bceSAndroid Build Coastguard Worker     return returnValue;
570*35238bceSAndroid Build Coastguard Worker }
571*35238bceSAndroid Build Coastguard Worker 
572*35238bceSAndroid Build Coastguard Worker template <typename WeightEquation>
calcSingleSampleLineInterpolationRangeWithWeightEquation(const tcu::Vec2 & pa,float wa,const tcu::Vec2 & pb,float wb,const tcu::IVec2 & pixel,int subpixelBits,WeightEquation weightEquation)573*35238bceSAndroid Build Coastguard Worker LineInterpolationRange calcSingleSampleLineInterpolationRangeWithWeightEquation(const tcu::Vec2 &pa, float wa,
574*35238bceSAndroid Build Coastguard Worker                                                                                 const tcu::Vec2 &pb, float wb,
575*35238bceSAndroid Build Coastguard Worker                                                                                 const tcu::IVec2 &pixel,
576*35238bceSAndroid Build Coastguard Worker                                                                                 int subpixelBits,
577*35238bceSAndroid Build Coastguard Worker                                                                                 WeightEquation weightEquation)
578*35238bceSAndroid Build Coastguard Worker {
579*35238bceSAndroid Build Coastguard Worker     // allow interpolation weights anywhere in the central subpixels
580*35238bceSAndroid Build Coastguard Worker     const float testSquareSize = (2.0f / (float)(1UL << subpixelBits));
581*35238bceSAndroid Build Coastguard Worker     const float testSquarePos  = (0.5f - testSquareSize / 2);
582*35238bceSAndroid Build Coastguard Worker 
583*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 corners[4] = {
584*35238bceSAndroid Build Coastguard Worker         tcu::Vec2((float)pixel.x() + testSquarePos + 0.0f, (float)pixel.y() + testSquarePos + 0.0f),
585*35238bceSAndroid Build Coastguard Worker         tcu::Vec2((float)pixel.x() + testSquarePos + 0.0f, (float)pixel.y() + testSquarePos + testSquareSize),
586*35238bceSAndroid Build Coastguard Worker         tcu::Vec2((float)pixel.x() + testSquarePos + testSquareSize, (float)pixel.y() + testSquarePos + testSquareSize),
587*35238bceSAndroid Build Coastguard Worker         tcu::Vec2((float)pixel.x() + testSquarePos + testSquareSize, (float)pixel.y() + testSquarePos + 0.0f),
588*35238bceSAndroid Build Coastguard Worker     };
589*35238bceSAndroid Build Coastguard Worker 
590*35238bceSAndroid Build Coastguard Worker     // calculate interpolation as a line
591*35238bceSAndroid Build Coastguard Worker     const LineInterpolationRange weights[4] = {
592*35238bceSAndroid Build Coastguard Worker         weightEquation(pa, wa, pb, wb, corners[0]),
593*35238bceSAndroid Build Coastguard Worker         weightEquation(pa, wa, pb, wb, corners[1]),
594*35238bceSAndroid Build Coastguard Worker         weightEquation(pa, wa, pb, wb, corners[2]),
595*35238bceSAndroid Build Coastguard Worker         weightEquation(pa, wa, pb, wb, corners[3]),
596*35238bceSAndroid Build Coastguard Worker     };
597*35238bceSAndroid Build Coastguard Worker 
598*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 minWeights =
599*35238bceSAndroid Build Coastguard Worker         tcu::min(tcu::min(weights[0].min, weights[1].min), tcu::min(weights[2].min, weights[3].min));
600*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 maxWeights =
601*35238bceSAndroid Build Coastguard Worker         tcu::max(tcu::max(weights[0].max, weights[1].max), tcu::max(weights[2].max, weights[3].max));
602*35238bceSAndroid Build Coastguard Worker 
603*35238bceSAndroid Build Coastguard Worker     LineInterpolationRange result;
604*35238bceSAndroid Build Coastguard Worker     result.min = minWeights;
605*35238bceSAndroid Build Coastguard Worker     result.max = maxWeights;
606*35238bceSAndroid Build Coastguard Worker     return result;
607*35238bceSAndroid Build Coastguard Worker }
608*35238bceSAndroid Build Coastguard Worker 
calcSingleSampleLineInterpolationRange(const tcu::Vec2 & pa,float wa,const tcu::Vec2 & pb,float wb,const tcu::IVec2 & pixel,int subpixelBits)609*35238bceSAndroid Build Coastguard Worker LineInterpolationRange calcSingleSampleLineInterpolationRange(const tcu::Vec2 &pa, float wa, const tcu::Vec2 &pb,
610*35238bceSAndroid Build Coastguard Worker                                                               float wb, const tcu::IVec2 &pixel, int subpixelBits)
611*35238bceSAndroid Build Coastguard Worker {
612*35238bceSAndroid Build Coastguard Worker     return calcSingleSampleLineInterpolationRangeWithWeightEquation(pa, wa, pb, wb, pixel, subpixelBits,
613*35238bceSAndroid Build Coastguard Worker                                                                     calcLineInterpolationWeights);
614*35238bceSAndroid Build Coastguard Worker }
615*35238bceSAndroid Build Coastguard Worker 
calcSingleSampleLineInterpolationRangeAxisProjected(const tcu::Vec2 & pa,float wa,const tcu::Vec2 & pb,float wb,const tcu::IVec2 & pixel,int subpixelBits)616*35238bceSAndroid Build Coastguard Worker LineInterpolationRange calcSingleSampleLineInterpolationRangeAxisProjected(const tcu::Vec2 &pa, float wa,
617*35238bceSAndroid Build Coastguard Worker                                                                            const tcu::Vec2 &pb, float wb,
618*35238bceSAndroid Build Coastguard Worker                                                                            const tcu::IVec2 &pixel, int subpixelBits)
619*35238bceSAndroid Build Coastguard Worker {
620*35238bceSAndroid Build Coastguard Worker     return calcSingleSampleLineInterpolationRangeWithWeightEquation(pa, wa, pb, wb, pixel, subpixelBits,
621*35238bceSAndroid Build Coastguard Worker                                                                     calcLineInterpolationWeightsAxisProjected);
622*35238bceSAndroid Build Coastguard Worker }
623*35238bceSAndroid Build Coastguard Worker 
624*35238bceSAndroid Build Coastguard Worker struct TriangleInterpolator
625*35238bceSAndroid Build Coastguard Worker {
626*35238bceSAndroid Build Coastguard Worker     const TriangleSceneSpec &scene;
627*35238bceSAndroid Build Coastguard Worker 
TriangleInterpolatortcu::__anone85a11dd0111::TriangleInterpolator628*35238bceSAndroid Build Coastguard Worker     TriangleInterpolator(const TriangleSceneSpec &scene_) : scene(scene_)
629*35238bceSAndroid Build Coastguard Worker     {
630*35238bceSAndroid Build Coastguard Worker     }
631*35238bceSAndroid Build Coastguard Worker 
interpolatetcu::__anone85a11dd0111::TriangleInterpolator632*35238bceSAndroid Build Coastguard Worker     InterpolationRange interpolate(int primitiveNdx, const tcu::IVec2 pixel, const tcu::IVec2 viewportSize,
633*35238bceSAndroid Build Coastguard Worker                                    bool multisample, int subpixelBits) const
634*35238bceSAndroid Build Coastguard Worker     {
635*35238bceSAndroid Build Coastguard Worker         // allow anywhere in the pixel area in multisample
636*35238bceSAndroid Build Coastguard Worker         // allow only in the center subpixels (4 subpixels) in singlesample
637*35238bceSAndroid Build Coastguard Worker         const float testSquareSize = (multisample) ? (1.0f) : (2.0f / (float)(1UL << subpixelBits));
638*35238bceSAndroid Build Coastguard Worker         const float testSquarePos  = (multisample) ? (0.0f) : (0.5f - testSquareSize / 2);
639*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 corners[4] = {
640*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(((float)pixel.x() + testSquarePos + 0.0f) / (float)viewportSize.x() * 2.0f - 1.0f,
641*35238bceSAndroid Build Coastguard Worker                       ((float)pixel.y() + testSquarePos + 0.0f) / (float)viewportSize.y() * 2.0f - 1.0f),
642*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(((float)pixel.x() + testSquarePos + 0.0f) / (float)viewportSize.x() * 2.0f - 1.0f,
643*35238bceSAndroid Build Coastguard Worker                       ((float)pixel.y() + testSquarePos + testSquareSize) / (float)viewportSize.y() * 2.0f - 1.0f),
644*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(((float)pixel.x() + testSquarePos + testSquareSize) / (float)viewportSize.x() * 2.0f - 1.0f,
645*35238bceSAndroid Build Coastguard Worker                       ((float)pixel.y() + testSquarePos + testSquareSize) / (float)viewportSize.y() * 2.0f - 1.0f),
646*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(((float)pixel.x() + testSquarePos + testSquareSize) / (float)viewportSize.x() * 2.0f - 1.0f,
647*35238bceSAndroid Build Coastguard Worker                       ((float)pixel.y() + testSquarePos + 0.0f) / (float)viewportSize.y() * 2.0f - 1.0f),
648*35238bceSAndroid Build Coastguard Worker         };
649*35238bceSAndroid Build Coastguard Worker         const InterpolationRange weights[4] = {
650*35238bceSAndroid Build Coastguard Worker             calcTriangleInterpolationWeights(scene.triangles[primitiveNdx].positions[0],
651*35238bceSAndroid Build Coastguard Worker                                              scene.triangles[primitiveNdx].positions[1],
652*35238bceSAndroid Build Coastguard Worker                                              scene.triangles[primitiveNdx].positions[2], corners[0]),
653*35238bceSAndroid Build Coastguard Worker             calcTriangleInterpolationWeights(scene.triangles[primitiveNdx].positions[0],
654*35238bceSAndroid Build Coastguard Worker                                              scene.triangles[primitiveNdx].positions[1],
655*35238bceSAndroid Build Coastguard Worker                                              scene.triangles[primitiveNdx].positions[2], corners[1]),
656*35238bceSAndroid Build Coastguard Worker             calcTriangleInterpolationWeights(scene.triangles[primitiveNdx].positions[0],
657*35238bceSAndroid Build Coastguard Worker                                              scene.triangles[primitiveNdx].positions[1],
658*35238bceSAndroid Build Coastguard Worker                                              scene.triangles[primitiveNdx].positions[2], corners[2]),
659*35238bceSAndroid Build Coastguard Worker             calcTriangleInterpolationWeights(scene.triangles[primitiveNdx].positions[0],
660*35238bceSAndroid Build Coastguard Worker                                              scene.triangles[primitiveNdx].positions[1],
661*35238bceSAndroid Build Coastguard Worker                                              scene.triangles[primitiveNdx].positions[2], corners[3]),
662*35238bceSAndroid Build Coastguard Worker         };
663*35238bceSAndroid Build Coastguard Worker 
664*35238bceSAndroid Build Coastguard Worker         InterpolationRange result;
665*35238bceSAndroid Build Coastguard Worker         result.min = tcu::min(tcu::min(weights[0].min, weights[1].min), tcu::min(weights[2].min, weights[3].min));
666*35238bceSAndroid Build Coastguard Worker         result.max = tcu::max(tcu::max(weights[0].max, weights[1].max), tcu::max(weights[2].max, weights[3].max));
667*35238bceSAndroid Build Coastguard Worker         return result;
668*35238bceSAndroid Build Coastguard Worker     }
669*35238bceSAndroid Build Coastguard Worker };
670*35238bceSAndroid Build Coastguard Worker 
671*35238bceSAndroid Build Coastguard Worker /*--------------------------------------------------------------------*//*!
672*35238bceSAndroid Build Coastguard Worker  * Used only by verifyMultisampleLineGroupInterpolation to calculate
673*35238bceSAndroid Build Coastguard Worker  * correct line interpolations for the triangulated lines.
674*35238bceSAndroid Build Coastguard Worker  *//*--------------------------------------------------------------------*/
675*35238bceSAndroid Build Coastguard Worker struct MultisampleLineInterpolator
676*35238bceSAndroid Build Coastguard Worker {
677*35238bceSAndroid Build Coastguard Worker     const LineSceneSpec &scene;
678*35238bceSAndroid Build Coastguard Worker 
MultisampleLineInterpolatortcu::__anone85a11dd0111::MultisampleLineInterpolator679*35238bceSAndroid Build Coastguard Worker     MultisampleLineInterpolator(const LineSceneSpec &scene_) : scene(scene_)
680*35238bceSAndroid Build Coastguard Worker     {
681*35238bceSAndroid Build Coastguard Worker     }
682*35238bceSAndroid Build Coastguard Worker 
interpolatetcu::__anone85a11dd0111::MultisampleLineInterpolator683*35238bceSAndroid Build Coastguard Worker     InterpolationRange interpolate(int primitiveNdx, const tcu::IVec2 pixel, const tcu::IVec2 viewportSize,
684*35238bceSAndroid Build Coastguard Worker                                    bool multisample, int subpixelBits) const
685*35238bceSAndroid Build Coastguard Worker     {
686*35238bceSAndroid Build Coastguard Worker         DE_UNREF(multisample);
687*35238bceSAndroid Build Coastguard Worker         DE_UNREF(subpixelBits);
688*35238bceSAndroid Build Coastguard Worker 
689*35238bceSAndroid Build Coastguard Worker         // in triangulation, one line emits two triangles
690*35238bceSAndroid Build Coastguard Worker         const int lineNdx = primitiveNdx / 2;
691*35238bceSAndroid Build Coastguard Worker 
692*35238bceSAndroid Build Coastguard Worker         // allow interpolation weights anywhere in the pixel
693*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 corners[4] = {
694*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)pixel.x() + 0.0f, (float)pixel.y() + 0.0f),
695*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)pixel.x() + 0.0f, (float)pixel.y() + 1.0f),
696*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)pixel.x() + 1.0f, (float)pixel.y() + 1.0f),
697*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)pixel.x() + 1.0f, (float)pixel.y() + 0.0f),
698*35238bceSAndroid Build Coastguard Worker         };
699*35238bceSAndroid Build Coastguard Worker 
700*35238bceSAndroid Build Coastguard Worker         const float wa = scene.lines[lineNdx].positions[0].w();
701*35238bceSAndroid Build Coastguard Worker         const float wb = scene.lines[lineNdx].positions[1].w();
702*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 pa =
703*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((scene.lines[lineNdx].positions[0].x() / wa + 1.0f) * 0.5f * (float)viewportSize.x(),
704*35238bceSAndroid Build Coastguard Worker                       (scene.lines[lineNdx].positions[0].y() / wa + 1.0f) * 0.5f * (float)viewportSize.y());
705*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 pb =
706*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((scene.lines[lineNdx].positions[1].x() / wb + 1.0f) * 0.5f * (float)viewportSize.x(),
707*35238bceSAndroid Build Coastguard Worker                       (scene.lines[lineNdx].positions[1].y() / wb + 1.0f) * 0.5f * (float)viewportSize.y());
708*35238bceSAndroid Build Coastguard Worker 
709*35238bceSAndroid Build Coastguard Worker         // calculate interpolation as a line
710*35238bceSAndroid Build Coastguard Worker         const LineInterpolationRange weights[4] = {
711*35238bceSAndroid Build Coastguard Worker             calcLineInterpolationWeights(pa, wa, pb, wb, corners[0]),
712*35238bceSAndroid Build Coastguard Worker             calcLineInterpolationWeights(pa, wa, pb, wb, corners[1]),
713*35238bceSAndroid Build Coastguard Worker             calcLineInterpolationWeights(pa, wa, pb, wb, corners[2]),
714*35238bceSAndroid Build Coastguard Worker             calcLineInterpolationWeights(pa, wa, pb, wb, corners[3]),
715*35238bceSAndroid Build Coastguard Worker         };
716*35238bceSAndroid Build Coastguard Worker 
717*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 minWeights =
718*35238bceSAndroid Build Coastguard Worker             tcu::min(tcu::min(weights[0].min, weights[1].min), tcu::min(weights[2].min, weights[3].min));
719*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 maxWeights =
720*35238bceSAndroid Build Coastguard Worker             tcu::max(tcu::max(weights[0].max, weights[1].max), tcu::max(weights[2].max, weights[3].max));
721*35238bceSAndroid Build Coastguard Worker 
722*35238bceSAndroid Build Coastguard Worker         // 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
723*35238bceSAndroid Build Coastguard Worker         InterpolationRange result;
724*35238bceSAndroid Build Coastguard Worker         result.min = tcu::Vec3(minWeights.x(), 0.0f, minWeights.y());
725*35238bceSAndroid Build Coastguard Worker         result.max = tcu::Vec3(maxWeights.x(), 0.0f, maxWeights.y());
726*35238bceSAndroid Build Coastguard Worker         return result;
727*35238bceSAndroid Build Coastguard Worker     }
728*35238bceSAndroid Build Coastguard Worker };
729*35238bceSAndroid Build Coastguard Worker 
730*35238bceSAndroid Build Coastguard Worker template <typename Interpolator>
verifyTriangleGroupInterpolationWithInterpolator(const tcu::Surface & surface,const TriangleSceneSpec & scene,const RasterizationArguments & args,VerifyTriangleGroupInterpolationLogStash & logStash,const Interpolator & interpolator)731*35238bceSAndroid Build Coastguard Worker bool verifyTriangleGroupInterpolationWithInterpolator(const tcu::Surface &surface, const TriangleSceneSpec &scene,
732*35238bceSAndroid Build Coastguard Worker                                                       const RasterizationArguments &args,
733*35238bceSAndroid Build Coastguard Worker                                                       VerifyTriangleGroupInterpolationLogStash &logStash,
734*35238bceSAndroid Build Coastguard Worker                                                       const Interpolator &interpolator)
735*35238bceSAndroid Build Coastguard Worker {
736*35238bceSAndroid Build Coastguard Worker     const tcu::RGBA invalidPixelColor = tcu::RGBA(255, 0, 0, 255);
737*35238bceSAndroid Build Coastguard Worker     const bool multisampled           = (args.numSamples != 0);
738*35238bceSAndroid Build Coastguard Worker     const tcu::IVec2 viewportSize     = tcu::IVec2(surface.getWidth(), surface.getHeight());
739*35238bceSAndroid Build Coastguard Worker     const int errorFloodThreshold     = 4;
740*35238bceSAndroid Build Coastguard Worker     int errorCount                    = 0;
741*35238bceSAndroid Build Coastguard Worker     int invalidPixels                 = 0;
742*35238bceSAndroid Build Coastguard Worker     int subPixelBits                  = args.subpixelBits;
743*35238bceSAndroid Build Coastguard Worker     tcu::Surface errorMask(surface.getWidth(), surface.getHeight());
744*35238bceSAndroid Build Coastguard Worker 
745*35238bceSAndroid Build Coastguard Worker     tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
746*35238bceSAndroid Build Coastguard Worker 
747*35238bceSAndroid Build Coastguard Worker     // log format
748*35238bceSAndroid Build Coastguard Worker 
749*35238bceSAndroid Build Coastguard Worker     logStash.messages.push_back(std::string("Verifying rasterization result. Native format is RGB" +
750*35238bceSAndroid Build Coastguard Worker                                             de::toString(args.redBits) + de::toString(args.greenBits) +
751*35238bceSAndroid Build Coastguard Worker                                             de::toString(args.blueBits)));
752*35238bceSAndroid Build Coastguard Worker     if (args.redBits > 8 || args.greenBits > 8 || args.blueBits > 8)
753*35238bceSAndroid Build Coastguard Worker         logStash.messages.push_back(
754*35238bceSAndroid Build Coastguard Worker             std::string("Warning! More than 8 bits in a color channel, this may produce false negatives."));
755*35238bceSAndroid Build Coastguard Worker 
756*35238bceSAndroid Build Coastguard Worker     // subpixel bits in a valid range?
757*35238bceSAndroid Build Coastguard Worker 
758*35238bceSAndroid Build Coastguard Worker     if (subPixelBits < 0)
759*35238bceSAndroid Build Coastguard Worker     {
760*35238bceSAndroid Build Coastguard Worker         logStash.messages.push_back(
761*35238bceSAndroid Build Coastguard Worker             std::string("Invalid subpixel count (" + de::toString(subPixelBits) + "), assuming 0"));
762*35238bceSAndroid Build Coastguard Worker         subPixelBits = 0;
763*35238bceSAndroid Build Coastguard Worker     }
764*35238bceSAndroid Build Coastguard Worker     else if (subPixelBits > 16)
765*35238bceSAndroid Build Coastguard Worker     {
766*35238bceSAndroid Build Coastguard Worker         // At high subpixel bit counts we might overflow. Checking at lower bit count is ok, but is less strict
767*35238bceSAndroid Build Coastguard Worker         logStash.messages.push_back(
768*35238bceSAndroid Build Coastguard Worker             std::string("Subpixel count is greater than 16 (" + de::toString(subPixelBits) +
769*35238bceSAndroid Build Coastguard Worker                         ")."
770*35238bceSAndroid Build Coastguard Worker                         " Checking results using less strict 16 bit requirements. This may produce false positives."));
771*35238bceSAndroid Build Coastguard Worker         subPixelBits = 16;
772*35238bceSAndroid Build Coastguard Worker     }
773*35238bceSAndroid Build Coastguard Worker 
774*35238bceSAndroid Build Coastguard Worker     // check pixels
775*35238bceSAndroid Build Coastguard Worker 
776*35238bceSAndroid Build Coastguard Worker     for (int y = 0; y < surface.getHeight(); ++y)
777*35238bceSAndroid Build Coastguard Worker         for (int x = 0; x < surface.getWidth(); ++x)
778*35238bceSAndroid Build Coastguard Worker         {
779*35238bceSAndroid Build Coastguard Worker             const tcu::RGBA color = surface.getPixel(x, y);
780*35238bceSAndroid Build Coastguard Worker             bool stackBottomFound = false;
781*35238bceSAndroid Build Coastguard Worker             int stackSize         = 0;
782*35238bceSAndroid Build Coastguard Worker             tcu::Vec4 colorStackMin;
783*35238bceSAndroid Build Coastguard Worker             tcu::Vec4 colorStackMax;
784*35238bceSAndroid Build Coastguard Worker 
785*35238bceSAndroid Build Coastguard Worker             // Iterate triangle coverage front to back, find the stack of pontentially contributing fragments
786*35238bceSAndroid Build Coastguard Worker             for (int triNdx = (int)scene.triangles.size() - 1; triNdx >= 0; --triNdx)
787*35238bceSAndroid Build Coastguard Worker             {
788*35238bceSAndroid Build Coastguard Worker                 const CoverageType coverage = calculateTriangleCoverage(
789*35238bceSAndroid Build Coastguard Worker                     scene.triangles[triNdx].positions[0], scene.triangles[triNdx].positions[1],
790*35238bceSAndroid Build Coastguard Worker                     scene.triangles[triNdx].positions[2], tcu::IVec2(x, y), viewportSize, subPixelBits, multisampled);
791*35238bceSAndroid Build Coastguard Worker 
792*35238bceSAndroid Build Coastguard Worker                 if (coverage == COVERAGE_FULL || coverage == COVERAGE_PARTIAL)
793*35238bceSAndroid Build Coastguard Worker                 {
794*35238bceSAndroid Build Coastguard Worker                     // potentially contributes to the result fragment's value
795*35238bceSAndroid Build Coastguard Worker                     const InterpolationRange weights =
796*35238bceSAndroid Build Coastguard Worker                         interpolator.interpolate(triNdx, tcu::IVec2(x, y), viewportSize, multisampled, subPixelBits);
797*35238bceSAndroid Build Coastguard Worker 
798*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec4 fragmentColorMax =
799*35238bceSAndroid Build Coastguard Worker                         de::clamp(weights.max.x(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[0] +
800*35238bceSAndroid Build Coastguard Worker                         de::clamp(weights.max.y(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[1] +
801*35238bceSAndroid Build Coastguard Worker                         de::clamp(weights.max.z(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[2];
802*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec4 fragmentColorMin =
803*35238bceSAndroid Build Coastguard Worker                         de::clamp(weights.min.x(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[0] +
804*35238bceSAndroid Build Coastguard Worker                         de::clamp(weights.min.y(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[1] +
805*35238bceSAndroid Build Coastguard Worker                         de::clamp(weights.min.z(), 0.0f, 1.0f) * scene.triangles[triNdx].colors[2];
806*35238bceSAndroid Build Coastguard Worker 
807*35238bceSAndroid Build Coastguard Worker                     if (stackSize++ == 0)
808*35238bceSAndroid Build Coastguard Worker                     {
809*35238bceSAndroid Build Coastguard Worker                         // first triangle, set the values properly
810*35238bceSAndroid Build Coastguard Worker                         colorStackMin = fragmentColorMin;
811*35238bceSAndroid Build Coastguard Worker                         colorStackMax = fragmentColorMax;
812*35238bceSAndroid Build Coastguard Worker                     }
813*35238bceSAndroid Build Coastguard Worker                     else
814*35238bceSAndroid Build Coastguard Worker                     {
815*35238bceSAndroid Build Coastguard Worker                         // contributing triangle
816*35238bceSAndroid Build Coastguard Worker                         colorStackMin = tcu::min(colorStackMin, fragmentColorMin);
817*35238bceSAndroid Build Coastguard Worker                         colorStackMax = tcu::max(colorStackMax, fragmentColorMax);
818*35238bceSAndroid Build Coastguard Worker                     }
819*35238bceSAndroid Build Coastguard Worker 
820*35238bceSAndroid Build Coastguard Worker                     if (coverage == COVERAGE_FULL)
821*35238bceSAndroid Build Coastguard Worker                     {
822*35238bceSAndroid Build Coastguard Worker                         // loop terminates, this is the bottommost fragment
823*35238bceSAndroid Build Coastguard Worker                         stackBottomFound = true;
824*35238bceSAndroid Build Coastguard Worker                         break;
825*35238bceSAndroid Build Coastguard Worker                     }
826*35238bceSAndroid Build Coastguard Worker                 }
827*35238bceSAndroid Build Coastguard Worker             }
828*35238bceSAndroid Build Coastguard Worker 
829*35238bceSAndroid Build Coastguard Worker             // Partial coverage == background may be visible
830*35238bceSAndroid Build Coastguard Worker             if (stackSize != 0 && !stackBottomFound)
831*35238bceSAndroid Build Coastguard Worker             {
832*35238bceSAndroid Build Coastguard Worker                 stackSize++;
833*35238bceSAndroid Build Coastguard Worker                 colorStackMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
834*35238bceSAndroid Build Coastguard Worker             }
835*35238bceSAndroid Build Coastguard Worker 
836*35238bceSAndroid Build Coastguard Worker             // Is the result image color in the valid range.
837*35238bceSAndroid Build Coastguard Worker             if (stackSize == 0)
838*35238bceSAndroid Build Coastguard Worker             {
839*35238bceSAndroid Build Coastguard Worker                 // No coverage, allow only background (black, value=0)
840*35238bceSAndroid Build Coastguard Worker                 const tcu::IVec3 pixelNativeColor = convertRGB8ToNativeFormat(color, args);
841*35238bceSAndroid Build Coastguard Worker                 const int threshold               = 1;
842*35238bceSAndroid Build Coastguard Worker 
843*35238bceSAndroid Build Coastguard Worker                 if (pixelNativeColor.x() > threshold || pixelNativeColor.y() > threshold ||
844*35238bceSAndroid Build Coastguard Worker                     pixelNativeColor.z() > threshold)
845*35238bceSAndroid Build Coastguard Worker                 {
846*35238bceSAndroid Build Coastguard Worker                     ++errorCount;
847*35238bceSAndroid Build Coastguard Worker 
848*35238bceSAndroid Build Coastguard Worker                     // don't fill the logs with too much data
849*35238bceSAndroid Build Coastguard Worker                     if (errorCount < errorFloodThreshold)
850*35238bceSAndroid Build Coastguard Worker                     {
851*35238bceSAndroid Build Coastguard Worker                         std::ostringstream str;
852*35238bceSAndroid Build Coastguard Worker 
853*35238bceSAndroid Build Coastguard Worker                         str << "Found an invalid pixel at (" << x << "," << y << ")\n"
854*35238bceSAndroid Build Coastguard Worker                             << "\tPixel color:\t\t" << color << "\n"
855*35238bceSAndroid Build Coastguard Worker                             << "\tExpected background color.\n";
856*35238bceSAndroid Build Coastguard Worker 
857*35238bceSAndroid Build Coastguard Worker                         logStash.messages.push_back(str.str());
858*35238bceSAndroid Build Coastguard Worker                     }
859*35238bceSAndroid Build Coastguard Worker 
860*35238bceSAndroid Build Coastguard Worker                     ++invalidPixels;
861*35238bceSAndroid Build Coastguard Worker                     errorMask.setPixel(x, y, invalidPixelColor);
862*35238bceSAndroid Build Coastguard Worker                 }
863*35238bceSAndroid Build Coastguard Worker             }
864*35238bceSAndroid Build Coastguard Worker             else
865*35238bceSAndroid Build Coastguard Worker             {
866*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT(stackSize);
867*35238bceSAndroid Build Coastguard Worker 
868*35238bceSAndroid Build Coastguard Worker                 // Each additional step in the stack may cause conversion error of 1 bit due to undefined rounding direction
869*35238bceSAndroid Build Coastguard Worker                 const int thresholdRed   = stackSize - 1;
870*35238bceSAndroid Build Coastguard Worker                 const int thresholdGreen = stackSize - 1;
871*35238bceSAndroid Build Coastguard Worker                 const int thresholdBlue  = stackSize - 1;
872*35238bceSAndroid Build Coastguard Worker 
873*35238bceSAndroid Build Coastguard Worker                 const tcu::Vec3 valueRangeMin = tcu::Vec3(colorStackMin.xyz());
874*35238bceSAndroid Build Coastguard Worker                 const tcu::Vec3 valueRangeMax = tcu::Vec3(colorStackMax.xyz());
875*35238bceSAndroid Build Coastguard Worker 
876*35238bceSAndroid Build Coastguard Worker                 const tcu::IVec3 formatLimit((1 << args.redBits) - 1, (1 << args.greenBits) - 1,
877*35238bceSAndroid Build Coastguard Worker                                              (1 << args.blueBits) - 1);
878*35238bceSAndroid Build Coastguard Worker                 const tcu::Vec3 colorMinF(
879*35238bceSAndroid Build Coastguard Worker                     de::clamp(valueRangeMin.x() * (float)formatLimit.x(), 0.0f, (float)formatLimit.x()),
880*35238bceSAndroid Build Coastguard Worker                     de::clamp(valueRangeMin.y() * (float)formatLimit.y(), 0.0f, (float)formatLimit.y()),
881*35238bceSAndroid Build Coastguard Worker                     de::clamp(valueRangeMin.z() * (float)formatLimit.z(), 0.0f, (float)formatLimit.z()));
882*35238bceSAndroid Build Coastguard Worker                 const tcu::Vec3 colorMaxF(
883*35238bceSAndroid Build Coastguard Worker                     de::clamp(valueRangeMax.x() * (float)formatLimit.x(), 0.0f, (float)formatLimit.x()),
884*35238bceSAndroid Build Coastguard Worker                     de::clamp(valueRangeMax.y() * (float)formatLimit.y(), 0.0f, (float)formatLimit.y()),
885*35238bceSAndroid Build Coastguard Worker                     de::clamp(valueRangeMax.z() * (float)formatLimit.z(), 0.0f, (float)formatLimit.z()));
886*35238bceSAndroid Build Coastguard Worker                 const tcu::IVec3 colorMin((int)deFloatFloor(colorMinF.x()), (int)deFloatFloor(colorMinF.y()),
887*35238bceSAndroid Build Coastguard Worker                                           (int)deFloatFloor(colorMinF.z()));
888*35238bceSAndroid Build Coastguard Worker                 const tcu::IVec3 colorMax((int)deFloatCeil(colorMaxF.x()), (int)deFloatCeil(colorMaxF.y()),
889*35238bceSAndroid Build Coastguard Worker                                           (int)deFloatCeil(colorMaxF.z()));
890*35238bceSAndroid Build Coastguard Worker 
891*35238bceSAndroid Build Coastguard Worker                 // Convert pixel color from rgba8 to the real pixel format. Usually rgba8 or 565
892*35238bceSAndroid Build Coastguard Worker                 const tcu::IVec3 pixelNativeColor = convertRGB8ToNativeFormat(color, args);
893*35238bceSAndroid Build Coastguard Worker 
894*35238bceSAndroid Build Coastguard Worker                 // Validity check
895*35238bceSAndroid Build Coastguard Worker                 if (pixelNativeColor.x() < colorMin.x() - thresholdRed ||
896*35238bceSAndroid Build Coastguard Worker                     pixelNativeColor.y() < colorMin.y() - thresholdGreen ||
897*35238bceSAndroid Build Coastguard Worker                     pixelNativeColor.z() < colorMin.z() - thresholdBlue ||
898*35238bceSAndroid Build Coastguard Worker                     pixelNativeColor.x() > colorMax.x() + thresholdRed ||
899*35238bceSAndroid Build Coastguard Worker                     pixelNativeColor.y() > colorMax.y() + thresholdGreen ||
900*35238bceSAndroid Build Coastguard Worker                     pixelNativeColor.z() > colorMax.z() + thresholdBlue)
901*35238bceSAndroid Build Coastguard Worker                 {
902*35238bceSAndroid Build Coastguard Worker                     ++errorCount;
903*35238bceSAndroid Build Coastguard Worker 
904*35238bceSAndroid Build Coastguard Worker                     // don't fill the logs with too much data
905*35238bceSAndroid Build Coastguard Worker                     if (errorCount <= errorFloodThreshold)
906*35238bceSAndroid Build Coastguard Worker                     {
907*35238bceSAndroid Build Coastguard Worker                         std::ostringstream str;
908*35238bceSAndroid Build Coastguard Worker 
909*35238bceSAndroid Build Coastguard Worker                         str << "Found an invalid pixel at (" << x << "," << y << ")\n"
910*35238bceSAndroid Build Coastguard Worker                             << "\tPixel color:\t\t" << color << "\n"
911*35238bceSAndroid Build Coastguard Worker                             << "\tNative color:\t\t" << pixelNativeColor << "\n"
912*35238bceSAndroid Build Coastguard Worker                             << "\tAllowed error:\t\t" << tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue) << "\n"
913*35238bceSAndroid Build Coastguard Worker                             << "\tReference native color min: "
914*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(colorMin - tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue),
915*35238bceSAndroid Build Coastguard Worker                                           tcu::IVec3(0, 0, 0), formatLimit)
916*35238bceSAndroid Build Coastguard Worker                             << "\n"
917*35238bceSAndroid Build Coastguard Worker                             << "\tReference native color max: "
918*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(colorMax + tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue),
919*35238bceSAndroid Build Coastguard Worker                                           tcu::IVec3(0, 0, 0), formatLimit)
920*35238bceSAndroid Build Coastguard Worker                             << "\n"
921*35238bceSAndroid Build Coastguard Worker                             << "\tReference native float min: "
922*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(colorMinF -
923*35238bceSAndroid Build Coastguard Worker                                               tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue).cast<float>(),
924*35238bceSAndroid Build Coastguard Worker                                           tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>())
925*35238bceSAndroid Build Coastguard Worker                             << "\n"
926*35238bceSAndroid Build Coastguard Worker                             << "\tReference native float max: "
927*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(colorMaxF +
928*35238bceSAndroid Build Coastguard Worker                                               tcu::IVec3(thresholdRed, thresholdGreen, thresholdBlue).cast<float>(),
929*35238bceSAndroid Build Coastguard Worker                                           tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>())
930*35238bceSAndroid Build Coastguard Worker                             << "\n"
931*35238bceSAndroid Build Coastguard Worker                             << "\tFmin:\t"
932*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(valueRangeMin, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f))
933*35238bceSAndroid Build Coastguard Worker                             << "\n"
934*35238bceSAndroid Build Coastguard Worker                             << "\tFmax:\t"
935*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(valueRangeMax, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f))
936*35238bceSAndroid Build Coastguard Worker                             << "\n";
937*35238bceSAndroid Build Coastguard Worker                         logStash.messages.push_back(str.str());
938*35238bceSAndroid Build Coastguard Worker                     }
939*35238bceSAndroid Build Coastguard Worker 
940*35238bceSAndroid Build Coastguard Worker                     ++invalidPixels;
941*35238bceSAndroid Build Coastguard Worker                     errorMask.setPixel(x, y, invalidPixelColor);
942*35238bceSAndroid Build Coastguard Worker                 }
943*35238bceSAndroid Build Coastguard Worker             }
944*35238bceSAndroid Build Coastguard Worker         }
945*35238bceSAndroid Build Coastguard Worker 
946*35238bceSAndroid Build Coastguard Worker     // don't just hide failures
947*35238bceSAndroid Build Coastguard Worker     if (errorCount > errorFloodThreshold)
948*35238bceSAndroid Build Coastguard Worker         logStash.messages.push_back(
949*35238bceSAndroid Build Coastguard Worker             std::string("Omitted " + de::toString(errorCount - errorFloodThreshold) + " pixel error description(s)."));
950*35238bceSAndroid Build Coastguard Worker 
951*35238bceSAndroid Build Coastguard Worker     logStash.success       = (invalidPixels == 0);
952*35238bceSAndroid Build Coastguard Worker     logStash.invalidPixels = invalidPixels;
953*35238bceSAndroid Build Coastguard Worker 
954*35238bceSAndroid Build Coastguard Worker     // report result
955*35238bceSAndroid Build Coastguard Worker     if (!logStash.success)
956*35238bceSAndroid Build Coastguard Worker         logStash.errorMask = errorMask;
957*35238bceSAndroid Build Coastguard Worker 
958*35238bceSAndroid Build Coastguard Worker     return logStash.success;
959*35238bceSAndroid Build Coastguard Worker }
960*35238bceSAndroid Build Coastguard Worker 
calculateIntersectionParameter(const tcu::Vec2 line[2],float w,int componentNdx)961*35238bceSAndroid Build Coastguard Worker float calculateIntersectionParameter(const tcu::Vec2 line[2], float w, int componentNdx)
962*35238bceSAndroid Build Coastguard Worker {
963*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(componentNdx < 2);
964*35238bceSAndroid Build Coastguard Worker     if (line[1][componentNdx] == line[0][componentNdx])
965*35238bceSAndroid Build Coastguard Worker         return -1.0f;
966*35238bceSAndroid Build Coastguard Worker 
967*35238bceSAndroid Build Coastguard Worker     return (w - line[0][componentNdx]) / (line[1][componentNdx] - line[0][componentNdx]);
968*35238bceSAndroid Build Coastguard Worker }
969*35238bceSAndroid Build Coastguard Worker 
970*35238bceSAndroid Build Coastguard Worker // Clips the given line with a ((-w, -w), (-w, w), (w, w), (w, -w)) rectangle
applyClippingBox(tcu::Vec2 line[2],float w)971*35238bceSAndroid Build Coastguard Worker void applyClippingBox(tcu::Vec2 line[2], float w)
972*35238bceSAndroid Build Coastguard Worker {
973*35238bceSAndroid Build Coastguard Worker     for (int side = 0; side < 4; ++side)
974*35238bceSAndroid Build Coastguard Worker     {
975*35238bceSAndroid Build Coastguard Worker         const int sign      = ((side / 2) * -2) + 1;
976*35238bceSAndroid Build Coastguard Worker         const int component = side % 2;
977*35238bceSAndroid Build Coastguard Worker         const float t       = calculateIntersectionParameter(line, w * (float)sign, component);
978*35238bceSAndroid Build Coastguard Worker 
979*35238bceSAndroid Build Coastguard Worker         if ((t > 0) && (t < 1))
980*35238bceSAndroid Build Coastguard Worker         {
981*35238bceSAndroid Build Coastguard Worker             const float newCoord = t * line[1][1 - component] + (1 - t) * line[0][1 - component];
982*35238bceSAndroid Build Coastguard Worker 
983*35238bceSAndroid Build Coastguard Worker             if (line[1][component] > (w * (float)sign))
984*35238bceSAndroid Build Coastguard Worker             {
985*35238bceSAndroid Build Coastguard Worker                 line[1 - side / 2][component]     = w * (float)sign;
986*35238bceSAndroid Build Coastguard Worker                 line[1 - side / 2][1 - component] = newCoord;
987*35238bceSAndroid Build Coastguard Worker             }
988*35238bceSAndroid Build Coastguard Worker             else
989*35238bceSAndroid Build Coastguard Worker             {
990*35238bceSAndroid Build Coastguard Worker                 line[side / 2][component]     = w * (float)sign;
991*35238bceSAndroid Build Coastguard Worker                 line[side / 2][1 - component] = newCoord;
992*35238bceSAndroid Build Coastguard Worker             }
993*35238bceSAndroid Build Coastguard Worker         }
994*35238bceSAndroid Build Coastguard Worker     }
995*35238bceSAndroid Build Coastguard Worker }
996*35238bceSAndroid Build Coastguard Worker 
997*35238bceSAndroid Build Coastguard Worker enum ClipMode
998*35238bceSAndroid Build Coastguard Worker {
999*35238bceSAndroid Build Coastguard Worker     CLIPMODE_NO_CLIPPING = 0,
1000*35238bceSAndroid Build Coastguard Worker     CLIPMODE_USE_CLIPPING_BOX,
1001*35238bceSAndroid Build Coastguard Worker 
1002*35238bceSAndroid Build Coastguard Worker     CLIPMODE_LAST
1003*35238bceSAndroid Build Coastguard Worker };
1004*35238bceSAndroid Build Coastguard Worker 
verifyMultisampleLineGroupRasterization(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log,ClipMode clipMode,VerifyTriangleGroupRasterizationLogStash * logStash,const bool vulkanLinesTest,const bool strictMode,const bool carryRemainder)1005*35238bceSAndroid Build Coastguard Worker bool verifyMultisampleLineGroupRasterization(const tcu::Surface &surface, const LineSceneSpec &scene,
1006*35238bceSAndroid Build Coastguard Worker                                              const RasterizationArguments &args, tcu::TestLog &log, ClipMode clipMode,
1007*35238bceSAndroid Build Coastguard Worker                                              VerifyTriangleGroupRasterizationLogStash *logStash,
1008*35238bceSAndroid Build Coastguard Worker                                              const bool vulkanLinesTest, const bool strictMode,
1009*35238bceSAndroid Build Coastguard Worker                                              const bool carryRemainder)
1010*35238bceSAndroid Build Coastguard Worker {
1011*35238bceSAndroid Build Coastguard Worker     // Multisampled line == 2 triangles
1012*35238bceSAndroid Build Coastguard Worker 
1013*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 viewportSize = tcu::Vec2((float)surface.getWidth(), (float)surface.getHeight());
1014*35238bceSAndroid Build Coastguard Worker     const float halfLineWidth    = scene.lineWidth * 0.5f;
1015*35238bceSAndroid Build Coastguard Worker     TriangleSceneSpec triangleScene;
1016*35238bceSAndroid Build Coastguard Worker 
1017*35238bceSAndroid Build Coastguard Worker     uint32_t stippleCounter = 0;
1018*35238bceSAndroid Build Coastguard Worker     float leftoverPhase     = 0.0f;
1019*35238bceSAndroid Build Coastguard Worker 
1020*35238bceSAndroid Build Coastguard Worker     triangleScene.triangles.resize(2 * scene.lines.size());
1021*35238bceSAndroid Build Coastguard Worker     for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
1022*35238bceSAndroid Build Coastguard Worker     {
1023*35238bceSAndroid Build Coastguard Worker 
1024*35238bceSAndroid Build Coastguard Worker         if (!scene.isStrip)
1025*35238bceSAndroid Build Coastguard Worker         {
1026*35238bceSAndroid Build Coastguard Worker             // reset stipple at the start of each line segment
1027*35238bceSAndroid Build Coastguard Worker             stippleCounter = 0;
1028*35238bceSAndroid Build Coastguard Worker             leftoverPhase  = 0;
1029*35238bceSAndroid Build Coastguard Worker         }
1030*35238bceSAndroid Build Coastguard Worker 
1031*35238bceSAndroid Build Coastguard Worker         // Transform to screen space, add pixel offsets, convert back to normalized device space, and test as triangles
1032*35238bceSAndroid Build Coastguard Worker         tcu::Vec2 lineNormalizedDeviceSpace[2] = {
1033*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(scene.lines[lineNdx].positions[0].x() / scene.lines[lineNdx].positions[0].w(),
1034*35238bceSAndroid Build Coastguard Worker                       scene.lines[lineNdx].positions[0].y() / scene.lines[lineNdx].positions[0].w()),
1035*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(scene.lines[lineNdx].positions[1].x() / scene.lines[lineNdx].positions[1].w(),
1036*35238bceSAndroid Build Coastguard Worker                       scene.lines[lineNdx].positions[1].y() / scene.lines[lineNdx].positions[1].w()),
1037*35238bceSAndroid Build Coastguard Worker         };
1038*35238bceSAndroid Build Coastguard Worker 
1039*35238bceSAndroid Build Coastguard Worker         if (clipMode == CLIPMODE_USE_CLIPPING_BOX)
1040*35238bceSAndroid Build Coastguard Worker         {
1041*35238bceSAndroid Build Coastguard Worker             applyClippingBox(lineNormalizedDeviceSpace, 1.0f);
1042*35238bceSAndroid Build Coastguard Worker         }
1043*35238bceSAndroid Build Coastguard Worker 
1044*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineScreenSpace[2] = {
1045*35238bceSAndroid Build Coastguard Worker             (lineNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize,
1046*35238bceSAndroid Build Coastguard Worker             (lineNormalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize,
1047*35238bceSAndroid Build Coastguard Worker         };
1048*35238bceSAndroid Build Coastguard Worker 
1049*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineDir       = tcu::normalize(lineScreenSpace[1] - lineScreenSpace[0]);
1050*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineNormalDir = (strictMode || scene.isRectangular) ? tcu::Vec2(lineDir.y(), -lineDir.x()) :
1051*35238bceSAndroid Build Coastguard Worker                                         isLineXMajor(lineScreenSpace[0], lineScreenSpace[1]) ? tcu::Vec2(0.0f, 1.0f) :
1052*35238bceSAndroid Build Coastguard Worker                                                                                                tcu::Vec2(1.0f, 0.0f);
1053*35238bceSAndroid Build Coastguard Worker 
1054*35238bceSAndroid Build Coastguard Worker         if (scene.stippleEnable)
1055*35238bceSAndroid Build Coastguard Worker         {
1056*35238bceSAndroid Build Coastguard Worker             float lineLength = tcu::distance(lineScreenSpace[0], lineScreenSpace[1]);
1057*35238bceSAndroid Build Coastguard Worker             float lineOffset = 0.0f;
1058*35238bceSAndroid Build Coastguard Worker 
1059*35238bceSAndroid Build Coastguard Worker             while (lineOffset < lineLength)
1060*35238bceSAndroid Build Coastguard Worker             {
1061*35238bceSAndroid Build Coastguard Worker                 float d0 = (float)lineOffset;
1062*35238bceSAndroid Build Coastguard Worker                 float d1 = d0 + 1.0f;
1063*35238bceSAndroid Build Coastguard Worker 
1064*35238bceSAndroid Build Coastguard Worker                 if (carryRemainder)
1065*35238bceSAndroid Build Coastguard Worker                 {
1066*35238bceSAndroid Build Coastguard Worker                     // "leftoverPhase" carries over a fractional stipple phase that was "unused"
1067*35238bceSAndroid Build Coastguard Worker                     // by the last line segment in the strip, if it wasn't an integer length.
1068*35238bceSAndroid Build Coastguard Worker                     if (leftoverPhase > lineLength)
1069*35238bceSAndroid Build Coastguard Worker                     {
1070*35238bceSAndroid Build Coastguard Worker                         DE_ASSERT(d0 == 0.0f);
1071*35238bceSAndroid Build Coastguard Worker                         d1 = lineLength;
1072*35238bceSAndroid Build Coastguard Worker                         leftoverPhase -= lineLength;
1073*35238bceSAndroid Build Coastguard Worker                     }
1074*35238bceSAndroid Build Coastguard Worker                     else if (leftoverPhase != 0.0f)
1075*35238bceSAndroid Build Coastguard Worker                     {
1076*35238bceSAndroid Build Coastguard Worker                         DE_ASSERT(d0 == 0.0f);
1077*35238bceSAndroid Build Coastguard Worker                         d1            = leftoverPhase;
1078*35238bceSAndroid Build Coastguard Worker                         leftoverPhase = 0.0f;
1079*35238bceSAndroid Build Coastguard Worker                     }
1080*35238bceSAndroid Build Coastguard Worker                     else
1081*35238bceSAndroid Build Coastguard Worker                     {
1082*35238bceSAndroid Build Coastguard Worker                         if (d0 + 1.0f > lineLength)
1083*35238bceSAndroid Build Coastguard Worker                         {
1084*35238bceSAndroid Build Coastguard Worker                             d1            = lineLength;
1085*35238bceSAndroid Build Coastguard Worker                             leftoverPhase = d0 + 1.0f - lineLength;
1086*35238bceSAndroid Build Coastguard Worker                         }
1087*35238bceSAndroid Build Coastguard Worker                         else
1088*35238bceSAndroid Build Coastguard Worker                             d1 = d0 + 1.0f;
1089*35238bceSAndroid Build Coastguard Worker                     }
1090*35238bceSAndroid Build Coastguard Worker                 }
1091*35238bceSAndroid Build Coastguard Worker                 else
1092*35238bceSAndroid Build Coastguard Worker                 {
1093*35238bceSAndroid Build Coastguard Worker                     if (d1 > lineLength)
1094*35238bceSAndroid Build Coastguard Worker                         d1 = lineLength;
1095*35238bceSAndroid Build Coastguard Worker                 }
1096*35238bceSAndroid Build Coastguard Worker 
1097*35238bceSAndroid Build Coastguard Worker                 // set offset for next iteration
1098*35238bceSAndroid Build Coastguard Worker                 lineOffset = d1;
1099*35238bceSAndroid Build Coastguard Worker 
1100*35238bceSAndroid Build Coastguard Worker                 int stippleBit   = (stippleCounter / scene.stippleFactor) % 16;
1101*35238bceSAndroid Build Coastguard Worker                 bool stipplePass = (scene.stipplePattern & (1 << stippleBit)) != 0;
1102*35238bceSAndroid Build Coastguard Worker 
1103*35238bceSAndroid Build Coastguard Worker                 if (leftoverPhase == 0)
1104*35238bceSAndroid Build Coastguard Worker                     stippleCounter++;
1105*35238bceSAndroid Build Coastguard Worker 
1106*35238bceSAndroid Build Coastguard Worker                 if (!stipplePass)
1107*35238bceSAndroid Build Coastguard Worker                     continue;
1108*35238bceSAndroid Build Coastguard Worker 
1109*35238bceSAndroid Build Coastguard Worker                 d0 /= lineLength;
1110*35238bceSAndroid Build Coastguard Worker                 d1 /= lineLength;
1111*35238bceSAndroid Build Coastguard Worker 
1112*35238bceSAndroid Build Coastguard Worker                 tcu::Vec2 l0 = mix(lineScreenSpace[0], lineScreenSpace[1], d0);
1113*35238bceSAndroid Build Coastguard Worker                 tcu::Vec2 l1 = mix(lineScreenSpace[0], lineScreenSpace[1], d1);
1114*35238bceSAndroid Build Coastguard Worker 
1115*35238bceSAndroid Build Coastguard Worker                 const tcu::Vec2 lineQuadScreenSpace[4] = {
1116*35238bceSAndroid Build Coastguard Worker                     l0 + lineNormalDir * halfLineWidth,
1117*35238bceSAndroid Build Coastguard Worker                     l0 - lineNormalDir * halfLineWidth,
1118*35238bceSAndroid Build Coastguard Worker                     l1 - lineNormalDir * halfLineWidth,
1119*35238bceSAndroid Build Coastguard Worker                     l1 + lineNormalDir * halfLineWidth,
1120*35238bceSAndroid Build Coastguard Worker                 };
1121*35238bceSAndroid Build Coastguard Worker                 const tcu::Vec2 lineQuadNormalizedDeviceSpace[4] = {
1122*35238bceSAndroid Build Coastguard Worker                     lineQuadScreenSpace[0] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1123*35238bceSAndroid Build Coastguard Worker                     lineQuadScreenSpace[1] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1124*35238bceSAndroid Build Coastguard Worker                     lineQuadScreenSpace[2] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1125*35238bceSAndroid Build Coastguard Worker                     lineQuadScreenSpace[3] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1126*35238bceSAndroid Build Coastguard Worker                 };
1127*35238bceSAndroid Build Coastguard Worker 
1128*35238bceSAndroid Build Coastguard Worker                 TriangleSceneSpec::SceneTriangle tri;
1129*35238bceSAndroid Build Coastguard Worker 
1130*35238bceSAndroid Build Coastguard Worker                 tri.positions[0] =
1131*35238bceSAndroid Build Coastguard Worker                     tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);
1132*35238bceSAndroid Build Coastguard Worker                 tri.sharedEdge[0] = (d0 != 0.0f);
1133*35238bceSAndroid Build Coastguard Worker                 tri.positions[1] =
1134*35238bceSAndroid Build Coastguard Worker                     tcu::Vec4(lineQuadNormalizedDeviceSpace[1].x(), lineQuadNormalizedDeviceSpace[1].y(), 0.0f, 1.0f);
1135*35238bceSAndroid Build Coastguard Worker                 tri.sharedEdge[1] = false;
1136*35238bceSAndroid Build Coastguard Worker                 tri.positions[2] =
1137*35238bceSAndroid Build Coastguard Worker                     tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);
1138*35238bceSAndroid Build Coastguard Worker                 tri.sharedEdge[2] = true;
1139*35238bceSAndroid Build Coastguard Worker 
1140*35238bceSAndroid Build Coastguard Worker                 triangleScene.triangles.push_back(tri);
1141*35238bceSAndroid Build Coastguard Worker 
1142*35238bceSAndroid Build Coastguard Worker                 tri.positions[0] =
1143*35238bceSAndroid Build Coastguard Worker                     tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);
1144*35238bceSAndroid Build Coastguard Worker                 tri.sharedEdge[0] = true;
1145*35238bceSAndroid Build Coastguard Worker                 tri.positions[1] =
1146*35238bceSAndroid Build Coastguard Worker                     tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);
1147*35238bceSAndroid Build Coastguard Worker                 tri.sharedEdge[1] = (d1 != 1.0f);
1148*35238bceSAndroid Build Coastguard Worker                 tri.positions[2] =
1149*35238bceSAndroid Build Coastguard Worker                     tcu::Vec4(lineQuadNormalizedDeviceSpace[3].x(), lineQuadNormalizedDeviceSpace[3].y(), 0.0f, 1.0f);
1150*35238bceSAndroid Build Coastguard Worker                 tri.sharedEdge[2] = false;
1151*35238bceSAndroid Build Coastguard Worker 
1152*35238bceSAndroid Build Coastguard Worker                 triangleScene.triangles.push_back(tri);
1153*35238bceSAndroid Build Coastguard Worker             }
1154*35238bceSAndroid Build Coastguard Worker         }
1155*35238bceSAndroid Build Coastguard Worker         else
1156*35238bceSAndroid Build Coastguard Worker         {
1157*35238bceSAndroid Build Coastguard Worker             const tcu::Vec2 lineQuadScreenSpace[4] = {
1158*35238bceSAndroid Build Coastguard Worker                 lineScreenSpace[0] + lineNormalDir * halfLineWidth,
1159*35238bceSAndroid Build Coastguard Worker                 lineScreenSpace[0] - lineNormalDir * halfLineWidth,
1160*35238bceSAndroid Build Coastguard Worker                 lineScreenSpace[1] - lineNormalDir * halfLineWidth,
1161*35238bceSAndroid Build Coastguard Worker                 lineScreenSpace[1] + lineNormalDir * halfLineWidth,
1162*35238bceSAndroid Build Coastguard Worker             };
1163*35238bceSAndroid Build Coastguard Worker             const tcu::Vec2 lineQuadNormalizedDeviceSpace[4] = {
1164*35238bceSAndroid Build Coastguard Worker                 lineQuadScreenSpace[0] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1165*35238bceSAndroid Build Coastguard Worker                 lineQuadScreenSpace[1] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1166*35238bceSAndroid Build Coastguard Worker                 lineQuadScreenSpace[2] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1167*35238bceSAndroid Build Coastguard Worker                 lineQuadScreenSpace[3] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1168*35238bceSAndroid Build Coastguard Worker             };
1169*35238bceSAndroid Build Coastguard Worker 
1170*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 0].positions[0] =
1171*35238bceSAndroid Build Coastguard Worker                 tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);
1172*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 0].sharedEdge[0] = false;
1173*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 0].positions[1] =
1174*35238bceSAndroid Build Coastguard Worker                 tcu::Vec4(lineQuadNormalizedDeviceSpace[1].x(), lineQuadNormalizedDeviceSpace[1].y(), 0.0f, 1.0f);
1175*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 0].sharedEdge[1] = false;
1176*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 0].positions[2] =
1177*35238bceSAndroid Build Coastguard Worker                 tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);
1178*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 0].sharedEdge[2] = true;
1179*35238bceSAndroid Build Coastguard Worker 
1180*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 1].positions[0] =
1181*35238bceSAndroid Build Coastguard Worker                 tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);
1182*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 1].sharedEdge[0] = true;
1183*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 1].positions[1] =
1184*35238bceSAndroid Build Coastguard Worker                 tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);
1185*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 1].sharedEdge[1] = false;
1186*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 1].positions[2] =
1187*35238bceSAndroid Build Coastguard Worker                 tcu::Vec4(lineQuadNormalizedDeviceSpace[3].x(), lineQuadNormalizedDeviceSpace[3].y(), 0.0f, 1.0f);
1188*35238bceSAndroid Build Coastguard Worker             triangleScene.triangles[lineNdx * 2 + 1].sharedEdge[2] = false;
1189*35238bceSAndroid Build Coastguard Worker         }
1190*35238bceSAndroid Build Coastguard Worker     }
1191*35238bceSAndroid Build Coastguard Worker 
1192*35238bceSAndroid Build Coastguard Worker     if (logStash != DE_NULL)
1193*35238bceSAndroid Build Coastguard Worker     {
1194*35238bceSAndroid Build Coastguard Worker         logStash->messages.push_back(
1195*35238bceSAndroid Build Coastguard Worker             "Rasterization clipping mode: " +
1196*35238bceSAndroid Build Coastguard Worker             std::string(clipMode == CLIPMODE_USE_CLIPPING_BOX ? "CLIPMODE_USE_CLIPPING_BOX" : "CLIPMODE_NO_CLIPPING") +
1197*35238bceSAndroid Build Coastguard Worker             ".");
1198*35238bceSAndroid Build Coastguard Worker         logStash->messages.push_back(
1199*35238bceSAndroid Build Coastguard Worker             "Rasterization line draw strictness mode: " + std::string(strictMode ? "strict" : "non-strict") + ".");
1200*35238bceSAndroid Build Coastguard Worker     }
1201*35238bceSAndroid Build Coastguard Worker 
1202*35238bceSAndroid Build Coastguard Worker     return verifyTriangleGroupRasterization(surface, triangleScene, args, log, scene.verificationMode, logStash,
1203*35238bceSAndroid Build Coastguard Worker                                             vulkanLinesTest);
1204*35238bceSAndroid Build Coastguard Worker }
1205*35238bceSAndroid Build Coastguard Worker 
verifyMultisampleLineGroupRasterization(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log,ClipMode clipMode,VerifyTriangleGroupRasterizationLogStash * logStash,const bool vulkanLinesTest,const bool strictMode)1206*35238bceSAndroid Build Coastguard Worker bool verifyMultisampleLineGroupRasterization(const tcu::Surface &surface, const LineSceneSpec &scene,
1207*35238bceSAndroid Build Coastguard Worker                                              const RasterizationArguments &args, tcu::TestLog &log, ClipMode clipMode,
1208*35238bceSAndroid Build Coastguard Worker                                              VerifyTriangleGroupRasterizationLogStash *logStash,
1209*35238bceSAndroid Build Coastguard Worker                                              const bool vulkanLinesTest, const bool strictMode)
1210*35238bceSAndroid Build Coastguard Worker {
1211*35238bceSAndroid Build Coastguard Worker     if (scene.stippleEnable)
1212*35238bceSAndroid Build Coastguard Worker         return verifyMultisampleLineGroupRasterization(surface, scene, args, log, clipMode, logStash, vulkanLinesTest,
1213*35238bceSAndroid Build Coastguard Worker                                                        strictMode, true) ||
1214*35238bceSAndroid Build Coastguard Worker                verifyMultisampleLineGroupRasterization(surface, scene, args, log, clipMode, logStash, vulkanLinesTest,
1215*35238bceSAndroid Build Coastguard Worker                                                        strictMode, false);
1216*35238bceSAndroid Build Coastguard Worker     else
1217*35238bceSAndroid Build Coastguard Worker         return verifyMultisampleLineGroupRasterization(surface, scene, args, log, clipMode, logStash, vulkanLinesTest,
1218*35238bceSAndroid Build Coastguard Worker                                                        strictMode, true);
1219*35238bceSAndroid Build Coastguard Worker }
1220*35238bceSAndroid Build Coastguard Worker 
verifyMultisampleLineGroupInterpolationInternal(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,VerifyTriangleGroupInterpolationLogStash & logStash,const bool strictMode)1221*35238bceSAndroid Build Coastguard Worker static bool verifyMultisampleLineGroupInterpolationInternal(const tcu::Surface &surface, const LineSceneSpec &scene,
1222*35238bceSAndroid Build Coastguard Worker                                                             const RasterizationArguments &args,
1223*35238bceSAndroid Build Coastguard Worker                                                             VerifyTriangleGroupInterpolationLogStash &logStash,
1224*35238bceSAndroid Build Coastguard Worker                                                             const bool strictMode)
1225*35238bceSAndroid Build Coastguard Worker {
1226*35238bceSAndroid Build Coastguard Worker     // Multisampled line == 2 triangles
1227*35238bceSAndroid Build Coastguard Worker 
1228*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 viewportSize = tcu::Vec2((float)surface.getWidth(), (float)surface.getHeight());
1229*35238bceSAndroid Build Coastguard Worker     const float halfLineWidth    = scene.lineWidth * 0.5f;
1230*35238bceSAndroid Build Coastguard Worker     TriangleSceneSpec triangleScene;
1231*35238bceSAndroid Build Coastguard Worker 
1232*35238bceSAndroid Build Coastguard Worker     triangleScene.triangles.resize(2 * scene.lines.size());
1233*35238bceSAndroid Build Coastguard Worker     for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
1234*35238bceSAndroid Build Coastguard Worker     {
1235*35238bceSAndroid Build Coastguard Worker         // Need the w-coordinates a couple of times
1236*35238bceSAndroid Build Coastguard Worker         const float wa = scene.lines[lineNdx].positions[0].w();
1237*35238bceSAndroid Build Coastguard Worker         const float wb = scene.lines[lineNdx].positions[1].w();
1238*35238bceSAndroid Build Coastguard Worker 
1239*35238bceSAndroid Build Coastguard Worker         // Transform to screen space, add pixel offsets, convert back to normalized device space, and test as triangles
1240*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineNormalizedDeviceSpace[2] = {
1241*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(scene.lines[lineNdx].positions[0].x() / wa, scene.lines[lineNdx].positions[0].y() / wa),
1242*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(scene.lines[lineNdx].positions[1].x() / wb, scene.lines[lineNdx].positions[1].y() / wb),
1243*35238bceSAndroid Build Coastguard Worker         };
1244*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineScreenSpace[2] = {
1245*35238bceSAndroid Build Coastguard Worker             (lineNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize,
1246*35238bceSAndroid Build Coastguard Worker             (lineNormalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize,
1247*35238bceSAndroid Build Coastguard Worker         };
1248*35238bceSAndroid Build Coastguard Worker 
1249*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineDir       = tcu::normalize(lineScreenSpace[1] - lineScreenSpace[0]);
1250*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineNormalDir = (strictMode || scene.isRectangular) ? tcu::Vec2(lineDir.y(), -lineDir.x()) :
1251*35238bceSAndroid Build Coastguard Worker                                         isLineXMajor(lineScreenSpace[0], lineScreenSpace[1]) ? tcu::Vec2(0.0f, 1.0f) :
1252*35238bceSAndroid Build Coastguard Worker                                                                                                tcu::Vec2(1.0f, 0.0f);
1253*35238bceSAndroid Build Coastguard Worker 
1254*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineQuadScreenSpace[4] = {
1255*35238bceSAndroid Build Coastguard Worker             lineScreenSpace[0] + lineNormalDir * halfLineWidth,
1256*35238bceSAndroid Build Coastguard Worker             lineScreenSpace[0] - lineNormalDir * halfLineWidth,
1257*35238bceSAndroid Build Coastguard Worker             lineScreenSpace[1] - lineNormalDir * halfLineWidth,
1258*35238bceSAndroid Build Coastguard Worker             lineScreenSpace[1] + lineNormalDir * halfLineWidth,
1259*35238bceSAndroid Build Coastguard Worker         };
1260*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineQuadNormalizedDeviceSpace[4] = {
1261*35238bceSAndroid Build Coastguard Worker             lineQuadScreenSpace[0] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1262*35238bceSAndroid Build Coastguard Worker             lineQuadScreenSpace[1] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1263*35238bceSAndroid Build Coastguard Worker             lineQuadScreenSpace[2] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1264*35238bceSAndroid Build Coastguard Worker             lineQuadScreenSpace[3] / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1265*35238bceSAndroid Build Coastguard Worker         };
1266*35238bceSAndroid Build Coastguard Worker 
1267*35238bceSAndroid Build Coastguard Worker         // Re-construct un-projected geometry using the quantised positions
1268*35238bceSAndroid Build Coastguard Worker         const tcu::Vec4 lineQuadUnprojected[4] = {
1269*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x() * wa, lineQuadNormalizedDeviceSpace[0].y() * wa, 0.0f, wa),
1270*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[1].x() * wa, lineQuadNormalizedDeviceSpace[1].y() * wa, 0.0f, wa),
1271*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x() * wb, lineQuadNormalizedDeviceSpace[2].y() * wb, 0.0f, wb),
1272*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[3].x() * wb, lineQuadNormalizedDeviceSpace[3].y() * wb, 0.0f, wb),
1273*35238bceSAndroid Build Coastguard Worker         };
1274*35238bceSAndroid Build Coastguard Worker 
1275*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 0].positions[0] = lineQuadUnprojected[0];
1276*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 0].positions[1] = lineQuadUnprojected[1];
1277*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 0].positions[2] = lineQuadUnprojected[2];
1278*35238bceSAndroid Build Coastguard Worker 
1279*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 0].sharedEdge[0] = false;
1280*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 0].sharedEdge[1] = false;
1281*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 0].sharedEdge[2] = true;
1282*35238bceSAndroid Build Coastguard Worker 
1283*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 0].colors[0] = scene.lines[lineNdx].colors[0];
1284*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 0].colors[1] = scene.lines[lineNdx].colors[0];
1285*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 0].colors[2] = scene.lines[lineNdx].colors[1];
1286*35238bceSAndroid Build Coastguard Worker 
1287*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 1].positions[0] = lineQuadUnprojected[0];
1288*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 1].positions[1] = lineQuadUnprojected[2];
1289*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 1].positions[2] = lineQuadUnprojected[3];
1290*35238bceSAndroid Build Coastguard Worker 
1291*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 1].sharedEdge[0] = true;
1292*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 1].sharedEdge[1] = false;
1293*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 1].sharedEdge[2] = false;
1294*35238bceSAndroid Build Coastguard Worker 
1295*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 1].colors[0] = scene.lines[lineNdx].colors[0];
1296*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 1].colors[1] = scene.lines[lineNdx].colors[1];
1297*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[lineNdx * 2 + 1].colors[2] = scene.lines[lineNdx].colors[1];
1298*35238bceSAndroid Build Coastguard Worker     }
1299*35238bceSAndroid Build Coastguard Worker 
1300*35238bceSAndroid Build Coastguard Worker     if (strictMode)
1301*35238bceSAndroid Build Coastguard Worker     {
1302*35238bceSAndroid Build Coastguard Worker         // Strict mode interpolation should be purely in the direction of the line-segment
1303*35238bceSAndroid Build Coastguard Worker         logStash.messages.push_back("Verify using line interpolator");
1304*35238bceSAndroid Build Coastguard Worker         return verifyTriangleGroupInterpolationWithInterpolator(surface, triangleScene, args, logStash,
1305*35238bceSAndroid Build Coastguard Worker                                                                 MultisampleLineInterpolator(scene));
1306*35238bceSAndroid Build Coastguard Worker     }
1307*35238bceSAndroid Build Coastguard Worker     else
1308*35238bceSAndroid Build Coastguard Worker     {
1309*35238bceSAndroid Build Coastguard Worker         // For non-strict lines some allowance needs to be inplace for a few different styles of implementation.
1310*35238bceSAndroid Build Coastguard Worker         //
1311*35238bceSAndroid Build Coastguard Worker         // Some implementations duplicate the attributes at the endpoints to the corners of the triangle
1312*35238bceSAndroid Build Coastguard Worker         // deconstruted parallelogram. Gradients along the line will be seen to travel in the major axis,
1313*35238bceSAndroid Build Coastguard Worker         // with values effectively duplicated in the minor axis direction. In other cases, implementations
1314*35238bceSAndroid Build Coastguard Worker         // will use the original parameters of the line to calculate attribute interpolation so it will
1315*35238bceSAndroid Build Coastguard Worker         // follow the direction of the line-segment.
1316*35238bceSAndroid Build Coastguard Worker         logStash.messages.push_back("Verify using triangle interpolator");
1317*35238bceSAndroid Build Coastguard Worker         if (!verifyTriangleGroupInterpolationWithInterpolator(surface, triangleScene, args, logStash,
1318*35238bceSAndroid Build Coastguard Worker                                                               TriangleInterpolator(triangleScene)))
1319*35238bceSAndroid Build Coastguard Worker         {
1320*35238bceSAndroid Build Coastguard Worker             logStash.messages.push_back("Verify using line interpolator");
1321*35238bceSAndroid Build Coastguard Worker             return verifyTriangleGroupInterpolationWithInterpolator(surface, triangleScene, args, logStash,
1322*35238bceSAndroid Build Coastguard Worker                                                                     MultisampleLineInterpolator(scene));
1323*35238bceSAndroid Build Coastguard Worker         }
1324*35238bceSAndroid Build Coastguard Worker         return true;
1325*35238bceSAndroid Build Coastguard Worker     }
1326*35238bceSAndroid Build Coastguard Worker }
1327*35238bceSAndroid Build Coastguard Worker 
logTriangleGroupnterpolationStash(const tcu::Surface & surface,tcu::TestLog & log,VerifyTriangleGroupInterpolationLogStash & logStash)1328*35238bceSAndroid Build Coastguard Worker static void logTriangleGroupnterpolationStash(const tcu::Surface &surface, tcu::TestLog &log,
1329*35238bceSAndroid Build Coastguard Worker                                               VerifyTriangleGroupInterpolationLogStash &logStash)
1330*35238bceSAndroid Build Coastguard Worker {
1331*35238bceSAndroid Build Coastguard Worker     // Output results
1332*35238bceSAndroid Build Coastguard Worker     log << tcu::TestLog::Message << "Verifying rasterization result." << tcu::TestLog::EndMessage;
1333*35238bceSAndroid Build Coastguard Worker 
1334*35238bceSAndroid Build Coastguard Worker     for (size_t msgNdx = 0; msgNdx < logStash.messages.size(); ++msgNdx)
1335*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << logStash.messages[msgNdx] << tcu::TestLog::EndMessage;
1336*35238bceSAndroid Build Coastguard Worker 
1337*35238bceSAndroid Build Coastguard Worker     // report result
1338*35238bceSAndroid Build Coastguard Worker     if (!logStash.success)
1339*35238bceSAndroid Build Coastguard Worker     {
1340*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << logStash.invalidPixels << " invalid pixel(s) found."
1341*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::EndMessage;
1342*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
1343*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Result", "Result", surface)
1344*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("ErrorMask", "ErrorMask", logStash.errorMask) << tcu::TestLog::EndImageSet;
1345*35238bceSAndroid Build Coastguard Worker     }
1346*35238bceSAndroid Build Coastguard Worker     else
1347*35238bceSAndroid Build Coastguard Worker     {
1348*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
1349*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
1350*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Result", "Result", surface) << tcu::TestLog::EndImageSet;
1351*35238bceSAndroid Build Coastguard Worker     }
1352*35238bceSAndroid Build Coastguard Worker }
1353*35238bceSAndroid Build Coastguard Worker 
verifyMultisampleLineGroupInterpolation(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log,const bool strictMode=true,const bool allowBresenhamForNonStrictLines=false)1354*35238bceSAndroid Build Coastguard Worker static bool verifyMultisampleLineGroupInterpolation(const tcu::Surface &surface, const LineSceneSpec &scene,
1355*35238bceSAndroid Build Coastguard Worker                                                     const RasterizationArguments &args, tcu::TestLog &log,
1356*35238bceSAndroid Build Coastguard Worker                                                     const bool strictMode                      = true,
1357*35238bceSAndroid Build Coastguard Worker                                                     const bool allowBresenhamForNonStrictLines = false)
1358*35238bceSAndroid Build Coastguard Worker {
1359*35238bceSAndroid Build Coastguard Worker     bool result = false;
1360*35238bceSAndroid Build Coastguard Worker     VerifyTriangleGroupInterpolationLogStash nonStrictModeLogStash;
1361*35238bceSAndroid Build Coastguard Worker     VerifyTriangleGroupInterpolationLogStash strictModeLogStash;
1362*35238bceSAndroid Build Coastguard Worker 
1363*35238bceSAndroid Build Coastguard Worker     nonStrictModeLogStash.messages.push_back("Non-strict line draw mode.");
1364*35238bceSAndroid Build Coastguard Worker     strictModeLogStash.messages.push_back("Strict mode line draw mode.");
1365*35238bceSAndroid Build Coastguard Worker 
1366*35238bceSAndroid Build Coastguard Worker     if (strictMode)
1367*35238bceSAndroid Build Coastguard Worker     {
1368*35238bceSAndroid Build Coastguard Worker         result = verifyMultisampleLineGroupInterpolationInternal(surface, scene, args, strictModeLogStash, strictMode);
1369*35238bceSAndroid Build Coastguard Worker 
1370*35238bceSAndroid Build Coastguard Worker         logTriangleGroupnterpolationStash(surface, log, strictModeLogStash);
1371*35238bceSAndroid Build Coastguard Worker     }
1372*35238bceSAndroid Build Coastguard Worker     else
1373*35238bceSAndroid Build Coastguard Worker     {
1374*35238bceSAndroid Build Coastguard Worker         if (verifyMultisampleLineGroupInterpolationInternal(surface, scene, args, nonStrictModeLogStash, false))
1375*35238bceSAndroid Build Coastguard Worker         {
1376*35238bceSAndroid Build Coastguard Worker             logTriangleGroupnterpolationStash(surface, log, nonStrictModeLogStash);
1377*35238bceSAndroid Build Coastguard Worker 
1378*35238bceSAndroid Build Coastguard Worker             result = true;
1379*35238bceSAndroid Build Coastguard Worker         }
1380*35238bceSAndroid Build Coastguard Worker         else if (verifyMultisampleLineGroupInterpolationInternal(surface, scene, args, strictModeLogStash, true))
1381*35238bceSAndroid Build Coastguard Worker         {
1382*35238bceSAndroid Build Coastguard Worker             logTriangleGroupnterpolationStash(surface, log, strictModeLogStash);
1383*35238bceSAndroid Build Coastguard Worker 
1384*35238bceSAndroid Build Coastguard Worker             result = true;
1385*35238bceSAndroid Build Coastguard Worker         }
1386*35238bceSAndroid Build Coastguard Worker         else
1387*35238bceSAndroid Build Coastguard Worker         {
1388*35238bceSAndroid Build Coastguard Worker             logTriangleGroupnterpolationStash(surface, log, nonStrictModeLogStash);
1389*35238bceSAndroid Build Coastguard Worker             logTriangleGroupnterpolationStash(surface, log, strictModeLogStash);
1390*35238bceSAndroid Build Coastguard Worker         }
1391*35238bceSAndroid Build Coastguard Worker 
1392*35238bceSAndroid Build Coastguard Worker         // In the non-strict line case, bresenham is also permissable, though not specified. This is due
1393*35238bceSAndroid Build Coastguard Worker         // to a change in how lines are specified in Vulkan versus GLES; in GLES bresenham lines using the
1394*35238bceSAndroid Build Coastguard Worker         // diamond-exit rule were the preferred way to draw single pixel non-antialiased lines, and not all
1395*35238bceSAndroid Build Coastguard Worker         // GLES implementations are able to disable this behaviour.
1396*35238bceSAndroid Build Coastguard Worker         if (result == false)
1397*35238bceSAndroid Build Coastguard Worker         {
1398*35238bceSAndroid Build Coastguard Worker             log << tcu::TestLog::Message
1399*35238bceSAndroid Build Coastguard Worker                 << "Checking line rasterisation using verifySinglesampleNarrowLineGroupInterpolation for nonStrict "
1400*35238bceSAndroid Build Coastguard Worker                    "lines"
1401*35238bceSAndroid Build Coastguard Worker                 << tcu::TestLog::EndMessage;
1402*35238bceSAndroid Build Coastguard Worker             if (args.numSamples <= 1 && allowBresenhamForNonStrictLines &&
1403*35238bceSAndroid Build Coastguard Worker                 verifyLineGroupInterpolationWithProjectedWeights(surface, scene, args, log))
1404*35238bceSAndroid Build Coastguard Worker             {
1405*35238bceSAndroid Build Coastguard Worker                 log << tcu::TestLog::Message
1406*35238bceSAndroid Build Coastguard Worker                     << "verifySinglesampleNarrowLineGroupInterpolation for nonStrict lines Passed"
1407*35238bceSAndroid Build Coastguard Worker                     << tcu::TestLog::EndMessage;
1408*35238bceSAndroid Build Coastguard Worker 
1409*35238bceSAndroid Build Coastguard Worker                 result = true;
1410*35238bceSAndroid Build Coastguard Worker             }
1411*35238bceSAndroid Build Coastguard Worker         }
1412*35238bceSAndroid Build Coastguard Worker     }
1413*35238bceSAndroid Build Coastguard Worker 
1414*35238bceSAndroid Build Coastguard Worker     return result;
1415*35238bceSAndroid Build Coastguard Worker }
1416*35238bceSAndroid Build Coastguard Worker 
verifyMultisamplePointGroupRasterization(const tcu::Surface & surface,const PointSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)1417*35238bceSAndroid Build Coastguard Worker bool verifyMultisamplePointGroupRasterization(const tcu::Surface &surface, const PointSceneSpec &scene,
1418*35238bceSAndroid Build Coastguard Worker                                               const RasterizationArguments &args, tcu::TestLog &log)
1419*35238bceSAndroid Build Coastguard Worker {
1420*35238bceSAndroid Build Coastguard Worker     // Multisampled point == 2 triangles
1421*35238bceSAndroid Build Coastguard Worker 
1422*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 viewportSize = tcu::Vec2((float)surface.getWidth(), (float)surface.getHeight());
1423*35238bceSAndroid Build Coastguard Worker     TriangleSceneSpec triangleScene;
1424*35238bceSAndroid Build Coastguard Worker 
1425*35238bceSAndroid Build Coastguard Worker     triangleScene.triangles.resize(2 * scene.points.size());
1426*35238bceSAndroid Build Coastguard Worker     for (int pointNdx = 0; pointNdx < (int)scene.points.size(); ++pointNdx)
1427*35238bceSAndroid Build Coastguard Worker     {
1428*35238bceSAndroid Build Coastguard Worker         // Transform to screen space, add pixel offsets, convert back to normalized device space, and test as triangles
1429*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 pointNormalizedDeviceSpace =
1430*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(scene.points[pointNdx].position.x() / scene.points[pointNdx].position.w(),
1431*35238bceSAndroid Build Coastguard Worker                       scene.points[pointNdx].position.y() / scene.points[pointNdx].position.w());
1432*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 pointScreenSpace = (pointNormalizedDeviceSpace + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize;
1433*35238bceSAndroid Build Coastguard Worker         const float offset               = scene.points[pointNdx].pointSize * 0.5f;
1434*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineQuadNormalizedDeviceSpace[4] = {
1435*35238bceSAndroid Build Coastguard Worker             (pointScreenSpace + tcu::Vec2(-offset, -offset)) / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1436*35238bceSAndroid Build Coastguard Worker             (pointScreenSpace + tcu::Vec2(-offset, offset)) / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1437*35238bceSAndroid Build Coastguard Worker             (pointScreenSpace + tcu::Vec2(offset, offset)) / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1438*35238bceSAndroid Build Coastguard Worker             (pointScreenSpace + tcu::Vec2(offset, -offset)) / viewportSize * 2.0f - tcu::Vec2(1.0f, 1.0f),
1439*35238bceSAndroid Build Coastguard Worker         };
1440*35238bceSAndroid Build Coastguard Worker 
1441*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 0].positions[0] =
1442*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);
1443*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 0].sharedEdge[0] = false;
1444*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 0].positions[1] =
1445*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[1].x(), lineQuadNormalizedDeviceSpace[1].y(), 0.0f, 1.0f);
1446*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 0].sharedEdge[1] = false;
1447*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 0].positions[2] =
1448*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);
1449*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 0].sharedEdge[2] = true;
1450*35238bceSAndroid Build Coastguard Worker 
1451*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 1].positions[0] =
1452*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[0].x(), lineQuadNormalizedDeviceSpace[0].y(), 0.0f, 1.0f);
1453*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 1].sharedEdge[0] = true;
1454*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 1].positions[1] =
1455*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[2].x(), lineQuadNormalizedDeviceSpace[2].y(), 0.0f, 1.0f);
1456*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 1].sharedEdge[1] = false;
1457*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 1].positions[2] =
1458*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineQuadNormalizedDeviceSpace[3].x(), lineQuadNormalizedDeviceSpace[3].y(), 0.0f, 1.0f);
1459*35238bceSAndroid Build Coastguard Worker         triangleScene.triangles[pointNdx * 2 + 1].sharedEdge[2] = false;
1460*35238bceSAndroid Build Coastguard Worker     }
1461*35238bceSAndroid Build Coastguard Worker 
1462*35238bceSAndroid Build Coastguard Worker     return verifyTriangleGroupRasterization(surface, triangleScene, args, log);
1463*35238bceSAndroid Build Coastguard Worker }
1464*35238bceSAndroid Build Coastguard Worker 
genScreenSpaceLines(std::vector<tcu::Vec4> & screenspaceLines,const std::vector<LineSceneSpec::SceneLine> & lines,const tcu::IVec2 & viewportSize)1465*35238bceSAndroid Build Coastguard Worker void genScreenSpaceLines(std::vector<tcu::Vec4> &screenspaceLines, const std::vector<LineSceneSpec::SceneLine> &lines,
1466*35238bceSAndroid Build Coastguard Worker                          const tcu::IVec2 &viewportSize)
1467*35238bceSAndroid Build Coastguard Worker {
1468*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(screenspaceLines.size() == lines.size());
1469*35238bceSAndroid Build Coastguard Worker 
1470*35238bceSAndroid Build Coastguard Worker     for (int lineNdx = 0; lineNdx < (int)lines.size(); ++lineNdx)
1471*35238bceSAndroid Build Coastguard Worker     {
1472*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 lineNormalizedDeviceSpace[2] = {
1473*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(lines[lineNdx].positions[0].x() / lines[lineNdx].positions[0].w(),
1474*35238bceSAndroid Build Coastguard Worker                       lines[lineNdx].positions[0].y() / lines[lineNdx].positions[0].w()),
1475*35238bceSAndroid Build Coastguard Worker             tcu::Vec2(lines[lineNdx].positions[1].x() / lines[lineNdx].positions[1].w(),
1476*35238bceSAndroid Build Coastguard Worker                       lines[lineNdx].positions[1].y() / lines[lineNdx].positions[1].w()),
1477*35238bceSAndroid Build Coastguard Worker         };
1478*35238bceSAndroid Build Coastguard Worker         const tcu::Vec4 lineScreenSpace[2] = {
1479*35238bceSAndroid Build Coastguard Worker             tcu::Vec4((lineNormalizedDeviceSpace[0].x() + 1.0f) * 0.5f * (float)viewportSize.x(),
1480*35238bceSAndroid Build Coastguard Worker                       (lineNormalizedDeviceSpace[0].y() + 1.0f) * 0.5f * (float)viewportSize.y(), 0.0f, 1.0f),
1481*35238bceSAndroid Build Coastguard Worker             tcu::Vec4((lineNormalizedDeviceSpace[1].x() + 1.0f) * 0.5f * (float)viewportSize.x(),
1482*35238bceSAndroid Build Coastguard Worker                       (lineNormalizedDeviceSpace[1].y() + 1.0f) * 0.5f * (float)viewportSize.y(), 0.0f, 1.0f),
1483*35238bceSAndroid Build Coastguard Worker         };
1484*35238bceSAndroid Build Coastguard Worker 
1485*35238bceSAndroid Build Coastguard Worker         screenspaceLines[lineNdx] =
1486*35238bceSAndroid Build Coastguard Worker             tcu::Vec4(lineScreenSpace[0].x(), lineScreenSpace[0].y(), lineScreenSpace[1].x(), lineScreenSpace[1].y());
1487*35238bceSAndroid Build Coastguard Worker     }
1488*35238bceSAndroid Build Coastguard Worker }
1489*35238bceSAndroid Build Coastguard Worker 
verifySinglesampleLineGroupRasterization(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)1490*35238bceSAndroid Build Coastguard Worker bool verifySinglesampleLineGroupRasterization(const tcu::Surface &surface, const LineSceneSpec &scene,
1491*35238bceSAndroid Build Coastguard Worker                                               const RasterizationArguments &args, tcu::TestLog &log)
1492*35238bceSAndroid Build Coastguard Worker {
1493*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(deFloatFrac(scene.lineWidth) != 0.5f); // rounding direction is not defined, disallow undefined cases
1494*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(scene.lines.size() < 255);             // indices are stored as unsigned 8-bit ints
1495*35238bceSAndroid Build Coastguard Worker 
1496*35238bceSAndroid Build Coastguard Worker     bool allOK               = true;
1497*35238bceSAndroid Build Coastguard Worker     bool overdrawInReference = false;
1498*35238bceSAndroid Build Coastguard Worker     int referenceFragments   = 0;
1499*35238bceSAndroid Build Coastguard Worker     int resultFragments      = 0;
1500*35238bceSAndroid Build Coastguard Worker     int lineWidth            = deFloorFloatToInt32(scene.lineWidth + 0.5f);
1501*35238bceSAndroid Build Coastguard Worker     std::vector<bool> lineIsXMajor(scene.lines.size());
1502*35238bceSAndroid Build Coastguard Worker     std::vector<tcu::Vec4> screenspaceLines(scene.lines.size());
1503*35238bceSAndroid Build Coastguard Worker 
1504*35238bceSAndroid Build Coastguard Worker     // 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
1505*35238bceSAndroid Build Coastguard Worker     tcu::TextureLevel referenceLineMap(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT8),
1506*35238bceSAndroid Build Coastguard Worker                                        surface.getWidth(), surface.getHeight());
1507*35238bceSAndroid Build Coastguard Worker     tcu::clear(referenceLineMap.getAccess(), tcu::IVec4(0, 0, 0, 0));
1508*35238bceSAndroid Build Coastguard Worker 
1509*35238bceSAndroid Build Coastguard Worker     genScreenSpaceLines(screenspaceLines, scene.lines, tcu::IVec2(surface.getWidth(), surface.getHeight()));
1510*35238bceSAndroid Build Coastguard Worker 
1511*35238bceSAndroid Build Coastguard Worker     rr::SingleSampleLineRasterizer rasterizer(tcu::IVec4(0, 0, surface.getWidth(), surface.getHeight()),
1512*35238bceSAndroid Build Coastguard Worker                                               args.subpixelBits);
1513*35238bceSAndroid Build Coastguard Worker     for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
1514*35238bceSAndroid Build Coastguard Worker     {
1515*35238bceSAndroid Build Coastguard Worker         rasterizer.init(tcu::Vec4(screenspaceLines[lineNdx][0], screenspaceLines[lineNdx][1], 0.0f, 1.0f),
1516*35238bceSAndroid Build Coastguard Worker                         tcu::Vec4(screenspaceLines[lineNdx][2], screenspaceLines[lineNdx][3], 0.0f, 1.0f),
1517*35238bceSAndroid Build Coastguard Worker                         scene.lineWidth, scene.stippleFactor, scene.stipplePattern);
1518*35238bceSAndroid Build Coastguard Worker 
1519*35238bceSAndroid Build Coastguard Worker         if (!scene.isStrip)
1520*35238bceSAndroid Build Coastguard Worker             rasterizer.resetStipple();
1521*35238bceSAndroid Build Coastguard Worker 
1522*35238bceSAndroid Build Coastguard Worker         // calculate majority of later use
1523*35238bceSAndroid Build Coastguard Worker         lineIsXMajor[lineNdx] = isPackedSSLineXMajor(screenspaceLines[lineNdx]);
1524*35238bceSAndroid Build Coastguard Worker 
1525*35238bceSAndroid Build Coastguard Worker         for (;;)
1526*35238bceSAndroid Build Coastguard Worker         {
1527*35238bceSAndroid Build Coastguard Worker             const int maxPackets = 32;
1528*35238bceSAndroid Build Coastguard Worker             int numRasterized    = 0;
1529*35238bceSAndroid Build Coastguard Worker             rr::FragmentPacket packets[maxPackets];
1530*35238bceSAndroid Build Coastguard Worker 
1531*35238bceSAndroid Build Coastguard Worker             rasterizer.rasterize(packets, DE_NULL, maxPackets, numRasterized);
1532*35238bceSAndroid Build Coastguard Worker 
1533*35238bceSAndroid Build Coastguard Worker             for (int packetNdx = 0; packetNdx < numRasterized; ++packetNdx)
1534*35238bceSAndroid Build Coastguard Worker             {
1535*35238bceSAndroid Build Coastguard Worker                 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1536*35238bceSAndroid Build Coastguard Worker                 {
1537*35238bceSAndroid Build Coastguard Worker                     if ((uint32_t)packets[packetNdx].coverage & (1 << fragNdx))
1538*35238bceSAndroid Build Coastguard Worker                     {
1539*35238bceSAndroid Build Coastguard Worker                         const tcu::IVec2 fragPos = packets[packetNdx].position + tcu::IVec2(fragNdx % 2, fragNdx / 2);
1540*35238bceSAndroid Build Coastguard Worker 
1541*35238bceSAndroid Build Coastguard Worker                         // Check for overdraw
1542*35238bceSAndroid Build Coastguard Worker                         if (!overdrawInReference)
1543*35238bceSAndroid Build Coastguard Worker                             overdrawInReference =
1544*35238bceSAndroid Build Coastguard Worker                                 referenceLineMap.getAccess().getPixelInt(fragPos.x(), fragPos.y()).x() != 0;
1545*35238bceSAndroid Build Coastguard Worker 
1546*35238bceSAndroid Build Coastguard Worker                         // Output pixel
1547*35238bceSAndroid Build Coastguard Worker                         referenceLineMap.getAccess().setPixel(tcu::IVec4(lineNdx + 1, 0, 0, 0), fragPos.x(),
1548*35238bceSAndroid Build Coastguard Worker                                                               fragPos.y());
1549*35238bceSAndroid Build Coastguard Worker                     }
1550*35238bceSAndroid Build Coastguard Worker                 }
1551*35238bceSAndroid Build Coastguard Worker             }
1552*35238bceSAndroid Build Coastguard Worker 
1553*35238bceSAndroid Build Coastguard Worker             if (numRasterized != maxPackets)
1554*35238bceSAndroid Build Coastguard Worker                 break;
1555*35238bceSAndroid Build Coastguard Worker         }
1556*35238bceSAndroid Build Coastguard Worker     }
1557*35238bceSAndroid Build Coastguard Worker 
1558*35238bceSAndroid Build Coastguard Worker     // Requirement 1: The coordinates of a fragment produced by the algorithm may not deviate by more than one unit
1559*35238bceSAndroid Build Coastguard Worker     {
1560*35238bceSAndroid Build Coastguard Worker         tcu::Surface errorMask(surface.getWidth(), surface.getHeight());
1561*35238bceSAndroid Build Coastguard Worker         bool missingFragments = false;
1562*35238bceSAndroid Build Coastguard Worker 
1563*35238bceSAndroid Build Coastguard Worker         tcu::clear(errorMask.getAccess(), tcu::IVec4(0, 255, 0, 255));
1564*35238bceSAndroid Build Coastguard Worker 
1565*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Searching for deviating fragments." << tcu::TestLog::EndMessage;
1566*35238bceSAndroid Build Coastguard Worker 
1567*35238bceSAndroid Build Coastguard Worker         for (int y = 0; y < referenceLineMap.getHeight(); ++y)
1568*35238bceSAndroid Build Coastguard Worker             for (int x = 0; x < referenceLineMap.getWidth(); ++x)
1569*35238bceSAndroid Build Coastguard Worker             {
1570*35238bceSAndroid Build Coastguard Worker                 const bool reference = referenceLineMap.getAccess().getPixelInt(x, y).x() != 0;
1571*35238bceSAndroid Build Coastguard Worker                 const bool result    = compareColors(surface.getPixel(x, y), tcu::RGBA::white(), args.redBits,
1572*35238bceSAndroid Build Coastguard Worker                                                      args.greenBits, args.blueBits);
1573*35238bceSAndroid Build Coastguard Worker 
1574*35238bceSAndroid Build Coastguard Worker                 if (reference)
1575*35238bceSAndroid Build Coastguard Worker                     ++referenceFragments;
1576*35238bceSAndroid Build Coastguard Worker                 if (result)
1577*35238bceSAndroid Build Coastguard Worker                     ++resultFragments;
1578*35238bceSAndroid Build Coastguard Worker 
1579*35238bceSAndroid Build Coastguard Worker                 if (reference == result)
1580*35238bceSAndroid Build Coastguard Worker                     continue;
1581*35238bceSAndroid Build Coastguard Worker 
1582*35238bceSAndroid Build Coastguard Worker                 // Reference fragment here, matching result fragment must be nearby
1583*35238bceSAndroid Build Coastguard Worker                 if (reference && !result)
1584*35238bceSAndroid Build Coastguard Worker                 {
1585*35238bceSAndroid Build Coastguard Worker                     bool foundFragment = false;
1586*35238bceSAndroid Build Coastguard Worker 
1587*35238bceSAndroid Build Coastguard Worker                     if (x == 0 || y == 0 || x == referenceLineMap.getWidth() - 1 ||
1588*35238bceSAndroid Build Coastguard Worker                         y == referenceLineMap.getHeight() - 1)
1589*35238bceSAndroid Build Coastguard Worker                     {
1590*35238bceSAndroid Build Coastguard Worker                         // image boundary, missing fragment could be over the image edge
1591*35238bceSAndroid Build Coastguard Worker                         foundFragment = true;
1592*35238bceSAndroid Build Coastguard Worker                     }
1593*35238bceSAndroid Build Coastguard Worker 
1594*35238bceSAndroid Build Coastguard Worker                     // find nearby fragment
1595*35238bceSAndroid Build Coastguard Worker                     for (int dy = -1; dy < 2 && !foundFragment; ++dy)
1596*35238bceSAndroid Build Coastguard Worker                         for (int dx = -1; dx < 2 && !foundFragment; ++dx)
1597*35238bceSAndroid Build Coastguard Worker                         {
1598*35238bceSAndroid Build Coastguard Worker                             if (compareColors(surface.getPixel(x + dx, y + dy), tcu::RGBA::white(), args.redBits,
1599*35238bceSAndroid Build Coastguard Worker                                               args.greenBits, args.blueBits))
1600*35238bceSAndroid Build Coastguard Worker                                 foundFragment = true;
1601*35238bceSAndroid Build Coastguard Worker                         }
1602*35238bceSAndroid Build Coastguard Worker 
1603*35238bceSAndroid Build Coastguard Worker                     if (!foundFragment)
1604*35238bceSAndroid Build Coastguard Worker                     {
1605*35238bceSAndroid Build Coastguard Worker                         missingFragments = true;
1606*35238bceSAndroid Build Coastguard Worker                         errorMask.setPixel(x, y, tcu::RGBA::red());
1607*35238bceSAndroid Build Coastguard Worker                     }
1608*35238bceSAndroid Build Coastguard Worker                 }
1609*35238bceSAndroid Build Coastguard Worker             }
1610*35238bceSAndroid Build Coastguard Worker 
1611*35238bceSAndroid Build Coastguard Worker         if (missingFragments)
1612*35238bceSAndroid Build Coastguard Worker         {
1613*35238bceSAndroid Build Coastguard Worker 
1614*35238bceSAndroid Build Coastguard Worker             allOK = false;
1615*35238bceSAndroid Build Coastguard Worker         }
1616*35238bceSAndroid Build Coastguard Worker         else
1617*35238bceSAndroid Build Coastguard Worker         {
1618*35238bceSAndroid Build Coastguard Worker             log << tcu::TestLog::Message << "No invalid deviations found." << tcu::TestLog::EndMessage;
1619*35238bceSAndroid Build Coastguard Worker         }
1620*35238bceSAndroid Build Coastguard Worker     }
1621*35238bceSAndroid Build Coastguard Worker 
1622*35238bceSAndroid Build Coastguard Worker     // Requirement 2: The total number of fragments produced by the algorithm may differ from
1623*35238bceSAndroid Build Coastguard Worker     //                that produced by the diamond-exit rule by no more than one.
1624*35238bceSAndroid Build Coastguard Worker     {
1625*35238bceSAndroid Build Coastguard Worker         // Check is not valid if the primitives intersect or otherwise share same fragments
1626*35238bceSAndroid Build Coastguard Worker         if (!overdrawInReference)
1627*35238bceSAndroid Build Coastguard Worker         {
1628*35238bceSAndroid Build Coastguard Worker             int allowedDeviation =
1629*35238bceSAndroid Build Coastguard Worker                 (int)scene.lines.size() * lineWidth; // one pixel per primitive in the major direction
1630*35238bceSAndroid Build Coastguard Worker 
1631*35238bceSAndroid Build Coastguard Worker             log << tcu::TestLog::Message << "Verifying fragment counts:\n"
1632*35238bceSAndroid Build Coastguard Worker                 << "\tDiamond-exit rule: " << referenceFragments << " fragments.\n"
1633*35238bceSAndroid Build Coastguard Worker                 << "\tResult image: " << resultFragments << " fragments.\n"
1634*35238bceSAndroid Build Coastguard Worker                 << "\tAllowing deviation of " << allowedDeviation << " fragments.\n"
1635*35238bceSAndroid Build Coastguard Worker                 << tcu::TestLog::EndMessage;
1636*35238bceSAndroid Build Coastguard Worker 
1637*35238bceSAndroid Build Coastguard Worker             if (deAbs32(referenceFragments - resultFragments) > allowedDeviation)
1638*35238bceSAndroid Build Coastguard Worker             {
1639*35238bceSAndroid Build Coastguard Worker                 tcu::Surface reference(surface.getWidth(), surface.getHeight());
1640*35238bceSAndroid Build Coastguard Worker 
1641*35238bceSAndroid Build Coastguard Worker                 // show a helpful reference image
1642*35238bceSAndroid Build Coastguard Worker                 tcu::clear(reference.getAccess(), tcu::IVec4(0, 0, 0, 255));
1643*35238bceSAndroid Build Coastguard Worker                 for (int y = 0; y < surface.getHeight(); ++y)
1644*35238bceSAndroid Build Coastguard Worker                     for (int x = 0; x < surface.getWidth(); ++x)
1645*35238bceSAndroid Build Coastguard Worker                         if (referenceLineMap.getAccess().getPixelInt(x, y).x())
1646*35238bceSAndroid Build Coastguard Worker                             reference.setPixel(x, y, tcu::RGBA::white());
1647*35238bceSAndroid Build Coastguard Worker 
1648*35238bceSAndroid Build Coastguard Worker                 log << tcu::TestLog::Message << "Invalid fragment count in result image." << tcu::TestLog::EndMessage;
1649*35238bceSAndroid Build Coastguard Worker                 log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
1650*35238bceSAndroid Build Coastguard Worker                     << tcu::TestLog::Image("Reference", "Reference", reference)
1651*35238bceSAndroid Build Coastguard Worker                     << tcu::TestLog::Image("Result", "Result", surface) << tcu::TestLog::EndImageSet;
1652*35238bceSAndroid Build Coastguard Worker 
1653*35238bceSAndroid Build Coastguard Worker                 allOK = false;
1654*35238bceSAndroid Build Coastguard Worker             }
1655*35238bceSAndroid Build Coastguard Worker             else
1656*35238bceSAndroid Build Coastguard Worker             {
1657*35238bceSAndroid Build Coastguard Worker                 log << tcu::TestLog::Message << "Fragment count is valid." << tcu::TestLog::EndMessage;
1658*35238bceSAndroid Build Coastguard Worker             }
1659*35238bceSAndroid Build Coastguard Worker         }
1660*35238bceSAndroid Build Coastguard Worker         else
1661*35238bceSAndroid Build Coastguard Worker         {
1662*35238bceSAndroid Build Coastguard Worker             log << tcu::TestLog::Message
1663*35238bceSAndroid Build Coastguard Worker                 << "Overdraw in scene. Fragment count cannot be verified. Skipping fragment count checks."
1664*35238bceSAndroid Build Coastguard Worker                 << tcu::TestLog::EndMessage;
1665*35238bceSAndroid Build Coastguard Worker         }
1666*35238bceSAndroid Build Coastguard Worker     }
1667*35238bceSAndroid Build Coastguard Worker 
1668*35238bceSAndroid Build Coastguard Worker     // Requirement 3: Line width must be constant
1669*35238bceSAndroid Build Coastguard Worker     {
1670*35238bceSAndroid Build Coastguard Worker         bool invalidWidthFound = false;
1671*35238bceSAndroid Build Coastguard Worker 
1672*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Verifying line widths of the x-major lines." << tcu::TestLog::EndMessage;
1673*35238bceSAndroid Build Coastguard Worker         for (int y = 1; y < referenceLineMap.getHeight() - 1; ++y)
1674*35238bceSAndroid Build Coastguard Worker         {
1675*35238bceSAndroid Build Coastguard Worker             bool fullyVisibleLine       = false;
1676*35238bceSAndroid Build Coastguard Worker             bool previousPixelUndefined = false;
1677*35238bceSAndroid Build Coastguard Worker             int currentLine             = 0;
1678*35238bceSAndroid Build Coastguard Worker             int currentWidth            = 1;
1679*35238bceSAndroid Build Coastguard Worker 
1680*35238bceSAndroid Build Coastguard Worker             for (int x = 1; x < referenceLineMap.getWidth() - 1; ++x)
1681*35238bceSAndroid Build Coastguard Worker             {
1682*35238bceSAndroid Build Coastguard Worker                 const bool result = compareColors(surface.getPixel(x, y), tcu::RGBA::white(), args.redBits,
1683*35238bceSAndroid Build Coastguard Worker                                                   args.greenBits, args.blueBits);
1684*35238bceSAndroid Build Coastguard Worker                 int lineID        = 0;
1685*35238bceSAndroid Build Coastguard Worker 
1686*35238bceSAndroid Build Coastguard Worker                 // Which line does this fragment belong to?
1687*35238bceSAndroid Build Coastguard Worker 
1688*35238bceSAndroid Build Coastguard Worker                 if (result)
1689*35238bceSAndroid Build Coastguard Worker                 {
1690*35238bceSAndroid Build Coastguard Worker                     bool multipleNearbyLines = false;
1691*35238bceSAndroid Build Coastguard Worker                     bool renderAtSurfaceEdge = false;
1692*35238bceSAndroid Build Coastguard Worker 
1693*35238bceSAndroid Build Coastguard Worker                     renderAtSurfaceEdge = (x == 1) || (x == referenceLineMap.getWidth() - 2);
1694*35238bceSAndroid Build Coastguard Worker 
1695*35238bceSAndroid Build Coastguard Worker                     for (int dy = -1; dy < 2; ++dy)
1696*35238bceSAndroid Build Coastguard Worker                         for (int dx = -1; dx < 2; ++dx)
1697*35238bceSAndroid Build Coastguard Worker                         {
1698*35238bceSAndroid Build Coastguard Worker                             const int nearbyID = referenceLineMap.getAccess().getPixelInt(x + dx, y + dy).x();
1699*35238bceSAndroid Build Coastguard Worker                             if (nearbyID)
1700*35238bceSAndroid Build Coastguard Worker                             {
1701*35238bceSAndroid Build Coastguard Worker                                 if (lineID && lineID != nearbyID)
1702*35238bceSAndroid Build Coastguard Worker                                     multipleNearbyLines = true;
1703*35238bceSAndroid Build Coastguard Worker                             }
1704*35238bceSAndroid Build Coastguard Worker                         }
1705*35238bceSAndroid Build Coastguard Worker 
1706*35238bceSAndroid Build Coastguard Worker                     if (multipleNearbyLines || renderAtSurfaceEdge)
1707*35238bceSAndroid Build Coastguard Worker                     {
1708*35238bceSAndroid Build Coastguard Worker                         // Another line is too close, don't try to calculate width here
1709*35238bceSAndroid Build Coastguard Worker                         // Or the render result is outside of surface range
1710*35238bceSAndroid Build Coastguard Worker                         previousPixelUndefined = true;
1711*35238bceSAndroid Build Coastguard Worker                         continue;
1712*35238bceSAndroid Build Coastguard Worker                     }
1713*35238bceSAndroid Build Coastguard Worker                 }
1714*35238bceSAndroid Build Coastguard Worker 
1715*35238bceSAndroid Build Coastguard Worker                 // Only line with id of lineID is nearby
1716*35238bceSAndroid Build Coastguard Worker 
1717*35238bceSAndroid Build Coastguard Worker                 if (previousPixelUndefined)
1718*35238bceSAndroid Build Coastguard Worker                 {
1719*35238bceSAndroid Build Coastguard Worker                     // The line might have been overdrawn or not
1720*35238bceSAndroid Build Coastguard Worker                     currentLine            = lineID;
1721*35238bceSAndroid Build Coastguard Worker                     currentWidth           = 1;
1722*35238bceSAndroid Build Coastguard Worker                     fullyVisibleLine       = false;
1723*35238bceSAndroid Build Coastguard Worker                     previousPixelUndefined = false;
1724*35238bceSAndroid Build Coastguard Worker                 }
1725*35238bceSAndroid Build Coastguard Worker                 else if (lineID == currentLine)
1726*35238bceSAndroid Build Coastguard Worker                 {
1727*35238bceSAndroid Build Coastguard Worker                     // Current line continues
1728*35238bceSAndroid Build Coastguard Worker                     ++currentWidth;
1729*35238bceSAndroid Build Coastguard Worker                 }
1730*35238bceSAndroid Build Coastguard Worker                 else if (lineID > currentLine)
1731*35238bceSAndroid Build Coastguard Worker                 {
1732*35238bceSAndroid Build Coastguard Worker                     // Another line was drawn over or the line ends
1733*35238bceSAndroid Build Coastguard Worker                     currentLine      = lineID;
1734*35238bceSAndroid Build Coastguard Worker                     currentWidth     = 1;
1735*35238bceSAndroid Build Coastguard Worker                     fullyVisibleLine = true;
1736*35238bceSAndroid Build Coastguard Worker                 }
1737*35238bceSAndroid Build Coastguard Worker                 else
1738*35238bceSAndroid Build Coastguard Worker                 {
1739*35238bceSAndroid Build Coastguard Worker                     // The line ends
1740*35238bceSAndroid Build Coastguard Worker                     if (fullyVisibleLine && !lineIsXMajor[currentLine - 1])
1741*35238bceSAndroid Build Coastguard Worker                     {
1742*35238bceSAndroid Build Coastguard Worker                         // check width
1743*35238bceSAndroid Build Coastguard Worker                         if (currentWidth != lineWidth)
1744*35238bceSAndroid Build Coastguard Worker                         {
1745*35238bceSAndroid Build Coastguard Worker                             log << tcu::TestLog::Message << "\tInvalid line width at (" << x - currentWidth << ", " << y
1746*35238bceSAndroid Build Coastguard Worker                                 << ") - (" << x - 1 << ", " << y << "). Detected width of " << currentWidth
1747*35238bceSAndroid Build Coastguard Worker                                 << ", expected " << lineWidth << tcu::TestLog::EndMessage;
1748*35238bceSAndroid Build Coastguard Worker                             invalidWidthFound = true;
1749*35238bceSAndroid Build Coastguard Worker                         }
1750*35238bceSAndroid Build Coastguard Worker                     }
1751*35238bceSAndroid Build Coastguard Worker 
1752*35238bceSAndroid Build Coastguard Worker                     currentLine      = lineID;
1753*35238bceSAndroid Build Coastguard Worker                     currentWidth     = 1;
1754*35238bceSAndroid Build Coastguard Worker                     fullyVisibleLine = false;
1755*35238bceSAndroid Build Coastguard Worker                 }
1756*35238bceSAndroid Build Coastguard Worker             }
1757*35238bceSAndroid Build Coastguard Worker         }
1758*35238bceSAndroid Build Coastguard Worker 
1759*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Verifying line widths of the y-major lines." << tcu::TestLog::EndMessage;
1760*35238bceSAndroid Build Coastguard Worker         for (int x = 1; x < referenceLineMap.getWidth() - 1; ++x)
1761*35238bceSAndroid Build Coastguard Worker         {
1762*35238bceSAndroid Build Coastguard Worker             bool fullyVisibleLine       = false;
1763*35238bceSAndroid Build Coastguard Worker             bool previousPixelUndefined = false;
1764*35238bceSAndroid Build Coastguard Worker             int currentLine             = 0;
1765*35238bceSAndroid Build Coastguard Worker             int currentWidth            = 1;
1766*35238bceSAndroid Build Coastguard Worker 
1767*35238bceSAndroid Build Coastguard Worker             for (int y = 1; y < referenceLineMap.getHeight() - 1; ++y)
1768*35238bceSAndroid Build Coastguard Worker             {
1769*35238bceSAndroid Build Coastguard Worker                 const bool result = compareColors(surface.getPixel(x, y), tcu::RGBA::white(), args.redBits,
1770*35238bceSAndroid Build Coastguard Worker                                                   args.greenBits, args.blueBits);
1771*35238bceSAndroid Build Coastguard Worker                 int lineID        = 0;
1772*35238bceSAndroid Build Coastguard Worker 
1773*35238bceSAndroid Build Coastguard Worker                 // Which line does this fragment belong to?
1774*35238bceSAndroid Build Coastguard Worker 
1775*35238bceSAndroid Build Coastguard Worker                 if (result)
1776*35238bceSAndroid Build Coastguard Worker                 {
1777*35238bceSAndroid Build Coastguard Worker                     bool multipleNearbyLines = false;
1778*35238bceSAndroid Build Coastguard Worker                     bool renderAtSurfaceEdge = false;
1779*35238bceSAndroid Build Coastguard Worker 
1780*35238bceSAndroid Build Coastguard Worker                     renderAtSurfaceEdge = (y == 1) || (y == referenceLineMap.getWidth() - 2);
1781*35238bceSAndroid Build Coastguard Worker 
1782*35238bceSAndroid Build Coastguard Worker                     for (int dy = -1; dy < 2; ++dy)
1783*35238bceSAndroid Build Coastguard Worker                         for (int dx = -1; dx < 2; ++dx)
1784*35238bceSAndroid Build Coastguard Worker                         {
1785*35238bceSAndroid Build Coastguard Worker                             const int nearbyID = referenceLineMap.getAccess().getPixelInt(x + dx, y + dy).x();
1786*35238bceSAndroid Build Coastguard Worker                             if (nearbyID)
1787*35238bceSAndroid Build Coastguard Worker                             {
1788*35238bceSAndroid Build Coastguard Worker                                 if (lineID && lineID != nearbyID)
1789*35238bceSAndroid Build Coastguard Worker                                     multipleNearbyLines = true;
1790*35238bceSAndroid Build Coastguard Worker                                 lineID = nearbyID;
1791*35238bceSAndroid Build Coastguard Worker                             }
1792*35238bceSAndroid Build Coastguard Worker                         }
1793*35238bceSAndroid Build Coastguard Worker 
1794*35238bceSAndroid Build Coastguard Worker                     if (multipleNearbyLines || renderAtSurfaceEdge)
1795*35238bceSAndroid Build Coastguard Worker                     {
1796*35238bceSAndroid Build Coastguard Worker                         // Another line is too close, don't try to calculate width here
1797*35238bceSAndroid Build Coastguard Worker                         // Or the render result is outside of surface range
1798*35238bceSAndroid Build Coastguard Worker                         previousPixelUndefined = true;
1799*35238bceSAndroid Build Coastguard Worker                         continue;
1800*35238bceSAndroid Build Coastguard Worker                     }
1801*35238bceSAndroid Build Coastguard Worker                 }
1802*35238bceSAndroid Build Coastguard Worker 
1803*35238bceSAndroid Build Coastguard Worker                 // Only line with id of lineID is nearby
1804*35238bceSAndroid Build Coastguard Worker 
1805*35238bceSAndroid Build Coastguard Worker                 if (previousPixelUndefined)
1806*35238bceSAndroid Build Coastguard Worker                 {
1807*35238bceSAndroid Build Coastguard Worker                     // The line might have been overdrawn or not
1808*35238bceSAndroid Build Coastguard Worker                     currentLine            = lineID;
1809*35238bceSAndroid Build Coastguard Worker                     currentWidth           = 1;
1810*35238bceSAndroid Build Coastguard Worker                     fullyVisibleLine       = false;
1811*35238bceSAndroid Build Coastguard Worker                     previousPixelUndefined = false;
1812*35238bceSAndroid Build Coastguard Worker                 }
1813*35238bceSAndroid Build Coastguard Worker                 else if (lineID == currentLine)
1814*35238bceSAndroid Build Coastguard Worker                 {
1815*35238bceSAndroid Build Coastguard Worker                     // Current line continues
1816*35238bceSAndroid Build Coastguard Worker                     ++currentWidth;
1817*35238bceSAndroid Build Coastguard Worker                 }
1818*35238bceSAndroid Build Coastguard Worker                 else if (lineID > currentLine)
1819*35238bceSAndroid Build Coastguard Worker                 {
1820*35238bceSAndroid Build Coastguard Worker                     // Another line was drawn over or the line ends
1821*35238bceSAndroid Build Coastguard Worker                     currentLine      = lineID;
1822*35238bceSAndroid Build Coastguard Worker                     currentWidth     = 1;
1823*35238bceSAndroid Build Coastguard Worker                     fullyVisibleLine = true;
1824*35238bceSAndroid Build Coastguard Worker                 }
1825*35238bceSAndroid Build Coastguard Worker                 else
1826*35238bceSAndroid Build Coastguard Worker                 {
1827*35238bceSAndroid Build Coastguard Worker                     // The line ends
1828*35238bceSAndroid Build Coastguard Worker                     if (fullyVisibleLine && lineIsXMajor[currentLine - 1])
1829*35238bceSAndroid Build Coastguard Worker                     {
1830*35238bceSAndroid Build Coastguard Worker                         // check width
1831*35238bceSAndroid Build Coastguard Worker                         if (currentWidth != lineWidth)
1832*35238bceSAndroid Build Coastguard Worker                         {
1833*35238bceSAndroid Build Coastguard Worker                             log << tcu::TestLog::Message << "\tInvalid line width at (" << x << ", " << y - currentWidth
1834*35238bceSAndroid Build Coastguard Worker                                 << ") - (" << x << ", " << y - 1 << "). Detected width of " << currentWidth
1835*35238bceSAndroid Build Coastguard Worker                                 << ", expected " << lineWidth << tcu::TestLog::EndMessage;
1836*35238bceSAndroid Build Coastguard Worker                             invalidWidthFound = true;
1837*35238bceSAndroid Build Coastguard Worker                         }
1838*35238bceSAndroid Build Coastguard Worker                     }
1839*35238bceSAndroid Build Coastguard Worker 
1840*35238bceSAndroid Build Coastguard Worker                     currentLine      = lineID;
1841*35238bceSAndroid Build Coastguard Worker                     currentWidth     = 1;
1842*35238bceSAndroid Build Coastguard Worker                     fullyVisibleLine = false;
1843*35238bceSAndroid Build Coastguard Worker                 }
1844*35238bceSAndroid Build Coastguard Worker             }
1845*35238bceSAndroid Build Coastguard Worker         }
1846*35238bceSAndroid Build Coastguard Worker 
1847*35238bceSAndroid Build Coastguard Worker         if (invalidWidthFound)
1848*35238bceSAndroid Build Coastguard Worker         {
1849*35238bceSAndroid Build Coastguard Worker             log << tcu::TestLog::Message << "Invalid line width found, image is not valid." << tcu::TestLog::EndMessage;
1850*35238bceSAndroid Build Coastguard Worker             allOK = false;
1851*35238bceSAndroid Build Coastguard Worker         }
1852*35238bceSAndroid Build Coastguard Worker         else
1853*35238bceSAndroid Build Coastguard Worker         {
1854*35238bceSAndroid Build Coastguard Worker             log << tcu::TestLog::Message << "Line widths are valid." << tcu::TestLog::EndMessage;
1855*35238bceSAndroid Build Coastguard Worker         }
1856*35238bceSAndroid Build Coastguard Worker     }
1857*35238bceSAndroid Build Coastguard Worker 
1858*35238bceSAndroid Build Coastguard Worker     //\todo [2013-10-24 jarkko].
1859*35238bceSAndroid Build Coastguard Worker     //Requirement 4. If two line segments share a common endpoint, and both segments are either
1860*35238bceSAndroid Build Coastguard Worker     //x-major (both left-to-right or both right-to-left) or y-major (both bottom-totop
1861*35238bceSAndroid Build Coastguard Worker     //or both top-to-bottom), then rasterizing both segments may not produce
1862*35238bceSAndroid Build Coastguard Worker     //duplicate fragments, nor may any fragments be omitted so as to interrupt
1863*35238bceSAndroid Build Coastguard Worker     //continuity of the connected segments.
1864*35238bceSAndroid Build Coastguard Worker 
1865*35238bceSAndroid Build Coastguard Worker     {
1866*35238bceSAndroid Build Coastguard Worker         tcu::Surface reference(surface.getWidth(), surface.getHeight());
1867*35238bceSAndroid Build Coastguard Worker         tcu::clear(reference.getAccess(), tcu::IVec4(0, 0, 0, 255));
1868*35238bceSAndroid Build Coastguard Worker         for (int y = 0; y < surface.getHeight(); ++y)
1869*35238bceSAndroid Build Coastguard Worker             for (int x = 0; x < surface.getWidth(); ++x)
1870*35238bceSAndroid Build Coastguard Worker                 if (referenceLineMap.getAccess().getPixelInt(x, y).x())
1871*35238bceSAndroid Build Coastguard Worker                     reference.setPixel(x, y, tcu::RGBA::white());
1872*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Invalid fragment count in result image." << tcu::TestLog::EndMessage;
1873*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
1874*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Reference", "Reference", reference)
1875*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Result", "Result", surface) << tcu::TestLog::EndImageSet;
1876*35238bceSAndroid Build Coastguard Worker     }
1877*35238bceSAndroid Build Coastguard Worker 
1878*35238bceSAndroid Build Coastguard Worker     return allOK;
1879*35238bceSAndroid Build Coastguard Worker }
1880*35238bceSAndroid Build Coastguard Worker 
1881*35238bceSAndroid Build Coastguard Worker struct SingleSampleNarrowLineCandidate
1882*35238bceSAndroid Build Coastguard Worker {
1883*35238bceSAndroid Build Coastguard Worker     int lineNdx;
1884*35238bceSAndroid Build Coastguard Worker     tcu::IVec3 colorMin;
1885*35238bceSAndroid Build Coastguard Worker     tcu::IVec3 colorMax;
1886*35238bceSAndroid Build Coastguard Worker     tcu::Vec3 colorMinF;
1887*35238bceSAndroid Build Coastguard Worker     tcu::Vec3 colorMaxF;
1888*35238bceSAndroid Build Coastguard Worker     tcu::Vec3 valueRangeMin;
1889*35238bceSAndroid Build Coastguard Worker     tcu::Vec3 valueRangeMax;
1890*35238bceSAndroid Build Coastguard Worker };
1891*35238bceSAndroid Build Coastguard Worker 
setMaskMapCoverageBitForLine(int bitNdx,const tcu::Vec2 & screenSpaceP0,const tcu::Vec2 & screenSpaceP1,float lineWidth,tcu::PixelBufferAccess maskMap,const int subpixelBits)1892*35238bceSAndroid Build Coastguard Worker void setMaskMapCoverageBitForLine(int bitNdx, const tcu::Vec2 &screenSpaceP0, const tcu::Vec2 &screenSpaceP1,
1893*35238bceSAndroid Build Coastguard Worker                                   float lineWidth, tcu::PixelBufferAccess maskMap, const int subpixelBits)
1894*35238bceSAndroid Build Coastguard Worker {
1895*35238bceSAndroid Build Coastguard Worker     enum
1896*35238bceSAndroid Build Coastguard Worker     {
1897*35238bceSAndroid Build Coastguard Worker         MAX_PACKETS = 32,
1898*35238bceSAndroid Build Coastguard Worker     };
1899*35238bceSAndroid Build Coastguard Worker 
1900*35238bceSAndroid Build Coastguard Worker     rr::SingleSampleLineRasterizer rasterizer(tcu::IVec4(0, 0, maskMap.getWidth(), maskMap.getHeight()), subpixelBits);
1901*35238bceSAndroid Build Coastguard Worker     int numRasterized = MAX_PACKETS;
1902*35238bceSAndroid Build Coastguard Worker     rr::FragmentPacket packets[MAX_PACKETS];
1903*35238bceSAndroid Build Coastguard Worker 
1904*35238bceSAndroid Build Coastguard Worker     rasterizer.init(tcu::Vec4(screenSpaceP0.x(), screenSpaceP0.y(), 0.0f, 1.0f),
1905*35238bceSAndroid Build Coastguard Worker                     tcu::Vec4(screenSpaceP1.x(), screenSpaceP1.y(), 0.0f, 1.0f), lineWidth, 1, 0xFFFF);
1906*35238bceSAndroid Build Coastguard Worker 
1907*35238bceSAndroid Build Coastguard Worker     while (numRasterized == MAX_PACKETS)
1908*35238bceSAndroid Build Coastguard Worker     {
1909*35238bceSAndroid Build Coastguard Worker         rasterizer.rasterize(packets, DE_NULL, MAX_PACKETS, numRasterized);
1910*35238bceSAndroid Build Coastguard Worker 
1911*35238bceSAndroid Build Coastguard Worker         for (int packetNdx = 0; packetNdx < numRasterized; ++packetNdx)
1912*35238bceSAndroid Build Coastguard Worker         {
1913*35238bceSAndroid Build Coastguard Worker             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1914*35238bceSAndroid Build Coastguard Worker             {
1915*35238bceSAndroid Build Coastguard Worker                 if ((uint32_t)packets[packetNdx].coverage & (1 << fragNdx))
1916*35238bceSAndroid Build Coastguard Worker                 {
1917*35238bceSAndroid Build Coastguard Worker                     const tcu::IVec2 fragPos = packets[packetNdx].position + tcu::IVec2(fragNdx % 2, fragNdx / 2);
1918*35238bceSAndroid Build Coastguard Worker 
1919*35238bceSAndroid Build Coastguard Worker                     DE_ASSERT(deInBounds32(fragPos.x(), 0, maskMap.getWidth()));
1920*35238bceSAndroid Build Coastguard Worker                     DE_ASSERT(deInBounds32(fragPos.y(), 0, maskMap.getHeight()));
1921*35238bceSAndroid Build Coastguard Worker 
1922*35238bceSAndroid Build Coastguard Worker                     const uint32_t previousMask = maskMap.getPixelUint(fragPos.x(), fragPos.y()).x();
1923*35238bceSAndroid Build Coastguard Worker                     const uint32_t newMask      = (previousMask) | ((uint32_t)1u << bitNdx);
1924*35238bceSAndroid Build Coastguard Worker 
1925*35238bceSAndroid Build Coastguard Worker                     maskMap.setPixel(tcu::UVec4(newMask, 0, 0, 0), fragPos.x(), fragPos.y());
1926*35238bceSAndroid Build Coastguard Worker                 }
1927*35238bceSAndroid Build Coastguard Worker             }
1928*35238bceSAndroid Build Coastguard Worker         }
1929*35238bceSAndroid Build Coastguard Worker     }
1930*35238bceSAndroid Build Coastguard Worker }
1931*35238bceSAndroid Build Coastguard Worker 
setMaskMapCoverageBitForLines(const std::vector<tcu::Vec4> & screenspaceLines,float lineWidth,tcu::PixelBufferAccess maskMap,const int subpixelBits)1932*35238bceSAndroid Build Coastguard Worker void setMaskMapCoverageBitForLines(const std::vector<tcu::Vec4> &screenspaceLines, float lineWidth,
1933*35238bceSAndroid Build Coastguard Worker                                    tcu::PixelBufferAccess maskMap, const int subpixelBits)
1934*35238bceSAndroid Build Coastguard Worker {
1935*35238bceSAndroid Build Coastguard Worker     for (int lineNdx = 0; lineNdx < (int)screenspaceLines.size(); ++lineNdx)
1936*35238bceSAndroid Build Coastguard Worker     {
1937*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 pa = screenspaceLines[lineNdx].swizzle(0, 1);
1938*35238bceSAndroid Build Coastguard Worker         const tcu::Vec2 pb = screenspaceLines[lineNdx].swizzle(2, 3);
1939*35238bceSAndroid Build Coastguard Worker 
1940*35238bceSAndroid Build Coastguard Worker         setMaskMapCoverageBitForLine(lineNdx, pa, pb, lineWidth, maskMap, subpixelBits);
1941*35238bceSAndroid Build Coastguard Worker     }
1942*35238bceSAndroid Build Coastguard Worker }
1943*35238bceSAndroid Build Coastguard Worker 
1944*35238bceSAndroid Build Coastguard Worker // verify line interpolation assuming line pixels are interpolated independently depending only on screen space location
verifyLineGroupPixelIndependentInterpolation(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log,LineInterpolationMethod interpolationMethod)1945*35238bceSAndroid Build Coastguard Worker bool verifyLineGroupPixelIndependentInterpolation(const tcu::Surface &surface, const LineSceneSpec &scene,
1946*35238bceSAndroid Build Coastguard Worker                                                   const RasterizationArguments &args, tcu::TestLog &log,
1947*35238bceSAndroid Build Coastguard Worker                                                   LineInterpolationMethod interpolationMethod)
1948*35238bceSAndroid Build Coastguard Worker {
1949*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(scene.lines.size() < 8); // coverage indices are stored as bitmask in a unsigned 8-bit ints
1950*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(interpolationMethod == LINEINTERPOLATION_STRICTLY_CORRECT ||
1951*35238bceSAndroid Build Coastguard Worker               interpolationMethod == LINEINTERPOLATION_PROJECTED);
1952*35238bceSAndroid Build Coastguard Worker 
1953*35238bceSAndroid Build Coastguard Worker     const tcu::RGBA invalidPixelColor = tcu::RGBA(255, 0, 0, 255);
1954*35238bceSAndroid Build Coastguard Worker     const tcu::IVec2 viewportSize     = tcu::IVec2(surface.getWidth(), surface.getHeight());
1955*35238bceSAndroid Build Coastguard Worker     const int errorFloodThreshold     = 4;
1956*35238bceSAndroid Build Coastguard Worker     int errorCount                    = 0;
1957*35238bceSAndroid Build Coastguard Worker     tcu::Surface errorMask(surface.getWidth(), surface.getHeight());
1958*35238bceSAndroid Build Coastguard Worker     int invalidPixels = 0;
1959*35238bceSAndroid Build Coastguard Worker     std::vector<tcu::Vec4> screenspaceLines(scene.lines.size()); //!< packed (x0, y0, x1, y1)
1960*35238bceSAndroid Build Coastguard Worker 
1961*35238bceSAndroid Build Coastguard Worker     // Reference renderer produces correct fragments using the diamond-exit-rule. Make 2D int array, store line coverage as a 8-bit bitfield
1962*35238bceSAndroid Build Coastguard Worker     // The map is used to find lines with potential coverage to a given pixel
1963*35238bceSAndroid Build Coastguard Worker     tcu::TextureLevel referenceLineMap(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT8),
1964*35238bceSAndroid Build Coastguard Worker                                        surface.getWidth(), surface.getHeight());
1965*35238bceSAndroid Build Coastguard Worker 
1966*35238bceSAndroid Build Coastguard Worker     tcu::clear(referenceLineMap.getAccess(), tcu::IVec4(0, 0, 0, 0));
1967*35238bceSAndroid Build Coastguard Worker     tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1968*35238bceSAndroid Build Coastguard Worker 
1969*35238bceSAndroid Build Coastguard Worker     // log format
1970*35238bceSAndroid Build Coastguard Worker 
1971*35238bceSAndroid Build Coastguard Worker     log << tcu::TestLog::Message << "Verifying rasterization result. Native format is RGB" << args.redBits
1972*35238bceSAndroid Build Coastguard Worker         << args.greenBits << args.blueBits << tcu::TestLog::EndMessage;
1973*35238bceSAndroid Build Coastguard Worker     if (args.redBits > 8 || args.greenBits > 8 || args.blueBits > 8)
1974*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message
1975*35238bceSAndroid Build Coastguard Worker             << "Warning! More than 8 bits in a color channel, this may produce false negatives."
1976*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::EndMessage;
1977*35238bceSAndroid Build Coastguard Worker 
1978*35238bceSAndroid Build Coastguard Worker     // prepare lookup map
1979*35238bceSAndroid Build Coastguard Worker 
1980*35238bceSAndroid Build Coastguard Worker     genScreenSpaceLines(screenspaceLines, scene.lines, viewportSize);
1981*35238bceSAndroid Build Coastguard Worker     setMaskMapCoverageBitForLines(screenspaceLines, scene.lineWidth, referenceLineMap.getAccess(), args.subpixelBits);
1982*35238bceSAndroid Build Coastguard Worker 
1983*35238bceSAndroid Build Coastguard Worker     // Find all possible lines with coverage, check pixel color matches one of them
1984*35238bceSAndroid Build Coastguard Worker 
1985*35238bceSAndroid Build Coastguard Worker     for (int y = 1; y < surface.getHeight() - 1; ++y)
1986*35238bceSAndroid Build Coastguard Worker         for (int x = 1; x < surface.getWidth() - 1; ++x)
1987*35238bceSAndroid Build Coastguard Worker         {
1988*35238bceSAndroid Build Coastguard Worker             const tcu::RGBA color             = surface.getPixel(x, y);
1989*35238bceSAndroid Build Coastguard Worker             const tcu::IVec3 pixelNativeColor = convertRGB8ToNativeFormat(
1990*35238bceSAndroid Build Coastguard Worker                 color, args); // Convert pixel color from rgba8 to the real pixel format. Usually rgba8 or 565
1991*35238bceSAndroid Build Coastguard Worker             int lineCoverageSet         = 0;      // !< lines that may cover this fragment
1992*35238bceSAndroid Build Coastguard Worker             int lineSurroundingCoverage = 0xFFFF; // !< lines that will cover this fragment
1993*35238bceSAndroid Build Coastguard Worker             bool matchFound             = false;
1994*35238bceSAndroid Build Coastguard Worker             const tcu::IVec3 formatLimit((1 << args.redBits) - 1, (1 << args.greenBits) - 1, (1 << args.blueBits) - 1);
1995*35238bceSAndroid Build Coastguard Worker 
1996*35238bceSAndroid Build Coastguard Worker             std::vector<SingleSampleNarrowLineCandidate> candidates;
1997*35238bceSAndroid Build Coastguard Worker 
1998*35238bceSAndroid Build Coastguard Worker             // Find lines with possible coverage
1999*35238bceSAndroid Build Coastguard Worker 
2000*35238bceSAndroid Build Coastguard Worker             for (int dy = -1; dy < 2; ++dy)
2001*35238bceSAndroid Build Coastguard Worker                 for (int dx = -1; dx < 2; ++dx)
2002*35238bceSAndroid Build Coastguard Worker                 {
2003*35238bceSAndroid Build Coastguard Worker                     const int coverage = referenceLineMap.getAccess().getPixelInt(x + dx, y + dy).x();
2004*35238bceSAndroid Build Coastguard Worker 
2005*35238bceSAndroid Build Coastguard Worker                     lineCoverageSet |= coverage;
2006*35238bceSAndroid Build Coastguard Worker                     lineSurroundingCoverage &= coverage;
2007*35238bceSAndroid Build Coastguard Worker                 }
2008*35238bceSAndroid Build Coastguard Worker 
2009*35238bceSAndroid Build Coastguard Worker             // background color is possible?
2010*35238bceSAndroid Build Coastguard Worker             if (lineSurroundingCoverage == 0 &&
2011*35238bceSAndroid Build Coastguard Worker                 compareColors(color, tcu::RGBA::black(), args.redBits, args.greenBits, args.blueBits))
2012*35238bceSAndroid Build Coastguard Worker                 continue;
2013*35238bceSAndroid Build Coastguard Worker 
2014*35238bceSAndroid Build Coastguard Worker             // Check those lines
2015*35238bceSAndroid Build Coastguard Worker 
2016*35238bceSAndroid Build Coastguard Worker             for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
2017*35238bceSAndroid Build Coastguard Worker             {
2018*35238bceSAndroid Build Coastguard Worker                 if (((lineCoverageSet >> lineNdx) & 0x01) != 0)
2019*35238bceSAndroid Build Coastguard Worker                 {
2020*35238bceSAndroid Build Coastguard Worker                     const float wa     = scene.lines[lineNdx].positions[0].w();
2021*35238bceSAndroid Build Coastguard Worker                     const float wb     = scene.lines[lineNdx].positions[1].w();
2022*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec2 pa = screenspaceLines[lineNdx].swizzle(0, 1);
2023*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec2 pb = screenspaceLines[lineNdx].swizzle(2, 3);
2024*35238bceSAndroid Build Coastguard Worker 
2025*35238bceSAndroid Build Coastguard Worker                     const LineInterpolationRange range = (interpolationMethod == LINEINTERPOLATION_STRICTLY_CORRECT) ?
2026*35238bceSAndroid Build Coastguard Worker                                                              (calcSingleSampleLineInterpolationRange(
2027*35238bceSAndroid Build Coastguard Worker                                                                  pa, wa, pb, wb, tcu::IVec2(x, y), args.subpixelBits)) :
2028*35238bceSAndroid Build Coastguard Worker                                                              (calcSingleSampleLineInterpolationRangeAxisProjected(
2029*35238bceSAndroid Build Coastguard Worker                                                                  pa, wa, pb, wb, tcu::IVec2(x, y), args.subpixelBits));
2030*35238bceSAndroid Build Coastguard Worker 
2031*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec4 valueMin = de::clamp(range.min.x(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[0] +
2032*35238bceSAndroid Build Coastguard Worker                                                de::clamp(range.min.y(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[1];
2033*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec4 valueMax = de::clamp(range.max.x(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[0] +
2034*35238bceSAndroid Build Coastguard Worker                                                de::clamp(range.max.y(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[1];
2035*35238bceSAndroid Build Coastguard Worker 
2036*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec3 colorMinF(
2037*35238bceSAndroid Build Coastguard Worker                         de::clamp(valueMin.x() * (float)formatLimit.x(), 0.0f, (float)formatLimit.x()),
2038*35238bceSAndroid Build Coastguard Worker                         de::clamp(valueMin.y() * (float)formatLimit.y(), 0.0f, (float)formatLimit.y()),
2039*35238bceSAndroid Build Coastguard Worker                         de::clamp(valueMin.z() * (float)formatLimit.z(), 0.0f, (float)formatLimit.z()));
2040*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec3 colorMaxF(
2041*35238bceSAndroid Build Coastguard Worker                         de::clamp(valueMax.x() * (float)formatLimit.x(), 0.0f, (float)formatLimit.x()),
2042*35238bceSAndroid Build Coastguard Worker                         de::clamp(valueMax.y() * (float)formatLimit.y(), 0.0f, (float)formatLimit.y()),
2043*35238bceSAndroid Build Coastguard Worker                         de::clamp(valueMax.z() * (float)formatLimit.z(), 0.0f, (float)formatLimit.z()));
2044*35238bceSAndroid Build Coastguard Worker                     const tcu::IVec3 colorMin((int)deFloatFloor(colorMinF.x()), (int)deFloatFloor(colorMinF.y()),
2045*35238bceSAndroid Build Coastguard Worker                                               (int)deFloatFloor(colorMinF.z()));
2046*35238bceSAndroid Build Coastguard Worker                     const tcu::IVec3 colorMax((int)deFloatCeil(colorMaxF.x()), (int)deFloatCeil(colorMaxF.y()),
2047*35238bceSAndroid Build Coastguard Worker                                               (int)deFloatCeil(colorMaxF.z()));
2048*35238bceSAndroid Build Coastguard Worker 
2049*35238bceSAndroid Build Coastguard Worker                     // Verify validity
2050*35238bceSAndroid Build Coastguard Worker                     if (pixelNativeColor.x() < colorMin.x() || pixelNativeColor.y() < colorMin.y() ||
2051*35238bceSAndroid Build Coastguard Worker                         pixelNativeColor.z() < colorMin.z() || pixelNativeColor.x() > colorMax.x() ||
2052*35238bceSAndroid Build Coastguard Worker                         pixelNativeColor.y() > colorMax.y() || pixelNativeColor.z() > colorMax.z())
2053*35238bceSAndroid Build Coastguard Worker                     {
2054*35238bceSAndroid Build Coastguard Worker                         if (errorCount < errorFloodThreshold)
2055*35238bceSAndroid Build Coastguard Worker                         {
2056*35238bceSAndroid Build Coastguard Worker                             // Store candidate information for logging
2057*35238bceSAndroid Build Coastguard Worker                             SingleSampleNarrowLineCandidate candidate;
2058*35238bceSAndroid Build Coastguard Worker 
2059*35238bceSAndroid Build Coastguard Worker                             candidate.lineNdx       = lineNdx;
2060*35238bceSAndroid Build Coastguard Worker                             candidate.colorMin      = colorMin;
2061*35238bceSAndroid Build Coastguard Worker                             candidate.colorMax      = colorMax;
2062*35238bceSAndroid Build Coastguard Worker                             candidate.colorMinF     = colorMinF;
2063*35238bceSAndroid Build Coastguard Worker                             candidate.colorMaxF     = colorMaxF;
2064*35238bceSAndroid Build Coastguard Worker                             candidate.valueRangeMin = valueMin.swizzle(0, 1, 2);
2065*35238bceSAndroid Build Coastguard Worker                             candidate.valueRangeMax = valueMax.swizzle(0, 1, 2);
2066*35238bceSAndroid Build Coastguard Worker 
2067*35238bceSAndroid Build Coastguard Worker                             candidates.push_back(candidate);
2068*35238bceSAndroid Build Coastguard Worker                         }
2069*35238bceSAndroid Build Coastguard Worker                     }
2070*35238bceSAndroid Build Coastguard Worker                     else
2071*35238bceSAndroid Build Coastguard Worker                     {
2072*35238bceSAndroid Build Coastguard Worker                         matchFound = true;
2073*35238bceSAndroid Build Coastguard Worker                         break;
2074*35238bceSAndroid Build Coastguard Worker                     }
2075*35238bceSAndroid Build Coastguard Worker                 }
2076*35238bceSAndroid Build Coastguard Worker             }
2077*35238bceSAndroid Build Coastguard Worker 
2078*35238bceSAndroid Build Coastguard Worker             if (matchFound)
2079*35238bceSAndroid Build Coastguard Worker                 continue;
2080*35238bceSAndroid Build Coastguard Worker 
2081*35238bceSAndroid Build Coastguard Worker             // invalid fragment
2082*35238bceSAndroid Build Coastguard Worker             ++invalidPixels;
2083*35238bceSAndroid Build Coastguard Worker             errorMask.setPixel(x, y, invalidPixelColor);
2084*35238bceSAndroid Build Coastguard Worker 
2085*35238bceSAndroid Build Coastguard Worker             ++errorCount;
2086*35238bceSAndroid Build Coastguard Worker 
2087*35238bceSAndroid Build Coastguard Worker             // don't fill the logs with too much data
2088*35238bceSAndroid Build Coastguard Worker             if (errorCount < errorFloodThreshold)
2089*35238bceSAndroid Build Coastguard Worker             {
2090*35238bceSAndroid Build Coastguard Worker                 log << tcu::TestLog::Message << "Found an invalid pixel at (" << x << "," << y << "), "
2091*35238bceSAndroid Build Coastguard Worker                     << (int)candidates.size() << " candidate reference value(s) found:\n"
2092*35238bceSAndroid Build Coastguard Worker                     << "\tPixel color:\t\t" << color << "\n"
2093*35238bceSAndroid Build Coastguard Worker                     << "\tNative color:\t\t" << pixelNativeColor << "\n"
2094*35238bceSAndroid Build Coastguard Worker                     << tcu::TestLog::EndMessage;
2095*35238bceSAndroid Build Coastguard Worker 
2096*35238bceSAndroid Build Coastguard Worker                 for (int candidateNdx = 0; candidateNdx < (int)candidates.size(); ++candidateNdx)
2097*35238bceSAndroid Build Coastguard Worker                 {
2098*35238bceSAndroid Build Coastguard Worker                     const SingleSampleNarrowLineCandidate &candidate = candidates[candidateNdx];
2099*35238bceSAndroid Build Coastguard Worker 
2100*35238bceSAndroid Build Coastguard Worker                     log << tcu::TestLog::Message << "\tCandidate (line " << candidate.lineNdx << "):\n"
2101*35238bceSAndroid Build Coastguard Worker                         << "\t\tReference native color min: "
2102*35238bceSAndroid Build Coastguard Worker                         << tcu::clamp(candidate.colorMin, tcu::IVec3(0, 0, 0), formatLimit) << "\n"
2103*35238bceSAndroid Build Coastguard Worker                         << "\t\tReference native color max: "
2104*35238bceSAndroid Build Coastguard Worker                         << tcu::clamp(candidate.colorMax, tcu::IVec3(0, 0, 0), formatLimit) << "\n"
2105*35238bceSAndroid Build Coastguard Worker                         << "\t\tReference native float min: "
2106*35238bceSAndroid Build Coastguard Worker                         << tcu::clamp(candidate.colorMinF, tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>())
2107*35238bceSAndroid Build Coastguard Worker                         << "\n"
2108*35238bceSAndroid Build Coastguard Worker                         << "\t\tReference native float max: "
2109*35238bceSAndroid Build Coastguard Worker                         << tcu::clamp(candidate.colorMaxF, tcu::Vec3(0.0f, 0.0f, 0.0f), formatLimit.cast<float>())
2110*35238bceSAndroid Build Coastguard Worker                         << "\n"
2111*35238bceSAndroid Build Coastguard Worker                         << "\t\tFmin:\t"
2112*35238bceSAndroid Build Coastguard Worker                         << tcu::clamp(candidate.valueRangeMin, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f))
2113*35238bceSAndroid Build Coastguard Worker                         << "\n"
2114*35238bceSAndroid Build Coastguard Worker                         << "\t\tFmax:\t"
2115*35238bceSAndroid Build Coastguard Worker                         << tcu::clamp(candidate.valueRangeMax, tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 1.0f))
2116*35238bceSAndroid Build Coastguard Worker                         << "\n"
2117*35238bceSAndroid Build Coastguard Worker                         << tcu::TestLog::EndMessage;
2118*35238bceSAndroid Build Coastguard Worker                 }
2119*35238bceSAndroid Build Coastguard Worker             }
2120*35238bceSAndroid Build Coastguard Worker         }
2121*35238bceSAndroid Build Coastguard Worker 
2122*35238bceSAndroid Build Coastguard Worker     // don't just hide failures
2123*35238bceSAndroid Build Coastguard Worker     if (errorCount > errorFloodThreshold)
2124*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Omitted " << (errorCount - errorFloodThreshold)
2125*35238bceSAndroid Build Coastguard Worker             << " pixel error description(s)." << tcu::TestLog::EndMessage;
2126*35238bceSAndroid Build Coastguard Worker 
2127*35238bceSAndroid Build Coastguard Worker     // report result
2128*35238bceSAndroid Build Coastguard Worker     if (invalidPixels)
2129*35238bceSAndroid Build Coastguard Worker     {
2130*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << invalidPixels << " invalid pixel(s) found." << tcu::TestLog::EndMessage;
2131*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2132*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Result", "Result", surface)
2133*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
2134*35238bceSAndroid Build Coastguard Worker 
2135*35238bceSAndroid Build Coastguard Worker         return false;
2136*35238bceSAndroid Build Coastguard Worker     }
2137*35238bceSAndroid Build Coastguard Worker     else
2138*35238bceSAndroid Build Coastguard Worker     {
2139*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
2140*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2141*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Result", "Result", surface) << tcu::TestLog::EndImageSet;
2142*35238bceSAndroid Build Coastguard Worker 
2143*35238bceSAndroid Build Coastguard Worker         return true;
2144*35238bceSAndroid Build Coastguard Worker     }
2145*35238bceSAndroid Build Coastguard Worker }
2146*35238bceSAndroid Build Coastguard Worker 
verifySinglesampleNarrowLineGroupInterpolation(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)2147*35238bceSAndroid Build Coastguard Worker bool verifySinglesampleNarrowLineGroupInterpolation(const tcu::Surface &surface, const LineSceneSpec &scene,
2148*35238bceSAndroid Build Coastguard Worker                                                     const RasterizationArguments &args, tcu::TestLog &log)
2149*35238bceSAndroid Build Coastguard Worker {
2150*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(scene.lineWidth == 1.0f);
2151*35238bceSAndroid Build Coastguard Worker     return verifyLineGroupPixelIndependentInterpolation(surface, scene, args, log, LINEINTERPOLATION_STRICTLY_CORRECT);
2152*35238bceSAndroid Build Coastguard Worker }
2153*35238bceSAndroid Build Coastguard Worker 
verifyLineGroupInterpolationWithNonProjectedWeights(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)2154*35238bceSAndroid Build Coastguard Worker bool verifyLineGroupInterpolationWithNonProjectedWeights(const tcu::Surface &surface, const LineSceneSpec &scene,
2155*35238bceSAndroid Build Coastguard Worker                                                          const RasterizationArguments &args, tcu::TestLog &log)
2156*35238bceSAndroid Build Coastguard Worker {
2157*35238bceSAndroid Build Coastguard Worker     return verifyLineGroupPixelIndependentInterpolation(surface, scene, args, log, LINEINTERPOLATION_STRICTLY_CORRECT);
2158*35238bceSAndroid Build Coastguard Worker }
2159*35238bceSAndroid Build Coastguard Worker 
verifyLineGroupInterpolationWithProjectedWeights(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)2160*35238bceSAndroid Build Coastguard Worker bool verifyLineGroupInterpolationWithProjectedWeights(const tcu::Surface &surface, const LineSceneSpec &scene,
2161*35238bceSAndroid Build Coastguard Worker                                                       const RasterizationArguments &args, tcu::TestLog &log)
2162*35238bceSAndroid Build Coastguard Worker {
2163*35238bceSAndroid Build Coastguard Worker     return verifyLineGroupPixelIndependentInterpolation(surface, scene, args, log, LINEINTERPOLATION_PROJECTED);
2164*35238bceSAndroid Build Coastguard Worker }
2165*35238bceSAndroid Build Coastguard Worker 
2166*35238bceSAndroid Build Coastguard Worker struct SingleSampleWideLineCandidate
2167*35238bceSAndroid Build Coastguard Worker {
2168*35238bceSAndroid Build Coastguard Worker     struct InterpolationPointCandidate
2169*35238bceSAndroid Build Coastguard Worker     {
2170*35238bceSAndroid Build Coastguard Worker         tcu::IVec2 interpolationPoint;
2171*35238bceSAndroid Build Coastguard Worker         tcu::IVec3 colorMin;
2172*35238bceSAndroid Build Coastguard Worker         tcu::IVec3 colorMax;
2173*35238bceSAndroid Build Coastguard Worker         tcu::Vec3 colorMinF;
2174*35238bceSAndroid Build Coastguard Worker         tcu::Vec3 colorMaxF;
2175*35238bceSAndroid Build Coastguard Worker         tcu::Vec3 valueRangeMin;
2176*35238bceSAndroid Build Coastguard Worker         tcu::Vec3 valueRangeMax;
2177*35238bceSAndroid Build Coastguard Worker     };
2178*35238bceSAndroid Build Coastguard Worker 
2179*35238bceSAndroid Build Coastguard Worker     int lineNdx;
2180*35238bceSAndroid Build Coastguard Worker     int numCandidates;
2181*35238bceSAndroid Build Coastguard Worker     InterpolationPointCandidate interpolationCandidates[3];
2182*35238bceSAndroid Build Coastguard Worker };
2183*35238bceSAndroid Build Coastguard Worker 
2184*35238bceSAndroid Build Coastguard Worker // return point on line at a given position on a given axis
getLineCoordAtAxisCoord(const tcu::Vec2 & pa,const tcu::Vec2 & pb,bool isXAxis,float axisCoord)2185*35238bceSAndroid Build Coastguard Worker tcu::Vec2 getLineCoordAtAxisCoord(const tcu::Vec2 &pa, const tcu::Vec2 &pb, bool isXAxis, float axisCoord)
2186*35238bceSAndroid Build Coastguard Worker {
2187*35238bceSAndroid Build Coastguard Worker     const int fixedCoordNdx   = (isXAxis) ? (0) : (1);
2188*35238bceSAndroid Build Coastguard Worker     const int varyingCoordNdx = (isXAxis) ? (1) : (0);
2189*35238bceSAndroid Build Coastguard Worker 
2190*35238bceSAndroid Build Coastguard Worker     const float fixedDifference   = pb[fixedCoordNdx] - pa[fixedCoordNdx];
2191*35238bceSAndroid Build Coastguard Worker     const float varyingDifference = pb[varyingCoordNdx] - pa[varyingCoordNdx];
2192*35238bceSAndroid Build Coastguard Worker 
2193*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(fixedDifference != 0.0f);
2194*35238bceSAndroid Build Coastguard Worker 
2195*35238bceSAndroid Build Coastguard Worker     const float resultFixedCoord = axisCoord;
2196*35238bceSAndroid Build Coastguard Worker     const float resultVaryingCoord =
2197*35238bceSAndroid Build Coastguard Worker         pa[varyingCoordNdx] + (axisCoord - pa[fixedCoordNdx]) * (varyingDifference / fixedDifference);
2198*35238bceSAndroid Build Coastguard Worker 
2199*35238bceSAndroid Build Coastguard Worker     return (isXAxis) ? (tcu::Vec2(resultFixedCoord, resultVaryingCoord)) :
2200*35238bceSAndroid Build Coastguard Worker                        (tcu::Vec2(resultVaryingCoord, resultFixedCoord));
2201*35238bceSAndroid Build Coastguard Worker }
2202*35238bceSAndroid Build Coastguard Worker 
isBlack(const tcu::RGBA & c)2203*35238bceSAndroid Build Coastguard Worker bool isBlack(const tcu::RGBA &c)
2204*35238bceSAndroid Build Coastguard Worker {
2205*35238bceSAndroid Build Coastguard Worker     return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0;
2206*35238bceSAndroid Build Coastguard Worker }
2207*35238bceSAndroid Build Coastguard Worker 
verifySinglesampleWideLineGroupInterpolation(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)2208*35238bceSAndroid Build Coastguard Worker bool verifySinglesampleWideLineGroupInterpolation(const tcu::Surface &surface, const LineSceneSpec &scene,
2209*35238bceSAndroid Build Coastguard Worker                                                   const RasterizationArguments &args, tcu::TestLog &log)
2210*35238bceSAndroid Build Coastguard Worker {
2211*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(deFloatFrac(scene.lineWidth) != 0.5f); // rounding direction is not defined, disallow undefined cases
2212*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(scene.lines.size() < 8);               // coverage indices are stored as bitmask in a unsigned 8-bit ints
2213*35238bceSAndroid Build Coastguard Worker 
2214*35238bceSAndroid Build Coastguard Worker     enum
2215*35238bceSAndroid Build Coastguard Worker     {
2216*35238bceSAndroid Build Coastguard Worker         FLAG_ROOT_NOT_SET = (1u << 16)
2217*35238bceSAndroid Build Coastguard Worker     };
2218*35238bceSAndroid Build Coastguard Worker 
2219*35238bceSAndroid Build Coastguard Worker     const tcu::RGBA invalidPixelColor = tcu::RGBA(255, 0, 0, 255);
2220*35238bceSAndroid Build Coastguard Worker     const tcu::IVec2 viewportSize     = tcu::IVec2(surface.getWidth(), surface.getHeight());
2221*35238bceSAndroid Build Coastguard Worker     const int errorFloodThreshold     = 4;
2222*35238bceSAndroid Build Coastguard Worker     int errorCount                    = 0;
2223*35238bceSAndroid Build Coastguard Worker     tcu::Surface errorMask(surface.getWidth(), surface.getHeight());
2224*35238bceSAndroid Build Coastguard Worker     int invalidPixels = 0;
2225*35238bceSAndroid Build Coastguard Worker     std::vector<tcu::Vec4> effectiveLines(scene.lines.size()); //!< packed (x0, y0, x1, y1)
2226*35238bceSAndroid Build Coastguard Worker     std::vector<bool> lineIsXMajor(scene.lines.size());
2227*35238bceSAndroid Build Coastguard Worker 
2228*35238bceSAndroid Build Coastguard Worker     // for each line, for every distinct major direction fragment, store root pixel location (along
2229*35238bceSAndroid Build Coastguard Worker     // minor direction);
2230*35238bceSAndroid Build Coastguard Worker     std::vector<std::vector<uint32_t>> rootPixelLocation(
2231*35238bceSAndroid Build Coastguard Worker         scene.lines.size()); //!< packed [16b - flags] [16b - coordinate]
2232*35238bceSAndroid Build Coastguard Worker 
2233*35238bceSAndroid Build Coastguard Worker     // log format
2234*35238bceSAndroid Build Coastguard Worker 
2235*35238bceSAndroid Build Coastguard Worker     log << tcu::TestLog::Message << "Verifying rasterization result. Native format is RGB" << args.redBits
2236*35238bceSAndroid Build Coastguard Worker         << args.greenBits << args.blueBits << tcu::TestLog::EndMessage;
2237*35238bceSAndroid Build Coastguard Worker     if (args.redBits > 8 || args.greenBits > 8 || args.blueBits > 8)
2238*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message
2239*35238bceSAndroid Build Coastguard Worker             << "Warning! More than 8 bits in a color channel, this may produce false negatives."
2240*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::EndMessage;
2241*35238bceSAndroid Build Coastguard Worker 
2242*35238bceSAndroid Build Coastguard Worker     // Reference renderer produces correct fragments using the diamond-exit-rule. Make 2D int array, store line coverage as a 8-bit bitfield
2243*35238bceSAndroid Build Coastguard Worker     // The map is used to find lines with potential coverage to a given pixel
2244*35238bceSAndroid Build Coastguard Worker     tcu::TextureLevel referenceLineMap(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT8),
2245*35238bceSAndroid Build Coastguard Worker                                        surface.getWidth(), surface.getHeight());
2246*35238bceSAndroid Build Coastguard Worker     tcu::clear(referenceLineMap.getAccess(), tcu::IVec4(0, 0, 0, 0));
2247*35238bceSAndroid Build Coastguard Worker 
2248*35238bceSAndroid Build Coastguard Worker     tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
2249*35238bceSAndroid Build Coastguard Worker 
2250*35238bceSAndroid Build Coastguard Worker     // calculate mask and effective line coordinates
2251*35238bceSAndroid Build Coastguard Worker     {
2252*35238bceSAndroid Build Coastguard Worker         std::vector<tcu::Vec4> screenspaceLines(scene.lines.size());
2253*35238bceSAndroid Build Coastguard Worker 
2254*35238bceSAndroid Build Coastguard Worker         genScreenSpaceLines(screenspaceLines, scene.lines, viewportSize);
2255*35238bceSAndroid Build Coastguard Worker         setMaskMapCoverageBitForLines(screenspaceLines, scene.lineWidth, referenceLineMap.getAccess(),
2256*35238bceSAndroid Build Coastguard Worker                                       args.subpixelBits);
2257*35238bceSAndroid Build Coastguard Worker 
2258*35238bceSAndroid Build Coastguard Worker         for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
2259*35238bceSAndroid Build Coastguard Worker         {
2260*35238bceSAndroid Build Coastguard Worker             const tcu::Vec2 lineScreenSpaceP0 = screenspaceLines[lineNdx].swizzle(0, 1);
2261*35238bceSAndroid Build Coastguard Worker             const tcu::Vec2 lineScreenSpaceP1 = screenspaceLines[lineNdx].swizzle(2, 3);
2262*35238bceSAndroid Build Coastguard Worker             const bool isXMajor               = isPackedSSLineXMajor(screenspaceLines[lineNdx]);
2263*35238bceSAndroid Build Coastguard Worker 
2264*35238bceSAndroid Build Coastguard Worker             lineIsXMajor[lineNdx] = isXMajor;
2265*35238bceSAndroid Build Coastguard Worker 
2266*35238bceSAndroid Build Coastguard Worker             // wide line interpolations are calculated for a line moved in minor direction
2267*35238bceSAndroid Build Coastguard Worker             {
2268*35238bceSAndroid Build Coastguard Worker                 const float offsetLength        = (scene.lineWidth - 1.0f) / 2.0f;
2269*35238bceSAndroid Build Coastguard Worker                 const tcu::Vec2 offsetDirection = (isXMajor) ? (tcu::Vec2(0.0f, -1.0f)) : (tcu::Vec2(-1.0f, 0.0f));
2270*35238bceSAndroid Build Coastguard Worker                 const tcu::Vec2 offset          = offsetDirection * offsetLength;
2271*35238bceSAndroid Build Coastguard Worker 
2272*35238bceSAndroid Build Coastguard Worker                 effectiveLines[lineNdx] =
2273*35238bceSAndroid Build Coastguard Worker                     tcu::Vec4(lineScreenSpaceP0.x() + offset.x(), lineScreenSpaceP0.y() + offset.y(),
2274*35238bceSAndroid Build Coastguard Worker                               lineScreenSpaceP1.x() + offset.x(), lineScreenSpaceP1.y() + offset.y());
2275*35238bceSAndroid Build Coastguard Worker             }
2276*35238bceSAndroid Build Coastguard Worker         }
2277*35238bceSAndroid Build Coastguard Worker     }
2278*35238bceSAndroid Build Coastguard Worker 
2279*35238bceSAndroid Build Coastguard Worker     for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
2280*35238bceSAndroid Build Coastguard Worker     {
2281*35238bceSAndroid Build Coastguard Worker         // Calculate root pixel lookup table for this line. Since the implementation's fragment
2282*35238bceSAndroid Build Coastguard Worker         // major coordinate range might not be a subset of the correct line range (they are allowed
2283*35238bceSAndroid Build Coastguard Worker         // to vary by one pixel), we must extend the domain to cover whole viewport along major
2284*35238bceSAndroid Build Coastguard Worker         // dimension.
2285*35238bceSAndroid Build Coastguard Worker         //
2286*35238bceSAndroid Build Coastguard Worker         // Expanding line strip to (effectively) infinite line might result in exit-diamnod set
2287*35238bceSAndroid Build Coastguard Worker         // that is not a superset of the exit-diamond set of the line strip. In practice, this
2288*35238bceSAndroid Build Coastguard Worker         // won't be an issue, since the allow-one-pixel-variation rule should tolerate this even
2289*35238bceSAndroid Build Coastguard Worker         // if the original and extended line would resolve differently a diamond the line just
2290*35238bceSAndroid Build Coastguard Worker         // touches (precision lost in expansion changes enter/exit status).
2291*35238bceSAndroid Build Coastguard Worker 
2292*35238bceSAndroid Build Coastguard Worker         {
2293*35238bceSAndroid Build Coastguard Worker             const bool isXMajor = lineIsXMajor[lineNdx];
2294*35238bceSAndroid Build Coastguard Worker             const int majorSize = (isXMajor) ? (surface.getWidth()) : (surface.getHeight());
2295*35238bceSAndroid Build Coastguard Worker             rr::LineExitDiamondGenerator diamondGenerator(args.subpixelBits);
2296*35238bceSAndroid Build Coastguard Worker             rr::LineExitDiamond diamonds[32];
2297*35238bceSAndroid Build Coastguard Worker             int numRasterized = DE_LENGTH_OF_ARRAY(diamonds);
2298*35238bceSAndroid Build Coastguard Worker 
2299*35238bceSAndroid Build Coastguard Worker             // Expand to effectively infinite line (endpoints are just one pixel over viewport boundaries)
2300*35238bceSAndroid Build Coastguard Worker             const tcu::Vec2 expandedP0 = getLineCoordAtAxisCoord(
2301*35238bceSAndroid Build Coastguard Worker                 effectiveLines[lineNdx].swizzle(0, 1), effectiveLines[lineNdx].swizzle(2, 3), isXMajor, -1.0f);
2302*35238bceSAndroid Build Coastguard Worker             const tcu::Vec2 expandedP1 =
2303*35238bceSAndroid Build Coastguard Worker                 getLineCoordAtAxisCoord(effectiveLines[lineNdx].swizzle(0, 1), effectiveLines[lineNdx].swizzle(2, 3),
2304*35238bceSAndroid Build Coastguard Worker                                         isXMajor, (float)majorSize + 1.0f);
2305*35238bceSAndroid Build Coastguard Worker 
2306*35238bceSAndroid Build Coastguard Worker             diamondGenerator.init(tcu::Vec4(expandedP0.x(), expandedP0.y(), 0.0f, 1.0f),
2307*35238bceSAndroid Build Coastguard Worker                                   tcu::Vec4(expandedP1.x(), expandedP1.y(), 0.0f, 1.0f));
2308*35238bceSAndroid Build Coastguard Worker 
2309*35238bceSAndroid Build Coastguard Worker             rootPixelLocation[lineNdx].resize(majorSize, FLAG_ROOT_NOT_SET);
2310*35238bceSAndroid Build Coastguard Worker 
2311*35238bceSAndroid Build Coastguard Worker             while (numRasterized == DE_LENGTH_OF_ARRAY(diamonds))
2312*35238bceSAndroid Build Coastguard Worker             {
2313*35238bceSAndroid Build Coastguard Worker                 diamondGenerator.rasterize(diamonds, DE_LENGTH_OF_ARRAY(diamonds), numRasterized);
2314*35238bceSAndroid Build Coastguard Worker 
2315*35238bceSAndroid Build Coastguard Worker                 for (int packetNdx = 0; packetNdx < numRasterized; ++packetNdx)
2316*35238bceSAndroid Build Coastguard Worker                 {
2317*35238bceSAndroid Build Coastguard Worker                     const tcu::IVec2 fragPos = diamonds[packetNdx].position;
2318*35238bceSAndroid Build Coastguard Worker                     const int majorPos       = (isXMajor) ? (fragPos.x()) : (fragPos.y());
2319*35238bceSAndroid Build Coastguard Worker                     const int rootPos        = (isXMajor) ? (fragPos.y()) : (fragPos.x());
2320*35238bceSAndroid Build Coastguard Worker                     const uint32_t packed    = (uint32_t)((uint16_t)((int16_t)rootPos));
2321*35238bceSAndroid Build Coastguard Worker 
2322*35238bceSAndroid Build Coastguard Worker                     // infinite line will generate some diamonds outside the viewport
2323*35238bceSAndroid Build Coastguard Worker                     if (deInBounds32(majorPos, 0, majorSize))
2324*35238bceSAndroid Build Coastguard Worker                     {
2325*35238bceSAndroid Build Coastguard Worker                         DE_ASSERT((rootPixelLocation[lineNdx][majorPos] & FLAG_ROOT_NOT_SET) != 0u);
2326*35238bceSAndroid Build Coastguard Worker                         rootPixelLocation[lineNdx][majorPos] = packed;
2327*35238bceSAndroid Build Coastguard Worker                     }
2328*35238bceSAndroid Build Coastguard Worker                 }
2329*35238bceSAndroid Build Coastguard Worker             }
2330*35238bceSAndroid Build Coastguard Worker 
2331*35238bceSAndroid Build Coastguard Worker             // Filled whole lookup table
2332*35238bceSAndroid Build Coastguard Worker             for (int majorPos = 0; majorPos < majorSize; ++majorPos)
2333*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT((rootPixelLocation[lineNdx][majorPos] & FLAG_ROOT_NOT_SET) == 0u);
2334*35238bceSAndroid Build Coastguard Worker         }
2335*35238bceSAndroid Build Coastguard Worker     }
2336*35238bceSAndroid Build Coastguard Worker 
2337*35238bceSAndroid Build Coastguard Worker     // Find all possible lines with coverage, check pixel color matches one of them
2338*35238bceSAndroid Build Coastguard Worker 
2339*35238bceSAndroid Build Coastguard Worker     for (int y = 1; y < surface.getHeight() - 1; ++y)
2340*35238bceSAndroid Build Coastguard Worker         for (int x = 1; x < surface.getWidth() - 1; ++x)
2341*35238bceSAndroid Build Coastguard Worker         {
2342*35238bceSAndroid Build Coastguard Worker             const tcu::RGBA color             = surface.getPixel(x, y);
2343*35238bceSAndroid Build Coastguard Worker             const tcu::IVec3 pixelNativeColor = convertRGB8ToNativeFormat(
2344*35238bceSAndroid Build Coastguard Worker                 color, args); // Convert pixel color from rgba8 to the real pixel format. Usually rgba8 or 565
2345*35238bceSAndroid Build Coastguard Worker             int lineCoverageSet         = 0;      // !< lines that may cover this fragment
2346*35238bceSAndroid Build Coastguard Worker             int lineSurroundingCoverage = 0xFFFF; // !< lines that will cover this fragment
2347*35238bceSAndroid Build Coastguard Worker             bool matchFound             = false;
2348*35238bceSAndroid Build Coastguard Worker             const tcu::IVec3 formatLimit((1 << args.redBits) - 1, (1 << args.greenBits) - 1, (1 << args.blueBits) - 1);
2349*35238bceSAndroid Build Coastguard Worker 
2350*35238bceSAndroid Build Coastguard Worker             std::vector<SingleSampleWideLineCandidate> candidates;
2351*35238bceSAndroid Build Coastguard Worker 
2352*35238bceSAndroid Build Coastguard Worker             // Find lines with possible coverage
2353*35238bceSAndroid Build Coastguard Worker 
2354*35238bceSAndroid Build Coastguard Worker             for (int dy = -1; dy < 2; ++dy)
2355*35238bceSAndroid Build Coastguard Worker                 for (int dx = -1; dx < 2; ++dx)
2356*35238bceSAndroid Build Coastguard Worker                 {
2357*35238bceSAndroid Build Coastguard Worker                     const int coverage = referenceLineMap.getAccess().getPixelInt(x + dx, y + dy).x();
2358*35238bceSAndroid Build Coastguard Worker 
2359*35238bceSAndroid Build Coastguard Worker                     lineCoverageSet |= coverage;
2360*35238bceSAndroid Build Coastguard Worker                     lineSurroundingCoverage &= coverage;
2361*35238bceSAndroid Build Coastguard Worker                 }
2362*35238bceSAndroid Build Coastguard Worker 
2363*35238bceSAndroid Build Coastguard Worker             // background color is possible?
2364*35238bceSAndroid Build Coastguard Worker             if (lineSurroundingCoverage == 0 &&
2365*35238bceSAndroid Build Coastguard Worker                 compareColors(color, tcu::RGBA::black(), args.redBits, args.greenBits, args.blueBits))
2366*35238bceSAndroid Build Coastguard Worker                 continue;
2367*35238bceSAndroid Build Coastguard Worker 
2368*35238bceSAndroid Build Coastguard Worker             // Check those lines
2369*35238bceSAndroid Build Coastguard Worker 
2370*35238bceSAndroid Build Coastguard Worker             for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx)
2371*35238bceSAndroid Build Coastguard Worker             {
2372*35238bceSAndroid Build Coastguard Worker                 if (((lineCoverageSet >> lineNdx) & 0x01) != 0)
2373*35238bceSAndroid Build Coastguard Worker                 {
2374*35238bceSAndroid Build Coastguard Worker                     const float wa     = scene.lines[lineNdx].positions[0].w();
2375*35238bceSAndroid Build Coastguard Worker                     const float wb     = scene.lines[lineNdx].positions[1].w();
2376*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec2 pa = effectiveLines[lineNdx].swizzle(0, 1);
2377*35238bceSAndroid Build Coastguard Worker                     const tcu::Vec2 pb = effectiveLines[lineNdx].swizzle(2, 3);
2378*35238bceSAndroid Build Coastguard Worker 
2379*35238bceSAndroid Build Coastguard Worker                     // \note Wide line fragments are generated by replicating the root fragment for each
2380*35238bceSAndroid Build Coastguard Worker                     //       fragment column (row for y-major). Calculate interpolation at the root
2381*35238bceSAndroid Build Coastguard Worker                     //       fragment.
2382*35238bceSAndroid Build Coastguard Worker                     const bool isXMajor             = lineIsXMajor[lineNdx];
2383*35238bceSAndroid Build Coastguard Worker                     const int majorPosition         = (isXMajor) ? (x) : (y);
2384*35238bceSAndroid Build Coastguard Worker                     const uint32_t minorInfoPacked  = rootPixelLocation[lineNdx][majorPosition];
2385*35238bceSAndroid Build Coastguard Worker                     const int minorPosition         = (int)((int16_t)((uint16_t)(minorInfoPacked & 0xFFFFu)));
2386*35238bceSAndroid Build Coastguard Worker                     const tcu::IVec2 idealRootPos   = (isXMajor) ? (tcu::IVec2(majorPosition, minorPosition)) :
2387*35238bceSAndroid Build Coastguard Worker                                                                    (tcu::IVec2(minorPosition, majorPosition));
2388*35238bceSAndroid Build Coastguard Worker                     const tcu::IVec2 minorDirection = (isXMajor) ? (tcu::IVec2(0, 1)) : (tcu::IVec2(1, 0));
2389*35238bceSAndroid Build Coastguard Worker 
2390*35238bceSAndroid Build Coastguard Worker                     SingleSampleWideLineCandidate candidate;
2391*35238bceSAndroid Build Coastguard Worker 
2392*35238bceSAndroid Build Coastguard Worker                     candidate.lineNdx       = lineNdx;
2393*35238bceSAndroid Build Coastguard Worker                     candidate.numCandidates = 0;
2394*35238bceSAndroid Build Coastguard Worker                     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(candidate.interpolationCandidates) == 3);
2395*35238bceSAndroid Build Coastguard Worker 
2396*35238bceSAndroid Build Coastguard Worker                     // Interpolation happens at the root fragment, which is then replicated in minor
2397*35238bceSAndroid Build Coastguard Worker                     // direction. Search for implementation's root position near accurate root.
2398*35238bceSAndroid Build Coastguard Worker                     for (int minorOffset = -1; minorOffset < 2; ++minorOffset)
2399*35238bceSAndroid Build Coastguard Worker                     {
2400*35238bceSAndroid Build Coastguard Worker                         const tcu::IVec2 rootPosition = idealRootPos + minorOffset * minorDirection;
2401*35238bceSAndroid Build Coastguard Worker 
2402*35238bceSAndroid Build Coastguard Worker                         // A fragment can be root fragment only if it exists
2403*35238bceSAndroid Build Coastguard Worker                         // \note root fragment can "exist" outside viewport
2404*35238bceSAndroid Build Coastguard Worker                         // \note no pixel format theshold since in this case allowing only black is more conservative
2405*35238bceSAndroid Build Coastguard Worker                         if (deInBounds32(rootPosition.x(), 0, surface.getWidth()) &&
2406*35238bceSAndroid Build Coastguard Worker                             deInBounds32(rootPosition.y(), 0, surface.getHeight()) &&
2407*35238bceSAndroid Build Coastguard Worker                             isBlack(surface.getPixel(rootPosition.x(), rootPosition.y())))
2408*35238bceSAndroid Build Coastguard Worker                         {
2409*35238bceSAndroid Build Coastguard Worker                             continue;
2410*35238bceSAndroid Build Coastguard Worker                         }
2411*35238bceSAndroid Build Coastguard Worker 
2412*35238bceSAndroid Build Coastguard Worker                         const LineInterpolationRange range =
2413*35238bceSAndroid Build Coastguard Worker                             calcSingleSampleLineInterpolationRange(pa, wa, pb, wb, rootPosition, args.subpixelBits);
2414*35238bceSAndroid Build Coastguard Worker 
2415*35238bceSAndroid Build Coastguard Worker                         const tcu::Vec4 valueMin =
2416*35238bceSAndroid Build Coastguard Worker                             de::clamp(range.min.x(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[0] +
2417*35238bceSAndroid Build Coastguard Worker                             de::clamp(range.min.y(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[1];
2418*35238bceSAndroid Build Coastguard Worker                         const tcu::Vec4 valueMax =
2419*35238bceSAndroid Build Coastguard Worker                             de::clamp(range.max.x(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[0] +
2420*35238bceSAndroid Build Coastguard Worker                             de::clamp(range.max.y(), 0.0f, 1.0f) * scene.lines[lineNdx].colors[1];
2421*35238bceSAndroid Build Coastguard Worker 
2422*35238bceSAndroid Build Coastguard Worker                         const tcu::Vec3 colorMinF(
2423*35238bceSAndroid Build Coastguard Worker                             de::clamp(valueMin.x() * (float)formatLimit.x(), 0.0f, (float)formatLimit.x()),
2424*35238bceSAndroid Build Coastguard Worker                             de::clamp(valueMin.y() * (float)formatLimit.y(), 0.0f, (float)formatLimit.y()),
2425*35238bceSAndroid Build Coastguard Worker                             de::clamp(valueMin.z() * (float)formatLimit.z(), 0.0f, (float)formatLimit.z()));
2426*35238bceSAndroid Build Coastguard Worker                         const tcu::Vec3 colorMaxF(
2427*35238bceSAndroid Build Coastguard Worker                             de::clamp(valueMax.x() * (float)formatLimit.x(), 0.0f, (float)formatLimit.x()),
2428*35238bceSAndroid Build Coastguard Worker                             de::clamp(valueMax.y() * (float)formatLimit.y(), 0.0f, (float)formatLimit.y()),
2429*35238bceSAndroid Build Coastguard Worker                             de::clamp(valueMax.z() * (float)formatLimit.z(), 0.0f, (float)formatLimit.z()));
2430*35238bceSAndroid Build Coastguard Worker                         const tcu::IVec3 colorMin((int)deFloatFloor(colorMinF.x()), (int)deFloatFloor(colorMinF.y()),
2431*35238bceSAndroid Build Coastguard Worker                                                   (int)deFloatFloor(colorMinF.z()));
2432*35238bceSAndroid Build Coastguard Worker                         const tcu::IVec3 colorMax((int)deFloatCeil(colorMaxF.x()), (int)deFloatCeil(colorMaxF.y()),
2433*35238bceSAndroid Build Coastguard Worker                                                   (int)deFloatCeil(colorMaxF.z()));
2434*35238bceSAndroid Build Coastguard Worker 
2435*35238bceSAndroid Build Coastguard Worker                         // Verify validity
2436*35238bceSAndroid Build Coastguard Worker                         if (pixelNativeColor.x() < colorMin.x() || pixelNativeColor.y() < colorMin.y() ||
2437*35238bceSAndroid Build Coastguard Worker                             pixelNativeColor.z() < colorMin.z() || pixelNativeColor.x() > colorMax.x() ||
2438*35238bceSAndroid Build Coastguard Worker                             pixelNativeColor.y() > colorMax.y() || pixelNativeColor.z() > colorMax.z())
2439*35238bceSAndroid Build Coastguard Worker                         {
2440*35238bceSAndroid Build Coastguard Worker                             if (errorCount < errorFloodThreshold)
2441*35238bceSAndroid Build Coastguard Worker                             {
2442*35238bceSAndroid Build Coastguard Worker                                 // Store candidate information for logging
2443*35238bceSAndroid Build Coastguard Worker                                 SingleSampleWideLineCandidate::InterpolationPointCandidate &interpolationCandidate =
2444*35238bceSAndroid Build Coastguard Worker                                     candidate.interpolationCandidates[candidate.numCandidates++];
2445*35238bceSAndroid Build Coastguard Worker                                 DE_ASSERT(candidate.numCandidates <=
2446*35238bceSAndroid Build Coastguard Worker                                           DE_LENGTH_OF_ARRAY(candidate.interpolationCandidates));
2447*35238bceSAndroid Build Coastguard Worker 
2448*35238bceSAndroid Build Coastguard Worker                                 interpolationCandidate.interpolationPoint = rootPosition;
2449*35238bceSAndroid Build Coastguard Worker                                 interpolationCandidate.colorMin           = colorMin;
2450*35238bceSAndroid Build Coastguard Worker                                 interpolationCandidate.colorMax           = colorMax;
2451*35238bceSAndroid Build Coastguard Worker                                 interpolationCandidate.colorMinF          = colorMinF;
2452*35238bceSAndroid Build Coastguard Worker                                 interpolationCandidate.colorMaxF          = colorMaxF;
2453*35238bceSAndroid Build Coastguard Worker                                 interpolationCandidate.valueRangeMin      = valueMin.swizzle(0, 1, 2);
2454*35238bceSAndroid Build Coastguard Worker                                 interpolationCandidate.valueRangeMax      = valueMax.swizzle(0, 1, 2);
2455*35238bceSAndroid Build Coastguard Worker                             }
2456*35238bceSAndroid Build Coastguard Worker                         }
2457*35238bceSAndroid Build Coastguard Worker                         else
2458*35238bceSAndroid Build Coastguard Worker                         {
2459*35238bceSAndroid Build Coastguard Worker                             matchFound = true;
2460*35238bceSAndroid Build Coastguard Worker                             break;
2461*35238bceSAndroid Build Coastguard Worker                         }
2462*35238bceSAndroid Build Coastguard Worker                     }
2463*35238bceSAndroid Build Coastguard Worker 
2464*35238bceSAndroid Build Coastguard Worker                     if (!matchFound)
2465*35238bceSAndroid Build Coastguard Worker                     {
2466*35238bceSAndroid Build Coastguard Worker                         // store info for logging
2467*35238bceSAndroid Build Coastguard Worker                         if (errorCount < errorFloodThreshold && candidate.numCandidates > 0)
2468*35238bceSAndroid Build Coastguard Worker                             candidates.push_back(candidate);
2469*35238bceSAndroid Build Coastguard Worker                     }
2470*35238bceSAndroid Build Coastguard Worker                     else
2471*35238bceSAndroid Build Coastguard Worker                     {
2472*35238bceSAndroid Build Coastguard Worker                         // no need to check other lines
2473*35238bceSAndroid Build Coastguard Worker                         break;
2474*35238bceSAndroid Build Coastguard Worker                     }
2475*35238bceSAndroid Build Coastguard Worker                 }
2476*35238bceSAndroid Build Coastguard Worker             }
2477*35238bceSAndroid Build Coastguard Worker 
2478*35238bceSAndroid Build Coastguard Worker             if (matchFound)
2479*35238bceSAndroid Build Coastguard Worker                 continue;
2480*35238bceSAndroid Build Coastguard Worker 
2481*35238bceSAndroid Build Coastguard Worker             // invalid fragment
2482*35238bceSAndroid Build Coastguard Worker             ++invalidPixels;
2483*35238bceSAndroid Build Coastguard Worker             errorMask.setPixel(x, y, invalidPixelColor);
2484*35238bceSAndroid Build Coastguard Worker 
2485*35238bceSAndroid Build Coastguard Worker             ++errorCount;
2486*35238bceSAndroid Build Coastguard Worker 
2487*35238bceSAndroid Build Coastguard Worker             // don't fill the logs with too much data
2488*35238bceSAndroid Build Coastguard Worker             if (errorCount < errorFloodThreshold)
2489*35238bceSAndroid Build Coastguard Worker             {
2490*35238bceSAndroid Build Coastguard Worker                 tcu::MessageBuilder msg(&log);
2491*35238bceSAndroid Build Coastguard Worker 
2492*35238bceSAndroid Build Coastguard Worker                 msg << "Found an invalid pixel at (" << x << "," << y << "), " << (int)candidates.size()
2493*35238bceSAndroid Build Coastguard Worker                     << " candidate reference value(s) found:\n"
2494*35238bceSAndroid Build Coastguard Worker                     << "\tPixel color:\t\t" << color << "\n"
2495*35238bceSAndroid Build Coastguard Worker                     << "\tNative color:\t\t" << pixelNativeColor << "\n";
2496*35238bceSAndroid Build Coastguard Worker 
2497*35238bceSAndroid Build Coastguard Worker                 for (int lineCandidateNdx = 0; lineCandidateNdx < (int)candidates.size(); ++lineCandidateNdx)
2498*35238bceSAndroid Build Coastguard Worker                 {
2499*35238bceSAndroid Build Coastguard Worker                     const SingleSampleWideLineCandidate &candidate = candidates[lineCandidateNdx];
2500*35238bceSAndroid Build Coastguard Worker 
2501*35238bceSAndroid Build Coastguard Worker                     msg << "\tCandidate line (line " << candidate.lineNdx << "):\n";
2502*35238bceSAndroid Build Coastguard Worker 
2503*35238bceSAndroid Build Coastguard Worker                     for (int interpolationCandidateNdx = 0; interpolationCandidateNdx < candidate.numCandidates;
2504*35238bceSAndroid Build Coastguard Worker                          ++interpolationCandidateNdx)
2505*35238bceSAndroid Build Coastguard Worker                     {
2506*35238bceSAndroid Build Coastguard Worker                         const SingleSampleWideLineCandidate::InterpolationPointCandidate &interpolationCandidate =
2507*35238bceSAndroid Build Coastguard Worker                             candidate.interpolationCandidates[interpolationCandidateNdx];
2508*35238bceSAndroid Build Coastguard Worker 
2509*35238bceSAndroid Build Coastguard Worker                         msg << "\t\tCandidate interpolation point (index " << interpolationCandidateNdx << "):\n"
2510*35238bceSAndroid Build Coastguard Worker                             << "\t\t\tRoot fragment position (non-replicated fragment): "
2511*35238bceSAndroid Build Coastguard Worker                             << interpolationCandidate.interpolationPoint << ":\n"
2512*35238bceSAndroid Build Coastguard Worker                             << "\t\t\tReference native color min: "
2513*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(interpolationCandidate.colorMin, tcu::IVec3(0, 0, 0), formatLimit) << "\n"
2514*35238bceSAndroid Build Coastguard Worker                             << "\t\t\tReference native color max: "
2515*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(interpolationCandidate.colorMax, tcu::IVec3(0, 0, 0), formatLimit) << "\n"
2516*35238bceSAndroid Build Coastguard Worker                             << "\t\t\tReference native float min: "
2517*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(interpolationCandidate.colorMinF, tcu::Vec3(0.0f, 0.0f, 0.0f),
2518*35238bceSAndroid Build Coastguard Worker                                           formatLimit.cast<float>())
2519*35238bceSAndroid Build Coastguard Worker                             << "\n"
2520*35238bceSAndroid Build Coastguard Worker                             << "\t\t\tReference native float max: "
2521*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(interpolationCandidate.colorMaxF, tcu::Vec3(0.0f, 0.0f, 0.0f),
2522*35238bceSAndroid Build Coastguard Worker                                           formatLimit.cast<float>())
2523*35238bceSAndroid Build Coastguard Worker                             << "\n"
2524*35238bceSAndroid Build Coastguard Worker                             << "\t\t\tFmin:\t"
2525*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(interpolationCandidate.valueRangeMin, tcu::Vec3(0.0f, 0.0f, 0.0f),
2526*35238bceSAndroid Build Coastguard Worker                                           tcu::Vec3(1.0f, 1.0f, 1.0f))
2527*35238bceSAndroid Build Coastguard Worker                             << "\n"
2528*35238bceSAndroid Build Coastguard Worker                             << "\t\t\tFmax:\t"
2529*35238bceSAndroid Build Coastguard Worker                             << tcu::clamp(interpolationCandidate.valueRangeMax, tcu::Vec3(0.0f, 0.0f, 0.0f),
2530*35238bceSAndroid Build Coastguard Worker                                           tcu::Vec3(1.0f, 1.0f, 1.0f))
2531*35238bceSAndroid Build Coastguard Worker                             << "\n";
2532*35238bceSAndroid Build Coastguard Worker                     }
2533*35238bceSAndroid Build Coastguard Worker                 }
2534*35238bceSAndroid Build Coastguard Worker 
2535*35238bceSAndroid Build Coastguard Worker                 msg << tcu::TestLog::EndMessage;
2536*35238bceSAndroid Build Coastguard Worker             }
2537*35238bceSAndroid Build Coastguard Worker         }
2538*35238bceSAndroid Build Coastguard Worker 
2539*35238bceSAndroid Build Coastguard Worker     // don't just hide failures
2540*35238bceSAndroid Build Coastguard Worker     if (errorCount > errorFloodThreshold)
2541*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Omitted " << (errorCount - errorFloodThreshold)
2542*35238bceSAndroid Build Coastguard Worker             << " pixel error description(s)." << tcu::TestLog::EndMessage;
2543*35238bceSAndroid Build Coastguard Worker 
2544*35238bceSAndroid Build Coastguard Worker     // report result
2545*35238bceSAndroid Build Coastguard Worker     if (invalidPixels)
2546*35238bceSAndroid Build Coastguard Worker     {
2547*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << invalidPixels << " invalid pixel(s) found." << tcu::TestLog::EndMessage;
2548*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2549*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Result", "Result", surface)
2550*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
2551*35238bceSAndroid Build Coastguard Worker 
2552*35238bceSAndroid Build Coastguard Worker         return false;
2553*35238bceSAndroid Build Coastguard Worker     }
2554*35238bceSAndroid Build Coastguard Worker     else
2555*35238bceSAndroid Build Coastguard Worker     {
2556*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
2557*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2558*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Result", "Result", surface) << tcu::TestLog::EndImageSet;
2559*35238bceSAndroid Build Coastguard Worker 
2560*35238bceSAndroid Build Coastguard Worker         return true;
2561*35238bceSAndroid Build Coastguard Worker     }
2562*35238bceSAndroid Build Coastguard Worker }
2563*35238bceSAndroid Build Coastguard Worker 
2564*35238bceSAndroid Build Coastguard Worker } // namespace
2565*35238bceSAndroid Build Coastguard Worker 
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)2566*35238bceSAndroid Build Coastguard Worker CoverageType calculateTriangleCoverage(const tcu::Vec4 &p0, const tcu::Vec4 &p1, const tcu::Vec4 &p2,
2567*35238bceSAndroid Build Coastguard Worker                                        const tcu::IVec2 &pixel, const tcu::IVec2 &viewportSize, int subpixelBits,
2568*35238bceSAndroid Build Coastguard Worker                                        bool multisample)
2569*35238bceSAndroid Build Coastguard Worker {
2570*35238bceSAndroid Build Coastguard Worker     using tcu::I64Vec2;
2571*35238bceSAndroid Build Coastguard Worker 
2572*35238bceSAndroid Build Coastguard Worker     const uint64_t numSubPixels = ((uint64_t)1) << subpixelBits;
2573*35238bceSAndroid Build Coastguard Worker     const uint64_t pixelHitBoxSize =
2574*35238bceSAndroid Build Coastguard Worker         (multisample) ? (numSubPixels) :
2575*35238bceSAndroid Build Coastguard Worker                         5; //!< 5 = ceil(6 * sqrt(2) / 2) to account for a 3 subpixel fuzz around pixel center
2576*35238bceSAndroid Build Coastguard Worker     const bool order           = isTriangleClockwise(p0, p1, p2); //!< clockwise / counter-clockwise
2577*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 &orderedP0 = p0;                              //!< vertices of a clockwise triangle
2578*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 &orderedP1 = (order) ? (p1) : (p2);
2579*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 &orderedP2 = (order) ? (p2) : (p1);
2580*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 triangleNormalizedDeviceSpace[3] = {
2581*35238bceSAndroid Build Coastguard Worker         tcu::Vec2(orderedP0.x() / orderedP0.w(), orderedP0.y() / orderedP0.w()),
2582*35238bceSAndroid Build Coastguard Worker         tcu::Vec2(orderedP1.x() / orderedP1.w(), orderedP1.y() / orderedP1.w()),
2583*35238bceSAndroid Build Coastguard Worker         tcu::Vec2(orderedP2.x() / orderedP2.w(), orderedP2.y() / orderedP2.w()),
2584*35238bceSAndroid Build Coastguard Worker     };
2585*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 triangleScreenSpace[3] = {
2586*35238bceSAndroid Build Coastguard Worker         (triangleNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
2587*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
2588*35238bceSAndroid Build Coastguard Worker         (triangleNormalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
2589*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
2590*35238bceSAndroid Build Coastguard Worker         (triangleNormalizedDeviceSpace[2] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
2591*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
2592*35238bceSAndroid Build Coastguard Worker     };
2593*35238bceSAndroid Build Coastguard Worker 
2594*35238bceSAndroid Build Coastguard Worker     // Broad bounding box - pixel check
2595*35238bceSAndroid Build Coastguard Worker     {
2596*35238bceSAndroid Build Coastguard Worker         const float minX =
2597*35238bceSAndroid Build Coastguard Worker             de::min(de::min(triangleScreenSpace[0].x(), triangleScreenSpace[1].x()), triangleScreenSpace[2].x());
2598*35238bceSAndroid Build Coastguard Worker         const float minY =
2599*35238bceSAndroid Build Coastguard Worker             de::min(de::min(triangleScreenSpace[0].y(), triangleScreenSpace[1].y()), triangleScreenSpace[2].y());
2600*35238bceSAndroid Build Coastguard Worker         const float maxX =
2601*35238bceSAndroid Build Coastguard Worker             de::max(de::max(triangleScreenSpace[0].x(), triangleScreenSpace[1].x()), triangleScreenSpace[2].x());
2602*35238bceSAndroid Build Coastguard Worker         const float maxY =
2603*35238bceSAndroid Build Coastguard Worker             de::max(de::max(triangleScreenSpace[0].y(), triangleScreenSpace[1].y()), triangleScreenSpace[2].y());
2604*35238bceSAndroid Build Coastguard Worker 
2605*35238bceSAndroid Build Coastguard Worker         if ((float)pixel.x() > maxX + 1 || (float)pixel.y() > maxY + 1 || (float)pixel.x() < minX - 1 ||
2606*35238bceSAndroid Build Coastguard Worker             (float)pixel.y() < minY - 1)
2607*35238bceSAndroid Build Coastguard Worker             return COVERAGE_NONE;
2608*35238bceSAndroid Build Coastguard Worker     }
2609*35238bceSAndroid Build Coastguard Worker 
2610*35238bceSAndroid Build Coastguard Worker     // Broad triangle - pixel area intersection
2611*35238bceSAndroid Build Coastguard Worker     {
2612*35238bceSAndroid Build Coastguard Worker         const DVec2 pixelCenterPosition =
2613*35238bceSAndroid Build Coastguard Worker             DVec2((double)pixel.x(), (double)pixel.y()) * DVec2((double)numSubPixels, (double)numSubPixels) +
2614*35238bceSAndroid Build Coastguard Worker             DVec2((double)numSubPixels / 2, (double)numSubPixels / 2);
2615*35238bceSAndroid Build Coastguard Worker         const DVec2 triangleSubPixelSpace[3] = {
2616*35238bceSAndroid Build Coastguard Worker             DVec2(triangleScreenSpace[0].x() * (double)numSubPixels, triangleScreenSpace[0].y() * (double)numSubPixels),
2617*35238bceSAndroid Build Coastguard Worker             DVec2(triangleScreenSpace[1].x() * (double)numSubPixels, triangleScreenSpace[1].y() * (double)numSubPixels),
2618*35238bceSAndroid Build Coastguard Worker             DVec2(triangleScreenSpace[2].x() * (double)numSubPixels, triangleScreenSpace[2].y() * (double)numSubPixels),
2619*35238bceSAndroid Build Coastguard Worker         };
2620*35238bceSAndroid Build Coastguard Worker 
2621*35238bceSAndroid Build Coastguard Worker         // Check (using cross product) if pixel center is
2622*35238bceSAndroid Build Coastguard Worker         // a) too far from any edge
2623*35238bceSAndroid Build Coastguard Worker         // b) fully inside all edges
2624*35238bceSAndroid Build Coastguard Worker         bool insideAllEdges = true;
2625*35238bceSAndroid Build Coastguard Worker         for (int vtxNdx = 0; vtxNdx < 3; ++vtxNdx)
2626*35238bceSAndroid Build Coastguard Worker         {
2627*35238bceSAndroid Build Coastguard Worker             const int otherVtxNdx = (vtxNdx + 1) % 3;
2628*35238bceSAndroid Build Coastguard Worker             const double maxPixelDistanceSquared =
2629*35238bceSAndroid Build Coastguard Worker                 (double)(pixelHitBoxSize *
2630*35238bceSAndroid Build Coastguard Worker                          pixelHitBoxSize); // Max distance from the pixel center from within the pixel is (sqrt(2) * boxWidth/2). Use 2x value for rounding tolerance
2631*35238bceSAndroid Build Coastguard Worker             const DVec2 edge          = triangleSubPixelSpace[otherVtxNdx] - triangleSubPixelSpace[vtxNdx];
2632*35238bceSAndroid Build Coastguard Worker             const DVec2 v             = pixelCenterPosition - triangleSubPixelSpace[vtxNdx];
2633*35238bceSAndroid Build Coastguard Worker             const double crossProduct = (edge.x() * v.y() - edge.y() * v.x());
2634*35238bceSAndroid Build Coastguard Worker 
2635*35238bceSAndroid Build Coastguard Worker             // distance from edge: (edge x v) / |edge|
2636*35238bceSAndroid Build Coastguard Worker             //     (edge x v) / |edge| > maxPixelDistance
2637*35238bceSAndroid Build Coastguard Worker             // ==> (edge x v)^2 / edge^2 > maxPixelDistance^2    | edge x v > 0
2638*35238bceSAndroid Build Coastguard Worker             // ==> (edge x v)^2 > maxPixelDistance^2 * edge^2
2639*35238bceSAndroid Build Coastguard Worker             if (crossProduct < 0 && crossProduct * crossProduct > maxPixelDistanceSquared * tcu::lengthSquared(edge))
2640*35238bceSAndroid Build Coastguard Worker                 return COVERAGE_NONE;
2641*35238bceSAndroid Build Coastguard Worker             if (crossProduct < 0 || crossProduct * crossProduct < maxPixelDistanceSquared * tcu::lengthSquared(edge))
2642*35238bceSAndroid Build Coastguard Worker                 insideAllEdges = false;
2643*35238bceSAndroid Build Coastguard Worker         }
2644*35238bceSAndroid Build Coastguard Worker 
2645*35238bceSAndroid Build Coastguard Worker         if (insideAllEdges)
2646*35238bceSAndroid Build Coastguard Worker             return COVERAGE_FULL;
2647*35238bceSAndroid Build Coastguard Worker     }
2648*35238bceSAndroid Build Coastguard Worker 
2649*35238bceSAndroid Build Coastguard Worker     // Accurate intersection for edge pixels
2650*35238bceSAndroid Build Coastguard Worker     {
2651*35238bceSAndroid Build Coastguard Worker         //  In multisampling, the sample points can be anywhere in the pixel, and in single sampling only in the center.
2652*35238bceSAndroid Build Coastguard Worker         const I64Vec2 pixelCorners[4] = {
2653*35238bceSAndroid Build Coastguard Worker             I64Vec2((pixel.x() + 0) * numSubPixels, (pixel.y() + 0) * numSubPixels),
2654*35238bceSAndroid Build Coastguard Worker             I64Vec2((pixel.x() + 1) * numSubPixels, (pixel.y() + 0) * numSubPixels),
2655*35238bceSAndroid Build Coastguard Worker             I64Vec2((pixel.x() + 1) * numSubPixels, (pixel.y() + 1) * numSubPixels),
2656*35238bceSAndroid Build Coastguard Worker             I64Vec2((pixel.x() + 0) * numSubPixels, (pixel.y() + 1) * numSubPixels),
2657*35238bceSAndroid Build Coastguard Worker         };
2658*35238bceSAndroid Build Coastguard Worker 
2659*35238bceSAndroid Build Coastguard Worker         // 3 subpixel tolerance around pixel center to account for accumulated errors during various line rasterization methods
2660*35238bceSAndroid Build Coastguard Worker         const I64Vec2 pixelCenterCorners[4] = {
2661*35238bceSAndroid Build Coastguard Worker             I64Vec2(pixel.x() * numSubPixels + numSubPixels / 2 - 3, pixel.y() * numSubPixels + numSubPixels / 2 - 3),
2662*35238bceSAndroid Build Coastguard Worker             I64Vec2(pixel.x() * numSubPixels + numSubPixels / 2 + 3, pixel.y() * numSubPixels + numSubPixels / 2 - 3),
2663*35238bceSAndroid Build Coastguard Worker             I64Vec2(pixel.x() * numSubPixels + numSubPixels / 2 + 3, pixel.y() * numSubPixels + numSubPixels / 2 + 3),
2664*35238bceSAndroid Build Coastguard Worker             I64Vec2(pixel.x() * numSubPixels + numSubPixels / 2 - 3, pixel.y() * numSubPixels + numSubPixels / 2 + 3),
2665*35238bceSAndroid Build Coastguard Worker         };
2666*35238bceSAndroid Build Coastguard Worker 
2667*35238bceSAndroid Build Coastguard Worker         // both rounding directions
2668*35238bceSAndroid Build Coastguard Worker         const I64Vec2 triangleSubPixelSpaceFloor[3] = {
2669*35238bceSAndroid Build Coastguard Worker             I64Vec2(deFloorFloatToInt32(triangleScreenSpace[0].x() * (float)numSubPixels),
2670*35238bceSAndroid Build Coastguard Worker                     deFloorFloatToInt32(triangleScreenSpace[0].y() * (float)numSubPixels)),
2671*35238bceSAndroid Build Coastguard Worker             I64Vec2(deFloorFloatToInt32(triangleScreenSpace[1].x() * (float)numSubPixels),
2672*35238bceSAndroid Build Coastguard Worker                     deFloorFloatToInt32(triangleScreenSpace[1].y() * (float)numSubPixels)),
2673*35238bceSAndroid Build Coastguard Worker             I64Vec2(deFloorFloatToInt32(triangleScreenSpace[2].x() * (float)numSubPixels),
2674*35238bceSAndroid Build Coastguard Worker                     deFloorFloatToInt32(triangleScreenSpace[2].y() * (float)numSubPixels)),
2675*35238bceSAndroid Build Coastguard Worker         };
2676*35238bceSAndroid Build Coastguard Worker         const I64Vec2 triangleSubPixelSpaceCeil[3] = {
2677*35238bceSAndroid Build Coastguard Worker             I64Vec2(deCeilFloatToInt32(triangleScreenSpace[0].x() * (float)numSubPixels),
2678*35238bceSAndroid Build Coastguard Worker                     deCeilFloatToInt32(triangleScreenSpace[0].y() * (float)numSubPixels)),
2679*35238bceSAndroid Build Coastguard Worker             I64Vec2(deCeilFloatToInt32(triangleScreenSpace[1].x() * (float)numSubPixels),
2680*35238bceSAndroid Build Coastguard Worker                     deCeilFloatToInt32(triangleScreenSpace[1].y() * (float)numSubPixels)),
2681*35238bceSAndroid Build Coastguard Worker             I64Vec2(deCeilFloatToInt32(triangleScreenSpace[2].x() * (float)numSubPixels),
2682*35238bceSAndroid Build Coastguard Worker                     deCeilFloatToInt32(triangleScreenSpace[2].y() * (float)numSubPixels)),
2683*35238bceSAndroid Build Coastguard Worker         };
2684*35238bceSAndroid Build Coastguard Worker         const I64Vec2 *const corners = (multisample) ? (pixelCorners) : (pixelCenterCorners);
2685*35238bceSAndroid Build Coastguard Worker 
2686*35238bceSAndroid Build Coastguard Worker         // Test if any edge (with any rounding) intersects the pixel (boundary). If it does => Partial. If not => fully inside or outside
2687*35238bceSAndroid Build Coastguard Worker 
2688*35238bceSAndroid Build Coastguard Worker         for (int edgeNdx = 0; edgeNdx < 3; ++edgeNdx)
2689*35238bceSAndroid Build Coastguard Worker             for (int startRounding = 0; startRounding < 4; ++startRounding)
2690*35238bceSAndroid Build Coastguard Worker                 for (int endRounding = 0; endRounding < 4; ++endRounding)
2691*35238bceSAndroid Build Coastguard Worker                 {
2692*35238bceSAndroid Build Coastguard Worker                     const int nextEdgeNdx = (edgeNdx + 1) % 3;
2693*35238bceSAndroid Build Coastguard Worker                     const I64Vec2 startPos((startRounding & 0x01) ? (triangleSubPixelSpaceFloor[edgeNdx].x()) :
2694*35238bceSAndroid Build Coastguard Worker                                                                     (triangleSubPixelSpaceCeil[edgeNdx].x()),
2695*35238bceSAndroid Build Coastguard Worker                                            (startRounding & 0x02) ? (triangleSubPixelSpaceFloor[edgeNdx].y()) :
2696*35238bceSAndroid Build Coastguard Worker                                                                     (triangleSubPixelSpaceCeil[edgeNdx].y()));
2697*35238bceSAndroid Build Coastguard Worker                     const I64Vec2 endPos((endRounding & 0x01) ? (triangleSubPixelSpaceFloor[nextEdgeNdx].x()) :
2698*35238bceSAndroid Build Coastguard Worker                                                                 (triangleSubPixelSpaceCeil[nextEdgeNdx].x()),
2699*35238bceSAndroid Build Coastguard Worker                                          (endRounding & 0x02) ? (triangleSubPixelSpaceFloor[nextEdgeNdx].y()) :
2700*35238bceSAndroid Build Coastguard Worker                                                                 (triangleSubPixelSpaceCeil[nextEdgeNdx].y()));
2701*35238bceSAndroid Build Coastguard Worker 
2702*35238bceSAndroid Build Coastguard Worker                     for (int pixelEdgeNdx = 0; pixelEdgeNdx < 4; ++pixelEdgeNdx)
2703*35238bceSAndroid Build Coastguard Worker                     {
2704*35238bceSAndroid Build Coastguard Worker                         const int pixelEdgeEnd = (pixelEdgeNdx + 1) % 4;
2705*35238bceSAndroid Build Coastguard Worker 
2706*35238bceSAndroid Build Coastguard Worker                         if (lineLineIntersect(startPos, endPos, corners[pixelEdgeNdx], corners[pixelEdgeEnd]))
2707*35238bceSAndroid Build Coastguard Worker                             return COVERAGE_PARTIAL;
2708*35238bceSAndroid Build Coastguard Worker                     }
2709*35238bceSAndroid Build Coastguard Worker                 }
2710*35238bceSAndroid Build Coastguard Worker 
2711*35238bceSAndroid Build Coastguard Worker         // fully inside or outside
2712*35238bceSAndroid Build Coastguard Worker         for (int edgeNdx = 0; edgeNdx < 3; ++edgeNdx)
2713*35238bceSAndroid Build Coastguard Worker         {
2714*35238bceSAndroid Build Coastguard Worker             const int nextEdgeNdx      = (edgeNdx + 1) % 3;
2715*35238bceSAndroid Build Coastguard Worker             const I64Vec2 &startPos    = triangleSubPixelSpaceFloor[edgeNdx];
2716*35238bceSAndroid Build Coastguard Worker             const I64Vec2 &endPos      = triangleSubPixelSpaceFloor[nextEdgeNdx];
2717*35238bceSAndroid Build Coastguard Worker             const I64Vec2 edge         = endPos - startPos;
2718*35238bceSAndroid Build Coastguard Worker             const I64Vec2 v            = corners[0] - endPos;
2719*35238bceSAndroid Build Coastguard Worker             const int64_t crossProduct = (edge.x() * v.y() - edge.y() * v.x());
2720*35238bceSAndroid Build Coastguard Worker 
2721*35238bceSAndroid Build Coastguard Worker             // a corner of the pixel is outside => "fully inside" option is impossible
2722*35238bceSAndroid Build Coastguard Worker             if (crossProduct < 0)
2723*35238bceSAndroid Build Coastguard Worker                 return COVERAGE_NONE;
2724*35238bceSAndroid Build Coastguard Worker         }
2725*35238bceSAndroid Build Coastguard Worker 
2726*35238bceSAndroid Build Coastguard Worker         return COVERAGE_FULL;
2727*35238bceSAndroid Build Coastguard Worker     }
2728*35238bceSAndroid Build Coastguard Worker }
2729*35238bceSAndroid Build Coastguard Worker 
calculateUnderestimateLineCoverage(const tcu::Vec4 & p0,const tcu::Vec4 & p1,const float lineWidth,const tcu::IVec2 & pixel,const tcu::IVec2 & viewportSize)2730*35238bceSAndroid Build Coastguard Worker CoverageType calculateUnderestimateLineCoverage(const tcu::Vec4 &p0, const tcu::Vec4 &p1, const float lineWidth,
2731*35238bceSAndroid Build Coastguard Worker                                                 const tcu::IVec2 &pixel, const tcu::IVec2 &viewportSize)
2732*35238bceSAndroid Build Coastguard Worker {
2733*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(viewportSize.x() == viewportSize.y() && viewportSize.x() > 0);
2734*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(p0.w() == 1.0f && p1.w() == 1.0f);
2735*35238bceSAndroid Build Coastguard Worker 
2736*35238bceSAndroid Build Coastguard Worker     const Vec2 p    = Vec2(p0.x(), p0.y());
2737*35238bceSAndroid Build Coastguard Worker     const Vec2 q    = Vec2(p1.x(), p1.y());
2738*35238bceSAndroid Build Coastguard Worker     const Vec2 pq   = Vec2(p1.x() - p0.x(), p1.y() - p0.y());
2739*35238bceSAndroid Build Coastguard Worker     const Vec2 pqn  = normalize(pq);
2740*35238bceSAndroid Build Coastguard Worker     const Vec2 lw   = 0.5f * lineWidth * pqn;
2741*35238bceSAndroid Build Coastguard Worker     const Vec2 n    = Vec2(lw.y(), -lw.x());
2742*35238bceSAndroid Build Coastguard Worker     const Vec2 vp   = Vec2(float(viewportSize.x()), float(viewportSize.y()));
2743*35238bceSAndroid Build Coastguard Worker     const Vec2 a    = 0.5f * (p + Vec2(1.0f, 1.0f)) * vp + n;
2744*35238bceSAndroid Build Coastguard Worker     const Vec2 b    = 0.5f * (p + Vec2(1.0f, 1.0f)) * vp - n;
2745*35238bceSAndroid Build Coastguard Worker     const Vec2 c    = 0.5f * (q + Vec2(1.0f, 1.0f)) * vp - n;
2746*35238bceSAndroid Build Coastguard Worker     const Vec2 ba   = b - a;
2747*35238bceSAndroid Build Coastguard Worker     const Vec2 bc   = b - c;
2748*35238bceSAndroid Build Coastguard Worker     const float det = ba.x() * bc.y() - ba.y() * bc.x();
2749*35238bceSAndroid Build Coastguard Worker     int within      = 0;
2750*35238bceSAndroid Build Coastguard Worker 
2751*35238bceSAndroid Build Coastguard Worker     if (det != 0.0f)
2752*35238bceSAndroid Build Coastguard Worker     {
2753*35238bceSAndroid Build Coastguard Worker         for (int cornerNdx = 0; cornerNdx < 4; ++cornerNdx)
2754*35238bceSAndroid Build Coastguard Worker         {
2755*35238bceSAndroid Build Coastguard Worker             const int pixelCornerOffsetX = ((cornerNdx & 1) ? 1 : 0);
2756*35238bceSAndroid Build Coastguard Worker             const int pixelCornerOffsetY = ((cornerNdx & 2) ? 1 : 0);
2757*35238bceSAndroid Build Coastguard Worker             const Vec2 f      = Vec2(float(pixel.x() + pixelCornerOffsetX), float(pixel.y() + pixelCornerOffsetY));
2758*35238bceSAndroid Build Coastguard Worker             const Vec2 bf     = b - f;
2759*35238bceSAndroid Build Coastguard Worker             const float alpha = (bf.x() * bc.y() - bc.x() * bf.y()) / det;
2760*35238bceSAndroid Build Coastguard Worker             const float beta  = (ba.x() * bf.y() - bf.x() * ba.y()) / det;
2761*35238bceSAndroid Build Coastguard Worker             bool cornerWithin = de::inRange(alpha, 0.0f, 1.0f) && de::inRange(beta, 0.0f, 1.0f);
2762*35238bceSAndroid Build Coastguard Worker 
2763*35238bceSAndroid Build Coastguard Worker             if (cornerWithin)
2764*35238bceSAndroid Build Coastguard Worker                 within++;
2765*35238bceSAndroid Build Coastguard Worker         }
2766*35238bceSAndroid Build Coastguard Worker     }
2767*35238bceSAndroid Build Coastguard Worker 
2768*35238bceSAndroid Build Coastguard Worker     if (within == 0)
2769*35238bceSAndroid Build Coastguard Worker         return COVERAGE_NONE;
2770*35238bceSAndroid Build Coastguard Worker     else if (within == 4)
2771*35238bceSAndroid Build Coastguard Worker         return COVERAGE_FULL;
2772*35238bceSAndroid Build Coastguard Worker     else
2773*35238bceSAndroid Build Coastguard Worker         return COVERAGE_PARTIAL;
2774*35238bceSAndroid Build Coastguard Worker }
2775*35238bceSAndroid Build Coastguard Worker 
calculateUnderestimateTriangleCoverage(const tcu::Vec4 & p0,const tcu::Vec4 & p1,const tcu::Vec4 & p2,const tcu::IVec2 & pixel,int subpixelBits,const tcu::IVec2 & viewportSize)2776*35238bceSAndroid Build Coastguard Worker CoverageType calculateUnderestimateTriangleCoverage(const tcu::Vec4 &p0, const tcu::Vec4 &p1, const tcu::Vec4 &p2,
2777*35238bceSAndroid Build Coastguard Worker                                                     const tcu::IVec2 &pixel, int subpixelBits,
2778*35238bceSAndroid Build Coastguard Worker                                                     const tcu::IVec2 &viewportSize)
2779*35238bceSAndroid Build Coastguard Worker {
2780*35238bceSAndroid Build Coastguard Worker     using tcu::I64Vec2;
2781*35238bceSAndroid Build Coastguard Worker 
2782*35238bceSAndroid Build Coastguard Worker     const uint64_t numSubPixels = ((uint64_t)1) << subpixelBits;
2783*35238bceSAndroid Build Coastguard Worker     const bool order            = isTriangleClockwise(p0, p1, p2); //!< clockwise / counter-clockwise
2784*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 &orderedP0  = p0;                              //!< vertices of a clockwise triangle
2785*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 &orderedP1  = (order) ? (p1) : (p2);
2786*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 &orderedP2  = (order) ? (p2) : (p1);
2787*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 triangleNormalizedDeviceSpace[3] = {
2788*35238bceSAndroid Build Coastguard Worker         tcu::Vec2(orderedP0.x() / orderedP0.w(), orderedP0.y() / orderedP0.w()),
2789*35238bceSAndroid Build Coastguard Worker         tcu::Vec2(orderedP1.x() / orderedP1.w(), orderedP1.y() / orderedP1.w()),
2790*35238bceSAndroid Build Coastguard Worker         tcu::Vec2(orderedP2.x() / orderedP2.w(), orderedP2.y() / orderedP2.w()),
2791*35238bceSAndroid Build Coastguard Worker     };
2792*35238bceSAndroid Build Coastguard Worker     const tcu::Vec2 triangleScreenSpace[3] = {
2793*35238bceSAndroid Build Coastguard Worker         (triangleNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
2794*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
2795*35238bceSAndroid Build Coastguard Worker         (triangleNormalizedDeviceSpace[1] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
2796*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
2797*35238bceSAndroid Build Coastguard Worker         (triangleNormalizedDeviceSpace[2] + tcu::Vec2(1.0f, 1.0f)) * 0.5f *
2798*35238bceSAndroid Build Coastguard Worker             tcu::Vec2((float)viewportSize.x(), (float)viewportSize.y()),
2799*35238bceSAndroid Build Coastguard Worker     };
2800*35238bceSAndroid Build Coastguard Worker 
2801*35238bceSAndroid Build Coastguard Worker     // Broad bounding box - pixel check
2802*35238bceSAndroid Build Coastguard Worker     {
2803*35238bceSAndroid Build Coastguard Worker         const float minX =
2804*35238bceSAndroid Build Coastguard Worker             de::min(de::min(triangleScreenSpace[0].x(), triangleScreenSpace[1].x()), triangleScreenSpace[2].x());
2805*35238bceSAndroid Build Coastguard Worker         const float minY =
2806*35238bceSAndroid Build Coastguard Worker             de::min(de::min(triangleScreenSpace[0].y(), triangleScreenSpace[1].y()), triangleScreenSpace[2].y());
2807*35238bceSAndroid Build Coastguard Worker         const float maxX =
2808*35238bceSAndroid Build Coastguard Worker             de::max(de::max(triangleScreenSpace[0].x(), triangleScreenSpace[1].x()), triangleScreenSpace[2].x());
2809*35238bceSAndroid Build Coastguard Worker         const float maxY =
2810*35238bceSAndroid Build Coastguard Worker             de::max(de::max(triangleScreenSpace[0].y(), triangleScreenSpace[1].y()), triangleScreenSpace[2].y());
2811*35238bceSAndroid Build Coastguard Worker 
2812*35238bceSAndroid Build Coastguard Worker         if ((float)pixel.x() > maxX + 1 || (float)pixel.y() > maxY + 1 || (float)pixel.x() < minX - 1 ||
2813*35238bceSAndroid Build Coastguard Worker             (float)pixel.y() < minY - 1)
2814*35238bceSAndroid Build Coastguard Worker             return COVERAGE_NONE;
2815*35238bceSAndroid Build Coastguard Worker     }
2816*35238bceSAndroid Build Coastguard Worker 
2817*35238bceSAndroid Build Coastguard Worker     // Accurate intersection for edge pixels
2818*35238bceSAndroid Build Coastguard Worker     {
2819*35238bceSAndroid Build Coastguard Worker         //  In multisampling, the sample points can be anywhere in the pixel, and in single sampling only in the center.
2820*35238bceSAndroid Build Coastguard Worker         const I64Vec2 pixelCorners[4] = {
2821*35238bceSAndroid Build Coastguard Worker             I64Vec2((pixel.x() + 0) * numSubPixels, (pixel.y() + 0) * numSubPixels),
2822*35238bceSAndroid Build Coastguard Worker             I64Vec2((pixel.x() + 1) * numSubPixels, (pixel.y() + 0) * numSubPixels),
2823*35238bceSAndroid Build Coastguard Worker             I64Vec2((pixel.x() + 1) * numSubPixels, (pixel.y() + 1) * numSubPixels),
2824*35238bceSAndroid Build Coastguard Worker             I64Vec2((pixel.x() + 0) * numSubPixels, (pixel.y() + 1) * numSubPixels),
2825*35238bceSAndroid Build Coastguard Worker         };
2826*35238bceSAndroid Build Coastguard Worker         // both rounding directions
2827*35238bceSAndroid Build Coastguard Worker         const I64Vec2 triangleSubPixelSpaceFloor[3] = {
2828*35238bceSAndroid Build Coastguard Worker             I64Vec2(deFloorFloatToInt32(triangleScreenSpace[0].x() * (float)numSubPixels),
2829*35238bceSAndroid Build Coastguard Worker                     deFloorFloatToInt32(triangleScreenSpace[0].y() * (float)numSubPixels)),
2830*35238bceSAndroid Build Coastguard Worker             I64Vec2(deFloorFloatToInt32(triangleScreenSpace[1].x() * (float)numSubPixels),
2831*35238bceSAndroid Build Coastguard Worker                     deFloorFloatToInt32(triangleScreenSpace[1].y() * (float)numSubPixels)),
2832*35238bceSAndroid Build Coastguard Worker             I64Vec2(deFloorFloatToInt32(triangleScreenSpace[2].x() * (float)numSubPixels),
2833*35238bceSAndroid Build Coastguard Worker                     deFloorFloatToInt32(triangleScreenSpace[2].y() * (float)numSubPixels)),
2834*35238bceSAndroid Build Coastguard Worker         };
2835*35238bceSAndroid Build Coastguard Worker         const I64Vec2 triangleSubPixelSpaceCeil[3] = {
2836*35238bceSAndroid Build Coastguard Worker             I64Vec2(deCeilFloatToInt32(triangleScreenSpace[0].x() * (float)numSubPixels),
2837*35238bceSAndroid Build Coastguard Worker                     deCeilFloatToInt32(triangleScreenSpace[0].y() * (float)numSubPixels)),
2838*35238bceSAndroid Build Coastguard Worker             I64Vec2(deCeilFloatToInt32(triangleScreenSpace[1].x() * (float)numSubPixels),
2839*35238bceSAndroid Build Coastguard Worker                     deCeilFloatToInt32(triangleScreenSpace[1].y() * (float)numSubPixels)),
2840*35238bceSAndroid Build Coastguard Worker             I64Vec2(deCeilFloatToInt32(triangleScreenSpace[2].x() * (float)numSubPixels),
2841*35238bceSAndroid Build Coastguard Worker                     deCeilFloatToInt32(triangleScreenSpace[2].y() * (float)numSubPixels)),
2842*35238bceSAndroid Build Coastguard Worker         };
2843*35238bceSAndroid Build Coastguard Worker 
2844*35238bceSAndroid Build Coastguard Worker         // Test if any edge (with any rounding) intersects the pixel (boundary). If it does => Partial. If not => fully inside or outside
2845*35238bceSAndroid Build Coastguard Worker 
2846*35238bceSAndroid Build Coastguard Worker         for (int edgeNdx = 0; edgeNdx < 3; ++edgeNdx)
2847*35238bceSAndroid Build Coastguard Worker             for (int startRounding = 0; startRounding < 4; ++startRounding)
2848*35238bceSAndroid Build Coastguard Worker                 for (int endRounding = 0; endRounding < 4; ++endRounding)
2849*35238bceSAndroid Build Coastguard Worker                 {
2850*35238bceSAndroid Build Coastguard Worker                     const int nextEdgeNdx = (edgeNdx + 1) % 3;
2851*35238bceSAndroid Build Coastguard Worker                     const I64Vec2 startPos((startRounding & 0x01) ? (triangleSubPixelSpaceFloor[edgeNdx].x()) :
2852*35238bceSAndroid Build Coastguard Worker                                                                     (triangleSubPixelSpaceCeil[edgeNdx].x()),
2853*35238bceSAndroid Build Coastguard Worker                                            (startRounding & 0x02) ? (triangleSubPixelSpaceFloor[edgeNdx].y()) :
2854*35238bceSAndroid Build Coastguard Worker                                                                     (triangleSubPixelSpaceCeil[edgeNdx].y()));
2855*35238bceSAndroid Build Coastguard Worker                     const I64Vec2 endPos((endRounding & 0x01) ? (triangleSubPixelSpaceFloor[nextEdgeNdx].x()) :
2856*35238bceSAndroid Build Coastguard Worker                                                                 (triangleSubPixelSpaceCeil[nextEdgeNdx].x()),
2857*35238bceSAndroid Build Coastguard Worker                                          (endRounding & 0x02) ? (triangleSubPixelSpaceFloor[nextEdgeNdx].y()) :
2858*35238bceSAndroid Build Coastguard Worker                                                                 (triangleSubPixelSpaceCeil[nextEdgeNdx].y()));
2859*35238bceSAndroid Build Coastguard Worker 
2860*35238bceSAndroid Build Coastguard Worker                     for (int pixelEdgeNdx = 0; pixelEdgeNdx < 4; ++pixelEdgeNdx)
2861*35238bceSAndroid Build Coastguard Worker                     {
2862*35238bceSAndroid Build Coastguard Worker                         const int pixelEdgeEnd = (pixelEdgeNdx + 1) % 4;
2863*35238bceSAndroid Build Coastguard Worker 
2864*35238bceSAndroid Build Coastguard Worker                         if (lineLineIntersect(startPos, endPos, pixelCorners[pixelEdgeNdx], pixelCorners[pixelEdgeEnd]))
2865*35238bceSAndroid Build Coastguard Worker                             return COVERAGE_PARTIAL;
2866*35238bceSAndroid Build Coastguard Worker                     }
2867*35238bceSAndroid Build Coastguard Worker                 }
2868*35238bceSAndroid Build Coastguard Worker 
2869*35238bceSAndroid Build Coastguard Worker         // fully inside or outside
2870*35238bceSAndroid Build Coastguard Worker         for (int edgeNdx = 0; edgeNdx < 3; ++edgeNdx)
2871*35238bceSAndroid Build Coastguard Worker         {
2872*35238bceSAndroid Build Coastguard Worker             const int nextEdgeNdx      = (edgeNdx + 1) % 3;
2873*35238bceSAndroid Build Coastguard Worker             const I64Vec2 &startPos    = triangleSubPixelSpaceFloor[edgeNdx];
2874*35238bceSAndroid Build Coastguard Worker             const I64Vec2 &endPos      = triangleSubPixelSpaceFloor[nextEdgeNdx];
2875*35238bceSAndroid Build Coastguard Worker             const I64Vec2 edge         = endPos - startPos;
2876*35238bceSAndroid Build Coastguard Worker             const I64Vec2 v            = pixelCorners[0] - endPos;
2877*35238bceSAndroid Build Coastguard Worker             const int64_t crossProduct = (edge.x() * v.y() - edge.y() * v.x());
2878*35238bceSAndroid Build Coastguard Worker 
2879*35238bceSAndroid Build Coastguard Worker             // a corner of the pixel is outside => "fully inside" option is impossible
2880*35238bceSAndroid Build Coastguard Worker             if (crossProduct < 0)
2881*35238bceSAndroid Build Coastguard Worker                 return COVERAGE_NONE;
2882*35238bceSAndroid Build Coastguard Worker         }
2883*35238bceSAndroid Build Coastguard Worker 
2884*35238bceSAndroid Build Coastguard Worker         return COVERAGE_FULL;
2885*35238bceSAndroid Build Coastguard Worker     }
2886*35238bceSAndroid Build Coastguard Worker }
2887*35238bceSAndroid Build Coastguard Worker 
logTriangleGroupRasterizationStash(const tcu::Surface & surface,tcu::TestLog & log,VerifyTriangleGroupRasterizationLogStash & logStash)2888*35238bceSAndroid Build Coastguard Worker static void logTriangleGroupRasterizationStash(const tcu::Surface &surface, tcu::TestLog &log,
2889*35238bceSAndroid Build Coastguard Worker                                                VerifyTriangleGroupRasterizationLogStash &logStash)
2890*35238bceSAndroid Build Coastguard Worker {
2891*35238bceSAndroid Build Coastguard Worker     // Output results
2892*35238bceSAndroid Build Coastguard Worker     log << tcu::TestLog::Message << "Verifying rasterization result." << tcu::TestLog::EndMessage;
2893*35238bceSAndroid Build Coastguard Worker 
2894*35238bceSAndroid Build Coastguard Worker     for (size_t msgNdx = 0; msgNdx < logStash.messages.size(); ++msgNdx)
2895*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << logStash.messages[msgNdx] << tcu::TestLog::EndMessage;
2896*35238bceSAndroid Build Coastguard Worker 
2897*35238bceSAndroid Build Coastguard Worker     if (!logStash.result)
2898*35238bceSAndroid Build Coastguard Worker     {
2899*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Invalid pixels found:\n\t" << logStash.missingPixels
2900*35238bceSAndroid Build Coastguard Worker             << " missing pixels. (Marked with purple)\n\t" << logStash.unexpectedPixels
2901*35238bceSAndroid Build Coastguard Worker             << " incorrectly filled pixels. (Marked with red)\n\t"
2902*35238bceSAndroid Build Coastguard Worker             << "Unknown (subpixel on edge) pixels are marked with yellow." << tcu::TestLog::EndMessage;
2903*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2904*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Result", "Result", surface)
2905*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("ErrorMask", "ErrorMask", logStash.errorMask) << tcu::TestLog::EndImageSet;
2906*35238bceSAndroid Build Coastguard Worker     }
2907*35238bceSAndroid Build Coastguard Worker     else
2908*35238bceSAndroid Build Coastguard Worker     {
2909*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
2910*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2911*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::Image("Result", "Result", surface) << tcu::TestLog::EndImageSet;
2912*35238bceSAndroid Build Coastguard Worker     }
2913*35238bceSAndroid Build Coastguard Worker }
2914*35238bceSAndroid Build Coastguard Worker 
verifyTriangleGroupRasterization(const tcu::Surface & surface,const TriangleSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log,VerificationMode mode,VerifyTriangleGroupRasterizationLogStash * logStash,const bool vulkanLinesTest)2915*35238bceSAndroid Build Coastguard Worker bool verifyTriangleGroupRasterization(const tcu::Surface &surface, const TriangleSceneSpec &scene,
2916*35238bceSAndroid Build Coastguard Worker                                       const RasterizationArguments &args, tcu::TestLog &log, VerificationMode mode,
2917*35238bceSAndroid Build Coastguard Worker                                       VerifyTriangleGroupRasterizationLogStash *logStash, const bool vulkanLinesTest)
2918*35238bceSAndroid Build Coastguard Worker {
2919*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(mode < VERIFICATIONMODE_LAST);
2920*35238bceSAndroid Build Coastguard Worker 
2921*35238bceSAndroid Build Coastguard Worker     const tcu::RGBA backGroundColor       = tcu::RGBA(0, 0, 0, 255);
2922*35238bceSAndroid Build Coastguard Worker     const tcu::RGBA triangleColor         = tcu::RGBA(255, 255, 255, 255);
2923*35238bceSAndroid Build Coastguard Worker     const tcu::RGBA missingPixelColor     = tcu::RGBA(255, 0, 255, 255);
2924*35238bceSAndroid Build Coastguard Worker     const tcu::RGBA unexpectedPixelColor  = tcu::RGBA(255, 0, 0, 255);
2925*35238bceSAndroid Build Coastguard Worker     const tcu::RGBA partialPixelColor     = tcu::RGBA(255, 255, 0, 255);
2926*35238bceSAndroid Build Coastguard Worker     const tcu::RGBA primitivePixelColor   = tcu::RGBA(30, 30, 30, 255);
2927*35238bceSAndroid Build Coastguard Worker     const int weakVerificationThreshold   = 10;
2928*35238bceSAndroid Build Coastguard Worker     const int weakerVerificationThreshold = 25;
2929*35238bceSAndroid Build Coastguard Worker     const bool multisampled               = (args.numSamples != 0);
2930*35238bceSAndroid Build Coastguard Worker     const tcu::IVec2 viewportSize         = tcu::IVec2(surface.getWidth(), surface.getHeight());
2931*35238bceSAndroid Build Coastguard Worker     int missingPixels                     = 0;
2932*35238bceSAndroid Build Coastguard Worker     int unexpectedPixels                  = 0;
2933*35238bceSAndroid Build Coastguard Worker     int subPixelBits                      = args.subpixelBits;
2934*35238bceSAndroid Build Coastguard Worker     tcu::TextureLevel coverageMap(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT8),
2935*35238bceSAndroid Build Coastguard Worker                                   surface.getWidth(), surface.getHeight());
2936*35238bceSAndroid Build Coastguard Worker     tcu::Surface errorMask(surface.getWidth(), surface.getHeight());
2937*35238bceSAndroid Build Coastguard Worker     bool result = false;
2938*35238bceSAndroid Build Coastguard Worker 
2939*35238bceSAndroid Build Coastguard Worker     // subpixel bits in a valid range?
2940*35238bceSAndroid Build Coastguard Worker 
2941*35238bceSAndroid Build Coastguard Worker     if (subPixelBits < 0)
2942*35238bceSAndroid Build Coastguard Worker     {
2943*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Invalid subpixel count (" << subPixelBits << "), assuming 0"
2944*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::EndMessage;
2945*35238bceSAndroid Build Coastguard Worker         subPixelBits = 0;
2946*35238bceSAndroid Build Coastguard Worker     }
2947*35238bceSAndroid Build Coastguard Worker     else if (subPixelBits > 16)
2948*35238bceSAndroid Build Coastguard Worker     {
2949*35238bceSAndroid Build Coastguard Worker         // At high subpixel bit counts we might overflow. Checking at lower bit count is ok, but is less strict
2950*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Subpixel count is greater than 16 (" << subPixelBits
2951*35238bceSAndroid Build Coastguard Worker             << "). Checking results using less strict 16 bit requirements. This may produce false positives."
2952*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::EndMessage;
2953*35238bceSAndroid Build Coastguard Worker         subPixelBits = 16;
2954*35238bceSAndroid Build Coastguard Worker     }
2955*35238bceSAndroid Build Coastguard Worker 
2956*35238bceSAndroid Build Coastguard Worker     // generate coverage map
2957*35238bceSAndroid Build Coastguard Worker 
2958*35238bceSAndroid Build Coastguard Worker     tcu::clear(coverageMap.getAccess(), tcu::IVec4(COVERAGE_NONE, 0, 0, 0));
2959*35238bceSAndroid Build Coastguard Worker 
2960*35238bceSAndroid Build Coastguard Worker     for (int triNdx = 0; triNdx < (int)scene.triangles.size(); ++triNdx)
2961*35238bceSAndroid Build Coastguard Worker     {
2962*35238bceSAndroid Build Coastguard Worker         const tcu::IVec4 aabb = getTriangleAABB(scene.triangles[triNdx], viewportSize);
2963*35238bceSAndroid Build Coastguard Worker 
2964*35238bceSAndroid Build Coastguard Worker         for (int y = de::max(0, aabb.y()); y <= de::min(aabb.w(), coverageMap.getHeight() - 1); ++y)
2965*35238bceSAndroid Build Coastguard Worker             for (int x = de::max(0, aabb.x()); x <= de::min(aabb.z(), coverageMap.getWidth() - 1); ++x)
2966*35238bceSAndroid Build Coastguard Worker             {
2967*35238bceSAndroid Build Coastguard Worker                 if (coverageMap.getAccess().getPixelUint(x, y).x() == COVERAGE_FULL)
2968*35238bceSAndroid Build Coastguard Worker                     continue;
2969*35238bceSAndroid Build Coastguard Worker 
2970*35238bceSAndroid Build Coastguard Worker                 const CoverageType coverage = calculateTriangleCoverage(
2971*35238bceSAndroid Build Coastguard Worker                     scene.triangles[triNdx].positions[0], scene.triangles[triNdx].positions[1],
2972*35238bceSAndroid Build Coastguard Worker                     scene.triangles[triNdx].positions[2], tcu::IVec2(x, y), viewportSize, subPixelBits, multisampled);
2973*35238bceSAndroid Build Coastguard Worker 
2974*35238bceSAndroid Build Coastguard Worker                 if (coverage == COVERAGE_FULL)
2975*35238bceSAndroid Build Coastguard Worker                 {
2976*35238bceSAndroid Build Coastguard Worker                     coverageMap.getAccess().setPixel(tcu::IVec4(COVERAGE_FULL, 0, 0, 0), x, y);
2977*35238bceSAndroid Build Coastguard Worker                 }
2978*35238bceSAndroid Build Coastguard Worker                 else if (coverage == COVERAGE_PARTIAL)
2979*35238bceSAndroid Build Coastguard Worker                 {
2980*35238bceSAndroid Build Coastguard Worker                     CoverageType resultCoverage = COVERAGE_PARTIAL;
2981*35238bceSAndroid Build Coastguard Worker 
2982*35238bceSAndroid Build Coastguard Worker                     // Sharing an edge with another triangle?
2983*35238bceSAndroid Build Coastguard Worker                     // There should always be such a triangle, but the pixel in the other triangle might be
2984*35238bceSAndroid Build Coastguard Worker                     // on multiple edges, some of which are not shared. In these cases the coverage cannot be determined.
2985*35238bceSAndroid Build Coastguard Worker                     // Assume full coverage if the pixel is only on a shared edge in shared triangle too.
2986*35238bceSAndroid Build Coastguard Worker                     if (pixelOnlyOnASharedEdge(tcu::IVec2(x, y), scene.triangles[triNdx], viewportSize))
2987*35238bceSAndroid Build Coastguard Worker                     {
2988*35238bceSAndroid Build Coastguard Worker                         bool friendFound = false;
2989*35238bceSAndroid Build Coastguard Worker                         for (int friendTriNdx = 0; friendTriNdx < (int)scene.triangles.size(); ++friendTriNdx)
2990*35238bceSAndroid Build Coastguard Worker                         {
2991*35238bceSAndroid Build Coastguard Worker                             if (friendTriNdx == triNdx)
2992*35238bceSAndroid Build Coastguard Worker                                 continue;
2993*35238bceSAndroid Build Coastguard Worker 
2994*35238bceSAndroid Build Coastguard Worker                             const CoverageType friendCoverage = calculateTriangleCoverage(
2995*35238bceSAndroid Build Coastguard Worker                                 scene.triangles[friendTriNdx].positions[0], scene.triangles[friendTriNdx].positions[1],
2996*35238bceSAndroid Build Coastguard Worker                                 scene.triangles[friendTriNdx].positions[2], tcu::IVec2(x, y), viewportSize,
2997*35238bceSAndroid Build Coastguard Worker                                 subPixelBits, multisampled);
2998*35238bceSAndroid Build Coastguard Worker 
2999*35238bceSAndroid Build Coastguard Worker                             if (friendCoverage != COVERAGE_NONE &&
3000*35238bceSAndroid Build Coastguard Worker                                 pixelOnlyOnASharedEdge(tcu::IVec2(x, y), scene.triangles[friendTriNdx], viewportSize))
3001*35238bceSAndroid Build Coastguard Worker                             {
3002*35238bceSAndroid Build Coastguard Worker                                 friendFound = true;
3003*35238bceSAndroid Build Coastguard Worker                                 break;
3004*35238bceSAndroid Build Coastguard Worker                             }
3005*35238bceSAndroid Build Coastguard Worker                         }
3006*35238bceSAndroid Build Coastguard Worker 
3007*35238bceSAndroid Build Coastguard Worker                         if (friendFound)
3008*35238bceSAndroid Build Coastguard Worker                             resultCoverage = COVERAGE_FULL;
3009*35238bceSAndroid Build Coastguard Worker                     }
3010*35238bceSAndroid Build Coastguard Worker 
3011*35238bceSAndroid Build Coastguard Worker                     coverageMap.getAccess().setPixel(tcu::IVec4(resultCoverage, 0, 0, 0), x, y);
3012*35238bceSAndroid Build Coastguard Worker                 }
3013*35238bceSAndroid Build Coastguard Worker             }
3014*35238bceSAndroid Build Coastguard Worker     }
3015*35238bceSAndroid Build Coastguard Worker 
3016*35238bceSAndroid Build Coastguard Worker     // check pixels
3017*35238bceSAndroid Build Coastguard Worker 
3018*35238bceSAndroid Build Coastguard Worker     tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
3019*35238bceSAndroid Build Coastguard Worker 
3020*35238bceSAndroid Build Coastguard Worker     // Use these to quick check there is something drawn when a test expects something else than an empty picture.
3021*35238bceSAndroid Build Coastguard Worker     bool referenceEmpty = true;
3022*35238bceSAndroid Build Coastguard Worker     bool resultEmpty    = true;
3023*35238bceSAndroid Build Coastguard Worker 
3024*35238bceSAndroid Build Coastguard Worker     for (int y = 0; y < surface.getHeight(); ++y)
3025*35238bceSAndroid Build Coastguard Worker         for (int x = 0; x < surface.getWidth(); ++x)
3026*35238bceSAndroid Build Coastguard Worker         {
3027*35238bceSAndroid Build Coastguard Worker             const tcu::RGBA color = surface.getPixel(x, y);
3028*35238bceSAndroid Build Coastguard Worker             const bool imageNoCoverage =
3029*35238bceSAndroid Build Coastguard Worker                 compareColors(color, backGroundColor, args.redBits, args.greenBits, args.blueBits);
3030*35238bceSAndroid Build Coastguard Worker             const bool imageFullCoverage =
3031*35238bceSAndroid Build Coastguard Worker                 compareColors(color, triangleColor, args.redBits, args.greenBits, args.blueBits);
3032*35238bceSAndroid Build Coastguard Worker             CoverageType referenceCoverage = (CoverageType)coverageMap.getAccess().getPixelUint(x, y).x();
3033*35238bceSAndroid Build Coastguard Worker 
3034*35238bceSAndroid Build Coastguard Worker             if (!imageNoCoverage)
3035*35238bceSAndroid Build Coastguard Worker                 resultEmpty = false;
3036*35238bceSAndroid Build Coastguard Worker 
3037*35238bceSAndroid Build Coastguard Worker             switch (referenceCoverage)
3038*35238bceSAndroid Build Coastguard Worker             {
3039*35238bceSAndroid Build Coastguard Worker             case COVERAGE_NONE:
3040*35238bceSAndroid Build Coastguard Worker                 if (!imageNoCoverage)
3041*35238bceSAndroid Build Coastguard Worker                 {
3042*35238bceSAndroid Build Coastguard Worker                     // coverage where there should not be
3043*35238bceSAndroid Build Coastguard Worker                     ++unexpectedPixels;
3044*35238bceSAndroid Build Coastguard Worker                     errorMask.setPixel(x, y, unexpectedPixelColor);
3045*35238bceSAndroid Build Coastguard Worker                 }
3046*35238bceSAndroid Build Coastguard Worker                 break;
3047*35238bceSAndroid Build Coastguard Worker 
3048*35238bceSAndroid Build Coastguard Worker             case COVERAGE_PARTIAL:
3049*35238bceSAndroid Build Coastguard Worker             {
3050*35238bceSAndroid Build Coastguard Worker                 referenceEmpty     = false;
3051*35238bceSAndroid Build Coastguard Worker                 bool foundFragment = false;
3052*35238bceSAndroid Build Coastguard Worker                 if (vulkanLinesTest == true)
3053*35238bceSAndroid Build Coastguard Worker                 {
3054*35238bceSAndroid Build Coastguard Worker                     for (int dy = -1; dy < 2 && !foundFragment; ++dy)
3055*35238bceSAndroid Build Coastguard Worker                         for (int dx = -1; dx < 2 && !foundFragment; ++dx)
3056*35238bceSAndroid Build Coastguard Worker                         {
3057*35238bceSAndroid Build Coastguard Worker                             if (x + dx >= 0 && x + dx != surface.getWidth() && y + dy >= 0 &&
3058*35238bceSAndroid Build Coastguard Worker                                 y + dy != surface.getHeight() &&
3059*35238bceSAndroid Build Coastguard Worker                                 (CoverageType)coverageMap.getAccess().getPixelUint(x + dx, y + dy).x() != COVERAGE_NONE)
3060*35238bceSAndroid Build Coastguard Worker                             {
3061*35238bceSAndroid Build Coastguard Worker                                 const tcu::RGBA color2 = surface.getPixel(x + dx, y + dy);
3062*35238bceSAndroid Build Coastguard Worker                                 if (compareColors(color2, triangleColor, args.redBits, args.greenBits, args.blueBits))
3063*35238bceSAndroid Build Coastguard Worker                                     foundFragment = true;
3064*35238bceSAndroid Build Coastguard Worker                             }
3065*35238bceSAndroid Build Coastguard Worker                         }
3066*35238bceSAndroid Build Coastguard Worker                 }
3067*35238bceSAndroid Build Coastguard Worker                 // anything goes
3068*35238bceSAndroid Build Coastguard Worker                 if (foundFragment == false)
3069*35238bceSAndroid Build Coastguard Worker                 {
3070*35238bceSAndroid Build Coastguard Worker                     errorMask.setPixel(x, y, partialPixelColor);
3071*35238bceSAndroid Build Coastguard Worker                     if (vulkanLinesTest == true)
3072*35238bceSAndroid Build Coastguard Worker                         ++missingPixels;
3073*35238bceSAndroid Build Coastguard Worker                 }
3074*35238bceSAndroid Build Coastguard Worker             }
3075*35238bceSAndroid Build Coastguard Worker             break;
3076*35238bceSAndroid Build Coastguard Worker 
3077*35238bceSAndroid Build Coastguard Worker             case COVERAGE_FULL:
3078*35238bceSAndroid Build Coastguard Worker                 referenceEmpty = false;
3079*35238bceSAndroid Build Coastguard Worker                 if (!imageFullCoverage)
3080*35238bceSAndroid Build Coastguard Worker                 {
3081*35238bceSAndroid Build Coastguard Worker                     // no coverage where there should be
3082*35238bceSAndroid Build Coastguard Worker                     ++missingPixels;
3083*35238bceSAndroid Build Coastguard Worker                     errorMask.setPixel(x, y, missingPixelColor);
3084*35238bceSAndroid Build Coastguard Worker                 }
3085*35238bceSAndroid Build Coastguard Worker                 else
3086*35238bceSAndroid Build Coastguard Worker                 {
3087*35238bceSAndroid Build Coastguard Worker                     errorMask.setPixel(x, y, primitivePixelColor);
3088*35238bceSAndroid Build Coastguard Worker                 }
3089*35238bceSAndroid Build Coastguard Worker                 break;
3090*35238bceSAndroid Build Coastguard Worker 
3091*35238bceSAndroid Build Coastguard Worker             default:
3092*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT(false);
3093*35238bceSAndroid Build Coastguard Worker             }
3094*35238bceSAndroid Build Coastguard Worker         }
3095*35238bceSAndroid Build Coastguard Worker 
3096*35238bceSAndroid Build Coastguard Worker     if (((mode == VERIFICATIONMODE_STRICT) && (missingPixels + unexpectedPixels > 0)) ||
3097*35238bceSAndroid Build Coastguard Worker         ((mode == VERIFICATIONMODE_WEAK) && (missingPixels + unexpectedPixels > weakVerificationThreshold)) ||
3098*35238bceSAndroid Build Coastguard Worker         ((mode == VERIFICATIONMODE_WEAKER) && (missingPixels + unexpectedPixels > weakerVerificationThreshold)) ||
3099*35238bceSAndroid Build Coastguard Worker         ((mode == VERIFICATIONMODE_SMOOTH) && (missingPixels > weakVerificationThreshold)) ||
3100*35238bceSAndroid Build Coastguard Worker         referenceEmpty != resultEmpty)
3101*35238bceSAndroid Build Coastguard Worker     {
3102*35238bceSAndroid Build Coastguard Worker         result = false;
3103*35238bceSAndroid Build Coastguard Worker     }
3104*35238bceSAndroid Build Coastguard Worker     else
3105*35238bceSAndroid Build Coastguard Worker     {
3106*35238bceSAndroid Build Coastguard Worker         result = true;
3107*35238bceSAndroid Build Coastguard Worker     }
3108*35238bceSAndroid Build Coastguard Worker 
3109*35238bceSAndroid Build Coastguard Worker     // Output or stash results
3110*35238bceSAndroid Build Coastguard Worker     {
3111*35238bceSAndroid Build Coastguard Worker         VerifyTriangleGroupRasterizationLogStash *tempLogStash =
3112*35238bceSAndroid Build Coastguard Worker             (logStash == DE_NULL) ? new VerifyTriangleGroupRasterizationLogStash : logStash;
3113*35238bceSAndroid Build Coastguard Worker 
3114*35238bceSAndroid Build Coastguard Worker         tempLogStash->result           = result;
3115*35238bceSAndroid Build Coastguard Worker         tempLogStash->missingPixels    = missingPixels;
3116*35238bceSAndroid Build Coastguard Worker         tempLogStash->unexpectedPixels = unexpectedPixels;
3117*35238bceSAndroid Build Coastguard Worker         tempLogStash->errorMask        = errorMask;
3118*35238bceSAndroid Build Coastguard Worker 
3119*35238bceSAndroid Build Coastguard Worker         if (logStash == DE_NULL)
3120*35238bceSAndroid Build Coastguard Worker         {
3121*35238bceSAndroid Build Coastguard Worker             logTriangleGroupRasterizationStash(surface, log, *tempLogStash);
3122*35238bceSAndroid Build Coastguard Worker             delete tempLogStash;
3123*35238bceSAndroid Build Coastguard Worker         }
3124*35238bceSAndroid Build Coastguard Worker     }
3125*35238bceSAndroid Build Coastguard Worker 
3126*35238bceSAndroid Build Coastguard Worker     return result;
3127*35238bceSAndroid Build Coastguard Worker }
3128*35238bceSAndroid Build Coastguard Worker 
verifyLineGroupRasterization(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)3129*35238bceSAndroid Build Coastguard Worker bool verifyLineGroupRasterization(const tcu::Surface &surface, const LineSceneSpec &scene,
3130*35238bceSAndroid Build Coastguard Worker                                   const RasterizationArguments &args, tcu::TestLog &log)
3131*35238bceSAndroid Build Coastguard Worker {
3132*35238bceSAndroid Build Coastguard Worker     const bool multisampled = args.numSamples != 0;
3133*35238bceSAndroid Build Coastguard Worker 
3134*35238bceSAndroid Build Coastguard Worker     if (multisampled)
3135*35238bceSAndroid Build Coastguard Worker         return verifyMultisampleLineGroupRasterization(surface, scene, args, log, CLIPMODE_NO_CLIPPING, DE_NULL, false,
3136*35238bceSAndroid Build Coastguard Worker                                                        true);
3137*35238bceSAndroid Build Coastguard Worker     else
3138*35238bceSAndroid Build Coastguard Worker         return verifySinglesampleLineGroupRasterization(surface, scene, args, log);
3139*35238bceSAndroid Build Coastguard Worker }
3140*35238bceSAndroid Build Coastguard Worker 
verifyClippedTriangulatedLineGroupRasterization(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)3141*35238bceSAndroid Build Coastguard Worker bool verifyClippedTriangulatedLineGroupRasterization(const tcu::Surface &surface, const LineSceneSpec &scene,
3142*35238bceSAndroid Build Coastguard Worker                                                      const RasterizationArguments &args, tcu::TestLog &log)
3143*35238bceSAndroid Build Coastguard Worker {
3144*35238bceSAndroid Build Coastguard Worker     return verifyMultisampleLineGroupRasterization(surface, scene, args, log, CLIPMODE_USE_CLIPPING_BOX, DE_NULL, false,
3145*35238bceSAndroid Build Coastguard Worker                                                    true);
3146*35238bceSAndroid Build Coastguard Worker }
3147*35238bceSAndroid Build Coastguard Worker 
verifyRelaxedLineGroupRasterization(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log,const bool vulkanLinesTest,const bool strict)3148*35238bceSAndroid Build Coastguard Worker bool verifyRelaxedLineGroupRasterization(const tcu::Surface &surface, const LineSceneSpec &scene,
3149*35238bceSAndroid Build Coastguard Worker                                          const RasterizationArguments &args, tcu::TestLog &log,
3150*35238bceSAndroid Build Coastguard Worker                                          const bool vulkanLinesTest, const bool strict)
3151*35238bceSAndroid Build Coastguard Worker {
3152*35238bceSAndroid Build Coastguard Worker     VerifyTriangleGroupRasterizationLogStash useClippingLogStash;
3153*35238bceSAndroid Build Coastguard Worker     VerifyTriangleGroupRasterizationLogStash noClippingLogStash;
3154*35238bceSAndroid Build Coastguard Worker     VerifyTriangleGroupRasterizationLogStash useClippingForcedStrictLogStash;
3155*35238bceSAndroid Build Coastguard Worker     VerifyTriangleGroupRasterizationLogStash noClippingForcedStrictLogStash;
3156*35238bceSAndroid Build Coastguard Worker 
3157*35238bceSAndroid Build Coastguard Worker     if (verifyMultisampleLineGroupRasterization(surface, scene, args, log, CLIPMODE_USE_CLIPPING_BOX,
3158*35238bceSAndroid Build Coastguard Worker                                                 &useClippingLogStash, vulkanLinesTest, strict))
3159*35238bceSAndroid Build Coastguard Worker     {
3160*35238bceSAndroid Build Coastguard Worker         logTriangleGroupRasterizationStash(surface, log, useClippingLogStash);
3161*35238bceSAndroid Build Coastguard Worker 
3162*35238bceSAndroid Build Coastguard Worker         return true;
3163*35238bceSAndroid Build Coastguard Worker     }
3164*35238bceSAndroid Build Coastguard Worker     else if (verifyMultisampleLineGroupRasterization(surface, scene, args, log, CLIPMODE_NO_CLIPPING,
3165*35238bceSAndroid Build Coastguard Worker                                                      &noClippingLogStash, vulkanLinesTest, strict))
3166*35238bceSAndroid Build Coastguard Worker     {
3167*35238bceSAndroid Build Coastguard Worker         logTriangleGroupRasterizationStash(surface, log, noClippingLogStash);
3168*35238bceSAndroid Build Coastguard Worker 
3169*35238bceSAndroid Build Coastguard Worker         return true;
3170*35238bceSAndroid Build Coastguard Worker     }
3171*35238bceSAndroid Build Coastguard Worker     else if (strict == false &&
3172*35238bceSAndroid Build Coastguard Worker              verifyMultisampleLineGroupRasterization(surface, scene, args, log, CLIPMODE_USE_CLIPPING_BOX,
3173*35238bceSAndroid Build Coastguard Worker                                                      &useClippingForcedStrictLogStash, vulkanLinesTest, true))
3174*35238bceSAndroid Build Coastguard Worker     {
3175*35238bceSAndroid Build Coastguard Worker         logTriangleGroupRasterizationStash(surface, log, useClippingForcedStrictLogStash);
3176*35238bceSAndroid Build Coastguard Worker 
3177*35238bceSAndroid Build Coastguard Worker         return true;
3178*35238bceSAndroid Build Coastguard Worker     }
3179*35238bceSAndroid Build Coastguard Worker     else if (strict == false &&
3180*35238bceSAndroid Build Coastguard Worker              verifyMultisampleLineGroupRasterization(surface, scene, args, log, CLIPMODE_NO_CLIPPING,
3181*35238bceSAndroid Build Coastguard Worker                                                      &noClippingForcedStrictLogStash, vulkanLinesTest, true))
3182*35238bceSAndroid Build Coastguard Worker     {
3183*35238bceSAndroid Build Coastguard Worker         logTriangleGroupRasterizationStash(surface, log, noClippingForcedStrictLogStash);
3184*35238bceSAndroid Build Coastguard Worker 
3185*35238bceSAndroid Build Coastguard Worker         return true;
3186*35238bceSAndroid Build Coastguard Worker     }
3187*35238bceSAndroid Build Coastguard Worker     else if (strict == false && args.numSamples == 0 && verifyLineGroupRasterization(surface, scene, args, log))
3188*35238bceSAndroid Build Coastguard Worker     {
3189*35238bceSAndroid Build Coastguard Worker         return true;
3190*35238bceSAndroid Build Coastguard Worker     }
3191*35238bceSAndroid Build Coastguard Worker     else
3192*35238bceSAndroid Build Coastguard Worker     {
3193*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message << "Relaxed rasterization failed, details follow." << tcu::TestLog::EndMessage;
3194*35238bceSAndroid Build Coastguard Worker 
3195*35238bceSAndroid Build Coastguard Worker         logTriangleGroupRasterizationStash(surface, log, useClippingLogStash);
3196*35238bceSAndroid Build Coastguard Worker         logTriangleGroupRasterizationStash(surface, log, noClippingLogStash);
3197*35238bceSAndroid Build Coastguard Worker 
3198*35238bceSAndroid Build Coastguard Worker         if (strict == false)
3199*35238bceSAndroid Build Coastguard Worker         {
3200*35238bceSAndroid Build Coastguard Worker             logTriangleGroupRasterizationStash(surface, log, useClippingForcedStrictLogStash);
3201*35238bceSAndroid Build Coastguard Worker             logTriangleGroupRasterizationStash(surface, log, noClippingForcedStrictLogStash);
3202*35238bceSAndroid Build Coastguard Worker         }
3203*35238bceSAndroid Build Coastguard Worker 
3204*35238bceSAndroid Build Coastguard Worker         return false;
3205*35238bceSAndroid Build Coastguard Worker     }
3206*35238bceSAndroid Build Coastguard Worker }
3207*35238bceSAndroid Build Coastguard Worker 
verifyPointGroupRasterization(const tcu::Surface & surface,const PointSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)3208*35238bceSAndroid Build Coastguard Worker bool verifyPointGroupRasterization(const tcu::Surface &surface, const PointSceneSpec &scene,
3209*35238bceSAndroid Build Coastguard Worker                                    const RasterizationArguments &args, tcu::TestLog &log)
3210*35238bceSAndroid Build Coastguard Worker {
3211*35238bceSAndroid Build Coastguard Worker     // Splitting to triangles is a valid solution in multisampled cases and even in non-multisample cases too.
3212*35238bceSAndroid Build Coastguard Worker     return verifyMultisamplePointGroupRasterization(surface, scene, args, log);
3213*35238bceSAndroid Build Coastguard Worker }
3214*35238bceSAndroid Build Coastguard Worker 
verifyTriangleGroupInterpolation(const tcu::Surface & surface,const TriangleSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)3215*35238bceSAndroid Build Coastguard Worker bool verifyTriangleGroupInterpolation(const tcu::Surface &surface, const TriangleSceneSpec &scene,
3216*35238bceSAndroid Build Coastguard Worker                                       const RasterizationArguments &args, tcu::TestLog &log)
3217*35238bceSAndroid Build Coastguard Worker {
3218*35238bceSAndroid Build Coastguard Worker     VerifyTriangleGroupInterpolationLogStash logStash;
3219*35238bceSAndroid Build Coastguard Worker     const bool result =
3220*35238bceSAndroid Build Coastguard Worker         verifyTriangleGroupInterpolationWithInterpolator(surface, scene, args, logStash, TriangleInterpolator(scene));
3221*35238bceSAndroid Build Coastguard Worker 
3222*35238bceSAndroid Build Coastguard Worker     logTriangleGroupnterpolationStash(surface, log, logStash);
3223*35238bceSAndroid Build Coastguard Worker 
3224*35238bceSAndroid Build Coastguard Worker     return result;
3225*35238bceSAndroid Build Coastguard Worker }
3226*35238bceSAndroid Build Coastguard Worker 
verifyLineGroupInterpolation(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log)3227*35238bceSAndroid Build Coastguard Worker LineInterpolationMethod verifyLineGroupInterpolation(const tcu::Surface &surface, const LineSceneSpec &scene,
3228*35238bceSAndroid Build Coastguard Worker                                                      const RasterizationArguments &args, tcu::TestLog &log)
3229*35238bceSAndroid Build Coastguard Worker {
3230*35238bceSAndroid Build Coastguard Worker     const bool multisampled = args.numSamples != 0;
3231*35238bceSAndroid Build Coastguard Worker 
3232*35238bceSAndroid Build Coastguard Worker     if (multisampled)
3233*35238bceSAndroid Build Coastguard Worker     {
3234*35238bceSAndroid Build Coastguard Worker         if (verifyMultisampleLineGroupInterpolation(surface, scene, args, log))
3235*35238bceSAndroid Build Coastguard Worker             return LINEINTERPOLATION_STRICTLY_CORRECT;
3236*35238bceSAndroid Build Coastguard Worker         return LINEINTERPOLATION_INCORRECT;
3237*35238bceSAndroid Build Coastguard Worker     }
3238*35238bceSAndroid Build Coastguard Worker     else
3239*35238bceSAndroid Build Coastguard Worker     {
3240*35238bceSAndroid Build Coastguard Worker         const bool isNarrow = (scene.lineWidth == 1.0f);
3241*35238bceSAndroid Build Coastguard Worker 
3242*35238bceSAndroid Build Coastguard Worker         // accurate interpolation
3243*35238bceSAndroid Build Coastguard Worker         if (isNarrow)
3244*35238bceSAndroid Build Coastguard Worker         {
3245*35238bceSAndroid Build Coastguard Worker             if (verifySinglesampleNarrowLineGroupInterpolation(surface, scene, args, log))
3246*35238bceSAndroid Build Coastguard Worker                 return LINEINTERPOLATION_STRICTLY_CORRECT;
3247*35238bceSAndroid Build Coastguard Worker         }
3248*35238bceSAndroid Build Coastguard Worker         else
3249*35238bceSAndroid Build Coastguard Worker         {
3250*35238bceSAndroid Build Coastguard Worker             if (verifySinglesampleWideLineGroupInterpolation(surface, scene, args, log))
3251*35238bceSAndroid Build Coastguard Worker                 return LINEINTERPOLATION_STRICTLY_CORRECT;
3252*35238bceSAndroid Build Coastguard Worker 
3253*35238bceSAndroid Build Coastguard Worker             if (scene.allowNonProjectedInterpolation &&
3254*35238bceSAndroid Build Coastguard Worker                 verifyLineGroupInterpolationWithNonProjectedWeights(surface, scene, args, log))
3255*35238bceSAndroid Build Coastguard Worker                 return LINEINTERPOLATION_STRICTLY_CORRECT;
3256*35238bceSAndroid Build Coastguard Worker         }
3257*35238bceSAndroid Build Coastguard Worker 
3258*35238bceSAndroid Build Coastguard Worker         // check with projected (inaccurate) interpolation
3259*35238bceSAndroid Build Coastguard Worker         log << tcu::TestLog::Message
3260*35238bceSAndroid Build Coastguard Worker             << "Accurate verification failed, checking with projected weights (inaccurate equation)."
3261*35238bceSAndroid Build Coastguard Worker             << tcu::TestLog::EndMessage;
3262*35238bceSAndroid Build Coastguard Worker         if (verifyLineGroupInterpolationWithProjectedWeights(surface, scene, args, log))
3263*35238bceSAndroid Build Coastguard Worker             return LINEINTERPOLATION_PROJECTED;
3264*35238bceSAndroid Build Coastguard Worker 
3265*35238bceSAndroid Build Coastguard Worker         return LINEINTERPOLATION_INCORRECT;
3266*35238bceSAndroid Build Coastguard Worker     }
3267*35238bceSAndroid Build Coastguard Worker }
3268*35238bceSAndroid Build Coastguard Worker 
verifyTriangulatedLineGroupInterpolation(const tcu::Surface & surface,const LineSceneSpec & scene,const RasterizationArguments & args,tcu::TestLog & log,const bool strictMode,const bool allowBresenhamForNonStrictLines)3269*35238bceSAndroid Build Coastguard Worker bool verifyTriangulatedLineGroupInterpolation(const tcu::Surface &surface, const LineSceneSpec &scene,
3270*35238bceSAndroid Build Coastguard Worker                                               const RasterizationArguments &args, tcu::TestLog &log,
3271*35238bceSAndroid Build Coastguard Worker                                               const bool strictMode, const bool allowBresenhamForNonStrictLines)
3272*35238bceSAndroid Build Coastguard Worker {
3273*35238bceSAndroid Build Coastguard Worker     return verifyMultisampleLineGroupInterpolation(surface, scene, args, log, strictMode,
3274*35238bceSAndroid Build Coastguard Worker                                                    allowBresenhamForNonStrictLines);
3275*35238bceSAndroid Build Coastguard Worker }
3276*35238bceSAndroid Build Coastguard Worker 
3277*35238bceSAndroid Build Coastguard Worker } // namespace tcu
3278