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