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