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