1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program OpenGL ES Utilities
3e5c31af7Sopenharmony_ci * ------------------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief Utility functions and structures for texture tests. This code
22e5c31af7Sopenharmony_ci * is originated from the modules/glshared/glsTextureTestUtil.hpp and it
23e5c31af7Sopenharmony_ci * is tightly coupled with the GLES and Vulkan texture tests!
24e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ci#include "gluTextureTestUtil.hpp"
27e5c31af7Sopenharmony_ci
28e5c31af7Sopenharmony_ci#include "tcuFloat.hpp"
29e5c31af7Sopenharmony_ci#include "tcuImageCompare.hpp"
30e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
31e5c31af7Sopenharmony_ci#include "tcuVectorUtil.hpp"
32e5c31af7Sopenharmony_ci
33e5c31af7Sopenharmony_ci#include "deMath.h"
34e5c31af7Sopenharmony_ci#include "deStringUtil.hpp"
35e5c31af7Sopenharmony_ci
36e5c31af7Sopenharmony_ci#include <string>
37e5c31af7Sopenharmony_ci
38e5c31af7Sopenharmony_ciusing std::string;
39e5c31af7Sopenharmony_ci
40e5c31af7Sopenharmony_cinamespace glu
41e5c31af7Sopenharmony_ci{
42e5c31af7Sopenharmony_ci
43e5c31af7Sopenharmony_cinamespace TextureTestUtil
44e5c31af7Sopenharmony_ci{
45e5c31af7Sopenharmony_ci
46e5c31af7Sopenharmony_cienum
47e5c31af7Sopenharmony_ci{
48e5c31af7Sopenharmony_ci	MIN_SUBPIXEL_BITS	= 4
49e5c31af7Sopenharmony_ci};
50e5c31af7Sopenharmony_ci
51e5c31af7Sopenharmony_ciSamplerType getSamplerType (tcu::TextureFormat format)
52e5c31af7Sopenharmony_ci{
53e5c31af7Sopenharmony_ci	using tcu::TextureFormat;
54e5c31af7Sopenharmony_ci
55e5c31af7Sopenharmony_ci	switch (format.type)
56e5c31af7Sopenharmony_ci	{
57e5c31af7Sopenharmony_ci		case TextureFormat::SIGNED_INT8:
58e5c31af7Sopenharmony_ci		case TextureFormat::SIGNED_INT16:
59e5c31af7Sopenharmony_ci		case TextureFormat::SIGNED_INT32:
60e5c31af7Sopenharmony_ci			return SAMPLERTYPE_INT;
61e5c31af7Sopenharmony_ci
62e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT8:
63e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT32:
64e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT_1010102_REV:
65e5c31af7Sopenharmony_ci			return SAMPLERTYPE_UINT;
66e5c31af7Sopenharmony_ci
67e5c31af7Sopenharmony_ci		// Texture formats used in depth/stencil textures.
68e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT16:
69e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT_24_8:
70e5c31af7Sopenharmony_ci			return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FLOAT : SAMPLERTYPE_UINT;
71e5c31af7Sopenharmony_ci
72e5c31af7Sopenharmony_ci		default:
73e5c31af7Sopenharmony_ci			return SAMPLERTYPE_FLOAT;
74e5c31af7Sopenharmony_ci	}
75e5c31af7Sopenharmony_ci}
76e5c31af7Sopenharmony_ci
77e5c31af7Sopenharmony_ciSamplerType getFetchSamplerType (tcu::TextureFormat format)
78e5c31af7Sopenharmony_ci{
79e5c31af7Sopenharmony_ci	using tcu::TextureFormat;
80e5c31af7Sopenharmony_ci
81e5c31af7Sopenharmony_ci	switch (format.type)
82e5c31af7Sopenharmony_ci	{
83e5c31af7Sopenharmony_ci		case TextureFormat::SIGNED_INT8:
84e5c31af7Sopenharmony_ci		case TextureFormat::SIGNED_INT16:
85e5c31af7Sopenharmony_ci		case TextureFormat::SIGNED_INT32:
86e5c31af7Sopenharmony_ci			return SAMPLERTYPE_FETCH_INT;
87e5c31af7Sopenharmony_ci
88e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT8:
89e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT32:
90e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT_1010102_REV:
91e5c31af7Sopenharmony_ci			return SAMPLERTYPE_FETCH_UINT;
92e5c31af7Sopenharmony_ci
93e5c31af7Sopenharmony_ci		// Texture formats used in depth/stencil textures.
94e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT16:
95e5c31af7Sopenharmony_ci		case TextureFormat::UNSIGNED_INT_24_8:
96e5c31af7Sopenharmony_ci			return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FETCH_FLOAT : SAMPLERTYPE_FETCH_UINT;
97e5c31af7Sopenharmony_ci
98e5c31af7Sopenharmony_ci		default:
99e5c31af7Sopenharmony_ci			return SAMPLERTYPE_FETCH_FLOAT;
100e5c31af7Sopenharmony_ci	}
101e5c31af7Sopenharmony_ci}
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_cistatic tcu::Texture1DView getSubView (const tcu::Texture1DView& view, int baseLevel, int maxLevel, tcu::ImageViewMinLodParams* minLodParams DE_UNUSED_ATTR)
104e5c31af7Sopenharmony_ci{
105e5c31af7Sopenharmony_ci	const int	clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
106e5c31af7Sopenharmony_ci	const int	clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
107e5c31af7Sopenharmony_ci	const int	numLevels	= clampedMax-clampedBase+1;
108e5c31af7Sopenharmony_ci	return tcu::Texture1DView(numLevels, view.getLevels()+clampedBase);
109e5c31af7Sopenharmony_ci}
110e5c31af7Sopenharmony_ci
111e5c31af7Sopenharmony_cistatic tcu::Texture2DView getSubView (const tcu::Texture2DView& view, int baseLevel, int maxLevel, tcu::ImageViewMinLodParams* minLodParams = DE_NULL)
112e5c31af7Sopenharmony_ci{
113e5c31af7Sopenharmony_ci	const int	clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
114e5c31af7Sopenharmony_ci	const int	clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
115e5c31af7Sopenharmony_ci	const int	numLevels	= clampedMax-clampedBase+1;
116e5c31af7Sopenharmony_ci	return tcu::Texture2DView(numLevels, view.getLevels()+clampedBase, view.isES2(), minLodParams);
117e5c31af7Sopenharmony_ci}
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_cistatic tcu::TextureCubeView getSubView (const tcu::TextureCubeView& view, int baseLevel, int maxLevel, tcu::ImageViewMinLodParams* minLodParams = DE_NULL)
120e5c31af7Sopenharmony_ci{
121e5c31af7Sopenharmony_ci	const int							clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
122e5c31af7Sopenharmony_ci	const int							clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
123e5c31af7Sopenharmony_ci	const int							numLevels	= clampedMax-clampedBase+1;
124e5c31af7Sopenharmony_ci	const tcu::ConstPixelBufferAccess*	levels[tcu::CUBEFACE_LAST];
125e5c31af7Sopenharmony_ci
126e5c31af7Sopenharmony_ci	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
127e5c31af7Sopenharmony_ci		levels[face] = view.getFaceLevels((tcu::CubeFace)face) + clampedBase;
128e5c31af7Sopenharmony_ci
129e5c31af7Sopenharmony_ci	return tcu::TextureCubeView(numLevels, levels, false, minLodParams);
130e5c31af7Sopenharmony_ci}
131e5c31af7Sopenharmony_ci
132e5c31af7Sopenharmony_cistatic tcu::Texture3DView getSubView (const tcu::Texture3DView& view, int baseLevel, int maxLevel, tcu::ImageViewMinLodParams* minLodParams = DE_NULL)
133e5c31af7Sopenharmony_ci{
134e5c31af7Sopenharmony_ci	const int	clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
135e5c31af7Sopenharmony_ci	const int	clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
136e5c31af7Sopenharmony_ci	const int	numLevels	= clampedMax-clampedBase+1;
137e5c31af7Sopenharmony_ci	return tcu::Texture3DView(numLevels, view.getLevels()+clampedBase, false, minLodParams);
138e5c31af7Sopenharmony_ci}
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_cistatic tcu::TextureCubeArrayView getSubView (const tcu::TextureCubeArrayView& view, int baseLevel, int maxLevel, tcu::ImageViewMinLodParams* minLodParams DE_UNUSED_ATTR = DE_NULL)
141e5c31af7Sopenharmony_ci{
142e5c31af7Sopenharmony_ci	const int	clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
143e5c31af7Sopenharmony_ci	const int	clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
144e5c31af7Sopenharmony_ci	const int	numLevels	= clampedMax-clampedBase+1;
145e5c31af7Sopenharmony_ci	return tcu::TextureCubeArrayView(numLevels, view.getLevels()+clampedBase);
146e5c31af7Sopenharmony_ci}
147e5c31af7Sopenharmony_ci
148e5c31af7Sopenharmony_ciinline float linearInterpolate (float t, float minVal, float maxVal)
149e5c31af7Sopenharmony_ci{
150e5c31af7Sopenharmony_ci	return minVal + (maxVal - minVal) * t;
151e5c31af7Sopenharmony_ci}
152e5c31af7Sopenharmony_ci
153e5c31af7Sopenharmony_ciinline tcu::Vec4 linearInterpolate (float t, const tcu::Vec4& a, const tcu::Vec4& b)
154e5c31af7Sopenharmony_ci{
155e5c31af7Sopenharmony_ci	return a + (b - a) * t;
156e5c31af7Sopenharmony_ci}
157e5c31af7Sopenharmony_ci
158e5c31af7Sopenharmony_ciinline float bilinearInterpolate (float x, float y, const tcu::Vec4& quad)
159e5c31af7Sopenharmony_ci{
160e5c31af7Sopenharmony_ci	float w00 = (1.0f-x)*(1.0f-y);
161e5c31af7Sopenharmony_ci	float w01 = (1.0f-x)*y;
162e5c31af7Sopenharmony_ci	float w10 = x*(1.0f-y);
163e5c31af7Sopenharmony_ci	float w11 = x*y;
164e5c31af7Sopenharmony_ci	return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11;
165e5c31af7Sopenharmony_ci}
166e5c31af7Sopenharmony_ci
167e5c31af7Sopenharmony_cifloat triangleInterpolate (float v0, float v1, float v2, float x, float y)
168e5c31af7Sopenharmony_ci{
169e5c31af7Sopenharmony_ci	return v0 + (v2-v0)*x + (v1-v0)*y;
170e5c31af7Sopenharmony_ci}
171e5c31af7Sopenharmony_ci
172e5c31af7Sopenharmony_cifloat triangleInterpolate (const tcu::Vec3& v, float x, float y)
173e5c31af7Sopenharmony_ci{
174e5c31af7Sopenharmony_ci	return triangleInterpolate(v.x(), v.y(), v.z(), x, y);
175e5c31af7Sopenharmony_ci}
176e5c31af7Sopenharmony_ci
177e5c31af7Sopenharmony_ci// 1D lookup LOD computation.
178e5c31af7Sopenharmony_ci
179e5c31af7Sopenharmony_cifloat computeLodFromDerivates (LodMode mode, float dudx, float dudy)
180e5c31af7Sopenharmony_ci{
181e5c31af7Sopenharmony_ci	float p = 0.0f;
182e5c31af7Sopenharmony_ci	switch (mode)
183e5c31af7Sopenharmony_ci	{
184e5c31af7Sopenharmony_ci		// \note [mika] Min and max bounds equal to exact with 1D textures
185e5c31af7Sopenharmony_ci		case LODMODE_EXACT:
186e5c31af7Sopenharmony_ci		case LODMODE_MIN_BOUND:
187e5c31af7Sopenharmony_ci		case LODMODE_MAX_BOUND:
188e5c31af7Sopenharmony_ci			p = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
189e5c31af7Sopenharmony_ci			break;
190e5c31af7Sopenharmony_ci
191e5c31af7Sopenharmony_ci		default:
192e5c31af7Sopenharmony_ci			DE_ASSERT(DE_FALSE);
193e5c31af7Sopenharmony_ci	}
194e5c31af7Sopenharmony_ci
195e5c31af7Sopenharmony_ci	return deFloatLog2(p);
196e5c31af7Sopenharmony_ci}
197e5c31af7Sopenharmony_ci
198e5c31af7Sopenharmony_cifloat computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, deInt32 srcSize, const tcu::Vec3& sq)
199e5c31af7Sopenharmony_ci{
200e5c31af7Sopenharmony_ci	float dux	= (sq.z() - sq.x()) * (float)srcSize;
201e5c31af7Sopenharmony_ci	float duy	= (sq.y() - sq.x()) * (float)srcSize;
202e5c31af7Sopenharmony_ci	float dx	= (float)dstSize.x();
203e5c31af7Sopenharmony_ci	float dy	= (float)dstSize.y();
204e5c31af7Sopenharmony_ci
205e5c31af7Sopenharmony_ci	return computeLodFromDerivates(mode, dux/dx, duy/dy);
206e5c31af7Sopenharmony_ci}
207e5c31af7Sopenharmony_ci
208e5c31af7Sopenharmony_ci// 2D lookup LOD computation.
209e5c31af7Sopenharmony_ci
210e5c31af7Sopenharmony_cifloat computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dudy, float dvdy)
211e5c31af7Sopenharmony_ci{
212e5c31af7Sopenharmony_ci	float p = 0.0f;
213e5c31af7Sopenharmony_ci	switch (mode)
214e5c31af7Sopenharmony_ci	{
215e5c31af7Sopenharmony_ci		case LODMODE_EXACT:
216e5c31af7Sopenharmony_ci			p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx), deFloatSqrt(dudy*dudy + dvdy*dvdy));
217e5c31af7Sopenharmony_ci			break;
218e5c31af7Sopenharmony_ci
219e5c31af7Sopenharmony_ci		case LODMODE_MIN_BOUND:
220e5c31af7Sopenharmony_ci		case LODMODE_MAX_BOUND:
221e5c31af7Sopenharmony_ci		{
222e5c31af7Sopenharmony_ci			float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
223e5c31af7Sopenharmony_ci			float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
224e5c31af7Sopenharmony_ci
225e5c31af7Sopenharmony_ci			p = mode == LODMODE_MIN_BOUND ? de::max(mu, mv) : mu + mv;
226e5c31af7Sopenharmony_ci			break;
227e5c31af7Sopenharmony_ci		}
228e5c31af7Sopenharmony_ci
229e5c31af7Sopenharmony_ci		default:
230e5c31af7Sopenharmony_ci			DE_ASSERT(DE_FALSE);
231e5c31af7Sopenharmony_ci	}
232e5c31af7Sopenharmony_ci
233e5c31af7Sopenharmony_ci	return deFloatLog2(p);
234e5c31af7Sopenharmony_ci}
235e5c31af7Sopenharmony_ci
236e5c31af7Sopenharmony_cifloat computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec2& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq)
237e5c31af7Sopenharmony_ci{
238e5c31af7Sopenharmony_ci	float dux	= (sq.z() - sq.x()) * (float)srcSize.x();
239e5c31af7Sopenharmony_ci	float duy	= (sq.y() - sq.x()) * (float)srcSize.x();
240e5c31af7Sopenharmony_ci	float dvx	= (tq.z() - tq.x()) * (float)srcSize.y();
241e5c31af7Sopenharmony_ci	float dvy	= (tq.y() - tq.x()) * (float)srcSize.y();
242e5c31af7Sopenharmony_ci	float dx	= (float)dstSize.x();
243e5c31af7Sopenharmony_ci	float dy	= (float)dstSize.y();
244e5c31af7Sopenharmony_ci
245e5c31af7Sopenharmony_ci	return computeLodFromDerivates(mode, dux/dx, dvx/dx, duy/dy, dvy/dy);
246e5c31af7Sopenharmony_ci}
247e5c31af7Sopenharmony_ci
248e5c31af7Sopenharmony_ci// 3D lookup LOD computation.
249e5c31af7Sopenharmony_ci
250e5c31af7Sopenharmony_cifloat computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dwdx, float dudy, float dvdy, float dwdy)
251e5c31af7Sopenharmony_ci{
252e5c31af7Sopenharmony_ci	float p = 0.0f;
253e5c31af7Sopenharmony_ci	switch (mode)
254e5c31af7Sopenharmony_ci	{
255e5c31af7Sopenharmony_ci		case LODMODE_EXACT:
256e5c31af7Sopenharmony_ci			p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx + dwdx*dwdx), deFloatSqrt(dudy*dudy + dvdy*dvdy + dwdy*dwdy));
257e5c31af7Sopenharmony_ci			break;
258e5c31af7Sopenharmony_ci
259e5c31af7Sopenharmony_ci		case LODMODE_MIN_BOUND:
260e5c31af7Sopenharmony_ci		case LODMODE_MAX_BOUND:
261e5c31af7Sopenharmony_ci		{
262e5c31af7Sopenharmony_ci			float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
263e5c31af7Sopenharmony_ci			float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
264e5c31af7Sopenharmony_ci			float mw = de::max(deFloatAbs(dwdx), deFloatAbs(dwdy));
265e5c31af7Sopenharmony_ci
266e5c31af7Sopenharmony_ci			p = mode == LODMODE_MIN_BOUND ? de::max(de::max(mu, mv), mw) : (mu + mv + mw);
267e5c31af7Sopenharmony_ci			break;
268e5c31af7Sopenharmony_ci		}
269e5c31af7Sopenharmony_ci
270e5c31af7Sopenharmony_ci		default:
271e5c31af7Sopenharmony_ci			DE_ASSERT(DE_FALSE);
272e5c31af7Sopenharmony_ci	}
273e5c31af7Sopenharmony_ci
274e5c31af7Sopenharmony_ci	return deFloatLog2(p);
275e5c31af7Sopenharmony_ci}
276e5c31af7Sopenharmony_ci
277e5c31af7Sopenharmony_cifloat computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec3& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq, const tcu::Vec3& rq)
278e5c31af7Sopenharmony_ci{
279e5c31af7Sopenharmony_ci	float dux	= (sq.z() - sq.x()) * (float)srcSize.x();
280e5c31af7Sopenharmony_ci	float duy	= (sq.y() - sq.x()) * (float)srcSize.x();
281e5c31af7Sopenharmony_ci	float dvx	= (tq.z() - tq.x()) * (float)srcSize.y();
282e5c31af7Sopenharmony_ci	float dvy	= (tq.y() - tq.x()) * (float)srcSize.y();
283e5c31af7Sopenharmony_ci	float dwx	= (rq.z() - rq.x()) * (float)srcSize.z();
284e5c31af7Sopenharmony_ci	float dwy	= (rq.y() - rq.x()) * (float)srcSize.z();
285e5c31af7Sopenharmony_ci	float dx	= (float)dstSize.x();
286e5c31af7Sopenharmony_ci	float dy	= (float)dstSize.y();
287e5c31af7Sopenharmony_ci
288e5c31af7Sopenharmony_ci	return computeLodFromDerivates(mode, dux/dx, dvx/dx, dwx/dx, duy/dy, dvy/dy, dwy/dy);
289e5c31af7Sopenharmony_ci}
290e5c31af7Sopenharmony_ci
291e5c31af7Sopenharmony_cistatic inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
292e5c31af7Sopenharmony_ci{
293e5c31af7Sopenharmony_ci	return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]);
294e5c31af7Sopenharmony_ci}
295e5c31af7Sopenharmony_ci
296e5c31af7Sopenharmony_cistatic inline float triDerivateX (const tcu::Vec3& s, const tcu::Vec3& w, float wx, float width, float ny)
297e5c31af7Sopenharmony_ci{
298e5c31af7Sopenharmony_ci	float d = w[1]*w[2]*(width*(ny - 1.0f) + wx) - w[0]*(w[2]*width*ny + w[1]*wx);
299e5c31af7Sopenharmony_ci	return (w[0]*w[1]*w[2]*width * (w[1]*(s[0] - s[2])*(ny - 1.0f) + ny*(w[2]*(s[1] - s[0]) + w[0]*(s[2] - s[1])))) / (d*d);
300e5c31af7Sopenharmony_ci}
301e5c31af7Sopenharmony_ci
302e5c31af7Sopenharmony_cistatic inline float triDerivateY (const tcu::Vec3& s, const tcu::Vec3& w, float wy, float height, float nx)
303e5c31af7Sopenharmony_ci{
304e5c31af7Sopenharmony_ci	float d = w[1]*w[2]*(height*(nx - 1.0f) + wy) - w[0]*(w[1]*height*nx + w[2]*wy);
305e5c31af7Sopenharmony_ci	return (w[0]*w[1]*w[2]*height * (w[2]*(s[0] - s[1])*(nx - 1.0f) + nx*(w[0]*(s[1] - s[2]) + w[1]*(s[2] - s[0])))) / (d*d);
306e5c31af7Sopenharmony_ci}
307e5c31af7Sopenharmony_ci
308e5c31af7Sopenharmony_ci// 1D lookup LOD.
309e5c31af7Sopenharmony_cistatic float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& projection, float wx, float wy, float width, float height)
310e5c31af7Sopenharmony_ci{
311e5c31af7Sopenharmony_ci	// Exact derivatives.
312e5c31af7Sopenharmony_ci	float dudx	= triDerivateX(u, projection, wx, width, wy/height);
313e5c31af7Sopenharmony_ci	float dudy	= triDerivateY(u, projection, wy, height, wx/width);
314e5c31af7Sopenharmony_ci
315e5c31af7Sopenharmony_ci	return computeLodFromDerivates(mode, dudx, dudy);
316e5c31af7Sopenharmony_ci}
317e5c31af7Sopenharmony_ci
318e5c31af7Sopenharmony_ci// 2D lookup LOD.
319e5c31af7Sopenharmony_cistatic float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& projection, float wx, float wy, float width, float height)
320e5c31af7Sopenharmony_ci{
321e5c31af7Sopenharmony_ci	// Exact derivatives.
322e5c31af7Sopenharmony_ci	float dudx	= triDerivateX(u, projection, wx, width, wy/height);
323e5c31af7Sopenharmony_ci	float dvdx	= triDerivateX(v, projection, wx, width, wy/height);
324e5c31af7Sopenharmony_ci	float dudy	= triDerivateY(u, projection, wy, height, wx/width);
325e5c31af7Sopenharmony_ci	float dvdy	= triDerivateY(v, projection, wy, height, wx/width);
326e5c31af7Sopenharmony_ci
327e5c31af7Sopenharmony_ci	return computeLodFromDerivates(mode, dudx, dvdx, dudy, dvdy);
328e5c31af7Sopenharmony_ci}
329e5c31af7Sopenharmony_ci
330e5c31af7Sopenharmony_ci// 3D lookup LOD.
331e5c31af7Sopenharmony_cistatic float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& w, const tcu::Vec3& projection, float wx, float wy, float width, float height)
332e5c31af7Sopenharmony_ci{
333e5c31af7Sopenharmony_ci	// Exact derivatives.
334e5c31af7Sopenharmony_ci	float dudx	= triDerivateX(u, projection, wx, width, wy/height);
335e5c31af7Sopenharmony_ci	float dvdx	= triDerivateX(v, projection, wx, width, wy/height);
336e5c31af7Sopenharmony_ci	float dwdx	= triDerivateX(w, projection, wx, width, wy/height);
337e5c31af7Sopenharmony_ci	float dudy	= triDerivateY(u, projection, wy, height, wx/width);
338e5c31af7Sopenharmony_ci	float dvdy	= triDerivateY(v, projection, wy, height, wx/width);
339e5c31af7Sopenharmony_ci	float dwdy	= triDerivateY(w, projection, wy, height, wx/width);
340e5c31af7Sopenharmony_ci
341e5c31af7Sopenharmony_ci	return computeLodFromDerivates(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy);
342e5c31af7Sopenharmony_ci}
343e5c31af7Sopenharmony_ci
344e5c31af7Sopenharmony_cistatic inline tcu::Vec4 execSample (const tcu::Texture1DView& src, const ReferenceParams& params, float s, float lod)
345e5c31af7Sopenharmony_ci{
346e5c31af7Sopenharmony_ci	if (params.samplerType == SAMPLERTYPE_SHADOW)
347e5c31af7Sopenharmony_ci		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, lod), 0.0, 0.0, 1.0f);
348e5c31af7Sopenharmony_ci	else
349e5c31af7Sopenharmony_ci		return src.sample(params.sampler, s, lod);
350e5c31af7Sopenharmony_ci}
351e5c31af7Sopenharmony_ci
352e5c31af7Sopenharmony_cistatic inline tcu::Vec4 execSample (const tcu::Texture2DView& src, const ReferenceParams& params, float s, float t, float lod)
353e5c31af7Sopenharmony_ci{
354e5c31af7Sopenharmony_ci	if (params.samplerType == SAMPLERTYPE_SHADOW)
355e5c31af7Sopenharmony_ci		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
356e5c31af7Sopenharmony_ci	else
357e5c31af7Sopenharmony_ci		return src.sample(params.sampler, s, t, lod);
358e5c31af7Sopenharmony_ci}
359e5c31af7Sopenharmony_ci
360e5c31af7Sopenharmony_cistatic inline tcu::Vec4 execSample (const tcu::TextureCubeView& src, const ReferenceParams& params, float s, float t, float r, float lod)
361e5c31af7Sopenharmony_ci{
362e5c31af7Sopenharmony_ci	if (params.samplerType == SAMPLERTYPE_SHADOW)
363e5c31af7Sopenharmony_ci		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
364e5c31af7Sopenharmony_ci	else
365e5c31af7Sopenharmony_ci		return src.sample(params.sampler, s, t, r, lod);
366e5c31af7Sopenharmony_ci}
367e5c31af7Sopenharmony_ci
368e5c31af7Sopenharmony_cistatic inline tcu::Vec4 execSample (const tcu::Texture2DArrayView& src, const ReferenceParams& params, float s, float t, float r, float lod)
369e5c31af7Sopenharmony_ci{
370e5c31af7Sopenharmony_ci	if (params.samplerType == SAMPLERTYPE_SHADOW)
371e5c31af7Sopenharmony_ci		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
372e5c31af7Sopenharmony_ci	else
373e5c31af7Sopenharmony_ci		return src.sample(params.sampler, s, t, r, lod);
374e5c31af7Sopenharmony_ci}
375e5c31af7Sopenharmony_ci
376e5c31af7Sopenharmony_cistatic inline tcu::Vec4 execSample (const tcu::TextureCubeArrayView& src, const ReferenceParams& params, float s, float t, float r, float q, float lod)
377e5c31af7Sopenharmony_ci{
378e5c31af7Sopenharmony_ci	if (params.samplerType == SAMPLERTYPE_SHADOW)
379e5c31af7Sopenharmony_ci		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, q, lod), 0.0, 0.0, 1.0f);
380e5c31af7Sopenharmony_ci	else
381e5c31af7Sopenharmony_ci		return src.sample(params.sampler, s, t, r, q, lod);
382e5c31af7Sopenharmony_ci}
383e5c31af7Sopenharmony_ci
384e5c31af7Sopenharmony_cistatic inline tcu::Vec4 execSample (const tcu::Texture1DArrayView& src, const ReferenceParams& params, float s, float t, float lod)
385e5c31af7Sopenharmony_ci{
386e5c31af7Sopenharmony_ci	if (params.samplerType == SAMPLERTYPE_SHADOW)
387e5c31af7Sopenharmony_ci		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
388e5c31af7Sopenharmony_ci	else
389e5c31af7Sopenharmony_ci		return src.sample(params.sampler, s, t, lod);
390e5c31af7Sopenharmony_ci}
391e5c31af7Sopenharmony_ci
392e5c31af7Sopenharmony_cistatic void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
393e5c31af7Sopenharmony_ci{
394e5c31af7Sopenharmony_ci	// Separate combined DS formats
395e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
396e5c31af7Sopenharmony_ci	const tcu::Texture1DView					src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
397e5c31af7Sopenharmony_ci
398e5c31af7Sopenharmony_ci	float										lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
399e5c31af7Sopenharmony_ci
400e5c31af7Sopenharmony_ci	tcu::IVec2									dstSize				= tcu::IVec2(dst.getWidth(), dst.getHeight());
401e5c31af7Sopenharmony_ci	int											srcSize				= src.getWidth();
402e5c31af7Sopenharmony_ci
403e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
404e5c31af7Sopenharmony_ci	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
405e5c31af7Sopenharmony_ci	float										triLod[2]			= { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, params.minLod, params.maxLod),
406e5c31af7Sopenharmony_ci																		de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias, params.minLod, params.maxLod) };
407e5c31af7Sopenharmony_ci
408e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
409e5c31af7Sopenharmony_ci	{
410e5c31af7Sopenharmony_ci		for (int x = 0; x < dst.getWidth(); x++)
411e5c31af7Sopenharmony_ci		{
412e5c31af7Sopenharmony_ci			float	yf		= ((float)y + 0.5f) / (float)dst.getHeight();
413e5c31af7Sopenharmony_ci			float	xf		= ((float)x + 0.5f) / (float)dst.getWidth();
414e5c31af7Sopenharmony_ci
415e5c31af7Sopenharmony_ci			int		triNdx	= xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
416e5c31af7Sopenharmony_ci			float	triX	= triNdx ? 1.0f-xf : xf;
417e5c31af7Sopenharmony_ci			float	triY	= triNdx ? 1.0f-yf : yf;
418e5c31af7Sopenharmony_ci
419e5c31af7Sopenharmony_ci			float	s		= triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
420e5c31af7Sopenharmony_ci			float	lod		= triLod[triNdx];
421e5c31af7Sopenharmony_ci
422e5c31af7Sopenharmony_ci			dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y);
423e5c31af7Sopenharmony_ci		}
424e5c31af7Sopenharmony_ci	}
425e5c31af7Sopenharmony_ci}
426e5c31af7Sopenharmony_ci
427e5c31af7Sopenharmony_citemplate<class PixelAccess>
428e5c31af7Sopenharmony_cistatic void sampleTextureNonProjected (const PixelAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
429e5c31af7Sopenharmony_ci{
430e5c31af7Sopenharmony_ci	// Separate combined DS formats
431e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
432e5c31af7Sopenharmony_ci	tcu::Texture2DView							src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
433e5c31af7Sopenharmony_ci
434e5c31af7Sopenharmony_ci	float										lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
435e5c31af7Sopenharmony_ci
436e5c31af7Sopenharmony_ci	tcu::IVec2									dstSize				= tcu::IVec2(dst.getWidth(), dst.getHeight());
437e5c31af7Sopenharmony_ci	tcu::IVec2									srcSize				= tcu::IVec2(src.getWidth(), src.getHeight());
438e5c31af7Sopenharmony_ci
439e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
440e5c31af7Sopenharmony_ci	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
441e5c31af7Sopenharmony_ci	tcu::Vec3									triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
442e5c31af7Sopenharmony_ci	float										triLod[2]			= { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
443e5c31af7Sopenharmony_ci																		de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
444e5c31af7Sopenharmony_ci
445e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
446e5c31af7Sopenharmony_ci	{
447e5c31af7Sopenharmony_ci		for (int x = 0; x < dst.getWidth(); x++)
448e5c31af7Sopenharmony_ci		{
449e5c31af7Sopenharmony_ci			float	yf		= ((float)y + 0.5f) / (float)dst.getHeight();
450e5c31af7Sopenharmony_ci			float	xf		= ((float)x + 0.5f) / (float)dst.getWidth();
451e5c31af7Sopenharmony_ci
452e5c31af7Sopenharmony_ci			int		triNdx	= xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
453e5c31af7Sopenharmony_ci			float	triX	= triNdx ? 1.0f-xf : xf;
454e5c31af7Sopenharmony_ci			float	triY	= triNdx ? 1.0f-yf : yf;
455e5c31af7Sopenharmony_ci
456e5c31af7Sopenharmony_ci			float	s		= triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
457e5c31af7Sopenharmony_ci			float	t		= triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
458e5c31af7Sopenharmony_ci			float	lod		= triLod[triNdx];
459e5c31af7Sopenharmony_ci
460e5c31af7Sopenharmony_ci			if (params.imageViewMinLod != 0.0f && params.samplerType == SAMPLERTYPE_FETCH_FLOAT)
461e5c31af7Sopenharmony_ci				lod = (float)params.lodTexelFetch;
462e5c31af7Sopenharmony_ci
463e5c31af7Sopenharmony_ci			if (params.float16TexCoord)
464e5c31af7Sopenharmony_ci			{
465e5c31af7Sopenharmony_ci				s   = tcu::Float16(s, tcu::ROUND_TO_ZERO).asFloat();
466e5c31af7Sopenharmony_ci				t   = tcu::Float16(t, tcu::ROUND_TO_ZERO).asFloat();
467e5c31af7Sopenharmony_ci			}
468e5c31af7Sopenharmony_ci
469e5c31af7Sopenharmony_ci			dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
470e5c31af7Sopenharmony_ci		}
471e5c31af7Sopenharmony_ci	}
472e5c31af7Sopenharmony_ci}
473e5c31af7Sopenharmony_ci
474e5c31af7Sopenharmony_cistatic void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
475e5c31af7Sopenharmony_ci{
476e5c31af7Sopenharmony_ci	// Separate combined DS formats
477e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
478e5c31af7Sopenharmony_ci	const tcu::Texture1DView					src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
479e5c31af7Sopenharmony_ci
480e5c31af7Sopenharmony_ci	float										lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
481e5c31af7Sopenharmony_ci	float										dstW				= (float)dst.getWidth();
482e5c31af7Sopenharmony_ci	float										dstH				= (float)dst.getHeight();
483e5c31af7Sopenharmony_ci
484e5c31af7Sopenharmony_ci	tcu::Vec4									uq					= sq * (float)src.getWidth();
485e5c31af7Sopenharmony_ci
486e5c31af7Sopenharmony_ci	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
487e5c31af7Sopenharmony_ci	tcu::Vec3									triU[2]				= { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
488e5c31af7Sopenharmony_ci	tcu::Vec3									triW[2]				= { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
489e5c31af7Sopenharmony_ci
490e5c31af7Sopenharmony_ci	for (int py = 0; py < dst.getHeight(); py++)
491e5c31af7Sopenharmony_ci	{
492e5c31af7Sopenharmony_ci		for (int px = 0; px < dst.getWidth(); px++)
493e5c31af7Sopenharmony_ci		{
494e5c31af7Sopenharmony_ci			float	wx		= (float)px + 0.5f;
495e5c31af7Sopenharmony_ci			float	wy		= (float)py + 0.5f;
496e5c31af7Sopenharmony_ci			float	nx		= wx / dstW;
497e5c31af7Sopenharmony_ci			float	ny		= wy / dstH;
498e5c31af7Sopenharmony_ci
499e5c31af7Sopenharmony_ci			int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
500e5c31af7Sopenharmony_ci			float	triWx	= triNdx ? dstW - wx : wx;
501e5c31af7Sopenharmony_ci			float	triWy	= triNdx ? dstH - wy : wy;
502e5c31af7Sopenharmony_ci			float	triNx	= triNdx ? 1.0f - nx : nx;
503e5c31af7Sopenharmony_ci			float	triNy	= triNdx ? 1.0f - ny : ny;
504e5c31af7Sopenharmony_ci
505e5c31af7Sopenharmony_ci			float	s		= projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
506e5c31af7Sopenharmony_ci			float	lod		= computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
507e5c31af7Sopenharmony_ci							+ lodBias;
508e5c31af7Sopenharmony_ci
509e5c31af7Sopenharmony_ci			dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py);
510e5c31af7Sopenharmony_ci		}
511e5c31af7Sopenharmony_ci	}
512e5c31af7Sopenharmony_ci}
513e5c31af7Sopenharmony_ci
514e5c31af7Sopenharmony_citemplate<class PixelAccess>
515e5c31af7Sopenharmony_cistatic void sampleTextureProjected (const PixelAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
516e5c31af7Sopenharmony_ci{
517e5c31af7Sopenharmony_ci	// Separate combined DS formats
518e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
519e5c31af7Sopenharmony_ci	const tcu::Texture2DView					src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
520e5c31af7Sopenharmony_ci
521e5c31af7Sopenharmony_ci	float										lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
522e5c31af7Sopenharmony_ci	float										dstW				= (float)dst.getWidth();
523e5c31af7Sopenharmony_ci	float										dstH				= (float)dst.getHeight();
524e5c31af7Sopenharmony_ci
525e5c31af7Sopenharmony_ci	tcu::Vec4									uq					= sq * (float)src.getWidth();
526e5c31af7Sopenharmony_ci	tcu::Vec4									vq					= tq * (float)src.getHeight();
527e5c31af7Sopenharmony_ci
528e5c31af7Sopenharmony_ci	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
529e5c31af7Sopenharmony_ci	tcu::Vec3									triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
530e5c31af7Sopenharmony_ci	tcu::Vec3									triU[2]				= { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
531e5c31af7Sopenharmony_ci	tcu::Vec3									triV[2]				= { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
532e5c31af7Sopenharmony_ci	tcu::Vec3									triW[2]				= { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
533e5c31af7Sopenharmony_ci
534e5c31af7Sopenharmony_ci	for (int py = 0; py < dst.getHeight(); py++)
535e5c31af7Sopenharmony_ci	{
536e5c31af7Sopenharmony_ci		for (int px = 0; px < dst.getWidth(); px++)
537e5c31af7Sopenharmony_ci		{
538e5c31af7Sopenharmony_ci			float	wx		= (float)px + 0.5f;
539e5c31af7Sopenharmony_ci			float	wy		= (float)py + 0.5f;
540e5c31af7Sopenharmony_ci			float	nx		= wx / dstW;
541e5c31af7Sopenharmony_ci			float	ny		= wy / dstH;
542e5c31af7Sopenharmony_ci
543e5c31af7Sopenharmony_ci			int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
544e5c31af7Sopenharmony_ci			float	triWx	= triNdx ? dstW - wx : wx;
545e5c31af7Sopenharmony_ci			float	triWy	= triNdx ? dstH - wy : wy;
546e5c31af7Sopenharmony_ci			float	triNx	= triNdx ? 1.0f - nx : nx;
547e5c31af7Sopenharmony_ci			float	triNy	= triNdx ? 1.0f - ny : ny;
548e5c31af7Sopenharmony_ci
549e5c31af7Sopenharmony_ci			float	s		= projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
550e5c31af7Sopenharmony_ci			float	t		= projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
551e5c31af7Sopenharmony_ci			float	lod		= computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
552e5c31af7Sopenharmony_ci							+ lodBias;
553e5c31af7Sopenharmony_ci
554e5c31af7Sopenharmony_ci			dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py);
555e5c31af7Sopenharmony_ci		}
556e5c31af7Sopenharmony_ci	}
557e5c31af7Sopenharmony_ci}
558e5c31af7Sopenharmony_ci
559e5c31af7Sopenharmony_civoid sampleTexture (const tcu::PixelBufferAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params)
560e5c31af7Sopenharmony_ci{
561e5c31af7Sopenharmony_ci	tcu::ImageViewMinLodParams	minLodParams =
562e5c31af7Sopenharmony_ci	{
563e5c31af7Sopenharmony_ci		params.baseLevel,								// int		baseLevel;
564e5c31af7Sopenharmony_ci		{
565e5c31af7Sopenharmony_ci			params.imageViewMinLod,							// float	minLod;
566e5c31af7Sopenharmony_ci			params.imageViewMinLodMode,						// ImageViewMinLodMode
567e5c31af7Sopenharmony_ci		},
568e5c31af7Sopenharmony_ci		params.samplerType == SAMPLERTYPE_FETCH_FLOAT	// bool	intTexCoord;
569e5c31af7Sopenharmony_ci	};
570e5c31af7Sopenharmony_ci
571e5c31af7Sopenharmony_ci	const tcu::Texture2DView	view	= getSubView(src, params.baseLevel, params.maxLevel, params.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
572e5c31af7Sopenharmony_ci	const tcu::Vec4				sq		= tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
573e5c31af7Sopenharmony_ci	const tcu::Vec4				tq		= tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
574e5c31af7Sopenharmony_ci
575e5c31af7Sopenharmony_ci	if (params.flags & ReferenceParams::PROJECTED)
576e5c31af7Sopenharmony_ci		sampleTextureProjected(dst, view, sq, tq, params);
577e5c31af7Sopenharmony_ci	else
578e5c31af7Sopenharmony_ci		sampleTextureNonProjected(dst, view, sq, tq, params);
579e5c31af7Sopenharmony_ci}
580e5c31af7Sopenharmony_ci
581e5c31af7Sopenharmony_civoid sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params)
582e5c31af7Sopenharmony_ci{
583e5c31af7Sopenharmony_ci	tcu::ImageViewMinLodParams	minLodParams =
584e5c31af7Sopenharmony_ci	{
585e5c31af7Sopenharmony_ci		params.baseLevel,								// int		baseLevel;
586e5c31af7Sopenharmony_ci		{
587e5c31af7Sopenharmony_ci			params.imageViewMinLod,							// float	minLod;
588e5c31af7Sopenharmony_ci			params.imageViewMinLodMode,						// ImageViewMinLodMode
589e5c31af7Sopenharmony_ci		},
590e5c31af7Sopenharmony_ci		params.samplerType == SAMPLERTYPE_FETCH_FLOAT	// bool		intTexCoord;
591e5c31af7Sopenharmony_ci	};
592e5c31af7Sopenharmony_ci
593e5c31af7Sopenharmony_ci	const tcu::Texture2DView	view	= getSubView(src, params.baseLevel, params.maxLevel, params.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
594e5c31af7Sopenharmony_ci	const tcu::Vec4				sq		= tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
595e5c31af7Sopenharmony_ci	const tcu::Vec4				tq		= tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
596e5c31af7Sopenharmony_ci
597e5c31af7Sopenharmony_ci	if (params.flags & ReferenceParams::PROJECTED)
598e5c31af7Sopenharmony_ci		sampleTextureProjected(dst, view, sq, tq, params);
599e5c31af7Sopenharmony_ci	else
600e5c31af7Sopenharmony_ci		sampleTextureNonProjected(dst, view, sq, tq, params);
601e5c31af7Sopenharmony_ci}
602e5c31af7Sopenharmony_ci
603e5c31af7Sopenharmony_civoid sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& src, const float* texCoord, const ReferenceParams& params)
604e5c31af7Sopenharmony_ci{
605e5c31af7Sopenharmony_ci	const tcu::Texture1DView	view	= getSubView(src, params.baseLevel, params.maxLevel, DE_NULL);
606e5c31af7Sopenharmony_ci	const tcu::Vec4				sq		= tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
607e5c31af7Sopenharmony_ci
608e5c31af7Sopenharmony_ci	if (params.flags & ReferenceParams::PROJECTED)
609e5c31af7Sopenharmony_ci		sampleTextureProjected(dst, view, sq, params);
610e5c31af7Sopenharmony_ci	else
611e5c31af7Sopenharmony_ci		sampleTextureNonProjected(dst, view, sq, params);
612e5c31af7Sopenharmony_ci}
613e5c31af7Sopenharmony_ci
614e5c31af7Sopenharmony_cistatic float computeCubeLodFromDerivates (LodMode lodMode, const tcu::Vec3& coord, const tcu::Vec3& coordDx, const tcu::Vec3& coordDy, const int faceSize)
615e5c31af7Sopenharmony_ci{
616e5c31af7Sopenharmony_ci	const tcu::CubeFace	face	= tcu::selectCubeFace(coord);
617e5c31af7Sopenharmony_ci	int					maNdx	= 0;
618e5c31af7Sopenharmony_ci	int					sNdx	= 0;
619e5c31af7Sopenharmony_ci	int					tNdx	= 0;
620e5c31af7Sopenharmony_ci
621e5c31af7Sopenharmony_ci	// \note Derivate signs don't matter when computing lod
622e5c31af7Sopenharmony_ci	switch (face)
623e5c31af7Sopenharmony_ci	{
624e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_X:
625e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
626e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_Y:
627e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
628e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_Z:
629e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
630e5c31af7Sopenharmony_ci		default:
631e5c31af7Sopenharmony_ci			DE_ASSERT(DE_FALSE);
632e5c31af7Sopenharmony_ci	}
633e5c31af7Sopenharmony_ci
634e5c31af7Sopenharmony_ci	{
635e5c31af7Sopenharmony_ci		const float		sc		= coord[sNdx];
636e5c31af7Sopenharmony_ci		const float		tc		= coord[tNdx];
637e5c31af7Sopenharmony_ci		const float		ma		= de::abs(coord[maNdx]);
638e5c31af7Sopenharmony_ci		const float		scdx	= coordDx[sNdx];
639e5c31af7Sopenharmony_ci		const float		tcdx	= coordDx[tNdx];
640e5c31af7Sopenharmony_ci		const float		madx	= de::abs(coordDx[maNdx]);
641e5c31af7Sopenharmony_ci		const float		scdy	= coordDy[sNdx];
642e5c31af7Sopenharmony_ci		const float		tcdy	= coordDy[tNdx];
643e5c31af7Sopenharmony_ci		const float		mady	= de::abs(coordDy[maNdx]);
644e5c31af7Sopenharmony_ci		const float		dudx	= float(faceSize) * 0.5f * (scdx*ma - sc*madx) / (ma*ma);
645e5c31af7Sopenharmony_ci		const float		dvdx	= float(faceSize) * 0.5f * (tcdx*ma - tc*madx) / (ma*ma);
646e5c31af7Sopenharmony_ci		const float		dudy	= float(faceSize) * 0.5f * (scdy*ma - sc*mady) / (ma*ma);
647e5c31af7Sopenharmony_ci		const float		dvdy	= float(faceSize) * 0.5f * (tcdy*ma - tc*mady) / (ma*ma);
648e5c31af7Sopenharmony_ci
649e5c31af7Sopenharmony_ci		return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy);
650e5c31af7Sopenharmony_ci	}
651e5c31af7Sopenharmony_ci}
652e5c31af7Sopenharmony_ci
653e5c31af7Sopenharmony_cistatic void sampleTextureCube (const tcu::SurfaceAccess& dst, const tcu::TextureCubeView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
654e5c31af7Sopenharmony_ci{
655e5c31af7Sopenharmony_ci	// Separate combined DS formats
656e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
657e5c31af7Sopenharmony_ci	const tcu::TextureCubeView					src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
658e5c31af7Sopenharmony_ci
659e5c31af7Sopenharmony_ci	const tcu::IVec2							dstSize				= tcu::IVec2(dst.getWidth(), dst.getHeight());
660e5c31af7Sopenharmony_ci	const float									dstW				= float(dstSize.x());
661e5c31af7Sopenharmony_ci	const float									dstH				= float(dstSize.y());
662e5c31af7Sopenharmony_ci	const int									srcSize				= src.getSize();
663e5c31af7Sopenharmony_ci
664e5c31af7Sopenharmony_ci	// Coordinates per triangle.
665e5c31af7Sopenharmony_ci	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
666e5c31af7Sopenharmony_ci	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
667e5c31af7Sopenharmony_ci	const tcu::Vec3								triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
668e5c31af7Sopenharmony_ci	const tcu::Vec3								triW[2]				= { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
669e5c31af7Sopenharmony_ci
670e5c31af7Sopenharmony_ci	const float									lodBias				((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f);
671e5c31af7Sopenharmony_ci
672e5c31af7Sopenharmony_ci	for (int py = 0; py < dst.getHeight(); py++)
673e5c31af7Sopenharmony_ci	{
674e5c31af7Sopenharmony_ci		for (int px = 0; px < dst.getWidth(); px++)
675e5c31af7Sopenharmony_ci		{
676e5c31af7Sopenharmony_ci			const float		wx		= (float)px + 0.5f;
677e5c31af7Sopenharmony_ci			const float		wy		= (float)py + 0.5f;
678e5c31af7Sopenharmony_ci			const float		nx		= wx / dstW;
679e5c31af7Sopenharmony_ci			const float		ny		= wy / dstH;
680e5c31af7Sopenharmony_ci
681e5c31af7Sopenharmony_ci			const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
682e5c31af7Sopenharmony_ci			const float		triNx	= triNdx ? 1.0f - nx : nx;
683e5c31af7Sopenharmony_ci			const float		triNy	= triNdx ? 1.0f - ny : ny;
684e5c31af7Sopenharmony_ci
685e5c31af7Sopenharmony_ci			const tcu::Vec3	coord		(triangleInterpolate(triS[triNdx], triNx, triNy),
686e5c31af7Sopenharmony_ci										 triangleInterpolate(triT[triNdx], triNx, triNy),
687e5c31af7Sopenharmony_ci										 triangleInterpolate(triR[triNdx], triNx, triNy));
688e5c31af7Sopenharmony_ci			const tcu::Vec3	coordDx		(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
689e5c31af7Sopenharmony_ci										 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
690e5c31af7Sopenharmony_ci										 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
691e5c31af7Sopenharmony_ci			const tcu::Vec3	coordDy		(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
692e5c31af7Sopenharmony_ci										 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
693e5c31af7Sopenharmony_ci										 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
694e5c31af7Sopenharmony_ci
695e5c31af7Sopenharmony_ci			const float		lod			= de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias, params.minLod, params.maxLod);
696e5c31af7Sopenharmony_ci
697e5c31af7Sopenharmony_ci			dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale + params.colorBias, px, py);
698e5c31af7Sopenharmony_ci		}
699e5c31af7Sopenharmony_ci	}
700e5c31af7Sopenharmony_ci}
701e5c31af7Sopenharmony_ci
702e5c31af7Sopenharmony_civoid sampleTexture (const tcu::SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params)
703e5c31af7Sopenharmony_ci{
704e5c31af7Sopenharmony_ci	tcu::ImageViewMinLodParams	minLodParams =
705e5c31af7Sopenharmony_ci	{
706e5c31af7Sopenharmony_ci		params.baseLevel,								// int		baseLevel;
707e5c31af7Sopenharmony_ci		{
708e5c31af7Sopenharmony_ci			params.imageViewMinLod,							// float	minLod;
709e5c31af7Sopenharmony_ci			params.imageViewMinLodMode,						// ImageViewMinLodMode
710e5c31af7Sopenharmony_ci		},
711e5c31af7Sopenharmony_ci		params.samplerType == SAMPLERTYPE_FETCH_FLOAT	// bool	intTexCoord;
712e5c31af7Sopenharmony_ci	};
713e5c31af7Sopenharmony_ci
714e5c31af7Sopenharmony_ci	const tcu::TextureCubeView	view	= getSubView(src, params.baseLevel, params.maxLevel, params.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
715e5c31af7Sopenharmony_ci	const tcu::Vec4				sq		= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
716e5c31af7Sopenharmony_ci	const tcu::Vec4				tq		= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
717e5c31af7Sopenharmony_ci	const tcu::Vec4				rq		= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
718e5c31af7Sopenharmony_ci
719e5c31af7Sopenharmony_ci	return sampleTextureCube(dst, view, sq, tq, rq, params);
720e5c31af7Sopenharmony_ci}
721e5c31af7Sopenharmony_ci
722e5c31af7Sopenharmony_cistatic void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture2DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
723e5c31af7Sopenharmony_ci{
724e5c31af7Sopenharmony_ci	// Separate combined DS formats
725e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
726e5c31af7Sopenharmony_ci	const tcu::Texture2DArrayView				src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
727e5c31af7Sopenharmony_ci
728e5c31af7Sopenharmony_ci	float										lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
729e5c31af7Sopenharmony_ci
730e5c31af7Sopenharmony_ci	tcu::IVec2									dstSize				= tcu::IVec2(dst.getWidth(), dst.getHeight());
731e5c31af7Sopenharmony_ci	tcu::IVec2									srcSize				= tcu::IVec2(src.getWidth(), src.getHeight());
732e5c31af7Sopenharmony_ci
733e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
734e5c31af7Sopenharmony_ci	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
735e5c31af7Sopenharmony_ci	tcu::Vec3									triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
736e5c31af7Sopenharmony_ci	tcu::Vec3									triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
737e5c31af7Sopenharmony_ci	float										triLod[2]			= { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
738e5c31af7Sopenharmony_ci																		de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
739e5c31af7Sopenharmony_ci
740e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
741e5c31af7Sopenharmony_ci	{
742e5c31af7Sopenharmony_ci		for (int x = 0; x < dst.getWidth(); x++)
743e5c31af7Sopenharmony_ci		{
744e5c31af7Sopenharmony_ci			float	yf		= ((float)y + 0.5f) / (float)dst.getHeight();
745e5c31af7Sopenharmony_ci			float	xf		= ((float)x + 0.5f) / (float)dst.getWidth();
746e5c31af7Sopenharmony_ci
747e5c31af7Sopenharmony_ci			int		triNdx	= xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
748e5c31af7Sopenharmony_ci			float	triX	= triNdx ? 1.0f-xf : xf;
749e5c31af7Sopenharmony_ci			float	triY	= triNdx ? 1.0f-yf : yf;
750e5c31af7Sopenharmony_ci
751e5c31af7Sopenharmony_ci			float	s		= triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
752e5c31af7Sopenharmony_ci			float	t		= triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
753e5c31af7Sopenharmony_ci			float	r		= triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
754e5c31af7Sopenharmony_ci			float	lod		= triLod[triNdx];
755e5c31af7Sopenharmony_ci
756e5c31af7Sopenharmony_ci			dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
757e5c31af7Sopenharmony_ci		}
758e5c31af7Sopenharmony_ci	}
759e5c31af7Sopenharmony_ci}
760e5c31af7Sopenharmony_ci
761e5c31af7Sopenharmony_civoid sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const float* texCoord, const ReferenceParams& params)
762e5c31af7Sopenharmony_ci{
763e5c31af7Sopenharmony_ci	tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
764e5c31af7Sopenharmony_ci	tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
765e5c31af7Sopenharmony_ci	tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
766e5c31af7Sopenharmony_ci
767e5c31af7Sopenharmony_ci	DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups.
768e5c31af7Sopenharmony_ci	sampleTextureNonProjected(dst, src, sq, tq, rq, params);
769e5c31af7Sopenharmony_ci}
770e5c31af7Sopenharmony_ci
771e5c31af7Sopenharmony_cistatic void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
772e5c31af7Sopenharmony_ci{
773e5c31af7Sopenharmony_ci	// Separate combined DS formats
774e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
775e5c31af7Sopenharmony_ci	const tcu::Texture1DArrayView				src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
776e5c31af7Sopenharmony_ci
777e5c31af7Sopenharmony_ci	float										lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
778e5c31af7Sopenharmony_ci
779e5c31af7Sopenharmony_ci	tcu::IVec2									dstSize				= tcu::IVec2(dst.getWidth(), dst.getHeight());
780e5c31af7Sopenharmony_ci	deInt32										srcSize				= src.getWidth();
781e5c31af7Sopenharmony_ci
782e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
783e5c31af7Sopenharmony_ci	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
784e5c31af7Sopenharmony_ci	tcu::Vec3									triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
785e5c31af7Sopenharmony_ci	float										triLod[2]			= { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
786e5c31af7Sopenharmony_ci																		computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias};
787e5c31af7Sopenharmony_ci
788e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
789e5c31af7Sopenharmony_ci	{
790e5c31af7Sopenharmony_ci		for (int x = 0; x < dst.getWidth(); x++)
791e5c31af7Sopenharmony_ci		{
792e5c31af7Sopenharmony_ci			float	yf		= ((float)y + 0.5f) / (float)dst.getHeight();
793e5c31af7Sopenharmony_ci			float	xf		= ((float)x + 0.5f) / (float)dst.getWidth();
794e5c31af7Sopenharmony_ci
795e5c31af7Sopenharmony_ci			int		triNdx	= xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
796e5c31af7Sopenharmony_ci			float	triX	= triNdx ? 1.0f-xf : xf;
797e5c31af7Sopenharmony_ci			float	triY	= triNdx ? 1.0f-yf : yf;
798e5c31af7Sopenharmony_ci
799e5c31af7Sopenharmony_ci			float	s		= triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
800e5c31af7Sopenharmony_ci			float	t		= triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
801e5c31af7Sopenharmony_ci			float	lod		= triLod[triNdx];
802e5c31af7Sopenharmony_ci
803e5c31af7Sopenharmony_ci			dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
804e5c31af7Sopenharmony_ci		}
805e5c31af7Sopenharmony_ci	}
806e5c31af7Sopenharmony_ci}
807e5c31af7Sopenharmony_ci
808e5c31af7Sopenharmony_civoid sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const float* texCoord, const ReferenceParams& params)
809e5c31af7Sopenharmony_ci{
810e5c31af7Sopenharmony_ci	tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
811e5c31af7Sopenharmony_ci	tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
812e5c31af7Sopenharmony_ci
813e5c31af7Sopenharmony_ci	DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups.
814e5c31af7Sopenharmony_ci	sampleTextureNonProjected(dst, src, sq, tq, params);
815e5c31af7Sopenharmony_ci}
816e5c31af7Sopenharmony_ci
817e5c31af7Sopenharmony_cistatic void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
818e5c31af7Sopenharmony_ci{
819e5c31af7Sopenharmony_ci	// Separate combined DS formats
820e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
821e5c31af7Sopenharmony_ci	const tcu::Texture3DView					src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
822e5c31af7Sopenharmony_ci
823e5c31af7Sopenharmony_ci	float										lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
824e5c31af7Sopenharmony_ci
825e5c31af7Sopenharmony_ci	tcu::IVec2									dstSize				= tcu::IVec2(dst.getWidth(), dst.getHeight());
826e5c31af7Sopenharmony_ci	tcu::IVec3									srcSize				= tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
827e5c31af7Sopenharmony_ci
828e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
829e5c31af7Sopenharmony_ci	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
830e5c31af7Sopenharmony_ci	tcu::Vec3									triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
831e5c31af7Sopenharmony_ci	tcu::Vec3									triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
832e5c31af7Sopenharmony_ci	float										triLod[2]			= { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias, params.minLod, params.maxLod),
833e5c31af7Sopenharmony_ci																		de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias, params.minLod, params.maxLod) };
834e5c31af7Sopenharmony_ci
835e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
836e5c31af7Sopenharmony_ci	{
837e5c31af7Sopenharmony_ci		for (int x = 0; x < dst.getWidth(); x++)
838e5c31af7Sopenharmony_ci		{
839e5c31af7Sopenharmony_ci			float	yf		= ((float)y + 0.5f) / (float)dst.getHeight();
840e5c31af7Sopenharmony_ci			float	xf		= ((float)x + 0.5f) / (float)dst.getWidth();
841e5c31af7Sopenharmony_ci
842e5c31af7Sopenharmony_ci			int		triNdx	= xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
843e5c31af7Sopenharmony_ci			float	triX	= triNdx ? 1.0f-xf : xf;
844e5c31af7Sopenharmony_ci			float	triY	= triNdx ? 1.0f-yf : yf;
845e5c31af7Sopenharmony_ci
846e5c31af7Sopenharmony_ci			float	s		= triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
847e5c31af7Sopenharmony_ci			float	t		= triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
848e5c31af7Sopenharmony_ci			float	r		= triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
849e5c31af7Sopenharmony_ci			float	lod		= triLod[triNdx];
850e5c31af7Sopenharmony_ci
851e5c31af7Sopenharmony_ci			if (params.imageViewMinLod != 0.0f && params.samplerType == SAMPLERTYPE_FETCH_FLOAT)
852e5c31af7Sopenharmony_ci				lod = (float)params.lodTexelFetch;
853e5c31af7Sopenharmony_ci
854e5c31af7Sopenharmony_ci			dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
855e5c31af7Sopenharmony_ci		}
856e5c31af7Sopenharmony_ci	}
857e5c31af7Sopenharmony_ci}
858e5c31af7Sopenharmony_ci
859e5c31af7Sopenharmony_cistatic void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
860e5c31af7Sopenharmony_ci{
861e5c31af7Sopenharmony_ci	// Separate combined DS formats
862e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
863e5c31af7Sopenharmony_ci	const tcu::Texture3DView					src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
864e5c31af7Sopenharmony_ci
865e5c31af7Sopenharmony_ci	float										lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
866e5c31af7Sopenharmony_ci	float										dstW				= (float)dst.getWidth();
867e5c31af7Sopenharmony_ci	float										dstH				= (float)dst.getHeight();
868e5c31af7Sopenharmony_ci
869e5c31af7Sopenharmony_ci	tcu::Vec4									uq					= sq * (float)src.getWidth();
870e5c31af7Sopenharmony_ci	tcu::Vec4									vq					= tq * (float)src.getHeight();
871e5c31af7Sopenharmony_ci	tcu::Vec4									wq					= rq * (float)src.getDepth();
872e5c31af7Sopenharmony_ci
873e5c31af7Sopenharmony_ci	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
874e5c31af7Sopenharmony_ci	tcu::Vec3									triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
875e5c31af7Sopenharmony_ci	tcu::Vec3									triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
876e5c31af7Sopenharmony_ci	tcu::Vec3									triU[2]				= { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
877e5c31af7Sopenharmony_ci	tcu::Vec3									triV[2]				= { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
878e5c31af7Sopenharmony_ci	tcu::Vec3									triW[2]				= { wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1) };
879e5c31af7Sopenharmony_ci	tcu::Vec3									triP[2]				= { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
880e5c31af7Sopenharmony_ci
881e5c31af7Sopenharmony_ci	for (int py = 0; py < dst.getHeight(); py++)
882e5c31af7Sopenharmony_ci	{
883e5c31af7Sopenharmony_ci		for (int px = 0; px < dst.getWidth(); px++)
884e5c31af7Sopenharmony_ci		{
885e5c31af7Sopenharmony_ci			float	wx		= (float)px + 0.5f;
886e5c31af7Sopenharmony_ci			float	wy		= (float)py + 0.5f;
887e5c31af7Sopenharmony_ci			float	nx		= wx / dstW;
888e5c31af7Sopenharmony_ci			float	ny		= wy / dstH;
889e5c31af7Sopenharmony_ci
890e5c31af7Sopenharmony_ci			int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
891e5c31af7Sopenharmony_ci			float	triWx	= triNdx ? dstW - wx : wx;
892e5c31af7Sopenharmony_ci			float	triWy	= triNdx ? dstH - wy : wy;
893e5c31af7Sopenharmony_ci			float	triNx	= triNdx ? 1.0f - nx : nx;
894e5c31af7Sopenharmony_ci			float	triNy	= triNdx ? 1.0f - ny : ny;
895e5c31af7Sopenharmony_ci
896e5c31af7Sopenharmony_ci			float	s		= projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy);
897e5c31af7Sopenharmony_ci			float	t		= projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy);
898e5c31af7Sopenharmony_ci			float	r		= projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy);
899e5c31af7Sopenharmony_ci			float	lod		= computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
900e5c31af7Sopenharmony_ci							+ lodBias;
901e5c31af7Sopenharmony_ci
902e5c31af7Sopenharmony_ci			dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py);
903e5c31af7Sopenharmony_ci		}
904e5c31af7Sopenharmony_ci	}
905e5c31af7Sopenharmony_ci}
906e5c31af7Sopenharmony_ci
907e5c31af7Sopenharmony_civoid sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& src, const float* texCoord, const ReferenceParams& params)
908e5c31af7Sopenharmony_ci{
909e5c31af7Sopenharmony_ci	tcu::ImageViewMinLodParams	minLodParams =
910e5c31af7Sopenharmony_ci	{
911e5c31af7Sopenharmony_ci		params.baseLevel,								// int		baseLevel;
912e5c31af7Sopenharmony_ci		{
913e5c31af7Sopenharmony_ci			params.imageViewMinLod,							// float	minLod;
914e5c31af7Sopenharmony_ci			params.imageViewMinLodMode,						// ImageViewMinLodMode
915e5c31af7Sopenharmony_ci		},
916e5c31af7Sopenharmony_ci		params.samplerType == SAMPLERTYPE_FETCH_FLOAT	// bool	intTexCoord;
917e5c31af7Sopenharmony_ci	};
918e5c31af7Sopenharmony_ci
919e5c31af7Sopenharmony_ci	const tcu::Texture3DView	view	= getSubView(src, params.baseLevel, params.maxLevel, params.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
920e5c31af7Sopenharmony_ci	const tcu::Vec4				sq		= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
921e5c31af7Sopenharmony_ci	const tcu::Vec4				tq		= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
922e5c31af7Sopenharmony_ci	const tcu::Vec4				rq		= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
923e5c31af7Sopenharmony_ci
924e5c31af7Sopenharmony_ci	if (params.flags & ReferenceParams::PROJECTED)
925e5c31af7Sopenharmony_ci		sampleTextureProjected(dst, view, sq, tq, rq, params);
926e5c31af7Sopenharmony_ci	else
927e5c31af7Sopenharmony_ci		sampleTextureNonProjected(dst, view, sq, tq, rq, params);
928e5c31af7Sopenharmony_ci}
929e5c31af7Sopenharmony_ci
930e5c31af7Sopenharmony_cistatic void sampleTextureCubeArray (const tcu::SurfaceAccess& dst, const tcu::TextureCubeArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const tcu::Vec4& qq, const ReferenceParams& params)
931e5c31af7Sopenharmony_ci{
932e5c31af7Sopenharmony_ci	// Separate combined DS formats
933e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
934e5c31af7Sopenharmony_ci	const tcu::TextureCubeArrayView				src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
935e5c31af7Sopenharmony_ci
936e5c31af7Sopenharmony_ci	const float									dstW				= (float)dst.getWidth();
937e5c31af7Sopenharmony_ci	const float									dstH				= (float)dst.getHeight();
938e5c31af7Sopenharmony_ci
939e5c31af7Sopenharmony_ci	// Coordinates per triangle.
940e5c31af7Sopenharmony_ci	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
941e5c31af7Sopenharmony_ci	tcu::Vec3									triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
942e5c31af7Sopenharmony_ci	tcu::Vec3									triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
943e5c31af7Sopenharmony_ci	tcu::Vec3									triQ[2]				= { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
944e5c31af7Sopenharmony_ci	const tcu::Vec3								triW[2]				= { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
945e5c31af7Sopenharmony_ci
946e5c31af7Sopenharmony_ci	const float									lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
947e5c31af7Sopenharmony_ci
948e5c31af7Sopenharmony_ci	for (int py = 0; py < dst.getHeight(); py++)
949e5c31af7Sopenharmony_ci	{
950e5c31af7Sopenharmony_ci		for (int px = 0; px < dst.getWidth(); px++)
951e5c31af7Sopenharmony_ci		{
952e5c31af7Sopenharmony_ci			const float		wx		= (float)px + 0.5f;
953e5c31af7Sopenharmony_ci			const float		wy		= (float)py + 0.5f;
954e5c31af7Sopenharmony_ci			const float		nx		= wx / dstW;
955e5c31af7Sopenharmony_ci			const float		ny		= wy / dstH;
956e5c31af7Sopenharmony_ci
957e5c31af7Sopenharmony_ci			const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
958e5c31af7Sopenharmony_ci			const float		triNx	= triNdx ? 1.0f - nx : nx;
959e5c31af7Sopenharmony_ci			const float		triNy	= triNdx ? 1.0f - ny : ny;
960e5c31af7Sopenharmony_ci
961e5c31af7Sopenharmony_ci			const tcu::Vec3	coord	(triangleInterpolate(triS[triNdx], triNx, triNy),
962e5c31af7Sopenharmony_ci									 triangleInterpolate(triT[triNdx], triNx, triNy),
963e5c31af7Sopenharmony_ci									 triangleInterpolate(triR[triNdx], triNx, triNy));
964e5c31af7Sopenharmony_ci
965e5c31af7Sopenharmony_ci			const float		coordQ	= triangleInterpolate(triQ[triNdx], triNx, triNy);
966e5c31af7Sopenharmony_ci
967e5c31af7Sopenharmony_ci			const tcu::Vec3	coordDx	(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
968e5c31af7Sopenharmony_ci									 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
969e5c31af7Sopenharmony_ci									 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
970e5c31af7Sopenharmony_ci			const tcu::Vec3	coordDy	(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
971e5c31af7Sopenharmony_ci									 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
972e5c31af7Sopenharmony_ci									 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
973e5c31af7Sopenharmony_ci
974e5c31af7Sopenharmony_ci			const float		lod		= de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod);
975e5c31af7Sopenharmony_ci
976e5c31af7Sopenharmony_ci			dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py);
977e5c31af7Sopenharmony_ci		}
978e5c31af7Sopenharmony_ci	}
979e5c31af7Sopenharmony_ci}
980e5c31af7Sopenharmony_ci
981e5c31af7Sopenharmony_civoid sampleTexture (const tcu::SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const float* texCoord, const ReferenceParams& params)
982e5c31af7Sopenharmony_ci{
983e5c31af7Sopenharmony_ci	tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
984e5c31af7Sopenharmony_ci	tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
985e5c31af7Sopenharmony_ci	tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
986e5c31af7Sopenharmony_ci	tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
987e5c31af7Sopenharmony_ci
988e5c31af7Sopenharmony_ci	sampleTextureCubeArray(dst, src, sq, tq, rq, qq, params);
989e5c31af7Sopenharmony_ci}
990e5c31af7Sopenharmony_ci
991e5c31af7Sopenharmony_civoid fetchTexture (const tcu::SurfaceAccess& dst, const tcu::ConstPixelBufferAccess& src, const float* texCoord, const tcu::Vec4& colorScale, const tcu::Vec4& colorBias)
992e5c31af7Sopenharmony_ci{
993e5c31af7Sopenharmony_ci	const tcu::Vec4		sq			= tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
994e5c31af7Sopenharmony_ci	const tcu::Vec3		triS[2]		= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
995e5c31af7Sopenharmony_ci
996e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
997e5c31af7Sopenharmony_ci	{
998e5c31af7Sopenharmony_ci		for (int x = 0; x < dst.getWidth(); x++)
999e5c31af7Sopenharmony_ci		{
1000e5c31af7Sopenharmony_ci			const float	yf		= ((float)y + 0.5f) / (float)dst.getHeight();
1001e5c31af7Sopenharmony_ci			const float	xf		= ((float)x + 0.5f) / (float)dst.getWidth();
1002e5c31af7Sopenharmony_ci
1003e5c31af7Sopenharmony_ci			const int	triNdx	= xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
1004e5c31af7Sopenharmony_ci			const float	triX	= triNdx ? 1.0f-xf : xf;
1005e5c31af7Sopenharmony_ci			const float	triY	= triNdx ? 1.0f-yf : yf;
1006e5c31af7Sopenharmony_ci
1007e5c31af7Sopenharmony_ci			const float	s		= triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
1008e5c31af7Sopenharmony_ci
1009e5c31af7Sopenharmony_ci			dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
1010e5c31af7Sopenharmony_ci		}
1011e5c31af7Sopenharmony_ci	}
1012e5c31af7Sopenharmony_ci}
1013e5c31af7Sopenharmony_ci
1014e5c31af7Sopenharmony_cibool compareImages (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
1015e5c31af7Sopenharmony_ci{
1016e5c31af7Sopenharmony_ci	return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
1017e5c31af7Sopenharmony_ci}
1018e5c31af7Sopenharmony_ci
1019e5c31af7Sopenharmony_cibool compareImages (tcu::TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
1020e5c31af7Sopenharmony_ci{
1021e5c31af7Sopenharmony_ci	return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
1022e5c31af7Sopenharmony_ci}
1023e5c31af7Sopenharmony_ci
1024e5c31af7Sopenharmony_ciint measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff)
1025e5c31af7Sopenharmony_ci{
1026e5c31af7Sopenharmony_ci	return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
1027e5c31af7Sopenharmony_ci}
1028e5c31af7Sopenharmony_ci
1029e5c31af7Sopenharmony_ciinline int rangeDiff (int x, int a, int b)
1030e5c31af7Sopenharmony_ci{
1031e5c31af7Sopenharmony_ci	if (x < a)
1032e5c31af7Sopenharmony_ci		return a-x;
1033e5c31af7Sopenharmony_ci	else if (x > b)
1034e5c31af7Sopenharmony_ci		return x-b;
1035e5c31af7Sopenharmony_ci	else
1036e5c31af7Sopenharmony_ci		return 0;
1037e5c31af7Sopenharmony_ci}
1038e5c31af7Sopenharmony_ci
1039e5c31af7Sopenharmony_ciinline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
1040e5c31af7Sopenharmony_ci{
1041e5c31af7Sopenharmony_ci	int rMin = de::min(a.getRed(),		b.getRed());
1042e5c31af7Sopenharmony_ci	int rMax = de::max(a.getRed(),		b.getRed());
1043e5c31af7Sopenharmony_ci	int gMin = de::min(a.getGreen(),	b.getGreen());
1044e5c31af7Sopenharmony_ci	int gMax = de::max(a.getGreen(),	b.getGreen());
1045e5c31af7Sopenharmony_ci	int bMin = de::min(a.getBlue(),		b.getBlue());
1046e5c31af7Sopenharmony_ci	int bMax = de::max(a.getBlue(),		b.getBlue());
1047e5c31af7Sopenharmony_ci	int aMin = de::min(a.getAlpha(),	b.getAlpha());
1048e5c31af7Sopenharmony_ci	int aMax = de::max(a.getAlpha(),	b.getAlpha());
1049e5c31af7Sopenharmony_ci
1050e5c31af7Sopenharmony_ci	return tcu::RGBA(rangeDiff(p.getRed(),		rMin, rMax),
1051e5c31af7Sopenharmony_ci					 rangeDiff(p.getGreen(),	gMin, gMax),
1052e5c31af7Sopenharmony_ci					 rangeDiff(p.getBlue(),		bMin, bMax),
1053e5c31af7Sopenharmony_ci					 rangeDiff(p.getAlpha(),	aMin, aMax));
1054e5c31af7Sopenharmony_ci}
1055e5c31af7Sopenharmony_ci
1056e5c31af7Sopenharmony_ciinline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
1057e5c31af7Sopenharmony_ci{
1058e5c31af7Sopenharmony_ci	tcu::RGBA diff = rangeDiff(p, a, b);
1059e5c31af7Sopenharmony_ci	return diff.getRed()	<= threshold.getRed() &&
1060e5c31af7Sopenharmony_ci		   diff.getGreen()	<= threshold.getGreen() &&
1061e5c31af7Sopenharmony_ci		   diff.getBlue()	<= threshold.getBlue() &&
1062e5c31af7Sopenharmony_ci		   diff.getAlpha()	<= threshold.getAlpha();
1063e5c31af7Sopenharmony_ci}
1064e5c31af7Sopenharmony_ci
1065e5c31af7Sopenharmony_civoid computeQuadTexCoord1D (std::vector<float>& dst, float left, float right)
1066e5c31af7Sopenharmony_ci{
1067e5c31af7Sopenharmony_ci	dst.resize(4);
1068e5c31af7Sopenharmony_ci
1069e5c31af7Sopenharmony_ci	dst[0] = left;
1070e5c31af7Sopenharmony_ci	dst[1] = left;
1071e5c31af7Sopenharmony_ci	dst[2] = right;
1072e5c31af7Sopenharmony_ci	dst[3] = right;
1073e5c31af7Sopenharmony_ci}
1074e5c31af7Sopenharmony_ci
1075e5c31af7Sopenharmony_civoid computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right)
1076e5c31af7Sopenharmony_ci{
1077e5c31af7Sopenharmony_ci	dst.resize(4*2);
1078e5c31af7Sopenharmony_ci
1079e5c31af7Sopenharmony_ci	dst[0] = left;	dst[1] = (float)layerNdx;
1080e5c31af7Sopenharmony_ci	dst[2] = left;	dst[3] = (float)layerNdx;
1081e5c31af7Sopenharmony_ci	dst[4] = right;	dst[5] = (float)layerNdx;
1082e5c31af7Sopenharmony_ci	dst[6] = right;	dst[7] = (float)layerNdx;
1083e5c31af7Sopenharmony_ci}
1084e5c31af7Sopenharmony_ci
1085e5c31af7Sopenharmony_civoid computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1086e5c31af7Sopenharmony_ci{
1087e5c31af7Sopenharmony_ci	dst.resize(4*2);
1088e5c31af7Sopenharmony_ci
1089e5c31af7Sopenharmony_ci	dst[0] = bottomLeft.x();	dst[1] = bottomLeft.y();
1090e5c31af7Sopenharmony_ci	dst[2] = bottomLeft.x();	dst[3] = topRight.y();
1091e5c31af7Sopenharmony_ci	dst[4] = topRight.x();		dst[5] = bottomLeft.y();
1092e5c31af7Sopenharmony_ci	dst[6] = topRight.x();		dst[7] = topRight.y();
1093e5c31af7Sopenharmony_ci}
1094e5c31af7Sopenharmony_ci
1095e5c31af7Sopenharmony_civoid computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1096e5c31af7Sopenharmony_ci{
1097e5c31af7Sopenharmony_ci	dst.resize(4*3);
1098e5c31af7Sopenharmony_ci
1099e5c31af7Sopenharmony_ci	dst[0] = bottomLeft.x();	dst[ 1] = bottomLeft.y();	dst[ 2] = (float)layerNdx;
1100e5c31af7Sopenharmony_ci	dst[3] = bottomLeft.x();	dst[ 4] = topRight.y();		dst[ 5] = (float)layerNdx;
1101e5c31af7Sopenharmony_ci	dst[6] = topRight.x();		dst[ 7] = bottomLeft.y();	dst[ 8] = (float)layerNdx;
1102e5c31af7Sopenharmony_ci	dst[9] = topRight.x();		dst[10] = topRight.y();		dst[11] = (float)layerNdx;
1103e5c31af7Sopenharmony_ci}
1104e5c31af7Sopenharmony_ci
1105e5c31af7Sopenharmony_civoid computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz)
1106e5c31af7Sopenharmony_ci{
1107e5c31af7Sopenharmony_ci	tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1108e5c31af7Sopenharmony_ci	tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1109e5c31af7Sopenharmony_ci	tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1110e5c31af7Sopenharmony_ci	tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1111e5c31af7Sopenharmony_ci
1112e5c31af7Sopenharmony_ci	tcu::Vec3 v0 = p0 + (p1-p0)*f0;
1113e5c31af7Sopenharmony_ci	tcu::Vec3 v1 = p0 + (p1-p0)*f1;
1114e5c31af7Sopenharmony_ci	tcu::Vec3 v2 = p0 + (p1-p0)*f2;
1115e5c31af7Sopenharmony_ci	tcu::Vec3 v3 = p0 + (p1-p0)*f3;
1116e5c31af7Sopenharmony_ci
1117e5c31af7Sopenharmony_ci	dst.resize(4*3);
1118e5c31af7Sopenharmony_ci
1119e5c31af7Sopenharmony_ci	dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z();
1120e5c31af7Sopenharmony_ci	dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z();
1121e5c31af7Sopenharmony_ci	dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z();
1122e5c31af7Sopenharmony_ci	dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z();
1123e5c31af7Sopenharmony_ci}
1124e5c31af7Sopenharmony_ci
1125e5c31af7Sopenharmony_civoid computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face)
1126e5c31af7Sopenharmony_ci{
1127e5c31af7Sopenharmony_ci	static const float texCoordNegX[] =
1128e5c31af7Sopenharmony_ci	{
1129e5c31af7Sopenharmony_ci		-1.0f,  1.0f, -1.0f,
1130e5c31af7Sopenharmony_ci		-1.0f, -1.0f, -1.0f,
1131e5c31af7Sopenharmony_ci		-1.0f,  1.0f,  1.0f,
1132e5c31af7Sopenharmony_ci		-1.0f, -1.0f,  1.0f
1133e5c31af7Sopenharmony_ci	};
1134e5c31af7Sopenharmony_ci	static const float texCoordPosX[] =
1135e5c31af7Sopenharmony_ci	{
1136e5c31af7Sopenharmony_ci		+1.0f,  1.0f,  1.0f,
1137e5c31af7Sopenharmony_ci		+1.0f, -1.0f,  1.0f,
1138e5c31af7Sopenharmony_ci		+1.0f,  1.0f, -1.0f,
1139e5c31af7Sopenharmony_ci		+1.0f, -1.0f, -1.0f
1140e5c31af7Sopenharmony_ci	};
1141e5c31af7Sopenharmony_ci	static const float texCoordNegY[] =
1142e5c31af7Sopenharmony_ci	{
1143e5c31af7Sopenharmony_ci		-1.0f, -1.0f,  1.0f,
1144e5c31af7Sopenharmony_ci		-1.0f, -1.0f, -1.0f,
1145e5c31af7Sopenharmony_ci		 1.0f, -1.0f,  1.0f,
1146e5c31af7Sopenharmony_ci		 1.0f, -1.0f, -1.0f
1147e5c31af7Sopenharmony_ci	};
1148e5c31af7Sopenharmony_ci	static const float texCoordPosY[] =
1149e5c31af7Sopenharmony_ci	{
1150e5c31af7Sopenharmony_ci		-1.0f, +1.0f, -1.0f,
1151e5c31af7Sopenharmony_ci		-1.0f, +1.0f,  1.0f,
1152e5c31af7Sopenharmony_ci		 1.0f, +1.0f, -1.0f,
1153e5c31af7Sopenharmony_ci		 1.0f, +1.0f,  1.0f
1154e5c31af7Sopenharmony_ci	};
1155e5c31af7Sopenharmony_ci	static const float texCoordNegZ[] =
1156e5c31af7Sopenharmony_ci	{
1157e5c31af7Sopenharmony_ci		 1.0f,  1.0f, -1.0f,
1158e5c31af7Sopenharmony_ci		 1.0f, -1.0f, -1.0f,
1159e5c31af7Sopenharmony_ci		-1.0f,  1.0f, -1.0f,
1160e5c31af7Sopenharmony_ci		-1.0f, -1.0f, -1.0f
1161e5c31af7Sopenharmony_ci	};
1162e5c31af7Sopenharmony_ci	static const float texCoordPosZ[] =
1163e5c31af7Sopenharmony_ci	{
1164e5c31af7Sopenharmony_ci		-1.0f,  1.0f, +1.0f,
1165e5c31af7Sopenharmony_ci		-1.0f, -1.0f, +1.0f,
1166e5c31af7Sopenharmony_ci		 1.0f,  1.0f, +1.0f,
1167e5c31af7Sopenharmony_ci		 1.0f, -1.0f, +1.0f
1168e5c31af7Sopenharmony_ci	};
1169e5c31af7Sopenharmony_ci
1170e5c31af7Sopenharmony_ci	const float*	texCoord		= DE_NULL;
1171e5c31af7Sopenharmony_ci	int				texCoordSize	= DE_LENGTH_OF_ARRAY(texCoordNegX);
1172e5c31af7Sopenharmony_ci
1173e5c31af7Sopenharmony_ci	switch (face)
1174e5c31af7Sopenharmony_ci	{
1175e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break;
1176e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break;
1177e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break;
1178e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break;
1179e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break;
1180e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break;
1181e5c31af7Sopenharmony_ci		default:
1182e5c31af7Sopenharmony_ci			DE_ASSERT(DE_FALSE);
1183e5c31af7Sopenharmony_ci			return;
1184e5c31af7Sopenharmony_ci	}
1185e5c31af7Sopenharmony_ci
1186e5c31af7Sopenharmony_ci	dst.resize(texCoordSize);
1187e5c31af7Sopenharmony_ci	std::copy(texCoord, texCoord+texCoordSize, dst.begin());
1188e5c31af7Sopenharmony_ci}
1189e5c31af7Sopenharmony_ci
1190e5c31af7Sopenharmony_civoid computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1191e5c31af7Sopenharmony_ci{
1192e5c31af7Sopenharmony_ci	int		sRow		= 0;
1193e5c31af7Sopenharmony_ci	int		tRow		= 0;
1194e5c31af7Sopenharmony_ci	int		mRow		= 0;
1195e5c31af7Sopenharmony_ci	float	sSign		= 1.0f;
1196e5c31af7Sopenharmony_ci	float	tSign		= 1.0f;
1197e5c31af7Sopenharmony_ci	float	mSign		= 1.0f;
1198e5c31af7Sopenharmony_ci
1199e5c31af7Sopenharmony_ci	switch (face)
1200e5c31af7Sopenharmony_ci	{
1201e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f;				   tSign = -1.0f;	break;
1202e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1;				sSign = -1.0f; tSign = -1.0f;	break;
1203e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f;				   tSign = -1.0f;	break;
1204e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2;												break;
1205e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f;	break;
1206e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1;							   tSign = -1.0f;	break;
1207e5c31af7Sopenharmony_ci		default:
1208e5c31af7Sopenharmony_ci			DE_ASSERT(DE_FALSE);
1209e5c31af7Sopenharmony_ci			return;
1210e5c31af7Sopenharmony_ci	}
1211e5c31af7Sopenharmony_ci
1212e5c31af7Sopenharmony_ci	dst.resize(3*4);
1213e5c31af7Sopenharmony_ci
1214e5c31af7Sopenharmony_ci	dst[0+mRow] = mSign;
1215e5c31af7Sopenharmony_ci	dst[3+mRow] = mSign;
1216e5c31af7Sopenharmony_ci	dst[6+mRow] = mSign;
1217e5c31af7Sopenharmony_ci	dst[9+mRow] = mSign;
1218e5c31af7Sopenharmony_ci
1219e5c31af7Sopenharmony_ci	dst[0+sRow] = sSign * bottomLeft.x();
1220e5c31af7Sopenharmony_ci	dst[3+sRow] = sSign * bottomLeft.x();
1221e5c31af7Sopenharmony_ci	dst[6+sRow] = sSign * topRight.x();
1222e5c31af7Sopenharmony_ci	dst[9+sRow] = sSign * topRight.x();
1223e5c31af7Sopenharmony_ci
1224e5c31af7Sopenharmony_ci	dst[0+tRow] = tSign * bottomLeft.y();
1225e5c31af7Sopenharmony_ci	dst[3+tRow] = tSign * topRight.y();
1226e5c31af7Sopenharmony_ci	dst[6+tRow] = tSign * bottomLeft.y();
1227e5c31af7Sopenharmony_ci	dst[9+tRow] = tSign * topRight.y();
1228e5c31af7Sopenharmony_ci}
1229e5c31af7Sopenharmony_ci
1230e5c31af7Sopenharmony_civoid computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
1231e5c31af7Sopenharmony_ci{
1232e5c31af7Sopenharmony_ci	int			sRow	= 0;
1233e5c31af7Sopenharmony_ci	int			tRow	= 0;
1234e5c31af7Sopenharmony_ci	int			mRow	= 0;
1235e5c31af7Sopenharmony_ci	const int	qRow	= 3;
1236e5c31af7Sopenharmony_ci	float		sSign	= 1.0f;
1237e5c31af7Sopenharmony_ci	float		tSign	= 1.0f;
1238e5c31af7Sopenharmony_ci	float		mSign	= 1.0f;
1239e5c31af7Sopenharmony_ci	const float	l0		= layerRange.x();
1240e5c31af7Sopenharmony_ci	const float	l1		= layerRange.y();
1241e5c31af7Sopenharmony_ci
1242e5c31af7Sopenharmony_ci	switch (face)
1243e5c31af7Sopenharmony_ci	{
1244e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f;				   tSign = -1.0f;	break;
1245e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1;				sSign = -1.0f; tSign = -1.0f;	break;
1246e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f;				   tSign = -1.0f;	break;
1247e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2;												break;
1248e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f;	break;
1249e5c31af7Sopenharmony_ci		case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1;							   tSign = -1.0f;	break;
1250e5c31af7Sopenharmony_ci		default:
1251e5c31af7Sopenharmony_ci			DE_ASSERT(DE_FALSE);
1252e5c31af7Sopenharmony_ci			return;
1253e5c31af7Sopenharmony_ci	}
1254e5c31af7Sopenharmony_ci
1255e5c31af7Sopenharmony_ci	dst.resize(4*4);
1256e5c31af7Sopenharmony_ci
1257e5c31af7Sopenharmony_ci	dst[ 0+mRow] = mSign;
1258e5c31af7Sopenharmony_ci	dst[ 4+mRow] = mSign;
1259e5c31af7Sopenharmony_ci	dst[ 8+mRow] = mSign;
1260e5c31af7Sopenharmony_ci	dst[12+mRow] = mSign;
1261e5c31af7Sopenharmony_ci
1262e5c31af7Sopenharmony_ci	dst[ 0+sRow] = sSign * bottomLeft.x();
1263e5c31af7Sopenharmony_ci	dst[ 4+sRow] = sSign * bottomLeft.x();
1264e5c31af7Sopenharmony_ci	dst[ 8+sRow] = sSign * topRight.x();
1265e5c31af7Sopenharmony_ci	dst[12+sRow] = sSign * topRight.x();
1266e5c31af7Sopenharmony_ci
1267e5c31af7Sopenharmony_ci	dst[ 0+tRow] = tSign * bottomLeft.y();
1268e5c31af7Sopenharmony_ci	dst[ 4+tRow] = tSign * topRight.y();
1269e5c31af7Sopenharmony_ci	dst[ 8+tRow] = tSign * bottomLeft.y();
1270e5c31af7Sopenharmony_ci	dst[12+tRow] = tSign * topRight.y();
1271e5c31af7Sopenharmony_ci
1272e5c31af7Sopenharmony_ci	if (l0 != l1)
1273e5c31af7Sopenharmony_ci	{
1274e5c31af7Sopenharmony_ci		dst[ 0+qRow] = l0;
1275e5c31af7Sopenharmony_ci		dst[ 4+qRow] = l0*0.5f + l1*0.5f;
1276e5c31af7Sopenharmony_ci		dst[ 8+qRow] = l0*0.5f + l1*0.5f;
1277e5c31af7Sopenharmony_ci		dst[12+qRow] = l1;
1278e5c31af7Sopenharmony_ci	}
1279e5c31af7Sopenharmony_ci	else
1280e5c31af7Sopenharmony_ci	{
1281e5c31af7Sopenharmony_ci		dst[ 0+qRow] = l0;
1282e5c31af7Sopenharmony_ci		dst[ 4+qRow] = l0;
1283e5c31af7Sopenharmony_ci		dst[ 8+qRow] = l0;
1284e5c31af7Sopenharmony_ci		dst[12+qRow] = l0;
1285e5c31af7Sopenharmony_ci	}
1286e5c31af7Sopenharmony_ci}
1287e5c31af7Sopenharmony_ci
1288e5c31af7Sopenharmony_ci// Texture result verification
1289e5c31af7Sopenharmony_ci
1290e5c31af7Sopenharmony_ci//! Verifies texture lookup results and returns number of failed pixels.
1291e5c31af7Sopenharmony_ciint computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
1292e5c31af7Sopenharmony_ci							  const tcu::ConstPixelBufferAccess&	reference,
1293e5c31af7Sopenharmony_ci							  const tcu::PixelBufferAccess&			errorMask,
1294e5c31af7Sopenharmony_ci							  const tcu::Texture1DView&				baseView,
1295e5c31af7Sopenharmony_ci							  const float*							texCoord,
1296e5c31af7Sopenharmony_ci							  const ReferenceParams&				sampleParams,
1297e5c31af7Sopenharmony_ci							  const tcu::LookupPrecision&			lookupPrec,
1298e5c31af7Sopenharmony_ci							  const tcu::LodPrecision&				lodPrec,
1299e5c31af7Sopenharmony_ci							  qpWatchDog*							watchDog)
1300e5c31af7Sopenharmony_ci{
1301e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1302e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1303e5c31af7Sopenharmony_ci
1304e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
1305e5c31af7Sopenharmony_ci	const tcu::Texture1DView					src					= getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel, DE_NULL), srcLevelStorage, sampleParams.sampler);
1306e5c31af7Sopenharmony_ci
1307e5c31af7Sopenharmony_ci	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1308e5c31af7Sopenharmony_ci
1309e5c31af7Sopenharmony_ci	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
1310e5c31af7Sopenharmony_ci	const float									dstW				= float(dstSize.x());
1311e5c31af7Sopenharmony_ci	const float									dstH				= float(dstSize.y());
1312e5c31af7Sopenharmony_ci	const int									srcSize				= src.getWidth();
1313e5c31af7Sopenharmony_ci
1314e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
1315e5c31af7Sopenharmony_ci	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1316e5c31af7Sopenharmony_ci	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1317e5c31af7Sopenharmony_ci
1318e5c31af7Sopenharmony_ci	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1319e5c31af7Sopenharmony_ci
1320e5c31af7Sopenharmony_ci	int											numFailed			= 0;
1321e5c31af7Sopenharmony_ci
1322e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
1323e5c31af7Sopenharmony_ci	{
1324e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
1325e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
1326e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
1327e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
1328e5c31af7Sopenharmony_ci	};
1329e5c31af7Sopenharmony_ci
1330e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
1331e5c31af7Sopenharmony_ci
1332e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
1333e5c31af7Sopenharmony_ci	{
1334e5c31af7Sopenharmony_ci		// Ugly hack, validation can take way too long at the moment.
1335e5c31af7Sopenharmony_ci		if (watchDog)
1336e5c31af7Sopenharmony_ci			qpWatchDog_touch(watchDog);
1337e5c31af7Sopenharmony_ci
1338e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
1339e5c31af7Sopenharmony_ci		{
1340e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
1341e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
1342e5c31af7Sopenharmony_ci
1343e5c31af7Sopenharmony_ci			// Try comparison to ideal reference first, and if that fails use slower verificator.
1344e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1345e5c31af7Sopenharmony_ci			{
1346e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
1347e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
1348e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
1349e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
1350e5c31af7Sopenharmony_ci
1351e5c31af7Sopenharmony_ci				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
1352e5c31af7Sopenharmony_ci				const float		triWx	= triNdx ? dstW - wx : wx;
1353e5c31af7Sopenharmony_ci				const float		triWy	= triNdx ? dstH - wy : wy;
1354e5c31af7Sopenharmony_ci				const float		triNx	= triNdx ? 1.0f - nx : nx;
1355e5c31af7Sopenharmony_ci				const float		triNy	= triNdx ? 1.0f - ny : ny;
1356e5c31af7Sopenharmony_ci
1357e5c31af7Sopenharmony_ci				const float		coord		= projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
1358e5c31af7Sopenharmony_ci				const float		coordDx		= triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
1359e5c31af7Sopenharmony_ci				const float		coordDy		= triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
1360e5c31af7Sopenharmony_ci
1361e5c31af7Sopenharmony_ci				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1362e5c31af7Sopenharmony_ci
1363e5c31af7Sopenharmony_ci				// Compute lod bounds across lodOffsets range.
1364e5c31af7Sopenharmony_ci				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1365e5c31af7Sopenharmony_ci				{
1366e5c31af7Sopenharmony_ci					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
1367e5c31af7Sopenharmony_ci					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
1368e5c31af7Sopenharmony_ci					const float		nxo		= wxo/dstW;
1369e5c31af7Sopenharmony_ci					const float		nyo		= wyo/dstH;
1370e5c31af7Sopenharmony_ci
1371e5c31af7Sopenharmony_ci					const float	coordDxo	= triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
1372e5c31af7Sopenharmony_ci					const float	coordDyo	= triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
1373e5c31af7Sopenharmony_ci					const tcu::Vec2	lodO	= tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1374e5c31af7Sopenharmony_ci
1375e5c31af7Sopenharmony_ci					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1376e5c31af7Sopenharmony_ci					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1377e5c31af7Sopenharmony_ci				}
1378e5c31af7Sopenharmony_ci
1379e5c31af7Sopenharmony_ci				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1380e5c31af7Sopenharmony_ci				const bool		isOk		= tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1381e5c31af7Sopenharmony_ci
1382e5c31af7Sopenharmony_ci				if (!isOk)
1383e5c31af7Sopenharmony_ci				{
1384e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1385e5c31af7Sopenharmony_ci					numFailed += 1;
1386e5c31af7Sopenharmony_ci				}
1387e5c31af7Sopenharmony_ci			}
1388e5c31af7Sopenharmony_ci		}
1389e5c31af7Sopenharmony_ci	}
1390e5c31af7Sopenharmony_ci
1391e5c31af7Sopenharmony_ci	return numFailed;
1392e5c31af7Sopenharmony_ci}
1393e5c31af7Sopenharmony_ci
1394e5c31af7Sopenharmony_ciint computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
1395e5c31af7Sopenharmony_ci							  const tcu::ConstPixelBufferAccess&	reference,
1396e5c31af7Sopenharmony_ci							  const tcu::PixelBufferAccess&			errorMask,
1397e5c31af7Sopenharmony_ci							  const tcu::Texture2DView&				baseView,
1398e5c31af7Sopenharmony_ci							  const float*							texCoord,
1399e5c31af7Sopenharmony_ci							  const ReferenceParams&				sampleParams,
1400e5c31af7Sopenharmony_ci							  const tcu::LookupPrecision&			lookupPrec,
1401e5c31af7Sopenharmony_ci							  const tcu::LodPrecision&				lodPrec,
1402e5c31af7Sopenharmony_ci							  qpWatchDog*							watchDog)
1403e5c31af7Sopenharmony_ci{
1404e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1405e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1406e5c31af7Sopenharmony_ci
1407e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
1408e5c31af7Sopenharmony_ci	tcu::ImageViewMinLodParams	minLodParams =
1409e5c31af7Sopenharmony_ci	{
1410e5c31af7Sopenharmony_ci		sampleParams.baseLevel,								// int		baseLevel;
1411e5c31af7Sopenharmony_ci		{
1412e5c31af7Sopenharmony_ci			sampleParams.imageViewMinLod,							// float	minLod;
1413e5c31af7Sopenharmony_ci			sampleParams.imageViewMinLodMode,						// ImageViewMinLodMode
1414e5c31af7Sopenharmony_ci		},
1415e5c31af7Sopenharmony_ci		sampleParams.samplerType == SAMPLERTYPE_FETCH_FLOAT	// bool	intTexCoord;
1416e5c31af7Sopenharmony_ci	};
1417e5c31af7Sopenharmony_ci
1418e5c31af7Sopenharmony_ci	const tcu::Texture2DView					view				= getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel, sampleParams.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
1419e5c31af7Sopenharmony_ci
1420e5c31af7Sopenharmony_ci	const tcu::Texture2DView					src					= getEffectiveTextureView(view, srcLevelStorage, sampleParams.sampler);
1421e5c31af7Sopenharmony_ci
1422e5c31af7Sopenharmony_ci	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1423e5c31af7Sopenharmony_ci	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1424e5c31af7Sopenharmony_ci
1425e5c31af7Sopenharmony_ci	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
1426e5c31af7Sopenharmony_ci	const float									dstW				= float(dstSize.x());
1427e5c31af7Sopenharmony_ci	const float									dstH				= float(dstSize.y());
1428e5c31af7Sopenharmony_ci	const tcu::IVec2							srcSize				= tcu::IVec2(src.getWidth(), src.getHeight());
1429e5c31af7Sopenharmony_ci
1430e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
1431e5c31af7Sopenharmony_ci	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1432e5c31af7Sopenharmony_ci	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1433e5c31af7Sopenharmony_ci	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1434e5c31af7Sopenharmony_ci
1435e5c31af7Sopenharmony_ci	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1436e5c31af7Sopenharmony_ci
1437e5c31af7Sopenharmony_ci	// imageViewMinLodRel is used to calculate the image level to sample from, when VK_EXT_image_view_min_lod extension is enabled.
1438e5c31af7Sopenharmony_ci	// The value is relative to baseLevel as the Texture*View 'src' was created as the baseLevel being level[0].
1439e5c31af7Sopenharmony_ci	const float									imageViewMinLodRel	= sampleParams.imageViewMinLod - (float)sampleParams.baseLevel;
1440e5c31af7Sopenharmony_ci	// We need to adapt ImageView's minLod value to the mipmap mdoe (i.e. nearest or linear) so we clamp with the right minLod value later.
1441e5c31af7Sopenharmony_ci	const float									imageViewMinLodRelMode = tcu::isSamplerMipmapModeLinear(sampleParams.sampler.minFilter) ? deFloatFloor(imageViewMinLodRel) : (float)deClamp32((int)deFloatCeil(imageViewMinLodRel + 0.5f) - 1, sampleParams.baseLevel, sampleParams.maxLevel);
1442e5c31af7Sopenharmony_ci	const float									minLod				= (sampleParams.imageViewMinLod != 0.0f) ? de::max(imageViewMinLodRelMode, sampleParams.minLod) : sampleParams.minLod;
1443e5c31af7Sopenharmony_ci
1444e5c31af7Sopenharmony_ci	const float									posEps				= 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1445e5c31af7Sopenharmony_ci
1446e5c31af7Sopenharmony_ci	int											numFailed			= 0;
1447e5c31af7Sopenharmony_ci
1448e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
1449e5c31af7Sopenharmony_ci	{
1450e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
1451e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
1452e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
1453e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
1454e5c31af7Sopenharmony_ci	};
1455e5c31af7Sopenharmony_ci
1456e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
1457e5c31af7Sopenharmony_ci
1458e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
1459e5c31af7Sopenharmony_ci	{
1460e5c31af7Sopenharmony_ci		// Ugly hack, validation can take way too long at the moment.
1461e5c31af7Sopenharmony_ci		if (watchDog)
1462e5c31af7Sopenharmony_ci			qpWatchDog_touch(watchDog);
1463e5c31af7Sopenharmony_ci
1464e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
1465e5c31af7Sopenharmony_ci		{
1466e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
1467e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
1468e5c31af7Sopenharmony_ci
1469e5c31af7Sopenharmony_ci			// Try comparison to ideal reference first, and if that fails use slower verificator.
1470e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1471e5c31af7Sopenharmony_ci			{
1472e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
1473e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
1474e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
1475e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
1476e5c31af7Sopenharmony_ci
1477e5c31af7Sopenharmony_ci				const bool		tri0	= (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1478e5c31af7Sopenharmony_ci				const bool		tri1	= (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1479e5c31af7Sopenharmony_ci
1480e5c31af7Sopenharmony_ci				bool			isOk	= false;
1481e5c31af7Sopenharmony_ci
1482e5c31af7Sopenharmony_ci				DE_ASSERT(tri0 || tri1);
1483e5c31af7Sopenharmony_ci
1484e5c31af7Sopenharmony_ci				// Pixel can belong to either of the triangles if it lies close enough to the edge.
1485e5c31af7Sopenharmony_ci				for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1486e5c31af7Sopenharmony_ci				{
1487e5c31af7Sopenharmony_ci					const float		triWx	= triNdx ? dstW - wx : wx;
1488e5c31af7Sopenharmony_ci					const float		triWy	= triNdx ? dstH - wy : wy;
1489e5c31af7Sopenharmony_ci					const float		triNx	= triNdx ? 1.0f - nx : nx;
1490e5c31af7Sopenharmony_ci					const float		triNy	= triNdx ? 1.0f - ny : ny;
1491e5c31af7Sopenharmony_ci
1492e5c31af7Sopenharmony_ci					const tcu::Vec2	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1493e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1494e5c31af7Sopenharmony_ci					const tcu::Vec2	coordDx		= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1495e5c31af7Sopenharmony_ci															triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1496e5c31af7Sopenharmony_ci					const tcu::Vec2	coordDy		= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1497e5c31af7Sopenharmony_ci															triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1498e5c31af7Sopenharmony_ci
1499e5c31af7Sopenharmony_ci					tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1500e5c31af7Sopenharmony_ci
1501e5c31af7Sopenharmony_ci					// Compute lod bounds across lodOffsets range.
1502e5c31af7Sopenharmony_ci					for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1503e5c31af7Sopenharmony_ci					{
1504e5c31af7Sopenharmony_ci						const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
1505e5c31af7Sopenharmony_ci						const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
1506e5c31af7Sopenharmony_ci						const float		nxo		= wxo/dstW;
1507e5c31af7Sopenharmony_ci						const float		nyo		= wyo/dstH;
1508e5c31af7Sopenharmony_ci
1509e5c31af7Sopenharmony_ci						const tcu::Vec2	coordDxo	= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1510e5c31af7Sopenharmony_ci																triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1511e5c31af7Sopenharmony_ci						const tcu::Vec2	coordDyo	= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1512e5c31af7Sopenharmony_ci																triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1513e5c31af7Sopenharmony_ci						const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1514e5c31af7Sopenharmony_ci
1515e5c31af7Sopenharmony_ci						lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1516e5c31af7Sopenharmony_ci						lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1517e5c31af7Sopenharmony_ci					}
1518e5c31af7Sopenharmony_ci
1519e5c31af7Sopenharmony_ci					const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
1520e5c31af7Sopenharmony_ci					if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1521e5c31af7Sopenharmony_ci					{
1522e5c31af7Sopenharmony_ci						isOk = true;
1523e5c31af7Sopenharmony_ci						break;
1524e5c31af7Sopenharmony_ci					}
1525e5c31af7Sopenharmony_ci				}
1526e5c31af7Sopenharmony_ci
1527e5c31af7Sopenharmony_ci				if (!isOk)
1528e5c31af7Sopenharmony_ci				{
1529e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1530e5c31af7Sopenharmony_ci					numFailed += 1;
1531e5c31af7Sopenharmony_ci				}
1532e5c31af7Sopenharmony_ci			}
1533e5c31af7Sopenharmony_ci		}
1534e5c31af7Sopenharmony_ci	}
1535e5c31af7Sopenharmony_ci
1536e5c31af7Sopenharmony_ci	return numFailed;
1537e5c31af7Sopenharmony_ci}
1538e5c31af7Sopenharmony_ci
1539e5c31af7Sopenharmony_cibool verifyTextureResult (tcu::TestContext&						testCtx,
1540e5c31af7Sopenharmony_ci						  const tcu::ConstPixelBufferAccess&	result,
1541e5c31af7Sopenharmony_ci						  const tcu::Texture1DView&				src,
1542e5c31af7Sopenharmony_ci						  const float*							texCoord,
1543e5c31af7Sopenharmony_ci						  const ReferenceParams&				sampleParams,
1544e5c31af7Sopenharmony_ci						  const tcu::LookupPrecision&			lookupPrec,
1545e5c31af7Sopenharmony_ci						  const tcu::LodPrecision&				lodPrec,
1546e5c31af7Sopenharmony_ci						  const tcu::PixelFormat&				pixelFormat)
1547e5c31af7Sopenharmony_ci{
1548e5c31af7Sopenharmony_ci	tcu::TestLog&	log				= testCtx.getLog();
1549e5c31af7Sopenharmony_ci	tcu::Surface	reference		(result.getWidth(), result.getHeight());
1550e5c31af7Sopenharmony_ci	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
1551e5c31af7Sopenharmony_ci	int				numFailedPixels;
1552e5c31af7Sopenharmony_ci
1553e5c31af7Sopenharmony_ci	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1554e5c31af7Sopenharmony_ci
1555e5c31af7Sopenharmony_ci	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1556e5c31af7Sopenharmony_ci	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1557e5c31af7Sopenharmony_ci
1558e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
1559e5c31af7Sopenharmony_ci		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1560e5c31af7Sopenharmony_ci
1561e5c31af7Sopenharmony_ci	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1562e5c31af7Sopenharmony_ci		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
1563e5c31af7Sopenharmony_ci
1564e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
1565e5c31af7Sopenharmony_ci	{
1566e5c31af7Sopenharmony_ci		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1567e5c31af7Sopenharmony_ci			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1568e5c31af7Sopenharmony_ci	}
1569e5c31af7Sopenharmony_ci
1570e5c31af7Sopenharmony_ci	log << tcu::TestLog::EndImageSet;
1571e5c31af7Sopenharmony_ci
1572e5c31af7Sopenharmony_ci	return numFailedPixels == 0;
1573e5c31af7Sopenharmony_ci}
1574e5c31af7Sopenharmony_ci
1575e5c31af7Sopenharmony_cibool verifyTextureResult (tcu::TestContext&						testCtx,
1576e5c31af7Sopenharmony_ci						  const tcu::ConstPixelBufferAccess&	result,
1577e5c31af7Sopenharmony_ci						  const tcu::Texture2DView&				src,
1578e5c31af7Sopenharmony_ci						  const float*							texCoord,
1579e5c31af7Sopenharmony_ci						  const ReferenceParams&				sampleParams,
1580e5c31af7Sopenharmony_ci						  const tcu::LookupPrecision&			lookupPrec,
1581e5c31af7Sopenharmony_ci						  const tcu::LodPrecision&				lodPrec,
1582e5c31af7Sopenharmony_ci						  const tcu::PixelFormat&				pixelFormat)
1583e5c31af7Sopenharmony_ci{
1584e5c31af7Sopenharmony_ci	tcu::TestLog&	log				= testCtx.getLog();
1585e5c31af7Sopenharmony_ci	tcu::Surface	reference		(result.getWidth(), result.getHeight());
1586e5c31af7Sopenharmony_ci	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
1587e5c31af7Sopenharmony_ci	int				numFailedPixels;
1588e5c31af7Sopenharmony_ci
1589e5c31af7Sopenharmony_ci	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1590e5c31af7Sopenharmony_ci
1591e5c31af7Sopenharmony_ci	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1592e5c31af7Sopenharmony_ci	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1593e5c31af7Sopenharmony_ci
1594e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
1595e5c31af7Sopenharmony_ci		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1596e5c31af7Sopenharmony_ci
1597e5c31af7Sopenharmony_ci	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1598e5c31af7Sopenharmony_ci		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
1599e5c31af7Sopenharmony_ci
1600e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
1601e5c31af7Sopenharmony_ci	{
1602e5c31af7Sopenharmony_ci		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1603e5c31af7Sopenharmony_ci			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1604e5c31af7Sopenharmony_ci	}
1605e5c31af7Sopenharmony_ci
1606e5c31af7Sopenharmony_ci	log << tcu::TestLog::EndImageSet;
1607e5c31af7Sopenharmony_ci
1608e5c31af7Sopenharmony_ci	return numFailedPixels == 0;
1609e5c31af7Sopenharmony_ci}
1610e5c31af7Sopenharmony_ci
1611e5c31af7Sopenharmony_ci//! Verifies texture lookup results and returns number of failed pixels.
1612e5c31af7Sopenharmony_ciint computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
1613e5c31af7Sopenharmony_ci							  const tcu::ConstPixelBufferAccess&	reference,
1614e5c31af7Sopenharmony_ci							  const tcu::PixelBufferAccess&			errorMask,
1615e5c31af7Sopenharmony_ci							  const tcu::TextureCubeView&			baseView,
1616e5c31af7Sopenharmony_ci							  const float*							texCoord,
1617e5c31af7Sopenharmony_ci							  const ReferenceParams&				sampleParams,
1618e5c31af7Sopenharmony_ci							  const tcu::LookupPrecision&			lookupPrec,
1619e5c31af7Sopenharmony_ci							  const tcu::LodPrecision&				lodPrec,
1620e5c31af7Sopenharmony_ci							  qpWatchDog*							watchDog)
1621e5c31af7Sopenharmony_ci{
1622e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1623e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1624e5c31af7Sopenharmony_ci
1625e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
1626e5c31af7Sopenharmony_ci	tcu::ImageViewMinLodParams	minLodParams =
1627e5c31af7Sopenharmony_ci	{
1628e5c31af7Sopenharmony_ci		sampleParams.baseLevel,								// int		baseLevel;
1629e5c31af7Sopenharmony_ci		{
1630e5c31af7Sopenharmony_ci			sampleParams.imageViewMinLod,					// float	minLod;
1631e5c31af7Sopenharmony_ci			sampleParams.imageViewMinLodMode,				// ImageViewMinLodMode
1632e5c31af7Sopenharmony_ci		},
1633e5c31af7Sopenharmony_ci		sampleParams.samplerType == SAMPLERTYPE_FETCH_FLOAT	// bool	intTexCoord;
1634e5c31af7Sopenharmony_ci	};
1635e5c31af7Sopenharmony_ci
1636e5c31af7Sopenharmony_ci	const tcu::TextureCubeView					src					= getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel, sampleParams.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL), srcLevelStorage, sampleParams.sampler);
1637e5c31af7Sopenharmony_ci
1638e5c31af7Sopenharmony_ci	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1639e5c31af7Sopenharmony_ci	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1640e5c31af7Sopenharmony_ci	const tcu::Vec4								rq					= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1641e5c31af7Sopenharmony_ci
1642e5c31af7Sopenharmony_ci	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
1643e5c31af7Sopenharmony_ci	const float									dstW				= float(dstSize.x());
1644e5c31af7Sopenharmony_ci	const float									dstH				= float(dstSize.y());
1645e5c31af7Sopenharmony_ci	const int									srcSize				= src.getSize();
1646e5c31af7Sopenharmony_ci
1647e5c31af7Sopenharmony_ci	// Coordinates per triangle.
1648e5c31af7Sopenharmony_ci	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1649e5c31af7Sopenharmony_ci	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1650e5c31af7Sopenharmony_ci	const tcu::Vec3								triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1651e5c31af7Sopenharmony_ci	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1652e5c31af7Sopenharmony_ci
1653e5c31af7Sopenharmony_ci	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1654e5c31af7Sopenharmony_ci
1655e5c31af7Sopenharmony_ci	const float									posEps				= 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1656e5c31af7Sopenharmony_ci
1657e5c31af7Sopenharmony_ci	// imageViewMinLodRel is used to calculate the image level to sample from, when VK_EXT_image_view_min_lod extension is enabled.
1658e5c31af7Sopenharmony_ci	// The value is relative to baseLevel as the Texture*View 'src' was created as the baseLevel being level[0].
1659e5c31af7Sopenharmony_ci	const float									imageViewMinLodRel	= sampleParams.imageViewMinLod - (float)sampleParams.baseLevel;
1660e5c31af7Sopenharmony_ci	// We need to adapt ImageView's minLod value to the mipmap mdoe (i.e. nearest or linear) so we clamp with the right minLod value later.
1661e5c31af7Sopenharmony_ci	const float									imageViewMinLodRelMode = tcu::isSamplerMipmapModeLinear(sampleParams.sampler.minFilter) ? deFloatFloor(imageViewMinLodRel) : (float)deClamp32((int)deFloatCeil(imageViewMinLodRel + 0.5f) - 1, sampleParams.baseLevel, sampleParams.maxLevel);
1662e5c31af7Sopenharmony_ci	const float									minLod				= (sampleParams.imageViewMinLod != 0.0f) ? de::max(imageViewMinLodRelMode, sampleParams.minLod) : sampleParams.minLod;
1663e5c31af7Sopenharmony_ci
1664e5c31af7Sopenharmony_ci	int											numFailed			= 0;
1665e5c31af7Sopenharmony_ci
1666e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
1667e5c31af7Sopenharmony_ci	{
1668e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
1669e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
1670e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
1671e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
1672e5c31af7Sopenharmony_ci
1673e5c31af7Sopenharmony_ci		// \note Not strictly allowed by spec, but implementations do this in practice.
1674e5c31af7Sopenharmony_ci		tcu::Vec2(-1, -1),
1675e5c31af7Sopenharmony_ci		tcu::Vec2(-1, +1),
1676e5c31af7Sopenharmony_ci		tcu::Vec2(+1, -1),
1677e5c31af7Sopenharmony_ci		tcu::Vec2(+1, +1),
1678e5c31af7Sopenharmony_ci	};
1679e5c31af7Sopenharmony_ci
1680e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
1681e5c31af7Sopenharmony_ci
1682e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
1683e5c31af7Sopenharmony_ci	{
1684e5c31af7Sopenharmony_ci		// Ugly hack, validation can take way too long at the moment.
1685e5c31af7Sopenharmony_ci		if (watchDog)
1686e5c31af7Sopenharmony_ci			qpWatchDog_touch(watchDog);
1687e5c31af7Sopenharmony_ci
1688e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
1689e5c31af7Sopenharmony_ci		{
1690e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
1691e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
1692e5c31af7Sopenharmony_ci
1693e5c31af7Sopenharmony_ci			// Try comparison to ideal reference first, and if that fails use slower verificator.
1694e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1695e5c31af7Sopenharmony_ci			{
1696e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
1697e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
1698e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
1699e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
1700e5c31af7Sopenharmony_ci
1701e5c31af7Sopenharmony_ci				const bool		tri0	= (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1702e5c31af7Sopenharmony_ci				const bool		tri1	= (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1703e5c31af7Sopenharmony_ci
1704e5c31af7Sopenharmony_ci				bool			isOk	= false;
1705e5c31af7Sopenharmony_ci
1706e5c31af7Sopenharmony_ci				DE_ASSERT(tri0 || tri1);
1707e5c31af7Sopenharmony_ci
1708e5c31af7Sopenharmony_ci				// Pixel can belong to either of the triangles if it lies close enough to the edge.
1709e5c31af7Sopenharmony_ci				for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1710e5c31af7Sopenharmony_ci				{
1711e5c31af7Sopenharmony_ci					const float		triWx	= triNdx ? dstW - wx : wx;
1712e5c31af7Sopenharmony_ci					const float		triWy	= triNdx ? dstH - wy : wy;
1713e5c31af7Sopenharmony_ci					const float		triNx	= triNdx ? 1.0f - nx : nx;
1714e5c31af7Sopenharmony_ci					const float		triNy	= triNdx ? 1.0f - ny : ny;
1715e5c31af7Sopenharmony_ci
1716e5c31af7Sopenharmony_ci					const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1717e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1718e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1719e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDx		(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1720e5c31af7Sopenharmony_ci												 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1721e5c31af7Sopenharmony_ci												 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
1722e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDy		(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1723e5c31af7Sopenharmony_ci												 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1724e5c31af7Sopenharmony_ci												 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
1725e5c31af7Sopenharmony_ci
1726e5c31af7Sopenharmony_ci					tcu::Vec2		lodBounds	= tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
1727e5c31af7Sopenharmony_ci
1728e5c31af7Sopenharmony_ci					// Compute lod bounds across lodOffsets range.
1729e5c31af7Sopenharmony_ci					for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1730e5c31af7Sopenharmony_ci					{
1731e5c31af7Sopenharmony_ci						const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
1732e5c31af7Sopenharmony_ci						const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
1733e5c31af7Sopenharmony_ci						const float		nxo		= wxo/dstW;
1734e5c31af7Sopenharmony_ci						const float		nyo		= wyo/dstH;
1735e5c31af7Sopenharmony_ci
1736e5c31af7Sopenharmony_ci						const tcu::Vec3	coordO		(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
1737e5c31af7Sopenharmony_ci													 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
1738e5c31af7Sopenharmony_ci													 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
1739e5c31af7Sopenharmony_ci						const tcu::Vec3	coordDxo	(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1740e5c31af7Sopenharmony_ci													 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1741e5c31af7Sopenharmony_ci													 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
1742e5c31af7Sopenharmony_ci						const tcu::Vec3	coordDyo	(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1743e5c31af7Sopenharmony_ci													 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1744e5c31af7Sopenharmony_ci													 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
1745e5c31af7Sopenharmony_ci						const tcu::Vec2	lodO		= tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
1746e5c31af7Sopenharmony_ci
1747e5c31af7Sopenharmony_ci						lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1748e5c31af7Sopenharmony_ci						lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1749e5c31af7Sopenharmony_ci					}
1750e5c31af7Sopenharmony_ci
1751e5c31af7Sopenharmony_ci					const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
1752e5c31af7Sopenharmony_ci
1753e5c31af7Sopenharmony_ci					if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1754e5c31af7Sopenharmony_ci					{
1755e5c31af7Sopenharmony_ci						isOk = true;
1756e5c31af7Sopenharmony_ci						break;
1757e5c31af7Sopenharmony_ci					}
1758e5c31af7Sopenharmony_ci				}
1759e5c31af7Sopenharmony_ci
1760e5c31af7Sopenharmony_ci				if (!isOk)
1761e5c31af7Sopenharmony_ci				{
1762e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1763e5c31af7Sopenharmony_ci					numFailed += 1;
1764e5c31af7Sopenharmony_ci				}
1765e5c31af7Sopenharmony_ci			}
1766e5c31af7Sopenharmony_ci		}
1767e5c31af7Sopenharmony_ci	}
1768e5c31af7Sopenharmony_ci
1769e5c31af7Sopenharmony_ci	return numFailed;
1770e5c31af7Sopenharmony_ci}
1771e5c31af7Sopenharmony_ci
1772e5c31af7Sopenharmony_cibool verifyTextureResult (tcu::TestContext&						testCtx,
1773e5c31af7Sopenharmony_ci						  const tcu::ConstPixelBufferAccess&	result,
1774e5c31af7Sopenharmony_ci						  const tcu::TextureCubeView&			src,
1775e5c31af7Sopenharmony_ci						  const float*							texCoord,
1776e5c31af7Sopenharmony_ci						  const ReferenceParams&				sampleParams,
1777e5c31af7Sopenharmony_ci						  const tcu::LookupPrecision&			lookupPrec,
1778e5c31af7Sopenharmony_ci						  const tcu::LodPrecision&				lodPrec,
1779e5c31af7Sopenharmony_ci						  const tcu::PixelFormat&				pixelFormat)
1780e5c31af7Sopenharmony_ci{
1781e5c31af7Sopenharmony_ci	tcu::TestLog&	log				= testCtx.getLog();
1782e5c31af7Sopenharmony_ci	tcu::Surface	reference		(result.getWidth(), result.getHeight());
1783e5c31af7Sopenharmony_ci	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
1784e5c31af7Sopenharmony_ci	int				numFailedPixels;
1785e5c31af7Sopenharmony_ci
1786e5c31af7Sopenharmony_ci	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1787e5c31af7Sopenharmony_ci
1788e5c31af7Sopenharmony_ci	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1789e5c31af7Sopenharmony_ci	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1790e5c31af7Sopenharmony_ci
1791e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
1792e5c31af7Sopenharmony_ci		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1793e5c31af7Sopenharmony_ci
1794e5c31af7Sopenharmony_ci	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1795e5c31af7Sopenharmony_ci		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
1796e5c31af7Sopenharmony_ci
1797e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
1798e5c31af7Sopenharmony_ci	{
1799e5c31af7Sopenharmony_ci		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1800e5c31af7Sopenharmony_ci			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1801e5c31af7Sopenharmony_ci	}
1802e5c31af7Sopenharmony_ci
1803e5c31af7Sopenharmony_ci	log << tcu::TestLog::EndImageSet;
1804e5c31af7Sopenharmony_ci
1805e5c31af7Sopenharmony_ci	return numFailedPixels == 0;
1806e5c31af7Sopenharmony_ci}
1807e5c31af7Sopenharmony_ci
1808e5c31af7Sopenharmony_ci//! Verifies texture lookup results and returns number of failed pixels.
1809e5c31af7Sopenharmony_ciint computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
1810e5c31af7Sopenharmony_ci							  const tcu::ConstPixelBufferAccess&	reference,
1811e5c31af7Sopenharmony_ci							  const tcu::PixelBufferAccess&			errorMask,
1812e5c31af7Sopenharmony_ci							  const tcu::Texture3DView&				baseView,
1813e5c31af7Sopenharmony_ci							  const float*							texCoord,
1814e5c31af7Sopenharmony_ci							  const ReferenceParams&				sampleParams,
1815e5c31af7Sopenharmony_ci							  const tcu::LookupPrecision&			lookupPrec,
1816e5c31af7Sopenharmony_ci							  const tcu::LodPrecision&				lodPrec,
1817e5c31af7Sopenharmony_ci							  qpWatchDog*							watchDog)
1818e5c31af7Sopenharmony_ci{
1819e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1820e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1821e5c31af7Sopenharmony_ci
1822e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
1823e5c31af7Sopenharmony_ci	tcu::ImageViewMinLodParams	minLodParams =
1824e5c31af7Sopenharmony_ci	{
1825e5c31af7Sopenharmony_ci		sampleParams.baseLevel,									// int		baseLevel;
1826e5c31af7Sopenharmony_ci		{
1827e5c31af7Sopenharmony_ci			sampleParams.imageViewMinLod,						// float	minLod;
1828e5c31af7Sopenharmony_ci			sampleParams.imageViewMinLodMode,					// ImageViewMinLodMode
1829e5c31af7Sopenharmony_ci		},
1830e5c31af7Sopenharmony_ci		sampleParams.samplerType == SAMPLERTYPE_FETCH_FLOAT		// bool	intTexCoord;
1831e5c31af7Sopenharmony_ci	};
1832e5c31af7Sopenharmony_ci
1833e5c31af7Sopenharmony_ci	const tcu::Texture3DView					src					= getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel, sampleParams.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL), srcLevelStorage, sampleParams.sampler);
1834e5c31af7Sopenharmony_ci
1835e5c31af7Sopenharmony_ci	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1836e5c31af7Sopenharmony_ci	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1837e5c31af7Sopenharmony_ci	const tcu::Vec4								rq					= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1838e5c31af7Sopenharmony_ci
1839e5c31af7Sopenharmony_ci	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
1840e5c31af7Sopenharmony_ci	const float									dstW				= float(dstSize.x());
1841e5c31af7Sopenharmony_ci	const float									dstH				= float(dstSize.y());
1842e5c31af7Sopenharmony_ci	const tcu::IVec3							srcSize				= tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
1843e5c31af7Sopenharmony_ci
1844e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
1845e5c31af7Sopenharmony_ci	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1846e5c31af7Sopenharmony_ci	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1847e5c31af7Sopenharmony_ci	const tcu::Vec3								triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1848e5c31af7Sopenharmony_ci	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1849e5c31af7Sopenharmony_ci
1850e5c31af7Sopenharmony_ci	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1851e5c31af7Sopenharmony_ci
1852e5c31af7Sopenharmony_ci	// imageViewMinLodRel is used to calculate the image level to sample from, when VK_EXT_image_view_min_lod extension is enabled.
1853e5c31af7Sopenharmony_ci	// The value is relative to baseLevel as the Texture*View 'src' was created as the baseLevel being level[0].
1854e5c31af7Sopenharmony_ci	const float									imageViewMinLodRel	= sampleParams.imageViewMinLod - (float)sampleParams.baseLevel;
1855e5c31af7Sopenharmony_ci	// We need to adapt ImageView's minLod value to the mipmap mdoe (i.e. nearest or linear) so we clamp with the right minLod value later.
1856e5c31af7Sopenharmony_ci	const float									imageViewMinLodRelMode = tcu::isSamplerMipmapModeLinear(sampleParams.sampler.minFilter) ? deFloatFloor(imageViewMinLodRel) : (float)deClamp32((int)deFloatCeil(imageViewMinLodRel + 0.5f) - 1, sampleParams.baseLevel, sampleParams.maxLevel);
1857e5c31af7Sopenharmony_ci	const float									minLod				= (sampleParams.imageViewMinLod != 0.0f) ? de::max(imageViewMinLodRelMode, sampleParams.minLod) : sampleParams.minLod;
1858e5c31af7Sopenharmony_ci
1859e5c31af7Sopenharmony_ci	const float									posEps				= 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1860e5c31af7Sopenharmony_ci
1861e5c31af7Sopenharmony_ci	int											numFailed			= 0;
1862e5c31af7Sopenharmony_ci
1863e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
1864e5c31af7Sopenharmony_ci	{
1865e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
1866e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
1867e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
1868e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
1869e5c31af7Sopenharmony_ci	};
1870e5c31af7Sopenharmony_ci
1871e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
1872e5c31af7Sopenharmony_ci
1873e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
1874e5c31af7Sopenharmony_ci	{
1875e5c31af7Sopenharmony_ci		// Ugly hack, validation can take way too long at the moment.
1876e5c31af7Sopenharmony_ci		if (watchDog)
1877e5c31af7Sopenharmony_ci			qpWatchDog_touch(watchDog);
1878e5c31af7Sopenharmony_ci
1879e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
1880e5c31af7Sopenharmony_ci		{
1881e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
1882e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
1883e5c31af7Sopenharmony_ci
1884e5c31af7Sopenharmony_ci			// Try comparison to ideal reference first, and if that fails use slower verificator.
1885e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1886e5c31af7Sopenharmony_ci			{
1887e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
1888e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
1889e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
1890e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
1891e5c31af7Sopenharmony_ci
1892e5c31af7Sopenharmony_ci				const bool		tri0	= (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1893e5c31af7Sopenharmony_ci				const bool		tri1	= (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1894e5c31af7Sopenharmony_ci
1895e5c31af7Sopenharmony_ci				bool			isOk	= false;
1896e5c31af7Sopenharmony_ci
1897e5c31af7Sopenharmony_ci				DE_ASSERT(tri0 || tri1);
1898e5c31af7Sopenharmony_ci
1899e5c31af7Sopenharmony_ci				// Pixel can belong to either of the triangles if it lies close enough to the edge.
1900e5c31af7Sopenharmony_ci				for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1901e5c31af7Sopenharmony_ci				{
1902e5c31af7Sopenharmony_ci					const float		triWx	= triNdx ? dstW - wx : wx;
1903e5c31af7Sopenharmony_ci					const float		triWy	= triNdx ? dstH - wy : wy;
1904e5c31af7Sopenharmony_ci					const float		triNx	= triNdx ? 1.0f - nx : nx;
1905e5c31af7Sopenharmony_ci					const float		triNy	= triNdx ? 1.0f - ny : ny;
1906e5c31af7Sopenharmony_ci
1907e5c31af7Sopenharmony_ci					const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1908e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1909e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1910e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDx		= tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1911e5c31af7Sopenharmony_ci															triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1912e5c31af7Sopenharmony_ci															triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1913e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDy		= tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1914e5c31af7Sopenharmony_ci															triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1915e5c31af7Sopenharmony_ci															triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1916e5c31af7Sopenharmony_ci
1917e5c31af7Sopenharmony_ci					tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
1918e5c31af7Sopenharmony_ci
1919e5c31af7Sopenharmony_ci					// Compute lod bounds across lodOffsets range.
1920e5c31af7Sopenharmony_ci					for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1921e5c31af7Sopenharmony_ci					{
1922e5c31af7Sopenharmony_ci						const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
1923e5c31af7Sopenharmony_ci						const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
1924e5c31af7Sopenharmony_ci						const float		nxo		= wxo/dstW;
1925e5c31af7Sopenharmony_ci						const float		nyo		= wyo/dstH;
1926e5c31af7Sopenharmony_ci
1927e5c31af7Sopenharmony_ci						const tcu::Vec3	coordDxo	= tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1928e5c31af7Sopenharmony_ci																triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1929e5c31af7Sopenharmony_ci																triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1930e5c31af7Sopenharmony_ci						const tcu::Vec3	coordDyo	= tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1931e5c31af7Sopenharmony_ci																triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1932e5c31af7Sopenharmony_ci																triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1933e5c31af7Sopenharmony_ci						const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
1934e5c31af7Sopenharmony_ci
1935e5c31af7Sopenharmony_ci						lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1936e5c31af7Sopenharmony_ci						lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1937e5c31af7Sopenharmony_ci					}
1938e5c31af7Sopenharmony_ci
1939e5c31af7Sopenharmony_ci					const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
1940e5c31af7Sopenharmony_ci
1941e5c31af7Sopenharmony_ci					if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1942e5c31af7Sopenharmony_ci					{
1943e5c31af7Sopenharmony_ci						isOk = true;
1944e5c31af7Sopenharmony_ci						break;
1945e5c31af7Sopenharmony_ci					}
1946e5c31af7Sopenharmony_ci				}
1947e5c31af7Sopenharmony_ci
1948e5c31af7Sopenharmony_ci				if (!isOk)
1949e5c31af7Sopenharmony_ci				{
1950e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1951e5c31af7Sopenharmony_ci					numFailed += 1;
1952e5c31af7Sopenharmony_ci				}
1953e5c31af7Sopenharmony_ci			}
1954e5c31af7Sopenharmony_ci		}
1955e5c31af7Sopenharmony_ci	}
1956e5c31af7Sopenharmony_ci
1957e5c31af7Sopenharmony_ci	return numFailed;
1958e5c31af7Sopenharmony_ci}
1959e5c31af7Sopenharmony_ci
1960e5c31af7Sopenharmony_cibool verifyTextureResult (tcu::TestContext&						testCtx,
1961e5c31af7Sopenharmony_ci						  const tcu::ConstPixelBufferAccess&	result,
1962e5c31af7Sopenharmony_ci						  const tcu::Texture3DView&				src,
1963e5c31af7Sopenharmony_ci						  const float*							texCoord,
1964e5c31af7Sopenharmony_ci						  const ReferenceParams&				sampleParams,
1965e5c31af7Sopenharmony_ci						  const tcu::LookupPrecision&			lookupPrec,
1966e5c31af7Sopenharmony_ci						  const tcu::LodPrecision&				lodPrec,
1967e5c31af7Sopenharmony_ci						  const tcu::PixelFormat&				pixelFormat)
1968e5c31af7Sopenharmony_ci{
1969e5c31af7Sopenharmony_ci	tcu::TestLog&	log				= testCtx.getLog();
1970e5c31af7Sopenharmony_ci	tcu::Surface	reference		(result.getWidth(), result.getHeight());
1971e5c31af7Sopenharmony_ci	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
1972e5c31af7Sopenharmony_ci	int				numFailedPixels;
1973e5c31af7Sopenharmony_ci
1974e5c31af7Sopenharmony_ci	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1975e5c31af7Sopenharmony_ci
1976e5c31af7Sopenharmony_ci	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1977e5c31af7Sopenharmony_ci	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1978e5c31af7Sopenharmony_ci
1979e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
1980e5c31af7Sopenharmony_ci		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1981e5c31af7Sopenharmony_ci
1982e5c31af7Sopenharmony_ci	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1983e5c31af7Sopenharmony_ci		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
1984e5c31af7Sopenharmony_ci
1985e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
1986e5c31af7Sopenharmony_ci	{
1987e5c31af7Sopenharmony_ci		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1988e5c31af7Sopenharmony_ci			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1989e5c31af7Sopenharmony_ci	}
1990e5c31af7Sopenharmony_ci
1991e5c31af7Sopenharmony_ci	log << tcu::TestLog::EndImageSet;
1992e5c31af7Sopenharmony_ci
1993e5c31af7Sopenharmony_ci	return numFailedPixels == 0;
1994e5c31af7Sopenharmony_ci}
1995e5c31af7Sopenharmony_ci
1996e5c31af7Sopenharmony_ci//! Verifies texture lookup results and returns number of failed pixels.
1997e5c31af7Sopenharmony_ciint computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
1998e5c31af7Sopenharmony_ci							  const tcu::ConstPixelBufferAccess&	reference,
1999e5c31af7Sopenharmony_ci							  const tcu::PixelBufferAccess&			errorMask,
2000e5c31af7Sopenharmony_ci							  const tcu::Texture1DArrayView&		baseView,
2001e5c31af7Sopenharmony_ci							  const float*							texCoord,
2002e5c31af7Sopenharmony_ci							  const ReferenceParams&				sampleParams,
2003e5c31af7Sopenharmony_ci							  const tcu::LookupPrecision&			lookupPrec,
2004e5c31af7Sopenharmony_ci							  const tcu::LodPrecision&				lodPrec,
2005e5c31af7Sopenharmony_ci							  qpWatchDog*							watchDog)
2006e5c31af7Sopenharmony_ci{
2007e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2008e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2009e5c31af7Sopenharmony_ci
2010e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
2011e5c31af7Sopenharmony_ci	const tcu::Texture1DArrayView				src					= getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
2012e5c31af7Sopenharmony_ci
2013e5c31af7Sopenharmony_ci	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2014e5c31af7Sopenharmony_ci	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2015e5c31af7Sopenharmony_ci
2016e5c31af7Sopenharmony_ci	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
2017e5c31af7Sopenharmony_ci	const float									dstW				= float(dstSize.x());
2018e5c31af7Sopenharmony_ci	const float									dstH				= float(dstSize.y());
2019e5c31af7Sopenharmony_ci	const float									srcSize				= float(src.getWidth()); // For lod computation, thus #layers is ignored.
2020e5c31af7Sopenharmony_ci
2021e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
2022e5c31af7Sopenharmony_ci	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2023e5c31af7Sopenharmony_ci	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2024e5c31af7Sopenharmony_ci	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2025e5c31af7Sopenharmony_ci
2026e5c31af7Sopenharmony_ci	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2027e5c31af7Sopenharmony_ci
2028e5c31af7Sopenharmony_ci	int											numFailed			= 0;
2029e5c31af7Sopenharmony_ci
2030e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
2031e5c31af7Sopenharmony_ci	{
2032e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
2033e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
2034e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
2035e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
2036e5c31af7Sopenharmony_ci	};
2037e5c31af7Sopenharmony_ci
2038e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2039e5c31af7Sopenharmony_ci
2040e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
2041e5c31af7Sopenharmony_ci	{
2042e5c31af7Sopenharmony_ci		// Ugly hack, validation can take way too long at the moment.
2043e5c31af7Sopenharmony_ci		if (watchDog)
2044e5c31af7Sopenharmony_ci			qpWatchDog_touch(watchDog);
2045e5c31af7Sopenharmony_ci
2046e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
2047e5c31af7Sopenharmony_ci		{
2048e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
2049e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
2050e5c31af7Sopenharmony_ci
2051e5c31af7Sopenharmony_ci			// Try comparison to ideal reference first, and if that fails use slower verificator.
2052e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2053e5c31af7Sopenharmony_ci			{
2054e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
2055e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
2056e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
2057e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
2058e5c31af7Sopenharmony_ci
2059e5c31af7Sopenharmony_ci				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2060e5c31af7Sopenharmony_ci				const float		triWx	= triNdx ? dstW - wx : wx;
2061e5c31af7Sopenharmony_ci				const float		triWy	= triNdx ? dstH - wy : wy;
2062e5c31af7Sopenharmony_ci				const float		triNx	= triNdx ? 1.0f - nx : nx;
2063e5c31af7Sopenharmony_ci				const float		triNy	= triNdx ? 1.0f - ny : ny;
2064e5c31af7Sopenharmony_ci
2065e5c31af7Sopenharmony_ci				const tcu::Vec2	coord	(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2066e5c31af7Sopenharmony_ci										 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2067e5c31af7Sopenharmony_ci				const float	coordDx		= triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
2068e5c31af7Sopenharmony_ci				const float	coordDy		= triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
2069e5c31af7Sopenharmony_ci
2070e5c31af7Sopenharmony_ci				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
2071e5c31af7Sopenharmony_ci
2072e5c31af7Sopenharmony_ci				// Compute lod bounds across lodOffsets range.
2073e5c31af7Sopenharmony_ci				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2074e5c31af7Sopenharmony_ci				{
2075e5c31af7Sopenharmony_ci					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2076e5c31af7Sopenharmony_ci					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2077e5c31af7Sopenharmony_ci					const float		nxo		= wxo/dstW;
2078e5c31af7Sopenharmony_ci					const float		nyo		= wyo/dstH;
2079e5c31af7Sopenharmony_ci
2080e5c31af7Sopenharmony_ci					const float	coordDxo		= triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
2081e5c31af7Sopenharmony_ci					const float	coordDyo		= triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
2082e5c31af7Sopenharmony_ci					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
2083e5c31af7Sopenharmony_ci
2084e5c31af7Sopenharmony_ci					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2085e5c31af7Sopenharmony_ci					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2086e5c31af7Sopenharmony_ci				}
2087e5c31af7Sopenharmony_ci
2088e5c31af7Sopenharmony_ci				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2089e5c31af7Sopenharmony_ci				const bool		isOk		= tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2090e5c31af7Sopenharmony_ci
2091e5c31af7Sopenharmony_ci				if (!isOk)
2092e5c31af7Sopenharmony_ci				{
2093e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2094e5c31af7Sopenharmony_ci					numFailed += 1;
2095e5c31af7Sopenharmony_ci				}
2096e5c31af7Sopenharmony_ci			}
2097e5c31af7Sopenharmony_ci		}
2098e5c31af7Sopenharmony_ci	}
2099e5c31af7Sopenharmony_ci
2100e5c31af7Sopenharmony_ci	return numFailed;
2101e5c31af7Sopenharmony_ci}
2102e5c31af7Sopenharmony_ci
2103e5c31af7Sopenharmony_ci//! Verifies texture lookup results and returns number of failed pixels.
2104e5c31af7Sopenharmony_ciint computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
2105e5c31af7Sopenharmony_ci							  const tcu::ConstPixelBufferAccess&	reference,
2106e5c31af7Sopenharmony_ci							  const tcu::PixelBufferAccess&			errorMask,
2107e5c31af7Sopenharmony_ci							  const tcu::Texture2DArrayView&		baseView,
2108e5c31af7Sopenharmony_ci							  const float*							texCoord,
2109e5c31af7Sopenharmony_ci							  const ReferenceParams&				sampleParams,
2110e5c31af7Sopenharmony_ci							  const tcu::LookupPrecision&			lookupPrec,
2111e5c31af7Sopenharmony_ci							  const tcu::LodPrecision&				lodPrec,
2112e5c31af7Sopenharmony_ci							  qpWatchDog*							watchDog)
2113e5c31af7Sopenharmony_ci{
2114e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2115e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2116e5c31af7Sopenharmony_ci
2117e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
2118e5c31af7Sopenharmony_ci	const tcu::Texture2DArrayView				src					= getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
2119e5c31af7Sopenharmony_ci
2120e5c31af7Sopenharmony_ci	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2121e5c31af7Sopenharmony_ci	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2122e5c31af7Sopenharmony_ci	const tcu::Vec4								rq					= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2123e5c31af7Sopenharmony_ci
2124e5c31af7Sopenharmony_ci	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
2125e5c31af7Sopenharmony_ci	const float									dstW				= float(dstSize.x());
2126e5c31af7Sopenharmony_ci	const float									dstH				= float(dstSize.y());
2127e5c31af7Sopenharmony_ci	const tcu::Vec2								srcSize				= tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
2128e5c31af7Sopenharmony_ci
2129e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
2130e5c31af7Sopenharmony_ci	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2131e5c31af7Sopenharmony_ci	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2132e5c31af7Sopenharmony_ci	const tcu::Vec3								triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2133e5c31af7Sopenharmony_ci	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2134e5c31af7Sopenharmony_ci
2135e5c31af7Sopenharmony_ci	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2136e5c31af7Sopenharmony_ci
2137e5c31af7Sopenharmony_ci	int											numFailed			= 0;
2138e5c31af7Sopenharmony_ci
2139e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
2140e5c31af7Sopenharmony_ci	{
2141e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
2142e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
2143e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
2144e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
2145e5c31af7Sopenharmony_ci	};
2146e5c31af7Sopenharmony_ci
2147e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2148e5c31af7Sopenharmony_ci
2149e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
2150e5c31af7Sopenharmony_ci	{
2151e5c31af7Sopenharmony_ci		// Ugly hack, validation can take way too long at the moment.
2152e5c31af7Sopenharmony_ci		if (watchDog)
2153e5c31af7Sopenharmony_ci			qpWatchDog_touch(watchDog);
2154e5c31af7Sopenharmony_ci
2155e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
2156e5c31af7Sopenharmony_ci		{
2157e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
2158e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
2159e5c31af7Sopenharmony_ci
2160e5c31af7Sopenharmony_ci			// Try comparison to ideal reference first, and if that fails use slower verificator.
2161e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2162e5c31af7Sopenharmony_ci			{
2163e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
2164e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
2165e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
2166e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
2167e5c31af7Sopenharmony_ci
2168e5c31af7Sopenharmony_ci				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2169e5c31af7Sopenharmony_ci				const float		triWx	= triNdx ? dstW - wx : wx;
2170e5c31af7Sopenharmony_ci				const float		triWy	= triNdx ? dstH - wy : wy;
2171e5c31af7Sopenharmony_ci				const float		triNx	= triNdx ? 1.0f - nx : nx;
2172e5c31af7Sopenharmony_ci				const float		triNy	= triNdx ? 1.0f - ny : ny;
2173e5c31af7Sopenharmony_ci
2174e5c31af7Sopenharmony_ci				const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2175e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2176e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2177e5c31af7Sopenharmony_ci				const tcu::Vec2	coordDx		= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2178e5c31af7Sopenharmony_ci														triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2179e5c31af7Sopenharmony_ci				const tcu::Vec2	coordDy		= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2180e5c31af7Sopenharmony_ci														triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2181e5c31af7Sopenharmony_ci
2182e5c31af7Sopenharmony_ci				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2183e5c31af7Sopenharmony_ci
2184e5c31af7Sopenharmony_ci				// Compute lod bounds across lodOffsets range.
2185e5c31af7Sopenharmony_ci				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2186e5c31af7Sopenharmony_ci				{
2187e5c31af7Sopenharmony_ci					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2188e5c31af7Sopenharmony_ci					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2189e5c31af7Sopenharmony_ci					const float		nxo		= wxo/dstW;
2190e5c31af7Sopenharmony_ci					const float		nyo		= wyo/dstH;
2191e5c31af7Sopenharmony_ci
2192e5c31af7Sopenharmony_ci					const tcu::Vec2	coordDxo	= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2193e5c31af7Sopenharmony_ci															triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2194e5c31af7Sopenharmony_ci					const tcu::Vec2	coordDyo	= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2195e5c31af7Sopenharmony_ci															triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2196e5c31af7Sopenharmony_ci					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2197e5c31af7Sopenharmony_ci
2198e5c31af7Sopenharmony_ci					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2199e5c31af7Sopenharmony_ci					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2200e5c31af7Sopenharmony_ci				}
2201e5c31af7Sopenharmony_ci
2202e5c31af7Sopenharmony_ci				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2203e5c31af7Sopenharmony_ci				const bool		isOk		= tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2204e5c31af7Sopenharmony_ci
2205e5c31af7Sopenharmony_ci				if (!isOk)
2206e5c31af7Sopenharmony_ci				{
2207e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2208e5c31af7Sopenharmony_ci					numFailed += 1;
2209e5c31af7Sopenharmony_ci				}
2210e5c31af7Sopenharmony_ci			}
2211e5c31af7Sopenharmony_ci		}
2212e5c31af7Sopenharmony_ci	}
2213e5c31af7Sopenharmony_ci
2214e5c31af7Sopenharmony_ci	return numFailed;
2215e5c31af7Sopenharmony_ci}
2216e5c31af7Sopenharmony_ci
2217e5c31af7Sopenharmony_cibool verifyTextureResult (tcu::TestContext&						testCtx,
2218e5c31af7Sopenharmony_ci						  const tcu::ConstPixelBufferAccess&	result,
2219e5c31af7Sopenharmony_ci						  const tcu::Texture1DArrayView&		src,
2220e5c31af7Sopenharmony_ci						  const float*							texCoord,
2221e5c31af7Sopenharmony_ci						  const ReferenceParams&				sampleParams,
2222e5c31af7Sopenharmony_ci						  const tcu::LookupPrecision&			lookupPrec,
2223e5c31af7Sopenharmony_ci						  const tcu::LodPrecision&				lodPrec,
2224e5c31af7Sopenharmony_ci						  const tcu::PixelFormat&				pixelFormat)
2225e5c31af7Sopenharmony_ci{
2226e5c31af7Sopenharmony_ci	tcu::TestLog&	log				= testCtx.getLog();
2227e5c31af7Sopenharmony_ci	tcu::Surface	reference		(result.getWidth(), result.getHeight());
2228e5c31af7Sopenharmony_ci	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
2229e5c31af7Sopenharmony_ci	int				numFailedPixels;
2230e5c31af7Sopenharmony_ci
2231e5c31af7Sopenharmony_ci	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2232e5c31af7Sopenharmony_ci
2233e5c31af7Sopenharmony_ci	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2234e5c31af7Sopenharmony_ci	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2235e5c31af7Sopenharmony_ci
2236e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
2237e5c31af7Sopenharmony_ci		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2238e5c31af7Sopenharmony_ci
2239e5c31af7Sopenharmony_ci	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2240e5c31af7Sopenharmony_ci		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
2241e5c31af7Sopenharmony_ci
2242e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
2243e5c31af7Sopenharmony_ci	{
2244e5c31af7Sopenharmony_ci		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2245e5c31af7Sopenharmony_ci			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2246e5c31af7Sopenharmony_ci	}
2247e5c31af7Sopenharmony_ci
2248e5c31af7Sopenharmony_ci	log << tcu::TestLog::EndImageSet;
2249e5c31af7Sopenharmony_ci
2250e5c31af7Sopenharmony_ci	return numFailedPixels == 0;
2251e5c31af7Sopenharmony_ci}
2252e5c31af7Sopenharmony_ci
2253e5c31af7Sopenharmony_cibool verifyTextureResult (tcu::TestContext&						testCtx,
2254e5c31af7Sopenharmony_ci						  const tcu::ConstPixelBufferAccess&	result,
2255e5c31af7Sopenharmony_ci						  const tcu::Texture2DArrayView&		src,
2256e5c31af7Sopenharmony_ci						  const float*							texCoord,
2257e5c31af7Sopenharmony_ci						  const ReferenceParams&				sampleParams,
2258e5c31af7Sopenharmony_ci						  const tcu::LookupPrecision&			lookupPrec,
2259e5c31af7Sopenharmony_ci						  const tcu::LodPrecision&				lodPrec,
2260e5c31af7Sopenharmony_ci						  const tcu::PixelFormat&				pixelFormat)
2261e5c31af7Sopenharmony_ci{
2262e5c31af7Sopenharmony_ci	tcu::TestLog&	log				= testCtx.getLog();
2263e5c31af7Sopenharmony_ci	tcu::Surface	reference		(result.getWidth(), result.getHeight());
2264e5c31af7Sopenharmony_ci	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
2265e5c31af7Sopenharmony_ci	int				numFailedPixels;
2266e5c31af7Sopenharmony_ci
2267e5c31af7Sopenharmony_ci	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2268e5c31af7Sopenharmony_ci
2269e5c31af7Sopenharmony_ci	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2270e5c31af7Sopenharmony_ci	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2271e5c31af7Sopenharmony_ci
2272e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
2273e5c31af7Sopenharmony_ci		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2274e5c31af7Sopenharmony_ci
2275e5c31af7Sopenharmony_ci	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2276e5c31af7Sopenharmony_ci		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
2277e5c31af7Sopenharmony_ci
2278e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
2279e5c31af7Sopenharmony_ci	{
2280e5c31af7Sopenharmony_ci		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2281e5c31af7Sopenharmony_ci			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2282e5c31af7Sopenharmony_ci	}
2283e5c31af7Sopenharmony_ci
2284e5c31af7Sopenharmony_ci	log << tcu::TestLog::EndImageSet;
2285e5c31af7Sopenharmony_ci
2286e5c31af7Sopenharmony_ci	return numFailedPixels == 0;
2287e5c31af7Sopenharmony_ci}
2288e5c31af7Sopenharmony_ci
2289e5c31af7Sopenharmony_ci//! Verifies texture lookup results and returns number of failed pixels.
2290e5c31af7Sopenharmony_ciint computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
2291e5c31af7Sopenharmony_ci							  const tcu::ConstPixelBufferAccess&	reference,
2292e5c31af7Sopenharmony_ci							  const tcu::PixelBufferAccess&			errorMask,
2293e5c31af7Sopenharmony_ci							  const tcu::TextureCubeArrayView&		baseView,
2294e5c31af7Sopenharmony_ci							  const float*							texCoord,
2295e5c31af7Sopenharmony_ci							  const ReferenceParams&				sampleParams,
2296e5c31af7Sopenharmony_ci							  const tcu::LookupPrecision&			lookupPrec,
2297e5c31af7Sopenharmony_ci							  const tcu::IVec4&						coordBits,
2298e5c31af7Sopenharmony_ci							  const tcu::LodPrecision&				lodPrec,
2299e5c31af7Sopenharmony_ci							  qpWatchDog*							watchDog)
2300e5c31af7Sopenharmony_ci{
2301e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2302e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2303e5c31af7Sopenharmony_ci
2304e5c31af7Sopenharmony_ci	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
2305e5c31af7Sopenharmony_ci	tcu::ImageViewMinLodParams	minLodParams =
2306e5c31af7Sopenharmony_ci	{
2307e5c31af7Sopenharmony_ci		sampleParams.baseLevel,									// int		baseLevel;
2308e5c31af7Sopenharmony_ci		{
2309e5c31af7Sopenharmony_ci			sampleParams.imageViewMinLod,							// float	minLod;
2310e5c31af7Sopenharmony_ci			sampleParams.imageViewMinLodMode,						// ImageViewMinLodMode
2311e5c31af7Sopenharmony_ci		},
2312e5c31af7Sopenharmony_ci		sampleParams.samplerType == SAMPLERTYPE_FETCH_FLOAT		// bool	intTexCoord;
2313e5c31af7Sopenharmony_ci	};
2314e5c31af7Sopenharmony_ci
2315e5c31af7Sopenharmony_ci	const tcu::TextureCubeArrayView				src					= getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel, sampleParams.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL), srcLevelStorage, sampleParams.sampler);
2316e5c31af7Sopenharmony_ci
2317e5c31af7Sopenharmony_ci	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2318e5c31af7Sopenharmony_ci	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2319e5c31af7Sopenharmony_ci	const tcu::Vec4								rq					= tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2320e5c31af7Sopenharmony_ci	const tcu::Vec4								qq					= tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2321e5c31af7Sopenharmony_ci
2322e5c31af7Sopenharmony_ci	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
2323e5c31af7Sopenharmony_ci	const float									dstW				= float(dstSize.x());
2324e5c31af7Sopenharmony_ci	const float									dstH				= float(dstSize.y());
2325e5c31af7Sopenharmony_ci	const int									srcSize				= src.getSize();
2326e5c31af7Sopenharmony_ci
2327e5c31af7Sopenharmony_ci	// Coordinates per triangle.
2328e5c31af7Sopenharmony_ci	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2329e5c31af7Sopenharmony_ci	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2330e5c31af7Sopenharmony_ci	const tcu::Vec3								triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2331e5c31af7Sopenharmony_ci	const tcu::Vec3								triQ[2]				= { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2332e5c31af7Sopenharmony_ci	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2333e5c31af7Sopenharmony_ci
2334e5c31af7Sopenharmony_ci	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2335e5c31af7Sopenharmony_ci
2336e5c31af7Sopenharmony_ci	const float									posEps				= 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2337e5c31af7Sopenharmony_ci
2338e5c31af7Sopenharmony_ci	int											numFailed			= 0;
2339e5c31af7Sopenharmony_ci
2340e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
2341e5c31af7Sopenharmony_ci	{
2342e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
2343e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
2344e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
2345e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
2346e5c31af7Sopenharmony_ci
2347e5c31af7Sopenharmony_ci		// \note Not strictly allowed by spec, but implementations do this in practice.
2348e5c31af7Sopenharmony_ci		tcu::Vec2(-1, -1),
2349e5c31af7Sopenharmony_ci		tcu::Vec2(-1, +1),
2350e5c31af7Sopenharmony_ci		tcu::Vec2(+1, -1),
2351e5c31af7Sopenharmony_ci		tcu::Vec2(+1, +1),
2352e5c31af7Sopenharmony_ci	};
2353e5c31af7Sopenharmony_ci
2354e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2355e5c31af7Sopenharmony_ci
2356e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
2357e5c31af7Sopenharmony_ci	{
2358e5c31af7Sopenharmony_ci		// Ugly hack, validation can take way too long at the moment.
2359e5c31af7Sopenharmony_ci		if (watchDog)
2360e5c31af7Sopenharmony_ci			qpWatchDog_touch(watchDog);
2361e5c31af7Sopenharmony_ci
2362e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
2363e5c31af7Sopenharmony_ci		{
2364e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
2365e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
2366e5c31af7Sopenharmony_ci
2367e5c31af7Sopenharmony_ci			// Try comparison to ideal reference first, and if that fails use slower verificator.
2368e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2369e5c31af7Sopenharmony_ci			{
2370e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
2371e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
2372e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
2373e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
2374e5c31af7Sopenharmony_ci
2375e5c31af7Sopenharmony_ci				const bool		tri0	= nx + ny - posEps <= 1.0f;
2376e5c31af7Sopenharmony_ci				const bool		tri1	= nx + ny + posEps >= 1.0f;
2377e5c31af7Sopenharmony_ci
2378e5c31af7Sopenharmony_ci				bool			isOk	= false;
2379e5c31af7Sopenharmony_ci
2380e5c31af7Sopenharmony_ci				DE_ASSERT(tri0 || tri1);
2381e5c31af7Sopenharmony_ci
2382e5c31af7Sopenharmony_ci				// Pixel can belong to either of the triangles if it lies close enough to the edge.
2383e5c31af7Sopenharmony_ci				for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2384e5c31af7Sopenharmony_ci				{
2385e5c31af7Sopenharmony_ci					const float		triWx		= triNdx ? dstW - wx : wx;
2386e5c31af7Sopenharmony_ci					const float		triWy		= triNdx ? dstH - wy : wy;
2387e5c31af7Sopenharmony_ci					const float		triNx		= triNdx ? 1.0f - nx : nx;
2388e5c31af7Sopenharmony_ci					const float		triNy		= triNdx ? 1.0f - ny : ny;
2389e5c31af7Sopenharmony_ci
2390e5c31af7Sopenharmony_ci					const tcu::Vec4	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2391e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2392e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2393e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2394e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDx		(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2395e5c31af7Sopenharmony_ci												 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2396e5c31af7Sopenharmony_ci												 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2397e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDy		(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2398e5c31af7Sopenharmony_ci												 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2399e5c31af7Sopenharmony_ci												 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2400e5c31af7Sopenharmony_ci
2401e5c31af7Sopenharmony_ci					tcu::Vec2		lodBounds	= tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2402e5c31af7Sopenharmony_ci
2403e5c31af7Sopenharmony_ci					// Compute lod bounds across lodOffsets range.
2404e5c31af7Sopenharmony_ci					for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2405e5c31af7Sopenharmony_ci					{
2406e5c31af7Sopenharmony_ci						const float		wxo			= triWx + lodOffsets[lodOffsNdx].x();
2407e5c31af7Sopenharmony_ci						const float		wyo			= triWy + lodOffsets[lodOffsNdx].y();
2408e5c31af7Sopenharmony_ci						const float		nxo			= wxo/dstW;
2409e5c31af7Sopenharmony_ci						const float		nyo			= wyo/dstH;
2410e5c31af7Sopenharmony_ci
2411e5c31af7Sopenharmony_ci						const tcu::Vec3	coordO		(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2412e5c31af7Sopenharmony_ci													 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2413e5c31af7Sopenharmony_ci													 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2414e5c31af7Sopenharmony_ci						const tcu::Vec3	coordDxo	(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2415e5c31af7Sopenharmony_ci													 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2416e5c31af7Sopenharmony_ci													 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2417e5c31af7Sopenharmony_ci						const tcu::Vec3	coordDyo	(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2418e5c31af7Sopenharmony_ci													 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2419e5c31af7Sopenharmony_ci													 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2420e5c31af7Sopenharmony_ci						const tcu::Vec2	lodO		= tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2421e5c31af7Sopenharmony_ci
2422e5c31af7Sopenharmony_ci						lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2423e5c31af7Sopenharmony_ci						lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2424e5c31af7Sopenharmony_ci					}
2425e5c31af7Sopenharmony_ci
2426e5c31af7Sopenharmony_ci					const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2427e5c31af7Sopenharmony_ci
2428e5c31af7Sopenharmony_ci					if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2429e5c31af7Sopenharmony_ci					{
2430e5c31af7Sopenharmony_ci						isOk = true;
2431e5c31af7Sopenharmony_ci						break;
2432e5c31af7Sopenharmony_ci					}
2433e5c31af7Sopenharmony_ci				}
2434e5c31af7Sopenharmony_ci
2435e5c31af7Sopenharmony_ci				if (!isOk)
2436e5c31af7Sopenharmony_ci				{
2437e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2438e5c31af7Sopenharmony_ci					numFailed += 1;
2439e5c31af7Sopenharmony_ci				}
2440e5c31af7Sopenharmony_ci			}
2441e5c31af7Sopenharmony_ci		}
2442e5c31af7Sopenharmony_ci	}
2443e5c31af7Sopenharmony_ci
2444e5c31af7Sopenharmony_ci	return numFailed;
2445e5c31af7Sopenharmony_ci}
2446e5c31af7Sopenharmony_ci
2447e5c31af7Sopenharmony_cibool verifyTextureResult (tcu::TestContext&						testCtx,
2448e5c31af7Sopenharmony_ci						  const tcu::ConstPixelBufferAccess&	result,
2449e5c31af7Sopenharmony_ci						  const tcu::TextureCubeArrayView&		src,
2450e5c31af7Sopenharmony_ci						  const float*							texCoord,
2451e5c31af7Sopenharmony_ci						  const ReferenceParams&				sampleParams,
2452e5c31af7Sopenharmony_ci						  const tcu::LookupPrecision&			lookupPrec,
2453e5c31af7Sopenharmony_ci						  const tcu::IVec4&						coordBits,
2454e5c31af7Sopenharmony_ci						  const tcu::LodPrecision&				lodPrec,
2455e5c31af7Sopenharmony_ci						  const tcu::PixelFormat&				pixelFormat)
2456e5c31af7Sopenharmony_ci{
2457e5c31af7Sopenharmony_ci	tcu::TestLog&	log				= testCtx.getLog();
2458e5c31af7Sopenharmony_ci	tcu::Surface	reference		(result.getWidth(), result.getHeight());
2459e5c31af7Sopenharmony_ci	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
2460e5c31af7Sopenharmony_ci	int				numFailedPixels;
2461e5c31af7Sopenharmony_ci
2462e5c31af7Sopenharmony_ci	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2463e5c31af7Sopenharmony_ci
2464e5c31af7Sopenharmony_ci	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2465e5c31af7Sopenharmony_ci	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2466e5c31af7Sopenharmony_ci
2467e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
2468e5c31af7Sopenharmony_ci		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2469e5c31af7Sopenharmony_ci
2470e5c31af7Sopenharmony_ci	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2471e5c31af7Sopenharmony_ci		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
2472e5c31af7Sopenharmony_ci
2473e5c31af7Sopenharmony_ci	if (numFailedPixels > 0)
2474e5c31af7Sopenharmony_ci	{
2475e5c31af7Sopenharmony_ci		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2476e5c31af7Sopenharmony_ci			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2477e5c31af7Sopenharmony_ci	}
2478e5c31af7Sopenharmony_ci
2479e5c31af7Sopenharmony_ci	log << tcu::TestLog::EndImageSet;
2480e5c31af7Sopenharmony_ci
2481e5c31af7Sopenharmony_ci	return numFailedPixels == 0;
2482e5c31af7Sopenharmony_ci}
2483e5c31af7Sopenharmony_ci
2484e5c31af7Sopenharmony_ci// Shadow lookup verification
2485e5c31af7Sopenharmony_ci
2486e5c31af7Sopenharmony_ciint computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&	result,
2487e5c31af7Sopenharmony_ci							   const tcu::ConstPixelBufferAccess&	reference,
2488e5c31af7Sopenharmony_ci							   const tcu::PixelBufferAccess&		errorMask,
2489e5c31af7Sopenharmony_ci							   const tcu::Texture2DView&			src,
2490e5c31af7Sopenharmony_ci							   const float*							texCoord,
2491e5c31af7Sopenharmony_ci							   const ReferenceParams&				sampleParams,
2492e5c31af7Sopenharmony_ci							   const tcu::TexComparePrecision&		comparePrec,
2493e5c31af7Sopenharmony_ci							   const tcu::LodPrecision&				lodPrec,
2494e5c31af7Sopenharmony_ci							   const tcu::Vec3&						nonShadowThreshold)
2495e5c31af7Sopenharmony_ci{
2496e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2497e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2498e5c31af7Sopenharmony_ci
2499e5c31af7Sopenharmony_ci	const tcu::Vec4		sq				= tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2500e5c31af7Sopenharmony_ci	const tcu::Vec4		tq				= tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2501e5c31af7Sopenharmony_ci
2502e5c31af7Sopenharmony_ci	const tcu::IVec2	dstSize			= tcu::IVec2(result.getWidth(), result.getHeight());
2503e5c31af7Sopenharmony_ci	const float			dstW			= float(dstSize.x());
2504e5c31af7Sopenharmony_ci	const float			dstH			= float(dstSize.y());
2505e5c31af7Sopenharmony_ci	const tcu::IVec2	srcSize			= tcu::IVec2(src.getWidth(), src.getHeight());
2506e5c31af7Sopenharmony_ci
2507e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
2508e5c31af7Sopenharmony_ci	const tcu::Vec3		triS[2]			= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2509e5c31af7Sopenharmony_ci	const tcu::Vec3		triT[2]			= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2510e5c31af7Sopenharmony_ci	const tcu::Vec3		triW[2]			= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2511e5c31af7Sopenharmony_ci
2512e5c31af7Sopenharmony_ci	const tcu::Vec2		lodBias			((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2513e5c31af7Sopenharmony_ci
2514e5c31af7Sopenharmony_ci	const float			minLod			= (sampleParams.imageViewMinLod != 0.0f) ? de::max(deFloatFloor(sampleParams.imageViewMinLod), sampleParams.minLod) : sampleParams.minLod;
2515e5c31af7Sopenharmony_ci
2516e5c31af7Sopenharmony_ci	int					numFailed		= 0;
2517e5c31af7Sopenharmony_ci
2518e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
2519e5c31af7Sopenharmony_ci	{
2520e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
2521e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
2522e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
2523e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
2524e5c31af7Sopenharmony_ci	};
2525e5c31af7Sopenharmony_ci
2526e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2527e5c31af7Sopenharmony_ci
2528e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
2529e5c31af7Sopenharmony_ci	{
2530e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
2531e5c31af7Sopenharmony_ci		{
2532e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= result.getPixel(px, py);
2533e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= reference.getPixel(px, py);
2534e5c31af7Sopenharmony_ci
2535e5c31af7Sopenharmony_ci			// Other channels should trivially match to reference.
2536e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2537e5c31af7Sopenharmony_ci			{
2538e5c31af7Sopenharmony_ci				errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2539e5c31af7Sopenharmony_ci				numFailed += 1;
2540e5c31af7Sopenharmony_ci				continue;
2541e5c31af7Sopenharmony_ci			}
2542e5c31af7Sopenharmony_ci
2543e5c31af7Sopenharmony_ci			// Reference result is known to be a valid result, we can
2544e5c31af7Sopenharmony_ci			// skip verification if thes results are equal
2545e5c31af7Sopenharmony_ci			if (resPix.x() != refPix.x())
2546e5c31af7Sopenharmony_ci			{
2547e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
2548e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
2549e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
2550e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
2551e5c31af7Sopenharmony_ci
2552e5c31af7Sopenharmony_ci				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2553e5c31af7Sopenharmony_ci				const float		triWx	= triNdx ? dstW - wx : wx;
2554e5c31af7Sopenharmony_ci				const float		triWy	= triNdx ? dstH - wy : wy;
2555e5c31af7Sopenharmony_ci				const float		triNx	= triNdx ? 1.0f - nx : nx;
2556e5c31af7Sopenharmony_ci				const float		triNy	= triNdx ? 1.0f - ny : ny;
2557e5c31af7Sopenharmony_ci
2558e5c31af7Sopenharmony_ci				const tcu::Vec2	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2559e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2560e5c31af7Sopenharmony_ci				const tcu::Vec2	coordDx		= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2561e5c31af7Sopenharmony_ci														triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2562e5c31af7Sopenharmony_ci				const tcu::Vec2	coordDy		= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2563e5c31af7Sopenharmony_ci														triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2564e5c31af7Sopenharmony_ci
2565e5c31af7Sopenharmony_ci				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2566e5c31af7Sopenharmony_ci
2567e5c31af7Sopenharmony_ci				// Compute lod bounds across lodOffsets range.
2568e5c31af7Sopenharmony_ci				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2569e5c31af7Sopenharmony_ci				{
2570e5c31af7Sopenharmony_ci					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2571e5c31af7Sopenharmony_ci					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2572e5c31af7Sopenharmony_ci					const float		nxo		= wxo/dstW;
2573e5c31af7Sopenharmony_ci					const float		nyo		= wyo/dstH;
2574e5c31af7Sopenharmony_ci
2575e5c31af7Sopenharmony_ci					const tcu::Vec2	coordDxo	= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2576e5c31af7Sopenharmony_ci															triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2577e5c31af7Sopenharmony_ci					const tcu::Vec2	coordDyo	= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2578e5c31af7Sopenharmony_ci															triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2579e5c31af7Sopenharmony_ci					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2580e5c31af7Sopenharmony_ci
2581e5c31af7Sopenharmony_ci					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2582e5c31af7Sopenharmony_ci					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2583e5c31af7Sopenharmony_ci				}
2584e5c31af7Sopenharmony_ci
2585e5c31af7Sopenharmony_ci				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
2586e5c31af7Sopenharmony_ci				const bool		isOk		= tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2587e5c31af7Sopenharmony_ci
2588e5c31af7Sopenharmony_ci				if (!isOk)
2589e5c31af7Sopenharmony_ci				{
2590e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2591e5c31af7Sopenharmony_ci					numFailed += 1;
2592e5c31af7Sopenharmony_ci				}
2593e5c31af7Sopenharmony_ci			}
2594e5c31af7Sopenharmony_ci		}
2595e5c31af7Sopenharmony_ci	}
2596e5c31af7Sopenharmony_ci
2597e5c31af7Sopenharmony_ci	return numFailed;
2598e5c31af7Sopenharmony_ci}
2599e5c31af7Sopenharmony_ci
2600e5c31af7Sopenharmony_ciint computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&	result,
2601e5c31af7Sopenharmony_ci							   const tcu::ConstPixelBufferAccess&	reference,
2602e5c31af7Sopenharmony_ci							   const tcu::PixelBufferAccess&		errorMask,
2603e5c31af7Sopenharmony_ci							   const tcu::TextureCubeView&			src,
2604e5c31af7Sopenharmony_ci							   const float*							texCoord,
2605e5c31af7Sopenharmony_ci							   const ReferenceParams&				sampleParams,
2606e5c31af7Sopenharmony_ci							   const tcu::TexComparePrecision&		comparePrec,
2607e5c31af7Sopenharmony_ci							   const tcu::LodPrecision&				lodPrec,
2608e5c31af7Sopenharmony_ci							   const tcu::Vec3&						nonShadowThreshold)
2609e5c31af7Sopenharmony_ci{
2610e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2611e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2612e5c31af7Sopenharmony_ci
2613e5c31af7Sopenharmony_ci	const tcu::Vec4		sq				= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2614e5c31af7Sopenharmony_ci	const tcu::Vec4		tq				= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2615e5c31af7Sopenharmony_ci	const tcu::Vec4		rq				= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2616e5c31af7Sopenharmony_ci
2617e5c31af7Sopenharmony_ci	const tcu::IVec2	dstSize			= tcu::IVec2(result.getWidth(), result.getHeight());
2618e5c31af7Sopenharmony_ci	const float			dstW			= float(dstSize.x());
2619e5c31af7Sopenharmony_ci	const float			dstH			= float(dstSize.y());
2620e5c31af7Sopenharmony_ci	const int			srcSize			= src.getSize();
2621e5c31af7Sopenharmony_ci
2622e5c31af7Sopenharmony_ci	// Coordinates per triangle.
2623e5c31af7Sopenharmony_ci	const tcu::Vec3		triS[2]			= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2624e5c31af7Sopenharmony_ci	const tcu::Vec3		triT[2]			= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2625e5c31af7Sopenharmony_ci	const tcu::Vec3		triR[2]			= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2626e5c31af7Sopenharmony_ci	const tcu::Vec3		triW[2]			= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2627e5c31af7Sopenharmony_ci
2628e5c31af7Sopenharmony_ci	const tcu::Vec2		lodBias			((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2629e5c31af7Sopenharmony_ci
2630e5c31af7Sopenharmony_ci	const float			minLod			= (sampleParams.imageViewMinLod != 0.0f) ? de::max(deFloatFloor(sampleParams.imageViewMinLod), sampleParams.minLod) : sampleParams.minLod;
2631e5c31af7Sopenharmony_ci
2632e5c31af7Sopenharmony_ci	int					numFailed		= 0;
2633e5c31af7Sopenharmony_ci
2634e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
2635e5c31af7Sopenharmony_ci	{
2636e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
2637e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
2638e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
2639e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
2640e5c31af7Sopenharmony_ci	};
2641e5c31af7Sopenharmony_ci
2642e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2643e5c31af7Sopenharmony_ci
2644e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
2645e5c31af7Sopenharmony_ci	{
2646e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
2647e5c31af7Sopenharmony_ci		{
2648e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= result.getPixel(px, py);
2649e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= reference.getPixel(px, py);
2650e5c31af7Sopenharmony_ci
2651e5c31af7Sopenharmony_ci			// Other channels should trivially match to reference.
2652e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2653e5c31af7Sopenharmony_ci			{
2654e5c31af7Sopenharmony_ci				errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2655e5c31af7Sopenharmony_ci				numFailed += 1;
2656e5c31af7Sopenharmony_ci				continue;
2657e5c31af7Sopenharmony_ci			}
2658e5c31af7Sopenharmony_ci
2659e5c31af7Sopenharmony_ci			// Reference result is known to be a valid result, we can
2660e5c31af7Sopenharmony_ci			// skip verification if thes results are equal
2661e5c31af7Sopenharmony_ci			if (resPix.x() != refPix.x())
2662e5c31af7Sopenharmony_ci			{
2663e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
2664e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
2665e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
2666e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
2667e5c31af7Sopenharmony_ci
2668e5c31af7Sopenharmony_ci				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2669e5c31af7Sopenharmony_ci				const float		triWx	= triNdx ? dstW - wx : wx;
2670e5c31af7Sopenharmony_ci				const float		triWy	= triNdx ? dstH - wy : wy;
2671e5c31af7Sopenharmony_ci				const float		triNx	= triNdx ? 1.0f - nx : nx;
2672e5c31af7Sopenharmony_ci				const float		triNy	= triNdx ? 1.0f - ny : ny;
2673e5c31af7Sopenharmony_ci
2674e5c31af7Sopenharmony_ci				const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2675e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2676e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2677e5c31af7Sopenharmony_ci				const tcu::Vec3	coordDx		(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2678e5c31af7Sopenharmony_ci											 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2679e5c31af7Sopenharmony_ci											 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2680e5c31af7Sopenharmony_ci				const tcu::Vec3	coordDy		(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2681e5c31af7Sopenharmony_ci											 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2682e5c31af7Sopenharmony_ci											 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2683e5c31af7Sopenharmony_ci
2684e5c31af7Sopenharmony_ci				tcu::Vec2		lodBounds	= tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2685e5c31af7Sopenharmony_ci
2686e5c31af7Sopenharmony_ci				// Compute lod bounds across lodOffsets range.
2687e5c31af7Sopenharmony_ci				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2688e5c31af7Sopenharmony_ci				{
2689e5c31af7Sopenharmony_ci					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2690e5c31af7Sopenharmony_ci					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2691e5c31af7Sopenharmony_ci					const float		nxo		= wxo/dstW;
2692e5c31af7Sopenharmony_ci					const float		nyo		= wyo/dstH;
2693e5c31af7Sopenharmony_ci
2694e5c31af7Sopenharmony_ci					const tcu::Vec3	coordO		(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2695e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2696e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2697e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDxo	(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2698e5c31af7Sopenharmony_ci												 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2699e5c31af7Sopenharmony_ci												 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2700e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDyo	(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2701e5c31af7Sopenharmony_ci												 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2702e5c31af7Sopenharmony_ci												 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2703e5c31af7Sopenharmony_ci					const tcu::Vec2	lodO		= tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2704e5c31af7Sopenharmony_ci
2705e5c31af7Sopenharmony_ci					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2706e5c31af7Sopenharmony_ci					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2707e5c31af7Sopenharmony_ci				}
2708e5c31af7Sopenharmony_ci
2709e5c31af7Sopenharmony_ci				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
2710e5c31af7Sopenharmony_ci				const bool		isOk		= tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2711e5c31af7Sopenharmony_ci
2712e5c31af7Sopenharmony_ci				if (!isOk)
2713e5c31af7Sopenharmony_ci				{
2714e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2715e5c31af7Sopenharmony_ci					numFailed += 1;
2716e5c31af7Sopenharmony_ci				}
2717e5c31af7Sopenharmony_ci			}
2718e5c31af7Sopenharmony_ci		}
2719e5c31af7Sopenharmony_ci	}
2720e5c31af7Sopenharmony_ci
2721e5c31af7Sopenharmony_ci	return numFailed;
2722e5c31af7Sopenharmony_ci}
2723e5c31af7Sopenharmony_ci
2724e5c31af7Sopenharmony_ciint computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&	result,
2725e5c31af7Sopenharmony_ci							   const tcu::ConstPixelBufferAccess&	reference,
2726e5c31af7Sopenharmony_ci							   const tcu::PixelBufferAccess&		errorMask,
2727e5c31af7Sopenharmony_ci							   const tcu::Texture2DArrayView&		src,
2728e5c31af7Sopenharmony_ci							   const float*							texCoord,
2729e5c31af7Sopenharmony_ci							   const ReferenceParams&				sampleParams,
2730e5c31af7Sopenharmony_ci							   const tcu::TexComparePrecision&		comparePrec,
2731e5c31af7Sopenharmony_ci							   const tcu::LodPrecision&				lodPrec,
2732e5c31af7Sopenharmony_ci							   const tcu::Vec3&						nonShadowThreshold)
2733e5c31af7Sopenharmony_ci{
2734e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2735e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2736e5c31af7Sopenharmony_ci
2737e5c31af7Sopenharmony_ci	const tcu::Vec4		sq				= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2738e5c31af7Sopenharmony_ci	const tcu::Vec4		tq				= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2739e5c31af7Sopenharmony_ci	const tcu::Vec4		rq				= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2740e5c31af7Sopenharmony_ci
2741e5c31af7Sopenharmony_ci	const tcu::IVec2	dstSize			= tcu::IVec2(result.getWidth(), result.getHeight());
2742e5c31af7Sopenharmony_ci	const float			dstW			= float(dstSize.x());
2743e5c31af7Sopenharmony_ci	const float			dstH			= float(dstSize.y());
2744e5c31af7Sopenharmony_ci	const tcu::IVec2	srcSize			= tcu::IVec2(src.getWidth(), src.getHeight());
2745e5c31af7Sopenharmony_ci
2746e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
2747e5c31af7Sopenharmony_ci	const tcu::Vec3		triS[2]			= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2748e5c31af7Sopenharmony_ci	const tcu::Vec3		triT[2]			= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2749e5c31af7Sopenharmony_ci	const tcu::Vec3		triR[2]			= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2750e5c31af7Sopenharmony_ci	const tcu::Vec3		triW[2]			= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2751e5c31af7Sopenharmony_ci
2752e5c31af7Sopenharmony_ci	const tcu::Vec2		lodBias			((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2753e5c31af7Sopenharmony_ci
2754e5c31af7Sopenharmony_ci	int					numFailed		= 0;
2755e5c31af7Sopenharmony_ci
2756e5c31af7Sopenharmony_ci	const tcu::Vec2 lodOffsets[] =
2757e5c31af7Sopenharmony_ci	{
2758e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
2759e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
2760e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
2761e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
2762e5c31af7Sopenharmony_ci	};
2763e5c31af7Sopenharmony_ci
2764e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2765e5c31af7Sopenharmony_ci
2766e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
2767e5c31af7Sopenharmony_ci	{
2768e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
2769e5c31af7Sopenharmony_ci		{
2770e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= result.getPixel(px, py);
2771e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= reference.getPixel(px, py);
2772e5c31af7Sopenharmony_ci
2773e5c31af7Sopenharmony_ci			// Other channels should trivially match to reference.
2774e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2775e5c31af7Sopenharmony_ci			{
2776e5c31af7Sopenharmony_ci				errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2777e5c31af7Sopenharmony_ci				numFailed += 1;
2778e5c31af7Sopenharmony_ci				continue;
2779e5c31af7Sopenharmony_ci			}
2780e5c31af7Sopenharmony_ci
2781e5c31af7Sopenharmony_ci			// Reference result is known to be a valid result, we can
2782e5c31af7Sopenharmony_ci			// skip verification if thes results are equal
2783e5c31af7Sopenharmony_ci			if (resPix.x() != refPix.x())
2784e5c31af7Sopenharmony_ci			{
2785e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
2786e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
2787e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
2788e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
2789e5c31af7Sopenharmony_ci
2790e5c31af7Sopenharmony_ci				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2791e5c31af7Sopenharmony_ci				const float		triWx	= triNdx ? dstW - wx : wx;
2792e5c31af7Sopenharmony_ci				const float		triWy	= triNdx ? dstH - wy : wy;
2793e5c31af7Sopenharmony_ci				const float		triNx	= triNdx ? 1.0f - nx : nx;
2794e5c31af7Sopenharmony_ci				const float		triNy	= triNdx ? 1.0f - ny : ny;
2795e5c31af7Sopenharmony_ci
2796e5c31af7Sopenharmony_ci				const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2797e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2798e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2799e5c31af7Sopenharmony_ci				const tcu::Vec2	coordDx		= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2800e5c31af7Sopenharmony_ci														triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2801e5c31af7Sopenharmony_ci				const tcu::Vec2	coordDy		= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2802e5c31af7Sopenharmony_ci														triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2803e5c31af7Sopenharmony_ci
2804e5c31af7Sopenharmony_ci				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2805e5c31af7Sopenharmony_ci
2806e5c31af7Sopenharmony_ci				// Compute lod bounds across lodOffsets range.
2807e5c31af7Sopenharmony_ci				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2808e5c31af7Sopenharmony_ci				{
2809e5c31af7Sopenharmony_ci					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2810e5c31af7Sopenharmony_ci					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2811e5c31af7Sopenharmony_ci					const float		nxo		= wxo/dstW;
2812e5c31af7Sopenharmony_ci					const float		nyo		= wyo/dstH;
2813e5c31af7Sopenharmony_ci
2814e5c31af7Sopenharmony_ci					const tcu::Vec2	coordDxo	= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2815e5c31af7Sopenharmony_ci															triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2816e5c31af7Sopenharmony_ci					const tcu::Vec2	coordDyo	= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2817e5c31af7Sopenharmony_ci															triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2818e5c31af7Sopenharmony_ci					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2819e5c31af7Sopenharmony_ci
2820e5c31af7Sopenharmony_ci					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2821e5c31af7Sopenharmony_ci					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2822e5c31af7Sopenharmony_ci				}
2823e5c31af7Sopenharmony_ci
2824e5c31af7Sopenharmony_ci				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2825e5c31af7Sopenharmony_ci				const bool		isOk		= tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2826e5c31af7Sopenharmony_ci
2827e5c31af7Sopenharmony_ci				if (!isOk)
2828e5c31af7Sopenharmony_ci				{
2829e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2830e5c31af7Sopenharmony_ci					numFailed += 1;
2831e5c31af7Sopenharmony_ci				}
2832e5c31af7Sopenharmony_ci			}
2833e5c31af7Sopenharmony_ci		}
2834e5c31af7Sopenharmony_ci	}
2835e5c31af7Sopenharmony_ci
2836e5c31af7Sopenharmony_ci	return numFailed;
2837e5c31af7Sopenharmony_ci}
2838e5c31af7Sopenharmony_ci
2839e5c31af7Sopenharmony_ciint computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&	result,
2840e5c31af7Sopenharmony_ci							   const tcu::ConstPixelBufferAccess&	reference,
2841e5c31af7Sopenharmony_ci							   const tcu::PixelBufferAccess&		errorMask,
2842e5c31af7Sopenharmony_ci							   const tcu::Texture1DView&			src,
2843e5c31af7Sopenharmony_ci							   const float*							texCoord,
2844e5c31af7Sopenharmony_ci							   const ReferenceParams&				sampleParams,
2845e5c31af7Sopenharmony_ci							   const tcu::TexComparePrecision&		comparePrec,
2846e5c31af7Sopenharmony_ci							   const tcu::LodPrecision&				lodPrec,
2847e5c31af7Sopenharmony_ci							   const tcu::Vec3&						nonShadowThreshold)
2848e5c31af7Sopenharmony_ci{
2849e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2850e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2851e5c31af7Sopenharmony_ci	DE_ASSERT(result.getHeight() == 1);
2852e5c31af7Sopenharmony_ci
2853e5c31af7Sopenharmony_ci	const tcu::Vec4		sq				= tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
2854e5c31af7Sopenharmony_ci
2855e5c31af7Sopenharmony_ci	const tcu::IVec2	dstSize			= tcu::IVec2(result.getWidth(), 1);
2856e5c31af7Sopenharmony_ci	const float			dstW			= float(dstSize.x());
2857e5c31af7Sopenharmony_ci	const float			dstH			= float(dstSize.y());
2858e5c31af7Sopenharmony_ci	const float			srcSize			= float(src.getWidth());
2859e5c31af7Sopenharmony_ci
2860e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
2861e5c31af7Sopenharmony_ci	const tcu::Vec3		triS[2]			= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2862e5c31af7Sopenharmony_ci	const tcu::Vec3		triW[2]			= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2863e5c31af7Sopenharmony_ci
2864e5c31af7Sopenharmony_ci	const tcu::Vec2		lodBias			((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2865e5c31af7Sopenharmony_ci
2866e5c31af7Sopenharmony_ci	int					numFailed		= 0;
2867e5c31af7Sopenharmony_ci
2868e5c31af7Sopenharmony_ci	const tcu::Vec2		lodOffsets[]	=
2869e5c31af7Sopenharmony_ci	{
2870e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
2871e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
2872e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
2873e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
2874e5c31af7Sopenharmony_ci	};
2875e5c31af7Sopenharmony_ci
2876e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2877e5c31af7Sopenharmony_ci
2878e5c31af7Sopenharmony_ci	const int py = 0;
2879e5c31af7Sopenharmony_ci	{
2880e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
2881e5c31af7Sopenharmony_ci		{
2882e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= result.getPixel(px, py);
2883e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= reference.getPixel(px, py);
2884e5c31af7Sopenharmony_ci
2885e5c31af7Sopenharmony_ci			// Other channels should trivially match to reference.
2886e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2887e5c31af7Sopenharmony_ci			{
2888e5c31af7Sopenharmony_ci				errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2889e5c31af7Sopenharmony_ci				numFailed += 1;
2890e5c31af7Sopenharmony_ci				continue;
2891e5c31af7Sopenharmony_ci			}
2892e5c31af7Sopenharmony_ci
2893e5c31af7Sopenharmony_ci			// Reference result is known to be a valid result, we can
2894e5c31af7Sopenharmony_ci			// skip verification if thes results are equal
2895e5c31af7Sopenharmony_ci			if (resPix.x() != refPix.x())
2896e5c31af7Sopenharmony_ci			{
2897e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
2898e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
2899e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
2900e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
2901e5c31af7Sopenharmony_ci
2902e5c31af7Sopenharmony_ci				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2903e5c31af7Sopenharmony_ci				const float		triWx	= triNdx ? dstW - wx : wx;
2904e5c31af7Sopenharmony_ci				const float		triWy	= triNdx ? dstH - wy : wy;
2905e5c31af7Sopenharmony_ci				const float		triNx	= triNdx ? 1.0f - nx : nx;
2906e5c31af7Sopenharmony_ci				const float		triNy	= triNdx ? 1.0f - ny : ny;
2907e5c31af7Sopenharmony_ci
2908e5c31af7Sopenharmony_ci				const float		coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy));
2909e5c31af7Sopenharmony_ci				const float		coordDx		= triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
2910e5c31af7Sopenharmony_ci
2911e5c31af7Sopenharmony_ci				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx, coordDx, lodPrec);
2912e5c31af7Sopenharmony_ci
2913e5c31af7Sopenharmony_ci				// Compute lod bounds across lodOffsets range.
2914e5c31af7Sopenharmony_ci				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2915e5c31af7Sopenharmony_ci				{
2916e5c31af7Sopenharmony_ci					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2917e5c31af7Sopenharmony_ci					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2918e5c31af7Sopenharmony_ci					const float		nxo		= wxo/dstW;
2919e5c31af7Sopenharmony_ci					const float		nyo		= wyo/dstH;
2920e5c31af7Sopenharmony_ci
2921e5c31af7Sopenharmony_ci					const float		coordDxo	= triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
2922e5c31af7Sopenharmony_ci					const float		coordDyo	= triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
2923e5c31af7Sopenharmony_ci					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
2924e5c31af7Sopenharmony_ci
2925e5c31af7Sopenharmony_ci					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2926e5c31af7Sopenharmony_ci					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2927e5c31af7Sopenharmony_ci				}
2928e5c31af7Sopenharmony_ci
2929e5c31af7Sopenharmony_ci				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2930e5c31af7Sopenharmony_ci				const bool		isOk		= tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, tcu::Vec1(coord), clampedLod, sampleParams.ref, resPix.x());
2931e5c31af7Sopenharmony_ci
2932e5c31af7Sopenharmony_ci				if (!isOk)
2933e5c31af7Sopenharmony_ci				{
2934e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2935e5c31af7Sopenharmony_ci					numFailed += 1;
2936e5c31af7Sopenharmony_ci				}
2937e5c31af7Sopenharmony_ci			}
2938e5c31af7Sopenharmony_ci		}
2939e5c31af7Sopenharmony_ci	}
2940e5c31af7Sopenharmony_ci
2941e5c31af7Sopenharmony_ci	return numFailed;
2942e5c31af7Sopenharmony_ci}
2943e5c31af7Sopenharmony_ci
2944e5c31af7Sopenharmony_ciint computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&	result,
2945e5c31af7Sopenharmony_ci							   const tcu::ConstPixelBufferAccess&	reference,
2946e5c31af7Sopenharmony_ci							   const tcu::PixelBufferAccess&		errorMask,
2947e5c31af7Sopenharmony_ci							   const tcu::Texture1DArrayView&		src,
2948e5c31af7Sopenharmony_ci							   const float*							texCoord,
2949e5c31af7Sopenharmony_ci							   const ReferenceParams&				sampleParams,
2950e5c31af7Sopenharmony_ci							   const tcu::TexComparePrecision&		comparePrec,
2951e5c31af7Sopenharmony_ci							   const tcu::LodPrecision&				lodPrec,
2952e5c31af7Sopenharmony_ci							   const tcu::Vec3&						nonShadowThreshold)
2953e5c31af7Sopenharmony_ci{
2954e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2955e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2956e5c31af7Sopenharmony_ci	DE_ASSERT(result.getHeight() == 1);
2957e5c31af7Sopenharmony_ci
2958e5c31af7Sopenharmony_ci	const tcu::Vec4		sq				= tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2959e5c31af7Sopenharmony_ci	const tcu::Vec4		tq				= tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2960e5c31af7Sopenharmony_ci
2961e5c31af7Sopenharmony_ci	const tcu::IVec2	dstSize			= tcu::IVec2(result.getWidth(), 1);
2962e5c31af7Sopenharmony_ci	const float			dstW			= float(dstSize.x());
2963e5c31af7Sopenharmony_ci	const float			dstH			= float(dstSize.y());
2964e5c31af7Sopenharmony_ci	const float			srcSize			= float(src.getWidth());
2965e5c31af7Sopenharmony_ci
2966e5c31af7Sopenharmony_ci	// Coordinates and lod per triangle.
2967e5c31af7Sopenharmony_ci	const tcu::Vec3		triS[2]			= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2968e5c31af7Sopenharmony_ci	const tcu::Vec3		triT[2]			= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2969e5c31af7Sopenharmony_ci	const tcu::Vec3		triW[2]			= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2970e5c31af7Sopenharmony_ci
2971e5c31af7Sopenharmony_ci	const tcu::Vec2		lodBias			((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2972e5c31af7Sopenharmony_ci
2973e5c31af7Sopenharmony_ci	int					numFailed		= 0;
2974e5c31af7Sopenharmony_ci
2975e5c31af7Sopenharmony_ci	const tcu::Vec2		lodOffsets[]	=
2976e5c31af7Sopenharmony_ci	{
2977e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
2978e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
2979e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
2980e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
2981e5c31af7Sopenharmony_ci	};
2982e5c31af7Sopenharmony_ci
2983e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2984e5c31af7Sopenharmony_ci
2985e5c31af7Sopenharmony_ci	const int py = 0;
2986e5c31af7Sopenharmony_ci	{
2987e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
2988e5c31af7Sopenharmony_ci		{
2989e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= result.getPixel(px, py);
2990e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= reference.getPixel(px, py);
2991e5c31af7Sopenharmony_ci
2992e5c31af7Sopenharmony_ci			// Other channels should trivially match to reference.
2993e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2994e5c31af7Sopenharmony_ci			{
2995e5c31af7Sopenharmony_ci				errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2996e5c31af7Sopenharmony_ci				numFailed += 1;
2997e5c31af7Sopenharmony_ci				continue;
2998e5c31af7Sopenharmony_ci			}
2999e5c31af7Sopenharmony_ci
3000e5c31af7Sopenharmony_ci			// Reference result is known to be a valid result, we can
3001e5c31af7Sopenharmony_ci			// skip verification if these results are equal
3002e5c31af7Sopenharmony_ci			if (resPix.x() != refPix.x())
3003e5c31af7Sopenharmony_ci			{
3004e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
3005e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
3006e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
3007e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
3008e5c31af7Sopenharmony_ci
3009e5c31af7Sopenharmony_ci				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
3010e5c31af7Sopenharmony_ci				const float		triWx	= triNdx ? dstW - wx : wx;
3011e5c31af7Sopenharmony_ci				const float		triWy	= triNdx ? dstH - wy : wy;
3012e5c31af7Sopenharmony_ci				const float		triNx	= triNdx ? 1.0f - nx : nx;
3013e5c31af7Sopenharmony_ci				const float		triNy	= triNdx ? 1.0f - ny : ny;
3014e5c31af7Sopenharmony_ci
3015e5c31af7Sopenharmony_ci				const tcu::Vec2	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
3016e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
3017e5c31af7Sopenharmony_ci				const float		coordDx		= triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
3018e5c31af7Sopenharmony_ci
3019e5c31af7Sopenharmony_ci				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx, coordDx, lodPrec);
3020e5c31af7Sopenharmony_ci
3021e5c31af7Sopenharmony_ci				// Compute lod bounds across lodOffsets range.
3022e5c31af7Sopenharmony_ci				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3023e5c31af7Sopenharmony_ci				{
3024e5c31af7Sopenharmony_ci					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
3025e5c31af7Sopenharmony_ci					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
3026e5c31af7Sopenharmony_ci					const float		nxo		= wxo/dstW;
3027e5c31af7Sopenharmony_ci					const float		nyo		= wyo/dstH;
3028e5c31af7Sopenharmony_ci
3029e5c31af7Sopenharmony_ci					const float		coordDxo	= triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
3030e5c31af7Sopenharmony_ci					const float		coordDyo	= triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
3031e5c31af7Sopenharmony_ci					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
3032e5c31af7Sopenharmony_ci
3033e5c31af7Sopenharmony_ci					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3034e5c31af7Sopenharmony_ci					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3035e5c31af7Sopenharmony_ci				}
3036e5c31af7Sopenharmony_ci
3037e5c31af7Sopenharmony_ci				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3038e5c31af7Sopenharmony_ci				const bool		isOk		= tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3039e5c31af7Sopenharmony_ci
3040e5c31af7Sopenharmony_ci				if (!isOk)
3041e5c31af7Sopenharmony_ci				{
3042e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3043e5c31af7Sopenharmony_ci					numFailed += 1;
3044e5c31af7Sopenharmony_ci				}
3045e5c31af7Sopenharmony_ci			}
3046e5c31af7Sopenharmony_ci		}
3047e5c31af7Sopenharmony_ci	}
3048e5c31af7Sopenharmony_ci
3049e5c31af7Sopenharmony_ci	return numFailed;
3050e5c31af7Sopenharmony_ci}
3051e5c31af7Sopenharmony_ci
3052e5c31af7Sopenharmony_ciint computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&	result,
3053e5c31af7Sopenharmony_ci							   const tcu::ConstPixelBufferAccess&	reference,
3054e5c31af7Sopenharmony_ci							   const tcu::PixelBufferAccess&		errorMask,
3055e5c31af7Sopenharmony_ci							   const tcu::TextureCubeArrayView&		src,
3056e5c31af7Sopenharmony_ci							   const float*							texCoord,
3057e5c31af7Sopenharmony_ci							   const ReferenceParams&				sampleParams,
3058e5c31af7Sopenharmony_ci							   const tcu::TexComparePrecision&		comparePrec,
3059e5c31af7Sopenharmony_ci							   const tcu::LodPrecision&				lodPrec,
3060e5c31af7Sopenharmony_ci							   const tcu::Vec3&						nonShadowThreshold)
3061e5c31af7Sopenharmony_ci{
3062e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3063e5c31af7Sopenharmony_ci	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
3064e5c31af7Sopenharmony_ci
3065e5c31af7Sopenharmony_ci	const tcu::Vec4		sq				= tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
3066e5c31af7Sopenharmony_ci	const tcu::Vec4		tq				= tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
3067e5c31af7Sopenharmony_ci	const tcu::Vec4		rq				= tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
3068e5c31af7Sopenharmony_ci	const tcu::Vec4		qq				= tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
3069e5c31af7Sopenharmony_ci
3070e5c31af7Sopenharmony_ci	const tcu::IVec2	dstSize			= tcu::IVec2(result.getWidth(), result.getHeight());
3071e5c31af7Sopenharmony_ci	const float			dstW			= float(dstSize.x());
3072e5c31af7Sopenharmony_ci	const float			dstH			= float(dstSize.y());
3073e5c31af7Sopenharmony_ci	const int			srcSize			= src.getSize();
3074e5c31af7Sopenharmony_ci
3075e5c31af7Sopenharmony_ci	// Coordinates per triangle.
3076e5c31af7Sopenharmony_ci	const tcu::Vec3		triS[2]			= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
3077e5c31af7Sopenharmony_ci	const tcu::Vec3		triT[2]			= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
3078e5c31af7Sopenharmony_ci	const tcu::Vec3		triR[2]			= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
3079e5c31af7Sopenharmony_ci	const tcu::Vec3		triQ[2]			= { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
3080e5c31af7Sopenharmony_ci	const tcu::Vec3		triW[2]			= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
3081e5c31af7Sopenharmony_ci
3082e5c31af7Sopenharmony_ci	const tcu::Vec2		lodBias			((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
3083e5c31af7Sopenharmony_ci
3084e5c31af7Sopenharmony_ci	int					numFailed		= 0;
3085e5c31af7Sopenharmony_ci
3086e5c31af7Sopenharmony_ci	const tcu::Vec2		lodOffsets[]	=
3087e5c31af7Sopenharmony_ci	{
3088e5c31af7Sopenharmony_ci		tcu::Vec2(-1,  0),
3089e5c31af7Sopenharmony_ci		tcu::Vec2(+1,  0),
3090e5c31af7Sopenharmony_ci		tcu::Vec2( 0, -1),
3091e5c31af7Sopenharmony_ci		tcu::Vec2( 0, +1),
3092e5c31af7Sopenharmony_ci	};
3093e5c31af7Sopenharmony_ci
3094e5c31af7Sopenharmony_ci	tcu::clear(errorMask, tcu::RGBA::green().toVec());
3095e5c31af7Sopenharmony_ci
3096e5c31af7Sopenharmony_ci	for (int py = 0; py < result.getHeight(); py++)
3097e5c31af7Sopenharmony_ci	{
3098e5c31af7Sopenharmony_ci		for (int px = 0; px < result.getWidth(); px++)
3099e5c31af7Sopenharmony_ci		{
3100e5c31af7Sopenharmony_ci			const tcu::Vec4	resPix	= result.getPixel(px, py);
3101e5c31af7Sopenharmony_ci			const tcu::Vec4	refPix	= reference.getPixel(px, py);
3102e5c31af7Sopenharmony_ci
3103e5c31af7Sopenharmony_ci			// Other channels should trivially match to reference.
3104e5c31af7Sopenharmony_ci			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
3105e5c31af7Sopenharmony_ci			{
3106e5c31af7Sopenharmony_ci				errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3107e5c31af7Sopenharmony_ci				numFailed += 1;
3108e5c31af7Sopenharmony_ci				continue;
3109e5c31af7Sopenharmony_ci			}
3110e5c31af7Sopenharmony_ci
3111e5c31af7Sopenharmony_ci			// Reference result is known to be a valid result, we can
3112e5c31af7Sopenharmony_ci			// skip verification if thes results are equal
3113e5c31af7Sopenharmony_ci			if (resPix.x() != refPix.x())
3114e5c31af7Sopenharmony_ci			{
3115e5c31af7Sopenharmony_ci				const float		wx		= (float)px + 0.5f;
3116e5c31af7Sopenharmony_ci				const float		wy		= (float)py + 0.5f;
3117e5c31af7Sopenharmony_ci				const float		nx		= wx / dstW;
3118e5c31af7Sopenharmony_ci				const float		ny		= wy / dstH;
3119e5c31af7Sopenharmony_ci
3120e5c31af7Sopenharmony_ci				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
3121e5c31af7Sopenharmony_ci				const float		triWx	= triNdx ? dstW - wx : wx;
3122e5c31af7Sopenharmony_ci				const float		triWy	= triNdx ? dstH - wy : wy;
3123e5c31af7Sopenharmony_ci				const float		triNx	= triNdx ? 1.0f - nx : nx;
3124e5c31af7Sopenharmony_ci				const float		triNy	= triNdx ? 1.0f - ny : ny;
3125e5c31af7Sopenharmony_ci
3126e5c31af7Sopenharmony_ci				const tcu::Vec4	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
3127e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
3128e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
3129e5c31af7Sopenharmony_ci											 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
3130e5c31af7Sopenharmony_ci				const tcu::Vec3	coordDx		(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
3131e5c31af7Sopenharmony_ci											 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
3132e5c31af7Sopenharmony_ci											 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
3133e5c31af7Sopenharmony_ci				const tcu::Vec3	coordDy		(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
3134e5c31af7Sopenharmony_ci											 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
3135e5c31af7Sopenharmony_ci											 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
3136e5c31af7Sopenharmony_ci
3137e5c31af7Sopenharmony_ci				tcu::Vec2		lodBounds	= tcu::computeCubeLodBoundsFromDerivates(coord.swizzle(0,1,2), coordDx, coordDy, srcSize, lodPrec);
3138e5c31af7Sopenharmony_ci
3139e5c31af7Sopenharmony_ci				// Compute lod bounds across lodOffsets range.
3140e5c31af7Sopenharmony_ci				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3141e5c31af7Sopenharmony_ci				{
3142e5c31af7Sopenharmony_ci					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
3143e5c31af7Sopenharmony_ci					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
3144e5c31af7Sopenharmony_ci					const float		nxo		= wxo/dstW;
3145e5c31af7Sopenharmony_ci					const float		nyo		= wyo/dstH;
3146e5c31af7Sopenharmony_ci
3147e5c31af7Sopenharmony_ci					const tcu::Vec3	coordO		(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
3148e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
3149e5c31af7Sopenharmony_ci												 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
3150e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDxo	(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
3151e5c31af7Sopenharmony_ci												 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
3152e5c31af7Sopenharmony_ci												 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
3153e5c31af7Sopenharmony_ci					const tcu::Vec3	coordDyo	(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
3154e5c31af7Sopenharmony_ci												 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
3155e5c31af7Sopenharmony_ci												 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
3156e5c31af7Sopenharmony_ci					const tcu::Vec2	lodO		= tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
3157e5c31af7Sopenharmony_ci
3158e5c31af7Sopenharmony_ci					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3159e5c31af7Sopenharmony_ci					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3160e5c31af7Sopenharmony_ci				}
3161e5c31af7Sopenharmony_ci
3162e5c31af7Sopenharmony_ci				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3163e5c31af7Sopenharmony_ci				const bool		isOk		= tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3164e5c31af7Sopenharmony_ci
3165e5c31af7Sopenharmony_ci				if (!isOk)
3166e5c31af7Sopenharmony_ci				{
3167e5c31af7Sopenharmony_ci					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3168e5c31af7Sopenharmony_ci					numFailed += 1;
3169e5c31af7Sopenharmony_ci				}
3170e5c31af7Sopenharmony_ci			}
3171e5c31af7Sopenharmony_ci		}
3172e5c31af7Sopenharmony_ci	}
3173e5c31af7Sopenharmony_ci
3174e5c31af7Sopenharmony_ci	return numFailed;
3175e5c31af7Sopenharmony_ci}
3176e5c31af7Sopenharmony_ci
3177e5c31af7Sopenharmony_ci// Mipmap generation comparison.
3178e5c31af7Sopenharmony_ci
3179e5c31af7Sopenharmony_cistatic int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3180e5c31af7Sopenharmony_ci{
3181e5c31af7Sopenharmony_ci	DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3182e5c31af7Sopenharmony_ci
3183e5c31af7Sopenharmony_ci	const float		dstW		= float(dst.getWidth());
3184e5c31af7Sopenharmony_ci	const float		dstH		= float(dst.getHeight());
3185e5c31af7Sopenharmony_ci	const float		srcW		= float(src.getWidth());
3186e5c31af7Sopenharmony_ci	const float		srcH		= float(src.getHeight());
3187e5c31af7Sopenharmony_ci	int				numFailed	= 0;
3188e5c31af7Sopenharmony_ci
3189e5c31af7Sopenharmony_ci	// Translation to lookup verification parameters.
3190e5c31af7Sopenharmony_ci	const tcu::Sampler		sampler		(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3191e5c31af7Sopenharmony_ci										 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3192e5c31af7Sopenharmony_ci	tcu::LookupPrecision	lookupPrec;
3193e5c31af7Sopenharmony_ci
3194e5c31af7Sopenharmony_ci	lookupPrec.colorThreshold	= precision.colorThreshold;
3195e5c31af7Sopenharmony_ci	lookupPrec.colorMask		= precision.colorMask;
3196e5c31af7Sopenharmony_ci	lookupPrec.coordBits		= tcu::IVec3(22);
3197e5c31af7Sopenharmony_ci	lookupPrec.uvwBits			= precision.filterBits;
3198e5c31af7Sopenharmony_ci
3199e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
3200e5c31af7Sopenharmony_ci	for (int x = 0; x < dst.getWidth(); x++)
3201e5c31af7Sopenharmony_ci	{
3202e5c31af7Sopenharmony_ci		const tcu::Vec4	result	= dst.getPixel(x, y);
3203e5c31af7Sopenharmony_ci		const float		cx		= (float(x)+0.5f) / dstW * srcW;
3204e5c31af7Sopenharmony_ci		const float		cy		= (float(y)+0.5f) / dstH * srcH;
3205e5c31af7Sopenharmony_ci		const bool		isOk	= tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3206e5c31af7Sopenharmony_ci
3207e5c31af7Sopenharmony_ci		errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
3208e5c31af7Sopenharmony_ci		if (!isOk)
3209e5c31af7Sopenharmony_ci			numFailed += 1;
3210e5c31af7Sopenharmony_ci	}
3211e5c31af7Sopenharmony_ci
3212e5c31af7Sopenharmony_ci	return numFailed;
3213e5c31af7Sopenharmony_ci}
3214e5c31af7Sopenharmony_ci
3215e5c31af7Sopenharmony_cistatic int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3216e5c31af7Sopenharmony_ci{
3217e5c31af7Sopenharmony_ci	DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3218e5c31af7Sopenharmony_ci
3219e5c31af7Sopenharmony_ci	const float		dstW		= float(dst.getWidth());
3220e5c31af7Sopenharmony_ci	const float		dstH		= float(dst.getHeight());
3221e5c31af7Sopenharmony_ci	const float		srcW		= float(src.getWidth());
3222e5c31af7Sopenharmony_ci	const float		srcH		= float(src.getHeight());
3223e5c31af7Sopenharmony_ci	int				numFailed	= 0;
3224e5c31af7Sopenharmony_ci
3225e5c31af7Sopenharmony_ci	// Translation to lookup verification parameters.
3226e5c31af7Sopenharmony_ci	const tcu::Sampler		sampler		(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3227e5c31af7Sopenharmony_ci										 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3228e5c31af7Sopenharmony_ci	tcu::LookupPrecision	lookupPrec;
3229e5c31af7Sopenharmony_ci
3230e5c31af7Sopenharmony_ci	lookupPrec.colorThreshold	= precision.colorThreshold;
3231e5c31af7Sopenharmony_ci	lookupPrec.colorMask		= precision.colorMask;
3232e5c31af7Sopenharmony_ci	lookupPrec.coordBits		= tcu::IVec3(22);
3233e5c31af7Sopenharmony_ci	lookupPrec.uvwBits			= precision.filterBits;
3234e5c31af7Sopenharmony_ci
3235e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
3236e5c31af7Sopenharmony_ci	for (int x = 0; x < dst.getWidth(); x++)
3237e5c31af7Sopenharmony_ci	{
3238e5c31af7Sopenharmony_ci		const tcu::Vec4	result	= dst.getPixel(x, y);
3239e5c31af7Sopenharmony_ci		const float		cx		= deFloatFloor(float(x) / dstW * srcW) + 1.0f;
3240e5c31af7Sopenharmony_ci		const float		cy		= deFloatFloor(float(y) / dstH * srcH) + 1.0f;
3241e5c31af7Sopenharmony_ci		const bool		isOk	= tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3242e5c31af7Sopenharmony_ci
3243e5c31af7Sopenharmony_ci		errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
3244e5c31af7Sopenharmony_ci		if (!isOk)
3245e5c31af7Sopenharmony_ci			numFailed += 1;
3246e5c31af7Sopenharmony_ci	}
3247e5c31af7Sopenharmony_ci
3248e5c31af7Sopenharmony_ci	return numFailed;
3249e5c31af7Sopenharmony_ci}
3250e5c31af7Sopenharmony_ci
3251e5c31af7Sopenharmony_cistatic int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3252e5c31af7Sopenharmony_ci{
3253e5c31af7Sopenharmony_ci	DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3254e5c31af7Sopenharmony_ci	DE_UNREF(precision);
3255e5c31af7Sopenharmony_ci
3256e5c31af7Sopenharmony_ci	const float		dstW		= float(dst.getWidth());
3257e5c31af7Sopenharmony_ci	const float		dstH		= float(dst.getHeight());
3258e5c31af7Sopenharmony_ci	const float		srcW		= float(src.getWidth());
3259e5c31af7Sopenharmony_ci	const float		srcH		= float(src.getHeight());
3260e5c31af7Sopenharmony_ci	int				numFailed	= 0;
3261e5c31af7Sopenharmony_ci
3262e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
3263e5c31af7Sopenharmony_ci	for (int x = 0; x < dst.getWidth(); x++)
3264e5c31af7Sopenharmony_ci	{
3265e5c31af7Sopenharmony_ci		const tcu::Vec4	result	= dst.getPixel(x, y);
3266e5c31af7Sopenharmony_ci		const int		minX		= deFloorFloatToInt32(((float)x-0.5f) / dstW * srcW);
3267e5c31af7Sopenharmony_ci		const int		minY		= deFloorFloatToInt32(((float)y-0.5f) / dstH * srcH);
3268e5c31af7Sopenharmony_ci		const int		maxX		= deCeilFloatToInt32(((float)x+1.5f) / dstW * srcW);
3269e5c31af7Sopenharmony_ci		const int		maxY		= deCeilFloatToInt32(((float)y+1.5f) / dstH * srcH);
3270e5c31af7Sopenharmony_ci		tcu::Vec4		minVal, maxVal;
3271e5c31af7Sopenharmony_ci		bool			isOk;
3272e5c31af7Sopenharmony_ci
3273e5c31af7Sopenharmony_ci		DE_ASSERT(minX < maxX && minY < maxY);
3274e5c31af7Sopenharmony_ci
3275e5c31af7Sopenharmony_ci		for (int ky = minY; ky <= maxY; ky++)
3276e5c31af7Sopenharmony_ci		{
3277e5c31af7Sopenharmony_ci			for (int kx = minX; kx <= maxX; kx++)
3278e5c31af7Sopenharmony_ci			{
3279e5c31af7Sopenharmony_ci				const int		sx		= de::clamp(kx, 0, src.getWidth()-1);
3280e5c31af7Sopenharmony_ci				const int		sy		= de::clamp(ky, 0, src.getHeight()-1);
3281e5c31af7Sopenharmony_ci				const tcu::Vec4	sample	= src.getPixel(sx, sy);
3282e5c31af7Sopenharmony_ci
3283e5c31af7Sopenharmony_ci				if (ky == minY && kx == minX)
3284e5c31af7Sopenharmony_ci				{
3285e5c31af7Sopenharmony_ci					minVal = sample;
3286e5c31af7Sopenharmony_ci					maxVal = sample;
3287e5c31af7Sopenharmony_ci				}
3288e5c31af7Sopenharmony_ci				else
3289e5c31af7Sopenharmony_ci				{
3290e5c31af7Sopenharmony_ci					minVal = min(sample, minVal);
3291e5c31af7Sopenharmony_ci					maxVal = max(sample, maxVal);
3292e5c31af7Sopenharmony_ci				}
3293e5c31af7Sopenharmony_ci			}
3294e5c31af7Sopenharmony_ci		}
3295e5c31af7Sopenharmony_ci
3296e5c31af7Sopenharmony_ci		isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
3297e5c31af7Sopenharmony_ci
3298e5c31af7Sopenharmony_ci		errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
3299e5c31af7Sopenharmony_ci		if (!isOk)
3300e5c31af7Sopenharmony_ci			numFailed += 1;
3301e5c31af7Sopenharmony_ci	}
3302e5c31af7Sopenharmony_ci
3303e5c31af7Sopenharmony_ci	return numFailed;
3304e5c31af7Sopenharmony_ci}
3305e5c31af7Sopenharmony_ci
3306e5c31af7Sopenharmony_ciqpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
3307e5c31af7Sopenharmony_ci{
3308e5c31af7Sopenharmony_ci	qpTestResult result = QP_TEST_RESULT_PASS;
3309e5c31af7Sopenharmony_ci
3310e5c31af7Sopenharmony_ci	// Special comparison for level 0.
3311e5c31af7Sopenharmony_ci	{
3312e5c31af7Sopenharmony_ci		const tcu::Vec4		threshold	= select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3313e5c31af7Sopenharmony_ci		const bool			level0Ok	= tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
3314e5c31af7Sopenharmony_ci
3315e5c31af7Sopenharmony_ci		if (!level0Ok)
3316e5c31af7Sopenharmony_ci		{
3317e5c31af7Sopenharmony_ci			log << tcu::TestLog::Message << "ERROR: Level 0 comparison failed!" << tcu::TestLog::EndMessage;
3318e5c31af7Sopenharmony_ci			result = QP_TEST_RESULT_FAIL;
3319e5c31af7Sopenharmony_ci		}
3320e5c31af7Sopenharmony_ci	}
3321e5c31af7Sopenharmony_ci
3322e5c31af7Sopenharmony_ci	for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3323e5c31af7Sopenharmony_ci	{
3324e5c31af7Sopenharmony_ci		const tcu::ConstPixelBufferAccess	src			= resultTexture.getLevel(levelNdx-1);
3325e5c31af7Sopenharmony_ci		const tcu::ConstPixelBufferAccess	dst			= resultTexture.getLevel(levelNdx);
3326e5c31af7Sopenharmony_ci		tcu::Surface						errorMask	(dst.getWidth(), dst.getHeight());
3327e5c31af7Sopenharmony_ci		bool								levelOk		= false;
3328e5c31af7Sopenharmony_ci
3329e5c31af7Sopenharmony_ci		// Try different comparisons in quality order.
3330e5c31af7Sopenharmony_ci
3331e5c31af7Sopenharmony_ci		if (!levelOk)
3332e5c31af7Sopenharmony_ci		{
3333e5c31af7Sopenharmony_ci			const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3334e5c31af7Sopenharmony_ci			if (numFailed == 0)
3335e5c31af7Sopenharmony_ci				levelOk = true;
3336e5c31af7Sopenharmony_ci			else
3337e5c31af7Sopenharmony_ci				log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
3338e5c31af7Sopenharmony_ci		}
3339e5c31af7Sopenharmony_ci
3340e5c31af7Sopenharmony_ci		if (!levelOk)
3341e5c31af7Sopenharmony_ci		{
3342e5c31af7Sopenharmony_ci			const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3343e5c31af7Sopenharmony_ci			if (numFailed == 0)
3344e5c31af7Sopenharmony_ci				levelOk = true;
3345e5c31af7Sopenharmony_ci			else
3346e5c31af7Sopenharmony_ci				log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
3347e5c31af7Sopenharmony_ci		}
3348e5c31af7Sopenharmony_ci
3349e5c31af7Sopenharmony_ci		// At this point all high-quality methods have been used.
3350e5c31af7Sopenharmony_ci		if (!levelOk && result == QP_TEST_RESULT_PASS)
3351e5c31af7Sopenharmony_ci			result = QP_TEST_RESULT_QUALITY_WARNING;
3352e5c31af7Sopenharmony_ci
3353e5c31af7Sopenharmony_ci		if (!levelOk)
3354e5c31af7Sopenharmony_ci		{
3355e5c31af7Sopenharmony_ci			const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3356e5c31af7Sopenharmony_ci			if (numFailed == 0)
3357e5c31af7Sopenharmony_ci				levelOk = true;
3358e5c31af7Sopenharmony_ci			else
3359e5c31af7Sopenharmony_ci				log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
3360e5c31af7Sopenharmony_ci		}
3361e5c31af7Sopenharmony_ci
3362e5c31af7Sopenharmony_ci		if (!levelOk)
3363e5c31af7Sopenharmony_ci			result = QP_TEST_RESULT_FAIL;
3364e5c31af7Sopenharmony_ci
3365e5c31af7Sopenharmony_ci		log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
3366e5c31af7Sopenharmony_ci			<< tcu::TestLog::Image("Result", "Result", dst);
3367e5c31af7Sopenharmony_ci
3368e5c31af7Sopenharmony_ci		if (!levelOk)
3369e5c31af7Sopenharmony_ci			log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
3370e5c31af7Sopenharmony_ci
3371e5c31af7Sopenharmony_ci		log << tcu::TestLog::EndImageSet;
3372e5c31af7Sopenharmony_ci	}
3373e5c31af7Sopenharmony_ci
3374e5c31af7Sopenharmony_ci	return result;
3375e5c31af7Sopenharmony_ci}
3376e5c31af7Sopenharmony_ci
3377e5c31af7Sopenharmony_ciqpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
3378e5c31af7Sopenharmony_ci{
3379e5c31af7Sopenharmony_ci	qpTestResult result = QP_TEST_RESULT_PASS;
3380e5c31af7Sopenharmony_ci
3381e5c31af7Sopenharmony_ci	static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
3382e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
3383e5c31af7Sopenharmony_ci
3384e5c31af7Sopenharmony_ci	// Special comparison for level 0.
3385e5c31af7Sopenharmony_ci	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3386e5c31af7Sopenharmony_ci	{
3387e5c31af7Sopenharmony_ci		const tcu::CubeFace	face		= tcu::CubeFace(faceNdx);
3388e5c31af7Sopenharmony_ci		const tcu::Vec4		threshold	= select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3389e5c31af7Sopenharmony_ci		const bool			level0Ok	= tcu::floatThresholdCompare(log,
3390e5c31af7Sopenharmony_ci																	 ("Level0Face" + de::toString(faceNdx)).c_str(),
3391e5c31af7Sopenharmony_ci																	 (string("Level 0, face ") + s_faceNames[face]).c_str(),
3392e5c31af7Sopenharmony_ci																	 level0Reference.getLevelFace(0, face),
3393e5c31af7Sopenharmony_ci																	 resultTexture.getLevelFace(0, face),
3394e5c31af7Sopenharmony_ci																	 threshold, tcu::COMPARE_LOG_RESULT);
3395e5c31af7Sopenharmony_ci
3396e5c31af7Sopenharmony_ci		if (!level0Ok)
3397e5c31af7Sopenharmony_ci		{
3398e5c31af7Sopenharmony_ci			log << tcu::TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << tcu::TestLog::EndMessage;
3399e5c31af7Sopenharmony_ci			result = QP_TEST_RESULT_FAIL;
3400e5c31af7Sopenharmony_ci		}
3401e5c31af7Sopenharmony_ci	}
3402e5c31af7Sopenharmony_ci
3403e5c31af7Sopenharmony_ci	for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3404e5c31af7Sopenharmony_ci	{
3405e5c31af7Sopenharmony_ci		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3406e5c31af7Sopenharmony_ci		{
3407e5c31af7Sopenharmony_ci			const tcu::CubeFace					face		= tcu::CubeFace(faceNdx);
3408e5c31af7Sopenharmony_ci			const char*							faceName	= s_faceNames[face];
3409e5c31af7Sopenharmony_ci			const tcu::ConstPixelBufferAccess	src			= resultTexture.getLevelFace(levelNdx-1,	face);
3410e5c31af7Sopenharmony_ci			const tcu::ConstPixelBufferAccess	dst			= resultTexture.getLevelFace(levelNdx,		face);
3411e5c31af7Sopenharmony_ci			tcu::Surface						errorMask	(dst.getWidth(), dst.getHeight());
3412e5c31af7Sopenharmony_ci			bool								levelOk		= false;
3413e5c31af7Sopenharmony_ci
3414e5c31af7Sopenharmony_ci			// Try different comparisons in quality order.
3415e5c31af7Sopenharmony_ci
3416e5c31af7Sopenharmony_ci			if (!levelOk)
3417e5c31af7Sopenharmony_ci			{
3418e5c31af7Sopenharmony_ci				const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3419e5c31af7Sopenharmony_ci				if (numFailed == 0)
3420e5c31af7Sopenharmony_ci					levelOk = true;
3421e5c31af7Sopenharmony_ci				else
3422e5c31af7Sopenharmony_ci					log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
3423e5c31af7Sopenharmony_ci			}
3424e5c31af7Sopenharmony_ci
3425e5c31af7Sopenharmony_ci			if (!levelOk)
3426e5c31af7Sopenharmony_ci			{
3427e5c31af7Sopenharmony_ci				const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3428e5c31af7Sopenharmony_ci				if (numFailed == 0)
3429e5c31af7Sopenharmony_ci					levelOk = true;
3430e5c31af7Sopenharmony_ci				else
3431e5c31af7Sopenharmony_ci					log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
3432e5c31af7Sopenharmony_ci			}
3433e5c31af7Sopenharmony_ci
3434e5c31af7Sopenharmony_ci			// At this point all high-quality methods have been used.
3435e5c31af7Sopenharmony_ci			if (!levelOk && result == QP_TEST_RESULT_PASS)
3436e5c31af7Sopenharmony_ci				result = QP_TEST_RESULT_QUALITY_WARNING;
3437e5c31af7Sopenharmony_ci
3438e5c31af7Sopenharmony_ci			if (!levelOk)
3439e5c31af7Sopenharmony_ci			{
3440e5c31af7Sopenharmony_ci				const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3441e5c31af7Sopenharmony_ci				if (numFailed == 0)
3442e5c31af7Sopenharmony_ci					levelOk = true;
3443e5c31af7Sopenharmony_ci				else
3444e5c31af7Sopenharmony_ci					log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
3445e5c31af7Sopenharmony_ci			}
3446e5c31af7Sopenharmony_ci
3447e5c31af7Sopenharmony_ci			if (!levelOk)
3448e5c31af7Sopenharmony_ci				result = QP_TEST_RESULT_FAIL;
3449e5c31af7Sopenharmony_ci
3450e5c31af7Sopenharmony_ci			log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
3451e5c31af7Sopenharmony_ci				<< tcu::TestLog::Image("Result", "Result", dst);
3452e5c31af7Sopenharmony_ci
3453e5c31af7Sopenharmony_ci			if (!levelOk)
3454e5c31af7Sopenharmony_ci				log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
3455e5c31af7Sopenharmony_ci
3456e5c31af7Sopenharmony_ci			log << tcu::TestLog::EndImageSet;
3457e5c31af7Sopenharmony_ci		}
3458e5c31af7Sopenharmony_ci	}
3459e5c31af7Sopenharmony_ci
3460e5c31af7Sopenharmony_ci	return result;
3461e5c31af7Sopenharmony_ci}
3462e5c31af7Sopenharmony_ci
3463e5c31af7Sopenharmony_ci// Logging utilities.
3464e5c31af7Sopenharmony_ci
3465e5c31af7Sopenharmony_cistd::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
3466e5c31af7Sopenharmony_ci{
3467e5c31af7Sopenharmony_ci	return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
3468e5c31af7Sopenharmony_ci			   <<  "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
3469e5c31af7Sopenharmony_ci			   <<  "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
3470e5c31af7Sopenharmony_ci			   <<  "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
3471e5c31af7Sopenharmony_ci}
3472e5c31af7Sopenharmony_ci
3473e5c31af7Sopenharmony_ci} // TextureTestUtil
3474e5c31af7Sopenharmony_ci} // glu
3475